hono 2.1.1 → 2.1.4

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
@@ -47,13 +47,13 @@ export default app
47
47
  **Hono is fastest**, compared to other routers for Cloudflare Workers.
48
48
 
49
49
  ```plain
50
- hono - trie-router(default) x 437,354 ops/sec ±4.58% (83 runs sampled)
51
- hono - regexp-router x 535,157 ops/sec ±3.46% (83 runs sampled)
52
- itty-router x 203,092 ops/sec ±3.64% (89 runs sampled)
53
- sunder x 308,252 ops/sec ±2.17% (91 runs sampled)
54
- worktop x 190,764 ops/sec ±3.11% (86 runs sampled)
50
+ hono - trie-router(default) x 482,004 ops/sec ±5.00% (79 runs sampled)
51
+ hono - regexp-router x 604,006 ops/sec ±4.80% (81 runs sampled)
52
+ itty-router x 203,623 ops/sec ±2.10% (94 runs sampled)
53
+ sunder x 306,457 ops/sec ±2.49% (89 runs sampled)
54
+ worktop x 189,450 ops/sec ±3.14% (88 runs sampled)
55
55
  Fastest is hono - regexp-router
56
- ✨ Done in 38.26s.
56
+ ✨ Done in 36.79s.
57
57
  ```
58
58
 
59
59
  ## Documentation
package/dist/compose.d.ts CHANGED
@@ -1,2 +1,7 @@
1
- import type { ErrorHandler, NotFoundHandler } from './hono';
2
- export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler<import("./hono").Environment> | undefined, onNotFound?: NotFoundHandler<import("./hono").Environment> | undefined) => (context: C, next?: Function | undefined) => Promise<C>;
1
+ import type { NotFoundHandler } from './hono';
2
+ interface ComposeContext {
3
+ finalized: boolean;
4
+ res: any;
5
+ }
6
+ export declare const compose: <C extends ComposeContext>(middleware: Function[], onNotFound?: NotFoundHandler<import("./hono").Environment> | undefined) => (context: C, next?: Function | undefined) => C | Promise<C>;
7
+ export {};
package/dist/compose.js CHANGED
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.compose = void 0;
4
4
  const context_1 = require("./context");
5
5
  // Based on the code in the MIT licensed `koa-compose` package.
6
- const compose = (middleware, onError, onNotFound) => {
6
+ const compose = (middleware, onNotFound) => {
7
7
  const middlewareLength = middleware.length;
8
8
  return (context, next) => {
9
9
  let index = -1;
10
10
  return dispatch(0);
11
- async function dispatch(i) {
11
+ function dispatch(i) {
12
12
  if (i <= index) {
13
13
  throw new Error('next() called multiple times');
14
14
  }
@@ -16,33 +16,32 @@ const compose = (middleware, onError, onNotFound) => {
16
16
  index = i;
17
17
  if (i === middlewareLength && next)
18
18
  handler = next;
19
+ let res;
19
20
  if (!handler) {
20
21
  if (context instanceof context_1.HonoContext && context.finalized === false && onNotFound) {
21
- context.res = await onNotFound(context);
22
+ res = onNotFound(context);
22
23
  }
23
- return context;
24
24
  }
25
- let res;
26
- let isError = false;
27
- try {
28
- const tmp = handler(context, () => dispatch(i + 1));
29
- res = tmp instanceof Promise ? await tmp : tmp;
25
+ else {
26
+ res = handler(context, () => {
27
+ const dispatchRes = dispatch(i + 1);
28
+ return dispatchRes instanceof Promise ? dispatchRes : Promise.resolve(dispatchRes);
29
+ });
30
30
  }
31
- catch (err) {
32
- if (context instanceof context_1.HonoContext && onError) {
33
- if (err instanceof Error) {
34
- isError = true;
35
- res = onError(err, context);
36
- }
37
- }
38
- if (!res) {
39
- throw err;
31
+ if (!(res instanceof Promise)) {
32
+ if (res && context.finalized === false) {
33
+ context.res = res;
40
34
  }
35
+ return context;
41
36
  }
42
- if (res && context instanceof context_1.HonoContext && (!context.finalized || isError)) {
43
- context.res = res;
37
+ else {
38
+ return res.then((res) => {
39
+ if (res && context.finalized === false) {
40
+ context.res = res;
41
+ }
42
+ return context;
43
+ });
44
44
  }
45
- return context;
46
45
  }
47
46
  };
48
47
  };
package/dist/context.d.ts CHANGED
@@ -4,7 +4,7 @@ import type { CookieOptions } from './utils/cookie';
4
4
  import type { StatusCode } from './utils/http-status';
5
5
  declare type Headers = Record<string, string>;
6
6
  export declare type Data = string | ArrayBuffer | ReadableStream;
7
- export interface Context<RequestParamKeyType extends string = string, E extends Partial<Environment> = Environment> {
7
+ export interface Context<RequestParamKeyType extends string = string, E extends Partial<Environment> = any> {
8
8
  req: Request<RequestParamKeyType>;
9
9
  env: E['Bindings'];
10
10
  event: FetchEvent;
package/dist/context.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HonoContext = void 0;
4
+ const hono_1 = require("./hono");
4
5
  const cookie_1 = require("./utils/cookie");
5
6
  const url_1 = require("./utils/url");
6
7
  class HonoContext {
@@ -10,7 +11,7 @@ class HonoContext {
10
11
  this._prettySpace = 2;
11
12
  this._executionCtx = executionCtx;
12
13
  this.req = req;
13
- this.env = env ? env : {};
14
+ this.env = env || {};
14
15
  this.notFoundHandler = notFoundHandler;
15
16
  this.finalized = false;
16
17
  }
@@ -31,7 +32,7 @@ class HonoContext {
31
32
  }
32
33
  }
33
34
  get res() {
34
- return (this._res || (this._res = new Response()));
35
+ return (this._res || (this._res = new Response(hono_1.defaultNotFoundMessage, { status: 404 })));
35
36
  }
36
37
  set res(_res) {
37
38
  this._res = _res;
package/dist/hono.d.ts CHANGED
@@ -13,14 +13,15 @@ export declare type Handler<RequestParamKeyType extends string = string, E exten
13
13
  export declare type NotFoundHandler<E extends Partial<Environment> = Environment> = (c: Context<string, E>) => Response | Promise<Response>;
14
14
  export declare type ErrorHandler<E extends Partial<Environment> = Environment> = (err: Error, c: Context<string, E>) => Response;
15
15
  export declare type Next = () => Promise<void>;
16
+ export declare const defaultNotFoundMessage = "404 Not Found";
16
17
  declare type ParamKeyName<NameWithPattern> = NameWithPattern extends `${infer Name}{${infer _Pattern}` ? Name : NameWithPattern;
17
18
  declare type ParamKey<Component> = Component extends `:${infer NameWithPattern}` ? ParamKeyName<NameWithPattern> : never;
18
19
  declare type ParamKeys<Path> = Path extends `${infer Component}/${infer Rest}` ? ParamKey<Component> | ParamKeys<Rest> : ParamKey<Path>;
19
20
  interface HandlerInterface<T extends string = string, E extends Partial<Environment> = Environment, U = Hono<E, T>> {
20
- <Path extends string, Env extends Partial<Environment> = E>(path: Path, ...handlers: Handler<ParamKeys<Path> extends never ? string : ParamKeys<Path>, Env>[]): U;
21
- (path: string, ...handlers: Handler<string, E>[]): U;
22
21
  <Path extends string, Env extends Partial<Environment> = E>(...handlers: Handler<ParamKeys<Path> extends never ? string : ParamKeys<Path>, Env>[]): U;
23
22
  (...handlers: Handler<string, E>[]): U;
23
+ <Path extends string, Env extends Partial<Environment> = E>(path: Path, ...handlers: Handler<ParamKeys<Path> extends never ? string : ParamKeys<Path>, Env>[]): U;
24
+ (path: string, ...handlers: Handler<string, E>[]): U;
24
25
  }
25
26
  interface Route<E extends Partial<Environment> = Environment> {
26
27
  path: string;
@@ -37,10 +38,7 @@ declare const Hono_base: new <E_1 extends Partial<Environment> = Environment, T
37
38
  options: HandlerInterface<T, E_1, U>;
38
39
  patch: HandlerInterface<T, E_1, U>;
39
40
  };
40
- export declare class Hono<E extends {
41
- Bindings?: Bindings;
42
- Variables?: Variables;
43
- } = Environment, P extends string = '/'> extends Hono_base<E, P, Hono<E, P>> {
41
+ export declare class Hono<E extends Partial<Environment> = Environment, P extends string = '/'> extends Hono_base<E, P, Hono<E, P>> {
44
42
  readonly router: Router<Handler<string, E>>;
45
43
  readonly strict: boolean;
46
44
  private _tempPath;
package/dist/hono.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Hono = void 0;
3
+ exports.Hono = exports.defaultNotFoundMessage = void 0;
4
4
  const compose_1 = require("./compose");
5
5
  const context_1 = require("./context");
6
6
  const request_1 = require("./request");
7
7
  const router_1 = require("./router");
8
8
  const trie_router_1 = require("./router/trie-router"); // Default Router
9
9
  const url_1 = require("./utils/url");
10
+ exports.defaultNotFoundMessage = '404 Not Found';
10
11
  const methods = ['get', 'post', 'put', 'delete', 'head', 'options', 'patch'];
11
12
  function defineDynamicClass() {
12
13
  return class {
@@ -21,7 +22,7 @@ class Hono extends defineDynamicClass() {
21
22
  this.path = '/';
22
23
  this.routes = [];
23
24
  this.notFoundHandler = (c) => {
24
- const message = '404 Not Found';
25
+ const message = exports.defaultNotFoundMessage;
25
26
  return c.text(message, 404);
26
27
  };
27
28
  this.errorHandler = (err, c) => {
@@ -99,12 +100,32 @@ class Hono extends defineDynamicClass() {
99
100
  const method = request.method;
100
101
  const result = this.matchRoute(method, path);
101
102
  request.paramData = result?.params;
102
- const handlers = result ? result.handlers : [this.notFoundHandler];
103
103
  const c = new context_1.HonoContext(request, env, eventOrExecutionCtx, this.notFoundHandler);
104
- const composed = (0, compose_1.compose)(handlers, this.errorHandler, this.notFoundHandler);
104
+ // Do not `compose` if it has only one handler
105
+ if (result && result.handlers.length === 1) {
106
+ const handler = result.handlers[0];
107
+ try {
108
+ const res = handler(c, async () => { });
109
+ if (res) {
110
+ const awaited = res instanceof Promise ? await res : res;
111
+ if (awaited)
112
+ return awaited;
113
+ }
114
+ return this.notFoundHandler(c);
115
+ }
116
+ catch (err) {
117
+ if (err instanceof Error) {
118
+ return this.errorHandler(err, c);
119
+ }
120
+ throw err;
121
+ }
122
+ }
123
+ const handlers = result ? result.handlers : [this.notFoundHandler];
124
+ const composed = (0, compose_1.compose)(handlers, this.notFoundHandler);
105
125
  let context;
106
126
  try {
107
- context = await composed(c);
127
+ const tmp = composed(c);
128
+ context = tmp instanceof Promise ? await tmp : tmp;
108
129
  if (!context.finalized) {
109
130
  throw new Error('Context is not finalized. You may forget returning Response object or `await next()`');
110
131
  }
@@ -1,3 +1,3 @@
1
1
  import type { ServeStaticOptions } from './serve-static';
2
- declare const module: (options?: ServeStaticOptions) => (c: import("../../context").Context<string, import("../../hono").Environment>, next: import("../../hono").Next) => Promise<Response | undefined>;
2
+ declare const module: (options?: ServeStaticOptions) => (c: import("../../context").Context<string, any>, next: import("../../hono").Next) => Promise<Response | undefined>;
3
3
  export { module as serveStatic };
@@ -9,7 +9,7 @@ const DEFAULT_DOCUMENT = 'index.html';
9
9
  const serveStatic = (options = { root: '' }) => {
10
10
  return async (c, next) => {
11
11
  // Do nothing if Response is already set
12
- if (c.res && c.finalized) {
12
+ if (c.finalized) {
13
13
  await next();
14
14
  }
15
15
  const url = new URL(c.req.url);
package/dist/request.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extendRequestPrototype = void 0;
4
4
  const body_1 = require("./utils/body");
5
5
  const cookie_1 = require("./utils/cookie");
6
+ const url_1 = require("./utils/url");
6
7
  function extendRequestPrototype() {
7
8
  if (!!Request.prototype.param) {
8
9
  // already extended
@@ -32,27 +33,29 @@ function extendRequestPrototype() {
32
33
  }
33
34
  };
34
35
  Request.prototype.query = function (key) {
35
- const url = new URL(this.url);
36
+ const queryString = (0, url_1.getQueryStringFromURL)(this.url);
37
+ const searchParams = new URLSearchParams(queryString);
36
38
  if (key) {
37
- return url.searchParams.get(key);
39
+ return searchParams.get(key);
38
40
  }
39
41
  else {
40
42
  const result = {};
41
- for (const key of url.searchParams.keys()) {
42
- result[key] = url.searchParams.get(key) || '';
43
+ for (const key of searchParams.keys()) {
44
+ result[key] = searchParams.get(key) || '';
43
45
  }
44
46
  return result;
45
47
  }
46
48
  };
47
49
  Request.prototype.queries = function (key) {
48
- const url = new URL(this.url);
50
+ const queryString = (0, url_1.getQueryStringFromURL)(this.url);
51
+ const searchParams = new URLSearchParams(queryString);
49
52
  if (key) {
50
- return url.searchParams.getAll(key);
53
+ return searchParams.getAll(key);
51
54
  }
52
55
  else {
53
56
  const result = {};
54
- for (const key of url.searchParams.keys()) {
55
- result[key] = url.searchParams.getAll(key);
57
+ for (const key of searchParams.keys()) {
58
+ result[key] = searchParams.getAll(key);
56
59
  }
57
60
  return result;
58
61
  }
@@ -237,7 +237,9 @@ class RegExpRouter {
237
237
  return this.match(method, path);
238
238
  }
239
239
  buildAllMatchers() {
240
- // @ts-ignore
240
+ if (!this.routeData) {
241
+ throw new Error('Can not call the buildAllMatchers since the matcher is already built.');
242
+ }
241
243
  this.routeData.routes.sort(({ hint: a }, { hint: b }) => {
242
244
  if (a.componentsLength !== b.componentsLength) {
243
245
  return a.componentsLength - b.componentsLength;
@@ -263,21 +265,26 @@ class RegExpRouter {
263
265
  const primaryMatchers = {};
264
266
  const secondaryMatchers = {};
265
267
  let hasAmbiguous = false;
266
- // @ts-ignore
267
268
  this.routeData.methods.forEach((method) => {
268
269
  let _hasAmbiguous;
269
270
  [primaryMatchers[method], secondaryMatchers[method], _hasAmbiguous] =
270
271
  this.buildMatcher(method);
271
272
  hasAmbiguous = hasAmbiguous || _hasAmbiguous;
272
273
  });
274
+ if (hasAmbiguous) {
275
+ // rebuild all matchers with ambiguous flag
276
+ this.routeData.methods.forEach((method) => {
277
+ ;
278
+ [primaryMatchers[method], secondaryMatchers[method]] = this.buildMatcher(method, hasAmbiguous);
279
+ });
280
+ }
273
281
  primaryMatchers[router_1.METHOD_NAME_ALL] || (primaryMatchers[router_1.METHOD_NAME_ALL] = nullMatcher);
274
282
  secondaryMatchers[router_1.METHOD_NAME_ALL] || (secondaryMatchers[router_1.METHOD_NAME_ALL] = []);
275
283
  delete this.routeData; // to reduce memory usage
276
284
  return [primaryMatchers, secondaryMatchers, hasAmbiguous];
277
285
  }
278
- buildMatcher(method) {
286
+ buildMatcher(method, hasAmbiguous = false) {
279
287
  var _a, _b;
280
- let hasAmbiguous = false;
281
288
  const targetMethods = new Set([method, router_1.METHOD_NAME_ALL]);
282
289
  // @ts-ignore
283
290
  const routes = this.routeData.routes.filter(({ method }) => targetMethods.has(method));
@@ -2,5 +2,6 @@ export declare type Pattern = readonly [string, string, RegExp | true] | '*';
2
2
  export declare const splitPath: (path: string) => string[];
3
3
  export declare const getPattern: (label: string) => Pattern | null;
4
4
  export declare const getPathFromURL: (url: string, strict?: boolean) => string;
5
+ export declare const getQueryStringFromURL: (url: string) => string;
5
6
  export declare const isAbsoluteURL: (url: string) => boolean;
6
7
  export declare const mergePath: (...paths: string[]) => string;
package/dist/utils/url.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mergePath = exports.isAbsoluteURL = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0;
3
+ exports.mergePath = exports.isAbsoluteURL = exports.getQueryStringFromURL = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0;
4
4
  const URL_REGEXP = /^https?:\/\/[a-zA-Z0-9\-\.:]+(\/?[^?#]*)/;
5
5
  const splitPath = (path) => {
6
6
  const paths = path.split(/\//); // faster than path.split('/')
@@ -45,6 +45,12 @@ const getPathFromURL = (url, strict = true) => {
45
45
  return result;
46
46
  };
47
47
  exports.getPathFromURL = getPathFromURL;
48
+ const getQueryStringFromURL = (url) => {
49
+ const queryIndex = url.indexOf('?');
50
+ const result = queryIndex !== -1 ? url.substring(queryIndex) : '';
51
+ return result;
52
+ };
53
+ exports.getQueryStringFromURL = getQueryStringFromURL;
48
54
  const isAbsoluteURL = (url) => {
49
55
  const match = url.match(URL_REGEXP);
50
56
  if (match) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "2.1.1",
3
+ "version": "2.1.4",
4
4
  "description": "Ultrafast web framework for Cloudflare Workers.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",