chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
#!/usr/bin/env node
// Build the self-contained Cloudflare worker artifact.
//
// The output is what the Workers script-upload API takes: one module file plus
// a manifest naming the compatibility settings, the bindings the module
// expects, and the migration that creates the Durable Object class. A deploy
// tool uploads these directly; it needs no wrangler and no checkout.
//
// node scripts/build-worker-bundle.mjs [outdir]
//
// Default outdir: dist/worker
//
// VERSION_SUFFIX (e.g. "-canary.ab12cd3") appends to the package version. A
// canary build carries the suffix in its running version, not only in the
// manifest: it reaches /xrpc/_health through core's VERSION constant, which
// is what the account page and the update page compare against. The build
// stamps the constant in the source, bundles, and restores the source.
import { spawnSync } from 'node:child_process';
import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const outdir = resolve(process.argv[2] ?? join(repoRoot, 'dist', 'worker'));
const suffix = process.env.VERSION_SUFFIX ?? '';
const { version: packageVersion } = JSON.parse(
readFileSync(join(repoRoot, 'packages/cloudflare/package.json'), 'utf8'),
);
const version = `${packageVersion}${suffix}`;
rmSync(outdir, { recursive: true, force: true });
mkdirSync(outdir, { recursive: true });
// The same constant scripts/sync-version.js maintains.
const coreSource = join(repoRoot, 'packages/core/src/pds.js');
const versionPattern = /^const VERSION = '[^']*';$/m;
let originalSource = null;
if (suffix) {
originalSource = readFileSync(coreSource, 'utf8');
if (!versionPattern.test(originalSource)) {
throw new Error(
'no VERSION constant in packages/core/src/pds.js to stamp the suffix into',
);
}
writeFileSync(
coreSource,
originalSource.replace(versionPattern, `const VERSION = '${version}';`),
);
}
// Wrangler's dry run bundles exactly what deploy would upload.
let result;
try {
result = spawnSync(
'npx',
['wrangler', 'deploy', '--dry-run', `--outdir=${outdir}`],
{ cwd: repoRoot, stdio: 'inherit' },
);
} finally {
if (originalSource !== null) writeFileSync(coreSource, originalSource);
}
if (result.status !== 0) {
process.exit(result.status ?? 1);
}
// The README wrangler writes into the outdir describes wrangler, not the
// artifact.
rmSync(join(outdir, 'README.md'), { force: true });
const wranglerToml = readFileSync(join(repoRoot, 'wrangler.toml'), 'utf8');
const compatibilityDate = wranglerToml.match(
/compatibility_date\s*=\s*"([^"]+)"/,
)?.[1];
if (!compatibilityDate) {
throw new Error('compatibility_date not found in wrangler.toml');
}
const manifest = {
version,
mainModule: 'index.js',
compatibilityDate,
compatibilityFlags: ['nodejs_compat'],
durableObjects: [{ name: 'PDS', className: 'PDSDurableObject' }],
// The migration for a first deploy. An existing worker keeps its migration
// history; this tag applies only when the class does not exist yet.
migrations: { new_tag: 'v1', new_sqlite_classes: ['PDSDurableObject'] },
r2Buckets: [{ binding: 'BLOBS' }],
requiredVars: ['HOSTNAME'],
requiredSecrets: ['JWT_SECRET', 'PDS_PASSWORD'],
};
writeFileSync(
join(outdir, 'manifest.json'),
`${JSON.stringify(manifest, null, 2)}\n`,
);
console.log(`\nArtifact in ${outdir}:`);
console.log(' index.js the worker module');
console.log(' index.js.map its source map (not uploaded)');
console.log(' manifest.json compatibility, bindings, migration');