hono 4.4.0 → 4.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/adapter/aws-lambda/handler.js +5 -20
  2. package/dist/adapter/bun/conninfo.js +2 -1
  3. package/dist/adapter/bun/server.js +5 -0
  4. package/dist/adapter/bun/websocket.js +5 -1
  5. package/dist/adapter/cloudflare-workers/websocket.js +5 -15
  6. package/dist/adapter/deno/websocket.js +4 -4
  7. package/dist/cjs/adapter/aws-lambda/handler.js +5 -20
  8. package/dist/cjs/adapter/bun/conninfo.js +2 -1
  9. package/dist/cjs/adapter/bun/server.js +28 -0
  10. package/dist/cjs/adapter/bun/websocket.js +5 -1
  11. package/dist/cjs/adapter/cloudflare-workers/websocket.js +5 -15
  12. package/dist/cjs/adapter/deno/websocket.js +4 -4
  13. package/dist/cjs/client/client.js +7 -1
  14. package/dist/cjs/helper/adapter/index.js +23 -10
  15. package/dist/cjs/helper/ssg/utils.js +6 -3
  16. package/dist/cjs/jsx/utils.js +5 -2
  17. package/dist/cjs/middleware/body-limit/index.js +2 -1
  18. package/dist/cjs/middleware/pretty-json/index.js +1 -1
  19. package/dist/cjs/validator/validator.js +1 -1
  20. package/dist/client/client.js +7 -1
  21. package/dist/helper/adapter/index.js +20 -9
  22. package/dist/helper/ssg/utils.js +6 -3
  23. package/dist/jsx/utils.js +5 -2
  24. package/dist/middleware/body-limit/index.js +2 -1
  25. package/dist/middleware/pretty-json/index.js +1 -1
  26. package/dist/types/adapter/bun/server.d.ts +24 -0
  27. package/dist/types/compose.d.ts +22 -0
  28. package/dist/types/context.d.ts +133 -1
  29. package/dist/types/helper/adapter/index.d.ts +2 -0
  30. package/dist/types/helper/testing/index.d.ts +3 -2
  31. package/dist/types/hono-base.d.ts +20 -0
  32. package/dist/types/hono.d.ts +15 -2
  33. package/dist/types/http-exception.d.ts +16 -0
  34. package/dist/types/index.d.ts +15 -0
  35. package/dist/types/jsx/utils.d.ts +1 -1
  36. package/dist/types/preset/quick.d.ts +2 -2
  37. package/dist/types/preset/tiny.d.ts +2 -2
  38. package/dist/types/request.d.ts +34 -0
  39. package/dist/types/router.d.ts +78 -0
  40. package/dist/types/types.d.ts +7 -6
  41. package/dist/validator/validator.js +1 -1
  42. package/package.json +2 -2
@@ -198,21 +198,6 @@ var ALBProcessor = class extends EventProcessor {
198
198
  }
199
199
  return headers;
200
200
  }
201
- setHeadersToResult(event, result, headers) {
202
- if (event.multiValueHeaders) {
203
- const multiValueHeaders = {};
204
- for (const [key, value] of headers.entries()) {
205
- multiValueHeaders[key] = [value];
206
- }
207
- result.multiValueHeaders = multiValueHeaders;
208
- } else {
209
- const singleValueHeaders = {};
210
- for (const [key, value] of headers.entries()) {
211
- singleValueHeaders[key] = value;
212
- }
213
- result.headers = singleValueHeaders;
214
- }
215
- }
216
201
  getPath(event) {
217
202
  return event.path;
218
203
  }
@@ -220,10 +205,10 @@ var ALBProcessor = class extends EventProcessor {
220
205
  return event.httpMethod;
221
206
  }
222
207
  getQueryString(event) {
223
- if (event.queryStringParameters) {
224
- return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value}`).join("&");
225
- } else {
208
+ if (event.multiValueQueryStringParameters) {
226
209
  return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value.join(`&${key}=`)}`).join("&");
210
+ } else {
211
+ return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value}`).join("&");
227
212
  }
228
213
  }
229
214
  getCookies(event, headers) {
@@ -256,10 +241,10 @@ var getProcessor = (event) => {
256
241
  return v1Processor;
257
242
  };
258
243
  var isProxyEventALB = (event) => {
259
- return Object.prototype.hasOwnProperty.call(event.requestContext, "elb");
244
+ return Object.hasOwn(event.requestContext, "elb");
260
245
  };
261
246
  var isProxyEventV2 = (event) => {
262
- return Object.prototype.hasOwnProperty.call(event, "rawPath");
247
+ return Object.hasOwn(event, "rawPath");
263
248
  };
264
249
  var isContentTypeBinary = (contentType) => {
265
250
  return !/^(text\/(plain|html|css|javascript|csv).*|application\/(.*json|.*xml).*|image\/svg\+xml.*)$/.test(
@@ -1,6 +1,7 @@
1
1
  // src/adapter/bun/conninfo.ts
2
+ import { getBunServer } from "./server.js";
2
3
  var getConnInfo = (c) => {
3
- const server = "server" in c.env ? c.env.server : c.env;
4
+ const server = getBunServer(c);
4
5
  if (!server) {
5
6
  throw new TypeError("env has to include the 2nd argument of fetch.");
6
7
  }
@@ -0,0 +1,5 @@
1
+ // src/adapter/bun/server.ts
2
+ var getBunServer = (c) => "server" in c.env ? c.env.server : c.env;
3
+ export {
4
+ getBunServer
5
+ };
@@ -1,5 +1,6 @@
1
1
  // src/adapter/bun/websocket.ts
2
2
  import { createWSMessageEvent } from "../../helper/websocket/index.js";
3
+ import { getBunServer } from "./server.js";
3
4
  var createWSContext = (ws) => {
4
5
  return {
5
6
  send: (source, options) => {
@@ -20,7 +21,10 @@ var createBunWebSocket = () => {
20
21
  const websocketConns = [];
21
22
  const upgradeWebSocket = (createEvents) => {
22
23
  return async (c, next) => {
23
- const server = c.env;
24
+ const server = getBunServer(c);
25
+ if (!server) {
26
+ throw new TypeError("env has to include the 2nd argument of fetch.");
27
+ }
24
28
  const connId = websocketConns.push(await createEvents(c)) - 1;
25
29
  const upgradeResult = server.upgrade(c.req.raw, {
26
30
  data: {
@@ -22,29 +22,19 @@ var upgradeWebSocket = (createEvents) => async (c, next) => {
22
22
  send: (source) => server.send(source)
23
23
  };
24
24
  if (events.onOpen) {
25
- server.addEventListener("open", (evt) => events.onOpen && events.onOpen(evt, wsContext));
25
+ server.addEventListener("open", (evt) => events.onOpen?.(evt, wsContext));
26
26
  }
27
27
  if (events.onClose) {
28
- server.addEventListener(
29
- "close",
30
- (evt) => events.onClose && events.onClose(evt, wsContext)
31
- );
28
+ server.addEventListener("close", (evt) => events.onClose?.(evt, wsContext));
32
29
  }
33
30
  if (events.onMessage) {
34
- server.addEventListener(
35
- "message",
36
- (evt) => events.onMessage && events.onMessage(evt, wsContext)
37
- );
31
+ server.addEventListener("message", (evt) => events.onMessage?.(evt, wsContext));
38
32
  }
39
33
  if (events.onError) {
40
- server.addEventListener(
41
- "error",
42
- (evt) => events.onError && events.onError(evt, wsContext)
43
- );
34
+ server.addEventListener("error", (evt) => events.onError?.(evt, wsContext));
44
35
  }
45
- server.accept();
36
+ server.accept?.();
46
37
  return new Response(null, {
47
- status: 101,
48
38
  webSocket: client
49
39
  });
50
40
  };
@@ -18,10 +18,10 @@ var upgradeWebSocket = (createEvents) => async (c, next) => {
18
18
  url: socket.url ? new URL(socket.url) : null,
19
19
  send: (source) => socket.send(source)
20
20
  };
21
- socket.onopen = (evt) => events.onOpen && events.onOpen(evt, wsContext);
22
- socket.onmessage = (evt) => events.onMessage && events.onMessage(evt, wsContext);
23
- socket.onclose = (evt) => events.onClose && events.onClose(evt, wsContext);
24
- socket.onerror = (evt) => events.onError && events.onError(evt, wsContext);
21
+ socket.onopen = (evt) => events.onOpen?.(evt, wsContext);
22
+ socket.onmessage = (evt) => events.onMessage?.(evt, wsContext);
23
+ socket.onclose = (evt) => events.onClose?.(evt, wsContext);
24
+ socket.onerror = (evt) => events.onError?.(evt, wsContext);
25
25
  return response;
26
26
  };
27
27
  export {
@@ -230,21 +230,6 @@ class ALBProcessor extends EventProcessor {
230
230
  }
231
231
  return headers;
232
232
  }
233
- setHeadersToResult(event, result, headers) {
234
- if (event.multiValueHeaders) {
235
- const multiValueHeaders = {};
236
- for (const [key, value] of headers.entries()) {
237
- multiValueHeaders[key] = [value];
238
- }
239
- result.multiValueHeaders = multiValueHeaders;
240
- } else {
241
- const singleValueHeaders = {};
242
- for (const [key, value] of headers.entries()) {
243
- singleValueHeaders[key] = value;
244
- }
245
- result.headers = singleValueHeaders;
246
- }
247
- }
248
233
  getPath(event) {
249
234
  return event.path;
250
235
  }
@@ -252,10 +237,10 @@ class ALBProcessor extends EventProcessor {
252
237
  return event.httpMethod;
253
238
  }
254
239
  getQueryString(event) {
255
- if (event.queryStringParameters) {
256
- return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value}`).join("&");
257
- } else {
240
+ if (event.multiValueQueryStringParameters) {
258
241
  return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value.join(`&${key}=`)}`).join("&");
242
+ } else {
243
+ return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value}`).join("&");
259
244
  }
260
245
  }
261
246
  getCookies(event, headers) {
@@ -288,10 +273,10 @@ const getProcessor = (event) => {
288
273
  return v1Processor;
289
274
  };
290
275
  const isProxyEventALB = (event) => {
291
- return Object.prototype.hasOwnProperty.call(event.requestContext, "elb");
276
+ return Object.hasOwn(event.requestContext, "elb");
292
277
  };
293
278
  const isProxyEventV2 = (event) => {
294
- return Object.prototype.hasOwnProperty.call(event, "rawPath");
279
+ return Object.hasOwn(event, "rawPath");
295
280
  };
296
281
  const isContentTypeBinary = (contentType) => {
297
282
  return !/^(text\/(plain|html|css|javascript|csv).*|application\/(.*json|.*xml).*|image\/svg\+xml.*)$/.test(
@@ -21,8 +21,9 @@ __export(conninfo_exports, {
21
21
  getConnInfo: () => getConnInfo
22
22
  });
23
23
  module.exports = __toCommonJS(conninfo_exports);
24
+ var import_server = require("./server");
24
25
  const getConnInfo = (c) => {
25
- const server = "server" in c.env ? c.env.server : c.env;
26
+ const server = (0, import_server.getBunServer)(c);
26
27
  if (!server) {
27
28
  throw new TypeError("env has to include the 2nd argument of fetch.");
28
29
  }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var server_exports = {};
20
+ __export(server_exports, {
21
+ getBunServer: () => getBunServer
22
+ });
23
+ module.exports = __toCommonJS(server_exports);
24
+ const getBunServer = (c) => "server" in c.env ? c.env.server : c.env;
25
+ // Annotate the CommonJS export names for ESM import in node:
26
+ 0 && (module.exports = {
27
+ getBunServer
28
+ });
@@ -22,6 +22,7 @@ __export(websocket_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(websocket_exports);
24
24
  var import_websocket = require("../../helper/websocket");
25
+ var import_server = require("./server");
25
26
  const createWSContext = (ws) => {
26
27
  return {
27
28
  send: (source, options) => {
@@ -42,7 +43,10 @@ const createBunWebSocket = () => {
42
43
  const websocketConns = [];
43
44
  const upgradeWebSocket = (createEvents) => {
44
45
  return async (c, next) => {
45
- const server = c.env;
46
+ const server = (0, import_server.getBunServer)(c);
47
+ if (!server) {
48
+ throw new TypeError("env has to include the 2nd argument of fetch.");
49
+ }
46
50
  const connId = websocketConns.push(await createEvents(c)) - 1;
47
51
  const upgradeResult = server.upgrade(c.req.raw, {
48
52
  data: {
@@ -44,29 +44,19 @@ const upgradeWebSocket = (createEvents) => async (c, next) => {
44
44
  send: (source) => server.send(source)
45
45
  };
46
46
  if (events.onOpen) {
47
- server.addEventListener("open", (evt) => events.onOpen && events.onOpen(evt, wsContext));
47
+ server.addEventListener("open", (evt) => events.onOpen?.(evt, wsContext));
48
48
  }
49
49
  if (events.onClose) {
50
- server.addEventListener(
51
- "close",
52
- (evt) => events.onClose && events.onClose(evt, wsContext)
53
- );
50
+ server.addEventListener("close", (evt) => events.onClose?.(evt, wsContext));
54
51
  }
55
52
  if (events.onMessage) {
56
- server.addEventListener(
57
- "message",
58
- (evt) => events.onMessage && events.onMessage(evt, wsContext)
59
- );
53
+ server.addEventListener("message", (evt) => events.onMessage?.(evt, wsContext));
60
54
  }
61
55
  if (events.onError) {
62
- server.addEventListener(
63
- "error",
64
- (evt) => events.onError && events.onError(evt, wsContext)
65
- );
56
+ server.addEventListener("error", (evt) => events.onError?.(evt, wsContext));
66
57
  }
67
- server.accept();
58
+ server.accept?.();
68
59
  return new Response(null, {
69
- status: 101,
70
60
  webSocket: client
71
61
  });
72
62
  };
@@ -40,10 +40,10 @@ const upgradeWebSocket = (createEvents) => async (c, next) => {
40
40
  url: socket.url ? new URL(socket.url) : null,
41
41
  send: (source) => socket.send(source)
42
42
  };
43
- socket.onopen = (evt) => events.onOpen && events.onOpen(evt, wsContext);
44
- socket.onmessage = (evt) => events.onMessage && events.onMessage(evt, wsContext);
45
- socket.onclose = (evt) => events.onClose && events.onClose(evt, wsContext);
46
- socket.onerror = (evt) => events.onError && events.onError(evt, wsContext);
43
+ socket.onopen = (evt) => events.onOpen?.(evt, wsContext);
44
+ socket.onmessage = (evt) => events.onMessage?.(evt, wsContext);
45
+ socket.onclose = (evt) => events.onClose?.(evt, wsContext);
46
+ socket.onerror = (evt) => events.onError?.(evt, wsContext);
47
47
  return response;
48
48
  };
49
49
  // Annotate the CommonJS export names for ESM import in node:
@@ -72,7 +72,13 @@ class ClientRequestImpl {
72
72
  if (args.form) {
73
73
  const form = new FormData();
74
74
  for (const [k, v] of Object.entries(args.form)) {
75
- form.append(k, v);
75
+ if (Array.isArray(v)) {
76
+ for (const v2 of v) {
77
+ form.append(k, v2);
78
+ }
79
+ } else {
80
+ form.append(k, v);
81
+ }
76
82
  }
77
83
  this.rBody = form;
78
84
  }
@@ -18,8 +18,10 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var adapter_exports = {};
20
20
  __export(adapter_exports, {
21
+ checkUserAgentEquals: () => checkUserAgentEquals,
21
22
  env: () => env,
22
- getRuntimeKey: () => getRuntimeKey
23
+ getRuntimeKey: () => getRuntimeKey,
24
+ knownUserAgents: () => knownUserAgents
23
25
  });
24
26
  module.exports = __toCommonJS(adapter_exports);
25
27
  const env = (c, runtime) => {
@@ -39,16 +41,21 @@ const env = (c, runtime) => {
39
41
  };
40
42
  return runtimeEnvHandlers[runtime]();
41
43
  };
44
+ const knownUserAgents = {
45
+ deno: "Deno",
46
+ bun: "Bun",
47
+ workerd: "Cloudflare-Workers",
48
+ node: "Node.js"
49
+ };
42
50
  const getRuntimeKey = () => {
43
51
  const global = globalThis;
44
- if (global?.Deno !== void 0) {
45
- return "deno";
46
- }
47
- if (global?.Bun !== void 0) {
48
- return "bun";
49
- }
50
- if (typeof global?.WebSocketPair === "function") {
51
- return "workerd";
52
+ const userAgentSupported = typeof navigator !== "undefined" && typeof navigator.userAgent === "string";
53
+ if (userAgentSupported) {
54
+ for (const [runtimeKey, userAgent] of Object.entries(knownUserAgents)) {
55
+ if (checkUserAgentEquals(userAgent)) {
56
+ return runtimeKey;
57
+ }
58
+ }
52
59
  }
53
60
  if (typeof global?.EdgeRuntime === "string") {
54
61
  return "edge-light";
@@ -61,8 +68,14 @@ const getRuntimeKey = () => {
61
68
  }
62
69
  return "other";
63
70
  };
71
+ const checkUserAgentEquals = (platform) => {
72
+ const userAgent = navigator.userAgent;
73
+ return userAgent.startsWith(platform);
74
+ };
64
75
  // Annotate the CommonJS export names for ESM import in node:
65
76
  0 && (module.exports = {
77
+ checkUserAgentEquals,
66
78
  env,
67
- getRuntimeKey
79
+ getRuntimeKey,
80
+ knownUserAgents
68
81
  });
@@ -32,8 +32,8 @@ const dirname = (path) => {
32
32
  const normalizePath = (path) => {
33
33
  return path.replace(/(\\)/g, "/").replace(/\/$/g, "");
34
34
  };
35
- const handleDotDot = (resultPaths) => {
36
- if (resultPaths.length === 0) {
35
+ const handleParent = (resultPaths, beforeParentFlag) => {
36
+ if (resultPaths.length === 0 || beforeParentFlag) {
37
37
  resultPaths.push("..");
38
38
  } else {
39
39
  resultPaths.pop();
@@ -46,11 +46,14 @@ const handleNonDot = (path, resultPaths) => {
46
46
  }
47
47
  };
48
48
  const handleSegments = (paths, resultPaths) => {
49
+ let beforeParentFlag = false;
49
50
  for (const path of paths) {
50
51
  if (path === "..") {
51
- handleDotDot(resultPaths);
52
+ handleParent(resultPaths, beforeParentFlag);
53
+ beforeParentFlag = true;
52
54
  } else {
53
55
  handleNonDot(path, resultPaths);
56
+ beforeParentFlag = false;
54
57
  }
55
58
  }
56
59
  };
@@ -30,9 +30,12 @@ const normalizeIntrinsicElementProps = (props) => {
30
30
  };
31
31
  const styleObjectForEach = (style, fn) => {
32
32
  for (const [k, v] of Object.entries(style)) {
33
+ const key = k[0] === "-" || !/[A-Z]/.test(k) ? k : k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
33
34
  fn(
34
- k[0] === "-" ? k : k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`),
35
- v == null ? null : typeof v === "number" ? v + "px" : v
35
+ key,
36
+ v == null ? null : typeof v === "number" ? !key.match(
37
+ /^(?:a|border-im|column(?:-c|s)|flex(?:$|-[^b])|grid-(?:ar|[^a])|font-w|li|or|sca|st|ta|wido|z)|ty$/
38
+ ) ? `${v}px` : `${v}` : v
36
39
  );
37
40
  }
38
41
  };
@@ -67,7 +67,8 @@ const bodyLimit = (options) => {
67
67
  }
68
68
  }
69
69
  });
70
- c.req.raw = new Request(c.req.raw, { body: reader });
70
+ const requestInit = { body: reader, duplex: "half" };
71
+ c.req.raw = new Request(c.req.raw, requestInit);
71
72
  await next();
72
73
  if (c.error instanceof BodyLimitError) {
73
74
  c.res = await onError(c);
@@ -23,7 +23,7 @@ __export(pretty_json_exports, {
23
23
  module.exports = __toCommonJS(pretty_json_exports);
24
24
  const prettyJSON = (options = { space: 2 }) => {
25
25
  return async function prettyJSON2(c, next) {
26
- const pretty = c.req.query("pretty") || c.req.query("pretty") === "" ? true : false;
26
+ const pretty = c.req.query("pretty") || c.req.query("pretty") === "";
27
27
  await next();
28
28
  if (pretty && c.res.headers.get("Content-Type")?.startsWith("application/json")) {
29
29
  const obj = await c.res.json();
@@ -30,7 +30,7 @@ const validator = (target, validationFunc) => {
30
30
  const contentType = c.req.header("Content-Type");
31
31
  switch (target) {
32
32
  case "json":
33
- if (!contentType || !/^application\/([a-z-]+\+)?json/.test(contentType)) {
33
+ if (!contentType || !/^application\/([a-z-\.]+\+)?json/.test(contentType)) {
34
34
  const message = `Invalid HTTP header: Content-Type=${contentType}`;
35
35
  throw new import_http_exception.HTTPException(400, { message });
36
36
  }
@@ -56,7 +56,13 @@ var ClientRequestImpl = class {
56
56
  if (args.form) {
57
57
  const form = new FormData();
58
58
  for (const [k, v] of Object.entries(args.form)) {
59
- form.append(k, v);
59
+ if (Array.isArray(v)) {
60
+ for (const v2 of v) {
61
+ form.append(k, v2);
62
+ }
63
+ } else {
64
+ form.append(k, v);
65
+ }
60
66
  }
61
67
  this.rBody = form;
62
68
  }
@@ -16,16 +16,21 @@ var env = (c, runtime) => {
16
16
  };
17
17
  return runtimeEnvHandlers[runtime]();
18
18
  };
19
+ var knownUserAgents = {
20
+ deno: "Deno",
21
+ bun: "Bun",
22
+ workerd: "Cloudflare-Workers",
23
+ node: "Node.js"
24
+ };
19
25
  var getRuntimeKey = () => {
20
26
  const global = globalThis;
21
- if (global?.Deno !== void 0) {
22
- return "deno";
23
- }
24
- if (global?.Bun !== void 0) {
25
- return "bun";
26
- }
27
- if (typeof global?.WebSocketPair === "function") {
28
- return "workerd";
27
+ const userAgentSupported = typeof navigator !== "undefined" && typeof navigator.userAgent === "string";
28
+ if (userAgentSupported) {
29
+ for (const [runtimeKey, userAgent] of Object.entries(knownUserAgents)) {
30
+ if (checkUserAgentEquals(userAgent)) {
31
+ return runtimeKey;
32
+ }
33
+ }
29
34
  }
30
35
  if (typeof global?.EdgeRuntime === "string") {
31
36
  return "edge-light";
@@ -38,7 +43,13 @@ var getRuntimeKey = () => {
38
43
  }
39
44
  return "other";
40
45
  };
46
+ var checkUserAgentEquals = (platform) => {
47
+ const userAgent = navigator.userAgent;
48
+ return userAgent.startsWith(platform);
49
+ };
41
50
  export {
51
+ checkUserAgentEquals,
42
52
  env,
43
- getRuntimeKey
53
+ getRuntimeKey,
54
+ knownUserAgents
44
55
  };
@@ -8,8 +8,8 @@ var dirname = (path) => {
8
8
  var normalizePath = (path) => {
9
9
  return path.replace(/(\\)/g, "/").replace(/\/$/g, "");
10
10
  };
11
- var handleDotDot = (resultPaths) => {
12
- if (resultPaths.length === 0) {
11
+ var handleParent = (resultPaths, beforeParentFlag) => {
12
+ if (resultPaths.length === 0 || beforeParentFlag) {
13
13
  resultPaths.push("..");
14
14
  } else {
15
15
  resultPaths.pop();
@@ -22,11 +22,14 @@ var handleNonDot = (path, resultPaths) => {
22
22
  }
23
23
  };
24
24
  var handleSegments = (paths, resultPaths) => {
25
+ let beforeParentFlag = false;
25
26
  for (const path of paths) {
26
27
  if (path === "..") {
27
- handleDotDot(resultPaths);
28
+ handleParent(resultPaths, beforeParentFlag);
29
+ beforeParentFlag = true;
28
30
  } else {
29
31
  handleNonDot(path, resultPaths);
32
+ beforeParentFlag = false;
30
33
  }
31
34
  }
32
35
  };
package/dist/jsx/utils.js CHANGED
@@ -7,9 +7,12 @@ var normalizeIntrinsicElementProps = (props) => {
7
7
  };
8
8
  var styleObjectForEach = (style, fn) => {
9
9
  for (const [k, v] of Object.entries(style)) {
10
+ const key = k[0] === "-" || !/[A-Z]/.test(k) ? k : k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
10
11
  fn(
11
- k[0] === "-" ? k : k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`),
12
- v == null ? null : typeof v === "number" ? v + "px" : v
12
+ key,
13
+ v == null ? null : typeof v === "number" ? !key.match(
14
+ /^(?:a|border-im|column(?:-c|s)|flex(?:$|-[^b])|grid-(?:ar|[^a])|font-w|li|or|sca|st|ta|wido|z)|ty$/
15
+ ) ? `${v}px` : `${v}` : v
13
16
  );
14
17
  }
15
18
  };
@@ -45,7 +45,8 @@ var bodyLimit = (options) => {
45
45
  }
46
46
  }
47
47
  });
48
- c.req.raw = new Request(c.req.raw, { body: reader });
48
+ const requestInit = { body: reader, duplex: "half" };
49
+ c.req.raw = new Request(c.req.raw, requestInit);
49
50
  await next();
50
51
  if (c.error instanceof BodyLimitError) {
51
52
  c.res = await onError(c);
@@ -1,7 +1,7 @@
1
1
  // src/middleware/pretty-json/index.ts
2
2
  var prettyJSON = (options = { space: 2 }) => {
3
3
  return async function prettyJSON2(c, next) {
4
- const pretty = c.req.query("pretty") || c.req.query("pretty") === "" ? true : false;
4
+ const pretty = c.req.query("pretty") || c.req.query("pretty") === "";
5
5
  await next();
6
6
  if (pretty && c.res.headers.get("Content-Type")?.startsWith("application/json")) {
7
7
  const obj = await c.res.json();
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Getting Bun Server Object for Bun adapters
3
+ * @module
4
+ */
5
+ import type { Context } from '../../context';
6
+ /**
7
+ * Bun Server Object
8
+ */
9
+ export interface BunServer {
10
+ requestIP?: (req: Request) => {
11
+ address: string;
12
+ family: string;
13
+ port: number;
14
+ };
15
+ upgrade<T>(req: Request, options?: {
16
+ data: T;
17
+ }): boolean;
18
+ }
19
+ /**
20
+ * Get Bun Server Object from Context
21
+ * @param c Context
22
+ * @returns Bun Server
23
+ */
24
+ export declare const getBunServer: (c: Context) => BunServer | undefined;
@@ -1,8 +1,30 @@
1
1
  import type { ParamIndexMap, Params } from './router';
2
2
  import type { Env, ErrorHandler, NotFoundHandler } from './types';
3
+ /**
4
+ * Interface representing the context for a composition operation.
5
+ */
3
6
  interface ComposeContext {
7
+ /**
8
+ * Indicates whether the composition process has been finalized.
9
+ */
4
10
  finalized: boolean;
11
+ /**
12
+ * The result of the composition process. The type is unknown and should be
13
+ * specified based on the context where this interface is used.
14
+ */
5
15
  res: unknown;
6
16
  }
17
+ /**
18
+ * Compose middleware functions into a single function based on `koa-compose` package.
19
+ *
20
+ * @template C - The context type.
21
+ * @template E - The environment type.
22
+ *
23
+ * @param {[[Function, unknown], ParamIndexMap | Params][]} middleware - An array of middleware functions and their corresponding parameters.
24
+ * @param {ErrorHandler<E>} [onError] - An optional error handler function.
25
+ * @param {NotFoundHandler<E>} [onNotFound] - An optional not-found handler function.
26
+ *
27
+ * @returns {(context: C, next?: Function) => Promise<C>} - A composed middleware function.
28
+ */
7
29
  export declare const compose: <C extends ComposeContext, E extends Env = Env>(middleware: [[Function, unknown], ParamIndexMap | Params][], onError?: ErrorHandler<E> | undefined, onNotFound?: NotFoundHandler<E> | undefined) => (context: C, next?: Function) => Promise<C>;
8
30
  export {};
@@ -3,50 +3,149 @@ import type { Env, FetchEventLike, Input, NotFoundHandler, TypedResponse } from
3
3
  import type { RedirectStatusCode, StatusCode } from './utils/http-status';
4
4
  import type { IsAny, JSONParsed, JSONValue, Simplify } from './utils/types';
5
5
  type HeaderRecord = Record<string, string | string[]>;
6
+ /**
7
+ * Data type can be a string, ArrayBuffer, or ReadableStream.
8
+ */
6
9
  export type Data = string | ArrayBuffer | ReadableStream;
10
+ /**
11
+ * Interface for the execution context in a web worker or similar environment.
12
+ */
7
13
  export interface ExecutionContext {
14
+ /**
15
+ * Extends the lifetime of the event callback until the promise is settled.
16
+ *
17
+ * @param promise - A promise to wait for.
18
+ */
8
19
  waitUntil(promise: Promise<unknown>): void;
20
+ /**
21
+ * Allows the event to be passed through to subsequent event listeners.
22
+ */
9
23
  passThroughOnException(): void;
10
24
  }
25
+ /**
26
+ * Interface for context variable mapping.
27
+ */
11
28
  export interface ContextVariableMap {
12
29
  }
30
+ /**
31
+ * Interface for context renderer.
32
+ */
13
33
  export interface ContextRenderer {
14
34
  }
35
+ /**
36
+ * Interface representing a renderer for content.
37
+ *
38
+ * @interface DefaultRenderer
39
+ * @param {string | Promise<string>} content - The content to be rendered, which can be either a string or a Promise resolving to a string.
40
+ * @returns {Response | Promise<Response>} - The response after rendering the content, which can be either a Response or a Promise resolving to a Response.
41
+ */
15
42
  interface DefaultRenderer {
16
43
  (content: string | Promise<string>): Response | Promise<Response>;
17
44
  }
45
+ /**
46
+ * Renderer type which can either be a ContextRenderer or DefaultRenderer.
47
+ */
18
48
  export type Renderer = ContextRenderer extends Function ? ContextRenderer : DefaultRenderer;
49
+ /**
50
+ * Extracts the props for the renderer.
51
+ */
19
52
  export type PropsForRenderer = [...Required<Parameters<Renderer>>] extends [unknown, infer Props] ? Props : unknown;
20
53
  export type Layout<T = Record<string, any>> = (props: T) => any;
54
+ /**
55
+ * Interface for getting context variables.
56
+ *
57
+ * @template E - Environment type.
58
+ */
21
59
  interface Get<E extends Env> {
22
60
  <Key extends keyof ContextVariableMap>(key: Key): ContextVariableMap[Key];
23
61
  <Key extends keyof E['Variables']>(key: Key): E['Variables'][Key];
24
62
  }
63
+ /**
64
+ * Interface for setting context variables.
65
+ *
66
+ * @template E - Environment type.
67
+ */
25
68
  interface Set<E extends Env> {
26
69
  <Key extends keyof ContextVariableMap>(key: Key, value: ContextVariableMap[Key]): void;
27
70
  <Key extends keyof E['Variables']>(key: Key, value: E['Variables'][Key]): void;
28
71
  }
72
+ /**
73
+ * Interface for creating a new response.
74
+ */
29
75
  interface NewResponse {
30
76
  (data: Data | null, status?: StatusCode, headers?: HeaderRecord): Response;
31
77
  (data: Data | null, init?: ResponseInit): Response;
32
78
  }
79
+ /**
80
+ * Interface for responding with a body.
81
+ */
33
82
  interface BodyRespond extends NewResponse {
34
83
  }
84
+ /**
85
+ * Interface for responding with text.
86
+ *
87
+ * @interface TextRespond
88
+ * @template T - The type of the text content.
89
+ * @template U - The type of the status code.
90
+ *
91
+ * @param {T} text - The text content to be included in the response.
92
+ * @param {U} [status] - An optional status code for the response.
93
+ * @param {HeaderRecord} [headers] - An optional record of headers to include in the response.
94
+ *
95
+ * @returns {Response & TypedResponse<T, U, 'text'>} - The response after rendering the text content, typed with the provided text and status code types.
96
+ */
35
97
  interface TextRespond {
36
98
  <T extends string, U extends StatusCode>(text: T, status?: U, headers?: HeaderRecord): Response & TypedResponse<T, U, 'text'>;
37
99
  <T extends string, U extends StatusCode>(text: T, init?: ResponseInit): Response & TypedResponse<T, U, 'text'>;
38
100
  }
101
+ /**
102
+ * Interface for responding with JSON.
103
+ *
104
+ * @interface JSONRespond
105
+ * @template T - The type of the JSON value or simplified unknown type.
106
+ * @template U - The type of the status code.
107
+ *
108
+ * @param {T} object - The JSON object to be included in the response.
109
+ * @param {U} [status] - An optional status code for the response.
110
+ * @param {HeaderRecord} [headers] - An optional record of headers to include in the response.
111
+ *
112
+ * @returns {Response & TypedResponse<Simplify<T> extends JSONValue ? (JSONValue extends Simplify<T> ? never : JSONParsed<T>) : never, U, 'json'>} - The response after rendering the JSON object, typed with the provided object and status code types.
113
+ */
39
114
  interface JSONRespond {
40
115
  <T extends JSONValue | Simplify<unknown>, U extends StatusCode>(object: T, status?: U, headers?: HeaderRecord): Response & TypedResponse<Simplify<T> extends JSONValue ? JSONValue extends Simplify<T> ? never : JSONParsed<T> : never, U, 'json'>;
41
116
  <T extends JSONValue | Simplify<unknown>, U extends StatusCode>(object: Simplify<T> extends JSONValue ? T : Simplify<T>, init?: ResponseInit): Response & TypedResponse<Simplify<T> extends JSONValue ? JSONValue extends Simplify<T> ? never : JSONParsed<T> : never, U, 'json'>;
42
117
  }
118
+ /**
119
+ * Interface representing a function that responds with HTML content.
120
+ *
121
+ * @param html - The HTML content to respond with, which can be a string or a Promise that resolves to a string.
122
+ * @param status - (Optional) The HTTP status code for the response.
123
+ * @param headers - (Optional) A record of headers to include in the response.
124
+ * @param init - (Optional) The response initialization object.
125
+ *
126
+ * @returns A Response object or a Promise that resolves to a Response object.
127
+ */
43
128
  interface HTMLRespond {
44
129
  (html: string | Promise<string>, status?: StatusCode, headers?: HeaderRecord): Response | Promise<Response>;
45
130
  (html: string | Promise<string>, init?: ResponseInit): Response | Promise<Response>;
46
131
  }
132
+ /**
133
+ * Options for configuring the context.
134
+ *
135
+ * @template E - Environment type.
136
+ */
47
137
  type ContextOptions<E extends Env> = {
138
+ /**
139
+ * Bindings for the environment.
140
+ */
48
141
  env: E['Bindings'];
142
+ /**
143
+ * Execution context for the request.
144
+ */
49
145
  executionCtx?: FetchEventLike | ExecutionContext | undefined;
146
+ /**
147
+ * Handler for not found responses.
148
+ */
50
149
  notFoundHandler?: NotFoundHandler<E>;
51
150
  };
52
151
  export declare const TEXT_PLAIN = "text/plain; charset=UTF-8";
@@ -87,22 +186,44 @@ export declare class Context<E extends Env = any, P extends string = any, I exte
87
186
  private layout;
88
187
  private renderer;
89
188
  private notFoundHandler;
189
+ /**
190
+ * Creates an instance of the Context class.
191
+ *
192
+ * @param req - The HonoRequest object.
193
+ * @param options - Optional configuration options for the context.
194
+ */
90
195
  constructor(req: HonoRequest<P, I['out']>, options?: ContextOptions<E>);
91
196
  /**
197
+ * The FetchEvent associated with the current request.
198
+ *
199
+ * @throws Will throw an error if the context does not have a FetchEvent.
200
+ *
92
201
  * @see https://hono.dev/api/context#event
93
202
  */
94
203
  get event(): FetchEventLike;
95
204
  /**
205
+ * The ExecutionContext associated with the current request.
206
+ *
207
+ * @throws Will throw an error if the context does not have an ExecutionContext.
208
+ *
96
209
  * @see https://hono.dev/api/context#executionctx
97
210
  */
98
211
  get executionCtx(): ExecutionContext;
99
212
  /**
213
+ * The Response object for the current request.
214
+ *
100
215
  * @see https://hono.dev/api/context#res
101
216
  */
102
217
  get res(): Response;
218
+ /**
219
+ * Sets the Response object for the current request.
220
+ *
221
+ * @param _res - The Response object to set.
222
+ */
103
223
  set res(_res: Response | undefined);
104
224
  /**
105
- * `.render()` can create a response within a layout.
225
+ * Renders a response within a layout.
226
+ *
106
227
  * @example
107
228
  * ```ts
108
229
  * app.get('/', (c) => {
@@ -112,11 +233,22 @@ export declare class Context<E extends Env = any, P extends string = any, I exte
112
233
  * @see https://hono.dev/api/context#render-setrenderer
113
234
  */
114
235
  render: Renderer;
236
+ /**
237
+ * Sets the layout for the response.
238
+ *
239
+ * @param layout - The layout to set.
240
+ * @returns The layout function.
241
+ */
115
242
  setLayout: (layout: Layout<PropsForRenderer & {
116
243
  Layout: Layout;
117
244
  }>) => Layout<PropsForRenderer & {
118
245
  Layout: Layout;
119
246
  }>;
247
+ /**
248
+ * Gets the current layout for the response.
249
+ *
250
+ * @returns The current layout function.
251
+ */
120
252
  getLayout: () => Layout<{
121
253
  Layout: Layout;
122
254
  }> | undefined;
@@ -5,4 +5,6 @@
5
5
  import type { Context } from '../../context';
6
6
  export type Runtime = 'node' | 'deno' | 'bun' | 'workerd' | 'fastly' | 'edge-light' | 'other';
7
7
  export declare const env: <T extends Record<string, unknown>, C extends Context<any, any, {}> = Context<{}, any, {}>>(c: C, runtime?: Runtime) => T & C["env"];
8
+ export declare const knownUserAgents: Partial<Record<Runtime, string>>;
8
9
  export declare const getRuntimeKey: () => Runtime;
10
+ export declare const checkUserAgentEquals: (platform: string) => boolean;
@@ -5,7 +5,8 @@
5
5
  import type { Client } from '../../client/types';
6
6
  import type { ExecutionContext } from '../../context';
7
7
  import type { Hono } from '../../hono';
8
+ import type { Schema } from '../../types';
8
9
  import type { UnionToIntersection } from '../../utils/types';
9
- type ExtractEnv<T> = T extends Hono<infer E, any, any> ? E : never;
10
- export declare const testClient: <T extends Hono<any, any, any>>(app: T, Env?: {} | ExtractEnv<T>["Bindings"] | undefined, executionCtx?: ExecutionContext) => UnionToIntersection<Client<T>>;
10
+ type ExtractEnv<T> = T extends Hono<infer E, Schema, string> ? E : never;
11
+ export declare const testClient: <T extends Hono<any, Schema, string>>(app: T, Env?: {} | ExtractEnv<T>["Bindings"] | undefined, executionCtx?: ExecutionContext) => UnionToIntersection<Client<T>>;
11
12
  export {};
@@ -6,6 +6,9 @@ import { Context } from './context';
6
6
  import type { ExecutionContext } from './context';
7
7
  import type { Router } from './router';
8
8
  import type { Env, ErrorHandler, H, HandlerInterface, MergePath, MergeSchemaPath, MiddlewareHandlerInterface, NotFoundHandler, OnHandlerInterface, RouterRoute, Schema } from './types';
9
+ /**
10
+ * Symbol used to mark a composed handler.
11
+ */
9
12
  export declare const COMPOSED_HANDLER: unique symbol;
10
13
  type GetPath<E extends Env> = (request: Request, options?: {
11
14
  env?: E['Bindings'];
@@ -94,6 +97,23 @@ declare class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends
94
97
  * @see https://hono.dev/api/hono#not-found
95
98
  */
96
99
  notFound: (handler: NotFoundHandler<E>) => Hono<E, S, BasePath>;
100
+ /**
101
+ * Mounts an external application handler to the specified path.
102
+ *
103
+ * @param path - The path where the external application handler should be mounted.
104
+ * @param applicationHandler - The external application handler function that processes requests.
105
+ * @param optionHandler - Optional function to handle additional options, such as environment variables and execution context.
106
+ *
107
+ * @returns The current instance of Hono for chaining.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * const app = new Hono()
112
+ * const externalAppHandler = () => new Response('External App')
113
+ * app.mount('/external', externalAppHandler)
114
+ * ```
115
+ * @see https://hono.dev/api/hono#mount
116
+ */
97
117
  mount(path: string, applicationHandler: (request: Request, ...args: any) => Response | Promise<Response>, optionHandler?: (c: Context) => unknown): Hono<E, S, BasePath>;
98
118
  private addRoute;
99
119
  private matchRoute;
@@ -1,6 +1,19 @@
1
1
  import { HonoBase } from './hono-base';
2
2
  import type { HonoOptions } from './hono-base';
3
- import type { BlankSchema, Env, Schema } from './types';
4
- export declare class Hono<E extends Env = Env, S extends Schema = BlankSchema, BasePath extends string = '/'> extends HonoBase<E, S, BasePath> {
3
+ import type { BlankEnv, BlankSchema, Env, Schema } from './types';
4
+ /**
5
+ * The Hono class extends the functionality of the HonoBase class.
6
+ * It sets up routing and allows for custom options to be passed.
7
+ *
8
+ * @template E - The environment type.
9
+ * @template S - The schema type.
10
+ * @template BasePath - The base path type.
11
+ */
12
+ export declare class Hono<E extends Env = BlankEnv, S extends Schema = BlankSchema, BasePath extends string = '/'> extends HonoBase<E, S, BasePath> {
13
+ /**
14
+ * Creates an instance of the Hono class.
15
+ *
16
+ * @param options - Optional configuration options for the Hono instance.
17
+ */
5
18
  constructor(options?: HonoOptions<E>);
6
19
  }
@@ -3,6 +3,12 @@
3
3
  * This module provides the `HTTPException` class.
4
4
  */
5
5
  import type { StatusCode } from './utils/http-status';
6
+ /**
7
+ * Options for creating an `HTTPException`.
8
+ * @property res - Optional response object to use.
9
+ * @property message - Optional custom error message.
10
+ * @property cause - Optional cause of the error.
11
+ */
6
12
  type HTTPExceptionOptions = {
7
13
  res?: Response;
8
14
  message?: string;
@@ -29,7 +35,17 @@ type HTTPExceptionOptions = {
29
35
  export declare class HTTPException extends Error {
30
36
  readonly res?: Response;
31
37
  readonly status: StatusCode;
38
+ /**
39
+ * Creates an instance of `HTTPException`.
40
+ * @param status - HTTP status code for the exception. Defaults to 500.
41
+ * @param options - Additional options for the exception.
42
+ */
32
43
  constructor(status?: StatusCode, options?: HTTPExceptionOptions);
44
+ /**
45
+ * Returns the response object associated with the exception.
46
+ * If a response object is not provided, a new response is created with the error message and status code.
47
+ * @returns The response object.
48
+ */
33
49
  getResponse(): Response;
34
50
  }
35
51
  export {};
@@ -14,8 +14,23 @@
14
14
  * ```
15
15
  */
16
16
  import { Hono } from './hono';
17
+ /**
18
+ * Types for environment variables, error handlers, handlers, middleware handlers, and more.
19
+ */
17
20
  export type { Env, ErrorHandler, Handler, MiddlewareHandler, Next, NotFoundHandler, ValidationTargets, Input, Schema, ToSchema, TypedResponse, } from './types';
21
+ /**
22
+ * Types for context, context variable map, context renderer, and execution context.
23
+ */
18
24
  export type { Context, ContextVariableMap, ContextRenderer, ExecutionContext } from './context';
25
+ /**
26
+ * Type for HonoRequest.
27
+ */
19
28
  export type { HonoRequest } from './request';
29
+ /**
30
+ * Types for inferring request and response types and client request options.
31
+ */
20
32
  export type { InferRequestType, InferResponseType, ClientRequestOptions } from './client';
33
+ /**
34
+ * Hono framework for building web applications.
35
+ */
21
36
  export { Hono };
@@ -1,2 +1,2 @@
1
1
  export declare const normalizeIntrinsicElementProps: (props: Record<string, unknown>) => void;
2
- export declare const styleObjectForEach: (style: Record<string, string>, fn: (key: string, value: string | null) => void) => void;
2
+ export declare const styleObjectForEach: (style: Record<string, string | number>, fn: (key: string, value: string | null) => void) => void;
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { HonoBase } from '../hono-base';
6
6
  import type { HonoOptions } from '../hono-base';
7
- import type { BlankSchema, Env, Schema } from '../types';
8
- export declare class Hono<E extends Env = Env, S extends Schema = BlankSchema, BasePath extends string = '/'> extends HonoBase<E, S, BasePath> {
7
+ import type { BlankEnv, BlankSchema, Env, Schema } from '../types';
8
+ export declare class Hono<E extends Env = BlankEnv, S extends Schema = BlankSchema, BasePath extends string = '/'> extends HonoBase<E, S, BasePath> {
9
9
  constructor(options?: HonoOptions<E>);
10
10
  }
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { HonoBase } from '../hono-base';
6
6
  import type { HonoOptions } from '../hono-base';
7
- import type { BlankSchema, Env, Schema } from '../types';
8
- export declare class Hono<E extends Env = Env, S extends Schema = BlankSchema, BasePath extends string = '/'> extends HonoBase<E, S, BasePath> {
7
+ import type { BlankEnv, BlankSchema, Env, Schema } from '../types';
8
+ export declare class Hono<E extends Env = BlankEnv, S extends Schema = BlankSchema, BasePath extends string = '/'> extends HonoBase<E, S, BasePath> {
9
9
  constructor(options?: HonoOptions<E>);
10
10
  }
@@ -147,9 +147,43 @@ export declare class HonoRequest<P extends string = '/', I extends Input['out']
147
147
  * @see https://hono.dev/api/request#arraybuffer
148
148
  */
149
149
  arrayBuffer(): Promise<ArrayBuffer>;
150
+ /**
151
+ * Parses the request body as a `Blob`.
152
+ * @example
153
+ * ```ts
154
+ * app.post('/entry', async (c) => {
155
+ * const body = await c.req.blob();
156
+ * });
157
+ * ```
158
+ * @see https://hono.dev/api/request#blob
159
+ */
150
160
  blob(): Promise<Blob>;
161
+ /**
162
+ * Parses the request body as `FormData`.
163
+ * @example
164
+ * ```ts
165
+ * app.post('/entry', async (c) => {
166
+ * const body = await c.req.formData();
167
+ * });
168
+ * ```
169
+ * @see https://hono.dev/api/request#formdata
170
+ */
151
171
  formData(): Promise<FormData>;
172
+ /**
173
+ * Adds validated data to the request.
174
+ *
175
+ * @param target - The target of the validation.
176
+ * @param data - The validated data to add.
177
+ */
152
178
  addValidatedData(target: keyof ValidationTargets, data: {}): void;
179
+ /**
180
+ * Gets validated data from the request.
181
+ *
182
+ * @param target - The target of the validation.
183
+ * @returns The validated data.
184
+ *
185
+ * @see https://hono.dev/api/request#valid
186
+ */
153
187
  valid<T extends keyof I & keyof ValidationTargets>(target: T): InputToDataByTarget<I, T>;
154
188
  /**
155
189
  * `.url()` can get the request url strings.
@@ -2,18 +2,96 @@
2
2
  * @module
3
3
  * This module provides types definitions and variables for the routers.
4
4
  */
5
+ /**
6
+ * Constant representing all HTTP methods in uppercase.
7
+ */
5
8
  export declare const METHOD_NAME_ALL: "ALL";
9
+ /**
10
+ * Constant representing all HTTP methods in lowercase.
11
+ */
6
12
  export declare const METHOD_NAME_ALL_LOWERCASE: "all";
13
+ /**
14
+ * Array of supported HTTP methods.
15
+ */
7
16
  export declare const METHODS: readonly ["get", "post", "put", "delete", "options", "patch"];
17
+ /**
18
+ * Error message indicating that a route cannot be added because the matcher is already built.
19
+ */
8
20
  export declare const MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
21
+ /**
22
+ * Interface representing a router.
23
+ *
24
+ * @template T - The type of the handler.
25
+ */
9
26
  export interface Router<T> {
27
+ /**
28
+ * The name of the router.
29
+ */
10
30
  name: string;
31
+ /**
32
+ * Adds a route to the router.
33
+ *
34
+ * @param method - The HTTP method (e.g., 'get', 'post').
35
+ * @param path - The path for the route.
36
+ * @param handler - The handler for the route.
37
+ */
11
38
  add(method: string, path: string, handler: T): void;
39
+ /**
40
+ * Matches a route based on the given method and path.
41
+ *
42
+ * @param method - The HTTP method (e.g., 'get', 'post').
43
+ * @param path - The path to match.
44
+ * @returns The result of the match.
45
+ */
12
46
  match(method: string, path: string): Result<T>;
13
47
  }
48
+ /**
49
+ * Type representing a map of parameter indices.
50
+ */
14
51
  export type ParamIndexMap = Record<string, number>;
52
+ /**
53
+ * Type representing a stash of parameters.
54
+ */
15
55
  export type ParamStash = string[];
56
+ /**
57
+ * Type representing a map of parameters.
58
+ */
16
59
  export type Params = Record<string, string>;
60
+ /**
61
+ * Type representing the result of a route match.
62
+ *
63
+ * The result can be in one of two formats:
64
+ * 1. An array of handlers with their corresponding parameter index maps, followed by a parameter stash.
65
+ * 2. An array of handlers with their corresponding parameter maps.
66
+ *
67
+ * Example:
68
+ *
69
+ * [[handler, paramIndexMap][], paramArray]
70
+ * ```typescript
71
+ * [
72
+ * [
73
+ * [middlewareA, {}], // '*'
74
+ * [funcA, {'id': 0}], // '/user/:id/*'
75
+ * [funcB, {'id': 0, 'action': 1}], // '/user/:id/:action'
76
+ * ],
77
+ * ['123', 'abc']
78
+ * ]
79
+ * ```
80
+ *
81
+ * [[handler, params][]]
82
+ * ```typescript
83
+ * [
84
+ * [
85
+ * [middlewareA, {}], // '*'
86
+ * [funcA, {'id': '123'}], // '/user/:id/*'
87
+ * [funcB, {'id': '123', 'action': 'abc'}], // '/user/:id/:action'
88
+ * ]
89
+ * ]
90
+ * ```
91
+ */
17
92
  export type Result<T> = [[T, ParamIndexMap][], ParamStash] | [[T, Params][]];
93
+ /**
94
+ * Error class representing an unsupported path error.
95
+ */
18
96
  export declare class UnsupportedPathError extends Error {
19
97
  }
@@ -8,6 +8,7 @@ import type { StatusCode } from './utils/http-status';
8
8
  import type { IfAnyThenEmptyObject, IsAny, JSONValue, Prettify, RemoveBlankRecord, Simplify, UnionToIntersection } from './utils/types';
9
9
  export type Bindings = Record<string, unknown>;
10
10
  export type Variables = Record<string, unknown>;
11
+ export type BlankEnv = {};
11
12
  export type Env = {
12
13
  Bindings?: Bindings;
13
14
  Variables?: Variables;
@@ -32,7 +33,7 @@ export type MiddlewareHandler<E extends Env = any, P extends string = string, I
32
33
  export type H<E extends Env = any, P extends string = any, I extends Input = BlankInput, R extends HandlerResponse<any> = any> = Handler<E, P, I, R> | MiddlewareHandler<E, P, I>;
33
34
  export type NotFoundHandler<E extends Env = any> = (c: Context<E>) => Response | Promise<Response>;
34
35
  export type ErrorHandler<E extends Env = any> = (err: Error, c: Context<E>) => Response | Promise<Response>;
35
- export interface HandlerInterface<E extends Env = Env, M extends string = string, S extends Schema = {}, BasePath extends string = '/'> {
36
+ export interface HandlerInterface<E extends Env = Env, M extends string = string, S extends Schema = BlankSchema, BasePath extends string = '/'> {
36
37
  <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, I extends Input = BlankInput, R extends HandlerResponse<any> = any, E2 extends Env = E>(handler: H<E2, P, I, R>): Hono<IntersectNonAnyTypes<[E, E2]>, S & ToSchema<M, P, I, MergeTypedResponse<R>>, BasePath>;
37
38
  <P extends string, MergedPath extends MergePath<BasePath, P> = MergePath<BasePath, P>, R extends HandlerResponse<any> = any, I extends Input = BlankInput, E2 extends Env = E>(path: P, handler: H<E2, MergedPath, I, R>): Hono<IntersectNonAnyTypes<[E, E2]>, S & ToSchema<M, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
38
39
  <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, I extends Input = BlankInput, I2 extends Input = I, R extends HandlerResponse<any> = any, E2 extends Env = E, E3 extends Env = IntersectNonAnyTypes<[E, E2]>>(...handlers: [H<E2, P, I>, H<E3, P, I2, R>]): Hono<IntersectNonAnyTypes<[E, E2, E3]>, S & ToSchema<M, P, I2, MergeTypedResponse<R>>, BasePath>;
@@ -156,9 +157,9 @@ export interface HandlerInterface<E extends Env = Env, M extends string = string
156
157
  ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11]>, S & ToSchema<M, MergePath<BasePath, P>, I10, MergeTypedResponse<R>>, BasePath>;
157
158
  <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, I extends Input = BlankInput, R extends HandlerResponse<any> = any>(...handlers: H<E, P, I, R>[]): Hono<E, S & ToSchema<M, P, I, MergeTypedResponse<R>>, BasePath>;
158
159
  <P extends string, I extends Input = BlankInput, R extends HandlerResponse<any> = any>(path: P, ...handlers: H<E, MergePath<BasePath, P>, I, R>[]): Hono<E, S & ToSchema<M, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
159
- <P extends string, R extends HandlerResponse<any> = any, I extends Input = {}>(path: P): Hono<E, S & ToSchema<M, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
160
+ <P extends string, R extends HandlerResponse<any> = any, I extends Input = BlankInput>(path: P): Hono<E, S & ToSchema<M, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
160
161
  }
161
- export interface MiddlewareHandlerInterface<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'> {
162
+ export interface MiddlewareHandlerInterface<E extends Env = Env, S extends Schema = BlankSchema, BasePath extends string = '/'> {
162
163
  <E2 extends Env = E>(...handlers: MiddlewareHandler<E2, MergePath<BasePath, ExtractKey<S>>>[]): Hono<IntersectNonAnyTypes<[E, E2]>, S, BasePath>;
163
164
  <E2 extends Env = E>(handler: MiddlewareHandler<E2, MergePath<BasePath, ExtractKey<S>>>): Hono<IntersectNonAnyTypes<[E, E2]>, S, BasePath>;
164
165
  <E2 extends Env = E, E3 extends Env = IntersectNonAnyTypes<[E, E2]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [MiddlewareHandler<E2, P>, MiddlewareHandler<E3, P>]): Hono<IntersectNonAnyTypes<[E, E2, E3]>, S, BasePath>;
@@ -228,7 +229,7 @@ export interface MiddlewareHandlerInterface<E extends Env = Env, S extends Schem
228
229
  ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11]>, S, BasePath>;
229
230
  <P extends string, E2 extends Env = E>(path: P, ...handlers: MiddlewareHandler<E2, MergePath<BasePath, P>>[]): Hono<E, S, BasePath>;
230
231
  }
231
- export interface OnHandlerInterface<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'> {
232
+ export interface OnHandlerInterface<E extends Env = Env, S extends Schema = BlankSchema, BasePath extends string = '/'> {
232
233
  <M extends string, P extends string, MergedPath extends MergePath<BasePath, P> = MergePath<BasePath, P>, R extends HandlerResponse<any> = any, I extends Input = BlankInput, E2 extends Env = E>(method: M, path: P, handler: H<E2, MergedPath, I, R>): Hono<IntersectNonAnyTypes<[E, E2]>, S & ToSchema<M, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
233
234
  <M extends string, P extends string, MergedPath extends MergePath<BasePath, P> = MergePath<BasePath, P>, R extends HandlerResponse<any> = any, I extends Input = BlankInput, I2 extends Input = I, E2 extends Env = E, E3 extends Env = IntersectNonAnyTypes<[E, E2]>>(method: M, path: P, ...handlers: [H<E2, MergedPath, I>, H<E3, MergedPath, I2, R>]): Hono<IntersectNonAnyTypes<[E, E2, E3]>, S & ToSchema<M, MergePath<BasePath, P>, I2, MergeTypedResponse<R>>, BasePath>;
234
235
  <M extends string, P extends string, MergedPath extends MergePath<BasePath, P> = MergePath<BasePath, P>, R extends HandlerResponse<any> = any, I extends Input = BlankInput, I2 extends Input = I, I3 extends Input = I & I2, E2 extends Env = E, E3 extends Env = E, E4 extends Env = IntersectNonAnyTypes<[E, E2, E3]>>(method: M, path: P, ...handlers: [H<E2, MergedPath, I>, H<E3, MergedPath, I2>, H<E4, MergedPath, I3, R>]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4]>, S & ToSchema<M, MergePath<BasePath, P>, I3, MergeTypedResponse<R>>, BasePath>;
@@ -295,7 +296,7 @@ export interface OnHandlerInterface<E extends Env = Env, S extends Schema = {},
295
296
  H<E10, MergedPath, I9>,
296
297
  H<E11, MergedPath, I10>
297
298
  ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11]>, S & ToSchema<M, MergePath<BasePath, P>, I10, MergeTypedResponse<HandlerResponse<any>>>, BasePath>;
298
- <M extends string, P extends string, R extends HandlerResponse<any> = any, I extends Input = {}>(method: M, path: P, ...handlers: H<E, MergePath<BasePath, P>, I, R>[]): Hono<E, S & ToSchema<M, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
299
+ <M extends string, P extends string, R extends HandlerResponse<any> = any, I extends Input = BlankInput>(method: M, path: P, ...handlers: H<E, MergePath<BasePath, P>, I, R>[]): Hono<E, S & ToSchema<M, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
299
300
  <Ms extends string[], P extends string, MergedPath extends MergePath<BasePath, P> = MergePath<BasePath, P>, R extends HandlerResponse<any> = any, I extends Input = BlankInput, E2 extends Env = E>(methods: Ms, path: P, handler: H<E2, MergedPath, I, R>): Hono<IntersectNonAnyTypes<[E, E2]>, S & ToSchema<Ms[number], MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
300
301
  <Ms extends string[], P extends string, MergedPath extends MergePath<BasePath, P> = MergePath<BasePath, P>, R extends HandlerResponse<any> = any, I extends Input = BlankInput, I2 extends Input = I, E2 extends Env = E, E3 extends Env = IntersectNonAnyTypes<[E, E2]>>(methods: Ms, path: P, ...handlers: [H<E2, MergedPath, I>, H<E3, MergedPath, I2, R>]): Hono<IntersectNonAnyTypes<[E, E2, E3]>, S & ToSchema<Ms[number], MergePath<BasePath, P>, I2, MergeTypedResponse<R>>, BasePath>;
301
302
  <Ms extends string[], P extends string, MergedPath extends MergePath<BasePath, P> = MergePath<BasePath, P>, R extends HandlerResponse<any> = any, I extends Input = BlankInput, I2 extends Input = I, I3 extends Input = I & I2, E2 extends Env = E, E3 extends Env = E, E4 extends Env = IntersectNonAnyTypes<[E, E2, E3]>>(methods: Ms, path: P, ...handlers: [H<E2, MergedPath, I>, H<E3, MergedPath, I2>, H<E4, MergedPath, I3, R>]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4]>, S & ToSchema<Ms[number], MergePath<BasePath, P>, I3, MergeTypedResponse<R>>, BasePath>;
@@ -362,7 +363,7 @@ export interface OnHandlerInterface<E extends Env = Env, S extends Schema = {},
362
363
  H<E10, MergedPath, I9>,
363
364
  H<E11, MergedPath, I10>
364
365
  ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11]>, S & ToSchema<Ms[number], MergePath<BasePath, P>, I10, MergeTypedResponse<HandlerResponse<any>>>, BasePath>;
365
- <P extends string, R extends HandlerResponse<any> = any, I extends Input = {}>(methods: string[], path: P, ...handlers: H<E, MergePath<BasePath, P>, I, R>[]): Hono<E, S & ToSchema<string, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
366
+ <P extends string, R extends HandlerResponse<any> = any, I extends Input = BlankInput>(methods: string[], path: P, ...handlers: H<E, MergePath<BasePath, P>, I, R>[]): Hono<E, S & ToSchema<string, MergePath<BasePath, P>, I, MergeTypedResponse<R>>, BasePath>;
366
367
  <I extends Input = BlankInput, R extends HandlerResponse<any> = any>(methods: string | string[], paths: string[], ...handlers: H<E, any, I, R>[]): Hono<E, S & ToSchema<string, string, I, MergeTypedResponse<R>>, BasePath>;
367
368
  }
368
369
  type ExtractKey<S> = S extends Record<infer Key, unknown> ? Key extends string ? Key : never : string;
@@ -8,7 +8,7 @@ var validator = (target, validationFunc) => {
8
8
  const contentType = c.req.header("Content-Type");
9
9
  switch (target) {
10
10
  case "json":
11
- if (!contentType || !/^application\/([a-z-]+\+)?json/.test(contentType)) {
11
+ if (!contentType || !/^application\/([a-z-\.]+\+)?json/.test(contentType)) {
12
12
  const message = `Invalid HTTP header: Content-Type=${contentType}`;
13
13
  throw new HTTPException(400, { message });
14
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "4.4.0",
3
+ "version": "4.4.2",
4
4
  "description": "Ultrafast web framework for the Edges",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",
@@ -583,7 +583,7 @@
583
583
  "eslint": "^8.55.0",
584
584
  "glob": "7.2.3",
585
585
  "jsdom": "^22.1.0",
586
- "msw": "1.3.2",
586
+ "msw": "^2.3.0",
587
587
  "np": "7.7.0",
588
588
  "prettier": "^2.6.2",
589
589
  "publint": "^0.1.8",