hono 0.5.0 → 0.5.1
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 +8 -10
- package/dist/compose.d.ts +1 -1
- package/dist/compose.js +18 -23
- package/dist/middleware/basic-auth/basic-auth.js +2 -1
- package/dist/middleware/body-parse/body-parse.js +2 -18
- package/dist/middleware/etag/etag.d.ts +6 -0
- package/dist/middleware/etag/etag.js +28 -0
- package/dist/utils/body.d.ts +1 -0
- package/dist/utils/body.js +24 -0
- package/dist/utils/buffer.d.ts +0 -2
- package/dist/utils/buffer.js +4 -46
- package/dist/utils/crypto.d.ts +10 -0
- package/dist/utils/crypto.js +58 -0
- package/dist/utils/mime.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,12 +31,12 @@ app.fire()
|
|
|
31
31
|
**Hono is fastest** compared to other routers for Cloudflare Workers.
|
|
32
32
|
|
|
33
33
|
```plain
|
|
34
|
-
hono x
|
|
35
|
-
itty-router x
|
|
36
|
-
sunder x
|
|
37
|
-
worktop x
|
|
34
|
+
hono x 809,503 ops/sec ±6.94% (73 runs sampled)
|
|
35
|
+
itty-router x 157,310 ops/sec ±4.31% (87 runs sampled)
|
|
36
|
+
sunder x 328,350 ops/sec ±2.30% (95 runs sampled)
|
|
37
|
+
worktop x 209,758 ops/sec ±4.28% (83 runs sampled)
|
|
38
38
|
Fastest is hono
|
|
39
|
-
✨ Done in
|
|
39
|
+
✨ Done in 60.66s.
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
## Hono in 1 minute
|
|
@@ -184,15 +184,13 @@ app.use('*', async (c, next) => {
|
|
|
184
184
|
// Add a custom header
|
|
185
185
|
app.use('/message/*', async (c, next) => {
|
|
186
186
|
await next()
|
|
187
|
-
|
|
187
|
+
c.header('x-message', 'This is middleware!')
|
|
188
188
|
})
|
|
189
189
|
|
|
190
190
|
app.get('/message/hello', (c) => c.text('Hello Middleware!'))
|
|
191
191
|
```
|
|
192
192
|
|
|
193
|
-
##
|
|
194
|
-
|
|
195
|
-
### Not Found
|
|
193
|
+
## Not Found
|
|
196
194
|
|
|
197
195
|
`app.notFound` for customizing Not Found Response.
|
|
198
196
|
|
|
@@ -202,7 +200,7 @@ app.notFound((c) => {
|
|
|
202
200
|
})
|
|
203
201
|
```
|
|
204
202
|
|
|
205
|
-
|
|
203
|
+
## Error Handling
|
|
206
204
|
|
|
207
205
|
`app.onError` handle the error and return the customized Response.
|
|
208
206
|
|
package/dist/compose.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ErrorHandler } from './hono';
|
|
2
|
-
export declare const compose: <
|
|
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
|
|
7
|
+
return function (context) {
|
|
8
8
|
let index = -1;
|
|
9
9
|
return dispatch(0);
|
|
10
10
|
async function dispatch(i) {
|
|
11
|
-
if (i
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
fn = next;
|
|
17
|
-
if (!fn)
|
|
19
|
+
return Promise.resolve(handler(context, dispatch.bind(null, i + 1)))
|
|
20
|
+
.then(() => {
|
|
18
21
|
return context;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
})
|
|
23
|
+
.catch((err) => {
|
|
24
|
+
if (onError && context instanceof context_1.Context) {
|
|
25
|
+
context.res = onError(err, context);
|
|
22
26
|
return context;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
};
|
|
@@ -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,
|
|
22
|
+
const userPass = USER_PASS_REGEXP.exec((0, crypto_1.decodeBase64)(match[1]));
|
|
22
23
|
if (!userPass) {
|
|
23
24
|
return undefined;
|
|
24
25
|
}
|
|
@@ -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
|
-
|
|
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,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;
|
package/dist/utils/buffer.d.ts
CHANGED
|
@@ -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
2
|
export declare const timingSafeEqual: (a: string | object | boolean, b: string | object | boolean) => Promise<boolean>;
|
package/dist/utils/buffer.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.timingSafeEqual = exports.
|
|
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,9 @@ 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;
|
|
58
|
-
}
|
|
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
23
|
const timingSafeEqual = async (a, b) => {
|
|
66
|
-
const sa = await (0,
|
|
67
|
-
const sb = await (0,
|
|
24
|
+
const sa = await (0, crypto_1.sha256)(a);
|
|
25
|
+
const sb = await (0, crypto_1.sha256)(b);
|
|
68
26
|
return sa === sb && a === b;
|
|
69
27
|
};
|
|
70
28
|
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;
|
package/dist/utils/mime.js
CHANGED
|
@@ -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',
|