File size: 5,417 Bytes
6111b2b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | // Server startup script
import initializeCloudSync from "./shared/services/initializeCloudSync";
import { enforceWebRuntimeEnv } from "./lib/env/runtimeEnv";
import { enforceSecrets } from "./shared/utils/secretsValidator";
import { initAuditLog, cleanupExpiredLogs, logAuditEvent } from "./lib/compliance/index";
import { initConsoleInterceptor } from "./lib/consoleInterceptor";
import { startBudgetResetJob } from "./lib/jobs/budgetResetJob";
import { startReasoningCacheCleanupJob } from "./lib/jobs/reasoningCacheCleanupJob";
import { getSettings } from "./lib/db/settings";
import { applyRuntimeSettings } from "./lib/config/runtimeSettings";
import { setSystemPromptConfig } from "@omniroute/open-sse/services/systemPrompt.ts";
import { startRuntimeConfigHotReload } from "./lib/config/hotReload";
import { startSpendBatchWriter } from "./lib/spend/batchWriter";
import { registerDefaultGuardrails } from "./lib/guardrails";
import { ensurePersistentManagementPasswordHash } from "./lib/auth/managementPassword";
import { skillExecutor } from "./lib/skills/executor";
import { registerBuiltinSkills } from "./lib/skills/builtins";
import { createLogger } from "./shared/utils/logger";
const startupLog = createLogger("server-init");
function getErrorMessage(error: unknown) {
return error instanceof Error ? error.message : String(error);
}
async function startServer() {
// Trigger request-log layout migration during startup, before serving requests.
await import("./lib/usage/migrations");
// Console interceptor: capture all console output to log file (must be first)
initConsoleInterceptor();
// FASE-01: Validate required secrets before anything else (fail-fast)
enforceSecrets();
enforceWebRuntimeEnv();
// Compliance: Initialize audit_log table
try {
initAuditLog();
startupLog.info("Audit log table initialized");
} catch (err) {
startupLog.warn({ err }, "Could not initialize audit log");
}
// Compliance: One-time cleanup of expired logs
try {
const cleanup = await cleanupExpiredLogs();
if (
cleanup.deletedUsage ||
cleanup.deletedCallLogs ||
cleanup.deletedProxyLogs ||
cleanup.deletedRequestDetailLogs ||
cleanup.deletedAuditLogs ||
cleanup.deletedMcpAuditLogs
) {
startupLog.info({ cleanup }, "Expired log cleanup completed");
}
} catch (err) {
startupLog.warn({ err }, "Log cleanup failed");
}
startupLog.info("Starting server with cloud sync");
try {
let settings = await getSettings();
const passwordState = await ensurePersistentManagementPasswordHash({
logger: { log: (message: string) => startupLog.info(message) },
settings,
source: "startup",
});
settings = passwordState.settings;
const runtimeChanges = await applyRuntimeSettings(settings, { force: true, source: "startup" });
if (runtimeChanges.length > 0) {
startupLog.info(
{ sections: runtimeChanges.map((entry) => entry.section) },
"Runtime settings hydrated"
);
}
// Restore the Global System Prompt into the in-memory config. It lives in the
// `settings.systemPrompt` key but is NOT covered by applyRuntimeSettings, so without
// this the toggle/prompt revert to defaults on every restart (#2470).
if (settings.systemPrompt) {
setSystemPromptConfig(settings.systemPrompt);
startupLog.info("Global System Prompt restored from settings");
}
// Initialize cloud sync
startSpendBatchWriter();
registerDefaultGuardrails();
registerBuiltinSkills(skillExecutor);
startupLog.info("Spend batch writer started");
startupLog.info("Guardrail registry initialized");
startupLog.info("Builtin skill handlers registered");
// Load active plugins on startup so they survive restarts
try {
const { pluginManager } = await import("./lib/plugins/manager");
await pluginManager.loadAll();
startupLog.info("Plugin manager loaded active plugins");
} catch (err) {
startupLog.warn({ err }, "Plugin manager loadAll failed (non-fatal)");
}
await initializeCloudSync();
startBudgetResetJob();
startReasoningCacheCleanupJob();
startRuntimeConfigHotReload();
startupLog.info("Server started with cloud sync initialized");
// Log server start event to audit log
logAuditEvent({
action: "server.start",
actor: "system",
target: "server-runtime",
resourceType: "maintenance",
status: "success",
details: { timestamp: new Date().toISOString() },
});
} catch (error) {
startupLog.error({ err: error }, "Error initializing cloud sync");
process.exit(1);
}
// Pricing sync: opt-in external pricing data (non-blocking, never fatal)
if (process.env.PRICING_SYNC_ENABLED === "true") {
try {
const { initPricingSync } = await import("./lib/pricingSync");
await initPricingSync();
} catch (err) {
startupLog.warn({ error: getErrorMessage(err) }, "Pricing sync could not initialize");
}
}
}
// Start the server initialization
startServer().catch((err) => {
startupLog.error({ err }, "Server initialization failed");
process.exit(1);
});
// Export for use as module if needed
export default startServer;
|