A better Rust ATProto crate
0

Configure Feed

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

Changelog#

[0.12.0] - 2026-06-013#

Breaking changes (in addition to those from the beta!)#

Session resume rework (jacquard, jacquard-common, jacquard-oauth)

  • Reworked session storage primitives somewhat, moving toward a shared SessionKey type
  • Added enumeration method to the SessionStore trait to list existing session keys, defaulted to return an empty Vec.
  • Added SessionHint enum and SessionSelector trait to enable generic resume of sessions with varying levels of input information and implementations for existing store types, as well as wrappers backed by an IdentityResolver for handle resolution.
  • Added resume-or-auth helpers for OAuth and app password session types, making the process of resuming any existing session, reauthenticating, or punting to the login if there's not enough information more straightforward.

jacquard-identity no longer requires reqwest

  • JacquardResolver now parameterized on C: HttpClient with PublicResolver aliased to the default reqwest-backed version.

Added#

  • Cow<'a, str> now supported by borrow-or-share pattern traits

OAuth permission sets, refactored scopes (jacquard-oauth, jacquard, jacquard-lexicon)

  • Added ergonomic Scope constructors for common atproto, account, identity, transition, repo, RPC, and permission-set scopes.
  • Added Scopes::from_scopes() and ScopesBuilder so callers can construct typed scopes programmatically while reusing the same validation, normalization, reduction, and indexing path as string parsing.
  • Added endpoint-aware Scope::rpc_request::<R: XrpcRequest>() and collection-aware repo helpers such as Scope::repo_create_record::<C: Collection>().
  • Added AuthorizeOptions helpers for setting scopes from a string or typed scope values; builders can be passed through existing with_scopes() after ScopesBuilder::build().
  • Added IncludeScope<S> scope variant referencing permission set NSIDs with optional ?aud=<did> audience.
  • Updated OAuth examples and inline docs to demonstrate typed scope builders and link to the atproto OAuth scope docs and interactive scope-string builder.

Bootstrap XRPC types (jacquard-common)

  • Added DidService<S> validated type for DID audiences with optional service-id fragments (e.g., did:web:example.com#bsky_appview).
  • Added OAuth scope primitive enums (AccountResource, AccountAction, RepoAction) shared between OAuth scopes and permission set lexicons.
  • Added bootstrap types for com.atproto.repo.createRecord, putRecord, deleteRecord, and uploadBlob, and com.atproto.server.createSession, getSession, and refreshSession, allowing record helpers and credential sessions to function without depending on the generated API crate.

Loopback OAuth (jacquard-oauth)

  • Replaced rouille dependency with a lightweight raw TCP listener for the localhost callback server.
  • Improved the OAuth callback success page with proper HTML.

Client (jacquard)

  • Added concrete app-password session helpers: CredentialSessionSelector, resume_or_login, login_with_hint, restore, switch_session, logout.
  • Added AtpSession::merge_refresh and AtpSession::pds_from_data helpers.

jacquard-axum re-added and overhauled

  • Reworked XRPC extractor to work with borrow-or-share types. Backing type for the query or body of the input can differ from the handler-visible backing type, to allow for non-overlapping extractor impls for the different backing types so that the potentially borrowed types like CowStr<'_> can still be used.
  • Better type enforcement in handler responses by default.
  • Service auth
    • Improved service auth extractor to properly handle 'did:web:for.some.reason.still.blueskyweb.xyz#bsky_appview'-type service ids (thanks @pds.dad)
    • Added default replay protection for jti using a ReplayStore trait, default-implemented using a mini-moka in-memory cache.
  • OAuth web helpers
    • Added OAuth client counterparts to the service auth extractors.
    • API-oriented extractor provides a useful error on auth failure, if auth is required.
    • Browser-oriented extractor redirects unauthenticated users to a configured URL, while passing state to allow returning to the original URL after login.
    • Configurable routes and handlers for common oauth paths
    • Added axum-based server-side confidential oauth client example

Changed#

  • Reduced allocations in the atproto!() macro by cleverly allowing use of the FromStaticStr constructions method or SmolStr::new_static() constructor in keys and values.
  • Improved type inference in the atproto!() macro and several other locations by explicitly defaulting to DefaultStr more clearly.

Type cleanup

  • Migrated GetRecord bootstrap type from lifetime-based CowStr<'a> to borrow-or-share GetRecord<S: BosStr>, consistent with all other bootstrap types.
  • Removed intermediate OAuthSession and OAuthState serialization structs from jacquard; FileAuthStore now serializes ClientSessionData and AuthRequestData directly.
  • Changed credential session methods (login, authenticated, restore, switch_session) to take &str parameters instead of CowStr<'_>, eliminating unnecessary lifetime exposure.
  • Changed CredentialLoginOptions from CredentialLoginOptions<'a> with CowStr<'a> fields to owned SmolStr fields.
  • Switched record helpers in AgentSessionExt to use bootstrap types from jacquard-common, enabling them to work without the api feature in some cases.

Codegen

  • Added some improved doc comment creation paths in lexicon-generated code
  • Fixed multi-line doc comment generation to use per-line #[doc] attributes, preventing rustdoc from interpreting indented continuation lines as code blocks (which caused broken doctests).
  • Generated builders now have two entry points:
    • Type::new() picks DefaultStr as the backing type. This avoids awkward turbofishes or explicit annotations in many scenarios where the builder couldn't work out what type it needed to be from the immediate surroundings.
    • Type::builder() allows the caller to choose, either explicitly via turbofish, or implicitly via inference if possible, the backing type (the previous behaviour).

Fixed#

Documentation

  • Updated documentation for 0.12 version, fixed a number of reported areas of confusion or lack of clarity.

Crate features

  • Added reqwest-compression feature to jacquard-common, which enables reqwest's compression options or, more importantly, means consumers can disable them.

Lexicon schema derive (jacquard-derive, jacquard-lexicon)

  • Re-enabled and hardened #[derive(LexiconSchema)] for borrow-or-share generic types, including defaulted S: BosStr = DefaultStr parameters and lifetime-plus-type generic combinations.
  • Fixed schema type mapping for BOS generic strings inside Option<S> and Vec<S>, and for non-S type parameter names such as Text: BosStr.
  • Preserved the intended negative behavior for unconstrained generics, which continue to generate local refs rather than being mistaken for strings.
  • Made open-union schema generation robust when #[open_union] has already injected the Unknown(Data<S>) variant before schema derivation runs.
  • Added focused tests for generic open unions, recursive BOS type mapping, old-style Bos<str> + AsRef<str> bounds, and local-ref behavior for nested object schemas.

Value serialization and conversion (jacquard-common)

  • Fixed Data unsigned integer handling so values larger than i64::MAX are rejected instead of silently wrapping during deserialization, serialization into Data, or RawData conversion.
  • Fixed raw blob-size conversion to reject negative or out-of-range sizes instead of casting with truncation or wraparound.
  • Added direct borrowed-string regression coverage for Data<&str> and nested Data<&str> object values.

OAuth requests (jacquard-oauth)

  • Reserved OAuth token introspection as a future, unconstructible API placeholder rather than leaving reachable runtime unimplemented!() paths.
  • Marked OAuthRequest as non-exhaustive to preserve future request API flexibility.
  • Replaced the non-PAR authorization path with a structured ParRequired error instead of panicking.

[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

OAuth permission sets, refactored scopes (jacquard-oauth, jacquard, jacquard-lexicon)

  • Added Scopes<S> validated container for space-separated OAuth scope strings, replacing Vec<Scope<S>>. Stores a single string buffer with pre-computed byte-range indices, yielding zero-copy Scope<&str> views.
  • Added IncludeScope<S> scope variant referencing permission set NSIDs with optional ?aud=<did> audience.
  • Added permission set lexicon types (LexPermissionSet, LexPermission, LexPermissionResource) in jacquard-lexicon.
  • Added expand_permission_set() and resolve_permission_set() for converting permission set lexicons into concrete scopes.
  • Added scope-check feature to jacquard-oauth and jacquard, enabling client-side scope validation and eager resolution of include: scopes at session creation.

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