An easy-to-host PDS on the ATProtocol, MacOS. Grandma-approved.

fix(relay): add MissingHeader doc comment; restore correct #[allow(dead_code)] scope

Minor 3 from final code review: clarify why DpopTokenEndpointError::MissingHeader carries
#[allow(dead_code)] — the handler pre-checks for a missing DPoP header before calling
validate_dpop_for_token_endpoint, so this variant is never constructed in practice but
exists for exhaustive match completeness.

Also includes CLAUDE.md and db/CLAUDE.md freshness updates from the project librarian step.

+6 -4
+1 -1
CLAUDE.md
··· 1 1 # ezpds 2 2 3 - Last verified: 2026-03-22 3 + Last verified: 2026-03-20 4 4 5 5 ## Tech Stack 6 6 - Language: Rust (stable channel via rust-toolchain.toml)
+4
crates/relay/src/auth/mod.rs
··· 365 365 /// Converted to `OAuthTokenError` by the handler in `routes/oauth_token.rs`. 366 366 pub(crate) enum DpopTokenEndpointError { 367 367 /// `DPoP:` header is absent. 368 + /// 369 + /// Never constructed in practice — the handler in `routes/oauth_token.rs` pre-checks for a 370 + /// missing `DPoP:` header and returns an error directly, so this function is only called when 371 + /// the header is present. Retained for API completeness so callers can match exhaustively. 368 372 #[allow(dead_code)] 369 373 MissingHeader, 370 374 /// DPoP proof is syntactically or semantically invalid.
+1 -3
crates/relay/src/db/CLAUDE.md
··· 1 1 # Database Module 2 2 3 - Last verified: 2026-03-22 3 + Last verified: 2026-03-21 4 4 5 5 ## Latest Updates 6 - - **V012**: Adds nullable `jkt` TEXT column to `oauth_tokens` (DPoP key thumbprint for DPoP-bound refresh tokens); creates `oauth_signing_key` table (WITHOUT ROWID, single-row, stores the server's persistent ES256 keypair with AES-256-GCM-encrypted private key) 7 6 - **V011**: Adds nullable `pending_share_{1,2,3}` TEXT columns to `pending_accounts` — stores pre-generated Shamir shares alongside `pending_did` so retried DID ceremony requests return the same shares (prevents Share 2 orphaning in accounts.recovery_share) 8 7 - **V010**: Adds nullable `recovery_share` column to `accounts` — stores Share 2 of the Shamir 2-of-3 split for relay-side custody; base32-encoded (52 chars); NULL for pre-Shamir accounts 9 8 - **V009**: Rebuilt sessions with nullable device_id (devices are deleted at DID promotion) and added token_hash UNIQUE column for Bearer token authentication (same SHA-256 hex pattern as pending_sessions) ··· 48 47 - `migrations/V009__sessions_v2.sql` - Rebuilds sessions: makes device_id nullable (devices are transient, deleted at DID promotion) and adds token_hash UNIQUE column for Bearer token auth via require_session 49 48 - `migrations/V010__recovery_shares.sql` - Adds nullable recovery_share TEXT to accounts: stores Share 2 of the Shamir 2-of-3 recovery split (base32, 52 chars); written atomically inside promote_account transaction 50 49 - `migrations/V011__pending_shares.sql` - Adds nullable pending_share_{1,2,3} TEXT columns to pending_accounts: idempotent share storage alongside pending_did; all three deleted when pending_accounts row is deleted at promotion 51 - - `migrations/V012__oauth_token_endpoint.sql` - Adds `jkt` TEXT column to oauth_tokens (DPoP thumbprint); creates `oauth_signing_key` table (WITHOUT ROWID, keyed by UUID id) for persistent ES256 keypair storage (public JWK + AES-256-GCM encrypted private key)