elysia 2.0.0-beta.2 → 2.0.0-beta.4

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 (175) hide show
  1. package/dist/adapter/bun/index.d.ts +1 -1
  2. package/dist/adapter/bun/index.js +320 -56
  3. package/dist/adapter/bun/index.mjs +321 -57
  4. package/dist/adapter/utils.js +51 -30
  5. package/dist/adapter/utils.mjs +52 -31
  6. package/dist/adapter/web-standard/handler.js +5 -2
  7. package/dist/adapter/web-standard/handler.mjs +5 -2
  8. package/dist/base.d.ts +18 -7
  9. package/dist/base.js +213 -101
  10. package/dist/base.mjs +215 -103
  11. package/dist/compile/aot-capture.js +1 -1
  12. package/dist/compile/aot-capture.mjs +1 -1
  13. package/dist/compile/aot.d.ts +5 -4
  14. package/dist/compile/aot.js +17 -9
  15. package/dist/compile/aot.mjs +18 -9
  16. package/dist/compile/handler/descriptor.js +1 -1
  17. package/dist/compile/handler/descriptor.mjs +1 -1
  18. package/dist/compile/handler/frozen-validator.d.ts +4 -1
  19. package/dist/compile/handler/frozen-validator.js +8 -3
  20. package/dist/compile/handler/frozen-validator.mjs +5 -3
  21. package/dist/compile/handler/index.d.ts +2 -2
  22. package/dist/compile/handler/index.js +8 -6
  23. package/dist/compile/handler/index.mjs +8 -6
  24. package/dist/compile/handler/reconstruct.d.ts +1 -1
  25. package/dist/compile/handler/reconstruct.js +4 -3
  26. package/dist/compile/handler/reconstruct.mjs +4 -3
  27. package/dist/compile/handler/utils.js +2 -2
  28. package/dist/compile/handler/utils.mjs +3 -3
  29. package/dist/compile/jit-probe.d.ts +2 -2
  30. package/dist/context.d.ts +1 -1
  31. package/dist/context.js +8 -5
  32. package/dist/context.mjs +8 -5
  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 +6 -5
  38. package/dist/cookie/cookie.mjs +6 -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/handler/error.d.ts +23 -12
  52. package/dist/handler/error.js +24 -21
  53. package/dist/handler/error.mjs +20 -21
  54. package/dist/handler/fetch.js +6 -7
  55. package/dist/handler/fetch.mjs +7 -8
  56. package/dist/handler/utils.js +4 -2
  57. package/dist/handler/utils.mjs +5 -3
  58. package/dist/index.js +1 -8
  59. package/dist/package.js +1 -1
  60. package/dist/package.mjs +1 -1
  61. package/dist/plugin/aot/core.d.ts +33 -6
  62. package/dist/plugin/aot/core.js +120 -40
  63. package/dist/plugin/aot/core.mjs +121 -43
  64. package/dist/plugin/aot/esbuild.js +8 -2
  65. package/dist/plugin/aot/esbuild.mjs +9 -3
  66. package/dist/plugin/aot/hooks.d.ts +2 -1
  67. package/dist/plugin/aot/hooks.js +3 -3
  68. package/dist/plugin/aot/hooks.mjs +4 -4
  69. package/dist/plugin/aot/source.d.ts +4 -1
  70. package/dist/plugin/aot/source.js +21 -14
  71. package/dist/plugin/aot/source.mjs +21 -14
  72. package/dist/plugin/aot/worker.js +2 -2
  73. package/dist/plugin/aot/worker.mjs +2 -2
  74. package/dist/route-table.d.ts +3 -0
  75. package/dist/route-table.js +16 -11
  76. package/dist/route-table.mjs +16 -11
  77. package/dist/schema-snapshot.js +17 -22
  78. package/dist/schema-snapshot.mjs +17 -22
  79. package/dist/type/bridge-live.d.ts +1 -1
  80. package/dist/type/bridge-live.js +2 -2
  81. package/dist/type/bridge-live.mjs +2 -2
  82. package/dist/type/bridge.d.ts +1 -1
  83. package/dist/type/coerce-plan.js +3 -4
  84. package/dist/type/coerce-plan.mjs +1 -1
  85. package/dist/type/coerce.d.ts +1 -1
  86. package/dist/type/compat.d.ts +3 -0
  87. package/dist/type/compat.js +32 -14
  88. package/dist/type/compat.mjs +27 -8
  89. package/dist/type/constants.d.ts +1 -1
  90. package/dist/type/elysia/array-buffer.js +2 -3
  91. package/dist/type/elysia/array-buffer.mjs +1 -1
  92. package/dist/type/elysia/array-string.js +7 -4
  93. package/dist/type/elysia/array-string.mjs +9 -5
  94. package/dist/type/elysia/boolean-string.js +2 -3
  95. package/dist/type/elysia/boolean-string.mjs +1 -1
  96. package/dist/type/elysia/boolean.js +4 -3
  97. package/dist/type/elysia/boolean.mjs +4 -2
  98. package/dist/type/elysia/cookie.js +2 -1
  99. package/dist/type/elysia/cookie.mjs +2 -1
  100. package/dist/type/elysia/date.js +7 -7
  101. package/dist/type/elysia/date.mjs +3 -2
  102. package/dist/type/elysia/file-type.d.ts +9 -2
  103. package/dist/type/elysia/file-type.js +16 -1
  104. package/dist/type/elysia/file-type.mjs +16 -2
  105. package/dist/type/elysia/file.js +8 -4
  106. package/dist/type/elysia/file.mjs +8 -3
  107. package/dist/type/elysia/files.js +6 -4
  108. package/dist/type/elysia/files.mjs +5 -2
  109. package/dist/type/elysia/form.js +2 -3
  110. package/dist/type/elysia/form.mjs +3 -3
  111. package/dist/type/elysia/integer-string.js +4 -5
  112. package/dist/type/elysia/integer-string.mjs +3 -3
  113. package/dist/type/elysia/integer.js +4 -3
  114. package/dist/type/elysia/integer.mjs +4 -2
  115. package/dist/type/elysia/maybe-empty.js +3 -4
  116. package/dist/type/elysia/maybe-empty.mjs +1 -1
  117. package/dist/type/elysia/nullable.js +2 -3
  118. package/dist/type/elysia/nullable.mjs +1 -1
  119. package/dist/type/elysia/number.js +4 -3
  120. package/dist/type/elysia/number.mjs +4 -2
  121. package/dist/type/elysia/numeric-enum.js +2 -3
  122. package/dist/type/elysia/numeric-enum.mjs +1 -1
  123. package/dist/type/elysia/numeric.js +5 -5
  124. package/dist/type/elysia/numeric.mjs +3 -2
  125. package/dist/type/elysia/object-string.js +7 -4
  126. package/dist/type/elysia/object-string.mjs +9 -5
  127. package/dist/type/elysia/string.js +4 -3
  128. package/dist/type/elysia/string.mjs +4 -2
  129. package/dist/type/elysia/uint8-array.js +2 -3
  130. package/dist/type/elysia/uint8-array.mjs +1 -1
  131. package/dist/type/elysia/union-enum.js +2 -3
  132. package/dist/type/elysia/union-enum.mjs +1 -1
  133. package/dist/type/elysia/utils.js +2 -3
  134. package/dist/type/elysia/utils.mjs +1 -1
  135. package/dist/type/exports.js +10 -1
  136. package/dist/type/exports.mjs +7 -0
  137. package/dist/type/index.d.ts +9 -1
  138. package/dist/type/index.js +41 -13
  139. package/dist/type/index.mjs +44 -9
  140. package/dist/type/typebox-type-live.d.ts +9 -0
  141. package/dist/type/typebox-type-live.js +31 -0
  142. package/dist/type/typebox-type-live.mjs +16 -0
  143. package/dist/type/typebox-type.d.ts +24 -0
  144. package/dist/type/typebox-type.js +130 -0
  145. package/dist/type/typebox-type.mjs +66 -0
  146. package/dist/type/typebox-value-live.d.ts +9 -0
  147. package/dist/type/typebox-value-live.js +27 -0
  148. package/dist/type/typebox-value-live.mjs +11 -0
  149. package/dist/type/typebox-value.d.ts +30 -0
  150. package/dist/type/typebox-value.js +147 -0
  151. package/dist/type/typebox-value.mjs +62 -0
  152. package/dist/type/validator/custom-error.js +4 -5
  153. package/dist/type/validator/custom-error.mjs +3 -3
  154. package/dist/type/validator/default-precompute.js +4 -5
  155. package/dist/type/validator/default-precompute.mjs +1 -1
  156. package/dist/type/validator/index.d.ts +1 -1
  157. package/dist/type/validator/index.js +51 -42
  158. package/dist/type/validator/index.mjs +33 -23
  159. package/dist/type/validator/validator-cache.d.ts +1 -1
  160. package/dist/type/validator/validator-cache.js +27 -14
  161. package/dist/type/validator/validator-cache.mjs +27 -13
  162. package/dist/universal/constants.d.ts +2 -1
  163. package/dist/universal/constants.js +3 -1
  164. package/dist/universal/constants.mjs +2 -1
  165. package/dist/utils.d.ts +19 -1
  166. package/dist/utils.js +25 -3
  167. package/dist/utils.mjs +19 -3
  168. package/dist/validator/index.js +2 -1
  169. package/dist/validator/index.mjs +2 -1
  170. package/dist/ws/context.d.ts +8 -1
  171. package/dist/ws/context.js +65 -29
  172. package/dist/ws/context.mjs +64 -29
  173. package/dist/ws/route.js +176 -28
  174. package/dist/ws/route.mjs +179 -31
  175. package/package.json +5 -3
@@ -7,14 +7,15 @@ declare const signCookieSyncImpl: (val: string, secret: string) => string;
7
7
  declare const keyCache: Map<string, Promise<CryptoKey>>;
8
8
  declare function importSecretKey(secret: string): Promise<CryptoKey>;
9
9
  declare function signCookieSubtle(val: string, secret: string): Promise<string>;
10
- declare function signCookie(val: string, secret: string | null): Promise<string>;
11
- declare function signCookieSync(val: string, secret: string | null): string;
12
- declare function unsignCookie(input: string, secret: string | null): Promise<string | false>;
13
- declare function unsignCookieSync(input: string, secret: string | null): string | false;
14
- declare function unsignWithSecretsSync(name: string, value: unknown, secrets: string | null | (string | null)[] | undefined): string;
15
- declare function unsignWithSecrets(name: string, value: unknown, secrets: string | null | (string | null)[] | undefined): Promise<string>;
10
+ declare const deriveSignKey: (secret: string, name: string) => string;
11
+ declare function signCookie(val: string, secret: string | null, name?: string): Promise<string>;
12
+ declare function signCookieSync(val: string, secret: string | null, name?: string): string;
13
+ declare function unsignCookie(input: string, secret: string | null, name?: string): Promise<string | false>;
14
+ declare function unsignCookieSync(input: string, secret: string | null, name?: string): string | false;
15
+ declare function unsignWithSecretsSync(name: string, value: unknown, secrets: string | null | (string | null)[] | undefined, legacy?: boolean): string;
16
+ declare function unsignWithSecrets(name: string, value: unknown, secrets: string | null | (string | null)[] | undefined, legacy?: boolean): Promise<string>;
16
17
  declare const rawJsonValue: WeakMap<object, string>;
17
18
  declare function maybeJsonDecode(value: unknown): any;
18
19
  declare function resolvePendingCookie(entry: Record<string, any>, name: string): void;
19
20
  //#endregion
20
- export { hasSyncHmac, hmacProvider, importSecretKey, keyCache, maybeJsonDecode, rawJsonValue, resolvePendingCookie, signCookie, signCookieBun, signCookieNode, signCookieSubtle, signCookieSync, signCookieSyncImpl, unsignCookie, unsignCookieSync, unsignWithSecrets, unsignWithSecretsSync };
21
+ export { deriveSignKey, hasSyncHmac, hmacProvider, importSecretKey, keyCache, maybeJsonDecode, rawJsonValue, resolvePendingCookie, signCookie, signCookieBun, signCookieNode, signCookieSubtle, signCookieSync, signCookieSyncImpl, unsignCookie, unsignCookieSync, unsignWithSecrets, unsignWithSecretsSync };
@@ -20,12 +20,11 @@ function nodeCrypto() {
20
20
  }
21
21
  return _nodeCrypto;
22
22
  }
23
- const HMAC_PROBE_DIGEST = "bzs6y9cVmkYub8fplSKaOuuqMqJlDwhMypFT/jSdCEk=";
24
23
  const bunCryptoHasher = (() => {
25
24
  const hasher = globalThis.Bun?.CryptoHasher;
26
25
  if (typeof hasher !== "function") return void 0;
27
26
  try {
28
- return new hasher("sha256", "elysia").update("probe").digest("base64") === HMAC_PROBE_DIGEST ? hasher : void 0;
27
+ return new hasher("sha256", "elysia").update("probe").digest("base64") === "bzs6y9cVmkYub8fplSKaOuuqMqJlDwhMypFT/jSdCEk=" ? hasher : void 0;
29
28
  } catch {
30
29
  return;
31
30
  }
@@ -62,19 +61,22 @@ async function signCookieSubtle(val, secret) {
62
61
  const hmacBuffer = await crypto.subtle.sign("HMAC", await importSecretKey(secret), encoder.encode(val));
63
62
  return `${val}.${btoa(String.fromCharCode(...new Uint8Array(hmacBuffer))).replace(removeTrailingEquals, "")}`;
64
63
  }
65
- async function signCookie(val, secret) {
64
+ const deriveSignKey = (secret, name) => `${name.length}\0${name}${secret}`;
65
+ async function signCookie(val, secret, name) {
66
66
  val = coerceValue(val);
67
- if (secret === null || secret === void 0) throw new TypeError("Secret key must be provided");
67
+ if (!secret?.trim()) throw new TypeError("Secret key must be provided");
68
+ if (name !== void 0) secret = deriveSignKey(secret, name);
68
69
  if (hasSyncHmac) return signCookieSyncImpl(val, secret);
69
70
  return signCookieSubtle(val, secret);
70
71
  }
71
- function signCookieSync(val, secret) {
72
+ function signCookieSync(val, secret, name) {
72
73
  val = coerceValue(val);
73
- if (secret === null || secret === void 0) throw new TypeError("Secret key must be provided");
74
+ if (!secret?.trim()) throw new TypeError("Secret key must be provided");
74
75
  if (!hasSyncHmac) throw new Error("signCookieSync called without a sync HMAC available");
76
+ if (name !== void 0) secret = deriveSignKey(secret, name);
75
77
  return signCookieSyncImpl(val, secret);
76
78
  }
77
- async function unsignCookie(input, secret) {
79
+ async function unsignCookie(input, secret, name) {
78
80
  if (typeof input !== "string") throw new TypeError("Signed cookie string must be provided.");
79
81
  const dot = input.lastIndexOf(".");
80
82
  if (dot === -1) {
@@ -82,10 +84,10 @@ async function unsignCookie(input, secret) {
82
84
  return false;
83
85
  }
84
86
  const tentativeValue = input.slice(0, dot);
85
- if (secret === null) return false;
86
- return require_utils.constantTimeEqual(await signCookie(tentativeValue, secret), input) ? tentativeValue : false;
87
+ if (!secret?.trim()) return false;
88
+ return require_utils.constantTimeEqual(await signCookie(tentativeValue, secret, name), input) ? tentativeValue : false;
87
89
  }
88
- function unsignCookieSync(input, secret) {
90
+ function unsignCookieSync(input, secret, name) {
89
91
  if (typeof input !== "string") throw new TypeError("Signed cookie string must be provided.");
90
92
  const dot = input.lastIndexOf(".");
91
93
  if (dot === -1) {
@@ -93,32 +95,36 @@ function unsignCookieSync(input, secret) {
93
95
  return false;
94
96
  }
95
97
  const tentativeValue = input.slice(0, dot);
96
- if (secret === null) return false;
97
- return require_utils.constantTimeEqual(signCookieSync(tentativeValue, secret), input) ? tentativeValue : false;
98
+ if (!secret?.trim()) return false;
99
+ return require_utils.constantTimeEqual(signCookieSync(tentativeValue, secret, name), input) ? tentativeValue : false;
98
100
  }
99
- function unsignWithSecretsSync(name, value, secrets) {
101
+ function unsignWithSecretsSync(name, value, secrets, legacy) {
100
102
  if (typeof value !== "string") throw require_cookie_error.InvalidCookie.signature(name);
101
- if (typeof secrets === "string") {
102
- const temp = unsignCookieSync(value, secrets);
103
- if (temp === false) throw require_cookie_error.InvalidCookie.signature(name);
104
- return temp;
105
- }
106
- if (Array.isArray(secrets)) for (let i = 0; i < secrets.length; i++) {
107
- const temp = unsignCookieSync(value, secrets[i]);
108
- if (temp !== false) return temp;
103
+ for (let pass = 0; pass < 2; pass++) {
104
+ const bound = pass === 0 ? name : void 0;
105
+ if (typeof secrets === "string") {
106
+ const temp = unsignCookieSync(value, secrets, bound);
107
+ if (temp !== false) return temp;
108
+ } else if (Array.isArray(secrets)) for (let i = 0; i < secrets.length; i++) {
109
+ const temp = unsignCookieSync(value, secrets[i], bound);
110
+ if (temp !== false) return temp;
111
+ }
112
+ if (!legacy) break;
109
113
  }
110
114
  throw require_cookie_error.InvalidCookie.signature(name);
111
115
  }
112
- async function unsignWithSecrets(name, value, secrets) {
116
+ async function unsignWithSecrets(name, value, secrets, legacy) {
113
117
  if (typeof value !== "string") throw require_cookie_error.InvalidCookie.signature(name);
114
- if (typeof secrets === "string") {
115
- const temp = await unsignCookie(value, secrets);
116
- if (temp === false) throw require_cookie_error.InvalidCookie.signature(name);
117
- return temp;
118
- }
119
- if (Array.isArray(secrets)) for (let i = 0; i < secrets.length; i++) {
120
- const temp = await unsignCookie(value, secrets[i]);
121
- if (temp !== false) return temp;
118
+ for (let pass = 0; pass < 2; pass++) {
119
+ const bound = pass === 0 ? name : void 0;
120
+ if (typeof secrets === "string") {
121
+ const temp = await unsignCookie(value, secrets, bound);
122
+ if (temp !== false) return temp;
123
+ } else if (Array.isArray(secrets)) for (let i = 0; i < secrets.length; i++) {
124
+ const temp = await unsignCookie(value, secrets[i], bound);
125
+ if (temp !== false) return temp;
126
+ }
127
+ if (!legacy) break;
122
128
  }
123
129
  throw require_cookie_error.InvalidCookie.signature(name);
124
130
  }
@@ -139,7 +145,7 @@ function resolvePendingCookie(entry, name) {
139
145
  const value = entry.value;
140
146
  if (typeof value !== "string") throw require_cookie_error.InvalidCookie.signature(name);
141
147
  if (!hasSyncHmac) throw new Error(`resolvePendingCookie called without sync HMAC. Unreachable under correct lane gating (cookie: "${name}")`);
142
- const resolvedValue = maybeJsonDecode(unsignWithSecretsSync(name, value, entry["~unsign"]));
148
+ const resolvedValue = maybeJsonDecode(unsignWithSecretsSync(name, value, entry["~unsign"], !entry["~strict"]));
143
149
  entry.value = resolvedValue;
144
150
  if (resolvedValue !== null && typeof resolvedValue === "object") {
145
151
  const raw = rawJsonValue.get(resolvedValue);
@@ -149,6 +155,7 @@ function resolvePendingCookie(entry, name) {
149
155
  }
150
156
 
151
157
  //#endregion
158
+ exports.deriveSignKey = deriveSignKey;
152
159
  exports.hasSyncHmac = hasSyncHmac;
153
160
  exports.hmacProvider = hmacProvider;
154
161
  exports.importSecretKey = importSecretKey;
@@ -19,12 +19,11 @@ function nodeCrypto() {
19
19
  }
20
20
  return _nodeCrypto;
21
21
  }
22
- const HMAC_PROBE_DIGEST = "bzs6y9cVmkYub8fplSKaOuuqMqJlDwhMypFT/jSdCEk=";
23
22
  const bunCryptoHasher = (() => {
24
23
  const hasher = globalThis.Bun?.CryptoHasher;
25
24
  if (typeof hasher !== "function") return void 0;
26
25
  try {
27
- return new hasher("sha256", "elysia").update("probe").digest("base64") === HMAC_PROBE_DIGEST ? hasher : void 0;
26
+ return new hasher("sha256", "elysia").update("probe").digest("base64") === "bzs6y9cVmkYub8fplSKaOuuqMqJlDwhMypFT/jSdCEk=" ? hasher : void 0;
28
27
  } catch {
29
28
  return;
30
29
  }
@@ -61,19 +60,22 @@ async function signCookieSubtle(val, secret) {
61
60
  const hmacBuffer = await crypto.subtle.sign("HMAC", await importSecretKey(secret), encoder.encode(val));
62
61
  return `${val}.${btoa(String.fromCharCode(...new Uint8Array(hmacBuffer))).replace(removeTrailingEquals, "")}`;
63
62
  }
64
- async function signCookie(val, secret) {
63
+ const deriveSignKey = (secret, name) => `${name.length}\0${name}${secret}`;
64
+ async function signCookie(val, secret, name) {
65
65
  val = coerceValue(val);
66
- if (secret === null || secret === void 0) throw new TypeError("Secret key must be provided");
66
+ if (!secret?.trim()) throw new TypeError("Secret key must be provided");
67
+ if (name !== void 0) secret = deriveSignKey(secret, name);
67
68
  if (hasSyncHmac) return signCookieSyncImpl(val, secret);
68
69
  return signCookieSubtle(val, secret);
69
70
  }
70
- function signCookieSync(val, secret) {
71
+ function signCookieSync(val, secret, name) {
71
72
  val = coerceValue(val);
72
- if (secret === null || secret === void 0) throw new TypeError("Secret key must be provided");
73
+ if (!secret?.trim()) throw new TypeError("Secret key must be provided");
73
74
  if (!hasSyncHmac) throw new Error("signCookieSync called without a sync HMAC available");
75
+ if (name !== void 0) secret = deriveSignKey(secret, name);
74
76
  return signCookieSyncImpl(val, secret);
75
77
  }
76
- async function unsignCookie(input, secret) {
78
+ async function unsignCookie(input, secret, name) {
77
79
  if (typeof input !== "string") throw new TypeError("Signed cookie string must be provided.");
78
80
  const dot = input.lastIndexOf(".");
79
81
  if (dot === -1) {
@@ -81,10 +83,10 @@ async function unsignCookie(input, secret) {
81
83
  return false;
82
84
  }
83
85
  const tentativeValue = input.slice(0, dot);
84
- if (secret === null) return false;
85
- return constantTimeEqual(await signCookie(tentativeValue, secret), input) ? tentativeValue : false;
86
+ if (!secret?.trim()) return false;
87
+ return constantTimeEqual(await signCookie(tentativeValue, secret, name), input) ? tentativeValue : false;
86
88
  }
87
- function unsignCookieSync(input, secret) {
89
+ function unsignCookieSync(input, secret, name) {
88
90
  if (typeof input !== "string") throw new TypeError("Signed cookie string must be provided.");
89
91
  const dot = input.lastIndexOf(".");
90
92
  if (dot === -1) {
@@ -92,32 +94,36 @@ function unsignCookieSync(input, secret) {
92
94
  return false;
93
95
  }
94
96
  const tentativeValue = input.slice(0, dot);
95
- if (secret === null) return false;
96
- return constantTimeEqual(signCookieSync(tentativeValue, secret), input) ? tentativeValue : false;
97
+ if (!secret?.trim()) return false;
98
+ return constantTimeEqual(signCookieSync(tentativeValue, secret, name), input) ? tentativeValue : false;
97
99
  }
98
- function unsignWithSecretsSync(name, value, secrets) {
100
+ function unsignWithSecretsSync(name, value, secrets, legacy) {
99
101
  if (typeof value !== "string") throw InvalidCookie.signature(name);
100
- if (typeof secrets === "string") {
101
- const temp = unsignCookieSync(value, secrets);
102
- if (temp === false) throw InvalidCookie.signature(name);
103
- return temp;
104
- }
105
- if (Array.isArray(secrets)) for (let i = 0; i < secrets.length; i++) {
106
- const temp = unsignCookieSync(value, secrets[i]);
107
- if (temp !== false) return temp;
102
+ for (let pass = 0; pass < 2; pass++) {
103
+ const bound = pass === 0 ? name : void 0;
104
+ if (typeof secrets === "string") {
105
+ const temp = unsignCookieSync(value, secrets, bound);
106
+ if (temp !== false) return temp;
107
+ } else if (Array.isArray(secrets)) for (let i = 0; i < secrets.length; i++) {
108
+ const temp = unsignCookieSync(value, secrets[i], bound);
109
+ if (temp !== false) return temp;
110
+ }
111
+ if (!legacy) break;
108
112
  }
109
113
  throw InvalidCookie.signature(name);
110
114
  }
111
- async function unsignWithSecrets(name, value, secrets) {
115
+ async function unsignWithSecrets(name, value, secrets, legacy) {
112
116
  if (typeof value !== "string") throw InvalidCookie.signature(name);
113
- if (typeof secrets === "string") {
114
- const temp = await unsignCookie(value, secrets);
115
- if (temp === false) throw InvalidCookie.signature(name);
116
- return temp;
117
- }
118
- if (Array.isArray(secrets)) for (let i = 0; i < secrets.length; i++) {
119
- const temp = await unsignCookie(value, secrets[i]);
120
- if (temp !== false) return temp;
117
+ for (let pass = 0; pass < 2; pass++) {
118
+ const bound = pass === 0 ? name : void 0;
119
+ if (typeof secrets === "string") {
120
+ const temp = await unsignCookie(value, secrets, bound);
121
+ if (temp !== false) return temp;
122
+ } else if (Array.isArray(secrets)) for (let i = 0; i < secrets.length; i++) {
123
+ const temp = await unsignCookie(value, secrets[i], bound);
124
+ if (temp !== false) return temp;
125
+ }
126
+ if (!legacy) break;
121
127
  }
122
128
  throw InvalidCookie.signature(name);
123
129
  }
@@ -138,7 +144,7 @@ function resolvePendingCookie(entry, name) {
138
144
  const value = entry.value;
139
145
  if (typeof value !== "string") throw InvalidCookie.signature(name);
140
146
  if (!hasSyncHmac) throw new Error(`resolvePendingCookie called without sync HMAC. Unreachable under correct lane gating (cookie: "${name}")`);
141
- const resolvedValue = maybeJsonDecode(unsignWithSecretsSync(name, value, entry["~unsign"]));
147
+ const resolvedValue = maybeJsonDecode(unsignWithSecretsSync(name, value, entry["~unsign"], !entry["~strict"]));
142
148
  entry.value = resolvedValue;
143
149
  if (resolvedValue !== null && typeof resolvedValue === "object") {
144
150
  const raw = rawJsonValue.get(resolvedValue);
@@ -148,4 +154,4 @@ function resolvePendingCookie(entry, name) {
148
154
  }
149
155
 
150
156
  //#endregion
151
- export { hasSyncHmac, hmacProvider, importSecretKey, keyCache, maybeJsonDecode, rawJsonValue, resolvePendingCookie, signCookie, signCookieBun, signCookieNode, signCookieSubtle, signCookieSync, signCookieSyncImpl, unsignCookie, unsignCookieSync, unsignWithSecrets, unsignWithSecretsSync };
157
+ export { deriveSignKey, hasSyncHmac, hmacProvider, importSecretKey, keyCache, maybeJsonDecode, rawJsonValue, resolvePendingCookie, signCookie, signCookieBun, signCookieNode, signCookieSubtle, signCookieSync, signCookieSyncImpl, unsignCookie, unsignCookieSync, unsignWithSecrets, unsignWithSecretsSync };
@@ -16,8 +16,7 @@ var InvalidCookie = class InvalidCookie extends require_error.ElysiaError {
16
16
  return new InvalidCookie(key, `"${key}" has invalid cookie signature`);
17
17
  }
18
18
  static secret(key) {
19
- if (key) return new InvalidCookie(key, `"${key}" is signed but no secret is provided`, 500);
20
- return new InvalidCookie(void 0, `Cookie is signed but no secret is provided`, 500);
19
+ return new InvalidCookie(key, `${key ? `Cookie "${key}"` : "A cookie"} is signed but \`cookie.secrets\` is missing or empty. Set it to a non-empty string: an empty secret signs with a zero-length key, which anyone can forge.`, 500);
21
20
  }
22
21
  };
23
22
 
@@ -15,8 +15,7 @@ var InvalidCookie = class InvalidCookie extends ElysiaError {
15
15
  return new InvalidCookie(key, `"${key}" has invalid cookie signature`);
16
16
  }
17
17
  static secret(key) {
18
- if (key) return new InvalidCookie(key, `"${key}" is signed but no secret is provided`, 500);
19
- return new InvalidCookie(void 0, `Cookie is signed but no secret is provided`, 500);
18
+ return new InvalidCookie(key, `${key ? `Cookie "${key}"` : "A cookie"} is signed but \`cookie.secrets\` is missing or empty. Set it to a non-empty string: an empty secret signs with a zero-length key, which anyone can forge.`, 500);
20
19
  }
21
20
  };
22
21
 
@@ -40,7 +40,11 @@ function serialize(name, value = "", options) {
40
40
  if (value) value = encodeURIComponent(value);
41
41
  let str = `${name}=${value}`;
42
42
  const maxAge = options.maxAge;
43
- if (maxAge !== void 0) str += "; Max-Age=" + maxAge;
43
+ if (maxAge !== void 0) {
44
+ const age = Math.floor(maxAge);
45
+ if (!Number.isFinite(age)) throw new require_cookie_error.InvalidCookie(`Invalid cookie Max-Age ${JSON.stringify(maxAge)}.`);
46
+ str += "; Max-Age=" + age;
47
+ }
44
48
  const domain = options.domain;
45
49
  if (domain) {
46
50
  if (COOKIE_ATTR_INVALID.test(domain)) throw new require_cookie_error.InvalidCookie(`Invalid cookie Domain ${JSON.stringify(domain)}.`);
@@ -39,7 +39,11 @@ function serialize(name, value = "", options) {
39
39
  if (value) value = encodeURIComponent(value);
40
40
  let str = `${name}=${value}`;
41
41
  const maxAge = options.maxAge;
42
- if (maxAge !== void 0) str += "; Max-Age=" + maxAge;
42
+ if (maxAge !== void 0) {
43
+ const age = Math.floor(maxAge);
44
+ if (!Number.isFinite(age)) throw new InvalidCookie(`Invalid cookie Max-Age ${JSON.stringify(maxAge)}.`);
45
+ str += "; Max-Age=" + age;
46
+ }
43
47
  const domain = options.domain;
44
48
  if (domain) {
45
49
  if (COOKIE_ATTR_INVALID.test(domain)) throw new InvalidCookie(`Invalid cookie Domain ${JSON.stringify(domain)}.`);
@@ -7,7 +7,7 @@ function serializeCookie(cookies) {
7
7
  if (!cookies || !require_utils.isNotEmpty(cookies)) return;
8
8
  let set;
9
9
  let isArray = false;
10
- for (const key in cookies) {
10
+ for (const key of Object.keys(cookies)) {
11
11
  if (!key) continue;
12
12
  const property = cookies[key];
13
13
  if (!property) continue;
@@ -6,7 +6,7 @@ function serializeCookie(cookies) {
6
6
  if (!cookies || !isNotEmpty(cookies)) return;
7
7
  let set;
8
8
  let isArray = false;
9
- for (const key in cookies) {
9
+ for (const key of Object.keys(cookies)) {
10
10
  if (!key) continue;
11
11
  const property = cookies[key];
12
12
  if (!property) continue;
@@ -108,6 +108,16 @@ interface CookieOptions {
108
108
  * `null` in the array makes Elysia accept an unsigned cookie (intended only for a one-way unsigned→signed migration)
109
109
  */
110
110
  secrets?: string | null | (string | null)[];
111
+ /**
112
+ * Only use secret for signing cookie instead of secret + seperator + name
113
+ *
114
+ * Set to `false` once every signed cookie in circulation has been re-issued
115
+ *
116
+ * Applies to the app and route level
117
+ *
118
+ * @default true
119
+ */
120
+ legacySignature?: boolean;
111
121
  }
112
122
  //#endregion
113
123
  export { BaseCookie, CookieOptions };
@@ -69,7 +69,7 @@ async function parseCookieRaw(cookieString, config) {
69
69
  if (v === void 0) continue;
70
70
  let value = (0, deuri.default)(v) ?? v;
71
71
  const signCheck = require_cookie_config.resolveSignSecrets(name, config);
72
- if (signCheck !== void 0) value = await require_cookie_crypto.unsignWithSecrets(name, value, signCheck);
72
+ if (signCheck !== void 0) value = await require_cookie_crypto.unsignWithSecrets(name, value, signCheck, config.legacySignature);
73
73
  out[name] = require_cookie_crypto.maybeJsonDecode(value);
74
74
  }
75
75
  return out;
@@ -85,7 +85,7 @@ function parseCookieRawSigned(cookieString, config) {
85
85
  if (v === void 0) continue;
86
86
  let value = (0, deuri.default)(v) ?? v;
87
87
  const signCheck = require_cookie_config.resolveSignSecrets(name, config);
88
- if (signCheck !== void 0) value = require_cookie_crypto.unsignWithSecretsSync(name, value, signCheck);
88
+ if (signCheck !== void 0) value = require_cookie_crypto.unsignWithSecretsSync(name, value, signCheck, config.legacySignature);
89
89
  out[name] = require_cookie_crypto.maybeJsonDecode(value);
90
90
  }
91
91
  return out;
@@ -101,7 +101,10 @@ function buildCookieJar(set, raw, config, lazySign, deferDecode) {
101
101
  if (entry.expires instanceof Date) entry.expires = new Date(entry.expires.getTime());
102
102
  if (lazySign && typeof entry.value === "string") {
103
103
  const secrets = require_cookie_config.resolveSignSecrets(name, config);
104
- if (secrets !== void 0) entry["~unsign"] = secrets;
104
+ if (secrets !== void 0) {
105
+ entry["~unsign"] = secrets;
106
+ if (!config.legacySignature) entry["~strict"] = 1;
107
+ }
105
108
  } else {
106
109
  const value = entry.value;
107
110
  if (value !== null && typeof value === "object") {
@@ -114,16 +117,27 @@ function buildCookieJar(set, raw, config, lazySign, deferDecode) {
114
117
  return entry;
115
118
  }
116
119
  const cache = require_utils.nullObject();
120
+ function settle(key) {
121
+ if (!(key in store)) return;
122
+ const entry = materializeEntry(key);
123
+ if ("~unsign" in entry) require_cookie_crypto.resolvePendingCookie(entry, key);
124
+ }
117
125
  return new Proxy(store, {
118
126
  get(_, key) {
119
127
  return cache[key] ??= new require_cookie_cookie.Cookie(key, set, key in store ? materializeEntry(key) : Object.assign(require_utils.nullObject(), config.defaults, config.fields[key]?.defaults));
120
128
  },
129
+ has(target, key) {
130
+ if (typeof key === "string") settle(key);
131
+ return Reflect.has(target, key);
132
+ },
133
+ ownKeys(target) {
134
+ const keys = Reflect.ownKeys(target);
135
+ for (let i = 0; i < keys.length; i++) settle(keys[i]);
136
+ return keys;
137
+ },
121
138
  getOwnPropertyDescriptor(target, key) {
122
- if (typeof key === "string" && key in target) materializeEntry(key);
123
- const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
124
- const entry = descriptor?.value;
125
- if (entry && typeof entry === "object" && "~unsign" in entry) require_cookie_crypto.resolvePendingCookie(entry, String(key));
126
- return descriptor;
139
+ if (typeof key === "string") settle(key);
140
+ return Reflect.getOwnPropertyDescriptor(target, key);
127
141
  }
128
142
  });
129
143
  }
@@ -142,11 +156,11 @@ function collectSignPending(cookies, config) {
142
156
  if (property["~raw"] === value) continue;
143
157
  } else if (typeof value !== "string") value = value + "";
144
158
  const secret = Array.isArray(r.secrets) ? r.secrets[0] ?? null : r.secrets;
145
- if (secret === null) throw new TypeError(`Cookie field "${key}" is signed but no \`secrets\` is provided.`);
159
+ if (!secret?.trim()) throw new TypeError(`Cookie field "${key}" is signed but no \`secrets\` is provided.`);
146
160
  (pending ??= []).push([
147
161
  property,
148
162
  value,
149
- secret
163
+ require_cookie_crypto.deriveSignKey(secret, key)
150
164
  ]);
151
165
  }
152
166
  return pending;
@@ -156,8 +170,8 @@ function signCookieValues(cookies, config) {
156
170
  if (!pending) return;
157
171
  if (require_cookie_crypto.hasSyncHmac) {
158
172
  for (let i = 0; i < pending.length; i++) {
159
- const [property, value, secret] = pending[i];
160
- property.value = require_cookie_crypto.signCookieSyncImpl(value, secret);
173
+ const [property, value, key] = pending[i];
174
+ property.value = require_cookie_crypto.signCookieSyncImpl(value, key);
161
175
  }
162
176
  return;
163
177
  }
@@ -165,8 +179,8 @@ function signCookieValues(cookies, config) {
165
179
  }
166
180
  async function signPending(pending) {
167
181
  for (let i = 0; i < pending.length; i++) {
168
- const [property, value, secret] = pending[i];
169
- property.value = await require_cookie_crypto.signCookie(value, secret);
182
+ const [property, value, key] = pending[i];
183
+ property.value = await require_cookie_crypto.signCookie(value, key);
170
184
  }
171
185
  }
172
186
 
@@ -1,7 +1,7 @@
1
1
  import { dangerousKeys } from "../constants.mjs";
2
2
  import { nullObject } from "../utils.mjs";
3
3
  import { parse } from "./lib.mjs";
4
- import { hasSyncHmac, maybeJsonDecode, rawJsonValue, resolvePendingCookie, signCookie, signCookieSyncImpl, unsignWithSecrets, unsignWithSecretsSync } from "./crypto.mjs";
4
+ import { deriveSignKey, hasSyncHmac, maybeJsonDecode, rawJsonValue, resolvePendingCookie, signCookie, signCookieSyncImpl, unsignWithSecrets, unsignWithSecretsSync } from "./crypto.mjs";
5
5
  import { Cookie } from "./cookie.mjs";
6
6
  import { compileCookieConfig, isCookieSigned, resolveSignSecrets } from "./config.mjs";
7
7
  import decodeComponent from "deuri";
@@ -66,7 +66,7 @@ async function parseCookieRaw(cookieString, config) {
66
66
  if (v === void 0) continue;
67
67
  let value = decodeComponent(v) ?? v;
68
68
  const signCheck = resolveSignSecrets(name, config);
69
- if (signCheck !== void 0) value = await unsignWithSecrets(name, value, signCheck);
69
+ if (signCheck !== void 0) value = await unsignWithSecrets(name, value, signCheck, config.legacySignature);
70
70
  out[name] = maybeJsonDecode(value);
71
71
  }
72
72
  return out;
@@ -82,7 +82,7 @@ function parseCookieRawSigned(cookieString, config) {
82
82
  if (v === void 0) continue;
83
83
  let value = decodeComponent(v) ?? v;
84
84
  const signCheck = resolveSignSecrets(name, config);
85
- if (signCheck !== void 0) value = unsignWithSecretsSync(name, value, signCheck);
85
+ if (signCheck !== void 0) value = unsignWithSecretsSync(name, value, signCheck, config.legacySignature);
86
86
  out[name] = maybeJsonDecode(value);
87
87
  }
88
88
  return out;
@@ -98,7 +98,10 @@ function buildCookieJar(set, raw, config, lazySign, deferDecode) {
98
98
  if (entry.expires instanceof Date) entry.expires = new Date(entry.expires.getTime());
99
99
  if (lazySign && typeof entry.value === "string") {
100
100
  const secrets = resolveSignSecrets(name, config);
101
- if (secrets !== void 0) entry["~unsign"] = secrets;
101
+ if (secrets !== void 0) {
102
+ entry["~unsign"] = secrets;
103
+ if (!config.legacySignature) entry["~strict"] = 1;
104
+ }
102
105
  } else {
103
106
  const value = entry.value;
104
107
  if (value !== null && typeof value === "object") {
@@ -111,16 +114,27 @@ function buildCookieJar(set, raw, config, lazySign, deferDecode) {
111
114
  return entry;
112
115
  }
113
116
  const cache = nullObject();
117
+ function settle(key) {
118
+ if (!(key in store)) return;
119
+ const entry = materializeEntry(key);
120
+ if ("~unsign" in entry) resolvePendingCookie(entry, key);
121
+ }
114
122
  return new Proxy(store, {
115
123
  get(_, key) {
116
124
  return cache[key] ??= new Cookie(key, set, key in store ? materializeEntry(key) : Object.assign(nullObject(), config.defaults, config.fields[key]?.defaults));
117
125
  },
126
+ has(target, key) {
127
+ if (typeof key === "string") settle(key);
128
+ return Reflect.has(target, key);
129
+ },
130
+ ownKeys(target) {
131
+ const keys = Reflect.ownKeys(target);
132
+ for (let i = 0; i < keys.length; i++) settle(keys[i]);
133
+ return keys;
134
+ },
118
135
  getOwnPropertyDescriptor(target, key) {
119
- if (typeof key === "string" && key in target) materializeEntry(key);
120
- const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
121
- const entry = descriptor?.value;
122
- if (entry && typeof entry === "object" && "~unsign" in entry) resolvePendingCookie(entry, String(key));
123
- return descriptor;
136
+ if (typeof key === "string") settle(key);
137
+ return Reflect.getOwnPropertyDescriptor(target, key);
124
138
  }
125
139
  });
126
140
  }
@@ -139,11 +153,11 @@ function collectSignPending(cookies, config) {
139
153
  if (property["~raw"] === value) continue;
140
154
  } else if (typeof value !== "string") value = value + "";
141
155
  const secret = Array.isArray(r.secrets) ? r.secrets[0] ?? null : r.secrets;
142
- if (secret === null) throw new TypeError(`Cookie field "${key}" is signed but no \`secrets\` is provided.`);
156
+ if (!secret?.trim()) throw new TypeError(`Cookie field "${key}" is signed but no \`secrets\` is provided.`);
143
157
  (pending ??= []).push([
144
158
  property,
145
159
  value,
146
- secret
160
+ deriveSignKey(secret, key)
147
161
  ]);
148
162
  }
149
163
  return pending;
@@ -153,8 +167,8 @@ function signCookieValues(cookies, config) {
153
167
  if (!pending) return;
154
168
  if (hasSyncHmac) {
155
169
  for (let i = 0; i < pending.length; i++) {
156
- const [property, value, secret] = pending[i];
157
- property.value = signCookieSyncImpl(value, secret);
170
+ const [property, value, key] = pending[i];
171
+ property.value = signCookieSyncImpl(value, key);
158
172
  }
159
173
  return;
160
174
  }
@@ -162,8 +176,8 @@ function signCookieValues(cookies, config) {
162
176
  }
163
177
  async function signPending(pending) {
164
178
  for (let i = 0; i < pending.length; i++) {
165
- const [property, value, secret] = pending[i];
166
- property.value = await signCookie(value, secret);
179
+ const [property, value, key] = pending[i];
180
+ property.value = await signCookie(value, key);
167
181
  }
168
182
  }
169
183
 
@@ -2,17 +2,7 @@ import { AppHook } from "../types.js";
2
2
  import { Context } from "../context.js";
3
3
 
4
4
  //#region src/handler/error.d.ts
5
- /**
6
- * Adopt the intercepted error's `type` into a problem the hook produced
7
- * without one.
8
- *
9
- * `'about:blank'` is RFC 9457's "unspecified" default, so it's the only value
10
- * worth replacing — an explicit type the handler set always wins.
11
- *
12
- * The result is copied rather than mutated: `.error(Class, value)` wraps a
13
- * non-function into `() => value`, so the very same `ElysiaStatus` is replayed
14
- * on every request and an in-place write would leak across requests
15
- */
5
+ declare const claimsProblemType: (error: any) => boolean;
16
6
  declare function adoptErrorType(result: any, error: any): any;
17
7
  /**
18
8
  * Response served once every error hook has declined the error.
@@ -21,6 +11,27 @@ declare function adoptErrorType(result: any, error: any): any;
21
11
  * which must land on *this* function rather than re-implementing it
22
12
  */
23
13
  declare function fallbackResponse(context: Context, error: any, mapResponse: (response: unknown, set: Context['set'], context?: Context) => unknown, defaultError?: Response): unknown;
14
+ /**
15
+ * Numeric form of an annotated status, which may be written as a name.
16
+ * A numeric string keeps coercing so the production mask below can't be
17
+ * slipped past with `'502'`
18
+ */
19
+ declare const resolveStatus: (status: unknown) => unknown;
20
+ /**
21
+ * Body served by an error that carries a status but no usable body:
22
+ * its declared `response`, otherwise its message
23
+ */
24
+ declare function statusFallbackBody(error: any, status: unknown): any;
25
+ /**
26
+ * Read one annotation knob.
27
+ *
28
+ * Both knobs are canonically methods, so they're evaluated per serve and may
29
+ * be `async`. Running a stranger's function is side-effect surface (it may
30
+ * consume a stream or do IO), so it takes the same problem claim the shaping
31
+ * does — an unclaimed duck error never invokes one. A *value* annotation stays
32
+ * inert data and keeps duck-participating as it always has
33
+ */
34
+ declare const readAnnotation: (self: any, key: "value" | "detail", claimsProblem: boolean) => any;
24
35
  declare function createErrorHandler(onErrors: AppHook['error'] | undefined, mapResponse: (response: unknown, set: Context['set'], ...any: unknown[]) => unknown, defaultError?: Response, allowUnsafe?: boolean): (context: Context, error: Error) => unknown;
25
36
  //#endregion
26
- export { adoptErrorType, createErrorHandler, fallbackResponse };
37
+ export { adoptErrorType, claimsProblemType, createErrorHandler, fallbackResponse, readAnnotation, resolveStatus, statusFallbackBody };