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
@@ -1,6 +1,7 @@
1
1
  // src/helper/streaming/sse.ts
2
2
  import { HtmlEscapedCallbackPhase, resolveCallback } from "../../utils/html.js";
3
3
  import { StreamingApi } from "../../utils/stream.js";
4
+ import { isOldBunVersion } from "./utils.js";
4
5
  var SSEStreamingApi = class extends StreamingApi {
5
6
  constructor(writable, readable) {
6
7
  super(writable, readable);
@@ -40,11 +41,13 @@ var contextStash = /* @__PURE__ */ new WeakMap();
40
41
  var streamSSE = (c, cb, onError) => {
41
42
  const { readable, writable } = new TransformStream();
42
43
  const stream = new SSEStreamingApi(writable, readable);
43
- c.req.raw.signal.addEventListener("abort", () => {
44
- if (!stream.closed) {
45
- stream.abort();
46
- }
47
- });
44
+ if (isOldBunVersion()) {
45
+ c.req.raw.signal.addEventListener("abort", () => {
46
+ if (!stream.closed) {
47
+ stream.abort();
48
+ }
49
+ });
50
+ }
48
51
  contextStash.set(stream.responseReadable, c);
49
52
  c.header("Transfer-Encoding", "chunked");
50
53
  c.header("Content-Type", "text/event-stream");
@@ -1,14 +1,17 @@
1
1
  // src/helper/streaming/stream.ts
2
2
  import { StreamingApi } from "../../utils/stream.js";
3
+ import { isOldBunVersion } from "./utils.js";
3
4
  var contextStash = /* @__PURE__ */ new WeakMap();
4
5
  var stream = (c, cb, onError) => {
5
6
  const { readable, writable } = new TransformStream();
6
7
  const stream2 = new StreamingApi(writable, readable);
7
- c.req.raw.signal.addEventListener("abort", () => {
8
- if (!stream2.closed) {
9
- stream2.abort();
10
- }
11
- });
8
+ if (isOldBunVersion()) {
9
+ c.req.raw.signal.addEventListener("abort", () => {
10
+ if (!stream2.closed) {
11
+ stream2.abort();
12
+ }
13
+ });
14
+ }
12
15
  contextStash.set(stream2.responseReadable, c);
13
16
  (async () => {
14
17
  try {
@@ -0,0 +1,13 @@
1
+ // src/helper/streaming/utils.ts
2
+ var isOldBunVersion = () => {
3
+ const version = typeof Bun !== "undefined" ? Bun.version : void 0;
4
+ if (version === void 0) {
5
+ return false;
6
+ }
7
+ const result = version.startsWith("1.1") || version.startsWith("1.0") || version.startsWith("0.");
8
+ isOldBunVersion = () => result;
9
+ return result;
10
+ };
11
+ export {
12
+ isOldBunVersion
13
+ };
@@ -8,7 +8,7 @@ var mergeBuffers = (buffer1, buffer2) => {
8
8
  merged.set(buffer2, buffer1.byteLength);
9
9
  return merged;
10
10
  };
11
- var generateDigest = async (stream) => {
11
+ var generateDigest = async (stream, generator) => {
12
12
  if (!stream || !crypto || !crypto.subtle) {
13
13
  return null;
14
14
  }
@@ -19,12 +19,7 @@ var generateDigest = async (stream) => {
19
19
  if (done) {
20
20
  break;
21
21
  }
22
- result = await crypto.subtle.digest(
23
- {
24
- name: "SHA-1"
25
- },
26
- mergeBuffers(result, value)
27
- );
22
+ result = await generator(mergeBuffers(result, value));
28
23
  }
29
24
  if (!result) {
30
25
  return null;
@@ -14,20 +14,25 @@ function etagMatches(etag2, ifNoneMatch) {
14
14
  var etag = (options) => {
15
15
  const retainedHeaders = options?.retainedHeaders ?? RETAINED_304_HEADERS;
16
16
  const weak = options?.weak ?? false;
17
+ const generator = options?.generateDigest ?? ((body) => crypto.subtle.digest(
18
+ {
19
+ name: "SHA-1"
20
+ },
21
+ body
22
+ ));
17
23
  return async function etag2(c, next) {
18
24
  const ifNoneMatch = c.req.header("If-None-Match") ?? null;
19
25
  await next();
20
26
  const res = c.res;
21
27
  let etag3 = res.headers.get("ETag");
22
28
  if (!etag3) {
23
- const hash = await generateDigest(res.clone().body);
29
+ const hash = await generateDigest(res.clone().body, generator);
24
30
  if (hash === null) {
25
31
  return;
26
32
  }
27
33
  etag3 = weak ? `W/"${hash}"` : `"${hash}"`;
28
34
  }
29
35
  if (etagMatches(etag3, ifNoneMatch)) {
30
- await c.res.blob();
31
36
  c.res = new Response(null, {
32
37
  status: 304,
33
38
  statusText: "Not Modified",
@@ -0,0 +1,5 @@
1
+ // src/middleware/jwk/index.ts
2
+ import { jwk } from "./jwk.js";
3
+ export {
4
+ jwk
5
+ };
@@ -0,0 +1,101 @@
1
+ // src/middleware/jwk/jwk.ts
2
+ import { getCookie, getSignedCookie } from "../../helper/cookie/index.js";
3
+ import { HTTPException } from "../../http-exception.js";
4
+ import { Jwt } from "../../utils/jwt/index.js";
5
+ import "../../context.js";
6
+ var jwk = (options, init) => {
7
+ if (!options || !(options.keys || options.jwks_uri)) {
8
+ throw new Error('JWK auth middleware requires options for either "keys" or "jwks_uri" or both');
9
+ }
10
+ if (!crypto.subtle || !crypto.subtle.importKey) {
11
+ throw new Error("`crypto.subtle.importKey` is undefined. JWK auth middleware requires it.");
12
+ }
13
+ return async function jwk2(ctx, next) {
14
+ const credentials = ctx.req.raw.headers.get("Authorization");
15
+ let token;
16
+ if (credentials) {
17
+ const parts = credentials.split(/\s+/);
18
+ if (parts.length !== 2) {
19
+ const errDescription = "invalid credentials structure";
20
+ throw new HTTPException(401, {
21
+ message: errDescription,
22
+ res: unauthorizedResponse({
23
+ ctx,
24
+ error: "invalid_request",
25
+ errDescription
26
+ })
27
+ });
28
+ } else {
29
+ token = parts[1];
30
+ }
31
+ } else if (options.cookie) {
32
+ if (typeof options.cookie == "string") {
33
+ token = getCookie(ctx, options.cookie);
34
+ } else if (options.cookie.secret) {
35
+ if (options.cookie.prefixOptions) {
36
+ token = await getSignedCookie(
37
+ ctx,
38
+ options.cookie.secret,
39
+ options.cookie.key,
40
+ options.cookie.prefixOptions
41
+ );
42
+ } else {
43
+ token = await getSignedCookie(ctx, options.cookie.secret, options.cookie.key);
44
+ }
45
+ } else {
46
+ if (options.cookie.prefixOptions) {
47
+ token = getCookie(ctx, options.cookie.key, options.cookie.prefixOptions);
48
+ } else {
49
+ token = getCookie(ctx, options.cookie.key);
50
+ }
51
+ }
52
+ }
53
+ if (!token) {
54
+ const errDescription = "no authorization included in request";
55
+ throw new HTTPException(401, {
56
+ message: errDescription,
57
+ res: unauthorizedResponse({
58
+ ctx,
59
+ error: "invalid_request",
60
+ errDescription
61
+ })
62
+ });
63
+ }
64
+ let payload;
65
+ let cause;
66
+ try {
67
+ payload = await Jwt.verifyFromJwks(token, options, init);
68
+ } catch (e) {
69
+ cause = e;
70
+ }
71
+ if (!payload) {
72
+ if (cause instanceof Error && cause.constructor === Error) {
73
+ throw cause;
74
+ }
75
+ throw new HTTPException(401, {
76
+ message: "Unauthorized",
77
+ res: unauthorizedResponse({
78
+ ctx,
79
+ error: "invalid_token",
80
+ statusText: "Unauthorized",
81
+ errDescription: "token verification failure"
82
+ }),
83
+ cause
84
+ });
85
+ }
86
+ ctx.set("jwtPayload", payload);
87
+ await next();
88
+ };
89
+ };
90
+ function unauthorizedResponse(opts) {
91
+ return new Response("Unauthorized", {
92
+ status: 401,
93
+ statusText: opts.statusText,
94
+ headers: {
95
+ "WWW-Authenticate": `Bearer realm="${opts.ctx.req.url}",error="${opts.error}",error_description="${opts.errDescription}"`
96
+ }
97
+ });
98
+ }
99
+ export {
100
+ jwk
101
+ };
@@ -0,0 +1,15 @@
1
+ // src/middleware/language/index.ts
2
+ import {
3
+ languageDetector,
4
+ detectFromCookie,
5
+ detectFromHeader,
6
+ detectFromPath,
7
+ detectFromQuery
8
+ } from "./language.js";
9
+ export {
10
+ detectFromCookie,
11
+ detectFromHeader,
12
+ detectFromPath,
13
+ detectFromQuery,
14
+ languageDetector
15
+ };
@@ -0,0 +1,178 @@
1
+ // src/middleware/language/language.ts
2
+ import { setCookie, getCookie } from "../../helper/cookie/index.js";
3
+ import { parseAccept } from "../../utils/accept.js";
4
+ var DEFAULT_OPTIONS = {
5
+ order: ["querystring", "cookie", "header"],
6
+ lookupQueryString: "lang",
7
+ lookupCookie: "language",
8
+ lookupFromHeaderKey: "accept-language",
9
+ lookupFromPathIndex: 0,
10
+ caches: ["cookie"],
11
+ ignoreCase: true,
12
+ fallbackLanguage: "en",
13
+ supportedLanguages: ["en"],
14
+ cookieOptions: {
15
+ sameSite: "Strict",
16
+ secure: true,
17
+ maxAge: 365 * 24 * 60 * 60,
18
+ httpOnly: true
19
+ },
20
+ debug: false
21
+ };
22
+ function parseAcceptLanguage(header) {
23
+ return parseAccept(header).map(({ type, q }) => ({ lang: type, q }));
24
+ }
25
+ var normalizeLanguage = (lang, options) => {
26
+ if (!lang) {
27
+ return void 0;
28
+ }
29
+ try {
30
+ let normalizedLang = lang.trim();
31
+ if (options.convertDetectedLanguage) {
32
+ normalizedLang = options.convertDetectedLanguage(normalizedLang);
33
+ }
34
+ const compLang = options.ignoreCase ? normalizedLang.toLowerCase() : normalizedLang;
35
+ const compSupported = options.supportedLanguages.map(
36
+ (l) => options.ignoreCase ? l.toLowerCase() : l
37
+ );
38
+ const matchedLang = compSupported.find((l) => l === compLang);
39
+ return matchedLang ? options.supportedLanguages[compSupported.indexOf(matchedLang)] : void 0;
40
+ } catch {
41
+ return void 0;
42
+ }
43
+ };
44
+ var detectFromQuery = (c, options) => {
45
+ try {
46
+ const query = c.req.query(options.lookupQueryString);
47
+ return normalizeLanguage(query, options);
48
+ } catch {
49
+ return void 0;
50
+ }
51
+ };
52
+ var detectFromCookie = (c, options) => {
53
+ try {
54
+ const cookie = getCookie(c, options.lookupCookie);
55
+ return normalizeLanguage(cookie, options);
56
+ } catch {
57
+ return void 0;
58
+ }
59
+ };
60
+ function detectFromHeader(c, options) {
61
+ try {
62
+ const acceptLanguage = c.req.header(options.lookupFromHeaderKey);
63
+ if (!acceptLanguage) {
64
+ return void 0;
65
+ }
66
+ const languages = parseAcceptLanguage(acceptLanguage);
67
+ for (const { lang } of languages) {
68
+ const normalizedLang = normalizeLanguage(lang, options);
69
+ if (normalizedLang) {
70
+ return normalizedLang;
71
+ }
72
+ }
73
+ return void 0;
74
+ } catch {
75
+ return void 0;
76
+ }
77
+ }
78
+ function detectFromPath(c, options) {
79
+ try {
80
+ const pathSegments = c.req.path.split("/").filter(Boolean);
81
+ const langSegment = pathSegments[options.lookupFromPathIndex];
82
+ return normalizeLanguage(langSegment, options);
83
+ } catch {
84
+ return void 0;
85
+ }
86
+ }
87
+ var detectors = {
88
+ querystring: detectFromQuery,
89
+ cookie: detectFromCookie,
90
+ header: detectFromHeader,
91
+ path: detectFromPath
92
+ };
93
+ function validateOptions(options) {
94
+ if (!options.supportedLanguages.includes(options.fallbackLanguage)) {
95
+ throw new Error("Fallback language must be included in supported languages");
96
+ }
97
+ if (options.lookupFromPathIndex < 0) {
98
+ throw new Error("Path index must be non-negative");
99
+ }
100
+ if (!options.order.every((detector) => Object.keys(detectors).includes(detector))) {
101
+ throw new Error("Invalid detector type in order array");
102
+ }
103
+ }
104
+ function cacheLanguage(c, language, options) {
105
+ if (!Array.isArray(options.caches) || !options.caches.includes("cookie")) {
106
+ return;
107
+ }
108
+ try {
109
+ setCookie(c, options.lookupCookie, language, options.cookieOptions);
110
+ } catch (error) {
111
+ if (options.debug) {
112
+ console.error("Failed to cache language:", error);
113
+ }
114
+ }
115
+ }
116
+ var detectLanguage = (c, options) => {
117
+ let detectedLang;
118
+ for (const detectorName of options.order) {
119
+ const detector = detectors[detectorName];
120
+ if (!detector) {
121
+ continue;
122
+ }
123
+ try {
124
+ detectedLang = detector(c, options);
125
+ if (detectedLang) {
126
+ if (options.debug) {
127
+ console.log(`Language detected from ${detectorName}: ${detectedLang}`);
128
+ }
129
+ break;
130
+ }
131
+ } catch (error) {
132
+ if (options.debug) {
133
+ console.error(`Error in ${detectorName} detector:`, error);
134
+ }
135
+ continue;
136
+ }
137
+ }
138
+ const finalLang = detectedLang || options.fallbackLanguage;
139
+ if (detectedLang && options.caches) {
140
+ cacheLanguage(c, finalLang, options);
141
+ }
142
+ return finalLang;
143
+ };
144
+ var languageDetector = (userOptions) => {
145
+ const options = {
146
+ ...DEFAULT_OPTIONS,
147
+ ...userOptions,
148
+ cookieOptions: {
149
+ ...DEFAULT_OPTIONS.cookieOptions,
150
+ ...userOptions.cookieOptions
151
+ }
152
+ };
153
+ validateOptions(options);
154
+ return async function languageDetector2(ctx, next) {
155
+ try {
156
+ const lang = detectLanguage(ctx, options);
157
+ ctx.set("language", lang);
158
+ } catch (error) {
159
+ if (options.debug) {
160
+ console.error("Language detection failed:", error);
161
+ }
162
+ ctx.set("language", options.fallbackLanguage);
163
+ }
164
+ await next();
165
+ };
166
+ };
167
+ export {
168
+ DEFAULT_OPTIONS,
169
+ detectFromCookie,
170
+ detectFromHeader,
171
+ detectFromPath,
172
+ detectFromQuery,
173
+ detectors,
174
+ languageDetector,
175
+ normalizeLanguage,
176
+ parseAcceptLanguage,
177
+ validateOptions
178
+ };
@@ -1,6 +1,5 @@
1
1
  // src/middleware/logger/index.ts
2
2
  import { getColorEnabled } from "../../utils/color.js";
3
- import { getPath } from "../../utils/url.js";
4
3
  var humanize = (times) => {
5
4
  const [delimiter, separator] = [",", "."];
6
5
  const orderTimes = times.map((v) => v.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter));
@@ -32,8 +31,8 @@ function log(fn, prefix, method, path, status = 0, elapsed) {
32
31
  }
33
32
  var logger = (fn = console.log) => {
34
33
  return async function logger2(c, next) {
35
- const { method } = c.req;
36
- const path = getPath(c.req.raw);
34
+ const { method, url } = c.req;
35
+ const path = url.slice(url.indexOf("/", 8));
37
36
  log(fn, "<--" /* Incoming */, method, path);
38
37
  const start = Date.now();
39
38
  await next();
package/dist/request.js CHANGED
@@ -45,7 +45,7 @@ var HonoRequest = class {
45
45
  }
46
46
  header(name) {
47
47
  if (name) {
48
- return this.raw.headers.get(name.toLowerCase()) ?? void 0;
48
+ return this.raw.headers.get(name) ?? void 0;
49
49
  }
50
50
  const headerData = {};
51
51
  this.raw.headers.forEach((value, key) => {
@@ -66,7 +66,9 @@ var LinearRouter = class {
66
66
  let value;
67
67
  if (name.charCodeAt(name.length - 1) === 125) {
68
68
  const openBracePos = name.indexOf("{");
69
- const pattern = name.slice(openBracePos + 1, -1);
69
+ const next = parts[j + 1];
70
+ const lookahead = next && next[1] !== ":" && next[1] !== "*" ? `(?=${next})` : "";
71
+ const pattern = name.slice(openBracePos + 1, -1) + lookahead;
70
72
  const restPath = path.slice(pos + 1);
71
73
  const match = new RegExp(pattern, "d").exec(restPath);
72
74
  if (!match || match.indices[0][0] !== 0 || match.indices[0][1] === 0) {
@@ -25,21 +25,23 @@ var Node = class {
25
25
  const possibleKeys = [];
26
26
  for (let i = 0, len = parts.length; i < len; i++) {
27
27
  const p = parts[i];
28
- if (Object.keys(curNode.#children).includes(p)) {
29
- curNode = curNode.#children[p];
30
- const pattern2 = getPattern(p);
28
+ const nextP = parts[i + 1];
29
+ const pattern = getPattern(p, nextP);
30
+ const key = Array.isArray(pattern) ? pattern[0] : p;
31
+ if (Object.keys(curNode.#children).includes(key)) {
32
+ curNode = curNode.#children[key];
33
+ const pattern2 = getPattern(p, nextP);
31
34
  if (pattern2) {
32
35
  possibleKeys.push(pattern2[1]);
33
36
  }
34
37
  continue;
35
38
  }
36
- curNode.#children[p] = new Node();
37
- const pattern = getPattern(p);
39
+ curNode.#children[key] = new Node();
38
40
  if (pattern) {
39
41
  curNode.#patterns.push(pattern);
40
42
  possibleKeys.push(pattern[1]);
41
43
  }
42
- curNode = curNode.#children[p];
44
+ curNode = curNode.#children[key];
43
45
  }
44
46
  const m = /* @__PURE__ */ Object.create(null);
45
47
  const handlerSet = {
@@ -78,6 +80,7 @@ var Node = class {
78
80
  const curNode = this;
79
81
  let curNodes = [curNode];
80
82
  const parts = splitPath(path);
83
+ const curNodesQueue = [];
81
84
  for (let i = 0, len = parts.length; i < len; i++) {
82
85
  const part = parts[i];
83
86
  const isLast = i === len - 1;
@@ -105,6 +108,7 @@ var Node = class {
105
108
  const astNode = node.#children["*"];
106
109
  if (astNode) {
107
110
  handlerSets.push(...this.#getHandlerSets(astNode, method, node.#params));
111
+ astNode.#params = params;
108
112
  tempNodes.push(astNode);
109
113
  }
110
114
  continue;
@@ -115,10 +119,19 @@ var Node = class {
115
119
  const [key, name, matcher] = pattern;
116
120
  const child = node.#children[key];
117
121
  const restPathString = parts.slice(i).join("/");
118
- if (matcher instanceof RegExp && matcher.test(restPathString)) {
119
- params[name] = restPathString;
120
- handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params));
121
- continue;
122
+ if (matcher instanceof RegExp) {
123
+ const m = matcher.exec(restPathString);
124
+ if (m) {
125
+ params[name] = m[0];
126
+ handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params));
127
+ if (Object.keys(child.#children).length) {
128
+ child.#params = params;
129
+ const componentCount = m[0].match(/\//)?.length ?? 0;
130
+ const targetCurNodes = curNodesQueue[componentCount] ||= [];
131
+ targetCurNodes.push(child);
132
+ }
133
+ continue;
134
+ }
122
135
  }
123
136
  if (matcher === true || matcher.test(part)) {
124
137
  params[name] = part;
@@ -136,7 +149,7 @@ var Node = class {
136
149
  }
137
150
  }
138
151
  }
139
- curNodes = tempNodes;
152
+ curNodes = tempNodes.concat(curNodesQueue.shift() ?? []);
140
153
  }
141
154
  if (handlerSets.length > 1) {
142
155
  handlerSets.sort((a, b) => {
@@ -47,7 +47,6 @@ export type ClientRequest<S extends Schema> = {
47
47
  } ? {
48
48
  $ws: (args?: I) => WebSocket;
49
49
  } : {} : {});
50
- type BlankRecordToNever<T> = T extends any ? T extends null ? null : keyof T extends never ? never : T : never;
51
50
  type ClientResponseOfEndpoint<T extends Endpoint = Endpoint> = T extends {
52
51
  output: infer O;
53
52
  outputFormat: infer F;
@@ -63,7 +62,7 @@ export interface ClientResponse<T, U extends number = StatusCode, F extends Resp
63
62
  url: string;
64
63
  redirect(url: string, status: number): Response;
65
64
  clone(): Response;
66
- json(): F extends "text" ? Promise<never> : F extends "json" ? Promise<BlankRecordToNever<T>> : Promise<unknown>;
65
+ json(): F extends "text" ? Promise<never> : F extends "json" ? Promise<T> : Promise<unknown>;
67
66
  text(): F extends "text" ? (T extends string ? Promise<T> : Promise<never>) : Promise<string>;
68
67
  blob(): Promise<Blob>;
69
68
  formData(): Promise<FormData>;
@@ -7,9 +7,9 @@ import type { BaseMime } from './utils/mime';
7
7
  import type { InvalidJSONValue, IsAny, JSONParsed, JSONValue, SimplifyDeepArray } from './utils/types';
8
8
  type HeaderRecord = Record<"Content-Type", BaseMime> | Record<ResponseHeader, string | string[]> | Record<string, string | string[]>;
9
9
  /**
10
- * Data type can be a string, ArrayBuffer, or ReadableStream.
10
+ * Data type can be a string, ArrayBuffer, Uint8Array (buffer), or ReadableStream.
11
11
  */
12
- export type Data = string | ArrayBuffer | ReadableStream;
12
+ export type Data = string | ArrayBuffer | ReadableStream | Uint8Array;
13
13
  /**
14
14
  * Interface for the execution context in a web worker or similar environment.
15
15
  */
@@ -13,7 +13,6 @@ export interface acceptsConfig {
13
13
  export interface acceptsOptions extends acceptsConfig {
14
14
  match?: (accepts: Accept[], config: acceptsConfig) => string;
15
15
  }
16
- export declare const parseAccept: (acceptHeader: string) => Accept[];
17
16
  export declare const defaultMatch: (accepts: Accept[], config: acceptsConfig) => string;
18
17
  /**
19
18
  * Match the accept header with the given options.
@@ -6,7 +6,7 @@ import type { Context } from '../../context';
6
6
  export type Runtime = "node" | "deno" | "bun" | "workerd" | "fastly" | "edge-light" | "other";
7
7
  export declare const env: <T extends Record<string, unknown>, C extends Context = Context<{
8
8
  Bindings: T;
9
- }, any, {}>>(c: C, runtime?: Runtime) => T & C["env"];
9
+ }, any, {}>>(c: T extends Record<string, unknown> ? Context : C, runtime?: Runtime) => T & C["env"];
10
10
  export declare const knownUserAgents: Partial<Record<Runtime, string>>;
11
11
  export declare const getRuntimeKey: () => Runtime;
12
12
  export declare const checkUserAgentEquals: (platform: string) => boolean;
@@ -3,6 +3,7 @@
3
3
  * Factory Helper for Hono.
4
4
  */
5
5
  import { Hono } from '../../hono';
6
+ import type { HonoOptions } from '../../hono-base';
6
7
  import type { Env, H, HandlerResponse, Input, IntersectNonAnyTypes, MiddlewareHandler } from '../../types';
7
8
  type InitApp<E extends Env = Env> = (app: Hono<E>) => void;
8
9
  export interface CreateHandlersInterface<E extends Env, P extends string> {
@@ -340,13 +341,15 @@ export interface CreateHandlersInterface<E extends Env, P extends string> {
340
341
  export declare class Factory<E extends Env = Env, P extends string = string> {
341
342
  constructor(init?: {
342
343
  initApp?: InitApp<E>;
344
+ defaultAppOptions?: HonoOptions<E>;
343
345
  });
344
- createApp: () => Hono<E>;
346
+ createApp: (options?: HonoOptions<E>) => Hono<E>;
345
347
  createMiddleware: <I extends Input = {}>(middleware: MiddlewareHandler<E, P, I>) => MiddlewareHandler<E, P, I>;
346
348
  createHandlers: CreateHandlersInterface<E, P>;
347
349
  }
348
350
  export declare const createFactory: <E extends Env = Env, P extends string = string>(init?: {
349
351
  initApp?: InitApp<E>;
352
+ defaultAppOptions?: HonoOptions<E>;
350
353
  }) => Factory<E, P>;
351
354
  export declare const createMiddleware: <E extends Env = any, P extends string = string, I extends Input = {}>(middleware: MiddlewareHandler<E, P, I>) => MiddlewareHandler<E, P, I>;
352
355
  export {};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @module
3
+ * Proxy Helper for Hono.
4
+ */
5
+ import type { RequestHeader } from '../../utils/headers';
6
+ interface ProxyRequestInit extends Omit<RequestInit, "headers"> {
7
+ raw?: Request;
8
+ headers?: HeadersInit | [
9
+ string,
10
+ string
11
+ ][] | Record<RequestHeader, string | undefined> | Record<string, string | undefined>;
12
+ }
13
+ interface ProxyFetch {
14
+ (input: string | URL | Request, init?: ProxyRequestInit): Promise<Response>;
15
+ }
16
+ /**
17
+ * Fetch API wrapper for proxy.
18
+ * The parameters and return value are the same as for `fetch` (except for the proxy-specific options).
19
+ *
20
+ * The “Accept-Encoding” header is replaced with an encoding that the current runtime can handle.
21
+ * Unnecessary response headers are deleted and a Response object is returned that can be returned
22
+ * as is as a response from the handler.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * app.get('/proxy/:path', (c) => {
27
+ * return proxy(`http://${originServer}/${c.req.param('path')}`, {
28
+ * headers: {
29
+ * ...c.req.header(), // optional, specify only when forwarding all the request data (including credentials) is necessary.
30
+ * 'X-Forwarded-For': '127.0.0.1',
31
+ * 'X-Forwarded-Host': c.req.header('host'),
32
+ * Authorization: undefined, // do not propagate request headers contained in c.req.header('Authorization')
33
+ * },
34
+ * }).then((res) => {
35
+ * res.headers.delete('Set-Cookie')
36
+ * return res
37
+ * })
38
+ * })
39
+ *
40
+ * app.all('/proxy/:path', (c) => {
41
+ * return proxy(`http://${originServer}/${c.req.param('path')}`, {
42
+ * ...c.req, // optional, specify only when forwarding all the request data (including credentials) is necessary.
43
+ * headers: {
44
+ * ...c.req.header(),
45
+ * 'X-Forwarded-For': '127.0.0.1',
46
+ * 'X-Forwarded-Host': c.req.header('host'),
47
+ * Authorization: undefined, // do not propagate request headers contained in c.req.header('Authorization')
48
+ * },
49
+ * })
50
+ * })
51
+ * ```
52
+ */
53
+ export declare const proxy: ProxyFetch;
54
+ export {};
@@ -0,0 +1 @@
1
+ export declare let isOldBunVersion: () => boolean;