hono 1.3.6 → 1.4.2
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 +76 -20
- package/dist/compose.d.ts +1 -1
- package/dist/compose.js +7 -8
- package/dist/context.d.ts +7 -7
- package/dist/context.js +16 -11
- package/dist/hono.d.ts +6 -10
- package/dist/hono.js +8 -11
- package/dist/middleware/basic-auth/index.js +3 -2
- package/dist/middleware/cookie/index.js +1 -1
- package/dist/middleware/cors/index.d.ts +1 -1
- package/dist/middleware/cors/index.js +5 -4
- package/dist/middleware/etag/index.js +3 -2
- package/dist/middleware/graphql-server/index.d.ts +2 -2
- package/dist/middleware/graphql-server/index.js +18 -23
- package/dist/middleware/jwt/index.js +3 -1
- package/dist/middleware/serve-static/serve-static.d.ts +2 -1
- package/dist/middleware/serve-static/serve-static.js +2 -1
- package/dist/response.d.ts +25 -0
- package/dist/response.js +35 -0
- package/dist/router/reg-exp-router/router.d.ts +10 -4
- package/dist/router/reg-exp-router/router.js +45 -14
- package/dist/router/reg-exp-router/trie.js +2 -0
- package/dist/router/trie-router/node.d.ts +12 -5
- package/dist/router/trie-router/node.js +41 -24
- package/dist/router/trie-router/router.d.ts +3 -4
- package/dist/router/trie-router/router.js +1 -3
- package/dist/router.d.ts +4 -5
- package/dist/router.js +1 -11
- package/dist/utils/body.js +1 -0
- package/dist/utils/buffer.d.ts +1 -1
- package/dist/utils/cloudflare.d.ts +1 -1
- package/dist/utils/cloudflare.js +1 -1
- package/dist/utils/crypto.d.ts +3 -3
- package/dist/utils/crypto.js +1 -0
- package/dist/utils/encode.js +1 -0
- package/dist/utils/mime.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,13 +38,13 @@ app.fire()
|
|
|
38
38
|
**Hono is fastest**, compared to other routers for Cloudflare Workers.
|
|
39
39
|
|
|
40
40
|
```plain
|
|
41
|
-
hono - trie-router(default) x
|
|
42
|
-
hono - regexp-router x 1,
|
|
43
|
-
itty-router x
|
|
44
|
-
sunder x
|
|
45
|
-
worktop x
|
|
41
|
+
hono - trie-router(default) x 724,143 ops/sec ±3.63% (80 runs sampled)
|
|
42
|
+
hono - regexp-router x 1,236,810 ops/sec ±6.77% (72 runs sampled)
|
|
43
|
+
itty-router x 161,786 ops/sec ±2.28% (97 runs sampled)
|
|
44
|
+
sunder x 312,262 ops/sec ±2.59% (85 runs sampled)
|
|
45
|
+
worktop x 224,979 ops/sec ±1.13% (96 runs sampled)
|
|
46
46
|
Fastest is hono - regexp-router
|
|
47
|
-
✨ Done in
|
|
47
|
+
✨ Done in 95.05s.
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
## Why so fast?
|
|
@@ -137,15 +137,15 @@ npm install hono
|
|
|
137
137
|
|
|
138
138
|
An instance of `Hono` has these methods.
|
|
139
139
|
|
|
140
|
-
- app.**HTTP_METHOD**(\[
|
|
141
|
-
- app.**all**(\[
|
|
142
|
-
- app.**route**(
|
|
143
|
-
- app.**use**(\[
|
|
140
|
+
- app.**HTTP_METHOD**(\[path,\]handler|middleware...)
|
|
141
|
+
- app.**all**(\[path,\]handler|middleware...)
|
|
142
|
+
- app.**route**(path, \[app\])
|
|
143
|
+
- app.**use**(\[path,\]middleware)
|
|
144
144
|
- app.**notFound**(handler)
|
|
145
145
|
- app.**onError**(err, handler)
|
|
146
146
|
- app.**fire**()
|
|
147
147
|
- app.**fetch**(request, env, event)
|
|
148
|
-
- app.**request**(
|
|
148
|
+
- app.**request**(path, options)
|
|
149
149
|
|
|
150
150
|
## Routing
|
|
151
151
|
|
|
@@ -249,12 +249,37 @@ app.route('/book', book)
|
|
|
249
249
|
|
|
250
250
|
## Middleware
|
|
251
251
|
|
|
252
|
-
Middleware
|
|
252
|
+
Middleware works after/before Handler. We can get `Request` before dispatching or manipulate `Response` after dispatching.
|
|
253
253
|
|
|
254
254
|
### Definition of Middleware
|
|
255
255
|
|
|
256
|
-
- Handler - should return `Response` object.
|
|
257
|
-
- Middleware - should return nothing,
|
|
256
|
+
- Handler - should return `Response` object. Only one handler will be called.
|
|
257
|
+
- Middleware - should return nothing, will be proceeded to next middleware with `await next()`
|
|
258
|
+
|
|
259
|
+
The user can register middleware using `c.use` or using `c.HTTP_METHOD` as well as the handlers. For this feature, it's easy to specify the path and the method.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
// match any method, all routes
|
|
263
|
+
app.use('*', logger())
|
|
264
|
+
|
|
265
|
+
// specify path
|
|
266
|
+
app.use('/posts/*', cors())
|
|
267
|
+
|
|
268
|
+
// specify method and path
|
|
269
|
+
app.post('/posts/*', basicAuth(), bodyParse())
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
If the handler returns `Response`, it will be used for the end-user, and stopping the processing.
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
app.post('/posts', (c) => c.text('Created!', 201))
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
In this case, four middleware are processed before dispatching like this:
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
logger() -> cors() -> basicAuth() -> bodyParse() -> *handler*
|
|
282
|
+
```
|
|
258
283
|
|
|
259
284
|
### Built-in Middleware
|
|
260
285
|
|
|
@@ -390,7 +415,6 @@ The Response is the same as below.
|
|
|
390
415
|
```ts
|
|
391
416
|
new Response('Thank you for comming', {
|
|
392
417
|
status: 201,
|
|
393
|
-
statusText: 'Created',
|
|
394
418
|
headers: {
|
|
395
419
|
'X-Message': 'Hello',
|
|
396
420
|
'Content-Type': 'text/plain',
|
|
@@ -518,14 +542,47 @@ test('GET /hello is ok', async () => {
|
|
|
518
542
|
})
|
|
519
543
|
```
|
|
520
544
|
|
|
521
|
-
##
|
|
545
|
+
## router
|
|
522
546
|
|
|
523
|
-
The `
|
|
547
|
+
The `router` option specify which router is used inside. The default router is `TrieRouter`. If you want to use `RexExpRouter`, write like this:
|
|
524
548
|
|
|
525
549
|
```ts
|
|
526
550
|
import { RegExpRouter } from 'hono/router/reg-exp-router'
|
|
527
551
|
|
|
528
|
-
const app = new Hono({
|
|
552
|
+
const app = new Hono({ router: new RegExpRouter() })
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
## Routing Ordering
|
|
556
|
+
|
|
557
|
+
The routing priority is decided by the order of registration. Only one handler will be dispatched.
|
|
558
|
+
|
|
559
|
+
```ts
|
|
560
|
+
app.get('/book/a', (c) => c.text('a')) // a
|
|
561
|
+
app.get('/book/:slug', (c) => c.text('common')) // common
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
```http
|
|
565
|
+
GET /book/a ---> `a` // common will not be dispatched
|
|
566
|
+
GET /book/b ---> `common` // a will not be dispatched
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
All scoring rules:
|
|
570
|
+
|
|
571
|
+
```ts
|
|
572
|
+
app.get('/api/*', 'c') // score 1.1 <--- `/*` is special wildcard
|
|
573
|
+
app.get('/api/:type/:id', 'd') // score 3.2
|
|
574
|
+
app.get('/api/posts/:id', 'e') // score 3.3
|
|
575
|
+
app.get('/api/posts/123', 'f') // score 3.4
|
|
576
|
+
app.get('/*/*/:id', 'g') // score 3.5
|
|
577
|
+
app.get('/api/posts/*/comment', 'h') // score 4.6 - not match
|
|
578
|
+
app.get('*', 'a') // score 0.7
|
|
579
|
+
app.get('*', 'b') // score 0.8
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
```plain
|
|
583
|
+
GET /api/posts/123
|
|
584
|
+
---> will match => c, d, e, f, b, a, b
|
|
585
|
+
---> sort by score => a, b, c, d, e, f, g
|
|
529
586
|
```
|
|
530
587
|
|
|
531
588
|
## Cloudflare Workers with Hono
|
|
@@ -615,6 +672,7 @@ export interface Bindings {
|
|
|
615
672
|
}
|
|
616
673
|
|
|
617
674
|
const api = new Hono<Bindings>()
|
|
675
|
+
api.use('/posts/*', cors())
|
|
618
676
|
|
|
619
677
|
api.get('/posts', (c) => {
|
|
620
678
|
const { limit, offset } = c.req.query()
|
|
@@ -641,8 +699,6 @@ api.post(
|
|
|
641
699
|
}
|
|
642
700
|
)
|
|
643
701
|
|
|
644
|
-
app.use('/posts/*', cors())
|
|
645
|
-
|
|
646
702
|
app.route('/api', api)
|
|
647
703
|
|
|
648
704
|
export default app
|
package/dist/compose.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ErrorHandler, NotFoundHandler } from './hono';
|
|
2
|
-
export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler, onNotFound?: NotFoundHandler) => (context: C, next?: Function) => Promise<C>;
|
|
2
|
+
export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler<import("./context").Env> | undefined, onNotFound?: NotFoundHandler<import("./context").Env> | undefined) => (context: C, next?: Function | undefined) => Promise<C>;
|
package/dist/compose.js
CHANGED
|
@@ -13,12 +13,12 @@ const compose = (middleware, onError, onNotFound) => {
|
|
|
13
13
|
}
|
|
14
14
|
let handler = middleware[i];
|
|
15
15
|
index = i;
|
|
16
|
-
if (i === middleware.length)
|
|
16
|
+
if (i === middleware.length && next)
|
|
17
17
|
handler = next;
|
|
18
|
-
if (handler
|
|
19
|
-
if (context instanceof context_1.Context && context.res.
|
|
18
|
+
if (!handler) {
|
|
19
|
+
if (context instanceof context_1.Context && context.res._finalized === false && onNotFound) {
|
|
20
20
|
context.res = onNotFound(context);
|
|
21
|
-
context.res.
|
|
21
|
+
context.res._finalized = true;
|
|
22
22
|
}
|
|
23
23
|
return Promise.resolve(context);
|
|
24
24
|
}
|
|
@@ -27,16 +27,15 @@ const compose = (middleware, onError, onNotFound) => {
|
|
|
27
27
|
// If handler return Response like `return c.text('foo')`
|
|
28
28
|
if (res && context instanceof context_1.Context) {
|
|
29
29
|
context.res = res;
|
|
30
|
-
context.res.
|
|
31
|
-
await dispatch(i + 1); // <--- Call next()
|
|
30
|
+
context.res._finalized = true;
|
|
32
31
|
}
|
|
33
32
|
return context;
|
|
34
33
|
})
|
|
35
34
|
.catch((err) => {
|
|
36
|
-
if (
|
|
35
|
+
if (context instanceof context_1.Context && onError) {
|
|
37
36
|
if (err instanceof Error) {
|
|
38
37
|
context.res = onError(err, context);
|
|
39
|
-
context.res.
|
|
38
|
+
context.res._finalized = true;
|
|
40
39
|
}
|
|
41
40
|
return context;
|
|
42
41
|
}
|
package/dist/context.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
+
import { HonoResponse } from './response';
|
|
2
3
|
import type { StatusCode } from './utils/http-status';
|
|
3
4
|
declare type Headers = Record<string, string>;
|
|
4
|
-
declare type Data = string | ArrayBuffer | ReadableStream;
|
|
5
|
+
export declare type Data = string | ArrayBuffer | ReadableStream;
|
|
5
6
|
export declare type Env = Record<string, any>;
|
|
6
7
|
export declare class Context<RequestParamKeyType extends string = string, E = Env> {
|
|
7
8
|
req: Request<RequestParamKeyType>;
|
|
8
9
|
res: Response;
|
|
9
10
|
env: E;
|
|
10
|
-
event: FetchEvent;
|
|
11
|
-
private _headers;
|
|
11
|
+
event: FetchEvent | undefined;
|
|
12
12
|
private _status;
|
|
13
13
|
private _pretty;
|
|
14
14
|
private _prettySpace;
|
|
@@ -16,9 +16,9 @@ export declare class Context<RequestParamKeyType extends string = string, E = En
|
|
|
16
16
|
render: (template: string, params?: object, options?: object) => Promise<Response>;
|
|
17
17
|
notFound: () => Response | Promise<Response>;
|
|
18
18
|
constructor(req: Request<RequestParamKeyType>, opts?: {
|
|
19
|
-
env
|
|
20
|
-
event
|
|
21
|
-
res?: Response;
|
|
19
|
+
env?: Env;
|
|
20
|
+
event?: FetchEvent;
|
|
21
|
+
res?: Response | HonoResponse;
|
|
22
22
|
});
|
|
23
23
|
private initRequest;
|
|
24
24
|
header(name: string, value: string): void;
|
|
@@ -26,7 +26,7 @@ export declare class Context<RequestParamKeyType extends string = string, E = En
|
|
|
26
26
|
set(key: string, value: any): void;
|
|
27
27
|
get(key: string): any;
|
|
28
28
|
pretty(prettyJSON: boolean, space?: number): void;
|
|
29
|
-
newResponse(data: Data, init?: ResponseInit): Response;
|
|
29
|
+
newResponse(data: Data | null, init?: ResponseInit): Response;
|
|
30
30
|
body(data: Data | null, status?: StatusCode, headers?: Headers): Response;
|
|
31
31
|
text(text: string, status?: StatusCode, headers?: Headers): Response;
|
|
32
32
|
json(object: object, status?: StatusCode, headers?: Headers): Response;
|
package/dist/context.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Context = void 0;
|
|
4
|
+
const response_1 = require("./response");
|
|
4
5
|
const url_1 = require("./utils/url");
|
|
5
6
|
class Context {
|
|
6
|
-
constructor(req, opts
|
|
7
|
-
|
|
7
|
+
constructor(req, opts = {
|
|
8
|
+
env: {},
|
|
9
|
+
event: undefined,
|
|
10
|
+
res: undefined,
|
|
11
|
+
}) {
|
|
8
12
|
this._status = 200;
|
|
9
13
|
this._pretty = false;
|
|
10
14
|
this._prettySpace = 2;
|
|
@@ -12,8 +16,8 @@ class Context {
|
|
|
12
16
|
this._map = {};
|
|
13
17
|
Object.assign(this, opts);
|
|
14
18
|
if (!this.res) {
|
|
15
|
-
const res = new
|
|
16
|
-
res.
|
|
19
|
+
const res = new response_1.HonoResponse(null, { status: 404 });
|
|
20
|
+
res._finalized = false;
|
|
17
21
|
this.res = res;
|
|
18
22
|
}
|
|
19
23
|
}
|
|
@@ -38,7 +42,7 @@ class Context {
|
|
|
38
42
|
else {
|
|
39
43
|
const result = {};
|
|
40
44
|
for (const key of url.searchParams.keys()) {
|
|
41
|
-
result[key] = url.searchParams.get(key);
|
|
45
|
+
result[key] = url.searchParams.get(key) || '';
|
|
42
46
|
}
|
|
43
47
|
return result;
|
|
44
48
|
}
|
|
@@ -59,10 +63,7 @@ class Context {
|
|
|
59
63
|
return req;
|
|
60
64
|
}
|
|
61
65
|
header(name, value) {
|
|
62
|
-
|
|
63
|
-
this.res.headers.set(name, value);
|
|
64
|
-
}
|
|
65
|
-
this._headers[name] = value;
|
|
66
|
+
this.res.headers.set(name, value);
|
|
66
67
|
}
|
|
67
68
|
status(status) {
|
|
68
69
|
this._status = status;
|
|
@@ -79,10 +80,14 @@ class Context {
|
|
|
79
80
|
}
|
|
80
81
|
newResponse(data, init = {}) {
|
|
81
82
|
init.status = init.status || this._status || 200;
|
|
82
|
-
|
|
83
|
+
const headers = {};
|
|
84
|
+
this.res.headers.forEach((v, k) => {
|
|
85
|
+
headers[k] = v;
|
|
86
|
+
});
|
|
87
|
+
init.headers = Object.assign(headers, init.headers);
|
|
83
88
|
return new Response(data, init);
|
|
84
89
|
}
|
|
85
|
-
body(data, status = this._status, headers =
|
|
90
|
+
body(data, status = this._status, headers = {}) {
|
|
86
91
|
return this.newResponse(data, {
|
|
87
92
|
status: status,
|
|
88
93
|
headers: headers,
|
package/dist/hono.d.ts
CHANGED
|
@@ -22,10 +22,10 @@ declare global {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
interface Response {
|
|
25
|
-
|
|
25
|
+
_finalized: boolean;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
export declare type Handler<RequestParamKeyType extends string = string, E = Env> = (c: Context<RequestParamKeyType, E>, next: Next) => Response | Promise<Response> | void | Promise<
|
|
28
|
+
export declare type Handler<RequestParamKeyType extends string = string, E = Env> = (c: Context<RequestParamKeyType, E>, next: Next) => Response | Promise<Response> | Promise<void> | Promise<Response | undefined>;
|
|
29
29
|
export declare type NotFoundHandler<E = Env> = (c: Context<string, E>) => Response;
|
|
30
30
|
export declare type ErrorHandler<E = Env> = (err: Error, c: Context<string, E>) => Response;
|
|
31
31
|
export declare type Next = () => Promise<void>;
|
|
@@ -44,26 +44,22 @@ interface Route<E extends Env> {
|
|
|
44
44
|
handler: Handler<string, E>;
|
|
45
45
|
}
|
|
46
46
|
declare const Hono_base: new <E_1 extends Env, T extends string, U>() => {
|
|
47
|
-
delete: HandlerInterface<T, E_1, U>;
|
|
48
|
-
get: HandlerInterface<T, E_1, U>;
|
|
49
47
|
all: HandlerInterface<T, E_1, U>;
|
|
48
|
+
get: HandlerInterface<T, E_1, U>;
|
|
50
49
|
post: HandlerInterface<T, E_1, U>;
|
|
51
50
|
put: HandlerInterface<T, E_1, U>;
|
|
51
|
+
delete: HandlerInterface<T, E_1, U>;
|
|
52
52
|
head: HandlerInterface<T, E_1, U>;
|
|
53
53
|
options: HandlerInterface<T, E_1, U>;
|
|
54
54
|
patch: HandlerInterface<T, E_1, U>;
|
|
55
55
|
};
|
|
56
56
|
export declare class Hono<E = Env, P extends string = '/'> extends Hono_base<E, P, Hono<E, P>> {
|
|
57
|
-
readonly
|
|
58
|
-
new (): Router<any>;
|
|
59
|
-
};
|
|
57
|
+
readonly router: Router<Handler<string, E>>;
|
|
60
58
|
readonly strict: boolean;
|
|
61
|
-
private _router;
|
|
62
59
|
private _tempPath;
|
|
63
60
|
private path;
|
|
64
|
-
private _cacheResponse;
|
|
65
61
|
routes: Route<E>[];
|
|
66
|
-
constructor(init?: Partial<Pick<Hono, '
|
|
62
|
+
constructor(init?: Partial<Pick<Hono, 'router' | 'strict'>>);
|
|
67
63
|
private notFoundHandler;
|
|
68
64
|
private errorHandler;
|
|
69
65
|
route(path: string, app?: Hono<any>): Hono<E, P>;
|
package/dist/hono.js
CHANGED
|
@@ -4,7 +4,6 @@ exports.Hono = void 0;
|
|
|
4
4
|
const compose_1 = require("./compose");
|
|
5
5
|
const context_1 = require("./context");
|
|
6
6
|
const router_1 = require("./router");
|
|
7
|
-
const router_2 = require("./router");
|
|
8
7
|
const trie_router_1 = require("./router/trie-router"); // Default Router
|
|
9
8
|
const url_1 = require("./utils/url");
|
|
10
9
|
const methods = ['get', 'post', 'put', 'delete', 'head', 'options', 'patch'];
|
|
@@ -15,8 +14,9 @@ function defineDynamicClass() {
|
|
|
15
14
|
class Hono extends defineDynamicClass() {
|
|
16
15
|
constructor(init = {}) {
|
|
17
16
|
super();
|
|
18
|
-
this.
|
|
17
|
+
this.router = new trie_router_1.TrieRouter();
|
|
19
18
|
this.strict = true; // strict routing - default is true
|
|
19
|
+
this._tempPath = '';
|
|
20
20
|
this.path = '/';
|
|
21
21
|
this.routes = [];
|
|
22
22
|
this.notFoundHandler = (c) => {
|
|
@@ -28,7 +28,7 @@ class Hono extends defineDynamicClass() {
|
|
|
28
28
|
const message = 'Internal Server Error';
|
|
29
29
|
return c.text(message, 500);
|
|
30
30
|
};
|
|
31
|
-
const allMethods = [...methods,
|
|
31
|
+
const allMethods = [...methods, router_1.METHOD_NAME_ALL_LOWERCASE];
|
|
32
32
|
allMethods.map((method) => {
|
|
33
33
|
this[method] = (args1, ...args) => {
|
|
34
34
|
if (typeof args1 === 'string') {
|
|
@@ -46,10 +46,6 @@ class Hono extends defineDynamicClass() {
|
|
|
46
46
|
};
|
|
47
47
|
});
|
|
48
48
|
Object.assign(this, init);
|
|
49
|
-
this._router = new this.routerClass();
|
|
50
|
-
this._tempPath = null;
|
|
51
|
-
this._cacheResponse = new Response(null, { status: 404 });
|
|
52
|
-
this._cacheResponse.finalized = false;
|
|
53
49
|
}
|
|
54
50
|
route(path, app) {
|
|
55
51
|
this._tempPath = path;
|
|
@@ -57,7 +53,7 @@ class Hono extends defineDynamicClass() {
|
|
|
57
53
|
app.routes.map((r) => {
|
|
58
54
|
this.addRoute(r.method, r.path, r.handler);
|
|
59
55
|
});
|
|
60
|
-
this._tempPath =
|
|
56
|
+
this._tempPath = '';
|
|
61
57
|
}
|
|
62
58
|
return this;
|
|
63
59
|
}
|
|
@@ -86,12 +82,12 @@ class Hono extends defineDynamicClass() {
|
|
|
86
82
|
if (this._tempPath) {
|
|
87
83
|
path = (0, url_1.mergePath)(this._tempPath, path);
|
|
88
84
|
}
|
|
89
|
-
this.
|
|
85
|
+
this.router.add(method, path, handler);
|
|
90
86
|
const r = { path: path, method: method, handler: handler };
|
|
91
87
|
this.routes.push(r);
|
|
92
88
|
}
|
|
93
89
|
async matchRoute(method, path) {
|
|
94
|
-
return this.
|
|
90
|
+
return this.router.match(method, path);
|
|
95
91
|
}
|
|
96
92
|
async dispatch(request, event, env) {
|
|
97
93
|
const path = (0, url_1.getPathFromURL)(request.url, { strict: this.strict });
|
|
@@ -106,12 +102,12 @@ class Hono extends defineDynamicClass() {
|
|
|
106
102
|
return result.params;
|
|
107
103
|
}
|
|
108
104
|
}
|
|
105
|
+
return null;
|
|
109
106
|
});
|
|
110
107
|
const handlers = result ? result.handlers : [this.notFoundHandler];
|
|
111
108
|
const c = new context_1.Context(request, {
|
|
112
109
|
env: env,
|
|
113
110
|
event: event,
|
|
114
|
-
res: this._cacheResponse,
|
|
115
111
|
});
|
|
116
112
|
c.notFound = () => this.notFoundHandler(c);
|
|
117
113
|
const composed = (0, compose_1.compose)(handlers, this.errorHandler, this.notFoundHandler);
|
|
@@ -123,6 +119,7 @@ class Hono extends defineDynamicClass() {
|
|
|
123
119
|
if (err instanceof Error) {
|
|
124
120
|
return this.errorHandler(err, c);
|
|
125
121
|
}
|
|
122
|
+
throw err;
|
|
126
123
|
}
|
|
127
124
|
if (!context.res)
|
|
128
125
|
return context.notFound();
|
|
@@ -15,7 +15,7 @@ const auth = (req) => {
|
|
|
15
15
|
if (!req.headers || typeof req.headers !== 'object') {
|
|
16
16
|
throw new TypeError('argument req is required to have headers property');
|
|
17
17
|
}
|
|
18
|
-
const match = CREDENTIALS_REGEXP.exec(req.headers.get('Authorization'));
|
|
18
|
+
const match = CREDENTIALS_REGEXP.exec(req.headers.get('Authorization') || '');
|
|
19
19
|
if (!match) {
|
|
20
20
|
return undefined;
|
|
21
21
|
}
|
|
@@ -34,6 +34,7 @@ const basicAuth = (options, ...users) => {
|
|
|
34
34
|
}
|
|
35
35
|
users.unshift({ username: options.username, password: options.password });
|
|
36
36
|
return async (ctx, next) => {
|
|
37
|
+
var _a;
|
|
37
38
|
const requestUser = auth(ctx.req);
|
|
38
39
|
if (requestUser) {
|
|
39
40
|
for (const user of users) {
|
|
@@ -49,7 +50,7 @@ const basicAuth = (options, ...users) => {
|
|
|
49
50
|
ctx.res = new Response('Unauthorized', {
|
|
50
51
|
status: 401,
|
|
51
52
|
headers: {
|
|
52
|
-
'WWW-Authenticate': 'Basic realm="' + options.realm.replace(/"/g, '\\"') + '"',
|
|
53
|
+
'WWW-Authenticate': 'Basic realm="' + ((_a = options.realm) === null || _a === void 0 ? void 0 : _a.replace(/"/g, '\\"')) + '"',
|
|
53
54
|
},
|
|
54
55
|
});
|
|
55
56
|
};
|
|
@@ -4,7 +4,7 @@ exports.cookie = void 0;
|
|
|
4
4
|
const cookie = () => {
|
|
5
5
|
return async (c, next) => {
|
|
6
6
|
c.req.cookie = ((name) => {
|
|
7
|
-
const cookie = c.req.headers.get('Cookie');
|
|
7
|
+
const cookie = c.req.headers.get('Cookie') || '';
|
|
8
8
|
const obj = parse(cookie);
|
|
9
9
|
if (name) {
|
|
10
10
|
const value = obj[name];
|
|
@@ -8,5 +8,5 @@ declare type CORSOptions = {
|
|
|
8
8
|
credentials?: boolean;
|
|
9
9
|
exposeHeaders?: string[];
|
|
10
10
|
};
|
|
11
|
-
export declare const cors: (options?: CORSOptions) => (c: Context, next: Next) => Promise<void>;
|
|
11
|
+
export declare const cors: (options?: CORSOptions | undefined) => (c: Context, next: Next) => Promise<void>;
|
|
12
12
|
export {};
|
|
@@ -10,6 +10,7 @@ const cors = (options) => {
|
|
|
10
10
|
};
|
|
11
11
|
const opts = Object.assign(Object.assign({}, defaults), options);
|
|
12
12
|
return async (c, next) => {
|
|
13
|
+
var _a, _b;
|
|
13
14
|
await next();
|
|
14
15
|
function set(key, value) {
|
|
15
16
|
c.res.headers.append(key, value);
|
|
@@ -23,7 +24,7 @@ const cors = (options) => {
|
|
|
23
24
|
if (opts.credentials) {
|
|
24
25
|
set('Access-Control-Allow-Credentials', 'true');
|
|
25
26
|
}
|
|
26
|
-
if (opts.exposeHeaders.length) {
|
|
27
|
+
if ((_a = opts.exposeHeaders) === null || _a === void 0 ? void 0 : _a.length) {
|
|
27
28
|
set('Access-Control-Expose-Headers', opts.exposeHeaders.join(','));
|
|
28
29
|
}
|
|
29
30
|
if (c.req.method === 'OPTIONS') {
|
|
@@ -31,17 +32,17 @@ const cors = (options) => {
|
|
|
31
32
|
if (opts.maxAge != null) {
|
|
32
33
|
set('Access-Control-Max-Age', opts.maxAge.toString());
|
|
33
34
|
}
|
|
34
|
-
if (opts.allowMethods.length) {
|
|
35
|
+
if ((_b = opts.allowMethods) === null || _b === void 0 ? void 0 : _b.length) {
|
|
35
36
|
set('Access-Control-Allow-Methods', opts.allowMethods.join(','));
|
|
36
37
|
}
|
|
37
38
|
let headers = opts.allowHeaders;
|
|
38
|
-
if (!headers.length) {
|
|
39
|
+
if (!(headers === null || headers === void 0 ? void 0 : headers.length)) {
|
|
39
40
|
const requestHeaders = c.req.headers.get('Access-Control-Request-Headers');
|
|
40
41
|
if (requestHeaders) {
|
|
41
42
|
headers = requestHeaders.split(/\s*,\s*/);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
|
-
if (headers.length) {
|
|
45
|
+
if (headers === null || headers === void 0 ? void 0 : headers.length) {
|
|
45
46
|
set('Access-Control-Allow-Headers', headers.join(','));
|
|
46
47
|
set('Vary', 'Access-Control-Request-Headers');
|
|
47
48
|
}
|
|
@@ -7,8 +7,9 @@ const etag = (options = { weak: false }) => {
|
|
|
7
7
|
return async (c, next) => {
|
|
8
8
|
const ifNoneMatch = c.req.header('If-None-Match') || c.req.header('if-none-match');
|
|
9
9
|
await next();
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
const res = c.res;
|
|
11
|
+
const clone = res.clone();
|
|
12
|
+
const body = await (0, body_1.parseBody)(res);
|
|
12
13
|
const hash = await (0, crypto_1.sha1)(body);
|
|
13
14
|
const etag = options.weak ? `W/"${hash}"` : `"${hash}"`;
|
|
14
15
|
if (ifNoneMatch && ifNoneMatch === etag) {
|
|
@@ -8,7 +8,7 @@ declare type Options = {
|
|
|
8
8
|
pretty?: boolean;
|
|
9
9
|
validationRules?: ReadonlyArray<ValidationRule>;
|
|
10
10
|
};
|
|
11
|
-
export declare const graphqlServer: (options: Options) => (c: Context, next: Next) => Promise<
|
|
11
|
+
export declare const graphqlServer: (options: Options) => (c: Context, next: Next) => Promise<Response>;
|
|
12
12
|
export interface GraphQLParams {
|
|
13
13
|
query: string | null;
|
|
14
14
|
variables: {
|
|
@@ -18,7 +18,7 @@ export interface GraphQLParams {
|
|
|
18
18
|
raw: boolean;
|
|
19
19
|
}
|
|
20
20
|
export declare const getGraphQLParams: (request: Request) => Promise<GraphQLParams>;
|
|
21
|
-
export declare const errorMessages: (messages: string[], graphqlErrors?: readonly GraphQLError[] | readonly GraphQLFormattedError[]) => {
|
|
21
|
+
export declare const errorMessages: (messages: string[], graphqlErrors?: readonly GraphQLError[] | readonly GraphQLFormattedError[] | undefined) => {
|
|
22
22
|
errors: readonly GraphQLError[] | readonly GraphQLFormattedError[];
|
|
23
23
|
} | {
|
|
24
24
|
errors: {
|
|
@@ -13,13 +13,11 @@ const graphqlServer = (options) => {
|
|
|
13
13
|
const validationRules = (_b = options.validationRules) !== null && _b !== void 0 ? _b : [];
|
|
14
14
|
// const showGraphiQL = options.graphiql ?? false
|
|
15
15
|
return async (c, next) => {
|
|
16
|
-
await next();
|
|
17
16
|
// GraphQL HTTP only supports GET and POST methods.
|
|
18
17
|
if (c.req.method !== 'GET' && c.req.method !== 'POST') {
|
|
19
|
-
|
|
18
|
+
return c.json((0, exports.errorMessages)(['GraphQL only supports GET and POST requests.']), 405, {
|
|
20
19
|
Allow: 'GET, POST',
|
|
21
20
|
});
|
|
22
|
-
return;
|
|
23
21
|
}
|
|
24
22
|
let params;
|
|
25
23
|
try {
|
|
@@ -28,20 +26,18 @@ const graphqlServer = (options) => {
|
|
|
28
26
|
catch (e) {
|
|
29
27
|
if (e instanceof Error) {
|
|
30
28
|
console.error(`${e.stack || e.message}`);
|
|
31
|
-
|
|
29
|
+
return c.json((0, exports.errorMessages)([e.message], [e]), 400);
|
|
32
30
|
}
|
|
33
|
-
|
|
31
|
+
throw e;
|
|
34
32
|
}
|
|
35
33
|
const { query, variables, operationName } = params;
|
|
36
34
|
if (query == null) {
|
|
37
|
-
|
|
38
|
-
return;
|
|
35
|
+
return c.json((0, exports.errorMessages)(['Must provide query string.']), 400);
|
|
39
36
|
}
|
|
40
37
|
const schemaValidationErrors = (0, graphql_1.validateSchema)(schema);
|
|
41
38
|
if (schemaValidationErrors.length > 0) {
|
|
42
39
|
// Return 500: Internal Server Error if invalid schema.
|
|
43
|
-
|
|
44
|
-
return;
|
|
40
|
+
return c.json((0, exports.errorMessages)(['GraphQL schema validation error.'], schemaValidationErrors), 500);
|
|
45
41
|
}
|
|
46
42
|
let documentAST;
|
|
47
43
|
try {
|
|
@@ -54,16 +50,15 @@ const graphqlServer = (options) => {
|
|
|
54
50
|
const e = new graphql_1.GraphQLError(syntaxError.message, {
|
|
55
51
|
originalError: syntaxError,
|
|
56
52
|
});
|
|
57
|
-
|
|
53
|
+
return c.json((0, exports.errorMessages)(['GraphQL syntax error.'], [e]), 400);
|
|
58
54
|
}
|
|
59
|
-
|
|
55
|
+
throw syntaxError;
|
|
60
56
|
}
|
|
61
57
|
// Validate AST, reporting any errors.
|
|
62
58
|
const validationErrors = (0, graphql_1.validate)(schema, documentAST, [...graphql_1.specifiedRules, ...validationRules]);
|
|
63
59
|
if (validationErrors.length > 0) {
|
|
64
60
|
// Return 400: Bad Request if any validation errors exist.
|
|
65
|
-
|
|
66
|
-
return;
|
|
61
|
+
return c.json((0, exports.errorMessages)(['GraphQL validation error.'], validationErrors), 400);
|
|
67
62
|
}
|
|
68
63
|
if (c.req.method === 'GET') {
|
|
69
64
|
// Determine if this GET request will perform a non-query.
|
|
@@ -76,10 +71,9 @@ const graphqlServer = (options) => {
|
|
|
76
71
|
}
|
|
77
72
|
*/
|
|
78
73
|
// Otherwise, report a 405: Method Not Allowed error.
|
|
79
|
-
|
|
74
|
+
return c.json((0, exports.errorMessages)([
|
|
80
75
|
`Can only perform a ${operationAST.operation} operation from a POST request.`,
|
|
81
76
|
]), 405, { Allow: 'POST' });
|
|
82
|
-
return;
|
|
83
77
|
}
|
|
84
78
|
}
|
|
85
79
|
let result;
|
|
@@ -100,13 +94,14 @@ const graphqlServer = (options) => {
|
|
|
100
94
|
nodes: documentAST,
|
|
101
95
|
});
|
|
102
96
|
// Return 400: Bad Request if any execution context errors exist.
|
|
103
|
-
|
|
97
|
+
return c.json((0, exports.errorMessages)(['GraphQL execution context error.'], [e]), 400);
|
|
104
98
|
}
|
|
105
|
-
|
|
99
|
+
throw contextError;
|
|
106
100
|
}
|
|
107
|
-
if (result.data
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
if (!result.data) {
|
|
102
|
+
if (result.errors) {
|
|
103
|
+
return c.json((0, exports.errorMessages)([result.errors.toString()], result.errors), 500);
|
|
104
|
+
}
|
|
110
105
|
}
|
|
111
106
|
/*
|
|
112
107
|
Now, does not support GraphiQL
|
|
@@ -115,14 +110,14 @@ const graphqlServer = (options) => {
|
|
|
115
110
|
*/
|
|
116
111
|
if (pretty) {
|
|
117
112
|
const payload = JSON.stringify(result, null, pretty ? 2 : 0);
|
|
118
|
-
|
|
113
|
+
return c.text(payload, 200, {
|
|
119
114
|
'Content-Type': 'application/json',
|
|
120
115
|
});
|
|
121
116
|
}
|
|
122
117
|
else {
|
|
123
|
-
|
|
118
|
+
return c.json(result);
|
|
124
119
|
}
|
|
125
|
-
|
|
120
|
+
await next(); // XXX
|
|
126
121
|
};
|
|
127
122
|
};
|
|
128
123
|
exports.graphqlServer = graphqlServer;
|