Files
Labyricorn 72e8b2de91
CI / verify (pull_request) Canceled after 0s
Harden control plane boundaries
2026-07-25 10:13:22 -07:00

54 lines
1.7 KiB
TypeScript

import "dotenv/config";
import express from "express";
import path from "node:path";
import { createServer as createViteServer } from "vite";
import { contentRouter } from "./src/backend/http/contentRouter";
import { controlRouter } from "./src/backend/http/controlRouter";
import { gitSourceRouter } from "./src/backend/http/gitSourceRouter";
import { previewRouter } from "./src/backend/http/previewRouter";
const parsePort = (value: string): number => {
const port = Number.parseInt(value, 10);
if (!Number.isInteger(port) || port < 1 || port > 65_535) {
throw new Error(`Invalid PORT value: ${value}`);
}
return port;
};
async function startServer(): Promise<void> {
const app = express();
const port = parsePort(process.env.PORT ?? "3000");
const host = process.env.HOST ?? "127.0.0.1";
app.disable("x-powered-by");
app.set("trust proxy", process.env.TRUST_PROXY ?? "loopback");
app.use(express.json({ limit: "1mb" }));
app.use("/api", controlRouter);
app.use("/api", gitSourceRouter);
app.use("/api", contentRouter);
app.use("/api", previewRouter);
if (process.env.NODE_ENV !== "production") {
const vite = await createViteServer({
server: { middlewareMode: true },
appType: "spa",
});
app.use(vite.middlewares);
} else {
const distPath = path.join(process.cwd(), "dist");
app.use(express.static(distPath));
app.get("*", (_req, res) => {
res.sendFile(path.join(distPath, "index.html"));
});
}
app.listen(port, host, () => {
console.log(`Labyricorn Control Plane running on http://${host}:${port}`);
});
}
startServer().catch((error) => {
console.error(error);
process.exitCode = 1;
});