chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
// Entrypoint for the container image. The image is a deployment artifact
// rather than part of the published API, so this composes @pdsjs/node from
// the environment the same way examples/node does, instead of adding a bin
// to the package.
import { createServer } from '@pdsjs/node';
/**
* Secrets and identity have no safe default. A container that quietly falls
* back to a well-known JWT secret issues tokens anyone can forge, one that
* guesses its own hostname serves a DID document nobody can resolve, and one
* with no account password accepts any password at all.
* @param {string} name
* @returns {string}
*/
function required(name) {
const value = process.env[name];
if (!value) {
console.error(`missing required environment variable: ${name}`);
process.exit(1);
}
return value;
}
const port = Number.parseInt(process.env.PORT || '3000', 10);
const server = await createServer({
hostname: required('PDS_HOSTNAME'),
jwtSecret: required('JWT_SECRET'),
dbPath: process.env.PDS_DB_PATH || '/data/pds.db',
blobsDir: process.env.PDS_BLOBS_DIR || '/data/blobs',
port,
appviewUrl: process.env.APPVIEW_URL,
appviewDid: process.env.APPVIEW_DID,
relayUrl: process.env.RELAY_URL,
plcUrl: process.env.PLC_URL,
password: required('PDS_PASSWORD'),
// Permissioned data (proposal 0016). Off unless explicitly enabled.
spaces: process.env.PDS_ENABLE_SPACES === 'true',
});
await server.listen();
console.log(`pds.js listening on :${port} as ${process.env.PDS_HOSTNAME}`);
// Container runtimes stop a process with SIGTERM. Without this the runtime
// waits out its full grace period on every restart, and SQLite is closed by
// the kill rather than by us.
for (const signal of ['SIGTERM', 'SIGINT']) {
process.on(signal, () => {
server.close().then(
() => process.exit(0),
(/** @type {unknown} */ err) => {
console.error(err);
process.exit(1);
},
);
});
}