hono 3.0.1 → 3.0.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.
package/README.md CHANGED
@@ -38,12 +38,18 @@ app.get('/', (c) => c.text('Hono!'))
38
38
  export default app
39
39
  ```
40
40
 
41
+ ## Quick Start
42
+
43
+ ```
44
+ npm create hono@latest my-app
45
+ ```
46
+
41
47
  ## Features
42
48
 
43
49
  - **Ultrafast** - The routers are really fast and smart. Not using linear loops. Fast.
44
50
  - **Multi-runtime** - Works on Cloudflare Workers, Fastly Compute@Edge, Deno, Bun, Lagon, or Node.js. The same code runs on all platforms.
45
51
  - **Batteries Included** - Hono has built-in middleware, custom middleware, and third-party middleware. Batteries included.
46
- - **Fine DX** - First-class TypeScript support. Now, we've got "Types".
52
+ - **Delightful DX** - First-class TypeScript support. Now, we've got "Types".
47
53
  - **Small** - About 20kB. Zero-dependencies. Using only Web Standard API.
48
54
 
49
55
  ## Benchmarks
@@ -1,7 +1,10 @@
1
1
  // src/adapter/cloudflare-pages/handler.ts
2
2
  import { Hono } from "../../hono.js";
3
- var handle = (subApp, path = "/") => ({ request, env, waitUntil }) => new Hono().route(path, subApp).fetch(request, env, { waitUntil, passThroughOnException: () => {
4
- } });
3
+ var handle = (subApp, path) => ({ request, env, waitUntil }) => {
4
+ const app = path ? new Hono().route(path, subApp) : subApp;
5
+ return app.fetch(request, env, { waitUntil, passThroughOnException: () => {
6
+ } });
7
+ };
5
8
  export {
6
9
  handle
7
10
  };
@@ -1,6 +1,9 @@
1
1
  // src/adapter/nextjs/handler.ts
2
2
  import { Hono } from "../../hono.js";
3
- var handle = (subApp, path = "/") => async (req) => new Hono().route(path, subApp).fetch(req);
3
+ var handle = (subApp, path) => (req) => {
4
+ const app = path ? new Hono().route(path, subApp) : subApp;
5
+ return app.fetch(req);
6
+ };
4
7
  export {
5
8
  handle
6
9
  };
@@ -22,8 +22,11 @@ __export(handler_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(handler_exports);
24
24
  var import_hono = require("../../hono");
25
- const handle = (subApp, path = "/") => ({ request, env, waitUntil }) => new import_hono.Hono().route(path, subApp).fetch(request, env, { waitUntil, passThroughOnException: () => {
26
- } });
25
+ const handle = (subApp, path) => ({ request, env, waitUntil }) => {
26
+ const app = path ? new import_hono.Hono().route(path, subApp) : subApp;
27
+ return app.fetch(request, env, { waitUntil, passThroughOnException: () => {
28
+ } });
29
+ };
27
30
  // Annotate the CommonJS export names for ESM import in node:
28
31
  0 && (module.exports = {
29
32
  handle
@@ -22,7 +22,10 @@ __export(handler_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(handler_exports);
24
24
  var import_hono = require("../../hono");
25
- const handle = (subApp, path = "/") => async (req) => new import_hono.Hono().route(path, subApp).fetch(req);
25
+ const handle = (subApp, path) => (req) => {
26
+ const app = path ? new import_hono.Hono().route(path, subApp) : subApp;
27
+ return app.fetch(req);
28
+ };
26
29
  // Annotate the CommonJS export names for ESM import in node:
27
30
  0 && (module.exports = {
28
31
  handle
@@ -89,7 +89,7 @@ class ClientRequestImpl {
89
89
  }
90
90
  methodUpperCase = this.method.toUpperCase();
91
91
  setBody = !(methodUpperCase === "GET" || methodUpperCase === "HEAD");
92
- return fetch(url, {
92
+ return (opt?.fetch || fetch)(url, {
93
93
  body: setBody ? this.rBody : void 0,
94
94
  method: methodUpperCase,
95
95
  headers
package/dist/cjs/hono.js CHANGED
@@ -51,7 +51,7 @@ class Hono extends defineDynamicClass() {
51
51
  routers: [new import_reg_exp_router.RegExpRouter(), new import_trie_router.TrieRouter()]
52
52
  });
53
53
  this.strict = true;
54
- this._tempPath = "";
54
+ this.basePath = "";
55
55
  this.path = "*";
56
56
  this.routes = [];
57
57
  this.notFoundHandler = notFoundHandler;
@@ -63,7 +63,15 @@ class Hono extends defineDynamicClass() {
63
63
  return this.dispatch(request, executionCtx, Env);
64
64
  };
65
65
  this.request = async (input, requestInit) => {
66
- const req = input instanceof Request ? input : new Request(input, requestInit);
66
+ if (input instanceof Request) {
67
+ if (requestInit !== void 0) {
68
+ input = new Request(input, requestInit);
69
+ }
70
+ return await this.fetch(input);
71
+ }
72
+ input = input.toString();
73
+ const path = /^https?:\/\//.test(input) ? input : `http://localhost${(0, import_url.mergePath)("/", input)}`;
74
+ const req = new Request(path, requestInit);
67
75
  return await this.fetch(req);
68
76
  };
69
77
  const allMethods = [...import_router.METHODS, import_router.METHOD_NAME_ALL_LOWERCASE];
@@ -106,16 +114,24 @@ class Hono extends defineDynamicClass() {
106
114
  };
107
115
  Object.assign(this, init);
108
116
  }
117
+ clone() {
118
+ const clone = new Hono({
119
+ router: this.router,
120
+ strict: this.strict
121
+ });
122
+ clone.routes = this.routes;
123
+ return clone;
124
+ }
109
125
  route(path, app) {
110
- this._tempPath = path;
126
+ const subApp = this.clone();
127
+ subApp.basePath = (0, import_url.mergePath)(this.basePath, path);
111
128
  if (app) {
112
129
  app.routes.map((r) => {
113
130
  const handler = app.errorHandler === errorHandler ? r.handler : async (c, next) => (await (0, import_compose.compose)([r.handler], app.errorHandler)(c, next)).res;
114
- this.addRoute(r.method, r.path, handler);
131
+ subApp.addRoute(r.method, r.path, handler);
115
132
  });
116
- this._tempPath = "";
117
133
  }
118
- return this;
134
+ return subApp;
119
135
  }
120
136
  onError(handler) {
121
137
  this.errorHandler = handler;
@@ -135,8 +151,8 @@ class Hono extends defineDynamicClass() {
135
151
  }
136
152
  addRoute(method, path, handler) {
137
153
  method = method.toUpperCase();
138
- if (this._tempPath) {
139
- path = (0, import_url.mergePath)(this._tempPath, path);
154
+ if (this.basePath) {
155
+ path = (0, import_url.mergePath)(this.basePath, path);
140
156
  }
141
157
  this.router.add(method, path, handler);
142
158
  const r = { path, method, handler };
@@ -31,36 +31,18 @@ const encodeBase64 = (str) => {
31
31
  if (str === null) {
32
32
  throw new TypeError('1st argument of "encodeBase64" should not be null.');
33
33
  }
34
- try {
35
- const encoder = new TextEncoder();
36
- const bytes = encoder.encode(str);
37
- return btoa(String.fromCharCode(...bytes));
38
- } catch {
39
- }
40
- try {
41
- return Buffer.from(str).toString("base64");
42
- } catch (e) {
43
- console.error('Error: If you want to do "encodeBase64", polyfill "buffer" module.');
44
- throw e;
45
- }
34
+ const encoder = new TextEncoder();
35
+ const bytes = encoder.encode(str);
36
+ return btoa(String.fromCharCode(...bytes));
46
37
  };
47
38
  const decodeBase64 = (str) => {
48
39
  if (str === null) {
49
40
  throw new TypeError('1st argument of "decodeBase64" should not be null.');
50
41
  }
51
- try {
52
- const text = atob(str);
53
- const bytes = new Uint8Array(text.split("").map((c) => c.charCodeAt(0)));
54
- const decoder = new TextDecoder();
55
- return decoder.decode(bytes);
56
- } catch {
57
- }
58
- try {
59
- return Buffer.from(str, "base64").toString();
60
- } catch (e) {
61
- console.error('Error: If you want to do "decodeBase64", polyfill "buffer" module.');
62
- throw e;
63
- }
42
+ const text = atob(str);
43
+ const bytes = new Uint8Array(text.split("").map((c) => c.charCodeAt(0)));
44
+ const decoder = new TextDecoder();
45
+ return decoder.decode(bytes);
64
46
  };
65
47
  const encodeBase64URL = (str) => {
66
48
  return encodeBase64(str).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
@@ -83,14 +65,7 @@ const utf8ToUint8Array = (str) => {
83
65
  return encoder.encode(str);
84
66
  };
85
67
  const arrayBufferToBase64 = async (buf) => {
86
- if (typeof btoa === "function") {
87
- return btoa(String.fromCharCode(...new Uint8Array(buf)));
88
- }
89
- try {
90
- return Buffer.from(String.fromCharCode(...new Uint8Array(buf))).toString("base64");
91
- } catch (e) {
92
- }
93
- return "";
68
+ return btoa(String.fromCharCode(...new Uint8Array(buf)));
94
69
  };
95
70
  const arrayBufferToBase64URL = async (buf) => {
96
71
  return (await arrayBufferToBase64(buf)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
@@ -21,13 +21,14 @@ __export(validator_exports, {
21
21
  validator: () => validator
22
22
  });
23
23
  module.exports = __toCommonJS(validator_exports);
24
+ var import_body = require("../utils/body");
24
25
  const validator = (target, validationFunc) => {
25
26
  return async (c, next) => {
26
27
  let value = {};
27
28
  switch (target) {
28
29
  case "json":
29
30
  try {
30
- value = await c.req.json();
31
+ value = await c.req.raw.clone().json();
31
32
  } catch {
32
33
  console.error("Error: Malformed JSON in request body");
33
34
  return c.json(
@@ -40,7 +41,7 @@ const validator = (target, validationFunc) => {
40
41
  }
41
42
  break;
42
43
  case "form":
43
- value = await c.req.parseBody();
44
+ value = await (0, import_body.parseBody)(c.req.raw.clone());
44
45
  break;
45
46
  case "query":
46
47
  value = c.req.query();
@@ -67,7 +67,7 @@ var ClientRequestImpl = class {
67
67
  }
68
68
  methodUpperCase = this.method.toUpperCase();
69
69
  setBody = !(methodUpperCase === "GET" || methodUpperCase === "HEAD");
70
- return fetch(url, {
70
+ return (opt?.fetch || fetch)(url, {
71
71
  body: setBody ? this.rBody : void 0,
72
72
  method: methodUpperCase,
73
73
  headers
package/dist/hono.js CHANGED
@@ -29,7 +29,7 @@ var Hono = class extends defineDynamicClass() {
29
29
  routers: [new RegExpRouter(), new TrieRouter()]
30
30
  });
31
31
  this.strict = true;
32
- this._tempPath = "";
32
+ this.basePath = "";
33
33
  this.path = "*";
34
34
  this.routes = [];
35
35
  this.notFoundHandler = notFoundHandler;
@@ -41,7 +41,15 @@ var Hono = class extends defineDynamicClass() {
41
41
  return this.dispatch(request, executionCtx, Env);
42
42
  };
43
43
  this.request = async (input, requestInit) => {
44
- const req = input instanceof Request ? input : new Request(input, requestInit);
44
+ if (input instanceof Request) {
45
+ if (requestInit !== void 0) {
46
+ input = new Request(input, requestInit);
47
+ }
48
+ return await this.fetch(input);
49
+ }
50
+ input = input.toString();
51
+ const path = /^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`;
52
+ const req = new Request(path, requestInit);
45
53
  return await this.fetch(req);
46
54
  };
47
55
  const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE];
@@ -84,16 +92,24 @@ var Hono = class extends defineDynamicClass() {
84
92
  };
85
93
  Object.assign(this, init);
86
94
  }
95
+ clone() {
96
+ const clone = new Hono({
97
+ router: this.router,
98
+ strict: this.strict
99
+ });
100
+ clone.routes = this.routes;
101
+ return clone;
102
+ }
87
103
  route(path, app) {
88
- this._tempPath = path;
104
+ const subApp = this.clone();
105
+ subApp.basePath = mergePath(this.basePath, path);
89
106
  if (app) {
90
107
  app.routes.map((r) => {
91
108
  const handler = app.errorHandler === errorHandler ? r.handler : async (c, next) => (await compose([r.handler], app.errorHandler)(c, next)).res;
92
- this.addRoute(r.method, r.path, handler);
109
+ subApp.addRoute(r.method, r.path, handler);
93
110
  });
94
- this._tempPath = "";
95
111
  }
96
- return this;
112
+ return subApp;
97
113
  }
98
114
  onError(handler) {
99
115
  this.errorHandler = handler;
@@ -113,8 +129,8 @@ var Hono = class extends defineDynamicClass() {
113
129
  }
114
130
  addRoute(method, path, handler) {
115
131
  method = method.toUpperCase();
116
- if (this._tempPath) {
117
- path = mergePath(this._tempPath, path);
132
+ if (this.basePath) {
133
+ path = mergePath(this.basePath, path);
118
134
  }
119
135
  this.router.add(method, path, handler);
120
136
  const r = { path, method, handler };
@@ -1,7 +1,7 @@
1
1
  import { Hono } from '../../hono';
2
2
  import type { Env } from '../../types';
3
3
  interface HandleInterface {
4
- <E extends Env>(subApp: Hono<E>, path?: string): (req: Request) => Promise<Response>;
4
+ <E extends Env>(subApp: Hono<E>, path?: string): (req: Request) => Response | Promise<Response>;
5
5
  }
6
6
  export declare const handle: HandleInterface;
7
7
  export {};
@@ -1,4 +1,4 @@
1
1
  import type { Hono } from '../hono';
2
2
  import type { UnionToIntersection } from '../utils/types';
3
3
  import type { Client, RequestOptions } from './types';
4
- export declare const hc: <T extends Hono<any, {}>>(baseUrl: string, options?: RequestOptions) => UnionToIntersection<Client<T>>;
4
+ export declare const hc: <T extends Hono<any, any, any>>(baseUrl: string, options?: RequestOptions) => UnionToIntersection<Client<T>>;
@@ -1,5 +1,6 @@
1
1
  import type { Hono } from '../hono';
2
2
  import type { ValidationTargets } from '../types';
3
+ import type { RemoveBlankRecord } from '../utils/types';
3
4
  declare type MethodName = `$${string}`;
4
5
  declare type Endpoint = Record<MethodName, Data>;
5
6
  declare type Data = {
@@ -10,25 +11,26 @@ declare type Data = {
10
11
  };
11
12
  export declare type RequestOptions = {
12
13
  headers?: Record<string, string>;
14
+ fetch?: typeof fetch;
13
15
  };
14
16
  declare type ClientRequest<S extends Data> = {
15
17
  [M in keyof S]: S[M] extends {
16
18
  input: infer R;
17
19
  output: infer O;
18
- } ? (args?: R, options?: RequestOptions) => Promise<ClientResponse<O>> : never;
20
+ } ? RemoveBlankRecord<R> extends never ? (args?: {}, options?: RequestOptions) => Promise<ClientResponse<O>> : (args: R, options?: RequestOptions) => Promise<ClientResponse<O>> : never;
19
21
  };
20
22
  export interface ClientResponse<T> extends Response {
21
23
  json(): Promise<T>;
22
24
  }
23
25
  export declare type Fetch<T> = (args?: InferRequestType<T>, opt?: RequestOptions) => Promise<ClientResponse<InferResponseType<T>>>;
24
- export declare type InferResponseType<T> = T extends () => Promise<ClientResponse<infer O>> ? O : never;
26
+ export declare type InferResponseType<T> = T extends (args: any | undefined) => Promise<ClientResponse<infer O>> ? O : never;
25
27
  export declare type InferRequestType<T> = T extends (args: infer R) => Promise<ClientResponse<unknown>> ? NonNullable<R> : never;
26
28
  declare type PathToChain<Path extends string, E extends Endpoint, Original extends string = ''> = Path extends `/${infer P}` ? PathToChain<P, E, Path> : Path extends `${infer P}/${infer R}` ? {
27
29
  [K in P]: PathToChain<R, E, Original>;
28
30
  } : {
29
31
  [K in Path extends '' ? 'index' : Path]: ClientRequest<E extends Record<string, unknown> ? E[Original] : never>;
30
32
  };
31
- export declare type Client<T> = T extends Hono<any, infer S> ? S extends Record<infer K, Endpoint> ? K extends string ? PathToChain<K, S> : never : never : never;
33
+ export declare type Client<T> = T extends Hono<any, infer S, any> ? S extends Record<infer K, Endpoint> ? K extends string ? PathToChain<K, S> : never : never : never;
32
34
  export declare type Callback = (opts: CallbackOptions) => unknown;
33
35
  interface CallbackOptions {
34
36
  path: string[];
@@ -3,6 +3,7 @@ import type { TypedResponse } from './types';
3
3
  import type { Env, NotFoundHandler, Input } from './types';
4
4
  import type { CookieOptions } from './utils/cookie';
5
5
  import type { StatusCode } from './utils/http-status';
6
+ import type { PrettyJSON, JSONValue } from './utils/types';
6
7
  declare type Runtime = 'node' | 'deno' | 'bun' | 'workerd' | 'fastly' | 'edge-light' | 'lagon' | 'other';
7
8
  declare type HeaderRecord = Record<string, string | string[]>;
8
9
  declare type Data = string | ArrayBuffer | ReadableStream;
@@ -52,7 +53,7 @@ export declare class Context<E extends Env = any, P extends string = any, I exte
52
53
  body: (data: Data | null, status?: StatusCode, headers?: HeaderRecord) => Response;
53
54
  text: (text: string, status?: StatusCode, headers?: HeaderRecord) => Response;
54
55
  json: <T = object>(object: T, status?: StatusCode, headers?: HeaderRecord) => Response;
55
- jsonT: <T = object>(object: T, status?: StatusCode, headers?: HeaderRecord) => TypedResponse<T>;
56
+ jsonT: <T>(object: T extends JSONValue ? T : JSONValue, status?: StatusCode, headers?: HeaderRecord) => TypedResponse<T extends JSONValue ? JSONValue extends T ? never : PrettyJSON<T> : never>;
56
57
  html: (html: string, status?: StatusCode, headers?: HeaderRecord) => Response;
57
58
  redirect: (location: string, status?: StatusCode) => Response;
58
59
  cookie: (name: string, value: string, opt?: CookieOptions) => void;
@@ -1,35 +1,37 @@
1
1
  import type { ExecutionContext } from './context';
2
2
  import type { Router } from './router';
3
- import type { Env, ErrorHandler, H, HandlerInterface, MiddlewareHandlerInterface, NotFoundHandler, OnHandlerInterface, MergeSchemaPath, RemoveBlankRecord } from './types';
3
+ import type { Env, ErrorHandler, H, HandlerInterface, MiddlewareHandlerInterface, NotFoundHandler, OnHandlerInterface, MergePath, MergeSchemaPath } from './types';
4
+ import type { RemoveBlankRecord } from './utils/types';
4
5
  interface RouterRoute {
5
6
  path: string;
6
7
  method: string;
7
8
  handler: H;
8
9
  }
9
- declare const Hono_base: new <E_1 extends Env = Env, S_1 = {}>() => {
10
- all: HandlerInterface<E_1, "all", S_1>;
11
- get: HandlerInterface<E_1, "get", S_1>;
12
- post: HandlerInterface<E_1, "post", S_1>;
13
- put: HandlerInterface<E_1, "put", S_1>;
14
- delete: HandlerInterface<E_1, "delete", S_1>;
15
- head: HandlerInterface<E_1, "head", S_1>;
16
- options: HandlerInterface<E_1, "options", S_1>;
17
- patch: HandlerInterface<E_1, "patch", S_1>;
10
+ declare const Hono_base: new <E_1 extends Env = Env, S_1 = {}, BasePath_1 extends string = "">() => {
11
+ all: HandlerInterface<E_1, "all", S_1, BasePath_1>;
12
+ get: HandlerInterface<E_1, "get", S_1, BasePath_1>;
13
+ post: HandlerInterface<E_1, "post", S_1, BasePath_1>;
14
+ put: HandlerInterface<E_1, "put", S_1, BasePath_1>;
15
+ delete: HandlerInterface<E_1, "delete", S_1, BasePath_1>;
16
+ head: HandlerInterface<E_1, "head", S_1, BasePath_1>;
17
+ options: HandlerInterface<E_1, "options", S_1, BasePath_1>;
18
+ patch: HandlerInterface<E_1, "patch", S_1, BasePath_1>;
18
19
  } & {
19
- on: OnHandlerInterface<E_1, S_1>;
20
+ on: OnHandlerInterface<E_1, S_1, BasePath_1>;
20
21
  } & {
21
- use: MiddlewareHandlerInterface<E_1, S_1>;
22
+ use: MiddlewareHandlerInterface<E_1, S_1, BasePath_1>;
22
23
  };
23
- export declare class Hono<E extends Env = Env, S = {}> extends Hono_base<E, S> {
24
+ export declare class Hono<E extends Env = Env, S = {}, BasePath extends string = ''> extends Hono_base<E, S, BasePath> {
24
25
  readonly router: Router<H>;
25
26
  readonly strict: boolean;
26
- private _tempPath;
27
+ private basePath;
27
28
  private path;
28
29
  routes: RouterRoute[];
29
30
  constructor(init?: Partial<Pick<Hono, 'router' | 'strict'>>);
31
+ private clone;
30
32
  private notFoundHandler;
31
33
  private errorHandler;
32
- route<SubPath extends string, SubSchema>(path: SubPath, app?: Hono<E, SubSchema>): Hono<E, RemoveBlankRecord<MergeSchemaPath<SubSchema, SubPath> | S>>;
34
+ route<SubPath extends string, SubEnv extends Env, SubSchema>(path: SubPath, app?: Hono<SubEnv, SubSchema>): Hono<E, RemoveBlankRecord<MergeSchemaPath<SubSchema, SubPath> | S>, MergePath<BasePath, SubPath>>;
33
35
  onError(handler: ErrorHandler<E>): this;
34
36
  notFound(handler: NotFoundHandler<E>): this;
35
37
  showRoutes(): void;
@@ -39,6 +41,6 @@ export declare class Hono<E extends Env = Env, S = {}> extends Hono_base<E, S> {
39
41
  private dispatch;
40
42
  handleEvent: (event: FetchEvent) => Response | Promise<Response>;
41
43
  fetch: (request: Request, Env?: E['Bindings'] | {}, executionCtx?: ExecutionContext) => Response | Promise<Response>;
42
- request: (input: Request | string, requestInit?: RequestInit) => Promise<Response>;
44
+ request: (input: Request | string | URL, requestInit?: RequestInit) => Promise<Response>;
43
45
  }
44
46
  export {};
@@ -1,6 +1,7 @@
1
1
  import { Hono } from './hono';
2
2
  export type { Env, ErrorHandler, Handler, MiddlewareHandler, Next, NotFoundHandler, ValidationTargets, } from './types';
3
3
  export type { Context, ContextVariableMap } from './context';
4
+ export type { HonoRequest } from './request';
4
5
  declare module './hono' {
5
6
  interface Hono {
6
7
  fire(): void;
@@ -1,6 +1,6 @@
1
1
  import type { Context } from './context';
2
2
  import type { Hono } from './hono';
3
- import type { UnionToIntersection } from './utils/types';
3
+ import type { UnionToIntersection, RemoveBlankRecord } from './utils/types';
4
4
  export declare type Bindings = Record<string, unknown>;
5
5
  export declare type Variables = Record<string, unknown>;
6
6
  export declare type Env = {
@@ -14,40 +14,70 @@ export declare type MiddlewareHandler<E extends Env = any, P extends string = an
14
14
  export declare type H<E extends Env = any, P extends string = any, I extends Input = {}, O = {}> = Handler<E, P, I, O> | MiddlewareHandler<E, P, I>;
15
15
  export declare type NotFoundHandler<E extends Env = any> = (c: Context<E>) => Response | Promise<Response>;
16
16
  export declare type ErrorHandler<E extends Env = any> = (err: Error, c: Context<E>) => Response;
17
- export interface HandlerInterface<E extends Env = Env, M extends string = any, S = {}> {
18
- <I = {}, O = {}>(...handlers: [H<E, ExtractKey<S>, I, O>, H<E, ExtractKey<S>, I, O>]): Hono<E, S & Schema<M, ExtractKey<S>, I, O>>;
19
- <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2>(...handlers: [H<E, ExtractKey<S>, I, O>, H<E, ExtractKey<S>, I2, O>, H<E, ExtractKey<S>, I3, O>]): Hono<E, S & Schema<M, ExtractKey<S>, I3, O>>;
17
+ export interface HandlerInterface<E extends Env = Env, M extends string = any, S = {}, BasePath extends string = ''> {
18
+ <I = {}, O = {}>(...handlers: [H<E, ExtractKey<S>, I, O>, H<E, ExtractKey<S>, I, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, ExtractKey<S>, I, O>>>;
19
+ <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2>(...handlers: [H<E, ExtractKey<S>, I, O>, H<E, ExtractKey<S>, I2, O>, H<E, ExtractKey<S>, I3, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, ExtractKey<S>, I3, O>>>;
20
20
  <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3>(...handlers: [
21
21
  H<E, ExtractKey<S>, I, O>,
22
22
  H<E, ExtractKey<S>, I2, O>,
23
23
  H<E, ExtractKey<S>, I3, O>,
24
24
  H<E, ExtractKey<S>, I4, O>
25
- ]): Hono<E, S & Schema<M, ExtractKey<S>, I4, O>>;
25
+ ]): Hono<E, RemoveBlankRecord<S | Schema<M, ExtractKey<S>, I4, O>>>;
26
26
  <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3, I5 = I3 & I4>(...handlers: [
27
27
  H<E, ExtractKey<S>, I, O>,
28
28
  H<E, ExtractKey<S>, I2, O>,
29
29
  H<E, ExtractKey<S>, I3, O>,
30
30
  H<E, ExtractKey<S>, I4, O>,
31
31
  H<E, ExtractKey<S>, I5, O>
32
- ]): Hono<E, S & Schema<M, ExtractKey<S>, I5, O>>;
33
- <I = {}, O = {}>(...handlers: Handler<E, ExtractKey<S>, I, O>[]): Hono<E, S & Schema<M, ExtractKey<S>, I, O>>;
34
- <P extends string, O = {}, I = {}>(path: P, ...handlers: [H<E, P, I, O>, H<E, P, I, O>]): Hono<E, S & Schema<M, P, I, O>>;
35
- <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2>(path: P, ...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>]): Hono<E, S & Schema<M, P, I3, O>>;
36
- <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3>(path: P, ...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>, H<E, P, I4, O>]): Hono<E, S & Schema<M, P, I4, O>>;
37
- <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3, I5 = I3 & I4>(path: P, ...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>, H<E, P, I4, O>, H<E, P, I5, O>]): Hono<E, S & Schema<M, P, I5, O>>;
38
- <P extends string, I = {}, O = {}>(path: P, ...handlers: H<E, P, I, O>[]): Hono<E, S & Schema<M, P, I, O>>;
32
+ ]): Hono<E, RemoveBlankRecord<S | Schema<M, ExtractKey<S>, I5, O>>>;
33
+ <I = {}, O = {}>(...handlers: Handler<E, ExtractKey<S>, I, O>[]): Hono<E, RemoveBlankRecord<S | Schema<M, ExtractKey<S>, I, O>>>;
34
+ <P extends string, O = {}, I = {}>(path: P, ...handlers: [H<E, P, I, O>, H<E, P, I, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I, O>>>;
35
+ <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2>(path: P, ...handlers: [
36
+ H<E, MergePath<BasePath, P>, I, O>,
37
+ H<E, MergePath<BasePath, P>, I2, O>,
38
+ H<E, MergePath<BasePath, P>, I3, O>
39
+ ]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I3, O>>>;
40
+ <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3>(path: P, ...handlers: [
41
+ H<E, MergePath<BasePath, P>, I, O>,
42
+ H<E, MergePath<BasePath, P>, I2, O>,
43
+ H<E, MergePath<BasePath, P>, I3, O>,
44
+ H<E, MergePath<BasePath, P>, I4, O>
45
+ ]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I4, O>>>;
46
+ <P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3, I5 = I3 & I4>(path: P, ...handlers: [
47
+ H<E, MergePath<BasePath, P>, I, O>,
48
+ H<E, MergePath<BasePath, P>, I2, O>,
49
+ H<E, MergePath<BasePath, P>, I3, O>,
50
+ H<E, MergePath<BasePath, P>, I4, O>,
51
+ H<E, MergePath<BasePath, P>, I5, O>
52
+ ]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I5, O>>>;
53
+ <P extends string, I = {}, O = {}>(path: P, ...handlers: H<E, MergePath<BasePath, P>, I, O>[]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I, O>>>;
39
54
  }
40
- export interface MiddlewareHandlerInterface<E extends Env = Env, S = {}> {
41
- (...handlers: MiddlewareHandler<E, ExtractKey<S>>[]): Hono<E, S>;
42
- <P extends string>(path: P, ...handlers: MiddlewareHandler<E, P>[]): Hono<E, S>;
55
+ export interface MiddlewareHandlerInterface<E extends Env = Env, S = {}, BasePath extends string = ''> {
56
+ (...handlers: MiddlewareHandler<E, MergePath<BasePath, ExtractKey<S>>>[]): Hono<E, S, BasePath>;
57
+ <P extends string>(path: P, ...handlers: MiddlewareHandler<E, MergePath<BasePath, P>>[]): Hono<E, S, BasePath>;
43
58
  }
44
- export interface OnHandlerInterface<E extends Env = Env, S = {}> {
45
- <M extends string, P extends string, O = {}, I = {}>(method: M, path: P, ...handlers: [H<E, P, I, O>, H<E, P, I, O>]): Hono<E, S & Schema<M, P, I, O>>;
46
- <M extends string, P extends string, O = {}, I = {}, I2 = I, I3 = I & I2>(method: M, path: P, ...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>]): Hono<E, S & Schema<M, P, I3, O>>;
47
- <M extends string, P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3>(method: M, path: P, ...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>, H<E, P, I4, O>]): Hono<E, S & Schema<M, P, I4, O>>;
48
- <M extends string, P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3, I5 = I3 & I4>(method: M, path: P, ...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>, H<E, P, I4, O>, H<E, P, I5, O>]): Hono<E, S & Schema<M, P, I5, O>>;
49
- <M extends string, P extends string, O extends {} = {}, I = {}>(method: M, path: P, ...handlers: H<E, P, I, O>[]): Hono<E, S & Schema<M, P, I, O>>;
50
- <P extends string, O extends {} = {}, I = {}>(methods: string[], path: P, ...handlers: H<E, P, I, O>[]): Hono<E, S & Schema<string, P, I, O>>;
59
+ export interface OnHandlerInterface<E extends Env = Env, S = {}, BasePath extends string = ''> {
60
+ <M extends string, P extends string, O = {}, I = {}>(method: M, path: P, ...handlers: [H<E, MergePath<BasePath, P>, I, O>, H<E, MergePath<BasePath, P>, I, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I, O>>, BasePath>;
61
+ <M extends string, P extends string, O = {}, I = {}, I2 = I, I3 = I & I2>(method: M, path: P, ...handlers: [
62
+ H<E, MergePath<BasePath, P>, I, O>,
63
+ H<E, MergePath<BasePath, P>, I2, O>,
64
+ H<E, MergePath<BasePath, P>, I3, O>
65
+ ]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I3, O>>, BasePath>;
66
+ <M extends string, P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3>(method: M, path: P, ...handlers: [
67
+ H<E, MergePath<BasePath, P>, I, O>,
68
+ H<E, MergePath<BasePath, P>, I2, O>,
69
+ H<E, MergePath<BasePath, P>, I3, O>,
70
+ H<E, MergePath<BasePath, P>, I4, O>
71
+ ]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I4, O>>, BasePath>;
72
+ <M extends string, P extends string, O = {}, I = {}, I2 = I, I3 = I & I2, I4 = I2 & I3, I5 = I3 & I4>(method: M, path: P, ...handlers: [
73
+ H<E, MergePath<BasePath, P>, I, O>,
74
+ H<E, MergePath<BasePath, P>, I2, O>,
75
+ H<E, MergePath<BasePath, P>, I3, O>,
76
+ H<E, MergePath<BasePath, P>, I4, O>,
77
+ H<E, MergePath<BasePath, P>, I5, O>
78
+ ]): Hono<E, S | Schema<M, MergePath<BasePath, P>, I5, O>, BasePath>;
79
+ <M extends string, P extends string, O extends {} = {}, I = {}>(method: M, path: P, ...handlers: H<E, MergePath<BasePath, P>, I, O>[]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I, O>>, BasePath>;
80
+ <P extends string, O extends {} = {}, I = {}>(methods: string[], path: P, ...handlers: H<E, MergePath<BasePath, P>, I, O>[]): Hono<E, RemoveBlankRecord<S | Schema<string, MergePath<BasePath, P>, I, O>>, BasePath>;
51
81
  }
52
82
  declare type ExtractKey<S> = S extends Record<infer Key, unknown> ? Key extends string ? Key : never : string;
53
83
  export declare type Schema<M extends string, P extends string, I extends Input, O> = {
@@ -65,7 +95,7 @@ export declare type AddDollar<T> = T extends Record<infer K, infer R> ? K extend
65
95
  [MethodName in `$${Lowercase<K>}`]: R;
66
96
  } : never : never;
67
97
  export declare type MergeSchemaPath<S, P extends string> = S extends Record<infer Key, infer T> ? Key extends string ? Record<MergePath<P, Key>, T> : never : never;
68
- export declare type MergePath<A extends string, B extends string> = A extends `${infer P}/` ? `${P}${B}` : `${A}${B}`;
98
+ export declare type MergePath<A extends string, B extends string> = A extends '' ? B : A extends `${infer P}/` ? B extends `/${infer Q}` ? `${P}/${Q}` : `${P}/${B}` : B extends `/${infer Q}` ? `${A}/${Q}` : `${A}/${B}`;
69
99
  export declare type TypedResponse<T = unknown> = {
70
100
  response: Response | Promise<Response>;
71
101
  data: T;
@@ -89,5 +119,4 @@ export declare type InputToDataByTarget<T extends Input, Target extends keyof Va
89
119
  export declare type RemoveQuestion<T> = T extends `${infer R}?` ? R : T;
90
120
  export declare type UndefinedIfHavingQuestion<T> = T extends `${infer _}?` ? string | undefined : string;
91
121
  export declare type ExtractSchema<T> = T extends Hono<infer _, infer S> ? S : never;
92
- export declare type RemoveBlankRecord<T> = T extends Record<infer K, unknown> ? K extends string ? T : never : never;
93
122
  export {};
@@ -2,3 +2,15 @@ export declare type Expect<T extends true> = T;
2
2
  export declare type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
3
3
  export declare type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true;
4
4
  export declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
5
+ export declare type RemoveBlankRecord<T> = T extends Record<infer K, unknown> ? K extends string ? T : never : never;
6
+ export declare type JSONPrimitive = string | boolean | number | null | undefined;
7
+ export declare type JSONArray = (JSONPrimitive | JSONObject | JSONArray)[];
8
+ export declare type JSONObject = {
9
+ [key: string]: JSONPrimitive | JSONArray | JSONObject;
10
+ };
11
+ export declare type JSONValue = JSONObject | JSONArray | JSONPrimitive;
12
+ declare type TrueAndFalseToBoolean<T> = T extends true ? boolean : T extends false ? boolean : T;
13
+ export declare type PrettyJSON<T> = T extends JSONPrimitive ? TrueAndFalseToBoolean<T> : T extends JSONArray ? PrettyJSON<T[number]> : T extends JSONObject ? {
14
+ [K in keyof T]: PrettyJSON<T[K]>;
15
+ } : never;
16
+ export {};
@@ -3,36 +3,18 @@ var encodeBase64 = (str) => {
3
3
  if (str === null) {
4
4
  throw new TypeError('1st argument of "encodeBase64" should not be null.');
5
5
  }
6
- try {
7
- const encoder = new TextEncoder();
8
- const bytes = encoder.encode(str);
9
- return btoa(String.fromCharCode(...bytes));
10
- } catch {
11
- }
12
- try {
13
- return Buffer.from(str).toString("base64");
14
- } catch (e) {
15
- console.error('Error: If you want to do "encodeBase64", polyfill "buffer" module.');
16
- throw e;
17
- }
6
+ const encoder = new TextEncoder();
7
+ const bytes = encoder.encode(str);
8
+ return btoa(String.fromCharCode(...bytes));
18
9
  };
19
10
  var decodeBase64 = (str) => {
20
11
  if (str === null) {
21
12
  throw new TypeError('1st argument of "decodeBase64" should not be null.');
22
13
  }
23
- try {
24
- const text = atob(str);
25
- const bytes = new Uint8Array(text.split("").map((c) => c.charCodeAt(0)));
26
- const decoder = new TextDecoder();
27
- return decoder.decode(bytes);
28
- } catch {
29
- }
30
- try {
31
- return Buffer.from(str, "base64").toString();
32
- } catch (e) {
33
- console.error('Error: If you want to do "decodeBase64", polyfill "buffer" module.');
34
- throw e;
35
- }
14
+ const text = atob(str);
15
+ const bytes = new Uint8Array(text.split("").map((c) => c.charCodeAt(0)));
16
+ const decoder = new TextDecoder();
17
+ return decoder.decode(bytes);
36
18
  };
37
19
  var encodeBase64URL = (str) => {
38
20
  return encodeBase64(str).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
@@ -55,14 +37,7 @@ var utf8ToUint8Array = (str) => {
55
37
  return encoder.encode(str);
56
38
  };
57
39
  var arrayBufferToBase64 = async (buf) => {
58
- if (typeof btoa === "function") {
59
- return btoa(String.fromCharCode(...new Uint8Array(buf)));
60
- }
61
- try {
62
- return Buffer.from(String.fromCharCode(...new Uint8Array(buf))).toString("base64");
63
- } catch (e) {
64
- }
65
- return "";
40
+ return btoa(String.fromCharCode(...new Uint8Array(buf)));
66
41
  };
67
42
  var arrayBufferToBase64URL = async (buf) => {
68
43
  return (await arrayBufferToBase64(buf)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
@@ -1,11 +1,12 @@
1
1
  // src/validator/validator.ts
2
+ import { parseBody } from "../utils/body.js";
2
3
  var validator = (target, validationFunc) => {
3
4
  return async (c, next) => {
4
5
  let value = {};
5
6
  switch (target) {
6
7
  case "json":
7
8
  try {
8
- value = await c.req.json();
9
+ value = await c.req.raw.clone().json();
9
10
  } catch {
10
11
  console.error("Error: Malformed JSON in request body");
11
12
  return c.json(
@@ -18,7 +19,7 @@ var validator = (target, validationFunc) => {
18
19
  }
19
20
  break;
20
21
  case "form":
21
- value = await c.req.parseBody();
22
+ value = await parseBody(c.req.raw.clone());
22
23
  break;
23
24
  case "query":
24
25
  value = c.req.query();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Ultrafast web framework for the Edge",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",