@suveren/gateway 0.6.5 → 0.7.0

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 (84) hide show
  1. package/bin/suveren-gateway.js +19 -2
  2. package/dist/control-plane/index.mjs +208 -34
  3. package/dist/ui/assets/index-CkWaRck1.css +1 -0
  4. package/dist/ui/assets/index-DHT9QCrE.js +110 -0
  5. package/dist/ui/favicon.svg +8 -0
  6. package/dist/ui/index.html +6 -2
  7. package/lib/autostart-templates.d.mts +2 -0
  8. package/lib/autostart-templates.mjs +16 -3
  9. package/node_modules/@hap/core/README.md +4 -4
  10. package/node_modules/@hap/core/package.json +1 -1
  11. package/node_modules/@hono/node-server/README.md +47 -1
  12. package/node_modules/@hono/node-server/dist/early-hints.cjs +35 -0
  13. package/node_modules/@hono/node-server/dist/early-hints.d.cts +16 -0
  14. package/node_modules/@hono/node-server/dist/early-hints.d.mts +16 -0
  15. package/node_modules/@hono/node-server/dist/early-hints.mjs +33 -0
  16. package/node_modules/@hono/node-server/dist/index.cjs +4 -1
  17. package/node_modules/@hono/node-server/dist/index.mjs +4 -1
  18. package/node_modules/@hono/node-server/package.json +14 -1
  19. package/node_modules/express-rate-limit/dist/index.cjs +6 -1
  20. package/node_modules/express-rate-limit/dist/index.mjs +6 -1
  21. package/node_modules/express-rate-limit/package.json +6 -6
  22. package/node_modules/hono/dist/cjs/context.js +28 -13
  23. package/node_modules/hono/dist/cjs/hono-base.js +3 -2
  24. package/node_modules/hono/dist/cjs/jsx/base.js +26 -14
  25. package/node_modules/hono/dist/cjs/jsx/hooks/index.js +2 -2
  26. package/node_modules/hono/dist/cjs/middleware/cache/index.js +103 -8
  27. package/node_modules/hono/dist/cjs/middleware/compress/index.js +5 -0
  28. package/node_modules/hono/dist/cjs/middleware/cors/index.js +1 -1
  29. package/node_modules/hono/dist/cjs/middleware/etag/index.js +4 -1
  30. package/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +9 -4
  31. package/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +9 -4
  32. package/node_modules/hono/dist/cjs/middleware/method-not-allowed/index.js +90 -0
  33. package/node_modules/hono/dist/cjs/request.js +6 -8
  34. package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +55 -56
  35. package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +64 -85
  36. package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +13 -5
  37. package/node_modules/hono/dist/cjs/router/trie-router/node.js +1 -1
  38. package/node_modules/hono/dist/cjs/router.js +1 -1
  39. package/node_modules/hono/dist/cjs/utils/cookie.js +1 -1
  40. package/node_modules/hono/dist/cjs/utils/stream.js +5 -2
  41. package/node_modules/hono/dist/cjs/utils/url.js +7 -7
  42. package/node_modules/hono/dist/context.js +28 -13
  43. package/node_modules/hono/dist/hono-base.js +3 -2
  44. package/node_modules/hono/dist/jsx/base.js +26 -14
  45. package/node_modules/hono/dist/jsx/hooks/index.js +2 -2
  46. package/node_modules/hono/dist/middleware/cache/index.js +103 -8
  47. package/node_modules/hono/dist/middleware/compress/index.js +5 -0
  48. package/node_modules/hono/dist/middleware/cors/index.js +1 -1
  49. package/node_modules/hono/dist/middleware/etag/index.js +4 -1
  50. package/node_modules/hono/dist/middleware/jwk/jwk.js +9 -4
  51. package/node_modules/hono/dist/middleware/jwt/jwt.js +9 -4
  52. package/node_modules/hono/dist/middleware/method-not-allowed/index.js +68 -0
  53. package/node_modules/hono/dist/request.js +7 -9
  54. package/node_modules/hono/dist/router/reg-exp-router/node.js +55 -56
  55. package/node_modules/hono/dist/router/reg-exp-router/router.js +64 -85
  56. package/node_modules/hono/dist/router/reg-exp-router/trie.js +13 -5
  57. package/node_modules/hono/dist/router/trie-router/node.js +1 -1
  58. package/node_modules/hono/dist/router.js +1 -1
  59. package/node_modules/hono/dist/types/client/types.d.ts +1 -1
  60. package/node_modules/hono/dist/types/hono-base.d.ts +4 -3
  61. package/node_modules/hono/dist/types/jsx/base.d.ts +4 -2
  62. package/node_modules/hono/dist/types/jsx/dom/index.d.ts +5 -5
  63. package/node_modules/hono/dist/types/jsx/dom/intrinsic-element/components.d.ts +2 -2
  64. package/node_modules/hono/dist/types/jsx/dom/server.d.ts +5 -5
  65. package/node_modules/hono/dist/types/jsx/hooks/index.d.ts +8 -6
  66. package/node_modules/hono/dist/types/jsx/index.d.ts +5 -5
  67. package/node_modules/hono/dist/types/middleware/cache/index.d.ts +6 -4
  68. package/node_modules/hono/dist/types/middleware/cors/index.d.ts +1 -1
  69. package/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +2 -2
  70. package/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts +2 -0
  71. package/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts +2 -0
  72. package/node_modules/hono/dist/types/middleware/method-not-allowed/index.d.ts +49 -0
  73. package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +1 -1
  74. package/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +2 -1
  75. package/node_modules/hono/dist/types/router.d.ts +1 -1
  76. package/node_modules/hono/dist/types/utils/headers.d.ts +2 -2
  77. package/node_modules/hono/dist/types/utils/url.d.ts +1 -0
  78. package/node_modules/hono/dist/utils/cookie.js +2 -2
  79. package/node_modules/hono/dist/utils/stream.js +5 -2
  80. package/node_modules/hono/dist/utils/url.js +5 -6
  81. package/node_modules/hono/package.json +9 -1
  82. package/package.json +1 -1
  83. package/dist/ui/assets/index-DIcuh0I4.css +0 -1
  84. package/dist/ui/assets/index-Dl5isaOV.js +0 -105
@@ -20,7 +20,21 @@ __export(cache_exports, {
20
20
  cache: () => cache
21
21
  });
22
22
  module.exports = __toCommonJS(cache_exports);
23
+ var import_request = require("../../request");
24
+ var import_crypto = require("../../utils/crypto");
23
25
  const defaultCacheableStatusCodes = [200];
26
+ const defaultMaxQueryBodySize = 64 * 1024;
27
+ const cacheKeyPath = "/.hono/cache";
28
+ const cacheKeyParameter = "__hono_cache_key";
29
+ const cacheMethodKeyParameter = "__hono_cache_method";
30
+ const queryDigestKeyParameter = "__hono_query_digest";
31
+ const cacheVaryKeyParameter = "__hono_cache_vary";
32
+ const queryRepresentationMetadataHeaders = [
33
+ "content-type",
34
+ "content-encoding",
35
+ "content-language",
36
+ "content-location"
37
+ ];
24
38
  const shouldSkipCacheControl = (cacheControl) => !!cacheControl && /(?:^|,\s*)(?:private|no-(?:store|cache))(?:\s*(?:=|,|$))/i.test(cacheControl);
25
39
  const parseVaryDirectives = (vary) => {
26
40
  if (vary == null) {
@@ -28,17 +42,86 @@ const parseVaryDirectives = (vary) => {
28
42
  }
29
43
  return (Array.isArray(vary) ? vary : vary.split(",")).map((directive) => directive.trim().toLowerCase()).filter(Boolean);
30
44
  };
45
+ const createCacheKey = (key, requestUrl, request, varyHeaders) => {
46
+ const url = new URL(cacheKeyPath, requestUrl);
47
+ url.searchParams.append(cacheKeyParameter, key.split("#", 1)[0]);
48
+ url.searchParams.append(cacheMethodKeyParameter, request.method);
49
+ if (request.method === "QUERY") {
50
+ url.searchParams.append(queryDigestKeyParameter, request.digest);
51
+ }
52
+ for (const header of varyHeaders) {
53
+ url.searchParams.append(cacheVaryKeyParameter, JSON.stringify(header));
54
+ }
55
+ return url.href;
56
+ };
31
57
  const shouldSkipCache = (res, optionsVaryDirectives, responseVary) => responseVary.length && (!optionsVaryDirectives || responseVary.some((name) => !optionsVaryDirectives.has(name))) || shouldSkipCacheControl(res.headers.get("Cache-Control")) || res.headers.has("Set-Cookie");
58
+ const reportCacheNotAvailable = (onCacheNotAvailable, reason) => {
59
+ if (onCacheNotAvailable === false) {
60
+ } else if (onCacheNotAvailable) {
61
+ onCacheNotAvailable(reason);
62
+ } else {
63
+ console.log(reason);
64
+ }
65
+ };
66
+ const createQueryDigest = async (c, maxQueryBodySize) => {
67
+ if (!globalThis.crypto?.subtle) {
68
+ return void 0;
69
+ }
70
+ if (c.req.raw.bodyUsed && Object.keys(c.req.bodyCache)[0] === "formData") {
71
+ return void 0;
72
+ }
73
+ try {
74
+ const requestHeaders = c.req.raw.headers;
75
+ const metadata = new TextEncoder().encode(
76
+ JSON.stringify(
77
+ queryRepresentationMetadataHeaders.map((header) => [header, requestHeaders.get(header)])
78
+ )
79
+ );
80
+ const body = (await (0, import_request.cloneRawRequest)(c.req)).body;
81
+ const chunks = [];
82
+ let bodySize = 0;
83
+ if (body) {
84
+ const reader = body.getReader();
85
+ for (; ; ) {
86
+ const { done, value } = await reader.read();
87
+ if (done) {
88
+ break;
89
+ }
90
+ bodySize += value.byteLength;
91
+ if (bodySize > maxQueryBodySize) {
92
+ void reader.cancel().catch(() => {
93
+ });
94
+ return void 0;
95
+ }
96
+ chunks.push(value);
97
+ }
98
+ }
99
+ const data = new Uint8Array(metadata.byteLength + bodySize);
100
+ data.set(metadata);
101
+ let offset = metadata.byteLength;
102
+ for (const chunk of chunks) {
103
+ data.set(chunk, offset);
104
+ offset += chunk.byteLength;
105
+ }
106
+ return await (0, import_crypto.sha256)(data) ?? void 0;
107
+ } catch {
108
+ return void 0;
109
+ }
110
+ };
32
111
  const cache = (options) => {
33
112
  if (!globalThis.caches) {
34
- if (options.onCacheNotAvailable === false) {
35
- } else if (options.onCacheNotAvailable) {
36
- options.onCacheNotAvailable();
37
- } else {
38
- console.log("Cache Middleware is not enabled because caches is not defined.");
39
- }
113
+ reportCacheNotAvailable(
114
+ options.onCacheNotAvailable,
115
+ "Cache Middleware is not enabled because caches is not defined."
116
+ );
40
117
  return async (_c, next) => await next();
41
118
  }
119
+ if (!globalThis.crypto?.subtle) {
120
+ reportCacheNotAvailable(
121
+ options.onCacheNotAvailable,
122
+ "Cache Middleware cannot cache QUERY requests because Web Crypto is not available."
123
+ );
124
+ }
42
125
  if (options.wait === void 0) {
43
126
  options.wait = false;
44
127
  }
@@ -53,6 +136,7 @@ const cache = (options) => {
53
136
  const cacheableStatusCodes = new Set(
54
137
  options.cacheableStatusCodes ?? defaultCacheableStatusCodes
55
138
  );
139
+ const maxQueryBodySize = options.maxQueryBodySize ?? defaultMaxQueryBodySize;
56
140
  const addHeader = (c, responseVary) => {
57
141
  if (cacheControlDirectives) {
58
142
  const existingDirectives = c.res.headers.get("Cache-Control")?.split(",").map((d) => d.trim().split("=", 1)[0].toLowerCase()) ?? [];
@@ -81,20 +165,31 @@ const cache = (options) => {
81
165
  }
82
166
  };
83
167
  return async function cache2(c, next) {
84
- if (c.req.method !== "GET" || c.req.raw.headers.has("Authorization")) {
168
+ if (c.req.method !== "GET" && c.req.method !== "QUERY" || c.req.raw.headers.has("Authorization")) {
85
169
  await next();
86
170
  return;
87
171
  }
172
+ let cacheKeyRequest = { method: "GET" };
173
+ if (c.req.method === "QUERY") {
174
+ const digest = await createQueryDigest(c, maxQueryBodySize);
175
+ if (digest === void 0) {
176
+ await next();
177
+ return;
178
+ }
179
+ cacheKeyRequest = { method: "QUERY", digest };
180
+ }
88
181
  let key = c.req.url;
89
182
  if (options.keyGenerator) {
90
183
  key = await options.keyGenerator(c);
91
184
  }
185
+ const varyHeaders = [];
92
186
  if (varyDirectives) {
93
187
  for (const directive of varyDirectives) {
94
188
  const value = c.req.raw.headers.get(directive) ?? "";
95
- key += `::${directive}=${encodeURIComponent(value)}`;
189
+ varyHeaders.push([directive, value]);
96
190
  }
97
191
  }
192
+ key = createCacheKey(key, c.req.url, cacheKeyRequest, varyHeaders);
98
193
  const cacheName = typeof options.cacheName === "function" ? await options.cacheName(c) : options.cacheName;
99
194
  const cache3 = await caches.open(cacheName);
100
195
  const response = await cache3.match(key);
@@ -43,6 +43,7 @@ const selectEncoding = (header, candidates) => {
43
43
  }
44
44
  return best?.encoding;
45
45
  };
46
+ const varyAcceptEncodingRegExp = /(?:^|,)\s*accept-encoding\s*(?:,|$)/i;
46
47
  const compress = (options) => {
47
48
  const threshold = options?.threshold ?? 1024;
48
49
  const candidates = options?.encoding ? [options.encoding] : ENCODING_TYPES;
@@ -66,6 +67,10 @@ const compress = (options) => {
66
67
  !shouldTransform(ctx.res)) {
67
68
  return;
68
69
  }
70
+ const current = ctx.res.headers.get("Vary");
71
+ if (current !== "*" && !(current && varyAcceptEncodingRegExp.test(current))) {
72
+ ctx.header("Vary", current ? `${current}, Accept-Encoding` : "Accept-Encoding");
73
+ }
69
74
  const accepted = ctx.req.header("Accept-Encoding");
70
75
  const encoding = selectEncoding(accepted, candidates);
71
76
  if (!encoding || !ctx.res.body) {
@@ -23,7 +23,7 @@ module.exports = __toCommonJS(cors_exports);
23
23
  const cors = (options) => {
24
24
  const opts = {
25
25
  origin: "*",
26
- allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"],
26
+ allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH", "QUERY"],
27
27
  allowHeaders: [],
28
28
  exposeHeaders: [],
29
29
  ...options
@@ -54,6 +54,9 @@ const etag = (options) => {
54
54
  return async function etag2(c, next) {
55
55
  const ifNoneMatch = c.req.header("If-None-Match") ?? null;
56
56
  await next();
57
+ if (!(c.req.method === "GET" || c.req.method === "HEAD" || c.req.method === "QUERY") || !c.res.ok) {
58
+ return;
59
+ }
57
60
  const res = c.res;
58
61
  let etag3 = res.headers.get("ETag");
59
62
  if (!etag3) {
@@ -70,7 +73,7 @@ const etag = (options) => {
70
73
  }
71
74
  etag3 = weak ? `W/"${hash}"` : `"${hash}"`;
72
75
  }
73
- const matched = ifNoneMatch === "*" ? (c.req.method === "GET" || c.req.method === "HEAD") && res.ok : etagMatches(etag3, ifNoneMatch);
76
+ const matched = ifNoneMatch === "*" || etagMatches(etag3, ifNoneMatch);
74
77
  if (matched) {
75
78
  c.res = new Response(null, {
76
79
  status: 304,
@@ -45,7 +45,8 @@ const jwk = (options, init) => {
45
45
  res: unauthorizedResponse({
46
46
  ctx,
47
47
  error: "invalid_request",
48
- errDescription
48
+ errDescription,
49
+ realm: options.realm
49
50
  })
50
51
  });
51
52
  } else {
@@ -83,7 +84,8 @@ const jwk = (options, init) => {
83
84
  res: unauthorizedResponse({
84
85
  ctx,
85
86
  error: "invalid_request",
86
- errDescription
87
+ errDescription,
88
+ realm: options.realm
87
89
  })
88
90
  });
89
91
  }
@@ -110,7 +112,8 @@ const jwk = (options, init) => {
110
112
  ctx,
111
113
  error: "invalid_token",
112
114
  statusText: "Unauthorized",
113
- errDescription: "token verification failure"
115
+ errDescription: "token verification failure",
116
+ realm: options.realm
114
117
  }),
115
118
  cause
116
119
  });
@@ -120,11 +123,13 @@ const jwk = (options, init) => {
120
123
  };
121
124
  };
122
125
  function unauthorizedResponse(opts) {
126
+ const realm = (opts.realm ?? opts.ctx.req.url).replace(/"/g, '\\"');
127
+ const errDescription = opts.errDescription.replace(/"/g, '\\"');
123
128
  return new Response("Unauthorized", {
124
129
  status: 401,
125
130
  statusText: opts.statusText,
126
131
  headers: {
127
- "WWW-Authenticate": `Bearer realm="${opts.ctx.req.url}",error="${opts.error}",error_description="${opts.errDescription}"`
132
+ "WWW-Authenticate": `Bearer realm="${realm}",error="${opts.error}",error_description="${errDescription}"`
128
133
  }
129
134
  });
130
135
  }
@@ -52,7 +52,8 @@ const jwt = (options) => {
52
52
  res: unauthorizedResponse({
53
53
  ctx,
54
54
  error: "invalid_request",
55
- errDescription
55
+ errDescription,
56
+ realm: options.realm
56
57
  })
57
58
  });
58
59
  } else {
@@ -87,7 +88,8 @@ const jwt = (options) => {
87
88
  res: unauthorizedResponse({
88
89
  ctx,
89
90
  error: "invalid_request",
90
- errDescription
91
+ errDescription,
92
+ realm: options.realm
91
93
  })
92
94
  });
93
95
  }
@@ -108,7 +110,8 @@ const jwt = (options) => {
108
110
  ctx,
109
111
  error: "invalid_token",
110
112
  statusText: "Unauthorized",
111
- errDescription: "token verification failure"
113
+ errDescription: "token verification failure",
114
+ realm: options.realm
112
115
  }),
113
116
  cause
114
117
  });
@@ -118,11 +121,13 @@ const jwt = (options) => {
118
121
  };
119
122
  };
120
123
  function unauthorizedResponse(opts) {
124
+ const realm = (opts.realm ?? opts.ctx.req.url).replace(/"/g, '\\"');
125
+ const errDescription = opts.errDescription.replace(/"/g, '\\"');
121
126
  return new Response("Unauthorized", {
122
127
  status: 401,
123
128
  statusText: opts.statusText,
124
129
  headers: {
125
- "WWW-Authenticate": `Bearer realm="${opts.ctx.req.url}",error="${opts.error}",error_description="${opts.errDescription}"`
130
+ "WWW-Authenticate": `Bearer realm="${realm}",error="${opts.error}",error_description="${errDescription}"`
126
131
  }
127
132
  });
128
133
  }
@@ -0,0 +1,90 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var method_not_allowed_exports = {};
19
+ __export(method_not_allowed_exports, {
20
+ methodNotAllowed: () => methodNotAllowed
21
+ });
22
+ module.exports = __toCommonJS(method_not_allowed_exports);
23
+ var import_route = require("../../helper/route");
24
+ var import_router = require("../../router");
25
+ var import_trie_router = require("../../router/trie-router");
26
+ const methodNotAllowed = (options) => {
27
+ let methodRouter;
28
+ return async function methodNotAllowed2(c, next) {
29
+ const routeIndex = c.req.routeIndex;
30
+ await next();
31
+ if (c.res.status !== 404) {
32
+ return;
33
+ }
34
+ if (c.error) {
35
+ return;
36
+ }
37
+ if (!methodRouter) {
38
+ const methodsByPath = /* @__PURE__ */ new Map();
39
+ for (const route of options.app.routes) {
40
+ if (route.method === import_router.METHOD_NAME_ALL || route.method === "HEAD") {
41
+ continue;
42
+ }
43
+ const methods2 = methodsByPath.get(route.path) ?? /* @__PURE__ */ new Set();
44
+ methods2.add(route.method);
45
+ if (route.method === "GET") {
46
+ methods2.add("HEAD");
47
+ }
48
+ methodsByPath.set(route.path, methods2);
49
+ }
50
+ methodRouter = new import_trie_router.TrieRouter();
51
+ for (const [path, methods2] of methodsByPath) {
52
+ methodRouter.add(import_router.METHOD_NAME_ALL, path, [...methods2]);
53
+ }
54
+ }
55
+ let requestPath = c.req.path;
56
+ const routes = (0, import_route.matchedRoutes)(c);
57
+ const currentRoute = routes[routeIndex];
58
+ const sourceRoute = options.app.routes.find((route) => route.handler === methodNotAllowed2);
59
+ if (currentRoute && sourceRoute) {
60
+ const currentBasePathParts = (0, import_route.basePath)(c, routeIndex).split("/").filter(Boolean);
61
+ const sourceBasePathLength = sourceRoute.basePath.split("/").filter(Boolean).length;
62
+ const mountBasePathParts = currentBasePathParts.slice(
63
+ 0,
64
+ currentBasePathParts.length - sourceBasePathLength
65
+ );
66
+ if (mountBasePathParts.length > 0) {
67
+ const mountBasePath = `/${mountBasePathParts.join("/")}`;
68
+ requestPath = c.req.path.slice(mountBasePath.length) || "/";
69
+ }
70
+ }
71
+ const allowedMethods = /* @__PURE__ */ new Set();
72
+ for (const [methods2] of methodRouter.match(import_router.METHOD_NAME_ALL, requestPath)[0]) {
73
+ for (const method of methods2) {
74
+ allowedMethods.add(method);
75
+ }
76
+ }
77
+ if (allowedMethods.size === 0 || allowedMethods.has(c.req.method)) {
78
+ return;
79
+ }
80
+ c.res.headers.delete("Allow");
81
+ c.res.headers.delete("Content-Length");
82
+ const methods = [...allowedMethods];
83
+ const allow = methods.join(", ");
84
+ c.res = options.onMethodNotAllowed ? await options.onMethodNotAllowed(c, methods) : c.text("Method Not Allowed", 405, { Allow: allow });
85
+ };
86
+ };
87
+ // Annotate the CommonJS export names for ESM import in node:
88
+ 0 && (module.exports = {
89
+ methodNotAllowed
90
+ });
@@ -25,7 +25,6 @@ var import_http_exception = require("./http-exception");
25
25
  var import_constants = require("./request/constants");
26
26
  var import_body = require("./utils/body");
27
27
  var import_url = require("./utils/url");
28
- const tryDecodeURIComponent = (str) => (0, import_url.tryDecode)(str, import_url.decodeURIComponent_);
29
28
  class HonoRequest {
30
29
  /**
31
30
  * `.raw` can get the raw Request object.
@@ -64,7 +63,6 @@ class HonoRequest {
64
63
  this.raw = request;
65
64
  this.path = path;
66
65
  this.#matchResult = matchResult;
67
- this.#validatedData = {};
68
66
  }
69
67
  param(key) {
70
68
  return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
@@ -72,7 +70,7 @@ class HonoRequest {
72
70
  #getDecodedParam(key) {
73
71
  const paramKey = this.#matchResult[0][this.routeIndex][1][key];
74
72
  const param = this.#getParamValue(paramKey);
75
- return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param;
73
+ return param && (0, import_url.tryDecodeURIComponent)(param);
76
74
  }
77
75
  #getAllDecodedParams() {
78
76
  const decoded = {};
@@ -80,7 +78,7 @@ class HonoRequest {
80
78
  for (const key of keys) {
81
79
  const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
82
80
  if (value !== void 0) {
83
- decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value;
81
+ decoded[key] = (0, import_url.tryDecodeURIComponent)(value);
84
82
  }
85
83
  }
86
84
  return decoded;
@@ -113,8 +111,7 @@ class HonoRequest {
113
111
  if (cachedBody) {
114
112
  return cachedBody;
115
113
  }
116
- const anyCachedKey = Object.keys(bodyCache)[0];
117
- if (anyCachedKey) {
114
+ for (const anyCachedKey in bodyCache) {
118
115
  return bodyCache[anyCachedKey].then((body) => {
119
116
  if (anyCachedKey === "json") {
120
117
  body = JSON.stringify(body);
@@ -217,10 +214,11 @@ class HonoRequest {
217
214
  * @param data - The validated data to add.
218
215
  */
219
216
  addValidatedData(target, data) {
220
- this.#validatedData[target] = data;
217
+ ;
218
+ (this.#validatedData ??= {})[target] = data;
221
219
  }
222
220
  valid(target) {
223
- return this.#validatedData[target];
221
+ return this.#validatedData?.[target];
224
222
  }
225
223
  /**
226
224
  * `.url()` can get the request url strings.
@@ -34,7 +34,7 @@ function compareKey(a, b) {
34
34
  return 1;
35
35
  }
36
36
  if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
37
- return 1;
37
+ return b === TAIL_WILDCARD_REG_EXP_STR ? -1 : 1;
38
38
  } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
39
39
  return -1;
40
40
  }
@@ -46,76 +46,75 @@ function compareKey(a, b) {
46
46
  return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
47
47
  }
48
48
  class Node {
49
+ // handler index of a dynamic path, or -1 for a static path terminal
49
50
  #index;
50
51
  #varIndex;
51
52
  #children = /* @__PURE__ */ Object.create(null);
52
- insert(tokens, index, paramMap, context, pathErrorCheckOnly) {
53
- if (tokens.length === 0) {
54
- if (this.#index !== void 0) {
55
- throw PATH_ERROR;
56
- }
57
- if (pathErrorCheckOnly) {
58
- return;
59
- }
60
- this.#index = index;
61
- return;
62
- }
63
- const [token, ...restTokens] = tokens;
64
- const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
65
- let node;
66
- if (pattern) {
67
- const name = pattern[1];
68
- let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
69
- if (name && pattern[2]) {
70
- if (regexpStr === ".*") {
71
- throw PATH_ERROR;
72
- }
73
- regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
74
- if (/\((?!\?:)/.test(regexpStr)) {
75
- throw PATH_ERROR;
53
+ insert(tokens, index, paramMap, context, isStatic) {
54
+ let node = this;
55
+ for (let i = 0, len = tokens.length; i < len; i++) {
56
+ const token = tokens[i];
57
+ const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : null : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
58
+ let nextNode;
59
+ if (pattern) {
60
+ const name = pattern[1];
61
+ let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
62
+ if (name && pattern[2]) {
63
+ if (regexpStr === ".*") {
64
+ throw PATH_ERROR;
65
+ }
66
+ regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
67
+ if (/\((?!\?:)/.test(regexpStr)) {
68
+ throw PATH_ERROR;
69
+ }
70
+ if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) {
71
+ throw PATH_ERROR;
72
+ }
76
73
  }
77
- }
78
- node = this.#children[regexpStr];
79
- if (!node) {
80
- if (Object.keys(this.#children).some(
81
- (k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
82
- )) {
83
- throw PATH_ERROR;
74
+ nextNode = node.#children[regexpStr];
75
+ if (!nextNode) {
76
+ if (regexpStr !== ONLY_WILDCARD_REG_EXP_STR && regexpStr !== TAIL_WILDCARD_REG_EXP_STR) {
77
+ for (const k in node.#children) {
78
+ if (
79
+ // a single-char pattern coexists with single-char literals as a literal does
80
+ (regexpStr.length > 1 || k.length > 1) && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
81
+ ) {
82
+ throw PATH_ERROR;
83
+ }
84
+ }
85
+ }
86
+ nextNode = node.#children[regexpStr] = new Node();
84
87
  }
85
- if (pathErrorCheckOnly) {
86
- return;
87
- }
88
- node = this.#children[regexpStr] = new Node();
89
88
  if (name !== "") {
90
- node.#varIndex = context.varIndex++;
89
+ nextNode.#varIndex ??= context.varIndex++;
90
+ paramMap.push([name, nextNode.#varIndex]);
91
91
  }
92
- }
93
- if (!pathErrorCheckOnly && name !== "") {
94
- paramMap.push([name, node.#varIndex]);
95
- }
96
- } else {
97
- node = this.#children[token];
98
- if (!node) {
99
- if (Object.keys(this.#children).some(
100
- (k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
101
- )) {
102
- throw PATH_ERROR;
92
+ } else {
93
+ nextNode = node.#children[token];
94
+ if (!nextNode) {
95
+ for (const k in node.#children) {
96
+ if (k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR) {
97
+ throw PATH_ERROR;
98
+ }
99
+ }
100
+ nextNode = node.#children[token] = new Node();
103
101
  }
104
- if (pathErrorCheckOnly) {
105
- return;
106
- }
107
- node = this.#children[token] = new Node();
108
102
  }
103
+ node = nextNode;
104
+ }
105
+ if (node.#index !== void 0) {
106
+ throw PATH_ERROR;
109
107
  }
110
- node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly);
108
+ node.#index = isStatic ? -1 : index;
111
109
  }
112
110
  buildRegExpStr() {
113
111
  const childKeys = Object.keys(this.#children).sort(compareKey);
114
112
  const strList = childKeys.map((k) => {
115
113
  const c = this.#children[k];
116
- return (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr();
117
- });
118
- if (typeof this.#index === "number") {
114
+ const childStr = c.buildRegExpStr();
115
+ return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr;
116
+ }).filter(Boolean);
117
+ if (typeof this.#index === "number" && this.#index !== -1) {
119
118
  strList.unshift(`#${this.#index}`);
120
119
  }
121
120
  if (strList.length === 0) {