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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +1 -0
  2. package/dist/adapter/bun/index.d.ts +6 -8
  3. package/dist/adapter/bun/index.js +6 -8
  4. package/dist/adapter/bun/index.mjs +7 -8
  5. package/dist/adapter/constants.mjs +1 -0
  6. package/dist/adapter/default-headers.mjs +1 -0
  7. package/dist/adapter/index.mjs +1 -0
  8. package/dist/adapter/origin.mjs +1 -0
  9. package/dist/adapter/response-ownership.mjs +1 -0
  10. package/dist/adapter/skip-clone.mjs +1 -0
  11. package/dist/adapter/types.mjs +1 -0
  12. package/dist/adapter/utils.d.ts +5 -8
  13. package/dist/adapter/utils.js +24 -18
  14. package/dist/adapter/utils.mjs +25 -18
  15. package/dist/adapter/web-standard/handler.mjs +2 -1
  16. package/dist/adapter/web-standard/index.mjs +1 -0
  17. package/dist/adapter/web-standard/utils.mjs +1 -0
  18. package/dist/base.d.ts +118 -69
  19. package/dist/base.js +214 -194
  20. package/dist/base.mjs +221 -200
  21. package/dist/compile/aot-capture.js +2 -2
  22. package/dist/compile/aot-capture.mjs +4 -3
  23. package/dist/compile/aot-emit.js +7 -8
  24. package/dist/compile/aot-emit.mjs +8 -8
  25. package/dist/compile/aot-reconstruct.mjs +3 -2
  26. package/dist/compile/aot.d.ts +3 -3
  27. package/dist/compile/aot.js +5 -5
  28. package/dist/compile/aot.mjs +6 -5
  29. package/dist/compile/handler/descriptor.d.ts +2 -5
  30. package/dist/compile/handler/descriptor.js +12 -17
  31. package/dist/compile/handler/descriptor.mjs +16 -21
  32. package/dist/compile/handler/frozen-validator.d.ts +2 -2
  33. package/dist/compile/handler/frozen-validator.js +3 -3
  34. package/dist/compile/handler/frozen-validator.mjs +4 -3
  35. package/dist/compile/handler/index.d.ts +3 -1
  36. package/dist/compile/handler/index.js +78 -118
  37. package/dist/compile/handler/index.mjs +84 -125
  38. package/dist/compile/handler/jit.d.ts +12 -12
  39. package/dist/compile/handler/jit.js +60 -43
  40. package/dist/compile/handler/jit.mjs +63 -47
  41. package/dist/compile/handler/params.d.ts +5 -1
  42. package/dist/compile/handler/params.js +14 -5
  43. package/dist/compile/handler/params.mjs +16 -7
  44. package/dist/compile/handler/reconstruct.d.ts +2 -2
  45. package/dist/compile/handler/reconstruct.js +2 -2
  46. package/dist/compile/handler/reconstruct.mjs +3 -2
  47. package/dist/compile/handler/static-clone-resolver.mjs +1 -0
  48. package/dist/compile/handler/utils.d.ts +13 -7
  49. package/dist/compile/handler/utils.js +75 -52
  50. package/dist/compile/handler/utils.mjs +77 -54
  51. package/dist/compile/jit-probe.mjs +1 -0
  52. package/dist/compile/lexer.js +4 -4
  53. package/dist/compile/lexer.mjs +5 -4
  54. package/dist/compile/utils.d.ts +2 -1
  55. package/dist/compile/utils.js +8 -3
  56. package/dist/compile/utils.mjs +8 -3
  57. package/dist/compiled.mjs +1 -0
  58. package/dist/constants.mjs +1 -0
  59. package/dist/context.d.ts +1 -1
  60. package/dist/context.js +1 -0
  61. package/dist/context.mjs +3 -1
  62. package/dist/cookie/config.d.ts +2 -2
  63. package/dist/cookie/config.js +21 -26
  64. package/dist/cookie/config.mjs +22 -26
  65. package/dist/cookie/cookie.mjs +1 -0
  66. package/dist/cookie/crypto.mjs +1 -0
  67. package/dist/cookie/error.mjs +1 -0
  68. package/dist/cookie/lib.mjs +1 -0
  69. package/dist/cookie/serialize.mjs +1 -0
  70. package/dist/cookie/types.mjs +1 -0
  71. package/dist/cookie/utils.d.ts +1 -1
  72. package/dist/cookie/utils.js +64 -45
  73. package/dist/cookie/utils.mjs +66 -46
  74. package/dist/error.d.ts +10 -6
  75. package/dist/error.js +22 -6
  76. package/dist/error.mjs +25 -9
  77. package/dist/generation.mjs +1 -0
  78. package/dist/handler/error.d.ts +12 -15
  79. package/dist/handler/error.js +43 -40
  80. package/dist/handler/error.mjs +45 -41
  81. package/dist/handler/fetch.js +59 -21
  82. package/dist/handler/fetch.mjs +61 -22
  83. package/dist/handler/utils.d.ts +16 -3
  84. package/dist/handler/utils.js +14 -13
  85. package/dist/handler/utils.mjs +16 -15
  86. package/dist/index.d.ts +9 -9
  87. package/dist/index.js +1 -0
  88. package/dist/index.mjs +3 -2
  89. package/dist/memory.mjs +1 -0
  90. package/dist/package.js +1 -1
  91. package/dist/package.mjs +2 -1
  92. package/dist/parse-query.js +76 -76
  93. package/dist/parse-query.mjs +77 -76
  94. package/dist/plugin/aot/bun.mjs +1 -0
  95. package/dist/plugin/aot/core.d.ts +1 -1
  96. package/dist/plugin/aot/core.js +7 -4
  97. package/dist/plugin/aot/core.mjs +8 -5
  98. package/dist/plugin/aot/esbuild.mjs +1 -0
  99. package/dist/plugin/aot/rspack-loader.mjs +1 -0
  100. package/dist/plugin/aot/rspack.mjs +1 -0
  101. package/dist/plugin/aot/treeshake.mjs +1 -0
  102. package/dist/plugin/aot/unplugin.mjs +4 -3
  103. package/dist/plugin/aot/vite.mjs +1 -0
  104. package/dist/plugin/aot/worker.mjs +1 -0
  105. package/dist/plugin/auto-head.mjs +1 -0
  106. package/dist/plugin/trace.mjs +1 -0
  107. package/dist/plugin/websocket.mjs +1 -0
  108. package/dist/route-table.mjs +1 -0
  109. package/dist/schema-snapshot.js +28 -3
  110. package/dist/schema-snapshot.mjs +29 -3
  111. package/dist/sucrose.d.ts +2 -2
  112. package/dist/sucrose.js +11 -11
  113. package/dist/sucrose.mjs +12 -11
  114. package/dist/trace.js +8 -10
  115. package/dist/trace.mjs +10 -11
  116. package/dist/type/bridge-live.d.ts +1 -1
  117. package/dist/type/bridge-live.mjs +1 -0
  118. package/dist/type/bridge.d.ts +1 -1
  119. package/dist/type/bridge.mjs +1 -0
  120. package/dist/type/coerce-plan.mjs +1 -0
  121. package/dist/type/coerce.d.ts +1 -1
  122. package/dist/type/coerce.mjs +1 -0
  123. package/dist/type/compat.mjs +1 -0
  124. package/dist/type/constants.d.ts +1 -1
  125. package/dist/type/constants.mjs +1 -0
  126. package/dist/type/elysia/accelerate.mjs +1 -0
  127. package/dist/type/elysia/array-buffer.d.ts +3 -2
  128. package/dist/type/elysia/array-buffer.js +5 -5
  129. package/dist/type/elysia/array-buffer.mjs +6 -5
  130. package/dist/type/elysia/array-string.mjs +1 -0
  131. package/dist/type/elysia/array.mjs +1 -0
  132. package/dist/type/elysia/boolean-string.mjs +1 -0
  133. package/dist/type/elysia/boolean.mjs +1 -0
  134. package/dist/type/elysia/cookie.mjs +1 -0
  135. package/dist/type/elysia/date.mjs +1 -0
  136. package/dist/type/elysia/file-type.mjs +1 -0
  137. package/dist/type/elysia/file.mjs +1 -0
  138. package/dist/type/elysia/files.mjs +1 -0
  139. package/dist/type/elysia/form.mjs +1 -0
  140. package/dist/type/elysia/integer-string.mjs +1 -0
  141. package/dist/type/elysia/integer.mjs +1 -0
  142. package/dist/type/elysia/intersect.mjs +1 -0
  143. package/dist/type/elysia/json-string.mjs +1 -0
  144. package/dist/type/elysia/keep-config.js +8 -8
  145. package/dist/type/elysia/keep-config.mjs +9 -8
  146. package/dist/type/elysia/maybe-empty.mjs +1 -0
  147. package/dist/type/elysia/no-validate.mjs +1 -0
  148. package/dist/type/elysia/nullable.mjs +1 -0
  149. package/dist/type/elysia/number.mjs +1 -0
  150. package/dist/type/elysia/numeric-enum.d.ts +4 -2
  151. package/dist/type/elysia/numeric-enum.mjs +1 -0
  152. package/dist/type/elysia/numeric.mjs +1 -0
  153. package/dist/type/elysia/object-string.mjs +1 -0
  154. package/dist/type/elysia/object.mjs +1 -0
  155. package/dist/type/elysia/optional.mjs +1 -0
  156. package/dist/type/elysia/problem.mjs +1 -0
  157. package/dist/type/elysia/string.mjs +1 -0
  158. package/dist/type/elysia/uint8-array.d.ts +2 -1
  159. package/dist/type/elysia/uint8-array.js +2 -2
  160. package/dist/type/elysia/uint8-array.mjs +3 -2
  161. package/dist/type/elysia/union-enum.mjs +1 -0
  162. package/dist/type/elysia/union.mjs +1 -0
  163. package/dist/type/elysia/utils.js +3 -3
  164. package/dist/type/elysia/utils.mjs +4 -3
  165. package/dist/type/exports.mjs +1 -0
  166. package/dist/type/index.mjs +2 -1
  167. package/dist/type/shared.mjs +1 -0
  168. package/dist/type/sync-require.mjs +1 -0
  169. package/dist/type/typebox-system-lite.mjs +1 -0
  170. package/dist/type/typebox-system-require.mjs +1 -0
  171. package/dist/type/typebox-type-live.mjs +1 -0
  172. package/dist/type/typebox-value-live.mjs +1 -0
  173. package/dist/type/typebox-value-ops.mjs +1 -0
  174. package/dist/type/typebox-value.mjs +1 -0
  175. package/dist/type/types.d.ts +1 -1
  176. package/dist/type/types.mjs +1 -0
  177. package/dist/type/utils.mjs +1 -0
  178. package/dist/type/validator/clean-safe.mjs +1 -0
  179. package/dist/type/validator/custom-error.js +41 -33
  180. package/dist/type/validator/custom-error.mjs +42 -33
  181. package/dist/type/validator/default-precompute.d.ts +2 -2
  182. package/dist/type/validator/default-precompute.js +10 -11
  183. package/dist/type/validator/default-precompute.mjs +13 -13
  184. package/dist/type/validator/exact-mirror.mjs +1 -0
  185. package/dist/type/validator/frozen-check.js +7 -7
  186. package/dist/type/validator/frozen-check.mjs +8 -7
  187. package/dist/type/validator/index.d.ts +2 -2
  188. package/dist/type/validator/index.js +4 -8
  189. package/dist/type/validator/index.mjs +5 -8
  190. package/dist/type/validator/string-codec-aot.d.ts +1 -1
  191. package/dist/type/validator/string-codec-aot.mjs +1 -0
  192. package/dist/type/validator/validator-cache.js +18 -18
  193. package/dist/type/validator/validator-cache.mjs +19 -18
  194. package/dist/types.d.ts +108 -70
  195. package/dist/types.mjs +1 -0
  196. package/dist/universal/constants.mjs +1 -0
  197. package/dist/universal/file.mjs +1 -0
  198. package/dist/universal/index.mjs +1 -0
  199. package/dist/universal/is-production.mjs +1 -0
  200. package/dist/universal/server.mjs +1 -0
  201. package/dist/utils.d.ts +49 -31
  202. package/dist/utils.js +221 -109
  203. package/dist/utils.mjs +215 -106
  204. package/dist/validator/index.d.ts +3 -3
  205. package/dist/validator/index.js +4 -4
  206. package/dist/validator/index.mjs +5 -4
  207. package/dist/validator/route.d.ts +2 -2
  208. package/dist/validator/route.mjs +1 -0
  209. package/dist/ws/context.js +1 -1
  210. package/dist/ws/context.mjs +2 -1
  211. package/dist/ws/index.mjs +1 -0
  212. package/dist/ws/parser.mjs +1 -0
  213. package/dist/ws/route.js +34 -25
  214. package/dist/ws/route.mjs +40 -30
  215. package/dist/ws/types.d.ts +2 -3
  216. package/dist/ws/types.mjs +1 -0
  217. package/package.json +2 -2
package/dist/utils.js CHANGED
@@ -8,6 +8,27 @@ const nullObject = () => Object.create(null);
8
8
  const mapDeriveEntry = (fn) => [fn, "mapDerive"];
9
9
  const deriveEntryFn = (entry) => Array.isArray(entry) ? entry[0] : entry;
10
10
  const isMapDeriveEntry = (entry) => Array.isArray(entry) && entry[1] === "mapDerive";
11
+ const isPlainDeriveEntry = (entry) => Array.isArray(entry) && entry[1] === "beforeHandle";
12
+ /**
13
+ * `~deriveEntries` for `hooks` whose role per occurrence is `at` (an entry
14
+ * for a derive, undefined for a plain hook). `deriveModes` gives each
15
+ * function's entries to its occurrences in order, so a plain occurrence
16
+ * before a derive of the same function gets a placeholder
17
+ */
18
+ function occurrenceDeriveEntries(hooks, at) {
19
+ const derived = /* @__PURE__ */ new Set();
20
+ const entries = [];
21
+ for (let i = hooks.length; i--;) {
22
+ const entry = at[i];
23
+ if (entry !== void 0) {
24
+ entries.push(entry);
25
+ derived.add(hooks[i]);
26
+ } else if (derived.has(hooks[i])) entries.push([hooks[i], "beforeHandle"]);
27
+ }
28
+ return entries.reverse();
29
+ }
30
+ /** Each function's derive entries, in occurrence order */
31
+ const deriveQueues = (entries) => entries && Map.groupBy(entries, deriveEntryFn);
11
32
  function isEmpty(obj) {
12
33
  for (const _ in obj) return false;
13
34
  return true;
@@ -37,6 +58,20 @@ function fnv1a(str) {
37
58
  }
38
59
  return hash >>> 0;
39
60
  }
61
+ /**
62
+ * 48-bit hash of a named plugin's key (fnv1a + 16 bits of a second hash): at
63
+ * 32 bits two plugins collide by ~77k and the second is dropped. 48 keeps
64
+ * `origin * 16 + slot` exact
65
+ */
66
+ function pluginHash(str) {
67
+ let mix = 2654435769;
68
+ const len = str.length;
69
+ for (let i = 0; i < len; i++) {
70
+ mix = Math.imul(mix ^ str.charCodeAt(i), 1540483477);
71
+ mix ^= mix >>> 15;
72
+ }
73
+ return (mix >>> 16) * 4294967296 + fnv1a(str);
74
+ }
40
75
  const compositionKeys = Object.freeze([
41
76
  "allOf",
42
77
  "anyOf",
@@ -58,24 +93,27 @@ function refTargets(roots, models = {}) {
58
93
  roots.concat(Object.values(models)).forEach(index);
59
94
  return (name) => targets[name] ?? [];
60
95
  }
96
+ const macroOrigin = /* @__PURE__ */ new WeakMap();
61
97
  /**
62
- * Maps each lifecycle/derive function to the hash of the named plugin it was
63
- * first registered on. Used by `.use()` to dedup absorbed hooks: if a fn's
64
- * origin is already in `parent.#apps`, the parent has already absorbed that
65
- * named plugin via another path and should skip re-adding the fn.
66
- *
67
- * Anonymous plugins (no name) don't tag their fns - there's no hash to dedup
68
- * by, so their fns always propagate.
98
+ * Id of `ref` in the registry at `globalThis[key]`, `next` being the last id
99
+ * handed out. Weak so it doesn't retain `ref`, realm-wide so every installed
100
+ * Elysia copy agrees
69
101
  */
70
- const fnOrigin = /* @__PURE__ */ new WeakMap();
71
- const macroOrigin = /* @__PURE__ */ new WeakMap();
72
- const isLocalScope = (s) => s === "local" || s === void 0;
102
+ function realmId(key, ref) {
103
+ const realm = globalThis;
104
+ const registry = realm[key] ??= {
105
+ ids: /* @__PURE__ */ new WeakMap(),
106
+ next: 0
107
+ };
108
+ let id = registry.ids.get(ref);
109
+ if (id === void 0) registry.ids.set(ref, id = ++registry.next);
110
+ return id;
111
+ }
73
112
  /**
74
- * The absorbing instance's chain as it stood at `.use()`: the `over` of a
75
- * combine node, or the node itself. A combine node is never on an instance's
76
- * own chain, so it can't serve as a `stopAt` directly
113
+ * Id of an unnamed plugin in `childrenHash`, negative so it never collides
114
+ * with a named plugin's unsigned hash
77
115
  */
78
- const rootSnapshot = (node) => node && "combine" in node ? node.over : node;
116
+ const pluginId = (plugin) => -realmId("~elysiaPluginIds", plugin);
79
117
  const COMPACT_CHUNK_SIZE = 32;
80
118
  const emptyCompactBeforeHandlePrefix = {
81
119
  length: 0,
@@ -158,14 +196,21 @@ function compactBeforeHandlePrefix(start) {
158
196
  }
159
197
  const flattenNodeStack = [];
160
198
  const flattenPhaseStack = [];
199
+ const deriveSlot = 15;
200
+ const withLayer = (outer, layer) => new Set([...outer ?? [], ...layer]);
161
201
  /**
162
202
  * Walk the chain tail-first into a fresh `Partial<AppHook>`
163
203
  *
204
+ * Each instance chain a combine node links is one layer, outermost first.
205
+ * A named plugin's hook is skipped when an outer layer, or `skip`, already
206
+ * installed that plugin's same lifecycle event: it runs once, at its
207
+ * outermost position. Within a layer every registration stays
208
+ *
164
209
  * Explicit-stack walk (no recursion) so it works uniformly for linear
165
210
  * chains and combine nodes without risking stack overflow on deep chains
166
211
  */
167
- function flattenChain(start, keep, stopAt, resolveAdded) {
168
- if (!start || start === stopAt) return;
212
+ function flattenChain(start, resolveAdded, skip, info) {
213
+ if (!start) return;
169
214
  const result = nullObject();
170
215
  const nodes = flattenNodeStack;
171
216
  const phases = flattenPhaseStack;
@@ -173,47 +218,79 @@ function flattenChain(start, keep, stopAt, resolveAdded) {
173
218
  phases.length = 0;
174
219
  nodes.push(start);
175
220
  phases.push(0);
221
+ let outer = skip;
222
+ let layer;
223
+ let roles;
176
224
  while (nodes.length) {
177
225
  const node = nodes.pop();
178
- if (phases.pop() === 1) {
226
+ const phase = phases.pop();
227
+ if (phase === 2) {
228
+ if (layer?.length) {
229
+ outer = withLayer(outer, layer);
230
+ layer.length = 0;
231
+ }
232
+ continue;
233
+ }
234
+ if (phase === 1) {
235
+ const { origin, propagated, scope } = node;
236
+ if (info && origin !== void 0) info.named = true;
179
237
  const added = resolveAdded ? resolveAdded(node) : node.added;
180
- if (added) {
181
- const nodeScope = node.scope;
182
- if (!(keep && !keep(nodeScope))) for (const key in added) {
183
- const v = added[key];
184
- if (v === void 0 || v === null) continue;
185
- if (eventProperties.has(key) || key === "schemas" || key === "~deriveEntries") {
186
- const existing = result[key];
187
- if (Array.isArray(v)) if (existing) {
188
- const arr = existing;
189
- for (let i = 0; i < v.length; i++) arr.push(v[i]);
190
- } else result[key] = v.slice();
191
- else if (existing) existing.push(v);
192
- else result[key] = [v];
193
- } else result[key] = v;
238
+ const base = origin !== void 0 && (propagated || scope === "plugin" || scope === "global") ? origin * 16 : void 0;
239
+ const derives = deriveQueues(added?.["~deriveEntries"]);
240
+ if (added) for (const key in added) {
241
+ const v = added[key];
242
+ if (v == null || key === "~deriveEntries") continue;
243
+ const slot = lifecycleEvents.indexOf(key);
244
+ if (key === "beforeHandle") {
245
+ for (const fn of Array.isArray(v) ? v : [v]) {
246
+ const entry = derives?.get(fn)?.shift();
247
+ if (base !== void 0) {
248
+ const pair = base + (entry === void 0 ? slot : deriveSlot);
249
+ if (outer?.has(pair)) continue;
250
+ (layer ??= []).push(pair);
251
+ }
252
+ const list = result.beforeHandle ??= [];
253
+ if (entry !== void 0) (roles ??= [])[list.length] = entry;
254
+ list.push(fn);
255
+ }
256
+ continue;
194
257
  }
258
+ if (base !== void 0 && slot !== -1) {
259
+ if (outer?.has(base + slot)) continue;
260
+ if (!Array.isArray(v) || v.length) (layer ??= []).push(base + slot);
261
+ }
262
+ if (slot !== -1 || key === "schemas") {
263
+ const existing = result[key];
264
+ if (Array.isArray(v)) if (existing) for (let i = 0; i < v.length; i++) existing.push(v[i]);
265
+ else result[key] = v.slice();
266
+ else if (existing) existing.push(v);
267
+ else result[key] = [v];
268
+ } else result[key] = v;
195
269
  }
196
270
  continue;
197
271
  }
198
- if (stopAt && node === stopAt) continue;
199
272
  if ("combine" in node) {
200
273
  if (node.combine) {
201
274
  nodes.push(node.combine);
202
275
  phases.push(0);
203
276
  }
204
277
  if (node.over) {
278
+ nodes.push(node);
279
+ phases.push(2);
205
280
  nodes.push(node.over);
206
281
  phases.push(0);
207
282
  }
208
283
  } else {
209
284
  nodes.push(node);
210
285
  phases.push(1);
211
- if (node.parent && node.parent !== stopAt) {
286
+ if (node.parent) {
212
287
  nodes.push(node.parent);
213
288
  phases.push(0);
214
289
  }
215
290
  }
216
291
  }
292
+ if (info) info.installs = layer?.length ? withLayer(outer, layer) : outer;
293
+ if (roles) result["~deriveEntries"] = occurrenceDeriveEntries(result.beforeHandle, roles);
217
294
  if (isNotEmpty(result)) return result;
218
295
  }
219
296
  /**
@@ -234,27 +311,45 @@ function clearFlattenChainMemo(root) {
234
311
  flattenChainMemos.delete(root);
235
312
  }
236
313
  const emptyFlatten = Object.freeze(nullObject());
237
- function flattenChainMemoReadonly(root, start, resolveAdded) {
238
- if (!start) return;
314
+ function flattenMemoOf(root) {
239
315
  let bucket = flattenChainMemos.get(root);
240
316
  if (!bucket || bucket.e !== macroTableEpoch) {
241
317
  bucket = {
242
318
  e: macroTableEpoch,
243
- per: /* @__PURE__ */ new WeakMap()
319
+ per: /* @__PURE__ */ new WeakMap(),
320
+ info: /* @__PURE__ */ new WeakMap()
244
321
  };
245
322
  flattenChainMemos.set(root, bucket);
246
323
  }
247
- const perRoot = bucket.per;
248
- let cached = perRoot.get(start);
324
+ return bucket;
325
+ }
326
+ /** What the chain installs, see {@link flattenChain} */
327
+ function flattenChainInfo(root, start, resolveAdded) {
328
+ if (!start) return;
329
+ const bucket = flattenMemoOf(root);
330
+ flattenChainMemoReadonly(root, start, resolveAdded);
331
+ return bucket.info.get(start);
332
+ }
333
+ function flattenChainMemoReadonly(root, start, resolveAdded, skip) {
334
+ if (!start) return;
335
+ const bucket = flattenMemoOf(root);
336
+ let memo = bucket.per;
337
+ if (skip) {
338
+ const skipped = bucket.skipped ??= /* @__PURE__ */ new WeakMap();
339
+ memo = skipped.get(start);
340
+ if (!memo) skipped.set(start, memo = /* @__PURE__ */ new WeakMap());
341
+ }
342
+ let cached = memo.get(skip ?? start);
249
343
  if (cached === void 0) {
250
- cached = flattenChain(start, void 0, void 0, resolveAdded) ?? emptyFlatten;
251
- perRoot.set(start, cached);
344
+ const info = skip ? void 0 : {};
345
+ cached = flattenChain(start, resolveAdded, skip, info) ?? emptyFlatten;
346
+ memo.set(skip ?? start, cached);
347
+ if (info?.named) bucket.info.set(start, info);
252
348
  }
253
- if (cached === emptyFlatten) return;
254
- return cached;
349
+ if (cached !== emptyFlatten) return cached;
255
350
  }
256
- function flattenChainMemo(root, start, resolveAdded) {
257
- const cached = flattenChainMemoReadonly(root, start, resolveAdded);
351
+ function flattenChainMemo(root, start, resolveAdded, skip) {
352
+ const cached = flattenChainMemoReadonly(root, start, resolveAdded, skip);
258
353
  if (cached) return cloneHook(cached);
259
354
  }
260
355
  const notLatin = /[^\x00-\xFF]/;
@@ -303,6 +398,7 @@ function formToFormData(value) {
303
398
  * ```
304
399
  */
305
400
  const form = (value) => Object.setPrototypeOf({ ...value }, ELYSIA_FORM_PROTOTYPE);
401
+ const macroType = () => void 0;
306
402
  const assignOwn = (target, source) => source != null && Object.hasOwn(source, "__proto__") ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : Object.assign(target, source);
307
403
  const getLoosePath = (path) => path.charCodeAt(path.length - 1) === 47 ? path.slice(0, -1) : path + "/";
308
404
  const byteStreams = /* @__PURE__ */ new WeakSet();
@@ -427,26 +523,6 @@ function mergeArray(a, b, reverse = false) {
427
523
  }
428
524
  return [a, b];
429
525
  }
430
- /**
431
- * Like {@link mergeArray} but drops entries from `a` that already appear in
432
- * `b` by reference. Always allocates fresh arrays - never mutates inputs.
433
- *
434
- * Used at the compile-time merge of a route's snapshotted `appHook` with the
435
- * root's current `rootHook`: the same fn can sit on both sides because
436
- * `.use()` propagates global/plugin-scoped hooks into the parent, while the
437
- * route's `appHook` was captured on the child and still holds the original.
438
- * The fn must run once, in `b`'s position.
439
- */
440
- function dedupedMergeArray(a, b, reverse = false) {
441
- if (!a) return Array.isArray(b) ? b.slice() : b;
442
- if (!b) return Array.isArray(a) ? a.slice() : a;
443
- const aArr = Array.isArray(a) ? a : [a];
444
- const bArr = Array.isArray(b) ? b : [b];
445
- const seen = new Set(bArr);
446
- const filtered = [];
447
- for (let i = 0; i < aArr.length; i++) if (!seen.has(aArr[i])) filtered.push(aArr[i]);
448
- return reverse ? bArr.concat(filtered) : filtered.concat(bArr);
449
- }
450
526
  const hookSchemaKeys = [
451
527
  "body",
452
528
  "headers",
@@ -467,7 +543,7 @@ const hookEventKeys = [
467
543
  "error",
468
544
  "trace"
469
545
  ];
470
- const eventProperties = new Set([
546
+ const lifecycleEvents = [
471
547
  "start",
472
548
  "stop",
473
549
  "trace",
@@ -479,7 +555,8 @@ const eventProperties = new Set([
479
555
  "mapResponse",
480
556
  "afterResponse",
481
557
  "error"
482
- ]);
558
+ ];
559
+ const eventProperties = new Set(lifecycleEvents);
483
560
  function hookToGuard(a) {
484
561
  if (a.schema !== "merge") {
485
562
  if (a.schema !== void 0 && a.schema !== "override") throw new Error(`[Elysia] Invalid guard schema ${JSON.stringify(a.schema)}, expected 'merge' or 'override' (1.x 'standalone' is 'merge')`);
@@ -516,25 +593,24 @@ function coalesceSchemas(existing, incoming) {
516
593
  if (!merged) existing.push(entry);
517
594
  }
518
595
  }
519
- function mergeHook(a, b, reverse = false, dedup = false) {
596
+ function mergeHook(a, b) {
520
597
  if (!b) return a;
521
598
  if (!a) return b;
522
- const merge = dedup ? dedupedMergeArray : mergeArray;
523
599
  for (const key of hookSchemaKeys) if (!a[key] && b[key]) a[key] = b[key];
524
600
  else if (key === "response" && a.response && b.response) a.response = mergeResponse(b.response, a.response);
525
- for (const key of hookEventKeys) if (a[key] || b[key]) a[key] = merge(a[key], b[key], reverse);
526
- if (a.schemas || b.schemas) a.schemas = mergeArray(a.schemas, b.schemas, reverse);
601
+ for (const key of hookEventKeys) if (a[key] || b[key]) a[key] = mergeArray(a[key], b[key], true);
602
+ if (a.schemas || b.schemas) a.schemas = mergeArray(a.schemas, b.schemas, true);
527
603
  const aDerive = a["~deriveEntries"];
528
604
  const bDerive = b["~deriveEntries"];
529
- if (aDerive || bDerive) a["~deriveEntries"] = mergeArray(aDerive, bDerive, reverse);
605
+ if (aDerive || bDerive) a["~deriveEntries"] = mergeArray(aDerive, bDerive, true);
530
606
  return a;
531
607
  }
532
608
  const createErrorEventHandler = (fn, error) => {
533
609
  const handler = (context) => {
534
610
  if (context.error instanceof error) return fn(context);
535
611
  };
536
- const p = error?.prototype;
537
- if (typeof p === "object" && p !== null && p !== Error.prototype && !(p instanceof Error)) handler["~errorClass"] = error;
612
+ const prototype = error?.prototype;
613
+ if (typeof prototype === "object" && prototype !== null && prototype !== Error.prototype && !(prototype instanceof Error)) handler["~errorClass"] = error;
538
614
  return handler;
539
615
  };
540
616
  const isObject = (item) => item && typeof item === "object" && !Array.isArray(item);
@@ -624,12 +700,6 @@ function joinPath(base, path) {
624
700
  if (!baseEndsWithSlash && !pathStartsWithSlash) return base + "/" + path;
625
701
  return base + path;
626
702
  }
627
- function pushField(target, key, item) {
628
- const v = target[key];
629
- if (v) if (Array.isArray(v)) target[key].push(item);
630
- else target[key] = [v, item];
631
- else target[key] = item;
632
- }
633
703
  const requestId = require_universal_constants.isBun ? Bun.randomUUIDv7 : crypto.randomUUID.bind(crypto);
634
704
  /**
635
705
  * Offset of the first byte after `://`, so the authority is never scanned as
@@ -647,22 +717,34 @@ function isPlainObject(v) {
647
717
  const proto = Object.getPrototypeOf(v);
648
718
  return proto === Object.prototype || proto === null;
649
719
  }
650
- function clonePlainDecorators(source, seen) {
651
- if (seen !== void 0) {
652
- const existing = seen.get(source);
653
- if (existing) return existing;
654
- }
720
+ function clonePlainDecorators(source, seen = /* @__PURE__ */ new WeakMap()) {
721
+ const existing = seen.get(source);
722
+ if (existing) return existing;
655
723
  const out = nullObject();
656
- if (seen !== void 0) seen.set(source, out);
657
- for (const key in source) {
658
- const value = source[key];
659
- if (isPlainObject(value)) {
660
- if (seen === void 0) (seen = /* @__PURE__ */ new WeakMap()).set(source, out);
661
- out[key] = clonePlainDecorators(value, seen);
662
- } else out[key] = value;
724
+ seen.set(source, out);
725
+ for (const key in source) copyKey(source, out, key, seen);
726
+ const own = Reflect.ownKeys(source);
727
+ if (own.length !== Object.keys(source).length) for (const key of own) {
728
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
729
+ if (!descriptor || descriptor.enumerable && typeof key === "string") continue;
730
+ try {
731
+ copyKey(source, out, key, seen, descriptor);
732
+ } catch {}
663
733
  }
734
+ if (!Object.isExtensible(source)) Object.preventExtensions(out);
664
735
  return out;
665
736
  }
737
+ const copyKey = (source, out, key, seen, descriptor = Object.getOwnPropertyDescriptor(source, key)) => {
738
+ let value = source[key];
739
+ if (isPlainObject(value)) value = clonePlainDecorators(value, seen);
740
+ if (!descriptor || descriptor.writable !== false && descriptor.enumerable && descriptor.configurable) out[key] = value;
741
+ else Object.defineProperty(out, key, {
742
+ value,
743
+ writable: descriptor.writable ?? true,
744
+ enumerable: descriptor.enumerable,
745
+ configurable: descriptor.configurable
746
+ });
747
+ };
666
748
  function prefix(prefix, models) {
667
749
  const prefixed = nullObject();
668
750
  for (const key in models) prefixed[`${prefix}.${key}`] = models[key];
@@ -673,18 +755,14 @@ prefix.capitalize = function prefixModelsCapitalize(prefix, models) {
673
755
  for (const key in models) prefixed[`${prefix}.${key.charAt(0).toUpperCase() + key.slice(1)}`] = models[key];
674
756
  return prefixed;
675
757
  };
676
- const macroSeedRefIds = /* @__PURE__ */ new WeakMap();
677
- let macroSeedRefCounter = 0;
678
- function macroSeedRefId(ref) {
679
- let id = macroSeedRefIds.get(ref);
680
- if (id === void 0) macroSeedRefIds.set(ref, id = ++macroSeedRefCounter);
681
- return id;
682
- }
683
758
  function serializeMacroSeed(_key, value) {
684
759
  switch (typeof value) {
685
- case "function": return "\0fn:" + macroSeedRefId(value);
760
+ case "function": return "\0ref:" + realmId("~elysiaSeedIds", value);
686
761
  case "bigint": return "\0bigint:" + value.toString();
687
- case "symbol": return "\0sym:" + String(value);
762
+ case "symbol": {
763
+ const key = Symbol.keyFor(value);
764
+ return key === void 0 ? "\0ref:" + realmId("~elysiaSeedIds", value) : "\0symfor:" + key;
765
+ }
688
766
  case "undefined": return "\0undefined";
689
767
  default: return value;
690
768
  }
@@ -705,7 +783,21 @@ const isDisposable = (value) => {
705
783
  };
706
784
  const singletons = /* @__PURE__ */ new WeakSet();
707
785
  const isSingleton = (value) => singletons.has(value);
708
- const markSingletons = (value, depth = 4, seen = /* @__PURE__ */ new Set()) => {
786
+ function pushHeld(object, into, seen) {
787
+ if (ArrayBuffer.isView(object)) return;
788
+ let all = false;
789
+ try {
790
+ all = typeof object !== "function" && object !== globalThis && !(object instanceof Error);
791
+ } catch {}
792
+ try {
793
+ const keys = all ? Reflect.ownKeys(object) : [...Object.keys(object), ...Object.getOwnPropertySymbols(object)];
794
+ for (const key of keys) {
795
+ const descriptor = Object.getOwnPropertyDescriptor(object, key);
796
+ if (descriptor && "value" in descriptor) enqueue(descriptor.value, into, seen);
797
+ }
798
+ } catch {}
799
+ }
800
+ function enqueue(value, into, seen) {
709
801
  if (value == null) return;
710
802
  const kind = typeof value;
711
803
  if (kind !== "object" && kind !== "function") return;
@@ -713,11 +805,27 @@ const markSingletons = (value, depth = 4, seen = /* @__PURE__ */ new Set()) => {
713
805
  if (seen.has(object)) return;
714
806
  seen.add(object);
715
807
  singletons.add(object);
716
- if (depth <= 0) return;
717
- for (const key of Object.keys(object)) {
718
- const descriptor = Object.getOwnPropertyDescriptor(object, key);
719
- if (descriptor && "value" in descriptor) markSingletons(descriptor.value, depth - 1, seen);
808
+ into.push(object);
809
+ }
810
+ function markLevels(level, depth, seen) {
811
+ while (level.length && depth > 0) {
812
+ const next = [];
813
+ for (const object of level) pushHeld(object, next, seen);
814
+ level = next;
815
+ depth--;
720
816
  }
817
+ }
818
+ const markSingletons = (value, depth = 4) => {
819
+ const seen = /* @__PURE__ */ new Set();
820
+ const level = [];
821
+ enqueue(value, level, seen);
822
+ markLevels(level, depth, seen);
823
+ };
824
+ const markPropertySingletons = (object) => {
825
+ const seen = /* @__PURE__ */ new Set();
826
+ const level = [];
827
+ pushHeld(object, level, seen);
828
+ markLevels(level, 4, seen);
721
829
  };
722
830
  const isSocketQuiet = (socket) => socket.readyState === 3 && !socket.data.inflight && !socket.data.opening && !socket.data.settling;
723
831
  const isHTMLBundle = (value) => Object.prototype.toString.call(value) === "[object HTMLBundle]" || typeof value?.index === "string" && Array.isArray(value.files);
@@ -738,12 +846,13 @@ exports.compositionKeys = compositionKeys;
738
846
  exports.constantTimeEqual = constantTimeEqual;
739
847
  exports.createErrorEventHandler = createErrorEventHandler;
740
848
  exports.deriveEntryFn = deriveEntryFn;
849
+ exports.deriveQueues = deriveQueues;
741
850
  exports.eventProperties = eventProperties;
742
851
  exports.evictOldestHalf = evictOldestHalf;
743
852
  exports.flattenChain = flattenChain;
853
+ exports.flattenChainInfo = flattenChainInfo;
744
854
  exports.flattenChainMemo = flattenChainMemo;
745
855
  exports.flattenChainMemoReadonly = flattenChainMemoReadonly;
746
- exports.fnOrigin = fnOrigin;
747
856
  exports.fnv1a = fnv1a;
748
857
  exports.form = form;
749
858
  exports.formToFormData = formToFormData;
@@ -758,9 +867,9 @@ exports.isDisposable = isDisposable;
758
867
  exports.isElysiaForm = isElysiaForm;
759
868
  exports.isEmpty = isEmpty;
760
869
  exports.isHTMLBundle = isHTMLBundle;
761
- exports.isLocalScope = isLocalScope;
762
870
  exports.isMapDeriveEntry = isMapDeriveEntry;
763
871
  exports.isNotEmpty = isNotEmpty;
872
+ exports.isPlainDeriveEntry = isPlainDeriveEntry;
764
873
  exports.isPlainObject = isPlainObject;
765
874
  exports.isRecordNumber = isRecordNumber;
766
875
  exports.isSingleton = isSingleton;
@@ -768,20 +877,23 @@ exports.isSocketQuiet = isSocketQuiet;
768
877
  exports.joinPath = joinPath;
769
878
  exports.macroEpoch = macroEpoch;
770
879
  exports.macroOrigin = macroOrigin;
880
+ exports.macroType = macroType;
771
881
  exports.mapDeriveEntry = mapDeriveEntry;
882
+ exports.markPropertySingletons = markPropertySingletons;
772
883
  exports.markSingletons = markSingletons;
773
884
  exports.mergeArray = mergeArray;
774
885
  exports.mergeDeep = mergeDeep;
775
886
  exports.mergeHook = mergeHook;
776
887
  exports.mergeResponse = mergeResponse;
777
888
  exports.nullObject = nullObject;
889
+ exports.occurrenceDeriveEntries = occurrenceDeriveEntries;
890
+ exports.pluginHash = pluginHash;
891
+ exports.pluginId = pluginId;
778
892
  exports.prefix = prefix;
779
- exports.pushField = pushField;
780
893
  exports.redirect = redirect;
781
894
  exports.refTargets = refTargets;
782
895
  exports.replaceUrlPath = replaceUrlPath;
783
896
  exports.requestId = requestId;
784
- exports.rootSnapshot = rootSnapshot;
785
897
  exports.schemaProperties = schemaProperties;
786
898
  exports.serializeMacroSeed = serializeMacroSeed;
787
899
  exports.sse = sse;