import "./load-env.js"; import { initInstrumentation } from "./instrumentation/index.js"; initInstrumentation(); import express from "express"; import * as Sentry from "@sentry/node"; import { apiReference } from "@scalar/express-api-reference"; import { existsSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, join } from "node:path"; import { createLogger } from "./infrastructure/logging/logger.js"; import { bootstrap, config } from "./composition/bootstrap.js"; import { runtime } from "./infrastructure/config/runtime.js"; import { SseHub } from "./interfaces/sse/sse.js"; import { createRouter } from "./interfaces/http/routes.js"; import { openapiDocument } from "./interfaces/http/openapi.js"; const log = createLogger("server"); const __dirname = dirname(fileURLToPath(import.meta.url)); const webDist = join(__dirname, "..", "web", "dist"); function main(): void { const ctx = bootstrap(); ctx.start(); const sse = new SseHub(ctx.application); sse.start(); const server = express(); server.use(express.json()); server.use("/api", createRouter(ctx.application, sse)); Sentry.setupExpressErrorHandler(server); server.use( "/api-docs", apiReference({ content: openapiDocument, pageTitle: "Arb Pulse — API Docs", }), ); if (existsSync(webDist)) { server.use(express.static(webDist)); server.get("*", (_req, res) => { res.sendFile(join(webDist, "index.html")); }); } else { server.get("/", (_req, res) => { res .status(200) .send( "Backend running. Frontend not built yet — run `npm run build` (or `npm run dev:web`).", ); }); } const httpServer = server.listen(config.port, () => { log.info(`listening on :${config.port} (demo=${runtime.demoMode})`); }); const shutdown = (): void => { log.info("shutting down"); sse.stop(); ctx.stop(); httpServer.close(() => process.exit(0)); setTimeout(() => process.exit(0), 2000); }; process.on("SIGTERM", shutdown); process.on("SIGINT", shutdown); } main();