hono 3.12.7 → 3.12.9

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 (37) hide show
  1. package/dist/adapter/aws-lambda/handler.js +2 -1
  2. package/dist/adapter/bun/serve-static.js +9 -11
  3. package/dist/adapter/cloudflare-workers/serve-static.js +2 -1
  4. package/dist/adapter/deno/serve-static.js +2 -1
  5. package/dist/cjs/adapter/aws-lambda/handler.js +2 -1
  6. package/dist/cjs/adapter/bun/serve-static.js +9 -11
  7. package/dist/cjs/adapter/cloudflare-workers/serve-static.js +2 -1
  8. package/dist/cjs/adapter/deno/serve-static.js +2 -1
  9. package/dist/cjs/client/client.js +4 -2
  10. package/dist/cjs/helper/adapter/index.js +14 -7
  11. package/dist/cjs/helper/cookie/index.js +8 -4
  12. package/dist/cjs/hono-base.js +6 -6
  13. package/dist/cjs/jsx/index.js +40 -12
  14. package/dist/cjs/request.js +26 -17
  15. package/dist/cjs/router/reg-exp-router/router.js +2 -1
  16. package/dist/cjs/router/trie-router/node.js +4 -2
  17. package/dist/cjs/utils/cookie.js +14 -7
  18. package/dist/cjs/utils/filepath.js +2 -1
  19. package/dist/cjs/utils/mime.js +2 -1
  20. package/dist/cjs/utils/url.js +2 -1
  21. package/dist/client/client.js +4 -2
  22. package/dist/helper/adapter/index.js +14 -7
  23. package/dist/helper/cookie/index.js +8 -4
  24. package/dist/hono-base.js +6 -6
  25. package/dist/jsx/index.js +40 -12
  26. package/dist/request.js +26 -17
  27. package/dist/router/reg-exp-router/router.js +2 -1
  28. package/dist/router/trie-router/node.js +4 -2
  29. package/dist/types/helper/factory/index.d.ts +1 -1
  30. package/dist/types/jsx/index.d.ts +2 -0
  31. package/dist/types/request.d.ts +3 -0
  32. package/dist/types/types.d.ts +22 -3
  33. package/dist/utils/cookie.js +14 -7
  34. package/dist/utils/filepath.js +2 -1
  35. package/dist/utils/mime.js +2 -1
  36. package/dist/utils/url.js +2 -1
  37. package/package.json +2 -2
@@ -84,8 +84,9 @@ var createRequest = (event) => {
84
84
  const headers = new Headers();
85
85
  getCookies(event, headers);
86
86
  for (const [k, v] of Object.entries(event.headers)) {
87
- if (v)
87
+ if (v) {
88
88
  headers.set(k, v);
89
+ }
89
90
  }
90
91
  const method = isProxyEventV2(event) ? event.requestContext.http.method : event.httpMethod;
91
92
  const requestInit = {
@@ -1,8 +1,6 @@
1
1
  // src/adapter/bun/serve-static.ts
2
- import { existsSync } from "fs";
3
2
  import { getFilePath } from "../../utils/filepath.js";
4
3
  import { getMimeType } from "../../utils/mime.js";
5
- var { file } = Bun;
6
4
  var DEFAULT_DOCUMENT = "index.html";
7
5
  var serveStatic = (options = { root: "" }) => {
8
6
  return async (c, next) => {
@@ -17,18 +15,18 @@ var serveStatic = (options = { root: "" }) => {
17
15
  root: options.root,
18
16
  defaultDocument: DEFAULT_DOCUMENT
19
17
  });
20
- if (!path)
18
+ if (!path) {
21
19
  return await next();
20
+ }
22
21
  path = `./${path}`;
23
- if (existsSync(path)) {
24
- const content = file(path);
25
- if (content) {
26
- const mimeType = getMimeType(path);
27
- if (mimeType) {
28
- c.header("Content-Type", mimeType);
29
- }
30
- return c.body(content);
22
+ const file = Bun.file(path);
23
+ const isExists = await file.exists();
24
+ if (isExists) {
25
+ const mimeType = getMimeType(path);
26
+ if (mimeType) {
27
+ c.header("Content-Type", mimeType);
31
28
  }
29
+ return c.body(file);
32
30
  }
33
31
  await options.onNotFound?.(path, c);
34
32
  await next();
@@ -16,8 +16,9 @@ var serveStatic = (options = { root: "" }) => {
16
16
  root: options.root,
17
17
  defaultDocument: DEFAULT_DOCUMENT
18
18
  });
19
- if (!path)
19
+ if (!path) {
20
20
  return await next();
21
+ }
21
22
  const content = await getContentFromKVAsset(path, {
22
23
  manifest: options.manifest,
23
24
  namespace: options.namespace ? options.namespace : c.env ? c.env.__STATIC_CONTENT : void 0
@@ -16,8 +16,9 @@ var serveStatic = (options = { root: "" }) => {
16
16
  root: options.root,
17
17
  defaultDocument: DEFAULT_DOCUMENT
18
18
  });
19
- if (!path)
19
+ if (!path) {
20
20
  return await next();
21
+ }
21
22
  path = `./${path}`;
22
23
  let file;
23
24
  try {
@@ -115,8 +115,9 @@ const createRequest = (event) => {
115
115
  const headers = new Headers();
116
116
  getCookies(event, headers);
117
117
  for (const [k, v] of Object.entries(event.headers)) {
118
- if (v)
118
+ if (v) {
119
119
  headers.set(k, v);
120
+ }
120
121
  }
121
122
  const method = isProxyEventV2(event) ? event.requestContext.http.method : event.httpMethod;
122
123
  const requestInit = {
@@ -21,10 +21,8 @@ __export(serve_static_exports, {
21
21
  serveStatic: () => serveStatic
22
22
  });
23
23
  module.exports = __toCommonJS(serve_static_exports);
24
- var import_fs = require("fs");
25
24
  var import_filepath = require("../../utils/filepath");
26
25
  var import_mime = require("../../utils/mime");
27
- const { file } = Bun;
28
26
  const DEFAULT_DOCUMENT = "index.html";
29
27
  const serveStatic = (options = { root: "" }) => {
30
28
  return async (c, next) => {
@@ -39,18 +37,18 @@ const serveStatic = (options = { root: "" }) => {
39
37
  root: options.root,
40
38
  defaultDocument: DEFAULT_DOCUMENT
41
39
  });
42
- if (!path)
40
+ if (!path) {
43
41
  return await next();
42
+ }
44
43
  path = `./${path}`;
45
- if ((0, import_fs.existsSync)(path)) {
46
- const content = file(path);
47
- if (content) {
48
- const mimeType = (0, import_mime.getMimeType)(path);
49
- if (mimeType) {
50
- c.header("Content-Type", mimeType);
51
- }
52
- return c.body(content);
44
+ const file = Bun.file(path);
45
+ const isExists = await file.exists();
46
+ if (isExists) {
47
+ const mimeType = (0, import_mime.getMimeType)(path);
48
+ if (mimeType) {
49
+ c.header("Content-Type", mimeType);
53
50
  }
51
+ return c.body(file);
54
52
  }
55
53
  await options.onNotFound?.(path, c);
56
54
  await next();
@@ -38,8 +38,9 @@ const serveStatic = (options = { root: "" }) => {
38
38
  root: options.root,
39
39
  defaultDocument: DEFAULT_DOCUMENT
40
40
  });
41
- if (!path)
41
+ if (!path) {
42
42
  return await next();
43
+ }
43
44
  const content = await (0, import_utils.getContentFromKVAsset)(path, {
44
45
  manifest: options.manifest,
45
46
  namespace: options.namespace ? options.namespace : c.env ? c.env.__STATIC_CONTENT : void 0
@@ -38,8 +38,9 @@ const serveStatic = (options = { root: "" }) => {
38
38
  root: options.root,
39
39
  defaultDocument: DEFAULT_DOCUMENT
40
40
  });
41
- if (!path)
41
+ if (!path) {
42
42
  return await next();
43
+ }
43
44
  path = `./${path}`;
44
45
  let file;
45
46
  try {
@@ -27,8 +27,9 @@ const createProxy = (callback, path) => {
27
27
  const proxy = new Proxy(() => {
28
28
  }, {
29
29
  get(_obj, key) {
30
- if (typeof key !== "string" || key === "then")
30
+ if (typeof key !== "string" || key === "then") {
31
31
  return void 0;
32
+ }
32
33
  return createProxy(callback, [...path, key]);
33
34
  },
34
35
  apply(_1, _2, args) {
@@ -98,8 +99,9 @@ class ClientRequestImpl {
98
99
  }
99
100
  headerValues["Cookie"] = cookies.join(",");
100
101
  }
101
- if (this.cType)
102
+ if (this.cType) {
102
103
  headerValues["Content-Type"] = this.cType;
104
+ }
103
105
  const headers = new Headers(headerValues ?? void 0);
104
106
  let url = this.url;
105
107
  url = (0, import_utils.removeIndexString)(url);
@@ -42,20 +42,27 @@ const env = (c, runtime) => {
42
42
  };
43
43
  const getRuntimeKey = () => {
44
44
  const global = globalThis;
45
- if (global?.Deno !== void 0)
45
+ if (global?.Deno !== void 0) {
46
46
  return "deno";
47
- if (global?.Bun !== void 0)
47
+ }
48
+ if (global?.Bun !== void 0) {
48
49
  return "bun";
49
- if (typeof global?.WebSocketPair === "function")
50
+ }
51
+ if (typeof global?.WebSocketPair === "function") {
50
52
  return "workerd";
51
- if (typeof global?.EdgeRuntime === "string")
53
+ }
54
+ if (typeof global?.EdgeRuntime === "string") {
52
55
  return "edge-light";
53
- if (global?.fastly !== void 0)
56
+ }
57
+ if (global?.fastly !== void 0) {
54
58
  return "fastly";
55
- if (global?.__lagon__ !== void 0)
59
+ }
60
+ if (global?.__lagon__ !== void 0) {
56
61
  return "lagon";
57
- if (global?.process?.release?.name === "node")
62
+ }
63
+ if (global?.process?.release?.name === "node") {
58
64
  return "node";
65
+ }
59
66
  return "other";
60
67
  };
61
68
  // Annotate the CommonJS export names for ESM import in node:
@@ -29,26 +29,30 @@ var import_cookie = require("../../utils/cookie");
29
29
  const getCookie = (c, key) => {
30
30
  const cookie = c.req.raw.headers.get("Cookie");
31
31
  if (typeof key === "string") {
32
- if (!cookie)
32
+ if (!cookie) {
33
33
  return void 0;
34
+ }
34
35
  const obj2 = (0, import_cookie.parse)(cookie, key);
35
36
  return obj2[key];
36
37
  }
37
- if (!cookie)
38
+ if (!cookie) {
38
39
  return {};
40
+ }
39
41
  const obj = (0, import_cookie.parse)(cookie);
40
42
  return obj;
41
43
  };
42
44
  const getSignedCookie = async (c, secret, key) => {
43
45
  const cookie = c.req.raw.headers.get("Cookie");
44
46
  if (typeof key === "string") {
45
- if (!cookie)
47
+ if (!cookie) {
46
48
  return void 0;
49
+ }
47
50
  const obj2 = await (0, import_cookie.parseSigned)(cookie, secret, key);
48
51
  return obj2[key];
49
52
  }
50
- if (!cookie)
53
+ if (!cookie) {
51
54
  return {};
55
+ }
52
56
  const obj = await (0, import_cookie.parseSigned)(cookie, secret);
53
57
  return obj;
54
58
  };
@@ -123,8 +123,9 @@ const _Hono = class extends defineDynamicClass() {
123
123
  };
124
124
  });
125
125
  this.on = (method, path, ...handlers) => {
126
- if (!method)
126
+ if (!method) {
127
127
  return this;
128
+ }
128
129
  __privateSet(this, _path, path);
129
130
  for (const m of [method].flat()) {
130
131
  handlers.map((handler) => {
@@ -206,8 +207,9 @@ const _Hono = class extends defineDynamicClass() {
206
207
  ),
207
208
  ...optionsArray
208
209
  );
209
- if (res)
210
+ if (res) {
210
211
  return res;
212
+ }
211
213
  await next();
212
214
  };
213
215
  this.addRoute(import_router.METHOD_NAME_ALL, (0, import_url.mergePath)(path, "*"), handler);
@@ -253,11 +255,9 @@ const _Hono = class extends defineDynamicClass() {
253
255
  } catch (err) {
254
256
  return this.handleError(err, c);
255
257
  }
256
- if (res instanceof Response)
257
- return res;
258
- return res.then(
258
+ return res instanceof Promise ? res.then(
259
259
  (resolved) => resolved || (c.finalized ? c.res : this.notFoundHandler(c))
260
- ).catch((err) => this.handleError(err, c));
260
+ ).catch((err) => this.handleError(err, c)) : res;
261
261
  }
262
262
  const composed = (0, import_compose.compose)(matchResult[0], this.errorHandler, this.notFoundHandler);
263
263
  return (async () => {
@@ -102,7 +102,16 @@ class JSXNode {
102
102
  }
103
103
  toString() {
104
104
  const buffer = [""];
105
- this.toStringToBuffer(buffer);
105
+ this.localContexts?.forEach(([context, value]) => {
106
+ context.values.push(value);
107
+ });
108
+ try {
109
+ this.toStringToBuffer(buffer);
110
+ } finally {
111
+ this.localContexts?.forEach(([context]) => {
112
+ context.values.pop();
113
+ });
114
+ }
106
115
  return buffer.length === 1 ? buffer[0] : (0, import_html2.stringBufferToString)(buffer);
107
116
  }
108
117
  toStringToBuffer(buffer) {
@@ -162,7 +171,23 @@ class JSXFunctionNode extends JSXNode {
162
171
  children: children.length <= 1 ? children[0] : children
163
172
  });
164
173
  if (res instanceof Promise) {
165
- buffer.unshift("", res);
174
+ if (globalContexts.length === 0) {
175
+ buffer.unshift("", res);
176
+ } else {
177
+ const currentContexts = globalContexts.map((c) => [
178
+ c,
179
+ c.values[c.values.length - 1]
180
+ ]);
181
+ buffer.unshift(
182
+ "",
183
+ res.then((childRes) => {
184
+ if (childRes instanceof JSXNode) {
185
+ childRes.localContexts = currentContexts;
186
+ }
187
+ return childRes;
188
+ })
189
+ );
190
+ }
166
191
  } else if (res instanceof JSXNode) {
167
192
  res.toStringToBuffer(buffer);
168
193
  } else if (typeof res === "number" || res.isEscaped) {
@@ -214,27 +239,30 @@ const memo = (component, propsAreEqual = shallowEqual) => {
214
239
  const Fragment = (props) => {
215
240
  return new JSXFragmentNode("", {}, props.children ? [props.children] : []);
216
241
  };
242
+ const globalContexts = [];
217
243
  const createContext = (defaultValue) => {
218
244
  const values = [defaultValue];
219
- return {
245
+ const context = {
220
246
  values,
221
247
  Provider(props) {
222
248
  values.push(props.value);
223
- const string = props.children ? (Array.isArray(props.children) ? new JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
224
- values.pop();
249
+ let string;
250
+ try {
251
+ string = props.children ? (Array.isArray(props.children) ? new JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
252
+ } finally {
253
+ values.pop();
254
+ }
225
255
  if (string instanceof Promise) {
226
- return Promise.resolve().then(async () => {
227
- values.push(props.value);
228
- const awaited = await string;
229
- const promiseRes = (0, import_html.raw)(awaited, awaited.callbacks);
230
- values.pop();
231
- return promiseRes;
232
- });
256
+ return string.then(
257
+ (resString) => (0, import_html.raw)(resString, resString.callbacks)
258
+ );
233
259
  } else {
234
260
  return (0, import_html.raw)(string);
235
261
  }
236
262
  }
237
263
  };
264
+ globalContexts.push(context);
265
+ return context;
238
266
  };
239
267
  const useContext = (context) => {
240
268
  return context.values[context.values.length - 1];
@@ -52,8 +52,9 @@ class HonoRequest {
52
52
  this.cachedBody = (key) => {
53
53
  const { bodyCache, raw } = this;
54
54
  const cachedBody = bodyCache[key];
55
- if (cachedBody)
55
+ if (cachedBody) {
56
56
  return cachedBody;
57
+ }
57
58
  if (bodyCache.arrayBuffer) {
58
59
  return (async () => {
59
60
  return await new Response(bodyCache.arrayBuffer)[key]();
@@ -67,21 +68,26 @@ class HonoRequest {
67
68
  __privateSet(this, _validatedData, {});
68
69
  }
69
70
  param(key) {
70
- if (key) {
71
- const param = __privateGet(this, _matchResult)[1] ? __privateGet(this, _matchResult)[1][__privateGet(this, _matchResult)[0][this.routeIndex][1][key]] : __privateGet(this, _matchResult)[0][this.routeIndex][1][key];
72
- return param ? /\%/.test(param) ? (0, import_url.decodeURIComponent_)(param) : param : void 0;
73
- } else {
74
- const decoded = {};
75
- const keys = Object.keys(__privateGet(this, _matchResult)[0][this.routeIndex][1]);
76
- for (let i = 0, len = keys.length; i < len; i++) {
77
- const key2 = keys[i];
78
- const value = __privateGet(this, _matchResult)[1] ? __privateGet(this, _matchResult)[1][__privateGet(this, _matchResult)[0][this.routeIndex][1][key2]] : __privateGet(this, _matchResult)[0][this.routeIndex][1][key2];
79
- if (value && typeof value === "string") {
80
- decoded[key2] = /\%/.test(value) ? (0, import_url.decodeURIComponent_)(value) : value;
81
- }
71
+ return key ? this.getDecodedParam(key) : this.getAllDecodedParams();
72
+ }
73
+ getDecodedParam(key) {
74
+ const paramKey = __privateGet(this, _matchResult)[0][this.routeIndex][1][key];
75
+ const param = this.getParamValue(paramKey);
76
+ return param ? /\%/.test(param) ? (0, import_url.decodeURIComponent_)(param) : param : void 0;
77
+ }
78
+ getAllDecodedParams() {
79
+ const decoded = {};
80
+ const keys = Object.keys(__privateGet(this, _matchResult)[0][this.routeIndex][1]);
81
+ for (const key of keys) {
82
+ const value = this.getParamValue(__privateGet(this, _matchResult)[0][this.routeIndex][1][key]);
83
+ if (value && typeof value === "string") {
84
+ decoded[key] = /\%/.test(value) ? (0, import_url.decodeURIComponent_)(value) : value;
82
85
  }
83
- return decoded;
84
86
  }
87
+ return decoded;
88
+ }
89
+ getParamValue(paramKey) {
90
+ return __privateGet(this, _matchResult)[1] ? __privateGet(this, _matchResult)[1][paramKey] : paramKey;
85
91
  }
86
92
  query(key) {
87
93
  return (0, import_url.getQueryParam)(this.url, key);
@@ -90,8 +96,9 @@ class HonoRequest {
90
96
  return (0, import_url.getQueryParams)(this.url, key);
91
97
  }
92
98
  header(name) {
93
- if (name)
99
+ if (name) {
94
100
  return this.raw.headers.get(name.toLowerCase()) ?? void 0;
101
+ }
95
102
  const headerData = {};
96
103
  this.raw.headers.forEach((value, key) => {
97
104
  headerData[key] = value;
@@ -100,8 +107,9 @@ class HonoRequest {
100
107
  }
101
108
  cookie(key) {
102
109
  const cookie = this.raw.headers.get("Cookie");
103
- if (!cookie)
110
+ if (!cookie) {
104
111
  return;
112
+ }
105
113
  const obj = (0, import_cookie.parse)(cookie);
106
114
  if (key) {
107
115
  const value = obj[key];
@@ -111,8 +119,9 @@ class HonoRequest {
111
119
  }
112
120
  }
113
121
  async parseBody(options) {
114
- if (this.bodyCache.parsedBody)
122
+ if (this.bodyCache.parsedBody) {
115
123
  return this.bodyCache.parsedBody;
124
+ }
116
125
  const parsedBody = await (0, import_body.parseBody)(this, options);
117
126
  this.bodyCache.parsedBody = parsedBody;
118
127
  return parsedBody;
@@ -117,8 +117,9 @@ class RegExpRouter {
117
117
  if (!middleware || !routes) {
118
118
  throw new Error(import_router.MESSAGE_MATCHER_IS_ALREADY_BUILT);
119
119
  }
120
- if (methodNames.indexOf(method) === -1)
120
+ if (methodNames.indexOf(method) === -1) {
121
121
  methodNames.push(method);
122
+ }
122
123
  if (!middleware[method]) {
123
124
  ;
124
125
  [middleware, routes].forEach((handlerMap) => {
@@ -50,8 +50,9 @@ class Node {
50
50
  parentPatterns.push(...curNode.patterns);
51
51
  curNode = curNode.children[p];
52
52
  const pattern2 = (0, import_url.getPattern)(p);
53
- if (pattern2)
53
+ if (pattern2) {
54
54
  possibleKeys.push(pattern2[1]);
55
+ }
55
56
  continue;
56
57
  }
57
58
  curNode.children[p] = new Node();
@@ -131,8 +132,9 @@ class Node {
131
132
  }
132
133
  continue;
133
134
  }
134
- if (part === "")
135
+ if (part === "") {
135
136
  continue;
137
+ }
136
138
  const [key, name, matcher] = pattern;
137
139
  const child = node.children[key];
138
140
  const restPathString = parts.slice(i).join("/");
@@ -39,8 +39,9 @@ const verifySignature = async (base64Signature, value, secret) => {
39
39
  try {
40
40
  const signatureBinStr = atob(base64Signature);
41
41
  const signature = new Uint8Array(signatureBinStr.length);
42
- for (let i = 0; i < signatureBinStr.length; i++)
42
+ for (let i = 0; i < signatureBinStr.length; i++) {
43
43
  signature[i] = signatureBinStr.charCodeAt(i);
44
+ }
44
45
  return await crypto.subtle.verify(algorithm, secret, signature, new TextEncoder().encode(value));
45
46
  } catch (e) {
46
47
  return false;
@@ -53,16 +54,20 @@ const parse = (cookie, name) => {
53
54
  return pairs.reduce((parsedCookie, pairStr) => {
54
55
  pairStr = pairStr.trim();
55
56
  const valueStartPos = pairStr.indexOf("=");
56
- if (valueStartPos === -1)
57
+ if (valueStartPos === -1) {
57
58
  return parsedCookie;
59
+ }
58
60
  const cookieName = pairStr.substring(0, valueStartPos).trim();
59
- if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName))
61
+ if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName)) {
60
62
  return parsedCookie;
63
+ }
61
64
  let cookieValue = pairStr.substring(valueStartPos + 1).trim();
62
- if (cookieValue.startsWith('"') && cookieValue.endsWith('"'))
65
+ if (cookieValue.startsWith('"') && cookieValue.endsWith('"')) {
63
66
  cookieValue = cookieValue.slice(1, -1);
64
- if (validCookieValueRegEx.test(cookieValue))
67
+ }
68
+ if (validCookieValueRegEx.test(cookieValue)) {
65
69
  parsedCookie[cookieName] = (0, import_url.decodeURIComponent_)(cookieValue);
70
+ }
66
71
  return parsedCookie;
67
72
  }, {});
68
73
  };
@@ -71,12 +76,14 @@ const parseSigned = async (cookie, secret, name) => {
71
76
  const secretKey = await getCryptoKey(secret);
72
77
  for (const [key, value] of Object.entries(parse(cookie, name))) {
73
78
  const signatureStartPos = value.lastIndexOf(".");
74
- if (signatureStartPos < 1)
79
+ if (signatureStartPos < 1) {
75
80
  continue;
81
+ }
76
82
  const signedValue = value.substring(0, signatureStartPos);
77
83
  const signature = value.substring(signatureStartPos + 1);
78
- if (signature.length !== 44 || !signature.endsWith("="))
84
+ if (signature.length !== 44 || !signature.endsWith("=")) {
79
85
  continue;
86
+ }
80
87
  const isVerified = await verifySignature(signature, signedValue, secretKey);
81
88
  parsedCookie[key] = isVerified ? signedValue : false;
82
89
  }
@@ -23,8 +23,9 @@ __export(filepath_exports, {
23
23
  module.exports = __toCommonJS(filepath_exports);
24
24
  const getFilePath = (options) => {
25
25
  let filename = options.filename;
26
- if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename))
26
+ if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
27
27
  return;
28
+ }
28
29
  let root = options.root || "";
29
30
  const defaultDocument = options.defaultDocument || "index.html";
30
31
  if (filename.endsWith("/")) {
@@ -24,8 +24,9 @@ module.exports = __toCommonJS(mime_exports);
24
24
  const getMimeType = (filename) => {
25
25
  const regexp = /\.([a-zA-Z0-9]+?)$/;
26
26
  const match = filename.match(regexp);
27
- if (!match)
27
+ if (!match) {
28
28
  return;
29
+ }
29
30
  let mimeType = mimes[match[1]];
30
31
  if (mimeType && mimeType.startsWith("text") || mimeType === "application/json") {
31
32
  mimeType += "; charset=utf-8";
@@ -117,8 +117,9 @@ const mergePath = (...paths) => {
117
117
  return p;
118
118
  };
119
119
  const checkOptionalParameter = (path) => {
120
- if (!path.match(/\:.+\?$/))
120
+ if (!path.match(/\:.+\?$/)) {
121
121
  return null;
122
+ }
122
123
  const segments = path.split("/");
123
124
  const results = [];
124
125
  let basePath = "";
@@ -5,8 +5,9 @@ var createProxy = (callback, path) => {
5
5
  const proxy = new Proxy(() => {
6
6
  }, {
7
7
  get(_obj, key) {
8
- if (typeof key !== "string" || key === "then")
8
+ if (typeof key !== "string" || key === "then") {
9
9
  return void 0;
10
+ }
10
11
  return createProxy(callback, [...path, key]);
11
12
  },
12
13
  apply(_1, _2, args) {
@@ -76,8 +77,9 @@ var ClientRequestImpl = class {
76
77
  }
77
78
  headerValues["Cookie"] = cookies.join(",");
78
79
  }
79
- if (this.cType)
80
+ if (this.cType) {
80
81
  headerValues["Content-Type"] = this.cType;
82
+ }
81
83
  const headers = new Headers(headerValues ?? void 0);
82
84
  let url = this.url;
83
85
  url = removeIndexString(url);
@@ -19,20 +19,27 @@ var env = (c, runtime) => {
19
19
  };
20
20
  var getRuntimeKey = () => {
21
21
  const global = globalThis;
22
- if (global?.Deno !== void 0)
22
+ if (global?.Deno !== void 0) {
23
23
  return "deno";
24
- if (global?.Bun !== void 0)
24
+ }
25
+ if (global?.Bun !== void 0) {
25
26
  return "bun";
26
- if (typeof global?.WebSocketPair === "function")
27
+ }
28
+ if (typeof global?.WebSocketPair === "function") {
27
29
  return "workerd";
28
- if (typeof global?.EdgeRuntime === "string")
30
+ }
31
+ if (typeof global?.EdgeRuntime === "string") {
29
32
  return "edge-light";
30
- if (global?.fastly !== void 0)
33
+ }
34
+ if (global?.fastly !== void 0) {
31
35
  return "fastly";
32
- if (global?.__lagon__ !== void 0)
36
+ }
37
+ if (global?.__lagon__ !== void 0) {
33
38
  return "lagon";
34
- if (global?.process?.release?.name === "node")
39
+ }
40
+ if (global?.process?.release?.name === "node") {
35
41
  return "node";
42
+ }
36
43
  return "other";
37
44
  };
38
45
  export {
@@ -3,26 +3,30 @@ import { parse, parseSigned, serialize, serializeSigned } from "../../utils/cook
3
3
  var getCookie = (c, key) => {
4
4
  const cookie = c.req.raw.headers.get("Cookie");
5
5
  if (typeof key === "string") {
6
- if (!cookie)
6
+ if (!cookie) {
7
7
  return void 0;
8
+ }
8
9
  const obj2 = parse(cookie, key);
9
10
  return obj2[key];
10
11
  }
11
- if (!cookie)
12
+ if (!cookie) {
12
13
  return {};
14
+ }
13
15
  const obj = parse(cookie);
14
16
  return obj;
15
17
  };
16
18
  var getSignedCookie = async (c, secret, key) => {
17
19
  const cookie = c.req.raw.headers.get("Cookie");
18
20
  if (typeof key === "string") {
19
- if (!cookie)
21
+ if (!cookie) {
20
22
  return void 0;
23
+ }
21
24
  const obj2 = await parseSigned(cookie, secret, key);
22
25
  return obj2[key];
23
26
  }
24
- if (!cookie)
27
+ if (!cookie) {
25
28
  return {};
29
+ }
26
30
  const obj = await parseSigned(cookie, secret);
27
31
  return obj;
28
32
  };
package/dist/hono-base.js CHANGED
@@ -101,8 +101,9 @@ var _Hono = class extends defineDynamicClass() {
101
101
  };
102
102
  });
103
103
  this.on = (method, path, ...handlers) => {
104
- if (!method)
104
+ if (!method) {
105
105
  return this;
106
+ }
106
107
  __privateSet(this, _path, path);
107
108
  for (const m of [method].flat()) {
108
109
  handlers.map((handler) => {
@@ -184,8 +185,9 @@ var _Hono = class extends defineDynamicClass() {
184
185
  ),
185
186
  ...optionsArray
186
187
  );
187
- if (res)
188
+ if (res) {
188
189
  return res;
190
+ }
189
191
  await next();
190
192
  };
191
193
  this.addRoute(METHOD_NAME_ALL, mergePath(path, "*"), handler);
@@ -231,11 +233,9 @@ var _Hono = class extends defineDynamicClass() {
231
233
  } catch (err) {
232
234
  return this.handleError(err, c);
233
235
  }
234
- if (res instanceof Response)
235
- return res;
236
- return res.then(
236
+ return res instanceof Promise ? res.then(
237
237
  (resolved) => resolved || (c.finalized ? c.res : this.notFoundHandler(c))
238
- ).catch((err) => this.handleError(err, c));
238
+ ).catch((err) => this.handleError(err, c)) : res;
239
239
  }
240
240
  const composed = compose(matchResult[0], this.errorHandler, this.notFoundHandler);
241
241
  return (async () => {
package/dist/jsx/index.js CHANGED
@@ -74,7 +74,16 @@ var JSXNode = class {
74
74
  }
75
75
  toString() {
76
76
  const buffer = [""];
77
- this.toStringToBuffer(buffer);
77
+ this.localContexts?.forEach(([context, value]) => {
78
+ context.values.push(value);
79
+ });
80
+ try {
81
+ this.toStringToBuffer(buffer);
82
+ } finally {
83
+ this.localContexts?.forEach(([context]) => {
84
+ context.values.pop();
85
+ });
86
+ }
78
87
  return buffer.length === 1 ? buffer[0] : stringBufferToString(buffer);
79
88
  }
80
89
  toStringToBuffer(buffer) {
@@ -134,7 +143,23 @@ var JSXFunctionNode = class extends JSXNode {
134
143
  children: children.length <= 1 ? children[0] : children
135
144
  });
136
145
  if (res instanceof Promise) {
137
- buffer.unshift("", res);
146
+ if (globalContexts.length === 0) {
147
+ buffer.unshift("", res);
148
+ } else {
149
+ const currentContexts = globalContexts.map((c) => [
150
+ c,
151
+ c.values[c.values.length - 1]
152
+ ]);
153
+ buffer.unshift(
154
+ "",
155
+ res.then((childRes) => {
156
+ if (childRes instanceof JSXNode) {
157
+ childRes.localContexts = currentContexts;
158
+ }
159
+ return childRes;
160
+ })
161
+ );
162
+ }
138
163
  } else if (res instanceof JSXNode) {
139
164
  res.toStringToBuffer(buffer);
140
165
  } else if (typeof res === "number" || res.isEscaped) {
@@ -186,27 +211,30 @@ var memo = (component, propsAreEqual = shallowEqual) => {
186
211
  var Fragment = (props) => {
187
212
  return new JSXFragmentNode("", {}, props.children ? [props.children] : []);
188
213
  };
214
+ var globalContexts = [];
189
215
  var createContext = (defaultValue) => {
190
216
  const values = [defaultValue];
191
- return {
217
+ const context = {
192
218
  values,
193
219
  Provider(props) {
194
220
  values.push(props.value);
195
- const string = props.children ? (Array.isArray(props.children) ? new JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
196
- values.pop();
221
+ let string;
222
+ try {
223
+ string = props.children ? (Array.isArray(props.children) ? new JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
224
+ } finally {
225
+ values.pop();
226
+ }
197
227
  if (string instanceof Promise) {
198
- return Promise.resolve().then(async () => {
199
- values.push(props.value);
200
- const awaited = await string;
201
- const promiseRes = raw(awaited, awaited.callbacks);
202
- values.pop();
203
- return promiseRes;
204
- });
228
+ return string.then(
229
+ (resString) => raw(resString, resString.callbacks)
230
+ );
205
231
  } else {
206
232
  return raw(string);
207
233
  }
208
234
  }
209
235
  };
236
+ globalContexts.push(context);
237
+ return context;
210
238
  };
211
239
  var useContext = (context) => {
212
240
  return context.values[context.values.length - 1];
package/dist/request.js CHANGED
@@ -31,8 +31,9 @@ var HonoRequest = class {
31
31
  this.cachedBody = (key) => {
32
32
  const { bodyCache, raw } = this;
33
33
  const cachedBody = bodyCache[key];
34
- if (cachedBody)
34
+ if (cachedBody) {
35
35
  return cachedBody;
36
+ }
36
37
  if (bodyCache.arrayBuffer) {
37
38
  return (async () => {
38
39
  return await new Response(bodyCache.arrayBuffer)[key]();
@@ -46,21 +47,26 @@ var HonoRequest = class {
46
47
  __privateSet(this, _validatedData, {});
47
48
  }
48
49
  param(key) {
49
- if (key) {
50
- const param = __privateGet(this, _matchResult)[1] ? __privateGet(this, _matchResult)[1][__privateGet(this, _matchResult)[0][this.routeIndex][1][key]] : __privateGet(this, _matchResult)[0][this.routeIndex][1][key];
51
- return param ? /\%/.test(param) ? decodeURIComponent_(param) : param : void 0;
52
- } else {
53
- const decoded = {};
54
- const keys = Object.keys(__privateGet(this, _matchResult)[0][this.routeIndex][1]);
55
- for (let i = 0, len = keys.length; i < len; i++) {
56
- const key2 = keys[i];
57
- const value = __privateGet(this, _matchResult)[1] ? __privateGet(this, _matchResult)[1][__privateGet(this, _matchResult)[0][this.routeIndex][1][key2]] : __privateGet(this, _matchResult)[0][this.routeIndex][1][key2];
58
- if (value && typeof value === "string") {
59
- decoded[key2] = /\%/.test(value) ? decodeURIComponent_(value) : value;
60
- }
50
+ return key ? this.getDecodedParam(key) : this.getAllDecodedParams();
51
+ }
52
+ getDecodedParam(key) {
53
+ const paramKey = __privateGet(this, _matchResult)[0][this.routeIndex][1][key];
54
+ const param = this.getParamValue(paramKey);
55
+ return param ? /\%/.test(param) ? decodeURIComponent_(param) : param : void 0;
56
+ }
57
+ getAllDecodedParams() {
58
+ const decoded = {};
59
+ const keys = Object.keys(__privateGet(this, _matchResult)[0][this.routeIndex][1]);
60
+ for (const key of keys) {
61
+ const value = this.getParamValue(__privateGet(this, _matchResult)[0][this.routeIndex][1][key]);
62
+ if (value && typeof value === "string") {
63
+ decoded[key] = /\%/.test(value) ? decodeURIComponent_(value) : value;
61
64
  }
62
- return decoded;
63
65
  }
66
+ return decoded;
67
+ }
68
+ getParamValue(paramKey) {
69
+ return __privateGet(this, _matchResult)[1] ? __privateGet(this, _matchResult)[1][paramKey] : paramKey;
64
70
  }
65
71
  query(key) {
66
72
  return getQueryParam(this.url, key);
@@ -69,8 +75,9 @@ var HonoRequest = class {
69
75
  return getQueryParams(this.url, key);
70
76
  }
71
77
  header(name) {
72
- if (name)
78
+ if (name) {
73
79
  return this.raw.headers.get(name.toLowerCase()) ?? void 0;
80
+ }
74
81
  const headerData = {};
75
82
  this.raw.headers.forEach((value, key) => {
76
83
  headerData[key] = value;
@@ -79,8 +86,9 @@ var HonoRequest = class {
79
86
  }
80
87
  cookie(key) {
81
88
  const cookie = this.raw.headers.get("Cookie");
82
- if (!cookie)
89
+ if (!cookie) {
83
90
  return;
91
+ }
84
92
  const obj = parse(cookie);
85
93
  if (key) {
86
94
  const value = obj[key];
@@ -90,8 +98,9 @@ var HonoRequest = class {
90
98
  }
91
99
  }
92
100
  async parseBody(options) {
93
- if (this.bodyCache.parsedBody)
101
+ if (this.bodyCache.parsedBody) {
94
102
  return this.bodyCache.parsedBody;
103
+ }
95
104
  const parsedBody = await parseBody(this, options);
96
105
  this.bodyCache.parsedBody = parsedBody;
97
106
  return parsedBody;
@@ -100,8 +100,9 @@ var RegExpRouter = class {
100
100
  if (!middleware || !routes) {
101
101
  throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
102
102
  }
103
- if (methodNames.indexOf(method) === -1)
103
+ if (methodNames.indexOf(method) === -1) {
104
104
  methodNames.push(method);
105
+ }
105
106
  if (!middleware[method]) {
106
107
  ;
107
108
  [middleware, routes].forEach((handlerMap) => {
@@ -28,8 +28,9 @@ var Node = class {
28
28
  parentPatterns.push(...curNode.patterns);
29
29
  curNode = curNode.children[p];
30
30
  const pattern2 = getPattern(p);
31
- if (pattern2)
31
+ if (pattern2) {
32
32
  possibleKeys.push(pattern2[1]);
33
+ }
33
34
  continue;
34
35
  }
35
36
  curNode.children[p] = new Node();
@@ -109,8 +110,9 @@ var Node = class {
109
110
  }
110
111
  continue;
111
112
  }
112
- if (part === "")
113
+ if (part === "") {
113
114
  continue;
115
+ }
114
116
  const [key, name, matcher] = pattern;
115
117
  const child = node.children[key];
116
118
  const restPathString = parts.slice(i).join("/");
@@ -111,4 +111,4 @@ export declare class Factory<E extends Env = any, P extends string = any> {
111
111
  * The API might be changed.
112
112
  */
113
113
  export declare const createFactory: <E extends Env = any, P extends string = any>() => Factory<E, P>;
114
- export declare const createMiddleware: <E extends Env = any, P extends string = any, I extends Input = {}>(middleware: MiddlewareHandler) => MiddlewareHandler<E, P, I>;
114
+ export declare const createMiddleware: <E extends Env = any, P extends string = any, I extends Input = {}>(middleware: MiddlewareHandler<E, P, I>) => MiddlewareHandler<E, P, I>;
@@ -13,12 +13,14 @@ declare global {
13
13
  }
14
14
  }
15
15
  }
16
+ type LocalContexts = [Context<unknown>, unknown][];
16
17
  export type Child = string | Promise<string> | number | JSXNode | Child[];
17
18
  export declare class JSXNode implements HtmlEscaped {
18
19
  tag: string | Function;
19
20
  props: Props;
20
21
  children: Child[];
21
22
  isEscaped: true;
23
+ localContexts?: LocalContexts;
22
24
  constructor(tag: string | Function, props: Props, children: Child[]);
23
25
  toString(): string | Promise<string>;
24
26
  toStringToBuffer(buffer: StringBuffer): void;
@@ -22,6 +22,9 @@ export declare class HonoRequest<P extends string = '/', I extends Input['out']
22
22
  constructor(request: Request, path?: string, matchResult?: Result<[unknown, RouterRoute]>);
23
23
  param<P2 extends string = P>(key: RemoveQuestion<ParamKeys<P2>>): UndefinedIfHavingQuestion<ParamKeys<P2>>;
24
24
  param<P2 extends string = P>(): UnionToIntersection<ParamKeyToRecord<ParamKeys<P2>>>;
25
+ private getDecodedParam;
26
+ private getAllDecodedParams;
27
+ private getParamValue;
25
28
  query(key: string): string | undefined;
26
29
  query(): Record<string, string>;
27
30
  queries(key: string): string[] | undefined;
@@ -1,6 +1,6 @@
1
1
  import type { Context } from './context';
2
2
  import type { Hono } from './hono';
3
- import type { IntersectNonAnyTypes, UnionToIntersection } from './utils/types';
3
+ import type { IntersectNonAnyTypes, RemoveBlankRecord, UnionToIntersection } from './utils/types';
4
4
  export type Bindings = Record<string, unknown>;
5
5
  export type Variables = Record<string, unknown>;
6
6
  export type Env = {
@@ -376,8 +376,27 @@ export type Schema = {
376
376
  };
377
377
  };
378
378
  };
379
- export type MergeSchemaPath<OrigSchema, SubPath extends string> = {
380
- [K in keyof OrigSchema as `${MergePath<SubPath, K & string>}`]: OrigSchema[K];
379
+ type ExtractParams<Path extends string> = string extends Path ? Record<string, string> : Path extends `${infer Start}:${infer Param}/${infer Rest}` ? {
380
+ [K in Param | keyof ExtractParams<`/${Rest}`>]: string;
381
+ } : Path extends `${infer Start}:${infer Param}` ? {
382
+ [K in Param]: string;
383
+ } : never;
384
+ export type MergeSchemaPath<OrigSchema extends Schema, SubPath extends string> = {
385
+ [P in keyof OrigSchema as MergePath<SubPath, P & string>]: {
386
+ [M in keyof OrigSchema[P]]: OrigSchema[P][M] extends {
387
+ input: infer Input;
388
+ output: infer Output;
389
+ } ? {
390
+ input: Input extends {
391
+ param: infer Params;
392
+ } ? {
393
+ param: Params & ExtractParams<SubPath>;
394
+ } : RemoveBlankRecord<ExtractParams<SubPath>> extends never ? Input : Input & {
395
+ param: ExtractParams<SubPath>;
396
+ };
397
+ output: Output;
398
+ } : never;
399
+ };
381
400
  };
382
401
  export type AddParam<I, P extends string> = ParamKeys<P> extends never ? I : I & {
383
402
  param: UnionToIntersection<ParamKeyToRecord<ParamKeys<P>>>;
@@ -14,8 +14,9 @@ var verifySignature = async (base64Signature, value, secret) => {
14
14
  try {
15
15
  const signatureBinStr = atob(base64Signature);
16
16
  const signature = new Uint8Array(signatureBinStr.length);
17
- for (let i = 0; i < signatureBinStr.length; i++)
17
+ for (let i = 0; i < signatureBinStr.length; i++) {
18
18
  signature[i] = signatureBinStr.charCodeAt(i);
19
+ }
19
20
  return await crypto.subtle.verify(algorithm, secret, signature, new TextEncoder().encode(value));
20
21
  } catch (e) {
21
22
  return false;
@@ -28,16 +29,20 @@ var parse = (cookie, name) => {
28
29
  return pairs.reduce((parsedCookie, pairStr) => {
29
30
  pairStr = pairStr.trim();
30
31
  const valueStartPos = pairStr.indexOf("=");
31
- if (valueStartPos === -1)
32
+ if (valueStartPos === -1) {
32
33
  return parsedCookie;
34
+ }
33
35
  const cookieName = pairStr.substring(0, valueStartPos).trim();
34
- if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName))
36
+ if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName)) {
35
37
  return parsedCookie;
38
+ }
36
39
  let cookieValue = pairStr.substring(valueStartPos + 1).trim();
37
- if (cookieValue.startsWith('"') && cookieValue.endsWith('"'))
40
+ if (cookieValue.startsWith('"') && cookieValue.endsWith('"')) {
38
41
  cookieValue = cookieValue.slice(1, -1);
39
- if (validCookieValueRegEx.test(cookieValue))
42
+ }
43
+ if (validCookieValueRegEx.test(cookieValue)) {
40
44
  parsedCookie[cookieName] = decodeURIComponent_(cookieValue);
45
+ }
41
46
  return parsedCookie;
42
47
  }, {});
43
48
  };
@@ -46,12 +51,14 @@ var parseSigned = async (cookie, secret, name) => {
46
51
  const secretKey = await getCryptoKey(secret);
47
52
  for (const [key, value] of Object.entries(parse(cookie, name))) {
48
53
  const signatureStartPos = value.lastIndexOf(".");
49
- if (signatureStartPos < 1)
54
+ if (signatureStartPos < 1) {
50
55
  continue;
56
+ }
51
57
  const signedValue = value.substring(0, signatureStartPos);
52
58
  const signature = value.substring(signatureStartPos + 1);
53
- if (signature.length !== 44 || !signature.endsWith("="))
59
+ if (signature.length !== 44 || !signature.endsWith("=")) {
54
60
  continue;
61
+ }
55
62
  const isVerified = await verifySignature(signature, signedValue, secretKey);
56
63
  parsedCookie[key] = isVerified ? signedValue : false;
57
64
  }
@@ -1,8 +1,9 @@
1
1
  // src/utils/filepath.ts
2
2
  var getFilePath = (options) => {
3
3
  let filename = options.filename;
4
- if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename))
4
+ if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
5
5
  return;
6
+ }
6
7
  let root = options.root || "";
7
8
  const defaultDocument = options.defaultDocument || "index.html";
8
9
  if (filename.endsWith("/")) {
@@ -2,8 +2,9 @@
2
2
  var getMimeType = (filename) => {
3
3
  const regexp = /\.([a-zA-Z0-9]+?)$/;
4
4
  const match = filename.match(regexp);
5
- if (!match)
5
+ if (!match) {
6
6
  return;
7
+ }
7
8
  let mimeType = mimes[match[1]];
8
9
  if (mimeType && mimeType.startsWith("text") || mimeType === "application/json") {
9
10
  mimeType += "; charset=utf-8";
package/dist/utils/url.js CHANGED
@@ -85,8 +85,9 @@ var mergePath = (...paths) => {
85
85
  return p;
86
86
  };
87
87
  var checkOptionalParameter = (path) => {
88
- if (!path.match(/\:.+\?$/))
88
+ if (!path.match(/\:.+\?$/)) {
89
89
  return null;
90
+ }
90
91
  const segments = path.split("/");
91
92
  const results = [];
92
93
  let basePath = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "3.12.7",
3
+ "version": "3.12.9",
4
4
  "description": "Ultrafast web framework for the Edges",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",
@@ -472,7 +472,7 @@
472
472
  ],
473
473
  "devDependencies": {
474
474
  "@cloudflare/workers-types": "^4.20231121.0",
475
- "@hono/eslint-config": "^0.0.3",
475
+ "@hono/eslint-config": "^0.0.4",
476
476
  "@hono/node-server": "^1.3.3",
477
477
  "@types/crypto-js": "^4.1.1",
478
478
  "@types/glob": "^8.0.0",