commits
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add @pds/lexicon-resolver package for AT Protocol lexicon resolution
and validation with live fetching from authoritative PDS.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document new @pds/lexicon-resolver package with AT Protocol lexicon
resolution and validation capabilities.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete lexicon validation implementation with live DNS-based schema resolution.
Key features:
- DNS authority lookup via _lexicon.{domain} subdomain
- DID resolution to PDS endpoint
- Recursive ref resolution (fetches all referenced schemas)
- Bundled core com.atproto schemas (strongRef, label.defs, moderation.defs)
- Cloudflare Workers compatibility (fetch binding fix)
Changes:
- Add @pds/lexicon-resolver package with DNS/DID resolution
- Add LexiconResolverPort to core PDS
- Validate records in createRecord, putRecord, applyWrites
- Return validationStatus: 'valid' | 'unknown' in responses
- Add default LexiconResolver to node, deno, cloudflare adapters
- Add e2e test for live lexicon resolution
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Node.js: createPDS → createServer, add await, move port to options
- Cloudflare: remove non-existent createCloudflareHandler, use re-export
- Deno: add await, port option, and listen() call
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The resolveHandle handler was missing the proxy header check that other
handlers have, causing requests with atproto-proxy headers to be handled
locally instead of being forwarded to the specified service.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Include @pds/blobs-deno and @pds/deno in tsconfig paths and remove
blobs-deno from build excludes so .d.ts files are generated.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The paths were pointing to packages/*/index.js but the actual
files are in packages/*/src/index.js.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The deno.json and tsconfig.json were pointing to non-existent files
at the package root (e.g., packages/deno/index.js) instead of the
actual source files in src/ subdirectories.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split the monolithic test/pds.test.js (126 tests) into 7 separate
test files in packages/core/test/, each corresponding to its source module:
- crypto.test.js (13 tests): Base32, P-256, JWT Base64URL, JWK Thumbprint
- repo.test.js (44 tests): CBOR, CID, TID, CAR, MIME, Blob Ref
- auth.test.js (12 tests): JWT Creation, JWT Verification
- mst.test.js (5 tests): MST Key Depth
- scope.test.js (39 tests): Scope Parsing, ScopePermissions
- oauth.test.js (3 tests): Client Metadata
- pds.test.js (10 tests): Proxy Utilities
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Aligns with APPVIEW_URL naming convention since the value is a URL.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MinIO service to docker-compose with health checks
- Node & Deno adapters accept optional `blobs` parameter for custom storage
- Test helper uses `minio` client for S3 blob operations
- Set `BLOB_STORAGE=s3` to enable S3 testing via MinIO
- Remove Deno package tsconfigs (excluded from build at root level)
Usage:
PLATFORM=node npm test # filesystem blobs (default)
PLATFORM=node BLOB_STORAGE=s3 npm test # S3 blobs via MinIO
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous Quick Start used localhost:3000 as the PDS URL, which would
register a DID with the production PLC directory pointing to localhost.
Now uses docker compose to run local PLC and relay for safe local dev.
Also clarifies that setup should only be run for Node.js deployments
once the PDS is accessible at a public URL.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Records must be sorted by their full MST key (collection/rkey) in byte
order, not by collection then rkey separately. This matters when
collection names have prefix relationships - e.g. "social.grain.gallery"
vs "social.grain.gallery.item" - because '.' (46) < '/' (47) in ASCII.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Deno as a supported platform alongside Node.js and Cloudflare Workers.
New packages:
- @pds/deno: HTTP server adapter using Deno.serve() and Deno.upgradeWebSocket()
- @pds/blobs-deno: Filesystem blob storage using Deno.readFile/writeFile
Changes:
- Abstract SQLite driver interface for better-sqlite3 and node:sqlite compatibility
- Align Node.js and Deno APIs: both use async createServer() with listen()/close()
- Remove createServerFromEnv convenience wrapper for explicit configuration
- Add Deno e2e tests (npm run test:e2e:deno)
Usage:
import { createServer } from '@pds/deno';
const { listen, close } = await createServer({ dbPath, blobsDir, jwtSecret });
await listen();
Requires Deno 2.2+ for node:sqlite support.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update changelog with hexagonal architecture refactor.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Generalize the package name to support both better-sqlite3 and
future node:sqlite implementations. The adapter accepts any
compatible sqlite connection.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major refactor to support multiple platforms (Node.js and Cloudflare Workers):
- Extract @pds/core with platform-agnostic business logic
- Add @pds/node with HTTP server and WebSocket support
- Add @pds/cloudflare with Durable Objects entry point
- Add @pds/storage-better-sqlite3 for SQLite-based storage
- Add @pds/blobs-fs and @pds/blobs-s3 for blob storage
- Introduce ActorStoragePort and SharedStoragePort for multi-tenant prep
- Remove monolithic src/pds.js in favor of packages
- Update README with multi-platform documentation
- Add docker-compose for local testing infrastructure
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
🤖 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>
Complete lexicon validation implementation with live DNS-based schema resolution.
Key features:
- DNS authority lookup via _lexicon.{domain} subdomain
- DID resolution to PDS endpoint
- Recursive ref resolution (fetches all referenced schemas)
- Bundled core com.atproto schemas (strongRef, label.defs, moderation.defs)
- Cloudflare Workers compatibility (fetch binding fix)
Changes:
- Add @pds/lexicon-resolver package with DNS/DID resolution
- Add LexiconResolverPort to core PDS
- Validate records in createRecord, putRecord, applyWrites
- Return validationStatus: 'valid' | 'unknown' in responses
- Add default LexiconResolver to node, deno, cloudflare adapters
- Add e2e test for live lexicon resolution
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split the monolithic test/pds.test.js (126 tests) into 7 separate
test files in packages/core/test/, each corresponding to its source module:
- crypto.test.js (13 tests): Base32, P-256, JWT Base64URL, JWK Thumbprint
- repo.test.js (44 tests): CBOR, CID, TID, CAR, MIME, Blob Ref
- auth.test.js (12 tests): JWT Creation, JWT Verification
- mst.test.js (5 tests): MST Key Depth
- scope.test.js (39 tests): Scope Parsing, ScopePermissions
- oauth.test.js (3 tests): Client Metadata
- pds.test.js (10 tests): Proxy Utilities
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MinIO service to docker-compose with health checks
- Node & Deno adapters accept optional `blobs` parameter for custom storage
- Test helper uses `minio` client for S3 blob operations
- Set `BLOB_STORAGE=s3` to enable S3 testing via MinIO
- Remove Deno package tsconfigs (excluded from build at root level)
Usage:
PLATFORM=node npm test # filesystem blobs (default)
PLATFORM=node BLOB_STORAGE=s3 npm test # S3 blobs via MinIO
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous Quick Start used localhost:3000 as the PDS URL, which would
register a DID with the production PLC directory pointing to localhost.
Now uses docker compose to run local PLC and relay for safe local dev.
Also clarifies that setup should only be run for Node.js deployments
once the PDS is accessible at a public URL.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Records must be sorted by their full MST key (collection/rkey) in byte
order, not by collection then rkey separately. This matters when
collection names have prefix relationships - e.g. "social.grain.gallery"
vs "social.grain.gallery.item" - because '.' (46) < '/' (47) in ASCII.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Deno as a supported platform alongside Node.js and Cloudflare Workers.
New packages:
- @pds/deno: HTTP server adapter using Deno.serve() and Deno.upgradeWebSocket()
- @pds/blobs-deno: Filesystem blob storage using Deno.readFile/writeFile
Changes:
- Abstract SQLite driver interface for better-sqlite3 and node:sqlite compatibility
- Align Node.js and Deno APIs: both use async createServer() with listen()/close()
- Remove createServerFromEnv convenience wrapper for explicit configuration
- Add Deno e2e tests (npm run test:e2e:deno)
Usage:
import { createServer } from '@pds/deno';
const { listen, close } = await createServer({ dbPath, blobsDir, jwtSecret });
await listen();
Requires Deno 2.2+ for node:sqlite support.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major refactor to support multiple platforms (Node.js and Cloudflare Workers):
- Extract @pds/core with platform-agnostic business logic
- Add @pds/node with HTTP server and WebSocket support
- Add @pds/cloudflare with Durable Objects entry point
- Add @pds/storage-better-sqlite3 for SQLite-based storage
- Add @pds/blobs-fs and @pds/blobs-s3 for blob storage
- Introduce ActorStoragePort and SharedStoragePort for multi-tenant prep
- Remove monolithic src/pds.js in favor of packages
- Update README with multi-platform documentation
- Add docker-compose for local testing infrastructure
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>