@bakery-framework/cli 2.2.1 → 2.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bakery-framework/cli",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "description": "Bakery entry point and process supervision: mode dispatch, dev watcher, cluster.",
5
5
  "keywords": [
6
6
  "bakery",
@@ -39,10 +39,10 @@
39
39
  "bun": ">=1.4.0"
40
40
  },
41
41
  "dependencies": {
42
- "@bakery-framework/core": "^2.2.1"
42
+ "@bakery-framework/core": "^2.3.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@bakery-framework/orm": "^2.2.1"
45
+ "@bakery-framework/orm": "^2.3.0"
46
46
  },
47
47
  "peerDependenciesMeta": {
48
48
  "@bakery-framework/orm": {
package/src/pipeline.ts CHANGED
@@ -35,12 +35,40 @@ export type RateLimitConfig = Exclude<ProcessedAppConfig['rateLimit'], false>
35
35
  * 400 is included: `>= 400`, not `> 400`. A handler returning a bare
36
36
  * `new Response(…, {status: 404})` must still reach `TSXErrorHandler` and get
37
37
  * the app's error page rather than an empty body.
38
+ *
39
+ * A Response whose body the app wrote as a document is not an error to dress,
40
+ * whatever its status: `hasOwnDocument`. The registry keeps only the status
41
+ * of what it replaces, so through 2.2.2 an `onRequest` answering with its own
42
+ * 404 page came back as the app's `error-404.html` (or Bakery's own page),
43
+ * and an API route's `Response.json({ error }, { status: 404 })` as an
44
+ * envelope whose message read `404`.
38
45
  */
39
46
  export function isErrorResult(res: unknown): boolean {
40
- if (res instanceof Response) return res.status >= 400
47
+ if (res instanceof Response) return res.status >= 400 && !hasOwnDocument(res)
41
48
  return is.object(res) && 'errorCode' in res
42
49
  }
43
50
 
51
+ /**
52
+ * Whether an error Response carries a document of its own: a body typed as
53
+ * anything but plain text (an HTML page, a JSON document, an uploaded site's
54
+ * `404.html`).
55
+ *
56
+ * What asks to be dressed is untyped or plain text: `response.error()`, a
57
+ * null body, and a string body such as the router's own
58
+ * `new Response('Not Found', { status: 404 })`, which Bun leaves untyped until
59
+ * it is sent. Those still get the app's error page, or the JSON envelope under
60
+ * `/api`.
61
+ *
62
+ * The header alone, never `res.body`: on Bun 1.4.2 reading the body of a Blob
63
+ * or file Response first makes its `content-type` read `null`, so
64
+ * `new Response(Bun.file('404.html'), { status: 404 })` would be judged
65
+ * untyped and dressed.
66
+ */
67
+ export function hasOwnDocument(res: Response): boolean {
68
+ const type = res.headers.get('content-type')
69
+ return Boolean(type) && !/^text\/plain\b/i.test(type!)
70
+ }
71
+
44
72
  /**
45
73
  * One bucket a request can be charged to: the top level, or a route rule,
46
74
  * checked and ready to match.
package/src/worker.ts CHANGED
@@ -305,6 +305,11 @@ try {
305
305
  Bakery.sharedPool.incrementCounter(COUNTER_SLOTS.TOTAL_ERRORS, 1)
306
306
  return await handleRequestError(path, req, res)
307
307
  }
308
+ // The app's own error page (see `hasOwnDocument`): sent as written,
309
+ // and still an error answer for the counter.
310
+ if (res instanceof Response && res.status >= 400) {
311
+ Bakery.sharedPool.incrementCounter(COUNTER_SLOTS.TOTAL_ERRORS, 1)
312
+ }
308
313
  return res
309
314
  },
310
315