import { mkdirSync } from "node:fs"; import type { RuntimeMode } from "../shared/api"; import type { ResolvedConfig, ResolvedLoggingConfig } from "./config/types"; import type { Logger } from "./logger"; import type { StartServerOptions } from "./server"; import { loadServerConfig } from "./config"; import { createConsoleFallback, createRuntimeLogger } from "./logger"; import { startServer } from "./server"; export interface BootstrapDependencies { createLogger?: (config: ResolvedLoggingConfig, mode: string, version?: string) => Promise; exit?: (code: number) => never; loadConfig?: (configPath: string) => Promise; onSignal?: (signal: "SIGINT" | "SIGTERM", handler: () => void) => void; startServer?: (options: StartServerOptions) => unknown; } export interface BootstrapOptions { configPath: string; mode: RuntimeMode; staticAssets?: StartServerOptions["staticAssets"]; version?: string; } export async function bootstrap(options: BootstrapOptions, dependencies: BootstrapDependencies = {}): Promise { const load = dependencies.loadConfig ?? loadServerConfig; const buildLogger = dependencies.createLogger ?? createRuntimeLogger; const serve = dependencies.startServer ?? startServer; const onSignal = dependencies.onSignal ?? ((signal: "SIGINT" | "SIGTERM", handler: () => void) => { process.on(signal, handler); }); const exit = dependencies.exit ?? ((code: number) => process.exit(code)); const createFallback = (): Logger => createConsoleFallback(); let logger: Logger | undefined; try { const config = await load(options.configPath); try { logger = await buildLogger(config.logging, options.mode, options.version); } catch (logInitError) { createFallback().fatal( `日志初始化失败: ${logInitError instanceof Error ? logInitError.message : String(logInitError)}`, ); exit(1); } logger!.info( { configDir: config.configDir, configPath: options.configPath, mode: options.mode, version: options.version }, "配置加载成功", ); mkdirSync(config.dataDir, { recursive: true }); logger!.info({ dataDir: config.dataDir }, "数据目录就绪"); const shutdown = () => { logger?.info("收到退出信号,开始优雅关闭"); logger?.flush(); exit(0); }; onSignal("SIGINT", shutdown); onSignal("SIGTERM", shutdown); serve({ config: { host: config.host, port: config.port }, logger: logger!.child({ component: "server" }), mode: options.mode, staticAssets: options.staticAssets, version: options.version, }); } catch (error) { if (logger) { logger.fatal({ error: error instanceof Error ? error.message : String(error) }, "启动失败"); logger.flush(); } else { createFallback().fatal(`启动失败: ${error instanceof Error ? error.message : String(error)}`); } exit(1); } }