Error Page
The last handler in the chain: it turns whatever an earlier handler threw into a response, and decides how much of it the client is allowed to read.
A stack trace, the request's own headers and the process environment are what a developer wants on a broken page and what an attacker wants from a probe. The split is the mode: dev shows the stack and the request, prod shows the status and a reason phrase. The mode is read from NODE_ENV when the caller does not set it, so a deployment that sets NODE_ENV the usual way is already in the closed position. Environment variables stay hidden even in dev until asked for by name.
The response is HTML or JSON depending on what the request said it accepts, or RFC 9457 application/problem+json when the caller asks for it.
b.errorPage.create(opts?) #
{
mode: "dev"|"prod", // default from NODE_ENV
defaultFormat: "auto"|"json"|"html",
problemDetails: boolean, // RFC 9457 application/problem+json
showStack: boolean, // dev only, default true
showRequestInfo: boolean, // dev only, default true
showEnvVars: boolean, // dev only, default false
brand: string, // name shown on the HTML page
contact: string, // support address shown on the HTML page
renderHtml: function, // (ctx) → HTML body
jsonFormatter: function, // (ctx) → JSON body
onError: function, // (err, req) side-channel hook
trustProxy: boolean|number,// how far to trust forwarding headers
log: object, // logger; defaults to the framework's
audit: boolean, // default true
auditAction: string, // default "request.error"
}
Build the error handler a router calls when a handler throws. Mount it last, since it answers whatever reached it.
Without mode, NODE_ENV === "production" selects prod and anything else selects dev. prod writes the status and its reason phrase and nothing else. dev adds the stack and the request line and headers, and adds the process environment only when showEnvVars asks for it by name, because an environment carries the credentials the rest of the page is careful about.
The body is HTML or JSON according to the request's Accept, which defaultFormat can pin. problemDetails: true answers RFC 9457 application/problem+json instead. renderHtml and jsonFormatter replace either body; both must be functions, and a value that is not one throws at construction rather than at the first error.
var b = require("@blamejs/core");
var app = b.router.create();
app.get("/boom", function () { throw new Error("nope"); });
app.use(b.errorPage.create({ mode: "prod", brand: "Example" }));