commits
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mascot: a cute rook chick nesting — 3-color palette (purple body,
cream face patch, amber eyes), built from geometric primitives.
Full mascot for README/docs, simplified icon for favicon/badges.
README: lowercase headings, lowercase project name in running text,
centered mascot header, sol pbc attribution in license footer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Try-it example now shows full WelcomeMat flow: ToS signing, access token,
DPoP proof on signup. Enrollment flow section describes all 5 steps.
Signup endpoint marked as DPoP-authenticated in the endpoint table.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
POST /api/signup now requires a DPoP header, tos_signature, and wm+jwt
access_token in the body. The server validates the DPoP proof (with no
ath for enrollment), verifies the ToS signature against the current
terms using the DPoP key, and validates the access token including
tos_hash. The thumbprint is derived from the DPoP proof instead of
being passed in the request body.
All write endpoints (createRecord, putRecord, deleteRecord, applyWrites,
uploadBlob) now validate the wm+jwt access token via validateAccessToken
after DPoP proof validation. Stale tos_hash returns 401 with
{ error: "tos_changed" }.
Test helpers extracted to test/helpers.ts (signJwt, generateAuthKeys,
createDpopJwt, buildAccessToken, signTos). All test files updated to
use valid wm+jwt access tokens. New integration tests cover enrollment
validation and tos_changed rejection on writes.
- Add "Live on the network" section with PDSls screenshots and goat commands
- Add "Try it" section with complete Node.js enrollment + write example
- Fix enrollment flow description: signup takes {handle, jwkThumbprint},
not ToS signatures and access tokens (those are for authenticated writes)
- Rewrite agent-guide.md to match actual API: 4-step flow (keygen, enroll,
build auth, write records) with complete CRUD examples
- Add production deploy notes: wildcard DNS, D1, R2 requirements
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fan out to Account DOs via rpcGetLatestCommit() to populate the
required head (CID) and rev (TID) fields on each repo object.
Cursor is based on D1 row count to avoid pagination gaps if any
DO returns null.
*.pds.solpbc.org/* now routes to the rookery Worker via zone-based
route, enabling AT Protocol HTTP handle verification (GET
https://{handle}/.well-known/atproto-did). DNS AAAA record for
*.pds.solpbc.org created via Cloudflare API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Register Hono's built-in cors() middleware on all routes with
Access-Control-Allow-Origin: * so browser-based clients (PDSls,
atproto-browser, etc.) can access pds.solpbc.org. OPTIONS preflight
returns 204 before reaching requestCrawl middleware. Adds three
CORS tests covering GET, OPTIONS preflight, and POST error responses.
Adds ROOKERY_RELAY_HOSTS so the worker announces pds.solpbc.org to the
Bluesky relay on cold start via com.atproto.sync.requestCrawl.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire production D1 database ID (rookery-directory) and add custom domain
route for pds.solpbc.org. R2 bucket (rookery-blobs) created alongside.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New test/integration.test.ts with 6 end-to-end tests:
- Full lifecycle: signup → write → read → CAR export → firehose events
- Multi-agent isolation: two agents on separate Account DOs
- DID lifecycle: signup creates did:plc, resolveHandle returns it
- Enrollment edge cases: duplicate handle, duplicate thumbprint, auth failures
- Blob round-trip: uploadBlob → getBlob via HTTP routes
- Lexicon-agnostic: various collection NSIDs accepted
Updated README.md: CF Worker architecture, wrangler quickstart, binding tables.
Updated docs/agent-guide.md: removed Node.js prerequisite.
Updated wrangler.toml: added [vars] for pds.solpbc.org.
Deleted schema/directory.sql (initDirectory() is authoritative).
Wire 12 missing HTTP route handlers into src/worker.ts:
- Static: GET /.well-known/welcome.md, GET /tos
- Public repo reads: getRecord, listRecords, describeRepo
- Authenticated writes: createRecord, putRecord, deleteRecord, applyWrites
- Public sync reads: getRepo (CAR), getLatestCommit, getRepoStatus
Add rpcPutRecord (create-or-update) and applyWrites#update support
to src/account-do.ts. Add ROOKERY_RELAY_HOSTS to Env in src/types.ts.
Add fire-and-forget requestCrawl relay announcement on first request.
Singleton SequencerDurableObject provides global monotonic event ordering
for the AT Proto subscribeRepos firehose. Account DOs call the Sequencer
via RPC after each repo write; the Sequencer assigns a sequence number,
persists the CBOR-encoded frame, and broadcasts to WebSocket subscribers
with cursor-based backfill and hibernation support.
- New SequencerDurableObject with SQLite-backed firehose_events table
- RPC methods: sequenceCommit, sequenceIdentity, sequenceAccount
- WebSocket endpoint: GET /xrpc/com.atproto.sync.subscribeRepos
- Account DO emits commit events after record create/delete/applyWrites
- Signup emits identity + account events
- Binary frame encoding: two concatenated DAG-CBOR values (header + body)
- Cursor-based backfill on WebSocket connect
- WebSocket hibernation for idle subscribers
Add the D1-backed account directory schema and helper module, wire the DIRECTORY binding into Wrangler and test config, and extend the worker with signup, handle resolution, repo listing, server description, and atproto DID lookup routes. Add D1-focused worker tests covering the new directory-backed endpoints.
Replace all node:crypto and Buffer usage with crypto.subtle and
Uint8Array/TextEncoder. Remove stale v0.1 imports (better-sqlite3,
config.js) and the broken createAuthMiddleware function. Add 16 auth
tests covering DPoP validation, access token validation, JWK thumbprint,
and key size enforcement, all running in the CF Workers test pool.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace standalone Node.js server (hono/node-server + better-sqlite3) with
Cloudflare Workers architecture: Worker entry point with Hono app +
AccountDurableObject class with DO-native SQLite storage.
Key changes:
- Add wrangler.toml with nodejs_compat and DO binding
- Create AccountDurableObject with lazy init, per-account keys in SQL,
and RPC methods (initAccount, getState, createRecord, deleteRecord, etc.)
- Port SqliteRepoStorage from better-sqlite3 to DO SqlStorage API with
BlockMap/CidSet private-field workarounds and prev_data_cid tracking
- Create Worker entry point with health check (GET / -> {status: ok})
- Define Env type for CF bindings (multi-tenant: keys in DO, not env)
- Add vitest + @cloudflare/vitest-pool-workers test infrastructure
- Remove Node.js entry point, db.ts, config.ts, sequencer, relay, routes
- Remove Docker/Makefile (CF-native deployment)
- Swap deps: +wrangler +@cloudflare/workers-types -better-sqlite3 -tsx
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fly.io config: shared-cpu-1x, 256MB RAM, 1GB persistent volume (Denver).
Cloudflare proxy handles TLS + wildcard subdomain routing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Buffer is not assignable to BodyInit — wrap in Uint8Array via
new Response() constructor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Hono c.body() method doesn't accept Node.js Buffer directly in
strict mode — wrap with ArrayBuffer slice for compatibility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract shared test helpers to test/helpers.ts, eliminating duplication
across auth, blob, and repo test files
- Add 11 integration tests covering full lifecycle (signup → write →
read → CAR export), multi-tenant isolation, DID lifecycle, enrollment
edge cases, lexicon-agnostic writes, firehose WebSocket, and sync
- Add multi-stage Dockerfile (node:22-slim) with HEALTHCHECK and
docker-compose.yml for local deployment
- Rewrite README with quickstart, configuration reference, architecture
diagram, enrollment flow, and XRPC endpoint tables
- Add docs/agent-guide.md with step-by-step enrollment and publishing
walkthrough using TypeScript code examples
# Conflicts:
# src/index.ts
# src/sync.ts
Implements the firehose event system for rookery:
- Event sequencer (src/sequencer.ts): sequenceCommit, sequenceIdentity,
sequenceAccount with CBOR-encoded Sync v1.1 frame format, cursor-based
backfill via getEventsSince, event pruning, and in-process subscriber
broadcast
- WebSocket endpoint: GET /xrpc/com.atproto.sync.subscribeRepos with
cursor-based backfill and live streaming via @hono/node-ws
- Write integration: createRecord, putRecord, deleteRecord, applyWrites
all emit commit events with correct ops, blocks (CAR), rev, prevData
- Signup integration: identity + account events emitted on signup
- Storage: captures last CommitData for sequencer access
- 27 new tests (119 total) covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements uploadBlob (authenticated), getBlob, listBlobs (unauthenticated sync
endpoints), and fire-and-forget relay announcement on startup. Blobs are stored
on the filesystem keyed by {blobDir}/{did}/{cid} with metadata in the existing
blobs SQLite table.
# Conflicts:
# src/repo.ts
# test/repo.test.ts
Implement createRecord, putRecord, deleteRecord, and applyWrites with
DPoP auth, NSID/rkey validation, MST-backed persistence, idempotent
deletes, atomic batch writes, and collection tracking.
- identity.test.ts: add tosText to config, swap createApp arg order
- auth.test.ts: mock fetch for PLC directory calls (real impl now posts to PLC)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts:
# src/app.ts
# src/identity.ts
# src/index.ts
Implement L3: welcome-mat v1.0 signup flow with DPoP proof validation,
self-signed access token verification, and Hono auth middleware.
New files:
- src/auth.ts: DPoP/JWT validation, JWK thumbprint, auth middleware
- src/app.ts: createApp factory with all route definitions
- src/identity.ts: did:plc creation stub (L2 will replace internals)
- test/auth.test.ts: 19 tests covering signup, rejection cases, middleware
Changes:
- src/config.ts: add tosText field, ROOKERY_TOS_PATH support
- src/db.ts: add UNIQUE constraints on handle and jwk_thumbprint
- src/index.ts: thin entry point delegating to createApp
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement L2 identity layer: PLC genesis operation construction and
signing, DID derivation, handle resolution via XRPC endpoint, and
.well-known/atproto-did endpoint. Extract app creation into src/app.ts
for testability. Add unique index on accounts(handle).
Implement four sync endpoints (getRepo, getLatestCommit, getRepoStatus,
listRepos) as the first XRPC routes in rookery. Routes are in a new
src/sync.ts module mounted from index.ts. Includes 18 tests covering
CAR round-trips, diff/since filtering, pagination, and error responses.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bootstrap TypeScript/Hono/better-sqlite3/vitest project with multi-tenant
SqliteRepoStorage implementing @atproto/repo's RepoStorage interface.
- tsconfig.json, vitest.config.ts, .gitignore, README.md
- src/config.ts: env var parsing with validation
- src/db.ts: schema init for accounts, blocks, collections, blobs, firehose_events
- src/storage.ts: SqliteRepoStorage with account-scoped queries, transactional applyCommit, prev_data_cid tracking
- src/cbor-compat.ts: CBOR compat layer ported from cirrus
- src/index.ts: Hono health-check server
- test/storage.test.ts: 8 tests covering Repo.create, applyWrites, multi-tenant isolation, transaction atomicity
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Makefile with install/build/test/dev targets and package.json with
full dependency list for rookery L1.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mascot: a cute rook chick nesting — 3-color palette (purple body,
cream face patch, amber eyes), built from geometric primitives.
Full mascot for README/docs, simplified icon for favicon/badges.
README: lowercase headings, lowercase project name in running text,
centered mascot header, sol pbc attribution in license footer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
POST /api/signup now requires a DPoP header, tos_signature, and wm+jwt
access_token in the body. The server validates the DPoP proof (with no
ath for enrollment), verifies the ToS signature against the current
terms using the DPoP key, and validates the access token including
tos_hash. The thumbprint is derived from the DPoP proof instead of
being passed in the request body.
All write endpoints (createRecord, putRecord, deleteRecord, applyWrites,
uploadBlob) now validate the wm+jwt access token via validateAccessToken
after DPoP proof validation. Stale tos_hash returns 401 with
{ error: "tos_changed" }.
Test helpers extracted to test/helpers.ts (signJwt, generateAuthKeys,
createDpopJwt, buildAccessToken, signTos). All test files updated to
use valid wm+jwt access tokens. New integration tests cover enrollment
validation and tos_changed rejection on writes.
- Add "Live on the network" section with PDSls screenshots and goat commands
- Add "Try it" section with complete Node.js enrollment + write example
- Fix enrollment flow description: signup takes {handle, jwkThumbprint},
not ToS signatures and access tokens (those are for authenticated writes)
- Rewrite agent-guide.md to match actual API: 4-step flow (keygen, enroll,
build auth, write records) with complete CRUD examples
- Add production deploy notes: wildcard DNS, D1, R2 requirements
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Register Hono's built-in cors() middleware on all routes with
Access-Control-Allow-Origin: * so browser-based clients (PDSls,
atproto-browser, etc.) can access pds.solpbc.org. OPTIONS preflight
returns 204 before reaching requestCrawl middleware. Adds three
CORS tests covering GET, OPTIONS preflight, and POST error responses.
New test/integration.test.ts with 6 end-to-end tests:
- Full lifecycle: signup → write → read → CAR export → firehose events
- Multi-agent isolation: two agents on separate Account DOs
- DID lifecycle: signup creates did:plc, resolveHandle returns it
- Enrollment edge cases: duplicate handle, duplicate thumbprint, auth failures
- Blob round-trip: uploadBlob → getBlob via HTTP routes
- Lexicon-agnostic: various collection NSIDs accepted
Updated README.md: CF Worker architecture, wrangler quickstart, binding tables.
Updated docs/agent-guide.md: removed Node.js prerequisite.
Updated wrangler.toml: added [vars] for pds.solpbc.org.
Deleted schema/directory.sql (initDirectory() is authoritative).
Wire 12 missing HTTP route handlers into src/worker.ts:
- Static: GET /.well-known/welcome.md, GET /tos
- Public repo reads: getRecord, listRecords, describeRepo
- Authenticated writes: createRecord, putRecord, deleteRecord, applyWrites
- Public sync reads: getRepo (CAR), getLatestCommit, getRepoStatus
Add rpcPutRecord (create-or-update) and applyWrites#update support
to src/account-do.ts. Add ROOKERY_RELAY_HOSTS to Env in src/types.ts.
Add fire-and-forget requestCrawl relay announcement on first request.
Singleton SequencerDurableObject provides global monotonic event ordering
for the AT Proto subscribeRepos firehose. Account DOs call the Sequencer
via RPC after each repo write; the Sequencer assigns a sequence number,
persists the CBOR-encoded frame, and broadcasts to WebSocket subscribers
with cursor-based backfill and hibernation support.
- New SequencerDurableObject with SQLite-backed firehose_events table
- RPC methods: sequenceCommit, sequenceIdentity, sequenceAccount
- WebSocket endpoint: GET /xrpc/com.atproto.sync.subscribeRepos
- Account DO emits commit events after record create/delete/applyWrites
- Signup emits identity + account events
- Binary frame encoding: two concatenated DAG-CBOR values (header + body)
- Cursor-based backfill on WebSocket connect
- WebSocket hibernation for idle subscribers
Add the D1-backed account directory schema and helper module, wire the DIRECTORY binding into Wrangler and test config, and extend the worker with signup, handle resolution, repo listing, server description, and atproto DID lookup routes. Add D1-focused worker tests covering the new directory-backed endpoints.
Replace all node:crypto and Buffer usage with crypto.subtle and
Uint8Array/TextEncoder. Remove stale v0.1 imports (better-sqlite3,
config.js) and the broken createAuthMiddleware function. Add 16 auth
tests covering DPoP validation, access token validation, JWK thumbprint,
and key size enforcement, all running in the CF Workers test pool.
Replace standalone Node.js server (hono/node-server + better-sqlite3) with
Cloudflare Workers architecture: Worker entry point with Hono app +
AccountDurableObject class with DO-native SQLite storage.
Key changes:
- Add wrangler.toml with nodejs_compat and DO binding
- Create AccountDurableObject with lazy init, per-account keys in SQL,
and RPC methods (initAccount, getState, createRecord, deleteRecord, etc.)
- Port SqliteRepoStorage from better-sqlite3 to DO SqlStorage API with
BlockMap/CidSet private-field workarounds and prev_data_cid tracking
- Create Worker entry point with health check (GET / -> {status: ok})
- Define Env type for CF bindings (multi-tenant: keys in DO, not env)
- Add vitest + @cloudflare/vitest-pool-workers test infrastructure
- Remove Node.js entry point, db.ts, config.ts, sequencer, relay, routes
- Remove Docker/Makefile (CF-native deployment)
- Swap deps: +wrangler +@cloudflare/workers-types -better-sqlite3 -tsx
- Extract shared test helpers to test/helpers.ts, eliminating duplication
across auth, blob, and repo test files
- Add 11 integration tests covering full lifecycle (signup → write →
read → CAR export), multi-tenant isolation, DID lifecycle, enrollment
edge cases, lexicon-agnostic writes, firehose WebSocket, and sync
- Add multi-stage Dockerfile (node:22-slim) with HEALTHCHECK and
docker-compose.yml for local deployment
- Rewrite README with quickstart, configuration reference, architecture
diagram, enrollment flow, and XRPC endpoint tables
- Add docs/agent-guide.md with step-by-step enrollment and publishing
walkthrough using TypeScript code examples
Implements the firehose event system for rookery:
- Event sequencer (src/sequencer.ts): sequenceCommit, sequenceIdentity,
sequenceAccount with CBOR-encoded Sync v1.1 frame format, cursor-based
backfill via getEventsSince, event pruning, and in-process subscriber
broadcast
- WebSocket endpoint: GET /xrpc/com.atproto.sync.subscribeRepos with
cursor-based backfill and live streaming via @hono/node-ws
- Write integration: createRecord, putRecord, deleteRecord, applyWrites
all emit commit events with correct ops, blocks (CAR), rev, prevData
- Signup integration: identity + account events emitted on signup
- Storage: captures last CommitData for sequencer access
- 27 new tests (119 total) covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement L3: welcome-mat v1.0 signup flow with DPoP proof validation,
self-signed access token verification, and Hono auth middleware.
New files:
- src/auth.ts: DPoP/JWT validation, JWK thumbprint, auth middleware
- src/app.ts: createApp factory with all route definitions
- src/identity.ts: did:plc creation stub (L2 will replace internals)
- test/auth.test.ts: 19 tests covering signup, rejection cases, middleware
Changes:
- src/config.ts: add tosText field, ROOKERY_TOS_PATH support
- src/db.ts: add UNIQUE constraints on handle and jwk_thumbprint
- src/index.ts: thin entry point delegating to createApp
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bootstrap TypeScript/Hono/better-sqlite3/vitest project with multi-tenant
SqliteRepoStorage implementing @atproto/repo's RepoStorage interface.
- tsconfig.json, vitest.config.ts, .gitignore, README.md
- src/config.ts: env var parsing with validation
- src/db.ts: schema init for accounts, blocks, collections, blobs, firehose_events
- src/storage.ts: SqliteRepoStorage with account-scoped queries, transactional applyCommit, prev_data_cid tracking
- src/cbor-compat.ts: CBOR compat layer ported from cirrus
- src/index.ts: Hono health-check server
- test/storage.test.ts: 8 tests covering Repo.create, applyWrites, multi-tenant isolation, transaction atomicity
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>