elysia 2.0.0-beta.1 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/dist/adapter/utils.d.ts +2 -2
  2. package/dist/adapter/utils.js +3 -3
  3. package/dist/adapter/utils.mjs +4 -4
  4. package/dist/adapter/web-standard/handler.js +14 -7
  5. package/dist/adapter/web-standard/handler.mjs +15 -8
  6. package/dist/base.d.ts +20 -5
  7. package/dist/base.js +73 -42
  8. package/dist/base.mjs +74 -43
  9. package/dist/compile/aot-capture.js +1 -1
  10. package/dist/compile/aot-capture.mjs +2 -2
  11. package/dist/compile/aot.d.ts +4 -4
  12. package/dist/compile/aot.js +14 -9
  13. package/dist/compile/aot.mjs +15 -9
  14. package/dist/compile/handler/descriptor.d.ts +1 -1
  15. package/dist/compile/handler/descriptor.js +1 -1
  16. package/dist/compile/handler/descriptor.mjs +1 -1
  17. package/dist/compile/handler/frozen-validator.d.ts +2 -1
  18. package/dist/compile/handler/frozen-validator.js +33 -3
  19. package/dist/compile/handler/frozen-validator.mjs +33 -4
  20. package/dist/compile/handler/index.d.ts +3 -3
  21. package/dist/compile/handler/index.js +6 -4
  22. package/dist/compile/handler/index.mjs +6 -4
  23. package/dist/compile/handler/jit.js +5 -8
  24. package/dist/compile/handler/jit.mjs +6 -9
  25. package/dist/compile/handler/params.js +3 -3
  26. package/dist/compile/handler/params.mjs +4 -4
  27. package/dist/compile/handler/utils.d.ts +1 -1
  28. package/dist/compile/handler/utils.js +7 -4
  29. package/dist/compile/handler/utils.mjs +8 -5
  30. package/dist/context.d.ts +2 -2
  31. package/dist/context.js +3 -4
  32. package/dist/context.mjs +3 -4
  33. package/dist/cookie/config.d.ts +1 -0
  34. package/dist/cookie/config.js +3 -2
  35. package/dist/cookie/config.mjs +3 -2
  36. package/dist/cookie/cookie.d.ts +1 -0
  37. package/dist/cookie/cookie.js +7 -5
  38. package/dist/cookie/cookie.mjs +7 -5
  39. package/dist/cookie/crypto.d.ts +8 -7
  40. package/dist/cookie/crypto.js +38 -31
  41. package/dist/cookie/crypto.mjs +38 -32
  42. package/dist/cookie/error.js +1 -2
  43. package/dist/cookie/error.mjs +1 -2
  44. package/dist/cookie/lib.js +5 -1
  45. package/dist/cookie/lib.mjs +5 -1
  46. package/dist/cookie/serialize.js +1 -1
  47. package/dist/cookie/serialize.mjs +1 -1
  48. package/dist/cookie/types.d.ts +10 -0
  49. package/dist/cookie/utils.js +28 -14
  50. package/dist/cookie/utils.mjs +29 -15
  51. package/dist/error.d.ts +139 -6
  52. package/dist/error.js +73 -0
  53. package/dist/error.mjs +73 -1
  54. package/dist/handler/error.d.ts +31 -1
  55. package/dist/handler/error.js +123 -8
  56. package/dist/handler/error.mjs +118 -9
  57. package/dist/handler/fetch.js +15 -12
  58. package/dist/handler/fetch.mjs +16 -13
  59. package/dist/handler/utils.js +4 -2
  60. package/dist/handler/utils.mjs +5 -3
  61. package/dist/index.d.ts +4 -4
  62. package/dist/index.js +2 -8
  63. package/dist/index.mjs +2 -2
  64. package/dist/package.js +1 -1
  65. package/dist/package.mjs +1 -1
  66. package/dist/plugin/aot/core.d.ts +26 -4
  67. package/dist/plugin/aot/core.js +36 -4
  68. package/dist/plugin/aot/core.mjs +36 -4
  69. package/dist/route-table.d.ts +1 -1
  70. package/dist/route-table.js +12 -10
  71. package/dist/route-table.mjs +12 -10
  72. package/dist/sucrose.js +118 -16
  73. package/dist/sucrose.mjs +118 -16
  74. package/dist/type/bridge-live.d.ts +1 -1
  75. package/dist/type/bridge-live.js +1 -1
  76. package/dist/type/bridge-live.mjs +1 -1
  77. package/dist/type/bridge.d.ts +6 -6
  78. package/dist/type/coerce-plan.js +3 -4
  79. package/dist/type/coerce-plan.mjs +1 -1
  80. package/dist/type/coerce.js +9 -4
  81. package/dist/type/coerce.mjs +9 -4
  82. package/dist/type/compat.d.ts +3 -0
  83. package/dist/type/compat.js +32 -14
  84. package/dist/type/compat.mjs +27 -8
  85. package/dist/type/elysia/array-buffer.js +2 -3
  86. package/dist/type/elysia/array-buffer.mjs +1 -1
  87. package/dist/type/elysia/array-string.js +35 -5
  88. package/dist/type/elysia/array-string.mjs +36 -5
  89. package/dist/type/elysia/boolean-string.js +2 -3
  90. package/dist/type/elysia/boolean-string.mjs +1 -1
  91. package/dist/type/elysia/boolean.js +4 -3
  92. package/dist/type/elysia/boolean.mjs +4 -2
  93. package/dist/type/elysia/cookie.js +2 -1
  94. package/dist/type/elysia/cookie.mjs +2 -1
  95. package/dist/type/elysia/date.js +7 -7
  96. package/dist/type/elysia/date.mjs +3 -2
  97. package/dist/type/elysia/file-type.d.ts +9 -2
  98. package/dist/type/elysia/file-type.js +27 -2
  99. package/dist/type/elysia/file-type.mjs +27 -3
  100. package/dist/type/elysia/file.js +8 -4
  101. package/dist/type/elysia/file.mjs +8 -3
  102. package/dist/type/elysia/files.js +6 -4
  103. package/dist/type/elysia/files.mjs +5 -2
  104. package/dist/type/elysia/form.js +3 -3
  105. package/dist/type/elysia/form.mjs +5 -4
  106. package/dist/type/elysia/integer-string.js +4 -5
  107. package/dist/type/elysia/integer-string.mjs +3 -3
  108. package/dist/type/elysia/integer.js +4 -3
  109. package/dist/type/elysia/integer.mjs +4 -2
  110. package/dist/type/elysia/maybe-empty.js +3 -4
  111. package/dist/type/elysia/maybe-empty.mjs +1 -1
  112. package/dist/type/elysia/nullable.js +2 -3
  113. package/dist/type/elysia/nullable.mjs +1 -1
  114. package/dist/type/elysia/number.js +4 -3
  115. package/dist/type/elysia/number.mjs +4 -2
  116. package/dist/type/elysia/numeric-enum.js +2 -3
  117. package/dist/type/elysia/numeric-enum.mjs +1 -1
  118. package/dist/type/elysia/numeric.js +5 -5
  119. package/dist/type/elysia/numeric.mjs +3 -2
  120. package/dist/type/elysia/object-string.js +32 -5
  121. package/dist/type/elysia/object-string.mjs +33 -5
  122. package/dist/type/elysia/string.js +4 -3
  123. package/dist/type/elysia/string.mjs +4 -2
  124. package/dist/type/elysia/uint8-array.js +2 -3
  125. package/dist/type/elysia/uint8-array.mjs +1 -1
  126. package/dist/type/elysia/union-enum.js +2 -3
  127. package/dist/type/elysia/union-enum.mjs +1 -1
  128. package/dist/type/elysia/utils.js +2 -3
  129. package/dist/type/elysia/utils.mjs +1 -1
  130. package/dist/type/exports.js +10 -1
  131. package/dist/type/exports.mjs +7 -0
  132. package/dist/type/index.d.ts +9 -1
  133. package/dist/type/index.js +41 -13
  134. package/dist/type/index.mjs +44 -9
  135. package/dist/type/typebox-type-live.d.ts +9 -0
  136. package/dist/type/typebox-type-live.js +31 -0
  137. package/dist/type/typebox-type-live.mjs +16 -0
  138. package/dist/type/typebox-type.d.ts +24 -0
  139. package/dist/type/typebox-type.js +130 -0
  140. package/dist/type/typebox-type.mjs +66 -0
  141. package/dist/type/typebox-value-live.d.ts +9 -0
  142. package/dist/type/typebox-value-live.js +27 -0
  143. package/dist/type/typebox-value-live.mjs +11 -0
  144. package/dist/type/typebox-value.d.ts +30 -0
  145. package/dist/type/typebox-value.js +147 -0
  146. package/dist/type/typebox-value.mjs +62 -0
  147. package/dist/type/validator/custom-error.js +4 -5
  148. package/dist/type/validator/custom-error.mjs +3 -3
  149. package/dist/type/validator/default-precompute.js +4 -5
  150. package/dist/type/validator/default-precompute.mjs +1 -1
  151. package/dist/type/validator/index.js +52 -48
  152. package/dist/type/validator/index.mjs +35 -30
  153. package/dist/type/validator/validator-cache.js +10 -5
  154. package/dist/type/validator/validator-cache.mjs +10 -4
  155. package/dist/types.d.ts +104 -18
  156. package/dist/universal/constants.d.ts +2 -1
  157. package/dist/universal/constants.js +3 -1
  158. package/dist/universal/constants.mjs +2 -1
  159. package/dist/universal/file.js +1 -0
  160. package/dist/universal/file.mjs +1 -0
  161. package/dist/universal/index.d.ts +1 -1
  162. package/dist/utils.d.ts +12 -5
  163. package/dist/utils.js +25 -12
  164. package/dist/utils.mjs +19 -12
  165. package/dist/validator/index.js +2 -1
  166. package/dist/validator/index.mjs +2 -1
  167. package/dist/ws/context.d.ts +4 -0
  168. package/dist/ws/context.js +44 -26
  169. package/dist/ws/context.mjs +44 -26
  170. package/dist/ws/route.js +127 -24
  171. package/dist/ws/route.mjs +128 -25
  172. package/package.json +5 -3
@@ -1,6 +1,6 @@
1
1
  import { BaseCookie } from "../cookie/types.js";
2
- import { StatusMap } from "../constants.js";
3
2
  import { ElysiaFile } from "../universal/file.js";
3
+ import { StatusMap } from "../constants.js";
4
4
  import { HTTPHeaders } from "../types.js";
5
5
  import { Context } from "../context.js";
6
6
  //#region src/adapter/utils.d.ts
@@ -14,7 +14,7 @@ declare function responseToSetHeaders(response: Response, set?: Context['set']):
14
14
  cookie?: Record<string, BaseCookie>;
15
15
  } | {
16
16
  headers: any;
17
- status: number | "Not Found" | "Continue" | "Switching Protocols" | "Processing" | "Early Hints" | "OK" | "Created" | "Accepted" | "Non-Authoritative Information" | "No Content" | "Reset Content" | "Partial Content" | "Multi-Status" | "Already Reported" | "Multiple Choices" | "Moved Permanently" | "Found" | "See Other" | "Not Modified" | "Temporary Redirect" | "Permanent Redirect" | "Bad Request" | "Unauthorized" | "Payment Required" | "Forbidden" | "Method Not Allowed" | "Not Acceptable" | "Proxy Authentication Required" | "Request Timeout" | "Conflict" | "Gone" | "Length Required" | "Precondition Failed" | "Payload Too Large" | "URI Too Long" | "Unsupported Media Type" | "Range Not Satisfiable" | "Expectation Failed" | "I'm a teapot" | "Enhance Your Calm" | "Misdirected Request" | "Unprocessable Content" | "Locked" | "Failed Dependency" | "Too Early" | "Upgrade Required" | "Precondition Required" | "Too Many Requests" | "Request Header Fields Too Large" | "Unavailable For Legal Reasons" | "Internal Server Error" | "Not Implemented" | "Bad Gateway" | "Service Unavailable" | "Gateway Timeout" | "HTTP Version Not Supported" | "Variant Also Negotiates" | "Insufficient Storage" | "Loop Detected" | "Not Extended" | "Network Authentication Required";
17
+ status: number | "Continue" | "Switching Protocols" | "Processing" | "Early Hints" | "OK" | "Created" | "Accepted" | "Non-Authoritative Information" | "No Content" | "Reset Content" | "Partial Content" | "Multi-Status" | "Already Reported" | "Multiple Choices" | "Moved Permanently" | "Found" | "See Other" | "Not Modified" | "Temporary Redirect" | "Permanent Redirect" | "Bad Request" | "Unauthorized" | "Payment Required" | "Forbidden" | "Not Found" | "Method Not Allowed" | "Not Acceptable" | "Proxy Authentication Required" | "Request Timeout" | "Conflict" | "Gone" | "Length Required" | "Precondition Failed" | "Payload Too Large" | "URI Too Long" | "Unsupported Media Type" | "Range Not Satisfiable" | "Expectation Failed" | "I'm a teapot" | "Enhance Your Calm" | "Misdirected Request" | "Unprocessable Content" | "Locked" | "Failed Dependency" | "Too Early" | "Upgrade Required" | "Precondition Required" | "Too Many Requests" | "Request Header Fields Too Large" | "Unavailable For Legal Reasons" | "Internal Server Error" | "Not Implemented" | "Bad Gateway" | "Service Unavailable" | "Gateway Timeout" | "HTTP Version Not Supported" | "Variant Also Negotiates" | "Insufficient Storage" | "Loop Detected" | "Not Extended" | "Network Authentication Required";
18
18
  };
19
19
  interface CreateHandlerParameter {
20
20
  mapResponse(response: unknown, set: Context['set'], request?: Request, owned?: boolean): Response;
@@ -14,7 +14,7 @@ function materializeSetHeaders(set) {
14
14
  if (headers["\0"] !== headers) return headers;
15
15
  return set.headers = Object.assign(require_utils.nullObject(), headers);
16
16
  }
17
- const sseFormat = (data) => `data: ${data}\n\n`;
17
+ const sseFormat = (data) => require_utils.sseData(data) + "\n";
18
18
  const identityFormat = (data) => data;
19
19
  const textEncoder = new TextEncoder();
20
20
  const encodeChunk = (s) => textEncoder.encode(s);
@@ -284,7 +284,7 @@ function handleSet(set) {
284
284
  const proto = Object.getPrototypeOf(set.headers);
285
285
  if (proto !== null && proto !== Object.prototype) {
286
286
  const flat = Object.create(null);
287
- for (const key in set.headers) flat[key] = set.headers[key];
287
+ for (const key of Object.keys(set.headers)) flat[key] = set.headers[key];
288
288
  set.headers = flat;
289
289
  }
290
290
  if (set.cookie && require_utils.isNotEmpty(set.cookie)) {
@@ -311,7 +311,7 @@ function applySetHeaders(target, setHeaders, present) {
311
311
  for (const key of setHeaders.keys()) if (key !== setCookie && !present.has(key)) target.set(key, setHeaders.get(key) ?? "");
312
312
  } else {
313
313
  let cookies;
314
- for (const key in setHeaders) if (key === setCookie) {
314
+ for (const key of Object.keys(setHeaders)) if (key === setCookie) {
315
315
  const cookie = setHeaders[key];
316
316
  cookies ??= target.getSetCookie();
317
317
  if (!cookies.includes(cookie)) {
@@ -1,6 +1,6 @@
1
1
  import { hasHeaderShorthand, isBun } from "../universal/constants.mjs";
2
2
  import { StatusMap } from "../constants.mjs";
3
- import { isByteStream, isNotEmpty, nullObject } from "../utils.mjs";
3
+ import { isByteStream, isNotEmpty, nullObject, sseData } from "../utils.mjs";
4
4
  import { skipClone } from "./skip-clone.mjs";
5
5
  import { serializeCookie } from "../cookie/serialize.mjs";
6
6
  import { isBorrowedResponse } from "./response-ownership.mjs";
@@ -13,7 +13,7 @@ function materializeSetHeaders(set) {
13
13
  if (headers["\0"] !== headers) return headers;
14
14
  return set.headers = Object.assign(nullObject(), headers);
15
15
  }
16
- const sseFormat = (data) => `data: ${data}\n\n`;
16
+ const sseFormat = (data) => sseData(data) + "\n";
17
17
  const identityFormat = (data) => data;
18
18
  const textEncoder = new TextEncoder();
19
19
  const encodeChunk = (s) => textEncoder.encode(s);
@@ -283,7 +283,7 @@ function handleSet(set) {
283
283
  const proto = Object.getPrototypeOf(set.headers);
284
284
  if (proto !== null && proto !== Object.prototype) {
285
285
  const flat = Object.create(null);
286
- for (const key in set.headers) flat[key] = set.headers[key];
286
+ for (const key of Object.keys(set.headers)) flat[key] = set.headers[key];
287
287
  set.headers = flat;
288
288
  }
289
289
  if (set.cookie && isNotEmpty(set.cookie)) {
@@ -310,7 +310,7 @@ function applySetHeaders(target, setHeaders, present) {
310
310
  for (const key of setHeaders.keys()) if (key !== setCookie && !present.has(key)) target.set(key, setHeaders.get(key) ?? "");
311
311
  } else {
312
312
  let cookies;
313
- for (const key in setHeaders) if (key === setCookie) {
313
+ for (const key of Object.keys(setHeaders)) if (key === setCookie) {
314
314
  const cookie = setHeaders[key];
315
315
  cookies ??= target.getSetCookie();
316
316
  if (!cookies.includes(cookie)) {
@@ -5,6 +5,7 @@ const require_utils = require('../../utils.js');
5
5
  const require_error = require('../../error.js');
6
6
  const require_adapter_default_headers = require('../default-headers.js');
7
7
  const require_adapter_utils = require('../utils.js');
8
+ const require_cookie_cookie = require('../../cookie/cookie.js');
8
9
 
9
10
  //#region src/adapter/web-standard/handler.ts
10
11
  const textPlainInit = { headers: { "content-type": "text/plain" } };
@@ -21,16 +22,22 @@ function handleElysiaFile(file, set = { headers: require_utils.nullObject() }, r
21
22
  });
22
23
  return require_adapter_utils.handleFile(file.value, set, request);
23
24
  }
25
+ function responseTag(response) {
26
+ if (response == null) return;
27
+ const constructor = Object.getPrototypeOf(response)?.constructor;
28
+ if (typeof constructor !== "function") return typeof response.next === "function" ? "" : void 0;
29
+ return constructor.name;
30
+ }
24
31
  function mapResponseWithSet(response, set, request, owned) {
25
32
  require_adapter_utils.handleSet(set);
26
33
  const headers = set.headers;
27
- switch (response?.constructor?.name) {
34
+ switch (responseTag(response)) {
28
35
  case "String":
29
36
  if (!require_universal_constants.isBun && !headers["content-type"]) require_adapter_utils.materializeSetHeaders(set)["content-type"] = "text/plain";
30
37
  return new Response(response, set);
31
38
  case "Array": return Response.json(response, set);
39
+ case "ElysiaForm": return new Response(require_utils.formToFormData(response), set);
32
40
  case "Object":
33
- if (response["~ely-form"]) return new Response(require_utils.formToFormData(response), set);
34
41
  if (typeof response?.next === "function") return handleStream(response, set, request, void 0, owned);
35
42
  return Response.json(response, set);
36
43
  case "Number":
@@ -66,12 +73,11 @@ function mapResponse(response, set, request, owned) {
66
73
  }
67
74
  const textHeaders = require_universal_constants.isBun ? void 0 : textPlainInit;
68
75
  function mapCompactResponse(response, request, owned) {
69
- switch (response?.constructor?.name) {
76
+ switch (responseTag(response)) {
70
77
  case "String": return new Response(response, textHeaders);
71
78
  case "Array": return Response.json(response);
72
- case "Object":
73
- if (response["~ely-form"]) return new Response(require_utils.formToFormData(response));
74
- return Response.json(response);
79
+ case "ElysiaForm": return new Response(require_utils.formToFormData(response));
80
+ case "Object": return Response.json(response);
75
81
  case "Number":
76
82
  case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString());
77
83
  case "ElysiaFile": return handleElysiaFile(response, void 0, request);
@@ -126,11 +132,12 @@ function mapFallback(response, set, request, owned = false) {
126
132
  headers: response.headers ? { ...response.headers } : {}
127
133
  }, request, owned);
128
134
  if (response instanceof require_universal_file.ElysiaFile) return handleElysiaFile(response, void 0, request);
135
+ if (require_utils.isElysiaForm(response)) return new Response(require_utils.formToFormData(response), set);
129
136
  if (typeof response?.next === "function" || response instanceof ReadableStream) return handleStream(response, set, request, void 0, owned);
130
137
  if (typeof response?.then === "function") return response.then((x) => set ? mapResponse(x, set, request, owned) : mapCompactResponse(x, request, owned));
131
138
  if (Array.isArray(response)) return Response.json(response);
132
139
  if (typeof response?.toResponse === "function") return set ? mapResponse(response.toResponse(), set, request, owned) : mapCompactResponse(response.toResponse(), request, owned);
133
- if (response?.constructor?.name === "Cookie" && response.jar) return new Response(response.value, set);
140
+ if (responseTag(response) === "Cookie" && require_cookie_cookie.Cookie.isCookie(response)) return set ? mapResponse(response.value, set, request, owned) : mapCompactResponse(response.value, request, owned);
134
141
  return new Response(response, set);
135
142
  }
136
143
  const handleResponse = require_adapter_utils.createResponseHandler({
@@ -1,9 +1,10 @@
1
1
  import { isBun } from "../../universal/constants.mjs";
2
2
  import { ElysiaFile, mime } from "../../universal/file.mjs";
3
- import { formToFormData, isNotEmpty, nullObject } from "../../utils.mjs";
3
+ import { formToFormData, isElysiaForm, isNotEmpty, nullObject } from "../../utils.mjs";
4
4
  import { ElysiaStatus, PROBLEM_JSON, internalServerErrorBody } from "../../error.mjs";
5
5
  import { defaultHeaders } from "../default-headers.mjs";
6
6
  import { createResponseHandler, createStreamHandler, handleFile, handleSet, materializeSetHeaders } from "../utils.mjs";
7
+ import { Cookie } from "../../cookie/cookie.mjs";
7
8
 
8
9
  //#region src/adapter/web-standard/handler.ts
9
10
  const textPlainInit = { headers: { "content-type": "text/plain" } };
@@ -20,16 +21,22 @@ function handleElysiaFile(file, set = { headers: nullObject() }, request) {
20
21
  });
21
22
  return handleFile(file.value, set, request);
22
23
  }
24
+ function responseTag(response) {
25
+ if (response == null) return;
26
+ const constructor = Object.getPrototypeOf(response)?.constructor;
27
+ if (typeof constructor !== "function") return typeof response.next === "function" ? "" : void 0;
28
+ return constructor.name;
29
+ }
23
30
  function mapResponseWithSet(response, set, request, owned) {
24
31
  handleSet(set);
25
32
  const headers = set.headers;
26
- switch (response?.constructor?.name) {
33
+ switch (responseTag(response)) {
27
34
  case "String":
28
35
  if (!isBun && !headers["content-type"]) materializeSetHeaders(set)["content-type"] = "text/plain";
29
36
  return new Response(response, set);
30
37
  case "Array": return Response.json(response, set);
38
+ case "ElysiaForm": return new Response(formToFormData(response), set);
31
39
  case "Object":
32
- if (response["~ely-form"]) return new Response(formToFormData(response), set);
33
40
  if (typeof response?.next === "function") return handleStream(response, set, request, void 0, owned);
34
41
  return Response.json(response, set);
35
42
  case "Number":
@@ -65,12 +72,11 @@ function mapResponse(response, set, request, owned) {
65
72
  }
66
73
  const textHeaders = isBun ? void 0 : textPlainInit;
67
74
  function mapCompactResponse(response, request, owned) {
68
- switch (response?.constructor?.name) {
75
+ switch (responseTag(response)) {
69
76
  case "String": return new Response(response, textHeaders);
70
77
  case "Array": return Response.json(response);
71
- case "Object":
72
- if (response["~ely-form"]) return new Response(formToFormData(response));
73
- return Response.json(response);
78
+ case "ElysiaForm": return new Response(formToFormData(response));
79
+ case "Object": return Response.json(response);
74
80
  case "Number":
75
81
  case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString());
76
82
  case "ElysiaFile": return handleElysiaFile(response, void 0, request);
@@ -125,11 +131,12 @@ function mapFallback(response, set, request, owned = false) {
125
131
  headers: response.headers ? { ...response.headers } : {}
126
132
  }, request, owned);
127
133
  if (response instanceof ElysiaFile) return handleElysiaFile(response, void 0, request);
134
+ if (isElysiaForm(response)) return new Response(formToFormData(response), set);
128
135
  if (typeof response?.next === "function" || response instanceof ReadableStream) return handleStream(response, set, request, void 0, owned);
129
136
  if (typeof response?.then === "function") return response.then((x) => set ? mapResponse(x, set, request, owned) : mapCompactResponse(x, request, owned));
130
137
  if (Array.isArray(response)) return Response.json(response);
131
138
  if (typeof response?.toResponse === "function") return set ? mapResponse(response.toResponse(), set, request, owned) : mapCompactResponse(response.toResponse(), request, owned);
132
- if (response?.constructor?.name === "Cookie" && response.jar) return new Response(response.value, set);
139
+ if (responseTag(response) === "Cookie" && Cookie.isCookie(response)) return set ? mapResponse(response.value, set, request, owned) : mapCompactResponse(response.value, request, owned);
133
140
  return new Response(response, set);
134
141
  }
135
142
  const handleResponse = createResponseHandler({
package/dist/base.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { ElysiaStatus } from "./error.js";
2
1
  import { TraceCapability, TraceHandler } from "./trace.js";
3
2
  import { ListenCallback, Serve, Server } from "./universal/server.js";
4
- import { AddRoute, AddWSRoute, AfterHandler, AfterResponseHandler, AnyErrorConstructor, AnyLocalHook, BodyHandler, CompiledHandler, CreateEden, DefaultEphemeral, DefaultMetadata, DefaultSingleton, DefinitionBase, DocumentDecoration, ElysiaConfig, ElysiaHandlerToResponseSchemaAmbiguous, EphemeralType, ErrorDefinitionEntry, ErrorHandler, EventScope, ExcludeElysiaResponse, ExtractErrorFromHandle, GlobalHookReturn, GracefulHandler, GuardHookSingleton, GuardLocalHook, HTTPMethod, HistoryEntry, HookContextSchema, HookContextSingleton, InlineHandler, InlineHandlerNonMacro, InputSchema, InputSchemaKey, InternalRoute, IntersectIfObjectSchema, JoinPath, LocalHook, LocalHookReturn, Macro, MacroSchemaChannel, MacroToContext, MacroToProperty, MapResponse, MaybeArray, MaybePromise, MergeElysiaInstances, MergeSchema, MergeScopedSchemas, MetadataBase, NonResolvableMacroKey, ObjectMacroDefs, OptionalHandler, PluginHookReturn, PreHandler, Prettify, PublicRoute, ResolveRouteErrors, RouteBase, ScopedHookReturn, ScopedMapDeriveReturn, SingletonBase, StaticMapAliases, TransformHandler, UnionResponseStatus, UnwrapRoute, WrapFn } from "./types.js";
5
3
  import { ChainNode } from "./utils.js";
4
+ import { AddRoute, AddWSRoute, AfterHandler, AfterResponseHandler, AnyErrorConstructor, AnyLocalHook, BodyHandler, CompiledHandler, CreateEden, DefaultEphemeral, DefaultMetadata, DefaultSingleton, DefinitionBase, DocumentDecoration, ElysiaConfig, ElysiaHandlerToResponseSchemaAmbiguous, EphemeralType, ErrorDefinitionEntry, ErrorHandler, EventScope, ExcludeElysiaResponse, ExtractErrorFromHandle, GlobalHookReturn, GracefulHandler, GuardHookSingleton, GuardLocalHook, HTTPMethod, HistoryEntry, HookContextSchema, HookContextSingleton, InlineHandler, InlineHandlerNonMacro, InputSchema, InputSchemaKey, InternalRoute, IntersectIfObjectSchema, JoinPath, LocalHook, LocalHookReturn, Macro, MacroSchemaChannel, MacroToContext, MacroToProperty, MapResponse, MaybeArray, MaybePromise, MergeElysiaInstances, MergeSchema, MergeScopedSchemas, MetadataBase, NonResolvableMacroKey, ObjectMacroDefs, OptionalHandler, PluginHookReturn, PreHandler, Prettify, PublicRoute, ResolveRouteErrors, RouteBase, ScopedHookReturn, ScopedMapDeriveReturn, SingletonBase, StaticMapAliases, TransformHandler, UnionResponseStatus, UnwrapRoute, WrapFn } from "./types.js";
5
+ import { ElysiaStatus } from "./error.js";
6
6
  import { Context, ErrorContext, LifecycleContext } from "./context.js";
7
7
  import { AnySchema } from "./type/types.js";
8
8
  import { AotFingerprint, CompilerSession, ProgramId } from "./compile/aot.js";
@@ -66,7 +66,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
66
66
  '~hasDynamicWS'?: boolean;
67
67
  '~hasTrace'?: boolean;
68
68
  '~finalizeError'?: (context: Context, error: Error) => MaybePromise<Response>;
69
- '~programId': ProgramId;
69
+ get ['~programId'](): ProgramId;
70
70
  '~aotFingerprint'?: AotFingerprint;
71
71
  '~compilerSession'?: CompilerSession;
72
72
  '~generation'?: Generation;
@@ -559,7 +559,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
559
559
  parser: Metadata['parser'];
560
560
  response: Metadata['response'];
561
561
  }, Routes, Ephemeral, Volatile>;
562
- '~applyMacro'(input: Partial<AnyLocalHook>, toApply?: Partial<AnyLocalHook>, iteration?: number, seen?: Set<string | Partial<any>>): Partial<AnyLocalHook>;
562
+ '~applyMacro'(input: Partial<AnyLocalHook>, toApply?: Partial<AnyLocalHook>, iteration?: number, seen?: Set<string | Partial<any>>, insertions?: Map<string, number>): Partial<AnyLocalHook>;
563
563
  /**
564
564
  * Merge a plugin instance
565
565
  */
@@ -864,11 +864,26 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
864
864
  * on the config and triggers a fresh build of the fetch handler).
865
865
  */
866
866
  compile(): this;
867
- handler(index: number, immediate?: boolean | undefined, route?: InternalRoute, precomputedStatic?: Response, aliases?: StaticMapAliases, table?: RouteTable): CompiledHandler;
867
+ handler(index: number, immediate?: boolean, route?: InternalRoute, precomputedStatic?: Response, aliases?: StaticMapAliases, table?: RouteTable): CompiledHandler;
868
868
  ['~newGeneration'](): this;
869
869
  get fetch(): (request: Request, ...rest: any[]) => MaybePromise<Response>;
870
870
  get handle(): (url: string | Request, options?: RequestInit) => Promise<Response>;
871
871
  listen(options: string | number | Partial<Serve>, callback?: ListenCallback): this;
872
+ /**
873
+ * Add a higher order function over Elysia.fetch
874
+ *
875
+ * @example
876
+ * ```ts
877
+ * const ctx = new AsyncLocalStorage<{ counter: number }>()
878
+ *
879
+ * new Elysia()
880
+ * .wrap(
881
+ * (fetch) => (request) =>
882
+ * ctx.run({ counter: 0 }, () => fetch(request))
883
+ * )
884
+ * .get('/', () => ctx.getStore())
885
+ * ```
886
+ */
872
887
  wrap<T extends (...params: any) => MaybePromise<Response> = (request: Request, ...rest: any[]) => MaybePromise<Response>>(callback: WrapFn<T>): this;
873
888
  /**
874
889
  * ### cleanup | Life cycle event
package/dist/base.js CHANGED
@@ -19,6 +19,29 @@ memoirist = require_runtime.__toESM(memoirist);
19
19
  const useNodesBuffer = [];
20
20
  const emptyHistory = Object.freeze([]);
21
21
  const canRegisterLoose = (path, isDynamic) => !isDynamic && (path.length === 0 || path.charCodeAt(path.length - 1) === 47);
22
+ /**
23
+ * Every key a single route must answer to, in registration order.
24
+ *
25
+ * `registerLoose` is the caller's call, not this helper's: HTTP gates it on
26
+ * `canRegisterLoose` because its lookup retries the trailing slash, while WS
27
+ * has no such retry and must own both directions outright
28
+ */
29
+ const expandPaths = (path, needsEncode, registerLoose, explicit) => {
30
+ const variants = [path];
31
+ if (needsEncode) {
32
+ const encoded = encodeURI(path);
33
+ if (encoded !== path) variants.push(encoded);
34
+ }
35
+ if (!registerLoose) return variants;
36
+ const paths = [];
37
+ for (let v = 0; v < variants.length; v++) {
38
+ const p = variants[v];
39
+ paths.push(p);
40
+ const loose = require_utils.getLoosePath(p);
41
+ if (loose !== p && !explicit?.has(loose)) paths.push(loose);
42
+ }
43
+ return paths;
44
+ };
22
45
  var Elysia = class Elysia {
23
46
  #hasPlugin;
24
47
  #hasGlobal;
@@ -80,11 +103,14 @@ var Elysia = class Elysia {
80
103
  #jitRoute;
81
104
  #jitStatic;
82
105
  #jitAliases;
106
+ get ["~programId"]() {
107
+ return this;
108
+ }
83
109
  constructor(config) {
84
110
  /**
85
111
  * ! Don't tune
86
112
  *
87
- * Interesting JSC internal: These `= undefined` are load-bearing
113
+ * Interesting JSC internal: These `= undefined` shouldn't be removed
88
114
  *
89
115
  * Inline slots live inside the object cell, so JSC must pick their
90
116
  * count at allocation before any initializer runs
@@ -102,7 +128,8 @@ var Elysia = class Elysia {
102
128
  * Don't omitted field either for monomorphic access
103
129
  *
104
130
  * @see test/memory/instance-footprint.test.ts
105
- * Est. Overflow 37 -> 21 = butterfly 64 -> 32 slots = 738B -> 450B/instance
131
+ * Est. overflow 37 -> 21 = butterfly 64 -> 32 slots = 738B -> 450B;
132
+ * reusing the app as its program identity brings the current cell to ~386B.
106
133
  **/
107
134
  this["~config"] = config;
108
135
  this["~ext"] = void 0;
@@ -122,7 +149,6 @@ var Elysia = class Elysia {
122
149
  this["~introspect"] = void 0;
123
150
  this["~scopeChild"] = void 0;
124
151
  this["~scopeChildren"] = void 0;
125
- this["~programId"] = require_compile_aot.createProgramId();
126
152
  if (config) {
127
153
  const { prefix, name, seed, adapter } = config;
128
154
  this["~Prefix"] = prefix ? prefix.charCodeAt(0) === 47 ? prefix : `/${prefix}` : void 0;
@@ -502,7 +528,7 @@ var Elysia = class Elysia {
502
528
  require_utils.invalidateMacroEpoch();
503
529
  return this;
504
530
  }
505
- "~applyMacro"(input, toApply = input, iteration = 0, seen = /* @__PURE__ */ new Set()) {
531
+ "~applyMacro"(input, toApply = input, iteration = 0, seen = /* @__PURE__ */ new Set(), insertions = /* @__PURE__ */ new Map()) {
506
532
  if (iteration >= 16) return input;
507
533
  const macro = this["~ext"]?.macro;
508
534
  if (!macro) return input;
@@ -547,7 +573,7 @@ var Elysia = class Elysia {
547
573
  continue;
548
574
  }
549
575
  if (k in macro) {
550
- this["~applyMacro"](input, { [k]: v }, iteration + 1, seen);
576
+ this["~applyMacro"](input, { [k]: v }, iteration + 1, seen, insertions);
551
577
  delete input[key];
552
578
  continue;
553
579
  }
@@ -568,19 +594,20 @@ var Elysia = class Elysia {
568
594
  delete input[key];
569
595
  continue;
570
596
  }
571
- if (k in input) {
572
- if (require_utils.eventProperties.has(k) || k === "derive") {
573
- const macroFns = Array.isArray(v) ? v : [v];
574
- const existing = Array.isArray(input[k]) ? input[k] : [input[k]];
575
- const merged = [];
576
- const seen = /* @__PURE__ */ new Set();
577
- for (const fn of macroFns) if (!existing.includes(fn) && !seen.has(fn)) {
578
- seen.add(fn);
579
- merged.push(fn);
580
- }
581
- for (const fn of existing) if (!seen.has(fn)) merged.push(fn);
582
- input[k] = merged;
583
- } else if (Array.isArray(input[k])) {
597
+ if (require_utils.eventProperties.has(k) || k === "derive") {
598
+ const incoming = Array.isArray(v) ? v : [v];
599
+ const existing = k in input ? Array.isArray(input[k]) ? input[k] : [input[k]] : [];
600
+ const added = [];
601
+ for (const fn of incoming) if (!existing.includes(fn) && !added.includes(fn)) added.push(fn);
602
+ const at = insertions.get(k) ?? 0;
603
+ input[k] = [
604
+ ...existing.slice(0, at),
605
+ ...added,
606
+ ...existing.slice(at)
607
+ ];
608
+ insertions.set(k, at + added.length);
609
+ } else if (k in input) {
610
+ if (Array.isArray(input[k])) {
584
611
  if (Array.isArray(v)) {
585
612
  for (const item of v) if (!input[k].some((e) => e === item)) input[k].unshift(item);
586
613
  } else if (!input[k].some((item) => item === v)) input[k].unshift(v);
@@ -1182,10 +1209,10 @@ var Elysia = class Elysia {
1182
1209
  this.fetch;
1183
1210
  return this;
1184
1211
  }
1185
- handler(index, immediate = this["~config"]?.precompile, route, precomputedStatic, aliases, table) {
1212
+ handler(index, immediate, route, precomputedStatic, aliases, table) {
1186
1213
  if (this.#compiled?.[index]) return this.#compiled[index];
1187
1214
  const compiled = this.#compiled ??= new Array(table?.length ?? this["~routes"].length);
1188
- if (immediate) {
1215
+ if (immediate ?? this["~config"]?.precompile) {
1189
1216
  const row = route ?? (table ? require_route_table.routeRow(table, index) : this["~routes"][index]);
1190
1217
  let handler;
1191
1218
  try {
@@ -1413,7 +1440,10 @@ var Elysia = class Elysia {
1413
1440
  const appChain = this["~hookChain"];
1414
1441
  if (this["~ext"]?.macro || this["~scopeChildren"] || appChain !== void 0 && appChain.refs) for (let i = 0; i < length; i++) this.#assertRouteModelRefs(require_route_table.routeRow(table, i), method[i]);
1415
1442
  else for (let i = 0; i < length; i++) if (this.#routeMayHaveModelRef(table, i)) this.#assertRouteModelRefs(require_route_table.routeRow(table, i), method[i]);
1416
- if (length) require_compile_aot.Compiled.claim(this["~programId"], this["~aotFingerprint"] = require_compile_aot.createAotFingerprint());
1443
+ if (length) {
1444
+ const programId = this["~programId"];
1445
+ if (!require_compile_aot.Compiled.claim(programId, this["~aotFingerprint"] = require_compile_aot.createAotFingerprint())) require_compile_aot.Compiled.assertUncontested(programId);
1446
+ }
1417
1447
  const isLoose = this["~config"]?.strictPath !== true;
1418
1448
  let explicitPaths;
1419
1449
  if (isLoose && table.hasLoose) {
@@ -1439,17 +1469,17 @@ var Elysia = class Elysia {
1439
1469
  const handler = ws[0];
1440
1470
  const options = ws[1];
1441
1471
  if (wsConfig === void 0 && wsCap.options) wsConfig = wsCap.options;
1472
+ const wsNeedsEncode = (routeFlags & require_route_table.RouteFlag.Encode) !== 0;
1442
1473
  if ((routeFlags & require_route_table.RouteFlag.Dynamic) !== 0) {
1443
- (this["~router"] ??= new memoirist.default({ loosePath: isLoose })).add("WS", routePath, handler);
1474
+ const wsRouter = this["~router"] ??= new memoirist.default({ loosePath: isLoose });
1475
+ const wsPaths = expandPaths(routePath, wsNeedsEncode, false, void 0);
1476
+ for (let v = 0; v < wsPaths.length; v++) wsRouter.add("WS", wsPaths[v], handler);
1444
1477
  this["~hasDynamicWS"] = true;
1445
1478
  } else {
1446
1479
  this.#initMap();
1447
1480
  const wsMap = this["~map"]["WS"] ??= require_utils.nullObject();
1448
- wsMap[routePath] = handler;
1449
- if (isLoose) {
1450
- const loose = require_utils.getLoosePath(routePath);
1451
- if (loose !== routePath && !explicitPaths?.get("WS")?.has(loose)) wsMap[loose] = handler;
1452
- }
1481
+ const wsPaths = expandPaths(routePath, wsNeedsEncode, isLoose, isLoose ? explicitPaths?.get("WS") : void 0);
1482
+ for (let v = 0; v < wsPaths.length; v++) wsMap[wsPaths[v]] = handler;
1453
1483
  }
1454
1484
  if (options && require_utils.isNotEmpty(options)) {
1455
1485
  wsConfig ??= require_utils.nullObject();
@@ -1460,26 +1490,12 @@ var Elysia = class Elysia {
1460
1490
  const isDynamic = (routeFlags & require_route_table.RouteFlag.Dynamic) !== 0;
1461
1491
  const needsEncode = (routeFlags & require_route_table.RouteFlag.Encode) !== 0;
1462
1492
  const registerLoose = isLoose && canRegisterLoose(routePath, isDynamic);
1463
- const explicitMain = registerLoose ? explicitPaths?.get(routeMethod) : void 0;
1464
1493
  if (!isDynamic && !needsEncode && !registerLoose) {
1465
1494
  const map = methods[routeMethod] ??= require_utils.nullObject();
1466
1495
  map[routePath] = this.handler(i, precompile, void 0, void 0, void 0, table);
1467
1496
  continue;
1468
1497
  }
1469
- const variants = [routePath];
1470
- if (needsEncode) {
1471
- const encoded = encodeURI(routePath);
1472
- if (encoded !== routePath) variants.push(encoded);
1473
- }
1474
- const paths = [];
1475
- for (let v = 0; v < variants.length; v++) {
1476
- const p = variants[v];
1477
- paths.push(p);
1478
- if (registerLoose) {
1479
- const loose = require_utils.getLoosePath(p);
1480
- if (loose !== p && !explicitMain?.has(loose)) paths.push(loose);
1481
- }
1482
- }
1498
+ const paths = expandPaths(routePath, needsEncode, registerLoose, registerLoose ? explicitPaths?.get(routeMethod) : void 0);
1483
1499
  if (isDynamic) {
1484
1500
  const router = this["~router"] ??= new memoirist.default({ loosePath: isLoose });
1485
1501
  const handler = this.handler(i, precompile, void 0, void 0, void 0, table);
@@ -1511,6 +1527,21 @@ var Elysia = class Elysia {
1511
1527
  if (!require_compile_aot.Capture.isAotBuildEnv()) listen(this, options, callback);
1512
1528
  return this;
1513
1529
  }
1530
+ /**
1531
+ * Add a higher order function over Elysia.fetch
1532
+ *
1533
+ * @example
1534
+ * ```ts
1535
+ * const ctx = new AsyncLocalStorage<{ counter: number }>()
1536
+ *
1537
+ * new Elysia()
1538
+ * .wrap(
1539
+ * (fetch) => (request) =>
1540
+ * ctx.run({ counter: 0 }, () => fetch(request))
1541
+ * )
1542
+ * .get('/', () => ctx.getStore())
1543
+ * ```
1544
+ */
1514
1545
  wrap(callback) {
1515
1546
  this.#assertMutable("wrap");
1516
1547
  if (this.#fetchFn && !this.#pending) console.warn("[Elysia] .wrap() was called after the fetch handler was built");