hono 3.2.3 → 3.2.5

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.
@@ -1,5 +1,6 @@
1
1
  // src/adapter/aws-lambda/handler.ts
2
2
  import crypto from "crypto";
3
+ import { encodeBase64 } from "../../utils/encode.js";
3
4
  globalThis.crypto = crypto;
4
5
  var handle = (app) => {
5
6
  return async (event) => {
@@ -11,7 +12,13 @@ var handle = (app) => {
11
12
  var createResult = async (res) => {
12
13
  const contentType = res.headers.get("content-type");
13
14
  const isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
14
- const body = isBase64Encoded ? await fromReadableToString(res) : await res.text();
15
+ let body;
16
+ if (isBase64Encoded) {
17
+ const buffer = await res.arrayBuffer();
18
+ body = encodeBase64(buffer);
19
+ } else {
20
+ body = await res.text();
21
+ }
15
22
  const result = {
16
23
  body,
17
24
  headers: {},
@@ -54,15 +61,6 @@ var isProxyEvent = (event) => {
54
61
  var isProxyEventV2 = (event) => {
55
62
  return Object.prototype.hasOwnProperty.call(event, "rawPath");
56
63
  };
57
- var fromReadableToString = async (res) => {
58
- const stream = res.body || new ReadableStream();
59
- const decoder = new TextDecoder();
60
- let string = "";
61
- for await (const chunk of stream) {
62
- string += decoder.decode(chunk);
63
- }
64
- return btoa(string);
65
- };
66
64
  var isContentTypeBinary = (contentType) => {
67
65
  return !/^(text\/(plain|html|css|javascript|csv).*|application\/(.*json|.*xml).*|image\/svg\+xml)$/.test(
68
66
  contentType
@@ -29,6 +29,7 @@ __export(handler_exports, {
29
29
  });
30
30
  module.exports = __toCommonJS(handler_exports);
31
31
  var import_crypto = __toESM(require("crypto"), 1);
32
+ var import_encode = require("../../utils/encode");
32
33
  globalThis.crypto = import_crypto.default;
33
34
  const handle = (app) => {
34
35
  return async (event) => {
@@ -40,7 +41,13 @@ const handle = (app) => {
40
41
  const createResult = async (res) => {
41
42
  const contentType = res.headers.get("content-type");
42
43
  const isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
43
- const body = isBase64Encoded ? await fromReadableToString(res) : await res.text();
44
+ let body;
45
+ if (isBase64Encoded) {
46
+ const buffer = await res.arrayBuffer();
47
+ body = (0, import_encode.encodeBase64)(buffer);
48
+ } else {
49
+ body = await res.text();
50
+ }
44
51
  const result = {
45
52
  body,
46
53
  headers: {},
@@ -83,15 +90,6 @@ const isProxyEvent = (event) => {
83
90
  const isProxyEventV2 = (event) => {
84
91
  return Object.prototype.hasOwnProperty.call(event, "rawPath");
85
92
  };
86
- const fromReadableToString = async (res) => {
87
- const stream = res.body || new ReadableStream();
88
- const decoder = new TextDecoder();
89
- let string = "";
90
- for await (const chunk of stream) {
91
- string += decoder.decode(chunk);
92
- }
93
- return btoa(string);
94
- };
95
93
  const isContentTypeBinary = (contentType) => {
96
94
  return !/^(text\/(plain|html|css|javascript|csv).*|application\/(.*json|.*xml).*|image\/svg\+xml)$/.test(
97
95
  contentType
@@ -176,7 +176,7 @@ class Context {
176
176
  if (options) {
177
177
  this._exCtx = options.executionCtx;
178
178
  this._path = options.path ?? "/";
179
- this._pData = options.paramData;
179
+ this._params = options.params;
180
180
  this.env = options.env;
181
181
  if (options.notFoundHandler) {
182
182
  this.notFoundHandler = options.notFoundHandler;
@@ -187,9 +187,9 @@ class Context {
187
187
  if (this._req) {
188
188
  return this._req;
189
189
  } else {
190
- this._req = new import_request.HonoRequest(this.rawRequest, this._path, this._pData);
190
+ this._req = new import_request.HonoRequest(this.rawRequest, this._path, this._params);
191
191
  this.rawRequest = void 0;
192
- this._pData = void 0;
192
+ this._params = void 0;
193
193
  return this._req;
194
194
  }
195
195
  }
@@ -49,11 +49,15 @@ class Hono extends defineDynamicClass() {
49
49
  this.routes = [];
50
50
  this.notFoundHandler = notFoundHandler;
51
51
  this.errorHandler = errorHandler;
52
+ this.head = () => {
53
+ console.warn("`app.head()` is no longer used. `app.get()` implicitly handles the HEAD method.");
54
+ return this;
55
+ };
52
56
  this.handleEvent = (event) => {
53
- return this.dispatch(event.request, event);
57
+ return this.dispatch(event.request, event, void 0, event.request.method);
54
58
  };
55
59
  this.fetch = (request, Env, executionCtx) => {
56
- return this.dispatch(request, executionCtx, Env);
60
+ return this.dispatch(request, executionCtx, Env, request.method);
57
61
  };
58
62
  this.request = async (input, requestInit) => {
59
63
  if (input instanceof Request) {
@@ -191,7 +195,7 @@ class Hono extends defineDynamicClass() {
191
195
  this.routes.push(r);
192
196
  }
193
197
  matchRoute(method, path) {
194
- return this.router.match(method, path);
198
+ return this.router.match(method, path) || { handlers: [], params: {} };
195
199
  }
196
200
  handleError(err, c) {
197
201
  if (err instanceof Error) {
@@ -199,23 +203,23 @@ class Hono extends defineDynamicClass() {
199
203
  }
200
204
  throw err;
201
205
  }
202
- dispatch(request, eventOrExecutionCtx, env) {
206
+ dispatch(request, executionCtx, env, method) {
203
207
  const path = this.getPath(request);
204
- const method = request.method;
205
- const result = this.matchRoute(method, path);
206
- const paramData = result?.params;
208
+ if (method === "HEAD") {
209
+ return (async () => new Response(null, await this.dispatch(request, executionCtx, env, "GET")))();
210
+ }
211
+ const { handlers, params } = this.matchRoute(method, path);
207
212
  const c = new import_context.Context(request, {
208
213
  env,
209
- executionCtx: eventOrExecutionCtx,
214
+ executionCtx,
210
215
  notFoundHandler: this.notFoundHandler,
211
216
  path,
212
- paramData
217
+ params
213
218
  });
214
- if (result?.handlers.length === 1) {
215
- const handler = result.handlers[0];
219
+ if (handlers.length === 1) {
216
220
  let res;
217
221
  try {
218
- res = handler(c, async () => {
222
+ res = handlers[0](c, async () => {
219
223
  });
220
224
  if (!res) {
221
225
  return this.notFoundHandler(c);
@@ -246,7 +250,6 @@ class Hono extends defineDynamicClass() {
246
250
  return awaited;
247
251
  })();
248
252
  }
249
- const handlers = result ? result.handlers : [this.notFoundHandler];
250
253
  const composed = (0, import_compose.compose)(handlers, this.errorHandler, this.notFoundHandler);
251
254
  return (async () => {
252
255
  try {
@@ -32,8 +32,7 @@ class HTTPException extends Error {
32
32
  return this.res;
33
33
  }
34
34
  return new Response(this.message, {
35
- status: this.status,
36
- statusText: this.message
35
+ status: this.status
37
36
  });
38
37
  }
39
38
  }
@@ -104,19 +104,23 @@ class JSXNode {
104
104
  buffer[0] += `<${tag}`;
105
105
  const propsKeys = Object.keys(props || {});
106
106
  for (let i = 0, len = propsKeys.length; i < len; i++) {
107
- const v = props[propsKeys[i]];
108
- if (typeof v === "string") {
109
- buffer[0] += ` ${propsKeys[i]}="`;
107
+ const key = propsKeys[i];
108
+ const v = props[key];
109
+ if (key === "style" && typeof v === "object") {
110
+ const styles = Object.keys(v).map((k) => `${k}:${v[k]}`).join(";").replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
111
+ buffer[0] += ` style="${styles}"`;
112
+ } else if (typeof v === "string") {
113
+ buffer[0] += ` ${key}="`;
110
114
  (0, import_html.escapeToBuffer)(v, buffer);
111
115
  buffer[0] += '"';
112
116
  } else if (typeof v === "number") {
113
- buffer[0] += ` ${propsKeys[i]}="${v}"`;
117
+ buffer[0] += ` ${key}="${v}"`;
114
118
  } else if (v === null || v === void 0) {
115
- } else if (typeof v === "boolean" && booleanAttributes.includes(propsKeys[i])) {
119
+ } else if (typeof v === "boolean" && booleanAttributes.includes(key)) {
116
120
  if (v) {
117
- buffer[0] += ` ${propsKeys[i]}=""`;
121
+ buffer[0] += ` ${key}=""`;
118
122
  }
119
- } else if (propsKeys[i] === "dangerouslySetInnerHTML") {
123
+ } else if (key === "dangerouslySetInnerHTML") {
120
124
  if (children.length > 0) {
121
125
  throw "Can only set one of `children` or `props.dangerouslySetInnerHTML`.";
122
126
  }
@@ -124,7 +128,7 @@ class JSXNode {
124
128
  escapedString.isEscaped = true;
125
129
  children = [escapedString];
126
130
  } else {
127
- buffer[0] += ` ${propsKeys[i]}="`;
131
+ buffer[0] += ` ${key}="`;
128
132
  (0, import_html.escapeToBuffer)(v.toString(), buffer);
129
133
  buffer[0] += '"';
130
134
  }
@@ -62,21 +62,22 @@ class PatternRouter {
62
62
  }
63
63
  match(method, path) {
64
64
  const handlers = [];
65
- let params = void 0;
65
+ const params = {};
66
66
  for (const [pattern, routeMethod, handler] of this.routes) {
67
+ const isRegExp = pattern.source.charCodeAt(pattern.source.length - 1) === 36;
67
68
  if (routeMethod === import_router.METHOD_NAME_ALL || routeMethod === method) {
68
69
  const match = pattern.exec(path);
69
70
  if (match) {
70
71
  handlers.push(handler);
71
- if (pattern.source.charCodeAt(pattern.source.length - 1) === 36) {
72
- params ?? (params = match.groups || {});
72
+ if (isRegExp) {
73
+ Object.assign(params, match.groups);
73
74
  }
74
75
  }
75
76
  }
76
77
  }
77
78
  return handlers.length ? {
78
79
  handlers,
79
- params: params || {}
80
+ params
80
81
  } : null;
81
82
  }
82
83
  }
@@ -39,18 +39,18 @@ function clearWildcardRegExpCache() {
39
39
  }
40
40
  function buildMatcherFromPreprocessedRoutes(routes) {
41
41
  const trie = new import_trie.Trie();
42
- const handlers = [];
42
+ const handlerData = [];
43
43
  if (routes.length === 0) {
44
44
  return nullMatcher;
45
45
  }
46
- routes = routes.sort(([a], [b]) => a.length - b.length);
46
+ const routesWithStaticPathFlag = routes.map((route) => [!/\*|\/:/.test(route[0]), ...route]).sort(
47
+ ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
48
+ );
47
49
  const staticMap = {};
48
- for (let i = 0, j = -1, len = routes.length; i < len; i++) {
49
- const path = routes[i][0];
50
- let pathErrorCheckOnly = false;
51
- if (!/\*|\/:/.test(path)) {
52
- pathErrorCheckOnly = true;
53
- staticMap[routes[i][0]] = { handlers: routes[i][1], params: emptyParam };
50
+ for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
51
+ const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i];
52
+ if (pathErrorCheckOnly) {
53
+ staticMap[path] = { handlers, params: emptyParam };
54
54
  } else {
55
55
  j++;
56
56
  }
@@ -63,11 +63,11 @@ function buildMatcherFromPreprocessedRoutes(routes) {
63
63
  if (pathErrorCheckOnly) {
64
64
  continue;
65
65
  }
66
- handlers[j] = paramMap.length === 0 ? [{ handlers: routes[i][1], params: emptyParam }, null] : [routes[i][1], paramMap];
66
+ handlerData[j] = paramMap.length === 0 ? [{ handlers, params: emptyParam }, null] : [handlers, paramMap];
67
67
  }
68
68
  const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
69
- for (let i = 0, len = handlers.length; i < len; i++) {
70
- const paramMap = handlers[i][1];
69
+ for (let i = 0, len = handlerData.length; i < len; i++) {
70
+ const paramMap = handlerData[i][1];
71
71
  if (paramMap) {
72
72
  for (let j = 0, len2 = paramMap.length; j < len2; j++) {
73
73
  paramMap[j][1] = paramReplacementMap[paramMap[j][1]];
@@ -76,7 +76,7 @@ function buildMatcherFromPreprocessedRoutes(routes) {
76
76
  }
77
77
  const handlerMap = [];
78
78
  for (const i in indexReplacementMap) {
79
- handlerMap[i] = handlers[indexReplacementMap[i]];
79
+ handlerMap[i] = handlerData[indexReplacementMap[i]];
80
80
  }
81
81
  return [regexp, handlerMap, staticMap];
82
82
  }
@@ -103,7 +103,7 @@ class RegExpRouter {
103
103
  if (!middleware || !routes) {
104
104
  throw new Error("Can not add a route since the matcher is already built.");
105
105
  }
106
- if (!methodNames.includes(method))
106
+ if (methodNames.indexOf(method) === -1)
107
107
  methodNames.push(method);
108
108
  if (!middleware[method]) {
109
109
  ;
@@ -40,7 +40,6 @@ function findParam(node, name) {
40
40
  class Node {
41
41
  constructor(method, handler, children) {
42
42
  this.order = 0;
43
- this.shouldCapture = false;
44
43
  this.children = children || {};
45
44
  this.methods = [];
46
45
  this.name = "";
@@ -72,7 +71,6 @@ class Node {
72
71
  const pattern = (0, import_url.getPattern)(p);
73
72
  if (pattern) {
74
73
  if (typeof pattern === "object") {
75
- this.shouldCapture = true;
76
74
  for (let j = 0, len2 = parentPatterns.length; j < len2; j++) {
77
75
  if (typeof parentPatterns[j] === "object" && parentPatterns[j][1] === pattern[1]) {
78
76
  throw new Error(errorMessage(pattern[1]));
@@ -87,7 +85,6 @@ class Node {
87
85
  }
88
86
  parentPatterns.push(...curNode.patterns);
89
87
  curNode = curNode.children[p];
90
- curNode.shouldCapture = this.shouldCapture;
91
88
  }
92
89
  if (!curNode.methods.length) {
93
90
  curNode.methods = [];
@@ -167,7 +164,7 @@ class Node {
167
164
  if (typeof name === "string" && !matched) {
168
165
  params[name] = part;
169
166
  } else {
170
- if (node.children[part] && node.children[part].shouldCapture) {
167
+ if (node.children[part]) {
171
168
  params[name] = part;
172
169
  }
173
170
  }
@@ -26,7 +26,7 @@ __export(router_exports, {
26
26
  module.exports = __toCommonJS(router_exports);
27
27
  const METHOD_NAME_ALL = "ALL";
28
28
  const METHOD_NAME_ALL_LOWERCASE = "all";
29
- const METHODS = ["get", "post", "put", "delete", "head", "options", "patch"];
29
+ const METHODS = ["get", "post", "put", "delete", "options", "patch"];
30
30
  class UnsupportedPathError extends Error {
31
31
  }
32
32
  // Annotate the CommonJS export names for ESM import in node:
@@ -29,7 +29,11 @@ const decodeBase64Url = (str) => {
29
29
  };
30
30
  const encodeBase64Url = (buf) => encodeBase64(buf).replace(/\/|\+/g, (m) => ({ "/": "_", "+": "-" })[m] ?? m);
31
31
  const encodeBase64 = (buf) => {
32
- const binary = String.fromCharCode(...new Uint8Array(buf));
32
+ let binary = "";
33
+ const bytes = new Uint8Array(buf);
34
+ for (let i = 0; i < bytes.length; i++) {
35
+ binary += String.fromCharCode(bytes[i]);
36
+ }
33
37
  return btoa(binary);
34
38
  };
35
39
  const decodeBase64 = (str) => {
@@ -128,10 +128,10 @@ const _decodeURI = (value) => {
128
128
  if (!/[%+]/.test(value)) {
129
129
  return value;
130
130
  }
131
- if (value.includes("+")) {
131
+ if (value.indexOf("+") !== -1) {
132
132
  value = value.replace(/\+/g, " ");
133
133
  }
134
- return value.includes("%") ? decodeURIComponent_(value) : value;
134
+ return value.indexOf("%") === -1 ? value : decodeURIComponent_(value);
135
135
  };
136
136
  const _getQueryParam = (url, key, multiple) => {
137
137
  let encoded;
package/dist/context.js CHANGED
@@ -154,7 +154,7 @@ var Context = class {
154
154
  if (options) {
155
155
  this._exCtx = options.executionCtx;
156
156
  this._path = options.path ?? "/";
157
- this._pData = options.paramData;
157
+ this._params = options.params;
158
158
  this.env = options.env;
159
159
  if (options.notFoundHandler) {
160
160
  this.notFoundHandler = options.notFoundHandler;
@@ -165,9 +165,9 @@ var Context = class {
165
165
  if (this._req) {
166
166
  return this._req;
167
167
  } else {
168
- this._req = new HonoRequest(this.rawRequest, this._path, this._pData);
168
+ this._req = new HonoRequest(this.rawRequest, this._path, this._params);
169
169
  this.rawRequest = void 0;
170
- this._pData = void 0;
170
+ this._params = void 0;
171
171
  return this._req;
172
172
  }
173
173
  }
package/dist/hono-base.js CHANGED
@@ -27,11 +27,15 @@ var Hono = class extends defineDynamicClass() {
27
27
  this.routes = [];
28
28
  this.notFoundHandler = notFoundHandler;
29
29
  this.errorHandler = errorHandler;
30
+ this.head = () => {
31
+ console.warn("`app.head()` is no longer used. `app.get()` implicitly handles the HEAD method.");
32
+ return this;
33
+ };
30
34
  this.handleEvent = (event) => {
31
- return this.dispatch(event.request, event);
35
+ return this.dispatch(event.request, event, void 0, event.request.method);
32
36
  };
33
37
  this.fetch = (request, Env, executionCtx) => {
34
- return this.dispatch(request, executionCtx, Env);
38
+ return this.dispatch(request, executionCtx, Env, request.method);
35
39
  };
36
40
  this.request = async (input, requestInit) => {
37
41
  if (input instanceof Request) {
@@ -169,7 +173,7 @@ var Hono = class extends defineDynamicClass() {
169
173
  this.routes.push(r);
170
174
  }
171
175
  matchRoute(method, path) {
172
- return this.router.match(method, path);
176
+ return this.router.match(method, path) || { handlers: [], params: {} };
173
177
  }
174
178
  handleError(err, c) {
175
179
  if (err instanceof Error) {
@@ -177,23 +181,23 @@ var Hono = class extends defineDynamicClass() {
177
181
  }
178
182
  throw err;
179
183
  }
180
- dispatch(request, eventOrExecutionCtx, env) {
184
+ dispatch(request, executionCtx, env, method) {
181
185
  const path = this.getPath(request);
182
- const method = request.method;
183
- const result = this.matchRoute(method, path);
184
- const paramData = result?.params;
186
+ if (method === "HEAD") {
187
+ return (async () => new Response(null, await this.dispatch(request, executionCtx, env, "GET")))();
188
+ }
189
+ const { handlers, params } = this.matchRoute(method, path);
185
190
  const c = new Context(request, {
186
191
  env,
187
- executionCtx: eventOrExecutionCtx,
192
+ executionCtx,
188
193
  notFoundHandler: this.notFoundHandler,
189
194
  path,
190
- paramData
195
+ params
191
196
  });
192
- if (result?.handlers.length === 1) {
193
- const handler = result.handlers[0];
197
+ if (handlers.length === 1) {
194
198
  let res;
195
199
  try {
196
- res = handler(c, async () => {
200
+ res = handlers[0](c, async () => {
197
201
  });
198
202
  if (!res) {
199
203
  return this.notFoundHandler(c);
@@ -224,7 +228,6 @@ var Hono = class extends defineDynamicClass() {
224
228
  return awaited;
225
229
  })();
226
230
  }
227
- const handlers = result ? result.handlers : [this.notFoundHandler];
228
231
  const composed = compose(handlers, this.errorHandler, this.notFoundHandler);
229
232
  return (async () => {
230
233
  try {
@@ -10,8 +10,7 @@ var HTTPException = class extends Error {
10
10
  return this.res;
11
11
  }
12
12
  return new Response(this.message, {
13
- status: this.status,
14
- statusText: this.message
13
+ status: this.status
15
14
  });
16
15
  }
17
16
  };
@@ -79,19 +79,23 @@ var JSXNode = class {
79
79
  buffer[0] += `<${tag}`;
80
80
  const propsKeys = Object.keys(props || {});
81
81
  for (let i = 0, len = propsKeys.length; i < len; i++) {
82
- const v = props[propsKeys[i]];
83
- if (typeof v === "string") {
84
- buffer[0] += ` ${propsKeys[i]}="`;
82
+ const key = propsKeys[i];
83
+ const v = props[key];
84
+ if (key === "style" && typeof v === "object") {
85
+ const styles = Object.keys(v).map((k) => `${k}:${v[k]}`).join(";").replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
86
+ buffer[0] += ` style="${styles}"`;
87
+ } else if (typeof v === "string") {
88
+ buffer[0] += ` ${key}="`;
85
89
  escapeToBuffer(v, buffer);
86
90
  buffer[0] += '"';
87
91
  } else if (typeof v === "number") {
88
- buffer[0] += ` ${propsKeys[i]}="${v}"`;
92
+ buffer[0] += ` ${key}="${v}"`;
89
93
  } else if (v === null || v === void 0) {
90
- } else if (typeof v === "boolean" && booleanAttributes.includes(propsKeys[i])) {
94
+ } else if (typeof v === "boolean" && booleanAttributes.includes(key)) {
91
95
  if (v) {
92
- buffer[0] += ` ${propsKeys[i]}=""`;
96
+ buffer[0] += ` ${key}=""`;
93
97
  }
94
- } else if (propsKeys[i] === "dangerouslySetInnerHTML") {
98
+ } else if (key === "dangerouslySetInnerHTML") {
95
99
  if (children.length > 0) {
96
100
  throw "Can only set one of `children` or `props.dangerouslySetInnerHTML`.";
97
101
  }
@@ -99,7 +103,7 @@ var JSXNode = class {
99
103
  escapedString.isEscaped = true;
100
104
  children = [escapedString];
101
105
  } else {
102
- buffer[0] += ` ${propsKeys[i]}="`;
106
+ buffer[0] += ` ${key}="`;
103
107
  escapeToBuffer(v.toString(), buffer);
104
108
  buffer[0] += '"';
105
109
  }
@@ -40,21 +40,22 @@ var PatternRouter = class {
40
40
  }
41
41
  match(method, path) {
42
42
  const handlers = [];
43
- let params = void 0;
43
+ const params = {};
44
44
  for (const [pattern, routeMethod, handler] of this.routes) {
45
+ const isRegExp = pattern.source.charCodeAt(pattern.source.length - 1) === 36;
45
46
  if (routeMethod === METHOD_NAME_ALL || routeMethod === method) {
46
47
  const match = pattern.exec(path);
47
48
  if (match) {
48
49
  handlers.push(handler);
49
- if (pattern.source.charCodeAt(pattern.source.length - 1) === 36) {
50
- params ?? (params = match.groups || {});
50
+ if (isRegExp) {
51
+ Object.assign(params, match.groups);
51
52
  }
52
53
  }
53
54
  }
54
55
  }
55
56
  return handlers.length ? {
56
57
  handlers,
57
- params: params || {}
58
+ params
58
59
  } : null;
59
60
  }
60
61
  };
@@ -17,18 +17,18 @@ function clearWildcardRegExpCache() {
17
17
  }
18
18
  function buildMatcherFromPreprocessedRoutes(routes) {
19
19
  const trie = new Trie();
20
- const handlers = [];
20
+ const handlerData = [];
21
21
  if (routes.length === 0) {
22
22
  return nullMatcher;
23
23
  }
24
- routes = routes.sort(([a], [b]) => a.length - b.length);
24
+ const routesWithStaticPathFlag = routes.map((route) => [!/\*|\/:/.test(route[0]), ...route]).sort(
25
+ ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
26
+ );
25
27
  const staticMap = {};
26
- for (let i = 0, j = -1, len = routes.length; i < len; i++) {
27
- const path = routes[i][0];
28
- let pathErrorCheckOnly = false;
29
- if (!/\*|\/:/.test(path)) {
30
- pathErrorCheckOnly = true;
31
- staticMap[routes[i][0]] = { handlers: routes[i][1], params: emptyParam };
28
+ for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
29
+ const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i];
30
+ if (pathErrorCheckOnly) {
31
+ staticMap[path] = { handlers, params: emptyParam };
32
32
  } else {
33
33
  j++;
34
34
  }
@@ -41,11 +41,11 @@ function buildMatcherFromPreprocessedRoutes(routes) {
41
41
  if (pathErrorCheckOnly) {
42
42
  continue;
43
43
  }
44
- handlers[j] = paramMap.length === 0 ? [{ handlers: routes[i][1], params: emptyParam }, null] : [routes[i][1], paramMap];
44
+ handlerData[j] = paramMap.length === 0 ? [{ handlers, params: emptyParam }, null] : [handlers, paramMap];
45
45
  }
46
46
  const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
47
- for (let i = 0, len = handlers.length; i < len; i++) {
48
- const paramMap = handlers[i][1];
47
+ for (let i = 0, len = handlerData.length; i < len; i++) {
48
+ const paramMap = handlerData[i][1];
49
49
  if (paramMap) {
50
50
  for (let j = 0, len2 = paramMap.length; j < len2; j++) {
51
51
  paramMap[j][1] = paramReplacementMap[paramMap[j][1]];
@@ -54,7 +54,7 @@ function buildMatcherFromPreprocessedRoutes(routes) {
54
54
  }
55
55
  const handlerMap = [];
56
56
  for (const i in indexReplacementMap) {
57
- handlerMap[i] = handlers[indexReplacementMap[i]];
57
+ handlerMap[i] = handlerData[indexReplacementMap[i]];
58
58
  }
59
59
  return [regexp, handlerMap, staticMap];
60
60
  }
@@ -81,7 +81,7 @@ var RegExpRouter = class {
81
81
  if (!middleware || !routes) {
82
82
  throw new Error("Can not add a route since the matcher is already built.");
83
83
  }
84
- if (!methodNames.includes(method))
84
+ if (methodNames.indexOf(method) === -1)
85
85
  methodNames.push(method);
86
86
  if (!middleware[method]) {
87
87
  ;
@@ -18,7 +18,6 @@ function findParam(node, name) {
18
18
  var Node = class {
19
19
  constructor(method, handler, children) {
20
20
  this.order = 0;
21
- this.shouldCapture = false;
22
21
  this.children = children || {};
23
22
  this.methods = [];
24
23
  this.name = "";
@@ -50,7 +49,6 @@ var Node = class {
50
49
  const pattern = getPattern(p);
51
50
  if (pattern) {
52
51
  if (typeof pattern === "object") {
53
- this.shouldCapture = true;
54
52
  for (let j = 0, len2 = parentPatterns.length; j < len2; j++) {
55
53
  if (typeof parentPatterns[j] === "object" && parentPatterns[j][1] === pattern[1]) {
56
54
  throw new Error(errorMessage(pattern[1]));
@@ -65,7 +63,6 @@ var Node = class {
65
63
  }
66
64
  parentPatterns.push(...curNode.patterns);
67
65
  curNode = curNode.children[p];
68
- curNode.shouldCapture = this.shouldCapture;
69
66
  }
70
67
  if (!curNode.methods.length) {
71
68
  curNode.methods = [];
@@ -145,7 +142,7 @@ var Node = class {
145
142
  if (typeof name === "string" && !matched) {
146
143
  params[name] = part;
147
144
  } else {
148
- if (node.children[part] && node.children[part].shouldCapture) {
145
+ if (node.children[part]) {
149
146
  params[name] = part;
150
147
  }
151
148
  }
package/dist/router.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/router.ts
2
2
  var METHOD_NAME_ALL = "ALL";
3
3
  var METHOD_NAME_ALL_LOWERCASE = "all";
4
- var METHODS = ["get", "post", "put", "delete", "head", "options", "patch"];
4
+ var METHODS = ["get", "post", "put", "delete", "options", "patch"];
5
5
  var UnsupportedPathError = class extends Error {
6
6
  };
7
7
  export {
@@ -3,7 +3,7 @@ import type { TypedResponse } from './types';
3
3
  import type { Env, NotFoundHandler, Input } from './types';
4
4
  import type { CookieOptions } from './utils/cookie';
5
5
  import type { StatusCode } from './utils/http-status';
6
- import type { JSONValue } from './utils/types';
6
+ import type { JSONValue, InterfaceToType } from './utils/types';
7
7
  declare type Runtime = 'node' | 'deno' | 'bun' | 'workerd' | 'fastly' | 'edge-light' | 'lagon' | 'other';
8
8
  declare type HeaderRecord = Record<string, string | string[]>;
9
9
  declare type Data = string | ArrayBuffer | ReadableStream;
@@ -36,8 +36,10 @@ interface JSONRespond {
36
36
  <T = JSONValue>(object: T, init?: ResponseInit): Response;
37
37
  }
38
38
  interface JSONTRespond {
39
- <T>(object: T extends JSONValue ? T : JSONValue, status?: StatusCode, headers?: HeaderRecord): TypedResponse<T extends JSONValue ? (JSONValue extends T ? never : T) : never>;
40
- <T>(object: T extends JSONValue ? T : JSONValue, init?: ResponseInit): TypedResponse<T extends JSONValue ? (JSONValue extends T ? never : T) : never>;
39
+ <T>(object: T extends JSONValue ? T : JSONValue, status?: StatusCode, headers?: HeaderRecord): TypedResponse<InterfaceToType<T> extends JSONValue ? JSONValue extends InterfaceToType<T> ? never : T : never>;
40
+ <T>(object: InterfaceToType<T> extends JSONValue ? T : JSONValue, status?: StatusCode, headers?: HeaderRecord): TypedResponse<InterfaceToType<T> extends JSONValue ? JSONValue extends InterfaceToType<T> ? never : T : never>;
41
+ <T>(object: T extends JSONValue ? T : JSONValue, init?: ResponseInit): TypedResponse<InterfaceToType<T> extends JSONValue ? JSONValue extends InterfaceToType<T> ? never : T : never>;
42
+ <T>(object: InterfaceToType<T> extends JSONValue ? T : JSONValue, init?: ResponseInit): TypedResponse<InterfaceToType<T> extends JSONValue ? JSONValue extends InterfaceToType<T> ? never : T : never>;
41
43
  }
42
44
  interface HTMLRespond {
43
45
  (html: string, status?: StatusCode, headers?: HeaderRecord): Response;
@@ -48,7 +50,7 @@ declare type ContextOptions<E extends Env> = {
48
50
  executionCtx?: FetchEvent | ExecutionContext | undefined;
49
51
  notFoundHandler?: NotFoundHandler<E>;
50
52
  path?: string;
51
- paramData?: Record<string, string>;
53
+ params?: Record<string, string>;
52
54
  };
53
55
  export declare class Context<E extends Env = any, P extends string = any, I extends Input = {}> {
54
56
  env: E['Bindings'];
@@ -64,7 +66,7 @@ export declare class Context<E extends Env = any, P extends string = any, I exte
64
66
  private _pH;
65
67
  private _res;
66
68
  private _path;
67
- private _pData?;
69
+ private _params?;
68
70
  private rawRequest?;
69
71
  private notFoundHandler;
70
72
  constructor(req: Request, options?: ContextOptions<E>);
@@ -14,7 +14,6 @@ declare const Hono_base: new <E_1 extends Env = Env, S_1 = {}, BasePath_1 extend
14
14
  post: HandlerInterface<E_1, "post", S_1, BasePath_1>;
15
15
  put: HandlerInterface<E_1, "put", S_1, BasePath_1>;
16
16
  delete: HandlerInterface<E_1, "delete", S_1, BasePath_1>;
17
- head: HandlerInterface<E_1, "head", S_1, BasePath_1>;
18
17
  options: HandlerInterface<E_1, "options", S_1, BasePath_1>;
19
18
  patch: HandlerInterface<E_1, "patch", S_1, BasePath_1>;
20
19
  } & {
@@ -51,6 +50,12 @@ declare class Hono<E extends Env = Env, S = {}, BasePath extends string = '/'> e
51
50
  */
52
51
  mount(path: string, applicationHandler: (request: Request, ...args: any) => Response | Promise<Response>, optionHandler?: (c: Context) => unknown): Hono<E, S, BasePath>;
53
52
  get routerName(): string;
53
+ /**
54
+ * @deprecate
55
+ * `app.head()` is no longer used.
56
+ * `app.get()` implicitly handles the HEAD method.
57
+ */
58
+ head: () => this;
54
59
  private addRoute;
55
60
  private matchRoute;
56
61
  private handleError;
@@ -3,6 +3,9 @@ declare type Props = Record<string, any>;
3
3
  declare global {
4
4
  namespace JSX {
5
5
  type Element = HtmlEscapedString;
6
+ interface ElementChildrenAttribute {
7
+ children: Child;
8
+ }
6
9
  interface IntrinsicElements {
7
10
  [tagName: string]: Props;
8
11
  }
@@ -12,7 +12,6 @@ export declare class Node<T> {
12
12
  order: number;
13
13
  name: string;
14
14
  handlerSetCache: Record<string, HandlerSet<T>[]>;
15
- shouldCapture: boolean;
16
15
  constructor(method?: string, handler?: T, children?: Record<string, Node<T>>);
17
16
  insert(method: string, path: string, handler: T): Node<T>;
18
17
  private gHSets;
@@ -1,6 +1,6 @@
1
1
  export declare const METHOD_NAME_ALL: "ALL";
2
2
  export declare const METHOD_NAME_ALL_LOWERCASE: "all";
3
- export declare const METHODS: readonly ["get", "post", "put", "delete", "head", "options", "patch"];
3
+ export declare const METHODS: readonly ["get", "post", "put", "delete", "options", "patch"];
4
4
  export interface Router<T> {
5
5
  name: string;
6
6
  add(method: string, path: string, handler: T): void;
@@ -9,3 +9,6 @@ export declare type JSONObject = {
9
9
  [key: string]: JSONPrimitive | JSONArray | JSONObject;
10
10
  };
11
11
  export declare type JSONValue = JSONObject | JSONArray | JSONPrimitive;
12
+ export declare type InterfaceToType<T> = T extends Function ? T : {
13
+ [K in keyof T]: InterfaceToType<T[K]>;
14
+ };
@@ -4,7 +4,11 @@ var decodeBase64Url = (str) => {
4
4
  };
5
5
  var encodeBase64Url = (buf) => encodeBase64(buf).replace(/\/|\+/g, (m) => ({ "/": "_", "+": "-" })[m] ?? m);
6
6
  var encodeBase64 = (buf) => {
7
- const binary = String.fromCharCode(...new Uint8Array(buf));
7
+ let binary = "";
8
+ const bytes = new Uint8Array(buf);
9
+ for (let i = 0; i < bytes.length; i++) {
10
+ binary += String.fromCharCode(bytes[i]);
11
+ }
8
12
  return btoa(binary);
9
13
  };
10
14
  var decodeBase64 = (str) => {
package/dist/utils/url.js CHANGED
@@ -97,10 +97,10 @@ var _decodeURI = (value) => {
97
97
  if (!/[%+]/.test(value)) {
98
98
  return value;
99
99
  }
100
- if (value.includes("+")) {
100
+ if (value.indexOf("+") !== -1) {
101
101
  value = value.replace(/\+/g, " ");
102
102
  }
103
- return value.includes("%") ? decodeURIComponent_(value) : value;
103
+ return value.indexOf("%") === -1 ? value : decodeURIComponent_(value);
104
104
  };
105
105
  var _getQueryParam = (url, key, multiple) => {
106
106
  let encoded;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "3.2.3",
3
+ "version": "3.2.5",
4
4
  "description": "Ultrafast web framework for the Edges",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  "scripts": {
13
13
  "test": "jest",
14
14
  "test:deno": "env NAME=Deno deno test --allow-read --allow-env runtime_tests/deno",
15
- "test:bun": "env NAME=Bun bun test --jsx-import-source ../../src/middleware/jsx/jsx-dev-runtime runtime_tests/bun/index.test.tsx",
15
+ "test:bun": "env NAME=Bun bun test --jsx-import-source ../../src/middleware/jsx runtime_tests/bun/index.test.tsx",
16
16
  "test:fastly": "jest --config ./runtime_tests/fastly/jest.config.js",
17
17
  "test:lagon": "start-server-and-test \"lagon dev runtime_tests/lagon/index.ts\" http://127.0.0.1:1234 \"yarn jest runtime_tests/lagon/index.test.ts --testMatch '**/*.test.ts'\"",
18
18
  "test:node": "env NAME=Node jest --config ./runtime_tests/node/jest.config.js",