@setu-ts/exceptions 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENT_CARD.md ADDED
@@ -0,0 +1,50 @@
1
+ # @setu-ts/exceptions — HTTP errors and error responses
2
+
3
+ **Add it:** REST scaffolds install this package; there is no `setu add` entry or capability. In
4
+ `setu.config.ts`, register `errorHandler` on the global middleware pipeline.
5
+
6
+ ## Format thrown errors consistently
7
+
8
+ ```ts
9
+ import { errorHandler } from "@setu-ts/exceptions";
10
+
11
+ app.middleware.add(errorHandler({ format: "rfc9457" }), {
12
+ priority: 0,
13
+ name: "error-handler",
14
+ });
15
+ ```
16
+
17
+ ## Refuse a request with an HTTP error
18
+
19
+ ```ts
20
+ import type { IRouterApi } from "@setu-ts/common";
21
+ import { notFound } from "@setu-ts/exceptions";
22
+
23
+ export function registerUserRoutes(router: IRouterApi): void {
24
+ router.get("/users/:id", {
25
+ handler: (ctx) => {
26
+ throw notFound(`User ${ctx.params.id} not found`);
27
+ },
28
+ });
29
+ }
30
+ ```
31
+
32
+ ## Behaviour the types do not show
33
+
34
+ - Priority `0` makes the handler wrap downstream middleware and routes; it catches their throws.
35
+ - `format` defaults to `"default"`; `"rfc9457"` sends `application/problem+json`.
36
+ - `maskInternalErrors` defaults to `true`: unexpected 5xx messages become the status title;
37
+ deliberately thrown `HttpError` messages are preserved.
38
+ - `includeStackTrace` defaults to `false`; masked errors never expose a stack even when enabled.
39
+ - `logErrors` defaults to `true`: warn below 500, error otherwise. Without a logger, only 5xx
40
+ reaches the runtime error sink.
41
+ - `respond` sees the normalized, masked error and resolved status. A returned response owns its
42
+ status, headers and body; `undefined` falls through to the configured formatter.
43
+
44
+ ## Other options
45
+
46
+ - `badRequest`, `unauthorized`, `forbidden`, `conflict`, `tooManyRequests` and `serviceUnavailable`
47
+ create other HTTP refusals.
48
+ - `validationError` stores field failures in `details.errors`; `internalServerError` accepts a
49
+ cause.
50
+ - `format` also accepts a formatter function or the deprecated `"rfc7807"` arm.
package/README.md CHANGED
@@ -30,6 +30,14 @@ app.router.get('/users/:id', async (ctx) => {
30
30
 
31
31
  ## Options
32
32
 
33
+ Caught errors produce one diagnostic: `warn` for a served status below 500, `error` otherwise. The
34
+ request logger records completion rather than a second failure diagnostic. With no registered
35
+ logger, handled 5xx goes to `IRuntimeServices.reportError`, the runtime's last-resort JSON stderr
36
+ sink (Workers uses its platform log channel); handled 4xx stays silent. `logErrors: false` disables
37
+ both paths. The responder's optional, pure `statusFor(error)` lets request logging predict this
38
+ middleware's status without reporting a clamp twice. A custom `respond` hook's different status is
39
+ not reflected in request completion logs.
40
+
33
41
  `errorHandler(options?)` takes:
34
42
 
35
43
  | Option | Type | Default | Description |
@@ -170,7 +178,7 @@ problem type identified by `https://setu-ts.dev/errors/validation` — the same
170
178
  | `ErrorFormat` | type |
171
179
  | `ErrorHandlerFormatter` | type |
172
180
 
173
- Generated from the package barrel by `deno task docs:exports`; `deno task check:docs` fails when it
181
+ Generated from the package barrel by `pnpm run docs:exports`; `pnpm run check:docs` fails when it
174
182
  drifts.
175
183
 
176
184
  ## Full API
@@ -1 +1 @@
1
- {"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../../src/errors/exceptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAMvD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAe1D,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtD;AAMD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC1C,SAAS,CAEX;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEnD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEnD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,eAAe,EAAE,EAClC,OAAO,CAAC,EAAE,MAAM,GACf,SAAS,CAGX;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC1C,SAAS,CAEX;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAE7E;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEzD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAE7D"}
1
+ {"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../../src/errors/exceptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAMvD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAe1D,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtD;AAMD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC1C,SAAS,CAEX;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEnD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEnD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAG/F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC1C,SAAS,CAEX;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAE7E;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEzD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAE7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"exceptions.js","sourceRoot":"","sources":["../../src/errors/exceptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAqC;IAC7D,GAAG,EAAE,aAAa;IAClB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,wBAAwB;IAC7B,GAAG,EAAE,sBAAsB;IAC3B,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,uBAAuB;IAC5B,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,aAAa;IAClB,GAAG,EAAE,qBAAqB;IAC1B,GAAG,EAAE,iBAAiB;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,UAAkB;IAC5C,OAAO,aAAa,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC;AAC9C,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACxB,OAAe,EACf,OAA2C;IAE3C,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAkC,EAClC,OAAgB;IAEhB,MAAM,OAAO,GAAG,OAAO,IAAI,0BAA0B,MAAM,CAAC,MAAM,YAAY,CAAC;IAC/E,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,OAA2C;IAE3C,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,KAAa;IAChE,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"exceptions.js","sourceRoot":"","sources":["../../src/errors/exceptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAqC;IAC7D,GAAG,EAAE,aAAa;IAClB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,wBAAwB;IAC7B,GAAG,EAAE,sBAAsB;IAC3B,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,uBAAuB;IAC5B,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,aAAa;IAClB,GAAG,EAAE,qBAAqB;IAC1B,GAAG,EAAE,iBAAiB;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,UAAkB;IAC5C,OAAO,aAAa,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC;AAC9C,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACxB,OAAe,EACf,OAA2C;IAE3C,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,MAAkC,EAAE,OAAgB;IAClF,MAAM,OAAO,GAAG,OAAO,IAAI,0BAA0B,MAAM,CAAC,MAAM,YAAY,CAAC;IAC/E,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,OAA2C;IAE3C,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,KAAa;IAChE,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"problem-details.d.ts","sourceRoot":"","sources":["../../src/formatters/problem-details.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAKvD;;;;GAIG;AACH,eAAO,MAAM,eAAe,+BAA+B,CAAC;AAE5D;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,MAAwC,CAAC;AAEvE;;;;;GAKG;AACH,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;QAC9B,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;IACH,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAAO,MAAmD,CAAC;AAE1F;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,KAAK,MAAM,CAAC;AAgBrF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,eAAe,GAAG,SAAS,EAChC,WAAW,EAAE,mBAAmB,GAC/B,cAAc,CA+BhB"}
1
+ {"version":3,"file":"problem-details.d.ts","sourceRoot":"","sources":["../../src/formatters/problem-details.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAKvD;;;;GAIG;AACH,eAAO,MAAM,eAAe,+BAA+B,CAAC;AAE5D;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,MAAwC,CAAC;AAEvE;;;;;GAKG;AACH,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;QAC9B,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;IACH,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAAO,MAAmD,CAAC;AAE1F;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,KAAK,MAAM,CAAC;AAgBrF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,eAAe,GAAG,SAAS,EAChC,WAAW,EAAE,mBAAmB,GAC/B,cAAc,CAgChB"}
@@ -1 +1 @@
1
- {"version":3,"file":"problem-details.js","sourceRoot":"","sources":["../../src/formatters/problem-details.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,4BAA4B,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAW,GAAG,eAAe,aAAa,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AAkCzC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAkB,MAAM,CAAC,kCAAkC,CAAC,CAAC;AAY1F;;;;;GAKG;AACH,SAAS,aAAa,CAAC,KAAgB;IACrC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC;QACpD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC,MAAkC,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAY,EACZ,GAAgC,EAChC,WAAgC;IAEhC,MAAM,MAAM,GAAG,KAAK,YAAY,SAAS,CAAC;IAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,0EAA0E;IAC1E,2EAA2E;IAC3E,2EAA2E;IAC3E,sBAAsB;IACtB,EAAE;IACF,0EAA0E;IAC1E,6EAA6E;IAC7E,sEAAsE;IACtE,kDAAkD;IAClD,yEAAyE;IACzE,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,2CAA2C;IAC3C,MAAM,aAAa,GAAG,MAAM,IAAI,gBAAgB,IAAI,KAAK;QACvD,CAAC,CAAE,KAAsD,CAAC,gBAAgB,CAAC;QAC3E,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,MAAM,GAAG,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAEjF,OAAO;QACL,IAAI,EAAE,WAAW,CAAC,UAAU,EAAE,MAAM,KAAK,SAAS,CAAC;QACnD,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC;QAC9B,MAAM,EAAE,UAAU;QAClB,MAAM;QACN,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACxD,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;KACxC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"problem-details.js","sourceRoot":"","sources":["../../src/formatters/problem-details.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,4BAA4B,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAW,GAAG,eAAe,aAAa,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AAkCzC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAkB,MAAM,CAAC,kCAAkC,CAAC,CAAC;AAY1F;;;;;GAKG;AACH,SAAS,aAAa,CAAC,KAAgB;IACrC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC;QACpD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC,MAAkC,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAY,EACZ,GAAgC,EAChC,WAAgC;IAEhC,MAAM,MAAM,GAAG,KAAK,YAAY,SAAS,CAAC;IAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,0EAA0E;IAC1E,2EAA2E;IAC3E,2EAA2E;IAC3E,sBAAsB;IACtB,EAAE;IACF,0EAA0E;IAC1E,6EAA6E;IAC7E,sEAAsE;IACtE,kDAAkD;IAClD,yEAAyE;IACzE,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,2CAA2C;IAC3C,MAAM,aAAa,GACjB,MAAM,IAAI,gBAAgB,IAAI,KAAK;QACjC,CAAC,CAAE,KAAsD,CAAC,gBAAgB,CAAC;QAC3E,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,MAAM,GAAG,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAEjF,OAAO;QACL,IAAI,EAAE,WAAW,CAAC,UAAU,EAAE,MAAM,KAAK,SAAS,CAAC;QACnD,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC;QAC9B,MAAM,EAAE,UAAU;QAClB,MAAM;QACN,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACxD,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;KACxC,CAAC;AACJ,CAAC"}
@@ -67,9 +67,8 @@ export interface ErrorHandlerOptions {
67
67
  */
68
68
  readonly maskInternalErrors?: boolean;
69
69
  /**
70
- * When `true` (the default), caught errors are logged at `error` level via
71
- * the `ILogger` resolved from `ctx.services` — but only if a logger is
72
- * registered. When no logger is present, logging is silently skipped.
70
+ * When `true` (the default), logs once at `warn` below 500 and `error`
71
+ * otherwise. Without a logger, only 5xx reaches runtime.reportError.
73
72
  */
74
73
  readonly logErrors?: boolean;
75
74
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,aAAa,EAAW,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAUnG,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAE3B,MAAM,kCAAkC,CAAC;AAI1C;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,qBAAqB,CAAC;IACtD;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IACrC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CACjB,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,eAAe,KACjB,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CACrE;AAuBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,kBAAkB,CAiK9E"}
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EACV,aAAa,EAEb,eAAe,EAEf,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAUzB,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAOpD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAE3B,MAAM,kCAAkC,CAAC;AAI1C;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,qBAAqB,CAAC;IACtD;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IACrC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACtC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CACjB,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,eAAe,KACjB,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CACrE;AAuBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,kBAAkB,CAkK9E"}
@@ -1,7 +1,7 @@
1
1
  import { brandErrorResponder, CAPABILITIES, ERROR_RESPONDER_STATE_KEY, httpStatusHintOf, resolveResponseStatus, serializeError, } from '@setu-ts/common';
2
2
  import { HttpError } from "../errors/http-error.js";
3
3
  import { internalServerError, statusTitle } from "../errors/exceptions.js";
4
- import { buildErrorFromInit, createErrorResponder } from "./error-responder-impl.js";
4
+ import { buildErrorFromInit, createErrorResponder, thrownErrorStatus, } from "./error-responder-impl.js";
5
5
  import { selectFormatter, } from "../formatters/error-formatter.js";
6
6
  import { rfc9457Formatter } from "../formatters/rfc9457-formatter.js";
7
7
  import { rfc7807Formatter } from "../formatters/rfc7807-formatter.js";
@@ -70,7 +70,9 @@ export function errorHandler(options) {
70
70
  catch (rawError) {
71
71
  // Normalize: HttpError passes through, anything else becomes a 500.
72
72
  const isHttpError = rawError instanceof HttpError;
73
- const error = isHttpError ? rawError : internalServerError(rawError instanceof Error ? rawError.message : 'Internal Server Error', rawError instanceof Error ? rawError : undefined);
73
+ const error = isHttpError
74
+ ? rawError
75
+ : internalServerError(rawError instanceof Error ? rawError.message : 'Internal Server Error', rawError instanceof Error ? rawError : undefined);
74
76
  // A thrower that cannot import this package states the status its own
75
77
  // error means by branding it with an `HttpStatusHint` (M89b) — the seam
76
78
  // `@setu-ts/database-plugin` uses for its query-shape refusals, which
@@ -116,7 +118,7 @@ export function errorHandler(options) {
116
118
  // the write also makes `responseError === error` false, which suppresses
117
119
  // the stack — correct by that check's own stated invariant, since the
118
120
  // error being SERVED is no longer the error that was LOGGED.
119
- const servedStatus = resolveResponseStatus(responseError.statusCode, ctx);
121
+ const servedStatus = resolveResponseStatus(thrownErrorStatus(rawError).requested, ctx);
120
122
  if (servedStatus !== responseError.statusCode) {
121
123
  responseError = new HttpError(servedStatus, responseError.message, responseError.details, responseError.cause instanceof Error ? responseError.cause : undefined);
122
124
  }
@@ -144,8 +146,7 @@ export function errorHandler(options) {
144
146
  }
145
147
  return result;
146
148
  }
147
- // Log the UNMASKED error, so the log keeps the SQL, the bound parameters
148
- // and the cause chain regardless of masking — and report the status the
149
+ // Log the unmasked diagnostic and cause chain, with the status the
149
150
  // formatter below will actually serve. A hint may change a normalized
150
151
  // `500` to `501`, so logging the pre-hint status would mislead operators.
151
152
  if (logErrors) {
@@ -187,8 +188,8 @@ export function errorHandler(options) {
187
188
  return handleError;
188
189
  }
189
190
  /**
190
- * Logs an error via the registered `ILogger`, if one is available. Silently
191
- * does nothing when no logger capability is registered.
191
+ * Logs once through the registered logger, or the runtime sink for 5xx when
192
+ * no logger is registered. Handled 4xx without a logger stays silent.
192
193
  *
193
194
  * @param ctx - The request context
194
195
  * @param error - The error to log, carrying the unmasked message and cause
@@ -196,12 +197,22 @@ export function errorHandler(options) {
196
197
  */
197
198
  function logError(ctx, error, statusCode) {
198
199
  if (!ctx.services.has(CAPABILITIES.LOGGER)) {
200
+ if (statusCode >= 500 && ctx.services.has(CAPABILITIES.RUNTIME)) {
201
+ ctx.services.get(CAPABILITIES.RUNTIME).reportError?.({
202
+ level: 'error',
203
+ ...serializeError(error),
204
+ statusCode,
205
+ requestId: ctx.id,
206
+ method: ctx.request.method,
207
+ path: ctx.request.path,
208
+ });
209
+ }
199
210
  return;
200
211
  }
201
212
  const logger = ctx.services.get(CAPABILITIES.LOGGER);
202
213
  // Serialize the cause (X2-5): a raw `Error` in log metadata renders as `{}`
203
214
  // under `JSON.stringify` because `message`/`stack` are non-enumerable.
204
- logger.error(error.message, {
215
+ logger[statusCode < 500 ? 'warn' : 'error'](error.message, {
205
216
  statusCode,
206
217
  requestId: ctx.id,
207
218
  ...(error.cause !== undefined && { cause: serializeError(error.cause) }),
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,11 @@
13
13
  import type { ErrorResponseInit, IErrorResponder } from '@setu-ts/common';
14
14
  import { HttpError } from '../errors/http-error.ts';
15
15
  import type { ErrorHandlerFormatter } from '../formatters/error-formatter.ts';
16
+ /** The pure thrown-value rule, shared by serving and request-log prediction. */
17
+ export declare function thrownErrorStatus(error: unknown): {
18
+ requested: number;
19
+ status: number;
20
+ };
16
21
  /**
17
22
  * Builds the {@linkcode HttpError} that carries one error response's status,
18
23
  * title and disclosure.
@@ -1 +1 @@
1
- {"version":3,"file":"error-responder-impl.d.ts","sourceRoot":"","sources":["../../src/middleware/error-responder-impl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAEV,iBAAiB,EACjB,eAAe,EAEhB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAqC9E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAkCrE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,qBAAqB,EAChC,WAAW,EAAE,MAAM,GAClB,eAAe,CA6CjB"}
1
+ {"version":3,"file":"error-responder-impl.d.ts","sourceRoot":"","sources":["../../src/middleware/error-responder-impl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAEV,iBAAiB,EACjB,eAAe,EAEhB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAW9E,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAcvF;AA4BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAiCrE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,qBAAqB,EAChC,WAAW,EAAE,MAAM,GAClB,eAAe,CA2CjB"}
@@ -1,4 +1,4 @@
1
- import { resolveResponseStatus } from '@setu-ts/common';
1
+ import { httpStatusHintOf, resolveResponseStatus } from '@setu-ts/common';
2
2
  import { HttpError } from "../errors/http-error.js";
3
3
  import { RESPONDER_DETAIL } from "../formatters/problem-details.js";
4
4
  /**
@@ -9,6 +9,20 @@ import { RESPONDER_DETAIL } from "../formatters/problem-details.js";
9
9
  * request path) exactly when its resolved content type is this one.
10
10
  */
11
11
  const PROBLEM_JSON = 'application/problem+json';
12
+ /** The pure thrown-value rule, shared by serving and request-log prediction. */
13
+ export function thrownErrorStatus(error) {
14
+ const requested = error instanceof HttpError ? error.statusCode : (httpStatusHintOf(error)?.status ?? 500);
15
+ // Fetch refuses informational responses and bodies on 204, 205 and 304.
16
+ const status = Number.isInteger(requested) &&
17
+ requested >= 200 &&
18
+ requested <= 599 &&
19
+ requested !== 204 &&
20
+ requested !== 205 &&
21
+ requested !== 304
22
+ ? requested
23
+ : 500;
24
+ return { requested, status };
25
+ }
12
26
  /**
13
27
  * Narrows an {@linkcode ErrorResponderTarget} to a full {@linkcode
14
28
  * IRequestContext} when it genuinely is one.
@@ -63,9 +77,7 @@ export function buildErrorFromInit(init) {
63
77
  // through unchanged. Carrying it this way — rather than in `error.message` —
64
78
  // keeps the title verbatim, which a site's (non-)disclosure decision depends
65
79
  // on.
66
- const details = init.detail !== undefined
67
- ? { ...init.details, detail: init.detail }
68
- : init.details;
80
+ const details = init.detail !== undefined ? { ...init.details, detail: init.detail } : init.details;
69
81
  const error = new HttpError(init.status, init.title, details);
70
82
  // Mark the error as responder-built and carry the disclosure on a
71
83
  // module-private symbol, which is what `buildProblemDetails` promotes to the
@@ -103,6 +115,7 @@ export function buildErrorFromInit(init) {
103
115
  */
104
116
  export function createErrorResponder(formatter, contentType) {
105
117
  return {
118
+ statusFor: (error) => thrownErrorStatus(error).status,
106
119
  respond(target, init) {
107
120
  // Sanitized before the error is built, not just before the status is
108
121
  // written, so the formatted body's `status` member agrees with the status
@@ -138,10 +151,7 @@ export function createErrorResponder(formatter, contentType) {
138
151
  body = { ...body, instance: target.request.path };
139
152
  }
140
153
  const bytes = new TextEncoder().encode(JSON.stringify(body));
141
- target.response
142
- .status(status)
143
- .header('content-type', contentType)
144
- .send(bytes);
154
+ target.response.status(status).header('content-type', contentType).send(bytes);
145
155
  },
146
156
  };
147
157
  }
@@ -1 +1 @@
1
- {"version":3,"file":"error-responder-impl.js","sourceRoot":"","sources":["../../src/middleware/error-responder-impl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"error-responder-impl.js","sourceRoot":"","sources":["../../src/middleware/error-responder-impl.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@setu-ts/exceptions",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Exception hierarchy, RFC 9457 Problem Details, and the error-handler middleware",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,13 +18,14 @@
18
18
  "type": "module",
19
19
  "license": "MIT",
20
20
  "engines": {
21
- "node": ">=22"
21
+ "node": "^22.23.4 || ^24.22.1 || >=26.12.1"
22
22
  },
23
23
  "files": [
24
24
  "dist",
25
25
  "src",
26
26
  "README.md",
27
- "LICENSE"
27
+ "LICENSE",
28
+ "AGENT_CARD.md"
28
29
  ],
29
30
  "exports": {
30
31
  ".": {
@@ -33,18 +34,18 @@
33
34
  }
34
35
  },
35
36
  "dependencies": {
36
- "@setu-ts/common": "^0.9.0"
37
+ "@setu-ts/common": "^0.10.0"
37
38
  },
38
39
  "devDependencies": {
39
- "@setu-ts/auth-plugin": "^0.9.0",
40
- "@setu-ts/feature-flags-plugin": "^0.9.0",
41
- "@setu-ts/http-security-plugin": "^0.9.0",
42
- "@setu-ts/logger-plugin": "^0.9.0",
43
- "@setu-ts/multi-tenancy-plugin": "^0.9.0",
44
- "@setu-ts/runtime": "^0.9.0",
45
- "@setu-ts/session-plugin": "^0.9.0",
46
- "@setu-ts/storage-plugin": "^0.9.0",
47
- "@setu-ts/testing": "^0.9.0",
40
+ "@setu-ts/auth-plugin": "^0.10.0",
41
+ "@setu-ts/feature-flags-plugin": "^0.10.0",
42
+ "@setu-ts/http-security-plugin": "^0.10.0",
43
+ "@setu-ts/logger-plugin": "^0.10.0",
44
+ "@setu-ts/multi-tenancy-plugin": "^0.10.0",
45
+ "@setu-ts/runtime": "^0.10.0",
46
+ "@setu-ts/session-plugin": "^0.10.0",
47
+ "@setu-ts/storage-plugin": "^0.10.0",
48
+ "@setu-ts/testing": "^0.10.0",
48
49
  "@types/node": "^24",
49
50
  "typescript": "6.0.3",
50
51
  "vitest": "5.0.3"
@@ -151,10 +151,7 @@ export function conflict(message: string): HttpError {
151
151
  * @returns A `422` {@linkcode HttpError}
152
152
  * @since 0.1.0
153
153
  */
154
- export function validationError(
155
- errors: readonly ValidationError[],
156
- message?: string,
157
- ): HttpError {
154
+ export function validationError(errors: readonly ValidationError[], message?: string): HttpError {
158
155
  const summary = message ?? `Validation failed with ${errors.length} error(s).`;
159
156
  return new HttpError(422, summary, { errors });
160
157
  }
@@ -160,9 +160,10 @@ export function buildProblemDetails(
160
160
  // that happens to use that key name (M70f code review, finding 4). Only an
161
161
  // error the responder built carries the marker, so a thrown error keeps the
162
162
  // pre-M70f shape: `detail` is the message.
163
- const carriedDetail = isHttp && RESPONDER_DETAIL in error
164
- ? (error as HttpError & { [RESPONDER_DETAIL]?: unknown })[RESPONDER_DETAIL]
165
- : undefined;
163
+ const carriedDetail =
164
+ isHttp && RESPONDER_DETAIL in error
165
+ ? (error as HttpError & { [RESPONDER_DETAIL]?: unknown })[RESPONDER_DETAIL]
166
+ : undefined;
166
167
  const detail = typeof carriedDetail === 'string' ? carriedDetail : error.message;
167
168
 
168
169
  return {
@@ -20,7 +20,13 @@
20
20
  *
21
21
  * @module
22
22
  */
23
- import type { HandlerResult, ILogger, IRequestContext, MiddlewareFunction } from '@setu-ts/common';
23
+ import type {
24
+ HandlerResult,
25
+ ILogger,
26
+ IRequestContext,
27
+ IRuntimeServices,
28
+ MiddlewareFunction,
29
+ } from '@setu-ts/common';
24
30
  import {
25
31
  brandErrorResponder,
26
32
  CAPABILITIES,
@@ -32,7 +38,11 @@ import {
32
38
 
33
39
  import { HttpError } from '../errors/http-error.ts';
34
40
  import { internalServerError, statusTitle } from '../errors/exceptions.ts';
35
- import { buildErrorFromInit, createErrorResponder } from './error-responder-impl.ts';
41
+ import {
42
+ buildErrorFromInit,
43
+ createErrorResponder,
44
+ thrownErrorStatus,
45
+ } from './error-responder-impl.ts';
36
46
  import {
37
47
  type ErrorFormat,
38
48
  type ErrorHandlerFormatter,
@@ -85,9 +95,8 @@ export interface ErrorHandlerOptions {
85
95
  */
86
96
  readonly maskInternalErrors?: boolean;
87
97
  /**
88
- * When `true` (the default), caught errors are logged at `error` level via
89
- * the `ILogger` resolved from `ctx.services` — but only if a logger is
90
- * registered. When no logger is present, logging is silently skipped.
98
+ * When `true` (the default), logs once at `warn` below 500 and `error`
99
+ * otherwise. Without a logger, only 5xx reaches runtime.reportError.
91
100
  */
92
101
  readonly logErrors?: boolean;
93
102
  /**
@@ -178,10 +187,12 @@ export function errorHandler(options?: ErrorHandlerOptions): MiddlewareFunction
178
187
  } catch (rawError) {
179
188
  // Normalize: HttpError passes through, anything else becomes a 500.
180
189
  const isHttpError = rawError instanceof HttpError;
181
- const error: HttpError = isHttpError ? rawError : internalServerError(
182
- rawError instanceof Error ? rawError.message : 'Internal Server Error',
183
- rawError instanceof Error ? rawError : undefined,
184
- );
190
+ const error: HttpError = isHttpError
191
+ ? rawError
192
+ : internalServerError(
193
+ rawError instanceof Error ? rawError.message : 'Internal Server Error',
194
+ rawError instanceof Error ? rawError : undefined,
195
+ );
185
196
 
186
197
  // A thrower that cannot import this package states the status its own
187
198
  // error means by branding it with an `HttpStatusHint` (M89b) — the seam
@@ -234,7 +245,7 @@ export function errorHandler(options?: ErrorHandlerOptions): MiddlewareFunction
234
245
  // the write also makes `responseError === error` false, which suppresses
235
246
  // the stack — correct by that check's own stated invariant, since the
236
247
  // error being SERVED is no longer the error that was LOGGED.
237
- const servedStatus = resolveResponseStatus(responseError.statusCode, ctx);
248
+ const servedStatus = resolveResponseStatus(thrownErrorStatus(rawError).requested, ctx);
238
249
  if (servedStatus !== responseError.statusCode) {
239
250
  responseError = new HttpError(
240
251
  servedStatus,
@@ -268,8 +279,7 @@ export function errorHandler(options?: ErrorHandlerOptions): MiddlewareFunction
268
279
  return result;
269
280
  }
270
281
 
271
- // Log the UNMASKED error, so the log keeps the SQL, the bound parameters
272
- // and the cause chain regardless of masking — and report the status the
282
+ // Log the unmasked diagnostic and cause chain, with the status the
273
283
  // formatter below will actually serve. A hint may change a normalized
274
284
  // `500` to `501`, so logging the pre-hint status would mislead operators.
275
285
  if (logErrors) {
@@ -315,8 +325,8 @@ export function errorHandler(options?: ErrorHandlerOptions): MiddlewareFunction
315
325
  }
316
326
 
317
327
  /**
318
- * Logs an error via the registered `ILogger`, if one is available. Silently
319
- * does nothing when no logger capability is registered.
328
+ * Logs once through the registered logger, or the runtime sink for 5xx when
329
+ * no logger is registered. Handled 4xx without a logger stays silent.
320
330
  *
321
331
  * @param ctx - The request context
322
332
  * @param error - The error to log, carrying the unmasked message and cause
@@ -324,12 +334,22 @@ export function errorHandler(options?: ErrorHandlerOptions): MiddlewareFunction
324
334
  */
325
335
  function logError(ctx: IRequestContext, error: HttpError, statusCode: number): void {
326
336
  if (!ctx.services.has(CAPABILITIES.LOGGER)) {
337
+ if (statusCode >= 500 && ctx.services.has(CAPABILITIES.RUNTIME)) {
338
+ ctx.services.get<IRuntimeServices>(CAPABILITIES.RUNTIME).reportError?.({
339
+ level: 'error',
340
+ ...serializeError(error),
341
+ statusCode,
342
+ requestId: ctx.id,
343
+ method: ctx.request.method,
344
+ path: ctx.request.path,
345
+ });
346
+ }
327
347
  return;
328
348
  }
329
349
  const logger = ctx.services.get<ILogger>(CAPABILITIES.LOGGER);
330
350
  // Serialize the cause (X2-5): a raw `Error` in log metadata renders as `{}`
331
351
  // under `JSON.stringify` because `message`/`stack` are non-enumerable.
332
- logger.error(error.message, {
352
+ logger[statusCode < 500 ? 'warn' : 'error'](error.message, {
333
353
  statusCode,
334
354
  requestId: ctx.id,
335
355
  ...(error.cause !== undefined && { cause: serializeError(error.cause) }),
@@ -16,7 +16,7 @@ import type {
16
16
  IErrorResponder,
17
17
  IRequestContext,
18
18
  } from '@setu-ts/common';
19
- import { resolveResponseStatus } from '@setu-ts/common';
19
+ import { httpStatusHintOf, resolveResponseStatus } from '@setu-ts/common';
20
20
 
21
21
  import { HttpError } from '../errors/http-error.ts';
22
22
  import { RESPONDER_DETAIL } from '../formatters/problem-details.ts';
@@ -31,6 +31,23 @@ import type { ErrorHandlerFormatter } from '../formatters/error-formatter.ts';
31
31
  */
32
32
  const PROBLEM_JSON = 'application/problem+json';
33
33
 
34
+ /** The pure thrown-value rule, shared by serving and request-log prediction. */
35
+ export function thrownErrorStatus(error: unknown): { requested: number; status: number } {
36
+ const requested =
37
+ error instanceof HttpError ? error.statusCode : (httpStatusHintOf(error)?.status ?? 500);
38
+ // Fetch refuses informational responses and bodies on 204, 205 and 304.
39
+ const status =
40
+ Number.isInteger(requested) &&
41
+ requested >= 200 &&
42
+ requested <= 599 &&
43
+ requested !== 204 &&
44
+ requested !== 205 &&
45
+ requested !== 304
46
+ ? requested
47
+ : 500;
48
+ return { requested, status };
49
+ }
50
+
34
51
  /**
35
52
  * Narrows an {@linkcode ErrorResponderTarget} to a full {@linkcode
36
53
  * IRequestContext} when it genuinely is one.
@@ -88,9 +105,8 @@ export function buildErrorFromInit(init: ErrorResponseInit): HttpError {
88
105
  // through unchanged. Carrying it this way — rather than in `error.message` —
89
106
  // keeps the title verbatim, which a site's (non-)disclosure decision depends
90
107
  // on.
91
- const details = init.detail !== undefined
92
- ? { ...init.details, detail: init.detail }
93
- : init.details;
108
+ const details =
109
+ init.detail !== undefined ? { ...init.details, detail: init.detail } : init.details;
94
110
  const error = new HttpError(init.status, init.title, details);
95
111
  // Mark the error as responder-built and carry the disclosure on a
96
112
  // module-private symbol, which is what `buildProblemDetails` promotes to the
@@ -132,6 +148,7 @@ export function createErrorResponder(
132
148
  contentType: string,
133
149
  ): IErrorResponder {
134
150
  return {
151
+ statusFor: (error: unknown): number => thrownErrorStatus(error).status,
135
152
  respond(target: ErrorResponderTarget, init: ErrorResponseInit): void {
136
153
  // Sanitized before the error is built, not just before the status is
137
154
  // written, so the formatted body's `status` member agrees with the status
@@ -169,10 +186,7 @@ export function createErrorResponder(
169
186
  body = { ...body, instance: target.request.path };
170
187
  }
171
188
  const bytes = new TextEncoder().encode(JSON.stringify(body));
172
- target.response
173
- .status(status)
174
- .header('content-type', contentType)
175
- .send(bytes);
189
+ target.response.status(status).header('content-type', contentType).send(bytes);
176
190
  },
177
191
  };
178
192
  }