···11+// @generated by jacquard-lexicon. DO NOT EDIT.
22+//
33+// This file was automatically generated from Lexicon schemas.
44+// Any manual changes will be overwritten on the next regeneration.
55+66+/// Marker type indicating a builder field has been set
77+pub struct Set<T>(pub T);
88+impl<T> Set<T> {
99+ /// Extract the inner value
1010+ #[inline]
1111+ pub fn into_inner(self) -> T {
1212+ self.0
1313+ }
1414+}
1515+1616+/// Marker type indicating a builder field has not been set
1717+pub struct Unset;
1818+/// Trait indicating a builder field is set (has a value)
1919+#[rustversion::attr(
2020+ since(1.78.0),
2121+ diagnostic::on_unimplemented(
2222+ message = "the field `{Self}` was not set, but this method requires it to be set",
2323+ label = "the field `{Self}` was not set"
2424+ )
2525+)]
2626+pub trait IsSet: private::Sealed {}
2727+/// Trait indicating a builder field is unset (no value yet)
2828+#[rustversion::attr(
2929+ since(1.78.0),
3030+ diagnostic::on_unimplemented(
3131+ message = "the field `{Self}` was already set, but this method requires it to be unset",
3232+ label = "the field `{Self}` was already set"
3333+ )
3434+)]
3535+pub trait IsUnset: private::Sealed {}
3636+impl<T> IsSet for Set<T> {}
3737+impl IsUnset for Unset {}
3838+mod private {
3939+ /// Sealed trait to prevent external implementations
4040+ pub trait Sealed {}
4141+ impl<T> Sealed for super::Set<T> {}
4242+ impl Sealed for super::Unset {}
4343+}
+191
cli/src/main.rs
···11+mod builder_types;
22+mod place_wisp;
33+44+use clap::Parser;
55+use jacquard::CowStr;
66+use jacquard::client::{Agent, FileAuthStore, AgentSessionExt};
77+use jacquard::oauth::client::OAuthClient;
88+use jacquard::oauth::loopback::LoopbackConfig;
99+use jacquard::prelude::IdentityResolver;
1010+use jacquard_common::types::string::{Datetime, Rkey, RecordKey};
1111+use jacquard_common::types::blob::MimeType;
1212+use miette::IntoDiagnostic;
1313+use std::path::{Path, PathBuf};
1414+use flate2::Compression;
1515+use flate2::write::GzEncoder;
1616+use std::io::Write;
1717+use base64::Engine;
1818+1919+use place_wisp::fs::*;
2020+2121+#[derive(Parser, Debug)]
2222+#[command(author, version, about = "Deploy a static site to wisp.place")]
2323+struct Args {
2424+ /// Handle (e.g., alice.bsky.social), DID, or PDS URL
2525+ input: CowStr<'static>,
2626+2727+ /// Path to the directory containing your static site
2828+ #[arg(short, long, default_value = ".")]
2929+ path: PathBuf,
3030+3131+ /// Site name (defaults to directory name)
3232+ #[arg(short, long)]
3333+ site: Option<String>,
3434+3535+ /// Path to auth store file (will be created if missing)
3636+ #[arg(long, default_value = "/tmp/wisp-oauth-session.json")]
3737+ store: String,
3838+}
3939+4040+#[tokio::main]
4141+async fn main() -> miette::Result<()> {
4242+ let args = Args::parse();
4343+4444+ let oauth = OAuthClient::with_default_config(FileAuthStore::new(&args.store));
4545+ let session = oauth
4646+ .login_with_local_server(args.input, Default::default(), LoopbackConfig::default())
4747+ .await?;
4848+4949+ let agent: Agent<_> = Agent::from(session);
5050+5151+ // Verify the path exists
5252+ if !args.path.exists() {
5353+ return Err(miette::miette!("Path does not exist: {}", args.path.display()));
5454+ }
5555+5656+ // Get site name
5757+ let site_name = args.site.unwrap_or_else(|| {
5858+ args.path
5959+ .file_name()
6060+ .and_then(|n| n.to_str())
6161+ .unwrap_or("site")
6262+ .to_string()
6363+ });
6464+6565+ println!("Deploying site '{}'...", site_name);
6666+6767+ // Build directory tree
6868+ let root_dir = build_directory(&agent, &args.path).await?;
6969+7070+ // Count total files
7171+ let file_count = count_files(&root_dir);
7272+7373+ // Create the Fs record
7474+ let fs_record = Fs::new()
7575+ .site(CowStr::from(site_name.clone()))
7676+ .root(root_dir)
7777+ .file_count(file_count as i64)
7878+ .created_at(Datetime::now())
7979+ .build();
8080+8181+ // Use site name as the record key
8282+ let rkey = Rkey::new(&site_name).map_err(|e| miette::miette!("Invalid rkey: {}", e))?;
8383+ let output = agent.put_record(RecordKey::from(rkey), fs_record).await?;
8484+8585+ // Extract DID from the AT URI (format: at://did:plc:xxx/collection/rkey)
8686+ let uri_str = output.uri.to_string();
8787+ let did = uri_str
8888+ .strip_prefix("at://")
8989+ .and_then(|s| s.split('/').next())
9090+ .ok_or_else(|| miette::miette!("Failed to parse DID from URI"))?;
9191+9292+ println!("Deployed site '{}': {}", site_name, output.uri);
9393+ println!("Available at: https://sites.wisp.place/{}/{}", did, site_name);
9494+9595+ Ok(())
9696+}
9797+9898+/// Recursively build a Directory from a filesystem path
9999+fn build_directory<'a>(
100100+ agent: &'a Agent<impl jacquard::client::AgentSession + IdentityResolver + 'a>,
101101+ dir_path: &'a Path,
102102+) -> std::pin::Pin<Box<dyn std::future::Future<Output = miette::Result<Directory<'static>>> + 'a>>
103103+{
104104+ Box::pin(async move {
105105+ let mut entries = Vec::new();
106106+107107+ for entry in std::fs::read_dir(dir_path).into_diagnostic()? {
108108+ let entry = entry.into_diagnostic()?;
109109+ let path = entry.path();
110110+ let name = entry.file_name();
111111+ let name_str = name.to_str()
112112+ .ok_or_else(|| miette::miette!("Invalid filename: {:?}", name))?;
113113+114114+ // Skip hidden files
115115+ if name_str.starts_with('.') {
116116+ continue;
117117+ }
118118+119119+ let metadata = entry.metadata().into_diagnostic()?;
120120+121121+ if metadata.is_file() {
122122+ let file_node = process_file(agent, &path).await?;
123123+ entries.push(Entry::new()
124124+ .name(CowStr::from(name_str.to_string()))
125125+ .node(EntryNode::File(Box::new(file_node)))
126126+ .build());
127127+ } else if metadata.is_dir() {
128128+ let subdir = build_directory(agent, &path).await?;
129129+ entries.push(Entry::new()
130130+ .name(CowStr::from(name_str.to_string()))
131131+ .node(EntryNode::Directory(Box::new(subdir)))
132132+ .build());
133133+ }
134134+ }
135135+136136+ Ok(Directory::new()
137137+ .r#type(CowStr::from("directory"))
138138+ .entries(entries)
139139+ .build())
140140+ })
141141+}
142142+143143+/// Process a single file: gzip -> base64 -> upload blob
144144+async fn process_file(
145145+ agent: &Agent<impl jacquard::client::AgentSession + IdentityResolver>,
146146+ file_path: &Path,
147147+) -> miette::Result<File<'static>>
148148+{
149149+ // Read file
150150+ let file_data = std::fs::read(file_path).into_diagnostic()?;
151151+152152+ // Detect original MIME type
153153+ let original_mime = mime_guess::from_path(file_path)
154154+ .first_or_octet_stream()
155155+ .to_string();
156156+157157+ // Gzip compress
158158+ let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
159159+ encoder.write_all(&file_data).into_diagnostic()?;
160160+ let gzipped = encoder.finish().into_diagnostic()?;
161161+162162+ // Base64 encode the gzipped data
163163+ let base64_bytes = base64::prelude::BASE64_STANDARD.encode(&gzipped).into_bytes();
164164+165165+ // Upload blob as octet-stream
166166+ let blob = agent.upload_blob(
167167+ base64_bytes,
168168+ MimeType::new_static("application/octet-stream"),
169169+ ).await?;
170170+171171+ Ok(File::new()
172172+ .r#type(CowStr::from("file"))
173173+ .blob(blob)
174174+ .encoding(CowStr::from("gzip"))
175175+ .mime_type(CowStr::from(original_mime))
176176+ .base64(true)
177177+ .build())
178178+}
179179+180180+/// Count total files in a directory tree
181181+fn count_files(dir: &Directory) -> usize {
182182+ let mut count = 0;
183183+ for entry in &dir.entries {
184184+ match &entry.node {
185185+ EntryNode::File(_) => count += 1,
186186+ EntryNode::Directory(subdir) => count += count_files(subdir),
187187+ _ => {} // Unknown variants
188188+ }
189189+ }
190190+ count
191191+}
+9
cli/src/mod.rs
···11+// @generated by jacquard-lexicon. DO NOT EDIT.
22+//
33+// This file was automatically generated from Lexicon schemas.
44+// Any manual changes will be overwritten on the next regeneration.
55+66+pub mod builder_types;
77+88+#[cfg(feature = "place_wisp")]
99+pub mod place_wisp;
+6
cli/src/place_wisp.rs
···11+// @generated by jacquard-lexicon. DO NOT EDIT.
22+//
33+// This file was automatically generated from Lexicon schemas.
44+// Any manual changes will be overwritten on the next regeneration.
55+66+pub mod fs;
+1230
cli/src/place_wisp/fs.rs
···11+// @generated by jacquard-lexicon. DO NOT EDIT.
22+//
33+// Lexicon: place.wisp.fs
44+//
55+// This file was automatically generated from Lexicon schemas.
66+// Any manual changes will be overwritten on the next regeneration.
77+88+#[jacquard_derive::lexicon]
99+#[derive(
1010+ serde::Serialize,
1111+ serde::Deserialize,
1212+ Debug,
1313+ Clone,
1414+ PartialEq,
1515+ Eq,
1616+ jacquard_derive::IntoStatic
1717+)]
1818+#[serde(rename_all = "camelCase")]
1919+pub struct Directory<'a> {
2020+ #[serde(borrow)]
2121+ pub entries: Vec<crate::place_wisp::fs::Entry<'a>>,
2222+ #[serde(borrow)]
2323+ pub r#type: jacquard_common::CowStr<'a>,
2424+}
2525+2626+pub mod directory_state {
2727+2828+ pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
2929+ #[allow(unused)]
3030+ use ::core::marker::PhantomData;
3131+ mod sealed {
3232+ pub trait Sealed {}
3333+ }
3434+ /// State trait tracking which required fields have been set
3535+ pub trait State: sealed::Sealed {
3636+ type Type;
3737+ type Entries;
3838+ }
3939+ /// Empty state - all required fields are unset
4040+ pub struct Empty(());
4141+ impl sealed::Sealed for Empty {}
4242+ impl State for Empty {
4343+ type Type = Unset;
4444+ type Entries = Unset;
4545+ }
4646+ ///State transition - sets the `type` field to Set
4747+ pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
4848+ impl<S: State> sealed::Sealed for SetType<S> {}
4949+ impl<S: State> State for SetType<S> {
5050+ type Type = Set<members::r#type>;
5151+ type Entries = S::Entries;
5252+ }
5353+ ///State transition - sets the `entries` field to Set
5454+ pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
5555+ impl<S: State> sealed::Sealed for SetEntries<S> {}
5656+ impl<S: State> State for SetEntries<S> {
5757+ type Type = S::Type;
5858+ type Entries = Set<members::entries>;
5959+ }
6060+ /// Marker types for field names
6161+ #[allow(non_camel_case_types)]
6262+ pub mod members {
6363+ ///Marker type for the `type` field
6464+ pub struct r#type(());
6565+ ///Marker type for the `entries` field
6666+ pub struct entries(());
6767+ }
6868+}
6969+7070+/// Builder for constructing an instance of this type
7171+pub struct DirectoryBuilder<'a, S: directory_state::State> {
7272+ _phantom_state: ::core::marker::PhantomData<fn() -> S>,
7373+ __unsafe_private_named: (
7474+ ::core::option::Option<Vec<crate::place_wisp::fs::Entry<'a>>>,
7575+ ::core::option::Option<jacquard_common::CowStr<'a>>,
7676+ ),
7777+ _phantom: ::core::marker::PhantomData<&'a ()>,
7878+}
7979+8080+impl<'a> Directory<'a> {
8181+ /// Create a new builder for this type
8282+ pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
8383+ DirectoryBuilder::new()
8484+ }
8585+}
8686+8787+impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
8888+ /// Create a new builder with all fields unset
8989+ pub fn new() -> Self {
9090+ DirectoryBuilder {
9191+ _phantom_state: ::core::marker::PhantomData,
9292+ __unsafe_private_named: (None, None),
9393+ _phantom: ::core::marker::PhantomData,
9494+ }
9595+ }
9696+}
9797+9898+impl<'a, S> DirectoryBuilder<'a, S>
9999+where
100100+ S: directory_state::State,
101101+ S::Entries: directory_state::IsUnset,
102102+{
103103+ /// Set the `entries` field (required)
104104+ pub fn entries(
105105+ mut self,
106106+ value: impl Into<Vec<crate::place_wisp::fs::Entry<'a>>>,
107107+ ) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108108+ self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109109+ DirectoryBuilder {
110110+ _phantom_state: ::core::marker::PhantomData,
111111+ __unsafe_private_named: self.__unsafe_private_named,
112112+ _phantom: ::core::marker::PhantomData,
113113+ }
114114+ }
115115+}
116116+117117+impl<'a, S> DirectoryBuilder<'a, S>
118118+where
119119+ S: directory_state::State,
120120+ S::Type: directory_state::IsUnset,
121121+{
122122+ /// Set the `type` field (required)
123123+ pub fn r#type(
124124+ mut self,
125125+ value: impl Into<jacquard_common::CowStr<'a>>,
126126+ ) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127127+ self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128128+ DirectoryBuilder {
129129+ _phantom_state: ::core::marker::PhantomData,
130130+ __unsafe_private_named: self.__unsafe_private_named,
131131+ _phantom: ::core::marker::PhantomData,
132132+ }
133133+ }
134134+}
135135+136136+impl<'a, S> DirectoryBuilder<'a, S>
137137+where
138138+ S: directory_state::State,
139139+ S::Type: directory_state::IsSet,
140140+ S::Entries: directory_state::IsSet,
141141+{
142142+ /// Build the final struct
143143+ pub fn build(self) -> Directory<'a> {
144144+ Directory {
145145+ entries: self.__unsafe_private_named.0.unwrap(),
146146+ r#type: self.__unsafe_private_named.1.unwrap(),
147147+ extra_data: Default::default(),
148148+ }
149149+ }
150150+ /// Build the final struct with custom extra_data
151151+ pub fn build_with_data(
152152+ self,
153153+ extra_data: std::collections::BTreeMap<
154154+ jacquard_common::smol_str::SmolStr,
155155+ jacquard_common::types::value::Data<'a>,
156156+ >,
157157+ ) -> Directory<'a> {
158158+ Directory {
159159+ entries: self.__unsafe_private_named.0.unwrap(),
160160+ r#type: self.__unsafe_private_named.1.unwrap(),
161161+ extra_data: Some(extra_data),
162162+ }
163163+ }
164164+}
165165+166166+fn lexicon_doc_place_wisp_fs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167167+ ::jacquard_lexicon::lexicon::LexiconDoc {
168168+ lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169169+ id: ::jacquard_common::CowStr::new_static("place.wisp.fs"),
170170+ revision: None,
171171+ description: None,
172172+ defs: {
173173+ let mut map = ::std::collections::BTreeMap::new();
174174+ map.insert(
175175+ ::jacquard_common::smol_str::SmolStr::new_static("directory"),
176176+ ::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177177+ description: None,
178178+ required: Some(
179179+ vec![
180180+ ::jacquard_common::smol_str::SmolStr::new_static("type"),
181181+ ::jacquard_common::smol_str::SmolStr::new_static("entries")
182182+ ],
183183+ ),
184184+ nullable: None,
185185+ properties: {
186186+ #[allow(unused_mut)]
187187+ let mut map = ::std::collections::BTreeMap::new();
188188+ map.insert(
189189+ ::jacquard_common::smol_str::SmolStr::new_static("entries"),
190190+ ::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191191+ description: None,
192192+ items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193193+ description: None,
194194+ r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195195+ }),
196196+ min_length: None,
197197+ max_length: Some(500usize),
198198+ }),
199199+ );
200200+ map.insert(
201201+ ::jacquard_common::smol_str::SmolStr::new_static("type"),
202202+ ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203203+ description: None,
204204+ format: None,
205205+ default: None,
206206+ min_length: None,
207207+ max_length: None,
208208+ min_graphemes: None,
209209+ max_graphemes: None,
210210+ r#enum: None,
211211+ r#const: None,
212212+ known_values: None,
213213+ }),
214214+ );
215215+ map
216216+ },
217217+ }),
218218+ );
219219+ map.insert(
220220+ ::jacquard_common::smol_str::SmolStr::new_static("entry"),
221221+ ::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222222+ description: None,
223223+ required: Some(
224224+ vec![
225225+ ::jacquard_common::smol_str::SmolStr::new_static("name"),
226226+ ::jacquard_common::smol_str::SmolStr::new_static("node")
227227+ ],
228228+ ),
229229+ nullable: None,
230230+ properties: {
231231+ #[allow(unused_mut)]
232232+ let mut map = ::std::collections::BTreeMap::new();
233233+ map.insert(
234234+ ::jacquard_common::smol_str::SmolStr::new_static("name"),
235235+ ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236236+ description: None,
237237+ format: None,
238238+ default: None,
239239+ min_length: None,
240240+ max_length: Some(255usize),
241241+ min_graphemes: None,
242242+ max_graphemes: None,
243243+ r#enum: None,
244244+ r#const: None,
245245+ known_values: None,
246246+ }),
247247+ );
248248+ map.insert(
249249+ ::jacquard_common::smol_str::SmolStr::new_static("node"),
250250+ ::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251251+ description: None,
252252+ refs: vec![
253253+ ::jacquard_common::CowStr::new_static("#file"),
254254+ ::jacquard_common::CowStr::new_static("#directory")
255255+ ],
256256+ closed: None,
257257+ }),
258258+ );
259259+ map
260260+ },
261261+ }),
262262+ );
263263+ map.insert(
264264+ ::jacquard_common::smol_str::SmolStr::new_static("file"),
265265+ ::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
266266+ description: None,
267267+ required: Some(
268268+ vec![
269269+ ::jacquard_common::smol_str::SmolStr::new_static("type"),
270270+ ::jacquard_common::smol_str::SmolStr::new_static("blob")
271271+ ],
272272+ ),
273273+ nullable: None,
274274+ properties: {
275275+ #[allow(unused_mut)]
276276+ let mut map = ::std::collections::BTreeMap::new();
277277+ map.insert(
278278+ ::jacquard_common::smol_str::SmolStr::new_static("base64"),
279279+ ::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
280280+ description: None,
281281+ default: None,
282282+ r#const: None,
283283+ }),
284284+ );
285285+ map.insert(
286286+ ::jacquard_common::smol_str::SmolStr::new_static("blob"),
287287+ ::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
288288+ description: None,
289289+ accept: None,
290290+ max_size: None,
291291+ }),
292292+ );
293293+ map.insert(
294294+ ::jacquard_common::smol_str::SmolStr::new_static("encoding"),
295295+ ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
296296+ description: Some(
297297+ ::jacquard_common::CowStr::new_static(
298298+ "Content encoding (e.g., gzip for compressed files)",
299299+ ),
300300+ ),
301301+ format: None,
302302+ default: None,
303303+ min_length: None,
304304+ max_length: None,
305305+ min_graphemes: None,
306306+ max_graphemes: None,
307307+ r#enum: None,
308308+ r#const: None,
309309+ known_values: None,
310310+ }),
311311+ );
312312+ map.insert(
313313+ ::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
314314+ ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
315315+ description: Some(
316316+ ::jacquard_common::CowStr::new_static(
317317+ "Original MIME type before compression",
318318+ ),
319319+ ),
320320+ format: None,
321321+ default: None,
322322+ min_length: None,
323323+ max_length: None,
324324+ min_graphemes: None,
325325+ max_graphemes: None,
326326+ r#enum: None,
327327+ r#const: None,
328328+ known_values: None,
329329+ }),
330330+ );
331331+ map.insert(
332332+ ::jacquard_common::smol_str::SmolStr::new_static("type"),
333333+ ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
334334+ description: None,
335335+ format: None,
336336+ default: None,
337337+ min_length: None,
338338+ max_length: None,
339339+ min_graphemes: None,
340340+ max_graphemes: None,
341341+ r#enum: None,
342342+ r#const: None,
343343+ known_values: None,
344344+ }),
345345+ );
346346+ map
347347+ },
348348+ }),
349349+ );
350350+ map.insert(
351351+ ::jacquard_common::smol_str::SmolStr::new_static("main"),
352352+ ::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
353353+ description: Some(
354354+ ::jacquard_common::CowStr::new_static(
355355+ "Virtual filesystem manifest for a Wisp site",
356356+ ),
357357+ ),
358358+ key: None,
359359+ record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
360360+ description: None,
361361+ required: Some(
362362+ vec![
363363+ ::jacquard_common::smol_str::SmolStr::new_static("site"),
364364+ ::jacquard_common::smol_str::SmolStr::new_static("root"),
365365+ ::jacquard_common::smol_str::SmolStr::new_static("createdAt")
366366+ ],
367367+ ),
368368+ nullable: None,
369369+ properties: {
370370+ #[allow(unused_mut)]
371371+ let mut map = ::std::collections::BTreeMap::new();
372372+ map.insert(
373373+ ::jacquard_common::smol_str::SmolStr::new_static(
374374+ "createdAt",
375375+ ),
376376+ ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
377377+ description: None,
378378+ format: Some(
379379+ ::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
380380+ ),
381381+ default: None,
382382+ min_length: None,
383383+ max_length: None,
384384+ min_graphemes: None,
385385+ max_graphemes: None,
386386+ r#enum: None,
387387+ r#const: None,
388388+ known_values: None,
389389+ }),
390390+ );
391391+ map.insert(
392392+ ::jacquard_common::smol_str::SmolStr::new_static(
393393+ "fileCount",
394394+ ),
395395+ ::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
396396+ description: None,
397397+ default: None,
398398+ minimum: Some(0i64),
399399+ maximum: Some(1000i64),
400400+ r#enum: None,
401401+ r#const: None,
402402+ }),
403403+ );
404404+ map.insert(
405405+ ::jacquard_common::smol_str::SmolStr::new_static("root"),
406406+ ::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
407407+ description: None,
408408+ r#ref: ::jacquard_common::CowStr::new_static("#directory"),
409409+ }),
410410+ );
411411+ map.insert(
412412+ ::jacquard_common::smol_str::SmolStr::new_static("site"),
413413+ ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
414414+ description: None,
415415+ format: None,
416416+ default: None,
417417+ min_length: None,
418418+ max_length: None,
419419+ min_graphemes: None,
420420+ max_graphemes: None,
421421+ r#enum: None,
422422+ r#const: None,
423423+ known_values: None,
424424+ }),
425425+ );
426426+ map
427427+ },
428428+ }),
429429+ }),
430430+ );
431431+ map
432432+ },
433433+ }
434434+}
435435+436436+impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
437437+ fn nsid() -> &'static str {
438438+ "place.wisp.fs"
439439+ }
440440+ fn def_name() -> &'static str {
441441+ "directory"
442442+ }
443443+ fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
444444+ lexicon_doc_place_wisp_fs()
445445+ }
446446+ fn validate(
447447+ &self,
448448+ ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
449449+ {
450450+ let value = &self.entries;
451451+ #[allow(unused_comparisons)]
452452+ if value.len() > 500usize {
453453+ return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
454454+ path: ::jacquard_lexicon::validation::ValidationPath::from_field(
455455+ "entries",
456456+ ),
457457+ max: 500usize,
458458+ actual: value.len(),
459459+ });
460460+ }
461461+ }
462462+ Ok(())
463463+ }
464464+}
465465+466466+#[jacquard_derive::lexicon]
467467+#[derive(
468468+ serde::Serialize,
469469+ serde::Deserialize,
470470+ Debug,
471471+ Clone,
472472+ PartialEq,
473473+ Eq,
474474+ jacquard_derive::IntoStatic
475475+)]
476476+#[serde(rename_all = "camelCase")]
477477+pub struct Entry<'a> {
478478+ #[serde(borrow)]
479479+ pub name: jacquard_common::CowStr<'a>,
480480+ #[serde(borrow)]
481481+ pub node: EntryNode<'a>,
482482+}
483483+484484+pub mod entry_state {
485485+486486+ pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
487487+ #[allow(unused)]
488488+ use ::core::marker::PhantomData;
489489+ mod sealed {
490490+ pub trait Sealed {}
491491+ }
492492+ /// State trait tracking which required fields have been set
493493+ pub trait State: sealed::Sealed {
494494+ type Name;
495495+ type Node;
496496+ }
497497+ /// Empty state - all required fields are unset
498498+ pub struct Empty(());
499499+ impl sealed::Sealed for Empty {}
500500+ impl State for Empty {
501501+ type Name = Unset;
502502+ type Node = Unset;
503503+ }
504504+ ///State transition - sets the `name` field to Set
505505+ pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
506506+ impl<S: State> sealed::Sealed for SetName<S> {}
507507+ impl<S: State> State for SetName<S> {
508508+ type Name = Set<members::name>;
509509+ type Node = S::Node;
510510+ }
511511+ ///State transition - sets the `node` field to Set
512512+ pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
513513+ impl<S: State> sealed::Sealed for SetNode<S> {}
514514+ impl<S: State> State for SetNode<S> {
515515+ type Name = S::Name;
516516+ type Node = Set<members::node>;
517517+ }
518518+ /// Marker types for field names
519519+ #[allow(non_camel_case_types)]
520520+ pub mod members {
521521+ ///Marker type for the `name` field
522522+ pub struct name(());
523523+ ///Marker type for the `node` field
524524+ pub struct node(());
525525+ }
526526+}
527527+528528+/// Builder for constructing an instance of this type
529529+pub struct EntryBuilder<'a, S: entry_state::State> {
530530+ _phantom_state: ::core::marker::PhantomData<fn() -> S>,
531531+ __unsafe_private_named: (
532532+ ::core::option::Option<jacquard_common::CowStr<'a>>,
533533+ ::core::option::Option<EntryNode<'a>>,
534534+ ),
535535+ _phantom: ::core::marker::PhantomData<&'a ()>,
536536+}
537537+538538+impl<'a> Entry<'a> {
539539+ /// Create a new builder for this type
540540+ pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
541541+ EntryBuilder::new()
542542+ }
543543+}
544544+545545+impl<'a> EntryBuilder<'a, entry_state::Empty> {
546546+ /// Create a new builder with all fields unset
547547+ pub fn new() -> Self {
548548+ EntryBuilder {
549549+ _phantom_state: ::core::marker::PhantomData,
550550+ __unsafe_private_named: (None, None),
551551+ _phantom: ::core::marker::PhantomData,
552552+ }
553553+ }
554554+}
555555+556556+impl<'a, S> EntryBuilder<'a, S>
557557+where
558558+ S: entry_state::State,
559559+ S::Name: entry_state::IsUnset,
560560+{
561561+ /// Set the `name` field (required)
562562+ pub fn name(
563563+ mut self,
564564+ value: impl Into<jacquard_common::CowStr<'a>>,
565565+ ) -> EntryBuilder<'a, entry_state::SetName<S>> {
566566+ self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
567567+ EntryBuilder {
568568+ _phantom_state: ::core::marker::PhantomData,
569569+ __unsafe_private_named: self.__unsafe_private_named,
570570+ _phantom: ::core::marker::PhantomData,
571571+ }
572572+ }
573573+}
574574+575575+impl<'a, S> EntryBuilder<'a, S>
576576+where
577577+ S: entry_state::State,
578578+ S::Node: entry_state::IsUnset,
579579+{
580580+ /// Set the `node` field (required)
581581+ pub fn node(
582582+ mut self,
583583+ value: impl Into<EntryNode<'a>>,
584584+ ) -> EntryBuilder<'a, entry_state::SetNode<S>> {
585585+ self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
586586+ EntryBuilder {
587587+ _phantom_state: ::core::marker::PhantomData,
588588+ __unsafe_private_named: self.__unsafe_private_named,
589589+ _phantom: ::core::marker::PhantomData,
590590+ }
591591+ }
592592+}
593593+594594+impl<'a, S> EntryBuilder<'a, S>
595595+where
596596+ S: entry_state::State,
597597+ S::Name: entry_state::IsSet,
598598+ S::Node: entry_state::IsSet,
599599+{
600600+ /// Build the final struct
601601+ pub fn build(self) -> Entry<'a> {
602602+ Entry {
603603+ name: self.__unsafe_private_named.0.unwrap(),
604604+ node: self.__unsafe_private_named.1.unwrap(),
605605+ extra_data: Default::default(),
606606+ }
607607+ }
608608+ /// Build the final struct with custom extra_data
609609+ pub fn build_with_data(
610610+ self,
611611+ extra_data: std::collections::BTreeMap<
612612+ jacquard_common::smol_str::SmolStr,
613613+ jacquard_common::types::value::Data<'a>,
614614+ >,
615615+ ) -> Entry<'a> {
616616+ Entry {
617617+ name: self.__unsafe_private_named.0.unwrap(),
618618+ node: self.__unsafe_private_named.1.unwrap(),
619619+ extra_data: Some(extra_data),
620620+ }
621621+ }
622622+}
623623+624624+#[jacquard_derive::open_union]
625625+#[derive(
626626+ serde::Serialize,
627627+ serde::Deserialize,
628628+ Debug,
629629+ Clone,
630630+ PartialEq,
631631+ Eq,
632632+ jacquard_derive::IntoStatic
633633+)]
634634+#[serde(tag = "$type")]
635635+#[serde(bound(deserialize = "'de: 'a"))]
636636+pub enum EntryNode<'a> {
637637+ #[serde(rename = "place.wisp.fs#file")]
638638+ File(Box<crate::place_wisp::fs::File<'a>>),
639639+ #[serde(rename = "place.wisp.fs#directory")]
640640+ Directory(Box<crate::place_wisp::fs::Directory<'a>>),
641641+}
642642+643643+impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
644644+ fn nsid() -> &'static str {
645645+ "place.wisp.fs"
646646+ }
647647+ fn def_name() -> &'static str {
648648+ "entry"
649649+ }
650650+ fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
651651+ lexicon_doc_place_wisp_fs()
652652+ }
653653+ fn validate(
654654+ &self,
655655+ ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
656656+ {
657657+ let value = &self.name;
658658+ #[allow(unused_comparisons)]
659659+ if <str>::len(value.as_ref()) > 255usize {
660660+ return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
661661+ path: ::jacquard_lexicon::validation::ValidationPath::from_field(
662662+ "name",
663663+ ),
664664+ max: 255usize,
665665+ actual: <str>::len(value.as_ref()),
666666+ });
667667+ }
668668+ }
669669+ Ok(())
670670+ }
671671+}
672672+673673+#[jacquard_derive::lexicon]
674674+#[derive(
675675+ serde::Serialize,
676676+ serde::Deserialize,
677677+ Debug,
678678+ Clone,
679679+ PartialEq,
680680+ Eq,
681681+ jacquard_derive::IntoStatic
682682+)]
683683+#[serde(rename_all = "camelCase")]
684684+pub struct File<'a> {
685685+ /// True if blob content is base64-encoded (used to bypass PDS content sniffing)
686686+ #[serde(skip_serializing_if = "std::option::Option::is_none")]
687687+ pub base64: Option<bool>,
688688+ /// Content blob ref
689689+ #[serde(borrow)]
690690+ pub blob: jacquard_common::types::blob::BlobRef<'a>,
691691+ /// Content encoding (e.g., gzip for compressed files)
692692+ #[serde(skip_serializing_if = "std::option::Option::is_none")]
693693+ #[serde(borrow)]
694694+ pub encoding: Option<jacquard_common::CowStr<'a>>,
695695+ /// Original MIME type before compression
696696+ #[serde(skip_serializing_if = "std::option::Option::is_none")]
697697+ #[serde(borrow)]
698698+ pub mime_type: Option<jacquard_common::CowStr<'a>>,
699699+ #[serde(borrow)]
700700+ pub r#type: jacquard_common::CowStr<'a>,
701701+}
702702+703703+pub mod file_state {
704704+705705+ pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
706706+ #[allow(unused)]
707707+ use ::core::marker::PhantomData;
708708+ mod sealed {
709709+ pub trait Sealed {}
710710+ }
711711+ /// State trait tracking which required fields have been set
712712+ pub trait State: sealed::Sealed {
713713+ type Type;
714714+ type Blob;
715715+ }
716716+ /// Empty state - all required fields are unset
717717+ pub struct Empty(());
718718+ impl sealed::Sealed for Empty {}
719719+ impl State for Empty {
720720+ type Type = Unset;
721721+ type Blob = Unset;
722722+ }
723723+ ///State transition - sets the `type` field to Set
724724+ pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
725725+ impl<S: State> sealed::Sealed for SetType<S> {}
726726+ impl<S: State> State for SetType<S> {
727727+ type Type = Set<members::r#type>;
728728+ type Blob = S::Blob;
729729+ }
730730+ ///State transition - sets the `blob` field to Set
731731+ pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
732732+ impl<S: State> sealed::Sealed for SetBlob<S> {}
733733+ impl<S: State> State for SetBlob<S> {
734734+ type Type = S::Type;
735735+ type Blob = Set<members::blob>;
736736+ }
737737+ /// Marker types for field names
738738+ #[allow(non_camel_case_types)]
739739+ pub mod members {
740740+ ///Marker type for the `type` field
741741+ pub struct r#type(());
742742+ ///Marker type for the `blob` field
743743+ pub struct blob(());
744744+ }
745745+}
746746+747747+/// Builder for constructing an instance of this type
748748+pub struct FileBuilder<'a, S: file_state::State> {
749749+ _phantom_state: ::core::marker::PhantomData<fn() -> S>,
750750+ __unsafe_private_named: (
751751+ ::core::option::Option<bool>,
752752+ ::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
753753+ ::core::option::Option<jacquard_common::CowStr<'a>>,
754754+ ::core::option::Option<jacquard_common::CowStr<'a>>,
755755+ ::core::option::Option<jacquard_common::CowStr<'a>>,
756756+ ),
757757+ _phantom: ::core::marker::PhantomData<&'a ()>,
758758+}
759759+760760+impl<'a> File<'a> {
761761+ /// Create a new builder for this type
762762+ pub fn new() -> FileBuilder<'a, file_state::Empty> {
763763+ FileBuilder::new()
764764+ }
765765+}
766766+767767+impl<'a> FileBuilder<'a, file_state::Empty> {
768768+ /// Create a new builder with all fields unset
769769+ pub fn new() -> Self {
770770+ FileBuilder {
771771+ _phantom_state: ::core::marker::PhantomData,
772772+ __unsafe_private_named: (None, None, None, None, None),
773773+ _phantom: ::core::marker::PhantomData,
774774+ }
775775+ }
776776+}
777777+778778+impl<'a, S: file_state::State> FileBuilder<'a, S> {
779779+ /// Set the `base64` field (optional)
780780+ pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
781781+ self.__unsafe_private_named.0 = value.into();
782782+ self
783783+ }
784784+ /// Set the `base64` field to an Option value (optional)
785785+ pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
786786+ self.__unsafe_private_named.0 = value;
787787+ self
788788+ }
789789+}
790790+791791+impl<'a, S> FileBuilder<'a, S>
792792+where
793793+ S: file_state::State,
794794+ S::Blob: file_state::IsUnset,
795795+{
796796+ /// Set the `blob` field (required)
797797+ pub fn blob(
798798+ mut self,
799799+ value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
800800+ ) -> FileBuilder<'a, file_state::SetBlob<S>> {
801801+ self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
802802+ FileBuilder {
803803+ _phantom_state: ::core::marker::PhantomData,
804804+ __unsafe_private_named: self.__unsafe_private_named,
805805+ _phantom: ::core::marker::PhantomData,
806806+ }
807807+ }
808808+}
809809+810810+impl<'a, S: file_state::State> FileBuilder<'a, S> {
811811+ /// Set the `encoding` field (optional)
812812+ pub fn encoding(
813813+ mut self,
814814+ value: impl Into<Option<jacquard_common::CowStr<'a>>>,
815815+ ) -> Self {
816816+ self.__unsafe_private_named.2 = value.into();
817817+ self
818818+ }
819819+ /// Set the `encoding` field to an Option value (optional)
820820+ pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
821821+ self.__unsafe_private_named.2 = value;
822822+ self
823823+ }
824824+}
825825+826826+impl<'a, S: file_state::State> FileBuilder<'a, S> {
827827+ /// Set the `mimeType` field (optional)
828828+ pub fn mime_type(
829829+ mut self,
830830+ value: impl Into<Option<jacquard_common::CowStr<'a>>>,
831831+ ) -> Self {
832832+ self.__unsafe_private_named.3 = value.into();
833833+ self
834834+ }
835835+ /// Set the `mimeType` field to an Option value (optional)
836836+ pub fn maybe_mime_type(
837837+ mut self,
838838+ value: Option<jacquard_common::CowStr<'a>>,
839839+ ) -> Self {
840840+ self.__unsafe_private_named.3 = value;
841841+ self
842842+ }
843843+}
844844+845845+impl<'a, S> FileBuilder<'a, S>
846846+where
847847+ S: file_state::State,
848848+ S::Type: file_state::IsUnset,
849849+{
850850+ /// Set the `type` field (required)
851851+ pub fn r#type(
852852+ mut self,
853853+ value: impl Into<jacquard_common::CowStr<'a>>,
854854+ ) -> FileBuilder<'a, file_state::SetType<S>> {
855855+ self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
856856+ FileBuilder {
857857+ _phantom_state: ::core::marker::PhantomData,
858858+ __unsafe_private_named: self.__unsafe_private_named,
859859+ _phantom: ::core::marker::PhantomData,
860860+ }
861861+ }
862862+}
863863+864864+impl<'a, S> FileBuilder<'a, S>
865865+where
866866+ S: file_state::State,
867867+ S::Type: file_state::IsSet,
868868+ S::Blob: file_state::IsSet,
869869+{
870870+ /// Build the final struct
871871+ pub fn build(self) -> File<'a> {
872872+ File {
873873+ base64: self.__unsafe_private_named.0,
874874+ blob: self.__unsafe_private_named.1.unwrap(),
875875+ encoding: self.__unsafe_private_named.2,
876876+ mime_type: self.__unsafe_private_named.3,
877877+ r#type: self.__unsafe_private_named.4.unwrap(),
878878+ extra_data: Default::default(),
879879+ }
880880+ }
881881+ /// Build the final struct with custom extra_data
882882+ pub fn build_with_data(
883883+ self,
884884+ extra_data: std::collections::BTreeMap<
885885+ jacquard_common::smol_str::SmolStr,
886886+ jacquard_common::types::value::Data<'a>,
887887+ >,
888888+ ) -> File<'a> {
889889+ File {
890890+ base64: self.__unsafe_private_named.0,
891891+ blob: self.__unsafe_private_named.1.unwrap(),
892892+ encoding: self.__unsafe_private_named.2,
893893+ mime_type: self.__unsafe_private_named.3,
894894+ r#type: self.__unsafe_private_named.4.unwrap(),
895895+ extra_data: Some(extra_data),
896896+ }
897897+ }
898898+}
899899+900900+impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
901901+ fn nsid() -> &'static str {
902902+ "place.wisp.fs"
903903+ }
904904+ fn def_name() -> &'static str {
905905+ "file"
906906+ }
907907+ fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
908908+ lexicon_doc_place_wisp_fs()
909909+ }
910910+ fn validate(
911911+ &self,
912912+ ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
913913+ Ok(())
914914+ }
915915+}
916916+917917+/// Virtual filesystem manifest for a Wisp site
918918+#[jacquard_derive::lexicon]
919919+#[derive(
920920+ serde::Serialize,
921921+ serde::Deserialize,
922922+ Debug,
923923+ Clone,
924924+ PartialEq,
925925+ Eq,
926926+ jacquard_derive::IntoStatic
927927+)]
928928+#[serde(rename_all = "camelCase")]
929929+pub struct Fs<'a> {
930930+ pub created_at: jacquard_common::types::string::Datetime,
931931+ #[serde(skip_serializing_if = "std::option::Option::is_none")]
932932+ pub file_count: Option<i64>,
933933+ #[serde(borrow)]
934934+ pub root: crate::place_wisp::fs::Directory<'a>,
935935+ #[serde(borrow)]
936936+ pub site: jacquard_common::CowStr<'a>,
937937+}
938938+939939+pub mod fs_state {
940940+941941+ pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
942942+ #[allow(unused)]
943943+ use ::core::marker::PhantomData;
944944+ mod sealed {
945945+ pub trait Sealed {}
946946+ }
947947+ /// State trait tracking which required fields have been set
948948+ pub trait State: sealed::Sealed {
949949+ type Site;
950950+ type Root;
951951+ type CreatedAt;
952952+ }
953953+ /// Empty state - all required fields are unset
954954+ pub struct Empty(());
955955+ impl sealed::Sealed for Empty {}
956956+ impl State for Empty {
957957+ type Site = Unset;
958958+ type Root = Unset;
959959+ type CreatedAt = Unset;
960960+ }
961961+ ///State transition - sets the `site` field to Set
962962+ pub struct SetSite<S: State = Empty>(PhantomData<fn() -> S>);
963963+ impl<S: State> sealed::Sealed for SetSite<S> {}
964964+ impl<S: State> State for SetSite<S> {
965965+ type Site = Set<members::site>;
966966+ type Root = S::Root;
967967+ type CreatedAt = S::CreatedAt;
968968+ }
969969+ ///State transition - sets the `root` field to Set
970970+ pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
971971+ impl<S: State> sealed::Sealed for SetRoot<S> {}
972972+ impl<S: State> State for SetRoot<S> {
973973+ type Site = S::Site;
974974+ type Root = Set<members::root>;
975975+ type CreatedAt = S::CreatedAt;
976976+ }
977977+ ///State transition - sets the `created_at` field to Set
978978+ pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
979979+ impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
980980+ impl<S: State> State for SetCreatedAt<S> {
981981+ type Site = S::Site;
982982+ type Root = S::Root;
983983+ type CreatedAt = Set<members::created_at>;
984984+ }
985985+ /// Marker types for field names
986986+ #[allow(non_camel_case_types)]
987987+ pub mod members {
988988+ ///Marker type for the `site` field
989989+ pub struct site(());
990990+ ///Marker type for the `root` field
991991+ pub struct root(());
992992+ ///Marker type for the `created_at` field
993993+ pub struct created_at(());
994994+ }
995995+}
996996+997997+/// Builder for constructing an instance of this type
998998+pub struct FsBuilder<'a, S: fs_state::State> {
999999+ _phantom_state: ::core::marker::PhantomData<fn() -> S>,
10001000+ __unsafe_private_named: (
10011001+ ::core::option::Option<jacquard_common::types::string::Datetime>,
10021002+ ::core::option::Option<i64>,
10031003+ ::core::option::Option<crate::place_wisp::fs::Directory<'a>>,
10041004+ ::core::option::Option<jacquard_common::CowStr<'a>>,
10051005+ ),
10061006+ _phantom: ::core::marker::PhantomData<&'a ()>,
10071007+}
10081008+10091009+impl<'a> Fs<'a> {
10101010+ /// Create a new builder for this type
10111011+ pub fn new() -> FsBuilder<'a, fs_state::Empty> {
10121012+ FsBuilder::new()
10131013+ }
10141014+}
10151015+10161016+impl<'a> FsBuilder<'a, fs_state::Empty> {
10171017+ /// Create a new builder with all fields unset
10181018+ pub fn new() -> Self {
10191019+ FsBuilder {
10201020+ _phantom_state: ::core::marker::PhantomData,
10211021+ __unsafe_private_named: (None, None, None, None),
10221022+ _phantom: ::core::marker::PhantomData,
10231023+ }
10241024+ }
10251025+}
10261026+10271027+impl<'a, S> FsBuilder<'a, S>
10281028+where
10291029+ S: fs_state::State,
10301030+ S::CreatedAt: fs_state::IsUnset,
10311031+{
10321032+ /// Set the `createdAt` field (required)
10331033+ pub fn created_at(
10341034+ mut self,
10351035+ value: impl Into<jacquard_common::types::string::Datetime>,
10361036+ ) -> FsBuilder<'a, fs_state::SetCreatedAt<S>> {
10371037+ self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
10381038+ FsBuilder {
10391039+ _phantom_state: ::core::marker::PhantomData,
10401040+ __unsafe_private_named: self.__unsafe_private_named,
10411041+ _phantom: ::core::marker::PhantomData,
10421042+ }
10431043+ }
10441044+}
10451045+10461046+impl<'a, S: fs_state::State> FsBuilder<'a, S> {
10471047+ /// Set the `fileCount` field (optional)
10481048+ pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
10491049+ self.__unsafe_private_named.1 = value.into();
10501050+ self
10511051+ }
10521052+ /// Set the `fileCount` field to an Option value (optional)
10531053+ pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
10541054+ self.__unsafe_private_named.1 = value;
10551055+ self
10561056+ }
10571057+}
10581058+10591059+impl<'a, S> FsBuilder<'a, S>
10601060+where
10611061+ S: fs_state::State,
10621062+ S::Root: fs_state::IsUnset,
10631063+{
10641064+ /// Set the `root` field (required)
10651065+ pub fn root(
10661066+ mut self,
10671067+ value: impl Into<crate::place_wisp::fs::Directory<'a>>,
10681068+ ) -> FsBuilder<'a, fs_state::SetRoot<S>> {
10691069+ self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
10701070+ FsBuilder {
10711071+ _phantom_state: ::core::marker::PhantomData,
10721072+ __unsafe_private_named: self.__unsafe_private_named,
10731073+ _phantom: ::core::marker::PhantomData,
10741074+ }
10751075+ }
10761076+}
10771077+10781078+impl<'a, S> FsBuilder<'a, S>
10791079+where
10801080+ S: fs_state::State,
10811081+ S::Site: fs_state::IsUnset,
10821082+{
10831083+ /// Set the `site` field (required)
10841084+ pub fn site(
10851085+ mut self,
10861086+ value: impl Into<jacquard_common::CowStr<'a>>,
10871087+ ) -> FsBuilder<'a, fs_state::SetSite<S>> {
10881088+ self.__unsafe_private_named.3 = ::core::option::Option::Some(value.into());
10891089+ FsBuilder {
10901090+ _phantom_state: ::core::marker::PhantomData,
10911091+ __unsafe_private_named: self.__unsafe_private_named,
10921092+ _phantom: ::core::marker::PhantomData,
10931093+ }
10941094+ }
10951095+}
10961096+10971097+impl<'a, S> FsBuilder<'a, S>
10981098+where
10991099+ S: fs_state::State,
11001100+ S::Site: fs_state::IsSet,
11011101+ S::Root: fs_state::IsSet,
11021102+ S::CreatedAt: fs_state::IsSet,
11031103+{
11041104+ /// Build the final struct
11051105+ pub fn build(self) -> Fs<'a> {
11061106+ Fs {
11071107+ created_at: self.__unsafe_private_named.0.unwrap(),
11081108+ file_count: self.__unsafe_private_named.1,
11091109+ root: self.__unsafe_private_named.2.unwrap(),
11101110+ site: self.__unsafe_private_named.3.unwrap(),
11111111+ extra_data: Default::default(),
11121112+ }
11131113+ }
11141114+ /// Build the final struct with custom extra_data
11151115+ pub fn build_with_data(
11161116+ self,
11171117+ extra_data: std::collections::BTreeMap<
11181118+ jacquard_common::smol_str::SmolStr,
11191119+ jacquard_common::types::value::Data<'a>,
11201120+ >,
11211121+ ) -> Fs<'a> {
11221122+ Fs {
11231123+ created_at: self.__unsafe_private_named.0.unwrap(),
11241124+ file_count: self.__unsafe_private_named.1,
11251125+ root: self.__unsafe_private_named.2.unwrap(),
11261126+ site: self.__unsafe_private_named.3.unwrap(),
11271127+ extra_data: Some(extra_data),
11281128+ }
11291129+ }
11301130+}
11311131+11321132+impl<'a> Fs<'a> {
11331133+ pub fn uri(
11341134+ uri: impl Into<jacquard_common::CowStr<'a>>,
11351135+ ) -> Result<
11361136+ jacquard_common::types::uri::RecordUri<'a, FsRecord>,
11371137+ jacquard_common::types::uri::UriError,
11381138+ > {
11391139+ jacquard_common::types::uri::RecordUri::try_from_uri(
11401140+ jacquard_common::types::string::AtUri::new_cow(uri.into())?,
11411141+ )
11421142+ }
11431143+}
11441144+11451145+/// Typed wrapper for GetRecord response with this collection's record type.
11461146+#[derive(
11471147+ serde::Serialize,
11481148+ serde::Deserialize,
11491149+ Debug,
11501150+ Clone,
11511151+ PartialEq,
11521152+ Eq,
11531153+ jacquard_derive::IntoStatic
11541154+)]
11551155+#[serde(rename_all = "camelCase")]
11561156+pub struct FsGetRecordOutput<'a> {
11571157+ #[serde(skip_serializing_if = "std::option::Option::is_none")]
11581158+ #[serde(borrow)]
11591159+ pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
11601160+ #[serde(borrow)]
11611161+ pub uri: jacquard_common::types::string::AtUri<'a>,
11621162+ #[serde(borrow)]
11631163+ pub value: Fs<'a>,
11641164+}
11651165+11661166+impl From<FsGetRecordOutput<'_>> for Fs<'_> {
11671167+ fn from(output: FsGetRecordOutput<'_>) -> Self {
11681168+ use jacquard_common::IntoStatic;
11691169+ output.value.into_static()
11701170+ }
11711171+}
11721172+11731173+impl jacquard_common::types::collection::Collection for Fs<'_> {
11741174+ const NSID: &'static str = "place.wisp.fs";
11751175+ type Record = FsRecord;
11761176+}
11771177+11781178+/// Marker type for deserializing records from this collection.
11791179+#[derive(Debug, serde::Serialize, serde::Deserialize)]
11801180+pub struct FsRecord;
11811181+impl jacquard_common::xrpc::XrpcResp for FsRecord {
11821182+ const NSID: &'static str = "place.wisp.fs";
11831183+ const ENCODING: &'static str = "application/json";
11841184+ type Output<'de> = FsGetRecordOutput<'de>;
11851185+ type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
11861186+}
11871187+11881188+impl jacquard_common::types::collection::Collection for FsRecord {
11891189+ const NSID: &'static str = "place.wisp.fs";
11901190+ type Record = FsRecord;
11911191+}
11921192+11931193+impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Fs<'a> {
11941194+ fn nsid() -> &'static str {
11951195+ "place.wisp.fs"
11961196+ }
11971197+ fn def_name() -> &'static str {
11981198+ "main"
11991199+ }
12001200+ fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
12011201+ lexicon_doc_place_wisp_fs()
12021202+ }
12031203+ fn validate(
12041204+ &self,
12051205+ ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
12061206+ if let Some(ref value) = self.file_count {
12071207+ if *value > 1000i64 {
12081208+ return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
12091209+ path: ::jacquard_lexicon::validation::ValidationPath::from_field(
12101210+ "file_count",
12111211+ ),
12121212+ max: 1000i64,
12131213+ actual: *value,
12141214+ });
12151215+ }
12161216+ }
12171217+ if let Some(ref value) = self.file_count {
12181218+ if *value < 0i64 {
12191219+ return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
12201220+ path: ::jacquard_lexicon::validation::ValidationPath::from_field(
12211221+ "file_count",
12221222+ ),
12231223+ min: 0i64,
12241224+ actual: *value,
12251225+ });
12261226+ }
12271227+ }
12281228+ Ok(())
12291229+ }
12301230+}
+14
cli/test_headers.rs
···11+use http::Request;
22+33+fn main() {
44+ let builder = Request::builder()
55+ .header(http::header::CONTENT_TYPE, "*/*")
66+ .header(http::header::CONTENT_TYPE, "application/octet-stream");
77+88+ let req = builder.body(()).unwrap();
99+1010+ println!("Content-Type headers:");
1111+ for value in req.headers().get_all(http::header::CONTENT_TYPE) {
1212+ println!(" {:?}", value);
1313+ }
1414+}
create-admin.ts
scripts/create-admin.ts
-44
src/lexicon/index.ts
···11-/**
22- * GENERATED CODE - DO NOT MODIFY
33- */
44-import {
55- type Auth,
66- type Options as XrpcOptions,
77- Server as XrpcServer,
88- type StreamConfigOrHandler,
99- type MethodConfigOrHandler,
1010- createServer as createXrpcServer,
1111-} from '@atproto/xrpc-server'
1212-import { schemas } from './lexicons.js'
1313-1414-export function createServer(options?: XrpcOptions): Server {
1515- return new Server(options)
1616-}
1717-1818-export class Server {
1919- xrpc: XrpcServer
2020- place: PlaceNS
2121-2222- constructor(options?: XrpcOptions) {
2323- this.xrpc = createXrpcServer(schemas, options)
2424- this.place = new PlaceNS(this)
2525- }
2626-}
2727-2828-export class PlaceNS {
2929- _server: Server
3030- wisp: PlaceWispNS
3131-3232- constructor(server: Server) {
3333- this._server = server
3434- this.wisp = new PlaceWispNS(server)
3535- }
3636-}
3737-3838-export class PlaceWispNS {
3939- _server: Server
4040-4141- constructor(server: Server) {
4242- this._server = server
4343- }
4444-}