hono 0.0.14 → 0.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.
package/README.md CHANGED
@@ -35,7 +35,7 @@ Fastest is hono
35
35
 
36
36
  Below is a demonstration to create an application of Cloudflare Workers with Hono.
37
37
 
38
- ![Demo](https://user-images.githubusercontent.com/10682/148223268-2484a891-57c1-472f-9df3-936a5586f002.gif)
38
+ ![Demo](https://user-images.githubusercontent.com/10682/151102477-be0f950e-8d23-49c5-b6d8-d8ecb6b7484e.gif)
39
39
 
40
40
  ## Install
41
41
 
@@ -90,7 +90,7 @@ app.all('/hello', (c) => c.text('Any Method /hello'))
90
90
 
91
91
  ```js
92
92
  app.get('/user/:name', (c) => {
93
- const name = c.req.params('name')
93
+ const name = c.req.param('name')
94
94
  ...
95
95
  })
96
96
  ```
@@ -99,8 +99,8 @@ app.get('/user/:name', (c) => {
99
99
 
100
100
  ```js
101
101
  app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
102
- const date = c.req.params('date')
103
- const title = c.req.params('title')
102
+ const date = c.req.param('date')
103
+ const title = c.req.param('title')
104
104
  ...
105
105
  ```
106
106
 
@@ -219,13 +219,18 @@ To handle Request and Reponse easily, you can use Context object:
219
219
  ### c.req
220
220
 
221
221
  ```js
222
-
223
222
  // Get Request object
224
223
  app.get('/hello', (c) => {
225
224
  const userAgent = c.req.headers.get('User-Agent')
226
225
  ...
227
226
  })
228
227
 
228
+ // Shortcut to get a header value
229
+ app.get('/shortcut', (c) => {
230
+ const userAgent = c.req.header('User-Agent')
231
+ ...
232
+ })
233
+
229
234
  // Query params
230
235
  app.get('/search', (c) => {
231
236
  const query = c.req.query('q')
@@ -234,40 +239,31 @@ app.get('/search', (c) => {
234
239
 
235
240
  // Captured params
236
241
  app.get('/entry/:id', (c) => {
237
- const id = c.req.params('id')
242
+ const id = c.req.param('id')
238
243
  ...
239
244
  })
240
245
  ```
241
246
 
242
- ### c.res
243
-
244
- ```js
245
- // Response object
246
- app.use('/', (c, next) => {
247
- next()
248
- c.res.headers.append('X-Debug', 'Debug message')
249
- })
250
- ```
251
-
252
- ### c.event
253
-
254
- ```js
255
- // FetchEvent object
256
- app.use('*', async (c, next) => {
257
- c.event.waitUntil(
258
- ...
259
- )
260
- await next()
261
- })
262
- ```
263
-
264
- ### c.env
247
+ ### Shortcuts for Response
265
248
 
266
249
  ```js
267
- // Environment object for Cloudflare Workers
268
- app.get('*', async c => {
269
- const counter = c.env.COUNTER
270
- ...
250
+ app.get('/welcome', (c) => {
251
+ c.header('X-Message', 'Hello!')
252
+ c.header('Content-Type', 'text/plain')
253
+ c.status(201)
254
+ c.statusText('201 Content Created')
255
+ return c.body('Thank you for comming')
256
+ /*
257
+ Same as:
258
+ return new Response('Thank you for comming', {
259
+ status: 201,
260
+ statusText: '201 Content Created',
261
+ headers: {
262
+ 'X-Message': 'Hello',
263
+ 'Content-Type': 'text/plain'
264
+ }
265
+ })
266
+ */
271
267
  })
272
268
  ```
273
269
 
@@ -310,6 +306,38 @@ app.get('/redirect', (c) => c.redirect('/'))
310
306
  app.get('/redirect-permanently', (c) => c.redirect('/', 301))
311
307
  ```
312
308
 
309
+ ### c.res
310
+
311
+ ```js
312
+ // Response object
313
+ app.use('/', (c, next) => {
314
+ next()
315
+ c.res.headers.append('X-Debug', 'Debug message')
316
+ })
317
+ ```
318
+
319
+ ### c.event
320
+
321
+ ```js
322
+ // FetchEvent object
323
+ app.use('*', async (c, next) => {
324
+ c.event.waitUntil(
325
+ ...
326
+ )
327
+ await next()
328
+ })
329
+ ```
330
+
331
+ ### c.env
332
+
333
+ ```js
334
+ // Environment object for Cloudflare Workers
335
+ app.get('*', async c => {
336
+ const counter = c.env.COUNTER
337
+ ...
338
+ })
339
+ ```
340
+
313
341
  ## fire
314
342
 
315
343
  `app.fire()` do:
package/dist/context.d.ts CHANGED
@@ -9,12 +9,19 @@ export declare class Context {
9
9
  res: Response;
10
10
  env: Env;
11
11
  event: FetchEvent;
12
+ private _headers;
13
+ private _status;
14
+ private _statusText;
15
+ body: (body: BodyInit, init?: ResponseInit) => Response;
12
16
  constructor(req: Request, opts?: {
13
17
  res: Response;
14
18
  env: Env;
15
19
  event: FetchEvent;
16
20
  });
17
- newResponse(body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response;
21
+ header(name: string, value: string): void;
22
+ status(number: number): void;
23
+ statusText(text: string): void;
24
+ newResponse(body: BodyInit, init?: ResponseInit): Response;
18
25
  text(text: string, status?: number, headers?: Headers): Response;
19
26
  json(object: object, status?: number, headers?: Headers): Response;
20
27
  html(html: string, status?: number, headers?: Headers): Response;
package/dist/context.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Context = void 0;
4
- const util_1 = require("./util");
4
+ const url_1 = require("./utils/url");
5
5
  class Context {
6
6
  constructor(req, opts) {
7
7
  this.req = req;
@@ -10,8 +10,22 @@ class Context {
10
10
  this.env = opts.env;
11
11
  this.event = opts.event;
12
12
  }
13
+ this._headers = {};
14
+ this.body = this.newResponse;
13
15
  }
14
- newResponse(body, init) {
16
+ header(name, value) {
17
+ this._headers[name] = value;
18
+ }
19
+ status(number) {
20
+ this._status = number;
21
+ }
22
+ statusText(text) {
23
+ this._statusText = text;
24
+ }
25
+ newResponse(body, init = {}) {
26
+ init.status = this._status || init.status;
27
+ init.statusText = this._statusText || init.statusText;
28
+ init.headers = Object.assign(Object.assign({}, init.headers), this._headers);
15
29
  return new Response(body, init);
16
30
  }
17
31
  text(text, status = 200, headers = {}) {
@@ -49,7 +63,7 @@ class Context {
49
63
  if (typeof location !== 'string') {
50
64
  throw new TypeError('location must be a string!');
51
65
  }
52
- if (!(0, util_1.isAbsoluteURL)(location)) {
66
+ if (!(0, url_1.isAbsoluteURL)(location)) {
53
67
  const url = new URL(this.req.url);
54
68
  url.pathname = location;
55
69
  location = url.toString();
package/dist/hono.d.ts CHANGED
@@ -5,8 +5,9 @@ import { Context } from './context';
5
5
  import type { Env } from './context';
6
6
  declare global {
7
7
  interface Request {
8
- params: (key: string) => string;
8
+ param: (key: string) => string;
9
9
  query: (key: string) => string | null;
10
+ header: (name: string) => string;
10
11
  parsedBody: any;
11
12
  }
12
13
  }
package/dist/hono.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Hono = exports.Router = void 0;
4
4
  const node_1 = require("./node");
5
5
  const compose_1 = require("./compose");
6
- const util_1 = require("./util");
6
+ const url_1 = require("./utils/url");
7
7
  const middleware_1 = require("./middleware");
8
8
  const context_1 = require("./context");
9
9
  const METHOD_NAME_OF_ALL = 'ALL';
@@ -94,9 +94,9 @@ class Hono {
94
94
  return this.router.match(method, path);
95
95
  }
96
96
  async dispatch(request, env, event) {
97
- const [method, path] = [request.method, (0, util_1.getPathFromURL)(request.url)];
97
+ const [method, path] = [request.method, (0, url_1.getPathFromURL)(request.url)];
98
98
  const result = await this.matchRoute(method, path);
99
- request.params = (key) => {
99
+ request.param = (key) => {
100
100
  if (result) {
101
101
  return result.params[key];
102
102
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.basicAuth = void 0;
4
- const util_1 = require("../../util");
4
+ const buffer_1 = require("../../utils/buffer");
5
5
  const CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/;
6
6
  const USER_PASS_REGEXP = /^([^:]*):(.*)$/;
7
7
  const auth = (req) => {
@@ -33,8 +33,8 @@ const basicAuth = (options) => {
33
33
  }
34
34
  return async (ctx, next) => {
35
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);
36
+ const usernameEqual = user && await (0, buffer_1.timingSafeEqual)(options.username, user.username);
37
+ const passwordEqual = user && await (0, buffer_1.timingSafeEqual)(options.password, user.password);
38
38
  if (!user || !usernameEqual || !passwordEqual) {
39
39
  ctx.res = new Response('Unauthorized', {
40
40
  status: 401,
@@ -0,0 +1,23 @@
1
+ import type { Context } from '../../context';
2
+ declare global {
3
+ interface Request {
4
+ cookie: (name: string) => string;
5
+ }
6
+ interface Response {
7
+ cookie: (name: string, value: string, options?: CookieOptions) => void;
8
+ }
9
+ }
10
+ export declare type Cookie = {
11
+ [key: string]: string;
12
+ };
13
+ export declare type CookieOptions = {
14
+ domain?: string;
15
+ expires?: Date;
16
+ httpOnly?: boolean;
17
+ maxAge?: number;
18
+ path?: string;
19
+ secure?: boolean;
20
+ signed?: boolean;
21
+ sameSite?: 'Strict' | 'Lax' | 'None';
22
+ };
23
+ export declare const cookie: () => (c: Context, next: Function) => Promise<void>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cookie = void 0;
4
+ const cookie = () => {
5
+ return async (c, next) => {
6
+ c.req.cookie = (name) => {
7
+ const cookie = c.req.headers.get('Cookie');
8
+ const obj = parse(cookie);
9
+ const value = obj[name];
10
+ return value;
11
+ };
12
+ await next();
13
+ c.res.cookie = (name, value, options) => {
14
+ console.log('c.res.cookie!');
15
+ const cookie = serialize(name, value);
16
+ c.res.headers.set('Set-Cookie', cookie);
17
+ };
18
+ };
19
+ };
20
+ exports.cookie = cookie;
21
+ const parse = (cookie) => {
22
+ const pairs = cookie.split(/;\s*/g);
23
+ const parsedCookie = {};
24
+ for (let i = 0, len = pairs.length; i < len; i++) {
25
+ const pair = pairs[i].split(/\s*=\s*([^\s]+)/);
26
+ parsedCookie[pair[0]] = decodeURIComponent(pair[1]);
27
+ }
28
+ return parsedCookie;
29
+ };
30
+ const serialize = (name, value, options = {}) => {
31
+ value = encodeURIComponent(value);
32
+ const cookie = `${name}=${value}`;
33
+ return cookie;
34
+ };
@@ -0,0 +1,11 @@
1
+ import type { Context } from '../../context';
2
+ declare type CORSOptions = {
3
+ origin: string;
4
+ allowMethods?: string[];
5
+ allowHeaders?: string[];
6
+ maxAge?: number;
7
+ credentials?: boolean;
8
+ exposeHeaders?: string[];
9
+ };
10
+ export declare const cors: (options?: CORSOptions) => (c: Context, next: Function) => Promise<void>;
11
+ export {};
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cors = void 0;
4
+ const cors = (options) => {
5
+ const defaults = {
6
+ origin: '*',
7
+ allowMethods: ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH'],
8
+ allowHeaders: [],
9
+ exposeHeaders: [],
10
+ };
11
+ const opts = Object.assign(Object.assign({}, defaults), options);
12
+ return async (c, next) => {
13
+ await next();
14
+ function set(key, value) {
15
+ c.res.headers.append(key, value);
16
+ }
17
+ set('Access-Control-Allow-Origin', opts.origin);
18
+ // Suppose the server sends a response with an Access-Control-Allow-Origin value with an explicit origin (rather than the "*" wildcard).
19
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
20
+ if (opts.origin !== '*') {
21
+ set('Vary', 'Origin');
22
+ }
23
+ if (opts.credentials) {
24
+ set('Access-Control-Allow-Credentials', 'true');
25
+ }
26
+ if (opts.exposeHeaders.length) {
27
+ set('Access-Control-Expose-Headers', opts.exposeHeaders.join(','));
28
+ }
29
+ if (c.req.method === 'OPTIONS') {
30
+ // Preflight
31
+ if (opts.maxAge != null) {
32
+ set('Access-Control-Max-Age', opts.maxAge.toString());
33
+ }
34
+ if (opts.allowMethods.length) {
35
+ set('Access-Control-Allow-Methods', opts.allowMethods.join(','));
36
+ }
37
+ let headers = opts.allowHeaders;
38
+ if (!headers.length) {
39
+ const requestHeaders = c.req.headers.get('Access-Control-Request-Headers');
40
+ if (requestHeaders) {
41
+ headers = requestHeaders.split(/\s*,\s*/);
42
+ }
43
+ }
44
+ if (headers.length) {
45
+ set('Access-Control-Allow-Headers', headers.join(','));
46
+ set('Vary', 'Access-Control-Request-Headers');
47
+ }
48
+ c.res = new Response(null, {
49
+ headers: c.res.headers,
50
+ status: 204,
51
+ statusText: c.res.statusText,
52
+ });
53
+ }
54
+ };
55
+ };
56
+ exports.cors = cors;
@@ -7,10 +7,20 @@ const defaultMiddleware = async (c, next) => {
7
7
  const url = new URL(c.req.url);
8
8
  return url.searchParams.get(key);
9
9
  };
10
+ c.req.header = (name) => {
11
+ return c.req.headers.get(name);
12
+ };
10
13
  await next();
11
14
  if (c.res.body) {
12
- const buff = await c.res.clone().arrayBuffer();
13
- c.res.headers.append('Content-Length', buff.byteLength.toString());
15
+ // Do not clone Response, ex: c.res.clone().arrayBuffer()
16
+ const buffer = await c.res.arrayBuffer();
17
+ const res = new Response(buffer, {
18
+ status: c.res.status,
19
+ statusText: c.res.statusText,
20
+ headers: c.res.headers,
21
+ });
22
+ res.headers.append('Content-Length', buffer.byteLength.toString());
23
+ c.res = res;
14
24
  }
15
25
  };
16
26
  exports.defaultMiddleware = defaultMiddleware;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.logger = void 0;
4
- const util_1 = require("../../util");
4
+ const url_1 = require("../../utils/url");
5
5
  const humanize = (n, opts) => {
6
6
  const options = opts || {};
7
7
  const d = options.delimiter || ',';
@@ -33,16 +33,16 @@ const colorStatus = (status = 0) => {
33
33
  };
34
34
  return out[(status / 100) | 0];
35
35
  };
36
- function log(fn, prefix, method, path, status, elasped) {
36
+ function log(fn, prefix, method, path, status, elasped, contentLength) {
37
37
  const out = prefix === LogPrefix.Incoming
38
38
  ? ` ${prefix} ${method} ${path}`
39
- : ` ${prefix} ${method} ${path} ${colorStatus(status)} ${elasped}`;
39
+ : ` ${prefix} ${method} ${path} ${colorStatus(status)} ${elasped} ${contentLength}`;
40
40
  fn(out);
41
41
  }
42
42
  const logger = (fn = console.log) => {
43
43
  return async (c, next) => {
44
44
  const { method } = c.req;
45
- const path = (0, util_1.getPathFromURL)(c.req.url);
45
+ const path = (0, url_1.getPathFromURL)(c.req.url);
46
46
  log(fn, LogPrefix.Incoming, method, path);
47
47
  const start = Date.now();
48
48
  try {
@@ -52,7 +52,13 @@ const logger = (fn = console.log) => {
52
52
  log(fn, LogPrefix.Error, method, path, c.res.status || 500, time(start));
53
53
  throw e;
54
54
  }
55
- log(fn, LogPrefix.Outgoing, method, path, c.res.status, time(start));
55
+ const len = parseFloat(c.res.headers.get('Content-Length'));
56
+ const contentLength = isNaN(len)
57
+ ? '0'
58
+ : len < 1024
59
+ ? `${len}b`
60
+ : `${len / 1024}kB`;
61
+ log(fn, LogPrefix.Outgoing, method, path, c.res.status, time(start), contentLength);
56
62
  };
57
63
  };
58
64
  exports.logger = logger;
@@ -12,4 +12,12 @@ export declare class Middleware {
12
12
  realm?: string;
13
13
  }) => (ctx: import("./context").Context, next: Function) => Promise<any>;
14
14
  static bodyParse: () => (ctx: import("./context").Context, next: Function) => Promise<void>;
15
+ static cors: (options?: {
16
+ origin: string;
17
+ allowMethods?: string[];
18
+ allowHeaders?: string[];
19
+ maxAge?: number;
20
+ credentials?: boolean;
21
+ exposeHeaders?: string[];
22
+ }) => (c: import("./context").Context, next: Function) => Promise<void>;
15
23
  }
@@ -6,6 +6,7 @@ const powered_by_1 = require("./middleware/powered-by/powered-by");
6
6
  const logger_1 = require("./middleware/logger/logger");
7
7
  const basic_auth_1 = require("./middleware/basic-auth/basic-auth");
8
8
  const body_parse_1 = require("./middleware/body-parse/body-parse");
9
+ const cors_1 = require("./middleware/cors/cors");
9
10
  class Middleware {
10
11
  }
11
12
  exports.Middleware = Middleware;
@@ -14,3 +15,4 @@ Middleware.poweredBy = powered_by_1.poweredBy;
14
15
  Middleware.logger = logger_1.logger;
15
16
  Middleware.basicAuth = basic_auth_1.basicAuth;
16
17
  Middleware.bodyParse = body_parse_1.bodyParse;
18
+ Middleware.cors = cors_1.cors;
package/dist/node.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Node = exports.Result = void 0;
4
- const util_1 = require("./util");
4
+ const url_1 = require("./utils/url");
5
5
  const METHOD_NAME_OF_ALL = 'ALL';
6
6
  class Result {
7
7
  constructor(handler, params) {
@@ -25,7 +25,7 @@ class Node {
25
25
  insert(method, path, handler) {
26
26
  // eslint-disable-next-line @typescript-eslint/no-this-alias
27
27
  let curNode = this;
28
- const parts = (0, util_1.splitPath)(path);
28
+ const parts = (0, url_1.splitPath)(path);
29
29
  for (let i = 0, len = parts.length; i < len; i++) {
30
30
  const p = parts[i];
31
31
  if (Object.keys(curNode.children).includes(p)) {
@@ -42,11 +42,12 @@ class Node {
42
42
  // eslint-disable-next-line @typescript-eslint/no-this-alias
43
43
  let curNode = this;
44
44
  const params = {};
45
- const parts = (0, util_1.splitPath)(path);
45
+ const parts = (0, url_1.splitPath)(path);
46
46
  for (let i = 0, len = parts.length; i < len; i++) {
47
47
  const p = parts[i];
48
48
  // '*' => match any path
49
- if (curNode.children['*']) {
49
+ // /api/* => default wildcard match
50
+ if (curNode.children['*'] && !curNode.children[p]) {
50
51
  const astNode = curNode.children['*'];
51
52
  if (Object.keys(astNode.children).length === 0) {
52
53
  curNode = astNode;
@@ -73,7 +74,7 @@ class Node {
73
74
  isWildcard = true;
74
75
  break;
75
76
  }
76
- const pattern = (0, util_1.getPattern)(key);
77
+ const pattern = (0, url_1.getPattern)(key);
77
78
  // Named match
78
79
  if (pattern) {
79
80
  const match = p.match(new RegExp(pattern[1]));
@@ -0,0 +1,2 @@
1
+ export declare const equal: (a: ArrayBuffer, b: ArrayBuffer) => boolean;
2
+ export declare const timingSafeEqual: (a: any, b: any) => Promise<boolean>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.timingSafeEqual = exports.equal = void 0;
4
+ const equal = (a, b) => {
5
+ if (a === b) {
6
+ return true;
7
+ }
8
+ if (a.byteLength !== b.byteLength) {
9
+ return false;
10
+ }
11
+ const va = new DataView(a);
12
+ const vb = new DataView(b);
13
+ let i = va.byteLength;
14
+ while (i--) {
15
+ if (va.getUint8(i) !== vb.getUint8(i)) {
16
+ return false;
17
+ }
18
+ }
19
+ return true;
20
+ };
21
+ exports.equal = equal;
22
+ const timingSafeEqual = async (a, b) => {
23
+ const sa = await crypto.subtle.digest({
24
+ name: 'SHA-256',
25
+ }, new TextEncoder().encode(String(a)));
26
+ const sb = await crypto.subtle.digest({
27
+ name: 'SHA-256',
28
+ }, new TextEncoder().encode(String(b)));
29
+ return (0, exports.equal)(sa, sb) && a === b;
30
+ };
31
+ exports.timingSafeEqual = timingSafeEqual;
@@ -2,4 +2,3 @@ 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
4
  export declare const isAbsoluteURL: (url: string) => boolean;
5
- export declare const timingSafeEqual: (a: any, b: any) => Promise<boolean>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.timingSafeEqual = exports.isAbsoluteURL = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0;
3
+ exports.isAbsoluteURL = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0;
4
4
  const URL_REGEXP = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
5
5
  const splitPath = (path) => {
6
6
  const paths = path.split(/\//); // faster than path.split('/')
@@ -27,7 +27,6 @@ const getPattern = (label) => {
27
27
  };
28
28
  exports.getPattern = getPattern;
29
29
  const getPathFromURL = (url) => {
30
- // XXX
31
30
  const match = url.match(URL_REGEXP);
32
31
  if (match) {
33
32
  return match[5];
@@ -43,30 +42,3 @@ const isAbsoluteURL = (url) => {
43
42
  return false;
44
43
  };
45
44
  exports.isAbsoluteURL = isAbsoluteURL;
46
- const bufferEqual = (a, b) => {
47
- if (a === b) {
48
- return true;
49
- }
50
- if (a.byteLength !== b.byteLength) {
51
- return false;
52
- }
53
- const va = new DataView(a);
54
- const vb = new DataView(b);
55
- let i = va.byteLength;
56
- while (i--) {
57
- if (va.getUint8(i) !== vb.getUint8(i)) {
58
- return false;
59
- }
60
- }
61
- return true;
62
- };
63
- const timingSafeEqual = async (a, b) => {
64
- const sa = await crypto.subtle.digest({
65
- name: 'SHA-256',
66
- }, new TextEncoder().encode(String(a)));
67
- const sb = await crypto.subtle.digest({
68
- name: 'SHA-256',
69
- }, new TextEncoder().encode(String(b)));
70
- return bufferEqual(sa, sb) && a === b;
71
- };
72
- exports.timingSafeEqual = timingSafeEqual;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "0.0.14",
3
+ "version": "0.2.0",
4
4
  "description": "[炎] Ultrafast web framework for Cloudflare Workers.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",