hono 2.1.4 → 2.2.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 +13 -14
- package/dist/cjs/compose.js +48 -0
- package/dist/cjs/context.js +147 -0
- package/dist/cjs/hono.js +152 -0
- package/dist/cjs/index.js +13 -0
- package/dist/cjs/middleware/basic-auth/index.js +48 -0
- package/dist/cjs/middleware/bearer-auth/index.js +57 -0
- package/dist/cjs/middleware/cache/index.js +32 -0
- package/dist/cjs/middleware/compress/index.js +19 -0
- package/dist/cjs/middleware/cors/index.js +75 -0
- package/dist/cjs/middleware/etag/index.js +27 -0
- package/dist/cjs/middleware/html/index.js +36 -0
- package/dist/cjs/middleware/jsx/index.js +193 -0
- package/dist/cjs/middleware/jsx/jsx-dev-runtime.js +10 -0
- package/dist/cjs/middleware/jsx/jsx-runtime.js +7 -0
- package/dist/cjs/middleware/jwt/index.js +63 -0
- package/dist/cjs/middleware/logger/index.js +49 -0
- package/dist/cjs/middleware/powered-by/index.js +10 -0
- package/dist/cjs/middleware/pretty-json/index.js +11 -0
- package/dist/cjs/middleware/serve-static/bun.js +41 -0
- package/dist/cjs/middleware/serve-static/index.js +5 -0
- package/dist/cjs/middleware/serve-static/serve-static.js +40 -0
- package/dist/cjs/middleware/validator/index.js +5 -0
- package/dist/cjs/middleware/validator/middleware.js +56 -0
- package/dist/cjs/middleware/validator/rule.js +66 -0
- package/dist/cjs/middleware/validator/sanitizer.js +6 -0
- package/dist/cjs/middleware/validator/validator.js +195 -0
- package/dist/cjs/request.js +120 -0
- package/dist/cjs/router/reg-exp-router/index.js +5 -0
- package/dist/cjs/router/reg-exp-router/node.js +108 -0
- package/dist/cjs/router/reg-exp-router/router.js +161 -0
- package/dist/cjs/router/reg-exp-router/trie.js +42 -0
- package/dist/cjs/router/smart-router/index.js +5 -0
- package/dist/cjs/router/smart-router/router.js +57 -0
- package/dist/cjs/router/static-router/index.js +5 -0
- package/dist/cjs/router/static-router/router.js +72 -0
- package/dist/cjs/router/trie-router/index.js +5 -0
- package/dist/cjs/router/trie-router/node.js +175 -0
- package/dist/cjs/router/trie-router/router.js +24 -0
- package/dist/cjs/router.js +9 -0
- package/dist/cjs/utils/body.js +18 -0
- package/dist/cjs/utils/buffer.js +39 -0
- package/dist/cjs/utils/cloudflare.js +39 -0
- package/dist/cjs/utils/cookie.js +40 -0
- package/dist/cjs/utils/crypto.js +53 -0
- package/dist/cjs/utils/encode.js +80 -0
- package/dist/cjs/utils/filepath.js +25 -0
- package/dist/cjs/utils/html.js +38 -0
- package/dist/cjs/utils/http-status.js +50 -0
- package/dist/cjs/utils/json.js +22 -0
- package/dist/cjs/utils/jwt/index.js +27 -0
- package/dist/cjs/utils/jwt/jwt.js +101 -0
- package/dist/cjs/utils/jwt/types.js +49 -0
- package/dist/cjs/utils/mime.js +92 -0
- package/dist/cjs/utils/url.js +94 -0
- package/dist/compose.d.ts +2 -2
- package/dist/compose.js +3 -7
- package/dist/context.d.ts +14 -9
- package/dist/context.js +55 -25
- package/dist/hono.d.ts +28 -27
- package/dist/hono.js +22 -23
- package/dist/index.js +3 -6
- package/dist/middleware/basic-auth/index.d.ts +2 -3
- package/dist/middleware/basic-auth/index.js +7 -11
- package/dist/middleware/bearer-auth/index.d.ts +2 -3
- package/dist/middleware/bearer-auth/index.js +4 -12
- package/dist/middleware/cache/index.d.ts +2 -3
- package/dist/middleware/cache/index.js +1 -5
- package/dist/middleware/compress/index.d.ts +2 -3
- package/dist/middleware/compress/index.js +1 -5
- package/dist/middleware/cors/index.d.ts +3 -4
- package/dist/middleware/cors/index.js +16 -6
- package/dist/middleware/etag/index.d.ts +2 -3
- package/dist/middleware/etag/index.js +3 -7
- package/dist/middleware/html/index.js +6 -11
- package/dist/middleware/jsx/index.js +9 -15
- package/dist/middleware/jsx/jsx-dev-runtime.js +3 -7
- package/dist/middleware/jsx/jsx-runtime.js +2 -7
- package/dist/middleware/jwt/index.d.ts +2 -3
- package/dist/middleware/jwt/index.js +3 -7
- package/dist/middleware/logger/index.d.ts +2 -3
- package/dist/middleware/logger/index.js +3 -7
- package/dist/middleware/powered-by/index.d.ts +2 -3
- package/dist/middleware/powered-by/index.js +1 -5
- package/dist/middleware/pretty-json/index.d.ts +2 -3
- package/dist/middleware/pretty-json/index.js +1 -5
- package/dist/middleware/serve-static/bun.d.ts +2 -3
- package/dist/middleware/serve-static/bun.js +18 -19
- package/dist/middleware/serve-static/index.js +1 -5
- package/dist/middleware/serve-static/module.d.mts +1 -1
- package/dist/middleware/serve-static/serve-static.d.ts +2 -3
- package/dist/middleware/serve-static/serve-static.js +7 -11
- package/dist/middleware/validator/index.d.ts +2 -0
- package/dist/middleware/validator/index.js +2 -0
- package/dist/middleware/validator/middleware.d.ts +21 -0
- package/dist/middleware/validator/middleware.js +52 -0
- package/dist/middleware/validator/rule.d.ts +21 -0
- package/dist/middleware/validator/rule.js +63 -0
- package/dist/middleware/validator/sanitizer.d.ts +3 -0
- package/dist/middleware/validator/sanitizer.js +3 -0
- package/dist/middleware/validator/validator.d.ts +75 -0
- package/dist/middleware/validator/validator.js +186 -0
- package/dist/request.d.ts +15 -5
- package/dist/request.js +58 -28
- package/dist/router/reg-exp-router/index.js +1 -5
- package/dist/router/reg-exp-router/node.d.ts +1 -3
- package/dist/router/reg-exp-router/node.js +21 -17
- package/dist/router/reg-exp-router/router.d.ts +3 -27
- package/dist/router/reg-exp-router/router.js +105 -315
- package/dist/router/reg-exp-router/trie.d.ts +0 -4
- package/dist/router/reg-exp-router/trie.js +4 -8
- package/dist/router/smart-router/index.d.ts +1 -0
- package/dist/router/smart-router/index.js +1 -0
- package/dist/router/smart-router/router.d.ts +9 -0
- package/dist/router/smart-router/router.js +53 -0
- package/dist/router/static-router/index.d.ts +1 -0
- package/dist/router/static-router/index.js +1 -0
- package/dist/router/static-router/router.d.ts +8 -0
- package/dist/router/static-router/router.js +68 -0
- package/dist/router/trie-router/index.js +1 -5
- package/dist/router/trie-router/node.js +7 -11
- package/dist/router/trie-router/router.js +11 -7
- package/dist/router.d.ts +3 -0
- package/dist/router.js +5 -5
- package/dist/utils/body.d.ts +2 -1
- package/dist/utils/body.js +1 -5
- package/dist/utils/buffer.d.ts +1 -1
- package/dist/utils/buffer.js +5 -11
- package/dist/utils/cloudflare.d.ts +1 -1
- package/dist/utils/cloudflare.js +1 -5
- package/dist/utils/cookie.js +2 -7
- package/dist/utils/crypto.js +8 -15
- package/dist/utils/encode.js +10 -20
- package/dist/utils/filepath.js +1 -5
- package/dist/utils/html.js +1 -5
- package/dist/utils/http-status.js +1 -5
- package/dist/utils/json.d.ts +1 -0
- package/dist/utils/json.js +18 -0
- package/dist/utils/jwt/index.js +1 -27
- package/dist/utils/jwt/jwt.js +22 -28
- package/dist/utils/jwt/types.js +8 -16
- package/dist/utils/mime.js +1 -5
- package/dist/utils/url.d.ts +1 -1
- package/dist/utils/url.js +18 -22
- package/package.json +122 -35
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
[](https://github.com/honojs/hono/pulse)
|
|
22
22
|
[](https://github.com/honojs/hono/commits/main)
|
|
23
23
|
[](https://doc.deno.land/https/deno.land/x/hono/mod.ts)
|
|
24
|
-
[](https://discord.gg/
|
|
24
|
+
[](https://discord.gg/KMh2eNSdxV)
|
|
25
25
|
|
|
26
26
|
Hono - _**[炎] means flame🔥 in Japanese**_ - is a small, simple, and ultrafast web framework for Cloudflare Workers, Deno, Bun, and others.
|
|
27
27
|
|
|
@@ -36,24 +36,23 @@ export default app
|
|
|
36
36
|
|
|
37
37
|
## Features
|
|
38
38
|
|
|
39
|
-
- **Ultrafast** -
|
|
40
|
-
- **Zero-dependencies** -
|
|
41
|
-
- **Middleware** - built-in middleware, custom middleware, and third-party middleware.
|
|
42
|
-
- **TypeScript** -
|
|
43
|
-
- **Multi-
|
|
39
|
+
- **Ultrafast** - The routers are really smart. Not using linear loops. The fastest one will be selected from three routers.
|
|
40
|
+
- **Zero-dependencies** - Using only Web Standard API. Does not depend on other npm or Deno libraries.
|
|
41
|
+
- **Middleware** - Hono has built-in middleware, custom middleware, and third-party middleware. Batteries included.
|
|
42
|
+
- **TypeScript** - First-class TypeScript support. Now, we've got "Types".
|
|
43
|
+
- **Multi-runtime** - Works on Cloudflare Workers, Fastly Compute@Edge, Deno, Bun, or Node.js. The same code runs on all platforms.
|
|
44
44
|
|
|
45
45
|
## Benchmarks
|
|
46
46
|
|
|
47
47
|
**Hono is fastest**, compared to other routers for Cloudflare Workers.
|
|
48
48
|
|
|
49
49
|
```plain
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
✨ Done in 36.79s.
|
|
50
|
+
Hono x 616,464 ops/sec ±4.76% (83 runs sampled)
|
|
51
|
+
itty-router x 203,074 ops/sec ±3.66% (88 runs sampled)
|
|
52
|
+
sunder x 314,306 ops/sec ±2.28% (87 runs sampled)
|
|
53
|
+
worktop x 194,111 ops/sec ±2.78% (81 runs sampled)
|
|
54
|
+
Fastest is Hono
|
|
55
|
+
✨ Done in 30.77s.
|
|
57
56
|
```
|
|
58
57
|
|
|
59
58
|
## Documentation
|
|
@@ -66,7 +65,7 @@ Migration guide is available on [docs/MIGRATION.md](docs/MIGRATION.md).
|
|
|
66
65
|
|
|
67
66
|
## Communication
|
|
68
67
|
|
|
69
|
-
[Twitter](https://twitter.com/honojs) and [Discord channel](https://discord.gg/
|
|
68
|
+
[Twitter](https://twitter.com/honojs) and [Discord channel](https://discord.gg/KMh2eNSdxV) are available.
|
|
70
69
|
|
|
71
70
|
## Contributing
|
|
72
71
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compose = void 0;
|
|
4
|
+
const context_1 = require("./context");
|
|
5
|
+
// Based on the code in the MIT licensed `koa-compose` package.
|
|
6
|
+
const compose = (middleware, onNotFound) => {
|
|
7
|
+
const middlewareLength = middleware.length;
|
|
8
|
+
return (context, next) => {
|
|
9
|
+
let index = -1;
|
|
10
|
+
return dispatch(0);
|
|
11
|
+
function dispatch(i) {
|
|
12
|
+
if (i <= index) {
|
|
13
|
+
throw new Error('next() called multiple times');
|
|
14
|
+
}
|
|
15
|
+
let handler = middleware[i];
|
|
16
|
+
index = i;
|
|
17
|
+
if (i === middlewareLength && next)
|
|
18
|
+
handler = next;
|
|
19
|
+
let res;
|
|
20
|
+
if (!handler) {
|
|
21
|
+
if (context instanceof context_1.HonoContext && context.finalized === false && onNotFound) {
|
|
22
|
+
res = onNotFound(context);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
res = handler(context, () => {
|
|
27
|
+
const dispatchRes = dispatch(i + 1);
|
|
28
|
+
return dispatchRes instanceof Promise ? dispatchRes : Promise.resolve(dispatchRes);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (!(res instanceof Promise)) {
|
|
32
|
+
if (res && context.finalized === false) {
|
|
33
|
+
context.res = res;
|
|
34
|
+
}
|
|
35
|
+
return context;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
return res.then((res) => {
|
|
39
|
+
if (res && context.finalized === false) {
|
|
40
|
+
context.res = res;
|
|
41
|
+
}
|
|
42
|
+
return context;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
exports.compose = compose;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HonoContext = void 0;
|
|
4
|
+
const cookie_1 = require("./utils/cookie");
|
|
5
|
+
class HonoContext {
|
|
6
|
+
constructor(req, env = undefined, executionCtx = undefined, notFoundHandler = () => new Response()) {
|
|
7
|
+
this._status = 200;
|
|
8
|
+
this._pretty = false;
|
|
9
|
+
this._prettySpace = 2;
|
|
10
|
+
this._executionCtx = executionCtx;
|
|
11
|
+
this.req = req;
|
|
12
|
+
this.env = env || {};
|
|
13
|
+
this.notFoundHandler = notFoundHandler;
|
|
14
|
+
this.finalized = false;
|
|
15
|
+
}
|
|
16
|
+
get event() {
|
|
17
|
+
if (this._executionCtx instanceof FetchEvent) {
|
|
18
|
+
return this._executionCtx;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
throw Error('This context has no FetchEvent');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
get executionCtx() {
|
|
25
|
+
if (this._executionCtx) {
|
|
26
|
+
return this._executionCtx;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw Error('This context has no ExecutionContext');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
get res() {
|
|
33
|
+
return (this._res || (this._res = new Response('404 Not Found', { status: 404 })));
|
|
34
|
+
}
|
|
35
|
+
set res(_res) {
|
|
36
|
+
this._res = _res;
|
|
37
|
+
this.finalized = true;
|
|
38
|
+
}
|
|
39
|
+
header(name, value, options) {
|
|
40
|
+
this._headers || (this._headers = {});
|
|
41
|
+
const key = name.toLowerCase();
|
|
42
|
+
let shouldAppend = false;
|
|
43
|
+
if (options && options.append) {
|
|
44
|
+
const vAlreadySet = this._headers[key];
|
|
45
|
+
if (vAlreadySet && vAlreadySet.length) {
|
|
46
|
+
shouldAppend = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (shouldAppend) {
|
|
50
|
+
this._headers[key].push(value);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this._headers[key] = [value];
|
|
54
|
+
}
|
|
55
|
+
if (this.finalized) {
|
|
56
|
+
if (shouldAppend) {
|
|
57
|
+
this.res.headers.append(name, value);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.res.headers.set(name, value);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
status(status) {
|
|
65
|
+
this._status = status;
|
|
66
|
+
}
|
|
67
|
+
set(key, value) {
|
|
68
|
+
this._map || (this._map = {});
|
|
69
|
+
this._map[key] = value;
|
|
70
|
+
}
|
|
71
|
+
get(key) {
|
|
72
|
+
if (!this._map) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
return this._map[key];
|
|
76
|
+
}
|
|
77
|
+
pretty(prettyJSON, space = 2) {
|
|
78
|
+
this._pretty = prettyJSON;
|
|
79
|
+
this._prettySpace = space;
|
|
80
|
+
}
|
|
81
|
+
newResponse(data, status, headers = {}) {
|
|
82
|
+
return new Response(data, {
|
|
83
|
+
status: status || this._status || 200,
|
|
84
|
+
headers: this._finalizeHeaders(headers),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
_finalizeHeaders(incomingHeaders) {
|
|
88
|
+
const finalizedHeaders = [];
|
|
89
|
+
const headersKv = this._headers || {};
|
|
90
|
+
// If Response is already set
|
|
91
|
+
if (this._res) {
|
|
92
|
+
this._res.headers.forEach((v, k) => {
|
|
93
|
+
headersKv[k] = [v];
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
for (const key of Object.keys(incomingHeaders)) {
|
|
97
|
+
const value = incomingHeaders[key];
|
|
98
|
+
if (typeof value === 'string') {
|
|
99
|
+
finalizedHeaders.push([key, value]);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
for (const v of value) {
|
|
103
|
+
finalizedHeaders.push([key, v]);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
delete headersKv[key];
|
|
107
|
+
}
|
|
108
|
+
for (const key of Object.keys(headersKv)) {
|
|
109
|
+
for (const value of headersKv[key]) {
|
|
110
|
+
const kv = [key, value];
|
|
111
|
+
finalizedHeaders.push(kv);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return finalizedHeaders;
|
|
115
|
+
}
|
|
116
|
+
body(data, status = this._status, headers = {}) {
|
|
117
|
+
return this.newResponse(data, status, headers);
|
|
118
|
+
}
|
|
119
|
+
text(text, status = this._status, headers = {}) {
|
|
120
|
+
headers['content-type'] = 'text/plain; charset=UTF-8';
|
|
121
|
+
return this.body(text, status, headers);
|
|
122
|
+
}
|
|
123
|
+
json(object, status = this._status, headers = {}) {
|
|
124
|
+
const body = this._pretty
|
|
125
|
+
? JSON.stringify(object, null, this._prettySpace)
|
|
126
|
+
: JSON.stringify(object);
|
|
127
|
+
headers['content-type'] = 'application/json; charset=UTF-8';
|
|
128
|
+
return this.body(body, status, headers);
|
|
129
|
+
}
|
|
130
|
+
html(html, status = this._status, headers = {}) {
|
|
131
|
+
headers['content-type'] = 'text/html; charset=UTF-8';
|
|
132
|
+
return this.body(html, status, headers);
|
|
133
|
+
}
|
|
134
|
+
redirect(location, status = 302) {
|
|
135
|
+
return this.newResponse(null, status, {
|
|
136
|
+
Location: location,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
cookie(name, value, opt) {
|
|
140
|
+
const cookie = (0, cookie_1.serialize)(name, value, opt);
|
|
141
|
+
this.header('set-cookie', cookie, { append: true });
|
|
142
|
+
}
|
|
143
|
+
notFound() {
|
|
144
|
+
return this.notFoundHandler(this);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.HonoContext = HonoContext;
|
package/dist/cjs/hono.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Hono = void 0;
|
|
4
|
+
const compose_1 = require("./compose");
|
|
5
|
+
const context_1 = require("./context");
|
|
6
|
+
const request_1 = require("./request");
|
|
7
|
+
const router_1 = require("./router");
|
|
8
|
+
const router_2 = require("./router");
|
|
9
|
+
const reg_exp_router_1 = require("./router/reg-exp-router");
|
|
10
|
+
const smart_router_1 = require("./router/smart-router");
|
|
11
|
+
const static_router_1 = require("./router/static-router");
|
|
12
|
+
const trie_router_1 = require("./router/trie-router");
|
|
13
|
+
const url_1 = require("./utils/url");
|
|
14
|
+
function defineDynamicClass() {
|
|
15
|
+
return class {
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
class Hono extends defineDynamicClass() {
|
|
19
|
+
constructor(init = {}) {
|
|
20
|
+
super();
|
|
21
|
+
this.router = new smart_router_1.SmartRouter({
|
|
22
|
+
routers: [new static_router_1.StaticRouter(), new reg_exp_router_1.RegExpRouter(), new trie_router_1.TrieRouter()],
|
|
23
|
+
});
|
|
24
|
+
this.strict = true; // strict routing - default is true
|
|
25
|
+
this._tempPath = '';
|
|
26
|
+
this.path = '/';
|
|
27
|
+
this.routes = [];
|
|
28
|
+
this.notFoundHandler = (c) => {
|
|
29
|
+
return c.text('404 Not Found', 404);
|
|
30
|
+
};
|
|
31
|
+
this.errorHandler = (err, c) => {
|
|
32
|
+
console.error(`${err.stack || err.message}`);
|
|
33
|
+
const message = 'Internal Server Error';
|
|
34
|
+
return c.text(message, 500);
|
|
35
|
+
};
|
|
36
|
+
this.fetch = (request, Environment, executionCtx) => {
|
|
37
|
+
return this.dispatch(request, executionCtx, Environment);
|
|
38
|
+
};
|
|
39
|
+
(0, request_1.extendRequestPrototype)();
|
|
40
|
+
const allMethods = [...router_1.METHODS, router_2.METHOD_NAME_ALL_LOWERCASE];
|
|
41
|
+
allMethods.map((method) => {
|
|
42
|
+
this[method] = (args1, ...args) => {
|
|
43
|
+
if (typeof args1 === 'string') {
|
|
44
|
+
this.path = args1;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.addRoute(method, this.path, args1);
|
|
48
|
+
}
|
|
49
|
+
args.map((handler) => {
|
|
50
|
+
if (typeof handler !== 'string') {
|
|
51
|
+
this.addRoute(method, this.path, handler);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return this;
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
Object.assign(this, init);
|
|
58
|
+
}
|
|
59
|
+
route(path, app) {
|
|
60
|
+
this._tempPath = path;
|
|
61
|
+
if (app) {
|
|
62
|
+
app.routes.map((r) => {
|
|
63
|
+
this.addRoute(r.method, r.path, r.handler);
|
|
64
|
+
});
|
|
65
|
+
this._tempPath = '';
|
|
66
|
+
}
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
use(arg1, ...handlers) {
|
|
70
|
+
if (typeof arg1 === 'string') {
|
|
71
|
+
this.path = arg1;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
handlers.unshift(arg1);
|
|
75
|
+
}
|
|
76
|
+
handlers.map((handler) => {
|
|
77
|
+
this.addRoute(router_2.METHOD_NAME_ALL, this.path, handler);
|
|
78
|
+
});
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
onError(handler) {
|
|
82
|
+
this.errorHandler = handler;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
notFound(handler) {
|
|
86
|
+
this.notFoundHandler = handler;
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
addRoute(method, path, handler) {
|
|
90
|
+
method = method.toUpperCase();
|
|
91
|
+
if (this._tempPath) {
|
|
92
|
+
path = (0, url_1.mergePath)(this._tempPath, path);
|
|
93
|
+
}
|
|
94
|
+
this.router.add(method, path, handler);
|
|
95
|
+
const r = { path: path, method: method, handler: handler };
|
|
96
|
+
this.routes.push(r);
|
|
97
|
+
}
|
|
98
|
+
matchRoute(method, path) {
|
|
99
|
+
return this.router.match(method, path);
|
|
100
|
+
}
|
|
101
|
+
async dispatch(request, eventOrExecutionCtx, env) {
|
|
102
|
+
const path = (0, url_1.getPathFromURL)(request.url, this.strict);
|
|
103
|
+
const method = request.method;
|
|
104
|
+
const result = this.matchRoute(method, path);
|
|
105
|
+
request.paramData = result?.params;
|
|
106
|
+
const c = new context_1.HonoContext(request, env, eventOrExecutionCtx, this.notFoundHandler);
|
|
107
|
+
// Do not `compose` if it has only one handler
|
|
108
|
+
if (result && result.handlers.length === 1) {
|
|
109
|
+
const handler = result.handlers[0];
|
|
110
|
+
try {
|
|
111
|
+
const res = handler(c, async () => { });
|
|
112
|
+
if (res) {
|
|
113
|
+
const awaited = res instanceof Promise ? await res : res;
|
|
114
|
+
if (awaited)
|
|
115
|
+
return awaited;
|
|
116
|
+
}
|
|
117
|
+
return this.notFoundHandler(c);
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
if (err instanceof Error) {
|
|
121
|
+
return this.errorHandler(err, c);
|
|
122
|
+
}
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const handlers = result ? result.handlers : [this.notFoundHandler];
|
|
127
|
+
const composed = (0, compose_1.compose)(handlers, this.notFoundHandler);
|
|
128
|
+
let context;
|
|
129
|
+
try {
|
|
130
|
+
const tmp = composed(c);
|
|
131
|
+
context = tmp instanceof Promise ? await tmp : tmp;
|
|
132
|
+
if (!context.finalized) {
|
|
133
|
+
throw new Error('Context is not finalized. You may forget returning Response object or `await next()`');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
if (err instanceof Error) {
|
|
138
|
+
return this.errorHandler(err, c);
|
|
139
|
+
}
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
return context.res;
|
|
143
|
+
}
|
|
144
|
+
handleEvent(event) {
|
|
145
|
+
return this.dispatch(event.request, event);
|
|
146
|
+
}
|
|
147
|
+
request(input, requestInit) {
|
|
148
|
+
const req = input instanceof Request ? input : new Request(input, requestInit);
|
|
149
|
+
return this.dispatch(req);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.Hono = Hono;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// @denoify-ignore
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
4
|
+
/// <reference path="./request.ts" /> Import "declare global" for the Request interface.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Hono = void 0;
|
|
7
|
+
const hono_1 = require("./hono");
|
|
8
|
+
Object.defineProperty(exports, "Hono", { enumerable: true, get: function () { return hono_1.Hono; } });
|
|
9
|
+
hono_1.Hono.prototype.fire = function () {
|
|
10
|
+
addEventListener('fetch', (event) => {
|
|
11
|
+
void event.respondWith(this.handleEvent(event));
|
|
12
|
+
});
|
|
13
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.basicAuth = void 0;
|
|
4
|
+
const buffer_1 = require("../../utils/buffer");
|
|
5
|
+
const encode_1 = require("../../utils/encode");
|
|
6
|
+
const CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/;
|
|
7
|
+
const USER_PASS_REGEXP = /^([^:]*):(.*)$/;
|
|
8
|
+
const auth = (req) => {
|
|
9
|
+
const match = CREDENTIALS_REGEXP.exec(req.headers.get('Authorization') || '');
|
|
10
|
+
if (!match) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const userPass = USER_PASS_REGEXP.exec((0, encode_1.decodeBase64)(match[1]));
|
|
14
|
+
if (!userPass) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
return { username: userPass[1], password: userPass[2] };
|
|
18
|
+
};
|
|
19
|
+
const basicAuth = (options, ...users) => {
|
|
20
|
+
if (!options) {
|
|
21
|
+
throw new Error('basic auth middleware requires options for "username and password"');
|
|
22
|
+
}
|
|
23
|
+
if (!options.realm) {
|
|
24
|
+
options.realm = 'Secure Area';
|
|
25
|
+
}
|
|
26
|
+
users.unshift({ username: options.username, password: options.password });
|
|
27
|
+
return async (ctx, next) => {
|
|
28
|
+
const requestUser = auth(ctx.req);
|
|
29
|
+
if (requestUser) {
|
|
30
|
+
for (const user of users) {
|
|
31
|
+
const usernameEqual = await (0, buffer_1.timingSafeEqual)(user.username, requestUser.username, options.hashFunction);
|
|
32
|
+
const passwordEqual = await (0, buffer_1.timingSafeEqual)(user.password, requestUser.password, options.hashFunction);
|
|
33
|
+
if (usernameEqual && passwordEqual) {
|
|
34
|
+
await next();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
ctx.res = new Response('Unauthorized', {
|
|
40
|
+
status: 401,
|
|
41
|
+
headers: {
|
|
42
|
+
'WWW-Authenticate': 'Basic realm="' + options.realm?.replace(/"/g, '\\"') + '"',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
await next();
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
exports.basicAuth = basicAuth;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bearerAuth = void 0;
|
|
4
|
+
const buffer_1 = require("../../utils/buffer");
|
|
5
|
+
const TOKEN_STRINGS = '[A-Za-z0-9._~+/-]+=*';
|
|
6
|
+
const PREFIX = 'Bearer';
|
|
7
|
+
const bearerAuth = (options) => {
|
|
8
|
+
if (!options.token) {
|
|
9
|
+
throw new Error('bearer auth middleware requires options for "token"');
|
|
10
|
+
}
|
|
11
|
+
if (!options.realm) {
|
|
12
|
+
options.realm = '';
|
|
13
|
+
}
|
|
14
|
+
if (!options.prefix) {
|
|
15
|
+
options.prefix = PREFIX;
|
|
16
|
+
}
|
|
17
|
+
const realm = options.realm?.replace(/"/g, '\\"');
|
|
18
|
+
return async (c, next) => {
|
|
19
|
+
const headerToken = c.req.headers.get('Authorization');
|
|
20
|
+
if (!headerToken) {
|
|
21
|
+
// No Authorization header
|
|
22
|
+
c.res = new Response('Unauthorized', {
|
|
23
|
+
status: 401,
|
|
24
|
+
headers: {
|
|
25
|
+
'WWW-Authenticate': `${options.prefix} realm="` + realm + '"',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const regexp = new RegExp('^' + options.prefix + ' +(' + TOKEN_STRINGS + ') *$');
|
|
31
|
+
const match = regexp.exec(headerToken);
|
|
32
|
+
if (!match) {
|
|
33
|
+
// Invalid Request
|
|
34
|
+
c.res = new Response('Bad Request', {
|
|
35
|
+
status: 400,
|
|
36
|
+
headers: {
|
|
37
|
+
'WWW-Authenticate': `${options.prefix} error="invalid_request"`,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const equal = await (0, buffer_1.timingSafeEqual)(options.token, match[1], options.hashFunction);
|
|
43
|
+
if (!equal) {
|
|
44
|
+
// Invalid Token
|
|
45
|
+
c.res = new Response('Unauthorized', {
|
|
46
|
+
status: 401,
|
|
47
|
+
headers: {
|
|
48
|
+
'WWW-Authenticate': `${options.prefix} error="invalid_token"`,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
await next();
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
exports.bearerAuth = bearerAuth;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cache = void 0;
|
|
4
|
+
const cache = (options) => {
|
|
5
|
+
if (options.wait === undefined) {
|
|
6
|
+
options.wait = false;
|
|
7
|
+
}
|
|
8
|
+
const addHeader = (response) => {
|
|
9
|
+
if (options.cacheControl)
|
|
10
|
+
response.headers.append('Cache-Control', options.cacheControl);
|
|
11
|
+
};
|
|
12
|
+
return async (c, next) => {
|
|
13
|
+
const key = c.req;
|
|
14
|
+
const cache = await caches.open(options.cacheName);
|
|
15
|
+
const response = await cache.match(key);
|
|
16
|
+
if (!response) {
|
|
17
|
+
await next();
|
|
18
|
+
addHeader(c.res);
|
|
19
|
+
const response = c.res.clone();
|
|
20
|
+
if (options.wait) {
|
|
21
|
+
await cache.put(key, response);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
c.executionCtx.waitUntil(cache.put(key, response));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return response;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
exports.cache = cache;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compress = void 0;
|
|
4
|
+
const compress = (options) => {
|
|
5
|
+
return async (ctx, next) => {
|
|
6
|
+
await next();
|
|
7
|
+
const accepted = ctx.req.headers.get('Accept-Encoding');
|
|
8
|
+
const pattern = options?.encoding ?? /gzip|deflate/;
|
|
9
|
+
const match = accepted?.match(pattern);
|
|
10
|
+
if (!accepted || !match || !ctx.res.body) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const encoding = match[0];
|
|
14
|
+
const stream = new CompressionStream(encoding);
|
|
15
|
+
ctx.res = new Response(ctx.res.body.pipeThrough(stream), ctx.res.clone());
|
|
16
|
+
ctx.res.headers.set('Content-Encoding', encoding);
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
exports.compress = compress;
|
|
@@ -0,0 +1,75 @@
|
|
|
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 = {
|
|
12
|
+
...defaults,
|
|
13
|
+
...options,
|
|
14
|
+
};
|
|
15
|
+
const findAllowOrigin = ((optsOrigin) => {
|
|
16
|
+
if (typeof optsOrigin === 'string') {
|
|
17
|
+
return () => optsOrigin;
|
|
18
|
+
}
|
|
19
|
+
else if (typeof optsOrigin === 'function') {
|
|
20
|
+
return optsOrigin;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return (origin) => (optsOrigin.includes(origin) ? origin : optsOrigin[0]);
|
|
24
|
+
}
|
|
25
|
+
})(opts.origin);
|
|
26
|
+
return async (c, next) => {
|
|
27
|
+
await next();
|
|
28
|
+
function set(key, value) {
|
|
29
|
+
c.res.headers.append(key, value);
|
|
30
|
+
}
|
|
31
|
+
const allowOrigin = findAllowOrigin(c.req.headers.get('origin') || '');
|
|
32
|
+
if (allowOrigin) {
|
|
33
|
+
set('Access-Control-Allow-Origin', allowOrigin);
|
|
34
|
+
}
|
|
35
|
+
// Suppose the server sends a response with an Access-Control-Allow-Origin value with an explicit origin (rather than the "*" wildcard).
|
|
36
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
|
37
|
+
if (opts.origin !== '*') {
|
|
38
|
+
set('Vary', 'Origin');
|
|
39
|
+
}
|
|
40
|
+
if (opts.credentials) {
|
|
41
|
+
set('Access-Control-Allow-Credentials', 'true');
|
|
42
|
+
}
|
|
43
|
+
if (opts.exposeHeaders?.length) {
|
|
44
|
+
set('Access-Control-Expose-Headers', opts.exposeHeaders.join(','));
|
|
45
|
+
}
|
|
46
|
+
if (c.req.method === 'OPTIONS') {
|
|
47
|
+
// Preflight
|
|
48
|
+
if (opts.maxAge != null) {
|
|
49
|
+
set('Access-Control-Max-Age', opts.maxAge.toString());
|
|
50
|
+
}
|
|
51
|
+
if (opts.allowMethods?.length) {
|
|
52
|
+
set('Access-Control-Allow-Methods', opts.allowMethods.join(','));
|
|
53
|
+
}
|
|
54
|
+
let headers = opts.allowHeaders;
|
|
55
|
+
if (!headers?.length) {
|
|
56
|
+
const requestHeaders = c.req.headers.get('Access-Control-Request-Headers');
|
|
57
|
+
if (requestHeaders) {
|
|
58
|
+
headers = requestHeaders.split(/\s*,\s*/);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (headers?.length) {
|
|
62
|
+
set('Access-Control-Allow-Headers', headers.join(','));
|
|
63
|
+
set('Vary', 'Access-Control-Request-Headers');
|
|
64
|
+
}
|
|
65
|
+
c.res.headers.delete('Content-Length');
|
|
66
|
+
c.res.headers.delete('Content-Type');
|
|
67
|
+
c.res = new Response(null, {
|
|
68
|
+
headers: c.res.headers,
|
|
69
|
+
status: 204,
|
|
70
|
+
statusText: c.res.statusText,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
exports.cors = cors;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.etag = void 0;
|
|
4
|
+
const crypto_1 = require("../../utils/crypto");
|
|
5
|
+
const etag = (options = { weak: false }) => {
|
|
6
|
+
return async (c, next) => {
|
|
7
|
+
const ifNoneMatch = c.req.header('If-None-Match') || c.req.header('if-none-match');
|
|
8
|
+
await next();
|
|
9
|
+
const res = c.res;
|
|
10
|
+
const clone = res.clone();
|
|
11
|
+
const hash = await (0, crypto_1.sha1)(res.body || '');
|
|
12
|
+
const etag = options.weak ? `W/"${hash}"` : `"${hash}"`;
|
|
13
|
+
if (ifNoneMatch && ifNoneMatch === etag) {
|
|
14
|
+
await clone.blob(); // Force using body
|
|
15
|
+
c.res = new Response(null, {
|
|
16
|
+
status: 304,
|
|
17
|
+
statusText: 'Not Modified',
|
|
18
|
+
});
|
|
19
|
+
c.res.headers.delete('Content-Length');
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
c.res = new Response(clone.body, clone);
|
|
23
|
+
c.res.headers.append('ETag', etag);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
exports.etag = etag;
|