import { join } from "node:path"; import type { DB, Kysely } from "@umt/db"; import { sql } from "@umt/db"; import type { Config } from "./config.ts"; export interface PreflightProblem { check: string; message: string; } export interface PreflightDeps { config: Config; db: Kysely; /** 测试可注入;默认取当前进程 uid(Windows 上为 null) */ uid?: number | null; } // 明显的占位符密钥:生产环境拒绝启动 const PLACEHOLDER = /change[-_]?me|replace[-_]?me|dev[-_]?only|example/i; /** 启动自检:返回问题列表,空数组表示通过。不打印变量值。 */ export async function runPreflight({ config, db, uid = Deno.uid() }: PreflightDeps): Promise { const problems: PreflightProblem[] = []; const prod = config.NODE_ENV === "production"; if (prod && PLACEHOLDER.test(config.SECRET_MASTER_KEY)) { problems.push({ check: "secret", message: "SECRET_MASTER_KEY 仍是占位符,生产环境必须换成随机串" }); } if (prod && uid === 0) { problems.push({ check: "user", message: "生产环境不允许以 root 运行" }); } try { await sql`select 1`.execute(db); } catch (err) { problems.push({ check: "db", message: `数据库不可达: ${(err as Error).message}` }); } if (config.WEB_ROOT) { try { await Deno.stat(join(config.WEB_ROOT, "index.html")); } catch { problems.push({ check: "web", message: `WEB_ROOT 下没有 index.html: ${config.WEB_ROOT}` }); } } return problems; }