import express from "express"; import { globalDeviceRouter } from "./routes/global-device.routes.js"; import { projectDeviceRouter } from "./routes/project-device.routes.js"; import { projectRouter } from "./routes/project.routes.js"; import { errorMiddleware } from "./middleware/error.middleware.js"; import { createLogger, toErrorMeta } from "../shared/logging/logger.js"; const logger = createLogger("api"); const app = express(); const port = Number(process.env.PORT || 3000); const heartbeatIntervalMs = 5 * 60 * 1000; app.use(express.json({ limit: "25mb" })); app.use((req, res, next) => { if (req.path === "/health") { next(); return; } const startedAt = Date.now(); logger.debug("request started", { method: req.method, path: req.originalUrl }); res.on("finish", () => { const meta = { method: req.method, path: req.originalUrl, status: res.statusCode, durationMs: Date.now() - startedAt, }; if (res.statusCode >= 500) logger.error("request completed", meta); else if (res.statusCode >= 400) logger.warn("request completed", meta); else logger.info("request completed", meta); }); res.on("close", () => { if (!res.writableEnded) { logger.warn("request aborted before response finished", { method: req.method, path: req.originalUrl, durationMs: Date.now() - startedAt, }); } }); next(); }); app.get("/health", (_req, res) => { res.json({ ok: true }); }); app.use("/api/projects", projectRouter); app.use("/api/global-devices", globalDeviceRouter); app.use("/api/project-devices", projectDeviceRouter); app.use(errorMiddleware); process.on("uncaughtException", (error) => { logger.error("uncaught exception, exiting", toErrorMeta(error)); process.exit(1); }); process.on("unhandledRejection", (reason) => { logger.error("unhandled rejection, exiting", toErrorMeta(reason)); process.exit(1); }); process.on("SIGTERM", () => logger.info("received SIGTERM")); process.on("SIGINT", () => logger.info("received SIGINT")); setInterval(() => { const memory = process.memoryUsage(); logger.verbose("heartbeat", { uptimeSeconds: Math.round(process.uptime()), rssMb: Math.round(memory.rss / 1024 / 1024), heapUsedMb: Math.round(memory.heapUsed / 1024 / 1024), }); }, heartbeatIntervalMs).unref(); app.listen(port, () => { logger.info("server started", { port }); });