A better Rust ATProto crate
at main 659 lines 29 kB view raw view rendered
1# Changelog 2 3## [0.9.6] - 2025-12-19 4 5### Changed 6 7**Logging** (`jacquard`, `jacquard-axum`) 8- [PR from @nekomimi.pet](https://tangled.org/nonbinary.computer/jacquard/pulls/5) cleaning up more debug logs, and adding tracing feature gate to jacquard-axum 9 10## Fixed 11 12**Repo commit signatures** (`jacquard-repo`) 13- commit signatures generated by `jacquard-repo` should now be consistent with other implementations 14- previously, they included an empty `sig` bytes field in the signed struct, which has a different CBOR serialization from the canonical relay implementation expectations. 15 16## [0.9.5] - 2025-12-19 17 18### Fixed 19 20**docs.rs configuration** 21- Fixed typo in `jacquard-common` docs.rs features (`crypto-ed22519``crypto-ed25519`) that was causing documentation builds to fail 22- Moved `loopback` feature documentation to `jacquard-oauth` where the feature is defined 23 24**OAuth flow** (`jacquard-oauth`) 25- Minor OAuth flow compatibility improvements 26 27**Serialization** (`jacquard-common`, `jacquard-identity`) 28- Fixed CID deserialization edge cases in `Data` and `RawData` types 29- Fixed DID document serialization when optional fields are absent 30 31**Lexicon code generation** (`jacquard-lexicon`, `jacquard-api`) 32- Fixed nullable field handling in generated code 33- Fixed lifetime handling in codegen of binary xrpc outputs 34- Fixed lifetime handling in unions 35- Fixed incorrectly unescaped rust keywords in module paths 36 37**Observability** (`jacquard`) 38- Fixed tracing span issues associated with some build failures 39 40### Added 41 42**mini-moka-wasm** (`mini-moka-wasm`, `jacquard-identity`) 43- Publishing vendored version of mini-moka with wasm browser compat fix to make usage easier 44 45**Service authentication** (`jacquard-axum`) 46- Optional service auth extractor option 47 48**Data handling** (`jacquard-common`) 49- Serde bytes helpers for JSON fields 50- Made PLC source fields public for library consumers 51 52**Lexicons** (`jacquard-api`) 53- Updated to latest AT Protocol lexicon schemas 54- API regeneration with builder fixes 55 56### Changed 57 58**Logging** (`jacquard`) 59- Improved client error logging with better context 60 61## [0.9.3] - 2025-11-17 (`jacquard`) 62 63### Fixed 64 65- 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 66 67## [0.9.2] - 2025-11-17 68 69### Added 70 71**WASM compatibility improvements** (`jacquard-common`, `jacquard-identity`) 72- Vendored mini-moka implementation with WASM support for caching 73- regex-lite usage on WASM targets for reduced binary size 74- Schema resolver now works on WASM targets 75 76**Data query improvements** (`jacquard-common`) 77- Mutable path query access and setting for `Data` values 78 79### Changed 80 81**URL handling** (`jacquard-common`) 82- Rework of some internal URL handling for better compatibility 83- Includes a minor change to the return type of the endpoint() method of XrpcClient and equivalents. 84 85**OAuth improvements** (`jacquard-oauth`) 86- Fixed OAuth scope handling in loopback flow 87- OAuth metadata resolution improvements 88- Various OAuth flow enhancements and bug fixes 89 90**Identity resolution** (`jacquard-identity`) 91- Fixed non-DNS lexicon and did:web resolution using Cloudflare DoH 92- Reduced noisy logging in identity resolution 93 94**Lexicons** (`jacquard-api`) 95- Updated to latest AT Protocol lexicons 96 97### Fixed 98 99**Data deserialization** (`jacquard-common`) 100- Fixed CID deserialization edge cases for better spec compliance 101- More permissive JSON shape handling for better interoperability with varied implementations 102 103## [0.9.1] - 2025-11-04 (`jacquard-identity`, `jacquard-lexicon`) 104 105### Fixed 106 107- slingshot resolver no longer spuriously warns when cross-validating handles 108 109## [0.9.0] - 2025-11-03 110 111### Added 112 113**Runtime schema validation** (`jacquard-lexicon`) 114- `SchemaValidator` for validating `Data` values against lexicon schemas 115- CID-based validation caching for efficient repeated validation 116- `ValidationResult` with structural and constraint error separation 117- Comprehensive error types: `StructuralError` (type mismatches, missing fields, union errors) and `ConstraintError` (length, grapheme, numeric bounds) 118- `ValidationPath` for precise error location reporting 119- Ref cycle detection with configurable max depth 120- Support for validating partial/malformed data without full deserialization 121 122**Value query DSL** (`jacquard-common`) 123- Pattern-based querying of nested `Data` structures 124- `data.query(pattern)` with expressive syntax: 125 - `field.nested` - exact path navigation 126 - `[..]` - wildcard over collections (array elements or object values) 127 - `field..nested` - scoped recursion (find nested within field, expect one) 128 - `...field` - global recursion (find all occurrences anywhere) 129- `QueryResult` enum with `Single`, `Multiple`, and `None` variants 130- `QueryMatch` with path tracking for multiple results 131- Iterator support via `.values()`, `.first()`, `.single()`, `.multiple()` 132 133**Data value enhancements** (`jacquard-common`) 134- `get_at_path()` for simple path-based field access on `Data` and `RawData` 135- Path syntax: `embed.images[0].alt` for navigating nested structures 136- `type_discriminator()` helper methods for AT Protocol union discrimination 137- Returns `$type` field value for objects with type discriminators 138- Added on `Data`, `Object`, and `RawData` types 139- Collection helper methods: `get()`, `contains_key()`, `len()`, `is_empty()`, `iter()`, `keys()`, `values()` 140- Index operator support: `obj["key"]` and `arr[0]` 141 142**Lexicon resolution** (`jacquard-identity`) 143- `LexiconResolver` for fetching lexicon schemas from AT Protocol services 144- Resolves lexicons from PDS instances and lexicon hosts 145- `resolve_lexicon()` fetches and parses lexicon schemas 146- `resolve_lexicon_raw()` fetches raw schema JSON 147- New example: `resolve_lexicon.rs` 148 149**Identity resolver caching** (`jacquard-identity`) 150- Optional `cache` feature with configurable in-memory caching 151- `JacquardResolver::with_cache()` constructor for cached resolver 152- Separate TTLs for handle→DID, DID→doc, and lexicon resolution 153 154**XRPC client improvements** (`jacquard-common`, `jacquard`, `jacquard-oauth`) 155- `set_options()` and `set_endpoint()` methods on `XrpcClient` trait 156- Default no-op implementations for stateless clients 157- Enables runtime reconfiguration of stateful clients 158- Better support for custom endpoint and option overrides 159 160**Lexicon schema generation from Rust types** (`jacquard-derive`, `jacquard-lexicon`) 161- New `#[derive(LexiconSchema)]` macro for generating lexicon schemas from Rust structs 162- New `#[lexicon_union]` attribute macro for lexicon union types (tagged enums) 163- Automatic schema generation for custom lexicons without writing JSON manually 164- Field-level attributes: `ref` for explicit type references, `union` for union fields 165- Fragment support for multi-def lexicons via `fragment = "..."` attribute 166- Generates `LexiconDoc` at compile time for runtime validation 167- Enables type-safe custom lexicon development 168 169**Lexicon codegen improvements** (`jacquard-lexicon`, `jacquard-api`) 170- Vendored in an implementation of the typed builder pattern from `bon` to **substantially** improve compile times 171- Feature-gated heavy code generation features so `jacquard-api` and other consumers of the validation capabilities don't pay the `syn` tax as badly. 172- LexiconSchema trait generated implementations for runtime validation 173 174**Session store improvements** (`jacquard`) 175- Improved trait bounds for `SessionStore` implementations 176- Better ergonomics for credential session types 177- Memory-based credential session helpers 178 179**New crate: `jacquard-lexgen`** 180- Lexicon code generation tooling extracted from `jacquard-lexicon` 181- Separates binary/CLI tools from library code 182- Contains lexicon fetching and code generation binaries 183- `jacquard-lexicon` remains as pure library for lexicon parsing, code generation, and validation 184 185**Examples** 186- `app_password_create_post.rs`: App password authentication example 187 188### Changed 189 190**Feature gating** (`jacquard-identity`) 191- Better conditional compilation for platform-specific features 192- Improved WASM target support 193 194**Dependency updates** 195- Updated to latest lexicons from atproto/bluesky 196- Added workspace dependencies: sha2, multihash, dashmap, cid 197- Various minor dependency version updates 198 199### Fixed 200 201**File auth store** (`jacquard`) 202- Fixed serialization/deserialization bugs in `FileAuthStore` implementation 203 204**Packaging** (`jacquard-lexgen`) 205- Added Nix flake apps for lexicon tools 206 207## [0.8.0] - 2025-10-23 208 209### Breaking Changes 210 211**Error type refactor** (`jacquard-common`, `jacquard-identity`, `jacquard-oauth`, `jacquard`) 212- Better error messages with contextual information and help text 213- Breaking: Error variant names and structures changed across all crates 214 215### Added 216 217**New crate: `jacquard-repo`** 218- AT Protocol repository primitives for working with atproto data structures 219- **MST (Merkle Search Tree)**: Immutable, deterministic tree operations with proper fanout 220 - Optimized block allocation (4.5% oversupply, validated against retr0id's test suite) 221 - Diff operations with protocol limit enforcement 222 - Cursor-based traversal 223- **Commits**: 224 - Proof generation and validation for Sync v1 and v1.1 Relay protocol 225- **CAR I/O**: 226 - Proof CAR validation with MST path verification 227- **Storage**: Pluggable block storage abstraction 228 - `MemoryBlockStore`: In-memory storage for testing 229 - `FileBlockStore`: Persistent file-based storage 230 - `LayeredBlockStore`: Layered read-through cache (memory over file, etc.) 231 232### Changed 233 234- Dependency updates (upgraded various crypto and serialization dependencies) 235- Documentation improvements throughout 236- 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). 237 238## [0.7.0] - 2025-10-19 239 240### Added 241 242**Bluesky-style rich text utilities** (`jacquard`) 243- Rich text parsing with automatic facet detection (mentions, links, hashtags) 244- Compatible with Bluesky, with the addition of support for markdown-style links (`[display](url)` syntax) 245- Embed candidate detection from URLs and at-URIs 246 - Record embeds (posts, lists, starter packs, feeds) 247 - External embeds with optional OpenGraph metadata fetching 248- Configurable embed domains for at-URI extraction (default: bsky.app, deer.social, blacksky.community, catsky.social) 249- Overlap detection and validation for facet byte ranges 250 251**Moderation/labeling client utilities** (`jacquard`) 252- Trait-based content moderation with `Labeled` and `Moderateable` traits 253- Generic moderation decision making via `moderate()` and `moderate_all()` 254- User preference handling (`ModerationPrefs`) with global and per-labeler overrides 255- `ModerationIterExt` trait for filtering/mapping moderation over iterators 256- `Labeled` implementations for Bluesky types (PostView, ProfileView, ListView, Generator, Notification, etc.) 257- `Labeled` implementations for community lexicons (net.anisota, social.grain) 258- `fetch_labels()` and `fetch_labeled_record()` helpers for retrieving labels via XRPC 259- `fetch_labeler_defs()` and `fetch_labeler_defs_direct()` for fetching labeler definitions 260 261**Subscription control** (`jacquard-common`) 262- `SubscriptionControlMessage` trait for dynamic subscription configuration 263- `SubscriptionController` for sending control messages to active WebSocket subscriptions 264- Enables runtime reconfiguration of subscriptions (e.g., Jetstream filtering) 265 266**Lexicons** (`jacquard-api`) 267- teal.fm alpha lexicons for music sharing (fm.teal.alpha.*) 268 - Actor profiles with music service status 269 - Feed generation from play history 270 - Statistics endpoints (top artists, top releases, user stats) 271 272**Examples** 273- Updated `create_post.rs` to demonstrate richtext parsing with automatic facet detection 274- New `moderated_timeline.rs` to demonstrate fetching timeline with labelers enabled and applying moderation decisions 275 276### Fixed 277 278**Data deserialization** (`jacquard-common`) 279- Fixed `Option<Vec<T>>` deserialization from `Data` values 280- Implemented explicit `deserialize_option` for `Data` and `RawData` deserializers 281- Properly handles null vs present array values when deserializing into optional fields 282 283 284## [0.6.0] - 2025-10-18 285 286### Added 287 288**HTTP streaming support** (`jacquard-common`, `jacquard`) 289- `HttpClientExt` trait for streaming HTTP requests/responses 290- `send_http_streaming()` for streaming response bodies 291- `send_http_bidirectional()` for streaming both request and response 292- `StreamingResponse` wrapper type with parts + `ByteStream` 293- `XrpcResponseStream<R>` for typed XRPC streaming responses 294- `ByteStream` / `ByteSink` platform-agnostic stream wrappers (uses n0-future) 295- `StreamError` concrete error type with kind enum (Transport, Closed, Protocol) 296- Native support via reqwest's `bytes_stream()` and `Body::wrap_stream()` 297- WASM compatibility via n0-future (no Send bounds required) 298 299 300**WebSocket subscription support** (`jacquard-common`) 301- Full XRPC WebSocket subscription infrastructure 302- `SubscriptionResp` trait for defining subscription message/error types 303- `XrpcSubscription` trait for subscription parameters 304- `SubscriptionStream<S>` typed wrapper with automatic message decoding 305- `SubscriptionClient` stateful trait + `TungsteniteSubscriptionClient` implementation 306- `SubscriptionExt` for stateless subscription calls 307- Support for both JSON and DAG-CBOR message encodings 308- Custom path support via `CUSTOM_PATH` constant for non-XRPC endpoints 309- WebSocket integration into `Agent` struct (agents can now subscribe) 310- `into_stream()`, `into_raw_data_stream()`, `into_data_stream()` methods for different deserialization modes 311 312**Framed DAG-CBOR message decoding** (`jacquard-common`, `jacquard-api`, `jacquard-lexicon`) 313- Two-stage deserialization for AT Protocol event streams (header + body) 314- `EventHeader` struct and `parse_event_header()` function 315- `decode_framed()` methods generated for all DAG-CBOR subscription message enums 316- `decode_message()` override in `SubscriptionResp` trait for custom decoding 317- `UnknownEventType` variant in `DecodeError` for unknown discriminators 318- Fixes "TrailingData" errors when consuming subscribeRepos and subscribeLabels 319 320**Jetstream support** (`jacquard-common`) 321- Full typed support for Jetstream JSON firehose 322- `JetstreamMessage` enum with `Commit`, `Identity`, `Account` variants 323- `JetstreamCommit`, `JetstreamIdentity`, `JetstreamAccount` detail structs 324- `CommitOperation` enum for create/update/delete operations 325- `JetstreamParams` with filtering options (collections, DIDs, cursor, compression) 326- Uses proper AT Protocol types (`Did`, `Handle`, `Datetime`, `Data`) 327 328**Zstd compression** (`jacquard-common`) 329- Optional `zstd` feature for Jetstream message decompression 330- Automatic detection and decompression of zstd-compressed binary frames 331- Includes official Bluesky Jetstream zstd dictionary 332- Transparent fallback to uncompressed when zstd unavailable 333- Works across all JSON stream methods (`into_stream()`, `into_raw_data_stream()`, `into_data_stream()`) 334 335**Typed AT URI wrapper** (`jacquard-common`, `jacquard-api`, `jacquard-lexicon`) 336- `AtUri<'a>` newtype wrapper for `at://` URIs with proper validation 337- Generated `fetch_uri()` method on all record types for fetching by AT URI 338- `AtUri::from_parts()` constructor for building URIs from components 339- Proper Display and FromStr implementations 340 341**Memory-based credential session helpers** (`jacquard`) (ty [@vielle.dev](https://tangled.org/@vielle.dev)) 342 343**Axum improvements** (`jacquard-axum`) 344- `XrpcError` now implements `IntoResponse` for better error handling 345- Proper typed error responses without manual conversion 346- Better integration with Axum's response system 347 348**Examples** 349- `subscribe_repos.rs`: Subscribe to PDS firehose with typed DAG-CBOR messages 350- `subscribe_jetstream.rs`: Subscribe to Jetstream with typed JSON messages and optional compression 351- `stream_get_blob.rs`: Download blobs using HTTP streaming 352- `app_password_example.rs`: App password authentication example (ty [@vielle.dev](https://tangled.org/@vielle.dev)) 353 354**CID deserialization improvements** (`jacquard-common`) 355- Fixed `Cid` type to properly deserialize CBOR tag 42 via `IpldCid::deserialize` 356- Separate handling for JSON (string) vs CBOR (tag 42) formats 357- `CidLink` correctly delegates to `Cid` for both formats 358 359### Changed 360 361**Default features** (`jacquard-common`) 362- Added `zstd` to default features for better Jetstream experience 363- Jetstream compression enabled by default when using the full feature set 364 365**Generated code** (`jacquard-lexicon`, `jacquard-api`) 366- All DAG-CBOR subscriptions (subscribeRepos, subscribeLabels) now use framed decoding 367- Generated `decode_framed()` implementations match on event type discriminator 368- Override `decode_message()` in trait impls to use framed decoding 369- All record types now have `fetch_uri()` and `fetch_record()` methods generated 370 371**Dependencies** (`jacquard-axum`) (ty [@thoth.ptnote.dev](https://tangled.org/@thoth.ptnote.dev)) 372- Disabled default features for `jacquard` dependency to reduce bloat 373 374### Fixed 375 376**Blob upload** (`jacquard`) (ty [@vielle.dev](https://tangled.org/@vielle.dev) for reporting this one) 377- Fixed `upload_blob()` authentication issues 378- Properly authenticates while allowing custom Content-Type headers 379 380**XRPC client** (`jacquard-common`, `jacquard-oauth`, `jacquard`) 381- Added `send_with_options()` method for per-request option overrides 382- Stateful clients can now override options while preserving internal auth 383 384 385--- 386 387## `jacquard-api` [0.5.5], `jacquard-lexicon` [0.5.4] - 2025-10-16 388 389### Fixed 390 391- events.smokesignal.invokeWebhook lexicon now generates valid code 392- lexicon code generation now uses `Data` for blank objects, rather than naming and then failing to generate a struct 393 394## [0.5.4] - 2025-10-16 395 396### Added 397 398**Initial streaming client support** (`jacquard-common`) 399- First primitives for streamed requests and responses 400 401**`send_with_options()` method on XrpcClient** (`jacquard-common`, `jacquard-oauth`, `jacquard`) 402- allows setting custom options per request in stateful client 403- updated oauth and credential session clients to use it 404- implementations should generally override provided auth with own internal auth 405 406**Prelude providing common traits into scope** 407 408### Fixed 409 410**`AgentSessionExt::upload_blob()` failed to authenticate** (`jacquard`) 411- new `XrpcClient::send_with_options()` method now allows properly overriding the content-type header while still handling auth internally 412 413## [0.5.3] - 2025-10-15 414 415### Added 416 417**Experimental WASM Support** (`jacquard-common`, `jacquard-api`, `jacquard-identity`, `jacquard-oauth`) 418- Core crates now compile for `wasm32-unknown-unknown` target 419- Traits use `trait-variant` to conditionally exclude `Send` bounds on WASM 420- Platform-specific trait method implementations for methods with `Self: Sync` bounds 421- DNS-based handle resolution remains gated behind `dns` feature (unavailable on WASM) 422- HTTPS well-known and PDS resolution work on all platforms 423 424### Fixed 425 426**OAuth client** (`jacquard-oauth`) 427- Fixed tokio runtime detection for non-WASM targets 428- Conditional compilation for tokio-specific features 429 430 431--- 432 433## [0.5.2] - 2025-10-14 434 435### Added 436 437**Value type deserialization** (`jacquard-common`) 438- `from_json_value()`: Deserialize typed data directly from `serde_json::Value` without borrowing 439- `from_data_owned()`, `from_raw_data_owned()`: Owned deserialization helpers 440- `Data::from_json_owned()`: Parse JSON into owned `Data<'static>` 441- `IntoStatic` implementation for `RawData` enabling owned conversions 442- Re-exported value types from crate root for easier imports 443- `Deserializer` trait implementations for `Data<'static>` and `RawData<'static>` 444- Owned deserializer helpers: `OwnedArrayDeserializer`, `OwnedObjectDeserializer`, `OwnedBlobDeserializer` 445 446**Service Auth** (`jacquard-axum`, `jacquard-common`) 447- Full service authentication implementation for inter-service JWT verification 448- `ExtractServiceAuth` Axum extractor for validating service auth tokens 449- Axum service auth middleware 450- JWT parsing and signature verification (ES256, ES256K) 451- Service auth claims validation (issuer, audience, expiration, method binding) 452- DID document resolution for signing key verification 453 454**XrpcRequest derive macro** (`jacquard-derive`) 455- `#[derive(XrpcRequest)]` for custom XRPC endpoints 456- Automatically generates response marker struct and trait implementations 457- Supports both client-side (`XrpcRequest`) and server-side (`XrpcEndpoint`) with `server` flag 458- Simplifies defining custom XRPC endpoints outside of generated API 459 460**Builder integration** (`jacquard-derive`) 461- `#[lexicon]` macro now detects `bon::Builder` derive 462- Automatically adds `#[builder(default)]` to `extra_data` field when Builder is present 463- Makes `extra_data` optional in generated builders 464 465### Fixed 466 467**String deserialization** (`jacquard-common`) 468- All string types (Did, Handle, Nsid, etc.) now properly handle URL-encoded values 469- `serde_html_form` correctly decodes percent-encoded characters during deserialization 470- Fixes issues with DIDs and other identifiers containing colons in query parameters 471 472**Axum extractor** (`jacquard-axum`) 473- Removed unnecessary URL-decoding workaround (now handled by improved string deserialization) 474- Added comprehensive tests for URL-encoded query parameters 475- Cleaner implementation with proper delegation to serde 476 477### Changed 478 479**Dependencies** 480- Moved `clap` to dev-dependencies in `jacquard` (only used in examples) 481- Moved `axum-macros` and `tracing-subscriber` to dev-dependencies in `jacquard-axum` (only used in examples) 482- Removed unused dependencies: `urlencoding` (jacquard, jacquard-axum), `uuid` (jacquard-oauth), `serde_with` (jacquard-common) 483- Removed `fancy` feature from `jacquard` (design smell for library crates) 484- Moved various proc-macro crate dependencies to dev-dependencies in `jacquard-derive` 485 486**Development tooling** 487- Improved justfile with dynamic example discovery 488- `just examples` now auto-discovers all examples 489- `just example <name>` auto-detects package without manual configuration 490- Better error messages when examples not found 491 492**Documentation** (`jacquard`, `jacquard-common`) 493- Improved lifetime pattern explanations 494- Better documentation of zero-copy deserialization approach 495- Links to docs.rs for generated documentation 496 497--- 498 499## [0.5.1] - 2025-10-13 500 501### Fixed 502 503**Trait bounds** (`jacquard-common`) 504- Removed lifetime parameter from `XrpcRequest` trait, simplifying trait bounds 505- Lifetime now only appears on `XrpcEndpoint::Request<'de>` associated type 506- Fixes issues with using XRPC types in async contexts like Axum extractors 507 508### Changed 509 510- Updated all workspace crates to 0.5.1 for consistency 511- `jacquard-axum` remains at 0.5.1 (unchanged) 512 513--- 514 515## `jacquard-axum` [0.5.1] - 2025-10-13 516 517### Fixed 518 519- Axum extractor now sets the correct Content-Type header during error path. 520 521--- 522 523## [0.5.0] - 2025-10-13 524 525### Added 526 527**Agent convenience methods** (`jacquard`) 528- New `AgentSessionExt` trait automatically implemented for `AgentSession + IdentityResolver` 529- **Basic CRUD**: `create_record()`, `get_record()`, `put_record()`, `delete_record()` 530- **Update patterns**: `update_record()` (fetch-modify-put), `update_vec()`, `update_vec_item()` 531- **Blob operations**: `upload_blob()` 532- All methods auto-fill repo from session or URI parameter as relevant, and collection from type's `Collection::NSID` 533 534**VecUpdate trait** (`jacquard`) 535- `VecUpdate` trait for fetch-modify-put patterns on array-based endpoints 536- `PreferencesUpdate` implementation for updating Bluesky user preferences 537- Enables simpler updates to preferences and other 'array of union' types 538 539**Typed record retrieval** (`jacquard-api`, `jacquard-common`, `jacquard-lexicon`) 540- Each collection generates `{Type}Record` marker struct implementing `XrpcResp` 541- `Collection::Record` associated type points to the marker 542- `get_record::<R>()` returns `Response<R::Record>` with zero-copy `.parse()` 543- Response transmutation enables type-safe record operations 544 545**Examples** 546- `create_post.rs`: Creating posts with Agent convenience methods 547- `update_profile.rs`: Updating profile with fetch-modify-put 548- `post_with_image.rs`: Uploading images and creating posts with embeds 549- `update_preferences.rs`: Using VecUpdate for preferences 550- `create_whitewind_post.rs`, `read_whitewind_post.rs`: Third-party lexicons 551- `read_tangled_repo.rs`: Reading git repo metadata from tangled.org 552- `resolve_did.rs`: Identity resolution examples 553- `public_atproto_feed.rs`: Unauthenticated feed access 554- `axum_server.rs`: Server-side XRPC handler 555 556 557**Documentation** (`jacquard`) 558- A whole host of examples added, as well as a lengthy explainer of the trait patterns. 559 560## [0.4.1] - 2025-10-13 561 562### Added 563 564**Collection trait improvements** (`jacquard-api`) 565- Generated `{Type}Record` marker structs for all record types 566- Each implements `XrpcResp` with `Output<'de> = {Type}<'de>` and `Err<'de> = RecordError<'de>` 567- Enables typed `get_record` returning `Response<R::Record>` 568 569### Changed 570 571- Minor improvements to derive macros (`jacquard-derive`) 572- Identity resolution refinements (`jacquard-identity`) 573- OAuth client improvements (`jacquard-oauth`) 574 575--- 576 577## [0.4.0] - 2025-10-11 578 579### Breaking Changes 580 581**Zero-copy deserialization** (`jacquard-common`, `jacquard-api`) 582- `XrpcRequest` now takes a `'de` lifetime parameter and requires `Deserialize<'de>` 583- For raw data, `Response::parse_data()` gives validated loosely-typed atproto data, while `Response::parse_raw()` gives the raw values, with minimal validation. 584 585**XRPC module moved** (`jacquard-common`) 586- `xrpc.rs` is now top-level instead of under `types` 587- Import from `jacquard_common::xrpc::*` not `jacquard_common::types::xrpc::*` 588 589**Response API changes** (`jacquard-common`) 590- `XrpcRequest::Output` and `XrpcRequest::Err` are associated types with lifetimes 591- Split response and request traits: `XrpcRequest<'de>` for client, `XrpcEndpoint` for server 592- Added `XrpcResp` marker trait 593 594**Various traits** (`jacquard`, `jacquard-common`, `jacquard-lexicon`, `jacquard-oauth`) 595- Removed #[async_trait] attribute macro usage in favour of `impl Future` return types with manual bounds. 596- Boxing imposed by asyc_trait negatively affected borrowing modes in async methods. 597- Currently no semver guarantees on API trait bounds, if they need to tighten, they will. 598 599### Added 600 601**New crate: `jacquard-axum`** 602- Server-side XRPC handlers for Axum 603- `ExtractXrpc<R>` deserializes incoming requests (query params for Query, body for Procedure) 604- Automatic error responses 605 606**Lexicon codegen fixes** (`jacquard-lexicon`) 607- Union variant collision detection: when multiple namespaces have similar type names, foreign ones get prefixed (e.g., `Images` vs `BskyImages`) 608- Token types generate unit structs with `Display` instead of being skipped 609- Namespace dependency tracking during union generation 610- `generate_cargo_features()` outputs Cargo.toml features with correct deps 611- `sanitize_name()` ensures valid Rust identifiers 612 613**Lexicons** (`jacquard-api`) 614 615Added 646 lexicon schemas. Highlights: 616 617Core ATProto: 618- `com.atproto.*` 619- `com.bad-example.*` for identity resolution 620 621Bluesky: 622- `app.bsky.*` bluesky app 623- `chat.bsky.*` chat client 624- `tools.ozone.*` moderation 625 626Third-party: 627- `sh.tangled.*` - git forge 628- `sh.weaver.*` - orual's WIP markdown blog platform 629- `pub.leaflet.*` - longform publishing 630- `net.anisota.*` - gamified and calming take on bluesky 631- `network.slices.*` - serverless atproto hosting 632- `tools.smokesignal.*` - automation 633- `com.whtwnd.*` - markdown blogging 634- `place.stream.*` - livestreaming 635- `blue.2048.*` - 2048 game 636- `community.lexicon.*` - community extensions (bookmarks, calendar, location, payments) 637- `my.skylights.*` - media tracking 638- `social.psky.*` - social extensions 639- `blue.linkat.*` - link boards 640 641Plus 30+ more experimental/community namespaces. 642 643**Value types** (`jacquard-common`) 644- `RawData` to `Data` conversion with type inference 645- `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`. 646 647### Changed 648 649- `generate_union()` takes current NSID for dependency tracking 650- Generated code uses `sanitize_name()` for identifiers more consistently 651- Added derive macro for IntoStatic trait implementation 652 653### Fixed 654 655- Methods to extract the output from an XRPC response now behave well with respect to lifetimes and borrowing. 656- Now possible to use jacquard types in places like axum extractors due to lifetime improvements 657- Union variants don't collide when multiple namespaces define similar types and another namespace includes them 658 659---