hono 1.4.7 → 1.5.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.
package/README.md CHANGED
@@ -483,10 +483,22 @@ app.use('/', async (c, next) => {
483
483
  })
484
484
  ```
485
485
 
486
+ ### c.executionCtx
487
+
488
+ ```ts
489
+ // ExecutionContext object
490
+ app.get('/foo', async (c) => {
491
+ c.executionCtx.waitUntil(
492
+ c.env.KV.put(key, data)
493
+ )
494
+ ...
495
+ })
496
+ ```
497
+
486
498
  ### c.event
487
499
 
488
500
  ```ts
489
- // FetchEvent object
501
+ // FetchEvent object (only set when using Service Worker syntax)
490
502
  app.get('/foo', async (c) => {
491
503
  c.event.waitUntil(
492
504
  c.env.KV.put(key, data)
@@ -523,8 +535,8 @@ addEventListener('fetch', (event) => {
523
535
 
524
536
  ```ts
525
537
  export default {
526
- fetch(request: Request, env: Env, event: FetchEvent) {
527
- return app.fetch(request, env, event)
538
+ fetch(request: Request, env: Env, ctx: ExecutionContext) {
539
+ return app.fetch(request, env, ctx)
528
540
  },
529
541
  }
530
542
  ```
@@ -556,9 +568,9 @@ import { RegExpRouter } from 'hono/router/reg-exp-router'
556
568
  const app = new Hono({ router: new RegExpRouter() })
557
569
  ```
558
570
 
559
- ## Routing Ordering
571
+ ## Routing priority
560
572
 
561
- The routing priority is decided by the order of registration. Only one handler will be dispatched.
573
+ Handlers or middleware will be executed in registration order.
562
574
 
563
575
  ```ts
564
576
  app.get('/book/a', (c) => c.text('a')) // a
@@ -566,27 +578,37 @@ app.get('/book/:slug', (c) => c.text('common')) // common
566
578
  ```
567
579
 
568
580
  ```http
569
- GET /book/a ---> `a` // common will not be dispatched
570
- GET /book/b ---> `common` // a will not be dispatched
581
+ GET /book/a ---> `a`
582
+ GET /book/b ---> `common`
571
583
  ```
572
584
 
573
- All scoring rules:
585
+ When a handler is executed, the process will be stopped.
574
586
 
575
587
  ```ts
576
- app.get('/api/*', 'c') // score 1.1 <--- `/*` is special wildcard
577
- app.get('/api/:type/:id', 'd') // score 3.2
578
- app.get('/api/posts/:id', 'e') // score 3.3
579
- app.get('/api/posts/123', 'f') // score 3.4
580
- app.get('/*/*/:id', 'g') // score 3.5
581
- app.get('/api/posts/*/comment', 'h') // score 4.6 - not match
582
- app.get('*', 'a') // score 0.7
583
- app.get('*', 'b') // score 0.8
588
+ app.get('*', (c) => c.text('common')) // common
589
+ app.get('/foo', (c) => c.text('foo')) // foo
584
590
  ```
585
591
 
586
- ```plain
587
- GET /api/posts/123
588
- ---> will match => c, d, e, f, b, a, b
589
- ---> sort by score => a, b, c, d, e, f, g
592
+ ```http
593
+ GET /foo ---> `common` // foo will not be dispatched
594
+ ```
595
+
596
+ If you have the middleware that you want to execute, write the code above the handler.
597
+
598
+ ```ts
599
+ app.use('*', logger())
600
+ app.get('/foo', (c) => c.text('foo'))
601
+ ```
602
+
603
+ If you want a "_fallback_" handler, write the code below the other handler.
604
+
605
+ ```ts
606
+ app.get('/foo', (c) => c.text('foo')) // foo
607
+ app.get('*', (c) => c.text('fallback')) // fallback
608
+ ```
609
+
610
+ ```http
611
+ GET /bar ---> `fallback`
590
612
  ```
591
613
 
592
614
  ## Cloudflare Workers with Hono
package/dist/context.d.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
2
  import type { NotFoundHandler } from './hono';
3
+ import type { HonoRequest } from './request';
3
4
  import type { StatusCode } from './utils/http-status';
4
5
  declare type Headers = Record<string, string>;
5
6
  export declare type Data = string | ArrayBuffer | ReadableStream;
6
7
  export declare type Env = Record<string, any>;
7
8
  export declare class Context<RequestParamKeyType extends string = string, E = Env> {
8
- req: Request<RequestParamKeyType>;
9
+ req: HonoRequest<RequestParamKeyType>;
9
10
  env: E;
10
11
  event: FetchEvent | undefined;
12
+ executionCtx: ExecutionContext | undefined;
11
13
  finalized: boolean;
12
14
  private _status;
13
15
  private _pretty;
@@ -17,7 +19,7 @@ export declare class Context<RequestParamKeyType extends string = string, E = En
17
19
  private _res;
18
20
  private notFoundHandler;
19
21
  render: (content: string, params?: object, options?: object) => Response | Promise<Response>;
20
- constructor(req: Request<RequestParamKeyType>, env?: E | undefined, event?: FetchEvent | undefined, notFoundHandler?: NotFoundHandler);
22
+ constructor(req: HonoRequest | Request, env?: E | undefined, eventOrExecutionCtx?: FetchEvent | ExecutionContext | undefined, notFoundHandler?: NotFoundHandler);
21
23
  get res(): Response;
22
24
  set res(_res: Response);
23
25
  header(name: string, value: string): void;
package/dist/context.js CHANGED
@@ -1,17 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Context = void 0;
4
+ const request_1 = require("./request");
4
5
  const url_1 = require("./utils/url");
5
6
  class Context {
6
- constructor(req, env = undefined, event = undefined, notFoundHandler = () => new Response()) {
7
+ constructor(req, env = undefined, eventOrExecutionCtx = undefined, notFoundHandler = () => new Response()) {
7
8
  this._status = 200;
8
9
  this._pretty = false;
9
10
  this._prettySpace = 2;
10
- this.req = req;
11
+ if (req instanceof Request) {
12
+ this.req = (0, request_1.extendHonoRequest)(req);
13
+ }
14
+ else {
15
+ this.req = req;
16
+ }
11
17
  if (env) {
12
18
  this.env = env;
13
19
  }
14
- this.event = event;
20
+ this.executionCtx = eventOrExecutionCtx;
21
+ if (eventOrExecutionCtx && 'respondWith' in eventOrExecutionCtx) {
22
+ this.event = eventOrExecutionCtx;
23
+ }
15
24
  this.notFoundHandler = notFoundHandler;
16
25
  this.finalized = false;
17
26
  }
package/dist/hono.d.ts CHANGED
@@ -48,7 +48,7 @@ export declare class Hono<E extends Env = Env, P extends string = '/'> extends H
48
48
  private matchRoute;
49
49
  private dispatch;
50
50
  handleEvent(event: FetchEvent): Promise<Response>;
51
- fetch(request: Request, env?: E, event?: FetchEvent): Promise<Response>;
51
+ fetch(request: Request, env?: E, executionCtx?: ExecutionContext): Promise<Response>;
52
52
  request(input: RequestInfo, requestInit?: RequestInit): Promise<Response>;
53
53
  fire(): void;
54
54
  }
package/dist/hono.js CHANGED
@@ -29,7 +29,6 @@ class Hono extends defineDynamicClass() {
29
29
  const message = 'Internal Server Error';
30
30
  return c.text(message, 500);
31
31
  };
32
- (0, request_1.extendRequestPrototype)(); // FIXME: should be executed at a better timing
33
32
  const allMethods = [...methods, router_1.METHOD_NAME_ALL_LOWERCASE];
34
33
  allMethods.map((method) => {
35
34
  this[method] = (args1, ...args) => {
@@ -91,13 +90,14 @@ class Hono extends defineDynamicClass() {
91
90
  matchRoute(method, path) {
92
91
  return this.router.match(method, path);
93
92
  }
94
- async dispatch(request, event, env) {
93
+ async dispatch(request, executionCtx, env) {
94
+ request = (0, request_1.extendHonoRequest)(request);
95
95
  const path = (0, url_1.getPathFromURL)(request.url, this.strict);
96
96
  const method = request.method;
97
97
  const result = this.matchRoute(method, path);
98
98
  request.paramData = result?.params;
99
99
  const handlers = result ? result.handlers : [this.notFoundHandler];
100
- const c = new context_1.Context(request, env, event, this.notFoundHandler);
100
+ const c = new context_1.Context(request, env, executionCtx, this.notFoundHandler);
101
101
  const composed = (0, compose_1.compose)(handlers, this.errorHandler, this.notFoundHandler);
102
102
  let context;
103
103
  try {
@@ -117,8 +117,8 @@ class Hono extends defineDynamicClass() {
117
117
  async handleEvent(event) {
118
118
  return this.dispatch(event.request, event);
119
119
  }
120
- async fetch(request, env, event) {
121
- return this.dispatch(request, event, env);
120
+ async fetch(request, env, executionCtx) {
121
+ return this.dispatch(request, executionCtx, env);
122
122
  }
123
123
  request(input, requestInit) {
124
124
  const req = input instanceof Request ? input : new Request(input, requestInit);
@@ -1,7 +1,7 @@
1
1
  import type { Context } from '../../context';
2
2
  import type { Next } from '../../hono';
3
- declare global {
4
- interface Request {
3
+ declare module '../../request' {
4
+ interface HonoRequest {
5
5
  parsedBody: any;
6
6
  }
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import type { Context } from '../../context';
2
2
  import type { Next } from '../../hono';
3
- declare global {
4
- interface Request {
3
+ declare module '../../request' {
4
+ interface HonoRequest {
5
5
  cookie: {
6
6
  (name: string): string;
7
7
  (): Record<string, string>;
@@ -2,7 +2,8 @@
2
2
  import type { Env } from '../../context';
3
3
  import type { Handler } from '../../hono';
4
4
  export declare type ServeStaticOptions = {
5
- root: string;
5
+ root?: string;
6
+ path?: string;
6
7
  manifest?: object | string;
7
8
  namespace?: KVNamespace;
8
9
  };
@@ -13,7 +13,7 @@ const serveStatic = (options = { root: '' }) => {
13
13
  }
14
14
  const url = new URL(c.req.url);
15
15
  const path = (0, cloudflare_1.getKVFilePath)({
16
- filename: url.pathname,
16
+ filename: options.path ?? url.pathname,
17
17
  root: options.root,
18
18
  defaultDocument: DEFAULT_DOCUMENT,
19
19
  });
package/dist/request.d.ts CHANGED
@@ -1,22 +1,20 @@
1
- declare global {
2
- interface Request<ParamKeyType extends string = string> {
3
- param: {
4
- (key: ParamKeyType): string;
5
- (): Record<ParamKeyType, string>;
6
- };
7
- paramData?: Record<ParamKeyType, string>;
8
- query: {
9
- (key: string): string;
10
- (): Record<string, string>;
11
- };
12
- queries: {
13
- (key: string): string[];
14
- (): Record<string, string[]>;
15
- };
16
- header: {
17
- (name: string): string;
18
- (): Record<string, string>;
19
- };
20
- }
1
+ export declare class HonoRequest<ParamKeyType extends string = string> extends Request {
2
+ param: {
3
+ (key: ParamKeyType): string;
4
+ (): Record<ParamKeyType, string>;
5
+ };
6
+ paramData?: Record<ParamKeyType, string>;
7
+ query: {
8
+ (key: string): string;
9
+ (): Record<string, string>;
10
+ };
11
+ queries: {
12
+ (key: string): string[];
13
+ (): Record<string, string[]>;
14
+ };
15
+ header: {
16
+ (name: string): string;
17
+ (): Record<string, string>;
18
+ };
21
19
  }
22
- export declare function extendRequestPrototype(): void;
20
+ export declare function extendHonoRequest(request: HonoRequest): HonoRequest;
package/dist/request.js CHANGED
@@ -1,12 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.extendRequestPrototype = void 0;
4
- function extendRequestPrototype() {
5
- if (!!Request.prototype.param) {
6
- // already extended
7
- return;
8
- }
9
- Request.prototype.param = function (key) {
3
+ exports.extendHonoRequest = exports.HonoRequest = void 0;
4
+ class HonoRequest extends Request {
5
+ }
6
+ exports.HonoRequest = HonoRequest;
7
+ function extendHonoRequest(request) {
8
+ request.param = function (key) {
10
9
  if (this.paramData) {
11
10
  if (key) {
12
11
  return this.paramData[key];
@@ -17,7 +16,7 @@ function extendRequestPrototype() {
17
16
  }
18
17
  return null;
19
18
  };
20
- Request.prototype.header = function (name) {
19
+ request.header = function (name) {
21
20
  if (name) {
22
21
  return this.headers.get(name);
23
22
  }
@@ -29,7 +28,7 @@ function extendRequestPrototype() {
29
28
  return result;
30
29
  }
31
30
  };
32
- Request.prototype.query = function (key) {
31
+ request.query = function (key) {
33
32
  const url = new URL(this.url);
34
33
  if (key) {
35
34
  return url.searchParams.get(key);
@@ -42,7 +41,7 @@ function extendRequestPrototype() {
42
41
  return result;
43
42
  }
44
43
  };
45
- Request.prototype.queries = function (key) {
44
+ request.queries = function (key) {
46
45
  const url = new URL(this.url);
47
46
  if (key) {
48
47
  return url.searchParams.getAll(key);
@@ -55,5 +54,6 @@ function extendRequestPrototype() {
55
54
  return result;
56
55
  }
57
56
  };
57
+ return request;
58
58
  }
59
- exports.extendRequestPrototype = extendRequestPrototype;
59
+ exports.extendHonoRequest = extendHonoRequest;
@@ -11,7 +11,6 @@ interface Hint {
11
11
  interface HandlerWithSortIndex<T> {
12
12
  handler: T;
13
13
  index: number;
14
- componentsLength: number;
15
14
  }
16
15
  interface Route<T> {
17
16
  method: string;
@@ -65,9 +65,7 @@ function compareRoute(a, b) {
65
65
  return i === b.hint.regExpComponents.length || a.hint.endWithWildcard ? 1 : 0;
66
66
  }
67
67
  function compareHandler(a, b) {
68
- return a.componentsLength !== b.componentsLength
69
- ? a.componentsLength - b.componentsLength
70
- : a.index - b.index;
68
+ return a.index - b.index;
71
69
  }
72
70
  function getSortedHandlers(handlers) {
73
71
  return [...handlers].sort(compareHandler).map((h) => h.handler);
@@ -158,7 +156,6 @@ class RegExpRouter {
158
156
  const handlerWithSortIndex = {
159
157
  index,
160
158
  handler,
161
- componentsLength: hint.components.length || 1,
162
159
  };
163
160
  for (let i = 0, len = routes.length; i < len; i++) {
164
161
  if (routes[i].method === method && routes[i].path === path) {
@@ -318,9 +315,7 @@ class RegExpRouter {
318
315
  }
319
316
  }
320
317
  if (routes[j].hint.components.length < routes[i].hint.components.length) {
321
- const componentsLength = routes[j].hint.components.length || 1;
322
318
  routes[j].middleware.push(...routes[i].handlers.map((h) => ({
323
- componentsLength,
324
319
  index: h.index,
325
320
  handler: h.handler,
326
321
  })));
@@ -66,18 +66,11 @@ class Node {
66
66
  parentPatterns.push(...curNode.patterns);
67
67
  curNode = curNode.children[p];
68
68
  }
69
- let score = 1;
70
- if (path === '*') {
71
- score = score + this.order * 0.01;
72
- }
73
- else {
74
- score = parts.length + this.order * 0.01;
75
- }
76
69
  if (!curNode.methods.length) {
77
70
  curNode.methods = [];
78
71
  }
79
72
  const m = {};
80
- const handlerSet = { handler: handler, name: this.name, score: score };
73
+ const handlerSet = { handler: handler, name: this.name, score: this.order };
81
74
  m[method] = handlerSet;
82
75
  curNode.methods.push(m);
83
76
  return curNode;
@@ -90,9 +83,6 @@ class Node {
90
83
  const handlerSet = m[method] || m[router_1.METHOD_NAME_ALL];
91
84
  if (handlerSet !== undefined) {
92
85
  const hs = { ...handlerSet };
93
- if (wildcard) {
94
- hs.score = handlerSet.score - 1;
95
- }
96
86
  handlerSets.push(hs);
97
87
  return;
98
88
  }
@@ -50,7 +50,7 @@ const getKVFilePath = (options) => {
50
50
  filename = filename.concat('/' + defaultDocument);
51
51
  }
52
52
  // /foo.html => foo.html
53
- filename = filename.replace(/^\//, '');
53
+ filename = filename.replace(/^\.?\//, '');
54
54
  // assets/ => assets
55
55
  root = root.replace(/\/$/, '');
56
56
  // ./assets/foo.html => assets/foo.html
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "1.4.7",
3
+ "version": "1.5.2",
4
4
  "description": "Ultrafast web framework for Cloudflare Workers.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -145,7 +145,7 @@
145
145
  "form-data": "^4.0.0",
146
146
  "graphql": "^16.4.0",
147
147
  "jest": "27.5.1",
148
- "jest-environment-miniflare": "^2.5.0",
148
+ "jest-environment-miniflare": "^2.5.1",
149
149
  "mustache": "^4.2.0",
150
150
  "prettier": "^2.6.2",
151
151
  "prettier-plugin-md-nocjsp": "^1.2.0",