A better Rust ATProto crate
102
fork

Configure Feed

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

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