56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
import { type Request, type Response, Router } from "express";
|
|
|
|
const problemDetails = (req: Request, status: number, body: unknown) => {
|
|
const record =
|
|
typeof body === "object" && body !== null
|
|
? (body as Record<string, unknown>)
|
|
: {};
|
|
const detail =
|
|
typeof record.detail === "string"
|
|
? record.detail
|
|
: typeof record.message === "string"
|
|
? record.message
|
|
: `Request failed with status ${status}`;
|
|
const codeByStatus: Record<number, string> = {
|
|
400: "invalid_request",
|
|
401: "unauthenticated",
|
|
403: "forbidden",
|
|
404: "not_found",
|
|
409: "conflict",
|
|
422: "validation_error",
|
|
503: "dependency_unavailable",
|
|
};
|
|
const code = codeByStatus[status] ?? "request_error";
|
|
return {
|
|
type: `https://tjwater.example/problems/${code.replaceAll("_", "-")}`,
|
|
title: code.replaceAll("_", " "),
|
|
status,
|
|
detail,
|
|
instance: req.originalUrl.split("?")[0],
|
|
code,
|
|
trace_id: req.header("x-request-id") ?? randomUUID(),
|
|
errors: record.detail && typeof record.detail === "object" ? [record.detail] : [],
|
|
};
|
|
};
|
|
|
|
export const buildAgentPublicRouter = (chatRouter: Router) => {
|
|
const router = Router();
|
|
|
|
router.use((req, res, next) => {
|
|
const json = res.json.bind(res);
|
|
res.json = ((body: unknown) => {
|
|
if (res.statusCode >= 400) {
|
|
res.type("application/problem+json");
|
|
return json(problemDetails(req, res.statusCode, body));
|
|
}
|
|
return json(body);
|
|
}) as Response["json"];
|
|
next();
|
|
});
|
|
|
|
router.use(chatRouter);
|
|
|
|
return router;
|
|
};
|