elysia 2.0.0-exp.2 → 2.0.0-exp.21

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 (135) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +2 -0
  2. package/dist/adapter/bun/index.d.ts +2 -25
  3. package/dist/adapter/bun/index.js +18 -12
  4. package/dist/adapter/bun/index.mjs +19 -13
  5. package/dist/adapter/bun/router.js +1 -1
  6. package/dist/adapter/bun/router.mjs +1 -1
  7. package/dist/adapter/constants.d.ts +3 -26
  8. package/dist/adapter/index.d.ts +1 -26
  9. package/dist/adapter/index.js +1 -17
  10. package/dist/adapter/index.mjs +1 -17
  11. package/dist/adapter/types.d.ts +1 -0
  12. package/dist/adapter/utils.d.ts +3 -4
  13. package/dist/adapter/utils.js +83 -81
  14. package/dist/adapter/utils.mjs +82 -80
  15. package/dist/adapter/web-standard/handler.js +6 -3
  16. package/dist/adapter/web-standard/handler.mjs +6 -3
  17. package/dist/adapter/web-standard/index.d.ts +2 -26
  18. package/dist/adapter/web-standard/index.js +12 -1
  19. package/dist/adapter/web-standard/index.mjs +12 -1
  20. package/dist/base.d.ts +38 -68
  21. package/dist/base.js +133 -97
  22. package/dist/base.mjs +133 -97
  23. package/dist/compile/aot.d.ts +22 -1
  24. package/dist/compile/aot.js +22 -0
  25. package/dist/compile/aot.mjs +22 -0
  26. package/dist/compile/handler/index.d.ts +2 -2
  27. package/dist/compile/handler/index.js +85 -456
  28. package/dist/compile/handler/index.mjs +86 -457
  29. package/dist/compile/handler/jit.d.ts +35 -0
  30. package/dist/compile/handler/jit.js +445 -0
  31. package/dist/compile/handler/jit.mjs +443 -0
  32. package/dist/compile/handler/params.js +3 -2
  33. package/dist/compile/handler/params.mjs +4 -3
  34. package/dist/compile/handler/reconstruct.d.ts +13 -0
  35. package/dist/compile/handler/reconstruct.js +29 -0
  36. package/dist/compile/handler/reconstruct.mjs +28 -0
  37. package/dist/compile/handler/utils.d.ts +2 -1
  38. package/dist/compile/handler/utils.js +9 -3
  39. package/dist/compile/handler/utils.mjs +9 -4
  40. package/dist/compile/jit-probe.d.ts +19 -0
  41. package/dist/compile/jit-probe.js +38 -0
  42. package/dist/compile/jit-probe.mjs +36 -0
  43. package/dist/cookie/index.d.ts +4 -3
  44. package/dist/cookie/index.js +2 -1
  45. package/dist/cookie/index.mjs +2 -1
  46. package/dist/cookie/serialize.d.ts +6 -0
  47. package/dist/cookie/serialize.js +28 -0
  48. package/dist/cookie/serialize.mjs +27 -0
  49. package/dist/cookie/utils.d.ts +1 -2
  50. package/dist/cookie/utils.js +2 -23
  51. package/dist/cookie/utils.mjs +5 -25
  52. package/dist/handler/error.js +2 -2
  53. package/dist/handler/error.mjs +3 -3
  54. package/dist/handler/fetch.js +49 -42
  55. package/dist/handler/fetch.mjs +50 -43
  56. package/dist/index.d.ts +13 -8
  57. package/dist/index.js +11 -4
  58. package/dist/index.mjs +7 -6
  59. package/dist/parse-query.js +1 -1
  60. package/dist/parse-query.mjs +1 -1
  61. package/dist/plugin/bun.d.ts +10 -0
  62. package/dist/plugin/bun.js +18 -1
  63. package/dist/plugin/bun.mjs +19 -2
  64. package/dist/plugin/core.d.ts +61 -1
  65. package/dist/plugin/core.js +90 -10
  66. package/dist/plugin/core.mjs +90 -12
  67. package/dist/plugin/esbuild.d.ts +10 -0
  68. package/dist/plugin/esbuild.js +18 -1
  69. package/dist/plugin/esbuild.mjs +19 -2
  70. package/dist/plugin/source.d.ts +38 -1
  71. package/dist/plugin/source.js +104 -13
  72. package/dist/plugin/source.mjs +102 -14
  73. package/dist/plugin/vite.d.ts +7 -0
  74. package/dist/plugin/vite.js +22 -1
  75. package/dist/plugin/vite.mjs +23 -2
  76. package/dist/sucrose.js +23 -10
  77. package/dist/sucrose.mjs +23 -10
  78. package/dist/trace.d.ts +1 -1
  79. package/dist/trace.js +4 -6
  80. package/dist/trace.mjs +4 -6
  81. package/dist/type/bridge.d.ts +9 -8
  82. package/dist/type/coerce.d.ts +20 -2
  83. package/dist/type/coerce.js +110 -0
  84. package/dist/type/coerce.mjs +109 -2
  85. package/dist/type/compat.js +4 -3
  86. package/dist/type/compat.mjs +2 -1
  87. package/dist/type/constants.d.ts +1 -1
  88. package/dist/type/elysia/boolean-string.js +1 -1
  89. package/dist/type/elysia/boolean-string.mjs +1 -1
  90. package/dist/type/elysia/file-type.js +1 -1
  91. package/dist/type/elysia/file-type.mjs +1 -1
  92. package/dist/type/elysia/integer-string.js +1 -1
  93. package/dist/type/elysia/integer-string.mjs +1 -1
  94. package/dist/type/exports.js +29 -2059
  95. package/dist/type/exports.mjs +7 -295
  96. package/dist/type/index.d.ts +6 -2
  97. package/dist/type/index.js +4 -0
  98. package/dist/type/index.mjs +3 -1
  99. package/dist/type/types.d.ts +1 -1
  100. package/dist/type/utils.js +4 -4
  101. package/dist/type/utils.mjs +4 -4
  102. package/dist/type/validator/custom-error.d.ts +10 -0
  103. package/dist/type/validator/custom-error.js +113 -0
  104. package/dist/type/validator/custom-error.mjs +110 -0
  105. package/dist/type/validator/default-precompute.d.ts +22 -0
  106. package/dist/type/validator/default-precompute.js +476 -0
  107. package/dist/type/validator/default-precompute.mjs +465 -0
  108. package/dist/type/validator/frozen-check.d.ts +11 -0
  109. package/dist/type/validator/frozen-check.js +19 -0
  110. package/dist/type/validator/frozen-check.mjs +18 -0
  111. package/dist/type/{validator.d.ts → validator/index.d.ts} +7 -20
  112. package/dist/type/validator/index.js +572 -0
  113. package/dist/type/validator/index.mjs +567 -0
  114. package/dist/type/validator/string-codec-aot.d.ts +9 -0
  115. package/dist/type/validator/string-codec-aot.js +106 -0
  116. package/dist/type/validator/string-codec-aot.mjs +102 -0
  117. package/dist/type/validator/validator-cache.d.ts +21 -0
  118. package/dist/type/validator/validator-cache.js +163 -0
  119. package/dist/type/validator/validator-cache.mjs +161 -0
  120. package/dist/types.d.ts +22 -14
  121. package/dist/universal/file.d.ts +1 -1
  122. package/dist/universal/file.js +35 -29
  123. package/dist/universal/file.mjs +35 -29
  124. package/dist/utils.d.ts +12 -1
  125. package/dist/utils.js +89 -45
  126. package/dist/utils.mjs +88 -46
  127. package/dist/validator/index.d.ts +1 -1
  128. package/dist/validator/index.js +15 -2
  129. package/dist/validator/index.mjs +15 -2
  130. package/dist/validator/route.d.ts +0 -1
  131. package/dist/ws/route.js +47 -24
  132. package/dist/ws/route.mjs +48 -25
  133. package/package.json +10 -4
  134. package/dist/type/validator.js +0 -1033
  135. package/dist/type/validator.mjs +0 -1029
@@ -1,4 +1,4 @@
1
- import { generateCompiledModule, resolveEntry } from "./core.mjs";
1
+ import { STUB_SOURCES, generateCompiledArtifacts, resolveEntry } from "./core.mjs";
2
2
  import { rewriteTypeImport } from "./treeshake.mjs";
3
3
 
4
4
  //#region src/plugin/vite.ts
@@ -17,17 +17,34 @@ const VIRTUAL = "\0elysia/compiled";
17
17
  * plugins: [aot('src/index.ts')]
18
18
  * })
19
19
  * ```
20
+ *
21
+ * The plugin imports your entry to capture the compiled app, running its
22
+ * top-level code. `.listen()` is auto-skipped during build (gated on
23
+ * `ELYSIA_AOT_BUILD`), but any other import-time handle — a DB pool,
24
+ * `setInterval`, a queue consumer — can keep the build process alive after
25
+ * the bundle is written. Gate the side effect with
26
+ * `if (!process.env.ELYSIA_AOT_BUILD)`.
20
27
  */
21
28
  const aot = (entry, options) => {
22
29
  const entryPath = resolveEntry(entry);
23
30
  const treeShake = options?.treeShake ?? true;
24
31
  let source = "";
32
+ let stub = {
33
+ jit: false,
34
+ ws: false,
35
+ reconstruct: false,
36
+ cookie: false,
37
+ trace: false,
38
+ sucrose: false
39
+ };
25
40
  return {
26
41
  name: "elysia-aot",
27
42
  enforce: "pre",
28
43
  apply: "build",
29
44
  async buildStart() {
30
- source = await generateCompiledModule(entry, options);
45
+ const generated = await generateCompiledArtifacts(entry, options);
46
+ source = generated.source;
47
+ stub = generated.stub;
31
48
  },
32
49
  resolveId(id) {
33
50
  if (id === "elysia/compiled") return VIRTUAL;
@@ -36,6 +53,10 @@ const aot = (entry, options) => {
36
53
  if (id === VIRTUAL) return source;
37
54
  },
38
55
  transform(code, id) {
56
+ for (const key of Object.keys(STUB_SOURCES)) {
57
+ if (!stub[key]) continue;
58
+ for (const { filter, source: stubSource } of STUB_SOURCES[key]) if (filter.test(id)) return stubSource;
59
+ }
39
60
  let out = code;
40
61
  if (treeShake && SOURCE.test(id) && !id.includes("node_modules")) out = rewriteTypeImport(out);
41
62
  if (id === entryPath) out = `import 'elysia/compiled'\n${out}`;
package/dist/sucrose.js CHANGED
@@ -14,7 +14,7 @@ const require_utils = require('./utils.js');
14
14
  function separateFunction(code) {
15
15
  if (code.startsWith("async")) code = code.slice(5);
16
16
  code = code.trimStart();
17
- let index = -1;
17
+ let index;
18
18
  if (code.charCodeAt(0) === 40) {
19
19
  index = code.indexOf("=>", code.indexOf(")"));
20
20
  if (index !== -1) {
@@ -167,10 +167,19 @@ function findParameterReference(parameter, inference) {
167
167
  return Object.keys(parameters).join(", ");
168
168
  }
169
169
  function findEndIndex(type, content, index) {
170
- const regex = new RegExp(`${type.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\n\\t,; ]`);
171
- if (index !== void 0) regex.lastIndex = index;
172
- const match = regex.exec(content);
173
- return match ? match.index : -1;
170
+ let search = index ?? 0;
171
+ while (true) {
172
+ const found = content.indexOf(type, search);
173
+ if (found === -1) return -1;
174
+ switch (content.charCodeAt(found + type.length)) {
175
+ case 10:
176
+ case 9:
177
+ case 44:
178
+ case 59:
179
+ case 32: return found;
180
+ }
181
+ search = found + 1;
182
+ }
174
183
  }
175
184
  /**
176
185
  * Find alias of variable from function body
@@ -246,7 +255,7 @@ function extractMainParameter(parameter) {
246
255
  * Analyze if context is mentioned in body
247
256
  */
248
257
  function inferBodyReference(code, aliases, inference) {
249
- const access = (type, alias) => new RegExp(`${alias}\\??\\.(${type})|${alias}(?:\\?\\.)?\\["${type}"\\]|${alias}(?:\\?\\.)?\\['${type}'\\]`).test(code);
258
+ const access = (type, alias) => code.includes(`${alias}.${type}`) || code.includes(`${alias}?.${type}`) || code.includes(`${alias}["${type}"]`) || code.includes(`${alias}?.["${type}"]`) || code.includes(`${alias}['${type}']`) || code.includes(`${alias}?.['${type}']`);
250
259
  for (const alias of aliases) {
251
260
  if (!alias) continue;
252
261
  if (alias.charCodeAt(0) === 123) {
@@ -357,6 +366,11 @@ function clearSucroseCache(delay) {
357
366
  clearCache();
358
367
  }
359
368
  }
369
+ function scheduleSucroseCacheClear() {
370
+ if (pendingGC || require_universal_constants.isCloudflareWorker) return;
371
+ pendingGC = setTimeout(clearCache, 60 * 1e3);
372
+ pendingGC.unref?.();
373
+ }
360
374
  function mergeInference(a, b) {
361
375
  return {
362
376
  body: a.body || b.body,
@@ -425,9 +439,9 @@ function sucrose(handler, lifeCycle) {
425
439
  inference ??= defaultSucrose();
426
440
  if (needGc) {
427
441
  needGc = false;
428
- clearSucroseCache();
442
+ scheduleSucroseCacheClear();
429
443
  }
430
- let fnInference = defaultSucrose();
444
+ const fnInference = defaultSucrose();
431
445
  const [parameter, body] = separateFunction(content);
432
446
  const mainParameter = extractMainParameter(findParameterReference(parameter, fnInference));
433
447
  if (mainParameter) {
@@ -448,8 +462,7 @@ function sucrose(handler, lifeCycle) {
448
462
  }
449
463
  if (typeof event === "function") functionCaches.set(event, fnInference);
450
464
  inference = mergeInference(inference, fnInference);
451
- fnInference = void 0;
452
- if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.url && inference.route && inference.path) break;
465
+ if (inference && inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.url && inference.route && inference.path) break;
453
466
  }
454
467
  events.length = 0;
455
468
  return inference ?? defaultSucrose();
package/dist/sucrose.mjs CHANGED
@@ -13,7 +13,7 @@ import { fnv1a } from "./utils.mjs";
13
13
  function separateFunction(code) {
14
14
  if (code.startsWith("async")) code = code.slice(5);
15
15
  code = code.trimStart();
16
- let index = -1;
16
+ let index;
17
17
  if (code.charCodeAt(0) === 40) {
18
18
  index = code.indexOf("=>", code.indexOf(")"));
19
19
  if (index !== -1) {
@@ -166,10 +166,19 @@ function findParameterReference(parameter, inference) {
166
166
  return Object.keys(parameters).join(", ");
167
167
  }
168
168
  function findEndIndex(type, content, index) {
169
- const regex = new RegExp(`${type.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\n\\t,; ]`);
170
- if (index !== void 0) regex.lastIndex = index;
171
- const match = regex.exec(content);
172
- return match ? match.index : -1;
169
+ let search = index ?? 0;
170
+ while (true) {
171
+ const found = content.indexOf(type, search);
172
+ if (found === -1) return -1;
173
+ switch (content.charCodeAt(found + type.length)) {
174
+ case 10:
175
+ case 9:
176
+ case 44:
177
+ case 59:
178
+ case 32: return found;
179
+ }
180
+ search = found + 1;
181
+ }
173
182
  }
174
183
  /**
175
184
  * Find alias of variable from function body
@@ -245,7 +254,7 @@ function extractMainParameter(parameter) {
245
254
  * Analyze if context is mentioned in body
246
255
  */
247
256
  function inferBodyReference(code, aliases, inference) {
248
- const access = (type, alias) => new RegExp(`${alias}\\??\\.(${type})|${alias}(?:\\?\\.)?\\["${type}"\\]|${alias}(?:\\?\\.)?\\['${type}'\\]`).test(code);
257
+ const access = (type, alias) => code.includes(`${alias}.${type}`) || code.includes(`${alias}?.${type}`) || code.includes(`${alias}["${type}"]`) || code.includes(`${alias}?.["${type}"]`) || code.includes(`${alias}['${type}']`) || code.includes(`${alias}?.['${type}']`);
249
258
  for (const alias of aliases) {
250
259
  if (!alias) continue;
251
260
  if (alias.charCodeAt(0) === 123) {
@@ -356,6 +365,11 @@ function clearSucroseCache(delay) {
356
365
  clearCache();
357
366
  }
358
367
  }
368
+ function scheduleSucroseCacheClear() {
369
+ if (pendingGC || isCloudflareWorker) return;
370
+ pendingGC = setTimeout(clearCache, 60 * 1e3);
371
+ pendingGC.unref?.();
372
+ }
359
373
  function mergeInference(a, b) {
360
374
  return {
361
375
  body: a.body || b.body,
@@ -424,9 +438,9 @@ function sucrose(handler, lifeCycle) {
424
438
  inference ??= defaultSucrose();
425
439
  if (needGc) {
426
440
  needGc = false;
427
- clearSucroseCache();
441
+ scheduleSucroseCacheClear();
428
442
  }
429
- let fnInference = defaultSucrose();
443
+ const fnInference = defaultSucrose();
430
444
  const [parameter, body] = separateFunction(content);
431
445
  const mainParameter = extractMainParameter(findParameterReference(parameter, fnInference));
432
446
  if (mainParameter) {
@@ -447,8 +461,7 @@ function sucrose(handler, lifeCycle) {
447
461
  }
448
462
  if (typeof event === "function") functionCaches.set(event, fnInference);
449
463
  inference = mergeInference(inference, fnInference);
450
- fnInference = void 0;
451
- if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.url && inference.route && inference.path) break;
464
+ if (inference && inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.url && inference.route && inference.path) break;
452
465
  }
453
466
  events.length = 0;
454
467
  return inference ?? defaultSucrose();
package/dist/trace.d.ts CHANGED
@@ -177,4 +177,4 @@ declare class TracerHandle {
177
177
  }
178
178
  declare const createTracer: (traceListener: TraceHandler) => (context: Context) => TracerHandle;
179
179
  //#endregion
180
- export { TraceEvent, TraceHandler, TraceListener, TraceProcess, TraceStream, createTracer };
180
+ export { TraceEndDetail, TraceEvent, TraceHandler, TraceListener, TraceProcess, TraceStream, createTracer };
package/dist/trace.js CHANGED
@@ -264,12 +264,10 @@ var TracerLifecycle = class {
264
264
  return this.#handle.listen(8);
265
265
  }
266
266
  };
267
- const createTracer = (traceListener) => {
268
- return (context) => {
269
- const handle = new TracerHandle();
270
- traceListener(new TracerLifecycle(handle, context));
271
- return handle;
272
- };
267
+ const createTracer = (traceListener) => (context) => {
268
+ const handle = new TracerHandle();
269
+ traceListener(new TracerLifecycle(handle, context));
270
+ return handle;
273
271
  };
274
272
 
275
273
  //#endregion
package/dist/trace.mjs CHANGED
@@ -262,12 +262,10 @@ var TracerLifecycle = class {
262
262
  return this.#handle.listen(8);
263
263
  }
264
264
  };
265
- const createTracer = (traceListener) => {
266
- return (context) => {
267
- const handle = new TracerHandle();
268
- traceListener(new TracerLifecycle(handle, context));
269
- return handle;
270
- };
265
+ const createTracer = (traceListener) => (context) => {
266
+ const handle = new TracerHandle();
267
+ traceListener(new TracerLifecycle(handle, context));
268
+ return handle;
271
269
  };
272
270
 
273
271
  //#endregion
@@ -1,15 +1,16 @@
1
- import { Intersect as Intersect$2 } from "./elysia/intersect.js";
1
+ import { Intersect as Intersect$1 } from "./elysia/intersect.js";
2
2
  import { applyCoercions as applyCoercions$1, coerceBody as coerceBody$1, coerceFormData as coerceFormData$1, coerceQuery as coerceQuery$1, coerceRoot as coerceRoot$1, coerceStringToStructure as coerceStringToStructure$1 } from "./coerce.js";
3
- import { TypeBoxValidator as TypeBoxValidator$1, TypeBoxValidatorCache as TypeBoxValidatorCache$1 } from "./validator.js";
4
3
  import { hasTypes as hasTypes$1 } from "./utils.js";
5
- import { Compile as Compile$1 } from "typebox/compile";
4
+ import { TypeBoxValidatorCache as TypeBoxValidatorCache$1 } from "./validator/validator-cache.js";
5
+ import { TypeBoxValidator as TypeBoxValidator$1 } from "./validator/index.js";
6
6
  import { Ref as Ref$1, TAny, TSchema } from "typebox/type";
7
- import { Decode as Decode$2, Default as Default$1, HasCodec as HasCodec$1 } from "typebox/value";
7
+ import { Compile as Compile$1 } from "typebox/compile";
8
+ import { Decode as Decode$1, Default as Default$1, HasCodec as HasCodec$1 } from "typebox/value";
8
9
 
9
10
  //#region src/type/bridge.d.ts
10
11
  interface TypeboxModule {
11
12
  Compile: typeof Compile$1;
12
- Decode: typeof Decode$2;
13
+ Decode: typeof Decode$1;
13
14
  applyCoercions: typeof applyCoercions$1;
14
15
  TypeBoxValidator: TypeBoxValidator$1;
15
16
  TypeBoxValidatorCache: TypeBoxValidatorCache$1;
@@ -20,12 +21,12 @@ interface TypeboxModule {
20
21
  coerceBody: typeof coerceBody$1;
21
22
  hasTypes: typeof hasTypes$1;
22
23
  HasCodec: typeof HasCodec$1;
23
- Intersect: typeof Intersect$2;
24
+ Intersect: typeof Intersect$1;
24
25
  Default: typeof Default$1;
25
26
  Ref: typeof Ref$1;
26
27
  }
27
28
  declare let Compile: typeof Compile$1;
28
- declare let Decode: typeof Decode$2;
29
+ declare let Decode: typeof Decode$1;
29
30
  declare let applyCoercions: typeof applyCoercions$1;
30
31
  declare let TypeBoxValidator: TypeBoxValidator$1;
31
32
  type TypeBoxValidator<T extends TSchema = TAny> = TypeBoxValidator$1<T>;
@@ -38,7 +39,7 @@ declare let coerceStringToStructure: typeof coerceStringToStructure$1;
38
39
  declare let coerceBody: typeof coerceBody$1;
39
40
  declare let hasTypes: typeof hasTypes$1;
40
41
  declare let HasCodec: typeof HasCodec$1;
41
- declare let Intersect: typeof Intersect$2;
42
+ declare let Intersect: typeof Intersect$1;
42
43
  declare let Default: typeof Default$1;
43
44
  declare let Ref: typeof Ref$1;
44
45
  declare function useTypebox(mod: TypeboxModule): void;
@@ -36,8 +36,26 @@ declare const coerceQuery: () => CoerceOption[];
36
36
  declare const coerceBody: () => CoerceOption[];
37
37
  declare const coerceFormData: () => CoerceOption[];
38
38
  declare const coerceStringToStructure: () => CoerceOption[];
39
- declare function applyCoercions(schema: BaseSchema | TSchema, coerces: CoerceOption[] | undefined): TSchema | BaseSchema;
39
+ declare function applyCoercions(schema: BaseSchema | TSchema, coerces: CoerceOption[] | undefined): BaseSchema | TSchema;
40
+ interface CoerceLeaf {
41
+ e: number;
42
+ c?: Record<string, unknown>;
43
+ o?: unknown;
44
+ }
45
+ interface CoerceObjStr {
46
+ os: number;
47
+ o?: unknown;
48
+ }
49
+ type CoerceNode = CoerceLeaf | CoerceObjStr | CoercePlan;
50
+ interface CoercePlan {
51
+ p?: Record<string, CoerceNode>;
52
+ i?: CoerceNode;
53
+ }
54
+ declare function captureCoercePlan(original: any, coerced: any): CoercePlan | null;
55
+ declare function buildCoercedFromPlan(original: any, plan: CoercePlan): any;
56
+ /** @internal test isolation */
57
+ declare function clearCoerceLeafCache(): void;
40
58
  declare function nonAdditionalProperties(schema: BaseSchema | TSchema): BaseSchema;
41
59
  declare function deferCoercions(): void;
42
60
  //#endregion
43
- export { CoerceOption, applyCoercions, coerce, coerceBody, coerceFormData, coerceQuery, coerceRoot, coerceStringToStructure, deferCoercions, nonAdditionalProperties };
61
+ export { CoerceLeaf, CoerceObjStr, CoerceOption, CoercePlan, applyCoercions, buildCoercedFromPlan, captureCoercePlan, clearCoerceLeafCache, coerce, coerceBody, coerceFormData, coerceQuery, coerceRoot, coerceStringToStructure, deferCoercions, nonAdditionalProperties };
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_utils = require('../utils.js');
2
3
  const require_type_constants = require('./constants.js');
3
4
  const require_type_elysia_array_string = require('./elysia/array-string.js');
4
5
  const require_type_elysia_object_string = require('./elysia/object-string.js');
@@ -235,6 +236,112 @@ function applyCoercions(schema, coerces) {
235
236
  if (coerces) for (const coercion of coerces) schema = coerce(schema, coercion[0], coercion[1]);
236
237
  return schema;
237
238
  }
239
+ const COERCE_LEAF_CTOR = {
240
+ [require_type_constants.ELYSIA_TYPES.Numeric]: require_type_elysia_numeric.Numeric,
241
+ [require_type_constants.ELYSIA_TYPES.Integer]: require_type_elysia_integer_string.IntegerString,
242
+ [require_type_constants.ELYSIA_TYPES.BooleanString]: require_type_elysia_boolean_string.BooleanString
243
+ };
244
+ const isCoerceLeaf = (x) => typeof x.e === "number";
245
+ const isCoerceObjStr = (x) => typeof x.os === "number";
246
+ function captureCoercePlan(original, coerced) {
247
+ let bakeable = true;
248
+ let any = false;
249
+ const walk = (o, c) => {
250
+ if (o === c || !c || typeof c !== "object") return null;
251
+ const ely = c["~elyTyp"];
252
+ if (ely === require_type_constants.ELYSIA_TYPES.ObjectString && (!o || o["~elyTyp"] !== ely)) {
253
+ any = true;
254
+ const site = { os: ely };
255
+ if (o && "~optional" in o) site.o = o["~optional"];
256
+ return site;
257
+ }
258
+ if (ely === require_type_constants.ELYSIA_TYPES.ArrayString) {
259
+ bakeable = false;
260
+ return null;
261
+ }
262
+ if (ely && COERCE_LEAF_CTOR[ely] && (!o || o["~elyTyp"] !== ely)) {
263
+ any = true;
264
+ const leaf = { e: ely };
265
+ if (o) {
266
+ const { type, ...rest } = o;
267
+ if (Object.keys(rest).length) leaf.c = rest;
268
+ if ("~optional" in o) leaf.o = o["~optional"];
269
+ }
270
+ return leaf;
271
+ }
272
+ if (Array.isArray(c.anyOf) && c.anyOf.some((b, i) => b !== o?.anyOf?.[i]) || Array.isArray(c.allOf) && c.allOf.some((b, i) => b !== o?.allOf?.[i]) || Array.isArray(c.oneOf) && c.oneOf.some((b, i) => b !== o?.oneOf?.[i]) || Array.isArray(c.items) && c.items.some((b, i) => b !== o?.items?.[i]) || c.not && c.not !== o?.not || c.additionalProperties && typeof c.additionalProperties === "object" && c.additionalProperties !== o?.additionalProperties) {
273
+ bakeable = false;
274
+ return null;
275
+ }
276
+ const plan = require_utils.nullObject();
277
+ if (c.properties && o?.properties) for (const k in c.properties) {
278
+ const sub = walk(o.properties[k], c.properties[k]);
279
+ if (sub) (plan.p ??= require_utils.nullObject())[k] = sub;
280
+ }
281
+ if (c.items && !Array.isArray(c.items) && o?.items && !Array.isArray(o.items)) {
282
+ const sub = walk(o.items, c.items);
283
+ if (sub) plan.i = sub;
284
+ }
285
+ return plan.p || plan.i ? plan : null;
286
+ };
287
+ const plan = walk(original, coerced);
288
+ if (!bakeable || !any || !plan || isCoerceLeaf(plan) || isCoerceObjStr(plan)) return null;
289
+ if (!jsonSafe(plan)) return null;
290
+ return plan;
291
+ }
292
+ function jsonSafe(value) {
293
+ if (value === null) return true;
294
+ const t = typeof value;
295
+ if (t === "number") return Number.isFinite(value);
296
+ if (t === "string" || t === "boolean") return true;
297
+ if (t !== "object") return false;
298
+ if (Array.isArray(value)) return value.every(jsonSafe);
299
+ for (const k in value) if (!jsonSafe(value[k])) return false;
300
+ return true;
301
+ }
302
+ function rebuildObjStr(original, site) {
303
+ const { type, ...rest } = original;
304
+ const node = site.os === require_type_constants.ELYSIA_TYPES.ObjectString ? toObjectString(rest) : toArrayString(rest);
305
+ if ("o" in site) return Object.defineProperty(node, "~optional", {
306
+ value: site.o,
307
+ enumerable: false
308
+ });
309
+ return node;
310
+ }
311
+ const buildCoerceNode = (original, node) => isCoerceLeaf(node) ? coerceLeaf(node) : isCoerceObjStr(node) ? rebuildObjStr(original, node) : buildCoercedFromPlan(original, node);
312
+ const coerceLeafCache = /* @__PURE__ */ new Map();
313
+ function coerceLeaf(leaf) {
314
+ const key = leaf.e + (leaf.c ? JSON.stringify(leaf.c) : "");
315
+ let node = coerceLeafCache.get(key);
316
+ if (node === void 0) {
317
+ node = COERCE_LEAF_CTOR[leaf.e](leaf.c);
318
+ coerceLeafCache.set(key, node);
319
+ }
320
+ if ("o" in leaf) return Object.defineProperty(Object.create(node), "~optional", {
321
+ value: leaf.o,
322
+ enumerable: false
323
+ });
324
+ return node;
325
+ }
326
+ function buildCoercedFromPlan(original, plan) {
327
+ const out = Object.create(Object.getPrototypeOf(original));
328
+ for (const k in original) out[k] = original[k];
329
+ for (const s of Object.getOwnPropertyNames(original)) {
330
+ const d = Object.getOwnPropertyDescriptor(original, s);
331
+ if (!d.enumerable) Object.defineProperty(out, s, d);
332
+ }
333
+ if (plan.p) {
334
+ const props = { ...original.properties };
335
+ for (const k in plan.p) props[k] = buildCoerceNode(original.properties[k], plan.p[k]);
336
+ out.properties = props;
337
+ }
338
+ if (plan.i) out.items = buildCoerceNode(original.items, plan.i);
339
+ return out;
340
+ }
341
+ /** @internal test isolation */
342
+ function clearCoerceLeafCache() {
343
+ coerceLeafCache.clear();
344
+ }
238
345
  const noEnumerable = { enumerable: false };
239
346
  function cloneNode(node, out) {
240
347
  if (out !== node) return out;
@@ -354,6 +461,9 @@ function deferCoercions() {
354
461
 
355
462
  //#endregion
356
463
  exports.applyCoercions = applyCoercions;
464
+ exports.buildCoercedFromPlan = buildCoercedFromPlan;
465
+ exports.captureCoercePlan = captureCoercePlan;
466
+ exports.clearCoerceLeafCache = clearCoerceLeafCache;
357
467
  exports.coerce = coerce;
358
468
  exports.coerceBody = coerceBody;
359
469
  exports.coerceFormData = coerceFormData;
@@ -1,4 +1,5 @@
1
- import { primitiveElysiaTypes } from "./constants.mjs";
1
+ import { nullObject } from "../utils.mjs";
2
+ import { ELYSIA_TYPES, primitiveElysiaTypes } from "./constants.mjs";
2
3
  import { ArrayString } from "./elysia/array-string.mjs";
3
4
  import { ObjectString } from "./elysia/object-string.mjs";
4
5
  import { Numeric } from "./elysia/numeric.mjs";
@@ -234,6 +235,112 @@ function applyCoercions(schema, coerces) {
234
235
  if (coerces) for (const coercion of coerces) schema = coerce(schema, coercion[0], coercion[1]);
235
236
  return schema;
236
237
  }
238
+ const COERCE_LEAF_CTOR = {
239
+ [ELYSIA_TYPES.Numeric]: Numeric,
240
+ [ELYSIA_TYPES.Integer]: IntegerString,
241
+ [ELYSIA_TYPES.BooleanString]: BooleanString
242
+ };
243
+ const isCoerceLeaf = (x) => typeof x.e === "number";
244
+ const isCoerceObjStr = (x) => typeof x.os === "number";
245
+ function captureCoercePlan(original, coerced) {
246
+ let bakeable = true;
247
+ let any = false;
248
+ const walk = (o, c) => {
249
+ if (o === c || !c || typeof c !== "object") return null;
250
+ const ely = c["~elyTyp"];
251
+ if (ely === ELYSIA_TYPES.ObjectString && (!o || o["~elyTyp"] !== ely)) {
252
+ any = true;
253
+ const site = { os: ely };
254
+ if (o && "~optional" in o) site.o = o["~optional"];
255
+ return site;
256
+ }
257
+ if (ely === ELYSIA_TYPES.ArrayString) {
258
+ bakeable = false;
259
+ return null;
260
+ }
261
+ if (ely && COERCE_LEAF_CTOR[ely] && (!o || o["~elyTyp"] !== ely)) {
262
+ any = true;
263
+ const leaf = { e: ely };
264
+ if (o) {
265
+ const { type, ...rest } = o;
266
+ if (Object.keys(rest).length) leaf.c = rest;
267
+ if ("~optional" in o) leaf.o = o["~optional"];
268
+ }
269
+ return leaf;
270
+ }
271
+ if (Array.isArray(c.anyOf) && c.anyOf.some((b, i) => b !== o?.anyOf?.[i]) || Array.isArray(c.allOf) && c.allOf.some((b, i) => b !== o?.allOf?.[i]) || Array.isArray(c.oneOf) && c.oneOf.some((b, i) => b !== o?.oneOf?.[i]) || Array.isArray(c.items) && c.items.some((b, i) => b !== o?.items?.[i]) || c.not && c.not !== o?.not || c.additionalProperties && typeof c.additionalProperties === "object" && c.additionalProperties !== o?.additionalProperties) {
272
+ bakeable = false;
273
+ return null;
274
+ }
275
+ const plan = nullObject();
276
+ if (c.properties && o?.properties) for (const k in c.properties) {
277
+ const sub = walk(o.properties[k], c.properties[k]);
278
+ if (sub) (plan.p ??= nullObject())[k] = sub;
279
+ }
280
+ if (c.items && !Array.isArray(c.items) && o?.items && !Array.isArray(o.items)) {
281
+ const sub = walk(o.items, c.items);
282
+ if (sub) plan.i = sub;
283
+ }
284
+ return plan.p || plan.i ? plan : null;
285
+ };
286
+ const plan = walk(original, coerced);
287
+ if (!bakeable || !any || !plan || isCoerceLeaf(plan) || isCoerceObjStr(plan)) return null;
288
+ if (!jsonSafe(plan)) return null;
289
+ return plan;
290
+ }
291
+ function jsonSafe(value) {
292
+ if (value === null) return true;
293
+ const t = typeof value;
294
+ if (t === "number") return Number.isFinite(value);
295
+ if (t === "string" || t === "boolean") return true;
296
+ if (t !== "object") return false;
297
+ if (Array.isArray(value)) return value.every(jsonSafe);
298
+ for (const k in value) if (!jsonSafe(value[k])) return false;
299
+ return true;
300
+ }
301
+ function rebuildObjStr(original, site) {
302
+ const { type, ...rest } = original;
303
+ const node = site.os === ELYSIA_TYPES.ObjectString ? toObjectString(rest) : toArrayString(rest);
304
+ if ("o" in site) return Object.defineProperty(node, "~optional", {
305
+ value: site.o,
306
+ enumerable: false
307
+ });
308
+ return node;
309
+ }
310
+ const buildCoerceNode = (original, node) => isCoerceLeaf(node) ? coerceLeaf(node) : isCoerceObjStr(node) ? rebuildObjStr(original, node) : buildCoercedFromPlan(original, node);
311
+ const coerceLeafCache = /* @__PURE__ */ new Map();
312
+ function coerceLeaf(leaf) {
313
+ const key = leaf.e + (leaf.c ? JSON.stringify(leaf.c) : "");
314
+ let node = coerceLeafCache.get(key);
315
+ if (node === void 0) {
316
+ node = COERCE_LEAF_CTOR[leaf.e](leaf.c);
317
+ coerceLeafCache.set(key, node);
318
+ }
319
+ if ("o" in leaf) return Object.defineProperty(Object.create(node), "~optional", {
320
+ value: leaf.o,
321
+ enumerable: false
322
+ });
323
+ return node;
324
+ }
325
+ function buildCoercedFromPlan(original, plan) {
326
+ const out = Object.create(Object.getPrototypeOf(original));
327
+ for (const k in original) out[k] = original[k];
328
+ for (const s of Object.getOwnPropertyNames(original)) {
329
+ const d = Object.getOwnPropertyDescriptor(original, s);
330
+ if (!d.enumerable) Object.defineProperty(out, s, d);
331
+ }
332
+ if (plan.p) {
333
+ const props = { ...original.properties };
334
+ for (const k in plan.p) props[k] = buildCoerceNode(original.properties[k], plan.p[k]);
335
+ out.properties = props;
336
+ }
337
+ if (plan.i) out.items = buildCoerceNode(original.items, plan.i);
338
+ return out;
339
+ }
340
+ /** @internal test isolation */
341
+ function clearCoerceLeafCache() {
342
+ coerceLeafCache.clear();
343
+ }
237
344
  const noEnumerable = { enumerable: false };
238
345
  function cloneNode(node, out) {
239
346
  if (out !== node) return out;
@@ -352,4 +459,4 @@ function deferCoercions() {
352
459
  }
353
460
 
354
461
  //#endregion
355
- export { applyCoercions, coerce, coerceBody, coerceFormData, coerceQuery, coerceRoot, coerceStringToStructure, deferCoercions, nonAdditionalProperties };
462
+ export { applyCoercions, buildCoercedFromPlan, captureCoercePlan, clearCoerceLeafCache, coerce, coerceBody, coerceFormData, coerceQuery, coerceRoot, coerceStringToStructure, deferCoercions, nonAdditionalProperties };
@@ -3,7 +3,8 @@ const require_runtime = require('../_virtual/_rolldown/runtime.js');
3
3
  const require_type_bridge = require('./bridge.js');
4
4
  const require_type_coerce = require('./coerce.js');
5
5
  const require_type_utils = require('./utils.js');
6
- const require_type_validator = require('./validator.js');
6
+ const require_type_validator_validator_cache = require('./validator/validator-cache.js');
7
+ const require_type_validator_index = require('./validator/index.js');
7
8
  const require_type_elysia_intersect = require('./elysia/intersect.js');
8
9
  let typebox_compile = require("typebox/compile");
9
10
  let typebox_type = require("typebox/type");
@@ -20,8 +21,8 @@ function setupTypebox() {
20
21
  Compile: typebox_compile.Compile,
21
22
  Decode: typebox_value.Decode,
22
23
  applyCoercions: require_type_coerce.applyCoercions,
23
- TypeBoxValidator: require_type_validator.TypeBoxValidator,
24
- TypeBoxValidatorCache: require_type_validator.TypeBoxValidatorCache,
24
+ TypeBoxValidator: require_type_validator_index.TypeBoxValidator,
25
+ TypeBoxValidatorCache: require_type_validator_validator_cache.TypeBoxValidatorCache,
25
26
  coerceFormData: require_type_coerce.coerceFormData,
26
27
  coerceQuery: require_type_coerce.coerceQuery,
27
28
  coerceRoot: require_type_coerce.coerceRoot,
@@ -1,7 +1,8 @@
1
1
  import { useTypebox } from "./bridge.mjs";
2
2
  import { applyCoercions, coerceBody, coerceFormData, coerceQuery, coerceRoot, coerceStringToStructure } from "./coerce.mjs";
3
3
  import { hasTypes } from "./utils.mjs";
4
- import { TypeBoxValidator, TypeBoxValidatorCache } from "./validator.mjs";
4
+ import { TypeBoxValidatorCache } from "./validator/validator-cache.mjs";
5
+ import { TypeBoxValidator } from "./validator/index.mjs";
5
6
  import { Intersect as Intersect$1 } from "./elysia/intersect.mjs";
6
7
  import { Compile } from "typebox/compile";
7
8
  import { Ref } from "typebox/type";
@@ -17,7 +17,7 @@ declare const ELYSIA_TYPES: {
17
17
  readonly NoValidate: 15;
18
18
  };
19
19
  type ELYSIA_TYPES = typeof ELYSIA_TYPES;
20
- declare const primitiveElysiaTypes: Set<1 | 2 | 3 | 6 | 14 | 13 | 11 | 10>;
20
+ declare const primitiveElysiaTypes: Set<1 | 2 | 3 | 6 | 10 | 11 | 13 | 14>;
21
21
  declare const noEnumerable: {
22
22
  readonly enumerable: false;
23
23
  };
@@ -13,7 +13,7 @@ let StringifiedBoolean;
13
13
  let emptyBooleanString;
14
14
  function BooleanString(property) {
15
15
  StringifiedBoolean ??= (0, typebox_type.Decode)((0, typebox_type.Refine)(require_type_elysia_string.StringType(), (value) => value === "true" || value === "false", () => "must be boolean"), (value) => value === "true" ? true : false);
16
- if (!property || require_utils.isEmpty(property)) return emptyBooleanString ??= require_type_elysia_utils.elyType(require_type_constants.ELYSIA_TYPES.BooleanString, require_type_elysia_union.Union([require_type_elysia_boolean.BooleanType(), StringifiedBoolean]));
16
+ if (!property || require_utils.isEmpty(property)) return emptyBooleanString ??= Object.freeze(require_type_elysia_utils.elyType(require_type_constants.ELYSIA_TYPES.BooleanString, require_type_elysia_union.Union([require_type_elysia_boolean.BooleanType(), StringifiedBoolean])));
17
17
  const [, meta] = require_type_elysia_utils.getMeta(property);
18
18
  const boolean = require_type_elysia_boolean.BooleanType(property);
19
19
  return require_type_elysia_utils.elyType(require_type_constants.ELYSIA_TYPES.BooleanString, require_type_elysia_union.Union([boolean, StringifiedBoolean], meta));
@@ -11,7 +11,7 @@ let StringifiedBoolean;
11
11
  let emptyBooleanString;
12
12
  function BooleanString(property) {
13
13
  StringifiedBoolean ??= Decode(Refine(StringType(), (value) => value === "true" || value === "false", () => "must be boolean"), (value) => value === "true" ? true : false);
14
- if (!property || isEmpty(property)) return emptyBooleanString ??= elyType(ELYSIA_TYPES.BooleanString, Union([BooleanType(), StringifiedBoolean]));
14
+ if (!property || isEmpty(property)) return emptyBooleanString ??= Object.freeze(elyType(ELYSIA_TYPES.BooleanString, Union([BooleanType(), StringifiedBoolean])));
15
15
  const [, meta] = getMeta(property);
16
16
  const boolean = BooleanType(property);
17
17
  return elyType(ELYSIA_TYPES.BooleanString, Union([boolean, StringifiedBoolean], meta));
@@ -16,7 +16,7 @@ let warnedNoFileTypeDetector = false;
16
16
  function warnNoFileTypeDetector() {
17
17
  if (warnedNoFileTypeDetector) return;
18
18
  warnedNoFileTypeDetector = true;
19
- console.warn("[Elysia] Attempt to validate file type without a file type detector, only the file's reported mime type is checked which can be spoofed. This may lead to security risks. We recommend registering a detector with `setFileTypeDetector`, eg. `setFileTypeDetector(fileTypeFromBlob)` using the 'file-type' package.");
19
+ console.warn("[Elysia] Attempt to validate file type without a file type detector, please set one using `setFileTypeDetector`");
20
20
  }
21
21
  async function fileType(file, type) {
22
22
  if (Array.isArray(file)) return (await Promise.all(file.map((f) => fileType(f, type)))).every(Boolean);
@@ -14,7 +14,7 @@ let warnedNoFileTypeDetector = false;
14
14
  function warnNoFileTypeDetector() {
15
15
  if (warnedNoFileTypeDetector) return;
16
16
  warnedNoFileTypeDetector = true;
17
- console.warn("[Elysia] Attempt to validate file type without a file type detector, only the file's reported mime type is checked which can be spoofed. This may lead to security risks. We recommend registering a detector with `setFileTypeDetector`, eg. `setFileTypeDetector(fileTypeFromBlob)` using the 'file-type' package.");
17
+ console.warn("[Elysia] Attempt to validate file type without a file type detector, please set one using `setFileTypeDetector`");
18
18
  }
19
19
  async function fileType(file, type) {
20
20
  if (Array.isArray(file)) return (await Promise.all(file.map((f) => fileType(f, type)))).every(Boolean);