hono 2.1.3 → 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 +6 -6
- package/dist/compose.d.ts +6 -1
- package/dist/compose.js +21 -7
- package/dist/context.js +2 -1
- package/dist/hono.d.ts +1 -0
- package/dist/hono.js +25 -4
- package/dist/middleware/serve-static/serve-static.js +1 -1
- package/dist/request.js +11 -8
- package/dist/router/reg-exp-router/router.js +11 -4
- package/dist/utils/url.d.ts +1 -0
- package/dist/utils/url.js +7 -1
- package/package.json +1 -1
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
|
|
51
|
-
hono - regexp-router x
|
|
52
|
-
itty-router x 203,
|
|
53
|
-
sunder x
|
|
54
|
-
worktop x
|
|
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
|
|
56
|
+
✨ Done in 36.79s.
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
## Documentation
|
package/dist/compose.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
import type { NotFoundHandler } from './hono';
|
|
2
|
-
|
|
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
|
@@ -8,7 +8,7 @@ const compose = (middleware, onNotFound) => {
|
|
|
8
8
|
return (context, next) => {
|
|
9
9
|
let index = -1;
|
|
10
10
|
return dispatch(0);
|
|
11
|
-
|
|
11
|
+
function dispatch(i) {
|
|
12
12
|
if (i <= index) {
|
|
13
13
|
throw new Error('next() called multiple times');
|
|
14
14
|
}
|
|
@@ -16,18 +16,32 @@ const compose = (middleware, 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
|
-
|
|
22
|
+
res = onNotFound(context);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
res = handler(context, () => {
|
|
27
|
+
const dispatchRes = dispatch(i + 1);
|
|
28
|
+
return dispatchRes instanceof Promise ? dispatchRes : Promise.resolve(dispatchRes);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (!(res instanceof Promise)) {
|
|
32
|
+
if (res && context.finalized === false) {
|
|
33
|
+
context.res = res;
|
|
22
34
|
}
|
|
23
35
|
return context;
|
|
24
36
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
else {
|
|
38
|
+
return res.then((res) => {
|
|
39
|
+
if (res && context.finalized === false) {
|
|
40
|
+
context.res = res;
|
|
41
|
+
}
|
|
42
|
+
return context;
|
|
43
|
+
});
|
|
29
44
|
}
|
|
30
|
-
return context;
|
|
31
45
|
}
|
|
32
46
|
};
|
|
33
47
|
};
|
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 {
|
|
@@ -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,6 +13,7 @@ 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>;
|
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 =
|
|
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
|
+
// 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];
|
|
104
124
|
const composed = (0, compose_1.compose)(handlers, this.notFoundHandler);
|
|
105
125
|
let context;
|
|
106
126
|
try {
|
|
107
|
-
|
|
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
|
}
|
|
@@ -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.
|
|
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
|
|
36
|
+
const queryString = (0, url_1.getQueryStringFromURL)(this.url);
|
|
37
|
+
const searchParams = new URLSearchParams(queryString);
|
|
36
38
|
if (key) {
|
|
37
|
-
return
|
|
39
|
+
return searchParams.get(key);
|
|
38
40
|
}
|
|
39
41
|
else {
|
|
40
42
|
const result = {};
|
|
41
|
-
for (const key of
|
|
42
|
-
result[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
|
|
50
|
+
const queryString = (0, url_1.getQueryStringFromURL)(this.url);
|
|
51
|
+
const searchParams = new URLSearchParams(queryString);
|
|
49
52
|
if (key) {
|
|
50
|
-
return
|
|
53
|
+
return searchParams.getAll(key);
|
|
51
54
|
}
|
|
52
55
|
else {
|
|
53
56
|
const result = {};
|
|
54
|
-
for (const key of
|
|
55
|
-
result[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
|
-
|
|
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));
|
package/dist/utils/url.d.ts
CHANGED
|
@@ -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) {
|