commits
Shows the authorizing user's avatar, display name, and handle on the
consent page. Fetches profile from Bluesky public API using the
login_hint parameter. Degrades gracefully if fetch fails.
- Uses JSON.stringify for safe JS string escaping (XSS prevention)
- Adds e2e tests for profile card rendering and XSS protection
- Adds retry logic for flaky wrangler dev errors in e2e tests
- Bumps version to 0.6.0
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- setup.js now imports shared helpers from pds.js instead of duplicating them
- Export cborEncodeDagCbor from pds.js for proper DAG-CBOR encoding
- Add docker-compose.yml for local PLC directory testing
- Reduces setup.js from 558 to 362 lines
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Cleanup from simplified proxy routing logic.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- parseAtprotoProxyHeader() parses did:web:api.bsky.app#bsky_appview format
- getKnownServiceUrl() maps known service DIDs to URLs
- proxyToService() generic proxy utility with header forwarding
- Repo endpoints (getRecord, listRecords, describeRepo) support explicit proxying
- Returns appropriate errors for malformed headers or unknown services
- Refactored handleAppViewProxy to use shared proxyToService utility
- Added caching for registered DIDs lookup (30s TTL)
- Added unit tests for proxy utilities
- Added E2E tests for foreign DID proxying behavior
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add VERSION constant at top of pds.js and reference it in the health
check endpoint instead of hardcoded value.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add granular OAuth scope enforcement:
- parseRepoScope() parses repo:collection?action=create&action=update format
- parseBlobScope() parses blob:image/* format with MIME wildcards
- ScopePermissions class for checking repo/blob permissions
- Enforced on createRecord, putRecord, deleteRecord, applyWrites, uploadBlob
Add consent page permissions table:
- Identity-only: "wants to uniquely identify you" message
- Granular scopes: Table with Collection + Create/Update/Delete columns
- Full access: Warning banner for transition:generic
- parseScopesForDisplay() helper for consent page rendering
Also includes:
- Comprehensive E2E tests for scope enforcement and consent display
- OAuth token helper extracted to test/helpers/oauth.js
- Updated scope-comparison.md documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
10-task TDD plan for implementing OAuth scope validation:
- Repo scope parsing and enforcement
- Blob scope parsing with MIME wildcard matching
- ScopePermissions class
- Per-endpoint integration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents gaps in OAuth scope enforcement between pds.js and the
official implementation, covering repo/blob/transition scopes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Only preferences are stored natively in PDS; the rest are proxied.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents coverage gaps and parameter differences between pds.js and
the official AT Protocol PDS implementation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete OAuth 2.0 implementation for AT Protocol with:
- Discovery endpoints (AS metadata, protected resource, JWKS)
- Pushed Authorization Requests (PAR) with DPoP validation
- Authorization endpoint with consent UI (dark theme)
- Token endpoint (authorization_code + refresh_token grants)
- Token revocation (RFC 7009)
- DPoP proof validation and token binding
- PKCE with S256 code challenge
- Client metadata fetching and validation
- Loopback client support for development
Security features:
- DPoP JTI tracking to prevent replay attacks
- Timing-safe password comparison
- 24-hour maximum token lifetime
- Automatic cleanup of expired authorization requests
Also includes comprehensive e2e tests and JSDoc types.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BREAKING CHANGE: Existing Durable Objects need storage reset.
- Rename tables: blob → blobs, record_blob → record_blobs
- Rename columns: mimeType → mime_type, createdAt → created_at,
blobCid → blob_cid, recordUri → record_uri
- Update index: idx_record_blob_uri → idx_record_blobs_record_uri
- Add CHANGELOG.md
- Add .backup/ to .gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The endpoint was defined but never exposed publicly.
Delete records via API instead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Delete each record through the normal flow before wiping,
so relays and indexers can clean up their indexes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Standardize JSDoc type annotation spacing and improve multiline
formatting for better readability.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add JSDoc type annotations for TypeScript checking
- Reorganize pds.js into 13 logical sections with box-style headers:
Types & Constants, Utilities, CBOR Encoding, Content Identifiers,
Cryptography, Authentication, Merkle Search Tree, CAR Files,
Blob Handling, Relay Notification, Routing, Personal Data Server,
Workers Entry Point
- Add ASCII art file header with feature list
- Add tsconfig.json for type checking
- Add typecheck npm script
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements full AT Protocol blob support:
- uploadBlob: Upload blobs with MIME type sniffing (JPEG, PNG, GIF,
WebP, MP4, AVIF, HEIC) and CID generation using raw codec
- getBlob: Retrieve blobs with proper Content-Type, security headers,
and CID format validation
- listBlobs: Paginated blob listing with composite cursor
Storage and lifecycle:
- R2 bucket for blob data with DID-prefixed keys
- SQLite tables for blob metadata and record associations
- Automatic orphan cleanup via DO alarm (24hr) and on record deletion
- Race-safe concurrent upload handling
Includes comprehensive test coverage:
- Unit tests for MIME sniffing, CID generation, blob ref detection
- E2E tests for all blob endpoints and lifecycle scenarios
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement com.atproto.server.refreshSession for token refresh:
- Add verifyRefreshJwt with audience validation
- Extract shared verifyJwt helper to reduce duplication
- Change refresh token expiration from 90 days to 24 hours
- Fix error name AuthenticationRequired → AuthRequired
Tests:
- Unit tests for verifyRefreshJwt (valid, expired, wrong type, malformed)
- E2E tests for happy path and error cases
- Remove test numbers from e2e.sh for easier maintenance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Format test/e2e.sh with shfmt
- Add shfmt to npm run format script
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add @biomejs/biome with 2-space indent, single quotes
- Add npm scripts: format, lint, check
- Auto-fix all lint issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add notifyCrawlers() to notify relays after writes via requestCrawl
- Add worker-level routing for sync endpoints (getLatestCommit, getRepoStatus, getRepo, getRecord)
- Fix /init to register handles in default DO's handleMap
- Add self-contained E2E test suite (23 tests) covering:
- Server basics, identity, authentication
- Repo CRUD, applyWrites batch operations
- Sync endpoints (CAR file retrieval)
- Error handling (401, 403, 404)
- Move test credentials to .dev.vars (gitignored)
- Update .env.example with all config options
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement full authentication system for ATProto PDS:
- JWT helpers: base64url encode/decode, HMAC-SHA256 signing
- Access tokens (2hr) and refresh tokens (90 days)
- createSession endpoint with password validation
- getSession endpoint with token verification
- Auth middleware protecting write endpoints (createRecord, deleteRecord, putRecord, applyWrites)
- AppView proxy with ES256 service auth for app.bsky.* endpoints
- Local storage for user preferences (getPreferences, putPreferences)
- resolveHandle XRPC endpoint
Refactoring:
- Consolidated 4 CBOR encoders into 2
- Added errorResponse() helper for consistent ATProto error format
- Extracted handleAuthenticatedRepoWrite() to reduce duplication
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements record deletion with proper ATProto event emission:
- Removes record from database and rebuilds MST
- Creates signed commit with updated repo state
- Emits delete event to firehose for relay/indexer propagation
- Routes POST requests with repo in body to correct Durable Object
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ATProto MST spec: "Layers are counted from the bottom of the tree,
starting with zero." This means:
- Layer 0 is at the BOTTOM
- Root is at the HIGHEST layer (max depth of any key)
- Subtrees go DOWN to lower layers
Previous implementation had this inverted, causing "depths are out of
order" validation errors in pdsls.
Also includes:
- MST nodes must include l and t fields (even when null) per ATProto schema
- handleGetRepo now only includes blocks reachable from current commit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add scripts/update-did.js for updating PLC DID handle and PDS endpoint
- Fix handle resolution to work with bare domain handles (not just subdomains)
- This allows workers.dev deployments where nested subdomains aren't supported
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add handle -> DID mapping storage in default DO
- Route /.well-known/atproto-did based on subdomain
- Update setup script to register handle mappings
- Bare domain returns 404 for handle resolution (use subdomain)
Works with custom domains that have wildcard SSL certs.
Note: workers.dev doesn't support nested subdomains (SSL limitation).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CBOR tag 42 decoding for CID links in cborDecode
- Use DAG-CBOR encoding for records (length-first key sorting)
- Return full proof chain in sync.getRecord (commit + MST + record)
- Skip CORS wrapping for WebSocket upgrade responses (status 101)
- Simplify setup script to use PDS hostname as handle
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Plan covers: CBOR constants, shared encodeHead, JSDoc on exports,
route table pattern, and protocol-specific "why" comments.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Shows the authorizing user's avatar, display name, and handle on the
consent page. Fetches profile from Bluesky public API using the
login_hint parameter. Degrades gracefully if fetch fails.
- Uses JSON.stringify for safe JS string escaping (XSS prevention)
- Adds e2e tests for profile card rendering and XSS protection
- Adds retry logic for flaky wrangler dev errors in e2e tests
- Bumps version to 0.6.0
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- setup.js now imports shared helpers from pds.js instead of duplicating them
- Export cborEncodeDagCbor from pds.js for proper DAG-CBOR encoding
- Add docker-compose.yml for local PLC directory testing
- Reduces setup.js from 558 to 362 lines
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- parseAtprotoProxyHeader() parses did:web:api.bsky.app#bsky_appview format
- getKnownServiceUrl() maps known service DIDs to URLs
- proxyToService() generic proxy utility with header forwarding
- Repo endpoints (getRecord, listRecords, describeRepo) support explicit proxying
- Returns appropriate errors for malformed headers or unknown services
- Refactored handleAppViewProxy to use shared proxyToService utility
- Added caching for registered DIDs lookup (30s TTL)
- Added unit tests for proxy utilities
- Added E2E tests for foreign DID proxying behavior
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add granular OAuth scope enforcement:
- parseRepoScope() parses repo:collection?action=create&action=update format
- parseBlobScope() parses blob:image/* format with MIME wildcards
- ScopePermissions class for checking repo/blob permissions
- Enforced on createRecord, putRecord, deleteRecord, applyWrites, uploadBlob
Add consent page permissions table:
- Identity-only: "wants to uniquely identify you" message
- Granular scopes: Table with Collection + Create/Update/Delete columns
- Full access: Warning banner for transition:generic
- parseScopesForDisplay() helper for consent page rendering
Also includes:
- Comprehensive E2E tests for scope enforcement and consent display
- OAuth token helper extracted to test/helpers/oauth.js
- Updated scope-comparison.md documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
10-task TDD plan for implementing OAuth scope validation:
- Repo scope parsing and enforcement
- Blob scope parsing with MIME wildcard matching
- ScopePermissions class
- Per-endpoint integration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete OAuth 2.0 implementation for AT Protocol with:
- Discovery endpoints (AS metadata, protected resource, JWKS)
- Pushed Authorization Requests (PAR) with DPoP validation
- Authorization endpoint with consent UI (dark theme)
- Token endpoint (authorization_code + refresh_token grants)
- Token revocation (RFC 7009)
- DPoP proof validation and token binding
- PKCE with S256 code challenge
- Client metadata fetching and validation
- Loopback client support for development
Security features:
- DPoP JTI tracking to prevent replay attacks
- Timing-safe password comparison
- 24-hour maximum token lifetime
- Automatic cleanup of expired authorization requests
Also includes comprehensive e2e tests and JSDoc types.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BREAKING CHANGE: Existing Durable Objects need storage reset.
- Rename tables: blob → blobs, record_blob → record_blobs
- Rename columns: mimeType → mime_type, createdAt → created_at,
blobCid → blob_cid, recordUri → record_uri
- Update index: idx_record_blob_uri → idx_record_blobs_record_uri
- Add CHANGELOG.md
- Add .backup/ to .gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add JSDoc type annotations for TypeScript checking
- Reorganize pds.js into 13 logical sections with box-style headers:
Types & Constants, Utilities, CBOR Encoding, Content Identifiers,
Cryptography, Authentication, Merkle Search Tree, CAR Files,
Blob Handling, Relay Notification, Routing, Personal Data Server,
Workers Entry Point
- Add ASCII art file header with feature list
- Add tsconfig.json for type checking
- Add typecheck npm script
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements full AT Protocol blob support:
- uploadBlob: Upload blobs with MIME type sniffing (JPEG, PNG, GIF,
WebP, MP4, AVIF, HEIC) and CID generation using raw codec
- getBlob: Retrieve blobs with proper Content-Type, security headers,
and CID format validation
- listBlobs: Paginated blob listing with composite cursor
Storage and lifecycle:
- R2 bucket for blob data with DID-prefixed keys
- SQLite tables for blob metadata and record associations
- Automatic orphan cleanup via DO alarm (24hr) and on record deletion
- Race-safe concurrent upload handling
Includes comprehensive test coverage:
- Unit tests for MIME sniffing, CID generation, blob ref detection
- E2E tests for all blob endpoints and lifecycle scenarios
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement com.atproto.server.refreshSession for token refresh:
- Add verifyRefreshJwt with audience validation
- Extract shared verifyJwt helper to reduce duplication
- Change refresh token expiration from 90 days to 24 hours
- Fix error name AuthenticationRequired → AuthRequired
Tests:
- Unit tests for verifyRefreshJwt (valid, expired, wrong type, malformed)
- E2E tests for happy path and error cases
- Remove test numbers from e2e.sh for easier maintenance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add notifyCrawlers() to notify relays after writes via requestCrawl
- Add worker-level routing for sync endpoints (getLatestCommit, getRepoStatus, getRepo, getRecord)
- Fix /init to register handles in default DO's handleMap
- Add self-contained E2E test suite (23 tests) covering:
- Server basics, identity, authentication
- Repo CRUD, applyWrites batch operations
- Sync endpoints (CAR file retrieval)
- Error handling (401, 403, 404)
- Move test credentials to .dev.vars (gitignored)
- Update .env.example with all config options
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement full authentication system for ATProto PDS:
- JWT helpers: base64url encode/decode, HMAC-SHA256 signing
- Access tokens (2hr) and refresh tokens (90 days)
- createSession endpoint with password validation
- getSession endpoint with token verification
- Auth middleware protecting write endpoints (createRecord, deleteRecord, putRecord, applyWrites)
- AppView proxy with ES256 service auth for app.bsky.* endpoints
- Local storage for user preferences (getPreferences, putPreferences)
- resolveHandle XRPC endpoint
Refactoring:
- Consolidated 4 CBOR encoders into 2
- Added errorResponse() helper for consistent ATProto error format
- Extracted handleAuthenticatedRepoWrite() to reduce duplication
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements record deletion with proper ATProto event emission:
- Removes record from database and rebuilds MST
- Creates signed commit with updated repo state
- Emits delete event to firehose for relay/indexer propagation
- Routes POST requests with repo in body to correct Durable Object
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ATProto MST spec: "Layers are counted from the bottom of the tree,
starting with zero." This means:
- Layer 0 is at the BOTTOM
- Root is at the HIGHEST layer (max depth of any key)
- Subtrees go DOWN to lower layers
Previous implementation had this inverted, causing "depths are out of
order" validation errors in pdsls.
Also includes:
- MST nodes must include l and t fields (even when null) per ATProto schema
- handleGetRepo now only includes blocks reachable from current commit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add scripts/update-did.js for updating PLC DID handle and PDS endpoint
- Fix handle resolution to work with bare domain handles (not just subdomains)
- This allows workers.dev deployments where nested subdomains aren't supported
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add handle -> DID mapping storage in default DO
- Route /.well-known/atproto-did based on subdomain
- Update setup script to register handle mappings
- Bare domain returns 404 for handle resolution (use subdomain)
Works with custom domains that have wildcard SSL certs.
Note: workers.dev doesn't support nested subdomains (SSL limitation).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CBOR tag 42 decoding for CID links in cborDecode
- Use DAG-CBOR encoding for records (length-first key sorting)
- Return full proof chain in sync.getRecord (commit + MST + record)
- Skip CORS wrapping for WebSocket upgrade responses (status 101)
- Simplify setup script to use PDS hostname as handle
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>