elysia 2.0.0-beta.1 → 2.0.0-beta.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 (172) hide show
  1. package/dist/adapter/utils.d.ts +2 -2
  2. package/dist/adapter/utils.js +3 -3
  3. package/dist/adapter/utils.mjs +4 -4
  4. package/dist/adapter/web-standard/handler.js +14 -7
  5. package/dist/adapter/web-standard/handler.mjs +15 -8
  6. package/dist/base.d.ts +20 -5
  7. package/dist/base.js +73 -42
  8. package/dist/base.mjs +74 -43
  9. package/dist/compile/aot-capture.js +1 -1
  10. package/dist/compile/aot-capture.mjs +2 -2
  11. package/dist/compile/aot.d.ts +4 -4
  12. package/dist/compile/aot.js +14 -9
  13. package/dist/compile/aot.mjs +15 -9
  14. package/dist/compile/handler/descriptor.d.ts +1 -1
  15. package/dist/compile/handler/descriptor.js +1 -1
  16. package/dist/compile/handler/descriptor.mjs +1 -1
  17. package/dist/compile/handler/frozen-validator.d.ts +2 -1
  18. package/dist/compile/handler/frozen-validator.js +33 -3
  19. package/dist/compile/handler/frozen-validator.mjs +33 -4
  20. package/dist/compile/handler/index.d.ts +3 -3
  21. package/dist/compile/handler/index.js +6 -4
  22. package/dist/compile/handler/index.mjs +6 -4
  23. package/dist/compile/handler/jit.js +5 -8
  24. package/dist/compile/handler/jit.mjs +6 -9
  25. package/dist/compile/handler/params.js +3 -3
  26. package/dist/compile/handler/params.mjs +4 -4
  27. package/dist/compile/handler/utils.d.ts +1 -1
  28. package/dist/compile/handler/utils.js +7 -4
  29. package/dist/compile/handler/utils.mjs +8 -5
  30. package/dist/context.d.ts +2 -2
  31. package/dist/context.js +3 -4
  32. package/dist/context.mjs +3 -4
  33. package/dist/cookie/config.d.ts +1 -0
  34. package/dist/cookie/config.js +3 -2
  35. package/dist/cookie/config.mjs +3 -2
  36. package/dist/cookie/cookie.d.ts +1 -0
  37. package/dist/cookie/cookie.js +7 -5
  38. package/dist/cookie/cookie.mjs +7 -5
  39. package/dist/cookie/crypto.d.ts +8 -7
  40. package/dist/cookie/crypto.js +38 -31
  41. package/dist/cookie/crypto.mjs +38 -32
  42. package/dist/cookie/error.js +1 -2
  43. package/dist/cookie/error.mjs +1 -2
  44. package/dist/cookie/lib.js +5 -1
  45. package/dist/cookie/lib.mjs +5 -1
  46. package/dist/cookie/serialize.js +1 -1
  47. package/dist/cookie/serialize.mjs +1 -1
  48. package/dist/cookie/types.d.ts +10 -0
  49. package/dist/cookie/utils.js +28 -14
  50. package/dist/cookie/utils.mjs +29 -15
  51. package/dist/error.d.ts +139 -6
  52. package/dist/error.js +73 -0
  53. package/dist/error.mjs +73 -1
  54. package/dist/handler/error.d.ts +31 -1
  55. package/dist/handler/error.js +123 -8
  56. package/dist/handler/error.mjs +118 -9
  57. package/dist/handler/fetch.js +15 -12
  58. package/dist/handler/fetch.mjs +16 -13
  59. package/dist/handler/utils.js +4 -2
  60. package/dist/handler/utils.mjs +5 -3
  61. package/dist/index.d.ts +4 -4
  62. package/dist/index.js +2 -8
  63. package/dist/index.mjs +2 -2
  64. package/dist/package.js +1 -1
  65. package/dist/package.mjs +1 -1
  66. package/dist/plugin/aot/core.d.ts +26 -4
  67. package/dist/plugin/aot/core.js +36 -4
  68. package/dist/plugin/aot/core.mjs +36 -4
  69. package/dist/route-table.d.ts +1 -1
  70. package/dist/route-table.js +12 -10
  71. package/dist/route-table.mjs +12 -10
  72. package/dist/sucrose.js +118 -16
  73. package/dist/sucrose.mjs +118 -16
  74. package/dist/type/bridge-live.d.ts +1 -1
  75. package/dist/type/bridge-live.js +1 -1
  76. package/dist/type/bridge-live.mjs +1 -1
  77. package/dist/type/bridge.d.ts +6 -6
  78. package/dist/type/coerce-plan.js +3 -4
  79. package/dist/type/coerce-plan.mjs +1 -1
  80. package/dist/type/coerce.js +9 -4
  81. package/dist/type/coerce.mjs +9 -4
  82. package/dist/type/compat.d.ts +3 -0
  83. package/dist/type/compat.js +32 -14
  84. package/dist/type/compat.mjs +27 -8
  85. package/dist/type/elysia/array-buffer.js +2 -3
  86. package/dist/type/elysia/array-buffer.mjs +1 -1
  87. package/dist/type/elysia/array-string.js +35 -5
  88. package/dist/type/elysia/array-string.mjs +36 -5
  89. package/dist/type/elysia/boolean-string.js +2 -3
  90. package/dist/type/elysia/boolean-string.mjs +1 -1
  91. package/dist/type/elysia/boolean.js +4 -3
  92. package/dist/type/elysia/boolean.mjs +4 -2
  93. package/dist/type/elysia/cookie.js +2 -1
  94. package/dist/type/elysia/cookie.mjs +2 -1
  95. package/dist/type/elysia/date.js +7 -7
  96. package/dist/type/elysia/date.mjs +3 -2
  97. package/dist/type/elysia/file-type.d.ts +9 -2
  98. package/dist/type/elysia/file-type.js +27 -2
  99. package/dist/type/elysia/file-type.mjs +27 -3
  100. package/dist/type/elysia/file.js +8 -4
  101. package/dist/type/elysia/file.mjs +8 -3
  102. package/dist/type/elysia/files.js +6 -4
  103. package/dist/type/elysia/files.mjs +5 -2
  104. package/dist/type/elysia/form.js +3 -3
  105. package/dist/type/elysia/form.mjs +5 -4
  106. package/dist/type/elysia/integer-string.js +4 -5
  107. package/dist/type/elysia/integer-string.mjs +3 -3
  108. package/dist/type/elysia/integer.js +4 -3
  109. package/dist/type/elysia/integer.mjs +4 -2
  110. package/dist/type/elysia/maybe-empty.js +3 -4
  111. package/dist/type/elysia/maybe-empty.mjs +1 -1
  112. package/dist/type/elysia/nullable.js +2 -3
  113. package/dist/type/elysia/nullable.mjs +1 -1
  114. package/dist/type/elysia/number.js +4 -3
  115. package/dist/type/elysia/number.mjs +4 -2
  116. package/dist/type/elysia/numeric-enum.js +2 -3
  117. package/dist/type/elysia/numeric-enum.mjs +1 -1
  118. package/dist/type/elysia/numeric.js +5 -5
  119. package/dist/type/elysia/numeric.mjs +3 -2
  120. package/dist/type/elysia/object-string.js +32 -5
  121. package/dist/type/elysia/object-string.mjs +33 -5
  122. package/dist/type/elysia/string.js +4 -3
  123. package/dist/type/elysia/string.mjs +4 -2
  124. package/dist/type/elysia/uint8-array.js +2 -3
  125. package/dist/type/elysia/uint8-array.mjs +1 -1
  126. package/dist/type/elysia/union-enum.js +2 -3
  127. package/dist/type/elysia/union-enum.mjs +1 -1
  128. package/dist/type/elysia/utils.js +2 -3
  129. package/dist/type/elysia/utils.mjs +1 -1
  130. package/dist/type/exports.js +10 -1
  131. package/dist/type/exports.mjs +7 -0
  132. package/dist/type/index.d.ts +9 -1
  133. package/dist/type/index.js +41 -13
  134. package/dist/type/index.mjs +44 -9
  135. package/dist/type/typebox-type-live.d.ts +9 -0
  136. package/dist/type/typebox-type-live.js +31 -0
  137. package/dist/type/typebox-type-live.mjs +16 -0
  138. package/dist/type/typebox-type.d.ts +24 -0
  139. package/dist/type/typebox-type.js +130 -0
  140. package/dist/type/typebox-type.mjs +66 -0
  141. package/dist/type/typebox-value-live.d.ts +9 -0
  142. package/dist/type/typebox-value-live.js +27 -0
  143. package/dist/type/typebox-value-live.mjs +11 -0
  144. package/dist/type/typebox-value.d.ts +30 -0
  145. package/dist/type/typebox-value.js +147 -0
  146. package/dist/type/typebox-value.mjs +62 -0
  147. package/dist/type/validator/custom-error.js +4 -5
  148. package/dist/type/validator/custom-error.mjs +3 -3
  149. package/dist/type/validator/default-precompute.js +4 -5
  150. package/dist/type/validator/default-precompute.mjs +1 -1
  151. package/dist/type/validator/index.js +52 -48
  152. package/dist/type/validator/index.mjs +35 -30
  153. package/dist/type/validator/validator-cache.js +10 -5
  154. package/dist/type/validator/validator-cache.mjs +10 -4
  155. package/dist/types.d.ts +104 -18
  156. package/dist/universal/constants.d.ts +2 -1
  157. package/dist/universal/constants.js +3 -1
  158. package/dist/universal/constants.mjs +2 -1
  159. package/dist/universal/file.js +1 -0
  160. package/dist/universal/file.mjs +1 -0
  161. package/dist/universal/index.d.ts +1 -1
  162. package/dist/utils.d.ts +12 -5
  163. package/dist/utils.js +25 -12
  164. package/dist/utils.mjs +19 -12
  165. package/dist/validator/index.js +2 -1
  166. package/dist/validator/index.mjs +2 -1
  167. package/dist/ws/context.d.ts +4 -0
  168. package/dist/ws/context.js +44 -26
  169. package/dist/ws/context.mjs +44 -26
  170. package/dist/ws/route.js +127 -24
  171. package/dist/ws/route.mjs +128 -25
  172. package/package.json +5 -3
package/dist/base.mjs CHANGED
@@ -2,7 +2,7 @@ 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 } from "./utils.mjs";
3
3
  import { Ref } from "./type/bridge.mjs";
4
4
  import { isProduction } from "./universal/is-production.mjs";
5
- import { Capture, Compiled, beginCompilerSession, createAotFingerprint, createProgramId, endCompilerSession } from "./compile/aot.mjs";
5
+ import { Capture, Compiled, beginCompilerSession, createAotFingerprint, endCompilerSession } from "./compile/aot.mjs";
6
6
  import { traceCapabilityRequired, wsCapabilityRequired } from "./generation.mjs";
7
7
  import { compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook } from "./compile/handler/index.mjs";
8
8
  import { RouteFlag, buildRouteTable, routeRow } from "./route-table.mjs";
@@ -16,6 +16,29 @@ import Memoirist from "memoirist";
16
16
  const useNodesBuffer = [];
17
17
  const emptyHistory = Object.freeze([]);
18
18
  const canRegisterLoose = (path, isDynamic) => !isDynamic && (path.length === 0 || path.charCodeAt(path.length - 1) === 47);
19
+ /**
20
+ * Every key a single route must answer to, in registration order.
21
+ *
22
+ * `registerLoose` is the caller's call, not this helper's: HTTP gates it on
23
+ * `canRegisterLoose` because its lookup retries the trailing slash, while WS
24
+ * has no such retry and must own both directions outright
25
+ */
26
+ const expandPaths = (path, needsEncode, registerLoose, explicit) => {
27
+ const variants = [path];
28
+ if (needsEncode) {
29
+ const encoded = encodeURI(path);
30
+ if (encoded !== path) variants.push(encoded);
31
+ }
32
+ if (!registerLoose) return variants;
33
+ const paths = [];
34
+ for (let v = 0; v < variants.length; v++) {
35
+ const p = variants[v];
36
+ paths.push(p);
37
+ const loose = getLoosePath(p);
38
+ if (loose !== p && !explicit?.has(loose)) paths.push(loose);
39
+ }
40
+ return paths;
41
+ };
19
42
  var Elysia = class Elysia {
20
43
  #hasPlugin;
21
44
  #hasGlobal;
@@ -77,11 +100,14 @@ var Elysia = class Elysia {
77
100
  #jitRoute;
78
101
  #jitStatic;
79
102
  #jitAliases;
103
+ get ["~programId"]() {
104
+ return this;
105
+ }
80
106
  constructor(config) {
81
107
  /**
82
108
  * ! Don't tune
83
109
  *
84
- * Interesting JSC internal: These `= undefined` are load-bearing
110
+ * Interesting JSC internal: These `= undefined` shouldn't be removed
85
111
  *
86
112
  * Inline slots live inside the object cell, so JSC must pick their
87
113
  * count at allocation before any initializer runs
@@ -99,7 +125,8 @@ var Elysia = class Elysia {
99
125
  * Don't omitted field either for monomorphic access
100
126
  *
101
127
  * @see test/memory/instance-footprint.test.ts
102
- * Est. Overflow 37 -> 21 = butterfly 64 -> 32 slots = 738B -> 450B/instance
128
+ * Est. overflow 37 -> 21 = butterfly 64 -> 32 slots = 738B -> 450B;
129
+ * reusing the app as its program identity brings the current cell to ~386B.
103
130
  **/
104
131
  this["~config"] = config;
105
132
  this["~ext"] = void 0;
@@ -119,7 +146,6 @@ var Elysia = class Elysia {
119
146
  this["~introspect"] = void 0;
120
147
  this["~scopeChild"] = void 0;
121
148
  this["~scopeChildren"] = void 0;
122
- this["~programId"] = createProgramId();
123
149
  if (config) {
124
150
  const { prefix, name, seed, adapter } = config;
125
151
  this["~Prefix"] = prefix ? prefix.charCodeAt(0) === 47 ? prefix : `/${prefix}` : void 0;
@@ -499,7 +525,7 @@ var Elysia = class Elysia {
499
525
  invalidateMacroEpoch();
500
526
  return this;
501
527
  }
502
- "~applyMacro"(input, toApply = input, iteration = 0, seen = /* @__PURE__ */ new Set()) {
528
+ "~applyMacro"(input, toApply = input, iteration = 0, seen = /* @__PURE__ */ new Set(), insertions = /* @__PURE__ */ new Map()) {
503
529
  if (iteration >= 16) return input;
504
530
  const macro = this["~ext"]?.macro;
505
531
  if (!macro) return input;
@@ -544,7 +570,7 @@ var Elysia = class Elysia {
544
570
  continue;
545
571
  }
546
572
  if (k in macro) {
547
- this["~applyMacro"](input, { [k]: v }, iteration + 1, seen);
573
+ this["~applyMacro"](input, { [k]: v }, iteration + 1, seen, insertions);
548
574
  delete input[key];
549
575
  continue;
550
576
  }
@@ -565,19 +591,20 @@ var Elysia = class Elysia {
565
591
  delete input[key];
566
592
  continue;
567
593
  }
568
- if (k in input) {
569
- if (eventProperties.has(k) || k === "derive") {
570
- const macroFns = Array.isArray(v) ? v : [v];
571
- const existing = Array.isArray(input[k]) ? input[k] : [input[k]];
572
- const merged = [];
573
- const seen = /* @__PURE__ */ new Set();
574
- for (const fn of macroFns) if (!existing.includes(fn) && !seen.has(fn)) {
575
- seen.add(fn);
576
- merged.push(fn);
577
- }
578
- for (const fn of existing) if (!seen.has(fn)) merged.push(fn);
579
- input[k] = merged;
580
- } else if (Array.isArray(input[k])) {
594
+ if (eventProperties.has(k) || k === "derive") {
595
+ const incoming = Array.isArray(v) ? v : [v];
596
+ const existing = k in input ? Array.isArray(input[k]) ? input[k] : [input[k]] : [];
597
+ const added = [];
598
+ for (const fn of incoming) if (!existing.includes(fn) && !added.includes(fn)) added.push(fn);
599
+ const at = insertions.get(k) ?? 0;
600
+ input[k] = [
601
+ ...existing.slice(0, at),
602
+ ...added,
603
+ ...existing.slice(at)
604
+ ];
605
+ insertions.set(k, at + added.length);
606
+ } else if (k in input) {
607
+ if (Array.isArray(input[k])) {
581
608
  if (Array.isArray(v)) {
582
609
  for (const item of v) if (!input[k].some((e) => e === item)) input[k].unshift(item);
583
610
  } else if (!input[k].some((item) => item === v)) input[k].unshift(v);
@@ -1179,10 +1206,10 @@ var Elysia = class Elysia {
1179
1206
  this.fetch;
1180
1207
  return this;
1181
1208
  }
1182
- handler(index, immediate = this["~config"]?.precompile, route, precomputedStatic, aliases, table) {
1209
+ handler(index, immediate, route, precomputedStatic, aliases, table) {
1183
1210
  if (this.#compiled?.[index]) return this.#compiled[index];
1184
1211
  const compiled = this.#compiled ??= new Array(table?.length ?? this["~routes"].length);
1185
- if (immediate) {
1212
+ if (immediate ?? this["~config"]?.precompile) {
1186
1213
  const row = route ?? (table ? routeRow(table, index) : this["~routes"][index]);
1187
1214
  let handler;
1188
1215
  try {
@@ -1410,7 +1437,10 @@ var Elysia = class Elysia {
1410
1437
  const appChain = this["~hookChain"];
1411
1438
  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]);
1412
1439
  else for (let i = 0; i < length; i++) if (this.#routeMayHaveModelRef(table, i)) this.#assertRouteModelRefs(routeRow(table, i), method[i]);
1413
- if (length) Compiled.claim(this["~programId"], this["~aotFingerprint"] = createAotFingerprint());
1440
+ if (length) {
1441
+ const programId = this["~programId"];
1442
+ if (!Compiled.claim(programId, this["~aotFingerprint"] = createAotFingerprint())) Compiled.assertUncontested(programId);
1443
+ }
1414
1444
  const isLoose = this["~config"]?.strictPath !== true;
1415
1445
  let explicitPaths;
1416
1446
  if (isLoose && table.hasLoose) {
@@ -1436,17 +1466,17 @@ var Elysia = class Elysia {
1436
1466
  const handler = ws[0];
1437
1467
  const options = ws[1];
1438
1468
  if (wsConfig === void 0 && wsCap.options) wsConfig = wsCap.options;
1469
+ const wsNeedsEncode = (routeFlags & RouteFlag.Encode) !== 0;
1439
1470
  if ((routeFlags & RouteFlag.Dynamic) !== 0) {
1440
- (this["~router"] ??= new Memoirist({ loosePath: isLoose })).add("WS", routePath, handler);
1471
+ const wsRouter = this["~router"] ??= new Memoirist({ loosePath: isLoose });
1472
+ const wsPaths = expandPaths(routePath, wsNeedsEncode, false, void 0);
1473
+ for (let v = 0; v < wsPaths.length; v++) wsRouter.add("WS", wsPaths[v], handler);
1441
1474
  this["~hasDynamicWS"] = true;
1442
1475
  } else {
1443
1476
  this.#initMap();
1444
1477
  const wsMap = this["~map"]["WS"] ??= nullObject();
1445
- wsMap[routePath] = handler;
1446
- if (isLoose) {
1447
- const loose = getLoosePath(routePath);
1448
- if (loose !== routePath && !explicitPaths?.get("WS")?.has(loose)) wsMap[loose] = handler;
1449
- }
1478
+ const wsPaths = expandPaths(routePath, wsNeedsEncode, isLoose, isLoose ? explicitPaths?.get("WS") : void 0);
1479
+ for (let v = 0; v < wsPaths.length; v++) wsMap[wsPaths[v]] = handler;
1450
1480
  }
1451
1481
  if (options && isNotEmpty(options)) {
1452
1482
  wsConfig ??= nullObject();
@@ -1457,26 +1487,12 @@ var Elysia = class Elysia {
1457
1487
  const isDynamic = (routeFlags & RouteFlag.Dynamic) !== 0;
1458
1488
  const needsEncode = (routeFlags & RouteFlag.Encode) !== 0;
1459
1489
  const registerLoose = isLoose && canRegisterLoose(routePath, isDynamic);
1460
- const explicitMain = registerLoose ? explicitPaths?.get(routeMethod) : void 0;
1461
1490
  if (!isDynamic && !needsEncode && !registerLoose) {
1462
1491
  const map = methods[routeMethod] ??= nullObject();
1463
1492
  map[routePath] = this.handler(i, precompile, void 0, void 0, void 0, table);
1464
1493
  continue;
1465
1494
  }
1466
- const variants = [routePath];
1467
- if (needsEncode) {
1468
- const encoded = encodeURI(routePath);
1469
- if (encoded !== routePath) variants.push(encoded);
1470
- }
1471
- const paths = [];
1472
- for (let v = 0; v < variants.length; v++) {
1473
- const p = variants[v];
1474
- paths.push(p);
1475
- if (registerLoose) {
1476
- const loose = getLoosePath(p);
1477
- if (loose !== p && !explicitMain?.has(loose)) paths.push(loose);
1478
- }
1479
- }
1495
+ const paths = expandPaths(routePath, needsEncode, registerLoose, registerLoose ? explicitPaths?.get(routeMethod) : void 0);
1480
1496
  if (isDynamic) {
1481
1497
  const router = this["~router"] ??= new Memoirist({ loosePath: isLoose });
1482
1498
  const handler = this.handler(i, precompile, void 0, void 0, void 0, table);
@@ -1508,6 +1524,21 @@ var Elysia = class Elysia {
1508
1524
  if (!Capture.isAotBuildEnv()) listen(this, options, callback);
1509
1525
  return this;
1510
1526
  }
1527
+ /**
1528
+ * Add a higher order function over Elysia.fetch
1529
+ *
1530
+ * @example
1531
+ * ```ts
1532
+ * const ctx = new AsyncLocalStorage<{ counter: number }>()
1533
+ *
1534
+ * new Elysia()
1535
+ * .wrap(
1536
+ * (fetch) => (request) =>
1537
+ * ctx.run({ counter: 0 }, () => fetch(request))
1538
+ * )
1539
+ * .get('/', () => ctx.getStore())
1540
+ * ```
1541
+ */
1511
1542
  wrap(callback) {
1512
1543
  this.#assertMutable("wrap");
1513
1544
  if (this.#fetchFn && !this.#pending) console.warn("[Elysia] .wrap() was called after the fetch handler was built");
@@ -282,7 +282,7 @@ function captureBridgeFree(aot, slot, rawSchema) {
282
282
  path: aot.path,
283
283
  slot
284
284
  }, { bridgeFree });
285
- if (bridgeFree && !require_compile_handler_frozen_validator.isCompactDiagnosable(coerced)) warnCompactErrorLoss(aot, slot);
285
+ if (bridgeFree && !require_compile_handler_frozen_validator.isCompactWalkable(coerced)) warnCompactErrorLoss(aot, slot);
286
286
  }
287
287
  }
288
288
  function beginValidatorCapture() {
@@ -2,7 +2,7 @@ import { nullObject } from "../utils.mjs";
2
2
  import { env } from "../universal/env.mjs";
3
3
  import { Capture, CompilerState, aotActivationError, captureImpl, setCaptureImpl } from "./aot.mjs";
4
4
  import { isAsyncPredicate } from "../type/elysia/file-type.mjs";
5
- import { isCapturedBridgeFree, isCompactDiagnosable } from "./handler/frozen-validator.mjs";
5
+ import { isCapturedBridgeFree, isCompactWalkable } from "./handler/frozen-validator.mjs";
6
6
  import { buildCoercedFromPlan, captureCoercePlan } from "../type/coerce.mjs";
7
7
  import { applyPrecomputed, buildDefaultClonerSource, buildObjectDefaultMergeSource, canonical, createMergerFromSource, setDefaultProbeImpl, verifyPreallocatableDefault } from "../type/validator/default-precompute.mjs";
8
8
  import { collectExternals } from "./aot-reconstruct.mjs";
@@ -280,7 +280,7 @@ function captureBridgeFree(aot, slot, rawSchema) {
280
280
  path: aot.path,
281
281
  slot
282
282
  }, { bridgeFree });
283
- if (bridgeFree && !isCompactDiagnosable(coerced)) warnCompactErrorLoss(aot, slot);
283
+ if (bridgeFree && !isCompactWalkable(coerced)) warnCompactErrorLoss(aot, slot);
284
284
  }
285
285
  }
286
286
  function beginValidatorCapture() {
@@ -8,8 +8,7 @@ interface AotFingerprint {
8
8
  interface ProgramId {
9
9
  readonly _: unique symbol;
10
10
  }
11
- declare const createProgramId: () => ProgramId;
12
- declare function createAotFingerprint(): AotFingerprint;
11
+ declare const createAotFingerprint: () => AotFingerprint;
13
12
  interface CompilerSession {
14
13
  readonly sucroseCache: Map<number, {
15
14
  content: string;
@@ -91,7 +90,7 @@ interface HandlerManifest {
91
90
  }
92
91
  interface CompiledSnapshot {
93
92
  registered: CompiledProgramRegistration | undefined;
94
- claimed: boolean;
93
+ claimed: WeakRef<ProgramId> | undefined;
95
94
  programs: WeakMap<ProgramId, CompiledProgram>;
96
95
  }
97
96
  interface CompiledProgramRegistration {
@@ -131,6 +130,7 @@ declare function reconstruct(): ReconstructImpl;
131
130
  declare abstract class Compiled {
132
131
  static register(manifest: CompiledProgramRegistration): void;
133
132
  static claim(id: ProgramId, fingerprint: AotFingerprint): boolean;
133
+ static assertUncontested(id: ProgramId): void;
134
134
  static get reconstruct(): ReconstructImpl | undefined;
135
135
  static set reconstruct(impl: ReconstructImpl | undefined);
136
136
  static getHandler(id: ProgramId | undefined, method: string, path: string): FrozenHandler | undefined;
@@ -284,4 +284,4 @@ interface CaptureImpl {
284
284
  declare let captureImpl: CaptureImpl | undefined;
285
285
  declare function setCaptureImpl(impl: CaptureImpl | undefined): void;
286
286
  //#endregion
287
- export { AOT_ABI, AOT_MANIFEST_FORMAT, AotFingerprint, Capture, CaptureImpl, CapturedHandler, CapturedMirror, CapturedValidator, CheckBuildResult, Compiled, CompiledProgramRegistration, CompiledSnapshot, CompilerSession, CompilerState, EMPTY_EXTERNALS, FrozenBothFactory, FrozenCheckFactory, FrozenHandler, FrozenMirror, FrozenMirrorFactory, FrozenValidator, HandlerManifest, ProgramId, ReconstructImpl, StringCodecNode, ValidatorManifest, ValidatorSlot, aotActivationError, beginCompilerSession, captureImpl, createAotFingerprint, createProgramId, endCompilerSession, getCompilerSession, reconstruct, setCaptureImpl };
287
+ export { AOT_ABI, AOT_MANIFEST_FORMAT, AotFingerprint, Capture, CaptureImpl, CapturedHandler, CapturedMirror, CapturedValidator, CheckBuildResult, Compiled, CompiledProgramRegistration, CompiledSnapshot, CompilerSession, CompilerState, EMPTY_EXTERNALS, FrozenBothFactory, FrozenCheckFactory, FrozenHandler, FrozenMirror, FrozenMirrorFactory, FrozenValidator, HandlerManifest, ProgramId, ReconstructImpl, StringCodecNode, ValidatorManifest, ValidatorSlot, aotActivationError, beginCompilerSession, captureImpl, createAotFingerprint, endCompilerSession, getCompilerSession, reconstruct, setCaptureImpl };
@@ -6,11 +6,8 @@ const require_package = require('../package.js');
6
6
  //#region src/compile/aot.ts
7
7
  const AOT_MANIFEST_FORMAT = 3;
8
8
  const AOT_ABI = `${require_package.version}:${3}`;
9
- const createProgramId = () => ({});
10
9
  const sharedAotFingerprint = Object.freeze({ abi: AOT_ABI });
11
- function createAotFingerprint() {
12
- return sharedAotFingerprint;
13
- }
10
+ const createAotFingerprint = () => sharedAotFingerprint;
14
11
  let activeSession;
15
12
  const newCompilerSession = () => ({ sucroseCache: /* @__PURE__ */ new Map() });
16
13
  function beginCompilerSession(app) {
@@ -41,7 +38,12 @@ function reconstruct() {
41
38
  return reconstructImpl;
42
39
  }
43
40
  let registered;
44
- let claimed = false;
41
+ /**
42
+ * App that consumed this process's manifest, held weakly: it only has to
43
+ * recognise a re-claim by the *same* app, and `assertUncontested` always
44
+ * compares against a live id, so a cleared ref answers as a strong one would
45
+ */
46
+ let claimed;
45
47
  let programs = /* @__PURE__ */ new WeakMap();
46
48
  const programFor = (id) => id ? programs.get(id) : void 0;
47
49
  const fingerprintMismatch = (manifest, actual) => {
@@ -54,14 +56,14 @@ const fingerprintMismatch = (manifest, actual) => {
54
56
  var Compiled = class {
55
57
  static register(manifest) {
56
58
  registered = manifest;
57
- claimed = false;
59
+ claimed = void 0;
58
60
  }
59
61
  static claim(id, fingerprint) {
60
62
  if (!registered || claimed) return false;
61
63
  const manifest = registered;
62
64
  const differences = fingerprintMismatch(manifest, fingerprint);
63
65
  if (differences.length) throw new Error(`[elysia-aot] Registered manifest fingerprint mismatch: ${differences.join("; ")}.`);
64
- claimed = true;
66
+ claimed = new WeakRef(id);
65
67
  registered = void 0;
66
68
  programs.set(id, {
67
69
  ...manifest,
@@ -69,6 +71,10 @@ var Compiled = class {
69
71
  });
70
72
  return true;
71
73
  }
74
+ static assertUncontested(id) {
75
+ if (claimed === void 0 || claimed.deref() === id || isAotBuildEnv()) return;
76
+ throw new Error("[elysia-aot] A second Elysia app built a router in this process. An AOT build seals one app per process.");
77
+ }
72
78
  static get reconstruct() {
73
79
  return reconstructImpl;
74
80
  }
@@ -116,7 +122,7 @@ var Compiled = class {
116
122
  /** @internal test isolation */
117
123
  static clear() {
118
124
  registered = void 0;
119
- claimed = false;
125
+ claimed = void 0;
120
126
  programs = /* @__PURE__ */ new WeakMap();
121
127
  }
122
128
  };
@@ -213,7 +219,6 @@ Object.defineProperty(exports, 'captureImpl', {
213
219
  }
214
220
  });
215
221
  exports.createAotFingerprint = createAotFingerprint;
216
- exports.createProgramId = createProgramId;
217
222
  exports.endCompilerSession = endCompilerSession;
218
223
  exports.getCompilerSession = getCompilerSession;
219
224
  exports.reconstruct = reconstruct;
@@ -5,11 +5,8 @@ import { version } from "../package.mjs";
5
5
  //#region src/compile/aot.ts
6
6
  const AOT_MANIFEST_FORMAT = 3;
7
7
  const AOT_ABI = `${version}:${3}`;
8
- const createProgramId = () => ({});
9
8
  const sharedAotFingerprint = Object.freeze({ abi: AOT_ABI });
10
- function createAotFingerprint() {
11
- return sharedAotFingerprint;
12
- }
9
+ const createAotFingerprint = () => sharedAotFingerprint;
13
10
  let activeSession;
14
11
  const newCompilerSession = () => ({ sucroseCache: /* @__PURE__ */ new Map() });
15
12
  function beginCompilerSession(app) {
@@ -40,7 +37,12 @@ function reconstruct() {
40
37
  return reconstructImpl;
41
38
  }
42
39
  let registered;
43
- let claimed = false;
40
+ /**
41
+ * App that consumed this process's manifest, held weakly: it only has to
42
+ * recognise a re-claim by the *same* app, and `assertUncontested` always
43
+ * compares against a live id, so a cleared ref answers as a strong one would
44
+ */
45
+ let claimed;
44
46
  let programs = /* @__PURE__ */ new WeakMap();
45
47
  const programFor = (id) => id ? programs.get(id) : void 0;
46
48
  const fingerprintMismatch = (manifest, actual) => {
@@ -53,14 +55,14 @@ const fingerprintMismatch = (manifest, actual) => {
53
55
  var Compiled = class {
54
56
  static register(manifest) {
55
57
  registered = manifest;
56
- claimed = false;
58
+ claimed = void 0;
57
59
  }
58
60
  static claim(id, fingerprint) {
59
61
  if (!registered || claimed) return false;
60
62
  const manifest = registered;
61
63
  const differences = fingerprintMismatch(manifest, fingerprint);
62
64
  if (differences.length) throw new Error(`[elysia-aot] Registered manifest fingerprint mismatch: ${differences.join("; ")}.`);
63
- claimed = true;
65
+ claimed = new WeakRef(id);
64
66
  registered = void 0;
65
67
  programs.set(id, {
66
68
  ...manifest,
@@ -68,6 +70,10 @@ var Compiled = class {
68
70
  });
69
71
  return true;
70
72
  }
73
+ static assertUncontested(id) {
74
+ if (claimed === void 0 || claimed.deref() === id || isAotBuildEnv()) return;
75
+ throw new Error("[elysia-aot] A second Elysia app built a router in this process. An AOT build seals one app per process.");
76
+ }
71
77
  static get reconstruct() {
72
78
  return reconstructImpl;
73
79
  }
@@ -115,7 +121,7 @@ var Compiled = class {
115
121
  /** @internal test isolation */
116
122
  static clear() {
117
123
  registered = void 0;
118
- claimed = false;
124
+ claimed = void 0;
119
125
  programs = /* @__PURE__ */ new WeakMap();
120
126
  }
121
127
  };
@@ -197,4 +203,4 @@ function setCaptureImpl(impl) {
197
203
  }
198
204
 
199
205
  //#endregion
200
- export { AOT_ABI, AOT_MANIFEST_FORMAT, Capture, Compiled, CompilerState, EMPTY_EXTERNALS, aotActivationError, beginCompilerSession, captureImpl, createAotFingerprint, createProgramId, endCompilerSession, getCompilerSession, reconstruct, setCaptureImpl };
206
+ export { AOT_ABI, AOT_MANIFEST_FORMAT, Capture, Compiled, CompilerState, EMPTY_EXTERNALS, aotActivationError, beginCompilerSession, captureImpl, createAotFingerprint, endCompilerSession, getCompilerSession, reconstruct, setCaptureImpl };
@@ -1,6 +1,6 @@
1
1
  import { TraceEvent } from "../../trace.js";
2
- import { AnyLocalHook, MaybeArray } from "../../types.js";
3
2
  import { CompactBeforeHandlePrefix } from "../../utils.js";
3
+ import { AnyLocalHook, MaybeArray } from "../../types.js";
4
4
  import { CompiledCookieConfig } from "../../cookie/config.js";
5
5
  import { AnyElysia } from "../../base.js";
6
6
  import { ElysiaAdapter } from "../../adapter/index.js";
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_utils = require('../../utils.js');
3
+ const require_cookie_crypto = require('../../cookie/crypto.js');
3
4
  const require_compile_aot = require('../aot.js');
4
5
  const require_generation = require('../../generation.js');
5
- const require_cookie_crypto = require('../../cookie/crypto.js');
6
6
  const require_cookie_config = require('../../cookie/config.js');
7
7
  const require_compile_utils = require('../utils.js');
8
8
  const require_compile_jit_probe = require('../jit-probe.js');
@@ -1,7 +1,7 @@
1
1
  import { isNotEmpty } from "../../utils.mjs";
2
+ import { hasSyncHmac } from "../../cookie/crypto.mjs";
2
3
  import { Capture } from "../aot.mjs";
3
4
  import { frozenRootOf, resolvedTraceOf, traceCapabilityRequired } from "../../generation.mjs";
4
- import { hasSyncHmac } from "../../cookie/crypto.mjs";
5
5
  import { compileCookieConfig } from "../../cookie/config.mjs";
6
6
  import { isAsyncFunction, isAsyncLifecycle, mayReturnPromise } from "../utils.mjs";
7
7
  import { JITProbe } from "../jit-probe.mjs";
@@ -11,6 +11,7 @@ interface SlotCheckClean {
11
11
  decode?: (value: unknown) => unknown;
12
12
  }
13
13
  declare function isCompactDiagnosable(schema: any): boolean;
14
+ declare function isCompactWalkable(schema: any): boolean;
14
15
  declare class FrozenSlotValidator {
15
16
  #private;
16
17
  isAsync: boolean;
@@ -36,4 +37,4 @@ declare function mergeSchemasAllStandard(schemas: Array<Record<string, unknown>>
36
37
  declare function buildFrozenRouteValidator(hook: AnyLocalHook, root: AnyElysia, method: HTTPMethod, path: string): FrozenRouteValidatorShape | undefined;
37
38
  declare function isCapturedBridgeFree(c: CapturedValidator, schema: unknown, coerced?: unknown): boolean;
38
39
  //#endregion
39
- export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isStandardSchema, mergeSchemasAllStandard };
40
+ export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isCompactWalkable, isStandardSchema, mergeSchemasAllStandard };
@@ -55,17 +55,30 @@ const typeError = (schema, instancePath, schemaPath) => ({
55
55
  **/
56
56
  function walkCompactError(schema, value, instancePath, schemaPath) {
57
57
  if (!schema || typeof schema !== "object") return;
58
+ const elyTyp = schema["~elyTyp"];
59
+ if (schema.anyOf && (elyTyp === require_type_constants.ELYSIA_TYPES.ObjectString || elyTyp === require_type_constants.ELYSIA_TYPES.ArrayString)) {
60
+ let decoded = value;
61
+ if (typeof value === "string") try {
62
+ decoded = JSON.parse(value);
63
+ } catch {
64
+ return;
65
+ }
66
+ else if (value === void 0) return;
67
+ return walkCompactError(schema.anyOf[0], decoded, instancePath, `${schemaPath}/anyOf/0`);
68
+ }
58
69
  const type = schema.type;
59
70
  if (type === "object") {
60
71
  if (typeof value !== "object" || value === null || Array.isArray(value)) return typeError(schema, instancePath, schemaPath);
61
72
  const required = schema.required;
62
73
  if (Array.isArray(required)) {
63
- for (const key of required) if (!(key in value)) return {
74
+ let missing;
75
+ for (const key of required) if (!(key in value)) (missing ??= []).push(key);
76
+ if (missing) return {
64
77
  keyword: "required",
65
78
  schemaPath,
66
79
  instancePath,
67
- params: { requiredProperties: [key] },
68
- message: `must have required properties ${key}`
80
+ params: { requiredProperties: missing },
81
+ message: `must have required properties ${missing.join(", ")}`
69
82
  };
70
83
  }
71
84
  const properties = schema.properties;
@@ -121,6 +134,22 @@ function isCompactDiagnosable(schema) {
121
134
  if (type === "array") return isCompactDiagnosable(schema.items);
122
135
  return type === "string" || type === "number" || type === "integer" || type === "boolean" || type === "null";
123
136
  }
137
+ function isCompactWalkable(schema) {
138
+ if (!schema || typeof schema !== "object") return false;
139
+ const elyTyp = schema["~elyTyp"];
140
+ if (schema.anyOf && (elyTyp === require_type_constants.ELYSIA_TYPES.ObjectString || elyTyp === require_type_constants.ELYSIA_TYPES.ArrayString)) return isCompactWalkable(schema.anyOf[0]);
141
+ if (schema.anyOf || schema.oneOf || schema.allOf) return false;
142
+ const type = schema.type;
143
+ if (type === "object") {
144
+ const properties = schema.properties;
145
+ if (properties) {
146
+ for (const key in properties) if (!isCompactWalkable(properties[key])) return false;
147
+ }
148
+ return true;
149
+ }
150
+ if (type === "array") return isCompactWalkable(schema.items);
151
+ return type === "string" || type === "number" || type === "integer" || type === "boolean" || type === "null";
152
+ }
124
153
  var FrozenSlotValidator = class {
125
154
  #check;
126
155
  #clean;
@@ -315,5 +344,6 @@ exports.buildFrozenRouteValidator = buildFrozenRouteValidator;
315
344
  exports.isBridgeNotInitialized = isBridgeNotInitialized;
316
345
  exports.isCapturedBridgeFree = isCapturedBridgeFree;
317
346
  exports.isCompactDiagnosable = isCompactDiagnosable;
347
+ exports.isCompactWalkable = isCompactWalkable;
318
348
  exports.isStandardSchema = isStandardSchema;
319
349
  exports.mergeSchemasAllStandard = mergeSchemasAllStandard;
@@ -54,17 +54,30 @@ const typeError = (schema, instancePath, schemaPath) => ({
54
54
  **/
55
55
  function walkCompactError(schema, value, instancePath, schemaPath) {
56
56
  if (!schema || typeof schema !== "object") return;
57
+ const elyTyp = schema["~elyTyp"];
58
+ if (schema.anyOf && (elyTyp === ELYSIA_TYPES.ObjectString || elyTyp === ELYSIA_TYPES.ArrayString)) {
59
+ let decoded = value;
60
+ if (typeof value === "string") try {
61
+ decoded = JSON.parse(value);
62
+ } catch {
63
+ return;
64
+ }
65
+ else if (value === void 0) return;
66
+ return walkCompactError(schema.anyOf[0], decoded, instancePath, `${schemaPath}/anyOf/0`);
67
+ }
57
68
  const type = schema.type;
58
69
  if (type === "object") {
59
70
  if (typeof value !== "object" || value === null || Array.isArray(value)) return typeError(schema, instancePath, schemaPath);
60
71
  const required = schema.required;
61
72
  if (Array.isArray(required)) {
62
- for (const key of required) if (!(key in value)) return {
73
+ let missing;
74
+ for (const key of required) if (!(key in value)) (missing ??= []).push(key);
75
+ if (missing) return {
63
76
  keyword: "required",
64
77
  schemaPath,
65
78
  instancePath,
66
- params: { requiredProperties: [key] },
67
- message: `must have required properties ${key}`
79
+ params: { requiredProperties: missing },
80
+ message: `must have required properties ${missing.join(", ")}`
68
81
  };
69
82
  }
70
83
  const properties = schema.properties;
@@ -120,6 +133,22 @@ function isCompactDiagnosable(schema) {
120
133
  if (type === "array") return isCompactDiagnosable(schema.items);
121
134
  return type === "string" || type === "number" || type === "integer" || type === "boolean" || type === "null";
122
135
  }
136
+ function isCompactWalkable(schema) {
137
+ if (!schema || typeof schema !== "object") return false;
138
+ const elyTyp = schema["~elyTyp"];
139
+ if (schema.anyOf && (elyTyp === ELYSIA_TYPES.ObjectString || elyTyp === ELYSIA_TYPES.ArrayString)) return isCompactWalkable(schema.anyOf[0]);
140
+ if (schema.anyOf || schema.oneOf || schema.allOf) return false;
141
+ const type = schema.type;
142
+ if (type === "object") {
143
+ const properties = schema.properties;
144
+ if (properties) {
145
+ for (const key in properties) if (!isCompactWalkable(properties[key])) return false;
146
+ }
147
+ return true;
148
+ }
149
+ if (type === "array") return isCompactWalkable(schema.items);
150
+ return type === "string" || type === "number" || type === "integer" || type === "boolean" || type === "null";
151
+ }
123
152
  var FrozenSlotValidator = class {
124
153
  #check;
125
154
  #clean;
@@ -310,4 +339,4 @@ function isCapturedBridgeFree(c, schema, coerced = schema) {
310
339
  }
311
340
 
312
341
  //#endregion
313
- export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isStandardSchema, mergeSchemasAllStandard };
342
+ export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isCompactWalkable, isStandardSchema, mergeSchemasAllStandard };
@@ -1,5 +1,5 @@
1
- import { AnyLocalHook, CompiledHandler, InternalRoute } from "../../types.js";
2
1
  import { ChainNode } from "../../utils.js";
2
+ import { AnyLocalHook, CompiledHandler, InternalRoute } from "../../types.js";
3
3
  import { AnyElysia } from "../../base.js";
4
4
  import { setCaptureHeaderShorthand } from "./jit.js";
5
5
 
@@ -12,8 +12,8 @@ declare function resolveWSLocalHook(scope: AnyElysia, hook: Partial<AnyLocalHook
12
12
  */
13
13
  declare function clearHandlerAnalysisCaches(root: AnyElysia): void;
14
14
  declare const localMacroRoot: (instance: AnyElysia, root: AnyElysia) => AnyElysia;
15
- declare function buildNativeStaticResponse([,, handler, instance, localHook, appHook, inheritedChain, macroScope]: InternalRoute, root: AnyElysia): Response | undefined;
15
+ declare function buildNativeStaticResponse(route: InternalRoute, root: AnyElysia): Response | undefined;
16
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 compileHandler([_method, path, handler, instance, localHook, appHook, inheritedChain, macroScope]: InternalRoute, root: AnyElysia, precomputedStatic?: Response): CompiledHandler;
17
+ declare function compileHandler(route: InternalRoute, root: AnyElysia, precomputedStatic?: Response): CompiledHandler;
18
18
  //#endregion
19
19
  export { buildNativeStaticResponse, clearHandlerAnalysisCaches, compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook, resolveWSLocalHook, setCaptureHeaderShorthand };
@@ -198,10 +198,10 @@ function resolveChainNode(root, node) {
198
198
  }
199
199
  return resolved;
200
200
  }
201
- const chainResolver = (root) => {
201
+ function chainResolver(root) {
202
202
  const frozenRoot = require_generation.frozenRootOf(root);
203
203
  return frozenRoot["~ext"]?.macro || frozenRoot["~scopeChildren"] ? (node) => resolveChainNode(root, node) : void 0;
204
- };
204
+ }
205
205
  const localMacroRoot = (instance, root) => instance !== root && instance["~scopeChild"] === true && require_generation.frozenRootOf(instance)["~ext"]?.macro ? instance : root;
206
206
  function composeRootHook(root, inheritedChain) {
207
207
  const resolve = chainResolver(root);
@@ -211,7 +211,8 @@ function composeRootHook(root, inheritedChain) {
211
211
  if (!locals) return inherited;
212
212
  return require_utils.mergeHook(inherited, locals);
213
213
  }
214
- function buildNativeStaticResponse([, , handler, instance, localHook, appHook, inheritedChain, macroScope], root) {
214
+ function buildNativeStaticResponse(route, root) {
215
+ const [, , handler, instance, localHook, appHook, inheritedChain, macroScope] = route;
215
216
  if (typeof handler === "function" || handler instanceof Error || handler instanceof Promise) return;
216
217
  const frozenRoot = require_generation.frozenRootOf(root);
217
218
  const adapter = frozenRoot["~config"]?.adapter ?? require_adapter_constants.defaultAdapter;
@@ -273,7 +274,8 @@ function isContextFreeHandler(handler) {
273
274
  const source = Function.prototype.toString.call(handler);
274
275
  return isBareArrow.test(source) && !isSucroseOpaque.test(source);
275
276
  }
276
- function compileHandler([_method, path, handler, instance, localHook, appHook, inheritedChain, macroScope], root, precomputedStatic) {
277
+ function compileHandler(route, root, precomputedStatic) {
278
+ let [_method, path, handler, instance, localHook, appHook, inheritedChain, macroScope] = route;
277
279
  const frozenRoot = require_generation.frozenRootOf(root);
278
280
  const adapter = frozenRoot["~config"]?.adapter ?? require_adapter_constants.defaultAdapter;
279
281
  const method = _method;