hono 0.4.1 → 0.5.1
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 +108 -84
- package/dist/compose.d.ts +2 -1
- package/dist/compose.js +20 -22
- package/dist/hono.d.ts +7 -11
- package/dist/hono.js +25 -32
- package/dist/middleware/basic-auth/basic-auth.d.ts +4 -1
- package/dist/middleware/basic-auth/basic-auth.js +24 -14
- package/dist/middleware/body-parse/body-parse.js +2 -18
- package/dist/middleware/etag/etag.d.ts +6 -0
- package/dist/middleware/etag/etag.js +28 -0
- package/dist/router/reg-exp-router/node.d.ts +1 -3
- package/dist/router/reg-exp-router/node.js +1 -1
- package/dist/router/reg-exp-router/router.js +7 -8
- package/dist/router/reg-exp-router/trie.js +1 -1
- package/dist/router/trie-router/index.d.ts +1 -0
- package/dist/router/trie-router/index.js +5 -0
- package/dist/{node.d.ts → router/trie-router/node.d.ts} +2 -2
- package/dist/{node.js → router/trie-router/node.js} +2 -2
- package/dist/router/trie-router/router.d.ts +9 -0
- package/dist/router/trie-router/router.js +18 -0
- package/dist/utils/body.d.ts +1 -0
- package/dist/utils/body.js +24 -0
- package/dist/utils/buffer.d.ts +0 -2
- package/dist/utils/buffer.js +4 -46
- package/dist/utils/crypto.d.ts +10 -0
- package/dist/utils/crypto.js +58 -0
- package/dist/utils/mime.js +3 -3
- package/package.json +12 -10
package/README.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# Hono
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/yusukebe/hono/actions)
|
|
4
|
+
[](https://github.com/yusukebe/hono/blob/master/LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/hono)
|
|
6
|
+
[](https://www.npmjs.com/package/hono)
|
|
7
|
+
[](https://www.npmjs.com/package/hono)
|
|
8
|
+
[](https://github.com/yusukebe/hono/pulse)
|
|
9
|
+
[](https://github.com/yusukebe/hono/commits/master)
|
|
10
|
+
|
|
11
|
+
Hono[炎] - _**means flame🔥 in Japanese**_ - is small, simple, and ultrafast web framework for Service Worker based serverless applications like Cloudflare Workers and Fastly Compute@Edge.
|
|
4
12
|
|
|
5
13
|
```js
|
|
6
14
|
import { Hono } from 'hono'
|
|
@@ -13,9 +21,9 @@ app.fire()
|
|
|
13
21
|
|
|
14
22
|
## Features
|
|
15
23
|
|
|
16
|
-
- **
|
|
17
|
-
- **Zero
|
|
18
|
-
- **Middleware** - builtin middleware
|
|
24
|
+
- **Ultrafast** - the router does not use linear loops.
|
|
25
|
+
- **Zero-dependencies** - using only Web standard API.
|
|
26
|
+
- **Middleware** - builtin middleware and your own middleware.
|
|
19
27
|
- **Optimized** - for Cloudflare Workers.
|
|
20
28
|
|
|
21
29
|
## Benchmark
|
|
@@ -23,17 +31,17 @@ app.fire()
|
|
|
23
31
|
**Hono is fastest** compared to other routers for Cloudflare Workers.
|
|
24
32
|
|
|
25
33
|
```plain
|
|
26
|
-
hono x
|
|
27
|
-
itty-router x
|
|
28
|
-
sunder x
|
|
29
|
-
worktop x
|
|
34
|
+
hono x 809,503 ops/sec ±6.94% (73 runs sampled)
|
|
35
|
+
itty-router x 157,310 ops/sec ±4.31% (87 runs sampled)
|
|
36
|
+
sunder x 328,350 ops/sec ±2.30% (95 runs sampled)
|
|
37
|
+
worktop x 209,758 ops/sec ±4.28% (83 runs sampled)
|
|
30
38
|
Fastest is hono
|
|
31
|
-
✨ Done in
|
|
39
|
+
✨ Done in 60.66s.
|
|
32
40
|
```
|
|
33
41
|
|
|
34
42
|
## Hono in 1 minute
|
|
35
43
|
|
|
36
|
-
|
|
44
|
+
A demonstration to create an application of Cloudflare Workers with Hono.
|
|
37
45
|
|
|
38
46
|

|
|
39
47
|
|
|
@@ -43,26 +51,28 @@ Now, the named path parameter has types.
|
|
|
43
51
|
|
|
44
52
|
## Install
|
|
45
53
|
|
|
46
|
-
You can install Hono from npm registry
|
|
54
|
+
You can install Hono from the npm registry.
|
|
47
55
|
|
|
48
56
|
```sh
|
|
49
|
-
yarn add hono
|
|
57
|
+
$ yarn add hono
|
|
50
58
|
```
|
|
51
59
|
|
|
52
60
|
or
|
|
53
61
|
|
|
54
62
|
```sh
|
|
55
|
-
npm install hono
|
|
63
|
+
$ npm install hono
|
|
56
64
|
```
|
|
57
65
|
|
|
58
66
|
## Methods
|
|
59
67
|
|
|
60
|
-
An instance of `Hono` has these methods
|
|
68
|
+
An instance of `Hono` has these methods.
|
|
61
69
|
|
|
62
70
|
- app.**HTTP_METHOD**(path, handler)
|
|
63
71
|
- app.**all**(path, handler)
|
|
64
72
|
- app.**route**(path)
|
|
65
73
|
- app.**use**(path, middleware)
|
|
74
|
+
- app.**notFound**(handler)
|
|
75
|
+
- app.**onError**(err, handler)
|
|
66
76
|
- app.**fire**()
|
|
67
77
|
- app.**fetch**(request, env, event)
|
|
68
78
|
|
|
@@ -70,8 +80,6 @@ An instance of `Hono` has these methods:
|
|
|
70
80
|
|
|
71
81
|
### Basic
|
|
72
82
|
|
|
73
|
-
`app.HTTP_METHOD`
|
|
74
|
-
|
|
75
83
|
```js
|
|
76
84
|
// HTTP Methods
|
|
77
85
|
app.get('/', (c) => c.text('GET /'))
|
|
@@ -81,11 +89,7 @@ app.post('/', (c) => c.text('POST /'))
|
|
|
81
89
|
app.get('/wild/*/card', (c) => {
|
|
82
90
|
return c.text('GET /wild/*/card')
|
|
83
91
|
})
|
|
84
|
-
```
|
|
85
92
|
|
|
86
|
-
`app.all`
|
|
87
|
-
|
|
88
|
-
```js
|
|
89
93
|
// Any HTTP methods
|
|
90
94
|
app.all('/hello', (c) => c.text('Any Method /hello'))
|
|
91
95
|
```
|
|
@@ -106,33 +110,32 @@ app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
|
|
|
106
110
|
const date = c.req.param('date')
|
|
107
111
|
const title = c.req.param('title')
|
|
108
112
|
...
|
|
113
|
+
})
|
|
109
114
|
```
|
|
110
115
|
|
|
111
116
|
### Nested route
|
|
112
117
|
|
|
113
118
|
```js
|
|
114
119
|
const book = app.route('/book')
|
|
115
|
-
book.get('/', (c) => c.text('List Books')) //
|
|
120
|
+
book.get('/', (c) => c.text('List Books')) // GET /book
|
|
116
121
|
book.get('/:id', (c) => {
|
|
117
|
-
//
|
|
122
|
+
// GET /book/:id
|
|
118
123
|
const id = c.req.param('id')
|
|
119
124
|
return c.text('Get Book: ' + id)
|
|
120
125
|
})
|
|
121
|
-
book.post('/', (c) => c.text('Create Book')) //
|
|
126
|
+
book.post('/', (c) => c.text('Create Book')) // POST /book
|
|
122
127
|
```
|
|
123
128
|
|
|
124
129
|
### no strict
|
|
125
130
|
|
|
126
|
-
If `strict` is set
|
|
131
|
+
If `strict` is set false, `/hello`and`/hello/` are treated the same.
|
|
127
132
|
|
|
128
133
|
```js
|
|
129
|
-
const app = new Hono({ strict: false })
|
|
134
|
+
const app = new Hono({ strict: false }) // Default is true
|
|
130
135
|
|
|
131
136
|
app.get('/hello', (c) => c.text('/hello or /hello/'))
|
|
132
137
|
```
|
|
133
138
|
|
|
134
|
-
Default is `true`.
|
|
135
|
-
|
|
136
139
|
### async/await
|
|
137
140
|
|
|
138
141
|
```js
|
|
@@ -156,14 +159,20 @@ const app = new Hono()
|
|
|
156
159
|
|
|
157
160
|
app.use('*', poweredBy())
|
|
158
161
|
app.use('*', logger())
|
|
159
|
-
app.use(
|
|
162
|
+
app.use(
|
|
163
|
+
'/auth/*',
|
|
164
|
+
basicAuth({
|
|
165
|
+
username: 'hono',
|
|
166
|
+
password: 'acoolproject',
|
|
167
|
+
})
|
|
168
|
+
)
|
|
160
169
|
```
|
|
161
170
|
|
|
162
171
|
Available builtin middleware are listed on [src/middleware](https://github.com/yusukebe/hono/tree/master/src/middleware).
|
|
163
172
|
|
|
164
173
|
### Custom Middleware
|
|
165
174
|
|
|
166
|
-
You can write your own middleware
|
|
175
|
+
You can write your own middleware.
|
|
167
176
|
|
|
168
177
|
```js
|
|
169
178
|
// Custom logger
|
|
@@ -175,15 +184,36 @@ app.use('*', async (c, next) => {
|
|
|
175
184
|
// Add a custom header
|
|
176
185
|
app.use('/message/*', async (c, next) => {
|
|
177
186
|
await next()
|
|
178
|
-
|
|
187
|
+
c.header('x-message', 'This is middleware!')
|
|
179
188
|
})
|
|
180
189
|
|
|
181
190
|
app.get('/message/hello', (c) => c.text('Hello Middleware!'))
|
|
182
191
|
```
|
|
183
192
|
|
|
193
|
+
## Not Found
|
|
194
|
+
|
|
195
|
+
`app.notFound` for customizing Not Found Response.
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
app.notFound((c) => {
|
|
199
|
+
return c.text('Custom 404 Message', 404)
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Error Handling
|
|
204
|
+
|
|
205
|
+
`app.onError` handle the error and return the customized Response.
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
app.onError((err, c) => {
|
|
209
|
+
console.error(`${err}`)
|
|
210
|
+
return c.text('Custom Error Message', 500)
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
184
214
|
## Context
|
|
185
215
|
|
|
186
|
-
To handle Request and Reponse, you can use Context object
|
|
216
|
+
To handle Request and Reponse, you can use Context object.
|
|
187
217
|
|
|
188
218
|
### c.req
|
|
189
219
|
|
|
@@ -217,30 +247,33 @@ app.get('/entry/:id', (c) => {
|
|
|
217
247
|
|
|
218
248
|
```js
|
|
219
249
|
app.get('/welcome', (c) => {
|
|
250
|
+
// Set headers
|
|
220
251
|
c.header('X-Message', 'Hello!')
|
|
221
252
|
c.header('Content-Type', 'text/plain')
|
|
253
|
+
// Set HTTP status code
|
|
222
254
|
c.status(201)
|
|
223
|
-
|
|
255
|
+
// Return the response body
|
|
224
256
|
return c.body('Thank you for comming')
|
|
257
|
+
})
|
|
258
|
+
```
|
|
225
259
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
*/
|
|
260
|
+
The Response is the same as below.
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
new Response('Thank you for comming', {
|
|
264
|
+
status: 201,
|
|
265
|
+
statusText: 'Created',
|
|
266
|
+
headers: {
|
|
267
|
+
'X-Message': 'Hello',
|
|
268
|
+
'Content-Type': 'text/plain',
|
|
269
|
+
'Content-Length': '22',
|
|
270
|
+
},
|
|
238
271
|
})
|
|
239
272
|
```
|
|
240
273
|
|
|
241
274
|
### c.text()
|
|
242
275
|
|
|
243
|
-
Render
|
|
276
|
+
Render texts as `Content-Type:text/plain`.
|
|
244
277
|
|
|
245
278
|
```js
|
|
246
279
|
app.get('/say', (c) => {
|
|
@@ -250,7 +283,7 @@ app.get('/say', (c) => {
|
|
|
250
283
|
|
|
251
284
|
### c.json()
|
|
252
285
|
|
|
253
|
-
Render JSON as `Content-Type:application/json
|
|
286
|
+
Render JSON as `Content-Type:application/json`.
|
|
254
287
|
|
|
255
288
|
```js
|
|
256
289
|
app.get('/api', (c) => {
|
|
@@ -260,7 +293,7 @@ app.get('/api', (c) => {
|
|
|
260
293
|
|
|
261
294
|
### c.html()
|
|
262
295
|
|
|
263
|
-
Render HTML as `Content-Type:text/html
|
|
296
|
+
Render HTML as `Content-Type:text/html`.
|
|
264
297
|
|
|
265
298
|
```js
|
|
266
299
|
app.get('/', (c) => {
|
|
@@ -270,7 +303,7 @@ app.get('/', (c) => {
|
|
|
270
303
|
|
|
271
304
|
### c.notFound()
|
|
272
305
|
|
|
273
|
-
Return the
|
|
306
|
+
Return the `404 Not Found` Response.
|
|
274
307
|
|
|
275
308
|
```js
|
|
276
309
|
app.get('/notfound', (c) => {
|
|
@@ -280,7 +313,7 @@ app.get('/notfound', (c) => {
|
|
|
280
313
|
|
|
281
314
|
### c.redirect()
|
|
282
315
|
|
|
283
|
-
Redirect, default status code is `302
|
|
316
|
+
Redirect, default status code is `302`.
|
|
284
317
|
|
|
285
318
|
```js
|
|
286
319
|
app.get('/redirect', (c) => c.redirect('/'))
|
|
@@ -319,29 +352,9 @@ app.get('*', async c => {
|
|
|
319
352
|
})
|
|
320
353
|
```
|
|
321
354
|
|
|
322
|
-
## Not Found
|
|
323
|
-
|
|
324
|
-
If you want, you can set the default `404 Not Found` Response:
|
|
325
|
-
|
|
326
|
-
```js
|
|
327
|
-
app.notFound = (c) => {
|
|
328
|
-
return c.text('This is default 404 Not Found', 404)
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
## Error handling
|
|
333
|
-
|
|
334
|
-
You can handle errors in your way:
|
|
335
|
-
|
|
336
|
-
```js
|
|
337
|
-
app.onError = (err, c) => {
|
|
338
|
-
return c.text(`This is error message: ${err.mssage}`, 500)
|
|
339
|
-
}
|
|
340
|
-
```
|
|
341
|
-
|
|
342
355
|
## fire
|
|
343
356
|
|
|
344
|
-
`app.fire()` do
|
|
357
|
+
`app.fire()` do this.
|
|
345
358
|
|
|
346
359
|
```js
|
|
347
360
|
addEventListener('fetch', (event) => {
|
|
@@ -351,7 +364,7 @@ addEventListener('fetch', (event) => {
|
|
|
351
364
|
|
|
352
365
|
## fetch
|
|
353
366
|
|
|
354
|
-
`app.fetch
|
|
367
|
+
`app.fetch` for Cloudflare Module Worker syntax.
|
|
355
368
|
|
|
356
369
|
```js
|
|
357
370
|
export default {
|
|
@@ -361,7 +374,7 @@ export default {
|
|
|
361
374
|
}
|
|
362
375
|
|
|
363
376
|
/*
|
|
364
|
-
or just do
|
|
377
|
+
or just do:
|
|
365
378
|
export default app
|
|
366
379
|
*/
|
|
367
380
|
```
|
|
@@ -374,15 +387,15 @@ Let's write your first code for Cloudflare Workers with Hono.
|
|
|
374
387
|
|
|
375
388
|
### 1. Install Wrangler
|
|
376
389
|
|
|
377
|
-
Install Cloudflare Command Line "[Wrangler](https://github.com/cloudflare/wrangler)"
|
|
390
|
+
Install Cloudflare Command Line "[Wrangler](https://github.com/cloudflare/wrangler)".
|
|
378
391
|
|
|
379
392
|
```sh
|
|
380
|
-
npm i @cloudflare/wrangler -g
|
|
393
|
+
$ npm i @cloudflare/wrangler -g
|
|
381
394
|
```
|
|
382
395
|
|
|
383
396
|
### 2. `npm init`
|
|
384
397
|
|
|
385
|
-
Make npm skeleton directory.
|
|
398
|
+
Make a npm skeleton directory.
|
|
386
399
|
|
|
387
400
|
```sh
|
|
388
401
|
mkdir hono-example
|
|
@@ -395,15 +408,15 @@ npm init -y
|
|
|
395
408
|
Init as a wrangler project.
|
|
396
409
|
|
|
397
410
|
```sh
|
|
398
|
-
wrangler init
|
|
411
|
+
$ wrangler init
|
|
399
412
|
```
|
|
400
413
|
|
|
401
414
|
### 4. `npm install hono`
|
|
402
415
|
|
|
403
|
-
Install `hono` from npm registry.
|
|
416
|
+
Install `hono` from the npm registry.
|
|
404
417
|
|
|
405
418
|
```sh
|
|
406
|
-
npm i hono
|
|
419
|
+
$ npm i hono
|
|
407
420
|
```
|
|
408
421
|
|
|
409
422
|
### 5. Write your app
|
|
@@ -421,10 +434,10 @@ app.fire()
|
|
|
421
434
|
|
|
422
435
|
### 6. Run
|
|
423
436
|
|
|
424
|
-
Run the development server locally. Then, access
|
|
437
|
+
Run the development server locally. Then, access `http://127.0.0.1:8787/` in your Web browser.
|
|
425
438
|
|
|
426
439
|
```sh
|
|
427
|
-
wrangler dev
|
|
440
|
+
$ wrangler dev
|
|
428
441
|
```
|
|
429
442
|
|
|
430
443
|
### 7. Publish
|
|
@@ -432,12 +445,22 @@ wrangler dev
|
|
|
432
445
|
Deploy to Cloudflare. That's all!
|
|
433
446
|
|
|
434
447
|
```sh
|
|
435
|
-
wrangler publish
|
|
448
|
+
$ wrangler publish
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Starter template
|
|
452
|
+
|
|
453
|
+
You can start making your application of Cloudflare Workers with [the starter template](https://github.com/yusukebe/hono-minimal). It is a realy minimal using TypeScript, esbuild, and Miniflare.
|
|
454
|
+
|
|
455
|
+
To generate a project skelton, run this command.
|
|
456
|
+
|
|
457
|
+
```
|
|
458
|
+
$ wrangler generate my-app https://github.com/yusukebe/hono-minimal
|
|
436
459
|
```
|
|
437
460
|
|
|
438
461
|
## Related projects
|
|
439
462
|
|
|
440
|
-
Implementation of the router is inspired by [goblin](https://github.com/bmf-san/goblin). API design is inspired by [express](https://github.com/expressjs/express) and [koa](https://github.com/koajs/koa). [itty-router](https://github.com/kwhitley/itty-router), [Sunder](https://github.com/SunderJS/sunder), and [worktop](https://github.com/lukeed/worktop) are the other routers or frameworks for Cloudflare Workers.
|
|
463
|
+
Implementation of the original router `TrieRouter` is inspired by [goblin](https://github.com/bmf-san/goblin). `RegExpRouter` is inspired by [Router::Boom](https://github.com/tokuhirom/Router-Boom). API design is inspired by [express](https://github.com/expressjs/express) and [koa](https://github.com/koajs/koa). [itty-router](https://github.com/kwhitley/itty-router), [Sunder](https://github.com/SunderJS/sunder), and [worktop](https://github.com/lukeed/worktop) are the other routers or frameworks for Cloudflare Workers.
|
|
441
464
|
|
|
442
465
|
- express <https://github.com/expressjs/express>
|
|
443
466
|
- koa <https://github.com/koajs/koa>
|
|
@@ -445,10 +468,11 @@ Implementation of the router is inspired by [goblin](https://github.com/bmf-san/
|
|
|
445
468
|
- Sunder <https://github.com/SunderJS/sunder>
|
|
446
469
|
- goblin <https://github.com/bmf-san/goblin>
|
|
447
470
|
- worktop <https://github.com/lukeed/worktop>
|
|
471
|
+
- Router::Boom <https://github.com/tokuhirom/Router-Boom>
|
|
448
472
|
|
|
449
473
|
## Contributing
|
|
450
474
|
|
|
451
|
-
Contributions Welcome! You can contribute by the following way
|
|
475
|
+
Contributions Welcome! You can contribute by the following way.
|
|
452
476
|
|
|
453
477
|
- Write or fix documents
|
|
454
478
|
- Write code of middleware
|
|
@@ -456,7 +480,7 @@ Contributions Welcome! You can contribute by the following way:
|
|
|
456
480
|
- Refactor the code
|
|
457
481
|
- etc.
|
|
458
482
|
|
|
459
|
-
|
|
483
|
+
Let's make Hono together!
|
|
460
484
|
|
|
461
485
|
## Contributors
|
|
462
486
|
|
package/dist/compose.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ErrorHandler } from './hono';
|
|
2
|
+
export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler) => (context: C) => Promise<C>;
|
package/dist/compose.js
CHANGED
|
@@ -4,33 +4,31 @@ 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
6
|
const compose = (middleware, onError) => {
|
|
7
|
-
|
|
8
|
-
return function (context, next) {
|
|
7
|
+
return function (context) {
|
|
9
8
|
let index = -1;
|
|
10
9
|
return dispatch(0);
|
|
11
10
|
async function dispatch(i) {
|
|
12
|
-
if (i
|
|
13
|
-
return
|
|
14
|
-
index = i;
|
|
15
|
-
let fn = middleware[i];
|
|
16
|
-
if (i === middleware.length)
|
|
17
|
-
fn = next;
|
|
18
|
-
if (!fn)
|
|
19
|
-
return Promise.resolve();
|
|
20
|
-
try {
|
|
21
|
-
return Promise.resolve(fn(context, dispatch.bind(null, i + 1))).catch((e) => {
|
|
22
|
-
errors.push(e);
|
|
23
|
-
if (onError && context instanceof context_1.Context) {
|
|
24
|
-
context.res = onError(errors[0], context);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
throw errors[0];
|
|
28
|
-
}
|
|
29
|
-
});
|
|
11
|
+
if (i === middleware.length) {
|
|
12
|
+
return context;
|
|
30
13
|
}
|
|
31
|
-
|
|
32
|
-
return Promise.reject(
|
|
14
|
+
if (i <= index) {
|
|
15
|
+
return Promise.reject(new Error('next() called multiple times'));
|
|
33
16
|
}
|
|
17
|
+
const handler = middleware[i];
|
|
18
|
+
index = i;
|
|
19
|
+
return Promise.resolve(handler(context, dispatch.bind(null, i + 1)))
|
|
20
|
+
.then(() => {
|
|
21
|
+
return context;
|
|
22
|
+
})
|
|
23
|
+
.catch((err) => {
|
|
24
|
+
if (onError && context instanceof context_1.Context) {
|
|
25
|
+
context.res = onError(err, context);
|
|
26
|
+
return context;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
34
32
|
}
|
|
35
33
|
};
|
|
36
34
|
};
|
package/dist/hono.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
-
import { Node } from './node';
|
|
3
2
|
import { Context } from './context';
|
|
4
3
|
import type { Env } from './context';
|
|
5
|
-
import type { Result } from './router';
|
|
6
|
-
import { Router } from './router';
|
|
4
|
+
import type { Result, Router } from './router';
|
|
7
5
|
declare global {
|
|
8
6
|
interface Request<ParamKeyType = string> {
|
|
9
7
|
param: (key: ParamKeyType) => string;
|
|
@@ -14,15 +12,11 @@ declare global {
|
|
|
14
12
|
}
|
|
15
13
|
export declare type Handler<RequestParamKeyType = string> = (c: Context<RequestParamKeyType>, next?: Function) => Response | Promise<Response>;
|
|
16
14
|
export declare type MiddlewareHandler = (c: Context, next: Function) => Promise<void>;
|
|
15
|
+
export declare type NotFoundHandler = (c: Context) => Response;
|
|
16
|
+
export declare type ErrorHandler = (err: Error, c: Context) => Response;
|
|
17
17
|
declare type ParamKeyName<NameWithPattern> = NameWithPattern extends `${infer Name}{${infer _Pattern}` ? Name : NameWithPattern;
|
|
18
18
|
declare type ParamKey<Component> = Component extends `:${infer NameWithPattern}` ? ParamKeyName<NameWithPattern> : never;
|
|
19
19
|
declare type ParamKeys<Path> = Path extends `${infer Component}/${infer Rest}` ? ParamKey<Component> | ParamKeys<Rest> : ParamKey<Path>;
|
|
20
|
-
export declare class TrieRouter<T> extends Router<T> {
|
|
21
|
-
node: Node<T>;
|
|
22
|
-
constructor();
|
|
23
|
-
add(method: string, path: string, handler: T): void;
|
|
24
|
-
match(method: string, path: string): Result<T> | null;
|
|
25
|
-
}
|
|
26
20
|
export declare class Hono {
|
|
27
21
|
routerClass: {
|
|
28
22
|
new (): Router<any>;
|
|
@@ -32,6 +26,8 @@ export declare class Hono {
|
|
|
32
26
|
middlewareRouters: Router<MiddlewareHandler>[];
|
|
33
27
|
tempPath: string;
|
|
34
28
|
constructor(init?: Partial<Pick<Hono, 'routerClass' | 'strict'>>);
|
|
29
|
+
notFoundHandler: NotFoundHandler;
|
|
30
|
+
errorHandler: ErrorHandler;
|
|
35
31
|
get<Path extends string>(path: Path, handler: Handler<ParamKeys<Path>>): Hono;
|
|
36
32
|
post<Path extends string>(path: Path, handler: Handler<ParamKeys<Path>>): Hono;
|
|
37
33
|
put<Path extends string>(path: Path, handler: Handler<ParamKeys<Path>>): Hono;
|
|
@@ -42,13 +38,13 @@ export declare class Hono {
|
|
|
42
38
|
all<Path extends string>(path: Path, handler: Handler<ParamKeys<Path>>): Hono;
|
|
43
39
|
route(path: string): Hono;
|
|
44
40
|
use(path: string, middleware: MiddlewareHandler): void;
|
|
41
|
+
onError(handler: ErrorHandler): Hono;
|
|
42
|
+
notFound(handler: NotFoundHandler): Hono;
|
|
45
43
|
addRoute(method: string, path: string, handler: Handler): Hono;
|
|
46
44
|
matchRoute(method: string, path: string): Promise<Result<Handler>>;
|
|
47
45
|
dispatch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>;
|
|
48
46
|
handleEvent(event: FetchEvent): Promise<Response>;
|
|
49
47
|
fetch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>;
|
|
50
48
|
fire(): void;
|
|
51
|
-
onError(err: Error, c: Context): Response;
|
|
52
|
-
notFound(c: Context): Response;
|
|
53
49
|
}
|
|
54
50
|
export {};
|
package/dist/hono.js
CHANGED
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Hono =
|
|
4
|
-
const node_1 = require("./node");
|
|
3
|
+
exports.Hono = void 0;
|
|
5
4
|
const compose_1 = require("./compose");
|
|
6
5
|
const url_1 = require("./utils/url");
|
|
7
6
|
const context_1 = require("./context");
|
|
8
7
|
const router_1 = require("./router");
|
|
9
|
-
|
|
10
|
-
constructor() {
|
|
11
|
-
super();
|
|
12
|
-
this.node = new node_1.Node();
|
|
13
|
-
}
|
|
14
|
-
add(method, path, handler) {
|
|
15
|
-
this.node.insert(method, path, handler);
|
|
16
|
-
}
|
|
17
|
-
match(method, path) {
|
|
18
|
-
return this.node.search(method, path);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
exports.TrieRouter = TrieRouter;
|
|
8
|
+
const trie_router_1 = require("./router/trie-router"); // Default Router
|
|
22
9
|
class Hono {
|
|
23
10
|
constructor(init = {}) {
|
|
24
|
-
this.routerClass = TrieRouter;
|
|
11
|
+
this.routerClass = trie_router_1.TrieRouter;
|
|
25
12
|
this.strict = true; // strict routing - default is true
|
|
13
|
+
this.notFoundHandler = (c) => {
|
|
14
|
+
const message = '404 Not Found';
|
|
15
|
+
return c.text(message, 404);
|
|
16
|
+
};
|
|
17
|
+
this.errorHandler = (err, c) => {
|
|
18
|
+
console.error(`${err.message}`);
|
|
19
|
+
const message = 'Internal Server Error';
|
|
20
|
+
return c.text(message, 500);
|
|
21
|
+
};
|
|
26
22
|
Object.assign(this, init);
|
|
27
23
|
this.router = new this.routerClass();
|
|
28
24
|
this.middlewareRouters = [];
|
|
@@ -66,6 +62,14 @@ class Hono {
|
|
|
66
62
|
router.add(router_1.METHOD_NAME_OF_ALL, path, middleware);
|
|
67
63
|
this.middlewareRouters.push(router);
|
|
68
64
|
}
|
|
65
|
+
onError(handler) {
|
|
66
|
+
this.errorHandler = handler;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
notFound(handler) {
|
|
70
|
+
this.notFoundHandler = handler;
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
69
73
|
// addRoute('get', '/', handler)
|
|
70
74
|
addRoute(method, path, handler) {
|
|
71
75
|
method = method.toUpperCase();
|
|
@@ -95,7 +99,7 @@ class Hono {
|
|
|
95
99
|
const url = new URL(c.req.url);
|
|
96
100
|
return url.searchParams.get(key);
|
|
97
101
|
};
|
|
98
|
-
const handler = result ? result.handler : this.
|
|
102
|
+
const handler = result ? result.handler : this.notFoundHandler;
|
|
99
103
|
const middleware = [];
|
|
100
104
|
for (const mr of this.middlewareRouters) {
|
|
101
105
|
const mwResult = mr.match(router_1.METHOD_NAME_OF_ALL, path);
|
|
@@ -112,11 +116,11 @@ class Hono {
|
|
|
112
116
|
await next();
|
|
113
117
|
};
|
|
114
118
|
middleware.push(wrappedHandler);
|
|
115
|
-
const composed = (0, compose_1.compose)(middleware, this.
|
|
119
|
+
const composed = (0, compose_1.compose)(middleware, this.errorHandler);
|
|
116
120
|
const c = new context_1.Context(request, { env: env, event: event, res: null });
|
|
117
|
-
c.notFound = () => this.
|
|
118
|
-
await composed(c);
|
|
119
|
-
return
|
|
121
|
+
c.notFound = () => this.notFoundHandler(c);
|
|
122
|
+
const context = await composed(c);
|
|
123
|
+
return context.res;
|
|
120
124
|
}
|
|
121
125
|
async handleEvent(event) {
|
|
122
126
|
return this.dispatch(event.request, {}, event);
|
|
@@ -129,16 +133,5 @@ class Hono {
|
|
|
129
133
|
event.respondWith(this.handleEvent(event));
|
|
130
134
|
});
|
|
131
135
|
}
|
|
132
|
-
// Default error Response
|
|
133
|
-
onError(err, c) {
|
|
134
|
-
console.error(`${err.message}`);
|
|
135
|
-
const message = 'Internal Server Error';
|
|
136
|
-
return c.text(message, 500);
|
|
137
|
-
}
|
|
138
|
-
// Default 404 not found Response
|
|
139
|
-
notFound(c) {
|
|
140
|
-
const message = 'Not Found';
|
|
141
|
-
return c.text(message, 404);
|
|
142
|
-
}
|
|
143
136
|
}
|
|
144
137
|
exports.Hono = Hono;
|
|
@@ -3,4 +3,7 @@ export declare const basicAuth: (options: {
|
|
|
3
3
|
username: string;
|
|
4
4
|
password: string;
|
|
5
5
|
realm?: string;
|
|
6
|
-
}
|
|
6
|
+
}, ...users: {
|
|
7
|
+
username: string;
|
|
8
|
+
password: string;
|
|
9
|
+
}[]) => (ctx: Context, next: Function) => Promise<any>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.basicAuth = void 0;
|
|
4
4
|
const buffer_1 = require("../../utils/buffer");
|
|
5
|
+
const crypto_1 = require("../../utils/crypto");
|
|
5
6
|
const CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/;
|
|
6
7
|
const USER_PASS_REGEXP = /^([^:]*):(.*)$/;
|
|
7
8
|
const auth = (req) => {
|
|
@@ -18,30 +19,39 @@ const auth = (req) => {
|
|
|
18
19
|
if (!match) {
|
|
19
20
|
return undefined;
|
|
20
21
|
}
|
|
21
|
-
const userPass = USER_PASS_REGEXP.exec((0,
|
|
22
|
+
const userPass = USER_PASS_REGEXP.exec((0, crypto_1.decodeBase64)(match[1]));
|
|
22
23
|
if (!userPass) {
|
|
23
24
|
return undefined;
|
|
24
25
|
}
|
|
25
26
|
return { username: userPass[1], password: userPass[2] };
|
|
26
27
|
};
|
|
27
|
-
const basicAuth = (options) => {
|
|
28
|
+
const basicAuth = (options, ...users) => {
|
|
29
|
+
if (!options) {
|
|
30
|
+
throw new Error('basic auth middleware requires options for "username and password"');
|
|
31
|
+
}
|
|
28
32
|
if (!options.realm) {
|
|
29
33
|
options.realm = 'Secure Area';
|
|
30
34
|
}
|
|
35
|
+
users.unshift({ username: options.username, password: options.password });
|
|
31
36
|
return async (ctx, next) => {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return;
|
|
37
|
+
const requestUser = auth(ctx.req);
|
|
38
|
+
if (requestUser) {
|
|
39
|
+
for (const user of users) {
|
|
40
|
+
const usernameEqual = await (0, buffer_1.timingSafeEqual)(user.username, requestUser.username);
|
|
41
|
+
const passwordEqual = await (0, buffer_1.timingSafeEqual)(user.password, requestUser.password);
|
|
42
|
+
if (usernameEqual && passwordEqual) {
|
|
43
|
+
// Authorized OK
|
|
44
|
+
return next();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
43
47
|
}
|
|
44
|
-
|
|
48
|
+
ctx.res = new Response('Unauthorized', {
|
|
49
|
+
status: 401,
|
|
50
|
+
headers: {
|
|
51
|
+
'WWW-Authenticate': 'Basic realm="' + options.realm.replace(/"/g, '\\"') + '"',
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
45
55
|
};
|
|
46
56
|
};
|
|
47
57
|
exports.basicAuth = basicAuth;
|
|
@@ -1,26 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.bodyParse = void 0;
|
|
4
|
+
const body_1 = require("../../utils/body");
|
|
4
5
|
const bodyParse = () => {
|
|
5
6
|
return async (ctx, next) => {
|
|
6
|
-
|
|
7
|
-
if (contentType.includes('application/json')) {
|
|
8
|
-
ctx.req.parsedBody = await ctx.req.json();
|
|
9
|
-
}
|
|
10
|
-
else if (contentType.includes('application/text')) {
|
|
11
|
-
ctx.req.parsedBody = await ctx.req.text();
|
|
12
|
-
}
|
|
13
|
-
else if (contentType.includes('text/html')) {
|
|
14
|
-
ctx.req.parsedBody = await ctx.req.text();
|
|
15
|
-
}
|
|
16
|
-
else if (contentType.includes('form')) {
|
|
17
|
-
const form = {};
|
|
18
|
-
const data = [...(await ctx.req.formData())].reduce((acc, cur) => {
|
|
19
|
-
acc[cur[0]] = cur[1];
|
|
20
|
-
return acc;
|
|
21
|
-
}, form);
|
|
22
|
-
ctx.req.parsedBody = data;
|
|
23
|
-
}
|
|
7
|
+
ctx.req.parsedBody = await (0, body_1.parseBody)(ctx.req);
|
|
24
8
|
await next();
|
|
25
9
|
};
|
|
26
10
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.etag = void 0;
|
|
4
|
+
const crypto_1 = require("../../utils/crypto");
|
|
5
|
+
const body_1 = require("../../utils/body");
|
|
6
|
+
const etag = (options = { weak: false }) => {
|
|
7
|
+
return async (c, next) => {
|
|
8
|
+
const ifNoneMatch = c.req.header('If-None-Match') || c.req.header('if-none-match');
|
|
9
|
+
await next();
|
|
10
|
+
const clone = c.res.clone();
|
|
11
|
+
const body = await (0, body_1.parseBody)(c.res);
|
|
12
|
+
const hash = await (0, crypto_1.sha1)(body);
|
|
13
|
+
const etag = options.weak ? `W/"${hash}"` : `"${hash}"`;
|
|
14
|
+
if (ifNoneMatch && ifNoneMatch === etag) {
|
|
15
|
+
await clone.blob(); // Force using body
|
|
16
|
+
c.res = new Response(null, {
|
|
17
|
+
status: 304,
|
|
18
|
+
statusText: 'Not Modified',
|
|
19
|
+
});
|
|
20
|
+
c.res.headers.delete('Content-Length');
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
c.res = new Response(clone.body, clone);
|
|
24
|
+
c.res.headers.append('ETag', etag);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
exports.etag = etag;
|
|
@@ -41,9 +41,8 @@ class RegExpRouter extends router_1.Router {
|
|
|
41
41
|
const index = match.indexOf('', 1);
|
|
42
42
|
const [handler, paramMap] = handlers[replacementMap[index]];
|
|
43
43
|
const params = {};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
params[keys[i]] = match[paramMap[keys[i]]];
|
|
44
|
+
for (let i = 0; i < paramMap.length; i++) {
|
|
45
|
+
params[paramMap[i][0]] = match[paramMap[i][1]];
|
|
47
46
|
}
|
|
48
47
|
return new router_1.Result(handler, params);
|
|
49
48
|
}
|
|
@@ -68,7 +67,7 @@ class RegExpRouter extends router_1.Router {
|
|
|
68
67
|
return;
|
|
69
68
|
}
|
|
70
69
|
if (routes.length === 1 && routes[0][0] === '*') {
|
|
71
|
-
this.matchers[method] = [true, null, [[routes[0][1],
|
|
70
|
+
this.matchers[method] = [true, null, [[routes[0][1], []]]];
|
|
72
71
|
return;
|
|
73
72
|
}
|
|
74
73
|
if (routes.length === 1 && !routes[0][0].match(/:/)) {
|
|
@@ -77,7 +76,7 @@ class RegExpRouter extends router_1.Router {
|
|
|
77
76
|
? routes[0][0].replace(/\/\*$/, '(?:$|/)') // /path/to/* => /path/to(?:$|/)
|
|
78
77
|
: `${routes[0][0]}$`; // /path/to/action => /path/to/action$
|
|
79
78
|
const regExpStr = `^${tmp.replace(/\*/g, '[^/]+')}`; // /prefix/*/path/to => /prefix/[^/]+/path/to
|
|
80
|
-
this.matchers[method] = [new RegExp(regExpStr), null, [[routes[0][1],
|
|
79
|
+
this.matchers[method] = [new RegExp(regExpStr), null, [[routes[0][1], []]]];
|
|
81
80
|
return;
|
|
82
81
|
}
|
|
83
82
|
for (let i = 0; i < routes.length; i++) {
|
|
@@ -87,9 +86,9 @@ class RegExpRouter extends router_1.Router {
|
|
|
87
86
|
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
88
87
|
for (let i = 0; i < handlers.length; i++) {
|
|
89
88
|
const paramMap = handlers[i][1];
|
|
90
|
-
|
|
91
|
-
paramMap[
|
|
92
|
-
}
|
|
89
|
+
for (let i = 0; i < paramMap.length; i++) {
|
|
90
|
+
paramMap[i][1] = paramReplacementMap[paramMap[i][1]];
|
|
91
|
+
}
|
|
93
92
|
}
|
|
94
93
|
this.matchers[method] = [new RegExp(regexp), indexReplacementMap, handlers];
|
|
95
94
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TrieRouter } from './router';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Node = void 0;
|
|
4
|
-
const url_1 = require("
|
|
5
|
-
const router_1 = require("
|
|
4
|
+
const url_1 = require("../../utils/url");
|
|
5
|
+
const router_1 = require("../../router");
|
|
6
6
|
const noRoute = () => {
|
|
7
7
|
return null;
|
|
8
8
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Router } from '../../router';
|
|
2
|
+
import type { Result } from '../../router';
|
|
3
|
+
import { Node } from './node';
|
|
4
|
+
export declare class TrieRouter<T> extends Router<T> {
|
|
5
|
+
node: Node<T>;
|
|
6
|
+
constructor();
|
|
7
|
+
add(method: string, path: string, handler: T): void;
|
|
8
|
+
match(method: string, path: string): Result<T> | null;
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TrieRouter = void 0;
|
|
4
|
+
const router_1 = require("../../router");
|
|
5
|
+
const node_1 = require("./node");
|
|
6
|
+
class TrieRouter extends router_1.Router {
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
this.node = new node_1.Node();
|
|
10
|
+
}
|
|
11
|
+
add(method, path, handler) {
|
|
12
|
+
this.node.insert(method, path, handler);
|
|
13
|
+
}
|
|
14
|
+
match(method, path) {
|
|
15
|
+
return this.node.search(method, path);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.TrieRouter = TrieRouter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const parseBody: (r: Request | Response) => Promise<string | object | Record<string, string | File>>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseBody = void 0;
|
|
4
|
+
const parseBody = async (r) => {
|
|
5
|
+
const contentType = r.headers.get('Content-Type') || '';
|
|
6
|
+
if (contentType.includes('application/json')) {
|
|
7
|
+
return await r.json();
|
|
8
|
+
}
|
|
9
|
+
else if (contentType.includes('application/text')) {
|
|
10
|
+
return r.text();
|
|
11
|
+
}
|
|
12
|
+
else if (contentType.startsWith('text')) {
|
|
13
|
+
return r.text();
|
|
14
|
+
}
|
|
15
|
+
else if (contentType.includes('form')) {
|
|
16
|
+
const form = {};
|
|
17
|
+
const data = [...(await r.formData())].reduce((acc, cur) => {
|
|
18
|
+
acc[cur[0]] = cur[1];
|
|
19
|
+
return acc;
|
|
20
|
+
}, form);
|
|
21
|
+
return data;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
exports.parseBody = parseBody;
|
package/dist/utils/buffer.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
1
|
export declare const equal: (a: ArrayBuffer, b: ArrayBuffer) => boolean;
|
|
2
|
-
export declare const decodeBase64: (str: string) => any;
|
|
3
|
-
export declare const sha256: (a: string | object | boolean) => Promise<string>;
|
|
4
2
|
export declare const timingSafeEqual: (a: string | object | boolean, b: string | object | boolean) => Promise<boolean>;
|
package/dist/utils/buffer.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.timingSafeEqual = exports.
|
|
3
|
+
exports.timingSafeEqual = exports.equal = void 0;
|
|
4
|
+
const crypto_1 = require("./crypto");
|
|
4
5
|
const equal = (a, b) => {
|
|
5
6
|
if (a === b) {
|
|
6
7
|
return true;
|
|
@@ -19,52 +20,9 @@ const equal = (a, b) => {
|
|
|
19
20
|
return true;
|
|
20
21
|
};
|
|
21
22
|
exports.equal = equal;
|
|
22
|
-
const decodeBase64 = (str) => {
|
|
23
|
-
try {
|
|
24
|
-
const text = atob(str);
|
|
25
|
-
const length = text.length;
|
|
26
|
-
const bytes = new Uint8Array(length);
|
|
27
|
-
for (let i = 0; i < length; i++) {
|
|
28
|
-
bytes[i] = text.charCodeAt(i);
|
|
29
|
-
}
|
|
30
|
-
const decoder = new TextDecoder();
|
|
31
|
-
return decoder.decode(bytes);
|
|
32
|
-
}
|
|
33
|
-
catch (_a) { }
|
|
34
|
-
try {
|
|
35
|
-
const { Buffer } = require('buffer');
|
|
36
|
-
return Buffer.from(str, 'base64').toString();
|
|
37
|
-
}
|
|
38
|
-
catch (e) {
|
|
39
|
-
console.error('If you want to do "decodeBase64", polyfill "buffer" module.');
|
|
40
|
-
throw e;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
exports.decodeBase64 = decodeBase64;
|
|
44
|
-
const sha256 = async (a) => {
|
|
45
|
-
if (crypto && crypto.subtle) {
|
|
46
|
-
const buffer = await crypto.subtle.digest({
|
|
47
|
-
name: 'SHA-256',
|
|
48
|
-
}, new TextEncoder().encode(String(a)));
|
|
49
|
-
const hash = Array.prototype.map
|
|
50
|
-
.call(new Uint8Array(buffer), (x) => ('00' + x.toString(16)).slice(-2))
|
|
51
|
-
.join('');
|
|
52
|
-
return hash;
|
|
53
|
-
}
|
|
54
|
-
try {
|
|
55
|
-
const crypto = require('crypto');
|
|
56
|
-
const hash = crypto.createHash('sha256').update(a).digest('hex');
|
|
57
|
-
return hash;
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
console.error('If you want to do "sha256", polyfill "crypto" module.');
|
|
61
|
-
throw e;
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
exports.sha256 = sha256;
|
|
65
23
|
const timingSafeEqual = async (a, b) => {
|
|
66
|
-
const sa = await (0,
|
|
67
|
-
const sb = await (0,
|
|
24
|
+
const sa = await (0, crypto_1.sha256)(a);
|
|
25
|
+
const sb = await (0, crypto_1.sha256)(b);
|
|
68
26
|
return sa === sb && a === b;
|
|
69
27
|
};
|
|
70
28
|
exports.timingSafeEqual = timingSafeEqual;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare type Algorithm = {
|
|
2
|
+
name: string;
|
|
3
|
+
alias: string;
|
|
4
|
+
};
|
|
5
|
+
declare type Data = string | object | boolean;
|
|
6
|
+
export declare const sha256: (data: Data) => Promise<string>;
|
|
7
|
+
export declare const sha1: (data: Data) => Promise<string>;
|
|
8
|
+
export declare const createHash: (data: Data, algorithm: Algorithm) => Promise<string>;
|
|
9
|
+
export declare const decodeBase64: (str: string) => any;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decodeBase64 = exports.createHash = exports.sha1 = exports.sha256 = void 0;
|
|
4
|
+
const sha256 = async (data) => {
|
|
5
|
+
const algorithm = { name: 'SHA-256', alias: 'sha256' };
|
|
6
|
+
const hash = await (0, exports.createHash)(data, algorithm);
|
|
7
|
+
return hash;
|
|
8
|
+
};
|
|
9
|
+
exports.sha256 = sha256;
|
|
10
|
+
const sha1 = async (data) => {
|
|
11
|
+
const algorithm = { name: 'SHA-1', alias: 'sha1' };
|
|
12
|
+
const hash = await (0, exports.createHash)(data, algorithm);
|
|
13
|
+
return hash;
|
|
14
|
+
};
|
|
15
|
+
exports.sha1 = sha1;
|
|
16
|
+
const createHash = async (data, algorithm) => {
|
|
17
|
+
if (crypto && crypto.subtle) {
|
|
18
|
+
const buffer = await crypto.subtle.digest({
|
|
19
|
+
name: algorithm.name,
|
|
20
|
+
}, new TextEncoder().encode(String(data)));
|
|
21
|
+
const hash = Array.prototype.map
|
|
22
|
+
.call(new Uint8Array(buffer), (x) => ('00' + x.toString(16)).slice(-2))
|
|
23
|
+
.join('');
|
|
24
|
+
return hash;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const crypto = require('crypto');
|
|
28
|
+
const hash = crypto.createHash(algorithm.alias).update(data).digest('hex');
|
|
29
|
+
return hash;
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
console.error(`If you want to create hash ${algorithm.name}, polyfill "crypto" module.`);
|
|
33
|
+
throw e;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
exports.createHash = createHash;
|
|
37
|
+
const decodeBase64 = (str) => {
|
|
38
|
+
try {
|
|
39
|
+
const text = atob(str);
|
|
40
|
+
const length = text.length;
|
|
41
|
+
const bytes = new Uint8Array(length);
|
|
42
|
+
for (let i = 0; i < length; i++) {
|
|
43
|
+
bytes[i] = text.charCodeAt(i);
|
|
44
|
+
}
|
|
45
|
+
const decoder = new TextDecoder();
|
|
46
|
+
return decoder.decode(bytes);
|
|
47
|
+
}
|
|
48
|
+
catch (_a) { }
|
|
49
|
+
try {
|
|
50
|
+
const { Buffer } = require('buffer');
|
|
51
|
+
return Buffer.from(str, 'base64').toString();
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
console.error('If you want to do "decodeBase64", polyfill "buffer" module.');
|
|
55
|
+
throw e;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
exports.decodeBase64 = decodeBase64;
|
package/dist/utils/mime.js
CHANGED
|
@@ -4,11 +4,10 @@ exports.getMimeType = void 0;
|
|
|
4
4
|
const getMimeType = (filename) => {
|
|
5
5
|
const regexp = /\.([a-zA-Z0-9]+?)$/;
|
|
6
6
|
const match = filename.match(regexp);
|
|
7
|
-
if (!match)
|
|
7
|
+
if (!match)
|
|
8
8
|
return;
|
|
9
|
-
}
|
|
10
9
|
let mimeType = mimes[match[1]];
|
|
11
|
-
if (mimeType.startsWith('text') || mimeType === 'application/json') {
|
|
10
|
+
if ((mimeType && mimeType.startsWith('text')) || mimeType === 'application/json') {
|
|
12
11
|
mimeType += '; charset=utf-8';
|
|
13
12
|
}
|
|
14
13
|
return mimeType;
|
|
@@ -43,6 +42,7 @@ const mimes = {
|
|
|
43
42
|
js: 'text/javascript',
|
|
44
43
|
json: 'application/json',
|
|
45
44
|
jsonld: 'application/ld+json',
|
|
45
|
+
map: 'application/json',
|
|
46
46
|
mid: 'audio/x-midi',
|
|
47
47
|
midi: 'audio/x-midi',
|
|
48
48
|
mjs: 'text/javascript',
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "[炎] Ultrafast web framework for Cloudflare Workers.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist"
|
|
9
9
|
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "jest",
|
|
12
|
+
"lint": "eslint --ext js,ts src .eslintrc.js && prettier --check src",
|
|
13
|
+
"build": "rimraf dist && tsc",
|
|
14
|
+
"watch": "tsc -w",
|
|
15
|
+
"prepublishOnly": "yarn build"
|
|
16
|
+
},
|
|
10
17
|
"exports": {
|
|
11
18
|
".": "./dist/index.js",
|
|
12
19
|
"./basic-auth": "./dist/middleware/basic-auth/basic-auth.js",
|
|
@@ -17,8 +24,7 @@
|
|
|
17
24
|
"./mustache": "./dist/middleware/mustache/mustache.js",
|
|
18
25
|
"./powered-by": "./dist/middleware/powered-by/powered-by.js",
|
|
19
26
|
"./serve-static": "./dist/middleware/serve-static/serve-static.js",
|
|
20
|
-
"./
|
|
21
|
-
"./package.json": "./package.json"
|
|
27
|
+
"./router/reg-exp-router": "./dist/router/reg-exp-router/index.js"
|
|
22
28
|
},
|
|
23
29
|
"typesVersions": {
|
|
24
30
|
"*": {
|
|
@@ -45,16 +51,12 @@
|
|
|
45
51
|
],
|
|
46
52
|
"serve-static": [
|
|
47
53
|
"./dist/middleware/serve-static/serve-static.d.ts"
|
|
54
|
+
],
|
|
55
|
+
"router/reg-exp-router": [
|
|
56
|
+
"./dist/router/reg-exp-router/router.d.ts"
|
|
48
57
|
]
|
|
49
58
|
}
|
|
50
59
|
},
|
|
51
|
-
"scripts": {
|
|
52
|
-
"test": "jest",
|
|
53
|
-
"lint": "eslint --ext js,ts src .eslintrc.js test && prettier --check src",
|
|
54
|
-
"build": "rimraf dist && tsc",
|
|
55
|
-
"watch": "tsc -w",
|
|
56
|
-
"prepublishOnly": "yarn build"
|
|
57
|
-
},
|
|
58
60
|
"author": "Yusuke Wada <yusuke@kamawada.com> (https://github.com/yusukebe)",
|
|
59
61
|
"license": "MIT",
|
|
60
62
|
"repository": {
|