hono 0.5.0 → 0.5.3

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 CHANGED
@@ -1,4 +1,10 @@
1
- # Hono
1
+ # Hono\[炎\]
2
+
3
+ <p>
4
+ <a href="https://github.com/yusukebe/hono/blob/master/README.md">English</a>
5
+ &#x000B7;
6
+ <a href="https://github.com/yusukebe/hono/blob/master/docs/README.ja.md">日本語</a>
7
+ </p>
2
8
 
3
9
  [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/yusukebe/hono/ci)](https://github.com/yusukebe/hono/actions)
4
10
  [![GitHub](https://img.shields.io/github/license/yusukebe/hono)](https://github.com/yusukebe/hono/blob/master/LICENSE)
@@ -8,7 +14,7 @@
8
14
  [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/yusukebe/hono)](https://github.com/yusukebe/hono/pulse)
9
15
  [![GitHub last commit](https://img.shields.io/github/last-commit/yusukebe/hono)](https://github.com/yusukebe/hono/commits/master)
10
16
 
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.
17
+ Hono[炎] - _**means flame🔥 in Japanese**_ - is small, simple, and ultrafast web framework for Cloudflare Workers and Fastly Compute@Edge.
12
18
 
13
19
  ```js
14
20
  import { Hono } from 'hono'
@@ -22,26 +28,26 @@ app.fire()
22
28
  ## Features
23
29
 
24
30
  - **Ultrafast** - the router does not use linear loops.
25
- - **Zero-dependencies** - using only Web standard API.
26
- - **Middleware** - builtin middleware and your own middleware.
31
+ - **Zero-dependencies** - using only Service Worker and Web standard API.
32
+ - **Middleware** - built-in middleware and ability to extend with your own middleware.
27
33
  - **Optimized** - for Cloudflare Workers.
28
34
 
29
35
  ## Benchmark
30
36
 
31
- **Hono is fastest** compared to other routers for Cloudflare Workers.
37
+ **Hono is fastest**, compared to other routers for Cloudflare Workers.
32
38
 
33
39
  ```plain
34
- hono x 779,197 ops/sec ±6.55% (78 runs sampled)
35
- itty-router x 161,813 ops/sec ±3.87% (87 runs sampled)
36
- sunder x 334,096 ops/sec ±1.33% (93 runs sampled)
37
- worktop x 212,661 ops/sec ±4.40% (81 runs sampled)
40
+ hono x 809,503 ops/sec ±6.94% (73 runs sampled)
41
+ itty-router x 157,310 ops/sec ±4.31% (87 runs sampled)
42
+ sunder x 328,350 ops/sec ±2.30% (95 runs sampled)
43
+ worktop x 209,758 ops/sec ±4.28% (83 runs sampled)
38
44
  Fastest is hono
39
- ✨ Done in 58.29s.
45
+ ✨ Done in 60.66s.
40
46
  ```
41
47
 
42
48
  ## Hono in 1 minute
43
49
 
44
- A demonstration to create an application of Cloudflare Workers with Hono.
50
+ A demonstration to create an application for Cloudflare Workers with Hono.
45
51
 
46
52
  ![Demo](https://user-images.githubusercontent.com/10682/151973526-342644f9-71c5-4fee-81f4-64a7558bb192.gif)
47
53
 
@@ -53,13 +59,13 @@ Now, the named path parameter has types.
53
59
 
54
60
  You can install Hono from the npm registry.
55
61
 
56
- ```sh
62
+ ```
57
63
  $ yarn add hono
58
64
  ```
59
65
 
60
66
  or
61
67
 
62
- ```sh
68
+ ```
63
69
  $ npm install hono
64
70
  ```
65
71
 
@@ -75,6 +81,7 @@ An instance of `Hono` has these methods.
75
81
  - app.**onError**(err, handler)
76
82
  - app.**fire**()
77
83
  - app.**fetch**(request, env, event)
84
+ - app.**request**(path, option)
78
85
 
79
86
  ## Routing
80
87
 
@@ -147,7 +154,9 @@ app.get('/fetch-url', async (c) => {
147
154
 
148
155
  ## Middleware
149
156
 
150
- ### Builtin Middleware
157
+ ### Built-in Middleware
158
+
159
+ Hono has built-in middleware.
151
160
 
152
161
  ```js
153
162
  import { Hono } from 'hono'
@@ -168,7 +177,7 @@ app.use(
168
177
  )
169
178
  ```
170
179
 
171
- Available builtin middleware are listed on [src/middleware](https://github.com/yusukebe/hono/tree/master/src/middleware).
180
+ Available built-in middleware is listed on [src/middleware](https://github.com/yusukebe/hono/tree/master/src/middleware).
172
181
 
173
182
  ### Custom Middleware
174
183
 
@@ -184,15 +193,13 @@ app.use('*', async (c, next) => {
184
193
  // Add a custom header
185
194
  app.use('/message/*', async (c, next) => {
186
195
  await next()
187
- await c.header('x-message', 'This is middleware!')
196
+ c.header('x-message', 'This is middleware!')
188
197
  })
189
198
 
190
199
  app.get('/message/hello', (c) => c.text('Hello Middleware!'))
191
200
  ```
192
201
 
193
- ## Error
194
-
195
- ### Not Found
202
+ ## Not Found
196
203
 
197
204
  `app.notFound` for customizing Not Found Response.
198
205
 
@@ -202,7 +209,7 @@ app.notFound((c) => {
202
209
  })
203
210
  ```
204
211
 
205
- ### Error Handling
212
+ ## Error Handling
206
213
 
207
214
  `app.onError` handle the error and return the customized Response.
208
215
 
@@ -215,7 +222,7 @@ app.onError((err, c) => {
215
222
 
216
223
  ## Context
217
224
 
218
- To handle Request and Reponse, you can use Context object.
225
+ To handle Request and Reponse, you can use `Context` object.
219
226
 
220
227
  ### c.req
221
228
 
@@ -275,7 +282,7 @@ new Response('Thank you for comming', {
275
282
 
276
283
  ### c.text()
277
284
 
278
- Render texts as `Content-Type:text/plain`.
285
+ Render text as `Content-Type:text/plain`.
279
286
 
280
287
  ```js
281
288
  app.get('/say', (c) => {
@@ -305,7 +312,7 @@ app.get('/', (c) => {
305
312
 
306
313
  ### c.notFound()
307
314
 
308
- Return the `404 Not Found` Response.
315
+ Return the `Not Found` Response.
309
316
 
310
317
  ```js
311
318
  app.get('/notfound', (c) => {
@@ -381,51 +388,74 @@ export default app
381
388
  */
382
389
  ```
383
390
 
391
+ ## request
392
+
393
+ `request` is a useful method for testing.
394
+
395
+ ```js
396
+ test('GET /hello is ok', async () => {
397
+ const res = await app.request('http://localhost/hello')
398
+ expect(res.status).toBe(200)
399
+ })
400
+ ```
401
+
384
402
  ## Cloudflare Workers with Hono
385
403
 
386
- Using `wrangler` or `miniflare`, you can develop the application locally and publish it with few commands.
404
+ 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.
387
405
 
388
406
  Let's write your first code for Cloudflare Workers with Hono.
389
407
 
390
- ### 1. Install Wrangler
408
+ ---
391
409
 
392
- Install Cloudflare Command Line "[Wrangler](https://github.com/cloudflare/wrangler)".
410
+ ### Caution
393
411
 
394
- ```sh
395
- $ npm i @cloudflare/wrangler -g
396
- ```
412
+ **Wrangler 1.x** does not support importing middleware. We recommend two ways:
397
413
 
398
- ### 2. `npm init`
414
+ 1. Use [Wragler 2.0 Beta](https://github.com/cloudflare/wrangler2).
415
+ 2. Build without webpack 4.x. For example, you can use esbuild. See [the starter template](https://github.com/yusukebe/hono-minimal).
416
+
417
+ ---
418
+
419
+ ### 1. `npm init`
399
420
 
400
421
  Make a npm skeleton directory.
401
422
 
402
- ```sh
403
- mkdir hono-example
404
- cd hono-example
405
- npm init -y
423
+ ```
424
+ $ mkdir hono-example
425
+ $ cd hono-example
426
+ $ npm init -y
406
427
  ```
407
428
 
408
- ### 3. `wrangler init`
429
+ ### 2. `wrangler init`
409
430
 
410
- Init as a wrangler project.
431
+ Initialize as a wrangler project.
411
432
 
412
- ```sh
413
- $ wrangler init
433
+ ```
434
+ $ npx wrangler@beta init
414
435
  ```
415
436
 
416
- ### 4. `npm install hono`
437
+ Answer the questions. If you want, you can answer `y`.
438
+
439
+ ```
440
+ Would you like to install wrangler into your package.json? (y/n) <--- n
441
+ Would you like to use TypeScript? (y/n) <--- n
442
+ Would you like to create a Worker at src/index.js? (y/n) <--- n
443
+ ```
444
+
445
+ ### 3. `npm install hono`
417
446
 
418
447
  Install `hono` from the npm registry.
419
448
 
420
- ```sh
449
+ ```
421
450
  $ npm i hono
422
451
  ```
423
452
 
424
- ### 5. Write your app
453
+ ### 4. Write your app
425
454
 
426
455
  Only 4 lines!!
427
456
 
428
457
  ```js
458
+ // index.js
429
459
  import { Hono } from 'hono'
430
460
  const app = new Hono()
431
461
 
@@ -434,25 +464,25 @@ app.get('/', (c) => c.text('Hello! Hono!'))
434
464
  app.fire()
435
465
  ```
436
466
 
437
- ### 6. Run
467
+ ### 5. Run
438
468
 
439
469
  Run the development server locally. Then, access `http://127.0.0.1:8787/` in your Web browser.
440
470
 
441
- ```sh
442
- $ wrangler dev
471
+ ```
472
+ $ npx wrangler@beta dev index.js
443
473
  ```
444
474
 
445
- ### 7. Publish
475
+ ### 6. Publish
446
476
 
447
477
  Deploy to Cloudflare. That's all!
448
478
 
449
- ```sh
450
- $ wrangler publish
479
+ ```
480
+ $ npx wrangler@beta publish index.js
451
481
  ```
452
482
 
453
483
  ## Starter template
454
484
 
455
- 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.
485
+ 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.
456
486
 
457
487
  To generate a project skelton, run this command.
458
488
 
package/dist/compose.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  import type { ErrorHandler } from './hono';
2
- export declare const compose: <T>(middleware: Function[], onError?: ErrorHandler) => (context: T, next?: Function) => Promise<T>;
2
+ export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler) => (context: C) => Promise<C>;
package/dist/compose.js CHANGED
@@ -4,36 +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
- return function (context, next) {
7
+ return function (context) {
8
8
  let index = -1;
9
9
  return dispatch(0);
10
10
  async function dispatch(i) {
11
- if (i <= index)
11
+ if (i === middleware.length) {
12
+ return context;
13
+ }
14
+ if (i <= index) {
12
15
  return Promise.reject(new Error('next() called multiple times'));
16
+ }
17
+ const handler = middleware[i];
13
18
  index = i;
14
- let fn = middleware[i];
15
- if (i === middleware.length)
16
- fn = next;
17
- if (!fn)
19
+ return Promise.resolve(handler(context, dispatch.bind(null, i + 1)))
20
+ .then(() => {
18
21
  return context;
19
- try {
20
- return Promise.resolve(fn(context, dispatch.bind(null, i + 1)))
21
- .then(() => {
22
+ })
23
+ .catch((err) => {
24
+ if (onError && context instanceof context_1.Context) {
25
+ context.res = onError(err, context);
22
26
  return context;
23
- })
24
- .catch((err) => {
25
- if (onError && context instanceof context_1.Context) {
26
- context.res = onError(err, context);
27
- return context;
28
- }
29
- else {
30
- throw err;
31
- }
32
- });
33
- }
34
- catch (err) {
35
- return Promise.reject(err);
36
- }
27
+ }
28
+ else {
29
+ throw err;
30
+ }
31
+ });
37
32
  }
38
33
  };
39
34
  };
package/dist/context.js CHANGED
@@ -35,8 +35,8 @@ class Context {
35
35
  this._statusText = (0, http_status_1.getStatusText)(number);
36
36
  }
37
37
  newResponse(data, init = {}) {
38
- init.status = init.status || this._status;
39
- init.statusText = init.statusText || this._statusText;
38
+ init.status = init.status || this._status || 200;
39
+ init.statusText = init.statusText || this._statusText || (0, http_status_1.getStatusText)(init.status);
40
40
  init.headers = Object.assign(Object.assign({}, this._headers), init.headers);
41
41
  // Content-Length
42
42
  let length = 0;
package/dist/hono.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
2
  import { Context } from './context';
3
3
  import type { Env } from './context';
4
- import type { Result, Router } from './router';
4
+ import type { Router } from './router';
5
5
  declare global {
6
6
  interface Request<ParamKeyType = string> {
7
7
  param: (key: ParamKeyType) => string;
@@ -26,8 +26,8 @@ export declare class Hono {
26
26
  middlewareRouters: Router<MiddlewareHandler>[];
27
27
  tempPath: string;
28
28
  constructor(init?: Partial<Pick<Hono, 'routerClass' | 'strict'>>);
29
- notFoundHandler: NotFoundHandler;
30
- errorHandler: ErrorHandler;
29
+ private notFoundHandler;
30
+ private errorHandler;
31
31
  get<Path extends string>(path: Path, handler: Handler<ParamKeys<Path>>): Hono;
32
32
  post<Path extends string>(path: Path, handler: Handler<ParamKeys<Path>>): Hono;
33
33
  put<Path extends string>(path: Path, handler: Handler<ParamKeys<Path>>): Hono;
@@ -40,11 +40,12 @@ export declare class Hono {
40
40
  use(path: string, middleware: MiddlewareHandler): void;
41
41
  onError(handler: ErrorHandler): Hono;
42
42
  notFound(handler: NotFoundHandler): Hono;
43
- addRoute(method: string, path: string, handler: Handler): Hono;
44
- matchRoute(method: string, path: string): Promise<Result<Handler>>;
43
+ private addRoute;
44
+ private matchRoute;
45
45
  dispatch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>;
46
46
  handleEvent(event: FetchEvent): Promise<Response>;
47
47
  fetch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>;
48
+ request(input: RequestInfo, requestInit?: RequestInit): Promise<Response>;
48
49
  fire(): void;
49
50
  }
50
51
  export {};
package/dist/hono.js CHANGED
@@ -128,6 +128,10 @@ class Hono {
128
128
  async fetch(request, env, event) {
129
129
  return this.dispatch(request, env, event);
130
130
  }
131
+ request(input, requestInit) {
132
+ const req = new Request(input, requestInit);
133
+ return this.dispatch(req);
134
+ }
131
135
  fire() {
132
136
  addEventListener('fetch', (event) => {
133
137
  event.respondWith(this.handleEvent(event));
@@ -3,6 +3,7 @@ export declare const basicAuth: (options: {
3
3
  username: string;
4
4
  password: string;
5
5
  realm?: string;
6
+ hashFunction?: Function;
6
7
  }, ...users: {
7
8
  username: string;
8
9
  password: string;
@@ -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,7 +19,7 @@ const auth = (req) => {
18
19
  if (!match) {
19
20
  return undefined;
20
21
  }
21
- const userPass = USER_PASS_REGEXP.exec((0, buffer_1.decodeBase64)(match[1]));
22
+ const userPass = USER_PASS_REGEXP.exec((0, crypto_1.decodeBase64)(match[1]));
22
23
  if (!userPass) {
23
24
  return undefined;
24
25
  }
@@ -36,8 +37,8 @@ const basicAuth = (options, ...users) => {
36
37
  const requestUser = auth(ctx.req);
37
38
  if (requestUser) {
38
39
  for (const user of users) {
39
- const usernameEqual = await (0, buffer_1.timingSafeEqual)(user.username, requestUser.username);
40
- const passwordEqual = await (0, buffer_1.timingSafeEqual)(user.password, requestUser.password);
40
+ const usernameEqual = await (0, buffer_1.timingSafeEqual)(user.username, requestUser.username, options.hashFunction);
41
+ const passwordEqual = await (0, buffer_1.timingSafeEqual)(user.password, requestUser.password, options.hashFunction);
41
42
  if (usernameEqual && passwordEqual) {
42
43
  // Authorized OK
43
44
  return next();
@@ -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
- const contentType = ctx.req.headers.get('Content-Type') || '';
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,6 @@
1
+ import type { Context } from '../../context';
2
+ declare type ETagOptions = {
3
+ weak: boolean;
4
+ };
5
+ export declare const etag: (options?: ETagOptions) => (c: Context, next: Function) => Promise<void>;
6
+ export {};
@@ -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;
@@ -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;
@@ -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
- export declare const timingSafeEqual: (a: string | object | boolean, b: string | object | boolean) => Promise<boolean>;
2
+ export declare const timingSafeEqual: (a: string | object | boolean, b: string | object | boolean, hashFunction?: Function) => Promise<boolean>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.timingSafeEqual = exports.sha256 = exports.decodeBase64 = exports.equal = void 0;
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,12 @@ 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;
23
+ const timingSafeEqual = async (a, b, hashFunction) => {
24
+ if (!hashFunction) {
25
+ hashFunction = crypto_1.sha256;
58
26
  }
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
- const timingSafeEqual = async (a, b) => {
66
- const sa = await (0, exports.sha256)(a);
67
- const sb = await (0, exports.sha256)(b);
27
+ const sa = await hashFunction(a);
28
+ const sb = await hashFunction(b);
68
29
  return sa === sb && a === b;
69
30
  };
70
31
  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;
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "0.5.0",
3
+ "version": "0.5.3",
4
4
  "description": "[炎] Ultrafast web framework for Cloudflare Workers.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -78,11 +78,13 @@
78
78
  ],
79
79
  "devDependencies": {
80
80
  "@cloudflare/workers-types": "^3.3.0",
81
+ "@types/crypto-js": "^4.1.1",
81
82
  "@types/jest": "^27.4.0",
82
83
  "@types/mustache": "^4.1.2",
83
84
  "@types/node": "^17.0.8",
84
85
  "@typescript-eslint/eslint-plugin": "^5.9.0",
85
86
  "@typescript-eslint/parser": "^5.9.0",
87
+ "crypto-js": "^4.1.1",
86
88
  "eslint": "^7.26.0",
87
89
  "eslint-config-prettier": "^8.3.0",
88
90
  "eslint-define-config": "^1.2.1",
@@ -96,6 +98,7 @@
96
98
  "jest-environment-miniflare": "^2.0.0",
97
99
  "mustache": "^4.2.0",
98
100
  "prettier": "^2.5.1",
101
+ "prettier-plugin-md-nocjsp": "^1.2.0",
99
102
  "rimraf": "^3.0.2",
100
103
  "ts-jest": "^27.1.2",
101
104
  "typescript": "^4.5.5"