hono 1.0.0 → 1.2.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.
Files changed (43) hide show
  1. package/README.md +189 -125
  2. package/dist/compose.d.ts +2 -2
  3. package/dist/compose.js +20 -8
  4. package/dist/context.d.ts +4 -5
  5. package/dist/context.js +5 -17
  6. package/dist/hono.d.ts +51 -25
  7. package/dist/hono.js +106 -49
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +2 -1
  10. package/dist/middleware/basic-auth/index.js +11 -10
  11. package/dist/middleware/body-parse/index.d.ts +5 -0
  12. package/dist/middleware/cookie/index.d.ts +1 -3
  13. package/dist/middleware/graphql-server/parse-body.d.ts +1 -3
  14. package/dist/middleware/jwt/index.d.ts +6 -0
  15. package/dist/middleware/jwt/index.js +49 -0
  16. package/dist/middleware/logger/index.js +3 -5
  17. package/dist/middleware/mustache/index.js +3 -9
  18. package/dist/router/reg-exp-router/node.d.ts +3 -0
  19. package/dist/router/reg-exp-router/node.js +13 -7
  20. package/dist/router/reg-exp-router/router.d.ts +21 -2
  21. package/dist/router/reg-exp-router/router.js +300 -80
  22. package/dist/router/reg-exp-router/trie.d.ts +4 -0
  23. package/dist/router/reg-exp-router/trie.js +2 -2
  24. package/dist/router/trie-router/node.d.ts +4 -3
  25. package/dist/router/trie-router/node.js +123 -55
  26. package/dist/router/trie-router/router.d.ts +1 -1
  27. package/dist/router.d.ts +4 -3
  28. package/dist/router.js +5 -4
  29. package/dist/utils/body.js +2 -2
  30. package/dist/utils/buffer.d.ts +1 -0
  31. package/dist/utils/buffer.js +9 -1
  32. package/dist/utils/crypto.d.ts +0 -2
  33. package/dist/utils/crypto.js +1 -51
  34. package/dist/utils/encode.d.ts +7 -0
  35. package/dist/utils/encode.js +105 -0
  36. package/dist/utils/jwt/index.d.ts +1 -0
  37. package/dist/utils/jwt/index.js +27 -0
  38. package/dist/utils/jwt/jwt.d.ts +7 -0
  39. package/dist/utils/jwt/jwt.js +98 -0
  40. package/dist/utils/jwt/types.d.ts +20 -0
  41. package/dist/utils/jwt/types.js +44 -0
  42. package/dist/utils/url.js +4 -4
  43. package/package.json +29 -21
package/README.md CHANGED
@@ -1,28 +1,22 @@
1
1
  <div align="center">
2
- <a href="https://github.com/yusukebe/hono">
3
- <img src="https://raw.githubusercontent.com/yusukebe/hono/master/docs/images/hono-title.png" width="500" height="auto" alt="Hono"/>
2
+ <a href="https://github.com/honojs/hono">
3
+ <img src="https://raw.githubusercontent.com/honojs/hono/master/docs/images/hono-title.png" width="500" height="auto" alt="Hono"/>
4
4
  </a>
5
5
  </div>
6
6
 
7
7
  <hr />
8
8
 
9
- <p>
10
- <a href="https://github.com/yusukebe/hono/blob/master/README.md">English</a>
11
- &#x000B7;
12
- <a href="https://github.com/yusukebe/hono/blob/master/docs/README.ja.md">日本語</a>
13
- </p>
14
-
15
- [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/yusukebe/hono/ci)](https://github.com/yusukebe/hono/actions)
16
- [![GitHub](https://img.shields.io/github/license/yusukebe/hono)](https://github.com/yusukebe/hono/blob/master/LICENSE)
9
+ [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/honojs/hono/ci)](https://github.com/honojs/hono/actions)
10
+ [![GitHub](https://img.shields.io/github/license/honojs/hono)](https://github.com/honojs/hono/blob/master/LICENSE)
17
11
  [![npm](https://img.shields.io/npm/v/hono)](https://www.npmjs.com/package/hono)
18
12
  [![npm](https://img.shields.io/npm/dm/hono)](https://www.npmjs.com/package/hono)
19
13
  [![npm type definitions](https://img.shields.io/npm/types/hono)](https://www.npmjs.com/package/hono)
20
- [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/yusukebe/hono)](https://github.com/yusukebe/hono/pulse)
21
- [![GitHub last commit](https://img.shields.io/github/last-commit/yusukebe/hono)](https://github.com/yusukebe/hono/commits/master)
14
+ [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/honojs/hono)](https://github.com/honojs/hono/pulse)
15
+ [![GitHub last commit](https://img.shields.io/github/last-commit/honojs/hono)](https://github.com/honojs/hono/commits/master)
22
16
 
23
- Hono - _**[炎] means flame🔥 in Japanese**_ - is small, simple, and ultrafast web framework for Cloudflare Workers and Fastly Compute@Edge.
17
+ Hono - _**[炎] means flame🔥 in Japanese**_ - is a small, simple, and ultrafast web framework for Cloudflare Workers or Service Worker based serverless such as Fastly Compute@Edge.
24
18
 
25
- ```js
19
+ ```ts
26
20
  import { Hono } from 'hono'
27
21
  const app = new Hono()
28
22
 
@@ -34,7 +28,7 @@ app.fire()
34
28
  ## Features
35
29
 
36
30
  - **Ultrafast** - the router does not use linear loops.
37
- - **Zero-dependencies** - using only Service Worker and Web standard API.
31
+ - **Zero-dependencies** - using only Service Worker and Web Standard API.
38
32
  - **Middleware** - built-in middleware and ability to extend with your own middleware.
39
33
  - **TypeScript** - first-class TypeScript support.
40
34
  - **Optimized** - for Cloudflare Workers.
@@ -44,33 +38,97 @@ app.fire()
44
38
  **Hono is fastest**, compared to other routers for Cloudflare Workers.
45
39
 
46
40
  ```plain
47
- hono x 809,503 ops/sec ±6.94% (73 runs sampled)
48
- itty-router x 157,310 ops/sec ±4.31% (87 runs sampled)
49
- sunder x 328,350 ops/sec ±2.30% (95 runs sampled)
50
- worktop x 209,758 ops/sec ±4.28% (83 runs sampled)
51
- Fastest is hono
52
- ✨ Done in 60.66s.
41
+ hono - trie-router(default) x 737,602 ops/sec ±3.65% (67 runs sampled)
42
+ hono - regexp-router x 1,188,203 ops/sec ±6.42% (60 runs sampled)
43
+ itty-router x 163,970 ops/sec ±3.05% (91 runs sampled)
44
+ sunder x 344,468 ops/sec ±0.87% (97 runs sampled)
45
+ worktop x 222,044 ops/sec ±2.13% (85 runs sampled)
46
+ Fastest is hono - regexp-router
47
+ ✨ Done in 84.04s.
53
48
  ```
54
49
 
50
+ ## Why so fast?
51
+
52
+ Routers used in Hono are really smart.
53
+
54
+ - **TrieRouter**(default) - Implemented with Trie tree structure.
55
+ - **RegExpRouter** - Match routes with one big Regex made before dispatching at once.
56
+
55
57
  ## Hono in 1 minute
56
58
 
57
59
  A demonstration to create an application for Cloudflare Workers with Hono.
58
60
 
59
61
  ![Demo](https://user-images.githubusercontent.com/10682/151973526-342644f9-71c5-4fee-81f4-64a7558bb192.gif)
60
62
 
61
- Now, the named path parameter has types.
63
+ ## Not only fast
62
64
 
63
- ![Demo](https://user-images.githubusercontent.com/10682/154179671-9e491597-6778-44ac-a8e6-4483d7ad5393.png)
65
+ Hono is fast. But not only fast.
64
66
 
65
- ## Install
67
+ ### Write Less, do more
66
68
 
67
- You can install Hono from the npm registry.
69
+ Built-in middleware make _"**Write Less, do more**"_ in reality. You can use a lot of middleware without writing code from scratch. Below are examples.
68
70
 
69
- ```sh
70
- yarn add hono
71
+ - [Basic Authentication](https://github.com/honojs/hono/tree/master/src/middleware/basic-auth/)
72
+ - [Cookie parsing / serializing](https://github.com/honojs/hono/tree/master/src/middleware/cookie/)
73
+ - [CORS](https://github.com/honojs/hono/tree/master/src/middleware/cors/)
74
+ - [ETag](https://github.com/honojs/hono/tree/master/src/middleware/etag/)
75
+ - [GraphQL Server](https://github.com/honojs/hono/tree/master/src/middleware/graphql-server/)
76
+ - [JWT Authentication](https://github.com/honojs/hono/tree/master/src/middleware/jwt/)
77
+ - [Logger](https://github.com/honojs/hono/tree/master/src/middleware/logger/)
78
+ - [Mustache template engine](https://github.com/honojs/hono/tree/master/src/middleware/mustache/) (Only for Cloudflare Workers)
79
+ - [JSON pretty printing](https://github.com/honojs/hono/tree/master/src/middleware/pretty-json/)
80
+ - [Serving static files](https://github.com/honojs/hono/tree/master/src/middleware/serve-static/) (Only for Cloudflare Workers)
81
+
82
+ To enable logger and Etag middleware with just this code.
83
+
84
+ ```ts
85
+ import { Hono } from 'hono'
86
+ import { etag } from 'hono/etag'
87
+ import { logger } from 'hono/logger'
88
+
89
+ const app = new Hono()
90
+ app.use('*', etag(), (logger())
71
91
  ```
72
92
 
73
- or
93
+ And, the routing of Hono is so flexible. It's easy to construct large web applications.
94
+
95
+ ```ts
96
+ import { Hono, Route } from 'hono'
97
+ import { cors } from 'hono/cors'
98
+
99
+ const app = new Hono()
100
+
101
+ const v1 = new Route()
102
+ v1.get('/posts', (c) => {
103
+ return c.text('list pots')
104
+ })
105
+ .post('/posts', cors(), (c) => {
106
+ return c.text('created!', 201)
107
+ })
108
+ .get('/posts/:id', (c) => {
109
+ const id = c.req.param('id')
110
+ return c.text(`your id is ${id}`)
111
+ })
112
+
113
+ app.route('/v1', v1)
114
+ ```
115
+
116
+ ### Web Standard
117
+
118
+ Request and Response object used in Hono are extensions of the Web Standard [Fetch API](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API). If you are familiar with that, you don't need to know more than that.
119
+
120
+ ### Developer Experience
121
+
122
+ Hono provides fine _"**Developer Experience**"_. Easy access to Request/Response thanks to the `Context` object.
123
+ Above all, Hono is written in TypeScript. So, Hono has _"**Types**"_!
124
+
125
+ For example, the named path parameters will be literal types.
126
+
127
+ ![Demo](https://user-images.githubusercontent.com/10682/154179671-9e491597-6778-44ac-a8e6-4483d7ad5393.png)
128
+
129
+ ## Install
130
+
131
+ You can install Hono from the npm registry.
74
132
 
75
133
  ```sh
76
134
  npm install hono
@@ -80,21 +138,21 @@ npm install hono
80
138
 
81
139
  An instance of `Hono` has these methods.
82
140
 
83
- - app.**HTTP_METHOD**(path, handler)
84
- - app.**all**(path, handler)
85
- - app.**route**(path)
86
- - app.**use**(path, middleware)
141
+ - app.**HTTP_METHOD**(\[path,\] handler|middleware...)
142
+ - app.**all**(\[path,\] handler|middleware...)
143
+ - app.**route**(path, \[Route\])
144
+ - app.**use**(\[path,\] middleware)
87
145
  - app.**notFound**(handler)
88
146
  - app.**onError**(err, handler)
89
147
  - app.**fire**()
90
148
  - app.**fetch**(request, env, event)
91
- - app.**request**(path, option)
149
+ - app.**request**(path, options)
92
150
 
93
151
  ## Routing
94
152
 
95
153
  ### Basic
96
154
 
97
- ```js
155
+ ```ts
98
156
  // HTTP Methods
99
157
  app.get('/', (c) => c.text('GET /'))
100
158
  app.post('/', (c) => c.text('POST /'))
@@ -110,7 +168,7 @@ app.all('/hello', (c) => c.text('Any Method /hello'))
110
168
 
111
169
  ### Named Parameter
112
170
 
113
- ```js
171
+ ```ts
114
172
  app.get('/user/:name', (c) => {
115
173
  const name = c.req.param('name')
116
174
  ...
@@ -119,7 +177,7 @@ app.get('/user/:name', (c) => {
119
177
 
120
178
  ### Regexp
121
179
 
122
- ```js
180
+ ```ts
123
181
  app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
124
182
  const date = c.req.param('date')
125
183
  const title = c.req.param('title')
@@ -127,24 +185,26 @@ app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
127
185
  })
128
186
  ```
129
187
 
130
- ### Nested route
188
+ ### Chained route
131
189
 
132
- ```js
133
- const book = app.route('/book')
134
- book.get('/', (c) => c.text('List Books')) // GET /book
135
- book.get('/:id', (c) => {
136
- // GET /book/:id
137
- const id = c.req.param('id')
138
- return c.text('Get Book: ' + id)
139
- })
140
- book.post('/', (c) => c.text('Create Book')) // POST /book
190
+ ```ts
191
+ app
192
+ .get('/endpoint', (c) => {
193
+ return c.text('GET /endpoint')
194
+ })
195
+ .post((c) => {
196
+ return c.text('POST /endpoint')
197
+ })
198
+ .delete((c) => {
199
+ return c.text('DELETE /endpoint')
200
+ })
141
201
  ```
142
202
 
143
203
  ### no strict
144
204
 
145
205
  If `strict` is set false, `/hello`and`/hello/` are treated the same.
146
206
 
147
- ```js
207
+ ```ts
148
208
  const app = new Hono({ strict: false }) // Default is true
149
209
 
150
210
  app.get('/hello', (c) => c.text('/hello or /hello/'))
@@ -159,13 +219,38 @@ app.get('/fetch-url', async (c) => {
159
219
  })
160
220
  ```
161
221
 
222
+ ## Route
223
+
224
+ `Route` object enables Nested route.
225
+
226
+ ```ts
227
+ const book = new Route()
228
+
229
+ book.get('/', (c) => c.text('List Books')) // GET /book
230
+ book.get('/:id', (c) => {
231
+ // GET /book/:id
232
+ const id = c.req.param('id')
233
+ return c.text('Get Book: ' + id)
234
+ })
235
+ book.post('/', (c) => c.text('Create Book')) // POST /book
236
+
237
+ app.route('/book', book)
238
+ ```
239
+
162
240
  ## Middleware
163
241
 
242
+ Middleware operate after/before executing Handler. We can get `Response` before dispatching or manipulate `Response` after dispatching.
243
+
244
+ ### Definition of Middleware
245
+
246
+ - Handler - should return `Response` object.
247
+ - Middleware - should return nothing, do `await next()`
248
+
164
249
  ### Built-in Middleware
165
250
 
166
251
  Hono has built-in middleware.
167
252
 
168
- ```js
253
+ ```ts
169
254
  import { Hono } from 'hono'
170
255
  import { poweredBy } from 'hono/powered-by'
171
256
  import { logger } from 'hono/logger'
@@ -175,6 +260,7 @@ const app = new Hono()
175
260
 
176
261
  app.use('*', poweredBy())
177
262
  app.use('*', logger())
263
+
178
264
  app.use(
179
265
  '/auth/*',
180
266
  basicAuth({
@@ -184,13 +270,13 @@ app.use(
184
270
  )
185
271
  ```
186
272
 
187
- Available built-in middleware is listed on [src/middleware](https://github.com/yusukebe/hono/tree/master/src/middleware).
273
+ Available built-in middleware is listed on [src/middleware](https://github.com/honojs/hono/tree/master/src/middleware).
188
274
 
189
275
  ### Custom Middleware
190
276
 
191
277
  You can write your own middleware.
192
278
 
193
- ```js
279
+ ```ts
194
280
  // Custom logger
195
281
  app.use('*', async (c, next) => {
196
282
  console.log(`[${c.req.method}] ${c.req.url}`)
@@ -229,11 +315,11 @@ app.onError((err, c) => {
229
315
 
230
316
  ## Context
231
317
 
232
- To handle Request and Reponse, you can use `Context` object.
318
+ To handle Request and Response, you can use `Context` object.
233
319
 
234
320
  ### c.req
235
321
 
236
- ```js
322
+ ```ts
237
323
  // Get Request object
238
324
  app.get('/hello', (c) => {
239
325
  const userAgent = c.req.headers.get('User-Agent')
@@ -261,13 +347,15 @@ app.get('/entry/:id', (c) => {
261
347
 
262
348
  ### Shortcuts for Response
263
349
 
264
- ```js
350
+ ```ts
265
351
  app.get('/welcome', (c) => {
266
352
  // Set headers
267
353
  c.header('X-Message', 'Hello!')
268
354
  c.header('Content-Type', 'text/plain')
355
+
269
356
  // Set HTTP status code
270
357
  c.status(201)
358
+
271
359
  // Return the response body
272
360
  return c.body('Thank you for comming')
273
361
  })
@@ -275,14 +363,13 @@ app.get('/welcome', (c) => {
275
363
 
276
364
  The Response is the same as below.
277
365
 
278
- ```js
366
+ ```ts
279
367
  new Response('Thank you for comming', {
280
368
  status: 201,
281
369
  statusText: 'Created',
282
370
  headers: {
283
371
  'X-Message': 'Hello',
284
372
  'Content-Type': 'text/plain',
285
- 'Content-Length': '22',
286
373
  },
287
374
  })
288
375
  ```
@@ -291,7 +378,7 @@ new Response('Thank you for comming', {
291
378
 
292
379
  Render text as `Content-Type:text/plain`.
293
380
 
294
- ```js
381
+ ```ts
295
382
  app.get('/say', (c) => {
296
383
  return c.text('Hello!')
297
384
  })
@@ -301,7 +388,7 @@ app.get('/say', (c) => {
301
388
 
302
389
  Render JSON as `Content-Type:application/json`.
303
390
 
304
- ```js
391
+ ```ts
305
392
  app.get('/api', (c) => {
306
393
  return c.json({ message: 'Hello!' })
307
394
  })
@@ -311,7 +398,7 @@ app.get('/api', (c) => {
311
398
 
312
399
  Render HTML as `Content-Type:text/html`.
313
400
 
314
- ```js
401
+ ```ts
315
402
  app.get('/', (c) => {
316
403
  return c.html('<h1>Hello! Hono!</h1>')
317
404
  })
@@ -321,7 +408,7 @@ app.get('/', (c) => {
321
408
 
322
409
  Return the `Not Found` Response.
323
410
 
324
- ```js
411
+ ```ts
325
412
  app.get('/notfound', (c) => {
326
413
  return c.notFound()
327
414
  })
@@ -331,14 +418,14 @@ app.get('/notfound', (c) => {
331
418
 
332
419
  Redirect, default status code is `302`.
333
420
 
334
- ```js
421
+ ```ts
335
422
  app.get('/redirect', (c) => c.redirect('/'))
336
423
  app.get('/redirect-permanently', (c) => c.redirect('/', 301))
337
424
  ```
338
425
 
339
426
  ### c.res
340
427
 
341
- ```js
428
+ ```ts
342
429
  // Response object
343
430
  app.use('/', (c, next) => {
344
431
  next()
@@ -348,7 +435,7 @@ app.use('/', (c, next) => {
348
435
 
349
436
  ### c.event
350
437
 
351
- ```js
438
+ ```ts
352
439
  // FetchEvent object
353
440
  app.use('*', async (c, next) => {
354
441
  c.event.waitUntil(
@@ -360,7 +447,7 @@ app.use('*', async (c, next) => {
360
447
 
361
448
  ### c.env
362
449
 
363
- ```js
450
+ ```ts
364
451
  // Environment object for Cloudflare Workers
365
452
  app.get('*', async c => {
366
453
  const counter = c.env.COUNTER
@@ -372,7 +459,7 @@ app.get('*', async c => {
372
459
 
373
460
  `app.fire()` do this.
374
461
 
375
- ```js
462
+ ```ts
376
463
  addEventListener('fetch', (event) => {
377
464
  event.respondWith(this.handleEvent(event))
378
465
  })
@@ -382,17 +469,18 @@ addEventListener('fetch', (event) => {
382
469
 
383
470
  `app.fetch` for Cloudflare Module Worker syntax.
384
471
 
385
- ```js
472
+ ```ts
386
473
  export default {
387
474
  fetch(request: Request, env: Env, event: FetchEvent) {
388
475
  return app.fetch(request, env, event)
389
476
  },
390
477
  }
478
+ ```
391
479
 
392
- /*
393
480
  or just do:
481
+
482
+ ```ts
394
483
  export default app
395
- */
396
484
  ```
397
485
 
398
486
  ## request
@@ -408,61 +496,35 @@ test('GET /hello is ok', async () => {
408
496
 
409
497
  ## Cloudflare Workers with Hono
410
498
 
411
- Using [Wrangler](https://developers.cloudflare.com/workers/cli-wrangler/) or [Miniflare](https://miniflare.dev), you can develop the application locally and publish it with few commands.
499
+ Using [Wrangler](https://developers.cloudflare.com/workers/cli-wrangler/), you can develop the application locally and publish it with few commands.
412
500
 
413
501
  Let's write your first code for Cloudflare Workers with Hono.
414
502
 
415
- ---
416
-
417
- ### Caution
418
-
419
- **Wrangler 1.x** does not support importing middleware. We recommend two ways:
420
-
421
- 1. Use [Wragler 2.0 Beta](https://github.com/cloudflare/wrangler2).
422
- 2. Build without webpack 4.x. For example, you can use esbuild. See [the starter template](https://github.com/yusukebe/hono-minimal).
423
-
424
- ---
425
-
426
- ### 1. `npm init`
427
-
428
- Make a npm skeleton directory.
429
-
430
- ```sh
431
- mkdir hono-example
432
- cd hono-example
433
- npm init -y
434
- ```
435
-
436
- ### 2. `wrangler init`
503
+ ### 1. `wrangler init`
437
504
 
438
505
  Initialize as a wrangler project.
439
506
 
440
- ```sh
441
- npx wrangler@beta init
442
507
  ```
443
-
444
- Answer the questions. If you want, you can answer `y`.
445
-
446
- ```
447
- Would you like to install wrangler into your package.json? (y/n) <--- n
448
- Would you like to use TypeScript? (y/n) <--- n
449
- Would you like to create a Worker at src/index.js? (y/n) <--- n
508
+ mkdir hono-example
509
+ cd hono-example
510
+ npx wrangler init -y
450
511
  ```
451
512
 
452
- ### 3. `npm install hono`
513
+ ### 2. `npm install hono`
453
514
 
454
515
  Install `hono` from the npm registry.
455
516
 
456
- ```sh
517
+ ```
518
+ npm init -y
457
519
  npm i hono
458
520
  ```
459
521
 
460
- ### 4. Write your app
522
+ ### 3. Write your app
461
523
 
462
- Only 4 lines!!
524
+ Edit `src/index.ts`. Only 4 lines!!
463
525
 
464
- ```js
465
- // index.js
526
+ ```ts
527
+ // src/index.ts
466
528
  import { Hono } from 'hono'
467
529
  const app = new Hono()
468
530
 
@@ -471,47 +533,51 @@ app.get('/', (c) => c.text('Hello! Hono!'))
471
533
  app.fire()
472
534
  ```
473
535
 
474
- ### 5. Run
536
+ ### 4. Run
475
537
 
476
538
  Run the development server locally. Then, access `http://127.0.0.1:8787/` in your Web browser.
477
539
 
478
- ```sh
479
- npx wrangler@beta dev index.js
540
+ ```
541
+ npx wrangler dev
480
542
  ```
481
543
 
482
- ### 6. Publish
544
+ ### 5. Publish
483
545
 
484
546
  Deploy to Cloudflare. That's all!
485
547
 
486
- ```sh
487
- npx wrangler@beta publish index.js
548
+ ```
549
+ npx wrangler publish index.ts
488
550
  ```
489
551
 
490
552
  ## Starter template
491
553
 
492
- You can start making your Cloudflare Workers application with [the starter template](https://github.com/yusukebe/hono-minimal). It is really minimal using TypeScript, esbuild, and Miniflare.
554
+ You can start making your Cloudflare Workers application with [the starter template](https://github.com/honojs/hono-minimal). It is really minimal using TypeScript, esbuild, Miniflare, and Jest.
493
555
 
494
556
  To generate a project skelton, run this command.
495
557
 
496
- ```sh
497
- wrangler generate my-app https://github.com/yusukebe/hono-minimal
558
+ ```
559
+ npx create-cloudflare my-app https://github.com/honojs/hono-minimal
498
560
  ```
499
561
 
562
+ ## Examples
563
+
564
+ - Hono Examples - <https://github.com/honojs/examples>
565
+
500
566
  ## Related projects
501
567
 
502
568
  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.
503
569
 
504
- - express <https://github.com/expressjs/express>
505
- - koa <https://github.com/koajs/koa>
506
- - itty-router <https://github.com/kwhitley/itty-router>
507
- - Sunder <https://github.com/SunderJS/sunder>
508
- - goblin <https://github.com/bmf-san/goblin>
509
- - worktop <https://github.com/lukeed/worktop>
510
- - Router::Boom <https://github.com/tokuhirom/Router-Boom>
570
+ - express - <https://github.com/expressjs/express>
571
+ - koa - <https://github.com/koajs/koa>
572
+ - itty-router - <https://github.com/kwhitley/itty-router>
573
+ - Sunder - <https://github.com/SunderJS/sunder>
574
+ - goblin - <https://github.com/bmf-san/goblin>
575
+ - worktop - <https://github.com/lukeed/worktop>
576
+ - Router::Boom - <https://github.com/tokuhirom/Router-Boom>
511
577
 
512
578
  ## Contributing
513
579
 
514
- Contributions Welcome! You can contribute by the following way.
580
+ Contributions Welcome! You can contribute in the following ways.
515
581
 
516
582
  - Write or fix documents
517
583
  - Write code of middleware
@@ -519,11 +585,9 @@ Contributions Welcome! You can contribute by the following way.
519
585
  - Refactor the code
520
586
  - etc.
521
587
 
522
- Let's make Hono together!
523
-
524
588
  ## Contributors
525
589
 
526
- Thanks to [all contributors](https://github.com/yusukebe/hono/graphs/contributors)!
590
+ Thanks to [all contributors](https://github.com/honojs/hono/graphs/contributors)! Especially, [@metrue](https://github.com/metrue) and [@usualoma](https://github.com/usualoma)!
527
591
 
528
592
  ## Author
529
593
 
package/dist/compose.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import type { ErrorHandler } from './hono';
2
- export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler) => (context: C) => Promise<C>;
1
+ import type { ErrorHandler, NotFoundHandler } from './hono';
2
+ export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler, onNotFound?: NotFoundHandler) => (context: C, next?: Function) => Promise<C>;
package/dist/compose.js CHANGED
@@ -3,26 +3,38 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  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
- const compose = (middleware, onError) => {
7
- return function (context) {
6
+ const compose = (middleware, onError, onNotFound) => {
7
+ return async (context, next) => {
8
8
  let index = -1;
9
9
  return dispatch(0);
10
10
  async function dispatch(i) {
11
- if (i === middleware.length) {
12
- return context;
13
- }
14
11
  if (i <= index) {
15
12
  return Promise.reject(new Error('next() called multiple times'));
16
13
  }
17
- const handler = middleware[i];
14
+ let handler = middleware[i];
18
15
  index = i;
16
+ if (i === middleware.length)
17
+ handler = next;
18
+ if (handler === undefined) {
19
+ if (context instanceof context_1.Context && context.res === undefined) {
20
+ context.res = onNotFound(context);
21
+ }
22
+ return Promise.resolve(context);
23
+ }
19
24
  return Promise.resolve(handler(context, dispatch.bind(null, i + 1)))
20
- .then(() => {
25
+ .then(async (res) => {
26
+ // If handler return Response like `return c.text('foo')`
27
+ if (res && context instanceof context_1.Context) {
28
+ context.res = res;
29
+ dispatch(i + 1); // <--- Call next()
30
+ }
21
31
  return context;
22
32
  })
23
33
  .catch((err) => {
24
34
  if (onError && context instanceof context_1.Context) {
25
- context.res = onError(err, context);
35
+ if (err instanceof Error) {
36
+ context.res = onError(err, context);
37
+ }
26
38
  return context;
27
39
  }
28
40
  else {
package/dist/context.d.ts CHANGED
@@ -2,12 +2,11 @@
2
2
  import type { StatusCode } from './utils/http-status';
3
3
  declare type Headers = Record<string, string>;
4
4
  declare type Data = string | ArrayBuffer | ReadableStream;
5
- export interface Env {
6
- }
7
- export declare class Context<RequestParamKeyType = string> {
5
+ export declare type Env = Record<string, any>;
6
+ export declare class Context<RequestParamKeyType = string, E = Env> {
8
7
  req: Request<RequestParamKeyType>;
9
8
  res: Response;
10
- env: Env;
9
+ env: E;
11
10
  event: FetchEvent;
12
11
  private _headers;
13
12
  private _status;
@@ -18,7 +17,7 @@ export declare class Context<RequestParamKeyType = string> {
18
17
  notFound: () => Response | Promise<Response>;
19
18
  constructor(req: Request<RequestParamKeyType>, opts?: {
20
19
  res: Response;
21
- env: Env;
20
+ env: E;
22
21
  event: FetchEvent;
23
22
  });
24
23
  private initRequest;