elysia 2.0.0-beta.11 → 2.0.0-beta.13

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 (99) hide show
  1. package/dist/adapter/bun/index.js +36 -21
  2. package/dist/adapter/bun/index.mjs +36 -21
  3. package/dist/adapter/utils.js +1 -0
  4. package/dist/adapter/utils.mjs +1 -0
  5. package/dist/adapter/web-standard/handler.js +8 -2
  6. package/dist/adapter/web-standard/handler.mjs +8 -2
  7. package/dist/base.d.ts +5 -0
  8. package/dist/base.js +109 -4
  9. package/dist/base.mjs +111 -6
  10. package/dist/compile/aot-capture.d.ts +2 -13
  11. package/dist/compile/aot-capture.js +5 -27
  12. package/dist/compile/aot-capture.mjs +6 -24
  13. package/dist/compile/aot-emit.js +1 -1
  14. package/dist/compile/aot-emit.mjs +1 -1
  15. package/dist/compile/aot.d.ts +1 -1
  16. package/dist/compile/aot.js +2 -2
  17. package/dist/compile/aot.mjs +2 -2
  18. package/dist/compile/handler/descriptor.d.ts +4 -8
  19. package/dist/compile/handler/descriptor.js +8 -21
  20. package/dist/compile/handler/descriptor.mjs +9 -21
  21. package/dist/compile/handler/index.d.ts +4 -3
  22. package/dist/compile/handler/index.js +16 -6
  23. package/dist/compile/handler/index.mjs +16 -7
  24. package/dist/compile/handler/jit.js +82 -76
  25. package/dist/compile/handler/jit.mjs +83 -77
  26. package/dist/compile/handler/params.d.ts +1 -4
  27. package/dist/compile/handler/params.js +3 -4
  28. package/dist/compile/handler/params.mjs +5 -5
  29. package/dist/compile/handler/reconstruct.d.ts +1 -1
  30. package/dist/compile/handler/static-clone-resolver.d.ts +6 -0
  31. package/dist/compile/handler/static-clone-resolver.js +8 -0
  32. package/dist/compile/handler/static-clone-resolver.mjs +7 -0
  33. package/dist/compile/handler/utils.d.ts +7 -7
  34. package/dist/compile/handler/utils.js +24 -20
  35. package/dist/compile/handler/utils.mjs +24 -20
  36. package/dist/compile/utils.js +7 -4
  37. package/dist/compile/utils.mjs +7 -4
  38. package/dist/context.js +3 -21
  39. package/dist/context.mjs +4 -22
  40. package/dist/cookie/index.d.ts +1 -2
  41. package/dist/cookie/index.js +0 -2
  42. package/dist/cookie/index.mjs +1 -2
  43. package/dist/cookie/lib.js +2 -1
  44. package/dist/cookie/lib.mjs +2 -1
  45. package/dist/cookie/utils.d.ts +3 -7
  46. package/dist/cookie/utils.js +9 -28
  47. package/dist/cookie/utils.mjs +11 -29
  48. package/dist/error.d.ts +40 -83
  49. package/dist/error.js +18 -19
  50. package/dist/error.mjs +18 -20
  51. package/dist/handler/error.js +4 -5
  52. package/dist/handler/error.mjs +4 -5
  53. package/dist/handler/fetch.js +31 -17
  54. package/dist/handler/fetch.mjs +32 -18
  55. package/dist/handler/utils.d.ts +3 -3
  56. package/dist/handler/utils.js +28 -17
  57. package/dist/handler/utils.mjs +28 -17
  58. package/dist/index.d.ts +3 -3
  59. package/dist/package.js +1 -1
  60. package/dist/package.mjs +1 -1
  61. package/dist/plugin/aot/core.d.ts +3 -7
  62. package/dist/plugin/aot/core.js +8 -18
  63. package/dist/plugin/aot/core.mjs +9 -17
  64. package/dist/plugin/aot/hooks.js +5 -1
  65. package/dist/plugin/aot/hooks.mjs +5 -1
  66. package/dist/trace.js +23 -10
  67. package/dist/trace.mjs +23 -10
  68. package/dist/type/bridge-live.d.ts +3 -2
  69. package/dist/type/bridge-live.js +4 -2
  70. package/dist/type/bridge-live.mjs +3 -2
  71. package/dist/type/bridge.d.ts +6 -4
  72. package/dist/type/bridge.js +9 -1
  73. package/dist/type/bridge.mjs +3 -1
  74. package/dist/type/coerce-plan.d.ts +2 -2
  75. package/dist/type/coerce-plan.js +0 -1
  76. package/dist/type/coerce-plan.mjs +2 -2
  77. package/dist/type/compat.js +2 -1
  78. package/dist/type/compat.mjs +3 -2
  79. package/dist/type/constants.d.ts +1 -1
  80. package/dist/type/shared.d.ts +1 -3
  81. package/dist/type/shared.js +0 -3
  82. package/dist/type/shared.mjs +1 -3
  83. package/dist/type/typebox-value-live.d.ts +4 -3
  84. package/dist/type/typebox-value-live.js +5 -3
  85. package/dist/type/typebox-value-live.mjs +4 -3
  86. package/dist/type/typebox-value.d.ts +11 -7
  87. package/dist/type/typebox-value.js +2 -1
  88. package/dist/type/typebox-value.mjs +1 -1
  89. package/dist/type/validator/index.d.ts +1 -1
  90. package/dist/type/validator/validator-cache.d.ts +1 -1
  91. package/dist/types.d.ts +10 -17
  92. package/dist/universal/file.d.ts +1 -3
  93. package/dist/universal/file.js +0 -2
  94. package/dist/universal/file.mjs +1 -2
  95. package/dist/universal/is-production.d.ts +1 -2
  96. package/dist/universal/is-production.js +1 -3
  97. package/dist/universal/is-production.mjs +2 -3
  98. package/dist/utils.d.ts +0 -1
  99. package/package.json +13 -6
package/dist/base.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import { isBun } from "./universal/constants.mjs";
2
2
  import { clonePlainDecorators, clonePlainDeep, coalesceSchemas, createErrorEventHandler, eventProperties, fnOrigin, fnv1a, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isEmpty, isNotEmpty, isRecordNumber, joinPath, macroOrigin, mapDeriveEntry, mergeDeep, mergeResponse, nullObject, pushField, schemaProperties, serializeMacroSeed, throwLifecycleErrors } from "./utils.mjs";
3
- import { Ref } from "./type/bridge.mjs";
3
+ import { Ref, warmTypebox } from "./type/bridge.mjs";
4
4
  import { isProduction } from "./universal/is-production.mjs";
5
5
  import { Capture, Compiled, beginCompilerSession, createAotFingerprint, endCompilerSession } from "./compile/aot.mjs";
6
6
  import { traceCapabilityRequired, wsCapabilityRequired } from "./generation.mjs";
7
- import { compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook } from "./compile/handler/index.mjs";
7
+ import { chainResolver, compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook } from "./compile/handler/index.mjs";
8
8
  import { RouteFlag, buildRouteTable, routeRow } from "./route-table.mjs";
9
9
  import { BunAdapter } from "./adapter/bun/index.mjs";
10
10
  import { clearContextCache } from "./context.mjs";
@@ -42,6 +42,42 @@ const mergeExtCallbacks = (target, incoming) => {
42
42
  index.indexedLength = target.length;
43
43
  };
44
44
  const canRegisterLoose = (path, isDynamic) => !isDynamic && (path.length === 0 || path.charCodeAt(path.length - 1) === 47);
45
+ const isSchemaValue = (value) => {
46
+ if (value == null || typeof value === "string") return true;
47
+ if (typeof value !== "object" && typeof value !== "function") return false;
48
+ return "~kind" in value || "~standard" in value || "~elyAcl" in value || typeof value.Check === "function";
49
+ };
50
+ const hookKeys = new Set([
51
+ ...schemaProperties,
52
+ ...eventProperties,
53
+ "detail",
54
+ "tags"
55
+ ]);
56
+ const hasHookKeys = (value) => {
57
+ for (const key in value) if (hookKeys.has(key)) return true;
58
+ return false;
59
+ };
60
+ const isPlainObject = (value) => {
61
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
62
+ const proto = Object.getPrototypeOf(value);
63
+ return proto === Object.prototype || proto === null;
64
+ };
65
+ const assertSchemaShape = (hook, where) => {
66
+ for (const key in hook) {
67
+ if (!schemaProperties.has(key)) continue;
68
+ const value = hook[key];
69
+ if (isSchemaValue(value)) continue;
70
+ if (key === "response" && isPlainObject(value)) {
71
+ let isStatusMap = true;
72
+ for (const status in value) if (status !== "default" && isNaN(+status) || !isSchemaValue(value[status])) {
73
+ isStatusMap = false;
74
+ break;
75
+ }
76
+ if (isStatusMap) continue;
77
+ }
78
+ throw new Error(`[Elysia] ${where}: "${key}" is not a schema — use t.Object({ ... })`);
79
+ }
80
+ };
45
81
  /**
46
82
  * Every key a single route must answer to, in registration order.
47
83
  *
@@ -170,6 +206,11 @@ var Elysia = class Elysia {
170
206
  if (adapter?.setup) this.#useFn(adapter.setup);
171
207
  } else this["~Prefix"] = void 0;
172
208
  }
209
+ /**
210
+ * Every registered route with its merged hooks.
211
+ * Development shares a frozen cache. Production rebuilds the list so its
212
+ * metadata can be released after startup.
213
+ */
173
214
  get routes() {
174
215
  const generation = this["~generation"];
175
216
  if (this.#isCacheable && this.cachedGeneration === generation && this.cachedEpoch === mutationEpoch && this.cachedRoutes !== void 0) return this.cachedRoutes;
@@ -189,7 +230,8 @@ var Elysia = class Elysia {
189
230
  hooks: merged
190
231
  };
191
232
  });
192
- if (this.#isCacheable) {
233
+ if (this.#isCacheable && !isProduction()) {
234
+ Object.freeze(routes);
193
235
  this.#cacheRoutes(generation);
194
236
  this.cachedRoutes = routes;
195
237
  }
@@ -425,6 +467,7 @@ var Elysia = class Elysia {
425
467
  return this;
426
468
  }
427
469
  #guard(scope, hook) {
470
+ if (hook) assertSchemaShape(hook, ".guard()");
428
471
  hook = snapshotHookSchemas(hook);
429
472
  hookToGuard(hook);
430
473
  const trackFn = (fn) => {
@@ -537,13 +580,17 @@ var Elysia = class Elysia {
537
580
  };
538
581
  return this;
539
582
  }
540
- macro(macro) {
583
+ macro(macro, definition) {
541
584
  this.#assertMutable("macro");
542
585
  if (typeof macro === "function") throw new Error("use `.macro({ name: fn })` instead of `.macro(fn)`");
586
+ if (definition != null || typeof macro === "string") throw new Error("[Elysia] .macro(name, definition) was removed in 2.0 — use .macro({ [name]: definition })");
543
587
  const m = this.#ensureMacroTable();
544
588
  const baseline = this.macroBaseline;
545
589
  for (const key in macro) {
546
- if (typeof macro[key] === "object") macro[key] = hookToGuard(macro[key]);
590
+ if (typeof macro[key] === "object") {
591
+ if (macro[key]) assertSchemaShape(macro[key], `.macro(${key})`);
592
+ macro[key] = hookToGuard(macro[key]);
593
+ }
547
594
  if (this.hash !== void 0 && !macroOrigin.has(macro[key])) macroOrigin.set(macro[key], this.hash);
548
595
  if (baseline?.has(key) && key in m && m[key] !== macro[key]) throw new Error(`[Elysia] Macro "${key}" can be only define once`);
549
596
  }
@@ -1044,6 +1091,8 @@ var Elysia = class Elysia {
1044
1091
  #add(method, path, hookOrFn, fn, hasHook = fn !== void 0) {
1045
1092
  if (this["~Prefix"]) path = joinPath(this["~Prefix"], path);
1046
1093
  else if (path && path.charCodeAt(0) !== 47) path = "/" + path;
1094
+ if (typeof hookOrFn === "function" && !hasHookKeys(hookOrFn) && isPlainObject(fn) && hasHookKeys(fn)) throw new Error(`[Elysia] .${method === "*" ? "all" : method.toLowerCase()}('${path}', handler, hook) is the 1.x order; Elysia 2 takes (path, hook, handler) — see the 2.0 migration guide`);
1095
+ if (hasHook && hookOrFn) assertSchemaShape(hookOrFn, `${method} ${path}`);
1047
1096
  const handler = hasHook ? fn : hookOrFn;
1048
1097
  const hook = hasHook ? snapshotHookSchemas(hookOrFn) : void 0;
1049
1098
  const appHook = this["~hookChain"];
@@ -1395,6 +1444,56 @@ var Elysia = class Elysia {
1395
1444
  }
1396
1445
  return false;
1397
1446
  }
1447
+ static #slotHasTypeBox(value, models, record) {
1448
+ if (typeof value === "string") value = models?.[value];
1449
+ if (!value || typeof value !== "object") return false;
1450
+ if ("~kind" in value || "~elyAcl" in value) return true;
1451
+ if (!record || "~standard" in value) return false;
1452
+ for (const status in value) if (Elysia.#slotHasTypeBox(value[status], models)) return true;
1453
+ return false;
1454
+ }
1455
+ static #hookHasTypeBox(h, models) {
1456
+ if (!h || typeof h !== "object") return false;
1457
+ for (const key in h) {
1458
+ if (key === "schemas") {
1459
+ const schemas = h[key];
1460
+ if (Array.isArray(schemas)) {
1461
+ for (let s = 0; s < schemas.length; s++) if (Elysia.#hookHasTypeBox(schemas[s], models)) return true;
1462
+ }
1463
+ continue;
1464
+ }
1465
+ if (schemaProperties.has(key) && Elysia.#slotHasTypeBox(h[key], models, key === "response")) return true;
1466
+ }
1467
+ return false;
1468
+ }
1469
+ static #chainHasTypeBox(node, models, seen, resolve) {
1470
+ while (node) {
1471
+ if (seen.has(node)) return false;
1472
+ seen.add(node);
1473
+ if ("added" in node) {
1474
+ if (Elysia.#hookHasTypeBox(resolve ? resolve(node) : node.added, models)) return true;
1475
+ node = node.parent;
1476
+ } else {
1477
+ if (Elysia.#chainHasTypeBox(node.combine, models, seen, resolve)) return true;
1478
+ node = node.over;
1479
+ }
1480
+ }
1481
+ return false;
1482
+ }
1483
+ /**
1484
+ * Scan each route and its inherited hooks for TypeBox schemas.
1485
+ * This may warm TypeBox after a closer schema overrides it, avoiding a full
1486
+ * hook merge during build.
1487
+ */
1488
+ #hasTypeBoxSchema(table) {
1489
+ const models = this["~ext"]?.models;
1490
+ const resolve = chainResolver(this);
1491
+ const rootChain = this["~hookChain"];
1492
+ const seen = /* @__PURE__ */ new Set();
1493
+ const { localHook, appHook, inheritedChain, owner } = table;
1494
+ for (let i = 0; i < table.length; i++) if (Elysia.#hookHasTypeBox(localHook[i], models) || Elysia.#chainHasTypeBox(appHook[i], models, seen, resolve) || Elysia.#chainHasTypeBox(inheritedChain[i], models, seen, resolve) || owner[i] !== this && Elysia.#chainHasTypeBox(rootChain, models, seen, resolve)) return true;
1495
+ return false;
1496
+ }
1398
1497
  #routeMayHaveModelRef(table, i) {
1399
1498
  const macroScope = table.macroScope?.get(i);
1400
1499
  const owner = table.owner[i];
@@ -1548,6 +1647,9 @@ var Elysia = class Elysia {
1548
1647
  const appChain = this["~hookChain"];
1549
1648
  if (this["~ext"]?.macro || this["~scopeChildren"] || appChain !== void 0 && appChain.refs) for (let i = 0; i < length; i++) this.#assertRouteModelRefs(routeRow(table, i), method[i]);
1550
1649
  else for (let i = 0; i < length; i++) if (this.#routeMayHaveModelRef(table, i)) this.#assertRouteModelRefs(routeRow(table, i), method[i]);
1650
+ if (length && this.#hasTypeBoxSchema(table)) try {
1651
+ warmTypebox();
1652
+ } catch {}
1551
1653
  let markDuplicates = false;
1552
1654
  if (length) {
1553
1655
  const programId = this["~programId"];
@@ -1637,7 +1739,10 @@ var Elysia = class Elysia {
1637
1739
  }
1638
1740
  listen(options, callback) {
1639
1741
  const listen = (this["~config"]?.adapter ?? (isBun ? BunAdapter : void 0))?.listen;
1640
- if (!listen) throw new Error("No adapter provided for listen()");
1742
+ if (!listen) {
1743
+ const deno = typeof Deno !== "undefined";
1744
+ throw new Error(`[Elysia] listen() requires an adapter on ${deno ? "Deno" : typeof process === "undefined" ? "this runtime" : "Node.js"} — https://elysiajs.com/integrations/${deno ? "deno" : "node"}`);
1745
+ }
1641
1746
  if (!Capture.isAotBuildEnv()) listen(this, options, callback);
1642
1747
  return this;
1643
1748
  }
@@ -1,24 +1,13 @@
1
- import { CaptureImpl, CapturedHandler, CapturedValidator, CompiledSnapshot } from "./aot.js";
1
+ import { CapturedHandler, CapturedValidator, CompiledSnapshot } from "./aot.js";
2
2
 
3
3
  //#region src/compile/aot-capture.d.ts
4
- declare function resetCompactErrorWarnings(): void;
5
4
  declare function beginValidatorCapture(): void;
6
5
  declare function abortCapture(): void;
7
6
  declare function endValidatorCapture(): CapturedValidator[];
8
7
  declare function endHandlerCapture(): CapturedHandler[];
9
- /** @internal deterministic session/capture assertions. */
10
- declare const getCompilerSessionDiagnostics: () => {
11
- active: boolean;
12
- appAttached: boolean;
13
- validators: number;
14
- handlers: number;
15
- sucrose: number;
16
- };
17
8
  /** @internal preserve registry around in-process AOT analysis */
18
9
  declare const snapshotCompiled: () => CompiledSnapshot;
19
10
  /** @internal restore registry after in-process AOT analysis */
20
11
  declare function restoreCompiled(snapshot: CompiledSnapshot): void;
21
- declare const impl: CaptureImpl;
22
- declare function installCaptureImpl(): void;
23
12
  //#endregion
24
- export { abortCapture, beginValidatorCapture, impl as captureImplementation, endHandlerCapture, endValidatorCapture, getCompilerSessionDiagnostics, installCaptureImpl, resetCompactErrorWarnings, restoreCompiled, snapshotCompiled };
13
+ export { abortCapture, beginValidatorCapture, endHandlerCapture, endValidatorCapture, restoreCompiled, snapshotCompiled };
@@ -13,8 +13,8 @@ const require_type_validator_frozen_check = require('../type/validator/frozen-ch
13
13
  const require_type_validator_custom_error = require('../type/validator/custom-error.js');
14
14
  const require_type_validator_exact_mirror = require('../type/validator/exact-mirror.js');
15
15
  const require_type_validator_string_codec_aot = require('../type/validator/string-codec-aot.js');
16
- let typebox_schema = require("typebox/schema");
17
16
  let typebox_value = require("typebox/value");
17
+ let typebox_schema = require("typebox/schema");
18
18
 
19
19
  //#region src/compile/aot-capture.ts
20
20
  function emptyContainers(node, depth) {
@@ -254,9 +254,6 @@ function captureCodecMirror(schema, aot, slot, sanitize, dir) {
254
254
  }
255
255
  const compactErrorWarned = /* @__PURE__ */ new Set();
256
256
  const isVerboseAotWarnings = () => !!require_universal_env.env.ELYSIA_AOT_VERBOSE;
257
- function resetCompactErrorWarnings() {
258
- compactErrorWarned.clear();
259
- }
260
257
  function warnCompactErrorLoss(aot, slot) {
261
258
  const key = `${aot.method}\0${aot.path}\0${slot}`;
262
259
  if (compactErrorWarned.has(key)) return;
@@ -266,7 +263,7 @@ function warnCompactErrorLoss(aot, slot) {
266
263
  function flushCompactErrorWarnings() {
267
264
  const total = compactErrorWarned.size;
268
265
  if (total > 0 && !isVerboseAotWarnings()) console.warn(`[elysia-aot]: ${total} sealed validator slot${total === 1 ? "" : "s"} ${total === 1 ? "carries" : "carry"} a coercion/codec schema; 422 error details will be coarse (best-effort). Set ELYSIA_AOT_VERBOSE=1 for per-route detail.`);
269
- resetCompactErrorWarnings();
266
+ compactErrorWarned.clear();
270
267
  }
271
268
  function captureBridgeFree(aot, slot, rawSchema) {
272
269
  const captured = require_compile_aot.Capture.get({
@@ -333,44 +330,25 @@ function endHandlerCapture() {
333
330
  }
334
331
  return captured;
335
332
  }
336
- /** @internal deterministic session/capture assertions. */
337
- const getCompilerSessionDiagnostics = () => {
338
- const session = require_compile_aot.CompilerState.session;
339
- return {
340
- active: session !== void 0,
341
- appAttached: session?.app !== void 0,
342
- validators: session?.capture?.size ?? 0,
343
- handlers: session?.handlerCapture?.size ?? 0,
344
- sucrose: session?.sucroseCache.size ?? 0
345
- };
346
- };
347
333
  /** @internal preserve registry around in-process AOT analysis */
348
334
  const snapshotCompiled = () => require_compile_aot.CompilerState.registry;
349
335
  /** @internal restore registry after in-process AOT analysis */
350
336
  function restoreCompiled(snapshot) {
351
337
  require_compile_aot.CompilerState.registry = snapshot;
352
338
  }
353
- const impl = {
339
+ require_compile_aot.setCaptureImpl({
354
340
  sourceOnlyValidator,
355
341
  maybeCapture,
356
342
  captureMirror,
357
343
  captureCodecMirror,
358
344
  captureBridgeFree
359
- };
360
- function installCaptureImpl() {
361
- require_compile_aot.setCaptureImpl(impl);
362
- require_compile_aot_emit.installReconstructImpl();
363
- }
364
- installCaptureImpl();
345
+ });
346
+ require_compile_aot_emit.installReconstructImpl();
365
347
 
366
348
  //#endregion
367
349
  exports.abortCapture = abortCapture;
368
350
  exports.beginValidatorCapture = beginValidatorCapture;
369
- exports.captureImplementation = impl;
370
351
  exports.endHandlerCapture = endHandlerCapture;
371
352
  exports.endValidatorCapture = endValidatorCapture;
372
- exports.getCompilerSessionDiagnostics = getCompilerSessionDiagnostics;
373
- exports.installCaptureImpl = installCaptureImpl;
374
- exports.resetCompactErrorWarnings = resetCompactErrorWarnings;
375
353
  exports.restoreCompiled = restoreCompiled;
376
354
  exports.snapshotCompiled = snapshotCompiled;
@@ -11,8 +11,8 @@ import { buildFrozenCheck } from "../type/validator/frozen-check.mjs";
11
11
  import { captureCustomErrors } from "../type/validator/custom-error.mjs";
12
12
  import { getExactMirror } from "../type/validator/exact-mirror.mjs";
13
13
  import { captureStringCodecEntries } from "../type/validator/string-codec-aot.mjs";
14
- import { Build, Compile } from "typebox/schema";
15
14
  import { Default } from "typebox/value";
15
+ import { Build, Compile } from "typebox/schema";
16
16
 
17
17
  //#region src/compile/aot-capture.ts
18
18
  function emptyContainers(node, depth) {
@@ -252,9 +252,6 @@ function captureCodecMirror(schema, aot, slot, sanitize, dir) {
252
252
  }
253
253
  const compactErrorWarned = /* @__PURE__ */ new Set();
254
254
  const isVerboseAotWarnings = () => !!env.ELYSIA_AOT_VERBOSE;
255
- function resetCompactErrorWarnings() {
256
- compactErrorWarned.clear();
257
- }
258
255
  function warnCompactErrorLoss(aot, slot) {
259
256
  const key = `${aot.method}\0${aot.path}\0${slot}`;
260
257
  if (compactErrorWarned.has(key)) return;
@@ -264,7 +261,7 @@ function warnCompactErrorLoss(aot, slot) {
264
261
  function flushCompactErrorWarnings() {
265
262
  const total = compactErrorWarned.size;
266
263
  if (total > 0 && !isVerboseAotWarnings()) console.warn(`[elysia-aot]: ${total} sealed validator slot${total === 1 ? "" : "s"} ${total === 1 ? "carries" : "carry"} a coercion/codec schema; 422 error details will be coarse (best-effort). Set ELYSIA_AOT_VERBOSE=1 for per-route detail.`);
267
- resetCompactErrorWarnings();
264
+ compactErrorWarned.clear();
268
265
  }
269
266
  function captureBridgeFree(aot, slot, rawSchema) {
270
267
  const captured = Capture.get({
@@ -331,35 +328,20 @@ function endHandlerCapture() {
331
328
  }
332
329
  return captured;
333
330
  }
334
- /** @internal deterministic session/capture assertions. */
335
- const getCompilerSessionDiagnostics = () => {
336
- const session = CompilerState.session;
337
- return {
338
- active: session !== void 0,
339
- appAttached: session?.app !== void 0,
340
- validators: session?.capture?.size ?? 0,
341
- handlers: session?.handlerCapture?.size ?? 0,
342
- sucrose: session?.sucroseCache.size ?? 0
343
- };
344
- };
345
331
  /** @internal preserve registry around in-process AOT analysis */
346
332
  const snapshotCompiled = () => CompilerState.registry;
347
333
  /** @internal restore registry after in-process AOT analysis */
348
334
  function restoreCompiled(snapshot) {
349
335
  CompilerState.registry = snapshot;
350
336
  }
351
- const impl = {
337
+ setCaptureImpl({
352
338
  sourceOnlyValidator,
353
339
  maybeCapture,
354
340
  captureMirror,
355
341
  captureCodecMirror,
356
342
  captureBridgeFree
357
- };
358
- function installCaptureImpl() {
359
- setCaptureImpl(impl);
360
- installReconstructImpl();
361
- }
362
- installCaptureImpl();
343
+ });
344
+ installReconstructImpl();
363
345
 
364
346
  //#endregion
365
- export { abortCapture, beginValidatorCapture, impl as captureImplementation, endHandlerCapture, endValidatorCapture, getCompilerSessionDiagnostics, installCaptureImpl, resetCompactErrorWarnings, restoreCompiled, snapshotCompiled };
347
+ export { abortCapture, beginValidatorCapture, endHandlerCapture, endValidatorCapture, restoreCompiled, snapshotCompiled };
@@ -28,7 +28,7 @@ function reconstructCheckCode(build) {
28
28
  const { defs, value } = reconstructCheck(build);
29
29
  return checkCode(defs, value);
30
30
  }
31
- const checkFactorySource = (identifier, code) => `function(${identifier}){${code}}`;
31
+ const checkFactorySource = (identifier, code) => `(${identifier})=>{${code}}`;
32
32
  const handlerFactorySource = (alias, code) => `function(h${alias ? "," + alias : ""}){return ${code}}`;
33
33
  function externalsMatch(a, b) {
34
34
  if (a.length !== b.length) return false;
@@ -27,7 +27,7 @@ function reconstructCheckCode(build) {
27
27
  const { defs, value } = reconstructCheck(build);
28
28
  return checkCode(defs, value);
29
29
  }
30
- const checkFactorySource = (identifier, code) => `function(${identifier}){${code}}`;
30
+ const checkFactorySource = (identifier, code) => `(${identifier})=>{${code}}`;
31
31
  const handlerFactorySource = (alias, code) => `function(h${alias ? "," + alias : ""}){return ${code}}`;
32
32
  function externalsMatch(a, b) {
33
33
  if (a.length !== b.length) return false;
@@ -1,6 +1,6 @@
1
1
  import { CoerceNode } from "../type/coerce-plan.js";
2
2
  //#region src/compile/aot.d.ts
3
- declare const AOT_MANIFEST_FORMAT = 3;
3
+ declare const AOT_MANIFEST_FORMAT = 4;
4
4
  declare const AOT_ABI: string;
5
5
  interface AotFingerprint {
6
6
  abi: string;
@@ -4,8 +4,8 @@ const require_universal_env = require('../universal/env.js');
4
4
  const require_package = require('../package.js');
5
5
 
6
6
  //#region src/compile/aot.ts
7
- const AOT_MANIFEST_FORMAT = 3;
8
- const AOT_ABI = `${require_package.version}:${3}`;
7
+ const AOT_MANIFEST_FORMAT = 4;
8
+ const AOT_ABI = `${require_package.version}:${4}`;
9
9
  const sharedAotFingerprint = Object.freeze({ abi: AOT_ABI });
10
10
  const createAotFingerprint = () => sharedAotFingerprint;
11
11
  let activeSession;
@@ -3,8 +3,8 @@ import { env } from "../universal/env.mjs";
3
3
  import { version } from "../package.mjs";
4
4
 
5
5
  //#region src/compile/aot.ts
6
- const AOT_MANIFEST_FORMAT = 3;
7
- const AOT_ABI = `${version}:${3}`;
6
+ const AOT_MANIFEST_FORMAT = 4;
7
+ const AOT_ABI = `${version}:${4}`;
8
8
  const sharedAotFingerprint = Object.freeze({ abi: AOT_ABI });
9
9
  const createAotFingerprint = () => sharedAotFingerprint;
10
10
  let activeSession;
@@ -1,11 +1,11 @@
1
1
  import { TraceEvent } from "../../trace.js";
2
2
  import { CompactBeforeHandlePrefix } from "../../utils.js";
3
3
  import { AnyLocalHook, MaybeArray } from "../../types.js";
4
- import { CompiledCookieConfig } from "../../cookie/config.js";
5
4
  import { AnyElysia } from "../../base.js";
6
5
  import { ElysiaAdapter } from "../../adapter/index.js";
7
6
  import { Sucrose } from "../../sucrose.js";
8
7
  import { RouteValidator } from "../../validator/route.js";
8
+ import { CompiledCookieConfig } from "../../cookie/config.js";
9
9
 
10
10
  //#region src/compile/handler/descriptor.d.ts
11
11
  interface RouteDescriptor {
@@ -65,13 +65,9 @@ interface DescribeRouteInput {
65
65
  * Populated on each JIT compile, and read only by tests and introspection
66
66
  */
67
67
  declare const routeDescriptors: WeakMap<AnyElysia, Map<string, RouteDescriptor>>;
68
- declare function mayReturnIdentifier(fn: Function): boolean;
69
- declare const lifecycleMayReturnPromise: (handlers: MaybeArray<Function> | undefined, observed: boolean) => boolean;
70
- /**
71
- * Extracted from `buildNativeStaticResponse`'s for-in check so the native
72
- * static promotion predicate
73
- */
68
+ declare const lifecycleMayReturnPromise: (handlers: MaybeArray<Function> | undefined) => boolean;
69
+ /** Whether a hook can be skipped by a native static response. */
74
70
  declare function isEmptyPipelineHook(hook: AnyLocalHook | undefined): boolean;
75
71
  declare function describeRoute(input: DescribeRouteInput): RouteCompileState;
76
72
  //#endregion
77
- export { DescribeRouteInput, RouteCompileState, RouteDescriptor, describeRoute, isEmptyPipelineHook, lifecycleMayReturnPromise, mayReturnIdentifier, routeDescriptors };
73
+ export { DescribeRouteInput, RouteCompileState, RouteDescriptor, describeRoute, isEmptyPipelineHook, lifecycleMayReturnPromise, routeDescriptors };
@@ -15,16 +15,7 @@ const require_sucrose = require('../../sucrose.js');
15
15
  */
16
16
  const routeDescriptors = /* @__PURE__ */ new WeakMap();
17
17
  const noTracePhases = /* @__PURE__ */ new Set();
18
- const matchReturnIdentifier = /(?:=>\s*|\breturn\s+)(?!(?:true|false|null|undefined|void|new|typeof|async|await|function|class)\b)[A-Za-z_$][\w$]*(?:\s*\.\s*[A-Za-z_$][\w$]*)*\s*(?![\w$([])/;
19
- const mayReturnIdentifierCache = /* @__PURE__ */ new WeakMap();
20
- function mayReturnIdentifier(fn) {
21
- let result = mayReturnIdentifierCache.get(fn);
22
- if (result !== void 0) return result;
23
- result = matchReturnIdentifier.test(fn.toString());
24
- mayReturnIdentifierCache.set(fn, result);
25
- return result;
26
- }
27
- const lifecycleMayReturnPromise = (handlers, observed) => handlers ? Array.isArray(handlers) ? handlers.some((fn) => !require_compile_utils.isAsyncFunction(fn) && (require_compile_utils.mayReturnPromise(fn) || observed && mayReturnIdentifier(fn))) : !require_compile_utils.isAsyncFunction(handlers) && (require_compile_utils.mayReturnPromise(handlers) || observed && mayReturnIdentifier(handlers)) : false;
18
+ const lifecycleMayReturnPromise = (handlers) => handlers ? Array.isArray(handlers) ? handlers.some(require_compile_utils.mayReturnPromise) : require_compile_utils.mayReturnPromise(handlers) : false;
28
19
  const compactPrefixInference = /* @__PURE__ */ new WeakMap();
29
20
  const compactPrefixAsync = /* @__PURE__ */ new WeakMap();
30
21
  const inferCompactPrefix = (prefix) => {
@@ -66,7 +57,7 @@ function compactPrefixForcesAsync(prefix) {
66
57
  const item = pending[i];
67
58
  for (let j = 0; !value && j < item.added.length; j++) {
68
59
  const fn = item.added[j];
69
- value = require_compile_utils.isAsyncFunction(fn) || !require_compile_utils.isAsyncFunction(fn) && (require_compile_utils.mayReturnPromise(fn) || mayReturnIdentifier(fn));
60
+ value = require_compile_utils.mayReturnPromise(fn);
70
61
  }
71
62
  compactPrefixAsync.set(item, value);
72
63
  }
@@ -74,14 +65,11 @@ function compactPrefixForcesAsync(prefix) {
74
65
  }
75
66
  const isAsyncValidator = (vali) => vali?.isAsync ?? true;
76
67
  const mayReturnPromiseValidator = (vali) => vali?.mayReturnPromise === true;
77
- /**
78
- * Extracted from `buildNativeStaticResponse`'s for-in check so the native
79
- * static promotion predicate
80
- */
68
+ /** Whether a hook can be skipped by a native static response. */
81
69
  function isEmptyPipelineHook(hook) {
82
70
  if (!hook) return true;
83
71
  for (const key in hook) {
84
- if (key === "detail" || key === "tags") continue;
72
+ if (key === "detail" || key === "tags" || key === "error") continue;
85
73
  const value = hook[key];
86
74
  if (value !== void 0 && value !== false && (!Array.isArray(value) || value.length)) return false;
87
75
  }
@@ -137,11 +125,11 @@ function describeRoute(input) {
137
125
  }
138
126
  }
139
127
  const handlerIsAsync = isHandleFunction && require_compile_utils.isAsyncFunction(handler);
140
- const errorHookForcesAsync = hasErrorHook && (hasAfterHandle || hasMapResponse || hasResponseValidator || require_compile_utils.isAsyncLifecycle(hook?.error) || lifecycleMayReturnPromise(hook?.error, false));
128
+ const errorHookForcesAsync = hasErrorHook && (hasAfterHandle || hasMapResponse || hasResponseValidator || require_compile_utils.isAsyncLifecycle(hook?.error) || lifecycleMayReturnPromise(hook?.error));
141
129
  const afterResponseForcesAsync = hasStaticAfterResponse && require_compile_utils.isAsyncLifecycle(hook?.afterResponse) || hasAfterResponse && (hasAfterHandle || hasMapResponse || hasResponseValidator || hasErrorHook);
142
- const traceForcesAsync = (traceHandleOn || phaseOn("error") || phaseOn("afterResponse")) && isHandleFunction && !handlerIsAsync && (require_compile_utils.mayReturnPromise(handler) || mayReturnIdentifier(handler));
143
- const handlerResultObserved = isHandleFunction && !handlerIsAsync && (hasResponseValidator || hasAfterHandle || hasMapResponse) && (require_compile_utils.mayReturnPromise(handler) || mayReturnIdentifier(handler));
144
- const lifecycleForcesAsync = !!hook && ((beforeHandlePrefix ? compactPrefixForcesAsync(beforeHandlePrefix) : false) || lifecycleMayReturnPromise(hook.beforeHandle, true) || lifecycleMayReturnPromise(hook.transform, false) || lifecycleMayReturnPromise(hook.afterHandle, true) || lifecycleMayReturnPromise(hook.mapResponse, true));
130
+ const traceForcesAsync = (traceHandleOn || phaseOn("error") || phaseOn("afterResponse")) && isHandleFunction && !handlerIsAsync && require_compile_utils.mayReturnPromise(handler);
131
+ const handlerResultObserved = isHandleFunction && !handlerIsAsync && (hasResponseValidator || hasAfterHandle || hasMapResponse) && require_compile_utils.mayReturnPromise(handler);
132
+ const lifecycleForcesAsync = !!hook && ((beforeHandlePrefix ? compactPrefixForcesAsync(beforeHandlePrefix) : false) || lifecycleMayReturnPromise(hook.beforeHandle) || lifecycleMayReturnPromise(hook.transform) || lifecycleMayReturnPromise(hook.afterHandle) || lifecycleMayReturnPromise(hook.mapResponse));
145
133
  const isAsync = hasBody || handlerIsAsync || errorHookForcesAsync || traceForcesAsync || afterResponseForcesAsync || handlerResultObserved || lifecycleForcesAsync || asyncCookieSign || responseValiAsync || hook && (!!require_compile_utils.isAsyncLifecycle(hook?.afterHandle) || !!require_compile_utils.isAsyncLifecycle(hook?.beforeHandle) || !!require_compile_utils.isAsyncLifecycle(hook?.transform) || !!require_compile_utils.isAsyncLifecycle(hook?.mapResponse) || !!require_compile_utils.isAsyncLifecycle(hook?.error) || bodyValiIsAsync || headersValiIsAsync || paramsValiIsAsync || queryValiIsAsync || cookieValidIsAsync);
146
134
  const callHandlerSyncOnAsync = isAsync && isHandleFunction && !handlerIsAsync;
147
135
  const syncErrorHook = hasErrorHook && !isAsync && !hasTrace;
@@ -195,5 +183,4 @@ function describeRoute(input) {
195
183
  exports.describeRoute = describeRoute;
196
184
  exports.isEmptyPipelineHook = isEmptyPipelineHook;
197
185
  exports.lifecycleMayReturnPromise = lifecycleMayReturnPromise;
198
- exports.mayReturnIdentifier = mayReturnIdentifier;
199
186
  exports.routeDescriptors = routeDescriptors;
@@ -14,16 +14,7 @@ import { mergeInference, sucrose } from "../../sucrose.mjs";
14
14
  */
15
15
  const routeDescriptors = /* @__PURE__ */ new WeakMap();
16
16
  const noTracePhases = /* @__PURE__ */ new Set();
17
- const matchReturnIdentifier = /(?:=>\s*|\breturn\s+)(?!(?:true|false|null|undefined|void|new|typeof|async|await|function|class)\b)[A-Za-z_$][\w$]*(?:\s*\.\s*[A-Za-z_$][\w$]*)*\s*(?![\w$([])/;
18
- const mayReturnIdentifierCache = /* @__PURE__ */ new WeakMap();
19
- function mayReturnIdentifier(fn) {
20
- let result = mayReturnIdentifierCache.get(fn);
21
- if (result !== void 0) return result;
22
- result = matchReturnIdentifier.test(fn.toString());
23
- mayReturnIdentifierCache.set(fn, result);
24
- return result;
25
- }
26
- const lifecycleMayReturnPromise = (handlers, observed) => handlers ? Array.isArray(handlers) ? handlers.some((fn) => !isAsyncFunction(fn) && (mayReturnPromise(fn) || observed && mayReturnIdentifier(fn))) : !isAsyncFunction(handlers) && (mayReturnPromise(handlers) || observed && mayReturnIdentifier(handlers)) : false;
17
+ const lifecycleMayReturnPromise = (handlers) => handlers ? Array.isArray(handlers) ? handlers.some(mayReturnPromise) : mayReturnPromise(handlers) : false;
27
18
  const compactPrefixInference = /* @__PURE__ */ new WeakMap();
28
19
  const compactPrefixAsync = /* @__PURE__ */ new WeakMap();
29
20
  const inferCompactPrefix = (prefix) => {
@@ -65,7 +56,7 @@ function compactPrefixForcesAsync(prefix) {
65
56
  const item = pending[i];
66
57
  for (let j = 0; !value && j < item.added.length; j++) {
67
58
  const fn = item.added[j];
68
- value = isAsyncFunction(fn) || !isAsyncFunction(fn) && (mayReturnPromise(fn) || mayReturnIdentifier(fn));
59
+ value = mayReturnPromise(fn);
69
60
  }
70
61
  compactPrefixAsync.set(item, value);
71
62
  }
@@ -73,14 +64,11 @@ function compactPrefixForcesAsync(prefix) {
73
64
  }
74
65
  const isAsyncValidator = (vali) => vali?.isAsync ?? true;
75
66
  const mayReturnPromiseValidator = (vali) => vali?.mayReturnPromise === true;
76
- /**
77
- * Extracted from `buildNativeStaticResponse`'s for-in check so the native
78
- * static promotion predicate
79
- */
67
+ /** Whether a hook can be skipped by a native static response. */
80
68
  function isEmptyPipelineHook(hook) {
81
69
  if (!hook) return true;
82
70
  for (const key in hook) {
83
- if (key === "detail" || key === "tags") continue;
71
+ if (key === "detail" || key === "tags" || key === "error") continue;
84
72
  const value = hook[key];
85
73
  if (value !== void 0 && value !== false && (!Array.isArray(value) || value.length)) return false;
86
74
  }
@@ -136,11 +124,11 @@ function describeRoute(input) {
136
124
  }
137
125
  }
138
126
  const handlerIsAsync = isHandleFunction && isAsyncFunction(handler);
139
- const errorHookForcesAsync = hasErrorHook && (hasAfterHandle || hasMapResponse || hasResponseValidator || isAsyncLifecycle(hook?.error) || lifecycleMayReturnPromise(hook?.error, false));
127
+ const errorHookForcesAsync = hasErrorHook && (hasAfterHandle || hasMapResponse || hasResponseValidator || isAsyncLifecycle(hook?.error) || lifecycleMayReturnPromise(hook?.error));
140
128
  const afterResponseForcesAsync = hasStaticAfterResponse && isAsyncLifecycle(hook?.afterResponse) || hasAfterResponse && (hasAfterHandle || hasMapResponse || hasResponseValidator || hasErrorHook);
141
- const traceForcesAsync = (traceHandleOn || phaseOn("error") || phaseOn("afterResponse")) && isHandleFunction && !handlerIsAsync && (mayReturnPromise(handler) || mayReturnIdentifier(handler));
142
- const handlerResultObserved = isHandleFunction && !handlerIsAsync && (hasResponseValidator || hasAfterHandle || hasMapResponse) && (mayReturnPromise(handler) || mayReturnIdentifier(handler));
143
- const lifecycleForcesAsync = !!hook && ((beforeHandlePrefix ? compactPrefixForcesAsync(beforeHandlePrefix) : false) || lifecycleMayReturnPromise(hook.beforeHandle, true) || lifecycleMayReturnPromise(hook.transform, false) || lifecycleMayReturnPromise(hook.afterHandle, true) || lifecycleMayReturnPromise(hook.mapResponse, true));
129
+ const traceForcesAsync = (traceHandleOn || phaseOn("error") || phaseOn("afterResponse")) && isHandleFunction && !handlerIsAsync && mayReturnPromise(handler);
130
+ const handlerResultObserved = isHandleFunction && !handlerIsAsync && (hasResponseValidator || hasAfterHandle || hasMapResponse) && mayReturnPromise(handler);
131
+ const lifecycleForcesAsync = !!hook && ((beforeHandlePrefix ? compactPrefixForcesAsync(beforeHandlePrefix) : false) || lifecycleMayReturnPromise(hook.beforeHandle) || lifecycleMayReturnPromise(hook.transform) || lifecycleMayReturnPromise(hook.afterHandle) || lifecycleMayReturnPromise(hook.mapResponse));
144
132
  const isAsync = hasBody || handlerIsAsync || errorHookForcesAsync || traceForcesAsync || afterResponseForcesAsync || handlerResultObserved || lifecycleForcesAsync || asyncCookieSign || responseValiAsync || hook && (!!isAsyncLifecycle(hook?.afterHandle) || !!isAsyncLifecycle(hook?.beforeHandle) || !!isAsyncLifecycle(hook?.transform) || !!isAsyncLifecycle(hook?.mapResponse) || !!isAsyncLifecycle(hook?.error) || bodyValiIsAsync || headersValiIsAsync || paramsValiIsAsync || queryValiIsAsync || cookieValidIsAsync);
145
133
  const callHandlerSyncOnAsync = isAsync && isHandleFunction && !handlerIsAsync;
146
134
  const syncErrorHook = hasErrorHook && !isAsync && !hasTrace;
@@ -191,4 +179,4 @@ function describeRoute(input) {
191
179
  }
192
180
 
193
181
  //#endregion
194
- export { describeRoute, isEmptyPipelineHook, lifecycleMayReturnPromise, mayReturnIdentifier, routeDescriptors };
182
+ export { describeRoute, isEmptyPipelineHook, lifecycleMayReturnPromise, routeDescriptors };
@@ -1,5 +1,5 @@
1
1
  import { ChainNode } from "../../utils.js";
2
- import { AnyLocalHook, CompiledHandler, InternalRoute } from "../../types.js";
2
+ import { AnyLocalHook, AppHook, CompiledHandler, InternalRoute } from "../../types.js";
3
3
  import { AnyElysia } from "../../base.js";
4
4
  import { setCaptureHeaderShorthand } from "./jit.js";
5
5
 
@@ -11,9 +11,10 @@ declare function resolveWSLocalHook(scope: AnyElysia, hook: Partial<AnyLocalHook
11
11
  * (JIT or rebuild) compile repopulates them anyway, just uncached
12
12
  */
13
13
  declare function clearHandlerAnalysisCaches(root: AnyElysia): void;
14
+ declare function chainResolver(root: AnyElysia): ((node: ChainNode) => Partial<AppHook> | undefined) | undefined;
14
15
  declare const localMacroRoot: (instance: AnyElysia, root: AnyElysia) => AnyElysia;
15
16
  declare function buildNativeStaticResponse(route: InternalRoute, root: AnyElysia): Response | undefined;
16
- declare function composeRouteHook(instance: AnyElysia, localHook: Partial<AnyLocalHook> | undefined, appHook: ChainNode | undefined, inheritedChain: ChainNode | undefined, root: AnyElysia, macroScope?: AnyElysia): AnyLocalHook | undefined;
17
+ declare function composeRouteHook(instance: AnyElysia, localHook: Partial<AnyLocalHook> | undefined, appHook: ChainNode | undefined, inheritedChain: ChainNode | undefined, root: AnyElysia, macroScope?: AnyElysia, allowCompactPrefix?: boolean): AnyLocalHook | undefined;
17
18
  declare function compileHandler(route: InternalRoute, root: AnyElysia, precomputedStatic?: Response, liveOnly?: boolean): CompiledHandler;
18
19
  //#endregion
19
- export { buildNativeStaticResponse, clearHandlerAnalysisCaches, compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook, resolveWSLocalHook, setCaptureHeaderShorthand };
20
+ export { buildNativeStaticResponse, chainResolver, clearHandlerAnalysisCaches, compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook, resolveWSLocalHook, setCaptureHeaderShorthand };