@suveren/gateway 0.7.6 → 0.8.1

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 (181) hide show
  1. package/content/integrations/deploy-github.json +10 -1
  2. package/content/integrations/mollie.json +103 -28
  3. package/dist/mcp-server/http.mjs +510 -132
  4. package/dist/ui/assets/{index-CsrM6RQr.js → index-BFnSVa9N.js} +22 -22
  5. package/dist/ui/index.html +1 -1
  6. package/node_modules/@hap/core/dist/index.d.mts +29 -6
  7. package/node_modules/@hap/core/dist/index.d.ts +29 -6
  8. package/node_modules/@hap/core/dist/index.js +54 -8
  9. package/node_modules/@hap/core/dist/index.mjs +53 -8
  10. package/node_modules/@hap/core/package.json +2 -1
  11. package/node_modules/@hap/core/src/frame.ts +115 -14
  12. package/node_modules/@hap/core/src/gatekeeper.ts +26 -0
  13. package/node_modules/@hap/core/src/types.ts +7 -1
  14. package/node_modules/@types/node/README.md +1 -1
  15. package/node_modules/@types/node/buffer.buffer.d.ts +5 -0
  16. package/node_modules/@types/node/crypto.d.ts +0 -2
  17. package/node_modules/@types/node/dgram.d.ts +119 -4
  18. package/node_modules/@types/node/ffi.d.ts +1 -1
  19. package/node_modules/@types/node/fs/promises.d.ts +61 -65
  20. package/node_modules/@types/node/fs.d.ts +86 -76
  21. package/node_modules/@types/node/http.d.ts +1 -1
  22. package/node_modules/@types/node/http2.d.ts +2 -2
  23. package/node_modules/@types/node/index.d.ts +1 -0
  24. package/node_modules/@types/node/inspector.d.ts +2 -1
  25. package/node_modules/@types/node/net.d.ts +108 -16
  26. package/node_modules/@types/node/package.json +2 -2
  27. package/node_modules/@types/node/quic.d.ts +37 -11
  28. package/node_modules/@types/node/stream/iter.d.ts +4 -4
  29. package/node_modules/@types/node/tls.d.ts +24 -0
  30. package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +5 -0
  31. package/node_modules/@types/node/ts5.6/index.d.ts +1 -0
  32. package/node_modules/@types/node/ts5.7/index.d.ts +1 -0
  33. package/node_modules/@types/node/tty.d.ts +4 -3
  34. package/node_modules/@types/node/vfs.d.ts +210 -0
  35. package/node_modules/@types/node/vm.d.ts +1 -1
  36. package/node_modules/express-rate-limit/dist/index.cjs +6 -3
  37. package/node_modules/express-rate-limit/dist/index.d.cts +11 -0
  38. package/node_modules/express-rate-limit/dist/index.d.mts +11 -0
  39. package/node_modules/express-rate-limit/dist/index.d.ts +11 -0
  40. package/node_modules/express-rate-limit/dist/index.mjs +6 -3
  41. package/node_modules/express-rate-limit/{license.md → license} +7 -6
  42. package/node_modules/express-rate-limit/package.json +5 -5
  43. package/node_modules/express-rate-limit/readme.md +1 -0
  44. package/node_modules/fast-uri/index.js +20 -5
  45. package/node_modules/fast-uri/lib/utils.js +8 -1
  46. package/node_modules/fast-uri/package.json +1 -1
  47. package/node_modules/fast-uri/test/component-safe-serialization.test.js +58 -0
  48. package/node_modules/fast-uri/test/ipv6-validation.test.js +34 -0
  49. package/node_modules/hono/dist/cjs/client/client.js +4 -4
  50. package/node_modules/hono/dist/cjs/hono-base.js +7 -6
  51. package/node_modules/hono/dist/cjs/jsx/base.js +18 -1
  52. package/node_modules/hono/dist/cjs/jsx/components.js +25 -26
  53. package/node_modules/hono/dist/cjs/jsx/context.js +5 -5
  54. package/node_modules/hono/dist/cjs/jsx/dom/server.js +5 -1
  55. package/node_modules/hono/dist/cjs/jsx/intrinsic-element/components.js +2 -2
  56. package/node_modules/hono/dist/cjs/jsx/streaming.js +4 -5
  57. package/node_modules/hono/dist/client/client.js +4 -4
  58. package/node_modules/hono/dist/hono-base.js +7 -6
  59. package/node_modules/hono/dist/jsx/base.js +15 -1
  60. package/node_modules/hono/dist/jsx/components.js +26 -27
  61. package/node_modules/hono/dist/jsx/context.js +6 -6
  62. package/node_modules/hono/dist/jsx/dom/server.js +5 -1
  63. package/node_modules/hono/dist/jsx/intrinsic-element/components.js +3 -3
  64. package/node_modules/hono/dist/jsx/streaming.js +5 -6
  65. package/node_modules/hono/dist/types/context.d.ts +2 -2
  66. package/node_modules/hono/dist/types/jsx/base.d.ts +3 -0
  67. package/node_modules/hono/package.json +2 -2
  68. package/node_modules/ip-address/README.md +92 -82
  69. package/node_modules/ip-address/dist/common.d.ts +20 -0
  70. package/node_modules/ip-address/dist/common.js +36 -0
  71. package/node_modules/ip-address/dist/common.js.map +1 -1
  72. package/node_modules/ip-address/dist/ipv4.d.ts +50 -0
  73. package/node_modules/ip-address/dist/ipv4.js +75 -0
  74. package/node_modules/ip-address/dist/ipv4.js.map +1 -1
  75. package/node_modules/ip-address/dist/ipv6.d.ts +79 -10
  76. package/node_modules/ip-address/dist/ipv6.js +120 -30
  77. package/node_modules/ip-address/dist/ipv6.js.map +1 -1
  78. package/node_modules/ip-address/dist/v4/constants.d.ts +12 -0
  79. package/node_modules/ip-address/dist/v4/constants.js +40 -1
  80. package/node_modules/ip-address/dist/v4/constants.js.map +1 -1
  81. package/node_modules/ip-address/dist/v6/constants.d.ts +14 -0
  82. package/node_modules/ip-address/dist/v6/constants.js +47 -1
  83. package/node_modules/ip-address/dist/v6/constants.js.map +1 -1
  84. package/node_modules/ip-address/package.json +1 -1
  85. package/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +7 -16
  86. package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +6 -17
  87. package/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +7 -16
  88. package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +11 -34
  89. package/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +7 -16
  90. package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +15 -35
  91. package/node_modules/jose/dist/types/jwk/embedded.d.ts +3 -8
  92. package/node_modules/jose/dist/types/jwk/thumbprint.d.ts +5 -5
  93. package/node_modules/jose/dist/types/jwks/local.d.ts +6 -10
  94. package/node_modules/jose/dist/types/jwks/remote.d.ts +13 -24
  95. package/node_modules/jose/dist/types/jws/compact/sign.d.ts +5 -10
  96. package/node_modules/jose/dist/types/jws/compact/verify.d.ts +9 -18
  97. package/node_modules/jose/dist/types/jws/flattened/sign.d.ts +7 -16
  98. package/node_modules/jose/dist/types/jws/flattened/verify.d.ts +9 -18
  99. package/node_modules/jose/dist/types/jws/general/sign.d.ts +11 -21
  100. package/node_modules/jose/dist/types/jws/general/verify.d.ts +9 -18
  101. package/node_modules/jose/dist/types/jwt/decrypt.d.ts +10 -20
  102. package/node_modules/jose/dist/types/jwt/encrypt.d.ts +6 -13
  103. package/node_modules/jose/dist/types/jwt/sign.d.ts +5 -6
  104. package/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -14
  105. package/node_modules/jose/dist/types/jwt/verify.d.ts +9 -19
  106. package/node_modules/jose/dist/types/key/export.d.ts +4 -4
  107. package/node_modules/jose/dist/types/key/generate_key_pair.d.ts +6 -8
  108. package/node_modules/jose/dist/types/key/generate_secret.d.ts +4 -11
  109. package/node_modules/jose/dist/types/key/import.d.ts +10 -17
  110. package/node_modules/jose/dist/types/types.d.ts +44 -84
  111. package/node_modules/jose/dist/types/util/base64url.d.ts +2 -2
  112. package/node_modules/jose/dist/types/util/decode_jwt.d.ts +3 -10
  113. package/node_modules/jose/dist/types/util/decode_protected_header.d.ts +4 -4
  114. package/node_modules/jose/dist/types/util/errors.d.ts +26 -53
  115. package/node_modules/jose/dist/webapi/index.js +70 -32
  116. package/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +7 -8
  117. package/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +42 -48
  118. package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +14 -14
  119. package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +53 -64
  120. package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +38 -49
  121. package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +121 -169
  122. package/node_modules/jose/dist/webapi/jwk/embedded.js +30 -32
  123. package/node_modules/jose/dist/webapi/jwk/thumbprint.js +54 -70
  124. package/node_modules/jose/dist/webapi/jwks/local.js +47 -64
  125. package/node_modules/jose/dist/webapi/jwks/remote.js +88 -136
  126. package/node_modules/jose/dist/webapi/jws/compact/sign.js +21 -21
  127. package/node_modules/jose/dist/webapi/jws/compact/verify.js +7 -8
  128. package/node_modules/jose/dist/webapi/jws/flattened/sign.js +29 -31
  129. package/node_modules/jose/dist/webapi/jws/flattened/verify.js +21 -24
  130. package/node_modules/jose/dist/webapi/jws/general/sign.js +61 -72
  131. package/node_modules/jose/dist/webapi/jws/general/verify.js +45 -69
  132. package/node_modules/jose/dist/webapi/jwt/decrypt.js +13 -20
  133. package/node_modules/jose/dist/webapi/jwt/encrypt.js +57 -70
  134. package/node_modules/jose/dist/webapi/jwt/sign.js +17 -16
  135. package/node_modules/jose/dist/webapi/jwt/unsecured.js +32 -40
  136. package/node_modules/jose/dist/webapi/jwt/verify.js +12 -14
  137. package/node_modules/jose/dist/webapi/key/export.js +32 -37
  138. package/node_modules/jose/dist/webapi/key/generate_key_pair.js +40 -48
  139. package/node_modules/jose/dist/webapi/key/generate_secret.js +35 -40
  140. package/node_modules/jose/dist/webapi/key/import.js +52 -56
  141. package/node_modules/jose/dist/webapi/lib/asn1.js +130 -169
  142. package/node_modules/jose/dist/webapi/lib/base64.js +18 -20
  143. package/node_modules/jose/dist/webapi/lib/buffer_utils.js +34 -38
  144. package/node_modules/jose/dist/webapi/lib/content_encryption.js +79 -115
  145. package/node_modules/jose/dist/webapi/lib/crypto_key.js +24 -25
  146. package/node_modules/jose/dist/webapi/lib/deflate.js +45 -47
  147. package/node_modules/jose/dist/webapi/lib/helpers.js +40 -37
  148. package/node_modules/jose/dist/webapi/lib/invalid_key_input.js +10 -24
  149. package/node_modules/jose/dist/webapi/lib/is_key_like.js +17 -15
  150. package/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +106 -93
  151. package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +207 -230
  152. package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +104 -138
  153. package/node_modules/jose/dist/webapi/lib/jwk_metadata.js +17 -18
  154. package/node_modules/jose/dist/webapi/lib/jwk_to_key.js +9 -16
  155. package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +62 -61
  156. package/node_modules/jose/dist/webapi/lib/jws_sign.js +50 -75
  157. package/node_modules/jose/dist/webapi/lib/jws_verify.js +80 -125
  158. package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +123 -209
  159. package/node_modules/jose/dist/webapi/lib/key.js +84 -136
  160. package/node_modules/jose/dist/webapi/lib/key_algorithm.js +13 -8
  161. package/node_modules/jose/dist/webapi/lib/key_descriptor.js +8 -6
  162. package/node_modules/jose/dist/webapi/lib/key_management.js +200 -231
  163. package/node_modules/jose/dist/webapi/lib/key_options.js +7 -5
  164. package/node_modules/jose/dist/webapi/lib/options.js +55 -68
  165. package/node_modules/jose/dist/webapi/lib/signing.js +18 -22
  166. package/node_modules/jose/dist/webapi/lib/type_checks.js +26 -29
  167. package/node_modules/jose/dist/webapi/util/base64url.js +26 -35
  168. package/node_modules/jose/dist/webapi/util/decode_jwt.js +32 -31
  169. package/node_modules/jose/dist/webapi/util/decode_protected_header.js +18 -23
  170. package/node_modules/jose/dist/webapi/util/errors.js +94 -84
  171. package/node_modules/jose/package.json +17 -81
  172. package/package.json +2 -2
  173. package/profiles/calendar/0.5.profile.json +190 -0
  174. package/profiles/charge/0.5.profile.json +210 -0
  175. package/profiles/customers/0.7.profile.json +157 -0
  176. package/profiles/deploy/0.9.profile.json +176 -0
  177. package/profiles/email/0.6.profile.json +208 -0
  178. package/profiles/index.json +9 -1
  179. package/profiles/publish/0.5.profile.json +186 -0
  180. package/profiles/purchase/0.5.profile.json +231 -0
  181. package/profiles/records/0.5.profile.json +117 -0
@@ -408,6 +408,17 @@ export type Options = {
408
408
  * Defaults to `{limit}-in-{window}`.
409
409
  */
410
410
  identifier: string | ValueDeterminingMiddleware<string>;
411
+ /**
412
+ * Method to generate a custom `Retry-After` header value (in seconds) when
413
+ * a client is rate limited.
414
+ *
415
+ * This is advisory only, it customizes what the header says, it does not
416
+ * change how long the limiter actually keeps blocking the client for.
417
+ * That is still controlled by `windowMs`.
418
+ *
419
+ * By default, the number of seconds remaining until the window resets.
420
+ */
421
+ retryAfter?: number | ValueDeterminingMiddleware<number>;
411
422
  /**
412
423
  * The name of the property on the request object to store the rate limit info.
413
424
  *
@@ -408,6 +408,17 @@ export type Options = {
408
408
  * Defaults to `{limit}-in-{window}`.
409
409
  */
410
410
  identifier: string | ValueDeterminingMiddleware<string>;
411
+ /**
412
+ * Method to generate a custom `Retry-After` header value (in seconds) when
413
+ * a client is rate limited.
414
+ *
415
+ * This is advisory only, it customizes what the header says, it does not
416
+ * change how long the limiter actually keeps blocking the client for.
417
+ * That is still controlled by `windowMs`.
418
+ *
419
+ * By default, the number of seconds remaining until the window resets.
420
+ */
421
+ retryAfter?: number | ValueDeterminingMiddleware<number>;
411
422
  /**
412
423
  * The name of the property on the request object to store the rate limit info.
413
424
  *
@@ -254,9 +254,9 @@ var setDraft8Headers = (response, info, windowMs, name, key) => {
254
254
  response.append("RateLimit", `"${name}"; ${header}`);
255
255
  response.append("RateLimit-Policy", `"${name}"; ${policy}`);
256
256
  };
257
- var setRetryAfterHeader = (response, info, windowMs) => {
257
+ var setRetryAfterHeader = (response, info, windowMs, retryAfter) => {
258
258
  if (response.headersSent) return;
259
- const resetSeconds = getResetSeconds(windowMs, info.resetTime);
259
+ const resetSeconds = retryAfter ?? getResetSeconds(windowMs, info.resetTime);
260
260
  response.setHeader("Retry-After", resetSeconds.toString());
261
261
  };
262
262
 
@@ -523,6 +523,7 @@ var validations = {
523
523
  legacyHeaders: true,
524
524
  standardHeaders: true,
525
525
  identifier: true,
526
+ retryAfter: true,
526
527
  requestPropertyName: true,
527
528
  skipFailedRequests: true,
528
529
  skipSuccessfulRequests: true,
@@ -1007,7 +1008,9 @@ var rateLimit = (passedOptions) => {
1007
1008
  debug("limit exceeded");
1008
1009
  if (config.legacyHeaders || config.standardHeaders) {
1009
1010
  debug("set retry-after header");
1010
- setRetryAfterHeader(response, info, config.windowMs);
1011
+ const retrieveRetryAfter = typeof config.retryAfter === "function" ? config.retryAfter(request, response) : config.retryAfter;
1012
+ const retryAfter = await retrieveRetryAfter;
1013
+ setRetryAfterHeader(response, info, config.windowMs, retryAfter);
1011
1014
  }
1012
1015
  config.handler(request, response, next, options);
1013
1016
  return;
@@ -1,4 +1,4 @@
1
- # MIT License
1
+ MIT License
2
2
 
3
3
  Copyright 2023 Nathan Friedly, Vedant K
4
4
 
@@ -13,8 +13,9 @@ The above copyright notice and this permission notice shall be included in all
13
13
  copies or substantial portions of the Software.
14
14
 
15
15
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-rate-limit",
3
- "version": "8.6.2",
3
+ "version": "8.7.0",
4
4
  "description": "Basic IP rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset.",
5
5
  "author": {
6
6
  "name": "Nathan Friedly",
@@ -90,16 +90,16 @@
90
90
  "@types/debug": "4.1.13",
91
91
  "@types/express": "5.0.6",
92
92
  "@types/jest": "30.0.0",
93
- "@types/node": "26.1.2",
93
+ "@types/node": "26.2.0",
94
94
  "@types/supertest": "7.2.1",
95
95
  "del-cli": "7.0.0",
96
96
  "dts-bundle-generator": "8.1.2",
97
- "esbuild": "0.28.1",
97
+ "esbuild": "0.28.2",
98
98
  "express": "5.2.1",
99
99
  "husky": "9.1.7",
100
100
  "jest": "30.4.2",
101
- "lint-staged": "17.2.0",
102
- "mintlify": "4.2.743",
101
+ "lint-staged": "17.3.0",
102
+ "mintlify": "4.2.817",
103
103
  "npm-run-all": "4.1.5",
104
104
  "prettier": "3.9.6",
105
105
  "ratelimit-header-parser": "0.1.0",
@@ -5,6 +5,7 @@
5
5
  [![tests](https://img.shields.io/github/actions/workflow/status/express-rate-limit/express-rate-limit/ci.yaml)](https://github.com/express-rate-limit/express-rate-limit/actions/workflows/ci.yaml)
6
6
  [![npm version](https://img.shields.io/npm/v/express-rate-limit.svg)](https://npmjs.org/package/express-rate-limit 'View this project on NPM')
7
7
  [![npm downloads](https://img.shields.io/npm/dm/express-rate-limit)](https://www.npmjs.com/package/express-rate-limit)
8
+ [![inspect.software](https://raw.githubusercontent.com/inspect-software/badges/main/v1/e/express-rate-limit/express-rate-limit.svg)](https://inspect.software/software/express-rate-limit/express-rate-limit)
8
9
  [![license](https://img.shields.io/npm/l/express-rate-limit)](license.md)
9
10
 
10
11
  </div>
@@ -324,6 +324,18 @@ function hasMalformedPercentEncoding (component) {
324
324
  return false
325
325
  }
326
326
 
327
+ /**
328
+ * Whether the host is a bracketed IP literal (RFC 3986 `IP-literal`).
329
+ * An unterminated `[` is not a literal, so it must still be validated as a
330
+ * reg-name instead of being waved through as an IP.
331
+ *
332
+ * @param {string} host
333
+ * @returns {boolean}
334
+ */
335
+ function isIPLiteral (host) {
336
+ return host[0] === '[' && host[host.length - 1] === ']'
337
+ }
338
+
327
339
  /**
328
340
  * @param {RegExpMatchArray} matches
329
341
  * @returns {boolean}
@@ -333,7 +345,7 @@ function hasMalformedComponentPercentEncoding (matches) {
333
345
  // compatibility. Their parsing is intentionally left to normalizeIPv6.
334
346
  const host = matches[4]
335
347
  return hasMalformedPercentEncoding(matches[3]) ||
336
- (host !== undefined && !(host[0] === '[' && host[host.length - 1] === ']') && hasMalformedPercentEncoding(host)) ||
348
+ (host !== undefined && !isIPLiteral(host) && hasMalformedPercentEncoding(host)) ||
337
349
  hasMalformedPercentEncoding(matches[6]) ||
338
350
  hasMalformedPercentEncoding(matches[7]) ||
339
351
  hasMalformedPercentEncoding(matches[8])
@@ -351,7 +363,7 @@ function canonicalizeHost (parsed, options, schemeHandler, isIP) {
351
363
  !options.unicodeSupport &&
352
364
  (!schemeHandler || !schemeHandler.unicodeSupport) &&
353
365
  parsed.host &&
354
- parsed.host[0] !== '[' &&
366
+ !isIPLiteral(parsed.host) &&
355
367
  (options.domainHost || (schemeHandler && schemeHandler.domainHost)) &&
356
368
  isIP === false &&
357
369
  nonSimpleDomain(parsed.host)
@@ -476,10 +488,11 @@ function parseWithStatus (uri, opts) {
476
488
  if (parsed.host) {
477
489
  const ipv4result = isIPv4(parsed.host)
478
490
  if (ipv4result === false) {
479
- const bracketedIPLiteral = parsed.host[0] === '[' && parsed.host[parsed.host.length - 1] === ']'
491
+ const bracketedIPLiteral = isIPLiteral(parsed.host)
492
+ const hasIPLiteralBracket = parsed.host.indexOf('[') !== -1 || parsed.host.indexOf(']') !== -1
480
493
  const ipv6result = normalizeIPv6(parsed.host)
481
494
  isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true
482
- malformedIPLiteral = bracketedIPLiteral && ipv6result.error === true
495
+ malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true)
483
496
  parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase()
484
497
 
485
498
  if (malformedIPLiteral) {
@@ -509,7 +522,9 @@ function parseWithStatus (uri, opts) {
509
522
  const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme)
510
523
 
511
524
  // convert Unicode IDN -> ASCII IDN when the effective scheme uses domain hosts
512
- malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP)
525
+ if (!malformedIPLiteral) {
526
+ malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP)
527
+ }
513
528
 
514
529
  if (!schemeHandler || (schemeHandler && !schemeHandler.skipNormalize)) {
515
530
  if (uri.indexOf('%') !== -1) {
@@ -6,6 +6,9 @@ const isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\d
6
6
  /** @type {(value: string) => boolean} */
7
7
  const isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u)
8
8
 
9
+ /** @type {(value: string) => boolean} */
10
+ const isPort = RegExp.prototype.test.bind(/^\d*$/u)
11
+
9
12
  /** @type {(value: string) => boolean} */
10
13
  const isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu)
11
14
 
@@ -713,8 +716,12 @@ function recomposeAuthority (component) {
713
716
  }
714
717
 
715
718
  if (typeof component.port === 'number' || typeof component.port === 'string') {
719
+ const port = String(component.port)
720
+ if (!isPort(port)) {
721
+ throw new TypeError('URI port is malformed.')
722
+ }
716
723
  uriTokens.push(':')
717
- uriTokens.push(String(component.port))
724
+ uriTokens.push(port)
718
725
  }
719
726
 
720
727
  return uriTokens.length ? uriTokens.join('') : undefined
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fast-uri",
3
3
  "description": "Dependency-free RFC 3986 URI toolbox",
4
- "version": "3.1.6",
4
+ "version": "3.1.7",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
7
7
  "types": "types/index.d.ts",
@@ -24,6 +24,64 @@ test('userinfo serialization cannot terminate the authority', (t) => {
24
24
  t.end()
25
25
  })
26
26
 
27
+ test('port serialization rejects non-digit values', (t) => {
28
+ const malformedPorts = [
29
+ '@127.0.0.1:8124',
30
+ '8080@evil.example',
31
+ '8080/path',
32
+ '8080?query',
33
+ '8080#fragment',
34
+ '8080:9000',
35
+ '-1',
36
+ '1.5',
37
+ 1.5,
38
+ NaN,
39
+ Infinity,
40
+ '\u0661'
41
+ ]
42
+
43
+ for (const port of malformedPorts) {
44
+ t.throws(
45
+ () => fastURI.serialize({ scheme: 'http', host: 'trusted.example', port, path: '/app' }),
46
+ /URI port is malformed\./,
47
+ String(port)
48
+ )
49
+ }
50
+
51
+ t.throws(
52
+ () => fastURI.normalize({ scheme: 'http', host: 'trusted.example', port: '@evil.example' }),
53
+ /URI port is malformed\./,
54
+ 'object normalization rejects a malformed port'
55
+ )
56
+ t.equal(
57
+ fastURI.equal(
58
+ { scheme: 'http', host: 'trusted.example', port: '@evil.example' },
59
+ { scheme: 'http', host: 'trusted.example', port: '@evil.example' }
60
+ ),
61
+ false,
62
+ 'object equality fails closed for a malformed port'
63
+ )
64
+ t.end()
65
+ })
66
+
67
+ test('port serialization preserves RFC 3986 digit values', (t) => {
68
+ const validPorts = [
69
+ [8080, '8080'],
70
+ ['8080', '8080'],
71
+ ['00080', '00080'],
72
+ ['', '']
73
+ ]
74
+
75
+ for (const [port, expected] of validPorts) {
76
+ t.equal(
77
+ fastURI.serialize({ scheme: 'uri', host: 'example.test', port }),
78
+ `uri://example.test:${expected}`,
79
+ JSON.stringify(port)
80
+ )
81
+ }
82
+ t.end()
83
+ })
84
+
27
85
  test('query and fragment serialization cannot inject component delimiters', (t) => {
28
86
  const uri = fastURI.serialize({
29
87
  scheme: 'x',
@@ -88,3 +88,37 @@ test('valid IPv6, IPvFuture, embedded IPv4, and zone forms normalize safely', (t
88
88
  }
89
89
  t.end()
90
90
  })
91
+
92
+ test('hosts with unbalanced or misplaced IP-literal brackets are rejected', (t) => {
93
+ const malformed = [
94
+ 'http://[fe80',
95
+ 'http://[',
96
+ 'http://[not-an-ip',
97
+ 'http://[\u65e5\u672c',
98
+ 'http://user@[@127.0.0.1:8123/admin',
99
+ 'http://user@]127.0.0.1:8123/admin',
100
+ 'http://user@prefix[@127.0.0.1:8123/admin',
101
+ 'http://user@prefix]@127.0.0.1:8123/admin'
102
+ ]
103
+ const modes = [
104
+ ['default', undefined],
105
+ ['Unicode', { unicodeSupport: true }]
106
+ ]
107
+
108
+ for (const [mode, options] of modes) {
109
+ for (const uri of malformed) {
110
+ const parsed = fastURI.parse(uri, options)
111
+ const message = `${mode} mode rejects ${uri}`
112
+
113
+ t.equal(parsed.error, HOST_ERROR, `parse ${message}`)
114
+ t.equal(fastURI.normalize(uri, options), uri, `normalize preserves ${uri} in ${mode} mode`)
115
+ t.equal(fastURI.equal(uri, uri, options), false, `equal ${message}`)
116
+ t.throws(
117
+ () => fastURI.resolve('http://example.com/', uri, options),
118
+ /URI host is malformed\./,
119
+ `resolve ${message}`
120
+ )
121
+ }
122
+ }
123
+ t.end()
124
+ })
@@ -157,24 +157,24 @@ const hc = (baseUrl, options) => createProxy(function proxyCallback(opts) {
157
157
  const path = parts.join("/");
158
158
  const url = (0, import_utils.mergePath)(baseUrl, path);
159
159
  if (method === "url" || method === "path") {
160
- let result = url;
160
+ let result = (0, import_utils.removeIndexString)(url);
161
161
  if (opts.args[0]) {
162
162
  if (opts.args[0].param) {
163
- result = (0, import_utils.replaceUrlParam)(url, opts.args[0].param);
163
+ result = (0, import_utils.replaceUrlParam)(result, opts.args[0].param);
164
164
  }
165
165
  if (opts.args[0].query) {
166
166
  result = appendQueryParams(result, buildSearchParamsOption(opts.args[0].query));
167
167
  }
168
168
  }
169
- result = (0, import_utils.removeIndexString)(result);
170
169
  if (method === "url") {
171
170
  return new URL(result);
172
171
  }
173
172
  return result.slice(baseUrl.replace(/\/+$/, "").length).replace(/^\/?/, "/");
174
173
  }
175
174
  if (method === "ws") {
175
+ const normalizedUrl = (0, import_utils.removeIndexString)(url);
176
176
  const webSocketUrl = (0, import_utils.replaceUrlProtocol)(
177
- opts.args[0]?.param ? (0, import_utils.replaceUrlParam)(url, opts.args[0].param) : url,
177
+ opts.args[0]?.param ? (0, import_utils.replaceUrlParam)(normalizedUrl, opts.args[0].param) : normalizedUrl,
178
178
  "ws"
179
179
  );
180
180
  const targetUrl = new URL(webSocketUrl);
@@ -61,13 +61,14 @@ class Hono {
61
61
  const allMethods = [...import_router.METHODS, import_router.METHOD_NAME_ALL_LOWERCASE];
62
62
  allMethods.forEach((method) => {
63
63
  this[method] = (args1, ...args) => {
64
+ const methodName = method.toUpperCase();
64
65
  if (typeof args1 === "string") {
65
66
  this.#path = args1;
66
67
  } else {
67
- this.#addRoute(method, this.#path, args1);
68
+ this.#addRoute(methodName, this.#path, args1);
68
69
  }
69
70
  args.forEach((handler) => {
70
- this.#addRoute(method, this.#path, handler);
71
+ this.#addRoute(methodName, this.#path, handler);
71
72
  });
72
73
  return this;
73
74
  };
@@ -76,9 +77,10 @@ class Hono {
76
77
  for (const p of [path].flat()) {
77
78
  this.#path = p;
78
79
  for (const m of [method].flat()) {
79
- handlers.map((handler) => {
80
- this.#addRoute(m.toUpperCase(), this.#path, handler);
81
- });
80
+ const methodName = m.toUpperCase();
81
+ for (const handler of handlers) {
82
+ this.#addRoute(methodName, this.#path, handler);
83
+ }
82
84
  }
83
85
  }
84
86
  return this;
@@ -279,7 +281,6 @@ class Hono {
279
281
  return this;
280
282
  }
281
283
  #addRoute(method, path, handler, baseRoutePath) {
282
- method = method.toUpperCase();
283
284
  path = (0, import_url.mergePath)(this._basePath, path);
284
285
  const r = {
285
286
  basePath: baseRoutePath !== void 0 ? (0, import_url.mergePath)(this._basePath, baseRoutePath) : this._basePath,
@@ -33,11 +33,14 @@ __export(base_exports, {
33
33
  booleanAttributes: () => booleanAttributes,
34
34
  cloneElement: () => cloneElement,
35
35
  getNameSpaceContext: () => getNameSpaceContext,
36
+ isUntrustedObject: () => isUntrustedObject,
36
37
  isValidElement: () => isValidElement,
37
38
  jsx: () => jsx,
38
39
  jsxFn: () => jsxFn,
39
40
  memo: () => memo,
40
41
  reactAPICompatVersion: () => reactAPICompatVersion,
42
+ renderChildren: () => renderChildren,
43
+ renderUntrustedObject: () => renderUntrustedObject,
41
44
  shallowEqual: () => shallowEqual
42
45
  });
43
46
  module.exports = __toCommonJS(base_exports);
@@ -101,7 +104,7 @@ const booleanAttributes = [
101
104
  "selected"
102
105
  ];
103
106
  const resolveFunctionComponentResult = (result, suspendedContext) => result.then((resolved) => {
104
- if (!Array.isArray(resolved) && !(resolved instanceof JSXNode)) {
107
+ if (typeof resolved !== "string" && !Array.isArray(resolved) && !(resolved instanceof JSXNode)) {
105
108
  return resolved;
106
109
  }
107
110
  const children = Array.isArray(resolved) ? resolved : [resolved];
@@ -139,6 +142,17 @@ const childrenToStringToBuffer = (children, buffer) => {
139
142
  }
140
143
  }
141
144
  };
145
+ const renderChildren = (children) => (0, import_context.runWithRenderContext)(() => {
146
+ const buffer = [""];
147
+ childrenToStringToBuffer(children, buffer);
148
+ return buffer.length === 1 ? (0, import_html.raw)(buffer[0], buffer.callbacks) : (0, import_html2.stringBufferToString)(buffer, buffer.callbacks);
149
+ });
150
+ const isUntrustedObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof JSXNode) && !(value instanceof Promise) && !value.isEscaped && typeof value.toString === "function";
151
+ const renderUntrustedObject = (value) => {
152
+ const stringified = value.toString();
153
+ const escape = (result) => renderChildren([String(result)]);
154
+ return stringified instanceof Promise ? stringified.then(escape) : escape(stringified);
155
+ };
142
156
  class JSXNode {
143
157
  tag;
144
158
  props;
@@ -369,10 +383,13 @@ const reactAPICompatVersion = "19.0.0-hono-jsx";
369
383
  booleanAttributes,
370
384
  cloneElement,
371
385
  getNameSpaceContext,
386
+ isUntrustedObject,
372
387
  isValidElement,
373
388
  jsx,
374
389
  jsxFn,
375
390
  memo,
376
391
  reactAPICompatVersion,
392
+ renderChildren,
393
+ renderUntrustedObject,
377
394
  shallowEqual
378
395
  });
@@ -31,7 +31,7 @@ var import_streaming = require("./streaming");
31
31
  let errorBoundaryCounter = 0;
32
32
  const childrenToString = async (children) => {
33
33
  try {
34
- return children.flat().map((c) => c == null || typeof c === "boolean" ? "" : c.toString());
34
+ return children.flat().map(resolveChildEarly);
35
35
  } catch (e) {
36
36
  if (e instanceof Promise) {
37
37
  const resume = (0, import_context.captureRenderContext)();
@@ -42,18 +42,16 @@ const childrenToString = async (children) => {
42
42
  }
43
43
  }
44
44
  };
45
- const resolveChildEarly = (c) => {
46
- if (c == null || typeof c === "boolean") {
45
+ const resolveChildEarly = (child) => {
46
+ if (child == null || typeof child === "boolean") {
47
47
  return "";
48
- } else if (typeof c === "string") {
49
- return c;
48
+ } else if (typeof child === "string" || Array.isArray(child)) {
49
+ return (0, import_base.renderChildren)([child]);
50
+ } else if ((0, import_base.isUntrustedObject)(child)) {
51
+ return (0, import_base.renderUntrustedObject)(child);
50
52
  } else {
51
- const str = c.toString();
52
- if (!(str instanceof Promise)) {
53
- return (0, import_html.raw)(str);
54
- } else {
55
- return str;
56
- }
53
+ const str = child.toString();
54
+ return str instanceof Promise ? str : (0, import_html.raw)(str);
57
55
  }
58
56
  };
59
57
  const ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) => {
@@ -69,26 +67,27 @@ const ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) =>
69
67
  let fallbackStrPromise;
70
68
  const resolveFallbackStr = () => fallbackStrPromise ||= (async () => {
71
69
  const awaitedFallback = await fallback;
72
- if (typeof awaitedFallback === "string") {
73
- return awaitedFallback;
74
- } else {
75
- const fallbackResult = await getResume()(() => awaitedFallback?.toString());
76
- if (typeof fallbackResult === "string") {
77
- return (0, import_html.raw)(
78
- fallbackResult,
79
- fallbackResult.callbacks || awaitedFallback?.callbacks
80
- );
81
- }
70
+ if (awaitedFallback === null || awaitedFallback === void 0) {
71
+ return;
72
+ }
73
+ if (typeof awaitedFallback === "string" || Array.isArray(awaitedFallback)) {
74
+ return getResume()(() => (0, import_base.renderChildren)([awaitedFallback]));
75
+ }
76
+ if ((0, import_base.isUntrustedObject)(awaitedFallback)) {
77
+ return getResume()(() => (0, import_base.renderUntrustedObject)(awaitedFallback));
82
78
  }
79
+ const fallbackResult = await getResume()(() => awaitedFallback.toString());
80
+ return (0, import_html.raw)(
81
+ fallbackResult,
82
+ fallbackResult.callbacks || awaitedFallback.callbacks
83
+ );
83
84
  })();
84
85
  const renderFallback = async (error) => {
85
86
  const fallbackStr = await resolveFallbackStr();
86
87
  return getResume()(async () => {
87
88
  onError?.(error);
88
89
  const fallbackRes = fallbackStr !== void 0 ? fallbackStr : fallbackRender && (0, import_base.jsx)(import_base.Fragment, {}, fallbackRender(error)) || "";
89
- const fallbackResString = await (0, import_base.Fragment)({
90
- children: fallbackRes
91
- }).toString();
90
+ const fallbackResString = await (0, import_base.Fragment)({ children: fallbackRes }).toString();
92
91
  return (0, import_html.raw)(
93
92
  fallbackResString,
94
93
  fallbackResString.callbacks || fallbackRes.callbacks
@@ -121,7 +120,7 @@ const ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) =>
121
120
  const fallbackResString = await renderFallback(error2);
122
121
  const fallbackCallbacks = fallbackResString.callbacks;
123
122
  if (buffer) {
124
- buffer[0] = buffer[0].replace(replaceRe, fallbackResString);
123
+ buffer[0] = buffer[0].replace(replaceRe, () => fallbackResString);
125
124
  return fallbackCallbacks?.length ? (0, import_html.raw)("", fallbackCallbacks) : "";
126
125
  }
127
126
  return (0, import_html.raw)(
@@ -160,7 +159,7 @@ d.parentElement.insertBefore(c.content,d.nextSibling)
160
159
  </script>`;
161
160
  if (htmlArray.every((html2) => !html2.callbacks?.length)) {
162
161
  if (buffer) {
163
- buffer[0] = buffer[0].replace(replaceRe, content);
162
+ buffer[0] = buffer[0].replace(replaceRe, () => content);
164
163
  }
165
164
  return html;
166
165
  }
@@ -155,18 +155,18 @@ const createContext = (defaultValue) => {
155
155
  const context = ((props) => {
156
156
  const contextValues = getContextValuesIn(getCurrentStore(), context);
157
157
  contextValues.push(props.value);
158
- let string;
158
+ let rendered;
159
159
  try {
160
- string = props.children ? (Array.isArray(props.children) ? new import_base.JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
160
+ rendered = typeof props.children === "string" ? (0, import_base.renderChildren)([props.children]) : (0, import_base.isUntrustedObject)(props.children) ? (0, import_base.renderUntrustedObject)(props.children) : props.children ? (Array.isArray(props.children) ? new import_base.JSXFragmentNode("", {}, props.children) : props.children).toString() : (0, import_html.raw)("");
161
161
  } catch (e) {
162
162
  contextValues.pop();
163
163
  throw e;
164
164
  }
165
- if (string instanceof Promise) {
166
- return string.finally(() => contextValues.pop()).then((resString) => (0, import_html.raw)(resString, resString.callbacks));
165
+ if (rendered instanceof Promise) {
166
+ return rendered.finally(() => contextValues.pop()).then((resString) => (0, import_html.raw)(resString, resString.callbacks));
167
167
  } else {
168
168
  contextValues.pop();
169
- return (0, import_html.raw)(string);
169
+ return (0, import_html.raw)(rendered);
170
170
  }
171
171
  });
172
172
  context.values = values;
@@ -33,13 +33,16 @@ __export(server_exports, {
33
33
  version: () => import__.default
34
34
  });
35
35
  module.exports = __toCommonJS(server_exports);
36
+ var import_base = require("../base");
36
37
  var import_streaming = require("../streaming");
37
38
  var import__ = __toESM(require("./"), 1);
39
+ const prepareRoot = (element) => typeof element === "string" || Array.isArray(element) ? (0, import_base.renderChildren)([element]) : element;
38
40
  const renderToString = (element, options = {}) => {
39
41
  if (Object.keys(options).length > 0) {
40
42
  console.warn("options are not supported yet");
41
43
  }
42
- const res = element?.toString() ?? "";
44
+ element = prepareRoot(element);
45
+ const res = element instanceof Promise ? element : element?.toString() ?? "";
43
46
  if (typeof res !== "string") {
44
47
  throw new Error("Async component is not supported in renderToString");
45
48
  }
@@ -49,6 +52,7 @@ const renderToReadableStream = async (element, options = {}) => {
49
52
  if (Object.keys(options).some((key) => key !== "onError")) {
50
53
  console.warn("options are not supported yet, except onError");
51
54
  }
55
+ element = prepareRoot(element);
52
56
  if (!element || typeof element !== "object") {
53
57
  element = element?.toString() ?? "";
54
58
  }
@@ -85,10 +85,10 @@ const insertIntoHead = (tagName, tag, props, precedence) => ({ buffer, context }
85
85
  insertTags.forEach((tag2) => {
86
86
  buffer[0] = buffer[0].replaceAll(tag2, "");
87
87
  });
88
- buffer[0] = buffer[0].replace(/(?=<\/head>)/, insertTags.join(""));
88
+ buffer[0] = buffer[0].replace(/(?=<\/head>)/, () => insertTags.join(""));
89
89
  }
90
90
  };
91
- const returnWithoutSpecialBehavior = (tag, children, props) => (0, import_html.raw)(new import_base.JSXNode(tag, props, (0, import_children.toArray)(children ?? [])).toString());
91
+ const returnWithoutSpecialBehavior = (tag, children, props) => (0, import_base.renderChildren)([new import_base.JSXNode(tag, props, (0, import_children.toArray)(children ?? []))]);
92
92
  const documentMetadataTag = (tag, children, props, sort) => {
93
93
  if ("itemProp" in props) {
94
94
  return returnWithoutSpecialBehavior(tag, children, props);
@@ -32,6 +32,7 @@ var import_components2 = require("./dom/components");
32
32
  var import_render = require("./dom/render");
33
33
  const StreamingContext = (0, import_context.createContext)(null);
34
34
  let suspenseCounter = 0;
35
+ const serializeBoundaryChild = (child) => typeof child === "string" || Array.isArray(child) ? (0, import_base.renderChildren)([child]) : child == null || typeof child === "boolean" ? "" : (0, import_base.isUntrustedObject)(child) ? (0, import_base.renderUntrustedObject)(child) : child.toString();
35
36
  const Suspense = async ({
36
37
  children,
37
38
  fallback
@@ -48,9 +49,7 @@ const Suspense = async ({
48
49
  try {
49
50
  stackNode[import_constants.DOM_STASH][0] = 0;
50
51
  import_render.buildDataStack.push([[], stackNode]);
51
- resArray = children.map(
52
- (c) => c == null || typeof c === "boolean" ? "" : c.toString()
53
- );
52
+ resArray = children.map(serializeBoundaryChild);
54
53
  } catch (e) {
55
54
  if (e instanceof Promise) {
56
55
  const resume = (0, import_context.captureRenderContext)();
@@ -71,7 +70,7 @@ const Suspense = async ({
71
70
  }
72
71
  if (resArray.some((res) => res instanceof Promise)) {
73
72
  const index = suspenseCounter++;
74
- const fallbackStr = await fallback.toString();
73
+ const fallbackStr = await (typeof fallback === "string" || Array.isArray(fallback) ? (0, import_base.renderChildren)([fallback]) : (0, import_base.isUntrustedObject)(fallback) ? (0, import_base.renderUntrustedObject)(fallback) : fallback.toString());
75
74
  return (0, import_html.raw)(`<template id="H:${index}"></template>${fallbackStr}<!--/$-->`, [
76
75
  ...fallbackStr.callbacks || [],
77
76
  ({ phase, buffer, context }) => {
@@ -84,7 +83,7 @@ const Suspense = async ({
84
83
  if (buffer) {
85
84
  buffer[0] = buffer[0].replace(
86
85
  new RegExp(`<template id="H:${index}"></template>.*?<!--/\\$-->`),
87
- content
86
+ () => content
88
87
  );
89
88
  }
90
89
  let html = buffer ? "" : `<template data-hono-target="H:${index}">${content}</template><script${nonce ? ` nonce="${nonce}"` : ""}>