···192192//! be happy to debug, and if it's using a method from one of the jacquard crates and seems like
193193//! it *should* just work, that is a bug in jacquard, and you should [file an issue](https://tangled.org/@nonbinary.computer/jacquard/).
194194195195+#![no_std]
195196#![warn(missing_docs)]
197197+198198+#[macro_use]
199199+extern crate alloc;
200200+201201+#[cfg(feature = "std")]
202202+extern crate std;
203203+204204+/// Lazy initialization type for static values.
205205+///
206206+/// Uses `std::sync::LazyLock` when the `std` feature is enabled, or `spin::Lazy`
207207+/// for no_std environments. Exported so downstream crates can use it without
208208+/// their own conditional compilation.
209209+#[cfg(feature = "std")]
210210+pub type Lazy<T> = std::sync::LazyLock<T>;
211211+212212+#[cfg(not(feature = "std"))]
213213+pub use spin::Lazy;
214214+196215pub use bytes;
197216pub use chrono;
198217pub use cowstr::CowStr;
···11use serde::{Deserialize, Serialize};
2233+// Re-export Lazy from crate root for submodule use via `super::Lazy`
44+pub use crate::Lazy;
55+36/// AT Protocol URI (at://) types and validation
47pub mod aturi;
58/// Blob references for binary data
+9-5
crates/jacquard-common/src/types/aturi.rs
···33use crate::types::recordkey::{RecordKey, Rkey};
44use crate::types::string::AtStrError;
55use crate::{CowStr, IntoStatic};
66+use alloc::string::String;
77+use alloc::string::ToString;
88+use core::fmt;
99+use core::hash::{Hash, Hasher};
1010+use core::ops::Deref;
1111+use core::str::FromStr;
612#[cfg(not(target_arch = "wasm32"))]
713use regex::Regex;
814#[cfg(target_arch = "wasm32")]
···1016use serde::Serializer;
1117use serde::{Deserialize, Deserializer, Serialize, de::Error};
1218use smol_str::{SmolStr, ToSmolStr};
1313-use std::fmt;
1414-use std::hash::{Hash, Hasher};
1515-use std::sync::LazyLock;
1616-use std::{ops::Deref, str::FromStr};
1919+2020+use super::Lazy;
17211822/// AT Protocol URI (`at://`) for referencing records in repositories
1923///
···131135pub type UriPathBuf = RepoPath<'static>;
132136133137/// Regex for AT URI validation per AT Protocol spec
134134-pub static ATURI_REGEX: LazyLock<Regex> = LazyLock::new(|| {
138138+pub static ATURI_REGEX: Lazy<Regex> = Lazy::new(|| {
135139 // Fragment allows: / and \ and other special chars. In raw string, backslashes are literal.
136140 Regex::new(r##"^at://(?<authority>[a-zA-Z0-9._:%-]+)(/(?<collection>[a-zA-Z0-9-.]+)(/(?<rkey>[a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(#(?<fragment>/[a-zA-Z0-9._~:@!$&%')(*+,;=\-\[\]/\\]*))?$"##).unwrap()
137141});
+3-2
crates/jacquard-common/src/types/blob.rs
···22use crate::{CowStr, IntoStatic, types::cid::CidLink};
33use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
44use smol_str::ToSmolStr;
55-use std::convert::Infallible;
66-use std::{fmt, hash::Hash, ops::Deref, str::FromStr};
55+use alloc::string::{String, ToString};
66+use core::convert::Infallible;
77+use core::{fmt, hash::Hash, ops::Deref, str::FromStr};
7889/// Blob reference for binary data in AT Protocol
910///
+2-1
crates/jacquard-common/src/types/cid.rs
···22pub use cid::Cid as IpldCid;
33use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
44use smol_str::ToSmolStr;
55-use std::{convert::Infallible, fmt, ops::Deref, str::FromStr};
55+use alloc::string::{String, ToString};
66+use core::{convert::Infallible, fmt, ops::Deref, str::FromStr};
6778/// CID codec for AT Protocol (raw)
89pub const ATP_CID_CODEC: u64 = 0x55;
···66use regex_lite::Regex;
77use serde::{Deserialize, Deserializer, Serialize, de::Error};
88use smol_str::{SmolStr, ToSmolStr};
99-use std::fmt;
1010-use std::sync::LazyLock;
1111-use std::{ops::Deref, str::FromStr};
99+use alloc::string::{String, ToString};
1010+use core::fmt;
1111+use core::ops::Deref;
1212+use core::str::FromStr;
1313+1414+use super::Lazy;
12151316/// Decentralized Identifier (DID) for AT Protocol accounts
1417///
···3740/// enforce percent-encoding validity at validation time. While the spec states "percent sign
3841/// must be followed by two hex characters," this is treated as a best practice rather than
3942/// a hard validation requirement.
4040-pub static DID_REGEX: LazyLock<Regex> =
4141- LazyLock::new(|| Regex::new(r"^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$").unwrap());
4343+pub static DID_REGEX: Lazy<Regex> =
4444+ Lazy::new(|| Regex::new(r"^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$").unwrap());
42454346impl<'d> Did<'d> {
4447 /// Fallible constructor, validates, borrows from input
+9-7
crates/jacquard-common/src/types/did_doc.rs
···22use crate::types::string::{Did, Handle};
33use crate::types::value::Data;
44use crate::{CowStr, IntoStatic};
55+use alloc::collections::BTreeMap;
66+use alloc::vec::Vec;
57use bon::Builder;
68use serde::{Deserialize, Serialize};
79use smol_str::SmolStr;
88-use std::collections::BTreeMap;
910use url::Url;
10111112/// DID Document representation with borrowed data where possible.
···54555556 /// Alternate identifiers for the subject, such as at://\<handle\>
5657 #[serde(borrow)]
5757- #[serde(skip_serializing_if = "std::option::Option::is_none")]
5858+ #[serde(skip_serializing_if = "Option::is_none")]
5859 pub also_known_as: Option<Vec<CowStr<'a>>>,
59606061 /// Verification methods (keys) for this DID
6162 #[serde(borrow)]
6262- #[serde(skip_serializing_if = "std::option::Option::is_none")]
6363+ #[serde(skip_serializing_if = "Option::is_none")]
6364 pub verification_method: Option<Vec<VerificationMethod<'a>>>,
64656566 /// Services associated with this DID (e.g., AtprotoPersonalDataServer)
6667 #[serde(borrow)]
6767- #[serde(skip_serializing_if = "std::option::Option::is_none")]
6868+ #[serde(skip_serializing_if = "Option::is_none")]
6869 pub service: Option<Vec<Service<'a>>>,
69707071 /// Forward‑compatible capture of unmodeled fields
···174175 pub r#type: CowStr<'a>,
175176 /// Optional controller DID
176177 #[serde(borrow)]
177177- #[serde(skip_serializing_if = "std::option::Option::is_none")]
178178+ #[serde(skip_serializing_if = "Option::is_none")]
178179 pub controller: Option<CowStr<'a>>,
179180 /// Multikey `publicKeyMultibase` (base58btc)
180181 #[serde(borrow)]
181181- #[serde(skip_serializing_if = "std::option::Option::is_none")]
182182+ #[serde(skip_serializing_if = "Option::is_none")]
182183 pub public_key_multibase: Option<CowStr<'a>>,
183184184185 /// Forward‑compatible capture of unmodeled fields
···212213 pub r#type: CowStr<'a>,
213214 /// String or object; we preserve as Data
214215 #[serde(borrow)]
215215- #[serde(skip_serializing_if = "std::option::Option::is_none")]
216216+ #[serde(skip_serializing_if = "Option::is_none")]
216217 pub service_endpoint: Option<Data<'a>>,
217218218219 /// Forward‑compatible capture of unmodeled fields
···235236#[cfg(test)]
236237mod tests {
237238 use super::*;
239239+ use alloc::string::String;
238240 use serde_json::json;
239241240242 fn encode_uvarint(mut x: u64) -> Vec<u8> {
···11//! Lexicon integer types with minimum or maximum acceptable values.
22//! Copied from [atrium](https://github.com/atrium-rs/atrium/blob/main/atrium-api/src/types/integer.rs), because this they got right
3344-use std::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64};
55-use std::str::FromStr;
44+use alloc::string::{String, ToString};
55+use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64};
66+use core::str::FromStr;
6778use serde::{Deserialize, de::Error};
89
···22//
33// This test verifies that the derive macro generates lexicon documents that match
44// the original JSON schemas.
55-55+extern crate alloc;
66use jacquard_common::CowStr;
77use jacquard_common::types::string::{Datetime, Language};
88use jacquard_lexicon::lexicon::LexiconDoc;
+1-1
crates/jacquard-lexicon/tests/union_test.rs
···11// Minimal test for union attribute
22-22+extern crate alloc;
33use jacquard_common::CowStr;
44use serde::{Deserialize, Serialize};
55