// Example Node.js PDS server import { createLogEmailer, createServer, createSmtpEmailer } from '@pdsjs/node'; /** * Pick a backup target from the environment. A directory is the simple case * (`PDS_BACKUP_DIR`, ideally a different disk than the database); an * S3-compatible bucket — Bunny, Backblaze B2, MinIO, R2, AWS — takes * `PDS_BACKUP_S3_ENDPOINT`, `PDS_BACKUP_S3_BUCKET`, `PDS_BACKUP_S3_ACCESS_KEY` * and `PDS_BACKUP_S3_SECRET_KEY` (plus `PDS_BACKUP_S3_REGION` where the * provider cares), no SDK required. Neither set, the backups page reports * backups as unavailable. */ async function backupTargetFromEnv() { if (!process.env.PDS_BACKUP_S3_BUCKET) return undefined; const { createS3FetchBackupTarget } = await import('@pdsjs/blobs-s3'); return createS3FetchBackupTarget({ endpoint: /** @type {string} */ (process.env.PDS_BACKUP_S3_ENDPOINT), bucket: process.env.PDS_BACKUP_S3_BUCKET, region: process.env.PDS_BACKUP_S3_REGION || 'us-east-1', accessKeyId: /** @type {string} */ (process.env.PDS_BACKUP_S3_ACCESS_KEY), secretAccessKey: /** @type {string} */ ( process.env.PDS_BACKUP_S3_SECRET_KEY ), }); } /** * Pick a mail sender from the environment. `smtp` delivers to a catch-all * inbox like Mailpit (see docker-compose) so sent mail is visible in a * browser; `log` prints codes to the terminal; anything else stores addresses * without being able to confirm them. */ function emailerFromEnv() { if (process.env.PDS_EMAIL_TRANSPORT === 'smtp') return createSmtpEmailer({ host: process.env.PDS_SMTP_HOST, port: process.env.PDS_SMTP_PORT ? Number(process.env.PDS_SMTP_PORT) : undefined, from: process.env.PDS_EMAIL_FROM, }); if (process.env.PDS_EMAIL_TRANSPORT === 'log') return createLogEmailer(); return undefined; } const { listen } = await createServer({ dbPath: process.env.PDS_DB_PATH || './pds.db', blobsDir: process.env.PDS_BLOBS_DIR || './blobs', jwtSecret: process.env.JWT_SECRET || 'development-secret', blobUploadLimit: process.env.PDS_BLOB_UPLOAD_LIMIT ? Number(process.env.PDS_BLOB_UPLOAD_LIMIT) : undefined, port: parseInt(process.env.PORT || '3000', 10), hostname: process.env.HOSTNAME, appviewUrl: process.env.APPVIEW_URL, appviewDid: process.env.APPVIEW_DID, relayUrl: process.env.RELAY_URL, plcUrl: process.env.PLC_URL, password: process.env.PDS_PASSWORD, // Development only. A deployment supplies a real sender here. emailer: emailerFromEnv(), // The React account application. Installed here, so on unless refused. accountUi: process.env.PDS_ACCOUNT_UI !== 'false', // Permissioned data (proposal 0016). Off unless explicitly enabled. spaces: process.env.PDS_ENABLE_SPACES === 'true', // Semver-exempt experiments; see the experimental option's documentation. experimental: { // Git hosting: smart HTTP off unless enabled, browsing on unless // refused. `external` hands the reads to a separate forge process and // keeps only the branch-protection write guard here. git: { http: process.env.PDS_EXPERIMENTAL_GIT_HTTP === 'true', browse: process.env.PDS_EXPERIMENTAL_GIT_BROWSE !== 'false', external: process.env.PDS_EXPERIMENTAL_GIT_EXTERNAL === 'true', }, // Files stored in the repo, on unless refused. drive: process.env.PDS_EXPERIMENTAL_DRIVE !== 'false', // Registries for what this account publishes, both off unless enabled. // Each needs its own optional peer package installed. oci: process.env.PDS_EXPERIMENTAL_OCI === 'true', npm: process.env.PDS_EXPERIMENTAL_NPM === 'true', // Static sites from the repo (off without a domain) and queries. sites: { domain: process.env.PDS_EXPERIMENTAL_SITE_DOMAIN, apexName: process.env.PDS_EXPERIMENTAL_SITE_APEX_NAME, queries: process.env.PDS_EXPERIMENTAL_QUERIES === 'true', }, }, // Scheduled backups: a directory, or an S3-compatible bucket. backupDir: process.env.PDS_BACKUP_DIR, backupTarget: await backupTargetFromEnv(), }); await listen();