elysia 2.0.0-beta.2 → 2.0.0-beta.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 (339) hide show
  1. package/dist/adapter/bun/index.d.ts +18 -2
  2. package/dist/adapter/bun/index.js +467 -110
  3. package/dist/adapter/bun/index.mjs +467 -112
  4. package/dist/adapter/types.d.ts +2 -21
  5. package/dist/adapter/utils.d.ts +14 -3
  6. package/dist/adapter/utils.js +146 -87
  7. package/dist/adapter/utils.mjs +148 -90
  8. package/dist/adapter/web-standard/handler.d.ts +1 -1
  9. package/dist/adapter/web-standard/handler.js +47 -36
  10. package/dist/adapter/web-standard/handler.mjs +48 -37
  11. package/dist/adapter/web-standard/index.js +2 -30
  12. package/dist/adapter/web-standard/index.mjs +2 -30
  13. package/dist/adapter/web-standard/utils.js +5 -18
  14. package/dist/adapter/web-standard/utils.mjs +5 -18
  15. package/dist/base.d.ts +99 -67
  16. package/dist/base.js +678 -510
  17. package/dist/base.mjs +682 -514
  18. package/dist/compile/aot-capture.d.ts +2 -13
  19. package/dist/compile/aot-capture.js +26 -69
  20. package/dist/compile/aot-capture.mjs +28 -67
  21. package/dist/compile/aot-emit.d.ts +9 -7
  22. package/dist/compile/aot-emit.js +42 -19
  23. package/dist/compile/aot-emit.mjs +42 -20
  24. package/dist/compile/aot.d.ts +17 -19
  25. package/dist/compile/aot.js +41 -51
  26. package/dist/compile/aot.mjs +39 -49
  27. package/dist/compile/handler/descriptor.d.ts +9 -12
  28. package/dist/compile/handler/descriptor.js +19 -44
  29. package/dist/compile/handler/descriptor.mjs +20 -42
  30. package/dist/compile/handler/frozen-validator.d.ts +5 -10
  31. package/dist/compile/handler/frozen-validator.js +55 -105
  32. package/dist/compile/handler/frozen-validator.mjs +53 -105
  33. package/dist/compile/handler/index.d.ts +7 -5
  34. package/dist/compile/handler/index.js +270 -111
  35. package/dist/compile/handler/index.mjs +270 -113
  36. package/dist/compile/handler/jit.d.ts +19 -17
  37. package/dist/compile/handler/jit.js +222 -149
  38. package/dist/compile/handler/jit.mjs +224 -152
  39. package/dist/compile/handler/params.d.ts +1 -4
  40. package/dist/compile/handler/params.js +10 -5
  41. package/dist/compile/handler/params.mjs +14 -8
  42. package/dist/compile/handler/reconstruct.d.ts +2 -2
  43. package/dist/compile/handler/reconstruct.js +6 -4
  44. package/dist/compile/handler/reconstruct.mjs +6 -4
  45. package/dist/compile/handler/static-clone-resolver.d.ts +6 -0
  46. package/dist/compile/handler/static-clone-resolver.js +8 -0
  47. package/dist/compile/handler/static-clone-resolver.mjs +7 -0
  48. package/dist/compile/handler/utils.d.ts +22 -11
  49. package/dist/compile/handler/utils.js +159 -253
  50. package/dist/compile/handler/utils.mjs +155 -252
  51. package/dist/compile/jit-probe.d.ts +2 -2
  52. package/dist/compile/jit-probe.js +2 -3
  53. package/dist/compile/jit-probe.mjs +2 -3
  54. package/dist/compile/lexer.d.ts +7 -4
  55. package/dist/compile/lexer.js +268 -6
  56. package/dist/compile/lexer.mjs +268 -4
  57. package/dist/compile/utils.js +7 -4
  58. package/dist/compile/utils.mjs +7 -4
  59. package/dist/compiled.d.ts +0 -1
  60. package/dist/compiled.js +0 -1
  61. package/dist/compiled.mjs +0 -1
  62. package/dist/context.d.ts +14 -4
  63. package/dist/context.js +17 -32
  64. package/dist/context.mjs +19 -34
  65. package/dist/cookie/config.d.ts +7 -2
  66. package/dist/cookie/config.js +76 -16
  67. package/dist/cookie/config.mjs +77 -18
  68. package/dist/cookie/cookie.d.ts +1 -1
  69. package/dist/cookie/cookie.js +8 -10
  70. package/dist/cookie/cookie.mjs +8 -10
  71. package/dist/cookie/crypto.d.ts +8 -7
  72. package/dist/cookie/crypto.js +51 -40
  73. package/dist/cookie/crypto.mjs +51 -41
  74. package/dist/cookie/error.d.ts +1 -2
  75. package/dist/cookie/error.js +6 -4
  76. package/dist/cookie/error.mjs +6 -4
  77. package/dist/cookie/lib.js +7 -2
  78. package/dist/cookie/lib.mjs +7 -2
  79. package/dist/cookie/serialize.js +1 -1
  80. package/dist/cookie/serialize.mjs +1 -1
  81. package/dist/cookie/types.d.ts +10 -0
  82. package/dist/cookie/utils.d.ts +4 -8
  83. package/dist/cookie/utils.js +86 -52
  84. package/dist/cookie/utils.mjs +89 -54
  85. package/dist/error.d.ts +113 -103
  86. package/dist/error.js +181 -117
  87. package/dist/error.mjs +179 -118
  88. package/dist/generation.d.ts +2 -2
  89. package/dist/handler/error.d.ts +26 -15
  90. package/dist/handler/error.js +77 -96
  91. package/dist/handler/error.mjs +74 -97
  92. package/dist/handler/fetch.js +87 -108
  93. package/dist/handler/fetch.mjs +89 -110
  94. package/dist/handler/utils.d.ts +12 -6
  95. package/dist/handler/utils.js +84 -28
  96. package/dist/handler/utils.mjs +80 -28
  97. package/dist/index.d.ts +12 -12
  98. package/dist/index.js +2 -9
  99. package/dist/index.mjs +1 -1
  100. package/dist/memory.js +1 -1
  101. package/dist/memory.mjs +1 -1
  102. package/dist/package.js +1 -1
  103. package/dist/package.mjs +1 -1
  104. package/dist/plugin/aot/bun.d.ts +8 -1
  105. package/dist/plugin/aot/bun.js +16 -9
  106. package/dist/plugin/aot/bun.mjs +17 -10
  107. package/dist/plugin/aot/core.d.ts +52 -60
  108. package/dist/plugin/aot/core.js +208 -109
  109. package/dist/plugin/aot/core.mjs +205 -111
  110. package/dist/plugin/aot/esbuild.js +8 -5
  111. package/dist/plugin/aot/esbuild.mjs +9 -6
  112. package/dist/plugin/aot/hooks.d.ts +6 -17
  113. package/dist/plugin/aot/hooks.js +36 -14
  114. package/dist/plugin/aot/hooks.mjs +37 -16
  115. package/dist/plugin/aot/rspack-loader.d.ts +1 -5
  116. package/dist/plugin/aot/rspack-loader.js +1 -10
  117. package/dist/plugin/aot/rspack-loader.mjs +1 -10
  118. package/dist/plugin/aot/rspack.js +2 -5
  119. package/dist/plugin/aot/rspack.mjs +3 -6
  120. package/dist/plugin/aot/source.d.ts +6 -42
  121. package/dist/plugin/aot/source.js +71 -71
  122. package/dist/plugin/aot/source.mjs +72 -72
  123. package/dist/plugin/aot/treeshake.js +2 -6
  124. package/dist/plugin/aot/treeshake.mjs +2 -6
  125. package/dist/plugin/aot/unplugin.d.ts +1 -4
  126. package/dist/plugin/aot/unplugin.js +4 -13
  127. package/dist/plugin/aot/unplugin.mjs +4 -13
  128. package/dist/plugin/aot/vite.d.ts +2 -6
  129. package/dist/plugin/aot/worker.js +2 -2
  130. package/dist/plugin/aot/worker.mjs +2 -2
  131. package/dist/plugin/auto-head.js +1 -10
  132. package/dist/plugin/auto-head.mjs +1 -10
  133. package/dist/plugin/trace.d.ts +2 -1
  134. package/dist/route-table.d.ts +3 -0
  135. package/dist/route-table.js +16 -11
  136. package/dist/route-table.mjs +16 -11
  137. package/dist/schema-snapshot.d.ts +0 -4
  138. package/dist/schema-snapshot.js +32 -49
  139. package/dist/schema-snapshot.mjs +32 -49
  140. package/dist/sucrose.d.ts +6 -55
  141. package/dist/sucrose.js +103 -731
  142. package/dist/sucrose.mjs +102 -724
  143. package/dist/trace.d.ts +5 -8
  144. package/dist/trace.js +23 -134
  145. package/dist/trace.mjs +24 -135
  146. package/dist/type/bridge-live.d.ts +4 -2
  147. package/dist/type/bridge-live.js +6 -3
  148. package/dist/type/bridge-live.mjs +4 -2
  149. package/dist/type/bridge.d.ts +6 -4
  150. package/dist/type/bridge.js +17 -9
  151. package/dist/type/bridge.mjs +5 -3
  152. package/dist/type/coerce-plan.d.ts +5 -5
  153. package/dist/type/coerce-plan.js +41 -39
  154. package/dist/type/coerce-plan.mjs +43 -39
  155. package/dist/type/coerce.d.ts +3 -7
  156. package/dist/type/coerce.js +18 -75
  157. package/dist/type/coerce.mjs +19 -76
  158. package/dist/type/compat.d.ts +3 -0
  159. package/dist/type/compat.js +23 -14
  160. package/dist/type/compat.mjs +20 -10
  161. package/dist/type/elysia/array-buffer.d.ts +4 -1
  162. package/dist/type/elysia/array-buffer.js +17 -17
  163. package/dist/type/elysia/array-buffer.mjs +17 -17
  164. package/dist/type/elysia/array-string.js +2 -40
  165. package/dist/type/elysia/array-string.mjs +2 -39
  166. package/dist/type/elysia/array.js +5 -9
  167. package/dist/type/elysia/array.mjs +5 -9
  168. package/dist/type/elysia/boolean-string.js +2 -3
  169. package/dist/type/elysia/boolean-string.mjs +1 -1
  170. package/dist/type/elysia/boolean.js +3 -12
  171. package/dist/type/elysia/boolean.mjs +3 -11
  172. package/dist/type/elysia/cookie.d.ts +3 -4
  173. package/dist/type/elysia/cookie.js +5 -15
  174. package/dist/type/elysia/cookie.mjs +5 -15
  175. package/dist/type/elysia/date.js +13 -20
  176. package/dist/type/elysia/date.mjs +10 -16
  177. package/dist/type/elysia/file-type.d.ts +11 -4
  178. package/dist/type/elysia/file-type.js +17 -2
  179. package/dist/type/elysia/file-type.mjs +17 -3
  180. package/dist/type/elysia/file.d.ts +1 -3
  181. package/dist/type/elysia/file.js +11 -27
  182. package/dist/type/elysia/file.mjs +11 -12
  183. package/dist/type/elysia/files.js +7 -11
  184. package/dist/type/elysia/files.mjs +7 -10
  185. package/dist/type/elysia/form.js +2 -3
  186. package/dist/type/elysia/form.mjs +3 -3
  187. package/dist/type/elysia/integer-string.d.ts +1 -1
  188. package/dist/type/elysia/integer-string.js +4 -30
  189. package/dist/type/elysia/integer-string.mjs +5 -30
  190. package/dist/type/elysia/integer.js +3 -12
  191. package/dist/type/elysia/integer.mjs +3 -11
  192. package/dist/type/elysia/intersect.js +0 -5
  193. package/dist/type/elysia/intersect.mjs +0 -5
  194. package/dist/type/elysia/json-string.d.ts +7 -0
  195. package/dist/type/elysia/json-string.js +47 -0
  196. package/dist/type/elysia/json-string.mjs +46 -0
  197. package/dist/type/elysia/keep-config.d.ts +14 -0
  198. package/dist/type/elysia/keep-config.js +62 -0
  199. package/dist/type/elysia/keep-config.mjs +53 -0
  200. package/dist/type/elysia/maybe-empty.js +3 -4
  201. package/dist/type/elysia/maybe-empty.mjs +1 -1
  202. package/dist/type/elysia/nullable.js +2 -3
  203. package/dist/type/elysia/nullable.mjs +1 -1
  204. package/dist/type/elysia/number.d.ts +2 -1
  205. package/dist/type/elysia/number.js +19 -11
  206. package/dist/type/elysia/number.mjs +18 -10
  207. package/dist/type/elysia/numeric-enum.d.ts +1 -1
  208. package/dist/type/elysia/numeric-enum.js +4 -5
  209. package/dist/type/elysia/numeric-enum.mjs +3 -3
  210. package/dist/type/elysia/numeric.d.ts +4 -2
  211. package/dist/type/elysia/numeric.js +20 -17
  212. package/dist/type/elysia/numeric.mjs +19 -16
  213. package/dist/type/elysia/object-string.js +2 -37
  214. package/dist/type/elysia/object-string.mjs +2 -36
  215. package/dist/type/elysia/object.js +5 -9
  216. package/dist/type/elysia/object.mjs +5 -9
  217. package/dist/type/elysia/optional.js +8 -8
  218. package/dist/type/elysia/optional.mjs +7 -7
  219. package/dist/type/elysia/problem.d.ts +20 -0
  220. package/dist/type/elysia/problem.js +25 -0
  221. package/dist/type/elysia/problem.mjs +24 -0
  222. package/dist/type/elysia/string.js +4 -3
  223. package/dist/type/elysia/string.mjs +4 -2
  224. package/dist/type/elysia/uint8-array.d.ts +1 -1
  225. package/dist/type/elysia/uint8-array.js +5 -20
  226. package/dist/type/elysia/uint8-array.mjs +5 -19
  227. package/dist/type/elysia/union-enum.js +7 -8
  228. package/dist/type/elysia/union-enum.mjs +6 -6
  229. package/dist/type/elysia/union.js +0 -5
  230. package/dist/type/elysia/union.mjs +0 -5
  231. package/dist/type/elysia/utils.d.ts +2 -4
  232. package/dist/type/elysia/utils.js +10 -21
  233. package/dist/type/elysia/utils.mjs +7 -15
  234. package/dist/type/exports.d.ts +4 -2
  235. package/dist/type/exports.js +23 -2
  236. package/dist/type/exports.mjs +11 -2
  237. package/dist/type/index.d.ts +10 -2
  238. package/dist/type/index.js +62 -15
  239. package/dist/type/index.mjs +65 -11
  240. package/dist/type/shared.d.ts +3 -9
  241. package/dist/type/shared.js +44 -97
  242. package/dist/type/shared.mjs +43 -97
  243. package/dist/type/sync-require.d.ts +11 -0
  244. package/dist/type/sync-require.js +14 -0
  245. package/dist/type/sync-require.mjs +12 -0
  246. package/dist/type/typebox-system-lite.d.ts +2 -0
  247. package/dist/type/typebox-system-lite.js +34 -0
  248. package/dist/type/typebox-system-lite.mjs +3 -0
  249. package/dist/type/typebox-system-require.d.ts +7 -0
  250. package/dist/type/typebox-system-require.js +24 -0
  251. package/dist/type/typebox-system-require.mjs +23 -0
  252. package/dist/type/typebox-type-live.d.ts +11 -0
  253. package/dist/type/typebox-type-live.js +45 -0
  254. package/dist/type/typebox-type-live.mjs +20 -0
  255. package/dist/type/typebox-type.d.ts +34 -0
  256. package/dist/type/typebox-type.js +199 -0
  257. package/dist/type/typebox-type.mjs +86 -0
  258. package/dist/type/typebox-value-live.d.ts +11 -0
  259. package/dist/type/typebox-value-live.js +31 -0
  260. package/dist/type/typebox-value-live.mjs +13 -0
  261. package/dist/type/typebox-value-ops.d.ts +4 -0
  262. package/dist/type/typebox-value-ops.js +90 -0
  263. package/dist/type/typebox-value-ops.mjs +5 -0
  264. package/dist/type/typebox-value-require.d.ts +8 -0
  265. package/dist/type/typebox-value-require.js +28 -0
  266. package/dist/type/typebox-value-require.mjs +25 -0
  267. package/dist/type/typebox-value.d.ts +35 -0
  268. package/dist/type/typebox-value.js +161 -0
  269. package/dist/type/typebox-value.mjs +74 -0
  270. package/dist/type/utils.js +1 -10
  271. package/dist/type/utils.mjs +1 -10
  272. package/dist/type/validator/clean-safe.d.ts +2 -4
  273. package/dist/type/validator/clean-safe.js +15 -11
  274. package/dist/type/validator/clean-safe.mjs +16 -10
  275. package/dist/type/validator/custom-error.js +12 -16
  276. package/dist/type/validator/custom-error.mjs +11 -14
  277. package/dist/type/validator/default-precompute.d.ts +9 -1
  278. package/dist/type/validator/default-precompute.js +40 -77
  279. package/dist/type/validator/default-precompute.mjs +37 -74
  280. package/dist/type/validator/exact-mirror-live.d.ts +8 -0
  281. package/dist/type/validator/exact-mirror-live.js +22 -0
  282. package/dist/type/validator/exact-mirror-live.mjs +17 -0
  283. package/dist/type/validator/exact-mirror-require.d.ts +4 -0
  284. package/dist/type/validator/exact-mirror-require.js +11 -0
  285. package/dist/type/validator/exact-mirror-require.mjs +9 -0
  286. package/dist/type/validator/exact-mirror.js +8 -8
  287. package/dist/type/validator/exact-mirror.mjs +9 -8
  288. package/dist/type/validator/frozen-check.js +5 -6
  289. package/dist/type/validator/frozen-check.mjs +6 -7
  290. package/dist/type/validator/index.d.ts +1 -0
  291. package/dist/type/validator/index.js +169 -166
  292. package/dist/type/validator/index.mjs +162 -158
  293. package/dist/type/validator/string-codec-aot.d.ts +2 -1
  294. package/dist/type/validator/string-codec-aot.js +8 -2
  295. package/dist/type/validator/string-codec-aot.mjs +7 -2
  296. package/dist/type/validator/validator-cache.d.ts +5 -4
  297. package/dist/type/validator/validator-cache.js +41 -24
  298. package/dist/type/validator/validator-cache.mjs +40 -22
  299. package/dist/types.d.ts +263 -95
  300. package/dist/universal/constants.d.ts +2 -1
  301. package/dist/universal/constants.js +3 -1
  302. package/dist/universal/constants.mjs +2 -1
  303. package/dist/universal/env.js +2 -3
  304. package/dist/universal/env.mjs +2 -3
  305. package/dist/universal/file.d.ts +6 -4
  306. package/dist/universal/file.js +11 -16
  307. package/dist/universal/file.mjs +12 -16
  308. package/dist/universal/index.d.ts +2 -2
  309. package/dist/universal/is-production.d.ts +1 -2
  310. package/dist/universal/is-production.js +1 -3
  311. package/dist/universal/is-production.mjs +2 -3
  312. package/dist/universal/server.d.ts +0 -272
  313. package/dist/utils.d.ts +43 -7
  314. package/dist/utils.js +181 -126
  315. package/dist/utils.mjs +168 -126
  316. package/dist/validator/index.d.ts +1 -1
  317. package/dist/validator/index.js +17 -30
  318. package/dist/validator/index.mjs +18 -31
  319. package/dist/validator/route.js +2 -1
  320. package/dist/validator/route.mjs +2 -1
  321. package/dist/ws/context.d.ts +8 -1
  322. package/dist/ws/context.js +68 -44
  323. package/dist/ws/context.mjs +67 -44
  324. package/dist/ws/parser.js +10 -20
  325. package/dist/ws/parser.mjs +10 -20
  326. package/dist/ws/route.d.ts +2 -2
  327. package/dist/ws/route.js +249 -141
  328. package/dist/ws/route.mjs +254 -146
  329. package/dist/ws/types.d.ts +2 -2
  330. package/package.json +23 -49
  331. package/dist/compile/analysis-cache.d.ts +0 -6
  332. package/dist/compile/analysis-cache.js +0 -12
  333. package/dist/compile/analysis-cache.mjs +0 -11
  334. package/dist/cookie/index.d.ts +0 -7
  335. package/dist/cookie/index.js +0 -13
  336. package/dist/cookie/index.mjs +0 -7
  337. package/dist/handler/index.d.ts +0 -2
  338. package/dist/handler/index.js +0 -5
  339. package/dist/handler/index.mjs +0 -3
@@ -1,10 +1,10 @@
1
- import { isStandardSchema, mergeSchemasAllStandard } from "../../compile/handler/frozen-validator.mjs";
1
+ import { REQUEST_SLOTS, isResponseMap, isStandardSchema, mergeSchemasAllStandard, resolveModelRef } from "../../compile/handler/frozen-validator.mjs";
2
2
  import { composeRouteHook } from "../../compile/handler/index.mjs";
3
3
  import { captureArtifacts, compileToSource, replayStubbability } from "./source.mjs";
4
4
  import { createRequire } from "node:module";
5
- import { existsSync, realpathSync } from "node:fs";
6
- import { dirname, join, resolve } from "node:path";
7
- import { pathToFileURL } from "node:url";
5
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
6
+ import { dirname, extname, join, resolve } from "node:path";
7
+ import { fileURLToPath, pathToFileURL } from "node:url";
8
8
  import { Worker } from "node:worker_threads";
9
9
 
10
10
  //#region src/plugin/aot/core.ts
@@ -18,8 +18,31 @@ function findPackageRoot(from = process.cwd()) {
18
18
  return dir;
19
19
  }
20
20
  const resolveEntry = (entry) => resolve(findPackageRoot(), entry);
21
+ /** @internal Resolve the package condition used to evaluate an AOT entry. */
22
+ const resolveEntryModuleKind = (entry) => {
23
+ const entryPath = resolveEntry(entry);
24
+ switch (extname(entryPath)) {
25
+ case ".cjs":
26
+ case ".cts": return "cjs";
27
+ case ".mjs":
28
+ case ".mts":
29
+ case ".ts":
30
+ case ".tsx": return "esm";
31
+ case ".js":
32
+ case ".jsx": {
33
+ const packagePath = join(findPackageRoot(dirname(entryPath)), "package.json");
34
+ if (!existsSync(packagePath)) return "cjs";
35
+ const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
36
+ if (pkg.type === "module") return "esm";
37
+ if (pkg.type === void 0 || pkg.type === "commonjs") return "cjs";
38
+ throw new Error(`[elysia-aot] package.json has unsupported "type" ${JSON.stringify(pkg.type)} for JavaScript entry ${JSON.stringify(entryPath)}.`);
39
+ }
40
+ default: throw new Error(`[elysia-aot] entry ${JSON.stringify(entryPath)} has an ambiguous module condition. Use a .cjs/.cts CommonJS entry or a .mjs/.mts/.ts/.tsx ESM entry; .js/.jsx follows the nearest package.json "type".`);
41
+ }
42
+ };
21
43
  const NO_STUB = {
22
44
  jit: false,
45
+ staticClone: false,
23
46
  ws: false,
24
47
  reconstruct: false,
25
48
  cookie: false,
@@ -27,6 +50,8 @@ const NO_STUB = {
27
50
  sucrose: false,
28
51
  compat: false,
29
52
  bridge: false,
53
+ typeboxValue: false,
54
+ exactMirror: false,
30
55
  adapter: false,
31
56
  isProduction: false
32
57
  };
@@ -47,20 +72,23 @@ const NO_STUB = {
47
72
  * is not active, so the bridge must stay wired the ordinary way. No compat
48
73
  * stub, no reroute.
49
74
  */
50
- function planFromReport(strip, report, hasWS, mayTrace, aliases, allBridgeFree, zeroCapture, adapterStub = false, productionStub = true) {
75
+ function planFromReport(strip, report, hasWS, mayTrace, aliases, allBridgeFree, zeroCapture, adapterStub = false, productionStub = true, wsCookie = false, exactMirror = false) {
51
76
  const jit = report.jit;
52
77
  if (strip === true && !jit) throw new Error(`[elysia-aot] strip: true requires every route to be covered by the AOT handler manifest, but handler JIT is still reachable (${report.reasons.join(", ") || "unknown"}). Use strip: 'auto' to skip stubbing when the app is not fully precompiled.`);
53
78
  const mode = !jit ? "off" : allBridgeFree ? "sealed" : hasWS && zeroCapture ? "off" : "wired";
54
79
  return {
55
80
  plan: {
56
81
  jit,
82
+ staticClone: jit && !aliases.has("scl"),
57
83
  ws: !hasWS,
58
84
  reconstruct: jit && !aliases.has("va") && !aliases.has("cc") && !aliases.has("tr"),
59
- cookie: jit && !aliases.has("cc"),
85
+ cookie: jit && !aliases.has("cc") && !wsCookie,
60
86
  trace: !aliases.has("tr") && (jit || !mayTrace),
61
87
  sucrose: jit,
62
88
  compat: mode !== "off",
63
89
  bridge: mode === "wired",
90
+ typeboxValue: mode !== "sealed",
91
+ exactMirror: exactMirror && mode !== "sealed",
64
92
  adapter: adapterStub,
65
93
  isProduction: productionStub
66
94
  },
@@ -71,71 +99,48 @@ function adapterConstantsSource(target) {
71
99
  if (target === "bun") return "import { BunAdapter } from './bun/index'\nexport const defaultAdapter = BunAdapter\n";
72
100
  return "import { WebStandardAdapter } from './web-standard/index'\nexport const defaultAdapter = WebStandardAdapter\n";
73
101
  }
74
- /** Filter matching elysia's own `adapter/constants` module (src + dist). */
75
102
  const ADAPTER_CONSTANTS_FILTER = /[\\/]elysia[\\/](dist|src)[\\/]adapter[\\/]constants\.(m?js|ts)$/;
76
103
  const ADAPTER_BUN_FILTER = /[\\/]elysia[\\/](dist|src)[\\/]adapter[\\/]bun[\\/]index\.(m?js|ts)$/;
77
104
  const IS_PRODUCTION_FILTER = /[\\/]elysia[\\/](dist|src)[\\/]universal[\\/]is-production\.(m?js|ts)$/;
78
- /**
79
- * Loose fallback filter
80
- *
81
- * Matches the `/elysia/(dist|src)/` segment anywhere in a path (node_modules layouts,
82
- * monorepos, linked installs). Used by esbuild as a broad pre-filter
83
- *
84
- * The caller must further check that the path is under the resolved elysia package root
85
- * to avoid matching user code in a directory that happens to be named "elysia"
86
- *
87
- * @internal
88
- */
105
+ const TYPEBOX_TYPE_FILTER = /[\\/]elysia[\\/](dist|src)[\\/]type[\\/]typebox-type\.(m?js|ts)$/;
106
+ const TYPEBOX_SYSTEM_LITE_FILTER = /[\\/]elysia[\\/](dist|src)[\\/]type[\\/]typebox-system-lite\.(m?js|ts)$/;
107
+ const TYPEBOX_REQUIRE_FILTER = /[\\/]elysia[\\/](dist|src)[\\/]type[\\/]typebox-value-require\.(m?js|ts)$/;
108
+ const EXACT_MIRROR_REQUIRE_FILTER = /[\\/]elysia[\\/](dist|src)[\\/]type[\\/]validator[\\/]exact-mirror-require\.(m?js|ts)$/;
89
109
  const ELYSIA_MODULE_FILTER = /[\\/]elysia[\\/](dist|src)[\\/].+\.(m?js|ts)x?$/;
90
- /**
91
- * Build a predicate that returns `true` only for modules that are under the
92
- * resolved elysia package root (i.e. actually elysia's own files).
93
- *
94
- * Anchoring to the real package root prevents user projects rooted in a
95
- * directory named `elysia` (like this repo itself) from having their code
96
- * rewritten.
97
- *
98
- * Pass the result to both the esbuild `filter` (convert to RegExp via
99
- * `makeElysiaModuleFilterRegex`) and the Vite transform (`isElysiaModule`).
100
- */
101
- function resolveElysiaRoot(from = process.cwd()) {
110
+ function resolveElysiaRoot(from) {
102
111
  try {
103
112
  return dirname(createRequire(join(from, "package.json")).resolve("elysia/package.json"));
104
113
  } catch {
105
114
  return from;
106
115
  }
107
116
  }
108
- /**
109
- * Returns a predicate that is `true` only when the given module path is under
110
- * the resolved elysia package root AND matches the broad module filter.
111
- */
117
+ function resolveExactMirror(from) {
118
+ try {
119
+ createRequire(join(resolveElysiaRoot(from), "package.json")).resolve("exact-mirror");
120
+ return true;
121
+ } catch {
122
+ return false;
123
+ }
124
+ }
112
125
  function makeIsElysiaModule(elysiaRoot) {
113
126
  const root = elysiaRoot.replace(/\\/g, "/");
114
127
  return (path) => {
115
128
  return path.replace(/\\/g, "/").startsWith(root + "/") && ELYSIA_MODULE_FILTER.test(path);
116
129
  };
117
130
  }
118
- /**
119
- * Build an esbuild-compatible RegExp that anchors to the resolved elysia root
120
- * so the `onLoad` pre-filter is as tight as possible. esbuild uses this as an
121
- * initial path filter before calling the callback, so we still double-check
122
- * with `makeIsElysiaModule` inside the callback.
123
- */
124
- function makeElysiaModuleFilterRegex(elysiaRoot) {
125
- const escaped = elysiaRoot.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
126
- return new RegExp("^" + escaped + "[\\\\/](dist|src)[\\\\/].+\\.(m?js|ts)x?$");
127
- }
128
- function rewriteIsProductionCalls(code) {
129
- return code.replace(/(?<![.?])\bisProduction\(\)/g, "true");
130
- }
131
- const bunAdapterStubSource = "const e=(t)=>{throw new Error(`[elysia-aot] Bun adapter was stripped for target 'web-standard' .listen() is unavailable; use the exported fetch handler or rebuild with a different target.`)}\nexport const BunAdapter={name:'bun',runtime:'bun',isWebStandard:true,parse:{},response:{},listen:e}\nexport function collectStaticRoutes(){}\n";
131
+ const rewriteIsProductionCalls = (code) => code.replace(/(?<![.?])\bisProduction\(\)/g, "true");
132
+ const bunAdapterStubSource = "const e=(t)=>{throw new Error(`[elysia-aot] Bun adapter was stripped for target 'web-standard' .listen() is unavailable; use the exported fetch handler or rebuild with a different target.`)}\nexport const BunAdapter={parse:{},response:{},listen:e}\nexport function collectStaticRoutes(){}\n";
132
133
  const STUB_SOURCES = {
134
+ staticClone: [{
135
+ filter: /[\\/]elysia[\\/](dist|src)[\\/]compile[\\/]handler[\\/]static-clone-resolver\.(m?js|ts)$/,
136
+ source: `export const staticCloneResolver = undefined\n`
137
+ }],
133
138
  jit: [{
134
139
  filter: /[\\/]elysia[\\/](dist|src)[\\/]compile[\\/]handler[\\/]jit\.(m?js|ts)$/,
135
140
  source: "const e=()=>{throw new Error(\"[elysia-aot] handler compiler JIT was stripped (strip mode) but a route needed runtime compilation. Rebuild with strip:false.\")}\nexport function compileHandlerJit(){return e()}\nexport function createInlineHandler(){return e()}\nexport function setCaptureHeaderShorthand(){}\n"
136
141
  }, {
137
142
  filter: /[\\/]elysia[\\/](dist|src)[\\/]compile[\\/]handler[\\/]descriptor\.(m?js|ts)$/,
138
- source: "const e=()=>{throw new Error(\"[elysia-aot] handler compiler JIT was stripped (strip mode) but a route needed runtime compilation. Rebuild with strip:false.\")}\nexport function describeRoute(){return e()}\nexport const routeDescriptors=new WeakMap()\nexport function isEmptyPipelineHook(hook){\n if(!hook)return true\n for(const key in hook){\n if(key==='detail'||key==='tags')continue\n const value=hook[key]\n if(value!==undefined&&value!==false&&(!Array.isArray(value)||value.length))return false\n }\n return true\n}\n"
143
+ source: "const e=()=>{throw new Error(\"[elysia-aot] handler compiler JIT was stripped (strip mode) but a route needed runtime compilation. Rebuild with strip:false.\")}\nexport function describeRoute(){return e()}\nexport const routeDescriptors=new WeakMap()\n"
139
144
  }],
140
145
  ws: [{
141
146
  filter: /[\\/]elysia[\\/](dist|src)[\\/]ws[\\/]route\.(m?js|ts)$/,
@@ -145,13 +150,20 @@ const STUB_SOURCES = {
145
150
  filter: /[\\/]elysia[\\/](dist|src)[\\/]compile[\\/]handler[\\/]reconstruct\.(m?js|ts)$/,
146
151
  source: "const e=()=>{throw new Error(\"[elysia-aot] handler reconstruction was stripped (strip mode) but a route needed it. Rebuild with strip:false.\")}\nexport class Reconstrct {\n static validator(){return e()}\n static cookie(){return e()}\n static trace(){return e()}\n}\n"
147
152
  }],
148
- cookie: [{
149
- filter: /[\\/]elysia[\\/](dist|src)[\\/]cookie[\\/]utils\.(m?js|ts)$/,
150
- source: "const e=()=>{throw new Error(\"[elysia-aot] cookie support was stripped (strip mode) but a route used cookies. Rebuild with strip:false.\")}\nexport const hasSyncHmac=false\nexport function parseCookie(){return e()}\nexport function parseCookieRaw(){return e()}\nexport function parseCookieRawSync(){return e()}\nexport function parseCookieRawSigned(){return e()}\nexport function parseCookieRawLazy(){return e()}\nexport function parseCookieRawDeferred(){return e()}\nexport function buildCookieJar(){return e()}\nexport function signCookieValues(){return e()}\nexport function signCookie(){return e()}\nexport function signCookieSubtle(){return e()}\nexport function signCookieSync(){return e()}\nexport function unsignCookie(){return e()}\nexport function unsignCookieSync(){return e()}\n"
151
- }, {
152
- filter: /[\\/]elysia[\\/](dist|src)[\\/]cookie[\\/]config\.(m?js|ts)$/,
153
- source: "const e=()=>{throw new Error(\"[elysia-aot] cookie support was stripped (strip mode) but a route used cookies. Rebuild with strip:false.\")}\nexport function compileCookieConfig(){return e()}\nexport function isCookieSigned(){return e()}\n"
154
- }],
153
+ cookie: [
154
+ {
155
+ filter: /[\\/]elysia[\\/](dist|src)[\\/]cookie[\\/]crypto\.(m?js|ts)$/,
156
+ source: `export function resolvePendingCookie(){throw new Error("[elysia-aot] cookie support was stripped (strip mode) but a signed cookie was read. Rebuild with strip:false.")}\n`
157
+ },
158
+ {
159
+ filter: /[\\/]elysia[\\/](dist|src)[\\/]cookie[\\/]utils\.(m?js|ts)$/,
160
+ source: "const e=()=>{throw new Error(\"[elysia-aot] cookie support was stripped (strip mode) but a route used cookies. Rebuild with strip:false.\")}\nexport const hasSyncHmac=false\nexport function parseCookieRaw(){return e()}\nexport function parseCookieRawSync(){return e()}\nexport function parseCookieRawSigned(){return e()}\nexport function parseCookieRawLazy(){return e()}\nexport function parseCookieRawDeferred(){return e()}\nexport function buildCookieJar(){return e()}\nexport function signCookieValues(){return e()}\n"
161
+ },
162
+ {
163
+ filter: /[\\/]elysia[\\/](dist|src)[\\/]cookie[\\/]config\.(m?js|ts)$/,
164
+ source: "const e=()=>{throw new Error(\"[elysia-aot] cookie support was stripped (strip mode) but a route used cookies. Rebuild with strip:false.\")}\nexport function compileCookieConfig(){return e()}\n"
165
+ }
166
+ ],
155
167
  trace: [{
156
168
  filter: /[\\/]elysia[\\/](dist|src)[\\/]trace\.(m?js|ts)$/,
157
169
  source: "const e=()=>{throw new Error(\"[elysia-aot] trace support was stripped (strip mode) but a route used trace. Rebuild with strip:false.\")}\nexport function createTracer(){return e()}\nexport function unionTracePhases(){return new Set()}\n"
@@ -159,9 +171,6 @@ const STUB_SOURCES = {
159
171
  sucrose: [{
160
172
  filter: /[\\/]elysia[\\/](dist|src)[\\/]memory\.(m?js|ts)$/,
161
173
  source: "import { clearContextCache } from './context'\nimport { Validator } from './validator'\nexport function flushMemory() {\n clearContextCache()\n Validator.clear()\n}\n"
162
- }, {
163
- filter: /[\\/]elysia[\\/](dist|src)[\\/]compile[\\/]analysis-cache\.(m?js|ts)$/,
164
- source: "import { clearHandlerAnalysisCaches } from './handler/index'\nimport { clearFlattenChainMemo } from '../utils'\nexport function clearAuthoringAnalysisCaches(root) {\n clearHandlerAnalysisCaches(root)\n clearFlattenChainMemo(root)\n}\n"
165
174
  }],
166
175
  compat: [{
167
176
  filter: /[\\/]elysia[\\/](dist|src)[\\/]type[\\/]compat\.(m?js|ts)$/,
@@ -170,11 +179,23 @@ const STUB_SOURCES = {
170
179
  bridge: [{
171
180
  filter: /[\\/]elysia[\\/](dist|src)[\\/]type[\\/]bridge\.(m?js|ts)$/,
172
181
  source: `export * from './bridge-live'\n`
182
+ }],
183
+ typeboxValue: [{
184
+ filter: /[\\/]elysia[\\/](dist|src)[\\/]type[\\/]typebox-value\.(m?js|ts)$/,
185
+ source: `export * from './typebox-value-live'\n`
186
+ }],
187
+ exactMirror: [{
188
+ filter: /[\\/]elysia[\\/](dist|src)[\\/]type[\\/]validator[\\/]exact-mirror\.(m?js|ts)$/,
189
+ source: `export * from './exact-mirror-live'\n`
173
190
  }]
174
191
  };
175
192
  const alignStubExtensions = (stubSource, targetPath) => {
176
193
  const ext = targetPath.slice(targetPath.lastIndexOf("."));
177
194
  if (ext !== ".mjs" && ext !== ".js" && ext !== ".cjs") return stubSource;
195
+ if (ext !== ".mjs") {
196
+ const reexport = /^export \* from '(\.[^']+)'\n$/.exec(stubSource);
197
+ if (reexport) return `let m;const t=()=>m??=require('${reexport[1]}${ext}'),d=(o,k)=>Reflect.getOwnPropertyDescriptor(o,k)\nmodule.exports=new Proxy({},{get:(_,k)=>t()[k],has:(_,k)=>k in t(),ownKeys:()=>Reflect.ownKeys(t()),getOwnPropertyDescriptor:(o,k)=>{let x=d(o,k);if(x)return x;x=d(t(),k);if(x)x.configurable=true;return x},preventExtensions:o=>{for(const k of Reflect.ownKeys(t()))Object.defineProperty(o,k,d(t(),k));return Reflect.preventExtensions(o)}})\n`;
198
+ }
178
199
  return stubSource.replace(/(from ')(\.[^']+)(')/g, (_m, open, spec, close) => open + (spec === "./validator" ? spec + "/index" : spec) + ext + close);
179
200
  };
180
201
  const OVERRIDE_MAP = {
@@ -202,6 +223,10 @@ const OVERRIDE_MAP = {
202
223
  leaf: "boolean-string",
203
224
  export: "BooleanString"
204
225
  },
226
+ Composite: {
227
+ leaf: "keep-config",
228
+ export: "CompositeType"
229
+ },
205
230
  Cookie: {
206
231
  leaf: "cookie",
207
232
  export: "Cookie"
@@ -210,6 +235,10 @@ const OVERRIDE_MAP = {
210
235
  leaf: "date",
211
236
  export: "DateType"
212
237
  },
238
+ Evaluate: {
239
+ leaf: "keep-config",
240
+ export: "EvaluateType"
241
+ },
213
242
  File: {
214
243
  leaf: "file",
215
244
  export: "File"
@@ -230,10 +259,18 @@ const OVERRIDE_MAP = {
230
259
  leaf: "integer-string",
231
260
  export: "IntegerString"
232
261
  },
262
+ Interface: {
263
+ leaf: "keep-config",
264
+ export: "InterfaceType"
265
+ },
233
266
  Intersect: {
234
267
  leaf: "intersect",
235
268
  export: "Intersect"
236
269
  },
270
+ Mapped: {
271
+ leaf: "keep-config",
272
+ export: "MappedType"
273
+ },
237
274
  MaybeEmpty: {
238
275
  leaf: "maybe-empty",
239
276
  export: "MaybeEmpty"
@@ -266,10 +303,34 @@ const OVERRIDE_MAP = {
266
303
  leaf: "object-string",
267
304
  export: "ObjectString"
268
305
  },
306
+ Omit: {
307
+ leaf: "keep-config",
308
+ export: "OmitType"
309
+ },
269
310
  Optional: {
270
311
  leaf: "optional",
271
312
  export: "Optional"
272
313
  },
314
+ Partial: {
315
+ leaf: "keep-config",
316
+ export: "PartialType"
317
+ },
318
+ Pick: {
319
+ leaf: "keep-config",
320
+ export: "PickType"
321
+ },
322
+ Problem: {
323
+ leaf: "problem",
324
+ export: "Problem"
325
+ },
326
+ ReadonlyObject: {
327
+ leaf: "keep-config",
328
+ export: "ReadonlyObjectType"
329
+ },
330
+ Required: {
331
+ leaf: "keep-config",
332
+ export: "RequiredType"
333
+ },
273
334
  String: {
274
335
  leaf: "string",
275
336
  export: "StringType"
@@ -288,17 +349,20 @@ const OVERRIDE_MAP = {
288
349
  }
289
350
  };
290
351
  const requireFromHere = createRequire(import.meta.url);
291
- const resolveSpecifier = (specifier) => {
292
- const meta = import.meta;
293
- if (typeof meta.resolve === "function") {
294
- const url = meta.resolve(specifier);
295
- return url.startsWith("file://") ? new URL(url).pathname : url;
352
+ const moduleMeta = import.meta;
353
+ const loadedModuleCondition = import.meta.url.endsWith(".js") ? "cjs" : "esm";
354
+ const resolveSpecifier = (specifier, moduleCondition) => {
355
+ if (moduleCondition === "cjs") return requireFromHere.resolve(specifier);
356
+ if (moduleMeta.resolve) {
357
+ const url = moduleMeta.resolve(specifier);
358
+ return url.startsWith("file://") ? fileURLToPath(url) : url;
296
359
  }
360
+ if (moduleCondition === "esm") throw new Error("[elysia-aot] CommonJS-loaded build plugin cannot resolve the ESM package condition. Load the build plugin through import for an ESM entry.");
297
361
  return requireFromHere.resolve(specifier);
298
362
  };
299
- async function generateVirtualType(typeSpecifier = "elysia/type") {
300
- const typePath = resolveSpecifier(typeSpecifier);
301
- const typeboxPath = resolveSpecifier("typebox/type");
363
+ async function generateVirtualType(moduleCondition) {
364
+ const typePath = resolveSpecifier("elysia/type", moduleCondition);
365
+ const typeboxPath = resolveSpecifier("typebox/type", moduleCondition);
302
366
  const ext = typePath.slice(typePath.lastIndexOf("."));
303
367
  const leafDir = join(dirname(typePath), "elysia");
304
368
  const typebox = await import(pathToFileURL(typeboxPath).href);
@@ -314,13 +378,6 @@ async function generateVirtualType(typeSpecifier = "elysia/type") {
314
378
  return source;
315
379
  }
316
380
  const _importedEntries = /* @__PURE__ */ new Set();
317
- let activeGenerationWorkers = 0;
318
- let lastGenerationWorkerExit;
319
- /** @internal Test diagnostic for deterministic worker cleanup. */
320
- const getAotWorkerDiagnostics = () => ({
321
- activeWorkers: activeGenerationWorkers,
322
- lastExit: lastGenerationWorkerExit
323
- });
324
381
  /**
325
382
  * Extension mirroring the running module's own build output, so a sibling
326
383
  * source file can be resolved from `import.meta.url` in `.mjs`/`.js`/`.ts`
@@ -334,16 +391,15 @@ const workerUrl = () => {
334
391
  return new URL("./worker" + siblingModuleExt(moduleUrl), moduleUrl);
335
392
  };
336
393
  /** @internal Re-evaluate an entry in a disposable worker for watch rebuilds. */
337
- async function generateCompiledArtifactsIsolated(file, options) {
394
+ async function generateCompiledArtifactsIsolated(file, options, moduleCondition = resolveEntryModuleKind(file)) {
338
395
  const entry = resolveEntry(file);
339
396
  console.warn("[elysia-aot] re-evaluating \"" + entry + "\" in an isolated worker for rebuild. Top-level side effects run only inside the worker.");
340
397
  const worker = new Worker(workerUrl(), { workerData: {
341
398
  file: entry,
342
- options
399
+ options,
400
+ moduleCondition
343
401
  } });
344
- activeGenerationWorkers++;
345
402
  const exit = new Promise((resolve) => worker.once("exit", resolve));
346
- lastGenerationWorkerExit = exit;
347
403
  try {
348
404
  return await new Promise((resolve, reject) => {
349
405
  let received = false;
@@ -365,19 +421,34 @@ async function generateCompiledArtifactsIsolated(file, options) {
365
421
  await worker.terminate();
366
422
  } finally {
367
423
  await exit;
368
- activeGenerationWorkers--;
369
424
  }
370
425
  }
371
426
  }
372
- function isStandardResponse(response) {
373
- if (response == null || typeof response !== "object") return false;
374
- if (isStandardSchema(response)) return true;
375
- if ("~kind" in response || "~elyAcl" in response) return false;
376
- const entries = Object.values(response);
377
- if (entries.length === 0) return false;
378
- return entries.every((v) => isStandardSchema(v));
427
+ const validatorSlotKey = ({ method, path, slot }) => `${method}\0${path}\0${slot}`;
428
+ /** @internal Exact logical-slot gate used by AOT mode selection. */
429
+ function validatorSlotSetsMatch(expected, captured) {
430
+ const expectedKeys = new Set(expected.map(validatorSlotKey));
431
+ const capturedKeys = new Set(captured.map(validatorSlotKey));
432
+ if (expectedKeys.size !== capturedKeys.size) return false;
433
+ for (const key of expectedKeys) if (!capturedKeys.has(key)) return false;
434
+ return true;
379
435
  }
380
- async function generateCompiledArtifacts(file, options) {
436
+ /**
437
+ * The manifest is one flat `method -> path` table with no per-app namespace,
438
+ * bound to whichever app builds a router first, so a mounted sub-app (a second
439
+ * Elysia building on its own schedule) is not representable
440
+ *
441
+ * refuse at build time rather than ship a coin flip
442
+ */
443
+ const assertNoMount = (app, entry) => {
444
+ const routes = app["~routes"];
445
+ const mounted = [];
446
+ for (const route of routes) if (route[2]?.["~mount"] && !mounted.includes(route[1])) mounted.push(route[1]);
447
+ if (!mounted.length) return;
448
+ throw new Error(`[elysia-aot] "${entry}" mounts a sub-app (${mounted.join(", ")}). AOT cannot compile a mounted sub-app. Compose with .use() instead of .mount(), or disable AOT plugin`);
449
+ };
450
+ async function generateCompiledArtifacts(file, options, moduleCondition = resolveEntryModuleKind(file)) {
451
+ if (moduleCondition !== loadedModuleCondition) throw new Error(`[elysia-aot] entry uses the ${moduleCondition === "cjs" ? "CommonJS \"require\"" : "ESM \"import\""} package condition, but the AOT build plugin was loaded through ${loadedModuleCondition === "cjs" ? "CommonJS \"require\"" : "ESM \"import\""}; entry: ${JSON.stringify(resolveEntry(file))}. Load the plugin through ${moduleCondition === "cjs" ? "require()" : "import"} so capture and generated registration share one Elysia module instance.`);
381
452
  const previousAotBuild = process.env.ELYSIA_AOT_BUILD;
382
453
  process.env.ELYSIA_AOT_BUILD = "1";
383
454
  const previousAotVerbose = process.env.ELYSIA_AOT_VERBOSE;
@@ -386,14 +457,15 @@ async function generateCompiledArtifacts(file, options) {
386
457
  try {
387
458
  const entry = resolveEntry(file);
388
459
  const entryReal = realPath(entry);
389
- if (_importedEntries.has(entryReal)) return generateCompiledArtifactsIsolated(file, options);
460
+ if (_importedEntries.has(entryReal)) return generateCompiledArtifactsIsolated(file, options, moduleCondition);
390
461
  _importedEntries.add(entryReal);
391
462
  const mod = await import(entry);
392
463
  const app = mod.app ?? mod.default;
393
464
  if (!app || typeof app.compile !== "function") throw new Error(`[elysia-aot] "${entry}" must export an Elysia app`);
394
465
  const typedApp = app;
466
+ assertNoMount(typedApp, entry);
395
467
  const sourceOptions = {
396
- register: true,
468
+ moduleCondition,
397
469
  registerFrom: options?.registerFrom,
398
470
  reconstructFrom: options?.reconstructFrom,
399
471
  lazy: options?.lazy,
@@ -402,10 +474,13 @@ async function generateCompiledArtifacts(file, options) {
402
474
  const strip = options?.strip ?? "auto";
403
475
  const adapterStub = options?.target === "bun" ? "bun" : options?.target === "node" || options?.target === "workerd" ? "web-standard" : false;
404
476
  const productionStub = options?.production !== false;
477
+ const exactMirror = resolveExactMirror(entry);
405
478
  if (strip === false) return {
406
479
  source: await compileToSource(typedApp, sourceOptions),
407
480
  stub: {
408
481
  ...NO_STUB,
482
+ typeboxValue: true,
483
+ exactMirror,
409
484
  adapter: adapterStub,
410
485
  isProduction: productionStub
411
486
  },
@@ -415,32 +490,51 @@ async function generateCompiledArtifacts(file, options) {
415
490
  const report = replayStubbability(typedApp, artifacts.handlers);
416
491
  const aliases = /* @__PURE__ */ new Set();
417
492
  for (const handler of artifacts.handlers) if (handler.alias) for (const name of handler.alias.split(",")) aliases.add(name);
418
- const hasWS = !!typedApp["~hasWS"] || !!typedApp["~routes"]?.some((route) => route?.[0] === "WS");
419
- const history = typedApp["~routes"] ?? [];
493
+ const history = typedApp["~routes"];
494
+ const hasWS = !!typedApp["~hasWS"] || history.some((route) => route[0] === "WS");
420
495
  const mayTrace = !!typedApp["~hasTrace"] || history.some((route) => (route?.[4])?.trace?.length || route?.[2]?.["~mount"]);
421
- let expectedSlots = 0;
496
+ const expectedSlots = [];
497
+ const declaredTypeBoxSlots = /* @__PURE__ */ new Set();
422
498
  let routesForbidSeal = false;
499
+ let wsCookie = false;
423
500
  for (const route of history) {
501
+ const method = route[0];
502
+ const path = route[1];
503
+ const expectTypeBoxSlot = (slot) => {
504
+ const identity = {
505
+ method,
506
+ path,
507
+ slot
508
+ };
509
+ const key = validatorSlotKey(identity);
510
+ if (declaredTypeBoxSlots.has(key)) routesForbidSeal = true;
511
+ else {
512
+ declaredTypeBoxSlots.add(key);
513
+ expectedSlots.push(identity);
514
+ }
515
+ };
424
516
  const [, , , instance, hook, appHook, inheritedChain, macroScope] = route;
425
517
  const hooks = composeRouteHook(instance, hook, appHook, inheritedChain, typedApp, macroScope);
518
+ if (method === "WS" && (hook?.cookie !== void 0 || hooks?.cookie !== void 0)) wsCookie = true;
426
519
  if (!hooks) continue;
427
520
  let routeHasTypeBoxDirectSlot = false;
428
- for (const slot of [
429
- "body",
430
- "query",
431
- "params",
432
- "headers",
433
- "cookie"
434
- ]) {
435
- const value = hooks[slot];
436
- if (value === void 0) continue;
437
- if (isStandardSchema(value)) continue;
521
+ const classify = (schema, slot) => {
522
+ if (schema === void 0) {
523
+ routesForbidSeal = true;
524
+ return;
525
+ }
526
+ if (isStandardSchema(schema)) return;
438
527
  routeHasTypeBoxDirectSlot = true;
439
- expectedSlots++;
528
+ expectTypeBoxSlot(slot);
529
+ };
530
+ for (const slot of REQUEST_SLOTS) {
531
+ const value = hooks[slot];
532
+ if (value !== void 0) classify(resolveModelRef(value, typedApp), slot);
440
533
  }
441
- if (hooks.response !== void 0 && !isStandardResponse(hooks.response)) {
442
- routeHasTypeBoxDirectSlot = true;
443
- expectedSlots++;
534
+ if (hooks.response !== void 0) {
535
+ const response = resolveModelRef(hooks.response, typedApp);
536
+ if (isResponseMap(response)) for (const status in response) classify(resolveModelRef(response[status], typedApp), `response:${status}`);
537
+ else classify(response, "response:200");
444
538
  }
445
539
  const mergeSchemas = hooks.schemas;
446
540
  if (Array.isArray(mergeSchemas) && mergeSchemas.length > 0) {
@@ -448,13 +542,13 @@ async function generateCompiledArtifacts(file, options) {
448
542
  }
449
543
  }
450
544
  if (typedApp["~config"]?.normalize === "typebox") routesForbidSeal = true;
451
- const frozenSlots = artifacts.validators.length;
452
- const { plan: stub, mode } = planFromReport(strip, report, hasWS, mayTrace, aliases, (artifacts.handlers.length > 0 || artifacts.validators.length > 0) && !routesForbidSeal && frozenSlots === expectedSlots && artifacts.validators.every((v) => v.bridgeFree === true), artifacts.handlers.length === 0 && artifacts.validators.length === 0, adapterStub, productionStub);
545
+ const validatorSlotsMatch = validatorSlotSetsMatch(expectedSlots, artifacts.validators);
546
+ const { plan: stub, mode } = planFromReport(strip, report, hasWS, mayTrace, aliases, (artifacts.handlers.some((h) => h.code) || artifacts.validators.length > 0) && !routesForbidSeal && validatorSlotsMatch && artifacts.validators.every((v) => v.bridgeFree === true), !artifacts.handlers.some((h) => h.code) && artifacts.validators.length === 0, adapterStub, productionStub, wsCookie, exactMirror);
453
547
  if (options?.target === "workerd") {
454
548
  if (!report.jit) throw new Error(`[elysia-aot] target 'workerd' but handler JIT is still reachable (${report.reasons.join(", ") || "unknown"}). Every route must be captured into the AOT manifest.`);
455
- if (frozenSlots !== expectedSlots) console.warn(`[elysia-aot] target 'workerd': only ${frozenSlots}/${expectedSlots} validator slots were frozen unfrozen slots compile at runtime and will fail on workerd.`);
549
+ if (!validatorSlotsMatch) console.warn("[elysia-aot] target 'workerd': captured validator slots do not exactly match declared slots; unfrozen slots compile at runtime and will fail on workerd.");
456
550
  }
457
- const virtualType = mode === "off" ? void 0 : await generateVirtualType("elysia/type");
551
+ const virtualType = mode === "off" ? void 0 : await generateVirtualType(moduleCondition);
458
552
  return {
459
553
  source: artifacts.source,
460
554
  stub,
@@ -478,4 +572,4 @@ const realPath = (path) => {
478
572
  };
479
573
 
480
574
  //#endregion
481
- export { ADAPTER_BUN_FILTER, ADAPTER_CONSTANTS_FILTER, ELYSIA_MODULE_FILTER, IS_PRODUCTION_FILTER, NO_STUB, OVERRIDE_MAP, SOURCE_REGEX, STUB_SOURCES, adapterConstantsSource, alignStubExtensions, bunAdapterStubSource, generateCompiledArtifacts, generateCompiledArtifactsIsolated, generateVirtualType, getAotWorkerDiagnostics, makeElysiaModuleFilterRegex, makeIsElysiaModule, planFromReport, realPath, resolveElysiaRoot, resolveEntry, rewriteIsProductionCalls, siblingModuleExt };
575
+ export { ADAPTER_BUN_FILTER, ADAPTER_CONSTANTS_FILTER, ELYSIA_MODULE_FILTER, EXACT_MIRROR_REQUIRE_FILTER, IS_PRODUCTION_FILTER, NO_STUB, OVERRIDE_MAP, SOURCE_REGEX, STUB_SOURCES, TYPEBOX_REQUIRE_FILTER, TYPEBOX_SYSTEM_LITE_FILTER, TYPEBOX_TYPE_FILTER, adapterConstantsSource, alignStubExtensions, bunAdapterStubSource, generateCompiledArtifacts, generateCompiledArtifactsIsolated, generateVirtualType, makeIsElysiaModule, planFromReport, realPath, resolveElysiaRoot, resolveEntry, resolveEntryModuleKind, resolveExactMirror, rewriteIsProductionCalls, siblingModuleExt, validatorSlotSetsMatch };
@@ -28,7 +28,11 @@ let node_fs_promises = require("node:fs/promises");
28
28
  const aot = (entry, options) => ({
29
29
  name: "elysia-aot",
30
30
  async setup(build) {
31
- const hooks = require_plugin_aot_hooks.createAotPluginHooks(entry, options);
31
+ const entryPath = require_plugin_aot_core.resolveEntry(entry);
32
+ const moduleCondition = require_plugin_aot_core.resolveEntryModuleKind(entryPath);
33
+ if (build.initialOptions?.conditions?.includes("types")) throw new Error("[elysia-aot] esbuild conditions includes 'types'; this selects declaration files as runtime inputs. Remove the conflicting condition.");
34
+ if (moduleCondition === "cjs" && build.initialOptions?.conditions?.includes("import")) throw new Error("[elysia-aot] esbuild conditions includes 'import' for a CommonJS entry; this would load two Elysia module instances. Remove the conflicting condition.");
35
+ const hooks = require_plugin_aot_hooks.createAotPluginHooks(entry, options, moduleCondition);
32
36
  let initial = true;
33
37
  build.onStart(async () => {
34
38
  if (initial) {
@@ -37,10 +41,9 @@ const aot = (entry, options) => ({
37
41
  }
38
42
  await hooks.buildStart();
39
43
  });
40
- await require_plugin_aot_hooks.setupAotOnLoad(build, hooks, {
41
- readText: (path) => (0, node_fs_promises.readFile)(path, "utf8"),
42
- resolveDir: (0, node_path.dirname)(require_plugin_aot_core.resolveEntry(entry))
43
- });
44
+ await require_plugin_aot_hooks.setupAotOnLoad(build, hooks, (path) => (0, node_fs_promises.readFile)(path, "utf8"), (0, node_path.dirname)(entryPath));
45
+ const allowedKinds = moduleCondition === "cjs" ? new Set(["require-call", "require-resolve"]) : new Set(["import-statement", "dynamic-import"]);
46
+ build.onResolve({ filter: /^elysia(?:\/.*)?$/ }, (args) => allowedKinds.has(args.kind) ? void 0 : { errors: [{ text: `[elysia-aot] ${args.path} uses esbuild edge kind ${JSON.stringify(args.kind)}, which conflicts with the ${JSON.stringify(moduleCondition)} entry module condition. Use one consistent import/require condition for Elysia.` }] });
44
47
  }
45
48
  });
46
49
 
@@ -1,4 +1,4 @@
1
- import { resolveEntry } from "./core.mjs";
1
+ import { resolveEntry, resolveEntryModuleKind } from "./core.mjs";
2
2
  import { createAotPluginHooks, setupAotOnLoad } from "./hooks.mjs";
3
3
  import { dirname } from "node:path";
4
4
  import { readFile } from "node:fs/promises";
@@ -26,7 +26,11 @@ import { readFile } from "node:fs/promises";
26
26
  const aot = (entry, options) => ({
27
27
  name: "elysia-aot",
28
28
  async setup(build) {
29
- const hooks = createAotPluginHooks(entry, options);
29
+ const entryPath = resolveEntry(entry);
30
+ const moduleCondition = resolveEntryModuleKind(entryPath);
31
+ if (build.initialOptions?.conditions?.includes("types")) throw new Error("[elysia-aot] esbuild conditions includes 'types'; this selects declaration files as runtime inputs. Remove the conflicting condition.");
32
+ if (moduleCondition === "cjs" && build.initialOptions?.conditions?.includes("import")) throw new Error("[elysia-aot] esbuild conditions includes 'import' for a CommonJS entry; this would load two Elysia module instances. Remove the conflicting condition.");
33
+ const hooks = createAotPluginHooks(entry, options, moduleCondition);
30
34
  let initial = true;
31
35
  build.onStart(async () => {
32
36
  if (initial) {
@@ -35,10 +39,9 @@ const aot = (entry, options) => ({
35
39
  }
36
40
  await hooks.buildStart();
37
41
  });
38
- await setupAotOnLoad(build, hooks, {
39
- readText: (path) => readFile(path, "utf8"),
40
- resolveDir: dirname(resolveEntry(entry))
41
- });
42
+ await setupAotOnLoad(build, hooks, (path) => readFile(path, "utf8"), dirname(entryPath));
43
+ const allowedKinds = moduleCondition === "cjs" ? new Set(["require-call", "require-resolve"]) : new Set(["import-statement", "dynamic-import"]);
44
+ build.onResolve({ filter: /^elysia(?:\/.*)?$/ }, (args) => allowedKinds.has(args.kind) ? void 0 : { errors: [{ text: `[elysia-aot] ${args.path} uses esbuild edge kind ${JSON.stringify(args.kind)}, which conflicts with the ${JSON.stringify(moduleCondition)} entry module condition. Use one consistent import/require condition for Elysia.` }] });
42
45
  }
43
46
  });
44
47
 
@@ -1,3 +1,4 @@
1
+ import { AotModuleCondition } from "./source.js";
1
2
  import { ElysiaAotOptions } from "./core.js";
2
3
 
3
4
  //#region src/plugin/aot/hooks.d.ts
@@ -6,23 +7,11 @@ interface AotPluginHooks {
6
7
  buildEnd(): void;
7
8
  resolveId(id: string): string | undefined;
8
9
  load(id: string): string | undefined;
9
- transform(code: string, id: string): string | undefined | Promise<string | undefined>;
10
+ transform(code: string, id: string): string | undefined;
10
11
  isTransformCandidate(id: string): boolean;
11
12
  }
12
- declare const createAotPluginHooks: (entry: string, options?: ElysiaAotOptions) => AotPluginHooks;
13
- interface AotOnLoadAdapterOptions {
14
- /** Read a file's UTF-8 text (abstracted so Bun and esbuild can supply their own reader). */
15
- readText: (path: string) => Promise<string>;
16
- /**
17
- * resolveDir for the manifest/virtual-type module loads.
18
- * esbuild needs `dirname(entryPath)` so relative imports in the manifest
19
- * resolve correctly; Bun does not use it (pass undefined for Bun).
20
- */
21
- resolveDir?: string;
22
- }
23
- declare function setupAotOnLoad(build: any, hooks: AotPluginHooks, {
24
- readText,
25
- resolveDir
26
- }: AotOnLoadAdapterOptions): Promise<void>;
13
+ declare const createAotPluginHooks: (entry: string, options?: ElysiaAotOptions, moduleCondition?: AotModuleCondition) => AotPluginHooks;
14
+ declare const createTypeboxWiringHooks: () => AotPluginHooks;
15
+ declare function setupAotOnLoad(build: any, hooks: AotPluginHooks, readText: (path: string) => Promise<string>, resolveDir?: string): Promise<void>;
27
16
  //#endregion
28
- export { AotOnLoadAdapterOptions, AotPluginHooks, createAotPluginHooks, setupAotOnLoad };
17
+ export { AotPluginHooks, createAotPluginHooks, createTypeboxWiringHooks, setupAotOnLoad };