Initial commit

This commit is contained in:
nholtware 2026-11-05 01:44:23 -06:00
commit 107d03869b
28 changed files with 6437 additions and 0 deletions

56
src/app.ts Normal file
View file

@ -0,0 +1,56 @@
import express, { type ErrorRequestHandler } from "express";
import { randomUUID } from "node:crypto";
import { pinoHttp } from "pino-http";
import type { Logger } from "pino";
import type { Config } from "./lib/config.js";
import type { Db } from "./lib/db.js";
import type { Cache } from "./lib/redis.js";
import { healthRouter } from "./routes/health.js";
import { rootRouter } from "./routes/root.js";
export interface Deps {
config: Config;
logger: Logger;
db?: Db;
cache?: Cache;
}
export function createApp({ config, logger, db, cache }: Deps) {
const app = express();
app.disable("x-powered-by");
app.use(
pinoHttp({
logger,
genReqId: (req, res) => {
const incoming = req.headers["x-request-id"];
const id =
(Array.isArray(incoming) ? incoming[0] : incoming) ?? randomUUID();
res.setHeader("X-Request-Id", id);
return id;
},
// Keep the logging contract flat and small: req.id/method/url,
// res.statusCode, responseTime.
serializers: {
req: (req) => ({ id: req.id, method: req.method, url: req.url }),
res: (res) => ({ statusCode: res.statusCode }),
},
autoLogging: {
ignore: (req) => req.url === "/healthz" || req.url === "/readyz",
},
}),
);
app.use(healthRouter({ db, cache }));
app.use(rootRouter({ config, db, cache }));
// Express identifies error handlers by arity; keep all four args.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const onError: ErrorRequestHandler = (err, req, res, _next) => {
req.log.error({ err }, "unhandled error");
res.status(500).json({ error: "internal error" });
};
app.use(onError);
return app;
}