43 lines
2.2 KiB
TypeScript
43 lines
2.2 KiB
TypeScript
import { existsSync } from 'node:fs';
|
|
import { rm } from 'node:fs/promises';
|
|
import { join } from 'node:path';
|
|
|
|
const forbidden = ['CONVEX_BRIDGE_SECRET', 'CONVEX_SELF_HOSTED_ADMIN_KEY', 'APP_AUTH_PRIVATE_KEY', 'APP_AUTH_JWKS', 'TYPESAFE_API_KEY'];
|
|
const workerEnvironmentKeys = [
|
|
'PATH', 'HOME', 'TMPDIR', 'NODE_ENV', 'LANG', 'LC_ALL', 'TZ', 'NODE_EXTRA_CA_CERTS',
|
|
'CONVEX_URL', 'CONVEX_SYNC_WORKER_SECRET', 'TOKEN_ENCRYPTION_KEY',
|
|
'EVE_CLIENT_ID', 'EVE_CLIENT_SECRET', 'EVE_CALLBACK_URL', 'ESI_USER_AGENT', 'REFERENCE_DIR',
|
|
'SYNC_WORKER_ID', 'SYNC_WORKER_LEASE_MS', 'SYNC_WORKER_HEARTBEAT_MS', 'SYNC_WORKER_POLL_MS', 'SYNC_WORKER_ENRICHMENT_DEADLINE_MS', 'SYNC_WORKER_STARTUP_CHECK',
|
|
] as const;
|
|
export function workerEnvironment(base: Record<string, string | undefined>): Record<string, string> {
|
|
return Object.fromEntries(workerEnvironmentKeys.flatMap((key) => base[key] === undefined ? [] : [[key, base[key] as string]]));
|
|
}
|
|
|
|
export async function runSyncWorkerLauncher(): Promise<void> {
|
|
for (const name of forbidden) {
|
|
if (process.env[name]) throw new Error(`Sync worker refuses forbidden runtime credential: ${name}`);
|
|
}
|
|
if (!process.env.CONVEX_SYNC_WORKER_SECRET) throw new Error('CONVEX_SYNC_WORKER_SECRET is required for the sync worker');
|
|
|
|
const bundled = join(process.cwd(), 'build', 'sync-worker.js');
|
|
let entry = bundled;
|
|
let temporary = false;
|
|
if (!existsSync(entry)) {
|
|
entry = join('/tmp', `eve-sync-worker-${process.pid}.js`);
|
|
const result = await Bun.build({ entrypoints: ['workers/sync.ts'], target: 'bun', outdir: '/tmp', naming: `eve-sync-worker-${process.pid}.js`, minify: false });
|
|
if (!result.success) throw new Error('Could not bundle the sync worker');
|
|
temporary = true;
|
|
}
|
|
const child = Bun.spawn(['bun', entry], { env: workerEnvironment(process.env), stdin: 'inherit', stdout: 'inherit', stderr: 'inherit' });
|
|
const interrupt = () => child.kill('SIGINT');
|
|
const terminate = () => child.kill('SIGTERM');
|
|
process.on('SIGINT', interrupt); process.on('SIGTERM', terminate);
|
|
try { process.exitCode = await child.exited; }
|
|
finally {
|
|
process.off('SIGINT', interrupt); process.off('SIGTERM', terminate);
|
|
if (temporary) await rm(entry, { force: true });
|
|
}
|
|
}
|
|
|
|
if (import.meta.main) await runSyncWorkerLauncher();
|