chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
import { cborEncodeDagCbor, cidToString, createCid } from '@pdsjs/core/repo';
import { describe, expect, it } from 'vitest';
import { createQueryEngine, fieldAt } from '../src/query.js';
const DID = 'did:plc:querytest';
const DEFS = 'dev.pdsjs.query.def';
/**
* In-memory actorStorage over a mutable record set. Records are stored as
* DAG-CBOR bytes, the same shape the real storage returns.
* @param {Map<string, {value: unknown}>} store - uri -> record value
*/
function storageOver(store) {
const encoded = (/** @type {string} */ uri) => {
const entry = store.get(uri);
if (!entry) return null;
const bytes = cborEncodeDagCbor(entry.value);
return { bytes, cidOf: createCid(bytes) };
};
return /** @type {any} */ ({
listRecords: async (
/** @type {string} */ collection,
/** @type {string|null} */ cursor,
/** @type {number} */ limit,
) => {
const uris = [...store.keys()]
.filter((uri) => uri.includes(`/${collection}/`))
.sort();
const start = cursor ? Number(cursor) : 0;
const page = uris.slice(start, start + limit);
const records = [];
for (const uri of page) {
const row = encoded(uri);
if (!row) continue;
records.push({
uri,
cid: cidToString(await row.cidOf),
value: row.bytes,
});
}
const next = start + page.length;
return { records, cursor: next < uris.length ? String(next) : null };
},
getRecord: async (/** @type {string} */ uri) => {
const row = encoded(uri);
if (!row) return null;
return { cid: cidToString(await row.cidOf), value: row.bytes };
},
});
}
/** @param {Record<string, unknown>} defValue */
function withDef(defValue, extra = new Map()) {
const store = new Map(extra);
store.set(`at://${DID}/${DEFS}/test`, {
value: { $type: DEFS, createdAt: '2026-08-10T00:00:00.000Z', ...defValue },
});
return store;
}
/** @param {Map<string, {value: unknown}>} store */
function engineOver(store) {
return createQueryEngine({
actorStorage: storageOver(store),
getDid: async () => DID,
});
}
/** @param {ReturnType<typeof createQueryEngine>} engine @param {string} qs */
async function run(engine, qs) {
const url = new URL(`https://pds.example.com/xrpc/dev.pdsjs.query.run${qs}`);
const handler = engine.routes['/xrpc/dev.pdsjs.query.run'].handler;
const response = await handler(new Request(url), url);
return { status: response.status, body: await response.json() };
}
/** Three notes with staggered TIDs and scores. */
function noteRecords() {
const store = new Map();
const notes = [
{ rkey: '3aaa', text: 'first', score: 3 },
{ rkey: '3bbb', text: 'second', score: 1 },
{ rkey: '3ccc', text: 'third', score: 2 },
];
for (const note of notes) {
store.set(`at://${DID}/com.example.note/${note.rkey}`, {
value: {
$type: 'com.example.note',
text: note.text,
meta: { score: note.score },
},
});
}
return store;
}
describe('fieldAt', () => {
it('walks dot paths and returns undefined off the map', () => {
expect(fieldAt({ a: { b: 7 } }, 'a.b')).toBe(7);
expect(fieldAt({ a: 1 }, 'a.b')).toBeUndefined();
expect(fieldAt(null, 'a')).toBeUndefined();
});
});
describe('dev.pdsjs.query.run', () => {
it('requires a query name and 404s unknown ones', async () => {
const engine = engineOver(withDef({ collection: 'com.example.note' }));
expect((await run(engine, '')).status).toBe(400);
expect((await run(engine, '?query=nope')).status).toBe(404);
});
it('returns a whole collection newest-first by default', async () => {
const engine = engineOver(
withDef({ collection: 'com.example.note' }, noteRecords()),
);
const { status, body } = await run(engine, '?query=test');
expect(status).toBe(200);
expect(body.records.map((/** @type {any} */ r) => r.value.text)).toEqual([
'third',
'second',
'first',
]);
expect(body.cursor).toBeUndefined();
});
it('sorts by a dot-path field in either direction', async () => {
const asc = engineOver(
withDef(
{
collection: 'com.example.note',
sort: { field: 'meta.score', direction: 'asc' },
},
noteRecords(),
),
);
const { body } = await run(asc, '?query=test');
expect(
body.records.map((/** @type {any} */ r) => r.value.meta.score),
).toEqual([1, 2, 3]);
const desc = engineOver(
withDef(
{
collection: 'com.example.note',
sort: { field: 'meta.score', direction: 'desc' },
},
noteRecords(),
),
);
const result = await run(desc, '?query=test');
expect(
result.body.records.map((/** @type {any} */ r) => r.value.meta.score),
).toEqual([3, 2, 1]);
});
it('filters on where equality over dot paths', async () => {
const engine = engineOver(
withDef(
{ collection: 'com.example.note', where: { 'meta.score': 2 } },
noteRecords(),
),
);
const { body } = await run(engine, '?query=test');
expect(body.records).toHaveLength(1);
expect(body.records[0].value.text).toBe('third');
});
it('pages with limit and an offset cursor', async () => {
const engine = engineOver(
withDef({ collection: 'com.example.note' }, noteRecords()),
);
const first = await run(engine, '?query=test&limit=2');
expect(first.body.records).toHaveLength(2);
expect(first.body.cursor).toBe('2');
const second = await run(engine, '?query=test&limit=2&cursor=2');
expect(second.body.records).toHaveLength(1);
expect(second.body.cursor).toBeUndefined();
});
it('rejects a definition without a collection', async () => {
const engine = engineOver(withDef({}));
expect((await run(engine, '?query=test')).status).toBe(400);
});
});
describe('onCommit maintenance', () => {
it('applies creates, updates, and deletes to a loaded collection', async () => {
const store = withDef({ collection: 'com.example.note' }, noteRecords());
const engine = engineOver(store);
await run(engine, '?query=test');
const uri = `at://${DID}/com.example.note/3ddd`;
store.set(uri, {
value: { $type: 'com.example.note', text: 'fourth', meta: { score: 9 } },
});
await engine.onCommit({
did: DID,
seq: 1,
rev: 'rev1',
ops: [{ action: 'create', uri, cid: 'bafycid' }],
});
let result = await run(engine, '?query=test');
expect(result.body.records[0].value.text).toBe('fourth');
store.set(uri, {
value: { $type: 'com.example.note', text: 'fourth-edited', meta: {} },
});
await engine.onCommit({
did: DID,
seq: 2,
rev: 'rev2',
ops: [{ action: 'update', uri, cid: 'bafycid2' }],
});
result = await run(engine, '?query=test');
expect(result.body.records[0].value.text).toBe('fourth-edited');
store.delete(uri);
await engine.onCommit({
did: DID,
seq: 3,
rev: 'rev3',
ops: [{ action: 'delete', uri, cid: null }],
});
result = await run(engine, '?query=test');
expect(result.body.records).toHaveLength(3);
});
it('leaves collections nobody queried alone', async () => {
const store = withDef({ collection: 'com.example.note' }, noteRecords());
const storage = storageOver(store);
let reads = 0;
const counted = /** @type {any} */ ({
...storage,
getRecord: (/** @type {string} */ uri) => {
reads += 1;
return storage.getRecord(uri);
},
});
const engine = createQueryEngine({
actorStorage: counted,
getDid: async () => DID,
});
await engine.onCommit({
did: DID,
seq: 1,
rev: 'rev1',
ops: [
{
action: 'create',
uri: `at://${DID}/com.example.note/3zzz`,
cid: 'bafycid',
},
],
});
expect(reads).toBe(0);
});
it('makes a def written after startup queryable at once', async () => {
const store = withDef({ collection: 'com.example.note' }, noteRecords());
const engine = engineOver(store);
await run(engine, '?query=test');
const uri = `at://${DID}/${DEFS}/scores`;
store.set(uri, {
value: {
$type: DEFS,
collection: 'com.example.note',
sort: { field: 'meta.score', direction: 'asc' },
createdAt: '2026-08-10T00:00:00.000Z',
},
});
await engine.onCommit({
did: DID,
seq: 4,
rev: 'rev4',
ops: [{ action: 'create', uri, cid: 'bafydef' }],
});
const { status, body } = await run(engine, '?query=scores');
expect(status).toBe(200);
expect(body.records[0].value.meta.score).toBe(1);
});
});