import type { Request, Response, NextFunction } from "express"; import express from "express"; import process from "node:process"; import adminRouter from "./routes/admin.js"; import claimsRouter from "./routes/claims.js"; import open91Router from "./routes/open-91.js"; import tencentRouter from "./routes/tencent.js"; import webhooksRouter from "./routes/webhooks.js"; import { buildSuccessPayload, sendRouteError } from "./utils/http.js"; import { accessLogMiddleware } from "./middleware/access-log.js"; import { corsMiddleware } from "./middleware/cors.js"; import { buildHealthPayload, type StartupState } from "./startup/state.js"; type CreateAppOptions = { startupState: StartupState; isShutdownStarted: () => boolean; }; export function createApp({ startupState, isShutdownStarted, }: CreateAppOptions) { const app = express(); app.use(accessLogMiddleware); app.use(corsMiddleware); app.use(express.json({ limit: "2mb" })); app.use(express.urlencoded({ extended: true })); app.get("/health", (_req, res) => { res.json( buildSuccessPayload( buildHealthPayload(startupState, isShutdownStarted()), startupState.core.ready ? "ready" : "starting" ) ); }); app.get("/health/live", (_req, res) => { res.json( buildSuccessPayload({ status: isShutdownStarted() ? "shutting_down" : "alive", pid: process.pid, }) ); }); app.get("/health/ready", (_req, res) => { if (startupState.core.ready) { res.json( buildSuccessPayload( buildHealthPayload(startupState, isShutdownStarted()), "ready" ) ); return; } res.status(503).json({ code: 1, msg: startupState.core.lastError || "服务启动中,请稍后重试", errorCode: "service_not_ready", time: Math.floor(Date.now() / 1000), data: buildHealthPayload(startupState, isShutdownStarted()), }); }); app.use((req, res, next) => { if (startupState.core.ready) { next(); return; } res.status(503).json({ code: 1, msg: startupState.core.lastError || "服务启动中,请稍后重试", errorCode: "service_not_ready", time: Math.floor(Date.now() / 1000), data: { startup: { phase: startupState.phase, attemptCount: startupState.core.attemptCount, lastAttemptAt: startupState.core.lastAttemptAt, }, }, }); }); app.use("/api/v1/tencent", tencentRouter); app.use("/api/v1/open/91", open91Router); app.use("/api/v1/webhooks", webhooksRouter); app.use("/api/v1/claim", claimsRouter); app.use("/api/v1/admin", adminRouter); app.use((err: unknown, _req: Request, res: Response, _next: NextFunction) => { sendRouteError(res, err, "服务内部错误", "[global]"); }); return app; }