Files
tool-evaluator/artifacts/api-server/src/app.ts
T
opencode 0c6a35e841
Build & Push Docker Image / build (push) Successful in 8m33s
fix: category cache refresh, API 404, redundancy mapping, cost/relation authz, voterToken exposure
- Invalidate categories/features queries after creating/editing tools so new
  categories appear immediately in search, browse dropdown and tool form
- Always refetch categories/features when the combobox/suggestion inputs mount
- Return JSON 404 for unmatched /api routes instead of the SPA index.html
- Read the manually confirmed 'better tool' from the recommendation notes
  instead of using the min tool id in the redundancy dashboard
- Require admin for cost/relation update+delete endpoints
- Stop exposing the voter token in the ratings list response
- Fix parseInt type error on user id params (Express 5 params typing)
2026-08-01 15:25:06 +02:00

79 lines
1.9 KiB
TypeScript

import express, { type Express } from "express";
import cors from "cors";
import { existsSync } from "node:fs";
import { resolve } from "node:path";
import pinoHttp from "pino-http";
import session from "express-session";
import ConnectPgSimple from "connect-pg-simple";
import router from "./routes";
import { logger } from "./lib/logger";
import "./types/session.d.ts";
const PgStore = ConnectPgSimple(session);
const app: Express = express();
app.set("trust proxy", 1);
app.use(
pinoHttp({
logger,
serializers: {
req(req) {
return {
id: req.id,
method: req.method,
url: req.url?.split("?")[0],
};
},
res(res) {
return {
statusCode: res.statusCode,
};
},
},
}),
);
app.use(cors({ origin: true, credentials: true }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
session({
store: new PgStore({
conString: process.env.DATABASE_URL,
tableName: "sessions",
createTableIfMissing: true,
}),
secret: process.env.SESSION_SECRET || "dev-secret-change-in-production",
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === "production",
httpOnly: true,
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
sameSite: process.env.NODE_ENV === "production" ? "none" : "lax",
},
}),
);
app.use("/api", router);
// Any unmatched /api route should return a JSON 404 instead of falling
// through to the SPA catch-all below.
app.use("/api", (_req, res) => {
res.status(404).json({ error: "Not found" });
});
const staticDir = process.env.STATIC_DIR;
if (staticDir && existsSync(staticDir)) {
app.use(express.static(staticDir));
app.get("/*any", (_req, res) => {
res.sendFile(resolve(staticDir, "index.html"));
});
logger.info({ staticDir }, "Serving static files");
}
export default app;