import { Hono } from "hono"; import { serveStatic } from "hono/bun"; import { cors } from "hono/cors"; import dashboardRoutes from "./api/dashboard"; import executeRoutes from "./api/execute"; import pathsRoutes from "./api/paths"; import reviewRoutes from "./api/review"; import scanRoutes from "./api/scan"; import settingsRoutes from "./api/settings"; import subtitlesRoutes from "./api/subtitles"; import { getDb } from "./db/index"; import { log, error as logError } from "./lib/log"; import { startMqttClient } from "./services/mqtt"; const app = new Hono(); // ─── CORS (dev: Vite on :5173 talks to Hono on :3000) ──────────────────────── app.use("/api/*", cors({ origin: ["http://localhost:5173", "http://localhost:3000"] })); // ─── Request logging ────────────────────────────────────────────────────────── app.use("/api/*", async (c, next) => { const start = Date.now(); await next(); const ms = Date.now() - start; // Skip noisy SSE/polling endpoints if (c.req.path.endsWith("/events")) return; log(`${c.req.method} ${c.req.path} → ${c.res.status} (${ms}ms)`); }); // ─── API routes ─────────────────────────────────────────────────────────────── import pkg from "../package.json"; app.get("/api/version", (c) => c.json({ version: pkg.version })); app.route("/api/dashboard", dashboardRoutes); app.route("/api/settings", settingsRoutes); app.route("/api/scan", scanRoutes); app.route("/api/review", reviewRoutes); app.route("/api/execute", executeRoutes); app.route("/api/subtitles", subtitlesRoutes); app.route("/api/paths", pathsRoutes); // ─── Static assets (production: serve Vite build) ──────────────────────────── app.use("/assets/*", serveStatic({ root: "./dist" })); app.use("/favicon.ico", serveStatic({ path: "./dist/favicon.ico" })); // ─── SPA fallback ───────────────────────────────────────────────────────────── // All non-API routes serve the React index.html so TanStack Router handles them. app.get("*", async (c) => { if (c.req.path.startsWith("/api/")) return c.notFound(); // In dev the Vite server handles the SPA. In production serve dist/index.html. try { const html = await Bun.file("./dist/index.html").text(); return c.html(html); } catch { return c.text("Run `bun build` first to generate the frontend.", 503); } }); // ─── Start ──────────────────────────────────────────────────────────────────── const port = Number(process.env.PORT ?? "3000"); log(`netfelix-audio-fix v${pkg.version} starting on http://localhost:${port}`); getDb(); startMqttClient().catch((err) => logError("MQTT bootstrap failed:", err)); export default { port, fetch: app.fetch, idleTimeout: 0, };