hono 0.3.8 → 0.4.0
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 +32 -17
- package/dist/context.d.ts +1 -3
- package/dist/hono.d.ts +14 -18
- package/dist/hono.js +31 -32
- package/dist/middleware/mustache/mustache.d.ts +2 -2
- package/dist/middleware/mustache/mustache.js +7 -3
- package/dist/node.d.ts +6 -15
- package/dist/node.js +3 -3
- package/dist/utils/url.d.ts +6 -1
- package/dist/utils/url.js +31 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,9 +37,13 @@ Below is a demonstration to create an application of Cloudflare Workers with Hon
|
|
|
37
37
|
|
|
38
38
|

|
|
39
39
|
|
|
40
|
+
Now, the named path parameter has types.
|
|
41
|
+
|
|
42
|
+

|
|
43
|
+
|
|
40
44
|
## Install
|
|
41
45
|
|
|
42
|
-
You can install from npm registry:
|
|
46
|
+
You can install Hono from npm registry:
|
|
43
47
|
|
|
44
48
|
```sh
|
|
45
49
|
yarn add hono
|
|
@@ -53,7 +57,7 @@ npm install hono
|
|
|
53
57
|
|
|
54
58
|
## Methods
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
An instance of `Hono` has these methods:
|
|
57
61
|
|
|
58
62
|
- app.**HTTP_METHOD**(path, handler)
|
|
59
63
|
- app.**all**(path, handler)
|
|
@@ -104,14 +108,17 @@ app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
|
|
|
104
108
|
...
|
|
105
109
|
```
|
|
106
110
|
|
|
107
|
-
###
|
|
111
|
+
### Nested route
|
|
108
112
|
|
|
109
113
|
```js
|
|
110
|
-
app
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
const book = app.route('/book')
|
|
115
|
+
book.get('/', (c) => c.text('List Books')) // => GET /book
|
|
116
|
+
book.get('/:id', (c) => {
|
|
117
|
+
// => GET /book/:id
|
|
118
|
+
const id = c.req.param('id')
|
|
119
|
+
return c.text('Get Book: ' + id)
|
|
120
|
+
})
|
|
121
|
+
book.post('/', (c) => c.text('Create Book')) // => POST /book
|
|
115
122
|
```
|
|
116
123
|
|
|
117
124
|
### Custom 404 Response
|
|
@@ -124,6 +131,18 @@ app.get('*', (c) => {
|
|
|
124
131
|
})
|
|
125
132
|
```
|
|
126
133
|
|
|
134
|
+
### no strict
|
|
135
|
+
|
|
136
|
+
If `strict` is set `false`, `/hello`and`/hello/` are treated the same:
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
const app = new Hono({ strict: false })
|
|
140
|
+
|
|
141
|
+
app.get('/hello', (c) => c.text('/hello or /hello/'))
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Default is `true`.
|
|
145
|
+
|
|
127
146
|
## async/await
|
|
128
147
|
|
|
129
148
|
```js
|
|
@@ -147,15 +166,7 @@ const app = new Hono()
|
|
|
147
166
|
|
|
148
167
|
app.use('*', poweredBy())
|
|
149
168
|
app.use('*', logger())
|
|
150
|
-
app.use(
|
|
151
|
-
'/auth/*',
|
|
152
|
-
basicAuth({
|
|
153
|
-
username: 'hono',
|
|
154
|
-
password: 'acoolproject',
|
|
155
|
-
})
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
...
|
|
169
|
+
app.use('/auth/*', basicAuth({ username: 'hono', password: 'acoolproject' }))
|
|
159
170
|
```
|
|
160
171
|
|
|
161
172
|
Available builtin middleware are listed on [src/middleware](https://github.com/yusukebe/hono/tree/master/src/middleware).
|
|
@@ -440,6 +451,10 @@ Contributions Welcome! You can contribute by the following way:
|
|
|
440
451
|
|
|
441
452
|
If you can, let's make Hono together!
|
|
442
453
|
|
|
454
|
+
## Contributors
|
|
455
|
+
|
|
456
|
+
Thanks to [all contributors](https://github.com/yusukebe/hono/graphs/contributors)!
|
|
457
|
+
|
|
443
458
|
## Author
|
|
444
459
|
|
|
445
460
|
Yusuke Wada <https://github.com/yusukebe>
|
package/dist/context.d.ts
CHANGED
package/dist/hono.d.ts
CHANGED
|
@@ -22,30 +22,26 @@ export declare class Router<T> {
|
|
|
22
22
|
add(method: string, path: string, handler: T): void;
|
|
23
23
|
match(method: string, path: string): Result<T> | null;
|
|
24
24
|
}
|
|
25
|
+
declare type Init = {
|
|
26
|
+
strict?: boolean;
|
|
27
|
+
};
|
|
25
28
|
export declare class Hono {
|
|
26
29
|
router: Router<Handler[]>;
|
|
27
30
|
middlewareRouters: Router<MiddlewareHandler>[];
|
|
28
31
|
tempPath: string;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
get(
|
|
32
|
-
post<Path extends string>(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
delete(arg: Handler, ...args: Handler[]): Hono;
|
|
40
|
-
options<Path extends string>(arg: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
41
|
-
options(arg: Handler, ...args: Handler[]): Hono;
|
|
42
|
-
patch<Path extends string>(arg: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
43
|
-
patch(arg: Handler, ...args: Handler[]): Hono;
|
|
44
|
-
all<Path extends string>(arg: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
45
|
-
all(arg: Handler<never>, ...args: Handler<never>[]): Hono;
|
|
32
|
+
strict: boolean;
|
|
33
|
+
constructor(init?: Init);
|
|
34
|
+
get<Path extends string>(path: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
35
|
+
post<Path extends string>(path: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
36
|
+
put<Path extends string>(path: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
37
|
+
head<Path extends string>(path: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
38
|
+
delete<Path extends string>(path: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
39
|
+
options<Path extends string>(path: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
40
|
+
patch<Path extends string>(path: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
41
|
+
all<Path extends string>(path: Path, ...args: Handler<ParamKeys<Path>>[]): Hono;
|
|
46
42
|
route(path: string): Hono;
|
|
47
43
|
use(path: string, middleware: MiddlewareHandler): void;
|
|
48
|
-
addRoute(method: string,
|
|
44
|
+
addRoute(method: string, path: string, ...args: Handler[]): Hono;
|
|
49
45
|
matchRoute(method: string, path: string): Promise<Result<Handler[]>>;
|
|
50
46
|
dispatch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>;
|
|
51
47
|
handleEvent(event: FetchEvent): Promise<Response>;
|
package/dist/hono.js
CHANGED
|
@@ -5,7 +5,6 @@ const node_1 = require("./node");
|
|
|
5
5
|
const compose_1 = require("./compose");
|
|
6
6
|
const url_1 = require("./utils/url");
|
|
7
7
|
const context_1 = require("./context");
|
|
8
|
-
const METHOD_NAME_OF_ALL = 'ALL';
|
|
9
8
|
class Router {
|
|
10
9
|
constructor() {
|
|
11
10
|
this.node = new node_1.Node();
|
|
@@ -19,65 +18,65 @@ class Router {
|
|
|
19
18
|
}
|
|
20
19
|
exports.Router = Router;
|
|
21
20
|
class Hono {
|
|
22
|
-
constructor() {
|
|
21
|
+
constructor(init = { strict: true }) {
|
|
23
22
|
this.router = new Router();
|
|
24
23
|
this.middlewareRouters = [];
|
|
25
|
-
this.tempPath =
|
|
24
|
+
this.tempPath = null;
|
|
25
|
+
this.strict = init.strict; // strict routing - default is true
|
|
26
26
|
}
|
|
27
|
-
get(
|
|
28
|
-
return this.addRoute('get',
|
|
27
|
+
get(path, ...args) {
|
|
28
|
+
return this.addRoute('get', path, ...args);
|
|
29
29
|
}
|
|
30
|
-
post(
|
|
31
|
-
return this.addRoute('post',
|
|
30
|
+
post(path, ...args) {
|
|
31
|
+
return this.addRoute('post', path, ...args);
|
|
32
32
|
}
|
|
33
|
-
put(
|
|
34
|
-
return this.addRoute('put',
|
|
33
|
+
put(path, ...args) {
|
|
34
|
+
return this.addRoute('put', path, ...args);
|
|
35
35
|
}
|
|
36
|
-
head(
|
|
37
|
-
return this.addRoute('head',
|
|
36
|
+
head(path, ...args) {
|
|
37
|
+
return this.addRoute('head', path, ...args);
|
|
38
38
|
}
|
|
39
|
-
delete(
|
|
40
|
-
return this.addRoute('delete',
|
|
39
|
+
delete(path, ...args) {
|
|
40
|
+
return this.addRoute('delete', path, ...args);
|
|
41
41
|
}
|
|
42
|
-
options(
|
|
43
|
-
return this.addRoute('options',
|
|
42
|
+
options(path, ...args) {
|
|
43
|
+
return this.addRoute('options', path, ...args);
|
|
44
44
|
}
|
|
45
|
-
patch(
|
|
46
|
-
return this.addRoute('patch',
|
|
45
|
+
patch(path, ...args) {
|
|
46
|
+
return this.addRoute('patch', path, ...args);
|
|
47
47
|
}
|
|
48
|
-
all(
|
|
49
|
-
return this.addRoute('all',
|
|
48
|
+
all(path, ...args) {
|
|
49
|
+
return this.addRoute('all', path, ...args);
|
|
50
50
|
}
|
|
51
51
|
route(path) {
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
const newHono = new Hono();
|
|
53
|
+
newHono.tempPath = path;
|
|
54
|
+
newHono.router = this.router;
|
|
55
|
+
return newHono;
|
|
54
56
|
}
|
|
55
57
|
use(path, middleware) {
|
|
56
58
|
if (middleware.constructor.name !== 'AsyncFunction') {
|
|
57
59
|
throw new TypeError('middleware must be a async function!');
|
|
58
60
|
}
|
|
59
61
|
const router = new Router();
|
|
60
|
-
router.add(METHOD_NAME_OF_ALL, path, middleware);
|
|
62
|
+
router.add(node_1.METHOD_NAME_OF_ALL, path, middleware);
|
|
61
63
|
this.middlewareRouters.push(router);
|
|
62
64
|
}
|
|
63
65
|
// addRoute('get', '/', handler)
|
|
64
|
-
addRoute(method,
|
|
66
|
+
addRoute(method, path, ...args) {
|
|
65
67
|
method = method.toUpperCase();
|
|
66
|
-
if (
|
|
67
|
-
this.tempPath
|
|
68
|
-
this.router.add(method, arg, args);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
args.unshift(arg);
|
|
72
|
-
this.router.add(method, this.tempPath, args);
|
|
68
|
+
if (this.tempPath) {
|
|
69
|
+
path = (0, url_1.mergePath)(this.tempPath, path);
|
|
73
70
|
}
|
|
71
|
+
this.router.add(method, path, args);
|
|
74
72
|
return this;
|
|
75
73
|
}
|
|
76
74
|
async matchRoute(method, path) {
|
|
77
75
|
return this.router.match(method, path);
|
|
78
76
|
}
|
|
79
77
|
async dispatch(request, env, event) {
|
|
80
|
-
const
|
|
78
|
+
const path = (0, url_1.getPathFromURL)(request.url, { strict: this.strict });
|
|
79
|
+
const method = request.method;
|
|
81
80
|
const result = await this.matchRoute(method, path);
|
|
82
81
|
// Methods for Request object
|
|
83
82
|
request.param = (key) => {
|
|
@@ -95,7 +94,7 @@ class Hono {
|
|
|
95
94
|
const handler = result ? result.handler[0] : this.notFound; // XXX
|
|
96
95
|
const middleware = [];
|
|
97
96
|
for (const mr of this.middlewareRouters) {
|
|
98
|
-
const mwResult = mr.match(METHOD_NAME_OF_ALL, path);
|
|
97
|
+
const mwResult = mr.match(node_1.METHOD_NAME_OF_ALL, path);
|
|
99
98
|
if (mwResult) {
|
|
100
99
|
middleware.push(mwResult.handler);
|
|
101
100
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Context } from '../../context';
|
|
2
|
-
declare type
|
|
2
|
+
declare type Init = {
|
|
3
3
|
root: string;
|
|
4
4
|
};
|
|
5
|
-
export declare const mustache: (
|
|
5
|
+
export declare const mustache: (init?: Init) => (c: Context, next: Function) => Promise<void>;
|
|
6
6
|
export {};
|
|
@@ -4,8 +4,8 @@ exports.mustache = void 0;
|
|
|
4
4
|
const cloudflare_1 = require("../../utils/cloudflare");
|
|
5
5
|
const EXTENSION = '.mustache';
|
|
6
6
|
const DEFAULT_DOCUMENT = 'index.mustache';
|
|
7
|
-
const mustache = (
|
|
8
|
-
const { root } =
|
|
7
|
+
const mustache = (init = { root: '' }) => {
|
|
8
|
+
const { root } = init;
|
|
9
9
|
return async (c, next) => {
|
|
10
10
|
let Mustache;
|
|
11
11
|
try {
|
|
@@ -15,7 +15,11 @@ const mustache = (opt = { root: '' }) => {
|
|
|
15
15
|
throw new Error('If you want to use Mustache Middleware, install "mustache" package first.');
|
|
16
16
|
}
|
|
17
17
|
c.render = async (filename, params = {}, options) => {
|
|
18
|
-
const path = (0, cloudflare_1.getKVFilePath)({
|
|
18
|
+
const path = (0, cloudflare_1.getKVFilePath)({
|
|
19
|
+
filename: `${filename}${EXTENSION}`,
|
|
20
|
+
root: root,
|
|
21
|
+
defaultDocument: DEFAULT_DOCUMENT,
|
|
22
|
+
});
|
|
19
23
|
const buffer = await (0, cloudflare_1.getContentFromKVAsset)(path);
|
|
20
24
|
if (!buffer) {
|
|
21
25
|
throw new Error(`Template "${path}" is not found or blank.`);
|
package/dist/node.d.ts
CHANGED
|
@@ -1,24 +1,15 @@
|
|
|
1
|
+
export declare const METHOD_NAME_OF_ALL = "ALL";
|
|
1
2
|
export declare class Result<T> {
|
|
2
3
|
handler: T;
|
|
3
|
-
params:
|
|
4
|
-
|
|
5
|
-
};
|
|
6
|
-
constructor(handler: T, params: {
|
|
7
|
-
[key: string]: string;
|
|
8
|
-
});
|
|
4
|
+
params: Record<string, string>;
|
|
5
|
+
constructor(handler: T, params: Record<string, string>);
|
|
9
6
|
}
|
|
10
7
|
export declare class Node<T> {
|
|
11
|
-
method:
|
|
12
|
-
[key: string]: T;
|
|
13
|
-
};
|
|
8
|
+
method: Record<string, T>;
|
|
14
9
|
handler: T;
|
|
15
|
-
children:
|
|
16
|
-
[key: string]: Node<T>;
|
|
17
|
-
};
|
|
10
|
+
children: Record<string, Node<T>>;
|
|
18
11
|
middlewares: [];
|
|
19
|
-
constructor(method?: string, handler?: T, children?:
|
|
20
|
-
[key: string]: Node<T>;
|
|
21
|
-
});
|
|
12
|
+
constructor(method?: string, handler?: T, children?: Record<string, Node<T>>);
|
|
22
13
|
insert(method: string, path: string, handler: T): Node<T>;
|
|
23
14
|
search(method: string, path: string): Result<T>;
|
|
24
15
|
}
|
package/dist/node.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Node = exports.Result = void 0;
|
|
3
|
+
exports.Node = exports.Result = exports.METHOD_NAME_OF_ALL = void 0;
|
|
4
4
|
const url_1 = require("./utils/url");
|
|
5
|
-
|
|
5
|
+
exports.METHOD_NAME_OF_ALL = 'ALL';
|
|
6
6
|
class Result {
|
|
7
7
|
constructor(handler, params) {
|
|
8
8
|
this.handler = handler;
|
|
@@ -95,7 +95,7 @@ class Node {
|
|
|
95
95
|
return noRoute();
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
const handler = curNode.method[METHOD_NAME_OF_ALL] || curNode.method[method];
|
|
98
|
+
const handler = curNode.method[exports.METHOD_NAME_OF_ALL] || curNode.method[method];
|
|
99
99
|
if (!handler) {
|
|
100
100
|
return noRoute();
|
|
101
101
|
}
|
package/dist/utils/url.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export declare const splitPath: (path: string) => string[];
|
|
2
2
|
export declare const getPattern: (label: string) => string[] | null;
|
|
3
|
-
|
|
3
|
+
declare type Params = {
|
|
4
|
+
strict: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare const getPathFromURL: (url: string, params?: Params) => string;
|
|
4
7
|
export declare const isAbsoluteURL: (url: string) => boolean;
|
|
8
|
+
export declare const mergePath: (...paths: string[]) => string;
|
|
9
|
+
export {};
|
package/dist/utils/url.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isAbsoluteURL = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0;
|
|
3
|
+
exports.mergePath = exports.isAbsoluteURL = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0;
|
|
4
4
|
const URL_REGEXP = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
|
|
5
5
|
const splitPath = (path) => {
|
|
6
6
|
const paths = path.split(/\//); // faster than path.split('/')
|
|
@@ -26,7 +26,12 @@ const getPattern = (label) => {
|
|
|
26
26
|
return null;
|
|
27
27
|
};
|
|
28
28
|
exports.getPattern = getPattern;
|
|
29
|
-
const getPathFromURL = (url) => {
|
|
29
|
+
const getPathFromURL = (url, params = { strict: true }) => {
|
|
30
|
+
// if strict routing is false => `/hello/hey/` and `/hello/hey` are treated the same
|
|
31
|
+
// default is true
|
|
32
|
+
if (!params.strict && url.endsWith('/')) {
|
|
33
|
+
url = url.slice(0, -1);
|
|
34
|
+
}
|
|
30
35
|
const match = url.match(URL_REGEXP);
|
|
31
36
|
if (match) {
|
|
32
37
|
return match[5];
|
|
@@ -42,3 +47,27 @@ const isAbsoluteURL = (url) => {
|
|
|
42
47
|
return false;
|
|
43
48
|
};
|
|
44
49
|
exports.isAbsoluteURL = isAbsoluteURL;
|
|
50
|
+
const mergePath = (...paths) => {
|
|
51
|
+
let p = '';
|
|
52
|
+
let endsWithSlash = false;
|
|
53
|
+
for (let path of paths) {
|
|
54
|
+
/* ['/hey/','/say'] => ['/hey', '/say'] */
|
|
55
|
+
if (p.endsWith('/')) {
|
|
56
|
+
p = p.slice(0, -1);
|
|
57
|
+
endsWithSlash = true;
|
|
58
|
+
}
|
|
59
|
+
/* ['/hey','say'] => ['/hey', '/say'] */
|
|
60
|
+
if (!path.startsWith('/')) {
|
|
61
|
+
path = `/${path}`;
|
|
62
|
+
}
|
|
63
|
+
/* ['/hey/', '/'] => `/hey/` */
|
|
64
|
+
if (path === '/' && endsWithSlash) {
|
|
65
|
+
p = `${p}/`;
|
|
66
|
+
}
|
|
67
|
+
else if (path !== '/') {
|
|
68
|
+
p = `${p}${path}`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return p;
|
|
72
|
+
};
|
|
73
|
+
exports.mergePath = mergePath;
|