hono 4.7.10 → 4.8.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 (69) hide show
  1. package/README.md +1 -0
  2. package/dist/adapter/cloudflare-pages/handler.js +2 -1
  3. package/dist/adapter/service-worker/index.js +6 -0
  4. package/dist/cjs/adapter/cloudflare-pages/handler.js +2 -1
  5. package/dist/cjs/adapter/service-worker/index.js +7 -0
  6. package/dist/cjs/context.js +48 -116
  7. package/dist/cjs/helper/route/index.js +69 -0
  8. package/dist/cjs/helper/ssg/ssg.js +47 -8
  9. package/dist/cjs/helper/testing/index.js +2 -2
  10. package/dist/cjs/hono-base.js +3 -2
  11. package/dist/cjs/jsx/components.js +4 -1
  12. package/dist/cjs/jsx/streaming.js +6 -1
  13. package/dist/cjs/middleware/cache/index.js +5 -1
  14. package/dist/cjs/middleware/cors/index.js +12 -2
  15. package/dist/cjs/middleware/etag/index.js +2 -1
  16. package/dist/cjs/middleware/jwk/jwk.js +6 -1
  17. package/dist/cjs/middleware/jwt/jwt.js +2 -1
  18. package/dist/cjs/middleware/logger/index.js +6 -6
  19. package/dist/cjs/request/constants.js +28 -0
  20. package/dist/cjs/request.js +4 -0
  21. package/dist/cjs/router/trie-router/node.js +11 -13
  22. package/dist/cjs/utils/body.js +5 -1
  23. package/dist/cjs/utils/color.js +15 -2
  24. package/dist/cjs/utils/jwt/jwt.js +5 -6
  25. package/dist/cjs/utils/mime.js +1 -0
  26. package/dist/cjs/utils/url.js +5 -2
  27. package/dist/context.js +48 -116
  28. package/dist/helper/route/index.js +43 -0
  29. package/dist/helper/ssg/ssg.js +46 -8
  30. package/dist/helper/testing/index.js +2 -2
  31. package/dist/hono-base.js +3 -2
  32. package/dist/jsx/components.js +4 -1
  33. package/dist/jsx/streaming.js +5 -1
  34. package/dist/middleware/cache/index.js +5 -1
  35. package/dist/middleware/cors/index.js +12 -2
  36. package/dist/middleware/etag/index.js +2 -1
  37. package/dist/middleware/jwk/jwk.js +6 -1
  38. package/dist/middleware/jwt/jwt.js +2 -1
  39. package/dist/middleware/logger/index.js +7 -7
  40. package/dist/request/constants.js +5 -0
  41. package/dist/request.js +4 -0
  42. package/dist/router/trie-router/node.js +11 -13
  43. package/dist/types/adapter/cloudflare-pages/handler.d.ts +1 -0
  44. package/dist/types/adapter/service-worker/handler.d.ts +4 -3
  45. package/dist/types/adapter/service-worker/index.d.ts +23 -1
  46. package/dist/types/context.d.ts +5 -1
  47. package/dist/types/helper/adapter/index.d.ts +1 -1
  48. package/dist/types/helper/route/index.d.ts +67 -0
  49. package/dist/types/helper/ssg/ssg.d.ts +9 -2
  50. package/dist/types/helper/testing/index.d.ts +2 -2
  51. package/dist/types/hono-base.d.ts +10 -0
  52. package/dist/types/jsx/streaming.d.ts +16 -1
  53. package/dist/types/middleware/cache/index.d.ts +3 -0
  54. package/dist/types/middleware/cors/index.d.ts +2 -2
  55. package/dist/types/middleware/jwk/jwk.d.ts +10 -7
  56. package/dist/types/middleware/jwt/jwt.d.ts +3 -0
  57. package/dist/types/request/constants.d.ts +1 -0
  58. package/dist/types/request.d.ts +8 -0
  59. package/dist/types/types.d.ts +1 -0
  60. package/dist/types/utils/color.d.ts +9 -0
  61. package/dist/types/utils/jwt/index.d.ts +1 -1
  62. package/dist/types/utils/jwt/jwt.d.ts +1 -1
  63. package/dist/types/utils/mime.d.ts +1 -0
  64. package/dist/utils/body.js +5 -1
  65. package/dist/utils/color.js +7 -1
  66. package/dist/utils/jwt/jwt.js +5 -6
  67. package/dist/utils/mime.js +1 -0
  68. package/dist/utils/url.js +5 -2
  69. package/package.json +10 -1
@@ -37,8 +37,8 @@ const time = (start) => {
37
37
  const delta = Date.now() - start;
38
38
  return humanize([delta < 1e3 ? delta + "ms" : Math.round(delta / 1e3) + "s"]);
39
39
  };
40
- const colorStatus = (status) => {
41
- const colorEnabled = (0, import_color.getColorEnabled)();
40
+ const colorStatus = async (status) => {
41
+ const colorEnabled = await (0, import_color.getColorEnabledAsync)();
42
42
  if (colorEnabled) {
43
43
  switch (status / 100 | 0) {
44
44
  case 5:
@@ -53,18 +53,18 @@ const colorStatus = (status) => {
53
53
  }
54
54
  return `${status}`;
55
55
  };
56
- function log(fn, prefix, method, path, status = 0, elapsed) {
57
- const out = prefix === "<--" /* Incoming */ ? `${prefix} ${method} ${path}` : `${prefix} ${method} ${path} ${colorStatus(status)} ${elapsed}`;
56
+ async function log(fn, prefix, method, path, status = 0, elapsed) {
57
+ const out = prefix === "<--" /* Incoming */ ? `${prefix} ${method} ${path}` : `${prefix} ${method} ${path} ${await colorStatus(status)} ${elapsed}`;
58
58
  fn(out);
59
59
  }
60
60
  const logger = (fn = console.log) => {
61
61
  return async function logger2(c, next) {
62
62
  const { method, url } = c.req;
63
63
  const path = url.slice(url.indexOf("/", 8));
64
- log(fn, "<--" /* Incoming */, method, path);
64
+ await log(fn, "<--" /* Incoming */, method, path);
65
65
  const start = Date.now();
66
66
  await next();
67
- log(fn, "-->" /* Outgoing */, method, path, c.res.status, time(start));
67
+ await log(fn, "-->" /* Outgoing */, method, path, c.res.status, time(start));
68
68
  };
69
69
  };
70
70
  // Annotate the CommonJS export names for ESM import in node:
@@ -0,0 +1,28 @@
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 constants_exports = {};
20
+ __export(constants_exports, {
21
+ GET_MATCH_RESULT: () => GET_MATCH_RESULT
22
+ });
23
+ module.exports = __toCommonJS(constants_exports);
24
+ const GET_MATCH_RESULT = Symbol();
25
+ // Annotate the CommonJS export names for ESM import in node:
26
+ 0 && (module.exports = {
27
+ GET_MATCH_RESULT
28
+ });
@@ -21,6 +21,7 @@ __export(request_exports, {
21
21
  HonoRequest: () => HonoRequest
22
22
  });
23
23
  module.exports = __toCommonJS(request_exports);
24
+ var import_constants = require("./request/constants");
24
25
  var import_body = require("./utils/body");
25
26
  var import_url = require("./utils/url");
26
27
  const tryDecodeURIComponent = (str) => (0, import_url.tryDecode)(str, import_url.decodeURIComponent_);
@@ -122,6 +123,9 @@ class HonoRequest {
122
123
  get method() {
123
124
  return this.raw.method;
124
125
  }
126
+ get [import_constants.GET_MATCH_RESULT]() {
127
+ return this.#matchResult;
128
+ }
125
129
  get matchedRoutes() {
126
130
  return this.#matchResult[0].map(([[, route]]) => route);
127
131
  }
@@ -50,11 +50,10 @@ class Node {
50
50
  const nextP = parts[i + 1];
51
51
  const pattern = (0, import_url.getPattern)(p, nextP);
52
52
  const key = Array.isArray(pattern) ? pattern[0] : p;
53
- if (Object.keys(curNode.#children).includes(key)) {
53
+ if (key in curNode.#children) {
54
54
  curNode = curNode.#children[key];
55
- const pattern2 = (0, import_url.getPattern)(p, nextP);
56
- if (pattern2) {
57
- possibleKeys.push(pattern2[1]);
55
+ if (pattern) {
56
+ possibleKeys.push(pattern[1]);
58
57
  }
59
58
  continue;
60
59
  }
@@ -65,14 +64,13 @@ class Node {
65
64
  }
66
65
  curNode = curNode.#children[key];
67
66
  }
68
- const m = /* @__PURE__ */ Object.create(null);
69
- const handlerSet = {
70
- handler,
71
- possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i),
72
- score: this.#order
73
- };
74
- m[method] = handlerSet;
75
- curNode.#methods.push(m);
67
+ curNode.#methods.push({
68
+ [method]: {
69
+ handler,
70
+ possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i),
71
+ score: this.#order
72
+ }
73
+ });
76
74
  return curNode;
77
75
  }
78
76
  #getHandlerSets(node, method, nodeParams, params) {
@@ -135,7 +133,7 @@ class Node {
135
133
  }
136
134
  continue;
137
135
  }
138
- if (part === "") {
136
+ if (!part) {
139
137
  continue;
140
138
  }
141
139
  const [key, name, matcher] = pattern;
@@ -68,7 +68,11 @@ const handleParsingAllValues = (form, key, value) => {
68
68
  form[key] = [form[key], value];
69
69
  }
70
70
  } else {
71
- form[key] = value;
71
+ if (!key.endsWith("[]")) {
72
+ form[key] = value;
73
+ } else {
74
+ form[key] = [value];
75
+ }
72
76
  }
73
77
  };
74
78
  const handleParsingNestedValues = (form, key, value) => {
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,10 +17,15 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
18
24
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
25
  var color_exports = {};
20
26
  __export(color_exports, {
21
- getColorEnabled: () => getColorEnabled
27
+ getColorEnabled: () => getColorEnabled,
28
+ getColorEnabledAsync: () => getColorEnabledAsync
22
29
  });
23
30
  module.exports = __toCommonJS(color_exports);
24
31
  function getColorEnabled() {
@@ -26,7 +33,13 @@ function getColorEnabled() {
26
33
  const isNoColor = typeof Deno?.noColor === "boolean" ? Deno.noColor : process !== void 0 ? "NO_COLOR" in process?.env : false;
27
34
  return !isNoColor;
28
35
  }
36
+ async function getColorEnabledAsync() {
37
+ const { navigator } = globalThis;
38
+ const isNoColor = navigator !== void 0 && navigator.userAgent === "Cloudflare-Workers" ? "NO_COLOR" in ((await import("cloudflare:workers")).env ?? {}) : !getColorEnabled();
39
+ return !isNoColor;
40
+ }
29
41
  // Annotate the CommonJS export names for ESM import in node:
30
42
  0 && (module.exports = {
31
- getColorEnabled
43
+ getColorEnabled,
44
+ getColorEnabledAsync
32
45
  });
@@ -94,7 +94,6 @@ const verifyFromJwks = async (token, options, init) => {
94
94
  if (!header.kid) {
95
95
  throw new import_types.JwtHeaderRequiresKid(header);
96
96
  }
97
- let keys = typeof options.keys === "function" ? await options.keys() : options.keys;
98
97
  if (options.jwks_uri) {
99
98
  const response = await fetch(options.jwks_uri, init);
100
99
  if (!response.ok) {
@@ -107,15 +106,15 @@ const verifyFromJwks = async (token, options, init) => {
107
106
  if (!Array.isArray(data.keys)) {
108
107
  throw new Error('invalid JWKS response. "keys" field is not an array');
109
108
  }
110
- if (keys) {
111
- keys.push(...data.keys);
109
+ if (options.keys) {
110
+ options.keys.push(...data.keys);
112
111
  } else {
113
- keys = data.keys;
112
+ options.keys = data.keys;
114
113
  }
115
- } else if (!keys) {
114
+ } else if (!options.keys) {
116
115
  throw new Error('verifyFromJwks requires options for either "keys" or "jwks_uri" or both');
117
116
  }
118
- const matchingKey = keys.find((key) => key.kid === header.kid);
117
+ const matchingKey = options.keys.find((key) => key.kid === header.kid);
119
118
  if (!matchingKey) {
120
119
  throw new import_types.JwtTokenInvalid(token);
121
120
  }
@@ -88,6 +88,7 @@ const _baseMimes = {
88
88
  wasm: "application/wasm",
89
89
  webm: "video/webm",
90
90
  weba: "audio/webm",
91
+ webmanifest: "application/manifest+json",
91
92
  webp: "image/webp",
92
93
  woff: "font/woff",
93
94
  woff2: "font/woff2",
@@ -100,7 +100,10 @@ const tryDecode = (str, decoder) => {
100
100
  const tryDecodeURI = (str) => tryDecode(str, decodeURI);
101
101
  const getPath = (request) => {
102
102
  const url = request.url;
103
- const start = url.indexOf("/", 8);
103
+ const start = url.indexOf(
104
+ "/",
105
+ url.charCodeAt(9) === 58 ? 13 : 8
106
+ );
104
107
  let i = start;
105
108
  for (; i < url.length; i++) {
106
109
  const charCode = url.charCodeAt(i);
@@ -162,7 +165,7 @@ const _decodeURI = (value) => {
162
165
  if (value.indexOf("+") !== -1) {
163
166
  value = value.replace(/\+/g, " ");
164
167
  }
165
- return value.indexOf("%") !== -1 ? decodeURIComponent_(value) : value;
168
+ return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value;
166
169
  };
167
170
  const _getQueryParam = (url, key, multiple) => {
168
171
  let encoded;
package/dist/context.js CHANGED
@@ -2,11 +2,11 @@
2
2
  import { HonoRequest } from "./request.js";
3
3
  import { HtmlEscapedCallbackPhase, resolveCallback } from "./utils/html.js";
4
4
  var TEXT_PLAIN = "text/plain; charset=UTF-8";
5
- var setHeaders = (headers, map = {}) => {
6
- for (const key of Object.keys(map)) {
7
- headers.set(key, map[key]);
8
- }
9
- return headers;
5
+ var setDefaultContentType = (contentType, headers) => {
6
+ return {
7
+ "Content-Type": contentType,
8
+ ...headers
9
+ };
10
10
  };
11
11
  var Context = class {
12
12
  #rawRequest;
@@ -15,15 +15,13 @@ var Context = class {
15
15
  #var;
16
16
  finalized = false;
17
17
  error;
18
- #status = 200;
18
+ #status;
19
19
  #executionCtx;
20
- #headers;
21
- #preparedHeaders;
22
20
  #res;
23
- #isFresh = true;
24
21
  #layout;
25
22
  #renderer;
26
23
  #notFoundHandler;
24
+ #preparedHeaders;
27
25
  #matchResult;
28
26
  #path;
29
27
  constructor(req, options) {
@@ -55,11 +53,11 @@ var Context = class {
55
53
  }
56
54
  }
57
55
  get res() {
58
- this.#isFresh = false;
59
- return this.#res ||= new Response("404 Not Found", { status: 404 });
56
+ return this.#res ||= new Response(null, {
57
+ headers: this.#preparedHeaders ??= new Headers()
58
+ });
60
59
  }
61
60
  set res(_res) {
62
- this.#isFresh = false;
63
61
  if (this.#res && _res) {
64
62
  _res = new Response(_res.body, _res);
65
63
  for (const [k, v] of this.#res.headers.entries()) {
@@ -93,42 +91,16 @@ var Context = class {
93
91
  if (this.finalized) {
94
92
  this.#res = new Response(this.#res.body, this.#res);
95
93
  }
94
+ const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers();
96
95
  if (value === void 0) {
97
- if (this.#headers) {
98
- this.#headers.delete(name);
99
- } else if (this.#preparedHeaders) {
100
- delete this.#preparedHeaders[name.toLocaleLowerCase()];
101
- }
102
- if (this.finalized) {
103
- this.res.headers.delete(name);
104
- }
105
- return;
106
- }
107
- if (options?.append) {
108
- if (!this.#headers) {
109
- this.#isFresh = false;
110
- this.#headers = new Headers(this.#preparedHeaders);
111
- this.#preparedHeaders = {};
112
- }
113
- this.#headers.append(name, value);
96
+ headers.delete(name);
97
+ } else if (options?.append) {
98
+ headers.append(name, value);
114
99
  } else {
115
- if (this.#headers) {
116
- this.#headers.set(name, value);
117
- } else {
118
- this.#preparedHeaders ??= {};
119
- this.#preparedHeaders[name.toLowerCase()] = value;
120
- }
121
- }
122
- if (this.finalized) {
123
- if (options?.append) {
124
- this.res.headers.append(name, value);
125
- } else {
126
- this.res.headers.set(name, value);
127
- }
100
+ headers.set(name, value);
128
101
  }
129
102
  };
130
103
  status = (status) => {
131
- this.#isFresh = false;
132
104
  this.#status = status;
133
105
  };
134
106
  set = (key, value) => {
@@ -145,94 +117,54 @@ var Context = class {
145
117
  return Object.fromEntries(this.#var);
146
118
  }
147
119
  #newResponse(data, arg, headers) {
148
- if (this.#isFresh && !headers && !arg && this.#status === 200) {
149
- return new Response(data, {
150
- headers: this.#preparedHeaders
151
- });
152
- }
153
- if (arg && typeof arg !== "number") {
154
- const header = new Headers(arg.headers);
155
- if (this.#headers) {
156
- this.#headers.forEach((v, k) => {
157
- if (k === "set-cookie") {
158
- header.append(k, v);
159
- } else {
160
- header.set(k, v);
161
- }
162
- });
163
- }
164
- const headers2 = setHeaders(header, this.#preparedHeaders);
165
- return new Response(data, {
166
- headers: headers2,
167
- status: arg.status ?? this.#status
168
- });
169
- }
170
- const status = typeof arg === "number" ? arg : this.#status;
171
- this.#preparedHeaders ??= {};
172
- this.#headers ??= new Headers();
173
- setHeaders(this.#headers, this.#preparedHeaders);
174
- if (this.#res) {
175
- this.#res.headers.forEach((v, k) => {
176
- if (k === "set-cookie") {
177
- this.#headers?.append(k, v);
120
+ const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers();
121
+ if (typeof arg === "object" && "headers" in arg) {
122
+ const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers);
123
+ for (const [key, value] of argHeaders) {
124
+ if (key.toLowerCase() === "set-cookie") {
125
+ responseHeaders.append(key, value);
178
126
  } else {
179
- this.#headers?.set(k, v);
127
+ responseHeaders.set(key, value);
180
128
  }
181
- });
182
- setHeaders(this.#headers, this.#preparedHeaders);
129
+ }
183
130
  }
184
- headers ??= {};
185
- for (const [k, v] of Object.entries(headers)) {
186
- if (typeof v === "string") {
187
- this.#headers.set(k, v);
188
- } else {
189
- this.#headers.delete(k);
190
- for (const v2 of v) {
191
- this.#headers.append(k, v2);
131
+ if (headers) {
132
+ for (const [k, v] of Object.entries(headers)) {
133
+ if (typeof v === "string") {
134
+ responseHeaders.set(k, v);
135
+ } else {
136
+ responseHeaders.delete(k);
137
+ for (const v2 of v) {
138
+ responseHeaders.append(k, v2);
139
+ }
192
140
  }
193
141
  }
194
142
  }
195
- return new Response(data, {
196
- status,
197
- headers: this.#headers
198
- });
143
+ const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
144
+ return new Response(data, { status, headers: responseHeaders });
199
145
  }
200
146
  newResponse = (...args) => this.#newResponse(...args);
201
- body = (data, arg, headers) => {
202
- return typeof arg === "number" ? this.#newResponse(data, arg, headers) : this.#newResponse(data, arg);
203
- };
147
+ body = (data, arg, headers) => this.#newResponse(data, arg, headers);
204
148
  text = (text, arg, headers) => {
205
- if (!this.#preparedHeaders) {
206
- if (this.#isFresh && !headers && !arg) {
207
- return new Response(text);
208
- }
209
- this.#preparedHeaders = {};
210
- }
211
- this.#preparedHeaders["content-type"] = TEXT_PLAIN;
212
- if (typeof arg === "number") {
213
- return this.#newResponse(text, arg, headers);
214
- }
215
- return this.#newResponse(text, arg);
149
+ return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(
150
+ text,
151
+ arg,
152
+ setDefaultContentType(TEXT_PLAIN, headers)
153
+ );
216
154
  };
217
155
  json = (object, arg, headers) => {
218
- const body = JSON.stringify(object);
219
- this.#preparedHeaders ??= {};
220
- this.#preparedHeaders["content-type"] = "application/json";
221
- return typeof arg === "number" ? this.#newResponse(body, arg, headers) : this.#newResponse(body, arg);
156
+ return this.#newResponse(
157
+ JSON.stringify(object),
158
+ arg,
159
+ setDefaultContentType("application/json", headers)
160
+ );
222
161
  };
223
162
  html = (html, arg, headers) => {
224
- this.#preparedHeaders ??= {};
225
- this.#preparedHeaders["content-type"] = "text/html; charset=UTF-8";
226
- if (typeof html === "object") {
227
- return resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then((html2) => {
228
- return typeof arg === "number" ? this.#newResponse(html2, arg, headers) : this.#newResponse(html2, arg);
229
- });
230
- }
231
- return typeof arg === "number" ? this.#newResponse(html, arg, headers) : this.#newResponse(html, arg);
163
+ const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers));
164
+ return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
232
165
  };
233
166
  redirect = (location, status) => {
234
- this.#headers ??= new Headers();
235
- this.#headers.set("Location", String(location));
167
+ this.header("Location", String(location));
236
168
  return this.newResponse(null, status ?? 302);
237
169
  };
238
170
  notFound = () => {
@@ -0,0 +1,43 @@
1
+ // src/helper/route/index.ts
2
+ import { GET_MATCH_RESULT } from "../../request/constants.js";
3
+ import { getPattern, splitRoutingPath } from "../../utils/url.js";
4
+ var matchedRoutes = (c) => c.req[GET_MATCH_RESULT][0].map(([[, route]]) => route);
5
+ var routePath = (c) => matchedRoutes(c)[c.req.routeIndex].path;
6
+ var baseRoutePath = (c) => matchedRoutes(c)[c.req.routeIndex].basePath;
7
+ var basePathCacheMap = /* @__PURE__ */ new WeakMap();
8
+ var basePath = (c) => {
9
+ const routeIndex = c.req.routeIndex;
10
+ const cache = basePathCacheMap.get(c) || [];
11
+ if (typeof cache[routeIndex] === "string") {
12
+ return cache[routeIndex];
13
+ }
14
+ let result;
15
+ const rp = baseRoutePath(c);
16
+ if (!/[:*]/.test(rp)) {
17
+ result = rp;
18
+ } else {
19
+ const paths = splitRoutingPath(rp);
20
+ const reqPath = c.req.path;
21
+ let basePathLength = 0;
22
+ for (let i = 0, len = paths.length; i < len; i++) {
23
+ const pattern = getPattern(paths[i], paths[i + 1]);
24
+ if (pattern) {
25
+ const re = pattern[2] === true || pattern === "*" ? /[^\/]+/ : pattern[2];
26
+ basePathLength += reqPath.substring(basePathLength + 1).match(re)?.[0].length || 0;
27
+ } else {
28
+ basePathLength += paths[i].length;
29
+ }
30
+ basePathLength += 1;
31
+ }
32
+ result = reqPath.substring(0, basePathLength);
33
+ }
34
+ cache[routeIndex] = result;
35
+ basePathCacheMap.set(c, cache);
36
+ return result;
37
+ };
38
+ export {
39
+ basePath,
40
+ baseRoutePath,
41
+ matchedRoutes,
42
+ routePath
43
+ };
@@ -6,6 +6,7 @@ import { SSG_CONTEXT, X_HONO_DISABLE_SSG_HEADER_KEY } from "./middleware.js";
6
6
  import { dirname, filterStaticGenerateRoutes, joinPaths } from "./utils.js";
7
7
  var DEFAULT_CONCURRENCY = 2;
8
8
  var DEFAULT_CONTENT_TYPE = "text/plain";
9
+ var DEFAULT_OUTPUT_DIR = "./static";
9
10
  var generateFilePath = (routePath, outDir, mimeType, extensionMap) => {
10
11
  const extension = determineExtension(mimeType, extensionMap);
11
12
  if (routePath.endsWith(`.${extension}`)) {
@@ -82,13 +83,13 @@ var combineAfterResponseHooks = (hooks) => {
82
83
  return currentRes;
83
84
  };
84
85
  };
85
- var combineAfterGenerateHooks = (hooks) => {
86
+ var combineAfterGenerateHooks = (hooks, fsModule, options) => {
86
87
  if (!Array.isArray(hooks)) {
87
88
  return hooks;
88
89
  }
89
90
  return async (result) => {
90
91
  for (const hook of hooks) {
91
- await hook(result);
92
+ await hook(result, fsModule, options);
92
93
  }
93
94
  };
94
95
  };
@@ -190,14 +191,50 @@ var toSSG = async (app, fs, options) => {
190
191
  let result;
191
192
  const getInfoPromises = [];
192
193
  const savePromises = [];
194
+ const plugins = options?.plugins || [];
195
+ const beforeRequestHooks = [];
196
+ const afterResponseHooks = [];
197
+ const afterGenerateHooks = [];
198
+ if (options?.beforeRequestHook) {
199
+ beforeRequestHooks.push(
200
+ ...Array.isArray(options.beforeRequestHook) ? options.beforeRequestHook : [options.beforeRequestHook]
201
+ );
202
+ }
203
+ if (options?.afterResponseHook) {
204
+ afterResponseHooks.push(
205
+ ...Array.isArray(options.afterResponseHook) ? options.afterResponseHook : [options.afterResponseHook]
206
+ );
207
+ }
208
+ if (options?.afterGenerateHook) {
209
+ afterGenerateHooks.push(
210
+ ...Array.isArray(options.afterGenerateHook) ? options.afterGenerateHook : [options.afterGenerateHook]
211
+ );
212
+ }
213
+ for (const plugin of plugins) {
214
+ if (plugin.beforeRequestHook) {
215
+ beforeRequestHooks.push(
216
+ ...Array.isArray(plugin.beforeRequestHook) ? plugin.beforeRequestHook : [plugin.beforeRequestHook]
217
+ );
218
+ }
219
+ if (plugin.afterResponseHook) {
220
+ afterResponseHooks.push(
221
+ ...Array.isArray(plugin.afterResponseHook) ? plugin.afterResponseHook : [plugin.afterResponseHook]
222
+ );
223
+ }
224
+ if (plugin.afterGenerateHook) {
225
+ afterGenerateHooks.push(
226
+ ...Array.isArray(plugin.afterGenerateHook) ? plugin.afterGenerateHook : [plugin.afterGenerateHook]
227
+ );
228
+ }
229
+ }
193
230
  try {
194
- const outputDir = options?.dir ?? "./static";
231
+ const outputDir = options?.dir ?? DEFAULT_OUTPUT_DIR;
195
232
  const concurrency = options?.concurrency ?? DEFAULT_CONCURRENCY;
196
233
  const combinedBeforeRequestHook = combineBeforeRequestHooks(
197
- options?.beforeRequestHook || ((req) => req)
234
+ beforeRequestHooks.length > 0 ? beforeRequestHooks : [(req) => req]
198
235
  );
199
236
  const combinedAfterResponseHook = combineAfterResponseHooks(
200
- options?.afterResponseHook || ((req) => req)
237
+ afterResponseHooks.length > 0 ? afterResponseHooks : [(req) => req]
201
238
  );
202
239
  const getInfoGen = fetchRoutesContent(
203
240
  app,
@@ -234,13 +271,14 @@ var toSSG = async (app, fs, options) => {
234
271
  const errorObj = error instanceof Error ? error : new Error(String(error));
235
272
  result = { success: false, files: [], error: errorObj };
236
273
  }
237
- if (options?.afterGenerateHook) {
238
- const combinedAfterGenerateHooks = combineAfterGenerateHooks(options?.afterGenerateHook);
239
- await combinedAfterGenerateHooks(result);
274
+ if (afterGenerateHooks.length > 0) {
275
+ const combinedAfterGenerateHooks = combineAfterGenerateHooks(afterGenerateHooks, fs, options);
276
+ await combinedAfterGenerateHooks(result, fs, options);
240
277
  }
241
278
  return result;
242
279
  };
243
280
  export {
281
+ DEFAULT_OUTPUT_DIR,
244
282
  combineAfterGenerateHooks,
245
283
  combineAfterResponseHooks,
246
284
  combineBeforeRequestHooks,
@@ -1,10 +1,10 @@
1
1
  // src/helper/testing/index.ts
2
2
  import { hc } from "../../client/index.js";
3
- var testClient = (app, Env, executionCtx) => {
3
+ var testClient = (app, Env, executionCtx, options) => {
4
4
  const customFetch = (input, init) => {
5
5
  return app.request(input, init, Env, executionCtx);
6
6
  };
7
- return hc("http://localhost", { fetch: customFetch });
7
+ return hc("http://localhost", { ...options, fetch: customFetch });
8
8
  };
9
9
  export {
10
10
  testClient
package/dist/hono-base.js CHANGED
@@ -9,7 +9,8 @@ var notFoundHandler = (c) => {
9
9
  };
10
10
  var errorHandler = (err, c) => {
11
11
  if ("getResponse" in err) {
12
- return err.getResponse();
12
+ const res = err.getResponse();
13
+ return c.newResponse(res.body, res);
13
14
  }
14
15
  console.error(err);
15
16
  return c.text("Internal Server Error", 500);
@@ -158,7 +159,7 @@ var Hono = class {
158
159
  #addRoute(method, path, handler) {
159
160
  method = method.toUpperCase();
160
161
  path = mergePath(this._basePath, path);
161
- const r = { path, method, handler };
162
+ const r = { basePath: this._basePath, path, method, handler };
162
163
  this.router.add(method, path, [handler, r]);
163
164
  this.routes.push(r);
164
165
  }
@@ -2,7 +2,9 @@
2
2
  import { raw } from "../helper/html/index.js";
3
3
  import { HtmlEscapedCallbackPhase, resolveCallback } from "../utils/html.js";
4
4
  import { DOM_RENDERER } from "./constants.js";
5
+ import { useContext } from "./context.js";
5
6
  import { ErrorBoundary as ErrorBoundaryDomRenderer } from "./dom/components.js";
7
+ import { StreamingContext } from "./streaming.js";
6
8
  var errorBoundaryCounter = 0;
7
9
  var childrenToString = async (children) => {
8
10
  try {
@@ -23,6 +25,7 @@ var ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) => {
23
25
  if (!Array.isArray(children)) {
24
26
  children = [children];
25
27
  }
28
+ const nonce = useContext(StreamingContext)?.scriptNonce;
26
29
  let fallbackStr;
27
30
  const fallbackRes = (error) => {
28
31
  onError?.(error);
@@ -79,7 +82,7 @@ d.replaceWith(c.content)
79
82
  }
80
83
  htmlArray = htmlArray.flat();
81
84
  const content = htmlArray.join("");
82
- let html = buffer ? "" : `<template data-hono-target="E:${index}">${content}</template><script>
85
+ let html = buffer ? "" : `<template data-hono-target="E:${index}">${content}</template><script${nonce ? ` nonce="${nonce}"` : ""}>
83
86
  ((d,c) => {
84
87
  c=d.currentScript.previousSibling
85
88
  d=d.getElementById('E:${index}')