hono 3.12.6 → 3.12.8

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.
@@ -62,13 +62,7 @@ var createResult = async (event, res) => {
62
62
  const contentEncoding = res.headers.get("content-encoding");
63
63
  isBase64Encoded = isContentEncodingBinary(contentEncoding);
64
64
  }
65
- let body;
66
- if (isBase64Encoded) {
67
- const buffer = await res.arrayBuffer();
68
- body = encodeBase64(buffer);
69
- } else {
70
- body = await res.text();
71
- }
65
+ const body = isBase64Encoded ? encodeBase64(await res.arrayBuffer()) : await res.text();
72
66
  const result = {
73
67
  body,
74
68
  headers: {},
@@ -93,13 +93,7 @@ const createResult = async (event, res) => {
93
93
  const contentEncoding = res.headers.get("content-encoding");
94
94
  isBase64Encoded = isContentEncodingBinary(contentEncoding);
95
95
  }
96
- let body;
97
- if (isBase64Encoded) {
98
- const buffer = await res.arrayBuffer();
99
- body = (0, import_encode.encodeBase64)(buffer);
100
- } else {
101
- body = await res.text();
102
- }
96
+ const body = isBase64Encoded ? (0, import_encode.encodeBase64)(await res.arrayBuffer()) : await res.text();
103
97
  const result = {
104
98
  body,
105
99
  headers: {},
@@ -43,6 +43,9 @@ const inspectRoutes = (hono) => {
43
43
  });
44
44
  };
45
45
  const showRoutes = (hono, opts) => {
46
+ const { process, Deno } = globalThis;
47
+ const isNoColor = typeof process !== "undefined" ? "NO_COLOR" in process?.env : typeof Deno?.noColor === "boolean" ? Deno.noColor : false;
48
+ const colorEnabled = opts?.colorize ?? !isNoColor;
46
49
  const routeData = {};
47
50
  let maxMethodLength = 0;
48
51
  let maxPathLength = 0;
@@ -60,7 +63,7 @@ const showRoutes = (hono, opts) => {
60
63
  return;
61
64
  }
62
65
  const { method, path, routes } = data;
63
- const methodStr = opts?.colorize ?? true ? `\x1B[32m${method}\x1B[0m` : method;
66
+ const methodStr = colorEnabled ? `\x1B[32m${method}\x1B[0m` : method;
64
67
  console.log(`${methodStr} ${" ".repeat(maxMethodLength - method.length)} ${path}`);
65
68
  if (!opts?.verbose) {
66
69
  return;
@@ -248,27 +248,14 @@ const _Hono = class extends defineDynamicClass() {
248
248
  let res;
249
249
  try {
250
250
  res = matchResult[0][0][0][0](c, async () => {
251
+ c.res = await this.notFoundHandler(c);
251
252
  });
252
- if (!res) {
253
- return this.notFoundHandler(c);
254
- }
255
253
  } catch (err) {
256
254
  return this.handleError(err, c);
257
255
  }
258
- if (res instanceof Response)
259
- return res;
260
- return (async () => {
261
- let awaited;
262
- try {
263
- awaited = await res;
264
- if (!awaited) {
265
- return this.notFoundHandler(c);
266
- }
267
- } catch (err) {
268
- return this.handleError(err, c);
269
- }
270
- return awaited;
271
- })();
256
+ return res instanceof Promise ? res.then(
257
+ (resolved) => resolved || (c.finalized ? c.res : this.notFoundHandler(c))
258
+ ).catch((err) => this.handleError(err, c)) : res;
272
259
  }
273
260
  const composed = (0, import_compose.compose)(matchResult[0], this.errorHandler, this.notFoundHandler);
274
261
  return (async () => {
@@ -51,38 +51,48 @@ const DEFAULT_OPTIONS = {
51
51
  };
52
52
  const secureHeaders = (customOptions) => {
53
53
  const options = { ...DEFAULT_OPTIONS, ...customOptions };
54
- const headersToSet = Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([key, defaultValue]) => {
55
- const overrideValue = options[key];
56
- if (typeof overrideValue === "string")
57
- return [defaultValue[0], overrideValue];
58
- return defaultValue;
59
- });
54
+ const headersToSet = getFilteredHeaders(options);
60
55
  if (options.contentSecurityPolicy) {
61
- const cspDirectives = Object.entries(options.contentSecurityPolicy).map(([directive, value]) => {
62
- directive = directive.replace(
63
- /[A-Z]+(?![a-z])|[A-Z]/g,
64
- (match, offset) => (offset ? "-" : "") + match.toLowerCase()
65
- );
66
- return `${directive} ${Array.isArray(value) ? value.join(" ") : value}`;
67
- }).join("; ");
68
- headersToSet.push(["Content-Security-Policy", cspDirectives]);
56
+ headersToSet.push(["Content-Security-Policy", getCSPDirectives(options.contentSecurityPolicy)]);
69
57
  }
70
58
  if (options.reportingEndpoints) {
71
- const reportingEndpoints = options.reportingEndpoints.map((endpoint) => `${endpoint.name}="${endpoint.url}"`).join(", ");
72
- headersToSet.push(["Reporting-Endpoints", reportingEndpoints]);
59
+ headersToSet.push(["Reporting-Endpoints", getReportingEndpoints(options.reportingEndpoints)]);
73
60
  }
74
61
  if (options.reportTo) {
75
- const reportToOptions = options.reportTo.map((option) => JSON.stringify(option)).join(", ");
76
- headersToSet.push(["Report-To", reportToOptions]);
62
+ headersToSet.push(["Report-To", getReportToOptions(options.reportTo)]);
77
63
  }
78
64
  return async function secureHeaders2(ctx, next) {
79
65
  await next();
80
- headersToSet.forEach(([header, value]) => {
81
- ctx.res.headers.set(header, value);
82
- });
66
+ setHeaders(ctx, headersToSet);
83
67
  ctx.res.headers.delete("X-Powered-By");
84
68
  };
85
69
  };
70
+ function getFilteredHeaders(options) {
71
+ return Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([key, defaultValue]) => {
72
+ const overrideValue = options[key];
73
+ return typeof overrideValue === "string" ? [defaultValue[0], overrideValue] : defaultValue;
74
+ });
75
+ }
76
+ function getCSPDirectives(contentSecurityPolicy) {
77
+ return Object.entries(contentSecurityPolicy || []).map(([directive, value]) => {
78
+ const kebabCaseDirective = directive.replace(
79
+ /[A-Z]+(?![a-z])|[A-Z]/g,
80
+ (match, offset) => offset ? "-" + match.toLowerCase() : match.toLowerCase()
81
+ );
82
+ return `${kebabCaseDirective} ${Array.isArray(value) ? value.join(" ") : value}`;
83
+ }).join("; ");
84
+ }
85
+ function getReportingEndpoints(reportingEndpoints = []) {
86
+ return reportingEndpoints.map((endpoint) => `${endpoint.name}="${endpoint.url}"`).join(", ");
87
+ }
88
+ function getReportToOptions(reportTo = []) {
89
+ return reportTo.map((option) => JSON.stringify(option)).join(", ");
90
+ }
91
+ function setHeaders(ctx, headersToSet) {
92
+ headersToSet.forEach(([header, value]) => {
93
+ ctx.res.headers.set(header, value);
94
+ });
95
+ }
86
96
  // Annotate the CommonJS export names for ESM import in node:
87
97
  0 && (module.exports = {
88
98
  secureHeaders
@@ -67,21 +67,26 @@ class HonoRequest {
67
67
  __privateSet(this, _validatedData, {});
68
68
  }
69
69
  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
- }
70
+ return key ? this.getDecodedParam(key) : this.getAllDecodedParams();
71
+ }
72
+ getDecodedParam(key) {
73
+ const paramKey = __privateGet(this, _matchResult)[0][this.routeIndex][1][key];
74
+ const param = this.getParamValue(paramKey);
75
+ return param ? /\%/.test(param) ? (0, import_url.decodeURIComponent_)(param) : param : void 0;
76
+ }
77
+ getAllDecodedParams() {
78
+ const decoded = {};
79
+ const keys = Object.keys(__privateGet(this, _matchResult)[0][this.routeIndex][1]);
80
+ for (const key of keys) {
81
+ const value = this.getParamValue(__privateGet(this, _matchResult)[0][this.routeIndex][1][key]);
82
+ if (value && typeof value === "string") {
83
+ decoded[key] = /\%/.test(value) ? (0, import_url.decodeURIComponent_)(value) : value;
82
84
  }
83
- return decoded;
84
85
  }
86
+ return decoded;
87
+ }
88
+ getParamValue(paramKey) {
89
+ return __privateGet(this, _matchResult)[1] ? __privateGet(this, _matchResult)[1][paramKey] : paramKey;
85
90
  }
86
91
  query(key) {
87
92
  return (0, import_url.getQueryParam)(this.url, key);
@@ -21,39 +21,55 @@ __export(body_exports, {
21
21
  parseBody: () => parseBody
22
22
  });
23
23
  module.exports = __toCommonJS(body_exports);
24
- const isArrayField = (value) => {
25
- return Array.isArray(value);
26
- };
27
- const parseBody = async (request, options = {
28
- all: false
29
- }) => {
30
- let body = {};
24
+ const parseBody = async (request, options = { all: false }) => {
31
25
  const contentType = request.headers.get("Content-Type");
32
- if (contentType && (contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded"))) {
33
- const formData = await request.formData();
34
- if (formData) {
35
- const form = {};
36
- formData.forEach((value, key) => {
37
- const shouldParseAllValues = options.all || key.slice(-2) === "[]";
38
- if (!shouldParseAllValues) {
39
- form[key] = value;
40
- return;
41
- }
42
- if (form[key] && isArrayField(form[key])) {
43
- ;
44
- form[key].push(value);
45
- return;
46
- }
47
- if (form[key]) {
48
- form[key] = [form[key], value];
49
- return;
50
- }
51
- form[key] = value;
52
- });
53
- body = form;
26
+ if (isFormDataContent(contentType)) {
27
+ return parseFormData(request, options);
28
+ }
29
+ return {};
30
+ };
31
+ function isFormDataContent(contentType) {
32
+ if (contentType === null) {
33
+ return false;
34
+ }
35
+ return contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded");
36
+ }
37
+ async function parseFormData(request, options) {
38
+ const formData = await request.formData();
39
+ if (formData) {
40
+ return convertFormDataToBodyData(formData, options);
41
+ }
42
+ return {};
43
+ }
44
+ function convertFormDataToBodyData(formData, options) {
45
+ const form = {};
46
+ formData.forEach((value, key) => {
47
+ const shouldParseAllValues = options.all || key.endsWith("[]");
48
+ if (!shouldParseAllValues) {
49
+ form[key] = value;
50
+ } else {
51
+ handleParsingAllValues(form, key, value);
54
52
  }
53
+ });
54
+ return form;
55
+ }
56
+ const handleParsingAllValues = (form, key, value) => {
57
+ if (form[key] && isArrayField(form[key])) {
58
+ appendToExistingArray(form[key], value);
59
+ } else if (form[key]) {
60
+ convertToNewArray(form, key, value);
61
+ } else {
62
+ form[key] = value;
55
63
  }
56
- return body;
64
+ };
65
+ function isArrayField(field) {
66
+ return Array.isArray(field);
67
+ }
68
+ const appendToExistingArray = (arr, value) => {
69
+ arr.push(value);
70
+ };
71
+ const convertToNewArray = (form, key, value) => {
72
+ form[key] = [form[key], value];
57
73
  };
58
74
  // Annotate the CommonJS export names for ESM import in node:
59
75
  0 && (module.exports = {
@@ -31,11 +31,7 @@ class StreamingApi {
31
31
  this.responseReadable = new ReadableStream({
32
32
  async pull(controller) {
33
33
  const { done, value } = await reader.read();
34
- if (done) {
35
- controller.close();
36
- } else {
37
- controller.enqueue(value);
38
- }
34
+ done ? controller.close() : controller.enqueue(value);
39
35
  },
40
36
  cancel: () => {
41
37
  this.abortSubscribers.forEach((subscriber) => subscriber());
@@ -38,29 +38,25 @@ const splitPath = (path) => {
38
38
  }
39
39
  return paths;
40
40
  };
41
- const splitRoutingPath = (path) => {
41
+ const splitRoutingPath = (routePath) => {
42
+ const { groups, path } = extractGroupsFromPath(routePath);
43
+ const paths = splitPath(path);
44
+ return replaceGroupMarks(paths, groups);
45
+ };
46
+ const extractGroupsFromPath = (path) => {
42
47
  const groups = [];
43
- for (let i = 0; ; ) {
44
- let replaced = false;
45
- path = path.replace(/\{[^}]+\}/g, (m) => {
46
- const mark = `@\\${i}`;
47
- groups[i] = [mark, m];
48
- i++;
49
- replaced = true;
50
- return mark;
51
- });
52
- if (!replaced) {
53
- break;
54
- }
55
- }
56
- const paths = path.split("/");
57
- if (paths[0] === "") {
58
- paths.shift();
59
- }
48
+ path = path.replace(/\{[^}]+\}/g, (match, index) => {
49
+ const mark = `@${index}`;
50
+ groups.push([mark, match]);
51
+ return mark;
52
+ });
53
+ return { groups, path };
54
+ };
55
+ const replaceGroupMarks = (paths, groups) => {
60
56
  for (let i = groups.length - 1; i >= 0; i--) {
61
57
  const [mark] = groups[i];
62
58
  for (let j = paths.length - 1; j >= 0; j--) {
63
- if (paths[j].indexOf(mark) !== -1) {
59
+ if (paths[j].includes(mark)) {
64
60
  paths[j] = paths[j].replace(mark, groups[i][1]);
65
61
  break;
66
62
  }
@@ -19,6 +19,9 @@ var inspectRoutes = (hono) => {
19
19
  });
20
20
  };
21
21
  var showRoutes = (hono, opts) => {
22
+ const { process, Deno } = globalThis;
23
+ const isNoColor = typeof process !== "undefined" ? "NO_COLOR" in process?.env : typeof Deno?.noColor === "boolean" ? Deno.noColor : false;
24
+ const colorEnabled = opts?.colorize ?? !isNoColor;
22
25
  const routeData = {};
23
26
  let maxMethodLength = 0;
24
27
  let maxPathLength = 0;
@@ -36,7 +39,7 @@ var showRoutes = (hono, opts) => {
36
39
  return;
37
40
  }
38
41
  const { method, path, routes } = data;
39
- const methodStr = opts?.colorize ?? true ? `\x1B[32m${method}\x1B[0m` : method;
42
+ const methodStr = colorEnabled ? `\x1B[32m${method}\x1B[0m` : method;
40
43
  console.log(`${methodStr} ${" ".repeat(maxMethodLength - method.length)} ${path}`);
41
44
  if (!opts?.verbose) {
42
45
  return;
package/dist/hono-base.js CHANGED
@@ -226,27 +226,14 @@ var _Hono = class extends defineDynamicClass() {
226
226
  let res;
227
227
  try {
228
228
  res = matchResult[0][0][0][0](c, async () => {
229
+ c.res = await this.notFoundHandler(c);
229
230
  });
230
- if (!res) {
231
- return this.notFoundHandler(c);
232
- }
233
231
  } catch (err) {
234
232
  return this.handleError(err, c);
235
233
  }
236
- if (res instanceof Response)
237
- return res;
238
- return (async () => {
239
- let awaited;
240
- try {
241
- awaited = await res;
242
- if (!awaited) {
243
- return this.notFoundHandler(c);
244
- }
245
- } catch (err) {
246
- return this.handleError(err, c);
247
- }
248
- return awaited;
249
- })();
234
+ return res instanceof Promise ? res.then(
235
+ (resolved) => resolved || (c.finalized ? c.res : this.notFoundHandler(c))
236
+ ).catch((err) => this.handleError(err, c)) : res;
250
237
  }
251
238
  const composed = compose(matchResult[0], this.errorHandler, this.notFoundHandler);
252
239
  return (async () => {
@@ -29,38 +29,48 @@ var DEFAULT_OPTIONS = {
29
29
  };
30
30
  var secureHeaders = (customOptions) => {
31
31
  const options = { ...DEFAULT_OPTIONS, ...customOptions };
32
- const headersToSet = Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([key, defaultValue]) => {
33
- const overrideValue = options[key];
34
- if (typeof overrideValue === "string")
35
- return [defaultValue[0], overrideValue];
36
- return defaultValue;
37
- });
32
+ const headersToSet = getFilteredHeaders(options);
38
33
  if (options.contentSecurityPolicy) {
39
- const cspDirectives = Object.entries(options.contentSecurityPolicy).map(([directive, value]) => {
40
- directive = directive.replace(
41
- /[A-Z]+(?![a-z])|[A-Z]/g,
42
- (match, offset) => (offset ? "-" : "") + match.toLowerCase()
43
- );
44
- return `${directive} ${Array.isArray(value) ? value.join(" ") : value}`;
45
- }).join("; ");
46
- headersToSet.push(["Content-Security-Policy", cspDirectives]);
34
+ headersToSet.push(["Content-Security-Policy", getCSPDirectives(options.contentSecurityPolicy)]);
47
35
  }
48
36
  if (options.reportingEndpoints) {
49
- const reportingEndpoints = options.reportingEndpoints.map((endpoint) => `${endpoint.name}="${endpoint.url}"`).join(", ");
50
- headersToSet.push(["Reporting-Endpoints", reportingEndpoints]);
37
+ headersToSet.push(["Reporting-Endpoints", getReportingEndpoints(options.reportingEndpoints)]);
51
38
  }
52
39
  if (options.reportTo) {
53
- const reportToOptions = options.reportTo.map((option) => JSON.stringify(option)).join(", ");
54
- headersToSet.push(["Report-To", reportToOptions]);
40
+ headersToSet.push(["Report-To", getReportToOptions(options.reportTo)]);
55
41
  }
56
42
  return async function secureHeaders2(ctx, next) {
57
43
  await next();
58
- headersToSet.forEach(([header, value]) => {
59
- ctx.res.headers.set(header, value);
60
- });
44
+ setHeaders(ctx, headersToSet);
61
45
  ctx.res.headers.delete("X-Powered-By");
62
46
  };
63
47
  };
48
+ function getFilteredHeaders(options) {
49
+ return Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([key, defaultValue]) => {
50
+ const overrideValue = options[key];
51
+ return typeof overrideValue === "string" ? [defaultValue[0], overrideValue] : defaultValue;
52
+ });
53
+ }
54
+ function getCSPDirectives(contentSecurityPolicy) {
55
+ return Object.entries(contentSecurityPolicy || []).map(([directive, value]) => {
56
+ const kebabCaseDirective = directive.replace(
57
+ /[A-Z]+(?![a-z])|[A-Z]/g,
58
+ (match, offset) => offset ? "-" + match.toLowerCase() : match.toLowerCase()
59
+ );
60
+ return `${kebabCaseDirective} ${Array.isArray(value) ? value.join(" ") : value}`;
61
+ }).join("; ");
62
+ }
63
+ function getReportingEndpoints(reportingEndpoints = []) {
64
+ return reportingEndpoints.map((endpoint) => `${endpoint.name}="${endpoint.url}"`).join(", ");
65
+ }
66
+ function getReportToOptions(reportTo = []) {
67
+ return reportTo.map((option) => JSON.stringify(option)).join(", ");
68
+ }
69
+ function setHeaders(ctx, headersToSet) {
70
+ headersToSet.forEach(([header, value]) => {
71
+ ctx.res.headers.set(header, value);
72
+ });
73
+ }
64
74
  export {
65
75
  secureHeaders
66
76
  };
package/dist/request.js CHANGED
@@ -46,21 +46,26 @@ var HonoRequest = class {
46
46
  __privateSet(this, _validatedData, {});
47
47
  }
48
48
  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
- }
49
+ return key ? this.getDecodedParam(key) : this.getAllDecodedParams();
50
+ }
51
+ getDecodedParam(key) {
52
+ const paramKey = __privateGet(this, _matchResult)[0][this.routeIndex][1][key];
53
+ const param = this.getParamValue(paramKey);
54
+ return param ? /\%/.test(param) ? decodeURIComponent_(param) : param : void 0;
55
+ }
56
+ getAllDecodedParams() {
57
+ const decoded = {};
58
+ const keys = Object.keys(__privateGet(this, _matchResult)[0][this.routeIndex][1]);
59
+ for (const key of keys) {
60
+ const value = this.getParamValue(__privateGet(this, _matchResult)[0][this.routeIndex][1][key]);
61
+ if (value && typeof value === "string") {
62
+ decoded[key] = /\%/.test(value) ? decodeURIComponent_(value) : value;
61
63
  }
62
- return decoded;
63
64
  }
65
+ return decoded;
66
+ }
67
+ getParamValue(paramKey) {
68
+ return __privateGet(this, _matchResult)[1] ? __privateGet(this, _matchResult)[1][paramKey] : paramKey;
64
69
  }
65
70
  query(key) {
66
71
  return getQueryParam(this.url, key);
@@ -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>;
@@ -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
  export type Pattern = readonly [string, string, RegExp | true] | '*';
2
2
  export declare const splitPath: (path: string) => string[];
3
- export declare const splitRoutingPath: (path: string) => string[];
3
+ export declare const splitRoutingPath: (routePath: string) => string[];
4
4
  export declare const getPattern: (label: string) => Pattern | null;
5
5
  export declare const getPath: (request: Request) => string;
6
6
  export declare const getQueryStrings: (url: string) => string;
@@ -1,37 +1,53 @@
1
1
  // src/utils/body.ts
2
- var isArrayField = (value) => {
3
- return Array.isArray(value);
4
- };
5
- var parseBody = async (request, options = {
6
- all: false
7
- }) => {
8
- let body = {};
2
+ var parseBody = async (request, options = { all: false }) => {
9
3
  const contentType = request.headers.get("Content-Type");
10
- if (contentType && (contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded"))) {
11
- const formData = await request.formData();
12
- if (formData) {
13
- const form = {};
14
- formData.forEach((value, key) => {
15
- const shouldParseAllValues = options.all || key.slice(-2) === "[]";
16
- if (!shouldParseAllValues) {
17
- form[key] = value;
18
- return;
19
- }
20
- if (form[key] && isArrayField(form[key])) {
21
- ;
22
- form[key].push(value);
23
- return;
24
- }
25
- if (form[key]) {
26
- form[key] = [form[key], value];
27
- return;
28
- }
29
- form[key] = value;
30
- });
31
- body = form;
4
+ if (isFormDataContent(contentType)) {
5
+ return parseFormData(request, options);
6
+ }
7
+ return {};
8
+ };
9
+ function isFormDataContent(contentType) {
10
+ if (contentType === null) {
11
+ return false;
12
+ }
13
+ return contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded");
14
+ }
15
+ async function parseFormData(request, options) {
16
+ const formData = await request.formData();
17
+ if (formData) {
18
+ return convertFormDataToBodyData(formData, options);
19
+ }
20
+ return {};
21
+ }
22
+ function convertFormDataToBodyData(formData, options) {
23
+ const form = {};
24
+ formData.forEach((value, key) => {
25
+ const shouldParseAllValues = options.all || key.endsWith("[]");
26
+ if (!shouldParseAllValues) {
27
+ form[key] = value;
28
+ } else {
29
+ handleParsingAllValues(form, key, value);
32
30
  }
31
+ });
32
+ return form;
33
+ }
34
+ var handleParsingAllValues = (form, key, value) => {
35
+ if (form[key] && isArrayField(form[key])) {
36
+ appendToExistingArray(form[key], value);
37
+ } else if (form[key]) {
38
+ convertToNewArray(form, key, value);
39
+ } else {
40
+ form[key] = value;
33
41
  }
34
- return body;
42
+ };
43
+ function isArrayField(field) {
44
+ return Array.isArray(field);
45
+ }
46
+ var appendToExistingArray = (arr, value) => {
47
+ arr.push(value);
48
+ };
49
+ var convertToNewArray = (form, key, value) => {
50
+ form[key] = [form[key], value];
35
51
  };
36
52
  export {
37
53
  parseBody
@@ -9,11 +9,7 @@ var StreamingApi = class {
9
9
  this.responseReadable = new ReadableStream({
10
10
  async pull(controller) {
11
11
  const { done, value } = await reader.read();
12
- if (done) {
13
- controller.close();
14
- } else {
15
- controller.enqueue(value);
16
- }
12
+ done ? controller.close() : controller.enqueue(value);
17
13
  },
18
14
  cancel: () => {
19
15
  this.abortSubscribers.forEach((subscriber) => subscriber());
package/dist/utils/url.js CHANGED
@@ -6,29 +6,25 @@ var splitPath = (path) => {
6
6
  }
7
7
  return paths;
8
8
  };
9
- var splitRoutingPath = (path) => {
9
+ var splitRoutingPath = (routePath) => {
10
+ const { groups, path } = extractGroupsFromPath(routePath);
11
+ const paths = splitPath(path);
12
+ return replaceGroupMarks(paths, groups);
13
+ };
14
+ var extractGroupsFromPath = (path) => {
10
15
  const groups = [];
11
- for (let i = 0; ; ) {
12
- let replaced = false;
13
- path = path.replace(/\{[^}]+\}/g, (m) => {
14
- const mark = `@\\${i}`;
15
- groups[i] = [mark, m];
16
- i++;
17
- replaced = true;
18
- return mark;
19
- });
20
- if (!replaced) {
21
- break;
22
- }
23
- }
24
- const paths = path.split("/");
25
- if (paths[0] === "") {
26
- paths.shift();
27
- }
16
+ path = path.replace(/\{[^}]+\}/g, (match, index) => {
17
+ const mark = `@${index}`;
18
+ groups.push([mark, match]);
19
+ return mark;
20
+ });
21
+ return { groups, path };
22
+ };
23
+ var replaceGroupMarks = (paths, groups) => {
28
24
  for (let i = groups.length - 1; i >= 0; i--) {
29
25
  const [mark] = groups[i];
30
26
  for (let j = paths.length - 1; j >= 0; j--) {
31
- if (paths[j].indexOf(mark) !== -1) {
27
+ if (paths[j].includes(mark)) {
32
28
  paths[j] = paths[j].replace(mark, groups[i][1]);
33
29
  break;
34
30
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "3.12.6",
3
+ "version": "3.12.8",
4
4
  "description": "Ultrafast web framework for the Edges",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",
@@ -12,14 +12,14 @@
12
12
  "scripts": {
13
13
  "test": "tsc --noEmit && vitest --run",
14
14
  "test:watch": "vitest --watch",
15
- "test:deno": "env NAME=Deno deno test --allow-read --allow-env runtime_tests/deno && deno test --no-lock -c runtime_tests/deno-jsx/deno.precompile.json runtime_tests/deno-jsx && deno test --no-lock -c runtime_tests/deno-jsx/deno.react-jsx.json runtime_tests/deno-jsx",
16
- "test:bun": "env NAME=Bun bun test --jsx-import-source ../../src/jsx runtime_tests/bun/index.test.tsx",
15
+ "test:deno": "deno test --allow-read --allow-env runtime_tests/deno && deno test --no-lock -c runtime_tests/deno-jsx/deno.precompile.json runtime_tests/deno-jsx && deno test --no-lock -c runtime_tests/deno-jsx/deno.react-jsx.json runtime_tests/deno-jsx",
16
+ "test:bun": "bun test --jsx-import-source ../../src/jsx runtime_tests/bun/index.test.tsx",
17
17
  "test:fastly": "vitest --run --config ./runtime_tests/fastly/vitest.config.ts",
18
18
  "test:lagon": "start-server-and-test \"lagon dev runtime_tests/lagon/index.ts -e runtime_tests/lagon/.env.lagon\" http://127.0.0.1:1234 \"yarn vitest --run runtime_tests/lagon/index.test.ts --config runtime_tests/lagon/vitest.config.ts\"",
19
- "test:node": "env NAME=Node vitest --run --config ./runtime_tests/node/vitest.config.ts",
19
+ "test:node": "vitest --run --config ./runtime_tests/node/vitest.config.ts",
20
20
  "test:wrangler": "vitest --run --config ./runtime_tests/wrangler/vitest.config.ts",
21
- "test:lambda": "env NAME=Node vitest --run --config ./runtime_tests/lambda/vitest.config.ts",
22
- "test:lambda-edge": "env NAME=Node vitest --run --config ./runtime_tests/lambda-edge/vitest.config.ts",
21
+ "test:lambda": "vitest --run --config ./runtime_tests/lambda/vitest.config.ts",
22
+ "test:lambda-edge": "vitest --run --config ./runtime_tests/lambda-edge/vitest.config.ts",
23
23
  "test:all": "yarn test && yarn test:deno && yarn test:bun && yarn test:fastly && yarn test:lagon && yarn test:node && yarn test:wrangler && yarn test:lambda && yarn test:lambda-edge",
24
24
  "lint": "eslint --ext js,ts src runtime_tests",
25
25
  "lint:fix": "eslint --ext js,ts src runtime_tests --fix",