A better Rust ATProto crate
0

Configure Feed

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

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