# Changelog

## [0.12.0] - 2026-06-013

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

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

**`jacquard-identity` no longer requires `reqwest`**
- JacquardResolver now parameterized on `C: HttpClient` with `PublicResolver` aliased to the default `reqwest`-backed version.


### Added

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

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

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

**Loopback OAuth** (`jacquard-oauth`)
- Replaced `rouille` dependency with a lightweight raw TCP listener for the localhost callback server.
- Improved the OAuth callback success page with proper HTML.

**Client** (`jacquard`)
- Added concrete app-password session helpers: `CredentialSessionSelector`, `resume_or_login`, `login_with_hint`, `restore`, `switch_session`, `logout`.
- Added `AtpSession::merge_refresh` and `AtpSession::pds_from_data` helpers.

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



### Changed

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

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

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

### Fixed

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

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

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

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


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


## [0.12.0-beta.1] - 2026-03-23

### Breaking changes

**Borrow-or-share (BOS) type system** (all crates)
- All validated string types (`Did`, `Handle`, `Nsid`, `Rkey`, `AtUri`, `AtIdentifier`, `MimeType`, `Cid`, `CidLink`, `Blob`, `BlobRef`, `Data`, `Array`, `Object`, `DidDocument`, `RecordUri`, `UriValue`, `RepoPath`) are now parameterised on `S: BosStr = DefaultStr` instead of lifetimes
- `DefaultStr = SmolStr`: owned, inline ≤23 bytes, `DeserializeOwned`
- `&str`, `CowStr<'a>`, `String` all work as backing types via the `BosStr` trait
- `SmolStr`-backed types satisfy `DeserializeOwned`, enabling use in async contexts, collections, and across thread boundaries without `IntoStatic` conversion
- New `.borrow()` method on `Did`, `Handle`, `Nsid`, `Rkey`, `RecordKey` returns `Type<&str>` for cheap borrowing (analogous to `Uri::borrow()`)
- New `.convert::<B>()` method for cross-backing-type conversion

**XRPC trait changes** (`jacquard-common`)
- `XrpcResp::Output<S: BosStr>`: GAT parameterised on backing type S, not lifetime
- `XrpcResp::Err`: plain associated type, always `SmolStr`-backed and `DeserializeOwned`
- `XrpcRequest` now requires `Serialize` bound
- `XrpcEndpoint::Request<S: BosStr>`: GAT for server-side extraction
- `SubscriptionResp::Message<S: BosStr>`, `SubscriptionEndpoint::Params<S: BosStr>`: updated GATs
- `XrpcProcedureStream::Frame<S: BosStr>`, `XrpcStreamResp::Frame<S: BosStr>`: streaming frame GATs updated

**Response parsing** (`jacquard-common`)
- `Response::parse::<S>()`: caller chooses backing type via turbofish
- `Response::into_output()`: returns `SmolStr`-backed owned types via `DeserializeOwned`
- Zero-copy: `response.parse::<CowStr<'_>>()`; owned: `response.into_output()`

**Generated API types** (`jacquard-api`, `jacquard-lexicon`)
- All generated structs/enums: `Foo<S: BosStr = DefaultStr>` with `#[serde(bound(deserialize = "S: Deserialize<'de> + BosStr"))]`
- `#[serde(borrow)]` removed from all generated code
- String field defaults use `FromStaticStr::from_static()` for zero-alloc construction
- Error enums: `SmolStr` message fields, no lifetime parameters
- Type aliases: `<S = DefaultStr>` (no bounds, per rust type checker limitation)

**OAuth types** (`jacquard-oauth`)
- All session, metadata, token, scope, and JWT types parameterised on `S: BosStr = DefaultStr`
- `OAuthMetadata<S>` parameterised so callers can borrow from stored metadata
- `DpopDataSource` trait methods return `Option<&str>` (was `Option<CowStr<'_>>`)
- DPoP proof building uses `&str` for zero-copy JWT construction
- `build_dpop_proof` takes `&str` parameters, returns `SmolStr`

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

**Identity resolution** (`jacquard-identity`)
- `IdentityResolver::resolve_handle<S: BosStr + Sync>(&self, handle: &Handle<S>)`: generic over handle backing type
- `IdentityResolver::resolve_did_doc<S: BosStr + Sync>(&self, did: &Did<S>)`: generic over DID backing type

**Repository types** (`jacquard-repo`)
- `Commit<S: BosStr = DefaultStr>`, `UnsignedCommit<S>`, `RecordClaim<S>`, `VerifyProofsOutput<S>` parameterised on S
- `RecordWriteOp` now parameterised on both S (for string fields) and BS (for BlockStore)
- `RawData<'a>` intentionally remains lifetime-based

**Derive macros** (`jacquard-derive`)
- `#[lexicon]` detects type param S, emits `Data<S>` for `extra_data`
- `#[open_union]` detects type param S, emits `Unknown(Data<S>)`
- `#[derive(IntoStatic)]` handles S-parameterised types
- `#[derive(XrpcRequest)]` generates new `Output<S: BosStr>` and `Err` (not GAT) impls

**Client types** (`jacquard`)
- `AtpSession` fields `access_jwt`/`refresh_jwt` are now `SmolStr` (was `CowStr<'static>`)
- `SessionKey` uses `Did` and `SmolStr` (was `Did<'static>` and `CowStr<'static>`)
- `AgentSessionExt` record methods (`get_record`, `update_record`, etc.) take `AtUri<S>` / `RecordUri<S, R>` with generic S
- Moderation types (`ModerationPrefs`, `LabelerDefs`, `Labeled` trait, etc.) parameterised on S

### Removed

- `jacquard-axum` temporarily removed from workspace (extractor needs redesign for BOS type params)

### Changed

**Codegen** (`jacquard-lexicon`)
- Generated `XrpcResp` impls emit `Output<S: BosStr>` and `Err` (plain type, not GAT)
- Generated `XrpcEndpoint` impls emit `Request<S: BosStr>`

## [0.11.0] - 2026-03-21

### Breaking changes

**Code generation pipeline overhaul** (`jacquard-lexicon`, `jacquard-lexgen`)
- Jacquard's codegen output already was nice to *use*. now it's going to be nice to read.
- New code generation tracks the types used, makes an import block for the file, and then organizes the file with stuff you care about at the top and internal stuff, like the builders, at the bottom.
- Import resolution pass now conditionally generates short paths when types are unambiguous within a module, falling back to fully-qualified paths when collisions exist
- Improved default value handling in generated code, reducing unnecessary boilerplate

### Added

**Hand-written XRPC bootstrap types** (`jacquard-common`)
- Added minimal XRPC endpoint types for `com.atproto.repo.listRecords`, `com.atproto.repo.getRecord`, `com.atproto.identity.resolveHandle`, and `com.atproto.identity.resolveDid`
- These types break circular dependencies between `jacquard-lexgen`/`jacquard-identity` and `jacquard-api`, allowing the codegen tooling and identity resolver to function without depending on the generated API crate

### Changed

**Regenerated API crate** (`jacquard-api`)
- All generated code regenerated with the new codegen pipeline
- Shorter import paths where unambiguous, cleaner builder output, better formatting throughout

## [0.10.1] - 2026-03-20

### Fixed

**CID deserialization** (`jacquard-common`)
- Fixed `CidLink` deserialization from CBOR tag-42 bytes through internally-tagged enums (reported by @natalie.sh, fixed by adorable robot)
- `serde_ipld_dagcbor` buffers tag-42 CIDs as a newtype struct wrapping raw bytes when deserializing through `Content`; the visitor now handles `visit_bytes`, `visit_byte_buf`, and `visit_newtype_struct` to cover this path

**Lexicon code generation** (`jacquard-lexicon`, `jacquard-api`)
- Fixed `BlobRef` generation producing incorrect code in certain lexicon schemas

**Identity resolution** (`jacquard-identity`)
- Error message when handle resolution exhausts all resolution methods no longer misleading

## [0.10.0] - 2026-03-20

### Breaking changes

**URL type migration** (`jacquard-common`, `jacquard`, `jacquard-oauth`, `jacquard-identity`, `jacquard-api`)
- Migrated from `url` crate to `fluent_uri` for validated URL/URI types
- All `Url` types are now `Uri` from `fluent_uri`
- Affects any code that constructs, passes, or pattern-matches on endpoint URLs

**Re-exported crate paths** (`jacquard-api`, `jacquard-common`)
- Re-exported crates (including non-proc-macro dependencies of the generated API crate) are now centralized into a distinct module
- Import paths for re-exported types have changed as a result

### Added

**`no_std` groundwork** (`jacquard-common`, `jacquard-api`)
- Initial steps toward `no_std` support for core types
- `jacquard-api` gains feature gating for `std`/`no_std` usage

**Datetime improvements** (`jacquard-common`)
- [PR from @blyoom.dev](https://tangled.org/nonbinary.computer/jacquard/pulls/6/) exposing timestamps directly on `Datetime` type
- Naming aligned with `chrono` conventions

**Handle normalization** (`jacquard-common`)
- Handles are now lowercase-normalized on construction

**Embedded PDS primitives** (`jacquard-repo`)
- Initial lazy disk-spilling collection types for embedded PDS use cases
- Repo firehose types now use generated API types instead of hand-written equivalents

**Lexicon codegen improvements** (`jacquard-lexicon`, `jacquard-api`)
- `knownValues` generation now aligned with AT Protocol spec and triggers more frequently
- Improved feature dependency tracking for API crate features

**Additional signing algorithms** (`jacquard-oauth`)
- Keyset signing now supports ES384 (P-384), ES256K (secp256k1), and EdDSA (Ed25519) in addition to ES256
- `Keyset::create_jwt` now accepts `&[Signing]` (from `jose_jwa`) instead of string-based algorithm names

**Documentation** (`jacquard-oauth`, `jacquard-identity`)
- Doc comments across all public items in both crates (thanks Claude, but I played editor pretty heavily)

### Fixed

**Identity resolution** (`jacquard-identity`)
- [PR from @alephcubed.com](https://tangled.org/nonbinary.computer/jacquard/pulls/7/) fixing `DidDocument::handles()` always failing when parsed from `MiniDoc`

**Error handling** (`jacquard-common`, `jacquard`, `jacquard-oauth`)
- Big error quality-of-life pass with richer, more actionable diagnostics
- More resilient error parsing for auth errors
- Better lexicon parsing error messages

**WASM** (`jacquard-common`)
- Fixed WASM CI smoke test compilation

### Changed

**Lexicons** (`jacquard-api`)
- Large batch of lexicon schema updates with manual cleanup

## [0.9.6] - 2025-12-19

### Changed

**Logging** (`jacquard`, `jacquard-axum`)
- [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

### Fixed

**Repo commit signatures** (`jacquard-repo`)
- commit signatures generated by `jacquard-repo` should now be consistent with other implementations
- previously, they included an empty `sig` bytes field in the signed struct, which has a different CBOR serialization from the canonical relay implementation expectations.

## [0.9.5] - 2025-12-19

### Fixed

**docs.rs configuration**
- Fixed typo in `jacquard-common` docs.rs features (`crypto-ed22519` → `crypto-ed25519`) that was causing documentation builds to fail
- Moved `loopback` feature documentation to `jacquard-oauth` where the feature is defined

**OAuth flow** (`jacquard-oauth`)
- Minor OAuth flow compatibility improvements

**Serialization** (`jacquard-common`, `jacquard-identity`)
- Fixed CID deserialization edge cases in `Data` and `RawData` types
- Fixed DID document serialization when optional fields are absent

**Lexicon code generation** (`jacquard-lexicon`, `jacquard-api`)
- Fixed nullable field handling in generated code
- Fixed lifetime handling in codegen of binary xrpc outputs
- Fixed lifetime handling in unions
- Fixed incorrectly unescaped rust keywords in module paths

**Observability** (`jacquard`)
- Fixed tracing span issues associated with some build failures

### Added

**mini-moka-wasm** (`mini-moka-wasm`, `jacquard-identity`)
- Publishing vendored version of mini-moka with wasm browser compat fix to make usage easier

**Service authentication** (`jacquard-axum`)
- Optional service auth extractor option

**Data handling** (`jacquard-common`)
- Serde bytes helpers for JSON fields
- Made PLC source fields public for library consumers

**Lexicons** (`jacquard-api`)
- Updated to latest AT Protocol lexicon schemas
- API regeneration with builder fixes

### Changed

**Logging** (`jacquard`)
- Improved client error logging with better context

## [0.9.3] - 2025-11-17 (`jacquard`)

### Fixed

- SessionKey is now a proper tuple struct and not a type alias, which should help rustc not freak out when you do things like put MemoryCredentialSession in an Arc

## [0.9.2] - 2025-11-17

### Added

**WASM compatibility improvements** (`jacquard-common`, `jacquard-identity`)
- Vendored mini-moka implementation with WASM support for caching
- regex-lite usage on WASM targets for reduced binary size
- Schema resolver now works on WASM targets

**Data query improvements** (`jacquard-common`)
- Mutable path query access and setting for `Data` values

### Changed

**URL handling** (`jacquard-common`)
- Rework of some internal URL handling for better compatibility
- Includes a minor change to the return type of the endpoint() method of XrpcClient and equivalents.

**OAuth improvements** (`jacquard-oauth`)
- Fixed OAuth scope handling in loopback flow
- OAuth metadata resolution improvements
- Various OAuth flow enhancements and bug fixes

**Identity resolution** (`jacquard-identity`)
- Fixed non-DNS lexicon and did:web resolution using Cloudflare DoH
- Reduced noisy logging in identity resolution

**Lexicons** (`jacquard-api`)
- Updated to latest AT Protocol lexicons

### Fixed

**Data deserialization** (`jacquard-common`)
- Fixed CID deserialization edge cases for better spec compliance
- More permissive JSON shape handling for better interoperability with varied implementations

## [0.9.1] - 2025-11-04 (`jacquard-identity`, `jacquard-lexicon`)

### Fixed

- slingshot resolver no longer spuriously warns when cross-validating handles

## [0.9.0] - 2025-11-03

### Added

**Runtime schema validation** (`jacquard-lexicon`)
- `SchemaValidator` for validating `Data` values against lexicon schemas
- CID-based validation caching for efficient repeated validation
- `ValidationResult` with structural and constraint error separation
- Comprehensive error types: `StructuralError` (type mismatches, missing fields, union errors) and `ConstraintError` (length, grapheme, numeric bounds)
- `ValidationPath` for precise error location reporting
- Ref cycle detection with configurable max depth
- Support for validating partial/malformed data without full deserialization

**Value query DSL** (`jacquard-common`)
- Pattern-based querying of nested `Data` structures
- `data.query(pattern)` with expressive syntax:
  - `field.nested` - exact path navigation
  - `[..]` - wildcard over collections (array elements or object values)
  - `field..nested` - scoped recursion (find nested within field, expect one)
  - `...field` - global recursion (find all occurrences anywhere)
- `QueryResult` enum with `Single`, `Multiple`, and `None` variants
- `QueryMatch` with path tracking for multiple results
- Iterator support via `.values()`, `.first()`, `.single()`, `.multiple()`

**Data value enhancements** (`jacquard-common`)
- `get_at_path()` for simple path-based field access on `Data` and `RawData`
- Path syntax: `embed.images[0].alt` for navigating nested structures
- `type_discriminator()` helper methods for AT Protocol union discrimination
- Returns `$type` field value for objects with type discriminators
- Added on `Data`, `Object`, and `RawData` types
- Collection helper methods: `get()`, `contains_key()`, `len()`, `is_empty()`, `iter()`, `keys()`, `values()`
- Index operator support: `obj["key"]` and `arr[0]`

**Lexicon resolution** (`jacquard-identity`)
- `LexiconResolver` for fetching lexicon schemas from AT Protocol services
- Resolves lexicons from PDS instances and lexicon hosts
- `resolve_lexicon()` fetches and parses lexicon schemas
- `resolve_lexicon_raw()` fetches raw schema JSON
- New example: `resolve_lexicon.rs`

**Identity resolver caching** (`jacquard-identity`)
- Optional `cache` feature with configurable in-memory caching
- `JacquardResolver::with_cache()` constructor for cached resolver
- Separate TTLs for handle→DID, DID→doc, and lexicon resolution

**XRPC client improvements** (`jacquard-common`, `jacquard`, `jacquard-oauth`)
- `set_options()` and `set_endpoint()` methods on `XrpcClient` trait
- Default no-op implementations for stateless clients
- Enables runtime reconfiguration of stateful clients
- Better support for custom endpoint and option overrides

**Lexicon schema generation from Rust types** (`jacquard-derive`, `jacquard-lexicon`)
- New `#[derive(LexiconSchema)]` macro for generating lexicon schemas from Rust structs
- New `#[lexicon_union]` attribute macro for lexicon union types (tagged enums)
- Automatic schema generation for custom lexicons without writing JSON manually
- Field-level attributes: `ref` for explicit type references, `union` for union fields
- Fragment support for multi-def lexicons via `fragment = "..."` attribute
- Generates `LexiconDoc` at compile time for runtime validation
- Enables type-safe custom lexicon development

**Lexicon codegen improvements** (`jacquard-lexicon`, `jacquard-api`)
- Vendored in an implementation of the typed builder pattern from `bon` to **substantially** improve compile times
- Feature-gated heavy code generation features so `jacquard-api` and other consumers of the validation capabilities don't pay the `syn` tax as badly.
- LexiconSchema trait generated implementations for runtime validation

**Session store improvements** (`jacquard`)
- Improved trait bounds for `SessionStore` implementations
- Better ergonomics for credential session types
- Memory-based credential session helpers

**New crate: `jacquard-lexgen`**
- Lexicon code generation tooling extracted from `jacquard-lexicon`
- Separates binary/CLI tools from library code
- Contains lexicon fetching and code generation binaries
- `jacquard-lexicon` remains as pure library for lexicon parsing, code generation, and validation

**Examples**
- `app_password_create_post.rs`: App password authentication example

### Changed

**Feature gating** (`jacquard-identity`)
- Better conditional compilation for platform-specific features
- Improved WASM target support

**Dependency updates**
- Updated to latest lexicons from atproto/bluesky
- Added workspace dependencies: sha2, multihash, dashmap, cid
- Various minor dependency version updates

### Fixed

**File auth store** (`jacquard`)
- Fixed serialization/deserialization bugs in `FileAuthStore` implementation

**Packaging** (`jacquard-lexgen`)
- Added Nix flake apps for lexicon tools

## [0.8.0] - 2025-10-23

### Breaking Changes

**Error type refactor** (`jacquard-common`, `jacquard-identity`, `jacquard-oauth`, `jacquard`)
- Better error messages with contextual information and help text
- Breaking: Error variant names and structures changed across all crates

### Added

**New crate: `jacquard-repo`**
- AT Protocol repository primitives for working with atproto data structures
- **MST (Merkle Search Tree)**: Immutable, deterministic tree operations with proper fanout
  - Optimized block allocation (4.5% oversupply, validated against retr0id's test suite)
  - Diff operations with protocol limit enforcement
  - Cursor-based traversal
- **Commits**:
  - Proof generation and validation for Sync v1 and v1.1 Relay protocol
- **CAR I/O**:
  - Proof CAR validation with MST path verification
- **Storage**: Pluggable block storage abstraction
  - `MemoryBlockStore`: In-memory storage for testing
  - `FileBlockStore`: Persistent file-based storage
  - `LayeredBlockStore`: Layered read-through cache (memory over file, etc.)

### Changed

- Dependency updates (upgraded various crypto and serialization dependencies)
- Documentation improvements throughout
- Made handle parsing a bit more permissive for a common case ('handle.invalid' when someone has a messed up handle), added a method to confirm syntactic validity (the correct way to confirm validity is resolve_handle() from IdentityResolver, and comparing to the DID document).

## [0.7.0] - 2025-10-19

### Added

**Bluesky-style rich text utilities** (`jacquard`)
- Rich text parsing with automatic facet detection (mentions, links, hashtags)
- Compatible with Bluesky, with the addition of support for markdown-style links (`[display](url)` syntax)
- Embed candidate detection from URLs and at-URIs
  - Record embeds (posts, lists, starter packs, feeds)
  - External embeds with optional OpenGraph metadata fetching
- Configurable embed domains for at-URI extraction (default: bsky.app, deer.social, blacksky.community, catsky.social)
- Overlap detection and validation for facet byte ranges

**Moderation/labeling client utilities** (`jacquard`)
- Trait-based content moderation with `Labeled` and `Moderateable` traits
- Generic moderation decision making via `moderate()` and `moderate_all()`
- User preference handling (`ModerationPrefs`) with global and per-labeler overrides
- `ModerationIterExt` trait for filtering/mapping moderation over iterators
- `Labeled` implementations for Bluesky types (PostView, ProfileView, ListView, Generator, Notification, etc.)
- `Labeled` implementations for community lexicons (net.anisota, social.grain)
- `fetch_labels()` and `fetch_labeled_record()` helpers for retrieving labels via XRPC
- `fetch_labeler_defs()` and `fetch_labeler_defs_direct()` for fetching labeler definitions

**Subscription control** (`jacquard-common`)
- `SubscriptionControlMessage` trait for dynamic subscription configuration
- `SubscriptionController` for sending control messages to active WebSocket subscriptions
- Enables runtime reconfiguration of subscriptions (e.g., Jetstream filtering)

**Lexicons** (`jacquard-api`)
- teal.fm alpha lexicons for music sharing (fm.teal.alpha.*)
  - Actor profiles with music service status
  - Feed generation from play history
  - Statistics endpoints (top artists, top releases, user stats)

**Examples**
- Updated `create_post.rs` to demonstrate richtext parsing with automatic facet detection
- New `moderated_timeline.rs` to demonstrate fetching timeline with labelers enabled and applying moderation decisions

### Fixed

**Data deserialization** (`jacquard-common`)
- Fixed `Option<Vec<T>>` deserialization from `Data` values
- Implemented explicit `deserialize_option` for `Data` and `RawData` deserializers
- Properly handles null vs present array values when deserializing into optional fields


## [0.6.0] - 2025-10-18

### Added

**HTTP streaming support** (`jacquard-common`, `jacquard`)
- `HttpClientExt` trait for streaming HTTP requests/responses
- `send_http_streaming()` for streaming response bodies
- `send_http_bidirectional()` for streaming both request and response
- `StreamingResponse` wrapper type with parts + `ByteStream`
- `XrpcResponseStream<R>` for typed XRPC streaming responses
- `ByteStream` / `ByteSink` platform-agnostic stream wrappers (uses n0-future)
- `StreamError` concrete error type with kind enum (Transport, Closed, Protocol)
- Native support via reqwest's `bytes_stream()` and `Body::wrap_stream()`
- WASM compatibility via n0-future (no Send bounds required)


**WebSocket subscription support** (`jacquard-common`)
- Full XRPC WebSocket subscription infrastructure
- `SubscriptionResp` trait for defining subscription message/error types
- `XrpcSubscription` trait for subscription parameters
- `SubscriptionStream<S>` typed wrapper with automatic message decoding
- `SubscriptionClient` stateful trait + `TungsteniteSubscriptionClient` implementation
- `SubscriptionExt` for stateless subscription calls
- Support for both JSON and DAG-CBOR message encodings
- Custom path support via `CUSTOM_PATH` constant for non-XRPC endpoints
- WebSocket integration into `Agent` struct (agents can now subscribe)
- `into_stream()`, `into_raw_data_stream()`, `into_data_stream()` methods for different deserialization modes

**Framed DAG-CBOR message decoding** (`jacquard-common`, `jacquard-api`, `jacquard-lexicon`)
- Two-stage deserialization for AT Protocol event streams (header + body)
- `EventHeader` struct and `parse_event_header()` function
- `decode_framed()` methods generated for all DAG-CBOR subscription message enums
- `decode_message()` override in `SubscriptionResp` trait for custom decoding
- `UnknownEventType` variant in `DecodeError` for unknown discriminators
- Fixes "TrailingData" errors when consuming subscribeRepos and subscribeLabels

**Jetstream support** (`jacquard-common`)
- Full typed support for Jetstream JSON firehose
- `JetstreamMessage` enum with `Commit`, `Identity`, `Account` variants
- `JetstreamCommit`, `JetstreamIdentity`, `JetstreamAccount` detail structs
- `CommitOperation` enum for create/update/delete operations
- `JetstreamParams` with filtering options (collections, DIDs, cursor, compression)
- Uses proper AT Protocol types (`Did`, `Handle`, `Datetime`, `Data`)

**Zstd compression** (`jacquard-common`)
- Optional `zstd` feature for Jetstream message decompression
- Automatic detection and decompression of zstd-compressed binary frames
- Includes official Bluesky Jetstream zstd dictionary
- Transparent fallback to uncompressed when zstd unavailable
- Works across all JSON stream methods (`into_stream()`, `into_raw_data_stream()`, `into_data_stream()`)

**Typed AT URI wrapper** (`jacquard-common`, `jacquard-api`, `jacquard-lexicon`)
- `AtUri<'a>` newtype wrapper for `at://` URIs with proper validation
- Generated `fetch_uri()` method on all record types for fetching by AT URI
- `AtUri::from_parts()` constructor for building URIs from components
- Proper Display and FromStr implementations

**Memory-based credential session helpers** (`jacquard`) (ty [@vielle.dev](https://tangled.org/@vielle.dev))

**Axum improvements** (`jacquard-axum`)
- `XrpcError` now implements `IntoResponse` for better error handling
- Proper typed error responses without manual conversion
- Better integration with Axum's response system

**Examples**
- `subscribe_repos.rs`: Subscribe to PDS firehose with typed DAG-CBOR messages
- `subscribe_jetstream.rs`: Subscribe to Jetstream with typed JSON messages and optional compression
- `stream_get_blob.rs`: Download blobs using HTTP streaming
- `app_password_example.rs`: App password authentication example (ty [@vielle.dev](https://tangled.org/@vielle.dev))

**CID deserialization improvements** (`jacquard-common`)
- Fixed `Cid` type to properly deserialize CBOR tag 42 via `IpldCid::deserialize`
- Separate handling for JSON (string) vs CBOR (tag 42) formats
- `CidLink` correctly delegates to `Cid` for both formats

### Changed

**Default features** (`jacquard-common`)
- Added `zstd` to default features for better Jetstream experience
- Jetstream compression enabled by default when using the full feature set

**Generated code** (`jacquard-lexicon`, `jacquard-api`)
- All DAG-CBOR subscriptions (subscribeRepos, subscribeLabels) now use framed decoding
- Generated `decode_framed()` implementations match on event type discriminator
- Override `decode_message()` in trait impls to use framed decoding
- All record types now have `fetch_uri()` and `fetch_record()` methods generated

**Dependencies** (`jacquard-axum`) (ty [@thoth.ptnote.dev](https://tangled.org/@thoth.ptnote.dev))
- Disabled default features for `jacquard` dependency to reduce bloat

### Fixed

**Blob upload** (`jacquard`) (ty [@vielle.dev](https://tangled.org/@vielle.dev) for reporting this one)
- Fixed `upload_blob()` authentication issues
- Properly authenticates while allowing custom Content-Type headers

**XRPC client** (`jacquard-common`, `jacquard-oauth`, `jacquard`)
- Added `send_with_options()` method for per-request option overrides
- Stateful clients can now override options while preserving internal auth


---

## `jacquard-api` [0.5.5], `jacquard-lexicon` [0.5.4] - 2025-10-16

### Fixed

- events.smokesignal.invokeWebhook lexicon now generates valid code
- lexicon code generation now uses `Data` for blank objects, rather than naming and then failing to generate a struct

## [0.5.4] - 2025-10-16

### Added

**Initial streaming client support** (`jacquard-common`)
- First primitives for streamed requests and responses

**`send_with_options()` method on XrpcClient** (`jacquard-common`, `jacquard-oauth`, `jacquard`)
- allows setting custom options per request in stateful client
- updated oauth and credential session clients to use it
- implementations should generally override provided auth with own internal auth

**Prelude providing common traits into scope**

### Fixed

**`AgentSessionExt::upload_blob()` failed to authenticate** (`jacquard`)
- new `XrpcClient::send_with_options()` method now allows properly overriding the content-type header while still handling auth internally

## [0.5.3] - 2025-10-15

### Added

**Experimental WASM Support** (`jacquard-common`, `jacquard-api`, `jacquard-identity`, `jacquard-oauth`)
- Core crates now compile for `wasm32-unknown-unknown` target
- Traits use `trait-variant` to conditionally exclude `Send` bounds on WASM
- Platform-specific trait method implementations for methods with `Self: Sync` bounds
- DNS-based handle resolution remains gated behind `dns` feature (unavailable on WASM)
- HTTPS well-known and PDS resolution work on all platforms

### Fixed

**OAuth client** (`jacquard-oauth`)
- Fixed tokio runtime detection for non-WASM targets
- Conditional compilation for tokio-specific features


---

## [0.5.2] - 2025-10-14

### Added

**Value type deserialization** (`jacquard-common`)
- `from_json_value()`: Deserialize typed data directly from `serde_json::Value` without borrowing
- `from_data_owned()`, `from_raw_data_owned()`: Owned deserialization helpers
- `Data::from_json_owned()`: Parse JSON into owned `Data<'static>`
- `IntoStatic` implementation for `RawData` enabling owned conversions
- Re-exported value types from crate root for easier imports
- `Deserializer` trait implementations for `Data<'static>` and `RawData<'static>`
- Owned deserializer helpers: `OwnedArrayDeserializer`, `OwnedObjectDeserializer`, `OwnedBlobDeserializer`

**Service Auth** (`jacquard-axum`, `jacquard-common`)
- Full service authentication implementation for inter-service JWT verification
- `ExtractServiceAuth` Axum extractor for validating service auth tokens
- Axum service auth middleware
- JWT parsing and signature verification (ES256, ES256K)
- Service auth claims validation (issuer, audience, expiration, method binding)
- DID document resolution for signing key verification

**XrpcRequest derive macro** (`jacquard-derive`)
- `#[derive(XrpcRequest)]` for custom XRPC endpoints
- Automatically generates response marker struct and trait implementations
- Supports both client-side (`XrpcRequest`) and server-side (`XrpcEndpoint`) with `server` flag
- Simplifies defining custom XRPC endpoints outside of generated API

**Builder integration** (`jacquard-derive`)
- `#[lexicon]` macro now detects `bon::Builder` derive
- Automatically adds `#[builder(default)]` to `extra_data` field when Builder is present
- Makes `extra_data` optional in generated builders

### Fixed

**String deserialization** (`jacquard-common`)
- All string types (Did, Handle, Nsid, etc.) now properly handle URL-encoded values
- `serde_html_form` correctly decodes percent-encoded characters during deserialization
- Fixes issues with DIDs and other identifiers containing colons in query parameters

**Axum extractor** (`jacquard-axum`)
- Removed unnecessary URL-decoding workaround (now handled by improved string deserialization)
- Added comprehensive tests for URL-encoded query parameters
- Cleaner implementation with proper delegation to serde

### Changed

**Dependencies**
- Moved `clap` to dev-dependencies in `jacquard` (only used in examples)
- Moved `axum-macros` and `tracing-subscriber` to dev-dependencies in `jacquard-axum` (only used in examples)
- Removed unused dependencies: `urlencoding` (jacquard, jacquard-axum), `uuid` (jacquard-oauth), `serde_with` (jacquard-common)
- Removed `fancy` feature from `jacquard` (design smell for library crates)
- Moved various proc-macro crate dependencies to dev-dependencies in `jacquard-derive`

**Development tooling**
- Improved justfile with dynamic example discovery
- `just examples` now auto-discovers all examples
- `just example <name>` auto-detects package without manual configuration
- Better error messages when examples not found

**Documentation** (`jacquard`, `jacquard-common`)
- Improved lifetime pattern explanations
- Better documentation of zero-copy deserialization approach
- Links to docs.rs for generated documentation

---

## [0.5.1] - 2025-10-13

### Fixed

**Trait bounds** (`jacquard-common`)
- Removed lifetime parameter from `XrpcRequest` trait, simplifying trait bounds
- Lifetime now only appears on `XrpcEndpoint::Request<'de>` associated type
- Fixes issues with using XRPC types in async contexts like Axum extractors

### Changed

- Updated all workspace crates to 0.5.1 for consistency
- `jacquard-axum` remains at 0.5.1 (unchanged)

---

## `jacquard-axum` [0.5.1] - 2025-10-13

### Fixed

- Axum extractor now sets the correct Content-Type header during error path.

---

## [0.5.0] - 2025-10-13

### Added

**Agent convenience methods** (`jacquard`)
- New `AgentSessionExt` trait automatically implemented for `AgentSession + IdentityResolver`
- **Basic CRUD**: `create_record()`, `get_record()`, `put_record()`, `delete_record()`
- **Update patterns**: `update_record()` (fetch-modify-put), `update_vec()`, `update_vec_item()`
- **Blob operations**: `upload_blob()`
- All methods auto-fill repo from session or URI parameter as relevant, and collection from type's `Collection::NSID`

**VecUpdate trait** (`jacquard`)
- `VecUpdate` trait for fetch-modify-put patterns on array-based endpoints
- `PreferencesUpdate` implementation for updating Bluesky user preferences
- Enables simpler updates to preferences and other 'array of union' types

**Typed record retrieval** (`jacquard-api`, `jacquard-common`, `jacquard-lexicon`)
- Each collection generates `{Type}Record` marker struct implementing `XrpcResp`
- `Collection::Record` associated type points to the marker
- `get_record::<R>()` returns `Response<R::Record>` with zero-copy `.parse()`
- Response transmutation enables type-safe record operations

**Examples**
- `create_post.rs`: Creating posts with Agent convenience methods
- `update_profile.rs`: Updating profile with fetch-modify-put
- `post_with_image.rs`: Uploading images and creating posts with embeds
- `update_preferences.rs`: Using VecUpdate for preferences
- `create_whitewind_post.rs`, `read_whitewind_post.rs`: Third-party lexicons
- `read_tangled_repo.rs`: Reading git repo metadata from tangled.org
- `resolve_did.rs`: Identity resolution examples
- `public_atproto_feed.rs`: Unauthenticated feed access
- `axum_server.rs`: Server-side XRPC handler


**Documentation** (`jacquard`)
- A whole host of examples added, as well as a lengthy explainer of the trait patterns.

## [0.4.1] - 2025-10-13

### Added

**Collection trait improvements** (`jacquard-api`)
- Generated `{Type}Record` marker structs for all record types
- Each implements `XrpcResp` with `Output<'de> = {Type}<'de>` and `Err<'de> = RecordError<'de>`
- Enables typed `get_record` returning `Response<R::Record>`

### Changed

- Minor improvements to derive macros (`jacquard-derive`)
- Identity resolution refinements (`jacquard-identity`)
- OAuth client improvements (`jacquard-oauth`)

---

## [0.4.0] - 2025-10-11

### Breaking Changes

**Zero-copy deserialization** (`jacquard-common`, `jacquard-api`)
- `XrpcRequest` now takes a `'de` lifetime parameter and requires `Deserialize<'de>`
- For raw data, `Response::parse_data()` gives validated loosely-typed atproto data, while `Response::parse_raw()` gives the raw values, with minimal validation.

**XRPC module moved** (`jacquard-common`)
- `xrpc.rs` is now top-level instead of under `types`
- Import from `jacquard_common::xrpc::*`  not `jacquard_common::types::xrpc::*`

**Response API changes** (`jacquard-common`)
- `XrpcRequest::Output` and `XrpcRequest::Err` are associated types with lifetimes
- Split response and request traits: `XrpcRequest<'de>` for client, `XrpcEndpoint` for server
- Added `XrpcResp` marker trait

**Various traits** (`jacquard`, `jacquard-common`, `jacquard-lexicon`, `jacquard-oauth`)
- Removed #[async_trait] attribute macro usage in favour of `impl Future` return types with manual bounds.
- Boxing imposed by asyc_trait negatively affected borrowing modes in async methods.
- Currently no semver guarantees on API trait bounds, if they need to tighten, they will.

### Added

**New crate: `jacquard-axum`**
- Server-side XRPC handlers for Axum
- `ExtractXrpc<R>` deserializes incoming requests (query params for Query, body for Procedure)
- Automatic error responses

**Lexicon codegen fixes** (`jacquard-lexicon`)
- Union variant collision detection: when multiple namespaces have similar type names, foreign ones get prefixed (e.g., `Images` vs `BskyImages`)
- Token types generate unit structs with `Display` instead of being skipped
- Namespace dependency tracking during union generation
- `generate_cargo_features()` outputs Cargo.toml features with correct deps
- `sanitize_name()` ensures valid Rust identifiers

**Lexicons** (`jacquard-api`)

Added 646 lexicon schemas. Highlights:

Core ATProto:
- `com.atproto.*`
- `com.bad-example.*` for identity resolution

Bluesky:
- `app.bsky.*` bluesky app
- `chat.bsky.*` chat client
- `tools.ozone.*` moderation

Third-party:
- `sh.tangled.*` - git forge
- `sh.weaver.*` - orual's WIP markdown blog platform
- `pub.leaflet.*` - longform publishing
- `net.anisota.*` - gamified and calming take on bluesky
- `network.slices.*` - serverless atproto hosting
- `tools.smokesignal.*` - automation
- `com.whtwnd.*` - markdown blogging
- `place.stream.*` - livestreaming
- `blue.2048.*` - 2048 game
- `community.lexicon.*` - community extensions (bookmarks, calendar, location, payments)
- `my.skylights.*` - media tracking
- `social.psky.*` - social extensions
- `blue.linkat.*` - link boards

Plus 30+ more experimental/community namespaces.

**Value types** (`jacquard-common`)
- `RawData` to `Data` conversion with type inference
- `from_data`, `from_raw_data`, `to_data`, and `to_raw_data` to serialize to and deserialize from the loosely typed value data formats. Particularly useful for second-stage deserialization of type "unknown" fields in lexicons, such as `PostView.record`.

### Changed

- `generate_union()` takes current NSID for dependency tracking
- Generated code uses `sanitize_name()` for identifiers more consistently
- Added derive macro for IntoStatic trait implementation

### Fixed

- Methods to extract the output from an XRPC response now behave well with respect to lifetimes and borrowing.
- Now possible to use jacquard types in places like axum extractors due to lifetime improvements
- Union variants don't collide when multiple namespaces define similar types and another namespace includes them

---
