hono 0.3.5 → 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 +38 -45
- package/dist/compose.d.ts +1 -1
- package/dist/compose.js +1 -1
- package/dist/context.d.ts +7 -9
- package/dist/context.js +16 -6
- package/dist/hono.d.ts +23 -15
- package/dist/hono.js +53 -62
- package/dist/middleware/mustache/mustache.d.ts +2 -2
- package/dist/middleware/mustache/mustache.js +9 -5
- package/dist/node.d.ts +6 -15
- package/dist/node.js +3 -3
- package/dist/utils/buffer.d.ts +2 -2
- package/dist/utils/http-status.d.ts +1 -0
- package/dist/utils/http-status.js +46 -0
- package/dist/utils/url.d.ts +6 -1
- package/dist/utils/url.js +31 -2
- package/package.json +4 -2
- package/dist/middleware/default.d.ts +0 -2
- package/dist/middleware/default.js +0 -15
- package/dist/middleware.d.ts +0 -3
- package/dist/middleware.js +0 -8
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Hono
|
|
2
2
|
|
|
3
|
-
Hono[炎] - _**means flame🔥 in Japanese**_ - is small, simple, and ultrafast web
|
|
3
|
+
Hono[炎] - _**means flame🔥 in Japanese**_ - is small, simple, and ultrafast web framework for a Service Workers API based serverless such as Cloudflare Workers and Fastly Compute@Edge.
|
|
4
4
|
|
|
5
5
|
```js
|
|
6
6
|
import { Hono } from 'hono'
|
|
@@ -13,7 +13,7 @@ app.fire()
|
|
|
13
13
|
|
|
14
14
|
## Features
|
|
15
15
|
|
|
16
|
-
- **Ultra fast** - the router is implemented with Trie-Tree structure.
|
|
16
|
+
- **Ultra fast** - the router is implemented with Trie-Tree structure. Not use loops.
|
|
17
17
|
- **Zero dependencies** - using only Web standard API.
|
|
18
18
|
- **Middleware** - builtin middleware, and you can make your own middleware.
|
|
19
19
|
- **Optimized** - for Cloudflare Workers.
|
|
@@ -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).
|
|
@@ -174,7 +185,7 @@ app.use('*', async (c, next) => {
|
|
|
174
185
|
// Add a custom header
|
|
175
186
|
app.use('/message/*', async (c, next) => {
|
|
176
187
|
await next()
|
|
177
|
-
await c.
|
|
188
|
+
await c.header('x-message', 'This is middleware!')
|
|
178
189
|
})
|
|
179
190
|
|
|
180
191
|
app.get('/message/hello', (c) => c.text('Hello Middleware!'))
|
|
@@ -193,30 +204,9 @@ app.use('*', async (c, next) => {
|
|
|
193
204
|
})
|
|
194
205
|
```
|
|
195
206
|
|
|
196
|
-
### Complex Pattern
|
|
197
|
-
|
|
198
|
-
You can also do this:
|
|
199
|
-
|
|
200
|
-
```js
|
|
201
|
-
// Output response time
|
|
202
|
-
app.use('*', async (c, next) => {
|
|
203
|
-
await next()
|
|
204
|
-
const responseTime = await c.res.headers.get('X-Response-Time')
|
|
205
|
-
console.log(`X-Response-Time: ${responseTime}`)
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
// Add X-Response-Time header
|
|
209
|
-
app.use('*', async (c, next) => {
|
|
210
|
-
const start = Date.now()
|
|
211
|
-
await next()
|
|
212
|
-
const ms = Date.now() - start
|
|
213
|
-
await c.res.headers.append('X-Response-Time', `${ms}ms`)
|
|
214
|
-
})
|
|
215
|
-
```
|
|
216
|
-
|
|
217
207
|
## Context
|
|
218
208
|
|
|
219
|
-
To handle Request and Reponse
|
|
209
|
+
To handle Request and Reponse, you can use Context object:
|
|
220
210
|
|
|
221
211
|
### c.req
|
|
222
212
|
|
|
@@ -253,7 +243,6 @@ app.get('/welcome', (c) => {
|
|
|
253
243
|
c.header('X-Message', 'Hello!')
|
|
254
244
|
c.header('Content-Type', 'text/plain')
|
|
255
245
|
c.status(201)
|
|
256
|
-
c.statusText('201 Content Created')
|
|
257
246
|
|
|
258
247
|
return c.body('Thank you for comming')
|
|
259
248
|
|
|
@@ -261,7 +250,7 @@ app.get('/welcome', (c) => {
|
|
|
261
250
|
Same as:
|
|
262
251
|
return new Response('Thank you for comming', {
|
|
263
252
|
status: 201,
|
|
264
|
-
statusText: '
|
|
253
|
+
statusText: 'Created',
|
|
265
254
|
headers: {
|
|
266
255
|
'X-Message': 'Hello',
|
|
267
256
|
'Content-Type': 'text/plain',
|
|
@@ -431,7 +420,7 @@ Run the development server locally. Then, access like `http://127.0.0.1:8787/` i
|
|
|
431
420
|
wrangler dev
|
|
432
421
|
```
|
|
433
422
|
|
|
434
|
-
### Publish
|
|
423
|
+
### 7. Publish
|
|
435
424
|
|
|
436
425
|
Deploy to Cloudflare. That's all!
|
|
437
426
|
|
|
@@ -462,6 +451,10 @@ Contributions Welcome! You can contribute by the following way:
|
|
|
462
451
|
|
|
463
452
|
If you can, let's make Hono together!
|
|
464
453
|
|
|
454
|
+
## Contributors
|
|
455
|
+
|
|
456
|
+
Thanks to [all contributors](https://github.com/yusukebe/hono/graphs/contributors)!
|
|
457
|
+
|
|
465
458
|
## Author
|
|
466
459
|
|
|
467
460
|
Yusuke Wada <https://github.com/yusukebe>
|
package/dist/compose.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const compose: (middleware:
|
|
1
|
+
export declare const compose: <T>(middleware: Function[]) => (context: T, next?: Function) => Promise<void | object>;
|
package/dist/compose.js
CHANGED
|
@@ -7,7 +7,7 @@ const compose = (middleware) => {
|
|
|
7
7
|
return function (context, next) {
|
|
8
8
|
let index = -1;
|
|
9
9
|
return dispatch(0);
|
|
10
|
-
function dispatch(i) {
|
|
10
|
+
async function dispatch(i) {
|
|
11
11
|
if (i <= index)
|
|
12
12
|
return Promise.reject(new Error('next() called multiple times'));
|
|
13
13
|
index = i;
|
package/dist/context.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
-
declare type Headers =
|
|
3
|
-
|
|
4
|
-
};
|
|
2
|
+
declare type Headers = Record<string, string>;
|
|
3
|
+
declare type Data = string | ArrayBuffer | ReadableStream;
|
|
5
4
|
export interface Env {
|
|
6
5
|
}
|
|
7
|
-
export declare class Context {
|
|
8
|
-
req: Request
|
|
6
|
+
export declare class Context<RequestParamKeyType = string> {
|
|
7
|
+
req: Request<RequestParamKeyType>;
|
|
9
8
|
res: Response;
|
|
10
9
|
env: Env;
|
|
11
10
|
event: FetchEvent;
|
|
@@ -13,16 +12,15 @@ export declare class Context {
|
|
|
13
12
|
private _status;
|
|
14
13
|
private _statusText;
|
|
15
14
|
render: (template: string, params?: object, options?: object) => Promise<Response>;
|
|
16
|
-
constructor(req: Request
|
|
15
|
+
constructor(req: Request<RequestParamKeyType>, opts?: {
|
|
17
16
|
res: Response;
|
|
18
17
|
env: Env;
|
|
19
18
|
event: FetchEvent;
|
|
20
19
|
});
|
|
21
20
|
header(name: string, value: string): void;
|
|
22
21
|
status(number: number): void;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
body(data: any, status?: number, headers?: Headers): Response;
|
|
22
|
+
newResponse(data: Data, init?: ResponseInit): Response;
|
|
23
|
+
body(data: Data, status?: number, headers?: Headers): Response;
|
|
26
24
|
text(text: string, status?: number, headers?: Headers): Response;
|
|
27
25
|
json(object: object, status?: number, headers?: Headers): Response;
|
|
28
26
|
html(html: string, status?: number, headers?: Headers): Response;
|
package/dist/context.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Context = void 0;
|
|
4
4
|
const url_1 = require("./utils/url");
|
|
5
|
+
const http_status_1 = require("./utils/http-status");
|
|
5
6
|
class Context {
|
|
6
7
|
constructor(req, opts) {
|
|
7
8
|
this.req = req;
|
|
@@ -13,13 +14,25 @@ class Context {
|
|
|
13
14
|
this._headers = {};
|
|
14
15
|
}
|
|
15
16
|
header(name, value) {
|
|
17
|
+
/*
|
|
18
|
+
XXX:
|
|
19
|
+
app.use('*', (c, next) => {
|
|
20
|
+
next()
|
|
21
|
+
c.header('foo', 'bar') // => c.res.headers.set(...)
|
|
22
|
+
})
|
|
23
|
+
*/
|
|
24
|
+
if (this.res) {
|
|
25
|
+
this.res.headers.set(name, value);
|
|
26
|
+
}
|
|
16
27
|
this._headers[name] = value;
|
|
17
28
|
}
|
|
18
29
|
status(number) {
|
|
30
|
+
if (this.res) {
|
|
31
|
+
console.warn('c.res.status is already set.');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
19
34
|
this._status = number;
|
|
20
|
-
|
|
21
|
-
statusText(text) {
|
|
22
|
-
this._statusText = text;
|
|
35
|
+
this._statusText = (0, http_status_1.getStatusText)(number);
|
|
23
36
|
}
|
|
24
37
|
newResponse(data, init = {}) {
|
|
25
38
|
init.status = init.status || this._status;
|
|
@@ -35,9 +48,6 @@ class Context {
|
|
|
35
48
|
const Encoder = new TextEncoder();
|
|
36
49
|
length = Encoder.encode(data).byteLength || 0;
|
|
37
50
|
}
|
|
38
|
-
else {
|
|
39
|
-
length = data.bytelength;
|
|
40
|
-
}
|
|
41
51
|
}
|
|
42
52
|
init.headers = Object.assign(Object.assign({}, init.headers), { 'Content-Length': length.toString() });
|
|
43
53
|
return new Response(data, init);
|
package/dist/hono.d.ts
CHANGED
|
@@ -4,42 +4,50 @@ import { Node } from './node';
|
|
|
4
4
|
import { Context } from './context';
|
|
5
5
|
import type { Env } from './context';
|
|
6
6
|
declare global {
|
|
7
|
-
interface Request {
|
|
8
|
-
param: (key:
|
|
9
|
-
query: (key: string) => string
|
|
7
|
+
interface Request<ParamKeyType = string> {
|
|
8
|
+
param: (key: ParamKeyType) => string;
|
|
9
|
+
query: (key: string) => string;
|
|
10
10
|
header: (name: string) => string;
|
|
11
11
|
parsedBody: any;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
export declare type Handler = (c: Context
|
|
14
|
+
export declare type Handler<RequestParamKeyType = string> = (c: Context<RequestParamKeyType>, next?: Function) => Response | Promise<Response>;
|
|
15
15
|
export declare type MiddlewareHandler = (c: Context, next: Function) => Promise<void>;
|
|
16
|
+
declare type ParamKeyName<NameWithPattern> = NameWithPattern extends `${infer Name}{${infer _Pattern}` ? Name : NameWithPattern;
|
|
17
|
+
declare type ParamKey<Component> = Component extends `:${infer NameWithPattern}` ? ParamKeyName<NameWithPattern> : never;
|
|
18
|
+
declare type ParamKeys<Path> = Path extends `${infer Component}/${infer Rest}` ? ParamKey<Component> | ParamKeys<Rest> : ParamKey<Path>;
|
|
16
19
|
export declare class Router<T> {
|
|
17
20
|
node: Node<T>;
|
|
18
21
|
constructor();
|
|
19
22
|
add(method: string, path: string, handler: T): void;
|
|
20
23
|
match(method: string, path: string): Result<T> | null;
|
|
21
24
|
}
|
|
25
|
+
declare type Init = {
|
|
26
|
+
strict?: boolean;
|
|
27
|
+
};
|
|
22
28
|
export declare class Hono {
|
|
23
29
|
router: Router<Handler[]>;
|
|
24
30
|
middlewareRouters: Router<MiddlewareHandler>[];
|
|
25
31
|
tempPath: string;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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;
|
|
35
42
|
route(path: string): Hono;
|
|
36
43
|
use(path: string, middleware: MiddlewareHandler): void;
|
|
37
|
-
addRoute(method: string,
|
|
44
|
+
addRoute(method: string, path: string, ...args: Handler[]): Hono;
|
|
38
45
|
matchRoute(method: string, path: string): Promise<Result<Handler[]>>;
|
|
39
46
|
dispatch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>;
|
|
40
47
|
handleEvent(event: FetchEvent): Promise<Response>;
|
|
41
48
|
fetch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>;
|
|
42
49
|
fire(): void;
|
|
43
|
-
onError(err:
|
|
50
|
+
onError(err: Error): Response;
|
|
44
51
|
notFound(): Response;
|
|
45
52
|
}
|
|
53
|
+
export {};
|
package/dist/hono.js
CHANGED
|
@@ -4,9 +4,7 @@ exports.Hono = exports.Router = void 0;
|
|
|
4
4
|
const node_1 = require("./node");
|
|
5
5
|
const compose_1 = require("./compose");
|
|
6
6
|
const url_1 = require("./utils/url");
|
|
7
|
-
const middleware_1 = require("./middleware");
|
|
8
7
|
const context_1 = require("./context");
|
|
9
|
-
const METHOD_NAME_OF_ALL = 'ALL';
|
|
10
8
|
class Router {
|
|
11
9
|
constructor() {
|
|
12
10
|
this.node = new node_1.Node();
|
|
@@ -20,102 +18,95 @@ class Router {
|
|
|
20
18
|
}
|
|
21
19
|
exports.Router = Router;
|
|
22
20
|
class Hono {
|
|
23
|
-
constructor() {
|
|
21
|
+
constructor(init = { strict: true }) {
|
|
24
22
|
this.router = new Router();
|
|
25
23
|
this.middlewareRouters = [];
|
|
26
|
-
this.tempPath =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
get(
|
|
30
|
-
return this.addRoute('get',
|
|
31
|
-
}
|
|
32
|
-
post(
|
|
33
|
-
return this.addRoute('post',
|
|
34
|
-
}
|
|
35
|
-
put(
|
|
36
|
-
return this.addRoute('put',
|
|
37
|
-
}
|
|
38
|
-
head(
|
|
39
|
-
return this.addRoute('head',
|
|
40
|
-
}
|
|
41
|
-
delete(
|
|
42
|
-
return this.addRoute('delete',
|
|
43
|
-
}
|
|
44
|
-
options(
|
|
45
|
-
return this.addRoute('options',
|
|
46
|
-
}
|
|
47
|
-
patch(
|
|
48
|
-
return this.addRoute('patch',
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
trace
|
|
53
|
-
copy
|
|
54
|
-
lock
|
|
55
|
-
purge
|
|
56
|
-
unlock
|
|
57
|
-
report
|
|
58
|
-
checkout
|
|
59
|
-
merge
|
|
60
|
-
notify
|
|
61
|
-
subscribe
|
|
62
|
-
unsubscribe
|
|
63
|
-
search
|
|
64
|
-
connect
|
|
65
|
-
*/
|
|
66
|
-
all(arg, ...args) {
|
|
67
|
-
return this.addRoute('all', arg, ...args);
|
|
24
|
+
this.tempPath = null;
|
|
25
|
+
this.strict = init.strict; // strict routing - default is true
|
|
26
|
+
}
|
|
27
|
+
get(path, ...args) {
|
|
28
|
+
return this.addRoute('get', path, ...args);
|
|
29
|
+
}
|
|
30
|
+
post(path, ...args) {
|
|
31
|
+
return this.addRoute('post', path, ...args);
|
|
32
|
+
}
|
|
33
|
+
put(path, ...args) {
|
|
34
|
+
return this.addRoute('put', path, ...args);
|
|
35
|
+
}
|
|
36
|
+
head(path, ...args) {
|
|
37
|
+
return this.addRoute('head', path, ...args);
|
|
38
|
+
}
|
|
39
|
+
delete(path, ...args) {
|
|
40
|
+
return this.addRoute('delete', path, ...args);
|
|
41
|
+
}
|
|
42
|
+
options(path, ...args) {
|
|
43
|
+
return this.addRoute('options', path, ...args);
|
|
44
|
+
}
|
|
45
|
+
patch(path, ...args) {
|
|
46
|
+
return this.addRoute('patch', path, ...args);
|
|
47
|
+
}
|
|
48
|
+
all(path, ...args) {
|
|
49
|
+
return this.addRoute('all', path, ...args);
|
|
68
50
|
}
|
|
69
51
|
route(path) {
|
|
70
|
-
|
|
71
|
-
|
|
52
|
+
const newHono = new Hono();
|
|
53
|
+
newHono.tempPath = path;
|
|
54
|
+
newHono.router = this.router;
|
|
55
|
+
return newHono;
|
|
72
56
|
}
|
|
73
57
|
use(path, middleware) {
|
|
74
58
|
if (middleware.constructor.name !== 'AsyncFunction') {
|
|
75
59
|
throw new TypeError('middleware must be a async function!');
|
|
76
60
|
}
|
|
77
61
|
const router = new Router();
|
|
78
|
-
router.add(METHOD_NAME_OF_ALL, path, middleware);
|
|
62
|
+
router.add(node_1.METHOD_NAME_OF_ALL, path, middleware);
|
|
79
63
|
this.middlewareRouters.push(router);
|
|
80
64
|
}
|
|
81
65
|
// addRoute('get', '/', handler)
|
|
82
|
-
addRoute(method,
|
|
66
|
+
addRoute(method, path, ...args) {
|
|
83
67
|
method = method.toUpperCase();
|
|
84
|
-
if (
|
|
85
|
-
this.tempPath
|
|
86
|
-
this.router.add(method, arg, args);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
args.unshift(arg);
|
|
90
|
-
this.router.add(method, this.tempPath, args);
|
|
68
|
+
if (this.tempPath) {
|
|
69
|
+
path = (0, url_1.mergePath)(this.tempPath, path);
|
|
91
70
|
}
|
|
71
|
+
this.router.add(method, path, args);
|
|
92
72
|
return this;
|
|
93
73
|
}
|
|
94
74
|
async matchRoute(method, path) {
|
|
95
75
|
return this.router.match(method, path);
|
|
96
76
|
}
|
|
97
77
|
async dispatch(request, env, event) {
|
|
98
|
-
const
|
|
78
|
+
const path = (0, url_1.getPathFromURL)(request.url, { strict: this.strict });
|
|
79
|
+
const method = request.method;
|
|
99
80
|
const result = await this.matchRoute(method, path);
|
|
81
|
+
// Methods for Request object
|
|
100
82
|
request.param = (key) => {
|
|
101
83
|
if (result) {
|
|
102
84
|
return result.params[key];
|
|
103
85
|
}
|
|
104
|
-
|
|
86
|
+
};
|
|
87
|
+
request.header = (name) => {
|
|
88
|
+
return request.headers.get(name);
|
|
89
|
+
};
|
|
90
|
+
request.query = (key) => {
|
|
91
|
+
const url = new URL(c.req.url);
|
|
92
|
+
return url.searchParams.get(key);
|
|
105
93
|
};
|
|
106
94
|
const handler = result ? result.handler[0] : this.notFound; // XXX
|
|
107
95
|
const middleware = [];
|
|
108
96
|
for (const mr of this.middlewareRouters) {
|
|
109
|
-
const mwResult = mr.match(METHOD_NAME_OF_ALL, path);
|
|
97
|
+
const mwResult = mr.match(node_1.METHOD_NAME_OF_ALL, path);
|
|
110
98
|
if (mwResult) {
|
|
111
99
|
middleware.push(mwResult.handler);
|
|
112
100
|
}
|
|
113
101
|
}
|
|
114
102
|
const wrappedHandler = async (context, next) => {
|
|
115
|
-
|
|
103
|
+
const res = await handler(context);
|
|
104
|
+
if (!(res instanceof Response)) {
|
|
105
|
+
throw new TypeError('response must be a instace of Response');
|
|
106
|
+
}
|
|
107
|
+
context.res = res;
|
|
116
108
|
await next();
|
|
117
109
|
};
|
|
118
|
-
middleware.push(middleware_1.Middleware.default);
|
|
119
110
|
middleware.push(wrappedHandler);
|
|
120
111
|
const composed = (0, compose_1.compose)(middleware);
|
|
121
112
|
const c = new context_1.Context(request, { env: env, event: event, res: null });
|
|
@@ -149,7 +140,7 @@ class Hono {
|
|
|
149
140
|
}
|
|
150
141
|
notFound() {
|
|
151
142
|
const message = 'Not Found';
|
|
152
|
-
return new Response(
|
|
143
|
+
return new Response(message, {
|
|
153
144
|
status: 404,
|
|
154
145
|
headers: {
|
|
155
146
|
'Content-Length': message.length.toString(),
|
|
@@ -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 {
|
|
@@ -14,8 +14,12 @@ const mustache = (opt = { root: '' }) => {
|
|
|
14
14
|
catch (_a) {
|
|
15
15
|
throw new Error('If you want to use Mustache Middleware, install "mustache" package first.');
|
|
16
16
|
}
|
|
17
|
-
c.render = async (filename,
|
|
18
|
-
const path = (0, cloudflare_1.getKVFilePath)({
|
|
17
|
+
c.render = async (filename, params = {}, options) => {
|
|
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.`);
|
|
@@ -37,7 +41,7 @@ const mustache = (opt = { root: '' }) => {
|
|
|
37
41
|
partialArgs[key] = bufferToString(partialBuffer);
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
|
-
const output = Mustache.render(content,
|
|
44
|
+
const output = Mustache.render(content, params, partialArgs);
|
|
41
45
|
return c.html(output);
|
|
42
46
|
};
|
|
43
47
|
await next();
|
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?:
|
|
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/buffer.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare const equal: (a: ArrayBuffer, b: ArrayBuffer) => boolean;
|
|
2
2
|
export declare const decodeBase64: (str: string) => any;
|
|
3
|
-
export declare const sha256: (a: string) => Promise<string>;
|
|
4
|
-
export declare const timingSafeEqual: (a:
|
|
3
|
+
export declare const sha256: (a: string | object | boolean) => Promise<string>;
|
|
4
|
+
export declare const timingSafeEqual: (a: string | object | boolean, b: string | object | boolean) => Promise<boolean>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getStatusText: (statusNumber: number) => string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getStatusText = void 0;
|
|
4
|
+
const getStatusText = (statusNumber) => {
|
|
5
|
+
const text = statuses[statusNumber];
|
|
6
|
+
return text;
|
|
7
|
+
};
|
|
8
|
+
exports.getStatusText = getStatusText;
|
|
9
|
+
const statuses = {
|
|
10
|
+
200: 'OK',
|
|
11
|
+
201: 'Created',
|
|
12
|
+
202: 'Accepted',
|
|
13
|
+
204: 'No Content',
|
|
14
|
+
206: 'Partial Content',
|
|
15
|
+
301: 'Moved Permanently',
|
|
16
|
+
302: 'Moved Temporarily',
|
|
17
|
+
303: 'See Other',
|
|
18
|
+
304: 'Not Modified',
|
|
19
|
+
307: 'Temporary Redirect',
|
|
20
|
+
308: 'Permanent Redirect',
|
|
21
|
+
400: 'Bad Request',
|
|
22
|
+
401: 'Unauthorized',
|
|
23
|
+
402: 'Payment Required',
|
|
24
|
+
403: 'Forbidden',
|
|
25
|
+
404: 'Not Found',
|
|
26
|
+
405: 'Not Allowed',
|
|
27
|
+
406: 'Not Acceptable',
|
|
28
|
+
408: 'Request Time-out',
|
|
29
|
+
409: 'Conflict',
|
|
30
|
+
410: 'Gone',
|
|
31
|
+
411: 'Length Required',
|
|
32
|
+
412: 'Precondition Failed',
|
|
33
|
+
413: 'Request Entity Too Large',
|
|
34
|
+
414: 'Request-URI Too Large',
|
|
35
|
+
415: 'Unsupported Media Type',
|
|
36
|
+
416: 'Requested Range Not Satisfiable',
|
|
37
|
+
421: 'Misdirected Request',
|
|
38
|
+
429: 'Too Many Requests',
|
|
39
|
+
500: 'Internal Server Error',
|
|
40
|
+
501: 'Not Implemented',
|
|
41
|
+
502: 'Bad Gateway',
|
|
42
|
+
503: 'Service Temporarily Unavailable',
|
|
43
|
+
504: 'Gateway Time-out',
|
|
44
|
+
505: 'HTTP Version Not Supported',
|
|
45
|
+
507: 'Insufficient Storage',
|
|
46
|
+
};
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "[炎] Ultrafast web framework for Cloudflare Workers.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
"./logger": "./dist/middleware/logger/logger.js",
|
|
17
17
|
"./mustache": "./dist/middleware/mustache/mustache.js",
|
|
18
18
|
"./powered-by": "./dist/middleware/powered-by/powered-by.js",
|
|
19
|
-
"./serve-static": "./dist/middleware/serve-static/serve-static.js"
|
|
19
|
+
"./serve-static": "./dist/middleware/serve-static/serve-static.js",
|
|
20
|
+
"./utils/buffer": "./dist/utils/buffer.js",
|
|
21
|
+
"./package.json": "./package.json"
|
|
20
22
|
},
|
|
21
23
|
"typesVersions": {
|
|
22
24
|
"*": {
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.defaultMiddleware = void 0;
|
|
4
|
-
const defaultMiddleware = async (c, next) => {
|
|
5
|
-
c.req.query = (key) => {
|
|
6
|
-
// eslint-disable-next-line
|
|
7
|
-
const url = new URL(c.req.url);
|
|
8
|
-
return url.searchParams.get(key);
|
|
9
|
-
};
|
|
10
|
-
c.req.header = (name) => {
|
|
11
|
-
return c.req.headers.get(name);
|
|
12
|
-
};
|
|
13
|
-
await next();
|
|
14
|
-
};
|
|
15
|
-
exports.defaultMiddleware = defaultMiddleware;
|
package/dist/middleware.d.ts
DELETED
package/dist/middleware.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Middleware = void 0;
|
|
4
|
-
const default_1 = require("./middleware/default");
|
|
5
|
-
class Middleware {
|
|
6
|
-
}
|
|
7
|
-
exports.Middleware = Middleware;
|
|
8
|
-
Middleware.default = default_1.defaultMiddleware;
|