// @generated by jacquard-lexicon. DO NOT EDIT. // // Lexicon: dev.atfs.server // // This file was automatically generated from Lexicon schemas. // Any manual changes will be overwritten on the next regeneration. #[allow(unused_imports)] use alloc::collections::BTreeMap; #[allow(unused_imports)] use core::marker::PhantomData; use jacquard_common::{BosStr, CowStr, DefaultStr, FromStaticStr}; #[allow(unused_imports)] use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation; use jacquard_common::deps::smol_str::SmolStr; use jacquard_common::types::collection::{Collection, RecordError}; use jacquard_common::types::string::{AtUri, Cid, Did}; use jacquard_common::types::uri::{RecordUri, UriError}; use jacquard_common::types::value::Data; use jacquard_common::xrpc::XrpcResp; use jacquard_derive::{IntoStatic, lexicon}; use jacquard_lexicon::lexicon::LexiconDoc; use jacquard_lexicon::schema::LexiconSchema; #[allow(unused_imports)] use jacquard_lexicon::validation::{ConstraintError, ValidationPath}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)] #[serde( rename_all = "camelCase", rename = "dev.atfs.server", tag = "$type", bound(deserialize = "S: Deserialize<'de> + BosStr") )] pub struct Server { /// The complete upload allowlist: atproto accounts permitted to call uploadFile/uploadBlob and pinFile. Required, and the owner is NOT implicitly included — an operator who wants to upload to their own instance must list themselves like any other account. DIDs only, never handles: an entry then survives a handle change, and a reverse index over accounts can answer 'which atfs instances can this person use' without resolving anything first. pub accounts: Vec>, /// Other atfs instances this one mirrors, each named by the at-uri of that instance's own dev.atfs.server record (at://{their-owner}/dev.atfs.server/{their-peer-id}). Identity rather than a URL, so a followed instance can move without breaking the follow: the follower resolves this record to learn where to poll (its bare-domain did:web serviceDid, derived the same way as above) and whose name to hold the mirrored claims under (that same serviceDid, or an identity derived from its peer ID when it declares none). The follower periodically walks the followed instance's dev.atfs.repo.listFiles, pins whatever is new, and releases whatever has been absent from two consecutive listings. Following is unilateral and needs no consent: listFiles is public and every pinned cid is already a DHT provider record, so an opt-in would be unenforceable. Only directly-claimed content is exported by listFiles, so following an instance never transitively mirrors what *it* follows — follow each origin you want. Removing an entry releases every claim that instance's mirror held here, and the content is deleted once nothing else claims it. #[serde(skip_serializing_if = "Option::is_none")] pub follows: Option>>, /// An operator-declared ceiling on the request bodies this instance's ingress will actually let through, in bytes. atfs cannot discover this on its own — it never sees its own ingress, only what a fronting proxy or tunnel lets past — so this is one of three sources describeServer combines with the lowest winning, alongside the ATFS_MAX_REQUEST_BODY env var and headers sniffed off arriving requests (e.g. Cloudflare's CF-Ray, read as at least its Free/Pro plan figure). Set this when those under- or over-report — for example a Cloudflare zone on a paid plan above the Free/Pro figure sniffing assumes. #[serde(skip_serializing_if = "Option::is_none")] pub request_body_cap: Option, /// This instance's own identity and address. It's the `aud` uploaders must address in their inter-service auth JWTs, and — only when it's a bare-domain did:web (exactly one segment after `did:web:`, so no path and no port suffix: `did:web:atfs.example.com`, never `did:web:atfs.example.com:user:alice` or an encoded-port form) — it also doubles as this instance's single HTTPS base URL, and atfs serves its own DID document at that domain's /.well-known/did.json. Uploads stay disabled until this is a bare-domain did:web and accounts names at least one account. #[serde(skip_serializing_if = "Option::is_none")] pub service_did: Option>, #[serde( flatten, default, deserialize_with = "deserialize_server_extra_data", skip_serializing_if = "Option::is_none" )] pub extra_data: Option>>, } /// Typed wrapper for GetRecord response with this collection's record type. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)] #[serde(rename_all = "camelCase")] pub struct ServerGetRecordOutput { #[serde(skip_serializing_if = "Option::is_none")] pub cid: Option>, pub uri: AtUri, pub value: Server, } impl Server { pub fn uri(uri: S) -> Result, UriError> { RecordUri::try_from_uri(AtUri::new(uri)?) } } /// Marker type for deserializing records from this collection. #[derive(Debug, Serialize, Deserialize)] pub struct ServerRecord; impl XrpcResp for ServerRecord { const NSID: &'static str = "dev.atfs.server"; const ENCODING: &'static str = "application/json"; type Output = ServerGetRecordOutput; type Err = RecordError; } impl From> for Server { fn from(output: ServerGetRecordOutput) -> Self { output.value } } impl Collection for Server { const NSID: &'static str = "dev.atfs.server"; type Record = ServerRecord; } impl Collection for ServerRecord { const NSID: &'static str = "dev.atfs.server"; type Record = ServerRecord; } impl LexiconSchema for Server { fn nsid() -> &'static str { "dev.atfs.server" } fn def_name() -> &'static str { "main" } fn lexicon_doc() -> LexiconDoc<'static> { lexicon_doc_dev_atfs_server() } fn validate(&self) -> Result<(), ConstraintError> { if let Some(ref value) = self.request_body_cap { if *value < 1i64 { return Err(ConstraintError::Minimum { path: ValidationPath::from_field("request_body_cap"), min: 1i64, actual: *value, }); } } Ok(()) } } fn deserialize_server_extra_data<'de, S, D>( deserializer: D, ) -> Result>>, D::Error> where S: BosStr + serde::Deserialize<'de>, D: serde::Deserializer<'de>, { let mut data = >> as serde::Deserialize<'de>>::deserialize(deserializer)?; if let Some(extra_data) = &mut data { extra_data.remove("$type"); if extra_data.is_empty() { data = None; } } Ok(data) } pub mod server_state { pub use crate::builder_types::{IsSet, IsUnset, Set, Unset}; #[allow(unused)] use ::core::marker::PhantomData; mod sealed { pub trait Sealed {} } /// State trait tracking which required fields have been set pub trait State: sealed::Sealed { type Accounts; } /// Empty state - all required fields are unset pub struct Empty(()); impl sealed::Sealed for Empty {} impl State for Empty { type Accounts = Unset; } ///State transition - sets the `accounts` field to Set pub struct SetAccounts(PhantomData St>); impl sealed::Sealed for SetAccounts {} impl State for SetAccounts { type Accounts = Set; } /// Marker types for field names #[allow(non_camel_case_types)] pub mod members { ///Marker type for the `accounts` field pub struct accounts(()); } } /// Builder for constructing an instance of this type. pub struct ServerBuilder { _state: PhantomData St>, _fields: ( Option>>, Option>>, Option, Option>, ), _type: PhantomData S>, } impl Server { /// Create a new builder for this type, using the default string type (DefaultStr = SmolStr) if needed pub fn new() -> ServerBuilder { ServerBuilder::new() } } impl Server { /// Create a new builder for this type pub fn builder() -> ServerBuilder { ServerBuilder::builder() } } impl ServerBuilder { /// Create a new builder with all fields unset, using the default string type, if needed pub fn new() -> Self { ServerBuilder { _state: PhantomData, _fields: (None, None, None, None), _type: PhantomData, } } } impl ServerBuilder { /// Create a new builder with all fields unset pub fn builder() -> Self { ServerBuilder { _state: PhantomData, _fields: (None, None, None, None), _type: PhantomData, } } } impl ServerBuilder where St: server_state::State, St::Accounts: server_state::IsUnset, { /// Set the `accounts` field (required) pub fn accounts( mut self, value: impl Into>>, ) -> ServerBuilder, S> { self._fields.0 = Option::Some(value.into()); ServerBuilder { _state: PhantomData, _fields: self._fields, _type: PhantomData, } } } impl ServerBuilder { /// Set the `follows` field (optional) pub fn follows(mut self, value: impl Into>>>) -> Self { self._fields.1 = value.into(); self } /// Set the `follows` field to an Option value (optional) pub fn maybe_follows(mut self, value: Option>>) -> Self { self._fields.1 = value; self } } impl ServerBuilder { /// Set the `requestBodyCap` field (optional) pub fn request_body_cap(mut self, value: impl Into>) -> Self { self._fields.2 = value.into(); self } /// Set the `requestBodyCap` field to an Option value (optional) pub fn maybe_request_body_cap(mut self, value: Option) -> Self { self._fields.2 = value; self } } impl ServerBuilder { /// Set the `serviceDid` field (optional) pub fn service_did(mut self, value: impl Into>>) -> Self { self._fields.3 = value.into(); self } /// Set the `serviceDid` field to an Option value (optional) pub fn maybe_service_did(mut self, value: Option>) -> Self { self._fields.3 = value; self } } impl ServerBuilder where St: server_state::State, St::Accounts: server_state::IsSet, { /// Build the final struct. pub fn build(self) -> Server { Server { accounts: self._fields.0.unwrap(), follows: self._fields.1, request_body_cap: self._fields.2, service_did: self._fields.3, extra_data: Default::default(), } } /// Build the final struct with custom extra_data. pub fn build_with_data(self, extra_data: BTreeMap>) -> Server { Server { accounts: self._fields.0.unwrap(), follows: self._fields.1, request_body_cap: self._fields.2, service_did: self._fields.3, extra_data: Some(extra_data), } } } fn lexicon_doc_dev_atfs_server() -> LexiconDoc<'static> { use alloc::collections::BTreeMap; #[allow(unused_imports)] use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType}; use jacquard_lexicon::lexicon::*; LexiconDoc { lexicon: Lexicon::Lexicon1, id: CowStr::new_static("dev.atfs.server"), defs: { let mut map = BTreeMap::new(); map.insert( SmolStr::new_static("main"), LexUserType::Record(LexRecord { key: Some(CowStr::new_static("any")), record: LexRecordRecord::Object(LexObject { required: Some(vec![SmolStr::new_static("accounts")]), properties: { #[allow(unused_mut)] let mut map = BTreeMap::new(); map.insert( SmolStr::new_static("accounts"), LexObjectProperty::Array(LexArray { description: Some( CowStr::new_static( "The complete upload allowlist: atproto accounts permitted to call uploadFile/uploadBlob and pinFile. Required, and the owner is NOT implicitly included — an operator who wants to upload to their own instance must list themselves like any other account. DIDs only, never handles: an entry then survives a handle change, and a reverse index over accounts can answer 'which atfs instances can this person use' without resolving anything first.", ), ), items: LexArrayItem::String(LexString { format: Some(LexStringFormat::Did), ..Default::default() }), ..Default::default() }), ); map.insert( SmolStr::new_static("follows"), LexObjectProperty::Array(LexArray { description: Some( CowStr::new_static( "Other atfs instances this one mirrors, each named by the at-uri of that instance's own dev.atfs.server record (at://{their-owner}/dev.atfs.server/{their-peer-id}). Identity rather than a URL, so a followed instance can move without breaking the follow: the follower resolves this record to learn where to poll (its bare-domain did:web serviceDid, derived the same way as above) and whose name to hold the mirrored claims under (that same serviceDid, or an identity derived from its peer ID when it declares none). The follower periodically walks the followed instance's dev.atfs.repo.listFiles, pins whatever is new, and releases whatever has been absent from two consecutive listings. Following is unilateral and needs no consent: listFiles is public and every pinned cid is already a DHT provider record, so an opt-in would be unenforceable. Only directly-claimed content is exported by listFiles, so following an instance never transitively mirrors what *it* follows — follow each origin you want. Removing an entry releases every claim that instance's mirror held here, and the content is deleted once nothing else claims it.", ), ), items: LexArrayItem::String(LexString { format: Some(LexStringFormat::AtUri), ..Default::default() }), ..Default::default() }), ); map.insert( SmolStr::new_static("requestBodyCap"), LexObjectProperty::Integer(LexInteger { minimum: Some(1i64), ..Default::default() }), ); map.insert( SmolStr::new_static("serviceDid"), LexObjectProperty::String(LexString { description: Some( CowStr::new_static( "This instance's own identity and address. It's the `aud` uploaders must address in their inter-service auth JWTs, and — only when it's a bare-domain did:web (exactly one segment after `did:web:`, so no path and no port suffix: `did:web:atfs.example.com`, never `did:web:atfs.example.com:user:alice` or an encoded-port form) — it also doubles as this instance's single HTTPS base URL, and atfs serves its own DID document at that domain's /.well-known/did.json. Uploads stay disabled until this is a bare-domain did:web and accounts names at least one account.", ), ), format: Some(LexStringFormat::Did), ..Default::default() }), ); map }, ..Default::default() }), ..Default::default() }), ); map }, ..Default::default() } }