chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
// The sites extension against a fake host: a domain turns on the host
// handler, browser and installer; without one only the installs routes
// mount; queries add their route and commit tap.
import {
CID,
cborEncodeDagCbor,
cidToString,
createBlobCid,
createCid,
} from '@pdsjs/core/repo';
import { beforeEach, describe, expect, it } from 'vitest';
import { createSitesExtension } from '../src/extension.js';
import { clearManifestCache } from '../src/manifest.js';
const DID = 'did:plc:sitesextension';
/**
* One-file site record for `name`, plus the blob it points at.
* @param {string} name
*/
async function siteFixture(name) {
const data = new TextEncoder().encode(`<h1>${name}</h1>`);
const cidBytes = await createBlobCid(data);
const record = cborEncodeDagCbor({
$type: 'dev.pdsjs.site.deploy',
files: [
{
path: 'index.html',
blob: {
$type: 'blob',
ref: new CID(cidBytes),
mimeType: 'text/html',
size: data.length,
},
},
],
createdAt: '2026-08-06T00:00:00.000Z',
});
return {
uri: `at://${DID}/dev.pdsjs.site.deploy/${name}`,
row: { cid: cidToString(await createCid(record)), value: record },
blobCid: cidToString(cidBytes),
data,
};
}
/** @param {Awaited<ReturnType<typeof siteFixture>>[]} sites */
function createHost(sites) {
const records = new Map(sites.map((site) => [site.uri, site.row]));
const blobs = new Map(sites.map((site) => [site.blobCid, site.data]));
const host = {
actorStorage: {
getRecord: async (/** @type {string} */ uri) => records.get(uri) ?? null,
listRecords: async () => ({ records: [], cursor: null }),
linkBlobToRecord: async () => {},
},
blobs: {
get: async (/** @type {string} */ _did, /** @type {string} */ cid) => {
const data = blobs.get(cid);
return data ? { data, mimeType: 'text/html' } : null;
},
},
readOnly: false,
plcUrl: 'https://plc.directory',
blobUploadLimit: 1024,
getDid: async () => DID,
xrpc: async () => new Response('{}'),
createCommit: async () => ({ cid: 'bafy', rev: '3l' }),
reapOrphanedBlobs: async () => {},
accountApi: async () => new Response('{}'),
};
return /** @type {import('@pdsjs/core/ports').ExtensionHost} */ (
/** @type {unknown} */ (host)
);
}
beforeEach(() => clearManifestCache());
describe('createSitesExtension', () => {
it('serves the apex from the named site when a domain is set', async () => {
const www = await siteFixture('www');
const extension = createSitesExtension({
domain: 'example.com',
apexName: 'www',
})(createHost([www]));
expect(extension.name).toBe('sites');
expect(extension.features).toEqual({ sites: true });
expect(Object.keys(extension.routes ?? {})).toEqual(
expect.arrayContaining(['/account/api/sites', '/account/api/installs']),
);
const url = new URL('https://example.com/');
const response = await extension.handleHost?.(new Request(url), url);
expect(response?.status).toBe(200);
expect(await response?.text()).toBe('<h1>www</h1>');
});
it('mounts only the installs routes without a domain', async () => {
const extension = createSitesExtension()(createHost([]));
expect(extension.features).toEqual({ sites: false });
expect(extension.handleHost).toBeUndefined();
expect(extension.onCommit).toBeUndefined();
const routes = Object.keys(extension.routes ?? {});
expect(routes).toContain('/account/api/installs');
expect(routes).toContain('/account/api/sites');
expect(routes).not.toContain('/xrpc/dev.pdsjs.query.run');
});
it('adds the query route and commit tap when asked', async () => {
const extension = createSitesExtension({ queries: true })(createHost([]));
expect(extension.routes?.['/xrpc/dev.pdsjs.query.run']).toBeDefined();
expect(typeof extension.onCommit).toBe('function');
});
});