hono 4.6.19 → 4.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 (66) hide show
  1. package/dist/adapter/lambda-edge/handler.js +6 -2
  2. package/dist/cjs/adapter/lambda-edge/handler.js +6 -2
  3. package/dist/cjs/helper/accepts/accepts.js +4 -26
  4. package/dist/cjs/helper/factory/index.js +6 -2
  5. package/dist/cjs/helper/proxy/index.js +75 -0
  6. package/dist/cjs/helper/streaming/sse.js +8 -5
  7. package/dist/cjs/helper/streaming/stream.js +8 -5
  8. package/dist/cjs/helper/streaming/utils.js +36 -0
  9. package/dist/cjs/middleware/etag/digest.js +2 -7
  10. package/dist/cjs/middleware/etag/index.js +7 -2
  11. package/dist/cjs/middleware/jwk/index.js +28 -0
  12. package/dist/cjs/middleware/jwk/jwk.js +124 -0
  13. package/dist/cjs/middleware/language/index.js +36 -0
  14. package/dist/cjs/middleware/language/language.js +210 -0
  15. package/dist/cjs/middleware/logger/index.js +2 -3
  16. package/dist/cjs/request.js +1 -1
  17. package/dist/cjs/router/linear-router/router.js +3 -1
  18. package/dist/cjs/router/trie-router/node.js +24 -11
  19. package/dist/cjs/utils/accept.js +86 -0
  20. package/dist/cjs/utils/jwt/index.js +1 -1
  21. package/dist/cjs/utils/jwt/jwt.js +56 -3
  22. package/dist/cjs/utils/jwt/types.js +8 -0
  23. package/dist/cjs/utils/url.js +6 -5
  24. package/dist/helper/accepts/accepts.js +2 -23
  25. package/dist/helper/factory/index.js +6 -2
  26. package/dist/helper/proxy/index.js +52 -0
  27. package/dist/helper/streaming/sse.js +8 -5
  28. package/dist/helper/streaming/stream.js +8 -5
  29. package/dist/helper/streaming/utils.js +13 -0
  30. package/dist/middleware/etag/digest.js +2 -7
  31. package/dist/middleware/etag/index.js +7 -2
  32. package/dist/middleware/jwk/index.js +5 -0
  33. package/dist/middleware/jwk/jwk.js +101 -0
  34. package/dist/middleware/language/index.js +15 -0
  35. package/dist/middleware/language/language.js +178 -0
  36. package/dist/middleware/logger/index.js +2 -3
  37. package/dist/request.js +1 -1
  38. package/dist/router/linear-router/router.js +3 -1
  39. package/dist/router/trie-router/node.js +24 -11
  40. package/dist/types/client/types.d.ts +1 -2
  41. package/dist/types/context.d.ts +2 -2
  42. package/dist/types/helper/accepts/accepts.d.ts +0 -1
  43. package/dist/types/helper/adapter/index.d.ts +1 -1
  44. package/dist/types/helper/factory/index.d.ts +4 -1
  45. package/dist/types/helper/proxy/index.d.ts +54 -0
  46. package/dist/types/helper/streaming/utils.d.ts +1 -0
  47. package/dist/types/middleware/etag/digest.d.ts +1 -1
  48. package/dist/types/middleware/etag/index.d.ts +4 -0
  49. package/dist/types/middleware/jwk/index.d.ts +1 -0
  50. package/dist/types/middleware/jwk/jwk.d.ts +40 -0
  51. package/dist/types/middleware/language/index.d.ts +7 -0
  52. package/dist/types/middleware/language/language.d.ts +102 -0
  53. package/dist/types/utils/accept.d.ts +11 -0
  54. package/dist/types/utils/jwt/index.d.ts +4 -0
  55. package/dist/types/utils/jwt/jws.d.ts +4 -1
  56. package/dist/types/utils/jwt/jwt.d.ts +7 -1
  57. package/dist/types/utils/jwt/types.d.ts +4 -0
  58. package/dist/types/utils/url.d.ts +1 -1
  59. package/dist/utils/accept.js +63 -0
  60. package/dist/utils/jwt/index.js +2 -2
  61. package/dist/utils/jwt/jwt.js +54 -2
  62. package/dist/utils/jwt/types.js +7 -0
  63. package/dist/utils/url.js +6 -5
  64. package/package.json +26 -5
  65. package/perf-measures/bundle-check/generated/.gitkeep +0 -0
  66. package/perf-measures/type-check/generated/.gitkeep +0 -0
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var language_exports = {};
20
+ __export(language_exports, {
21
+ DEFAULT_OPTIONS: () => DEFAULT_OPTIONS,
22
+ detectFromCookie: () => detectFromCookie,
23
+ detectFromHeader: () => detectFromHeader,
24
+ detectFromPath: () => detectFromPath,
25
+ detectFromQuery: () => detectFromQuery,
26
+ detectors: () => detectors,
27
+ languageDetector: () => languageDetector,
28
+ normalizeLanguage: () => normalizeLanguage,
29
+ parseAcceptLanguage: () => parseAcceptLanguage,
30
+ validateOptions: () => validateOptions
31
+ });
32
+ module.exports = __toCommonJS(language_exports);
33
+ var import_cookie = require("../../helper/cookie");
34
+ var import_accept = require("../../utils/accept");
35
+ const DEFAULT_OPTIONS = {
36
+ order: ["querystring", "cookie", "header"],
37
+ lookupQueryString: "lang",
38
+ lookupCookie: "language",
39
+ lookupFromHeaderKey: "accept-language",
40
+ lookupFromPathIndex: 0,
41
+ caches: ["cookie"],
42
+ ignoreCase: true,
43
+ fallbackLanguage: "en",
44
+ supportedLanguages: ["en"],
45
+ cookieOptions: {
46
+ sameSite: "Strict",
47
+ secure: true,
48
+ maxAge: 365 * 24 * 60 * 60,
49
+ httpOnly: true
50
+ },
51
+ debug: false
52
+ };
53
+ function parseAcceptLanguage(header) {
54
+ return (0, import_accept.parseAccept)(header).map(({ type, q }) => ({ lang: type, q }));
55
+ }
56
+ const normalizeLanguage = (lang, options) => {
57
+ if (!lang) {
58
+ return void 0;
59
+ }
60
+ try {
61
+ let normalizedLang = lang.trim();
62
+ if (options.convertDetectedLanguage) {
63
+ normalizedLang = options.convertDetectedLanguage(normalizedLang);
64
+ }
65
+ const compLang = options.ignoreCase ? normalizedLang.toLowerCase() : normalizedLang;
66
+ const compSupported = options.supportedLanguages.map(
67
+ (l) => options.ignoreCase ? l.toLowerCase() : l
68
+ );
69
+ const matchedLang = compSupported.find((l) => l === compLang);
70
+ return matchedLang ? options.supportedLanguages[compSupported.indexOf(matchedLang)] : void 0;
71
+ } catch {
72
+ return void 0;
73
+ }
74
+ };
75
+ const detectFromQuery = (c, options) => {
76
+ try {
77
+ const query = c.req.query(options.lookupQueryString);
78
+ return normalizeLanguage(query, options);
79
+ } catch {
80
+ return void 0;
81
+ }
82
+ };
83
+ const detectFromCookie = (c, options) => {
84
+ try {
85
+ const cookie = (0, import_cookie.getCookie)(c, options.lookupCookie);
86
+ return normalizeLanguage(cookie, options);
87
+ } catch {
88
+ return void 0;
89
+ }
90
+ };
91
+ function detectFromHeader(c, options) {
92
+ try {
93
+ const acceptLanguage = c.req.header(options.lookupFromHeaderKey);
94
+ if (!acceptLanguage) {
95
+ return void 0;
96
+ }
97
+ const languages = parseAcceptLanguage(acceptLanguage);
98
+ for (const { lang } of languages) {
99
+ const normalizedLang = normalizeLanguage(lang, options);
100
+ if (normalizedLang) {
101
+ return normalizedLang;
102
+ }
103
+ }
104
+ return void 0;
105
+ } catch {
106
+ return void 0;
107
+ }
108
+ }
109
+ function detectFromPath(c, options) {
110
+ try {
111
+ const pathSegments = c.req.path.split("/").filter(Boolean);
112
+ const langSegment = pathSegments[options.lookupFromPathIndex];
113
+ return normalizeLanguage(langSegment, options);
114
+ } catch {
115
+ return void 0;
116
+ }
117
+ }
118
+ const detectors = {
119
+ querystring: detectFromQuery,
120
+ cookie: detectFromCookie,
121
+ header: detectFromHeader,
122
+ path: detectFromPath
123
+ };
124
+ function validateOptions(options) {
125
+ if (!options.supportedLanguages.includes(options.fallbackLanguage)) {
126
+ throw new Error("Fallback language must be included in supported languages");
127
+ }
128
+ if (options.lookupFromPathIndex < 0) {
129
+ throw new Error("Path index must be non-negative");
130
+ }
131
+ if (!options.order.every((detector) => Object.keys(detectors).includes(detector))) {
132
+ throw new Error("Invalid detector type in order array");
133
+ }
134
+ }
135
+ function cacheLanguage(c, language, options) {
136
+ if (!Array.isArray(options.caches) || !options.caches.includes("cookie")) {
137
+ return;
138
+ }
139
+ try {
140
+ (0, import_cookie.setCookie)(c, options.lookupCookie, language, options.cookieOptions);
141
+ } catch (error) {
142
+ if (options.debug) {
143
+ console.error("Failed to cache language:", error);
144
+ }
145
+ }
146
+ }
147
+ const detectLanguage = (c, options) => {
148
+ let detectedLang;
149
+ for (const detectorName of options.order) {
150
+ const detector = detectors[detectorName];
151
+ if (!detector) {
152
+ continue;
153
+ }
154
+ try {
155
+ detectedLang = detector(c, options);
156
+ if (detectedLang) {
157
+ if (options.debug) {
158
+ console.log(`Language detected from ${detectorName}: ${detectedLang}`);
159
+ }
160
+ break;
161
+ }
162
+ } catch (error) {
163
+ if (options.debug) {
164
+ console.error(`Error in ${detectorName} detector:`, error);
165
+ }
166
+ continue;
167
+ }
168
+ }
169
+ const finalLang = detectedLang || options.fallbackLanguage;
170
+ if (detectedLang && options.caches) {
171
+ cacheLanguage(c, finalLang, options);
172
+ }
173
+ return finalLang;
174
+ };
175
+ const languageDetector = (userOptions) => {
176
+ const options = {
177
+ ...DEFAULT_OPTIONS,
178
+ ...userOptions,
179
+ cookieOptions: {
180
+ ...DEFAULT_OPTIONS.cookieOptions,
181
+ ...userOptions.cookieOptions
182
+ }
183
+ };
184
+ validateOptions(options);
185
+ return async function languageDetector2(ctx, next) {
186
+ try {
187
+ const lang = detectLanguage(ctx, options);
188
+ ctx.set("language", lang);
189
+ } catch (error) {
190
+ if (options.debug) {
191
+ console.error("Language detection failed:", error);
192
+ }
193
+ ctx.set("language", options.fallbackLanguage);
194
+ }
195
+ await next();
196
+ };
197
+ };
198
+ // Annotate the CommonJS export names for ESM import in node:
199
+ 0 && (module.exports = {
200
+ DEFAULT_OPTIONS,
201
+ detectFromCookie,
202
+ detectFromHeader,
203
+ detectFromPath,
204
+ detectFromQuery,
205
+ detectors,
206
+ languageDetector,
207
+ normalizeLanguage,
208
+ parseAcceptLanguage,
209
+ validateOptions
210
+ });
@@ -22,7 +22,6 @@ __export(logger_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(logger_exports);
24
24
  var import_color = require("../../utils/color");
25
- var import_url = require("../../utils/url");
26
25
  var LogPrefix = /* @__PURE__ */ ((LogPrefix2) => {
27
26
  LogPrefix2["Outgoing"] = "-->";
28
27
  LogPrefix2["Incoming"] = "<--";
@@ -60,8 +59,8 @@ function log(fn, prefix, method, path, status = 0, elapsed) {
60
59
  }
61
60
  const logger = (fn = console.log) => {
62
61
  return async function logger2(c, next) {
63
- const { method } = c.req;
64
- const path = (0, import_url.getPath)(c.req.raw);
62
+ const { method, url } = c.req;
63
+ const path = url.slice(url.indexOf("/", 8));
65
64
  log(fn, "<--" /* Incoming */, method, path);
66
65
  const start = Date.now();
67
66
  await next();
@@ -67,7 +67,7 @@ class HonoRequest {
67
67
  }
68
68
  header(name) {
69
69
  if (name) {
70
- return this.raw.headers.get(name.toLowerCase()) ?? void 0;
70
+ return this.raw.headers.get(name) ?? void 0;
71
71
  }
72
72
  const headerData = {};
73
73
  this.raw.headers.forEach((value, key) => {
@@ -88,7 +88,9 @@ class LinearRouter {
88
88
  let value;
89
89
  if (name.charCodeAt(name.length - 1) === 125) {
90
90
  const openBracePos = name.indexOf("{");
91
- const pattern = name.slice(openBracePos + 1, -1);
91
+ const next = parts[j + 1];
92
+ const lookahead = next && next[1] !== ":" && next[1] !== "*" ? `(?=${next})` : "";
93
+ const pattern = name.slice(openBracePos + 1, -1) + lookahead;
92
94
  const restPath = path.slice(pos + 1);
93
95
  const match = new RegExp(pattern, "d").exec(restPath);
94
96
  if (!match || match.indices[0][0] !== 0 || match.indices[0][1] === 0) {
@@ -47,21 +47,23 @@ class Node {
47
47
  const possibleKeys = [];
48
48
  for (let i = 0, len = parts.length; i < len; i++) {
49
49
  const p = parts[i];
50
- if (Object.keys(curNode.#children).includes(p)) {
51
- curNode = curNode.#children[p];
52
- const pattern2 = (0, import_url.getPattern)(p);
50
+ const nextP = parts[i + 1];
51
+ const pattern = (0, import_url.getPattern)(p, nextP);
52
+ const key = Array.isArray(pattern) ? pattern[0] : p;
53
+ if (Object.keys(curNode.#children).includes(key)) {
54
+ curNode = curNode.#children[key];
55
+ const pattern2 = (0, import_url.getPattern)(p, nextP);
53
56
  if (pattern2) {
54
57
  possibleKeys.push(pattern2[1]);
55
58
  }
56
59
  continue;
57
60
  }
58
- curNode.#children[p] = new Node();
59
- const pattern = (0, import_url.getPattern)(p);
61
+ curNode.#children[key] = new Node();
60
62
  if (pattern) {
61
63
  curNode.#patterns.push(pattern);
62
64
  possibleKeys.push(pattern[1]);
63
65
  }
64
- curNode = curNode.#children[p];
66
+ curNode = curNode.#children[key];
65
67
  }
66
68
  const m = /* @__PURE__ */ Object.create(null);
67
69
  const handlerSet = {
@@ -100,6 +102,7 @@ class Node {
100
102
  const curNode = this;
101
103
  let curNodes = [curNode];
102
104
  const parts = (0, import_url.splitPath)(path);
105
+ const curNodesQueue = [];
103
106
  for (let i = 0, len = parts.length; i < len; i++) {
104
107
  const part = parts[i];
105
108
  const isLast = i === len - 1;
@@ -127,6 +130,7 @@ class Node {
127
130
  const astNode = node.#children["*"];
128
131
  if (astNode) {
129
132
  handlerSets.push(...this.#getHandlerSets(astNode, method, node.#params));
133
+ astNode.#params = params;
130
134
  tempNodes.push(astNode);
131
135
  }
132
136
  continue;
@@ -137,10 +141,19 @@ class Node {
137
141
  const [key, name, matcher] = pattern;
138
142
  const child = node.#children[key];
139
143
  const restPathString = parts.slice(i).join("/");
140
- if (matcher instanceof RegExp && matcher.test(restPathString)) {
141
- params[name] = restPathString;
142
- handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params));
143
- continue;
144
+ if (matcher instanceof RegExp) {
145
+ const m = matcher.exec(restPathString);
146
+ if (m) {
147
+ params[name] = m[0];
148
+ handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params));
149
+ if (Object.keys(child.#children).length) {
150
+ child.#params = params;
151
+ const componentCount = m[0].match(/\//)?.length ?? 0;
152
+ const targetCurNodes = curNodesQueue[componentCount] ||= [];
153
+ targetCurNodes.push(child);
154
+ }
155
+ continue;
156
+ }
144
157
  }
145
158
  if (matcher === true || matcher.test(part)) {
146
159
  params[name] = part;
@@ -158,7 +171,7 @@ class Node {
158
171
  }
159
172
  }
160
173
  }
161
- curNodes = tempNodes;
174
+ curNodes = tempNodes.concat(curNodesQueue.shift() ?? []);
162
175
  }
163
176
  if (handlerSets.length > 1) {
164
177
  handlerSets.sort((a, b) => {
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var accept_exports = {};
20
+ __export(accept_exports, {
21
+ parseAccept: () => parseAccept
22
+ });
23
+ module.exports = __toCommonJS(accept_exports);
24
+ const parseAccept = (acceptHeader) => {
25
+ if (!acceptHeader) {
26
+ return [];
27
+ }
28
+ const acceptValues = acceptHeader.split(",").map((value, index) => ({ value, index }));
29
+ return acceptValues.map(parseAcceptValue).filter((item) => Boolean(item)).sort(sortByQualityAndIndex).map(({ type, params, q }) => ({ type, params, q }));
30
+ };
31
+ const parseAcceptValueRegex = /;(?=(?:(?:[^"]*"){2})*[^"]*$)/;
32
+ const parseAcceptValue = ({ value, index }) => {
33
+ const parts = value.trim().split(parseAcceptValueRegex).map((s) => s.trim());
34
+ const type = parts[0];
35
+ if (!type) {
36
+ return null;
37
+ }
38
+ const params = parseParams(parts.slice(1));
39
+ const q = parseQuality(params.q);
40
+ return { type, params, q, index };
41
+ };
42
+ const parseParams = (paramParts) => {
43
+ return paramParts.reduce((acc, param) => {
44
+ const [key, val] = param.split("=").map((s) => s.trim());
45
+ if (key && val) {
46
+ acc[key] = val;
47
+ }
48
+ return acc;
49
+ }, {});
50
+ };
51
+ const parseQuality = (qVal) => {
52
+ if (qVal === void 0) {
53
+ return 1;
54
+ }
55
+ if (qVal === "") {
56
+ return 1;
57
+ }
58
+ if (qVal === "NaN") {
59
+ return 0;
60
+ }
61
+ const num = Number(qVal);
62
+ if (num === Infinity) {
63
+ return 1;
64
+ }
65
+ if (num === -Infinity) {
66
+ return 0;
67
+ }
68
+ if (Number.isNaN(num)) {
69
+ return 1;
70
+ }
71
+ if (num < 0 || num > 1) {
72
+ return 1;
73
+ }
74
+ return num;
75
+ };
76
+ const sortByQualityAndIndex = (a, b) => {
77
+ const qDiff = b.q - a.q;
78
+ if (qDiff !== 0) {
79
+ return qDiff;
80
+ }
81
+ return a.index - b.index;
82
+ };
83
+ // Annotate the CommonJS export names for ESM import in node:
84
+ 0 && (module.exports = {
85
+ parseAccept
86
+ });
@@ -22,7 +22,7 @@ __export(jwt_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(jwt_exports);
24
24
  var import_jwt = require("./jwt");
25
- const Jwt = { sign: import_jwt.sign, verify: import_jwt.verify, decode: import_jwt.decode };
25
+ const Jwt = { sign: import_jwt.sign, verify: import_jwt.verify, decode: import_jwt.decode, verifyFromJwks: import_jwt.verifyFromJwks };
26
26
  // Annotate the CommonJS export names for ESM import in node:
27
27
  0 && (module.exports = {
28
28
  Jwt
@@ -19,9 +19,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var jwt_exports = {};
20
20
  __export(jwt_exports, {
21
21
  decode: () => decode,
22
+ decodeHeader: () => decodeHeader,
22
23
  isTokenHeader: () => isTokenHeader,
23
24
  sign: () => sign,
24
- verify: () => verify
25
+ verify: () => verify,
26
+ verifyFromJwks: () => verifyFromJwks
25
27
  });
26
28
  module.exports = __toCommonJS(jwt_exports);
27
29
  var import_encode = require("../../utils/encode");
@@ -41,7 +43,13 @@ function isTokenHeader(obj) {
41
43
  }
42
44
  const sign = async (payload, privateKey, alg = "HS256") => {
43
45
  const encodedPayload = encodeJwtPart(payload);
44
- const encodedHeader = encodeJwtPart({ alg, typ: "JWT" });
46
+ let encodedHeader;
47
+ if (typeof privateKey === "object" && "alg" in privateKey) {
48
+ alg = privateKey.alg;
49
+ encodedHeader = encodeJwtPart({ alg, typ: "JWT", kid: privateKey.kid });
50
+ } else {
51
+ encodedHeader = encodeJwtPart({ alg, typ: "JWT" });
52
+ }
45
53
  const partialToken = `${encodedHeader}.${encodedPayload}`;
46
54
  const signaturePart = await (0, import_jws.signing)(privateKey, alg, import_utf8.utf8Encoder.encode(partialToken));
47
55
  const signature = encodeSignaturePart(signaturePart);
@@ -78,6 +86,41 @@ const verify = async (token, publicKey, alg = "HS256") => {
78
86
  }
79
87
  return payload;
80
88
  };
89
+ const verifyFromJwks = async (token, options, init) => {
90
+ const header = decodeHeader(token);
91
+ if (!isTokenHeader(header)) {
92
+ throw new import_types.JwtHeaderInvalid(header);
93
+ }
94
+ if (!header.kid) {
95
+ throw new import_types.JwtHeaderRequiresKid(header);
96
+ }
97
+ let keys = typeof options.keys === "function" ? await options.keys() : options.keys;
98
+ if (options.jwks_uri) {
99
+ const response = await fetch(options.jwks_uri, init);
100
+ if (!response.ok) {
101
+ throw new Error(`failed to fetch JWKS from ${options.jwks_uri}`);
102
+ }
103
+ const data = await response.json();
104
+ if (!data.keys) {
105
+ throw new Error('invalid JWKS response. "keys" field is missing');
106
+ }
107
+ if (!Array.isArray(data.keys)) {
108
+ throw new Error('invalid JWKS response. "keys" field is not an array');
109
+ }
110
+ if (keys) {
111
+ keys.push(...data.keys);
112
+ } else {
113
+ keys = data.keys;
114
+ }
115
+ } else if (!keys) {
116
+ throw new Error('verifyFromJwks requires options for either "keys" or "jwks_uri" or both');
117
+ }
118
+ const matchingKey = keys.find((key) => key.kid === header.kid);
119
+ if (!matchingKey) {
120
+ throw new import_types.JwtTokenInvalid(token);
121
+ }
122
+ return await verify(token, matchingKey, matchingKey.alg);
123
+ };
81
124
  const decode = (token) => {
82
125
  try {
83
126
  const [h, p] = token.split(".");
@@ -91,10 +134,20 @@ const decode = (token) => {
91
134
  throw new import_types.JwtTokenInvalid(token);
92
135
  }
93
136
  };
137
+ const decodeHeader = (token) => {
138
+ try {
139
+ const [h] = token.split(".");
140
+ return decodeJwtPart(h);
141
+ } catch {
142
+ throw new import_types.JwtTokenInvalid(token);
143
+ }
144
+ };
94
145
  // Annotate the CommonJS export names for ESM import in node:
95
146
  0 && (module.exports = {
96
147
  decode,
148
+ decodeHeader,
97
149
  isTokenHeader,
98
150
  sign,
99
- verify
151
+ verify,
152
+ verifyFromJwks
100
153
  });
@@ -21,6 +21,7 @@ __export(types_exports, {
21
21
  CryptoKeyUsage: () => CryptoKeyUsage,
22
22
  JwtAlgorithmNotImplemented: () => JwtAlgorithmNotImplemented,
23
23
  JwtHeaderInvalid: () => JwtHeaderInvalid,
24
+ JwtHeaderRequiresKid: () => JwtHeaderRequiresKid,
24
25
  JwtTokenExpired: () => JwtTokenExpired,
25
26
  JwtTokenInvalid: () => JwtTokenInvalid,
26
27
  JwtTokenIssuedAt: () => JwtTokenIssuedAt,
@@ -64,6 +65,12 @@ class JwtHeaderInvalid extends Error {
64
65
  this.name = "JwtHeaderInvalid";
65
66
  }
66
67
  }
68
+ class JwtHeaderRequiresKid extends Error {
69
+ constructor(header) {
70
+ super(`required "kid" in jwt header: ${JSON.stringify(header)}`);
71
+ this.name = "JwtHeaderRequiresKid";
72
+ }
73
+ }
67
74
  class JwtTokenSignatureMismatched extends Error {
68
75
  constructor(token) {
69
76
  super(`token(${token}) signature mismatched`);
@@ -86,6 +93,7 @@ var CryptoKeyUsage = /* @__PURE__ */ ((CryptoKeyUsage2) => {
86
93
  CryptoKeyUsage,
87
94
  JwtAlgorithmNotImplemented,
88
95
  JwtHeaderInvalid,
96
+ JwtHeaderRequiresKid,
89
97
  JwtTokenExpired,
90
98
  JwtTokenInvalid,
91
99
  JwtTokenIssuedAt,
@@ -66,20 +66,21 @@ const replaceGroupMarks = (paths, groups) => {
66
66
  return paths;
67
67
  };
68
68
  const patternCache = {};
69
- const getPattern = (label) => {
69
+ const getPattern = (label, next) => {
70
70
  if (label === "*") {
71
71
  return "*";
72
72
  }
73
73
  const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
74
74
  if (match) {
75
- if (!patternCache[label]) {
75
+ const cacheKey = `${label}#${next}`;
76
+ if (!patternCache[cacheKey]) {
76
77
  if (match[2]) {
77
- patternCache[label] = [label, match[1], new RegExp("^" + match[2] + "$")];
78
+ patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey, match[1], new RegExp(`^${match[2]}(?=/${next})`)] : [label, match[1], new RegExp(`^${match[2]}$`)];
78
79
  } else {
79
- patternCache[label] = [label, match[1], true];
80
+ patternCache[cacheKey] = [label, match[1], true];
80
81
  }
81
82
  }
82
- return patternCache[label];
83
+ return patternCache[cacheKey];
83
84
  }
84
85
  return null;
85
86
  };
@@ -1,25 +1,5 @@
1
1
  // src/helper/accepts/accepts.ts
2
- var parseAccept = (acceptHeader) => {
3
- const accepts2 = acceptHeader.split(",");
4
- return accepts2.map((accept) => {
5
- const parts = accept.trim().split(";");
6
- const type = parts[0];
7
- const params = parts.slice(1);
8
- const q = params.find((param) => param.startsWith("q="));
9
- const paramsObject = params.reduce((acc, param) => {
10
- const keyValue = param.split("=");
11
- const key = keyValue[0].trim();
12
- const value = keyValue[1].trim();
13
- acc[key] = value;
14
- return acc;
15
- }, {});
16
- return {
17
- type,
18
- params: paramsObject,
19
- q: q ? parseFloat(q.split("=")[1]) : 1
20
- };
21
- });
22
- };
2
+ import { parseAccept } from "../../utils/accept.js";
23
3
  var defaultMatch = (accepts2, config) => {
24
4
  const { supports, default: defaultSupport } = config;
25
5
  const accept = accepts2.sort((a, b) => b.q - a.q).find((accept2) => supports.includes(accept2.type));
@@ -36,6 +16,5 @@ var accepts = (c, options) => {
36
16
  };
37
17
  export {
38
18
  accepts,
39
- defaultMatch,
40
- parseAccept
19
+ defaultMatch
41
20
  };
@@ -2,11 +2,15 @@
2
2
  import { Hono } from "../../hono.js";
3
3
  var Factory = class {
4
4
  initApp;
5
+ #defaultAppOptions;
5
6
  constructor(init) {
6
7
  this.initApp = init?.initApp;
8
+ this.#defaultAppOptions = init?.defaultAppOptions;
7
9
  }
8
- createApp = () => {
9
- const app = new Hono();
10
+ createApp = (options) => {
11
+ const app = new Hono(
12
+ options && this.#defaultAppOptions ? { ...this.#defaultAppOptions, ...options } : options ?? this.#defaultAppOptions
13
+ );
10
14
  if (this.initApp) {
11
15
  this.initApp(app);
12
16
  }
@@ -0,0 +1,52 @@
1
+ // src/helper/proxy/index.ts
2
+ var hopByHopHeaders = [
3
+ "connection",
4
+ "keep-alive",
5
+ "proxy-authenticate",
6
+ "proxy-authorization",
7
+ "te",
8
+ "trailers",
9
+ "transfer-encoding"
10
+ ];
11
+ var buildRequestInitFromRequest = (request) => {
12
+ if (!request) {
13
+ return {};
14
+ }
15
+ const headers = new Headers(request.headers);
16
+ hopByHopHeaders.forEach((header) => {
17
+ headers.delete(header);
18
+ });
19
+ return {
20
+ method: request.method,
21
+ body: request.body,
22
+ duplex: request.body ? "half" : void 0,
23
+ headers
24
+ };
25
+ };
26
+ var proxy = async (input, proxyInit) => {
27
+ const { raw, ...requestInit } = proxyInit ?? {};
28
+ const req = new Request(
29
+ input,
30
+ {
31
+ ...buildRequestInitFromRequest(raw),
32
+ ...requestInit
33
+ }
34
+ );
35
+ req.headers.delete("accept-encoding");
36
+ const res = await fetch(req);
37
+ const resHeaders = new Headers(res.headers);
38
+ hopByHopHeaders.forEach((header) => {
39
+ resHeaders.delete(header);
40
+ });
41
+ if (resHeaders.has("content-encoding")) {
42
+ resHeaders.delete("content-encoding");
43
+ resHeaders.delete("content-length");
44
+ }
45
+ return new Response(res.body, {
46
+ ...res,
47
+ headers: resHeaders
48
+ });
49
+ };
50
+ export {
51
+ proxy
52
+ };