hono 4.2.1 → 4.2.3

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.
@@ -52,7 +52,7 @@ class ClientRequestImpl {
52
52
  this.url = url;
53
53
  this.method = method;
54
54
  }
55
- fetch = (args, opt) => {
55
+ fetch = async (args, opt) => {
56
56
  if (args) {
57
57
  if (args.query) {
58
58
  for (const [k, v] of Object.entries(args.query)) {
@@ -88,7 +88,7 @@ class ClientRequestImpl {
88
88
  let setBody = !(methodUpperCase === "GET" || methodUpperCase === "HEAD");
89
89
  const headerValues = {
90
90
  ...args?.header ?? {},
91
- ...opt?.headers ? opt.headers : {}
91
+ ...typeof opt?.headers === "function" ? await opt.headers() : opt?.headers ? opt.headers : {}
92
92
  };
93
93
  if (args?.cookie) {
94
94
  const cookies = [];
@@ -134,7 +134,10 @@ const hc = (baseUrl, options) => createProxy((opts) => {
134
134
  return new URL(url);
135
135
  }
136
136
  if (method === "ws") {
137
- const targetUrl = opts.args[0] && opts.args[0].param ? (0, import_utils.replaceUrlParam)(url, opts.args[0].param) : url;
137
+ const targetUrl = (0, import_utils.replaceUrlProtocol)(
138
+ opts.args[0] && opts.args[0].param ? (0, import_utils.replaceUrlParam)(url, opts.args[0].param) : url,
139
+ "ws"
140
+ );
138
141
  return new WebSocket(targetUrl);
139
142
  }
140
143
  const req = new ClientRequestImpl(url, method);
@@ -21,7 +21,8 @@ __export(utils_exports, {
21
21
  deepMerge: () => deepMerge,
22
22
  mergePath: () => mergePath,
23
23
  removeIndexString: () => removeIndexString,
24
- replaceUrlParam: () => replaceUrlParam
24
+ replaceUrlParam: () => replaceUrlParam,
25
+ replaceUrlProtocol: () => replaceUrlProtocol
25
26
  });
26
27
  module.exports = __toCommonJS(utils_exports);
27
28
  const mergePath = (base, path) => {
@@ -37,6 +38,14 @@ const replaceUrlParam = (urlString, params) => {
37
38
  }
38
39
  return urlString;
39
40
  };
41
+ const replaceUrlProtocol = (urlString, protocol) => {
42
+ switch (protocol) {
43
+ case "ws":
44
+ return urlString.replace(/^http/, "ws");
45
+ case "http":
46
+ return urlString.replace(/^ws/, "http");
47
+ }
48
+ };
40
49
  const removeIndexString = (urlSting) => {
41
50
  return urlSting.replace(/\/index$/, "");
42
51
  };
@@ -63,5 +72,6 @@ function deepMerge(target, source) {
63
72
  deepMerge,
64
73
  mergePath,
65
74
  removeIndexString,
66
- replaceUrlParam
75
+ replaceUrlParam,
76
+ replaceUrlProtocol
67
77
  });
@@ -19,7 +19,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
20
  var ssg_exports = {};
21
21
  __export(ssg_exports, {
22
- SSG_DISABLED_RESPONSE: () => import_middleware.SSG_DISABLED_RESPONSE,
22
+ X_HONO_DISABLE_SSG_HEADER_KEY: () => import_middleware.X_HONO_DISABLE_SSG_HEADER_KEY,
23
23
  disableSSG: () => import_middleware.disableSSG,
24
24
  isSSGContext: () => import_middleware.isSSGContext,
25
25
  onlySSG: () => import_middleware.onlySSG,
@@ -30,7 +30,7 @@ __reExport(ssg_exports, require("./ssg"), module.exports);
30
30
  var import_middleware = require("./middleware");
31
31
  // Annotate the CommonJS export names for ESM import in node:
32
32
  0 && (module.exports = {
33
- SSG_DISABLED_RESPONSE,
33
+ X_HONO_DISABLE_SSG_HEADER_KEY,
34
34
  disableSSG,
35
35
  isSSGContext,
36
36
  onlySSG,
@@ -20,6 +20,7 @@ var middleware_exports = {};
20
20
  __export(middleware_exports, {
21
21
  SSG_CONTEXT: () => SSG_CONTEXT,
22
22
  SSG_DISABLED_RESPONSE: () => SSG_DISABLED_RESPONSE,
23
+ X_HONO_DISABLE_SSG_HEADER_KEY: () => X_HONO_DISABLE_SSG_HEADER_KEY,
23
24
  disableSSG: () => disableSSG,
24
25
  isSSGContext: () => isSSGContext,
25
26
  onlySSG: () => onlySSG,
@@ -27,7 +28,17 @@ __export(middleware_exports, {
27
28
  });
28
29
  module.exports = __toCommonJS(middleware_exports);
29
30
  const SSG_CONTEXT = "HONO_SSG_CONTEXT";
30
- const SSG_DISABLED_RESPONSE = new Response("SSG is disabled", { status: 404 });
31
+ const X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg";
32
+ const SSG_DISABLED_RESPONSE = (() => {
33
+ try {
34
+ return new Response("SSG is disabled", {
35
+ status: 404,
36
+ headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" }
37
+ });
38
+ } catch (e) {
39
+ return null;
40
+ }
41
+ })();
31
42
  const ssgParams = (params) => async (c, next) => {
32
43
  ;
33
44
  c.req.raw.ssgParams = Array.isArray(params) ? params : await params(c);
@@ -36,7 +47,8 @@ const ssgParams = (params) => async (c, next) => {
36
47
  const isSSGContext = (c) => !!c.env?.[SSG_CONTEXT];
37
48
  const disableSSG = () => async function disableSSG2(c, next) {
38
49
  if (isSSGContext(c)) {
39
- return SSG_DISABLED_RESPONSE;
50
+ c.header(X_HONO_DISABLE_SSG_HEADER_KEY, "true");
51
+ return c.notFound();
40
52
  }
41
53
  await next();
42
54
  };
@@ -50,6 +62,7 @@ const onlySSG = () => async function onlySSG2(c, next) {
50
62
  0 && (module.exports = {
51
63
  SSG_CONTEXT,
52
64
  SSG_DISABLED_RESPONSE,
65
+ X_HONO_DISABLE_SSG_HEADER_KEY,
53
66
  disableSSG,
54
67
  isSSGContext,
55
68
  onlySSG,
@@ -109,7 +109,7 @@ const fetchRoutesContent = function* (app, beforeRequestHook, afterResponseHook,
109
109
  [import_middleware.SSG_CONTEXT]: true
110
110
  })
111
111
  );
112
- if (response === import_middleware.SSG_DISABLED_RESPONSE) {
112
+ if (response.headers.get(import_middleware.X_HONO_DISABLE_SSG_HEADER_KEY)) {
113
113
  resolveReq(void 0);
114
114
  return;
115
115
  }
@@ -30,7 +30,7 @@ const RequestContext = (0, import_jsx.createContext)(null);
30
30
  const createRenderer = (c, Layout, component, options) => (children, props) => {
31
31
  const docType = typeof options?.docType === "string" ? options.docType : options?.docType === false ? "" : "<!DOCTYPE html>";
32
32
  const currentLayout = component ? (0, import_jsx.jsx)(
33
- component,
33
+ (props2) => component(props2, c),
34
34
  {
35
35
  ...{ Layout, ...props }
36
36
  },
@@ -59,7 +59,7 @@ const jsxRenderer = (component, options) => function jsxRenderer2(c, next) {
59
59
  const Layout = c.getLayout() ?? import_jsx.Fragment;
60
60
  if (component) {
61
61
  c.setLayout((props) => {
62
- return component({ ...props, Layout });
62
+ return component({ ...props, Layout }, c);
63
63
  });
64
64
  }
65
65
  c.setRenderer(createRenderer(c, Layout, component, options));
@@ -1,6 +1,12 @@
1
1
  // src/client/client.ts
2
2
  import { serialize } from "../utils/cookie.js";
3
- import { deepMerge, mergePath, removeIndexString, replaceUrlParam } from "./utils.js";
3
+ import {
4
+ deepMerge,
5
+ mergePath,
6
+ removeIndexString,
7
+ replaceUrlParam,
8
+ replaceUrlProtocol
9
+ } from "./utils.js";
4
10
  var createProxy = (callback, path) => {
5
11
  const proxy = new Proxy(() => {
6
12
  }, {
@@ -30,7 +36,7 @@ var ClientRequestImpl = class {
30
36
  this.url = url;
31
37
  this.method = method;
32
38
  }
33
- fetch = (args, opt) => {
39
+ fetch = async (args, opt) => {
34
40
  if (args) {
35
41
  if (args.query) {
36
42
  for (const [k, v] of Object.entries(args.query)) {
@@ -66,7 +72,7 @@ var ClientRequestImpl = class {
66
72
  let setBody = !(methodUpperCase === "GET" || methodUpperCase === "HEAD");
67
73
  const headerValues = {
68
74
  ...args?.header ?? {},
69
- ...opt?.headers ? opt.headers : {}
75
+ ...typeof opt?.headers === "function" ? await opt.headers() : opt?.headers ? opt.headers : {}
70
76
  };
71
77
  if (args?.cookie) {
72
78
  const cookies = [];
@@ -112,7 +118,10 @@ var hc = (baseUrl, options) => createProxy((opts) => {
112
118
  return new URL(url);
113
119
  }
114
120
  if (method === "ws") {
115
- const targetUrl = opts.args[0] && opts.args[0].param ? replaceUrlParam(url, opts.args[0].param) : url;
121
+ const targetUrl = replaceUrlProtocol(
122
+ opts.args[0] && opts.args[0].param ? replaceUrlParam(url, opts.args[0].param) : url,
123
+ "ws"
124
+ );
116
125
  return new WebSocket(targetUrl);
117
126
  }
118
127
  const req = new ClientRequestImpl(url, method);
@@ -12,6 +12,14 @@ var replaceUrlParam = (urlString, params) => {
12
12
  }
13
13
  return urlString;
14
14
  };
15
+ var replaceUrlProtocol = (urlString, protocol) => {
16
+ switch (protocol) {
17
+ case "ws":
18
+ return urlString.replace(/^http/, "ws");
19
+ case "http":
20
+ return urlString.replace(/^ws/, "http");
21
+ }
22
+ };
15
23
  var removeIndexString = (urlSting) => {
16
24
  return urlSting.replace(/\/index$/, "");
17
25
  };
@@ -37,5 +45,6 @@ export {
37
45
  deepMerge,
38
46
  mergePath,
39
47
  removeIndexString,
40
- replaceUrlParam
48
+ replaceUrlParam,
49
+ replaceUrlProtocol
41
50
  };
@@ -1,8 +1,14 @@
1
1
  // src/helper/ssg/index.ts
2
2
  export * from "./ssg.js";
3
- import { SSG_DISABLED_RESPONSE, ssgParams, isSSGContext, disableSSG, onlySSG } from "./middleware.js";
3
+ import {
4
+ X_HONO_DISABLE_SSG_HEADER_KEY,
5
+ ssgParams,
6
+ isSSGContext,
7
+ disableSSG,
8
+ onlySSG
9
+ } from "./middleware.js";
4
10
  export {
5
- SSG_DISABLED_RESPONSE,
11
+ X_HONO_DISABLE_SSG_HEADER_KEY,
6
12
  disableSSG,
7
13
  isSSGContext,
8
14
  onlySSG,
@@ -1,6 +1,16 @@
1
1
  // src/helper/ssg/middleware.ts
2
2
  var SSG_CONTEXT = "HONO_SSG_CONTEXT";
3
- var SSG_DISABLED_RESPONSE = new Response("SSG is disabled", { status: 404 });
3
+ var X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg";
4
+ var SSG_DISABLED_RESPONSE = (() => {
5
+ try {
6
+ return new Response("SSG is disabled", {
7
+ status: 404,
8
+ headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" }
9
+ });
10
+ } catch (e) {
11
+ return null;
12
+ }
13
+ })();
4
14
  var ssgParams = (params) => async (c, next) => {
5
15
  ;
6
16
  c.req.raw.ssgParams = Array.isArray(params) ? params : await params(c);
@@ -9,7 +19,8 @@ var ssgParams = (params) => async (c, next) => {
9
19
  var isSSGContext = (c) => !!c.env?.[SSG_CONTEXT];
10
20
  var disableSSG = () => async function disableSSG2(c, next) {
11
21
  if (isSSGContext(c)) {
12
- return SSG_DISABLED_RESPONSE;
22
+ c.header(X_HONO_DISABLE_SSG_HEADER_KEY, "true");
23
+ return c.notFound();
13
24
  }
14
25
  await next();
15
26
  };
@@ -22,6 +33,7 @@ var onlySSG = () => async function onlySSG2(c, next) {
22
33
  export {
23
34
  SSG_CONTEXT,
24
35
  SSG_DISABLED_RESPONSE,
36
+ X_HONO_DISABLE_SSG_HEADER_KEY,
25
37
  disableSSG,
26
38
  isSSGContext,
27
39
  onlySSG,
@@ -2,7 +2,7 @@
2
2
  import { replaceUrlParam } from "../../client/utils.js";
3
3
  import { createPool } from "../../utils/concurrent.js";
4
4
  import { getExtension } from "../../utils/mime.js";
5
- import { SSG_DISABLED_RESPONSE, SSG_CONTEXT } from "./middleware.js";
5
+ import { X_HONO_DISABLE_SSG_HEADER_KEY, SSG_CONTEXT } from "./middleware.js";
6
6
  import { joinPaths, dirname, filterStaticGenerateRoutes } from "./utils.js";
7
7
  var DEFAULT_CONCURRENCY = 2;
8
8
  var generateFilePath = (routePath, outDir, mimeType, extensionMap) => {
@@ -84,7 +84,7 @@ var fetchRoutesContent = function* (app, beforeRequestHook, afterResponseHook, c
84
84
  [SSG_CONTEXT]: true
85
85
  })
86
86
  );
87
- if (response === SSG_DISABLED_RESPONSE) {
87
+ if (response.headers.get(X_HONO_DISABLE_SSG_HEADER_KEY)) {
88
88
  resolveReq(void 0);
89
89
  return;
90
90
  }
@@ -6,7 +6,7 @@ var RequestContext = createContext(null);
6
6
  var createRenderer = (c, Layout, component, options) => (children, props) => {
7
7
  const docType = typeof options?.docType === "string" ? options.docType : options?.docType === false ? "" : "<!DOCTYPE html>";
8
8
  const currentLayout = component ? jsx(
9
- component,
9
+ (props2) => component(props2, c),
10
10
  {
11
11
  ...{ Layout, ...props }
12
12
  },
@@ -35,7 +35,7 @@ var jsxRenderer = (component, options) => function jsxRenderer2(c, next) {
35
35
  const Layout = c.getLayout() ?? Fragment;
36
36
  if (component) {
37
37
  c.setLayout((props) => {
38
- return component({ ...props, Layout });
38
+ return component({ ...props, Layout }, c);
39
39
  });
40
40
  }
41
41
  c.setRenderer(createRenderer(c, Layout, component, options));
@@ -4,10 +4,10 @@ import type { Schema } from '../types';
4
4
  import type { HasRequiredKeys } from '../utils/types';
5
5
  type HonoRequest = (typeof Hono.prototype)['request'];
6
6
  export type ClientRequestOptions<T = unknown> = keyof T extends never ? {
7
- headers?: Record<string, string>;
7
+ headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
8
8
  fetch?: typeof fetch | HonoRequest;
9
9
  } : {
10
- headers: T;
10
+ headers: T | (() => T | Promise<T>);
11
11
  fetch?: typeof fetch | HonoRequest;
12
12
  };
13
13
  export type ClientRequest<S extends Schema> = {
@@ -32,7 +32,7 @@ export type ClientRequest<S extends Schema> = {
32
32
  input: infer I;
33
33
  } ? (args?: Omit<I, 'json'>) => WebSocket : never : never;
34
34
  };
35
- type BlankRecordToNever<T> = T extends any ? (keyof T extends never ? never : T) : never;
35
+ type BlankRecordToNever<T> = T extends any ? T extends null ? null : keyof T extends never ? never : T : never;
36
36
  export interface ClientResponse<T> {
37
37
  readonly body: ReadableStream | null;
38
38
  readonly bodyUsed: boolean;
@@ -1,4 +1,5 @@
1
1
  export declare const mergePath: (base: string, path: string) => string;
2
2
  export declare const replaceUrlParam: (urlString: string, params: Record<string, string>) => string;
3
+ export declare const replaceUrlProtocol: (urlString: string, protocol: 'ws' | 'http') => string;
3
4
  export declare const removeIndexString: (urlSting: string) => string;
4
5
  export declare function deepMerge<T>(target: T, source: Record<string, unknown>): T;
@@ -1,2 +1,2 @@
1
1
  export * from './ssg';
2
- export { SSG_DISABLED_RESPONSE, ssgParams, isSSGContext, disableSSG, onlySSG } from './middleware';
2
+ export { X_HONO_DISABLE_SSG_HEADER_KEY, ssgParams, isSSGContext, disableSSG, onlySSG, } from './middleware';
@@ -1,6 +1,12 @@
1
1
  import type { Context } from '../../context';
2
2
  import type { Env, MiddlewareHandler } from '../../types';
3
3
  export declare const SSG_CONTEXT = "HONO_SSG_CONTEXT";
4
+ export declare const X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg";
5
+ /**
6
+ * @deprecated
7
+ * Use `X_HONO_DISABLE_SSG_HEADER_KEY` instead.
8
+ * This constant will be removed in the next minor version.
9
+ */
4
10
  export declare const SSG_DISABLED_RESPONSE: Response;
5
11
  interface SSGParam {
6
12
  [key: string]: string;
@@ -1,13 +1,15 @@
1
1
  import type { Context, PropsForRenderer } from '../../context';
2
2
  import type { FC, PropsWithChildren } from '../../jsx';
3
3
  import type { Env, Input, MiddlewareHandler } from '../../types';
4
+ import type { HtmlEscapedString } from '../../utils/html';
4
5
  export declare const RequestContext: import("../../jsx").Context<Context<any, any, {}> | null>;
5
6
  type RendererOptions = {
6
7
  docType?: boolean | string;
7
8
  stream?: boolean | Record<string, string>;
8
9
  };
9
- export declare const jsxRenderer: (component?: FC<PropsWithChildren<PropsForRenderer & {
10
+ type ComponentWithChildren = (props: PropsWithChildren<PropsForRenderer & {
10
11
  Layout: FC;
11
- }>>, options?: RendererOptions) => MiddlewareHandler;
12
+ }>, c: Context) => HtmlEscapedString | Promise<HtmlEscapedString>;
13
+ export declare const jsxRenderer: (component?: ComponentWithChildren, options?: RendererOptions) => MiddlewareHandler;
12
14
  export declare const useRequestContext: <E extends Env = any, P extends string = any, I extends Input = {}>() => Context<E, P, I>;
13
15
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "4.2.1",
3
+ "version": "4.2.3",
4
4
  "description": "Ultrafast web framework for the Edges",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",
@@ -382,6 +382,9 @@
382
382
  "etag": [
383
383
  "./dist/types/middleware/etag"
384
384
  ],
385
+ "trailing-slash": [
386
+ "./dist/types/middleware/trailing-slash"
387
+ ],
385
388
  "html": [
386
389
  "./dist/types/helper/html"
387
390
  ],