hono 4.13.6 → 4.13.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.
package/README.md CHANGED
@@ -64,7 +64,7 @@ Contributions Welcome! You can contribute in the following ways.
64
64
 
65
65
  - Create an Issue - Propose a new feature. Report a bug.
66
66
  - Pull Request - Fix a bug or typo. Refactor the code.
67
- - Create third-party middleware - See instructions below.
67
+ - Create third-party middleware - See [Third-party middleware](docs/CONTRIBUTING.md#third-party-middleware).
68
68
  - Share - Share your thoughts on the Blog, X, and others.
69
69
  - Make your application - Please try to use Hono.
70
70
 
@@ -1,4 +1,5 @@
1
1
  // src/adapter/aws-lambda/handler.ts
2
+ import { pipeline } from "node:stream/promises";
2
3
  import { decodeBase64, encodeBase64 } from "../../utils/encode.js";
3
4
  function sanitizeHeaderValue(value) {
4
5
  const hasNonAscii = /[^\x00-\x7F]/.test(value);
@@ -10,14 +11,14 @@ function sanitizeHeaderValue(value) {
10
11
  var getRequestContext = (event) => {
11
12
  return event.requestContext;
12
13
  };
13
- var streamToNodeStream = async (reader, writer) => {
14
+ async function* readWebStream(reader) {
14
15
  let readResult = await reader.read();
15
16
  while (!readResult.done) {
16
- writer.write(readResult.value);
17
+ yield readResult.value;
17
18
  readResult = await reader.read();
18
19
  }
19
- writer.end();
20
- };
20
+ }
21
+ var streamToNodeStream = (reader, writer) => pipeline(readWebStream(reader), writer);
21
22
  var streamHandle = (app) => {
22
23
  return awslambda.streamifyResponse(
23
24
  async (event, responseStream, context) => {
@@ -29,6 +29,7 @@ __export(handler_exports, {
29
29
  streamHandle: () => streamHandle
30
30
  });
31
31
  module.exports = __toCommonJS(handler_exports);
32
+ var import_promises = require("node:stream/promises");
32
33
  var import_encode = require("../../utils/encode");
33
34
  function sanitizeHeaderValue(value) {
34
35
  const hasNonAscii = /[^\x00-\x7F]/.test(value);
@@ -40,14 +41,14 @@ function sanitizeHeaderValue(value) {
40
41
  const getRequestContext = (event) => {
41
42
  return event.requestContext;
42
43
  };
43
- const streamToNodeStream = async (reader, writer) => {
44
+ async function* readWebStream(reader) {
44
45
  let readResult = await reader.read();
45
46
  while (!readResult.done) {
46
- writer.write(readResult.value);
47
+ yield readResult.value;
47
48
  readResult = await reader.read();
48
49
  }
49
- writer.end();
50
- };
50
+ }
51
+ const streamToNodeStream = (reader, writer) => (0, import_promises.pipeline)(readWebStream(reader), writer);
51
52
  const streamHandle = (app) => {
52
53
  return awslambda.streamifyResponse(
53
54
  async (event, responseStream, context) => {
@@ -424,7 +424,7 @@ class Context {
424
424
  const locationString = String(location);
425
425
  this.header(
426
426
  "Location",
427
- // Multibyes should be encoded
427
+ // Multibytes should be encoded
428
428
  // eslint-disable-next-line no-control-regex
429
429
  !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString)
430
430
  );
@@ -47,7 +47,7 @@ const getSpecificity = (type) => {
47
47
  };
48
48
  const defaultMatch = (accepts2, config) => {
49
49
  const { supports, default: defaultSupport } = config;
50
- const sortedAccepts = accepts2.slice().sort((a, b) => {
50
+ const sortedAccepts = accepts2.filter((accept) => accept.q > 0).sort((a, b) => {
51
51
  if (b.q !== a.q) {
52
52
  return b.q - a.q;
53
53
  }
@@ -33,11 +33,14 @@ __export(base_exports, {
33
33
  booleanAttributes: () => booleanAttributes,
34
34
  cloneElement: () => cloneElement,
35
35
  getNameSpaceContext: () => getNameSpaceContext,
36
+ isUntrustedObject: () => isUntrustedObject,
36
37
  isValidElement: () => isValidElement,
37
38
  jsx: () => jsx,
38
39
  jsxFn: () => jsxFn,
39
40
  memo: () => memo,
40
41
  reactAPICompatVersion: () => reactAPICompatVersion,
42
+ renderChildren: () => renderChildren,
43
+ renderUntrustedObject: () => renderUntrustedObject,
41
44
  shallowEqual: () => shallowEqual
42
45
  });
43
46
  module.exports = __toCommonJS(base_exports);
@@ -101,7 +104,7 @@ const booleanAttributes = [
101
104
  "selected"
102
105
  ];
103
106
  const resolveFunctionComponentResult = (result, suspendedContext) => result.then((resolved) => {
104
- if (!Array.isArray(resolved) && !(resolved instanceof JSXNode)) {
107
+ if (typeof resolved !== "string" && !Array.isArray(resolved) && !(resolved instanceof JSXNode)) {
105
108
  return resolved;
106
109
  }
107
110
  const children = Array.isArray(resolved) ? resolved : [resolved];
@@ -139,6 +142,17 @@ const childrenToStringToBuffer = (children, buffer) => {
139
142
  }
140
143
  }
141
144
  };
145
+ const renderChildren = (children) => (0, import_context.runWithRenderContext)(() => {
146
+ const buffer = [""];
147
+ childrenToStringToBuffer(children, buffer);
148
+ return buffer.length === 1 ? (0, import_html.raw)(buffer[0], buffer.callbacks) : (0, import_html2.stringBufferToString)(buffer, buffer.callbacks);
149
+ });
150
+ const isUntrustedObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof JSXNode) && !(value instanceof Promise) && !value.isEscaped && typeof value.toString === "function";
151
+ const renderUntrustedObject = (value) => {
152
+ const stringified = value.toString();
153
+ const escape = (result) => renderChildren([String(result)]);
154
+ return stringified instanceof Promise ? stringified.then(escape) : escape(stringified);
155
+ };
142
156
  class JSXNode {
143
157
  tag;
144
158
  props;
@@ -369,10 +383,13 @@ const reactAPICompatVersion = "19.0.0-hono-jsx";
369
383
  booleanAttributes,
370
384
  cloneElement,
371
385
  getNameSpaceContext,
386
+ isUntrustedObject,
372
387
  isValidElement,
373
388
  jsx,
374
389
  jsxFn,
375
390
  memo,
376
391
  reactAPICompatVersion,
392
+ renderChildren,
393
+ renderUntrustedObject,
377
394
  shallowEqual
378
395
  });
@@ -31,7 +31,7 @@ var import_streaming = require("./streaming");
31
31
  let errorBoundaryCounter = 0;
32
32
  const childrenToString = async (children) => {
33
33
  try {
34
- return children.flat().map((c) => c == null || typeof c === "boolean" ? "" : c.toString());
34
+ return children.flat().map(resolveChildEarly);
35
35
  } catch (e) {
36
36
  if (e instanceof Promise) {
37
37
  const resume = (0, import_context.captureRenderContext)();
@@ -42,18 +42,16 @@ const childrenToString = async (children) => {
42
42
  }
43
43
  }
44
44
  };
45
- const resolveChildEarly = (c) => {
46
- if (c == null || typeof c === "boolean") {
45
+ const resolveChildEarly = (child) => {
46
+ if (child == null || typeof child === "boolean") {
47
47
  return "";
48
- } else if (typeof c === "string") {
49
- return c;
48
+ } else if (typeof child === "string" || Array.isArray(child)) {
49
+ return (0, import_base.renderChildren)([child]);
50
+ } else if ((0, import_base.isUntrustedObject)(child)) {
51
+ return (0, import_base.renderUntrustedObject)(child);
50
52
  } else {
51
- const str = c.toString();
52
- if (!(str instanceof Promise)) {
53
- return (0, import_html.raw)(str);
54
- } else {
55
- return str;
56
- }
53
+ const str = child.toString();
54
+ return str instanceof Promise ? str : (0, import_html.raw)(str);
57
55
  }
58
56
  };
59
57
  const ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) => {
@@ -69,26 +67,27 @@ const ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) =>
69
67
  let fallbackStrPromise;
70
68
  const resolveFallbackStr = () => fallbackStrPromise ||= (async () => {
71
69
  const awaitedFallback = await fallback;
72
- if (typeof awaitedFallback === "string") {
73
- return awaitedFallback;
74
- } else {
75
- const fallbackResult = await getResume()(() => awaitedFallback?.toString());
76
- if (typeof fallbackResult === "string") {
77
- return (0, import_html.raw)(
78
- fallbackResult,
79
- fallbackResult.callbacks || awaitedFallback?.callbacks
80
- );
81
- }
70
+ if (awaitedFallback === null || awaitedFallback === void 0) {
71
+ return;
72
+ }
73
+ if (typeof awaitedFallback === "string" || Array.isArray(awaitedFallback)) {
74
+ return getResume()(() => (0, import_base.renderChildren)([awaitedFallback]));
75
+ }
76
+ if ((0, import_base.isUntrustedObject)(awaitedFallback)) {
77
+ return getResume()(() => (0, import_base.renderUntrustedObject)(awaitedFallback));
82
78
  }
79
+ const fallbackResult = await getResume()(() => awaitedFallback.toString());
80
+ return (0, import_html.raw)(
81
+ fallbackResult,
82
+ fallbackResult.callbacks || awaitedFallback.callbacks
83
+ );
83
84
  })();
84
85
  const renderFallback = async (error) => {
85
86
  const fallbackStr = await resolveFallbackStr();
86
87
  return getResume()(async () => {
87
88
  onError?.(error);
88
89
  const fallbackRes = fallbackStr !== void 0 ? fallbackStr : fallbackRender && (0, import_base.jsx)(import_base.Fragment, {}, fallbackRender(error)) || "";
89
- const fallbackResString = await (0, import_base.Fragment)({
90
- children: fallbackRes
91
- }).toString();
90
+ const fallbackResString = await (0, import_base.Fragment)({ children: fallbackRes }).toString();
92
91
  return (0, import_html.raw)(
93
92
  fallbackResString,
94
93
  fallbackResString.callbacks || fallbackRes.callbacks
@@ -121,7 +120,7 @@ const ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) =>
121
120
  const fallbackResString = await renderFallback(error2);
122
121
  const fallbackCallbacks = fallbackResString.callbacks;
123
122
  if (buffer) {
124
- buffer[0] = buffer[0].replace(replaceRe, fallbackResString);
123
+ buffer[0] = buffer[0].replace(replaceRe, () => fallbackResString);
125
124
  return fallbackCallbacks?.length ? (0, import_html.raw)("", fallbackCallbacks) : "";
126
125
  }
127
126
  return (0, import_html.raw)(
@@ -160,7 +159,7 @@ d.parentElement.insertBefore(c.content,d.nextSibling)
160
159
  </script>`;
161
160
  if (htmlArray.every((html2) => !html2.callbacks?.length)) {
162
161
  if (buffer) {
163
- buffer[0] = buffer[0].replace(replaceRe, content);
162
+ buffer[0] = buffer[0].replace(replaceRe, () => content);
164
163
  }
165
164
  return html;
166
165
  }
@@ -155,18 +155,18 @@ const createContext = (defaultValue) => {
155
155
  const context = ((props) => {
156
156
  const contextValues = getContextValuesIn(getCurrentStore(), context);
157
157
  contextValues.push(props.value);
158
- let string;
158
+ let rendered;
159
159
  try {
160
- string = props.children ? (Array.isArray(props.children) ? new import_base.JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
160
+ rendered = typeof props.children === "string" ? (0, import_base.renderChildren)([props.children]) : (0, import_base.isUntrustedObject)(props.children) ? (0, import_base.renderUntrustedObject)(props.children) : props.children ? (Array.isArray(props.children) ? new import_base.JSXFragmentNode("", {}, props.children) : props.children).toString() : (0, import_html.raw)("");
161
161
  } catch (e) {
162
162
  contextValues.pop();
163
163
  throw e;
164
164
  }
165
- if (string instanceof Promise) {
166
- return string.finally(() => contextValues.pop()).then((resString) => (0, import_html.raw)(resString, resString.callbacks));
165
+ if (rendered instanceof Promise) {
166
+ return rendered.finally(() => contextValues.pop()).then((resString) => (0, import_html.raw)(resString, resString.callbacks));
167
167
  } else {
168
168
  contextValues.pop();
169
- return (0, import_html.raw)(string);
169
+ return (0, import_html.raw)(rendered);
170
170
  }
171
171
  });
172
172
  context.values = values;
@@ -355,6 +355,17 @@ const applyNodeObject = (node, container, isNew) => {
355
355
  }
356
356
  };
357
357
  const isSameContext = (oldContexts, newContexts) => !!(oldContexts && oldContexts.length === newContexts.length && oldContexts.every((ctx, i) => ctx[1] === newContexts[i][1]));
358
+ const indexChildrenByKey = (children) => {
359
+ const index = /* @__PURE__ */ new Map();
360
+ for (const child of children) {
361
+ const key = child.key;
362
+ if (index.has(key)) {
363
+ return;
364
+ }
365
+ index.set(key, child);
366
+ }
367
+ return index;
368
+ };
358
369
  const fallbackUpdateFnArrayMap = /* @__PURE__ */ new WeakMap();
359
370
  const build = (context, node, children) => {
360
371
  const buildWithPreviousChildren = !children && node.pC;
@@ -368,9 +379,11 @@ const build = (context, node, children) => {
368
379
  foundErrorHandler = children[0][import_constants.DOM_ERROR_HANDLER];
369
380
  context[5].push([context, foundErrorHandler, node]);
370
381
  }
371
- const oldVChildren = buildWithPreviousChildren ? [...node.pC] : node.vC ? [...node.vC] : void 0;
382
+ let oldVChildren = buildWithPreviousChildren ? [...node.pC] : node.vC ? [...node.vC] : void 0;
372
383
  const vChildren = [];
373
384
  let prevNode;
385
+ let scanBudget = (oldVChildren?.length || 0) * 2;
386
+ let oldChildrenByKey;
374
387
  for (let i = 0; i < children.length; i++) {
375
388
  if (Array.isArray(children[i])) {
376
389
  children.splice(i, 1, ...children[i].flat(Infinity));
@@ -389,13 +402,35 @@ const build = (context, node, children) => {
389
402
  }
390
403
  }
391
404
  let oldChild;
392
- if (oldVChildren && oldVChildren.length) {
393
- const i2 = oldVChildren.findIndex(
394
- isNodeString(child) ? (c) => isNodeString(c) : child.key !== void 0 ? (c) => c.key === child.key && c.tag === child.tag : (c) => c.tag === child.tag
395
- );
396
- if (i2 !== -1) {
397
- oldChild = oldVChildren[i2];
398
- oldVChildren.splice(i2, 1);
405
+ if (oldChildrenByKey && child.key === void 0 && !isNodeString(child)) {
406
+ oldVChildren = [...oldChildrenByKey.values()];
407
+ oldChildrenByKey = void 0;
408
+ }
409
+ if (oldChildrenByKey) {
410
+ const key = child.key;
411
+ const candidate = oldChildrenByKey.get(key);
412
+ if (candidate && (isNodeString(child) ? isNodeString(candidate) : candidate.tag === child.tag && candidate.key === key)) {
413
+ oldChild = candidate;
414
+ oldChildrenByKey.delete(key);
415
+ }
416
+ } else if (oldVChildren && oldVChildren.length) {
417
+ const first = oldVChildren[0];
418
+ const isMatchFirst = isNodeString(child) ? isNodeString(first) : !isNodeString(first) && (child.key !== void 0 ? first.key === child.key && first.tag === child.tag : first.tag === child.tag);
419
+ if (isMatchFirst) {
420
+ oldChild = oldVChildren.shift();
421
+ } else {
422
+ const i2 = oldVChildren.findIndex(
423
+ isNodeString(child) ? (c) => isNodeString(c) : child.key !== void 0 ? (c) => c.key === child.key && c.tag === child.tag : (c) => c.tag === child.tag
424
+ );
425
+ scanBudget -= i2 === -1 ? oldVChildren.length : i2;
426
+ if (i2 !== -1) {
427
+ oldChild = oldVChildren[i2];
428
+ oldVChildren.splice(i2, 1);
429
+ }
430
+ if (scanBudget < 0) {
431
+ scanBudget = Infinity;
432
+ oldChildrenByKey = indexChildrenByKey(oldVChildren);
433
+ }
399
434
  }
400
435
  }
401
436
  if (oldChild) {
@@ -441,6 +476,7 @@ const build = (context, node, children) => {
441
476
  prevNode = child;
442
477
  }
443
478
  }
479
+ oldVChildren = oldChildrenByKey ? [...oldChildrenByKey.values()] : oldVChildren;
444
480
  node.vR = buildWithPreviousChildren ? [...node.vC, ...oldVChildren || []] : oldVChildren || [];
445
481
  node.vC = vChildren;
446
482
  if (buildWithPreviousChildren) {
@@ -33,13 +33,16 @@ __export(server_exports, {
33
33
  version: () => import__.default
34
34
  });
35
35
  module.exports = __toCommonJS(server_exports);
36
+ var import_base = require("../base");
36
37
  var import_streaming = require("../streaming");
37
38
  var import__ = __toESM(require("./"), 1);
39
+ const prepareRoot = (element) => typeof element === "string" || Array.isArray(element) ? (0, import_base.renderChildren)([element]) : element;
38
40
  const renderToString = (element, options = {}) => {
39
41
  if (Object.keys(options).length > 0) {
40
42
  console.warn("options are not supported yet");
41
43
  }
42
- const res = element?.toString() ?? "";
44
+ element = prepareRoot(element);
45
+ const res = element instanceof Promise ? element : element?.toString() ?? "";
43
46
  if (typeof res !== "string") {
44
47
  throw new Error("Async component is not supported in renderToString");
45
48
  }
@@ -49,6 +52,7 @@ const renderToReadableStream = async (element, options = {}) => {
49
52
  if (Object.keys(options).some((key) => key !== "onError")) {
50
53
  console.warn("options are not supported yet, except onError");
51
54
  }
55
+ element = prepareRoot(element);
52
56
  if (!element || typeof element !== "object") {
53
57
  element = element?.toString() ?? "";
54
58
  }
@@ -85,10 +85,10 @@ const insertIntoHead = (tagName, tag, props, precedence) => ({ buffer, context }
85
85
  insertTags.forEach((tag2) => {
86
86
  buffer[0] = buffer[0].replaceAll(tag2, "");
87
87
  });
88
- buffer[0] = buffer[0].replace(/(?=<\/head>)/, insertTags.join(""));
88
+ buffer[0] = buffer[0].replace(/(?=<\/head>)/, () => insertTags.join(""));
89
89
  }
90
90
  };
91
- const returnWithoutSpecialBehavior = (tag, children, props) => (0, import_html.raw)(new import_base.JSXNode(tag, props, (0, import_children.toArray)(children ?? [])).toString());
91
+ const returnWithoutSpecialBehavior = (tag, children, props) => (0, import_base.renderChildren)([new import_base.JSXNode(tag, props, (0, import_children.toArray)(children ?? []))]);
92
92
  const documentMetadataTag = (tag, children, props, sort) => {
93
93
  if ("itemProp" in props) {
94
94
  return returnWithoutSpecialBehavior(tag, children, props);
@@ -32,6 +32,7 @@ var import_components2 = require("./dom/components");
32
32
  var import_render = require("./dom/render");
33
33
  const StreamingContext = (0, import_context.createContext)(null);
34
34
  let suspenseCounter = 0;
35
+ const serializeBoundaryChild = (child) => typeof child === "string" || Array.isArray(child) ? (0, import_base.renderChildren)([child]) : child == null || typeof child === "boolean" ? "" : (0, import_base.isUntrustedObject)(child) ? (0, import_base.renderUntrustedObject)(child) : child.toString();
35
36
  const Suspense = async ({
36
37
  children,
37
38
  fallback
@@ -48,9 +49,7 @@ const Suspense = async ({
48
49
  try {
49
50
  stackNode[import_constants.DOM_STASH][0] = 0;
50
51
  import_render.buildDataStack.push([[], stackNode]);
51
- resArray = children.map(
52
- (c) => c == null || typeof c === "boolean" ? "" : c.toString()
53
- );
52
+ resArray = children.map(serializeBoundaryChild);
54
53
  } catch (e) {
55
54
  if (e instanceof Promise) {
56
55
  const resume = (0, import_context.captureRenderContext)();
@@ -71,7 +70,7 @@ const Suspense = async ({
71
70
  }
72
71
  if (resArray.some((res) => res instanceof Promise)) {
73
72
  const index = suspenseCounter++;
74
- const fallbackStr = await fallback.toString();
73
+ const fallbackStr = await (typeof fallback === "string" || Array.isArray(fallback) ? (0, import_base.renderChildren)([fallback]) : (0, import_base.isUntrustedObject)(fallback) ? (0, import_base.renderUntrustedObject)(fallback) : fallback.toString());
75
74
  return (0, import_html.raw)(`<template id="H:${index}"></template>${fallbackStr}<!--/$-->`, [
76
75
  ...fallbackStr.callbacks || [],
77
76
  ({ phase, buffer, context }) => {
@@ -84,7 +83,7 @@ const Suspense = async ({
84
83
  if (buffer) {
85
84
  buffer[0] = buffer[0].replace(
86
85
  new RegExp(`<template id="H:${index}"></template>.*?<!--/\\$-->`),
87
- content
86
+ () => content
88
87
  );
89
88
  }
90
89
  let html = buffer ? "" : `<template data-hono-target="H:${index}">${content}</template><script${nonce ? ` nonce="${nonce}"` : ""}>
@@ -101,7 +101,10 @@ function detectFromHeader(c, options) {
101
101
  return void 0;
102
102
  }
103
103
  const languages = parseAcceptLanguage(acceptLanguage);
104
- for (const { lang } of languages) {
104
+ for (const { lang, q } of languages) {
105
+ if (q === 0) {
106
+ continue;
107
+ }
105
108
  const normalizedLang = normalizeLanguage(lang, options);
106
109
  if (normalizedLang) {
107
110
  return normalizedLang;
@@ -116,7 +116,10 @@ class HonoRequest {
116
116
  if (anyCachedKey === "json") {
117
117
  body = JSON.stringify(body);
118
118
  }
119
- return new Response(body)[key]();
119
+ const contentType = anyCachedKey === "formData" ? void 0 : raw.headers.get("content-type");
120
+ return new Response(body, {
121
+ headers: contentType ? { "Content-Type": contentType } : void 0
122
+ })[key]();
120
123
  });
121
124
  }
122
125
  return bodyCache[key] = raw[key]();
@@ -201,7 +201,7 @@ const parseAccept = (acceptHeader) => {
201
201
  ;
202
202
  [i, accept] = getNextAcceptValue(acceptHeader, i);
203
203
  if (accept) {
204
- accept.q = parseQuality(accept.params.q);
204
+ accept.q = parseQuality(accept.params.q ?? accept.params.Q);
205
205
  values.push(accept);
206
206
  if (lastAccept && lastAccept.q < accept.q) {
207
207
  requiresSort = true;
@@ -225,16 +225,13 @@ const parseQuality = (qVal) => {
225
225
  return 0;
226
226
  }
227
227
  const num = Number(qVal);
228
- if (num === Infinity) {
228
+ if (Number.isNaN(num)) {
229
229
  return 1;
230
230
  }
231
- if (num === -Infinity) {
231
+ if (num < 0) {
232
232
  return 0;
233
233
  }
234
- if (Number.isNaN(num)) {
235
- return 1;
236
- }
237
- if (num < 0 || num > 1) {
234
+ if (num > 1) {
238
235
  return 1;
239
236
  }
240
237
  return num;
package/dist/context.js CHANGED
@@ -402,7 +402,7 @@ var Context = class {
402
402
  const locationString = String(location);
403
403
  this.header(
404
404
  "Location",
405
- // Multibyes should be encoded
405
+ // Multibytes should be encoded
406
406
  // eslint-disable-next-line no-control-regex
407
407
  !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString)
408
408
  );
@@ -25,7 +25,7 @@ var getSpecificity = (type) => {
25
25
  };
26
26
  var defaultMatch = (accepts2, config) => {
27
27
  const { supports, default: defaultSupport } = config;
28
- const sortedAccepts = accepts2.slice().sort((a, b) => {
28
+ const sortedAccepts = accepts2.filter((accept) => accept.q > 0).sort((a, b) => {
29
29
  if (b.q !== a.q) {
30
30
  return b.q - a.q;
31
31
  }
package/dist/jsx/base.js CHANGED
@@ -70,7 +70,7 @@ var booleanAttributes = [
70
70
  "selected"
71
71
  ];
72
72
  var resolveFunctionComponentResult = (result, suspendedContext) => result.then((resolved) => {
73
- if (!Array.isArray(resolved) && !(resolved instanceof JSXNode)) {
73
+ if (typeof resolved !== "string" && !Array.isArray(resolved) && !(resolved instanceof JSXNode)) {
74
74
  return resolved;
75
75
  }
76
76
  const children = Array.isArray(resolved) ? resolved : [resolved];
@@ -108,6 +108,17 @@ var childrenToStringToBuffer = (children, buffer) => {
108
108
  }
109
109
  }
110
110
  };
111
+ var renderChildren = (children) => runWithRenderContext(() => {
112
+ const buffer = [""];
113
+ childrenToStringToBuffer(children, buffer);
114
+ return buffer.length === 1 ? raw(buffer[0], buffer.callbacks) : stringBufferToString(buffer, buffer.callbacks);
115
+ });
116
+ var isUntrustedObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof JSXNode) && !(value instanceof Promise) && !value.isEscaped && typeof value.toString === "function";
117
+ var renderUntrustedObject = (value) => {
118
+ const stringified = value.toString();
119
+ const escape = (result) => renderChildren([String(result)]);
120
+ return stringified instanceof Promise ? stringified.then(escape) : escape(stringified);
121
+ };
111
122
  var JSXNode = class {
112
123
  tag;
113
124
  props;
@@ -337,10 +348,13 @@ export {
337
348
  booleanAttributes,
338
349
  cloneElement,
339
350
  getNameSpaceContext,
351
+ isUntrustedObject,
340
352
  isValidElement,
341
353
  jsx,
342
354
  jsxFn,
343
355
  memo,
344
356
  reactAPICompatVersion,
357
+ renderChildren,
358
+ renderUntrustedObject,
345
359
  shallowEqual
346
360
  };
@@ -1,7 +1,7 @@
1
1
  // src/jsx/components.ts
2
2
  import { raw } from "../helper/html/index.js";
3
3
  import { HtmlEscapedCallbackPhase, resolveCallback } from "../utils/html.js";
4
- import { jsx, Fragment } from "./base.js";
4
+ import { jsx, Fragment, isUntrustedObject, renderChildren, renderUntrustedObject } from "./base.js";
5
5
  import { DOM_RENDERER } from "./constants.js";
6
6
  import { captureRenderContext, useContext } from "./context.js";
7
7
  import { ErrorBoundary as ErrorBoundaryDomRenderer } from "./dom/components.js";
@@ -9,7 +9,7 @@ import { StreamingContext } from "./streaming.js";
9
9
  var errorBoundaryCounter = 0;
10
10
  var childrenToString = async (children) => {
11
11
  try {
12
- return children.flat().map((c) => c == null || typeof c === "boolean" ? "" : c.toString());
12
+ return children.flat().map(resolveChildEarly);
13
13
  } catch (e) {
14
14
  if (e instanceof Promise) {
15
15
  const resume = captureRenderContext();
@@ -20,18 +20,16 @@ var childrenToString = async (children) => {
20
20
  }
21
21
  }
22
22
  };
23
- var resolveChildEarly = (c) => {
24
- if (c == null || typeof c === "boolean") {
23
+ var resolveChildEarly = (child) => {
24
+ if (child == null || typeof child === "boolean") {
25
25
  return "";
26
- } else if (typeof c === "string") {
27
- return c;
26
+ } else if (typeof child === "string" || Array.isArray(child)) {
27
+ return renderChildren([child]);
28
+ } else if (isUntrustedObject(child)) {
29
+ return renderUntrustedObject(child);
28
30
  } else {
29
- const str = c.toString();
30
- if (!(str instanceof Promise)) {
31
- return raw(str);
32
- } else {
33
- return str;
34
- }
31
+ const str = child.toString();
32
+ return str instanceof Promise ? str : raw(str);
35
33
  }
36
34
  };
37
35
  var ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) => {
@@ -47,26 +45,27 @@ var ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) => {
47
45
  let fallbackStrPromise;
48
46
  const resolveFallbackStr = () => fallbackStrPromise ||= (async () => {
49
47
  const awaitedFallback = await fallback;
50
- if (typeof awaitedFallback === "string") {
51
- return awaitedFallback;
52
- } else {
53
- const fallbackResult = await getResume()(() => awaitedFallback?.toString());
54
- if (typeof fallbackResult === "string") {
55
- return raw(
56
- fallbackResult,
57
- fallbackResult.callbacks || awaitedFallback?.callbacks
58
- );
59
- }
48
+ if (awaitedFallback === null || awaitedFallback === void 0) {
49
+ return;
50
+ }
51
+ if (typeof awaitedFallback === "string" || Array.isArray(awaitedFallback)) {
52
+ return getResume()(() => renderChildren([awaitedFallback]));
53
+ }
54
+ if (isUntrustedObject(awaitedFallback)) {
55
+ return getResume()(() => renderUntrustedObject(awaitedFallback));
60
56
  }
57
+ const fallbackResult = await getResume()(() => awaitedFallback.toString());
58
+ return raw(
59
+ fallbackResult,
60
+ fallbackResult.callbacks || awaitedFallback.callbacks
61
+ );
61
62
  })();
62
63
  const renderFallback = async (error) => {
63
64
  const fallbackStr = await resolveFallbackStr();
64
65
  return getResume()(async () => {
65
66
  onError?.(error);
66
67
  const fallbackRes = fallbackStr !== void 0 ? fallbackStr : fallbackRender && jsx(Fragment, {}, fallbackRender(error)) || "";
67
- const fallbackResString = await Fragment({
68
- children: fallbackRes
69
- }).toString();
68
+ const fallbackResString = await Fragment({ children: fallbackRes }).toString();
70
69
  return raw(
71
70
  fallbackResString,
72
71
  fallbackResString.callbacks || fallbackRes.callbacks
@@ -99,7 +98,7 @@ var ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) => {
99
98
  const fallbackResString = await renderFallback(error2);
100
99
  const fallbackCallbacks = fallbackResString.callbacks;
101
100
  if (buffer) {
102
- buffer[0] = buffer[0].replace(replaceRe, fallbackResString);
101
+ buffer[0] = buffer[0].replace(replaceRe, () => fallbackResString);
103
102
  return fallbackCallbacks?.length ? raw("", fallbackCallbacks) : "";
104
103
  }
105
104
  return raw(
@@ -138,7 +137,7 @@ d.parentElement.insertBefore(c.content,d.nextSibling)
138
137
  </script>`;
139
138
  if (htmlArray.every((html2) => !html2.callbacks?.length)) {
140
139
  if (buffer) {
141
- buffer[0] = buffer[0].replace(replaceRe, content);
140
+ buffer[0] = buffer[0].replace(replaceRe, () => content);
142
141
  }
143
142
  return html;
144
143
  }
@@ -1,6 +1,6 @@
1
1
  // src/jsx/context.ts
2
2
  import { raw } from "../helper/html/index.js";
3
- import { JSXFragmentNode } from "./base.js";
3
+ import { isUntrustedObject, JSXFragmentNode, renderChildren, renderUntrustedObject } from "./base.js";
4
4
  import { DOM_RENDERER } from "./constants.js";
5
5
  import { createContextProviderFunction } from "./dom/context.js";
6
6
  var globalContexts = [];
@@ -130,18 +130,18 @@ var createContext = (defaultValue) => {
130
130
  const context = ((props) => {
131
131
  const contextValues = getContextValuesIn(getCurrentStore(), context);
132
132
  contextValues.push(props.value);
133
- let string;
133
+ let rendered;
134
134
  try {
135
- string = props.children ? (Array.isArray(props.children) ? new JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
135
+ rendered = typeof props.children === "string" ? renderChildren([props.children]) : isUntrustedObject(props.children) ? renderUntrustedObject(props.children) : props.children ? (Array.isArray(props.children) ? new JSXFragmentNode("", {}, props.children) : props.children).toString() : raw("");
136
136
  } catch (e) {
137
137
  contextValues.pop();
138
138
  throw e;
139
139
  }
140
- if (string instanceof Promise) {
141
- return string.finally(() => contextValues.pop()).then((resString) => raw(resString, resString.callbacks));
140
+ if (rendered instanceof Promise) {
141
+ return rendered.finally(() => contextValues.pop()).then((resString) => raw(resString, resString.callbacks));
142
142
  } else {
143
143
  contextValues.pop();
144
- return raw(string);
144
+ return raw(rendered);
145
145
  }
146
146
  });
147
147
  context.values = values;
@@ -332,6 +332,17 @@ var applyNodeObject = (node, container, isNew) => {
332
332
  }
333
333
  };
334
334
  var isSameContext = (oldContexts, newContexts) => !!(oldContexts && oldContexts.length === newContexts.length && oldContexts.every((ctx, i) => ctx[1] === newContexts[i][1]));
335
+ var indexChildrenByKey = (children) => {
336
+ const index = /* @__PURE__ */ new Map();
337
+ for (const child of children) {
338
+ const key = child.key;
339
+ if (index.has(key)) {
340
+ return;
341
+ }
342
+ index.set(key, child);
343
+ }
344
+ return index;
345
+ };
335
346
  var fallbackUpdateFnArrayMap = /* @__PURE__ */ new WeakMap();
336
347
  var build = (context, node, children) => {
337
348
  const buildWithPreviousChildren = !children && node.pC;
@@ -345,9 +356,11 @@ var build = (context, node, children) => {
345
356
  foundErrorHandler = children[0][DOM_ERROR_HANDLER];
346
357
  context[5].push([context, foundErrorHandler, node]);
347
358
  }
348
- const oldVChildren = buildWithPreviousChildren ? [...node.pC] : node.vC ? [...node.vC] : void 0;
359
+ let oldVChildren = buildWithPreviousChildren ? [...node.pC] : node.vC ? [...node.vC] : void 0;
349
360
  const vChildren = [];
350
361
  let prevNode;
362
+ let scanBudget = (oldVChildren?.length || 0) * 2;
363
+ let oldChildrenByKey;
351
364
  for (let i = 0; i < children.length; i++) {
352
365
  if (Array.isArray(children[i])) {
353
366
  children.splice(i, 1, ...children[i].flat(Infinity));
@@ -366,13 +379,35 @@ var build = (context, node, children) => {
366
379
  }
367
380
  }
368
381
  let oldChild;
369
- if (oldVChildren && oldVChildren.length) {
370
- const i2 = oldVChildren.findIndex(
371
- isNodeString(child) ? (c) => isNodeString(c) : child.key !== void 0 ? (c) => c.key === child.key && c.tag === child.tag : (c) => c.tag === child.tag
372
- );
373
- if (i2 !== -1) {
374
- oldChild = oldVChildren[i2];
375
- oldVChildren.splice(i2, 1);
382
+ if (oldChildrenByKey && child.key === void 0 && !isNodeString(child)) {
383
+ oldVChildren = [...oldChildrenByKey.values()];
384
+ oldChildrenByKey = void 0;
385
+ }
386
+ if (oldChildrenByKey) {
387
+ const key = child.key;
388
+ const candidate = oldChildrenByKey.get(key);
389
+ if (candidate && (isNodeString(child) ? isNodeString(candidate) : candidate.tag === child.tag && candidate.key === key)) {
390
+ oldChild = candidate;
391
+ oldChildrenByKey.delete(key);
392
+ }
393
+ } else if (oldVChildren && oldVChildren.length) {
394
+ const first = oldVChildren[0];
395
+ const isMatchFirst = isNodeString(child) ? isNodeString(first) : !isNodeString(first) && (child.key !== void 0 ? first.key === child.key && first.tag === child.tag : first.tag === child.tag);
396
+ if (isMatchFirst) {
397
+ oldChild = oldVChildren.shift();
398
+ } else {
399
+ const i2 = oldVChildren.findIndex(
400
+ isNodeString(child) ? (c) => isNodeString(c) : child.key !== void 0 ? (c) => c.key === child.key && c.tag === child.tag : (c) => c.tag === child.tag
401
+ );
402
+ scanBudget -= i2 === -1 ? oldVChildren.length : i2;
403
+ if (i2 !== -1) {
404
+ oldChild = oldVChildren[i2];
405
+ oldVChildren.splice(i2, 1);
406
+ }
407
+ if (scanBudget < 0) {
408
+ scanBudget = Infinity;
409
+ oldChildrenByKey = indexChildrenByKey(oldVChildren);
410
+ }
376
411
  }
377
412
  }
378
413
  if (oldChild) {
@@ -418,6 +453,7 @@ var build = (context, node, children) => {
418
453
  prevNode = child;
419
454
  }
420
455
  }
456
+ oldVChildren = oldChildrenByKey ? [...oldChildrenByKey.values()] : oldVChildren;
421
457
  node.vR = buildWithPreviousChildren ? [...node.vC, ...oldVChildren || []] : oldVChildren || [];
422
458
  node.vC = vChildren;
423
459
  if (buildWithPreviousChildren) {
@@ -1,11 +1,14 @@
1
1
  // src/jsx/dom/server.ts
2
+ import { renderChildren } from "../base.js";
2
3
  import { renderToReadableStream as renderToReadableStreamHono } from "../streaming.js";
3
4
  import version from "./index.js";
5
+ var prepareRoot = (element) => typeof element === "string" || Array.isArray(element) ? renderChildren([element]) : element;
4
6
  var renderToString = (element, options = {}) => {
5
7
  if (Object.keys(options).length > 0) {
6
8
  console.warn("options are not supported yet");
7
9
  }
8
- const res = element?.toString() ?? "";
10
+ element = prepareRoot(element);
11
+ const res = element instanceof Promise ? element : element?.toString() ?? "";
9
12
  if (typeof res !== "string") {
10
13
  throw new Error("Async component is not supported in renderToString");
11
14
  }
@@ -15,6 +18,7 @@ var renderToReadableStream = async (element, options = {}) => {
15
18
  if (Object.keys(options).some((key) => key !== "onError")) {
16
19
  console.warn("options are not supported yet, except onError");
17
20
  }
21
+ element = prepareRoot(element);
18
22
  if (!element || typeof element !== "object") {
19
23
  element = element?.toString() ?? "";
20
24
  }
@@ -1,6 +1,6 @@
1
1
  // src/jsx/intrinsic-element/components.ts
2
2
  import { raw } from "../../helper/html/index.js";
3
- import { JSXNode, getNameSpaceContext } from "../base.js";
3
+ import { JSXNode, getNameSpaceContext, renderChildren } from "../base.js";
4
4
  import { toArray } from "../children.js";
5
5
  import { PERMALINK } from "../constants.js";
6
6
  import { useContext } from "../context.js";
@@ -62,10 +62,10 @@ var insertIntoHead = (tagName, tag, props, precedence) => ({ buffer, context })
62
62
  insertTags.forEach((tag2) => {
63
63
  buffer[0] = buffer[0].replaceAll(tag2, "");
64
64
  });
65
- buffer[0] = buffer[0].replace(/(?=<\/head>)/, insertTags.join(""));
65
+ buffer[0] = buffer[0].replace(/(?=<\/head>)/, () => insertTags.join(""));
66
66
  }
67
67
  };
68
- var returnWithoutSpecialBehavior = (tag, children, props) => raw(new JSXNode(tag, props, toArray(children ?? [])).toString());
68
+ var returnWithoutSpecialBehavior = (tag, children, props) => renderChildren([new JSXNode(tag, props, toArray(children ?? []))]);
69
69
  var documentMetadataTag = (tag, children, props, sort) => {
70
70
  if ("itemProp" in props) {
71
71
  return returnWithoutSpecialBehavior(tag, children, props);
@@ -1,7 +1,7 @@
1
1
  // src/jsx/streaming.ts
2
2
  import { raw } from "../helper/html/index.js";
3
3
  import { HtmlEscapedCallbackPhase, resolveCallback } from "../utils/html.js";
4
- import { JSXNode } from "./base.js";
4
+ import { isUntrustedObject, JSXNode, renderChildren, renderUntrustedObject } from "./base.js";
5
5
  import { childrenToString } from "./components.js";
6
6
  import { DOM_RENDERER, DOM_STASH } from "./constants.js";
7
7
  import { captureRenderContext, createContext, useContext } from "./context.js";
@@ -9,6 +9,7 @@ import { Suspense as SuspenseDomRenderer } from "./dom/components.js";
9
9
  import { buildDataStack } from "./dom/render.js";
10
10
  var StreamingContext = createContext(null);
11
11
  var suspenseCounter = 0;
12
+ var serializeBoundaryChild = (child) => typeof child === "string" || Array.isArray(child) ? renderChildren([child]) : child == null || typeof child === "boolean" ? "" : isUntrustedObject(child) ? renderUntrustedObject(child) : child.toString();
12
13
  var Suspense = async ({
13
14
  children,
14
15
  fallback
@@ -25,9 +26,7 @@ var Suspense = async ({
25
26
  try {
26
27
  stackNode[DOM_STASH][0] = 0;
27
28
  buildDataStack.push([[], stackNode]);
28
- resArray = children.map(
29
- (c) => c == null || typeof c === "boolean" ? "" : c.toString()
30
- );
29
+ resArray = children.map(serializeBoundaryChild);
31
30
  } catch (e) {
32
31
  if (e instanceof Promise) {
33
32
  const resume = captureRenderContext();
@@ -48,7 +47,7 @@ var Suspense = async ({
48
47
  }
49
48
  if (resArray.some((res) => res instanceof Promise)) {
50
49
  const index = suspenseCounter++;
51
- const fallbackStr = await fallback.toString();
50
+ const fallbackStr = await (typeof fallback === "string" || Array.isArray(fallback) ? renderChildren([fallback]) : isUntrustedObject(fallback) ? renderUntrustedObject(fallback) : fallback.toString());
52
51
  return raw(`<template id="H:${index}"></template>${fallbackStr}<!--/$-->`, [
53
52
  ...fallbackStr.callbacks || [],
54
53
  ({ phase, buffer, context }) => {
@@ -61,7 +60,7 @@ var Suspense = async ({
61
60
  if (buffer) {
62
61
  buffer[0] = buffer[0].replace(
63
62
  new RegExp(`<template id="H:${index}"></template>.*?<!--/\\$-->`),
64
- content
63
+ () => content
65
64
  );
66
65
  }
67
66
  let html = buffer ? "" : `<template data-hono-target="H:${index}">${content}</template><script${nonce ? ` nonce="${nonce}"` : ""}>
@@ -71,7 +71,10 @@ function detectFromHeader(c, options) {
71
71
  return void 0;
72
72
  }
73
73
  const languages = parseAcceptLanguage(acceptLanguage);
74
- for (const { lang } of languages) {
74
+ for (const { lang, q } of languages) {
75
+ if (q === 0) {
76
+ continue;
77
+ }
75
78
  const normalizedLang = normalizeLanguage(lang, options);
76
79
  if (normalizedLang) {
77
80
  return normalizedLang;
package/dist/request.js CHANGED
@@ -94,7 +94,10 @@ var HonoRequest = class {
94
94
  if (anyCachedKey === "json") {
95
95
  body = JSON.stringify(body);
96
96
  }
97
- return new Response(body)[key]();
97
+ const contentType = anyCachedKey === "formData" ? void 0 : raw.headers.get("content-type");
98
+ return new Response(body, {
99
+ headers: contentType ? { "Content-Type": contentType } : void 0
100
+ })[key]();
98
101
  });
99
102
  }
100
103
  return bodyCache[key] = raw[key]();
@@ -27,7 +27,7 @@ interface ProxyFetch {
27
27
  * Fetch API wrapper for proxy.
28
28
  * The parameters and return value are the same as for `fetch` (except for the proxy-specific options).
29
29
  *
30
- * The Accept-Encoding header is replaced with an encoding that the current runtime can handle.
30
+ * The "Accept-Encoding" header is replaced with an encoding that the current runtime can handle.
31
31
  * Unnecessary response headers are deleted and a Response object is returned that can be returned
32
32
  * as is as a response from the handler.
33
33
  *
@@ -31,7 +31,7 @@ export declare const matchedRoutes: (c: Context) => RouterRoute[];
31
31
  * Get the route path registered within the handler
32
32
  *
33
33
  * @param {Context} c - The context object
34
- * @param {number} index - The index of the root from which to retrieve the path, similar to Array.prototype.at(), where a negative number is the index counted from the end of the matching root. Defaults to the current root index.
34
+ * @param {number} index - The index of the route from which to retrieve the path, similar to Array.prototype.at(), where a negative number is the index counted from the end of the matching route. Defaults to the current route index.
35
35
  * @returns The route path registered within the handler
36
36
  *
37
37
  * @example
@@ -54,7 +54,7 @@ export declare const routePath: (c: Context, index?: number) => string;
54
54
  * Get the basePath of the as-is route specified by routing.
55
55
  *
56
56
  * @param {Context} c - The context object
57
- * @param {number} index - The index of the root from which to retrieve the path, similar to Array.prototype.at(), where a negative number is the index counted from the end of the matching root. Defaults to the current root index.
57
+ * @param {number} index - The index of the route from which to retrieve the path, similar to Array.prototype.at(), where a negative number is the index counted from the end of the matching route. Defaults to the current route index.
58
58
  * @returns The basePath of the as-is route specified by routing.
59
59
  *
60
60
  * @example
@@ -26,6 +26,9 @@ export declare namespace JSX {
26
26
  export declare const getNameSpaceContext: () => Context<string> | undefined;
27
27
  export declare const booleanAttributes: string[];
28
28
  export type Child = string | Promise<string> | number | JSXNode | null | undefined | boolean | Child[];
29
+ export declare const renderChildren: (children: Child[]) => HtmlEscapedString | Promise<HtmlEscapedString>;
30
+ export declare const isUntrustedObject: (value: unknown) => boolean;
31
+ export declare const renderUntrustedObject: (value: unknown) => HtmlEscapedString | Promise<HtmlEscapedString>;
29
32
  export declare class JSXNode implements HtmlEscaped {
30
33
  tag: string | Function;
31
34
  props: Props;
@@ -66,7 +66,9 @@ export declare const every: (...middleware: (MiddlewareHandler | Condition)[]) =
66
66
  * If there are multiple targets to match any of them, they can be passed as an array.
67
67
  * If a string is passed, it will be treated as a path pattern to match.
68
68
  * If a Condition function is passed, it will be evaluated against the request context.
69
- * @param middleware - A composed middleware
69
+ * @param middleware - Middleware to run when the condition is not met.
70
+ * Multiple middleware can be passed, and they are applied in the order they are passed.
71
+ * @returns A composed middleware.
70
72
  *
71
73
  * @example
72
74
  * ```ts
@@ -32,7 +32,7 @@ export type JSONValue = JSONObject | JSONArray | JSONPrimitive;
32
32
  * `JSON.stringify()` throws a `TypeError` when it encounters a `bigint` value,
33
33
  * unless a custom `replacer` function or `.toJSON()` method is provided.
34
34
  *
35
- * This behaviour can be controlled by the `TError` generic type parameter,
35
+ * This behavior can be controlled by the `TError` generic type parameter,
36
36
  * which defaults to `bigint | ReadonlyArray<bigint>`.
37
37
  * You can set it to `never` to disable this check.
38
38
  */
@@ -180,7 +180,7 @@ var parseAccept = (acceptHeader) => {
180
180
  ;
181
181
  [i, accept] = getNextAcceptValue(acceptHeader, i);
182
182
  if (accept) {
183
- accept.q = parseQuality(accept.params.q);
183
+ accept.q = parseQuality(accept.params.q ?? accept.params.Q);
184
184
  values.push(accept);
185
185
  if (lastAccept && lastAccept.q < accept.q) {
186
186
  requiresSort = true;
@@ -204,16 +204,13 @@ var parseQuality = (qVal) => {
204
204
  return 0;
205
205
  }
206
206
  const num = Number(qVal);
207
- if (num === Infinity) {
207
+ if (Number.isNaN(num)) {
208
208
  return 1;
209
209
  }
210
- if (num === -Infinity) {
210
+ if (num < 0) {
211
211
  return 0;
212
212
  }
213
- if (Number.isNaN(num)) {
214
- return 1;
215
- }
216
- if (num < 0 || num > 1) {
213
+ if (num > 1) {
217
214
  return 1;
218
215
  }
219
216
  return num;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "4.13.6",
3
+ "version": "4.13.8",
4
4
  "description": "Web framework built on Web Standards",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",