elysia 2.0.0-beta.21 → 2.0.0-beta.23

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.
Files changed (217) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +1 -0
  2. package/dist/adapter/bun/index.d.ts +6 -8
  3. package/dist/adapter/bun/index.js +6 -8
  4. package/dist/adapter/bun/index.mjs +7 -8
  5. package/dist/adapter/constants.mjs +1 -0
  6. package/dist/adapter/default-headers.mjs +1 -0
  7. package/dist/adapter/index.mjs +1 -0
  8. package/dist/adapter/origin.mjs +1 -0
  9. package/dist/adapter/response-ownership.mjs +1 -0
  10. package/dist/adapter/skip-clone.mjs +1 -0
  11. package/dist/adapter/types.mjs +1 -0
  12. package/dist/adapter/utils.d.ts +5 -8
  13. package/dist/adapter/utils.js +24 -18
  14. package/dist/adapter/utils.mjs +25 -18
  15. package/dist/adapter/web-standard/handler.mjs +2 -1
  16. package/dist/adapter/web-standard/index.mjs +1 -0
  17. package/dist/adapter/web-standard/utils.mjs +1 -0
  18. package/dist/base.d.ts +118 -69
  19. package/dist/base.js +214 -194
  20. package/dist/base.mjs +221 -200
  21. package/dist/compile/aot-capture.js +2 -2
  22. package/dist/compile/aot-capture.mjs +4 -3
  23. package/dist/compile/aot-emit.js +7 -8
  24. package/dist/compile/aot-emit.mjs +8 -8
  25. package/dist/compile/aot-reconstruct.mjs +3 -2
  26. package/dist/compile/aot.d.ts +3 -3
  27. package/dist/compile/aot.js +5 -5
  28. package/dist/compile/aot.mjs +6 -5
  29. package/dist/compile/handler/descriptor.d.ts +2 -5
  30. package/dist/compile/handler/descriptor.js +12 -17
  31. package/dist/compile/handler/descriptor.mjs +16 -21
  32. package/dist/compile/handler/frozen-validator.d.ts +2 -2
  33. package/dist/compile/handler/frozen-validator.js +3 -3
  34. package/dist/compile/handler/frozen-validator.mjs +4 -3
  35. package/dist/compile/handler/index.d.ts +3 -1
  36. package/dist/compile/handler/index.js +78 -118
  37. package/dist/compile/handler/index.mjs +84 -125
  38. package/dist/compile/handler/jit.d.ts +12 -12
  39. package/dist/compile/handler/jit.js +60 -43
  40. package/dist/compile/handler/jit.mjs +63 -47
  41. package/dist/compile/handler/params.d.ts +5 -1
  42. package/dist/compile/handler/params.js +14 -5
  43. package/dist/compile/handler/params.mjs +16 -7
  44. package/dist/compile/handler/reconstruct.d.ts +2 -2
  45. package/dist/compile/handler/reconstruct.js +2 -2
  46. package/dist/compile/handler/reconstruct.mjs +3 -2
  47. package/dist/compile/handler/static-clone-resolver.mjs +1 -0
  48. package/dist/compile/handler/utils.d.ts +13 -7
  49. package/dist/compile/handler/utils.js +75 -52
  50. package/dist/compile/handler/utils.mjs +77 -54
  51. package/dist/compile/jit-probe.mjs +1 -0
  52. package/dist/compile/lexer.js +4 -4
  53. package/dist/compile/lexer.mjs +5 -4
  54. package/dist/compile/utils.d.ts +2 -1
  55. package/dist/compile/utils.js +8 -3
  56. package/dist/compile/utils.mjs +8 -3
  57. package/dist/compiled.mjs +1 -0
  58. package/dist/constants.mjs +1 -0
  59. package/dist/context.d.ts +1 -1
  60. package/dist/context.js +1 -0
  61. package/dist/context.mjs +3 -1
  62. package/dist/cookie/config.d.ts +2 -2
  63. package/dist/cookie/config.js +21 -26
  64. package/dist/cookie/config.mjs +22 -26
  65. package/dist/cookie/cookie.mjs +1 -0
  66. package/dist/cookie/crypto.mjs +1 -0
  67. package/dist/cookie/error.mjs +1 -0
  68. package/dist/cookie/lib.mjs +1 -0
  69. package/dist/cookie/serialize.mjs +1 -0
  70. package/dist/cookie/types.mjs +1 -0
  71. package/dist/cookie/utils.d.ts +1 -1
  72. package/dist/cookie/utils.js +64 -45
  73. package/dist/cookie/utils.mjs +66 -46
  74. package/dist/error.d.ts +10 -6
  75. package/dist/error.js +22 -6
  76. package/dist/error.mjs +25 -9
  77. package/dist/generation.mjs +1 -0
  78. package/dist/handler/error.d.ts +12 -15
  79. package/dist/handler/error.js +43 -40
  80. package/dist/handler/error.mjs +45 -41
  81. package/dist/handler/fetch.js +59 -21
  82. package/dist/handler/fetch.mjs +61 -22
  83. package/dist/handler/utils.d.ts +16 -3
  84. package/dist/handler/utils.js +14 -13
  85. package/dist/handler/utils.mjs +16 -15
  86. package/dist/index.d.ts +9 -9
  87. package/dist/index.js +1 -0
  88. package/dist/index.mjs +3 -2
  89. package/dist/memory.mjs +1 -0
  90. package/dist/package.js +1 -1
  91. package/dist/package.mjs +2 -1
  92. package/dist/parse-query.js +76 -76
  93. package/dist/parse-query.mjs +77 -76
  94. package/dist/plugin/aot/bun.mjs +1 -0
  95. package/dist/plugin/aot/core.d.ts +1 -1
  96. package/dist/plugin/aot/core.js +7 -4
  97. package/dist/plugin/aot/core.mjs +8 -5
  98. package/dist/plugin/aot/esbuild.mjs +1 -0
  99. package/dist/plugin/aot/rspack-loader.mjs +1 -0
  100. package/dist/plugin/aot/rspack.mjs +1 -0
  101. package/dist/plugin/aot/treeshake.mjs +1 -0
  102. package/dist/plugin/aot/unplugin.mjs +4 -3
  103. package/dist/plugin/aot/vite.mjs +1 -0
  104. package/dist/plugin/aot/worker.mjs +1 -0
  105. package/dist/plugin/auto-head.mjs +1 -0
  106. package/dist/plugin/trace.mjs +1 -0
  107. package/dist/plugin/websocket.mjs +1 -0
  108. package/dist/route-table.mjs +1 -0
  109. package/dist/schema-snapshot.js +28 -3
  110. package/dist/schema-snapshot.mjs +29 -3
  111. package/dist/sucrose.d.ts +2 -2
  112. package/dist/sucrose.js +11 -11
  113. package/dist/sucrose.mjs +12 -11
  114. package/dist/trace.js +8 -10
  115. package/dist/trace.mjs +10 -11
  116. package/dist/type/bridge-live.d.ts +1 -1
  117. package/dist/type/bridge-live.mjs +1 -0
  118. package/dist/type/bridge.d.ts +1 -1
  119. package/dist/type/bridge.mjs +1 -0
  120. package/dist/type/coerce-plan.mjs +1 -0
  121. package/dist/type/coerce.d.ts +1 -1
  122. package/dist/type/coerce.mjs +1 -0
  123. package/dist/type/compat.mjs +1 -0
  124. package/dist/type/constants.d.ts +1 -1
  125. package/dist/type/constants.mjs +1 -0
  126. package/dist/type/elysia/accelerate.mjs +1 -0
  127. package/dist/type/elysia/array-buffer.d.ts +3 -2
  128. package/dist/type/elysia/array-buffer.js +5 -5
  129. package/dist/type/elysia/array-buffer.mjs +6 -5
  130. package/dist/type/elysia/array-string.mjs +1 -0
  131. package/dist/type/elysia/array.mjs +1 -0
  132. package/dist/type/elysia/boolean-string.mjs +1 -0
  133. package/dist/type/elysia/boolean.mjs +1 -0
  134. package/dist/type/elysia/cookie.mjs +1 -0
  135. package/dist/type/elysia/date.mjs +1 -0
  136. package/dist/type/elysia/file-type.mjs +1 -0
  137. package/dist/type/elysia/file.mjs +1 -0
  138. package/dist/type/elysia/files.mjs +1 -0
  139. package/dist/type/elysia/form.mjs +1 -0
  140. package/dist/type/elysia/integer-string.mjs +1 -0
  141. package/dist/type/elysia/integer.mjs +1 -0
  142. package/dist/type/elysia/intersect.mjs +1 -0
  143. package/dist/type/elysia/json-string.mjs +1 -0
  144. package/dist/type/elysia/keep-config.js +8 -8
  145. package/dist/type/elysia/keep-config.mjs +9 -8
  146. package/dist/type/elysia/maybe-empty.mjs +1 -0
  147. package/dist/type/elysia/no-validate.mjs +1 -0
  148. package/dist/type/elysia/nullable.mjs +1 -0
  149. package/dist/type/elysia/number.mjs +1 -0
  150. package/dist/type/elysia/numeric-enum.d.ts +4 -2
  151. package/dist/type/elysia/numeric-enum.mjs +1 -0
  152. package/dist/type/elysia/numeric.mjs +1 -0
  153. package/dist/type/elysia/object-string.mjs +1 -0
  154. package/dist/type/elysia/object.mjs +1 -0
  155. package/dist/type/elysia/optional.mjs +1 -0
  156. package/dist/type/elysia/problem.mjs +1 -0
  157. package/dist/type/elysia/string.mjs +1 -0
  158. package/dist/type/elysia/uint8-array.d.ts +2 -1
  159. package/dist/type/elysia/uint8-array.js +2 -2
  160. package/dist/type/elysia/uint8-array.mjs +3 -2
  161. package/dist/type/elysia/union-enum.mjs +1 -0
  162. package/dist/type/elysia/union.mjs +1 -0
  163. package/dist/type/elysia/utils.js +3 -3
  164. package/dist/type/elysia/utils.mjs +4 -3
  165. package/dist/type/exports.mjs +1 -0
  166. package/dist/type/index.mjs +2 -1
  167. package/dist/type/shared.mjs +1 -0
  168. package/dist/type/sync-require.mjs +1 -0
  169. package/dist/type/typebox-system-lite.mjs +1 -0
  170. package/dist/type/typebox-system-require.mjs +1 -0
  171. package/dist/type/typebox-type-live.mjs +1 -0
  172. package/dist/type/typebox-value-live.mjs +1 -0
  173. package/dist/type/typebox-value-ops.mjs +1 -0
  174. package/dist/type/typebox-value.mjs +1 -0
  175. package/dist/type/types.d.ts +1 -1
  176. package/dist/type/types.mjs +1 -0
  177. package/dist/type/utils.mjs +1 -0
  178. package/dist/type/validator/clean-safe.mjs +1 -0
  179. package/dist/type/validator/custom-error.js +41 -33
  180. package/dist/type/validator/custom-error.mjs +42 -33
  181. package/dist/type/validator/default-precompute.d.ts +2 -2
  182. package/dist/type/validator/default-precompute.js +10 -11
  183. package/dist/type/validator/default-precompute.mjs +13 -13
  184. package/dist/type/validator/exact-mirror.mjs +1 -0
  185. package/dist/type/validator/frozen-check.js +7 -7
  186. package/dist/type/validator/frozen-check.mjs +8 -7
  187. package/dist/type/validator/index.d.ts +2 -2
  188. package/dist/type/validator/index.js +4 -8
  189. package/dist/type/validator/index.mjs +5 -8
  190. package/dist/type/validator/string-codec-aot.d.ts +1 -1
  191. package/dist/type/validator/string-codec-aot.mjs +1 -0
  192. package/dist/type/validator/validator-cache.js +18 -18
  193. package/dist/type/validator/validator-cache.mjs +19 -18
  194. package/dist/types.d.ts +108 -70
  195. package/dist/types.mjs +1 -0
  196. package/dist/universal/constants.mjs +1 -0
  197. package/dist/universal/file.mjs +1 -0
  198. package/dist/universal/index.mjs +1 -0
  199. package/dist/universal/is-production.mjs +1 -0
  200. package/dist/universal/server.mjs +1 -0
  201. package/dist/utils.d.ts +49 -31
  202. package/dist/utils.js +221 -109
  203. package/dist/utils.mjs +215 -106
  204. package/dist/validator/index.d.ts +3 -3
  205. package/dist/validator/index.js +4 -4
  206. package/dist/validator/index.mjs +5 -4
  207. package/dist/validator/route.d.ts +2 -2
  208. package/dist/validator/route.mjs +1 -0
  209. package/dist/ws/context.js +1 -1
  210. package/dist/ws/context.mjs +2 -1
  211. package/dist/ws/index.mjs +1 -0
  212. package/dist/ws/parser.mjs +1 -0
  213. package/dist/ws/route.js +34 -25
  214. package/dist/ws/route.mjs +40 -30
  215. package/dist/ws/types.d.ts +2 -3
  216. package/dist/ws/types.mjs +1 -0
  217. package/package.json +2 -2
@@ -1,9 +1,10 @@
1
+ // @bun
1
2
  import { nullObject } from "../utils.mjs";
2
3
  import { InvalidCookie } from "./error.mjs";
3
4
  import { parse } from "./lib.mjs";
4
5
  import { deriveSignKey, hasSyncHmac, maybeJsonDecode, rawJsonValue, resolvePendingCookie, signCookie, signCookieSyncImpl, unsignWithSecrets, unsignWithSecretsSync } from "./crypto.mjs";
5
6
  import { Cookie } from "./cookie.mjs";
6
- import { isCookieSigned, legacySignatureOf, resolveSignSecrets } from "./config.mjs";
7
+ import { acceptsLegacySignature, isCookieSigned, resolveSignSecrets } from "./config.mjs";
7
8
  import decodeComponent from "deuri";
8
9
 
9
10
  //#region src/cookie/utils.ts
@@ -40,13 +41,13 @@ function parseCookieRawLazy(cookieString, config) {
40
41
  return out;
41
42
  }
42
43
  /**
43
- * Raw-record value of a signed cookie that failed verification on a lane that
44
- * can't verify on access (asynchronous HMAC, AOT); the jar rejects its first
45
- * read. A string key, not a module identity, so a second Elysia copy agrees.
46
- * Null-prototype, which `JSON.parse` never yields, so no cookie value a client
47
- * sends (unsigned, or accepted by a `null` rotation secret) can take its shape
44
+ * Stands in for a signed cookie that failed verification on a lane that can't
45
+ * verify on access (async HMAC, AOT); the jar rejects its first read.
46
+ * String key so a second Elysia copy agrees; null-prototype, which
47
+ * `JSON.parse` never yields, so no client-sent value (unsigned, or accepted by a
48
+ * `null` rotation secret) can forge it
48
49
  */
49
- const invalidSignature = () => {
50
+ const invalidSignatureMarker = () => {
50
51
  const marker = nullObject();
51
52
  marker["~invalid"] = 1;
52
53
  return marker;
@@ -63,10 +64,10 @@ async function parseCookieRaw(cookieString, config, lazy) {
63
64
  let value = decodeComponent(v) ?? v;
64
65
  const signCheck = resolveSignSecrets(name, config);
65
66
  if (signCheck !== void 0) try {
66
- value = await unsignWithSecrets(name, value, signCheck, legacySignatureOf(name, config));
67
+ value = await unsignWithSecrets(name, value, signCheck, acceptsLegacySignature(name, config));
67
68
  } catch (error) {
68
69
  if (!lazy || !(error instanceof InvalidCookie)) throw error;
69
- out[name] = invalidSignature();
70
+ out[name] = invalidSignatureMarker();
70
71
  continue;
71
72
  }
72
73
  out[name] = maybeJsonDecode(value);
@@ -84,31 +85,38 @@ function parseCookieRawSigned(cookieString, config, lazy) {
84
85
  let value = decodeComponent(v) ?? v;
85
86
  const signCheck = resolveSignSecrets(name, config);
86
87
  if (signCheck !== void 0) try {
87
- value = unsignWithSecretsSync(name, value, signCheck, legacySignatureOf(name, config));
88
+ value = unsignWithSecretsSync(name, value, signCheck, acceptsLegacySignature(name, config));
88
89
  } catch (error) {
89
90
  if (!lazy || !(error instanceof InvalidCookie)) throw error;
90
- out[name] = invalidSignature();
91
+ out[name] = invalidSignatureMarker();
91
92
  continue;
92
93
  }
93
94
  out[name] = maybeJsonDecode(value);
94
95
  }
95
96
  return out;
96
97
  }
97
- function buildCookieJar(set, raw, config, lazySign, deferDecode) {
98
- const store = raw;
99
- const materialized = nullObject();
100
- function materializeEntry(name) {
101
- if (materialized[name]) return store[name];
98
+ var CookieJarHandler = class {
99
+ constructor(setRef, config, lazySign, deferDecode) {
100
+ this.setRef = setRef;
101
+ this.config = config;
102
+ this.lazySign = lazySign;
103
+ this.deferDecode = deferDecode;
104
+ this.materialized = void 0;
105
+ this.cache = void 0;
106
+ }
107
+ materialize(store, name) {
108
+ if (this.materialized?.[name]) return store[name];
109
+ const config = this.config;
102
110
  const rawValue = store[name];
103
111
  const fieldDefaults = config.fields[name]?.defaults;
104
- const entry = Object.assign(nullObject(), config.defaults, fieldDefaults, { value: deferDecode ? maybeJsonDecode(decodeComponent(rawValue) ?? rawValue) : rawValue });
112
+ const entry = Object.assign(nullObject(), config.defaults, fieldDefaults, { value: this.deferDecode ? maybeJsonDecode(decodeComponent(rawValue) ?? rawValue) : rawValue });
105
113
  if (entry.expires instanceof Date) entry.expires = new Date(entry.expires.getTime());
106
114
  if (rawValue?.["~invalid"] === 1 && Object.getPrototypeOf(rawValue) === null) entry["~unsign"] = 1;
107
- else if (lazySign && typeof entry.value === "string") {
115
+ else if (this.lazySign && typeof entry.value === "string") {
108
116
  const secrets = resolveSignSecrets(name, config);
109
117
  if (secrets !== void 0) {
110
118
  entry["~unsign"] = secrets;
111
- if (!legacySignatureOf(name, config)) entry["~strict"] = 1;
119
+ if (!acceptsLegacySignature(name, config)) entry["~strict"] = 1;
112
120
  }
113
121
  } else {
114
122
  const value = entry.value;
@@ -118,33 +126,33 @@ function buildCookieJar(set, raw, config, lazySign, deferDecode) {
118
126
  }
119
127
  }
120
128
  store[name] = entry;
121
- materialized[name] = 1;
129
+ (this.materialized ??= nullObject())[name] = 1;
122
130
  return entry;
123
131
  }
124
- const cache = nullObject();
125
- function settle(key) {
132
+ settle(store, key) {
126
133
  if (!(key in store)) return;
127
- const entry = materializeEntry(key);
134
+ const entry = this.materialize(store, key);
128
135
  if ("~unsign" in entry) resolvePendingCookie(entry, key);
129
136
  }
130
- return new Proxy(store, {
131
- get(_, key) {
132
- return cache[key] ??= new Cookie(key, set, key in store ? materializeEntry(key) : Object.assign(nullObject(), config.defaults, config.fields[key]?.defaults));
133
- },
134
- has(target, key) {
135
- if (typeof key === "string") settle(key);
136
- return Reflect.has(target, key);
137
- },
138
- ownKeys(target) {
139
- const keys = Reflect.ownKeys(target);
140
- for (let i = 0; i < keys.length; i++) settle(keys[i]);
141
- return keys;
142
- },
143
- getOwnPropertyDescriptor(target, key) {
144
- if (typeof key === "string") settle(key);
145
- return Reflect.getOwnPropertyDescriptor(target, key);
146
- }
147
- });
137
+ get(store, key) {
138
+ return (this.cache ??= nullObject())[key] ??= new Cookie(key, this.setRef, key in store ? this.materialize(store, key) : Object.assign(nullObject(), this.config.defaults, this.config.fields[key]?.defaults));
139
+ }
140
+ has(store, key) {
141
+ if (typeof key === "string") this.settle(store, key);
142
+ return Reflect.has(store, key);
143
+ }
144
+ ownKeys(store) {
145
+ const keys = Reflect.ownKeys(store);
146
+ for (let i = 0; i < keys.length; i++) this.settle(store, keys[i]);
147
+ return keys;
148
+ }
149
+ getOwnPropertyDescriptor(store, key) {
150
+ if (typeof key === "string") this.settle(store, key);
151
+ return Reflect.getOwnPropertyDescriptor(store, key);
152
+ }
153
+ };
154
+ function buildCookieJar(set, raw, config, lazySign, deferDecode) {
155
+ return new Proxy(raw, new CookieJarHandler(set, config, lazySign, deferDecode));
148
156
  }
149
157
  function collectSignPending(cookies, config) {
150
158
  if (!cookies || !config.hasSign) return;
@@ -171,12 +179,24 @@ function collectSignPending(cookies, config) {
171
179
  }
172
180
  return pending;
173
181
  }
174
- function dropSigned(cookies, config) {
175
- for (const name in cookies) if (config.fields[name]?.sign || config.globalSign === true || config.globalSignSet?.has(name)) delete cookies[name];
182
+ function dropSigned(cookies, config, set) {
183
+ if (set) Object.defineProperty(set, "~signFailed", {
184
+ value: true,
185
+ configurable: true
186
+ });
187
+ const signed = (name) => config.fields[name]?.sign || config.globalSign === true || config.globalSignSet?.has(name);
188
+ let kept = false;
189
+ for (const name in cookies) if (signed(name) && !Reflect.deleteProperty(cookies, name)) kept = true;
190
+ if (kept && set?.cookie === cookies) {
191
+ const copy = nullObject();
192
+ for (const name in cookies) if (!signed(name)) copy[name] = cookies[name];
193
+ set.cookie = copy;
194
+ }
176
195
  }
177
- function signCookieValues(cookies, config) {
196
+ function signCookieValues(cookies, config, set) {
178
197
  let pending;
179
198
  try {
199
+ if (set?.["~signFailed"]) throw new TypeError("A signed cookie of this request failed to sign");
180
200
  pending = collectSignPending(cookies, config);
181
201
  if (!pending) return;
182
202
  if (hasSyncHmac) {
@@ -187,11 +207,11 @@ function signCookieValues(cookies, config) {
187
207
  return;
188
208
  }
189
209
  } catch (error) {
190
- dropSigned(cookies, config);
210
+ dropSigned(cookies, config, set);
191
211
  throw error;
192
212
  }
193
213
  return signPending(pending).catch((error) => {
194
- dropSigned(cookies, config);
214
+ dropSigned(cookies, config, set);
195
215
  throw error;
196
216
  });
197
217
  }
package/dist/error.d.ts CHANGED
@@ -181,6 +181,8 @@ type ProblemResponseBody<Status extends number, P> = Omit<{
181
181
  }, keyof P> & Omit<P, 'status'> & {
182
182
  status: Status;
183
183
  };
184
+ /** Title of a status, as `problemBody` fills it */
185
+ declare const titleOf: (status: number) => string;
184
186
  declare function problemBody(p: Problem): Record<string, unknown> & {
185
187
  status: number;
186
188
  };
@@ -234,9 +236,9 @@ type TaggedHTTPError<Type extends string, Annotation = {}> = {
234
236
  * the instance to a response on its own, no `.error(Class, handler)` needed
235
237
  *
236
238
  * Everything an owned `HTTPError` serves is an RFC 9457 problem document:
237
- * `type` is the problem type carried on the wire, an annotated object body
238
- * merges into the envelope, and any other body (or the error message, when
239
- * there is none) becomes `detail`
239
+ * `type` is the problem type carried on the wire, and the body (or the error
240
+ * message, when there is none) becomes `detail`, an object nested verbatim
241
+ * and never merged into the envelope
240
242
  *
241
243
  * - `detail()` - the common case. Whatever it returns becomes the `detail`
242
244
  * member of the problem document, verbatim, objects included. The envelope
@@ -303,8 +305,10 @@ declare abstract class HTTPError<const in out T extends string = string> extends
303
305
  readonly code?: string;
304
306
  /**
305
307
  * Absolute base for the RFC 9457 `type` URI, applied to every class made
306
- * by {@link HTTPError.id} and to every built-in `ElysiaError`
307
- * (`NotFound`, `ParseError`, …) both derive `type` from the same slug
308
+ * by {@link HTTPError.id} and to the built-in `ElysiaError`s (`NotFound`,
309
+ * `ParseError`, `InvalidCookie`, `InternalServerError`) both derive `type`
310
+ * from the same slug. Request validation is the exception, it keeps
311
+ * `type: 'validation'` unprefixed
308
312
  *
309
313
  * @example
310
314
  * ```ts
@@ -375,4 +379,4 @@ declare abstract class HTTPError<const in out T extends string = string> extends
375
379
  }>;
376
380
  }
377
381
  //#endregion
378
- export { ElysiaError, ElysiaStatus, HTTPError, InternalServerError, MAX_ERRORS, NotFound, NumericStatus, PROBLEM_JSON, ParseError, Problem, ProblemResponseBody, SelectiveProblem, SelectiveStatus, StatusResponse, TaggedHTTPError, ValidationError, ValidationErrorResponse, elysiaErrorProblem, internalServerErrorBody, internalServerErrorBodyString, internalServerErrorResponse, isProduction, problem, problemBody, problemResponse, problemTypeOf, status, subValueAt, validationDetail };
382
+ export { ElysiaError, ElysiaStatus, HTTPError, InternalServerError, MAX_ERRORS, NotFound, NumericStatus, PROBLEM_JSON, ParseError, Problem, ProblemResponseBody, SelectiveProblem, SelectiveStatus, StatusResponse, TaggedHTTPError, ValidationError, ValidationErrorResponse, elysiaErrorProblem, internalServerErrorBody, internalServerErrorBodyString, internalServerErrorResponse, isProduction, problem, problemBody, problemResponse, problemTypeOf, status, subValueAt, titleOf, validationDetail };
package/dist/error.js CHANGED
@@ -304,7 +304,14 @@ var ValidationError = class extends ElysiaError {
304
304
  resolved = this.#thunk() ?? [];
305
305
  if (resolved.length > 64) resolved = resolved.slice(0, 64);
306
306
  resolved = scopeIssues(resolved);
307
- const sub = walkSubSchema(this.schema, resolved[0]?.instancePath);
307
+ let sub = walkSubSchema(this.schema, resolved[0]?.instancePath);
308
+ const missing = resolved[0]?.keyword === "required" && sub?.properties ? resolved[0].params?.requiredProperties : void 0;
309
+ if (Array.isArray(missing)) {
310
+ for (const key of missing) if (sub.properties[key]?.error !== void 0) {
311
+ sub = sub.properties[key];
312
+ break;
313
+ }
314
+ }
308
315
  if (sub?.error !== void 0) custom = typeof sub.error === "function" ? sub.error(production && !allowUnsafe ? {
309
316
  type: "validation",
310
317
  on: type,
@@ -333,8 +340,9 @@ var ValidationError = class extends ElysiaError {
333
340
  if (!this.errors) return [];
334
341
  return this.#collapseCoercionErrors(this.errors.filter(Boolean)).map((e) => {
335
342
  if (!e) return e;
343
+ const raw = e.path ?? e.instancePath;
336
344
  const issue = {
337
- path: Array.isArray(e.path) ? e.path.length ? e.path.map(segmentString).join(".") : "root" : typeof e.path === "string" ? e.path.replace(/^\//, "").replace(/\//g, ".") || "root" : "root",
345
+ path: Array.isArray(raw) && raw.length ? raw.map(segmentString).join(".") : typeof raw === "string" && raw ? raw.replace(/^\//, "").replace(/\//g, ".") : "root",
338
346
  message: e.message ?? "",
339
347
  schemaPath: e.schemaPath,
340
348
  params: e.params
@@ -492,12 +500,19 @@ var ElysiaStatus = class {
492
500
  const response = res ?? (code in require_constants.StatusMapBack ? require_constants.StatusMapBack[code] : code);
493
501
  this.status = require_constants.StatusMap[code] ?? code;
494
502
  if (!emptyHttpStatus.has(this.status)) this.response = response;
503
+ else if (headers) {
504
+ const kept = {};
505
+ for (const key of Object.keys(headers)) if (key.toLowerCase() !== "content-type") kept[key] = headers[key];
506
+ headers = kept;
507
+ }
495
508
  this.headers = headers;
496
509
  }
497
510
  };
498
511
  Object.defineProperty(ElysiaStatus, "name", { value: "ElysiaStatus" });
499
512
  const status = (code, response) => new ElysiaStatus(code, response);
500
513
  const PROBLEM_JSON = "application/problem+json";
514
+ /** Title of a status, as `problemBody` fills it */
515
+ const titleOf = (status) => require_constants.StatusMapBack[status] ?? "Error";
501
516
  function problemBody(p) {
502
517
  const status = typeof p.status === "string" ? require_constants.StatusMap[p.status] ?? 500 : p.status ?? 500;
503
518
  const body = {
@@ -505,7 +520,7 @@ function problemBody(p) {
505
520
  ...p,
506
521
  status
507
522
  };
508
- if (body.title == null) body.title = require_constants.StatusMapBack[status] ?? "Error";
523
+ body.title ??= titleOf(status);
509
524
  return body;
510
525
  }
511
526
  function problemResponse(p, headers) {
@@ -571,9 +586,9 @@ function problem(statusOrDetail, detail) {
571
586
  * the instance to a response on its own, no `.error(Class, handler)` needed
572
587
  *
573
588
  * Everything an owned `HTTPError` serves is an RFC 9457 problem document:
574
- * `type` is the problem type carried on the wire, an annotated object body
575
- * merges into the envelope, and any other body (or the error message, when
576
- * there is none) becomes `detail`
589
+ * `type` is the problem type carried on the wire, and the body (or the error
590
+ * message, when there is none) becomes `detail`, an object nested verbatim
591
+ * and never merged into the envelope
577
592
  *
578
593
  * - `detail()` - the common case. Whatever it returns becomes the `detail`
579
594
  * member of the problem document, verbatim, objects included. The envelope
@@ -662,4 +677,5 @@ exports.problemResponse = problemResponse;
662
677
  exports.problemTypeOf = problemTypeOf;
663
678
  exports.status = status;
664
679
  exports.subValueAt = subValueAt;
680
+ exports.titleOf = titleOf;
665
681
  exports.validationDetail = validationDetail;
package/dist/error.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ // @bun
1
2
  import { StatusMap, StatusMapBack } from "./constants.mjs";
2
3
  import { Create } from "./type/bridge.mjs";
3
4
  import { isProduction } from "./universal/is-production.mjs";
@@ -48,7 +49,7 @@ function problemTypeOf(code) {
48
49
  }
49
50
  /**
50
51
  * Problem members an `ElysiaError` serves. `title` is left to `problemBody`,
51
- * which derives it from the status — so `response` is only worth serving as
52
+ * which derives it from the status \u2014 so `response` is only worth serving as
52
53
  * `detail` when it says something the title doesn't
53
54
  */
54
55
  function elysiaErrorProblem(error) {
@@ -303,7 +304,14 @@ var ValidationError = class extends ElysiaError {
303
304
  resolved = this.#thunk() ?? [];
304
305
  if (resolved.length > 64) resolved = resolved.slice(0, 64);
305
306
  resolved = scopeIssues(resolved);
306
- const sub = walkSubSchema(this.schema, resolved[0]?.instancePath);
307
+ let sub = walkSubSchema(this.schema, resolved[0]?.instancePath);
308
+ const missing = resolved[0]?.keyword === "required" && sub?.properties ? resolved[0].params?.requiredProperties : void 0;
309
+ if (Array.isArray(missing)) {
310
+ for (const key of missing) if (sub.properties[key]?.error !== void 0) {
311
+ sub = sub.properties[key];
312
+ break;
313
+ }
314
+ }
307
315
  if (sub?.error !== void 0) custom = typeof sub.error === "function" ? sub.error(production && !allowUnsafe ? {
308
316
  type: "validation",
309
317
  on: type,
@@ -332,8 +340,9 @@ var ValidationError = class extends ElysiaError {
332
340
  if (!this.errors) return [];
333
341
  return this.#collapseCoercionErrors(this.errors.filter(Boolean)).map((e) => {
334
342
  if (!e) return e;
343
+ const raw = e.path ?? e.instancePath;
335
344
  const issue = {
336
- path: Array.isArray(e.path) ? e.path.length ? e.path.map(segmentString).join(".") : "root" : typeof e.path === "string" ? e.path.replace(/^\//, "").replace(/\//g, ".") || "root" : "root",
345
+ path: Array.isArray(raw) && raw.length ? raw.map(segmentString).join(".") : typeof raw === "string" && raw ? raw.replace(/^\//, "").replace(/\//g, ".") : "root",
337
346
  message: e.message ?? "",
338
347
  schemaPath: e.schemaPath,
339
348
  params: e.params
@@ -491,12 +500,19 @@ var ElysiaStatus = class {
491
500
  const response = res ?? (code in StatusMapBack ? StatusMapBack[code] : code);
492
501
  this.status = StatusMap[code] ?? code;
493
502
  if (!emptyHttpStatus.has(this.status)) this.response = response;
503
+ else if (headers) {
504
+ const kept = {};
505
+ for (const key of Object.keys(headers)) if (key.toLowerCase() !== "content-type") kept[key] = headers[key];
506
+ headers = kept;
507
+ }
494
508
  this.headers = headers;
495
509
  }
496
510
  };
497
511
  Object.defineProperty(ElysiaStatus, "name", { value: "ElysiaStatus" });
498
512
  const status = (code, response) => new ElysiaStatus(code, response);
499
513
  const PROBLEM_JSON = "application/problem+json";
514
+ /** Title of a status, as `problemBody` fills it */
515
+ const titleOf = (status) => StatusMapBack[status] ?? "Error";
500
516
  function problemBody(p) {
501
517
  const status = typeof p.status === "string" ? StatusMap[p.status] ?? 500 : p.status ?? 500;
502
518
  const body = {
@@ -504,7 +520,7 @@ function problemBody(p) {
504
520
  ...p,
505
521
  status
506
522
  };
507
- if (body.title == null) body.title = StatusMapBack[status] ?? "Error";
523
+ body.title ??= titleOf(status);
508
524
  return body;
509
525
  }
510
526
  function problemResponse(p, headers) {
@@ -570,9 +586,9 @@ function problem(statusOrDetail, detail) {
570
586
  * the instance to a response on its own, no `.error(Class, handler)` needed
571
587
  *
572
588
  * Everything an owned `HTTPError` serves is an RFC 9457 problem document:
573
- * `type` is the problem type carried on the wire, an annotated object body
574
- * merges into the envelope, and any other body (or the error message, when
575
- * there is none) becomes `detail`
589
+ * `type` is the problem type carried on the wire, and the body (or the error
590
+ * message, when there is none) becomes `detail`, an object nested verbatim
591
+ * and never merged into the envelope
576
592
  *
577
593
  * - `detail()` - the common case. Whatever it returns becomes the `detail`
578
594
  * member of the problem document, verbatim, objects included. The envelope
@@ -594,7 +610,7 @@ function problem(statusOrDetail, detail) {
594
610
  * return { balance: 0, currency: 'usd' }
595
611
  * }
596
612
  * }
597
- * // → { type: 'OUT_OF_CREDIT', title: 'Payment Required', status: 402,
613
+ * // \u2192 { type: 'OUT_OF_CREDIT', title: 'Payment Required', status: 402,
598
614
  * // detail: { balance: 0, currency: 'usd' } }
599
615
  *
600
616
  * class Overdrawn extends HTTPError<'OVERDRAWN'> {
@@ -641,4 +657,4 @@ var HTTPError = class HTTPError extends Error {
641
657
  };
642
658
 
643
659
  //#endregion
644
- export { ElysiaError, ElysiaStatus, HTTPError, InternalServerError, MAX_ERRORS, NotFound, PROBLEM_JSON, ParseError, ValidationError, elysiaErrorProblem, internalServerErrorBody, internalServerErrorBodyString, internalServerErrorResponse, isProduction, problem, problemBody, problemResponse, problemTypeOf, status, subValueAt, validationDetail };
660
+ export { ElysiaError, ElysiaStatus, HTTPError, InternalServerError, MAX_ERRORS, NotFound, PROBLEM_JSON, ParseError, ValidationError, elysiaErrorProblem, internalServerErrorBody, internalServerErrorBodyString, internalServerErrorResponse, isProduction, problem, problemBody, problemResponse, problemTypeOf, status, subValueAt, titleOf, validationDetail };
@@ -1,3 +1,4 @@
1
+ // @bun
1
2
  //#region src/generation.ts
2
3
  const frozenRootOf = (root) => root["~generation"] ?? root;
3
4
  const resolvedTraceOf = (root) => frozenRootOf(root)["~ext"]?.capability?.trace?.provider;
@@ -2,7 +2,12 @@ import { Context } from "../context.js";
2
2
  import { AppHook } from "../types.js";
3
3
 
4
4
  //#region src/handler/error.d.ts
5
- declare const claimsProblemType: (error: any) => boolean;
5
+ /**
6
+ * Whether an error claims a problem type, judged on `type` as the caller
7
+ * read it once: a getter read again could answer anything else, `undefined`
8
+ * included
9
+ */
10
+ declare const claimsProblemType: (error: any, type: unknown) => boolean;
6
11
  declare function adoptErrorType(result: any, error: any): any;
7
12
  /**
8
13
  * Response served once every error hook has declined the error.
@@ -11,25 +16,17 @@ declare function adoptErrorType(result: any, error: any): any;
11
16
  * which must land on *this* function rather than re-implementing it
12
17
  */
13
18
  declare function fallbackResponse(context: Context, error: any, mapResponse: (response: unknown, set: Context['set'], context?: Context) => unknown): unknown;
14
- /**
15
- * Numeric form of an annotated status, which may be written as a name.
16
- * A numeric string keeps coercing so the production mask below can't be
17
- * slipped past with `'502'`
18
- */
19
19
  declare const resolveStatus: (status: unknown) => unknown;
20
20
  /**
21
21
  * Body served by an error that carries a status but no usable body:
22
- * its declared `response`, otherwise its message
22
+ * its declared `response`, otherwise its message, or `mask` in its place
23
+ * on a production 5xx
23
24
  */
24
- declare function statusFallbackBody(error: any, status: unknown): any;
25
+ declare function statusFallbackBody(error: any, status: unknown, mask?: string): any;
25
26
  /**
26
- * Read one annotation knob.
27
- *
28
- * Both knobs are canonically methods, so they're evaluated per serve and may
29
- * be `async`. Running a stranger's function is side-effect surface (it may
30
- * consume a stream or do IO), so it takes the same problem claim the shaping
31
- * does — an unclaimed duck error never invokes one. A *value* annotation stays
32
- * inert data and keeps duck-participating as it always has
27
+ * Read one annotation knob, a method (may be `async`) or a plain value.
28
+ * A method may have side effects, so only an error claiming a problem type
29
+ * gets it invoked; a plain value is read from any error
33
30
  */
34
31
  declare const readAnnotation: (self: any, key: "value" | "detail", claimsProblem: boolean) => any;
35
32
  declare function createErrorHandler(onErrors: AppHook['error'] | undefined, mapResponse: (response: unknown, set: Context['set'], ...any: unknown[]) => unknown, allowUnsafe?: boolean): (context: Context, error: Error, sign?: ((set: Context["set"]) => unknown) | undefined) => unknown;
@@ -31,14 +31,21 @@ function parseQuery(context) {
31
31
  });
32
32
  }
33
33
  const isPristineNotFound = (context, error) => error instanceof require_error.NotFound && error.response === "Not Found" && !context.set.cookie && !require_utils.isNotEmpty(context.set.headers);
34
- const claimsProblemType = (error) => typeof error?.type === "string" ? !(error instanceof require_error.ValidationError) && error.constructor?.name !== "ValidationError" : error instanceof require_error.HTTPError;
34
+ /**
35
+ * Whether an error claims a problem type, judged on `type` as the caller
36
+ * read it once: a getter read again could answer anything else, `undefined`
37
+ * included
38
+ */
39
+ const claimsProblemType = (error, type) => typeof type === "string" ? !(error instanceof require_error.ValidationError) && error.constructor?.name !== "ValidationError" : error instanceof require_error.HTTPError;
35
40
  function adoptErrorType(result, error) {
36
41
  const body = result?.response;
37
- if (typeof error?.type !== "string" || !claimsProblemType(error) || body?.type !== "about:blank" || result.headers?.["content-type"] !== "application/problem+json") return result;
42
+ const type = error?.type;
43
+ if (typeof type !== "string" || !claimsProblemType(error, type) || body?.type !== "about:blank" || result.headers?.["content-type"] !== "application/problem+json") return result;
44
+ const code = error.code;
38
45
  return new require_error.ElysiaStatus(result.status, {
39
46
  ...body,
40
- type: error.type,
41
- ...typeof error.code === "string" ? { code: error.code } : {}
47
+ type,
48
+ ...typeof code === "string" ? { code } : {}
42
49
  }, result.headers);
43
50
  }
44
51
  /**
@@ -55,38 +62,35 @@ function fallbackResponse(context, error, mapResponse) {
55
62
  } catch {}
56
63
  return fallbackErrorResponse(context, error, mapResponse);
57
64
  }
58
- /**
59
- * Numeric form of an annotated status, which may be written as a name.
60
- * A numeric string keeps coercing so the production mask below can't be
61
- * slipped past with `'502'`
62
- */
63
65
  const resolveStatus = (status) => typeof status === "string" ? require_constants.StatusMap[status] ?? +status : status;
64
66
  /**
65
67
  * Body served by an error that carries a status but no usable body:
66
- * its declared `response`, otherwise its message
68
+ * its declared `response`, otherwise its message, or `mask` in its place
69
+ * on a production 5xx
67
70
  */
68
- function statusFallbackBody(error, status) {
71
+ function statusFallbackBody(error, status, mask = "Internal Server Error") {
69
72
  const masked = require_universal_is_production.isProduction() && status >= 500;
70
73
  const declared = error.response;
71
- return declared !== void 0 && !(masked && typeof declared === "object") ? declared : masked ? "Internal Server Error" : error.message ?? "";
74
+ return declared !== void 0 && !(masked && typeof declared === "object") ? declared : masked ? mask : error.message ?? "";
72
75
  }
73
76
  /**
74
77
  * RFC 9457 problem document carrying `detail` verbatim, mirroring `problem()`.
78
+ * `type` comes in as the value the claim was checked on, and `code` is read
79
+ * once, so a getter can't put anything but a string on the wire
75
80
  */
76
- const problemOf = (self, detail, status, claimsProblem) => new require_error.ElysiaStatus(status, require_error.problemBody({
77
- type: self.type ?? "about:blank",
78
- ...claimsProblem && typeof self.code === "string" ? { code: self.code } : {},
79
- detail,
80
- status
81
- }), { "content-type": require_error.PROBLEM_JSON });
81
+ const problemOf = (self, type, detail, status, claimsProblem) => {
82
+ const code = claimsProblem ? self.code : void 0;
83
+ return new require_error.ElysiaStatus(status, require_error.problemBody({
84
+ type: typeof type === "string" ? type : "about:blank",
85
+ ...typeof code === "string" ? { code } : {},
86
+ detail,
87
+ status
88
+ }), { "content-type": require_error.PROBLEM_JSON });
89
+ };
82
90
  /**
83
- * Read one annotation knob.
84
- *
85
- * Both knobs are canonically methods, so they're evaluated per serve and may
86
- * be `async`. Running a stranger's function is side-effect surface (it may
87
- * consume a stream or do IO), so it takes the same problem claim the shaping
88
- * does — an unclaimed duck error never invokes one. A *value* annotation stays
89
- * inert data and keeps duck-participating as it always has
91
+ * Read one annotation knob, a method (may be `async`) or a plain value.
92
+ * A method may have side effects, so only an error claiming a problem type
93
+ * gets it invoked; a plain value is read from any error
90
94
  */
91
95
  const readAnnotation = (self, key, claimsProblem) => {
92
96
  const annotation = self[key];
@@ -98,7 +102,8 @@ function fallbackErrorResponse(context, error, mapResponse) {
98
102
  const self = error ?? {};
99
103
  const status = resolveStatus(self.status);
100
104
  const owned = error instanceof require_error.HTTPError;
101
- const claimsProblem = claimsProblemType(error);
105
+ const type = self.type;
106
+ const claimsProblem = claimsProblemType(error, type);
102
107
  const served = typeof status === "number" ? status : resolveStatus(context.set.status);
103
108
  const failed = (cause) => {
104
109
  context.set.status = 500;
@@ -109,32 +114,29 @@ function fallbackErrorResponse(context, error, mapResponse) {
109
114
  }
110
115
  const legacy = () => {
111
116
  if (error?.status) return mapResponse(statusFallbackBody(error, status), context.set, context);
112
- if (error?.message != null) {
113
- if (context.set.status === void 0 || context.set.status === 200) context.set.status = 500;
114
- return mapResponse(require_error.internalServerErrorResponse(error), context.set, context);
115
- }
117
+ if (error?.message != null && (context.set.status === void 0 || context.set.status === 200)) context.set.status = 500;
116
118
  return mapResponse(require_error.internalServerErrorResponse(error), context.set, context);
117
119
  };
118
120
  const serveMessage = () => {
119
121
  if (!claimsProblem) return legacy();
120
122
  mergeHeaders();
121
- return mapResponse(problemOf(self, statusFallbackBody(error, served), served, claimsProblem), context.set, context);
123
+ return mapResponse(problemOf(self, type, statusFallbackBody(error, served, require_error.titleOf(served)), served, claimsProblem), context.set, context);
122
124
  };
123
- const tier = (key) => {
125
+ const serveAnnotation = (key) => {
124
126
  let annotation;
125
127
  try {
126
128
  annotation = readAnnotation(self, key, claimsProblem);
127
129
  } catch (cause) {
128
130
  return failed(cause);
129
131
  }
130
- if (annotation === void 0) return key === "value" ? tier("detail") : serveMessage();
132
+ if (annotation === void 0) return key === "value" ? serveAnnotation("detail") : serveMessage();
131
133
  if (annotation instanceof Promise) return annotation.then((resolved) => {
132
- if (resolved === void 0) return key === "value" ? tier("detail") : serveMessage();
134
+ if (resolved === void 0) return key === "value" ? serveAnnotation("detail") : serveMessage();
133
135
  mergeHeaders();
134
- return mapResponse(key === "value" ? resolved : problemOf(self, resolved, served, claimsProblem), context.set, context);
136
+ return mapResponse(key === "value" ? resolved : problemOf(self, type, resolved, served, claimsProblem), context.set, context);
135
137
  }, failed);
136
138
  mergeHeaders();
137
- return mapResponse(key === "value" ? annotation : problemOf(self, annotation, served, claimsProblem), context.set, context);
139
+ return mapResponse(key === "value" ? annotation : problemOf(self, type, annotation, served, claimsProblem), context.set, context);
138
140
  };
139
141
  if (error instanceof require_error.ValidationError) return mapResponse(error.type === "response" ? require_error.internalServerErrorResponse(void 0) : new require_error.ElysiaStatus(422, require_error.problemBody({
140
142
  type: "validation",
@@ -142,7 +144,8 @@ function fallbackErrorResponse(context, error, mapResponse) {
142
144
  title: "Validation Error",
143
145
  status: 422
144
146
  }), { "content-type": require_error.PROBLEM_JSON }), context.set, context);
145
- if (owned || error instanceof Error && typeof status === "number" && status >= 100 && !(require_universal_is_production.isProduction() && status >= 500)) return tier("value");
147
+ if (owned || error instanceof Error && typeof status === "number" && status >= 100 && !(require_universal_is_production.isProduction() && status >= 500)) return serveAnnotation("value");
148
+ if (claimsProblem && error instanceof Error && typeof status === "number" && status >= 500) return mapResponse(problemOf(self, type, require_error.titleOf(status), status, false), context.set, context);
146
149
  return legacy();
147
150
  }
148
151
  function applyErrorStatus(context, error) {
@@ -166,7 +169,7 @@ function createErrorHandler(onErrors, mapResponse, allowUnsafe = false) {
166
169
  else if (context.set.status === void 0 || context.set.status === 200) context.set.status = 500;
167
170
  return mapWith(sign)(adoptErrorType(result, error), context.set, context);
168
171
  };
169
- const settle = (context, error, sign) => isPristineNotFound(context, error) ? require_handler_utils.getNotFound() : fallbackResponse(context, error, mapWith(sign));
172
+ const serveUnhandled = (context, error, sign) => isPristineNotFound(context, error) ? require_handler_utils.getNotFound() : fallbackResponse(context, error, mapWith(sign));
170
173
  if (require_handler_utils.hasAsync(onErrors)) return async (context, error, sign) => {
171
174
  require_adapter_utils.materializeSetHeaders(context.set);
172
175
  enter(context, error);
@@ -175,7 +178,7 @@ function createErrorHandler(onErrors, mapResponse, allowUnsafe = false) {
175
178
  if (typeof result?.then === "function") result = await result;
176
179
  if (result !== void 0) return respond(context, error, result, sign);
177
180
  }
178
- return settle(context, error, sign);
181
+ return serveUnhandled(context, error, sign);
179
182
  };
180
183
  return (context, error, sign) => {
181
184
  require_adapter_utils.materializeSetHeaders(context.set);
@@ -184,7 +187,7 @@ function createErrorHandler(onErrors, mapResponse, allowUnsafe = false) {
184
187
  const result = onErrors[i](context);
185
188
  if (result !== void 0) return respond(context, error, result, sign);
186
189
  }
187
- return settle(context, error, sign);
190
+ return serveUnhandled(context, error, sign);
188
191
  };
189
192
  }
190
193