import fs from "node:fs/promises"; import path from "node:path"; import { getDb, isDatabaseConfigured } from "../db"; import { ENV } from "./env"; type RuntimeHealthState = "starting" | "ready" | "maintenance" | "shutting_down"; const startedAt = Date.now(); let ready = false; let shuttingDown = false; function resolveMaintenanceFlagPath() { return path.resolve(ENV.maintenanceFlagPath || path.join(process.cwd(), "uploads/system/maintenance.flag")); } async function fileExists(filePath: string) { try { await fs.access(filePath); return true; } catch { return false; } } export function markRuntimeReady() { ready = true; } export function markRuntimeShuttingDown() { shuttingDown = true; ready = false; } export async function isMaintenanceModeEnabled() { return fileExists(resolveMaintenanceFlagPath()); } export async function buildRuntimeHealth() { const uptimeMs = Date.now() - startedAt; const db = await getDb(); const databaseOk = !isDatabaseConfigured() || Boolean(db); const startupDelaySatisfied = uptimeMs >= ENV.appReadyDelayMs; const maintenance = await isMaintenanceModeEnabled(); let state: RuntimeHealthState = "starting"; if (shuttingDown) { state = "shutting_down"; } else if (maintenance) { state = "maintenance"; } else if (ready && startupDelaySatisfied && databaseOk) { state = "ready"; } const ok = state === "ready" || state === "maintenance"; return { ok, state, service: "portail-associations", environment: process.env.NODE_ENV || "development", timestamp: new Date().toISOString(), uptimeMs, maintenance, checks: { startupDelaySatisfied, databaseConfigured: isDatabaseConfigured(), databaseOk, ready, shuttingDown, }, }; } export async function ensureMaintenanceFlagDirectory() { const filePath = resolveMaintenanceFlagPath(); await fs.mkdir(path.dirname(filePath), { recursive: true }); return filePath; }