chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
/**
* Permissioned data as a server extension: the platform builds the space
* storage and passes the factory to core's `extensions` option; core mounts
* the space endpoints, the account page's space routes and the admin port
* behind them.
*/
import { createSpaceAccountRoutes } from './account.js';
import { createSpaceAdmin } from './admin.js';
import { createNotifyOutbox } from './outbox.js';
import { createSpaceRoutes } from './routes.js';
/**
* @param {Object} [options]
* @param {typeof fetch} [options.fetch] - for the outbound notification calls; defaults to the global fetch
* @returns {import('@pdsjs/core/ports').ExtensionFactory}
*/
export function createSpacesExtension({ fetch: fetchImpl } = {}) {
return (host) => {
const { spaceStorage, actorStorage, blobs, didResolver, verifier } = host;
if (!spaceStorage) {
throw new Error('The spaces extension needs spaceStorage on the server');
}
if (!didResolver || !verifier) {
throw new Error(
'The spaces extension needs a didResolver and a verifier on the server',
);
}
const spaceAdmin = createSpaceAdmin({ spaceStorage, getDid: host.getDid });
const outbox = createNotifyOutbox({
spaceStorage,
getDid: host.getDid,
getSigner: host.getSigner,
resolveDid: didResolver,
fetch: fetchImpl ?? ((url, init) => fetch(url, init)),
scheduleWakeup: host.scheduleWakeup,
background: host.background,
});
return {
name: 'spaces',
// The space endpoints hold records of every collection an app writes
// into a space.
collections: ['*'],
routes: {
...createSpaceRoutes({
spaceStorage,
// A space record's blobs are ordinary account blobs, uploaded
// through com.atproto.repo.uploadBlob and linked in the one blob
// link table, so orphan cleanup sees a space reference the same as
// a public one.
blobs,
linkBlob: (cid, uri, time) =>
actorStorage.linkBlobToRecord(cid, uri, time),
unlinkBlobs: (uri) => actorStorage.unlinkBlobsFromRecord(uri),
getDid: host.getDid,
// The full document: space auth verifies signatures against the
// document's verification methods.
resolveDid: didResolver,
verifier,
recordGuard: host.writeGuard,
// Space tokens and service auth are signed by the account's atproto
// signing key; its KEM key MACs reads of its space repos.
getSigner: host.getSigner,
getKemKey: host.getKemKey,
fetch: fetchImpl ?? ((url, init) => fetch(url, init)),
outbox,
background: host.background,
}),
...createSpaceAccountRoutes({
host,
spaceBrowser: host.spaceBrowser ?? null,
spaceAdmin,
}),
},
features: { spaceAdmin: true },
// Write notices this repo still owes the authorities of spaces it
// writes into, and deletion notices owed to the syncers of spaces it
// deleted.
tick: () => outbox.tick(),
};
};
}