Changelog#
[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
Datavalues
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)
SchemaValidatorfor validatingDatavalues against lexicon schemas- CID-based validation caching for efficient repeated validation
ValidationResultwith structural and constraint error separation- Comprehensive error types:
StructuralError(type mismatches, missing fields, union errors) andConstraintError(length, grapheme, numeric bounds) ValidationPathfor 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
Datastructures 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)
QueryResultenum withSingle,Multiple, andNonevariantsQueryMatchwith 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 onDataandRawData- Path syntax:
embed.images[0].altfor navigating nested structures type_discriminator()helper methods for AT Protocol union discrimination- Returns
$typefield value for objects with type discriminators - Added on
Data,Object, andRawDatatypes - Collection helper methods:
get(),contains_key(),len(),is_empty(),iter(),keys(),values() - Index operator support:
obj["key"]andarr[0]
Lexicon resolution (jacquard-identity)
LexiconResolverfor fetching lexicon schemas from AT Protocol services- Resolves lexicons from PDS instances and lexicon hosts
resolve_lexicon()fetches and parses lexicon schemasresolve_lexicon_raw()fetches raw schema JSON- New example:
resolve_lexicon.rs
Identity resolver caching (jacquard-identity)
- Optional
cachefeature 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()andset_endpoint()methods onXrpcClienttrait- 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:
reffor explicit type references,unionfor union fields - Fragment support for multi-def lexicons via
fragment = "..."attribute - Generates
LexiconDocat 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
bonto substantially improve compile times - Feature-gated heavy code generation features so
jacquard-apiand other consumers of the validation capabilities don't pay thesyntax as badly. - LexiconSchema trait generated implementations for runtime validation
Session store improvements (jacquard)
- Improved trait bounds for
SessionStoreimplementations - 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-lexiconremains 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
FileAuthStoreimplementation
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 testingFileBlockStore: Persistent file-based storageLayeredBlockStore: 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
LabeledandModerateabletraits - Generic moderation decision making via
moderate()andmoderate_all() - User preference handling (
ModerationPrefs) with global and per-labeler overrides ModerationIterExttrait for filtering/mapping moderation over iteratorsLabeledimplementations for Bluesky types (PostView, ProfileView, ListView, Generator, Notification, etc.)Labeledimplementations for community lexicons (net.anisota, social.grain)fetch_labels()andfetch_labeled_record()helpers for retrieving labels via XRPCfetch_labeler_defs()andfetch_labeler_defs_direct()for fetching labeler definitions
Subscription control (jacquard-common)
SubscriptionControlMessagetrait for dynamic subscription configurationSubscriptionControllerfor 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.rsto demonstrate richtext parsing with automatic facet detection - New
moderated_timeline.rsto demonstrate fetching timeline with labelers enabled and applying moderation decisions
Fixed#
Data deserialization (jacquard-common)
- Fixed
Option<Vec<T>>deserialization fromDatavalues - Implemented explicit
deserialize_optionforDataandRawDatadeserializers - 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)
HttpClientExttrait for streaming HTTP requests/responsessend_http_streaming()for streaming response bodiessend_http_bidirectional()for streaming both request and responseStreamingResponsewrapper type with parts +ByteStreamXrpcResponseStream<R>for typed XRPC streaming responsesByteStream/ByteSinkplatform-agnostic stream wrappers (uses n0-future)StreamErrorconcrete error type with kind enum (Transport, Closed, Protocol)- Native support via reqwest's
bytes_stream()andBody::wrap_stream() - WASM compatibility via n0-future (no Send bounds required)
WebSocket subscription support (jacquard-common)
- Full XRPC WebSocket subscription infrastructure
SubscriptionResptrait for defining subscription message/error typesXrpcSubscriptiontrait for subscription parametersSubscriptionStream<S>typed wrapper with automatic message decodingSubscriptionClientstateful trait +TungsteniteSubscriptionClientimplementationSubscriptionExtfor stateless subscription calls- Support for both JSON and DAG-CBOR message encodings
- Custom path support via
CUSTOM_PATHconstant for non-XRPC endpoints - WebSocket integration into
Agentstruct (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)
EventHeaderstruct andparse_event_header()functiondecode_framed()methods generated for all DAG-CBOR subscription message enumsdecode_message()override inSubscriptionResptrait for custom decodingUnknownEventTypevariant inDecodeErrorfor unknown discriminators- Fixes "TrailingData" errors when consuming subscribeRepos and subscribeLabels
Jetstream support (jacquard-common)
- Full typed support for Jetstream JSON firehose
JetstreamMessageenum withCommit,Identity,AccountvariantsJetstreamCommit,JetstreamIdentity,JetstreamAccountdetail structsCommitOperationenum for create/update/delete operationsJetstreamParamswith filtering options (collections, DIDs, cursor, compression)- Uses proper AT Protocol types (
Did,Handle,Datetime,Data)
Zstd compression (jacquard-common)
- Optional
zstdfeature 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 forat://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)
XrpcErrornow implementsIntoResponsefor 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 messagessubscribe_jetstream.rs: Subscribe to Jetstream with typed JSON messages and optional compressionstream_get_blob.rs: Download blobs using HTTP streamingapp_password_example.rs: App password authentication example (ty @vielle.dev)
CID deserialization improvements (jacquard-common)
- Fixed
Cidtype to properly deserialize CBOR tag 42 viaIpldCid::deserialize - Separate handling for JSON (string) vs CBOR (tag 42) formats
CidLinkcorrectly delegates toCidfor both formats
Changed#
Default features (jacquard-common)
- Added
zstdto 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()andfetch_record()methods generated
Dependencies (jacquard-axum) (ty @thoth.ptnote.dev)
- Disabled default features for
jacquarddependency 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
Datafor 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-unknowntarget - Traits use
trait-variantto conditionally excludeSendbounds on WASM - Platform-specific trait method implementations for methods with
Self: Syncbounds - DNS-based handle resolution remains gated behind
dnsfeature (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 fromserde_json::Valuewithout borrowingfrom_data_owned(),from_raw_data_owned(): Owned deserialization helpersData::from_json_owned(): Parse JSON into ownedData<'static>IntoStaticimplementation forRawDataenabling owned conversions- Re-exported value types from crate root for easier imports
Deserializertrait implementations forData<'static>andRawData<'static>- Owned deserializer helpers:
OwnedArrayDeserializer,OwnedObjectDeserializer,OwnedBlobDeserializer
Service Auth (jacquard-axum, jacquard-common)
- Full service authentication implementation for inter-service JWT verification
ExtractServiceAuthAxum 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) withserverflag - Simplifies defining custom XRPC endpoints outside of generated API
Builder integration (jacquard-derive)
#[lexicon]macro now detectsbon::Builderderive- Automatically adds
#[builder(default)]toextra_datafield when Builder is present - Makes
extra_dataoptional in generated builders
Fixed#
String deserialization (jacquard-common)
- All string types (Did, Handle, Nsid, etc.) now properly handle URL-encoded values
serde_html_formcorrectly 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
clapto dev-dependencies injacquard(only used in examples) - Moved
axum-macrosandtracing-subscriberto dev-dependencies injacquard-axum(only used in examples) - Removed unused dependencies:
urlencoding(jacquard, jacquard-axum),uuid(jacquard-oauth),serde_with(jacquard-common) - Removed
fancyfeature fromjacquard(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 examplesnow auto-discovers all examplesjust 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
XrpcRequesttrait, 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-axumremains 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
AgentSessionExttrait automatically implemented forAgentSession + 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)
VecUpdatetrait for fetch-modify-put patterns on array-based endpointsPreferencesUpdateimplementation 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}Recordmarker struct implementingXrpcResp Collection::Recordassociated type points to the markerget_record::<R>()returnsResponse<R::Record>with zero-copy.parse()- Response transmutation enables type-safe record operations
Examples
create_post.rs: Creating posts with Agent convenience methodsupdate_profile.rs: Updating profile with fetch-modify-putpost_with_image.rs: Uploading images and creating posts with embedsupdate_preferences.rs: Using VecUpdate for preferencescreate_whitewind_post.rs,read_whitewind_post.rs: Third-party lexiconsread_tangled_repo.rs: Reading git repo metadata from tangled.orgresolve_did.rs: Identity resolution examplespublic_atproto_feed.rs: Unauthenticated feed accessaxum_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}Recordmarker structs for all record types - Each implements
XrpcRespwithOutput<'de> = {Type}<'de>andErr<'de> = RecordError<'de> - Enables typed
get_recordreturningResponse<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)
XrpcRequestnow takes a'delifetime parameter and requiresDeserialize<'de>- For raw data,
Response::parse_data()gives validated loosely-typed atproto data, whileResponse::parse_raw()gives the raw values, with minimal validation.
XRPC module moved (jacquard-common)
xrpc.rsis now top-level instead of undertypes- Import from
jacquard_common::xrpc::*notjacquard_common::types::xrpc::*
Response API changes (jacquard-common)
XrpcRequest::OutputandXrpcRequest::Errare associated types with lifetimes- Split response and request traits:
XrpcRequest<'de>for client,XrpcEndpointfor server - Added
XrpcRespmarker trait
Various traits (jacquard, jacquard-common, jacquard-lexicon, jacquard-oauth)
- Removed #[async_trait] attribute macro usage in favour of
impl Futurereturn 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.,
ImagesvsBskyImages) - Token types generate unit structs with
Displayinstead of being skipped - Namespace dependency tracking during union generation
generate_cargo_features()outputs Cargo.toml features with correct depssanitize_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 appchat.bsky.*chat clienttools.ozone.*moderation
Third-party:
sh.tangled.*- git forgesh.weaver.*- orual's WIP markdown blog platformpub.leaflet.*- longform publishingnet.anisota.*- gamified and calming take on blueskynetwork.slices.*- serverless atproto hostingtools.smokesignal.*- automationcom.whtwnd.*- markdown bloggingplace.stream.*- livestreamingblue.2048.*- 2048 gamecommunity.lexicon.*- community extensions (bookmarks, calendar, location, payments)my.skylights.*- media trackingsocial.psky.*- social extensionsblue.linkat.*- link boards
Plus 30+ more experimental/community namespaces.
Value types (jacquard-common)
RawDatatoDataconversion with type inferencefrom_data,from_raw_data,to_data, andto_raw_datato serialize to and deserialize from the loosely typed value data formats. Particularly useful for second-stage deserialization of type "unknown" fields in lexicons, such asPostView.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