chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
space-reference
Tests permissioned data against the reference implementation
(bluesky-social/atproto at 704b9e2ac, published as
@atproto/space@0.0.0-spaces-alpha-20261105160032), in both directions:
- pds.js produces, reference verifies.
gen-artifacts.mjsdrives the space handlers as a syncer would: getRepo, getLatestCommit and getRecord, each with anAtproto-Space-Want-Mackey share against the author's KEM key, and a credential issued by a pds.js authority through getSpaceCredential.ref-verify.test.tsruns the reference'sdecapsulate,verifyRepoStarFull,verifyCommit,verifyRecord,verifySpaceTokenandverifyCredentialSigover them. Passing means the KEM, both MACs, BLAKE3, LtHash, the STAR layout, record CIDs (a blob ref included), the tokens and the credential signature all agree. - Reference produces, pds.js verifies.
ref-generate.test.tsbuilds a repo, MACs and tokens with@atproto/space;test/space-reference.test.jsverifies them with@pdsjs/spaces. It also serves the reference's record from pds.js holding the reference's KEM key, presented with the reference's credential andcreateSpaceSigHeaderssignature, and checks that pds.js answers the same MAC the reference computed.
Both directions carry negative cases (wrong repo, wrong space, wrong key, wrong token type), so a pass cannot be vacuous.
Running
The second direction also runs in the plain test suite, against fixtures
committed under test/fixtures/space-reference-* — no atproto checkout needed.
The full two-directional run needs a worktree of the pinned reference, the same
one scripts/gen-space-vectors.md uses:
git -C ~/code/atproto worktree add ~/code/atproto-space-ref 704b9e2ac
cd ~/code/atproto-space-ref
pnpm install --frozen-lockfile
pnpm --filter '@atproto/space^...' run build
# atproto's root vitest config imports this plugin, so vitest cannot start
# until it is built. Nothing @atproto/space depends on pulls it in.
pnpm --filter '@atproto-labs/rolldown-plugin-bundle-manifest' run build
# vitest resolves every project in the workspace before it runs one, and
# oauth-provider-ui's vite config imports this package. Without it the run
# ends in a startup error naming a package the space tests never touch.
pnpm --filter '@atproto/oauth-provider-api' run build
Then:
npm run test:reference
npm run test:reference -- --refresh-fixtures # also update committed fixtures
--refresh-fixtures records the upstream SHA in the manifest; regenerating the
fixtures is how they track upstream, the same ritual as
test/fixtures/space-vectors.json.
Each alpha release moves upstream. Read generatedFrom.sha in the manifest to
see which upstream commit the committed fixtures came from, and move the
worktree to the new release before trusting a run against it. pnpm install
and the builds have to run again afterwards.
Notes
- Keys are generated fresh per run, and ECDSA signing faults can be
probabilistic (atproto rejects high-S signatures, which
crypto.subtle.signemits about half the time) — run it a few times when touching crypto. - Committed token fixtures are always expired, so the fixture-based test checks parsing and signatures, and sets the clock to the credential's issue time for the request it serves; expiry is exercised by unit tests and the live run.
- Not covered: the reference PDS as a running server (this exercises its verification library, not its HTTP endpoints), secp256k1 keys, blob bytes, and oplog replay over time.