elysia 2.0.0-beta.21 → 2.0.0-beta.22

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 (215) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +1 -0
  2. package/dist/adapter/bun/index.d.ts +6 -8
  3. package/dist/adapter/bun/index.js +6 -8
  4. package/dist/adapter/bun/index.mjs +7 -8
  5. package/dist/adapter/constants.mjs +1 -0
  6. package/dist/adapter/default-headers.mjs +1 -0
  7. package/dist/adapter/index.mjs +1 -0
  8. package/dist/adapter/origin.mjs +1 -0
  9. package/dist/adapter/response-ownership.mjs +1 -0
  10. package/dist/adapter/skip-clone.mjs +1 -0
  11. package/dist/adapter/types.mjs +1 -0
  12. package/dist/adapter/utils.d.ts +5 -8
  13. package/dist/adapter/utils.js +24 -18
  14. package/dist/adapter/utils.mjs +25 -18
  15. package/dist/adapter/web-standard/handler.mjs +2 -1
  16. package/dist/adapter/web-standard/index.mjs +1 -0
  17. package/dist/adapter/web-standard/utils.mjs +1 -0
  18. package/dist/base.d.ts +118 -69
  19. package/dist/base.js +213 -193
  20. package/dist/base.mjs +220 -199
  21. package/dist/compile/aot-capture.js +2 -2
  22. package/dist/compile/aot-capture.mjs +4 -3
  23. package/dist/compile/aot-emit.js +7 -8
  24. package/dist/compile/aot-emit.mjs +8 -8
  25. package/dist/compile/aot-reconstruct.mjs +3 -2
  26. package/dist/compile/aot.d.ts +3 -3
  27. package/dist/compile/aot.js +5 -5
  28. package/dist/compile/aot.mjs +6 -5
  29. package/dist/compile/handler/descriptor.d.ts +2 -5
  30. package/dist/compile/handler/descriptor.js +12 -17
  31. package/dist/compile/handler/descriptor.mjs +16 -21
  32. package/dist/compile/handler/frozen-validator.d.ts +2 -2
  33. package/dist/compile/handler/frozen-validator.js +3 -3
  34. package/dist/compile/handler/frozen-validator.mjs +4 -3
  35. package/dist/compile/handler/index.d.ts +3 -1
  36. package/dist/compile/handler/index.js +77 -118
  37. package/dist/compile/handler/index.mjs +83 -125
  38. package/dist/compile/handler/jit.d.ts +12 -12
  39. package/dist/compile/handler/jit.js +60 -43
  40. package/dist/compile/handler/jit.mjs +63 -47
  41. package/dist/compile/handler/params.d.ts +5 -1
  42. package/dist/compile/handler/params.js +14 -5
  43. package/dist/compile/handler/params.mjs +16 -7
  44. package/dist/compile/handler/reconstruct.d.ts +2 -2
  45. package/dist/compile/handler/reconstruct.js +2 -2
  46. package/dist/compile/handler/reconstruct.mjs +3 -2
  47. package/dist/compile/handler/static-clone-resolver.mjs +1 -0
  48. package/dist/compile/handler/utils.d.ts +13 -7
  49. package/dist/compile/handler/utils.js +75 -52
  50. package/dist/compile/handler/utils.mjs +77 -54
  51. package/dist/compile/jit-probe.mjs +1 -0
  52. package/dist/compile/lexer.js +4 -4
  53. package/dist/compile/lexer.mjs +5 -4
  54. package/dist/compile/utils.d.ts +2 -1
  55. package/dist/compile/utils.js +8 -3
  56. package/dist/compile/utils.mjs +8 -3
  57. package/dist/compiled.mjs +1 -0
  58. package/dist/constants.mjs +1 -0
  59. package/dist/context.d.ts +1 -1
  60. package/dist/context.js +1 -0
  61. package/dist/context.mjs +3 -1
  62. package/dist/cookie/config.d.ts +2 -2
  63. package/dist/cookie/config.js +21 -26
  64. package/dist/cookie/config.mjs +22 -26
  65. package/dist/cookie/cookie.mjs +1 -0
  66. package/dist/cookie/crypto.mjs +1 -0
  67. package/dist/cookie/error.mjs +1 -0
  68. package/dist/cookie/lib.mjs +1 -0
  69. package/dist/cookie/serialize.mjs +1 -0
  70. package/dist/cookie/types.mjs +1 -0
  71. package/dist/cookie/utils.d.ts +1 -1
  72. package/dist/cookie/utils.js +64 -45
  73. package/dist/cookie/utils.mjs +66 -46
  74. package/dist/error.d.ts +10 -6
  75. package/dist/error.js +22 -6
  76. package/dist/error.mjs +25 -9
  77. package/dist/generation.mjs +1 -0
  78. package/dist/handler/error.d.ts +12 -15
  79. package/dist/handler/error.js +43 -40
  80. package/dist/handler/error.mjs +45 -41
  81. package/dist/handler/fetch.js +59 -21
  82. package/dist/handler/fetch.mjs +61 -22
  83. package/dist/handler/utils.d.ts +16 -3
  84. package/dist/handler/utils.js +14 -13
  85. package/dist/handler/utils.mjs +16 -15
  86. package/dist/index.d.ts +9 -9
  87. package/dist/index.js +1 -0
  88. package/dist/index.mjs +3 -2
  89. package/dist/memory.mjs +1 -0
  90. package/dist/package.js +1 -1
  91. package/dist/package.mjs +2 -1
  92. package/dist/parse-query.js +76 -76
  93. package/dist/parse-query.mjs +77 -76
  94. package/dist/plugin/aot/bun.mjs +1 -0
  95. package/dist/plugin/aot/core.js +7 -4
  96. package/dist/plugin/aot/core.mjs +8 -5
  97. package/dist/plugin/aot/esbuild.mjs +1 -0
  98. package/dist/plugin/aot/rspack-loader.mjs +1 -0
  99. package/dist/plugin/aot/rspack.mjs +1 -0
  100. package/dist/plugin/aot/treeshake.mjs +1 -0
  101. package/dist/plugin/aot/unplugin.mjs +4 -3
  102. package/dist/plugin/aot/vite.mjs +1 -0
  103. package/dist/plugin/aot/worker.mjs +1 -0
  104. package/dist/plugin/auto-head.mjs +1 -0
  105. package/dist/plugin/trace.mjs +1 -0
  106. package/dist/plugin/websocket.mjs +1 -0
  107. package/dist/route-table.mjs +1 -0
  108. package/dist/schema-snapshot.mjs +1 -0
  109. package/dist/sucrose.d.ts +2 -2
  110. package/dist/sucrose.js +11 -11
  111. package/dist/sucrose.mjs +12 -11
  112. package/dist/trace.js +8 -10
  113. package/dist/trace.mjs +10 -11
  114. package/dist/type/bridge-live.d.ts +1 -1
  115. package/dist/type/bridge-live.mjs +1 -0
  116. package/dist/type/bridge.d.ts +1 -1
  117. package/dist/type/bridge.mjs +1 -0
  118. package/dist/type/coerce-plan.mjs +1 -0
  119. package/dist/type/coerce.d.ts +1 -1
  120. package/dist/type/coerce.mjs +1 -0
  121. package/dist/type/compat.mjs +1 -0
  122. package/dist/type/constants.d.ts +1 -1
  123. package/dist/type/constants.mjs +1 -0
  124. package/dist/type/elysia/accelerate.mjs +1 -0
  125. package/dist/type/elysia/array-buffer.d.ts +3 -2
  126. package/dist/type/elysia/array-buffer.js +5 -5
  127. package/dist/type/elysia/array-buffer.mjs +6 -5
  128. package/dist/type/elysia/array-string.mjs +1 -0
  129. package/dist/type/elysia/array.mjs +1 -0
  130. package/dist/type/elysia/boolean-string.mjs +1 -0
  131. package/dist/type/elysia/boolean.mjs +1 -0
  132. package/dist/type/elysia/cookie.mjs +1 -0
  133. package/dist/type/elysia/date.mjs +1 -0
  134. package/dist/type/elysia/file-type.mjs +1 -0
  135. package/dist/type/elysia/file.mjs +1 -0
  136. package/dist/type/elysia/files.mjs +1 -0
  137. package/dist/type/elysia/form.mjs +1 -0
  138. package/dist/type/elysia/integer-string.mjs +1 -0
  139. package/dist/type/elysia/integer.mjs +1 -0
  140. package/dist/type/elysia/intersect.mjs +1 -0
  141. package/dist/type/elysia/json-string.mjs +1 -0
  142. package/dist/type/elysia/keep-config.js +8 -8
  143. package/dist/type/elysia/keep-config.mjs +9 -8
  144. package/dist/type/elysia/maybe-empty.mjs +1 -0
  145. package/dist/type/elysia/no-validate.mjs +1 -0
  146. package/dist/type/elysia/nullable.mjs +1 -0
  147. package/dist/type/elysia/number.mjs +1 -0
  148. package/dist/type/elysia/numeric-enum.d.ts +4 -2
  149. package/dist/type/elysia/numeric-enum.mjs +1 -0
  150. package/dist/type/elysia/numeric.mjs +1 -0
  151. package/dist/type/elysia/object-string.mjs +1 -0
  152. package/dist/type/elysia/object.mjs +1 -0
  153. package/dist/type/elysia/optional.mjs +1 -0
  154. package/dist/type/elysia/problem.mjs +1 -0
  155. package/dist/type/elysia/string.mjs +1 -0
  156. package/dist/type/elysia/uint8-array.d.ts +2 -1
  157. package/dist/type/elysia/uint8-array.js +2 -2
  158. package/dist/type/elysia/uint8-array.mjs +3 -2
  159. package/dist/type/elysia/union-enum.mjs +1 -0
  160. package/dist/type/elysia/union.mjs +1 -0
  161. package/dist/type/elysia/utils.js +3 -3
  162. package/dist/type/elysia/utils.mjs +4 -3
  163. package/dist/type/exports.mjs +1 -0
  164. package/dist/type/index.mjs +2 -1
  165. package/dist/type/shared.mjs +1 -0
  166. package/dist/type/sync-require.mjs +1 -0
  167. package/dist/type/typebox-system-lite.mjs +1 -0
  168. package/dist/type/typebox-system-require.mjs +1 -0
  169. package/dist/type/typebox-type-live.mjs +1 -0
  170. package/dist/type/typebox-value-live.mjs +1 -0
  171. package/dist/type/typebox-value-ops.mjs +1 -0
  172. package/dist/type/typebox-value.mjs +1 -0
  173. package/dist/type/types.d.ts +1 -1
  174. package/dist/type/types.mjs +1 -0
  175. package/dist/type/utils.mjs +1 -0
  176. package/dist/type/validator/clean-safe.mjs +1 -0
  177. package/dist/type/validator/custom-error.js +41 -33
  178. package/dist/type/validator/custom-error.mjs +42 -33
  179. package/dist/type/validator/default-precompute.d.ts +2 -2
  180. package/dist/type/validator/default-precompute.js +10 -11
  181. package/dist/type/validator/default-precompute.mjs +13 -13
  182. package/dist/type/validator/exact-mirror.mjs +1 -0
  183. package/dist/type/validator/frozen-check.js +7 -7
  184. package/dist/type/validator/frozen-check.mjs +8 -7
  185. package/dist/type/validator/index.d.ts +2 -2
  186. package/dist/type/validator/index.js +4 -8
  187. package/dist/type/validator/index.mjs +5 -8
  188. package/dist/type/validator/string-codec-aot.d.ts +1 -1
  189. package/dist/type/validator/string-codec-aot.mjs +1 -0
  190. package/dist/type/validator/validator-cache.js +18 -18
  191. package/dist/type/validator/validator-cache.mjs +19 -18
  192. package/dist/types.d.ts +105 -69
  193. package/dist/types.mjs +1 -0
  194. package/dist/universal/constants.mjs +1 -0
  195. package/dist/universal/file.mjs +1 -0
  196. package/dist/universal/index.mjs +1 -0
  197. package/dist/universal/is-production.mjs +1 -0
  198. package/dist/universal/server.mjs +1 -0
  199. package/dist/utils.d.ts +49 -31
  200. package/dist/utils.js +221 -109
  201. package/dist/utils.mjs +215 -106
  202. package/dist/validator/index.d.ts +3 -3
  203. package/dist/validator/index.js +4 -4
  204. package/dist/validator/index.mjs +5 -4
  205. package/dist/validator/route.d.ts +2 -2
  206. package/dist/validator/route.mjs +1 -0
  207. package/dist/ws/context.js +1 -1
  208. package/dist/ws/context.mjs +2 -1
  209. package/dist/ws/index.mjs +1 -0
  210. package/dist/ws/parser.mjs +1 -0
  211. package/dist/ws/route.js +34 -25
  212. package/dist/ws/route.mjs +40 -30
  213. package/dist/ws/types.d.ts +2 -3
  214. package/dist/ws/types.mjs +1 -0
  215. package/package.json +2 -2
package/dist/base.js CHANGED
@@ -6,6 +6,7 @@ const require_type_bridge = require('./type/bridge.js');
6
6
  const require_universal_is_production = require('./universal/is-production.js');
7
7
  const require_compile_aot = require('./compile/aot.js');
8
8
  const require_generation = require('./generation.js');
9
+ const require_compile_handler_descriptor = require('./compile/handler/descriptor.js');
9
10
  const require_compile_handler_index = require('./compile/handler/index.js');
10
11
  const require_route_table = require('./route-table.js');
11
12
  const require_adapter_bun_index = require('./adapter/bun/index.js');
@@ -17,6 +18,9 @@ memoirist = require_runtime.__toESM(memoirist);
17
18
 
18
19
  //#region src/base.ts
19
20
  const useNodesBuffer = [];
21
+ const propagatedRegistrations = /* @__PURE__ */ new WeakMap();
22
+ const liftedRequests = /* @__PURE__ */ new WeakMap();
23
+ const hocOriginOf = (o) => typeof o === "object" ? o.origin : o;
20
24
  const emptyHistory = Object.freeze([]);
21
25
  let mutationEpoch = 0;
22
26
  const extCallbackIndexes = /* @__PURE__ */ new WeakMap();
@@ -42,6 +46,13 @@ const markStoredSingletons = (table, source) => {
42
46
  if (!table) return;
43
47
  for (const key in source) require_utils.markSingletons(table[key]);
44
48
  };
49
+ const sharedTables = [
50
+ "decorator",
51
+ "store",
52
+ "headers",
53
+ "models",
54
+ "parser"
55
+ ];
45
56
  const canRegisterLoose = (path, isDynamic) => !isDynamic && (path.length === 0 || path.charCodeAt(path.length - 1) === 47);
46
57
  const isSingleSchema = (value) => "~kind" in value || "~elyAcl" in value || "~standard" in value;
47
58
  const isSchemaValue = (value) => {
@@ -108,6 +119,7 @@ function expandPaths(path, needsEncode, registerLoose, explicit) {
108
119
  return paths;
109
120
  }
110
121
  var Elysia = class Elysia {
122
+ #pending = 0;
111
123
  get history() {
112
124
  const generation = this["~generation"];
113
125
  if (this.#isCacheable && this.cachedGeneration === generation && this.cachedEpoch === mutationEpoch && this.cachedHistory !== void 0) return this.cachedHistory;
@@ -161,8 +173,6 @@ var Elysia = class Elysia {
161
173
  return this;
162
174
  }
163
175
  constructor(config) {
164
- this._pending = 0;
165
- this.routerBuilt = false;
166
176
  /**
167
177
  * ! Don't tune
168
178
  *
@@ -208,7 +218,7 @@ var Elysia = class Elysia {
208
218
  if (config) {
209
219
  const { prefix, name, seed, adapter } = config;
210
220
  this["~Prefix"] = prefix ? prefix.charCodeAt(0) === 47 ? prefix : `/${prefix}` : void 0;
211
- if (name) this.hash = require_utils.fnv1a(seed ? `${name}_${typeof seed === "object" ? JSON.stringify(seed, require_utils.serializeMacroSeed) : seed}` : name);
221
+ if (name) this.hash = require_utils.pluginHash(JSON.stringify(seed === void 0 ? [name] : [name, seed], require_utils.serializeMacroSeed));
212
222
  if (adapter?.setup) this.#useFn(adapter.setup);
213
223
  } else this["~Prefix"] = void 0;
214
224
  }
@@ -224,6 +234,7 @@ var Elysia = class Elysia {
224
234
  if (!this.declaredRoutes?.length) return [];
225
235
  const routes = this["~routes"].map(([method, path, handler, instance, hook, appHook, inheritedChain, macroScope]) => {
226
236
  const merged = require_compile_handler_index.composeRouteHook(instance, hook, appHook, inheritedChain, this, macroScope);
237
+ require_compile_handler_index.runIntrospect(merged);
227
238
  if (merged?.schemas?.length) for (const entry of merged.schemas) {
228
239
  if (!entry?.response) continue;
229
240
  merged.response = require_utils.mergeResponse(merged.response, entry.response);
@@ -246,10 +257,10 @@ var Elysia = class Elysia {
246
257
  decorate(typeOrNameOrDecorators, nameOrDecorators, value) {
247
258
  return this.#setField("decorator", arguments.length, typeOrNameOrDecorators, nameOrDecorators, value);
248
259
  }
249
- #setField(field, length, typeOrName, nameOrValue, value) {
260
+ #setField(field, argCount, typeOrName, nameOrValue, value) {
250
261
  let as = "append";
251
262
  let name = "";
252
- switch (length) {
263
+ switch (argCount) {
253
264
  case 1:
254
265
  value = typeOrName;
255
266
  break;
@@ -264,10 +275,11 @@ var Elysia = class Elysia {
264
275
  break;
265
276
  default: return this;
266
277
  }
267
- this.#assertMutable(field === "store" ? "state" : "decorate");
268
- const ext = this.ext;
269
- const fresh = !ext[field];
270
- const target = ext[field] ??= require_utils.nullObject();
278
+ this.#assertTableMutable(field === "store" ? "state" : "decorate");
279
+ const ext = this.#ext;
280
+ let fresh = true;
281
+ for (let app = this; fresh && app; app = app.scopeParent) fresh = !app["~ext"]?.[field];
282
+ const target = this.#table(field);
271
283
  switch (typeof value) {
272
284
  case "object":
273
285
  if (!value) return this;
@@ -303,9 +315,8 @@ var Elysia = class Elysia {
303
315
  return this.#setField("store", arguments.length, typeOrNameOrStore, nameOrStore, value);
304
316
  }
305
317
  headers(headers) {
306
- this.#assertMutable("headers");
307
- const ext = this.ext;
308
- ext.headers = Object.assign(ext.headers ?? require_utils.nullObject(), headers);
318
+ this.#assertTableMutable("headers");
319
+ Object.assign(this.#table("headers"), headers);
309
320
  return this;
310
321
  }
311
322
  #on(type, fn, scope = this["~config"]?.as) {
@@ -314,32 +325,30 @@ var Elysia = class Elysia {
314
325
  const added = require_utils.nullObject();
315
326
  added[type] = fn;
316
327
  if (type === "trace") this["~hasTrace"] = true;
317
- this.#link(added, scope, this);
318
- this.#tagOrigin(fn);
328
+ this.#pushChainNode(added, scope);
319
329
  return this;
320
330
  }
321
- #link(added, scope, owner, mayRef = true, propagated) {
331
+ #pushChainNode(added, scope, registration, origin, owner) {
322
332
  const parent = this["~hookChain"];
323
- const refs = parent !== void 0 && parent.refs || mayRef && Elysia.#hookHasString(added);
324
- this["~hookChain"] = propagated ? {
333
+ const refs = parent !== void 0 && parent.refs || Elysia.#hookHasString(added);
334
+ this["~hookChain"] = registration ? {
325
335
  added,
326
336
  parent,
327
337
  refs,
328
338
  scope,
329
- propagated,
330
- owner
339
+ propagated: true,
340
+ owner,
341
+ origin,
342
+ registration
331
343
  } : {
332
344
  added,
333
345
  parent,
334
346
  refs,
335
347
  scope,
336
- owner
348
+ owner: this,
349
+ origin: this.hash
337
350
  };
338
351
  }
339
- #tagOrigin(value) {
340
- if (this.hash === void 0) return;
341
- for (const fn of Array.isArray(value) ? value : [value]) if (typeof fn === "function" && !require_utils.fnOrigin.has(fn)) require_utils.fnOrigin.set(fn, this.hash);
342
- }
343
352
  #onBranch(type, scopeOrFn, fn) {
344
353
  return fn ? this.#on(type, fn, scopeOrFn) : this.#on(type, scopeOrFn);
345
354
  }
@@ -354,9 +363,8 @@ var Elysia = class Elysia {
354
363
  return this.#onBranch("parse", scopeOrFnOrName, fn);
355
364
  }
356
365
  parser(name, fn) {
357
- this.#assertMutable("parser");
358
- const ext = this.ext;
359
- const parsers = ext.parser ??= require_utils.nullObject();
366
+ this.#assertTableMutable("parser");
367
+ const parsers = this.#table("parser");
360
368
  parsers[name] = fn;
361
369
  return this;
362
370
  }
@@ -376,7 +384,7 @@ var Elysia = class Elysia {
376
384
  */
377
385
  setup(handler) {
378
386
  this.#assertMutable("setup");
379
- (this.ext.setup ??= []).push(...[].concat(handler));
387
+ (this.#ext.setup ??= []).push(...[].concat(handler));
380
388
  return this;
381
389
  }
382
390
  transform(scopeOrFn, fn) {
@@ -415,13 +423,13 @@ var Elysia = class Elysia {
415
423
  if (scopeOrFnOrError && typeof scopeOrFnOrError === "object") return this;
416
424
  return this.#onBranch("error", scopeOrFnOrError);
417
425
  case 2:
418
- if (typeof scopeOrFnOrError === "function" && scopeOrFnOrError.prototype instanceof Object) return this.#errorClass(scopeOrFnOrError, fnOrError);
426
+ if (typeof scopeOrFnOrError === "function" && scopeOrFnOrError.prototype instanceof Object) return this.#onErrorClass(scopeOrFnOrError, fnOrError);
419
427
  return this.#onBranch("error", scopeOrFnOrError, fnOrError);
420
- case 3: return this.#errorClass(fnOrError, fn, scopeOrFnOrError);
428
+ case 3: return this.#onErrorClass(fnOrError, fn, scopeOrFnOrError);
421
429
  }
422
430
  return this;
423
431
  }
424
- #errorClass(ErrorClass, fn, scope) {
432
+ #onErrorClass(ErrorClass, fn, scope) {
425
433
  const run = typeof fn === "function" ? fn : () => fn;
426
434
  return this.#on("error", require_utils.createErrorEventHandler(run, ErrorClass), scope);
427
435
  }
@@ -440,9 +448,10 @@ var Elysia = class Elysia {
440
448
  node = node.over;
441
449
  continue;
442
450
  }
443
- if (node.scope !== "global") {
451
+ if (node.scope !== "global" && (node.scope !== scope || node.propagated)) {
444
452
  node.scope = scope;
445
453
  node.propagated = false;
454
+ require_utils.invalidateMacroEpoch();
446
455
  }
447
456
  node = node.parent;
448
457
  }
@@ -462,13 +471,11 @@ var Elysia = class Elysia {
462
471
  if (hook) assertSchemaShape(hook, ".guard()");
463
472
  hook = require_schema_snapshot.snapshotHookSchemas(hook);
464
473
  require_utils.hookToGuard(hook);
465
- for (const key in hook) if (require_utils.eventProperties.has(key)) this.#tagOrigin(hook[key]);
466
- this.#tagOrigin(hook.derive);
467
474
  this.#pushHook(hook, scope);
468
475
  return this;
469
476
  }
470
477
  group() {
471
- this.#assertMutable("group");
478
+ this.#assertTableMutable("group");
472
479
  const prefix = arguments[0];
473
480
  const schemaOrRun = arguments[1];
474
481
  const run = arguments[2];
@@ -487,12 +494,8 @@ var Elysia = class Elysia {
487
494
  const src = this["~ext"];
488
495
  if (src) {
489
496
  const ext = child["~ext"] ??= require_utils.nullObject();
490
- if (src.decorator) ext.decorator = Object.assign(require_utils.nullObject(), src.decorator);
491
- if (src.store) ext.store = Object.assign(require_utils.nullObject(), src.store);
492
- if (src.headers) ext.headers = Object.assign(require_utils.nullObject(), src.headers);
493
- if (src.models) ext.models = Object.assign(require_utils.nullObject(), src.models);
497
+ for (const field of sharedTables) if (src[field]) ext[field] = src[field];
494
498
  if (src.macro) ext.macro = Object.create(src.macro);
495
- if (src.parser) ext.parser = Object.assign(require_utils.nullObject(), src.parser);
496
499
  if (src.capability) {
497
500
  const cap = ext.capability = require_utils.nullObject();
498
501
  if (src.capability.trace) cap.trace = src.capability.trace;
@@ -505,9 +508,13 @@ var Elysia = class Elysia {
505
508
  this.#use(child);
506
509
  return this;
507
510
  }
508
- get ext() {
511
+ get #ext() {
509
512
  return this["~ext"] ??= require_utils.nullObject();
510
513
  }
514
+ /** A group child starts or takes up its parent's table, see `group()` */
515
+ #table(field) {
516
+ return this.#ext[field] ??= this.scopeParent ? this.scopeParent.#table(field) : require_utils.nullObject();
517
+ }
511
518
  ["~resolvedCapability"](kind) {
512
519
  if (kind === "ws") {
513
520
  const ws = this["~ext"]?.capability?.ws;
@@ -524,7 +531,7 @@ var Elysia = class Elysia {
524
531
  return provider;
525
532
  }
526
533
  #ensureMacroTable() {
527
- const ext = this.ext;
534
+ const ext = this.#ext;
528
535
  if (ext.macro) return ext.macro;
529
536
  const parent = this["~scopeChild"] ? this.scopeParent : void 0;
530
537
  ext.macro = parent ? Object.create(parent.#ensureMacroTable()) : require_utils.nullObject();
@@ -543,7 +550,7 @@ var Elysia = class Elysia {
543
550
  }
544
551
  }
545
552
  if (hook.trace) this["~hasTrace"] = true;
546
- this.#link(hook, scope, this);
553
+ this.#pushChainNode(hook, scope);
547
554
  return this;
548
555
  }
549
556
  macro(macro, definition) {
@@ -580,7 +587,7 @@ var Elysia = class Elysia {
580
587
  const seedSource = hook.seed ?? value;
581
588
  const seedType = typeof seedSource;
582
589
  let seedKey;
583
- if (seedSource === null || seedType !== "object") seedKey = key + "\0" + seedType + "\0" + String(seedSource);
590
+ if (seedSource === null || seedType !== "object") seedKey = `${key}\0${seedType}\0${require_utils.serializeMacroSeed("", seedSource)}`;
584
591
  else try {
585
592
  seedKey = key + "\0object\0" + JSON.stringify(seedSource, require_utils.serializeMacroSeed);
586
593
  } catch {
@@ -597,7 +604,7 @@ var Elysia = class Elysia {
597
604
  const v = hook[k];
598
605
  if (k === "seed" || k === "meta" || k === "$type") continue;
599
606
  if (k === "introspect") {
600
- v?.(input);
607
+ if (v) (input["~introspect"] ??= []).push(v);
601
608
  delete input[key];
602
609
  continue;
603
610
  }
@@ -633,15 +640,9 @@ var Elysia = class Elysia {
633
640
  if (require_utils.eventProperties.has(k) || k === "derive") {
634
641
  const incoming = Array.isArray(v) ? v : [v];
635
642
  const existing = k in input ? Array.isArray(input[k]) ? input[k] : [input[k]] : [];
636
- const added = [];
637
- for (const fn of incoming) if (!existing.includes(fn) && !added.includes(fn)) added.push(fn);
638
643
  const at = insertions.get(k) ?? 0;
639
- input[k] = [
640
- ...existing.slice(0, at),
641
- ...added,
642
- ...existing.slice(at)
643
- ];
644
- insertions.set(k, at + added.length);
644
+ input[k] = existing.toSpliced(at, 0, ...incoming);
645
+ insertions.set(k, at + incoming.length);
645
646
  } else if (k in input) {
646
647
  if (Array.isArray(input[k])) {
647
648
  for (const item of Array.isArray(v) ? v : [v]) if (!input[k].includes(item)) input[k].unshift(item);
@@ -654,7 +655,7 @@ var Elysia = class Elysia {
654
655
  }
655
656
  use(app) {
656
657
  if (!app) return this;
657
- this.#assertMutable("use");
658
+ this.#assertTableMutable("use");
658
659
  if (typeof app === "function") return this.#useFn(app);
659
660
  if (typeof app.then === "function") return this.#useAsync(app);
660
661
  if (Array.isArray(app)) {
@@ -667,6 +668,9 @@ var Elysia = class Elysia {
667
668
  this.#use(app);
668
669
  return this;
669
670
  }
671
+ has(plugin) {
672
+ return this.childrenHash?.has(plugin.hash ?? require_utils.pluginId(plugin)) ?? false;
673
+ }
670
674
  #useFn(app) {
671
675
  const prevBaseline = this.macroBaseline;
672
676
  const baseline = /* @__PURE__ */ new Set();
@@ -708,14 +712,15 @@ var Elysia = class Elysia {
708
712
  const config = app["~config"];
709
713
  if (app["~introspect"] || config?.introspect) this["~introspect"] = true;
710
714
  const name = config?.name;
711
- if (name) {
712
- const hash = app.hash;
713
- if (this.childrenHash?.has(hash)) return;
715
+ const childKey = name ? app.hash : require_utils.pluginId(app);
716
+ const exists = this.childrenHash?.has(childKey);
717
+ if (name && exists) return;
718
+ if (!exists) {
714
719
  this.childrenHash ??= /* @__PURE__ */ new Set();
715
- this.childrenHash.add(hash);
716
- (addedByThisCall ??= /* @__PURE__ */ new Set()).add(hash);
720
+ this.childrenHash.add(childKey);
721
+ (addedByThisCall ??= /* @__PURE__ */ new Set()).add(childKey);
717
722
  }
718
- if (app.childrenHash) addedByThisCall = this.#absorbChildrenHash(app, addedByThisCall);
723
+ if (app.childrenHash && !app["~scopeChild"]) addedByThisCall = this.#absorbChildrenHash(app, addedByThisCall);
719
724
  if (app["~ext"]) this.#assertMacroUnique(app, addedByThisCall);
720
725
  if (app["~hasTrace"]) this["~hasTrace"] = true;
721
726
  if (app.declaredRoutes === void 0 && app["~routeTable"]?.length) app.#materializeDeclaredRoutes();
@@ -728,20 +733,17 @@ var Elysia = class Elysia {
728
733
  for (const child of app["~scopeChildren"]) children.push(child);
729
734
  }
730
735
  const hookChain = app["~hookChain"];
731
- if (app["~ext"]) this.#absorbExt(app);
736
+ if (app["~ext"]) this.#absorbExt(app, addedByThisCall);
732
737
  if (hookChain) this.#propagateHooks(app, hookChain, addedByThisCall);
733
738
  }
734
739
  #absorbChildrenHash(app, addedByThisCall) {
735
- const incoming = app.childrenHash;
736
- if (this.childrenHash) for (const h of incoming) {
737
- if (this.childrenHash.has(h)) continue;
738
- this.childrenHash.add(h);
740
+ const childrenHash = this.childrenHash;
741
+ for (let h of app.childrenHash) {
742
+ if (typeof h === "object") h = require_utils.pluginId(h);
743
+ if (childrenHash.has(h)) continue;
744
+ childrenHash.add(h);
739
745
  (addedByThisCall ??= /* @__PURE__ */ new Set()).add(h);
740
746
  }
741
- else {
742
- this.childrenHash = new Set(incoming);
743
- addedByThisCall = new Set(incoming);
744
- }
745
747
  return addedByThisCall;
746
748
  }
747
749
  /**
@@ -770,22 +772,26 @@ var Elysia = class Elysia {
770
772
  *
771
773
  * Keep the cold blocks in their own frames.
772
774
  */
773
- #absorbExt(app) {
774
- const { decorator, store, headers, models, parser, macro, hoc, setup, cleanup, capability } = app["~ext"];
775
+ #absorbExt(app, addedByThisCall) {
776
+ const source = app["~ext"];
777
+ const { decorator, store, headers, models, parser, macro, hoc, setup, cleanup, capability } = source;
775
778
  const ext = this["~ext"] ??= require_utils.nullObject();
776
- if (decorator) {
779
+ if (app.scopeParent === this) {
780
+ for (const field of sharedTables) if (source[field]) ext[field] ??= source[field];
781
+ }
782
+ if (decorator && decorator !== ext.decorator) {
777
783
  if (ext.decorator) require_utils.mergeDeep(ext.decorator, decorator, void 0, true, false, void 0, { map: void 0 });
778
784
  else ext.decorator = require_utils.clonePlainDecorators(decorator);
779
785
  markStoredSingletons(ext.decorator, decorator);
780
786
  }
781
- if (store) {
787
+ if (store && store !== ext.store) {
782
788
  if (ext.store) require_utils.mergeDeep(ext.store, store);
783
789
  else ext.store = Object.assign(require_utils.nullObject(), store);
784
790
  markStoredSingletons(ext.store, store);
785
791
  }
786
- if (headers) ext.headers = Object.assign(ext.headers ?? require_utils.nullObject(), headers);
787
- if (models) ext.models = Object.assign(ext.models ?? require_utils.nullObject(), models);
788
- if (parser) ext.parser = Object.assign(ext.parser ?? require_utils.nullObject(), parser);
792
+ if (headers && headers !== ext.headers) ext.headers = Object.assign(ext.headers ?? require_utils.nullObject(), headers);
793
+ if (models && models !== ext.models) ext.models = Object.assign(ext.models ?? require_utils.nullObject(), models);
794
+ if (parser && parser !== ext.parser) ext.parser = Object.assign(ext.parser ?? require_utils.nullObject(), parser);
789
795
  if (macro) if (app["~scopeChild"]) {
790
796
  const pluginMacros = app.pluginMacros;
791
797
  let changed = false;
@@ -806,7 +812,20 @@ var Elysia = class Elysia {
806
812
  }
807
813
  require_utils.invalidateMacroEpoch();
808
814
  }
809
- if (hoc) ext.hoc = mergeExtCallbacks(ext.hoc, hoc);
815
+ if (hoc) {
816
+ const childrenHash = this.childrenHash;
817
+ const target = ext.hoc ??= [];
818
+ const origins = ext.hocOrigin ??= [];
819
+ for (let i = 0; i < hoc.length; i++) {
820
+ const fn = hoc[i];
821
+ const registration = source.hocOrigin?.[i] ?? app.hash;
822
+ const origin = typeof registration === "object" ? registration.origin ??= app.hash : registration;
823
+ if (origin !== void 0 && childrenHash.has(origin) && !addedByThisCall?.has(origin)) continue;
824
+ if (target.some((f, j) => f === fn && hocOriginOf(origins[j]) === origin)) continue;
825
+ origins.push(registration);
826
+ target.push(fn);
827
+ }
828
+ }
810
829
  if (setup) ext.setup = mergeExtCallbacks(ext.setup, setup);
811
830
  if (cleanup) ext.cleanup = mergeExtCallbacks(ext.cleanup, cleanup);
812
831
  if (capability) {
@@ -844,10 +863,6 @@ var Elysia = class Elysia {
844
863
  * Split out from #use, see #absorbExt
845
864
  */
846
865
  #propagateHooks(app, hookChain, addedByThisCall) {
847
- let pluginEvents;
848
- let globalEvents;
849
- let pluginMayRef = false;
850
- let globalMayRef = false;
851
866
  const nodes = useNodesBuffer;
852
867
  nodes.length = 0;
853
868
  let current = hookChain;
@@ -859,96 +874,71 @@ var Elysia = class Elysia {
859
874
  nodes.push(current);
860
875
  current = current.parent;
861
876
  }
877
+ const childrenHash = this.childrenHash;
878
+ const scopeChild = app["~scopeChild"];
879
+ let held = propagatedRegistrations.get(this);
880
+ const lifted = liftedRequests.get(this);
881
+ let lifting;
862
882
  for (let i = nodes.length - 1; i >= 0; i--) {
863
883
  const node = nodes[i];
864
- const nodeScope = node.scope;
865
- if (nodeScope !== "plugin" && nodeScope !== "global") continue;
866
- if (nodeScope === "plugin" && node.propagated) continue;
867
- const isGlobal = nodeScope === "global";
868
- const added = node.added;
869
- const keys = Object.keys(added);
870
- for (let k = 0; k < keys.length; k++) {
871
- const key = keys[k];
872
- if (key === "schemas") {
873
- const schemas = added.schemas;
874
- if (!schemas) continue;
875
- const target = isGlobal ? globalEvents ??= require_utils.nullObject() : pluginEvents ??= require_utils.nullObject();
876
- if (isGlobal) globalMayRef = true;
877
- else pluginMayRef = true;
878
- for (const s of schemas) (target.schemas ??= []).push(s);
879
- continue;
880
- }
881
- if (key === "schema") continue;
882
- if (require_utils.eventProperties.has(key)) {
883
- const raw = added[key];
884
- const many = Array.isArray(raw);
885
- const count = many ? raw.length : 1;
886
- for (let f = 0; f < count; f++) {
887
- const fn = many ? raw[f] : raw;
888
- const childrenHash = this.childrenHash;
889
- if (childrenHash !== void 0) {
890
- const origin = require_utils.fnOrigin.get(fn);
891
- if (origin !== void 0 && childrenHash.has(origin) && !addedByThisCall?.has(origin)) continue;
892
- }
893
- require_utils.pushField(isGlobal ? globalEvents ??= require_utils.nullObject() : pluginEvents ??= require_utils.nullObject(), key, fn);
894
- }
895
- continue;
896
- }
897
- if (key === "~deriveEntries") {
898
- const entries = added[key];
899
- if (!entries) continue;
900
- const target = isGlobal ? globalEvents ??= require_utils.nullObject() : pluginEvents ??= require_utils.nullObject();
901
- const list = target[key] ??= [];
902
- for (let j = 0; j < entries.length; j++) list.push(entries[j]);
903
- continue;
904
- }
905
- const target = isGlobal ? globalEvents ??= require_utils.nullObject() : pluginEvents ??= require_utils.nullObject();
906
- if (isGlobal) globalMayRef = true;
907
- else pluginMayRef = true;
908
- target[key] = added[key];
884
+ const scope = node.scope;
885
+ if (scope === "plugin" ? node.propagated : scope !== "global") continue;
886
+ let source = node.added;
887
+ if (scopeChild) {
888
+ const request = source.request;
889
+ if (!request) continue;
890
+ source = require_utils.nullObject();
891
+ source.request = request;
892
+ }
893
+ const origin = node.origin ?? app.hash;
894
+ const registration = node.registration ?? node;
895
+ let added = source;
896
+ let repeated = false;
897
+ if (origin !== void 0) {
898
+ if (!held) propagatedRegistrations.set(this, held = /* @__PURE__ */ new WeakMap());
899
+ const through = held.get(registration);
900
+ if (!through) held.set(registration, [origin]);
901
+ else if (through.includes(origin)) repeated = true;
902
+ else through.push(origin);
909
903
  }
904
+ const registrant = registration.origin;
905
+ if (repeated) {
906
+ const schemas = source.schemas;
907
+ if (!schemas) continue;
908
+ added = require_utils.nullObject();
909
+ added.schemas = schemas;
910
+ } else if (registrant !== void 0 && childrenHash?.has(registrant) && !addedByThisCall?.has(registrant)) {
911
+ added = require_utils.nullObject();
912
+ for (const key in source) if (key !== "~deriveEntries" && !require_utils.eventProperties.has(key)) added[key] = source[key];
913
+ }
914
+ let dropRequest = false;
915
+ if (origin !== void 0 && "request" in added) {
916
+ if (lifted?.has(origin)) dropRequest = true;
917
+ else if (scopeChild) (lifting ??= new Set(lifted)).add(origin);
918
+ }
919
+ if ("schema" in added || dropRequest) {
920
+ if (added === source) added = Object.assign(require_utils.nullObject(), source);
921
+ delete added.schema;
922
+ if (dropRequest) delete added.request;
923
+ }
924
+ if (require_utils.isNotEmpty(added)) this.#pushChainNode(added, scope, registration, origin, app);
910
925
  }
926
+ if (lifting) liftedRequests.set(this, lifting);
911
927
  nodes.length = 0;
912
- if (globalEvents) this.#link(globalEvents, "global", app, globalMayRef, true);
913
- if (pluginEvents) this.#link(pluginEvents, "plugin", app, pluginMayRef, true);
914
928
  }
915
929
  #emitChildRoutes(app, preChain, name) {
916
930
  const declared = app.declaredRoutes;
917
931
  const limit = declared.length;
918
- const tail = app["~hookChain"];
919
- let recent;
920
- let hasLocal = false;
932
+ const callback = app["~scopeChild"] ? app["~hookChain"] : void 0;
921
933
  let lastChildChain;
922
934
  let lastCombined;
923
- let lastTailChild = null;
924
- let lastTailCombined;
935
+ let lastInner = null;
936
+ let lastCovered;
925
937
  for (let i = 0; i < limit; i++) {
926
938
  const route = declared[i];
927
939
  const childChain = route[6];
928
- const absorbed = tail !== void 0 && route[3] !== app;
929
- if (absorbed && recent === void 0) {
930
- recent = /* @__PURE__ */ new Set();
931
- for (let node = tail; node && "added" in node; node = node.parent) {
932
- recent.add(node);
933
- if (require_utils.isLocalScope(node.scope)) {
934
- hasLocal = true;
935
- break;
936
- }
937
- }
938
- }
939
940
  let inheritedChain;
940
- if (absorbed && hasLocal && !recent.has(require_utils.rootSnapshot(childChain))) {
941
- if (childChain !== lastTailChild) {
942
- lastTailChild = childChain;
943
- lastTailCombined = {
944
- combine: childChain,
945
- over: preChain,
946
- tail,
947
- refs: !!(childChain?.refs || preChain?.refs || tail.refs)
948
- };
949
- }
950
- inheritedChain = lastTailCombined;
951
- } else if (childChain === void 0) inheritedChain = preChain;
941
+ if (childChain === void 0) inheritedChain = preChain;
952
942
  else if (preChain === void 0) inheritedChain = childChain;
953
943
  else if (childChain === lastChildChain) inheritedChain = lastCombined;
954
944
  else {
@@ -959,6 +949,19 @@ var Elysia = class Elysia {
959
949
  refs: childChain.refs || preChain.refs
960
950
  };
961
951
  }
952
+ if (callback) {
953
+ if (inheritedChain !== lastInner) {
954
+ lastInner = inheritedChain;
955
+ lastCovered = {
956
+ combine: inheritedChain,
957
+ over: void 0,
958
+ callback,
959
+ inner: childChain,
960
+ refs: !!(inheritedChain?.refs || callback.refs)
961
+ };
962
+ }
963
+ inheritedChain = lastCovered;
964
+ }
962
965
  this.#emitRoute(route, this["~scopeChild"] ? this : void 0, this["~Prefix"], inheritedChain, name);
963
966
  }
964
967
  }
@@ -988,11 +991,11 @@ var Elysia = class Elysia {
988
991
  });
989
992
  }
990
993
  get pending() {
991
- return this._pending > 0;
994
+ return this.#pending > 0;
992
995
  }
993
996
  #useAsync(promise) {
994
997
  if (!this.ready) this._error = void 0;
995
- this._pending++;
998
+ this.#pending++;
996
999
  const next = (this.ready ?? Promise.resolve()).then(() => promise).then((value) => {
997
1000
  const plugin = value && typeof value === "object" && "default" in value && value.default ? value.default : value;
998
1001
  const snapshots = this.macroSnapshots;
@@ -1016,19 +1019,19 @@ var Elysia = class Elysia {
1016
1019
  }
1017
1020
  }
1018
1021
  }).finally(() => {
1019
- this._pending--;
1022
+ this.#pending--;
1020
1023
  }).then(() => {}, (err) => {
1021
1024
  this._error ??= { error: err };
1022
1025
  console.error(err);
1023
1026
  }).finally(() => {
1024
- if (this._pending > 0) return;
1027
+ if (this.#pending > 0) return;
1025
1028
  if (this.ready !== next) return;
1026
1029
  const previousCompiled = this.compiled;
1027
1030
  const previousJitColdRemaining = this.jitColdRemaining;
1028
1031
  this.ready = void 0;
1029
1032
  this.compiled = void 0;
1030
1033
  this.fetchFn = void 0;
1031
- this.routerBuilt = false;
1034
+ this.#routerBuilt = false;
1032
1035
  require_context.clearContextCache(this);
1033
1036
  try {
1034
1037
  this.#buildRouter(false);
@@ -1080,7 +1083,7 @@ var Elysia = class Elysia {
1080
1083
  handler,
1081
1084
  this
1082
1085
  ]);
1083
- if (this.routerBuilt || this.compiled !== void 0) this.#invalidate();
1086
+ if (this.#routerBuilt || this.compiled !== void 0) this.#invalidateRouter();
1084
1087
  return this;
1085
1088
  }
1086
1089
  #assertMutable(api) {
@@ -1088,8 +1091,15 @@ var Elysia = class Elysia {
1088
1091
  if (this["~generation"] === void 0) return;
1089
1092
  throw new Error(`[Elysia] .${api}() called after the app was sealed by its first request, listen or compile`);
1090
1093
  }
1094
+ /**
1095
+ * `#assertMutable` for the tables a group child shares with its parents:
1096
+ * a child kept past its callback must not write into a sealed one
1097
+ */
1098
+ #assertTableMutable(api) {
1099
+ for (let app = this; app; app = app.scopeParent) app.#assertMutable(api);
1100
+ }
1091
1101
  get #isCacheable() {
1092
- return this["~generation"] !== void 0 && this.routerBuilt && !require_compile_aot.Capture.isCapturing();
1102
+ return this["~generation"] !== void 0 && this.#routerBuilt && !require_compile_aot.Capture.isCapturing();
1093
1103
  }
1094
1104
  #cacheRoutes(generation) {
1095
1105
  if (this.cachedGeneration === generation && this.cachedEpoch === mutationEpoch) return;
@@ -1112,29 +1122,29 @@ var Elysia = class Elysia {
1112
1122
  const sequence = routes.length;
1113
1123
  routes.push(route);
1114
1124
  if (source) (this.routeSources ??= [])[sequence] = source;
1115
- if (this.routerBuilt || this.compiled !== void 0) this.#invalidate();
1125
+ if (this.#routerBuilt || this.compiled !== void 0) this.#invalidateRouter();
1116
1126
  }
1117
- #invalidate() {
1127
+ #invalidateRouter() {
1118
1128
  this.compiled = void 0;
1119
1129
  this.jitColdRemaining = void 0;
1120
1130
  this.jitTable = void 0;
1121
1131
  this.jitRoute = void 0;
1122
1132
  this.jitAliases = void 0;
1123
1133
  this.fetchFn = void 0;
1124
- this.routerBuilt = false;
1134
+ this.#routerBuilt = false;
1125
1135
  }
1126
1136
  model(name, model) {
1127
- this.#assertMutable("model");
1128
- const models = this.ext.models ??= require_utils.nullObject();
1137
+ this.#assertTableMutable("model");
1138
+ const models = this.#table("models");
1129
1139
  switch (typeof name) {
1130
1140
  case "object":
1131
1141
  for (const [key, value] of Object.entries(name)) if (!(key in models)) models[key] = toModel(key, value);
1132
1142
  return this;
1133
1143
  case "function": {
1134
1144
  const remapped = name(models);
1135
- const next = require_utils.nullObject();
1145
+ const next = remapped === models ? models : require_utils.nullObject();
1136
1146
  for (const key in remapped) next[key] = toModel(key, remapped[key]);
1137
- this.ext.models = next;
1147
+ this.#ext.models = next;
1138
1148
  return this;
1139
1149
  }
1140
1150
  case "string":
@@ -1146,7 +1156,7 @@ var Elysia = class Elysia {
1146
1156
  * Registered reusable models (via `.model()`), keyed by name.
1147
1157
  */
1148
1158
  get models() {
1149
- return this["~ext"]?.models ?? require_utils.nullObject();
1159
+ return this["~ext"]?.models ?? this.scopeParent?.models ?? require_utils.nullObject();
1150
1160
  }
1151
1161
  Ref(key) {
1152
1162
  return require_type_bridge.Ref(key);
@@ -1243,13 +1253,13 @@ var Elysia = class Elysia {
1243
1253
  compile() {
1244
1254
  this["~config"] ??= require_utils.nullObject();
1245
1255
  this["~config"].precompile = true;
1246
- this.#invalidate();
1256
+ this.#invalidateRouter();
1247
1257
  this.fetch;
1248
1258
  return this;
1249
1259
  }
1250
1260
  handler(index, immediate, route, aliases, table) {
1251
1261
  if (this.compiled?.[index]) return this.compiled[index];
1252
- const indexedTable = table ?? (this.routerBuilt ? this["~routeTable"] : void 0);
1262
+ const indexedTable = table ?? (this.#routerBuilt ? this["~routeTable"] : void 0);
1253
1263
  const compiled = this.compiled ??= new Array(indexedTable?.length ?? this["~routes"].length);
1254
1264
  if (immediate ?? this["~config"]?.precompile) {
1255
1265
  const row = route ?? (indexedTable ? require_route_table.routeRow(indexedTable, index) : this["~routes"][index]);
@@ -1268,7 +1278,7 @@ var Elysia = class Elysia {
1268
1278
  if (indexedTable !== void 0) this.jitTable = indexedTable;
1269
1279
  if (jitRoute !== void 0) (this.jitRoute ??= [])[index] = jitRoute;
1270
1280
  if (aliases !== void 0) (this.jitAliases ??= [])[index] = aliases;
1271
- return (context) => this.#jitDispatch(index, context);
1281
+ return (context) => this["~dispatch"](index, context);
1272
1282
  }
1273
1283
  #staticAliases(table, index) {
1274
1284
  const flags = table.flags[index];
@@ -1294,6 +1304,7 @@ var Elysia = class Elysia {
1294
1304
  };
1295
1305
  }
1296
1306
  #releaseJit() {
1307
+ require_compile_handler_descriptor.releaseAnalysisCaches();
1297
1308
  require_compile_aot.Compiled.release(this["~programId"]);
1298
1309
  this.jitColdRemaining = void 0;
1299
1310
  this.jitRoute = void 0;
@@ -1312,7 +1323,7 @@ var Elysia = class Elysia {
1312
1323
  this.#releaseJit();
1313
1324
  return true;
1314
1325
  }
1315
- #jitDispatch(index, context) {
1326
+ "~dispatch"(index, context) {
1316
1327
  if (this.compiled[index]) return this.compiled[index](context);
1317
1328
  const route = this.jitRoute?.[index];
1318
1329
  const table = this.jitTable ?? this["~routeTable"];
@@ -1324,7 +1335,7 @@ var Elysia = class Elysia {
1324
1335
  } catch (error) {
1325
1336
  const routeError = new Error(`[Elysia] Failed to compile route ${materialized[0]} ${materialized[1]}: ${error?.message ?? error}`, { cause: error });
1326
1337
  const finalize = this["~finalizeError"];
1327
- if (finalize) return finalize(context, routeError);
1338
+ if (finalize) return finalize(context, routeError, void 0, true);
1328
1339
  throw routeError;
1329
1340
  }
1330
1341
  this.compiled[index] = handler;
@@ -1369,11 +1380,11 @@ var Elysia = class Elysia {
1369
1380
  }
1370
1381
  return false;
1371
1382
  }
1372
- static #slotHasTypeBox(value, models, record) {
1383
+ static #slotHasTypeBox(value, models, allowStatusMap) {
1373
1384
  if (typeof value === "string") value = models?.[value];
1374
1385
  if (!value || typeof value !== "object") return false;
1375
1386
  if ("~kind" in value || "~elyAcl" in value) return true;
1376
- if (!record || "~standard" in value) return false;
1387
+ if (!allowStatusMap || "~standard" in value) return false;
1377
1388
  for (const status in value) if (Elysia.#slotHasTypeBox(value[status], models)) return true;
1378
1389
  return false;
1379
1390
  }
@@ -1399,7 +1410,7 @@ var Elysia = class Elysia {
1399
1410
  if (Elysia.#hookHasTypeBox(resolve ? resolve(node) : node.added, models)) return true;
1400
1411
  node = node.parent;
1401
1412
  } else {
1402
- if (Elysia.#chainHasTypeBox(node.combine, models, seen, resolve) || Elysia.#chainHasTypeBox(node.tail, models, seen, resolve)) return true;
1413
+ if (Elysia.#chainHasTypeBox(node.combine, models, seen, resolve)) return true;
1403
1414
  node = node.over;
1404
1415
  }
1405
1416
  }
@@ -1430,8 +1441,9 @@ var Elysia = class Elysia {
1430
1441
  const schemas = hook?.schemas;
1431
1442
  if (Array.isArray(schemas)) for (let s = 0; s < schemas.length; s++) checkSlots(schemas[s]);
1432
1443
  }
1444
+ #routerBuilt = false;
1433
1445
  #buildRouter(seal = false) {
1434
- if (this.routerBuilt) {
1446
+ if (this.#routerBuilt) {
1435
1447
  if (seal && this["~generation"] === void 0) this.#publishGeneration();
1436
1448
  return;
1437
1449
  }
@@ -1466,8 +1478,8 @@ var Elysia = class Elysia {
1466
1478
  Object.assign(previousRouter, nextRouter);
1467
1479
  this["~router"] = previousRouter;
1468
1480
  }
1469
- this.routerBuilt = true;
1470
1481
  if (seal) this.#publishGeneration();
1482
+ this.#routerBuilt = true;
1471
1483
  buildSucceeded = true;
1472
1484
  } catch (error) {
1473
1485
  this["~map"] = previousMap;
@@ -1519,9 +1531,10 @@ var Elysia = class Elysia {
1519
1531
  if (!this["~ext"]?.macro && !this["~scopeChildren"]) this.declaredRoutes = void 0;
1520
1532
  }
1521
1533
  const ext = this["~ext"];
1522
- if (ext?.hoc) extCallbackIndexes.delete(ext.hoc);
1523
1534
  if (ext?.setup) extCallbackIndexes.delete(ext.setup);
1524
1535
  if (ext?.cleanup) extCallbackIndexes.delete(ext.cleanup);
1536
+ if (ext?.decorator) require_utils.markPropertySingletons(ext.decorator);
1537
+ if (ext?.store) require_utils.markPropertySingletons(ext.store);
1525
1538
  }
1526
1539
  #buildRouterUnsafe() {
1527
1540
  const precompile = this["~config"]?.precompile;
@@ -1624,8 +1637,14 @@ var Elysia = class Elysia {
1624
1637
  if (isDynamic) {
1625
1638
  if (require_utils.isHTMLBundle(table.handler[i])) continue;
1626
1639
  const router = this["~router"] ??= new memoirist.default({ loosePath: isLoose });
1627
- const handler = this.handler(i, precompile, void 0, void 0, table);
1628
- for (let p = 0; p < paths.length; p++) router.add(routeMethod, paths[p], handler);
1640
+ let store;
1641
+ if (precompile || this.compiled?.[i]) store = this.handler(i, precompile, void 0, void 0, table);
1642
+ else {
1643
+ this.compiled ??= new Array(length);
1644
+ this.jitTable = table;
1645
+ store = i;
1646
+ }
1647
+ for (let p = 0; p < paths.length; p++) router.add(routeMethod, paths[p], store);
1629
1648
  } else {
1630
1649
  const map = methods[routeMethod] ??= require_utils.nullObject();
1631
1650
  const handler = this.handler(i, precompile, void 0, {
@@ -1643,15 +1662,15 @@ var Elysia = class Elysia {
1643
1662
  const run = () => this.fetch(request, ...rest);
1644
1663
  return this.ready ? this.modules.then(run, run) : run();
1645
1664
  };
1646
- return this.#dispatch();
1665
+ return this.#buildFetch();
1647
1666
  }
1648
- #dispatch() {
1649
- this.#buildRouter(!this._pending);
1667
+ #buildFetch() {
1668
+ this.#buildRouter(!this.#pending);
1650
1669
  if (this.ready) return require_handler_fetch.applyHoc(this, require_handler_fetch.createFetchHandler(this));
1651
1670
  return this.fetchFn ??= require_handler_fetch.applyHoc(this, require_handler_fetch.createFetchHandler(this));
1652
1671
  }
1653
1672
  get handle() {
1654
- return this._handle ??= async (requestOrUrl, options) => (this.fetchFn ?? this.#dispatch())(typeof requestOrUrl === "string" ? new Request(requestOrUrl.charCodeAt(0) === 47 ? `http://e.ly${requestOrUrl}` : requestOrUrl, options) : requestOrUrl);
1673
+ return this._handle ??= async (requestOrUrl, options) => (this.fetchFn ?? this.#buildFetch())(typeof requestOrUrl === "string" ? new Request(requestOrUrl.charCodeAt(0) === 47 ? `http://e.ly${requestOrUrl}` : requestOrUrl, options) : requestOrUrl);
1655
1674
  }
1656
1675
  listen(options, callback) {
1657
1676
  const listen = (this["~config"]?.adapter ?? (require_universal_constants.isBun ? require_adapter_bun_index.BunAdapter : void 0))?.listen;
@@ -1671,17 +1690,18 @@ var Elysia = class Elysia {
1671
1690
  *
1672
1691
  * new Elysia()
1673
1692
  * .wrap(
1674
- * (fetch) => (request) =>
1675
- * ctx.run({ counter: 0 }, () => fetch(request))
1693
+ * (fetch) => (request, ...rest) =>
1694
+ * ctx.run({ counter: 0 }, () => fetch(request, ...rest))
1676
1695
  * )
1677
1696
  * .get('/', () => ctx.getStore())
1678
1697
  * ```
1679
1698
  */
1680
1699
  wrap(callback) {
1681
1700
  this.#assertMutable("wrap");
1682
- if (this.fetchFn && !this._pending) console.warn("[Elysia] .wrap() was called after the fetch handler was built");
1683
- const ext = this.ext;
1701
+ if (this.fetchFn && !this.#pending) console.warn("[Elysia] .wrap() was called after the fetch handler was built");
1702
+ const ext = this.#ext;
1684
1703
  (ext.hoc ??= []).push(callback);
1704
+ (ext.hocOrigin ??= []).push(this.hash ?? {});
1685
1705
  return this;
1686
1706
  }
1687
1707
  /**
@@ -1700,7 +1720,7 @@ var Elysia = class Elysia {
1700
1720
  cleanup(handler) {
1701
1721
  if (this["~ext"]?.cleanupEpoch?.(handler)) return this;
1702
1722
  this.#assertMutable("cleanup");
1703
- (this.ext.cleanup ??= []).push(...[].concat(handler));
1723
+ (this.#ext.cleanup ??= []).push(...[].concat(handler));
1704
1724
  return this;
1705
1725
  }
1706
1726
  /**