// The private write path and the ticket (design §18): what a writer does where a PDS would. import assert from 'node:assert/strict' import { describe, it } from 'node:test' import { COLLECTIONS } from '../dist/generated/records.js' import { MemoryRecordStore } from '../dist/store.js' import { materialize } from '../dist/materializer.js' import { recordCid } from '../dist/private/cid.js' import { createTidSource } from '../dist/private/tid.js' import { exportPublicKey, exportSigningKey, generateDeviceKey, importSigningKey, seal, verifyEnvelope, } from '../dist/private/envelope.js' import { admit } from '../dist/private/admission.js' import { MemoryEnvelopeStore } from '../dist/private/envelope-store.js' import { EnvelopeWriter, unsignedVersions } from '../dist/private/writer.js' import { TICKET_PREFIX, assertBootstrapTicket, assertSpacePin, decodeTicket, encodeTicket, mintTicket, spacePinMismatch, ticketDirectoryMismatch, ticketFingerprint, } from '../dist/private/ticket.js' const ROOT = 'did:plc:privateroot' const SPACE = `at://${ROOT}/${COLLECTIONS.space}/space` async function device(did, keyId) { const pair = await generateDeviceKey(true) return { did, keyId, publicKey: await exportPublicKey(pair.publicKey), privateKey: pair.privateKey } } /** The public `device` record a repo poll would have written, for the fold and for admission. */ const directoryRecord = (signer, createdAt = '2026-03-01T00:00:00Z') => ({ did: signer.did, collection: COLLECTIONS.device, rkey: signer.keyId, uri: `at://${signer.did}/${COLLECTIONS.device}/${signer.keyId}`, cid: `cid-device-${signer.keyId}`, rev: '0000000000001', value: { $type: COLLECTIONS.device, deviceKeyId: signer.keyId, publicKey: signer.publicKey, algorithm: 'ed25519', kind: 'node', createdAt, }, }) /** * A replica: a record store, an envelope store, and the one admission gate every envelope goes * through — the writer's own included, which is the property these tests are mostly about. */ function replica(...signers) { const records = new MemoryRecordStore() const envelopes = new MemoryEnvelopeStore(records) for (const signer of signers) records.put(directoryRecord(signer)) const keys = { publicKeyFor: (did, keyId) => signers.find((signer) => signer.did === did && signer.keyId === keyId)?.publicKey, } const published = [] const admitEnvelope = async (envelope) => { const outcome = await admit(envelope, { spaceUri: SPACE, keys }) if (outcome.status !== 'admitted') throw new Error(`${outcome.status}: ${outcome.reason}`) envelopes.put(outcome.envelope, '2026-03-01T00:00:00Z') } return { records, envelopes, published, admit: admitEnvelope, publish: async (envelope) => { published.push(envelope) }, writer: (signer, tid = createTidSource(() => 1_700_000_000_000, 7)) => new EnvelopeWriter({ spaceUri: SPACE, signer: { did: signer.did, deviceKeyId: signer.keyId, privateKey: signer.privateKey }, records, admit: admitEnvelope, publish: async (envelope) => { published.push(envelope) }, tid, }), } } const spaceRecord = { $type: COLLECTIONS.space, name: 'Private', description: 'off the PDS', private: true, createdAt: '2026-03-01T00:00:00Z', } describe('the private write path', () => { it('commits locally before it publishes, and returns the strongref a PDS would have', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) const writer = site.writer(root) const ref = await writer.create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }) assert.equal(ref.uri, SPACE) // The CID is the record's own canonical bytes — the same value a PDS would have computed, which // is what makes a strongref mean one thing across both buses. assert.equal(ref.cid, await recordCid(spaceRecord)) assert.equal(site.records.get(ROOT, COLLECTIONS.space, 'space').cid, ref.cid) assert.equal(site.published.length, 1) assert.equal(site.published[0].recordCid, ref.cid) assert.deepEqual(site.records.get(ROOT, COLLECTIONS.space, 'space').deviceKeyIds, ['root-node-1']) }) it('returns at local commit while delivery is pending', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) let release const delivery = new Promise((resolve) => { release = resolve }) let offered const writer = new EnvelopeWriter({ spaceUri: SPACE, signer: { did: root.did, deviceKeyId: root.keyId, privateKey: root.privateKey }, records: site.records, admit: site.admit, publish: async (envelope) => { offered = envelope await delivery }, tid: createTidSource(() => 1_700_000_000_000, 7), }) const ref = await writer.create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }) assert.equal(ref.cid, await recordCid(spaceRecord)) assert.equal(offered.recordCid, ref.cid) assert.equal(site.records.get(ROOT, COLLECTIONS.space, 'space').cid, ref.cid) assert.equal(site.envelopes.has(offered), true) release() await delivery }) it('contains a rejected delivery after commit without rejecting the write', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) const unhandled = [] const onUnhandled = (reason) => unhandled.push(reason) process.on('unhandledRejection', onUnhandled) try { const writer = new EnvelopeWriter({ spaceUri: SPACE, signer: { did: root.did, deviceKeyId: root.keyId, privateKey: root.privateKey }, records: site.records, admit: site.admit, publish: async () => { throw new Error('peer disappeared') }, tid: createTidSource(() => 1_700_000_000_000, 7), }) const ref = await writer.create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }) await new Promise((resolve) => setImmediate(resolve)) assert.equal(site.records.get(ROOT, COLLECTIONS.space, 'space').cid, ref.cid) assert.deepEqual(unhandled, []) } finally { process.off('unhandledRejection', onUnhandled) } }) it('publishes nothing when its own replica refuses the write', async () => { const root = await device(ROOT, 'root-node-1') const stranger = await device('did:plc:stranger', 'stranger-1') // The replica knows the stranger's key, so admission is not what fails: a record for ANOTHER // space is refused by the space binding, and the refusal has to come before the gossip. const site = replica(root, stranger) const writer = new EnvelopeWriter({ spaceUri: SPACE, signer: { did: root.did, deviceKeyId: root.keyId, privateKey: root.privateKey }, records: site.records, admit: async (envelope) => { const outcome = await admit(envelope, { spaceUri: 'at://did:plc:elsewhere/com.disnetdev.radial.space/other', keys: { publicKeyFor: () => root.publicKey }, }) if (outcome.status !== 'admitted') throw new Error(outcome.reason) }, publish: site.publish, tid: createTidSource(() => 1_700_000_000_000, 7), }) await assert.rejects( () => writer.create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }), /different space/, ) assert.equal(site.published.length, 0) }) it('refuses a second create at a taken rkey, the way a PDS does', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) const writer = site.writer(root) await writer.create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }) // `space join` writes a deterministic rkey precisely so a second attempt collides instead of // leaving two identical bookmarks in the repo. Nothing collides on its own here. await assert.rejects( () => writer.create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }), /RecordAlreadyExists/, ) }) it('mints a TID rkey when the caller does not pin one', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) const writer = site.writer(root) const first = await writer.create(COLLECTIONS.space, spaceRecord) const second = await writer.create(COLLECTIONS.space, { ...spaceRecord, name: 'Second' }) assert.notEqual(first.uri, second.uri) for (const ref of [first, second]) { assert.match(ref.uri, /^at:\/\/did:plc:privateroot\/com\.disnetdev\.radial\.space\/[234567a-z]{13}$/) } }) it('validates the record before anything is signed', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) await assert.rejects( () => site.writer(root).create(COLLECTIONS.space, { $type: COLLECTIONS.space, name: 'no createdAt' }), /createdAt/, ) assert.equal(site.published.length, 0) }) it('rewrites a deviceAddress in place, and refuses one it does not author', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) const writer = site.writer(root) const address = { $type: COLLECTIONS.deviceAddress, deviceKeyId: 'root-node-1', endpointId: 'a'.repeat(64), createdAt: '2026-03-01T00:00:00Z', } const first = await writer.create(COLLECTIONS.deviceAddress, address, { rkey: 'root-node-1' }) const moved = { ...address, endpointId: 'b'.repeat(64), createdAt: '2026-03-02T00:00:00Z' } const second = await writer.put(COLLECTIONS.deviceAddress, first.uri, moved, { swapRecord: first.cid }) assert.notEqual(second.cid, first.cid) // The third sanctioned in-place rewrite: latest rev wins, and `rev` here is the writer's own TID // inside the signed envelope rather than an observer-local repo revision. assert.equal(site.records.get(ROOT, COLLECTIONS.deviceAddress, 'root-node-1').value.endpointId, 'b'.repeat(64)) await assert.rejects( () => writer.put(COLLECTIONS.deviceAddress, `at://did:plc:someone/${COLLECTIONS.deviceAddress}/x`, moved), /Only a record's author can edit it/, ) await assert.rejects( () => writer.put(COLLECTIONS.deviceAddress, first.uri, moved, { swapRecord: first.cid }), /InvalidSwap/, ) }) it('answers getOwnRecord out of the store, which IS the commit here', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) const writer = site.writer(root) assert.equal(await writer.getOwnRecord(COLLECTIONS.space, 'space'), undefined) const ref = await writer.create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }) const held = await writer.getOwnRecord(COLLECTIONS.space, 'space') assert.deepEqual({ uri: held.uri, cid: held.cid }, ref) assert.equal(held.value.name, 'Private') }) }) describe('device signing keys', () => { it('round-trip an extractable key through the form a daemon writes to disk', async () => { const pair = await generateDeviceKey(true) const stored = await exportSigningKey(pair.privateKey) const reloaded = await importSigningKey(stored) const envelope = await seal({ space: SPACE, did: ROOT, collection: COLLECTIONS.space, rkey: 'space', record: spaceRecord, rev: '3ms26zx46yg2f', deviceKeyId: 'root-node-1', privateKey: reloaded, }) assert.equal(await verifyEnvelope(envelope, await exportPublicKey(pair.publicKey)), true) }) it('cannot export a browser-shaped key, which is the point of one', async () => { const pair = await generateDeviceKey() await assert.rejects(() => exportSigningKey(pair.privateKey)) }) }) describe('the creation ticket', () => { const ticketFor = (root) => mintTicket({ space: { uri: SPACE, cid: 'bafyreispace' }, founder: ROOT, device: { deviceKeyId: root.keyId, publicKey: root.publicKey, algorithm: 'ed25519' }, relays: ['https://relay.example'], peerHints: [ROOT], issuedAt: '2026-03-01T00:00:00Z', }) it('round-trips through the one-line form', async () => { const root = await device(ROOT, 'root-node-1') const encoded = encodeTicket(ticketFor(root)) assert.ok(encoded.startsWith(TICKET_PREFIX)) assert.deepEqual(decodeTicket(` ${encoded}\n`), ticketFor(root)) }) it('keeps old tickets readable but requires one unique hint to bootstrap', async () => { const root = await device(ROOT, 'root-node-1') const valid = ticketFor(root) assert.doesNotThrow(() => assertBootstrapTicket(valid)) const { peerHints: _peerHints, ...old } = valid assert.deepEqual(decodeTicket(encodeTicket(old)), old) assert.throws(() => assertBootstrapTicket(old), /fresh transfer ticket/) assert.throws(() => assertBootstrapTicket({ ...valid, peerHints: [] }), /fresh transfer ticket/) assert.throws(() => assertBootstrapTicket({ ...valid, peerHints: [ROOT, ROOT] }), /duplicates/) }) it('refuses a ticket whose founder does not author the space record', async () => { const root = await device(ROOT, 'root-node-1') assert.throws( () => mintTicket({ space: { uri: 'at://did:plc:someoneelse/com.disnetdev.radial.space/space', cid: 'bafyreispace' }, founder: ROOT, device: { deviceKeyId: root.keyId, publicKey: root.publicKey, algorithm: 'ed25519' }, issuedAt: '2026-03-01T00:00:00Z', }), /does not author the space record/, ) }) it('refuses text that is not a ticket, and a key that is not an Ed25519 key', async () => { assert.throws(() => decodeTicket('at://did:plc:root/space'), /not a Radial ticket/) assert.throws(() => decodeTicket(`${TICKET_PREFIX}bm90LWpzb24`), /not readable/) const root = await device(ROOT, 'root-node-1') assert.throws( () => encodeTicket({ ...ticketFor(root), device: { ...ticketFor(root).device, publicKey: 'short' } }), /32 bytes of unpadded base64url/, ) }) it('fingerprints the encoded form, so a log can name a ticket without carrying it', async () => { const root = await device(ROOT, 'root-node-1') const ticket = ticketFor(root) const fingerprint = await ticketFingerprint(ticket) assert.match(fingerprint, /^[0-9a-f]{12}$/) assert.equal(await ticketFingerprint(encodeTicket(ticket)), fingerprint) assert.notEqual(await ticketFingerprint({ ...ticket, relays: ['https://other.example'] }), fingerprint) }) it('reports a directory that disagrees with the ticket — and never folds differently', async () => { const root = await device(ROOT, 'root-node-1') const impostor = await device(ROOT, 'root-node-1') const ticket = ticketFor(root) assert.deepEqual(ticketDirectoryMismatch(ticket, []), { kind: 'missing' }) assert.equal(ticketDirectoryMismatch(ticket, [directoryRecord(root)]), undefined) const mismatch = ticketDirectoryMismatch(ticket, [directoryRecord(impostor)]) assert.equal(mismatch.kind, 'mismatch') assert.match(mismatch.reason, /somebody else is writing to that repo/) // A SIGNED copy of a device record is not the founder's PDS speaking, so it answers nothing — // the same rule `readDeviceDirectory` applies, for the same reason. assert.deepEqual( ticketDirectoryMismatch(ticket, [{ ...directoryRecord(root), deviceKeyIds: ['root-node-1'] }]), { kind: 'missing' }, ) }) it('pins the space record by cid, and says so when the one held is a different version', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) const pin = (cid) => ({ uri: SPACE, cid }) // Nothing held yet: an invitee who has accepted a ticket and reached no peer compares nothing. assert.equal(spacePinMismatch(pin('bafyreiwhatever'), site.records), undefined) const written = await site.writer(root).create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }) assert.equal(spacePinMismatch(pin(written.cid), site.records), undefined) const mismatch = spacePinMismatch(pin('bafyreisomeotherspacerecord'), site.records) assert.equal(mismatch.held, written.cid) assert.equal(mismatch.expected, 'bafyreisomeotherspacerecord') assert.match(mismatch.reason, /A space record is never rewritten/) assert.throws(() => assertSpacePin(pin('bafyreisomeotherspacerecord'), site.records), /never rewritten/) }) it('refuses a pin that does not name a space record', async () => { const site = replica() assert.throws(() => spacePinMismatch({ uri: 'not-a-uri', cid: 'x' }, site.records), /Not a space AT URI/) assert.throws( () => spacePinMismatch({ uri: `at://${ROOT}/${COLLECTIONS.goal}/goal`, cid: 'x' }, site.records), /must name a com.disnetdev.radial.space record/, ) }) it('is not a trust input: the fold never reads one', async () => { const root = await device(ROOT, 'root-node-1') const site = replica(root) const writer = site.writer(root) await writer.create(COLLECTIONS.space, spaceRecord, { rkey: 'space' }) const index = materialize(site.records, { spaceUri: SPACE }) assert.equal(index.private, true) // Nothing in the index carries a ticket, and no ignore reason mentions one. assert.equal(JSON.stringify(index).includes('ticket'), false) }) })