/** * Initialize the local PDS environment for development. * * Generates the pds/pds.env file with the necessary secrets and configuration. * Run this once before starting the PDS for the first time. * * Usage: bun run scripts/pds-init.ts */ import { existsSync, mkdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { randomBytes } from "node:crypto"; const ROOT = join(import.meta.dir, ".."); const PDS_DIR = join(ROOT, "pds"); const ENV_FILE = join(PDS_DIR, "pds.env"); if (existsSync(ENV_FILE)) { console.log("pds/pds.env already exists. Delete it to regenerate."); process.exit(0); } mkdirSync(PDS_DIR, { recursive: true }); const jwtSecret = randomBytes(32).toString("hex"); const adminPassword = "localdev"; const plcRotationKey = randomBytes(32).toString("hex"); // AT Protocol disallows these TLDs for handles: // .local, .arpa, .invalid, .localhost, .internal, .example, .alt, .onion // We use a real-looking domain so handle validation passes. // Handles will be .pds.dev — they won't resolve via DNS, but that's // fine for local dev (use the DID to log in instead). const pdsHostname = "pds.dev"; const env = `# Generated by scripts/pds-init.ts — do not commit PDS_HOSTNAME=${pdsHostname} PDS_PORT=3000 PDS_JWT_SECRET=${jwtSecret} PDS_ADMIN_PASSWORD=${adminPassword} PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=${plcRotationKey} PDS_DATA_DIRECTORY=/pds/data PDS_BLOBSTORE_DISK_LOCATION=/pds/data/blocks PDS_DID_PLC_URL=https://plc.directory PDS_DEV_MODE=1 PDS_LOG_ENABLED=true # AppView and moderation are not needed for local dev # but the PDS may require them to start PDS_BSKY_APP_VIEW_URL=https://api.bsky.app PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app PDS_REPORT_SERVICE_URL=https://mod.bsky.app PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac PDS_CRAWLERS= `; writeFileSync(ENV_FILE, env); console.log("Created pds/pds.env"); console.log(` Admin password: ${adminPassword}`); console.log(""); console.log("Start the PDS with:"); console.log(" docker compose -f docker-compose.dev.yml up -d");