hono 0.0.11 → 0.0.12

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
@@ -6,24 +6,24 @@ Hono [炎] - Tiny web framework for Cloudflare Workers and others.
6
6
  const { Hono } = require('hono')
7
7
  const app = new Hono()
8
8
 
9
- app.get('/', () => new Response('Hono!!'))
9
+ app.get('/', (c) => c.text('Hono!!'))
10
10
 
11
11
  app.fire()
12
12
  ```
13
13
 
14
- ![carbon](https://user-images.githubusercontent.com/10682/147877725-bce9bd46-953d-4d70-9c2b-3eae47ad4df9.png)
14
+ Hono[] - _**means flame🔥 in Japanese**_ - is small, fast and simple web flamework for a Service Workers API based serverless such as **Cloudflare Workers** and **Fastly Compute@Edge**. Hono does not depend on any npm packages. However, Hono has a router, context object, and middleware including the builtins. It's easy to make a web application.
15
15
 
16
- ## Feature
16
+ ## Features
17
17
 
18
- - Fast - the router is implemented with Trie-Tree structure.
19
- - Portable - zero dependencies.
20
- - Flexible - you can make your own middlewares.
21
- - Easy - simple API, builtin middleware, and TypeScript support.
22
- - Optimized - for Cloudflare Workers or Fastly Compute@Edge.
18
+ - **Fast** - the router is implemented with Trie-Tree structure.
19
+ - **Tiny** - zero dependencies, using Web standard API.
20
+ - **Flexible** - you can make your own middleware.
21
+ - **Easy** - simple API, builtin middleware, and written in TypeScript.
22
+ - **Optimized** - for Cloudflare Workers or Fastly Compute@Edge.
23
23
 
24
24
  ## Benchmark
25
25
 
26
- Hono is fastest!!
26
+ **Hono is fastest** compared to other routers for Cloudflare Workers.
27
27
 
28
28
  ```
29
29
  hono x 758,264 ops/sec ±5.41% (75 runs sampled)
@@ -33,8 +33,16 @@ Fastest is hono
33
33
  ✨ Done in 42.84s.
34
34
  ```
35
35
 
36
+ ## Hono in 1 minute
37
+
38
+ Below is a demonstration to create an application of Cloudflare Workers with Hono.
39
+
40
+ ![Demo](https://user-images.githubusercontent.com/10682/148223268-2484a891-57c1-472f-9df3-936a5586f002.gif)
41
+
36
42
  ## Install
37
43
 
44
+ You can install from npm registry:
45
+
38
46
  ```
39
47
  $ yarn add hono
40
48
  ```
@@ -47,10 +55,13 @@ $ npm install hono
47
55
 
48
56
  ## Methods
49
57
 
58
+ Instance of `Hono` has these methods:
59
+
50
60
  - app.**HTTP_METHOD**(path, handler)
51
61
  - app.**all**(path, handler)
52
62
  - app.**route**(path)
53
63
  - app.**use**(path, middleware)
64
+ - app.**fire**()
54
65
 
55
66
  ## Routing
56
67
 
@@ -104,7 +115,7 @@ app
104
115
  .put(() => {...})
105
116
  ```
106
117
 
107
- ## Async
118
+ ## async/await
108
119
 
109
120
  ```js
110
121
  app.get('/fetch-url', async () => {
@@ -122,13 +133,21 @@ const { Hono, Middleware } = require('hono')
122
133
 
123
134
  ...
124
135
 
125
- app.use('*', Middleware.poweredBy())
126
- app.use('*', Middleware.logger())
127
-
136
+ app.use(
137
+ '/auth/*',
138
+ Middleware.basicAuth({
139
+ username: 'hono',
140
+ password: 'acoolproject',
141
+ })
142
+ )
128
143
  ```
129
144
 
145
+ Available builtin middleware are listed on [src/middleware](https://github.com/yusukebe/hono/tree/master/src/middleware).
146
+
130
147
  ### Custom Middleware
131
148
 
149
+ You can write your own middleware:
150
+
132
151
  ```js
133
152
  // Custom logger
134
153
  app.use('*', async (c, next) => {
@@ -136,7 +155,7 @@ app.use('*', async (c, next) => {
136
155
  await next()
137
156
  })
138
157
 
139
- // Add custom header
158
+ // Add a custom header
140
159
  app.use('/message/*', async (c, next) => {
141
160
  await next()
142
161
  await c.res.headers.add('x-message', 'This is middleware!')
@@ -147,6 +166,8 @@ app.get('/message/hello', () => 'Hello Middleware!')
147
166
 
148
167
  ### Custom 404 Response
149
168
 
169
+ You can customize 404 Not Found response:
170
+
150
171
  ```js
151
172
  app.use('*', async (c, next) => {
152
173
  await next()
@@ -158,6 +179,8 @@ app.use('*', async (c, next) => {
158
179
 
159
180
  ### Complex Pattern
160
181
 
182
+ You can also do this:
183
+
161
184
  ```js
162
185
  // Output response time
163
186
  app.use('*', async (c, next) => {
@@ -177,7 +200,9 @@ app.use('*', async (c, next) => {
177
200
 
178
201
  ## Context
179
202
 
180
- ### req
203
+ To handle Request and Reponse easily, you can use Context object:
204
+
205
+ ### c.req
181
206
 
182
207
  ```js
183
208
 
@@ -200,7 +225,7 @@ app.get('/entry/:id', (c) => {
200
225
  })
201
226
  ```
202
227
 
203
- ### res
228
+ ### c.res
204
229
 
205
230
  ```js
206
231
  // Response object
@@ -210,7 +235,9 @@ app.use('/', (c, next) => {
210
235
  })
211
236
  ```
212
237
 
213
- ### text
238
+ ### c.text()
239
+
240
+ Render text as `Content-Type:text/plain`:
214
241
 
215
242
  ```js
216
243
  app.get('/say', (c) => {
@@ -218,13 +245,41 @@ app.get('/say', (c) => {
218
245
  })
219
246
  ```
220
247
 
221
- ## Hono in 1 minute
248
+ ### c.json()
222
249
 
223
- Create your first Cloudflare Workers with Hono from scratch.
250
+ Render JSON as `Content-Type:application/json`:
224
251
 
225
- ### How to setup
252
+ ```js
253
+ app.get('/api', (c) => {
254
+ return c.json({ message: 'Hello!' })
255
+ })
256
+ ```
226
257
 
227
- ![Demo](https://user-images.githubusercontent.com/10682/147877447-ff5907cd-49be-4976-b3b4-5df2ac6dfda4.gif)
258
+ ### c.html()
259
+
260
+ Render HTML as `Content-Type:text/html`:
261
+
262
+ ```js
263
+ app.get('/api', (c) => {
264
+ return c.html('<h1>Hello! Hono!</h1>')
265
+ })
266
+ ```
267
+
268
+ ## fire
269
+
270
+ `app.fire()` do:
271
+
272
+ ```js
273
+ addEventListener('fetch', (event) => {
274
+ event.respondWith(this.handleEvent(event))
275
+ })
276
+ ```
277
+
278
+ ## Cloudflare Workers with Hono
279
+
280
+ Using `wrangler` or `miniflare`, you can develop the application locally and publish it with few commands.
281
+
282
+ Let's write your first code for Cloudflare Workers with Hono.
228
283
 
229
284
  ### 1. Install Wrangler
230
285
 
@@ -254,7 +309,7 @@ $ wrangler init
254
309
 
255
310
  ### 4. `npm install hono`
256
311
 
257
- Install `hono` from npm repository.
312
+ Install `hono` from npm registry.
258
313
 
259
314
  ```
260
315
  $ npm i hono
@@ -262,38 +317,59 @@ $ npm i hono
262
317
 
263
318
  ### 5. Write your app
264
319
 
265
- Only 4 line!!
320
+ Only 4 lines!!
266
321
 
267
322
  ```js
268
323
  const { Hono } = require('hono')
269
324
  const app = new Hono()
270
325
 
271
- app.get('/', () => new Response('Hello! Hono!'))
326
+ app.get('/', (c) => c.text('Hello! Hono!'))
272
327
 
273
328
  app.fire()
274
329
  ```
275
330
 
276
- ### 6. Run!
331
+ ### 6. Run
277
332
 
278
- Run the development server locally.
333
+ Run the development server locally. Then, access like `http://127.0.0.1:8787/` in your Web browser.
279
334
 
280
335
  ```sh
281
336
  $ wrangler dev
282
337
  ```
283
338
 
339
+ ### Publish
340
+
341
+ Deploy to Cloudflare. That's all!
342
+
343
+ ```sh
344
+ $ wrangler publish
345
+ ```
346
+
284
347
  ## Related projects
285
348
 
286
- - koa <https://github.com/koajs/koa>
349
+ 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) and [Sunder](https://github.com/SunderJS/sunder) are the other routers or frameworks for Cloudflare Workers.
350
+
287
351
  - express <https://github.com/expressjs/express>
288
- - oak <https://github.com/oakserver/oak>
352
+ - koa <https://github.com/koajs/koa>
289
353
  - itty-router <https://github.com/kwhitley/itty-router>
290
354
  - Sunder <https://github.com/SunderJS/sunder>
291
355
  - goblin <https://github.com/bmf-san/goblin>
292
356
 
357
+ ## Contributing
358
+
359
+ Contributions Welcome! You can contribute by the following way:
360
+
361
+ - Write or fix documents
362
+ - Write code of middleware
363
+ - Fix bugs
364
+ - Refactor the code
365
+ - etc.
366
+
367
+ If you can, let's make Hono together!
368
+
293
369
  ## Author
294
370
 
295
371
  Yusuke Wada <https://github.com/yusukebe>
296
372
 
297
373
  ## License
298
374
 
299
- MIT
375
+ Distributed under the MIT License. See [LICENSE](LICENSE) for more information.
@@ -0,0 +1,9 @@
1
+ export declare class Context {
2
+ req: Request;
3
+ res: Response;
4
+ constructor(req: Request, res: Response);
5
+ newResponse(body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response;
6
+ text(body: string): Response;
7
+ json(object: object, replacer?: (string | number)[], space?: string | number): Response;
8
+ html(body: string): Response;
9
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Context = void 0;
4
+ class Context {
5
+ constructor(req, res) {
6
+ this.req = req;
7
+ this.res = res;
8
+ }
9
+ newResponse(body, init) {
10
+ return new Response(body, init);
11
+ }
12
+ text(body) {
13
+ if (typeof body !== 'string') {
14
+ throw new TypeError('text method arg must be a string!');
15
+ }
16
+ return this.newResponse(body, {
17
+ status: 200,
18
+ headers: {
19
+ 'Content-Type': 'text/plain',
20
+ },
21
+ });
22
+ }
23
+ json(object, replacer, space) {
24
+ if (typeof object !== 'object') {
25
+ throw new TypeError('json method arg must be a object!');
26
+ }
27
+ const body = JSON.stringify(object, replacer, space);
28
+ return this.newResponse(body, {
29
+ status: 200,
30
+ headers: {
31
+ 'Content-Type': 'application/json; charset=UTF-8',
32
+ },
33
+ });
34
+ }
35
+ html(body) {
36
+ if (typeof body !== 'string') {
37
+ throw new TypeError('html method arg must be a string!');
38
+ }
39
+ return this.newResponse(body, {
40
+ status: 200,
41
+ headers: {
42
+ 'Content-Type': 'text/html; charset=UTF-8',
43
+ },
44
+ });
45
+ }
46
+ }
47
+ exports.Context = Context;
package/dist/hono.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import { Node, Result } from './node';
2
+ import type { Result } from './node';
3
+ import { Node } from './node';
3
4
  import { Middleware } from './middleware';
5
+ import { Context } from './context';
4
6
  export { Middleware };
5
7
  declare global {
6
8
  interface Request {
@@ -8,13 +10,6 @@ declare global {
8
10
  query: (key: string) => string | null;
9
11
  }
10
12
  }
11
- export declare class Context {
12
- req: Request;
13
- res: Response;
14
- constructor(req: Request, res: Response);
15
- newResponse(body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response;
16
- text(body: string): Response;
17
- }
18
13
  declare type Handler = (c: Context, next?: Function) => Response | Promise<Response>;
19
14
  declare type MiddlwareHandler = (c: Context, next: Function) => Promise<void>;
20
15
  export declare class Router<T> {
package/dist/hono.js CHANGED
@@ -1,30 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Hono = exports.Router = exports.Context = exports.Middleware = void 0;
3
+ exports.Hono = exports.Router = exports.Middleware = void 0;
4
4
  const node_1 = require("./node");
5
5
  const compose_1 = require("./compose");
6
6
  const util_1 = require("./util");
7
7
  const middleware_1 = require("./middleware");
8
8
  Object.defineProperty(exports, "Middleware", { enumerable: true, get: function () { return middleware_1.Middleware; } });
9
+ const context_1 = require("./context");
9
10
  const METHOD_NAME_OF_ALL = 'ALL';
10
- class Context {
11
- constructor(req, res) {
12
- this.req = req;
13
- this.res = res;
14
- }
15
- newResponse(body, init) {
16
- return new Response(body, init);
17
- }
18
- text(body) {
19
- return this.newResponse(body, {
20
- status: 200,
21
- headers: {
22
- 'Content-Type': 'text/plain',
23
- },
24
- });
25
- }
26
- }
27
- exports.Context = Context;
28
11
  class Router {
29
12
  constructor() {
30
13
  this.node = new node_1.Node();
@@ -99,6 +82,7 @@ class Hono {
99
82
  addRoute(method, arg, ...args) {
100
83
  method = method.toUpperCase();
101
84
  if (typeof arg === 'string') {
85
+ this.tempPath = arg;
102
86
  this.router.add(method, arg, args);
103
87
  }
104
88
  else {
@@ -119,7 +103,7 @@ class Hono {
119
103
  }
120
104
  return '';
121
105
  };
122
- let handler = result ? result.handler[0] : this.notFound; // XXX
106
+ const handler = result ? result.handler[0] : this.notFound; // XXX
123
107
  const middleware = [];
124
108
  for (const mr of this.middlewareRouters) {
125
109
  const mwResult = mr.match(METHOD_NAME_OF_ALL, path);
@@ -127,14 +111,14 @@ class Hono {
127
111
  middleware.push(mwResult.handler);
128
112
  }
129
113
  }
130
- let wrappedHandler = async (context, next) => {
114
+ const wrappedHandler = async (context, next) => {
131
115
  context.res = await handler(context);
132
116
  await next();
133
117
  };
134
118
  middleware.push(middleware_1.Middleware.defaultFilter);
135
119
  middleware.push(wrappedHandler);
136
120
  const composed = (0, compose_1.compose)(middleware);
137
- const c = new Context(request, response);
121
+ const c = new context_1.Context(request, response);
138
122
  await composed(c);
139
123
  return c.res;
140
124
  }
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
- export { Hono, Middleware, Context } from './hono';
1
+ export { Hono, Middleware } from './hono';
2
+ export { Context } from './context';
package/dist/index.js CHANGED
@@ -4,4 +4,5 @@ exports.Context = exports.Middleware = exports.Hono = void 0;
4
4
  var hono_1 = require("./hono");
5
5
  Object.defineProperty(exports, "Hono", { enumerable: true, get: function () { return hono_1.Hono; } });
6
6
  Object.defineProperty(exports, "Middleware", { enumerable: true, get: function () { return hono_1.Middleware; } });
7
- Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return hono_1.Context; } });
7
+ var context_1 = require("./context");
8
+ Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return context_1.Context; } });
@@ -0,0 +1,6 @@
1
+ import type { Context } from '../../context';
2
+ export declare const basicAuth: (options: {
3
+ username: string;
4
+ password: string;
5
+ realm?: string;
6
+ }) => (ctx: Context, next: Function) => Promise<any>;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.basicAuth = void 0;
4
+ const util_1 = require("../../util");
5
+ const CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/;
6
+ const USER_PASS_REGEXP = /^([^:]*):(.*)$/;
7
+ const auth = (req) => {
8
+ if (!req) {
9
+ throw new TypeError('argument req is required');
10
+ }
11
+ if (typeof req !== 'object') {
12
+ throw new TypeError('argument req is required to be an object');
13
+ }
14
+ if (!req.headers || typeof req.headers !== 'object') {
15
+ throw new TypeError('argument req is required to have headers property');
16
+ }
17
+ const match = CREDENTIALS_REGEXP.exec(req.headers.get('Authorization'));
18
+ if (!match) {
19
+ return undefined;
20
+ }
21
+ const userPass = USER_PASS_REGEXP.exec(decodeBase64(match[1]));
22
+ if (!userPass) {
23
+ return undefined;
24
+ }
25
+ return { username: userPass[1], password: userPass[2] };
26
+ };
27
+ function decodeBase64(str) {
28
+ return Buffer.from(str, 'base64').toString();
29
+ }
30
+ const basicAuth = (options) => {
31
+ if (!options.realm) {
32
+ options.realm = 'Secure Area';
33
+ }
34
+ return async (ctx, next) => {
35
+ const user = auth(ctx.req);
36
+ const usernameEqual = user && await (0, util_1.timingSafeEqual)(options.username, user.username);
37
+ const passwordEqual = user && await (0, util_1.timingSafeEqual)(options.password, user.password);
38
+ if (!user || !usernameEqual || !passwordEqual) {
39
+ ctx.res = new Response('Unauthorized', {
40
+ status: 401,
41
+ headers: {
42
+ 'WWW-Authenticate': 'Basic realm="' + options.realm.replace(/"/g, '\\"') + '"',
43
+ },
44
+ });
45
+ return;
46
+ }
47
+ return next();
48
+ };
49
+ };
50
+ exports.basicAuth = basicAuth;
@@ -1,2 +1,2 @@
1
- import { Context } from '../hono';
1
+ import type { Context } from '../context';
2
2
  export declare const defaultFilter: (c: Context, next: Function) => Promise<void>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.defaultFilter = void 0;
4
4
  const defaultFilter = async (c, next) => {
5
5
  c.req.query = (key) => {
6
+ // eslint-disable-next-line
6
7
  const url = new URL(c.req.url);
7
8
  return url.searchParams.get(key);
8
9
  };
@@ -1,5 +1,6 @@
1
- import { Context } from '../../hono';
1
+ import type { Context } from '../../context';
2
2
  export declare const logger: (fn?: {
3
3
  (...data: any[]): void;
4
4
  (...data: any[]): void;
5
+ (message?: any, ...optionalParams: any[]): void;
5
6
  }) => (c: Context, next: Function) => Promise<void>;
@@ -12,7 +12,9 @@ const humanize = (n, opts) => {
12
12
  };
13
13
  const time = (start) => {
14
14
  const delta = Date.now() - start;
15
- return humanize([delta < 10000 ? delta + 'ms' : Math.round(delta / 1000) + 's']);
15
+ return humanize([
16
+ delta < 10000 ? delta + 'ms' : Math.round(delta / 1000) + 's',
17
+ ]);
16
18
  };
17
19
  const LogPrefix = {
18
20
  Outgoing: '-->',
@@ -1,2 +1,2 @@
1
- import { Context } from '../../hono';
1
+ import type { Context } from '../../context';
2
2
  export declare const poweredBy: () => (c: Context, next: Function) => Promise<void>;
@@ -1,8 +1,14 @@
1
1
  export declare class Middleware {
2
- static defaultFilter: (c: import("./hono").Context, next: Function) => Promise<void>;
3
- static poweredBy: () => (c: import("./hono").Context, next: Function) => Promise<void>;
2
+ static defaultFilter: (c: import("./context").Context, next: Function) => Promise<void>;
3
+ static poweredBy: () => (c: import("./context").Context, next: Function) => Promise<void>;
4
4
  static logger: (fn?: {
5
5
  (...data: any[]): void;
6
6
  (...data: any[]): void;
7
- }) => (c: import("./hono").Context, next: Function) => Promise<void>;
7
+ (message?: any, ...optionalParams: any[]): void;
8
+ }) => (c: import("./context").Context, next: Function) => Promise<void>;
9
+ static basicAuth: (options: {
10
+ username: string;
11
+ password: string;
12
+ realm?: string;
13
+ }) => (ctx: import("./context").Context, next: Function) => Promise<any>;
8
14
  }
@@ -4,9 +4,11 @@ exports.Middleware = void 0;
4
4
  const defaultFilter_1 = require("./middleware/defaultFilter");
5
5
  const poweredBy_1 = require("./middleware/poweredBy/poweredBy");
6
6
  const logger_1 = require("./middleware/logger/logger");
7
+ const basic_auth_1 = require("./middleware/basic-auth/basic-auth");
7
8
  class Middleware {
8
9
  }
9
10
  exports.Middleware = Middleware;
10
11
  Middleware.defaultFilter = defaultFilter_1.defaultFilter;
11
12
  Middleware.poweredBy = poweredBy_1.poweredBy;
12
13
  Middleware.logger = logger_1.logger;
14
+ Middleware.basicAuth = basic_auth_1.basicAuth;
package/dist/node.js CHANGED
@@ -23,6 +23,7 @@ class Node {
23
23
  this.middlewares = [];
24
24
  }
25
25
  insert(method, path, handler) {
26
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
26
27
  let curNode = this;
27
28
  const parts = (0, util_1.splitPath)(path);
28
29
  for (let i = 0, len = parts.length; i < len; i++) {
@@ -38,9 +39,10 @@ class Node {
38
39
  return curNode;
39
40
  }
40
41
  search(method, path) {
42
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
41
43
  let curNode = this;
42
44
  const params = {};
43
- let parts = (0, util_1.splitPath)(path);
45
+ const parts = (0, util_1.splitPath)(path);
44
46
  for (let i = 0, len = parts.length; i < len; i++) {
45
47
  const p = parts[i];
46
48
  // '*' => match any path
package/dist/util.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export declare const splitPath: (path: string) => string[];
2
2
  export declare const getPattern: (label: string) => string[] | null;
3
3
  export declare const getPathFromURL: (url: string) => string;
4
+ export declare const timingSafeEqual: (a: any, b: any) => Promise<boolean>;
package/dist/util.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0;
3
+ exports.timingSafeEqual = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0;
4
4
  const splitPath = (path) => {
5
5
  const paths = path.split(/\//); // faster than path.split('/')
6
6
  if (paths[0] === '') {
@@ -34,3 +34,30 @@ const getPathFromURL = (url) => {
34
34
  return '';
35
35
  };
36
36
  exports.getPathFromURL = getPathFromURL;
37
+ const bufferEqual = (a, b) => {
38
+ if (a === b) {
39
+ return true;
40
+ }
41
+ if (a.byteLength !== b.byteLength) {
42
+ return false;
43
+ }
44
+ const va = new DataView(a);
45
+ const vb = new DataView(b);
46
+ let i = va.byteLength;
47
+ while (i--) {
48
+ if (va.getUint8(i) !== vb.getUint8(i)) {
49
+ return false;
50
+ }
51
+ }
52
+ return true;
53
+ };
54
+ const timingSafeEqual = async (a, b) => {
55
+ const sa = await crypto.subtle.digest({
56
+ name: 'SHA-256',
57
+ }, new TextEncoder().encode(String(a)));
58
+ const sb = await crypto.subtle.digest({
59
+ name: 'SHA-256',
60
+ }, new TextEncoder().encode(String(b)));
61
+ return bufferEqual(sa, sb) && a === b;
62
+ };
63
+ exports.timingSafeEqual = timingSafeEqual;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "Tiny web framework for Cloudflare Workers and others.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,6 +9,7 @@
9
9
  ],
10
10
  "scripts": {
11
11
  "test": "jest",
12
+ "lint": "eslint --ext js,ts src .eslintrc.js test",
12
13
  "build": "rimraf dist && tsc",
13
14
  "watch": "tsc -w",
14
15
  "prepublishOnly": "yarn build"
@@ -35,11 +36,26 @@
35
36
  "devDependencies": {
36
37
  "@cloudflare/workers-types": "^3.3.0",
37
38
  "@types/jest": "^27.4.0",
39
+ "@types/node": "^17.0.8",
38
40
  "@types/service-worker-mock": "^2.0.1",
41
+ "@typescript-eslint/eslint-plugin": "^5.9.0",
42
+ "eslint": "^7.26.0",
43
+ "eslint-config-prettier": "^8.1.0",
44
+ "eslint-define-config": "^1.2.1",
45
+ "eslint-import-resolver-typescript": "^2.0.0",
46
+ "eslint-plugin-eslint-comments": "^3.2.0",
47
+ "eslint-plugin-flowtype": "^5.7.2",
48
+ "eslint-plugin-import": "^2.20.2",
49
+ "eslint-plugin-node": "^11.1.0",
50
+ "eslint-plugin-prettier": "^4.0.0",
39
51
  "jest": "^27.4.5",
40
52
  "rimraf": "^3.0.2",
41
53
  "service-worker-mock": "^2.0.5",
42
54
  "ts-jest": "^27.1.2",
55
+ "@typescript-eslint/parser": "^5.9.0",
43
56
  "typescript": "^4.5.4"
57
+ },
58
+ "engines": {
59
+ "node": ">=11.0.0"
44
60
  }
45
61
  }
package/dist/methods.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare const methods: string[];
package/dist/methods.js DELETED
@@ -1,31 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.methods = void 0;
4
- exports.methods = [
5
- 'get',
6
- 'post',
7
- 'put',
8
- 'head',
9
- 'delete',
10
- 'options',
11
- 'trace',
12
- 'copy',
13
- 'lock',
14
- 'mkcol',
15
- 'move',
16
- 'patch',
17
- 'purge',
18
- 'propfind',
19
- 'proppatch',
20
- 'unlock',
21
- 'report',
22
- 'mkactivity',
23
- 'checkout',
24
- 'merge',
25
- 'm-search',
26
- 'notify',
27
- 'subscribe',
28
- 'unsubscribe',
29
- 'search',
30
- 'connect',
31
- ];