// 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); }, ); }); }