elysia 2.0.0-exp.2 → 2.0.0-exp.3

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 (81) hide show
  1. package/dist/adapter/bun/index.d.ts +1 -1
  2. package/dist/adapter/bun/router.js +1 -1
  3. package/dist/adapter/bun/router.mjs +1 -1
  4. package/dist/adapter/constants.d.ts +1 -1
  5. package/dist/adapter/index.d.ts +1 -1
  6. package/dist/adapter/utils.d.ts +1 -1
  7. package/dist/adapter/web-standard/handler.js +5 -2
  8. package/dist/adapter/web-standard/handler.mjs +6 -3
  9. package/dist/adapter/web-standard/index.d.ts +1 -1
  10. package/dist/base.js +29 -43
  11. package/dist/base.mjs +29 -43
  12. package/dist/compile/aot.d.ts +4 -0
  13. package/dist/compile/aot.js +3 -0
  14. package/dist/compile/aot.mjs +3 -0
  15. package/dist/compile/handler/index.js +53 -16
  16. package/dist/compile/handler/index.mjs +54 -17
  17. package/dist/compile/handler/params.js +1 -0
  18. package/dist/compile/handler/params.mjs +2 -1
  19. package/dist/compile/handler/utils.d.ts +2 -1
  20. package/dist/compile/handler/utils.js +6 -0
  21. package/dist/compile/handler/utils.mjs +6 -1
  22. package/dist/cookie/utils.js +1 -1
  23. package/dist/cookie/utils.mjs +1 -1
  24. package/dist/error.d.ts +1 -1
  25. package/dist/handler/error.js +2 -2
  26. package/dist/handler/error.mjs +3 -3
  27. package/dist/handler/fetch.js +7 -5
  28. package/dist/handler/fetch.mjs +7 -5
  29. package/dist/parse-query.js +1 -1
  30. package/dist/parse-query.mjs +1 -1
  31. package/dist/plugin/core.js +16 -10
  32. package/dist/plugin/core.mjs +16 -10
  33. package/dist/plugin/source.js +9 -5
  34. package/dist/plugin/source.mjs +9 -5
  35. package/dist/sucrose.js +23 -10
  36. package/dist/sucrose.mjs +23 -10
  37. package/dist/type/bridge.d.ts +2 -1
  38. package/dist/type/coerce.d.ts +20 -2
  39. package/dist/type/coerce.js +110 -0
  40. package/dist/type/coerce.mjs +109 -2
  41. package/dist/type/compat.js +4 -3
  42. package/dist/type/compat.mjs +2 -1
  43. package/dist/type/constants.d.ts +1 -1
  44. package/dist/type/elysia/boolean-string.js +1 -1
  45. package/dist/type/elysia/boolean-string.mjs +1 -1
  46. package/dist/type/elysia/integer-string.js +1 -1
  47. package/dist/type/elysia/integer-string.mjs +1 -1
  48. package/dist/type/utils.js +4 -4
  49. package/dist/type/utils.mjs +4 -4
  50. package/dist/type/validator/custom-error.d.ts +10 -0
  51. package/dist/type/validator/custom-error.js +113 -0
  52. package/dist/type/validator/custom-error.mjs +110 -0
  53. package/dist/type/validator/default-precompute.d.ts +11 -0
  54. package/dist/type/validator/default-precompute.js +216 -0
  55. package/dist/type/validator/default-precompute.mjs +212 -0
  56. package/dist/type/validator/frozen-check.d.ts +11 -0
  57. package/dist/type/validator/frozen-check.js +19 -0
  58. package/dist/type/validator/frozen-check.mjs +18 -0
  59. package/dist/type/{validator.d.ts → validator/index.d.ts} +6 -19
  60. package/dist/type/validator/index.js +536 -0
  61. package/dist/type/validator/index.mjs +531 -0
  62. package/dist/type/validator/string-codec-aot.d.ts +9 -0
  63. package/dist/type/validator/string-codec-aot.js +106 -0
  64. package/dist/type/validator/string-codec-aot.mjs +102 -0
  65. package/dist/type/validator/validator-cache.d.ts +21 -0
  66. package/dist/type/validator/validator-cache.js +163 -0
  67. package/dist/type/validator/validator-cache.mjs +161 -0
  68. package/dist/types.d.ts +6 -0
  69. package/dist/universal/file.js +1 -1
  70. package/dist/universal/file.mjs +1 -1
  71. package/dist/utils.d.ts +8 -1
  72. package/dist/utils.js +71 -37
  73. package/dist/utils.mjs +71 -38
  74. package/dist/validator/index.d.ts +1 -1
  75. package/dist/validator/index.js +6 -0
  76. package/dist/validator/index.mjs +6 -0
  77. package/dist/ws/route.js +35 -22
  78. package/dist/ws/route.mjs +35 -22
  79. package/package.json +1 -1
  80. package/dist/type/validator.js +0 -1033
  81. package/dist/type/validator.mjs +0 -1029
@@ -10,7 +10,7 @@ import { sucrose } from "../../sucrose.mjs";
10
10
  import { Capture, Compiled } from "../aot.mjs";
11
11
  import { RouteValidator } from "../../validator/route.mjs";
12
12
  import { isAsyncFunction, isAsyncLifecycle, mayReturnPromise } from "../utils.mjs";
13
- import { cloneResponse, getQueryParseArgs, mapAfterHandle, mapAfterResponse, mapBeforeHandle, mapError, mapMapResponse, mapTransform } from "./utils.mjs";
13
+ import { cloneResponse, getQueryParseArgs, hasRequestBody, mapAfterHandle, mapAfterResponse, mapBeforeHandle, mapError, mapMapResponse, mapTransform } from "./utils.mjs";
14
14
  import { defaultAdapter } from "../../adapter/constants.mjs";
15
15
  import { forwardError } from "../../handler/utils.mjs";
16
16
  import { createTracer } from "../../trace.mjs";
@@ -93,20 +93,22 @@ c.contentType=ct
93
93
  const child = report?.resolveChild("default");
94
94
  const begin = child ? child.begin : "";
95
95
  const end = child ? child.end() : "";
96
- const guard = bodyVali ? "ct" : "ct&&c.request.body";
96
+ const guard = bodyVali ? "ct" : "ct&&hb(c.request)";
97
97
  code += hasFn ? `if(!hasBody&&${guard}){${begin}c.body=await pd(c,ct)\n${end}}\n` : `if(${guard}){${begin}c.body=await pd(c,ct)\n${end}}\n`;
98
+ if (!bodyVali) link(hasRequestBody, "hb");
98
99
  link(adapter.default, "pd");
99
100
  }
100
101
  return hasFn ? "let hasBody=false,_bp\n" + code : code;
101
102
  }
102
103
  const isAsyncValidator = (vali) => vali?.isAsync ?? true;
103
- function applyHook(localHook, appHook, rootHook) {
104
+ function applyHook(localHook, appHook, rootHook, appHookFresh = false) {
104
105
  let hook;
105
106
  if (localHook && appHook) hook = mergeHook(cloneHook(localHook), appHook, true);
106
107
  else {
107
108
  const base = localHook ?? appHook;
108
- if (!rootHook) return base ? cloneHook(base) : base;
109
- hook = base ? cloneHook(base) : nullObject();
109
+ const ownsBase = appHookFresh && !localHook && base !== void 0;
110
+ if (!rootHook) return ownsBase ? base : base ? cloneHook(base) : base;
111
+ hook = ownsBase ? base : base ? cloneHook(base) : nullObject();
110
112
  }
111
113
  if (rootHook) mergeHook(hook, rootHook, true, true);
112
114
  return hook;
@@ -134,11 +136,16 @@ function dropHooksByOrigin(hook, skip) {
134
136
  const v = hook[key];
135
137
  if (!v) continue;
136
138
  if (Array.isArray(v)) {
137
- const kept = v.filter((fn) => {
139
+ let kept;
140
+ for (let i = 0; i < v.length; i++) {
141
+ const fn = v[i];
138
142
  const origin = fnOrigin.get(fn);
139
- return origin === void 0 || !skip.has(origin);
140
- });
141
- if (kept.length !== v.length) {
143
+ const keep = origin === void 0 || !skip.has(origin);
144
+ if (kept) {
145
+ if (keep) kept.push(fn);
146
+ } else if (!keep) kept = v.slice(0, i);
147
+ }
148
+ if (kept) {
142
149
  if (out === hook) out = { ...hook };
143
150
  out[key] = kept;
144
151
  }
@@ -152,6 +159,21 @@ function dropHooksByOrigin(hook, skip) {
152
159
  }
153
160
  return out;
154
161
  }
162
+ function reconstructNeedsHookState(names) {
163
+ for (let i = 0; i < names.length; i++) switch (names[i]) {
164
+ case "ho":
165
+ case "tf":
166
+ case "bf":
167
+ case "af":
168
+ case "mr":
169
+ case "er":
170
+ case "ar":
171
+ case "va":
172
+ case "cc":
173
+ case "tr": return true;
174
+ }
175
+ return false;
176
+ }
155
177
  const createInlineHandler = (map, h) => ((c) => {
156
178
  const r = h(c);
157
179
  if (r instanceof Error) throw r;
@@ -202,7 +224,7 @@ function buildNativeStaticResponse([, , handler, instance, localHook, appHook, i
202
224
  if (localHook) root["~applyMacro"](localHook);
203
225
  resolveChainMacros(root, appHook);
204
226
  if (inheritedChain) resolveChainMacros(root, inheritedChain);
205
- const hook = applyHook(localHook, flattenChainMemo(root, appHook), instance !== root ? composeRootHook(root, inheritedChain) : void 0);
227
+ const hook = applyHook(localHook, flattenChainMemo(root, appHook), instance !== root ? composeRootHook(root, inheritedChain) : void 0, true);
206
228
  const has = (v) => Array.isArray(v) ? v.length > 0 : !!v;
207
229
  if (has(hook?.parse) || has(hook?.transform) || has(hook?.beforeHandle) || has(hook?.afterHandle) || has(hook?.mapResponse) || has(hook?.afterResponse) || has(hook?.trace)) return;
208
230
  if (hook?.body || hook?.query || hook?.params || hook?.headers || hook?.cookie || (hook?.schemas)?.length) return;
@@ -230,7 +252,7 @@ function composeRouteHook(instance, localHook, appHook, inheritedChain, root) {
230
252
  collectHookOrigins(flatAppHook, present);
231
253
  if (present.size) rootHook = dropHooksByOrigin(rootHook, present);
232
254
  }
233
- let hook = applyHook(localHook, flatAppHook, rootHook);
255
+ let hook = applyHook(localHook, flatAppHook, rootHook, true);
234
256
  if (instance !== root) {
235
257
  const errors = flattenChain(instance["~hookChain"], isLocalScope)?.error;
236
258
  if (errors) {
@@ -248,6 +270,16 @@ function composeRouteHook(instance, localHook, appHook, inheritedChain, root) {
248
270
  }
249
271
  function compileHandler([_method, path, handler, instance, localHook, appHook, inheritedChain], root, precomputedStatic) {
250
272
  const adapter = root["~config"]?.adapter ?? defaultAdapter;
273
+ const method = mapMethodBack(_method);
274
+ const reconstructed = Compiled.handlers?.[method]?.[path];
275
+ if (reconstructed && !precomputedStatic && typeof handler === "function" && !root["~ext"]?.macro && !reconstructNeedsHookState(reconstructed.a)) return reconstructed.f(handler, ...resolveHandlerParams(reconstructed.a, {
276
+ parse: adapter.parse,
277
+ res: adapter.response,
278
+ hook: nullObject(),
279
+ vali: void 0,
280
+ cookieConfig: void 0,
281
+ tracers: void 0
282
+ }));
251
283
  if (root["~ext"]?.macro) {
252
284
  if (localHook) root["~applyMacro"](localHook);
253
285
  if (appHook) resolveChainMacros(root, appHook);
@@ -264,8 +296,7 @@ function compileHandler([_method, path, handler, instance, localHook, appHook, i
264
296
  toArray("afterResponse", hook);
265
297
  toArray("error", hook);
266
298
  }
267
- const method = mapMethodBack(_method);
268
- const vali = hook ? new RouteValidator(hook, {
299
+ const buildValidator = () => hook ? new RouteValidator(hook, {
269
300
  models: root["~ext"]?.models,
270
301
  normalize: root["~config"]?.normalize,
271
302
  sanitize: root["~config"]?.sanitize,
@@ -296,15 +327,15 @@ function compileHandler([_method, path, handler, instance, localHook, appHook, i
296
327
  const resolve = (p) => typeof p === "string" && p in namedParsers ? namedParsers[p] : p;
297
328
  hook.parse = Array.isArray(hook.parse) ? hook.parse.map(resolve) : resolve(hook.parse);
298
329
  }
299
- const reconstructed = Compiled.handlers?.[method]?.[path];
300
330
  if (reconstructed) return reconstructed.f(handler, ...resolveHandlerParams(reconstructed.a, {
301
331
  parse: adapter.parse,
302
332
  res: adapter.response,
303
333
  hook: hook ?? nullObject(),
304
- vali,
334
+ vali: reconstructed.a.includes("va") ? buildValidator() : void 0,
305
335
  cookieConfig: reconstructed.a.includes("cc") ? compileCookieConfig(hook?.cookie, root["~config"]?.cookie) : void 0,
306
336
  tracers: reconstructed.a.includes("tr") ? (hook?.trace)?.map((fn) => createTracer(fn)) : void 0
307
337
  }));
338
+ const vali = buildValidator();
308
339
  const inference = sucrose(handler, hook);
309
340
  const params = /* @__PURE__ */ new Set();
310
341
  let alias = "";
@@ -373,7 +404,13 @@ function compileHandler([_method, path, handler, instance, localHook, appHook, i
373
404
  };
374
405
  } };
375
406
  };
376
- const responseValiAsync = !!(vali?.response && Object.values(vali.response).find(isAsyncValidator));
407
+ let responseValiAsync = false;
408
+ if (vali?.response) {
409
+ for (const code in vali.response) if (isAsyncValidator(vali.response[code])) {
410
+ responseValiAsync = true;
411
+ break;
412
+ }
413
+ }
377
414
  const handlerIsAsync = isHandleFunction && isAsyncFunction(handler);
378
415
  const errorHookForcesAsync = hasErrorHook && (hasAfterHandle || hasMapResponse || hasResponseValidator);
379
416
  const responseValiForcesAsync = hasResponseValidator && isHandleFunction && !handlerIsAsync && (mayReturnPromise(handler) || mayReturnIdentifier(handler));
@@ -609,7 +646,7 @@ let _r${hasMapResponse ? ",tmp" : ""}\n` + mapError(hook.error, [
609
646
  if (alias === "rc" || !isAsync && !syncErrorHook && alias === "rc,fe") return createInlineHandler(res.compact ?? res.map, handler);
610
647
  else if (alias === "rm" || !isAsync && !syncErrorHook && alias === "rm,fe") return createInlineHandlerWithSet(res.map, handler);
611
648
  }
612
- if (!precomputedStatic) Capture.handler({
649
+ Capture.handler({
613
650
  method,
614
651
  path,
615
652
  alias,
@@ -15,6 +15,7 @@ const HANDLER_PARAMS = {
15
15
  pa: (c) => c.parse.arrayBuffer,
16
16
  pt: (c) => c.parse.text,
17
17
  pd: (c) => c.parse.default,
18
+ hb: () => require_compile_handler_utils.hasRequestBody,
18
19
  rm: (c) => c.res.map,
19
20
  rc: (c) => c.res.compact ?? c.res.map,
20
21
  rid: () => require_utils.requestId,
@@ -3,7 +3,7 @@ import { ElysiaStatus, ParseError, ValidationError } from "../../error.mjs";
3
3
  import { buildCookieJar, parseCookieRaw, parseCookieRawSync, signCookieValues } from "../../cookie/utils.mjs";
4
4
  import { tee } from "../../adapter/utils.mjs";
5
5
  import { parseQueryFromURL } from "../../parse-query.mjs";
6
- import { cloneResponse } from "./utils.mjs";
6
+ import { cloneResponse, hasRequestBody } from "./utils.mjs";
7
7
  import { forwardError } from "../../handler/utils.mjs";
8
8
 
9
9
  //#region src/compile/handler/params.ts
@@ -14,6 +14,7 @@ const HANDLER_PARAMS = {
14
14
  pa: (c) => c.parse.arrayBuffer,
15
15
  pt: (c) => c.parse.text,
16
16
  pd: (c) => c.parse.default,
17
+ hb: () => hasRequestBody,
17
18
  rm: (c) => c.res.map,
18
19
  rc: (c) => c.res.compact ?? c.res.map,
19
20
  rid: () => requestId,
@@ -11,6 +11,7 @@ interface TraceReporter {
11
11
  };
12
12
  }
13
13
  declare const cloneResponse: (r: unknown) => unknown;
14
+ declare function hasRequestBody(request: Request): boolean;
14
15
  declare const mapTransform: (event: MaybeArray<TransformHandler<any, any, undefined, "local">>, rest?: [report?: TraceReporter | undefined] | undefined) => string;
15
16
  declare function extractDeriveKeys(fn: Function): string[] | null;
16
17
  declare function mapBeforeHandle(_hooks: AppHook['beforeHandle'] | AppHook['beforeHandle'][0], derive: AnyElysia['~derive'], link: Link, report?: TraceReporter): string;
@@ -26,4 +27,4 @@ declare function getQueryParseChannels(querySchema: any): QueryWalkState | undef
26
27
  declare function getQueryParseArgs(querySchema: any): string;
27
28
  declare const Await: (fn: Function) => "" | "await ";
28
29
  //#endregion
29
- export { Await, TraceReporter, cloneResponse, extractDeriveKeys, getQueryParseArgs, getQueryParseChannels, mapAfterHandle, mapAfterResponse, mapBeforeHandle, mapError, mapMapResponse, mapTransform };
30
+ export { Await, TraceReporter, cloneResponse, extractDeriveKeys, getQueryParseArgs, getQueryParseChannels, hasRequestBody, mapAfterHandle, mapAfterResponse, mapBeforeHandle, mapError, mapMapResponse, mapTransform };
@@ -10,6 +10,11 @@ const noTrace = {
10
10
  end: () => ""
11
11
  };
12
12
  const cloneResponse = (r) => r instanceof Response ? r.clone() : r;
13
+ function hasRequestBody(request) {
14
+ const length = request.headers.get("content-length");
15
+ if (length !== null) return length !== "0";
16
+ return request.body != null;
17
+ }
13
18
  const trace = (report, fn) => report?.resolveChild(childName(fn)) ?? noTrace;
14
19
  const toArray = (v) => Array.isArray(v) ? v : [v];
15
20
  const mapTransform = map((i, fn, [report]) => {
@@ -434,6 +439,7 @@ exports.cloneResponse = cloneResponse;
434
439
  exports.extractDeriveKeys = extractDeriveKeys;
435
440
  exports.getQueryParseArgs = getQueryParseArgs;
436
441
  exports.getQueryParseChannels = getQueryParseChannels;
442
+ exports.hasRequestBody = hasRequestBody;
437
443
  exports.mapAfterHandle = mapAfterHandle;
438
444
  exports.mapAfterResponse = mapAfterResponse;
439
445
  exports.mapBeforeHandle = mapBeforeHandle;
@@ -9,6 +9,11 @@ const noTrace = {
9
9
  end: () => ""
10
10
  };
11
11
  const cloneResponse = (r) => r instanceof Response ? r.clone() : r;
12
+ function hasRequestBody(request) {
13
+ const length = request.headers.get("content-length");
14
+ if (length !== null) return length !== "0";
15
+ return request.body != null;
16
+ }
12
17
  const trace = (report, fn) => report?.resolveChild(childName(fn)) ?? noTrace;
13
18
  const toArray = (v) => Array.isArray(v) ? v : [v];
14
19
  const mapTransform = map((i, fn, [report]) => {
@@ -428,4 +433,4 @@ function getQueryParseArgs(querySchema) {
428
433
  const Await = (fn) => isAsyncFunction(fn) ? "await " : "";
429
434
 
430
435
  //#endregion
431
- export { Await, cloneResponse, extractDeriveKeys, getQueryParseArgs, getQueryParseChannels, mapAfterHandle, mapAfterResponse, mapBeforeHandle, mapError, mapMapResponse, mapTransform };
436
+ export { Await, cloneResponse, extractDeriveKeys, getQueryParseArgs, getQueryParseChannels, hasRequestBody, mapAfterHandle, mapAfterResponse, mapBeforeHandle, mapError, mapMapResponse, mapTransform };
@@ -104,7 +104,7 @@ function signCookieValues(cookies, config) {
104
104
  if (value === void 0 || value === null) continue;
105
105
  if (typeof value === "object") value = JSON.stringify(value);
106
106
  else if (typeof value !== "string") value = value + "";
107
- const secret = Array.isArray(r.secrets) ? r.secrets.find((s) => s !== null) ?? null : r.secrets;
107
+ const secret = Array.isArray(r.secrets) ? r.secrets[0] ?? null : r.secrets;
108
108
  if (secret === null) throw new TypeError(`Cookie field "${key}" is signed but no \`secrets\` is provided.`);
109
109
  (pending ??= []).push([
110
110
  property,
@@ -102,7 +102,7 @@ function signCookieValues(cookies, config) {
102
102
  if (value === void 0 || value === null) continue;
103
103
  if (typeof value === "object") value = JSON.stringify(value);
104
104
  else if (typeof value !== "string") value = value + "";
105
- const secret = Array.isArray(r.secrets) ? r.secrets.find((s) => s !== null) ?? null : r.secrets;
105
+ const secret = Array.isArray(r.secrets) ? r.secrets[0] ?? null : r.secrets;
106
106
  if (secret === null) throw new TypeError(`Cookie field "${key}" is signed but no \`secrets\` is provided.`);
107
107
  (pending ??= []).push([
108
108
  property,
package/dist/error.d.ts CHANGED
@@ -85,7 +85,7 @@ declare class ElysiaStatus<const in out Code extends number | keyof StatusMap, T
85
85
  constructor(code: Code, res: T);
86
86
  get status(): number;
87
87
  }
88
- declare const status: <const Code extends number | keyof StatusMap, const T = (Code extends keyof StatusMapBack ? StatusMapBack[Code] : Code)>(code: Code, response?: T) => ElysiaStatus<Code, T, Code extends "Continue" | "Switching Protocols" | "Processing" | "Early Hints" | "OK" | "Created" | "Accepted" | "Non-Authoritative Information" | "No Content" | "Reset Content" | "Partial Content" | "Multi-Status" | "Already Reported" | "Multiple Choices" | "Moved Permanently" | "Found" | "See Other" | "Not Modified" | "Temporary Redirect" | "Permanent Redirect" | "Bad Request" | "Unauthorized" | "Payment Required" | "Forbidden" | "Not Found" | "Method Not Allowed" | "Not Acceptable" | "Proxy Authentication Required" | "Request Timeout" | "Conflict" | "Gone" | "Length Required" | "Precondition Failed" | "Payload Too Large" | "URI Too Long" | "Unsupported Media Type" | "Range Not Satisfiable" | "Expectation Failed" | "I'm a teapot" | "Enhance Your Calm" | "Misdirected Request" | "Unprocessable Content" | "Locked" | "Failed Dependency" | "Too Early" | "Upgrade Required" | "Precondition Required" | "Too Many Requests" | "Request Header Fields Too Large" | "Unavailable For Legal Reasons" | "Internal Server Error" | "Not Implemented" | "Bad Gateway" | "Service Unavailable" | "Gateway Timeout" | "HTTP Version Not Supported" | "Variant Also Negotiates" | "Insufficient Storage" | "Loop Detected" | "Not Extended" | "Network Authentication Required" ? {
88
+ declare const status: <const Code extends number | keyof StatusMap, const T = (Code extends keyof StatusMapBack ? StatusMapBack[Code] : Code)>(code: Code, response?: T) => ElysiaStatus<Code, T, Code extends "Bad Request" | "Continue" | "Switching Protocols" | "Processing" | "Early Hints" | "OK" | "Created" | "Accepted" | "Non-Authoritative Information" | "No Content" | "Reset Content" | "Partial Content" | "Multi-Status" | "Already Reported" | "Multiple Choices" | "Moved Permanently" | "Found" | "See Other" | "Not Modified" | "Temporary Redirect" | "Permanent Redirect" | "Unauthorized" | "Payment Required" | "Forbidden" | "Not Found" | "Method Not Allowed" | "Not Acceptable" | "Proxy Authentication Required" | "Request Timeout" | "Conflict" | "Gone" | "Length Required" | "Precondition Failed" | "Payload Too Large" | "URI Too Long" | "Unsupported Media Type" | "Range Not Satisfiable" | "Expectation Failed" | "I'm a teapot" | "Enhance Your Calm" | "Misdirected Request" | "Unprocessable Content" | "Locked" | "Failed Dependency" | "Too Early" | "Upgrade Required" | "Precondition Required" | "Too Many Requests" | "Request Header Fields Too Large" | "Unavailable For Legal Reasons" | "Internal Server Error" | "Not Implemented" | "Bad Gateway" | "Service Unavailable" | "Gateway Timeout" | "HTTP Version Not Supported" | "Variant Also Negotiates" | "Insufficient Storage" | "Loop Detected" | "Not Extended" | "Network Authentication Required" ? {
89
89
  readonly Continue: 100;
90
90
  readonly 'Switching Protocols': 101;
91
91
  readonly Processing: 102;
@@ -18,10 +18,10 @@ function fallbackResponse(context, error, mapResponse, defaultError) {
18
18
  return fallbackErrorResponse(context, error, mapResponse, defaultError);
19
19
  }
20
20
  function fallbackErrorResponse(context, error, mapResponse, defaultError) {
21
- if (error?.status) return mapResponse(error.response !== void 0 ? error.response : error.message ?? "", context.set, context);
21
+ if (error?.status) return mapResponse(error.response !== void 0 ? error.response : require_error.isProduction() && error.status >= 500 ? "Internal Server Error" : error.message ?? "", context.set, context);
22
22
  if (error?.message != null) {
23
23
  if (context.set.status === void 0 || context.set.status === 200) context.set.status = 500;
24
- return mapResponse(error.message, context.set, context);
24
+ return mapResponse(require_error.isProduction() ? "Internal Server Error" : error.message, context.set, context);
25
25
  }
26
26
  return defaultError ? defaultError.clone() : getDefaultError();
27
27
  }
@@ -1,4 +1,4 @@
1
- import { ElysiaStatus, ValidationError } from "../error.mjs";
1
+ import { ElysiaStatus, ValidationError, isProduction } from "../error.mjs";
2
2
  import { parseQueryFromURL } from "../parse-query.mjs";
3
3
  import { cachedResponse, getAsyncIndexes } from "./utils.mjs";
4
4
 
@@ -17,10 +17,10 @@ function fallbackResponse(context, error, mapResponse, defaultError) {
17
17
  return fallbackErrorResponse(context, error, mapResponse, defaultError);
18
18
  }
19
19
  function fallbackErrorResponse(context, error, mapResponse, defaultError) {
20
- if (error?.status) return mapResponse(error.response !== void 0 ? error.response : error.message ?? "", context.set, context);
20
+ if (error?.status) return mapResponse(error.response !== void 0 ? error.response : isProduction() && error.status >= 500 ? "Internal Server Error" : error.message ?? "", context.set, context);
21
21
  if (error?.message != null) {
22
22
  if (context.set.status === void 0 || context.set.status === 200) context.set.status = 500;
23
- return mapResponse(error.message, context.set, context);
23
+ return mapResponse(isProduction() ? "Internal Server Error" : error.message, context.set, context);
24
24
  }
25
25
  return defaultError ? defaultError.clone() : getDefaultError();
26
26
  }
@@ -140,25 +140,27 @@ function createFetchHandler(app) {
140
140
  const trace = new Array(traceLength);
141
141
  for (let i = 0; i < traceLength; i++) trace[i] = tracerFactories[i](context);
142
142
  context.trace = trace;
143
- const requestReports = trace.map((c) => c.request({
143
+ const requestReports = new Array(traceLength);
144
+ for (let i = 0; i < traceLength; i++) requestReports[i] = trace[i].request({
144
145
  id: context.rid,
145
146
  event: "request",
146
147
  name: "request",
147
148
  begin: performance.now(),
148
149
  total: onRequests.length
149
- }));
150
+ });
150
151
  try {
151
152
  for (let i = 0; i < onRequests.length; i++) {
152
- const endReports = requestReports.map((r) => r.resolveChild?.shift?.()?.({
153
+ const endReports = new Array(traceLength);
154
+ for (let j = 0; j < traceLength; j++) endReports[j] = requestReports[j].resolveChild?.shift?.()?.({
153
155
  id: context.rid,
154
156
  event: "request",
155
157
  name: onRequests[i].name || "anonymous",
156
158
  begin: performance.now()
157
- }));
159
+ });
158
160
  const result = asyncIndexes?.[i] ? await onRequests[i](context) : onRequests[i](context);
159
161
  for (let i = 0; i < traceLength; i++) endReports[i]?.();
160
162
  if (result !== void 0) {
161
- requestReports.forEach((r) => r.resolve());
163
+ for (let j = 0; j < traceLength; j++) requestReports[j].resolve();
162
164
  const response = mapResponse(result, context.set);
163
165
  afterResponse?.(context);
164
166
  return response;
@@ -138,25 +138,27 @@ function createFetchHandler(app) {
138
138
  const trace = new Array(traceLength);
139
139
  for (let i = 0; i < traceLength; i++) trace[i] = tracerFactories[i](context);
140
140
  context.trace = trace;
141
- const requestReports = trace.map((c) => c.request({
141
+ const requestReports = new Array(traceLength);
142
+ for (let i = 0; i < traceLength; i++) requestReports[i] = trace[i].request({
142
143
  id: context.rid,
143
144
  event: "request",
144
145
  name: "request",
145
146
  begin: performance.now(),
146
147
  total: onRequests.length
147
- }));
148
+ });
148
149
  try {
149
150
  for (let i = 0; i < onRequests.length; i++) {
150
- const endReports = requestReports.map((r) => r.resolveChild?.shift?.()?.({
151
+ const endReports = new Array(traceLength);
152
+ for (let j = 0; j < traceLength; j++) endReports[j] = requestReports[j].resolveChild?.shift?.()?.({
151
153
  id: context.rid,
152
154
  event: "request",
153
155
  name: onRequests[i].name || "anonymous",
154
156
  begin: performance.now()
155
- }));
157
+ });
156
158
  const result = asyncIndexes?.[i] ? await onRequests[i](context) : onRequests[i](context);
157
159
  for (let i = 0; i < traceLength; i++) endReports[i]?.();
158
160
  if (result !== void 0) {
159
- requestReports.forEach((r) => r.resolve());
161
+ for (let j = 0; j < traceLength; j++) requestReports[j].resolve();
160
162
  const response = mapResponse(result, context.set);
161
163
  afterResponse?.(context);
162
164
  return response;
@@ -60,7 +60,7 @@ function parseQueryFromURL(input, startIndex = input.indexOf("?", 11), array, ob
60
60
  }
61
61
  else finalValue = finalValue.slice(1, -1).split(",");
62
62
  if (currentValue === void 0) result[finalKey] = finalValue;
63
- else if (Array.isArray(currentValue)) currentValue.push(...finalValue);
63
+ else if (Array.isArray(currentValue)) for (let i = 0; i < finalValue.length; i++) currentValue.push(finalValue[i]);
64
64
  else {
65
65
  result[finalKey] = finalValue;
66
66
  result[finalKey].unshift(currentValue);
@@ -58,7 +58,7 @@ function parseQueryFromURL(input, startIndex = input.indexOf("?", 11), array, ob
58
58
  }
59
59
  else finalValue = finalValue.slice(1, -1).split(",");
60
60
  if (currentValue === void 0) result[finalKey] = finalValue;
61
- else if (Array.isArray(currentValue)) currentValue.push(...finalValue);
61
+ else if (Array.isArray(currentValue)) for (let i = 0; i < finalValue.length; i++) currentValue.push(finalValue[i]);
62
62
  else {
63
63
  result[finalKey] = finalValue;
64
64
  result[finalKey].unshift(currentValue);
@@ -21,17 +21,23 @@ function resolveLoader(entryPath) {
21
21
  }
22
22
  const entryFilter = (entryPath) => new RegExp("^" + entryPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "$");
23
23
  async function generateCompiledModule(file, options) {
24
+ const previousAotBuild = process.env.ELYSIA_AOT_BUILD;
24
25
  process.env.ELYSIA_AOT_BUILD = "1";
25
- const entry = resolveEntry(file);
26
- const mod = await import(entry);
27
- const app = mod.app ?? mod.default;
28
- if (!app || typeof app.compile !== "function") throw new Error(`[elysia-aot] "${entry}" must export an Elysia app`);
29
- return require_plugin_source.compileToSource(app, {
30
- register: true,
31
- registerFrom: options?.registerFrom,
32
- lazy: options?.lazy,
33
- target: options?.target
34
- });
26
+ try {
27
+ const entry = resolveEntry(file);
28
+ const mod = await import(entry);
29
+ const app = mod.app ?? mod.default;
30
+ if (!app || typeof app.compile !== "function") throw new Error(`[elysia-aot] "${entry}" must export an Elysia app`);
31
+ return await require_plugin_source.compileToSource(app, {
32
+ register: true,
33
+ registerFrom: options?.registerFrom,
34
+ lazy: options?.lazy,
35
+ target: options?.target
36
+ });
37
+ } finally {
38
+ if (previousAotBuild === void 0) delete process.env.ELYSIA_AOT_BUILD;
39
+ else process.env.ELYSIA_AOT_BUILD = previousAotBuild;
40
+ }
35
41
  }
36
42
 
37
43
  //#endregion
@@ -19,17 +19,23 @@ function resolveLoader(entryPath) {
19
19
  }
20
20
  const entryFilter = (entryPath) => new RegExp("^" + entryPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "$");
21
21
  async function generateCompiledModule(file, options) {
22
+ const previousAotBuild = process.env.ELYSIA_AOT_BUILD;
22
23
  process.env.ELYSIA_AOT_BUILD = "1";
23
- const entry = resolveEntry(file);
24
- const mod = await import(entry);
25
- const app = mod.app ?? mod.default;
26
- if (!app || typeof app.compile !== "function") throw new Error(`[elysia-aot] "${entry}" must export an Elysia app`);
27
- return compileToSource(app, {
28
- register: true,
29
- registerFrom: options?.registerFrom,
30
- lazy: options?.lazy,
31
- target: options?.target
32
- });
24
+ try {
25
+ const entry = resolveEntry(file);
26
+ const mod = await import(entry);
27
+ const app = mod.app ?? mod.default;
28
+ if (!app || typeof app.compile !== "function") throw new Error(`[elysia-aot] "${entry}" must export an Elysia app`);
29
+ return await compileToSource(app, {
30
+ register: true,
31
+ registerFrom: options?.registerFrom,
32
+ lazy: options?.lazy,
33
+ target: options?.target
34
+ });
35
+ } finally {
36
+ if (previousAotBuild === void 0) delete process.env.ELYSIA_AOT_BUILD;
37
+ else process.env.ELYSIA_AOT_BUILD = previousAotBuild;
38
+ }
33
39
  }
34
40
 
35
41
  //#endregion
@@ -7,17 +7,20 @@ const require_compile_handler_index = require('../compile/handler/index.js');
7
7
  //#region src/plugin/source.ts
8
8
  const autoGroupSize = (routes) => routes < 64 ? 1 : routes < 256 ? 2 : routes < 2048 ? 4 : routes < 8192 ? 16 : 64;
9
9
  async function compileToSource(app, options) {
10
+ const previousAotBuild = require_universal_env.env.ELYSIA_AOT_BUILD;
10
11
  require_universal_env.env.ELYSIA_AOT_BUILD = "1";
11
- if (!require_compile_aot.Capture.isCapturing()) throw new Error("[elysia-aot]: ELYSIA_AOT_BUILD=1 must be set to enable AOT capture mode");
12
- require_compile_aot.beginValidatorCapture();
13
- const modules = app.modules;
14
- if (modules) await modules;
15
- if (options?.target !== void 0) require_compile_handler_index.setCaptureHeaderShorthand(options.target === "bun");
16
12
  try {
13
+ if (!require_compile_aot.Capture.isCapturing()) throw new Error("[elysia-aot]: ELYSIA_AOT_BUILD=1 must be set to enable AOT capture mode");
14
+ require_compile_aot.beginValidatorCapture();
15
+ const modules = app.modules;
16
+ if (modules) await modules;
17
+ if (options?.target !== void 0) require_compile_handler_index.setCaptureHeaderShorthand(options.target === "bun");
17
18
  app.compile();
18
19
  return emitModule(require_compile_aot.endValidatorCapture(), require_compile_aot.endHandlerCapture(), options);
19
20
  } finally {
20
21
  require_compile_handler_index.setCaptureHeaderShorthand(void 0);
22
+ if (previousAotBuild === void 0) delete require_universal_env.env.ELYSIA_AOT_BUILD;
23
+ else require_universal_env.env.ELYSIA_AOT_BUILD = previousAotBuild;
21
24
  }
22
25
  }
23
26
  function emitModule(captured, handlers, options) {
@@ -99,6 +102,7 @@ function emitModule(captured, handlers, options) {
99
102
  }).join(", ");
100
103
  parts.push(`ic: [${ic}]`);
101
104
  }
105
+ if (c.coercePlan) parts.push(`cp: ${JSON.stringify(c.coercePlan)}`);
102
106
  return parts;
103
107
  };
104
108
  const treeToSource = (tree, slotRef, sink) => {
@@ -6,17 +6,20 @@ import { setCaptureHeaderShorthand } from "../compile/handler/index.mjs";
6
6
  //#region src/plugin/source.ts
7
7
  const autoGroupSize = (routes) => routes < 64 ? 1 : routes < 256 ? 2 : routes < 2048 ? 4 : routes < 8192 ? 16 : 64;
8
8
  async function compileToSource(app, options) {
9
+ const previousAotBuild = env.ELYSIA_AOT_BUILD;
9
10
  env.ELYSIA_AOT_BUILD = "1";
10
- if (!Capture.isCapturing()) throw new Error("[elysia-aot]: ELYSIA_AOT_BUILD=1 must be set to enable AOT capture mode");
11
- beginValidatorCapture();
12
- const modules = app.modules;
13
- if (modules) await modules;
14
- if (options?.target !== void 0) setCaptureHeaderShorthand(options.target === "bun");
15
11
  try {
12
+ if (!Capture.isCapturing()) throw new Error("[elysia-aot]: ELYSIA_AOT_BUILD=1 must be set to enable AOT capture mode");
13
+ beginValidatorCapture();
14
+ const modules = app.modules;
15
+ if (modules) await modules;
16
+ if (options?.target !== void 0) setCaptureHeaderShorthand(options.target === "bun");
16
17
  app.compile();
17
18
  return emitModule(endValidatorCapture(), endHandlerCapture(), options);
18
19
  } finally {
19
20
  setCaptureHeaderShorthand(void 0);
21
+ if (previousAotBuild === void 0) delete env.ELYSIA_AOT_BUILD;
22
+ else env.ELYSIA_AOT_BUILD = previousAotBuild;
20
23
  }
21
24
  }
22
25
  function emitModule(captured, handlers, options) {
@@ -98,6 +101,7 @@ function emitModule(captured, handlers, options) {
98
101
  }).join(", ");
99
102
  parts.push(`ic: [${ic}]`);
100
103
  }
104
+ if (c.coercePlan) parts.push(`cp: ${JSON.stringify(c.coercePlan)}`);
101
105
  return parts;
102
106
  };
103
107
  const treeToSource = (tree, slotRef, sink) => {
package/dist/sucrose.js CHANGED
@@ -14,7 +14,7 @@ const require_utils = require('./utils.js');
14
14
  function separateFunction(code) {
15
15
  if (code.startsWith("async")) code = code.slice(5);
16
16
  code = code.trimStart();
17
- let index = -1;
17
+ let index;
18
18
  if (code.charCodeAt(0) === 40) {
19
19
  index = code.indexOf("=>", code.indexOf(")"));
20
20
  if (index !== -1) {
@@ -167,10 +167,19 @@ function findParameterReference(parameter, inference) {
167
167
  return Object.keys(parameters).join(", ");
168
168
  }
169
169
  function findEndIndex(type, content, index) {
170
- const regex = new RegExp(`${type.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\n\\t,; ]`);
171
- if (index !== void 0) regex.lastIndex = index;
172
- const match = regex.exec(content);
173
- return match ? match.index : -1;
170
+ let search = index ?? 0;
171
+ while (true) {
172
+ const found = content.indexOf(type, search);
173
+ if (found === -1) return -1;
174
+ switch (content.charCodeAt(found + type.length)) {
175
+ case 10:
176
+ case 9:
177
+ case 44:
178
+ case 59:
179
+ case 32: return found;
180
+ }
181
+ search = found + 1;
182
+ }
174
183
  }
175
184
  /**
176
185
  * Find alias of variable from function body
@@ -246,7 +255,7 @@ function extractMainParameter(parameter) {
246
255
  * Analyze if context is mentioned in body
247
256
  */
248
257
  function inferBodyReference(code, aliases, inference) {
249
- const access = (type, alias) => new RegExp(`${alias}\\??\\.(${type})|${alias}(?:\\?\\.)?\\["${type}"\\]|${alias}(?:\\?\\.)?\\['${type}'\\]`).test(code);
258
+ const access = (type, alias) => code.includes(`${alias}.${type}`) || code.includes(`${alias}?.${type}`) || code.includes(`${alias}["${type}"]`) || code.includes(`${alias}?.["${type}"]`) || code.includes(`${alias}['${type}']`) || code.includes(`${alias}?.['${type}']`);
250
259
  for (const alias of aliases) {
251
260
  if (!alias) continue;
252
261
  if (alias.charCodeAt(0) === 123) {
@@ -357,6 +366,11 @@ function clearSucroseCache(delay) {
357
366
  clearCache();
358
367
  }
359
368
  }
369
+ function scheduleSucroseCacheClear() {
370
+ if (pendingGC || require_universal_constants.isCloudflareWorker) return;
371
+ pendingGC = setTimeout(clearCache, 60 * 1e3);
372
+ pendingGC.unref?.();
373
+ }
360
374
  function mergeInference(a, b) {
361
375
  return {
362
376
  body: a.body || b.body,
@@ -425,9 +439,9 @@ function sucrose(handler, lifeCycle) {
425
439
  inference ??= defaultSucrose();
426
440
  if (needGc) {
427
441
  needGc = false;
428
- clearSucroseCache();
442
+ scheduleSucroseCacheClear();
429
443
  }
430
- let fnInference = defaultSucrose();
444
+ const fnInference = defaultSucrose();
431
445
  const [parameter, body] = separateFunction(content);
432
446
  const mainParameter = extractMainParameter(findParameterReference(parameter, fnInference));
433
447
  if (mainParameter) {
@@ -448,8 +462,7 @@ function sucrose(handler, lifeCycle) {
448
462
  }
449
463
  if (typeof event === "function") functionCaches.set(event, fnInference);
450
464
  inference = mergeInference(inference, fnInference);
451
- fnInference = void 0;
452
- if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.url && inference.route && inference.path) break;
465
+ if (inference && inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.url && inference.route && inference.path) break;
453
466
  }
454
467
  events.length = 0;
455
468
  return inference ?? defaultSucrose();