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