v1.3 - added an sqlite db and built data structure

This commit is contained in:
Zaldimmar 2026-09-25 02:35:46 -05:00
parent b0fba52c0e
commit 5efdafbb97
37 changed files with 6414 additions and 1988 deletions

84
server/src/index.js Normal file
View file

@ -0,0 +1,84 @@
/* ═══════════════════════════════════════════════════════════════
NGU API
Binds to localhost only. nginx is the only thing that talks to
it, which is what lets the routes trust X-Forwarded-For and skip
CORS entirely — in production the API and the site share an
origin, and in development Vite proxies /api so they share one
there too.
═══════════════════════════════════════════════════════════════ */
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import { logger } from "hono/logger";
import { openDatabase, migrate } from "./db.js";
import { rateLimit } from "./rateLimit.js";
import content from "./routes/content.js";
import feedback from "./routes/feedback.js";
const HOST = process.env.HOST ?? "127.0.0.1";
const PORT = Number(process.env.PORT ?? 3001);
const DB_PATH = process.env.DB_PATH ?? "./ngu.db";
/* ── Boot ────────────────────────────────────────────────────── */
const db = await openDatabase(DB_PATH);
const version = migrate(db);
console.log(`db ${DB_PATH} (${db.driverName}, schema v${version})`);
/* ── App ─────────────────────────────────────────────────────── */
const app = new Hono();
app.use("*", logger());
app.use("*", async (c, next) => {
c.set("db", db);
await next();
});
app.get("/api/health", (c) =>
c.json({ ok: true, schema: version, driver: db.driverName }),
);
app.route("/api", content);
// Tighter limit on the write path than anything else gets.
app.use("/api/feedback", rateLimit({ windowMs: 60_000, max: 5 }));
app.route("/api/feedback", feedback);
app.notFound((c) => c.json({ error: "Not found" }, 404));
app.onError((err, c) => {
console.error(err);
// Never leak internals to the browser.
return c.json({ error: "Something went wrong." }, 500);
});
/* ── Serve ───────────────────────────────────────────────────── */
const server = serve({ fetch: app.fetch, hostname: HOST, port: PORT }, (info) =>
console.log(`listening http://${info.address}:${info.port}`),
);
/* ── Shutdown ──────────────────────────────────────────────────
systemd sends SIGTERM on stop and restart. Closing the handle
flushes the WAL cleanly, which saves a recovery pass on the
next boot.
───────────────────────────────────────────────────────────── */
for (const signal of ["SIGTERM", "SIGINT"]) {
process.on(signal, () => {
console.log(`${signal} — shutting down`);
server.close(() => {
try {
db.close();
} catch {
/* nothing useful to do here */
}
process.exit(0);
});
});
}