A better Rust ATProto crate
101
fork

Configure Feed

Select the types of activity you want to include in your feed.

Changelog#

[0.12.0-beta.1] - 2026-03-23#

Breaking changes#

Borrow-or-share (BOS) type system (all crates)

  • All validated string types (Did, Handle, Nsid, Rkey, AtUri, AtIdentifier, MimeType, Cid, CidLink, Blob, BlobRef, Data, Array, Object, DidDocument, RecordUri, UriValue, RepoPath) are now parameterised on S: BosStr = DefaultStr instead of lifetimes
  • DefaultStr = SmolStr: owned, inline ≤23 bytes, DeserializeOwned
  • &str, CowStr<'a>, String all work as backing types via the BosStr trait
  • SmolStr-backed types satisfy DeserializeOwned, enabling use in async contexts, collections, and across thread boundaries without IntoStatic conversion
  • New .borrow() method on Did, Handle, Nsid, Rkey, RecordKey returns Type<&str> for cheap borrowing (analogous to Uri::borrow())
  • New .convert::<B>() method for cross-backing-type conversion

XRPC trait changes (jacquard-common)

  • XrpcResp::Output<S: BosStr>: GAT parameterised on backing type S, not lifetime
  • XrpcResp::Err: plain associated type, always SmolStr-backed and DeserializeOwned
  • XrpcRequest now requires Serialize bound
  • XrpcEndpoint::Request<S: BosStr>: GAT for server-side extraction
  • SubscriptionResp::Message<S: BosStr>, SubscriptionEndpoint::Params<S: BosStr>: updated GATs
  • XrpcProcedureStream::Frame<S: BosStr>, XrpcStreamResp::Frame<S: BosStr>: streaming frame GATs updated

Response parsing (jacquard-common)

  • Response::parse::<S>(): caller chooses backing type via turbofish
  • Response::into_output(): returns SmolStr-backed owned types via DeserializeOwned
  • Zero-copy: response.parse::<CowStr<'_>>(); owned: response.into_output()

Generated API types (jacquard-api, jacquard-lexicon)

  • All generated structs/enums: Foo<S: BosStr = DefaultStr> with #[serde(bound(deserialize = "S: Deserialize<'de> + BosStr"))]
  • #[serde(borrow)] removed from all generated code
  • String field defaults use FromStaticStr::from_static() for zero-alloc construction
  • Error enums: SmolStr message fields, no lifetime parameters
  • Type aliases: <S = DefaultStr> (no bounds, per rust type checker limitation)

OAuth types (jacquard-oauth)

  • All session, metadata, token, scope, and JWT types parameterised on S: BosStr = DefaultStr
  • OAuthMetadata<S> parameterised so callers can borrow from stored metadata
  • DpopDataSource trait methods return Option<&str> (was Option<CowStr<'_>>)
  • DPoP proof building uses &str for zero-copy JWT construction
  • build_dpop_proof takes &str parameters, returns SmolStr

Identity resolution (jacquard-identity)

  • IdentityResolver::resolve_handle<S: BosStr + Sync>(&self, handle: &Handle<S>): generic over handle backing type
  • IdentityResolver::resolve_did_doc<S: BosStr + Sync>(&self, did: &Did<S>): generic over DID backing type

Repository types (jacquard-repo)

  • Commit<S: BosStr = DefaultStr>, UnsignedCommit<S>, RecordClaim<S>, VerifyProofsOutput<S> parameterised on S
  • RecordWriteOp now parameterised on both S (for string fields) and BS (for BlockStore)
  • RawData<'a> intentionally remains lifetime-based

Derive macros (jacquard-derive)

  • #[lexicon] detects type param S, emits Data<S> for extra_data
  • #[open_union] detects type param S, emits Unknown(Data<S>)
  • #[derive(IntoStatic)] handles S-parameterised types
  • #[derive(XrpcRequest)] generates new Output<S: BosStr> and Err (not GAT) impls

Client types (jacquard)

  • AtpSession fields access_jwt/refresh_jwt are now SmolStr (was CowStr<'static>)
  • SessionKey uses Did and SmolStr (was Did<'static> and CowStr<'static>)
  • AgentSessionExt record methods (get_record, update_record, etc.) take AtUri<S> / RecordUri<S, R> with generic S
  • Moderation types (ModerationPrefs, LabelerDefs, Labeled trait, etc.) parameterised on S

Removed#

  • jacquard-axum temporarily removed from workspace (extractor needs redesign for BOS type params)

Changed#

Codegen (jacquard-lexicon)

  • Generated XrpcResp impls emit Output<S: BosStr> and Err (plain type, not GAT)
  • Generated XrpcEndpoint impls emit Request<S: BosStr>

[0.11.0] - 2026-03-21#

Breaking changes#

Code generation pipeline overhaul (jacquard-lexicon, jacquard-lexgen)

  • Jacquard's codegen output already was nice to use. now it's going to be nice to read.
  • New code generation tracks the types used, makes an import block for the file, and then organizes the file with stuff you care about at the top and internal stuff, like the builders, at the bottom.
  • Import resolution pass now conditionally generates short paths when types are unambiguous within a module, falling back to fully-qualified paths when collisions exist
  • Improved default value handling in generated code, reducing unnecessary boilerplate

Added#

Hand-written XRPC bootstrap types (jacquard-common)

  • Added minimal XRPC endpoint types for com.atproto.repo.listRecords, com.atproto.repo.getRecord, com.atproto.identity.resolveHandle, and com.atproto.identity.resolveDid
  • These types break circular dependencies between jacquard-lexgen/jacquard-identity and jacquard-api, allowing the codegen tooling and identity resolver to function without depending on the generated API crate

Changed#

Regenerated API crate (jacquard-api)

  • All generated code regenerated with the new codegen pipeline
  • Shorter import paths where unambiguous, cleaner builder output, better formatting throughout

[0.10.1] - 2026-03-20#

Fixed#

CID deserialization (jacquard-common)

  • Fixed CidLink deserialization from CBOR tag-42 bytes through internally-tagged enums (reported by @natalie.sh, fixed by adorable robot)
  • serde_ipld_dagcbor buffers tag-42 CIDs as a newtype struct wrapping raw bytes when deserializing through Content; the visitor now handles visit_bytes, visit_byte_buf, and visit_newtype_struct to cover this path

Lexicon code generation (jacquard-lexicon, jacquard-api)

  • Fixed BlobRef generation producing incorrect code in certain lexicon schemas

Identity resolution (jacquard-identity)

  • Error message when handle resolution exhausts all resolution methods no longer misleading

[0.10.0] - 2026-03-20#

Breaking changes#

URL type migration (jacquard-common, jacquard, jacquard-oauth, jacquard-identity, jacquard-api)

  • Migrated from url crate to fluent_uri for validated URL/URI types
  • All Url types are now Uri from fluent_uri
  • Affects any code that constructs, passes, or pattern-matches on endpoint URLs

Re-exported crate paths (jacquard-api, jacquard-common)

  • Re-exported crates (including non-proc-macro dependencies of the generated API crate) are now centralized into a distinct module
  • Import paths for re-exported types have changed as a result

Added#

no_std groundwork (jacquard-common, jacquard-api)

  • Initial steps toward no_std support for core types
  • jacquard-api gains feature gating for std/no_std usage

Datetime improvements (jacquard-common)

  • PR from @blyoom.dev exposing timestamps directly on Datetime type
  • Naming aligned with chrono conventions

Handle normalization (jacquard-common)

  • Handles are now lowercase-normalized on construction

Embedded PDS primitives (jacquard-repo)

  • Initial lazy disk-spilling collection types for embedded PDS use cases
  • Repo firehose types now use generated API types instead of hand-written equivalents

Lexicon codegen improvements (jacquard-lexicon, jacquard-api)

  • knownValues generation now aligned with AT Protocol spec and triggers more frequently
  • Improved feature dependency tracking for API crate features

Additional signing algorithms (jacquard-oauth)

  • Keyset signing now supports ES384 (P-384), ES256K (secp256k1), and EdDSA (Ed25519) in addition to ES256
  • Keyset::create_jwt now accepts &[Signing] (from jose_jwa) instead of string-based algorithm names

Documentation (jacquard-oauth, jacquard-identity)

  • Doc comments across all public items in both crates (thanks Claude, but I played editor pretty heavily)

Fixed#

Identity resolution (jacquard-identity)

Error handling (jacquard-common, jacquard, jacquard-oauth)

  • Big error quality-of-life pass with richer, more actionable diagnostics
  • More resilient error parsing for auth errors
  • Better lexicon parsing error messages

WASM (jacquard-common)

  • Fixed WASM CI smoke test compilation

Changed#

Lexicons (jacquard-api)

  • Large batch of lexicon schema updates with manual cleanup

[0.9.6] - 2025-12-19#

Changed#

Logging (jacquard, jacquard-axum)

Fixed#

Repo commit signatures (jacquard-repo)

  • commit signatures generated by jacquard-repo should now be consistent with other implementations
  • previously, they included an empty sig bytes field in the signed struct, which has a different CBOR serialization from the canonical relay implementation expectations.

[0.9.5] - 2025-12-19#

Fixed#

docs.rs configuration

  • Fixed typo in jacquard-common docs.rs features (crypto-ed22519crypto-ed25519) that was causing documentation builds to fail
  • Moved loopback feature documentation to jacquard-oauth where the feature is defined

OAuth flow (jacquard-oauth)

  • Minor OAuth flow compatibility improvements

Serialization (jacquard-common, jacquard-identity)

  • Fixed CID deserialization edge cases in Data and RawData types
  • Fixed DID document serialization when optional fields are absent

Lexicon code generation (jacquard-lexicon, jacquard-api)

  • Fixed nullable field handling in generated code
  • Fixed lifetime handling in codegen of binary xrpc outputs
  • Fixed lifetime handling in unions
  • Fixed incorrectly unescaped rust keywords in module paths

Observability (jacquard)

  • Fixed tracing span issues associated with some build failures

Added#

mini-moka-wasm (mini-moka-wasm, jacquard-identity)

  • Publishing vendored version of mini-moka with wasm browser compat fix to make usage easier

Service authentication (jacquard-axum)

  • Optional service auth extractor option

Data handling (jacquard-common)

  • Serde bytes helpers for JSON fields
  • Made PLC source fields public for library consumers

Lexicons (jacquard-api)

  • Updated to latest AT Protocol lexicon schemas
  • API regeneration with builder fixes

Changed#

Logging (jacquard)

  • Improved client error logging with better context

[0.9.3] - 2025-11-17 (jacquard)#

Fixed#

  • SessionKey is now a proper tuple struct and not a type alias, which should help rustc not freak out when you do things like put MemoryCredentialSession in an Arc

[0.9.2] - 2025-11-17#

Added#

WASM compatibility improvements (jacquard-common, jacquard-identity)

  • Vendored mini-moka implementation with WASM support for caching
  • regex-lite usage on WASM targets for reduced binary size
  • Schema resolver now works on WASM targets

Data query improvements (jacquard-common)

  • Mutable path query access and setting for Data values

Changed#

URL handling (jacquard-common)

  • Rework of some internal URL handling for better compatibility
  • Includes a minor change to the return type of the endpoint() method of XrpcClient and equivalents.

OAuth improvements (jacquard-oauth)

  • Fixed OAuth scope handling in loopback flow
  • OAuth metadata resolution improvements
  • Various OAuth flow enhancements and bug fixes

Identity resolution (jacquard-identity)

  • Fixed non-DNS lexicon and did:web resolution using Cloudflare DoH
  • Reduced noisy logging in identity resolution

Lexicons (jacquard-api)

  • Updated to latest AT Protocol lexicons

Fixed#

Data deserialization (jacquard-common)

  • Fixed CID deserialization edge cases for better spec compliance
  • More permissive JSON shape handling for better interoperability with varied implementations

[0.9.1] - 2025-11-04 (jacquard-identity, jacquard-lexicon)#

Fixed#

  • slingshot resolver no longer spuriously warns when cross-validating handles

[0.9.0] - 2025-11-03#

Added#

Runtime schema validation (jacquard-lexicon)

  • SchemaValidator for validating Data values against lexicon schemas
  • CID-based validation caching for efficient repeated validation
  • ValidationResult with structural and constraint error separation
  • Comprehensive error types: StructuralError (type mismatches, missing fields, union errors) and ConstraintError (length, grapheme, numeric bounds)
  • ValidationPath for precise error location reporting
  • Ref cycle detection with configurable max depth
  • Support for validating partial/malformed data without full deserialization

Value query DSL (jacquard-common)

  • Pattern-based querying of nested Data structures
  • data.query(pattern) with expressive syntax:
    • field.nested - exact path navigation
    • [..] - wildcard over collections (array elements or object values)
    • field..nested - scoped recursion (find nested within field, expect one)
    • ...field - global recursion (find all occurrences anywhere)
  • QueryResult enum with Single, Multiple, and None variants
  • QueryMatch with path tracking for multiple results
  • Iterator support via .values(), .first(), .single(), .multiple()

Data value enhancements (jacquard-common)

  • get_at_path() for simple path-based field access on Data and RawData
  • Path syntax: embed.images[0].alt for navigating nested structures
  • type_discriminator() helper methods for AT Protocol union discrimination
  • Returns $type field value for objects with type discriminators
  • Added on Data, Object, and RawData types
  • Collection helper methods: get(), contains_key(), len(), is_empty(), iter(), keys(), values()
  • Index operator support: obj["key"] and arr[0]

Lexicon resolution (jacquard-identity)

  • LexiconResolver for fetching lexicon schemas from AT Protocol services
  • Resolves lexicons from PDS instances and lexicon hosts
  • resolve_lexicon() fetches and parses lexicon schemas
  • resolve_lexicon_raw() fetches raw schema JSON
  • New example: resolve_lexicon.rs

Identity resolver caching (jacquard-identity)

  • Optional cache feature with configurable in-memory caching
  • JacquardResolver::with_cache() constructor for cached resolver
  • Separate TTLs for handle→DID, DID→doc, and lexicon resolution

XRPC client improvements (jacquard-common, jacquard, jacquard-oauth)

  • set_options() and set_endpoint() methods on XrpcClient trait
  • Default no-op implementations for stateless clients
  • Enables runtime reconfiguration of stateful clients
  • Better support for custom endpoint and option overrides

Lexicon schema generation from Rust types (jacquard-derive, jacquard-lexicon)

  • New #[derive(LexiconSchema)] macro for generating lexicon schemas from Rust structs
  • New #[lexicon_union] attribute macro for lexicon union types (tagged enums)
  • Automatic schema generation for custom lexicons without writing JSON manually
  • Field-level attributes: ref for explicit type references, union for union fields
  • Fragment support for multi-def lexicons via fragment = "..." attribute
  • Generates LexiconDoc at compile time for runtime validation
  • Enables type-safe custom lexicon development

Lexicon codegen improvements (jacquard-lexicon, jacquard-api)

  • Vendored in an implementation of the typed builder pattern from bon to substantially improve compile times
  • Feature-gated heavy code generation features so jacquard-api and other consumers of the validation capabilities don't pay the syn tax as badly.
  • LexiconSchema trait generated implementations for runtime validation

Session store improvements (jacquard)

  • Improved trait bounds for SessionStore implementations
  • Better ergonomics for credential session types
  • Memory-based credential session helpers

New crate: jacquard-lexgen

  • Lexicon code generation tooling extracted from jacquard-lexicon
  • Separates binary/CLI tools from library code
  • Contains lexicon fetching and code generation binaries
  • jacquard-lexicon remains as pure library for lexicon parsing, code generation, and validation

Examples

  • app_password_create_post.rs: App password authentication example

Changed#

Feature gating (jacquard-identity)

  • Better conditional compilation for platform-specific features
  • Improved WASM target support

Dependency updates

  • Updated to latest lexicons from atproto/bluesky
  • Added workspace dependencies: sha2, multihash, dashmap, cid
  • Various minor dependency version updates

Fixed#

File auth store (jacquard)

  • Fixed serialization/deserialization bugs in FileAuthStore implementation

Packaging (jacquard-lexgen)

  • Added Nix flake apps for lexicon tools

[0.8.0] - 2025-10-23#

Breaking Changes#

Error type refactor (jacquard-common, jacquard-identity, jacquard-oauth, jacquard)

  • Better error messages with contextual information and help text
  • Breaking: Error variant names and structures changed across all crates

Added#

New crate: jacquard-repo

  • AT Protocol repository primitives for working with atproto data structures
  • MST (Merkle Search Tree): Immutable, deterministic tree operations with proper fanout
    • Optimized block allocation (4.5% oversupply, validated against retr0id's test suite)
    • Diff operations with protocol limit enforcement
    • Cursor-based traversal
  • Commits:
    • Proof generation and validation for Sync v1 and v1.1 Relay protocol
  • CAR I/O:
    • Proof CAR validation with MST path verification
  • Storage: Pluggable block storage abstraction
    • MemoryBlockStore: In-memory storage for testing
    • FileBlockStore: Persistent file-based storage
    • LayeredBlockStore: Layered read-through cache (memory over file, etc.)

Changed#

  • Dependency updates (upgraded various crypto and serialization dependencies)
  • Documentation improvements throughout
  • Made handle parsing a bit more permissive for a common case ('handle.invalid' when someone has a messed up handle), added a method to confirm syntactic validity (the correct way to confirm validity is resolve_handle() from IdentityResolver, and comparing to the DID document).

[0.7.0] - 2025-10-19#

Added#

Bluesky-style rich text utilities (jacquard)

  • Rich text parsing with automatic facet detection (mentions, links, hashtags)
  • Compatible with Bluesky, with the addition of support for markdown-style links ([display](url) syntax)
  • Embed candidate detection from URLs and at-URIs
    • Record embeds (posts, lists, starter packs, feeds)
    • External embeds with optional OpenGraph metadata fetching
  • Configurable embed domains for at-URI extraction (default: bsky.app, deer.social, blacksky.community, catsky.social)
  • Overlap detection and validation for facet byte ranges

Moderation/labeling client utilities (jacquard)

  • Trait-based content moderation with Labeled and Moderateable traits
  • Generic moderation decision making via moderate() and moderate_all()
  • User preference handling (ModerationPrefs) with global and per-labeler overrides
  • ModerationIterExt trait for filtering/mapping moderation over iterators
  • Labeled implementations for Bluesky types (PostView, ProfileView, ListView, Generator, Notification, etc.)
  • Labeled implementations for community lexicons (net.anisota, social.grain)
  • fetch_labels() and fetch_labeled_record() helpers for retrieving labels via XRPC
  • fetch_labeler_defs() and fetch_labeler_defs_direct() for fetching labeler definitions

Subscription control (jacquard-common)

  • SubscriptionControlMessage trait for dynamic subscription configuration
  • SubscriptionController for sending control messages to active WebSocket subscriptions
  • Enables runtime reconfiguration of subscriptions (e.g., Jetstream filtering)

Lexicons (jacquard-api)

  • teal.fm alpha lexicons for music sharing (fm.teal.alpha.*)
    • Actor profiles with music service status
    • Feed generation from play history
    • Statistics endpoints (top artists, top releases, user stats)

Examples

  • Updated create_post.rs to demonstrate richtext parsing with automatic facet detection
  • New moderated_timeline.rs to demonstrate fetching timeline with labelers enabled and applying moderation decisions

Fixed#

Data deserialization (jacquard-common)

  • Fixed Option<Vec<T>> deserialization from Data values
  • Implemented explicit deserialize_option for Data and RawData deserializers
  • Properly handles null vs present array values when deserializing into optional fields

[0.6.0] - 2025-10-18#

Added#

HTTP streaming support (jacquard-common, jacquard)

  • HttpClientExt trait for streaming HTTP requests/responses
  • send_http_streaming() for streaming response bodies
  • send_http_bidirectional() for streaming both request and response
  • StreamingResponse wrapper type with parts + ByteStream
  • XrpcResponseStream<R> for typed XRPC streaming responses
  • ByteStream / ByteSink platform-agnostic stream wrappers (uses n0-future)
  • StreamError concrete error type with kind enum (Transport, Closed, Protocol)
  • Native support via reqwest's bytes_stream() and Body::wrap_stream()
  • WASM compatibility via n0-future (no Send bounds required)

WebSocket subscription support (jacquard-common)

  • Full XRPC WebSocket subscription infrastructure
  • SubscriptionResp trait for defining subscription message/error types
  • XrpcSubscription trait for subscription parameters
  • SubscriptionStream<S> typed wrapper with automatic message decoding
  • SubscriptionClient stateful trait + TungsteniteSubscriptionClient implementation
  • SubscriptionExt for stateless subscription calls
  • Support for both JSON and DAG-CBOR message encodings
  • Custom path support via CUSTOM_PATH constant for non-XRPC endpoints
  • WebSocket integration into Agent struct (agents can now subscribe)
  • into_stream(), into_raw_data_stream(), into_data_stream() methods for different deserialization modes

Framed DAG-CBOR message decoding (jacquard-common, jacquard-api, jacquard-lexicon)

  • Two-stage deserialization for AT Protocol event streams (header + body)
  • EventHeader struct and parse_event_header() function
  • decode_framed() methods generated for all DAG-CBOR subscription message enums
  • decode_message() override in SubscriptionResp trait for custom decoding
  • UnknownEventType variant in DecodeError for unknown discriminators
  • Fixes "TrailingData" errors when consuming subscribeRepos and subscribeLabels

Jetstream support (jacquard-common)

  • Full typed support for Jetstream JSON firehose
  • JetstreamMessage enum with Commit, Identity, Account variants
  • JetstreamCommit, JetstreamIdentity, JetstreamAccount detail structs
  • CommitOperation enum for create/update/delete operations
  • JetstreamParams with filtering options (collections, DIDs, cursor, compression)
  • Uses proper AT Protocol types (Did, Handle, Datetime, Data)

Zstd compression (jacquard-common)

  • Optional zstd feature for Jetstream message decompression
  • Automatic detection and decompression of zstd-compressed binary frames
  • Includes official Bluesky Jetstream zstd dictionary
  • Transparent fallback to uncompressed when zstd unavailable
  • Works across all JSON stream methods (into_stream(), into_raw_data_stream(), into_data_stream())

Typed AT URI wrapper (jacquard-common, jacquard-api, jacquard-lexicon)

  • AtUri<'a> newtype wrapper for at:// URIs with proper validation
  • Generated fetch_uri() method on all record types for fetching by AT URI
  • AtUri::from_parts() constructor for building URIs from components
  • Proper Display and FromStr implementations

Memory-based credential session helpers (jacquard) (ty @vielle.dev)

Axum improvements (jacquard-axum)

  • XrpcError now implements IntoResponse for better error handling
  • Proper typed error responses without manual conversion
  • Better integration with Axum's response system

Examples

  • subscribe_repos.rs: Subscribe to PDS firehose with typed DAG-CBOR messages
  • subscribe_jetstream.rs: Subscribe to Jetstream with typed JSON messages and optional compression
  • stream_get_blob.rs: Download blobs using HTTP streaming
  • app_password_example.rs: App password authentication example (ty @vielle.dev)

CID deserialization improvements (jacquard-common)

  • Fixed Cid type to properly deserialize CBOR tag 42 via IpldCid::deserialize
  • Separate handling for JSON (string) vs CBOR (tag 42) formats
  • CidLink correctly delegates to Cid for both formats

Changed#

Default features (jacquard-common)

  • Added zstd to default features for better Jetstream experience
  • Jetstream compression enabled by default when using the full feature set

Generated code (jacquard-lexicon, jacquard-api)

  • All DAG-CBOR subscriptions (subscribeRepos, subscribeLabels) now use framed decoding
  • Generated decode_framed() implementations match on event type discriminator
  • Override decode_message() in trait impls to use framed decoding
  • All record types now have fetch_uri() and fetch_record() methods generated

Dependencies (jacquard-axum) (ty @thoth.ptnote.dev)

  • Disabled default features for jacquard dependency to reduce bloat

Fixed#

Blob upload (jacquard) (ty @vielle.dev for reporting this one)

  • Fixed upload_blob() authentication issues
  • Properly authenticates while allowing custom Content-Type headers

XRPC client (jacquard-common, jacquard-oauth, jacquard)

  • Added send_with_options() method for per-request option overrides
  • Stateful clients can now override options while preserving internal auth

jacquard-api [0.5.5], jacquard-lexicon [0.5.4] - 2025-10-16#

Fixed#

  • events.smokesignal.invokeWebhook lexicon now generates valid code
  • lexicon code generation now uses Data for blank objects, rather than naming and then failing to generate a struct

[0.5.4] - 2025-10-16#

Added#

Initial streaming client support (jacquard-common)

  • First primitives for streamed requests and responses

send_with_options() method on XrpcClient (jacquard-common, jacquard-oauth, jacquard)

  • allows setting custom options per request in stateful client
  • updated oauth and credential session clients to use it
  • implementations should generally override provided auth with own internal auth

Prelude providing common traits into scope

Fixed#

AgentSessionExt::upload_blob() failed to authenticate (jacquard)

  • new XrpcClient::send_with_options() method now allows properly overriding the content-type header while still handling auth internally

[0.5.3] - 2025-10-15#

Added#

Experimental WASM Support (jacquard-common, jacquard-api, jacquard-identity, jacquard-oauth)

  • Core crates now compile for wasm32-unknown-unknown target
  • Traits use trait-variant to conditionally exclude Send bounds on WASM
  • Platform-specific trait method implementations for methods with Self: Sync bounds
  • DNS-based handle resolution remains gated behind dns feature (unavailable on WASM)
  • HTTPS well-known and PDS resolution work on all platforms

Fixed#

OAuth client (jacquard-oauth)

  • Fixed tokio runtime detection for non-WASM targets
  • Conditional compilation for tokio-specific features

[0.5.2] - 2025-10-14#

Added#

Value type deserialization (jacquard-common)

  • from_json_value(): Deserialize typed data directly from serde_json::Value without borrowing
  • from_data_owned(), from_raw_data_owned(): Owned deserialization helpers
  • Data::from_json_owned(): Parse JSON into owned Data<'static>
  • IntoStatic implementation for RawData enabling owned conversions
  • Re-exported value types from crate root for easier imports
  • Deserializer trait implementations for Data<'static> and RawData<'static>
  • Owned deserializer helpers: OwnedArrayDeserializer, OwnedObjectDeserializer, OwnedBlobDeserializer

Service Auth (jacquard-axum, jacquard-common)

  • Full service authentication implementation for inter-service JWT verification
  • ExtractServiceAuth Axum extractor for validating service auth tokens
  • Axum service auth middleware
  • JWT parsing and signature verification (ES256, ES256K)
  • Service auth claims validation (issuer, audience, expiration, method binding)
  • DID document resolution for signing key verification

XrpcRequest derive macro (jacquard-derive)

  • #[derive(XrpcRequest)] for custom XRPC endpoints
  • Automatically generates response marker struct and trait implementations
  • Supports both client-side (XrpcRequest) and server-side (XrpcEndpoint) with server flag
  • Simplifies defining custom XRPC endpoints outside of generated API

Builder integration (jacquard-derive)

  • #[lexicon] macro now detects bon::Builder derive
  • Automatically adds #[builder(default)] to extra_data field when Builder is present
  • Makes extra_data optional in generated builders

Fixed#

String deserialization (jacquard-common)

  • All string types (Did, Handle, Nsid, etc.) now properly handle URL-encoded values
  • serde_html_form correctly decodes percent-encoded characters during deserialization
  • Fixes issues with DIDs and other identifiers containing colons in query parameters

Axum extractor (jacquard-axum)

  • Removed unnecessary URL-decoding workaround (now handled by improved string deserialization)
  • Added comprehensive tests for URL-encoded query parameters
  • Cleaner implementation with proper delegation to serde

Changed#

Dependencies

  • Moved clap to dev-dependencies in jacquard (only used in examples)
  • Moved axum-macros and tracing-subscriber to dev-dependencies in jacquard-axum (only used in examples)
  • Removed unused dependencies: urlencoding (jacquard, jacquard-axum), uuid (jacquard-oauth), serde_with (jacquard-common)
  • Removed fancy feature from jacquard (design smell for library crates)
  • Moved various proc-macro crate dependencies to dev-dependencies in jacquard-derive

Development tooling

  • Improved justfile with dynamic example discovery
  • just examples now auto-discovers all examples
  • just example <name> auto-detects package without manual configuration
  • Better error messages when examples not found

Documentation (jacquard, jacquard-common)

  • Improved lifetime pattern explanations
  • Better documentation of zero-copy deserialization approach
  • Links to docs.rs for generated documentation

[0.5.1] - 2025-10-13#

Fixed#

Trait bounds (jacquard-common)

  • Removed lifetime parameter from XrpcRequest trait, simplifying trait bounds
  • Lifetime now only appears on XrpcEndpoint::Request<'de> associated type
  • Fixes issues with using XRPC types in async contexts like Axum extractors

Changed#

  • Updated all workspace crates to 0.5.1 for consistency
  • jacquard-axum remains at 0.5.1 (unchanged)

jacquard-axum [0.5.1] - 2025-10-13#

Fixed#

  • Axum extractor now sets the correct Content-Type header during error path.

[0.5.0] - 2025-10-13#

Added#

Agent convenience methods (jacquard)

  • New AgentSessionExt trait automatically implemented for AgentSession + IdentityResolver
  • Basic CRUD: create_record(), get_record(), put_record(), delete_record()
  • Update patterns: update_record() (fetch-modify-put), update_vec(), update_vec_item()
  • Blob operations: upload_blob()
  • All methods auto-fill repo from session or URI parameter as relevant, and collection from type's Collection::NSID

VecUpdate trait (jacquard)

  • VecUpdate trait for fetch-modify-put patterns on array-based endpoints
  • PreferencesUpdate implementation for updating Bluesky user preferences
  • Enables simpler updates to preferences and other 'array of union' types

Typed record retrieval (jacquard-api, jacquard-common, jacquard-lexicon)

  • Each collection generates {Type}Record marker struct implementing XrpcResp
  • Collection::Record associated type points to the marker
  • get_record::<R>() returns Response<R::Record> with zero-copy .parse()
  • Response transmutation enables type-safe record operations

Examples

  • create_post.rs: Creating posts with Agent convenience methods
  • update_profile.rs: Updating profile with fetch-modify-put
  • post_with_image.rs: Uploading images and creating posts with embeds
  • update_preferences.rs: Using VecUpdate for preferences
  • create_whitewind_post.rs, read_whitewind_post.rs: Third-party lexicons
  • read_tangled_repo.rs: Reading git repo metadata from tangled.org
  • resolve_did.rs: Identity resolution examples
  • public_atproto_feed.rs: Unauthenticated feed access
  • axum_server.rs: Server-side XRPC handler

Documentation (jacquard)

  • A whole host of examples added, as well as a lengthy explainer of the trait patterns.

[0.4.1] - 2025-10-13#

Added#

Collection trait improvements (jacquard-api)

  • Generated {Type}Record marker structs for all record types
  • Each implements XrpcResp with Output<'de> = {Type}<'de> and Err<'de> = RecordError<'de>
  • Enables typed get_record returning Response<R::Record>

Changed#

  • Minor improvements to derive macros (jacquard-derive)
  • Identity resolution refinements (jacquard-identity)
  • OAuth client improvements (jacquard-oauth)

[0.4.0] - 2025-10-11#

Breaking Changes#

Zero-copy deserialization (jacquard-common, jacquard-api)

  • XrpcRequest now takes a 'de lifetime parameter and requires Deserialize<'de>
  • For raw data, Response::parse_data() gives validated loosely-typed atproto data, while Response::parse_raw() gives the raw values, with minimal validation.

XRPC module moved (jacquard-common)

  • xrpc.rs is now top-level instead of under types
  • Import from jacquard_common::xrpc::* not jacquard_common::types::xrpc::*

Response API changes (jacquard-common)

  • XrpcRequest::Output and XrpcRequest::Err are associated types with lifetimes
  • Split response and request traits: XrpcRequest<'de> for client, XrpcEndpoint for server
  • Added XrpcResp marker trait

Various traits (jacquard, jacquard-common, jacquard-lexicon, jacquard-oauth)

  • Removed #[async_trait] attribute macro usage in favour of impl Future return types with manual bounds.
  • Boxing imposed by asyc_trait negatively affected borrowing modes in async methods.
  • Currently no semver guarantees on API trait bounds, if they need to tighten, they will.

Added#

New crate: jacquard-axum

  • Server-side XRPC handlers for Axum
  • ExtractXrpc<R> deserializes incoming requests (query params for Query, body for Procedure)
  • Automatic error responses

Lexicon codegen fixes (jacquard-lexicon)

  • Union variant collision detection: when multiple namespaces have similar type names, foreign ones get prefixed (e.g., Images vs BskyImages)
  • Token types generate unit structs with Display instead of being skipped
  • Namespace dependency tracking during union generation
  • generate_cargo_features() outputs Cargo.toml features with correct deps
  • sanitize_name() ensures valid Rust identifiers

Lexicons (jacquard-api)

Added 646 lexicon schemas. Highlights:

Core ATProto:

  • com.atproto.*
  • com.bad-example.* for identity resolution

Bluesky:

  • app.bsky.* bluesky app
  • chat.bsky.* chat client
  • tools.ozone.* moderation

Third-party:

  • sh.tangled.* - git forge
  • sh.weaver.* - orual's WIP markdown blog platform
  • pub.leaflet.* - longform publishing
  • net.anisota.* - gamified and calming take on bluesky
  • network.slices.* - serverless atproto hosting
  • tools.smokesignal.* - automation
  • com.whtwnd.* - markdown blogging
  • place.stream.* - livestreaming
  • blue.2048.* - 2048 game
  • community.lexicon.* - community extensions (bookmarks, calendar, location, payments)
  • my.skylights.* - media tracking
  • social.psky.* - social extensions
  • blue.linkat.* - link boards

Plus 30+ more experimental/community namespaces.

Value types (jacquard-common)

  • RawData to Data conversion with type inference
  • from_data, from_raw_data, to_data, and to_raw_data to serialize to and deserialize from the loosely typed value data formats. Particularly useful for second-stage deserialization of type "unknown" fields in lexicons, such as PostView.record.

Changed#

  • generate_union() takes current NSID for dependency tracking
  • Generated code uses sanitize_name() for identifiers more consistently
  • Added derive macro for IntoStatic trait implementation

Fixed#

  • Methods to extract the output from an XRPC response now behave well with respect to lifetimes and borrowing.
  • Now possible to use jacquard types in places like axum extractors due to lifetime improvements
  • Union variants don't collide when multiple namespaces define similar types and another namespace includes them