hono 0.0.13 → 0.1.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 +24 -11
- package/dist/context.js +2 -2
- package/dist/hono.d.ts +1 -0
- package/dist/hono.js +12 -4
- package/dist/middleware/basic-auth/basic-auth.js +3 -3
- package/dist/middleware/cors/cors.d.ts +11 -0
- package/dist/middleware/cors/cors.js +56 -0
- package/dist/middleware/default.js +11 -0
- package/dist/middleware/logger/logger.js +11 -5
- package/dist/middleware.d.ts +8 -0
- package/dist/middleware.js +2 -0
- package/dist/node.js +6 -5
- package/dist/utils/buffer.d.ts +2 -0
- package/dist/utils/buffer.js +31 -0
- package/dist/{util.d.ts → utils/url.d.ts} +0 -1
- package/dist/{util.js → utils/url.js} +1 -29
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ app.fire()
|
|
|
13
13
|
|
|
14
14
|
## Features
|
|
15
15
|
|
|
16
|
-
- **Ultra
|
|
16
|
+
- **Ultra fast** - the router is implemented with Trie-Tree structure.
|
|
17
17
|
- **Zero dependencies** - using only Web standard API.
|
|
18
18
|
- **Middleware** - builtin middleware, and you can make your own middleware.
|
|
19
19
|
- **Optimized** - for Cloudflare Workers.
|
|
@@ -70,12 +70,12 @@ Instance of `Hono` has these methods:
|
|
|
70
70
|
|
|
71
71
|
```js
|
|
72
72
|
// HTTP Methods
|
|
73
|
-
app.get('/', () =>
|
|
74
|
-
app.post('/', () =>
|
|
73
|
+
app.get('/', (c) => c.text('GET /'))
|
|
74
|
+
app.post('/', (c) => c.text('POST /'))
|
|
75
75
|
|
|
76
76
|
// Wildcard
|
|
77
|
-
app.get('/wild/*/card', () => {
|
|
78
|
-
return
|
|
77
|
+
app.get('/wild/*/card', (c) => {
|
|
78
|
+
return c.text('GET /wild/*/card')
|
|
79
79
|
})
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -83,7 +83,7 @@ app.get('/wild/*/card', () => {
|
|
|
83
83
|
|
|
84
84
|
```js
|
|
85
85
|
// Any HTTP methods
|
|
86
|
-
app.all('/hello', () =>
|
|
86
|
+
app.all('/hello', (c) => c.text('Any Method /hello'))
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
### Named Parameter
|
|
@@ -117,9 +117,9 @@ app
|
|
|
117
117
|
## async/await
|
|
118
118
|
|
|
119
119
|
```js
|
|
120
|
-
app.get('/fetch-url', async () => {
|
|
120
|
+
app.get('/fetch-url', async (c) => {
|
|
121
121
|
const response = await fetch('https://example.com/')
|
|
122
|
-
return
|
|
122
|
+
return c.text(`Status is ${response.status}`)
|
|
123
123
|
})
|
|
124
124
|
```
|
|
125
125
|
|
|
@@ -162,7 +162,7 @@ app.use('/message/*', async (c, next) => {
|
|
|
162
162
|
await c.res.headers.add('x-message', 'This is middleware!')
|
|
163
163
|
})
|
|
164
164
|
|
|
165
|
-
app.get('/message/hello', () => 'Hello Middleware!')
|
|
165
|
+
app.get('/message/hello', (c) => c.text('Hello Middleware!'))
|
|
166
166
|
```
|
|
167
167
|
|
|
168
168
|
### Custom 404 Response
|
|
@@ -178,6 +178,19 @@ app.use('*', async (c, next) => {
|
|
|
178
178
|
})
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
+
### Handling Error
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
app.use('*', async (c, next) => {
|
|
185
|
+
try {
|
|
186
|
+
await next()
|
|
187
|
+
} catch (err) {
|
|
188
|
+
console.error(`${err}`)
|
|
189
|
+
c.res = new Response('Custom Error Message', { status: 500 })
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
```
|
|
193
|
+
|
|
181
194
|
### Complex Pattern
|
|
182
195
|
|
|
183
196
|
You can also do this:
|
|
@@ -239,7 +252,7 @@ app.use('/', (c, next) => {
|
|
|
239
252
|
### c.event
|
|
240
253
|
|
|
241
254
|
```js
|
|
242
|
-
// FetchEvent
|
|
255
|
+
// FetchEvent object
|
|
243
256
|
app.use('*', async (c, next) => {
|
|
244
257
|
c.event.waitUntil(
|
|
245
258
|
...
|
|
@@ -339,7 +352,7 @@ Make npm skeleton directory.
|
|
|
339
352
|
|
|
340
353
|
```sh
|
|
341
354
|
mkdir hono-example
|
|
342
|
-
|
|
355
|
+
cd hono-example
|
|
343
356
|
npm init -y
|
|
344
357
|
```
|
|
345
358
|
|
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
|
|
4
|
+
const url_1 = require("./utils/url");
|
|
5
5
|
class Context {
|
|
6
6
|
constructor(req, opts) {
|
|
7
7
|
this.req = req;
|
|
@@ -49,7 +49,7 @@ class Context {
|
|
|
49
49
|
if (typeof location !== 'string') {
|
|
50
50
|
throw new TypeError('location must be a string!');
|
|
51
51
|
}
|
|
52
|
-
if (!(0,
|
|
52
|
+
if (!(0, url_1.isAbsoluteURL)(location)) {
|
|
53
53
|
const url = new URL(this.req.url);
|
|
54
54
|
url.pathname = location;
|
|
55
55
|
location = url.toString();
|
package/dist/hono.d.ts
CHANGED
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
|
|
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,7 +94,7 @@ 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,
|
|
97
|
+
const [method, path] = [request.method, (0, url_1.getPathFromURL)(request.url)];
|
|
98
98
|
const result = await this.matchRoute(method, path);
|
|
99
99
|
request.params = (key) => {
|
|
100
100
|
if (result) {
|
|
@@ -122,16 +122,24 @@ class Hono {
|
|
|
122
122
|
return c.res;
|
|
123
123
|
}
|
|
124
124
|
async handleEvent(event) {
|
|
125
|
-
return this.dispatch(event.request, {}, event)
|
|
125
|
+
return this.dispatch(event.request, {}, event).catch((err) => {
|
|
126
|
+
return this.onError(err);
|
|
127
|
+
});
|
|
126
128
|
}
|
|
127
129
|
async fetch(request, env, event) {
|
|
128
|
-
return this.dispatch(request, env, event)
|
|
130
|
+
return this.dispatch(request, env, event).catch((err) => {
|
|
131
|
+
return this.onError(err);
|
|
132
|
+
});
|
|
129
133
|
}
|
|
130
134
|
fire() {
|
|
131
135
|
addEventListener('fetch', (event) => {
|
|
132
136
|
event.respondWith(this.handleEvent(event));
|
|
133
137
|
});
|
|
134
138
|
}
|
|
139
|
+
onError(err) {
|
|
140
|
+
console.error(err);
|
|
141
|
+
return new Response('Internal Server Error', { status: 500 });
|
|
142
|
+
}
|
|
135
143
|
notFound() {
|
|
136
144
|
return new Response('Not Found', { status: 404 });
|
|
137
145
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.basicAuth = void 0;
|
|
4
|
-
const
|
|
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,
|
|
37
|
-
const passwordEqual = user && await (0,
|
|
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,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;
|
|
@@ -8,5 +8,16 @@ const defaultMiddleware = async (c, next) => {
|
|
|
8
8
|
return url.searchParams.get(key);
|
|
9
9
|
};
|
|
10
10
|
await next();
|
|
11
|
+
if (c.res.body) {
|
|
12
|
+
// Do not clone Response, ex: c.res.clone().arrayBuffer()
|
|
13
|
+
const buffer = await c.res.arrayBuffer();
|
|
14
|
+
const res = new Response(buffer, {
|
|
15
|
+
status: c.res.status,
|
|
16
|
+
statusText: c.res.statusText,
|
|
17
|
+
headers: c.res.headers,
|
|
18
|
+
});
|
|
19
|
+
res.headers.append('Content-Length', buffer.byteLength.toString());
|
|
20
|
+
c.res = res;
|
|
21
|
+
}
|
|
11
22
|
};
|
|
12
23
|
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
|
|
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,
|
|
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
|
-
|
|
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;
|
package/dist/middleware.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/middleware.js
CHANGED
|
@@ -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
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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,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.
|
|
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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "Ultrafast web framework for Cloudflare Workers.",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "[炎] Ultrafast web framework for Cloudflare Workers.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|