An AT Protocol Personal Data Server written in JavaScript pdsjs.dev
pds atproto
README.md

space-reference #

Tests permissioned data against the reference implementation (bluesky-social/atproto PR #5187), in both directions:

  • pds.js produces, reference verifies. gen-artifacts.mjs drives the space handlers to build a repo and tokens; ref-verify.test.ts runs the reference's verifyRepoCarFull and verifySpaceToken over them. Passing means BLAKE3, LtHash, the commit ctx encoding, the MAC, the signature, the CAR layout and canonical DAG-CBOR ordering all agree.
  • Reference produces, pds.js verifies. ref-generate.test.ts builds a repo with @atproto/space; test/space-reference.test.js verifies it with @pdsjs/spaces, recomputing the set hash from the records rather than trusting the index.

Both directions carry negative cases (wrong author, wrong space, 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 pr-5187
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

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 the moving PR, the same ritual as test/fixtures/space-vectors.json.

The PR moves, and a worktree left on pr-5187 for a few days is behind it. Read generatedFrom.sha in the manifest to see which upstream commit the committed fixtures came from, and fast-forward the worktree before trusting a run against it. Both pnpm install and both 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.sign emits 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; 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, blobs, and oplog replay over time.