1#[allow(unused_imports)]
9use alloc::collections::BTreeMap;
10
11#[allow(unused_imports)]
12use core::marker::PhantomData;
13use jacquard_common::{CowStr, BosStr, DefaultStr, FromStaticStr};
14
15#[allow(unused_imports)]
16use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
17use jacquard_common::deps::smol_str::SmolStr;
18use jacquard_common::types::collection::{Collection, RecordError};
19use jacquard_common::types::string::{AtUri, Cid, Datetime};
20use jacquard_common::types::uri::{RecordUri, UriError};
21use jacquard_common::types::value::Data;
22use jacquard_common::xrpc::XrpcResp;
23use jacquard_derive::{IntoStatic, lexicon, open_union};
24use jacquard_lexicon::lexicon::LexiconDoc;
25use jacquard_lexicon::schema::LexiconSchema;
26
27#[allow(unused_imports)]
28use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
29use serde::{Serialize, Deserialize};
30use crate::app_bsky::feed::threadgate;
31#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
34#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
35pub struct FollowerRule<S: BosStr = DefaultStr> {
36 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
37 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
38}
39
40#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
43#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
44pub struct FollowingRule<S: BosStr = DefaultStr> {
45 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
46 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
47}
48
49#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
52#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
53pub struct ListRule<S: BosStr = DefaultStr> {
54 pub list: AtUri<S>,
55 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
56 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
57}
58
59#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
62#[serde(
63 rename_all = "camelCase",
64 rename = "app.bsky.feed.threadgate",
65 tag = "$type",
66 bound(deserialize = "S: Deserialize<'de> + BosStr")
67)]
68pub struct Threadgate<S: BosStr = DefaultStr> {
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub allow: Option<Vec<ThreadgateAllowItem<S>>>,
72 pub created_at: Datetime,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub hidden_replies: Option<Vec<AtUri<S>>>,
76 pub post: AtUri<S>,
78 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
79 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
80}
81
82
83#[open_union]
84#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
85#[serde(tag = "$type", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
86pub enum ThreadgateAllowItem<S: BosStr = DefaultStr> {
87 #[serde(rename = "app.bsky.feed.threadgate#mentionRule")]
88 MentionRule(Box<threadgate::MentionRule<S>>),
89 #[serde(rename = "app.bsky.feed.threadgate#followerRule")]
90 FollowerRule(Box<threadgate::FollowerRule<S>>),
91 #[serde(rename = "app.bsky.feed.threadgate#followingRule")]
92 FollowingRule(Box<threadgate::FollowingRule<S>>),
93 #[serde(rename = "app.bsky.feed.threadgate#listRule")]
94 ListRule(Box<threadgate::ListRule<S>>),
95}
96
97#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
100#[serde(rename_all = "camelCase")]
101pub struct ThreadgateGetRecordOutput<S: BosStr = DefaultStr> {
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub cid: Option<Cid<S>>,
104 pub uri: AtUri<S>,
105 pub value: Threadgate<S>,
106}
107
108#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
111#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
112pub struct MentionRule<S: BosStr = DefaultStr> {
113 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
114 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
115}
116
117impl<S: BosStr> Threadgate<S> {
118 pub fn uri(uri: S) -> Result<RecordUri<S, ThreadgateRecord>, UriError> {
119 RecordUri::try_from_uri(AtUri::new(uri)?)
120 }
121}
122
123impl<S: BosStr> LexiconSchema for FollowerRule<S> {
124 fn nsid() -> &'static str {
125 "app.bsky.feed.threadgate"
126 }
127 fn def_name() -> &'static str {
128 "followerRule"
129 }
130 fn lexicon_doc() -> LexiconDoc<'static> {
131 lexicon_doc_app_bsky_feed_threadgate()
132 }
133 fn validate(&self) -> Result<(), ConstraintError> {
134 Ok(())
135 }
136}
137
138impl<S: BosStr> LexiconSchema for FollowingRule<S> {
139 fn nsid() -> &'static str {
140 "app.bsky.feed.threadgate"
141 }
142 fn def_name() -> &'static str {
143 "followingRule"
144 }
145 fn lexicon_doc() -> LexiconDoc<'static> {
146 lexicon_doc_app_bsky_feed_threadgate()
147 }
148 fn validate(&self) -> Result<(), ConstraintError> {
149 Ok(())
150 }
151}
152
153impl<S: BosStr> LexiconSchema for ListRule<S> {
154 fn nsid() -> &'static str {
155 "app.bsky.feed.threadgate"
156 }
157 fn def_name() -> &'static str {
158 "listRule"
159 }
160 fn lexicon_doc() -> LexiconDoc<'static> {
161 lexicon_doc_app_bsky_feed_threadgate()
162 }
163 fn validate(&self) -> Result<(), ConstraintError> {
164 Ok(())
165 }
166}
167
168#[derive(Debug, Serialize, Deserialize)]
171pub struct ThreadgateRecord;
172impl XrpcResp for ThreadgateRecord {
173 const NSID: &'static str = "app.bsky.feed.threadgate";
174 const ENCODING: &'static str = "application/json";
175 type Output<S: BosStr> = ThreadgateGetRecordOutput<S>;
176 type Err = RecordError;
177}
178
179impl<S: BosStr> From<ThreadgateGetRecordOutput<S>> for Threadgate<S> {
180 fn from(output: ThreadgateGetRecordOutput<S>) -> Self {
181 output.value
182 }
183}
184
185impl<S: BosStr> Collection for Threadgate<S> {
186 const NSID: &'static str = "app.bsky.feed.threadgate";
187 type Record = ThreadgateRecord;
188}
189
190impl Collection for ThreadgateRecord {
191 const NSID: &'static str = "app.bsky.feed.threadgate";
192 type Record = ThreadgateRecord;
193}
194
195impl<S: BosStr> LexiconSchema for Threadgate<S> {
196 fn nsid() -> &'static str {
197 "app.bsky.feed.threadgate"
198 }
199 fn def_name() -> &'static str {
200 "main"
201 }
202 fn lexicon_doc() -> LexiconDoc<'static> {
203 lexicon_doc_app_bsky_feed_threadgate()
204 }
205 fn validate(&self) -> Result<(), ConstraintError> {
206 if let Some(ref value) = self.allow {
207 #[allow(unused_comparisons)]
208 if value.len() > 5usize {
209 return Err(ConstraintError::MaxLength {
210 path: ValidationPath::from_field("allow"),
211 max: 5usize,
212 actual: value.len(),
213 });
214 }
215 }
216 if let Some(ref value) = self.hidden_replies {
217 #[allow(unused_comparisons)]
218 if value.len() > 300usize {
219 return Err(ConstraintError::MaxLength {
220 path: ValidationPath::from_field("hidden_replies"),
221 max: 300usize,
222 actual: value.len(),
223 });
224 }
225 }
226 Ok(())
227 }
228}
229
230impl<S: BosStr> LexiconSchema for MentionRule<S> {
231 fn nsid() -> &'static str {
232 "app.bsky.feed.threadgate"
233 }
234 fn def_name() -> &'static str {
235 "mentionRule"
236 }
237 fn lexicon_doc() -> LexiconDoc<'static> {
238 lexicon_doc_app_bsky_feed_threadgate()
239 }
240 fn validate(&self) -> Result<(), ConstraintError> {
241 Ok(())
242 }
243}
244
245fn lexicon_doc_app_bsky_feed_threadgate() -> LexiconDoc<'static> {
246 #[allow(unused_imports)]
247 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
248 use jacquard_lexicon::lexicon::*;
249 use alloc::collections::BTreeMap;
250 LexiconDoc {
251 lexicon: Lexicon::Lexicon1,
252 id: CowStr::new_static("app.bsky.feed.threadgate"),
253 defs: {
254 let mut map = BTreeMap::new();
255 map.insert(
256 SmolStr::new_static("followerRule"),
257 LexUserType::Object(LexObject {
258 description: Some(
259 CowStr::new_static("Allow replies from actors who follow you."),
260 ),
261 properties: {
262 #[allow(unused_mut)]
263 let mut map = BTreeMap::new();
264 map
265 },
266 ..Default::default()
267 }),
268 );
269 map.insert(
270 SmolStr::new_static("followingRule"),
271 LexUserType::Object(LexObject {
272 description: Some(
273 CowStr::new_static("Allow replies from actors you follow."),
274 ),
275 properties: {
276 #[allow(unused_mut)]
277 let mut map = BTreeMap::new();
278 map
279 },
280 ..Default::default()
281 }),
282 );
283 map.insert(
284 SmolStr::new_static("listRule"),
285 LexUserType::Object(LexObject {
286 description: Some(
287 CowStr::new_static("Allow replies from actors on a list."),
288 ),
289 required: Some(vec![SmolStr::new_static("list")]),
290 properties: {
291 #[allow(unused_mut)]
292 let mut map = BTreeMap::new();
293 map.insert(
294 SmolStr::new_static("list"),
295 LexObjectProperty::String(LexString {
296 format: Some(LexStringFormat::AtUri),
297 ..Default::default()
298 }),
299 );
300 map
301 },
302 ..Default::default()
303 }),
304 );
305 map.insert(
306 SmolStr::new_static("main"),
307 LexUserType::Record(LexRecord {
308 description: Some(
309 CowStr::new_static(
310 "Record defining interaction gating rules for a thread (aka, reply controls). The record key (rkey) of the threadgate record must match the record key of the thread's root post, and that record must be in the same repository.",
311 ),
312 ),
313 key: Some(CowStr::new_static("tid")),
314 record: LexRecordRecord::Object(LexObject {
315 required: Some(
316 vec![
317 SmolStr::new_static("post"),
318 SmolStr::new_static("createdAt")
319 ],
320 ),
321 properties: {
322 #[allow(unused_mut)]
323 let mut map = BTreeMap::new();
324 map.insert(
325 SmolStr::new_static("allow"),
326 LexObjectProperty::Array(LexArray {
327 description: Some(
328 CowStr::new_static(
329 "List of rules defining who can reply to this post. If value is an empty array, no one can reply. If value is undefined, anyone can reply.",
330 ),
331 ),
332 items: LexArrayItem::Union(LexRefUnion {
333 refs: vec![
334 CowStr::new_static("#mentionRule"),
335 CowStr::new_static("#followerRule"),
336 CowStr::new_static("#followingRule"),
337 CowStr::new_static("#listRule")
338 ],
339 ..Default::default()
340 }),
341 max_length: Some(5usize),
342 ..Default::default()
343 }),
344 );
345 map.insert(
346 SmolStr::new_static("createdAt"),
347 LexObjectProperty::String(LexString {
348 format: Some(LexStringFormat::Datetime),
349 ..Default::default()
350 }),
351 );
352 map.insert(
353 SmolStr::new_static("hiddenReplies"),
354 LexObjectProperty::Array(LexArray {
355 description: Some(
356 CowStr::new_static("List of hidden reply URIs."),
357 ),
358 items: LexArrayItem::String(LexString {
359 format: Some(LexStringFormat::AtUri),
360 ..Default::default()
361 }),
362 max_length: Some(300usize),
363 ..Default::default()
364 }),
365 );
366 map.insert(
367 SmolStr::new_static("post"),
368 LexObjectProperty::String(LexString {
369 description: Some(
370 CowStr::new_static("Reference (AT-URI) to the post record."),
371 ),
372 format: Some(LexStringFormat::AtUri),
373 ..Default::default()
374 }),
375 );
376 map
377 },
378 ..Default::default()
379 }),
380 ..Default::default()
381 }),
382 );
383 map.insert(
384 SmolStr::new_static("mentionRule"),
385 LexUserType::Object(LexObject {
386 description: Some(
387 CowStr::new_static(
388 "Allow replies from actors mentioned in your post.",
389 ),
390 ),
391 properties: {
392 #[allow(unused_mut)]
393 let mut map = BTreeMap::new();
394 map
395 },
396 ..Default::default()
397 }),
398 );
399 map
400 },
401 ..Default::default()
402 }
403}
404
405pub mod list_rule_state {
406
407 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
408 #[allow(unused)]
409 use ::core::marker::PhantomData;
410 mod sealed {
411 pub trait Sealed {}
412 }
413 pub trait State: sealed::Sealed {
415 type List;
416 }
417 pub struct Empty(());
419 impl sealed::Sealed for Empty {}
420 impl State for Empty {
421 type List = Unset;
422 }
423 pub struct SetList<St: State = Empty>(PhantomData<fn() -> St>);
425 impl<St: State> sealed::Sealed for SetList<St> {}
426 impl<St: State> State for SetList<St> {
427 type List = Set<members::list>;
428 }
429 #[allow(non_camel_case_types)]
431 pub mod members {
432 pub struct list(());
434 }
435}
436
437pub struct ListRuleBuilder<St: list_rule_state::State, S: BosStr = DefaultStr> {
439 _state: PhantomData<fn() -> St>,
440 _fields: (Option<AtUri<S>>,),
441 _type: PhantomData<fn() -> S>,
442}
443
444impl ListRule<DefaultStr> {
445 pub fn new() -> ListRuleBuilder<list_rule_state::Empty, DefaultStr> {
447 ListRuleBuilder::new()
448 }
449}
450
451impl<S: BosStr> ListRule<S> {
452 pub fn builder() -> ListRuleBuilder<list_rule_state::Empty, S> {
454 ListRuleBuilder::builder()
455 }
456}
457
458impl ListRuleBuilder<list_rule_state::Empty, DefaultStr> {
459 pub fn new() -> Self {
461 ListRuleBuilder {
462 _state: PhantomData,
463 _fields: (None,),
464 _type: PhantomData,
465 }
466 }
467}
468
469impl<S: BosStr> ListRuleBuilder<list_rule_state::Empty, S> {
470 pub fn builder() -> Self {
472 ListRuleBuilder {
473 _state: PhantomData,
474 _fields: (None,),
475 _type: PhantomData,
476 }
477 }
478}
479
480impl<St, S: BosStr> ListRuleBuilder<St, S>
481where
482 St: list_rule_state::State,
483 St::List: list_rule_state::IsUnset,
484{
485 pub fn list(
487 mut self,
488 value: impl Into<AtUri<S>>,
489 ) -> ListRuleBuilder<list_rule_state::SetList<St>, S> {
490 self._fields.0 = Option::Some(value.into());
491 ListRuleBuilder {
492 _state: PhantomData,
493 _fields: self._fields,
494 _type: PhantomData,
495 }
496 }
497}
498
499impl<St, S: BosStr> ListRuleBuilder<St, S>
500where
501 St: list_rule_state::State,
502 St::List: list_rule_state::IsSet,
503{
504 pub fn build(self) -> ListRule<S> {
506 ListRule {
507 list: self._fields.0.unwrap(),
508 extra_data: Default::default(),
509 }
510 }
511 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> ListRule<S> {
513 ListRule {
514 list: self._fields.0.unwrap(),
515 extra_data: Some(extra_data),
516 }
517 }
518}
519
520pub mod threadgate_state {
521
522 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
523 #[allow(unused)]
524 use ::core::marker::PhantomData;
525 mod sealed {
526 pub trait Sealed {}
527 }
528 pub trait State: sealed::Sealed {
530 type CreatedAt;
531 type Post;
532 }
533 pub struct Empty(());
535 impl sealed::Sealed for Empty {}
536 impl State for Empty {
537 type CreatedAt = Unset;
538 type Post = Unset;
539 }
540 pub struct SetCreatedAt<St: State = Empty>(PhantomData<fn() -> St>);
542 impl<St: State> sealed::Sealed for SetCreatedAt<St> {}
543 impl<St: State> State for SetCreatedAt<St> {
544 type CreatedAt = Set<members::created_at>;
545 type Post = St::Post;
546 }
547 pub struct SetPost<St: State = Empty>(PhantomData<fn() -> St>);
549 impl<St: State> sealed::Sealed for SetPost<St> {}
550 impl<St: State> State for SetPost<St> {
551 type CreatedAt = St::CreatedAt;
552 type Post = Set<members::post>;
553 }
554 #[allow(non_camel_case_types)]
556 pub mod members {
557 pub struct created_at(());
559 pub struct post(());
561 }
562}
563
564pub struct ThreadgateBuilder<St: threadgate_state::State, S: BosStr = DefaultStr> {
566 _state: PhantomData<fn() -> St>,
567 _fields: (
568 Option<Vec<ThreadgateAllowItem<S>>>,
569 Option<Datetime>,
570 Option<Vec<AtUri<S>>>,
571 Option<AtUri<S>>,
572 ),
573 _type: PhantomData<fn() -> S>,
574}
575
576impl Threadgate<DefaultStr> {
577 pub fn new() -> ThreadgateBuilder<threadgate_state::Empty, DefaultStr> {
579 ThreadgateBuilder::new()
580 }
581}
582
583impl<S: BosStr> Threadgate<S> {
584 pub fn builder() -> ThreadgateBuilder<threadgate_state::Empty, S> {
586 ThreadgateBuilder::builder()
587 }
588}
589
590impl ThreadgateBuilder<threadgate_state::Empty, DefaultStr> {
591 pub fn new() -> Self {
593 ThreadgateBuilder {
594 _state: PhantomData,
595 _fields: (None, None, None, None),
596 _type: PhantomData,
597 }
598 }
599}
600
601impl<S: BosStr> ThreadgateBuilder<threadgate_state::Empty, S> {
602 pub fn builder() -> Self {
604 ThreadgateBuilder {
605 _state: PhantomData,
606 _fields: (None, None, None, None),
607 _type: PhantomData,
608 }
609 }
610}
611
612impl<St: threadgate_state::State, S: BosStr> ThreadgateBuilder<St, S> {
613 pub fn allow(
615 mut self,
616 value: impl Into<Option<Vec<ThreadgateAllowItem<S>>>>,
617 ) -> Self {
618 self._fields.0 = value.into();
619 self
620 }
621 pub fn maybe_allow(mut self, value: Option<Vec<ThreadgateAllowItem<S>>>) -> Self {
623 self._fields.0 = value;
624 self
625 }
626}
627
628impl<St, S: BosStr> ThreadgateBuilder<St, S>
629where
630 St: threadgate_state::State,
631 St::CreatedAt: threadgate_state::IsUnset,
632{
633 pub fn created_at(
635 mut self,
636 value: impl Into<Datetime>,
637 ) -> ThreadgateBuilder<threadgate_state::SetCreatedAt<St>, S> {
638 self._fields.1 = Option::Some(value.into());
639 ThreadgateBuilder {
640 _state: PhantomData,
641 _fields: self._fields,
642 _type: PhantomData,
643 }
644 }
645}
646
647impl<St: threadgate_state::State, S: BosStr> ThreadgateBuilder<St, S> {
648 pub fn hidden_replies(mut self, value: impl Into<Option<Vec<AtUri<S>>>>) -> Self {
650 self._fields.2 = value.into();
651 self
652 }
653 pub fn maybe_hidden_replies(mut self, value: Option<Vec<AtUri<S>>>) -> Self {
655 self._fields.2 = value;
656 self
657 }
658}
659
660impl<St, S: BosStr> ThreadgateBuilder<St, S>
661where
662 St: threadgate_state::State,
663 St::Post: threadgate_state::IsUnset,
664{
665 pub fn post(
667 mut self,
668 value: impl Into<AtUri<S>>,
669 ) -> ThreadgateBuilder<threadgate_state::SetPost<St>, S> {
670 self._fields.3 = Option::Some(value.into());
671 ThreadgateBuilder {
672 _state: PhantomData,
673 _fields: self._fields,
674 _type: PhantomData,
675 }
676 }
677}
678
679impl<St, S: BosStr> ThreadgateBuilder<St, S>
680where
681 St: threadgate_state::State,
682 St::CreatedAt: threadgate_state::IsSet,
683 St::Post: threadgate_state::IsSet,
684{
685 pub fn build(self) -> Threadgate<S> {
687 Threadgate {
688 allow: self._fields.0,
689 created_at: self._fields.1.unwrap(),
690 hidden_replies: self._fields.2,
691 post: self._fields.3.unwrap(),
692 extra_data: Default::default(),
693 }
694 }
695 pub fn build_with_data(
697 self,
698 extra_data: BTreeMap<SmolStr, Data<S>>,
699 ) -> Threadgate<S> {
700 Threadgate {
701 allow: self._fields.0,
702 created_at: self._fields.1.unwrap(),
703 hidden_replies: self._fields.2,
704 post: self._fields.3.unwrap(),
705 extra_data: Some(extra_data),
706 }
707 }
708}