import { dirname, isAbsolute, join } from 'node:path'; import { buildControlPlaneApp, type ControlPlaneApp, type SafeControlPlaneUpstream, } from './control-plane.js'; import { createCommandRunner, createLaunchdRestartLauncher, } from './application/system/console-update-service.js'; import { openDatabase } from './infrastructure/database/database.js'; import { migrateDatabase } from './infrastructure/database/migrations.js'; import { createDefaultSecretStore, resolveSecretBackend, defaultSecretFileMetadataCheck, } from './infrastructure/secrets/secret-backend.js'; import type { SecretStore } from './infrastructure/secrets/secret-store.js'; import { createProductionUpstream } from './infrastructure/transport/production-upstream.js'; import { createProductionReadiness, defaultKeychainMetadataCheck } from './production-readiness.js'; export interface ProductionControlPlaneOptions { readonly databasePath: string; readonly store?: SecretStore; readonly upstream?: SafeControlPlaneUpstream; readonly gatewayToken?: string; readonly keychainMetadataCheck?: () => boolean | Promise; readonly secretFileMetadataCheck?: () => boolean | Promise; readonly assetsCheck?: () => boolean | Promise; readonly runtimeVersion?: string; readonly recoveryMarkersCheck?: () => number | Promise; readonly upstreamGatewayCheck?: () => boolean | Promise; /** Production keeps device online state fresh on its own; tests and canaries can opt out. */ readonly heartbeatEnabled?: boolean; /** Environment used to find the launchd label that can restart this process. */ readonly env?: Readonly>; } export function buildProductionControlPlane( options: ProductionControlPlaneOptions, ): ControlPlaneApp { if ( typeof options.databasePath !== 'string' || options.databasePath.length === 0 || !isAbsolute(options.databasePath) ) { throw new Error('An explicit absolute SQLite database path is required'); } const db = openDatabase(options.databasePath); try { migrateDatabase(db); const env = options.env ?? process.env; const secretFilePath = join(dirname(options.databasePath), 'secrets.json'); const store = options.store ?? createDefaultSecretStore({ env, secretFilePath }); const secretBackend = resolveSecretBackend(env); const updateRoot = env.MULTI_SIMADMIN_UPDATE_ROOT ?? process.cwd(); const updateRunner = createCommandRunner({ cwd: updateRoot, timeoutMs: 120_000 }); const app = buildControlPlaneApp({ db, store, upstream: options.upstream ?? createProductionUpstream(), runtimeVersion: options.runtimeVersion ?? '0.1.0', backupDirectory: join(dirname(options.databasePath), 'backups'), heartbeatEnabled: options.heartbeatEnabled ?? true, update: { remote: env.MULTI_SIMADMIN_UPDATE_REMOTE ?? 'origin', root: updateRoot, runner: updateRunner, launcher: createLaunchdRestartLauncher({ env, runner: updateRunner }), }, // This route-local decision is safe only in this composition: when a token is // configured, buildApp's global onRequest hook rejects the request first. // Keep all other control-plane compositions fail-closed by default. ...(options.gatewayToken ? { authenticateEventStream: () => true } : {}), app: { logger: {}, ...(options.gatewayToken ? { gatewayToken: options.gatewayToken } : {}), readiness: createProductionReadiness({ db, gatewayToken: options.gatewayToken ?? '', ...(secretBackend === 'macos-keychain' ? { keychainMetadataCheck: options.keychainMetadataCheck ?? defaultKeychainMetadataCheck, } : { secretFileMetadataCheck: options.secretFileMetadataCheck ?? (async () => defaultSecretFileMetadataCheck(secretFilePath)), }), ...(options.assetsCheck ? { assetsCheck: options.assetsCheck } : {}), ...(options.recoveryMarkersCheck ? { recoveryMarkersCheck: options.recoveryMarkersCheck } : {}), ...(options.upstreamGatewayCheck ? { upstreamGatewayCheck: options.upstreamGatewayCheck } : {}), }), }, }); app.addHook('onClose', async () => { if (db.open) db.close(); }); return app; } catch (error) { if (db.open) db.close(); throw error; } }