cefense/apps/frontend/server.ts
2026-08-18 19:38:47 +05:30

56 lines
2.1 KiB
TypeScript

// Production static-file server for the built SPA, run by Bun (replaces nginx).
// Serves apps/frontend/dist and reverse-proxies backend routes so the
// session cookie stays first-party. Dev still uses Vite (see vite.config.ts).
const PORT = Number(process.env.PORT ?? 8080);
const BACKEND_URL = process.env.BACKEND_URL ?? "http://localhost:3001";
const DIST = "./dist";
function isProxied(pathname: string): boolean {
return (
pathname === "/health" ||
pathname.startsWith("/auth") ||
pathname.startsWith("/api") ||
pathname.startsWith("/internal")
);
}
// Forward the request to the backend, preserving method/headers/body/cookies.
async function proxy(req: Request, url: URL): Promise<Response> {
const target = new URL(url.pathname + url.search, BACKEND_URL);
const headers = new Headers(req.headers);
// Let fetch set Host from the target URL (Cloud Run routes by Host).
headers.delete("host");
headers.set("x-forwarded-host", url.host);
headers.set("x-forwarded-proto", url.protocol.replace(":", ""));
const init: RequestInit = { method: req.method, headers, redirect: "manual" };
if (req.method !== "GET" && req.method !== "HEAD") {
init.body = await req.arrayBuffer();
}
return fetch(target, init);
}
async function serveStatic(url: URL): Promise<Response> {
const pathname = url.pathname === "/" ? "/index.html" : url.pathname;
const file = Bun.file(`${DIST}${pathname}`);
if (await file.exists()) {
const headers: Record<string, string> =
pathname.startsWith("/assets/")
? { "Cache-Control": "public, max-age=31536000, immutable" }
: { "Cache-Control": "no-cache" };
return new Response(file, { headers });
}
// SPA fallback: serve index.html for client-side routes.
return new Response(Bun.file(`${DIST}/index.html`), { headers: { "Cache-Control": "no-cache" } });
}
Bun.serve({
port: PORT,
fetch(req) {
const url = new URL(req.url);
return isProxied(url.pathname) ? proxy(req, url) : serveStatic(url);
},
});
console.log(`cerebrus-frontend serving on :${PORT} (proxy backend routes -> ${BACKEND_URL})`);