import { Config } from './services/config.ts'; import { Database, MigrationService } from './services/storage/index.ts'; import { Logger } from './utils/logger.ts'; /** Application composition root. */ export class App { /** * Construct infrastructure and validate all routes before returning a runnable app. */ static async create(): Promise { const config = Config.fromEnv(); const debug = new Logger('sync-server-v2'); debug('config loaded: %O', config); // Persistence must be ready before routes accept traffic. const database = new Database({ path: config.database.path, debug }); const migrations = new MigrationService(database, debug); await migrations.migrateToLatest(); return new App(database); } private stopPromise: Promise | undefined; constructor(private readonly database: Database) {} async start(): Promise {} /** Stop transports before releasing the database they may still use. */ async stop(): Promise { this.stopPromise ??= this.database.destroy(); await this.stopPromise; } } const app = await App.create(); let shuttingDown = false; const shutdown = (signal: NodeJS.Signals): void => { if (shuttingDown) { return; } shuttingDown = true; void app.stop().catch((error) => { console.error('Graceful shutdown failed after ' + signal, error); process.exitCode = 1; }); }; process.once('SIGINT', (): void => shutdown('SIGINT')); process.once('SIGTERM', (): void => shutdown('SIGTERM')); try { await app.start(); } catch (error: unknown) { await app.stop(); throw error; }