/** * Minimal static server for the production build (dist/). * Zero dependencies. SPA fallback to index.html. * Binds 0.0.0.0 so the office is viewable from the LAN; * the transcript watcher stays localhost-only. */ import { createServer } from "node:http"; import { promises as fs } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const PORT = Number(process.env.PORT || 5182); const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "dist"); const MIME = { ".html": "text/html; charset=utf-8", ".js": "text/javascript", ".css": "text/css", ".svg": "image/svg+xml", ".png": "image/png", ".ico": "image/x-icon", ".json": "application/json", ".woff2": "font/woff2", ".map": "application/json", }; const server = createServer(async (req, res) => { try { const urlPath = decodeURIComponent((req.url || "/").split("?")[0]); let filePath = path.normalize(path.join(ROOT, urlPath)); if (!filePath.startsWith(ROOT)) { res.writeHead(403); res.end("forbidden"); return; } const stat = await fs.stat(filePath).catch(() => null); if (!stat || stat.isDirectory()) { filePath = path.join(ROOT, "index.html"); } const ext = path.extname(filePath); const data = await fs.readFile(filePath); res.writeHead(200, { "Content-Type": MIME[ext] || "application/octet-stream", "Cache-Control": urlPath.startsWith("/assets/") ? "public, max-age=31536000, immutable" : "no-cache", }); res.end(data); } catch { res.writeHead(500); res.end("server error"); } }); server.listen(PORT, "0.0.0.0", () => { console.log(`✳ Codex Office web http://localhost:${PORT} (serving dist/)`); });