hono 0.0.14 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -33
- package/dist/context.d.ts +8 -1
- package/dist/context.js +17 -3
- package/dist/hono.d.ts +2 -1
- package/dist/hono.js +3 -3
- package/dist/middleware/basic-auth/basic-auth.js +3 -3
- package/dist/middleware/cookie/cookie.d.ts +23 -0
- package/dist/middleware/cookie/cookie.js +34 -0
- package/dist/middleware/cors/cors.d.ts +11 -0
- package/dist/middleware/cors/cors.js +56 -0
- package/dist/middleware/default.js +12 -2
- 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 +1 -1
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Fastest is hono
|
|
|
35
35
|
|
|
36
36
|
Below is a demonstration to create an application of Cloudflare Workers with Hono.
|
|
37
37
|
|
|
38
|
-

|
|
39
39
|
|
|
40
40
|
## Install
|
|
41
41
|
|
|
@@ -90,7 +90,7 @@ app.all('/hello', (c) => c.text('Any Method /hello'))
|
|
|
90
90
|
|
|
91
91
|
```js
|
|
92
92
|
app.get('/user/:name', (c) => {
|
|
93
|
-
const name = c.req.
|
|
93
|
+
const name = c.req.param('name')
|
|
94
94
|
...
|
|
95
95
|
})
|
|
96
96
|
```
|
|
@@ -99,8 +99,8 @@ app.get('/user/:name', (c) => {
|
|
|
99
99
|
|
|
100
100
|
```js
|
|
101
101
|
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
|
|
102
|
-
const date = c.req.
|
|
103
|
-
const title = c.req.
|
|
102
|
+
const date = c.req.param('date')
|
|
103
|
+
const title = c.req.param('title')
|
|
104
104
|
...
|
|
105
105
|
```
|
|
106
106
|
|
|
@@ -219,13 +219,18 @@ To handle Request and Reponse easily, you can use Context object:
|
|
|
219
219
|
### c.req
|
|
220
220
|
|
|
221
221
|
```js
|
|
222
|
-
|
|
223
222
|
// Get Request object
|
|
224
223
|
app.get('/hello', (c) => {
|
|
225
224
|
const userAgent = c.req.headers.get('User-Agent')
|
|
226
225
|
...
|
|
227
226
|
})
|
|
228
227
|
|
|
228
|
+
// Shortcut to get a header value
|
|
229
|
+
app.get('/shortcut', (c) => {
|
|
230
|
+
const userAgent = c.req.header('User-Agent')
|
|
231
|
+
...
|
|
232
|
+
})
|
|
233
|
+
|
|
229
234
|
// Query params
|
|
230
235
|
app.get('/search', (c) => {
|
|
231
236
|
const query = c.req.query('q')
|
|
@@ -234,40 +239,31 @@ app.get('/search', (c) => {
|
|
|
234
239
|
|
|
235
240
|
// Captured params
|
|
236
241
|
app.get('/entry/:id', (c) => {
|
|
237
|
-
const id = c.req.
|
|
242
|
+
const id = c.req.param('id')
|
|
238
243
|
...
|
|
239
244
|
})
|
|
240
245
|
```
|
|
241
246
|
|
|
242
|
-
###
|
|
243
|
-
|
|
244
|
-
```js
|
|
245
|
-
// Response object
|
|
246
|
-
app.use('/', (c, next) => {
|
|
247
|
-
next()
|
|
248
|
-
c.res.headers.append('X-Debug', 'Debug message')
|
|
249
|
-
})
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### c.event
|
|
253
|
-
|
|
254
|
-
```js
|
|
255
|
-
// FetchEvent object
|
|
256
|
-
app.use('*', async (c, next) => {
|
|
257
|
-
c.event.waitUntil(
|
|
258
|
-
...
|
|
259
|
-
)
|
|
260
|
-
await next()
|
|
261
|
-
})
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### c.env
|
|
247
|
+
### Shortcuts for Response
|
|
265
248
|
|
|
266
249
|
```js
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
250
|
+
app.get('/welcome', (c) => {
|
|
251
|
+
c.header('X-Message', 'Hello!')
|
|
252
|
+
c.header('Content-Type', 'text/plain')
|
|
253
|
+
c.status(201)
|
|
254
|
+
c.statusText('201 Content Created')
|
|
255
|
+
return c.body('Thank you for comming')
|
|
256
|
+
/*
|
|
257
|
+
Same as:
|
|
258
|
+
return new Response('Thank you for comming', {
|
|
259
|
+
status: 201,
|
|
260
|
+
statusText: '201 Content Created',
|
|
261
|
+
headers: {
|
|
262
|
+
'X-Message': 'Hello',
|
|
263
|
+
'Content-Type': 'text/plain'
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
*/
|
|
271
267
|
})
|
|
272
268
|
```
|
|
273
269
|
|
|
@@ -310,6 +306,38 @@ app.get('/redirect', (c) => c.redirect('/'))
|
|
|
310
306
|
app.get('/redirect-permanently', (c) => c.redirect('/', 301))
|
|
311
307
|
```
|
|
312
308
|
|
|
309
|
+
### c.res
|
|
310
|
+
|
|
311
|
+
```js
|
|
312
|
+
// Response object
|
|
313
|
+
app.use('/', (c, next) => {
|
|
314
|
+
next()
|
|
315
|
+
c.res.headers.append('X-Debug', 'Debug message')
|
|
316
|
+
})
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### c.event
|
|
320
|
+
|
|
321
|
+
```js
|
|
322
|
+
// FetchEvent object
|
|
323
|
+
app.use('*', async (c, next) => {
|
|
324
|
+
c.event.waitUntil(
|
|
325
|
+
...
|
|
326
|
+
)
|
|
327
|
+
await next()
|
|
328
|
+
})
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### c.env
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
// Environment object for Cloudflare Workers
|
|
335
|
+
app.get('*', async c => {
|
|
336
|
+
const counter = c.env.COUNTER
|
|
337
|
+
...
|
|
338
|
+
})
|
|
339
|
+
```
|
|
340
|
+
|
|
313
341
|
## fire
|
|
314
342
|
|
|
315
343
|
`app.fire()` do:
|
package/dist/context.d.ts
CHANGED
|
@@ -9,12 +9,19 @@ export declare class Context {
|
|
|
9
9
|
res: Response;
|
|
10
10
|
env: Env;
|
|
11
11
|
event: FetchEvent;
|
|
12
|
+
private _headers;
|
|
13
|
+
private _status;
|
|
14
|
+
private _statusText;
|
|
15
|
+
body: (body: BodyInit, init?: ResponseInit) => Response;
|
|
12
16
|
constructor(req: Request, opts?: {
|
|
13
17
|
res: Response;
|
|
14
18
|
env: Env;
|
|
15
19
|
event: FetchEvent;
|
|
16
20
|
});
|
|
17
|
-
|
|
21
|
+
header(name: string, value: string): void;
|
|
22
|
+
status(number: number): void;
|
|
23
|
+
statusText(text: string): void;
|
|
24
|
+
newResponse(body: BodyInit, init?: ResponseInit): Response;
|
|
18
25
|
text(text: string, status?: number, headers?: Headers): Response;
|
|
19
26
|
json(object: object, status?: number, headers?: Headers): Response;
|
|
20
27
|
html(html: string, status?: number, headers?: Headers): Response;
|
package/dist/context.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Context = void 0;
|
|
4
|
-
const
|
|
4
|
+
const url_1 = require("./utils/url");
|
|
5
5
|
class Context {
|
|
6
6
|
constructor(req, opts) {
|
|
7
7
|
this.req = req;
|
|
@@ -10,8 +10,22 @@ class Context {
|
|
|
10
10
|
this.env = opts.env;
|
|
11
11
|
this.event = opts.event;
|
|
12
12
|
}
|
|
13
|
+
this._headers = {};
|
|
14
|
+
this.body = this.newResponse;
|
|
13
15
|
}
|
|
14
|
-
|
|
16
|
+
header(name, value) {
|
|
17
|
+
this._headers[name] = value;
|
|
18
|
+
}
|
|
19
|
+
status(number) {
|
|
20
|
+
this._status = number;
|
|
21
|
+
}
|
|
22
|
+
statusText(text) {
|
|
23
|
+
this._statusText = text;
|
|
24
|
+
}
|
|
25
|
+
newResponse(body, init = {}) {
|
|
26
|
+
init.status = this._status || init.status;
|
|
27
|
+
init.statusText = this._statusText || init.statusText;
|
|
28
|
+
init.headers = Object.assign(Object.assign({}, init.headers), this._headers);
|
|
15
29
|
return new Response(body, init);
|
|
16
30
|
}
|
|
17
31
|
text(text, status = 200, headers = {}) {
|
|
@@ -49,7 +63,7 @@ class Context {
|
|
|
49
63
|
if (typeof location !== 'string') {
|
|
50
64
|
throw new TypeError('location must be a string!');
|
|
51
65
|
}
|
|
52
|
-
if (!(0,
|
|
66
|
+
if (!(0, url_1.isAbsoluteURL)(location)) {
|
|
53
67
|
const url = new URL(this.req.url);
|
|
54
68
|
url.pathname = location;
|
|
55
69
|
location = url.toString();
|
package/dist/hono.d.ts
CHANGED
|
@@ -5,8 +5,9 @@ import { Context } from './context';
|
|
|
5
5
|
import type { Env } from './context';
|
|
6
6
|
declare global {
|
|
7
7
|
interface Request {
|
|
8
|
-
|
|
8
|
+
param: (key: string) => string;
|
|
9
9
|
query: (key: string) => string | null;
|
|
10
|
+
header: (name: string) => string;
|
|
10
11
|
parsedBody: any;
|
|
11
12
|
}
|
|
12
13
|
}
|
package/dist/hono.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Hono = exports.Router = void 0;
|
|
4
4
|
const node_1 = require("./node");
|
|
5
5
|
const compose_1 = require("./compose");
|
|
6
|
-
const
|
|
6
|
+
const url_1 = require("./utils/url");
|
|
7
7
|
const middleware_1 = require("./middleware");
|
|
8
8
|
const context_1 = require("./context");
|
|
9
9
|
const METHOD_NAME_OF_ALL = 'ALL';
|
|
@@ -94,9 +94,9 @@ class Hono {
|
|
|
94
94
|
return this.router.match(method, path);
|
|
95
95
|
}
|
|
96
96
|
async dispatch(request, env, event) {
|
|
97
|
-
const [method, path] = [request.method, (0,
|
|
97
|
+
const [method, path] = [request.method, (0, url_1.getPathFromURL)(request.url)];
|
|
98
98
|
const result = await this.matchRoute(method, path);
|
|
99
|
-
request.
|
|
99
|
+
request.param = (key) => {
|
|
100
100
|
if (result) {
|
|
101
101
|
return result.params[key];
|
|
102
102
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.basicAuth = void 0;
|
|
4
|
-
const
|
|
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,23 @@
|
|
|
1
|
+
import type { Context } from '../../context';
|
|
2
|
+
declare global {
|
|
3
|
+
interface Request {
|
|
4
|
+
cookie: (name: string) => string;
|
|
5
|
+
}
|
|
6
|
+
interface Response {
|
|
7
|
+
cookie: (name: string, value: string, options?: CookieOptions) => void;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export declare type Cookie = {
|
|
11
|
+
[key: string]: string;
|
|
12
|
+
};
|
|
13
|
+
export declare type CookieOptions = {
|
|
14
|
+
domain?: string;
|
|
15
|
+
expires?: Date;
|
|
16
|
+
httpOnly?: boolean;
|
|
17
|
+
maxAge?: number;
|
|
18
|
+
path?: string;
|
|
19
|
+
secure?: boolean;
|
|
20
|
+
signed?: boolean;
|
|
21
|
+
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
22
|
+
};
|
|
23
|
+
export declare const cookie: () => (c: Context, next: Function) => Promise<void>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cookie = void 0;
|
|
4
|
+
const cookie = () => {
|
|
5
|
+
return async (c, next) => {
|
|
6
|
+
c.req.cookie = (name) => {
|
|
7
|
+
const cookie = c.req.headers.get('Cookie');
|
|
8
|
+
const obj = parse(cookie);
|
|
9
|
+
const value = obj[name];
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
await next();
|
|
13
|
+
c.res.cookie = (name, value, options) => {
|
|
14
|
+
console.log('c.res.cookie!');
|
|
15
|
+
const cookie = serialize(name, value);
|
|
16
|
+
c.res.headers.set('Set-Cookie', cookie);
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
exports.cookie = cookie;
|
|
21
|
+
const parse = (cookie) => {
|
|
22
|
+
const pairs = cookie.split(/;\s*/g);
|
|
23
|
+
const parsedCookie = {};
|
|
24
|
+
for (let i = 0, len = pairs.length; i < len; i++) {
|
|
25
|
+
const pair = pairs[i].split(/\s*=\s*([^\s]+)/);
|
|
26
|
+
parsedCookie[pair[0]] = decodeURIComponent(pair[1]);
|
|
27
|
+
}
|
|
28
|
+
return parsedCookie;
|
|
29
|
+
};
|
|
30
|
+
const serialize = (name, value, options = {}) => {
|
|
31
|
+
value = encodeURIComponent(value);
|
|
32
|
+
const cookie = `${name}=${value}`;
|
|
33
|
+
return cookie;
|
|
34
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context } from '../../context';
|
|
2
|
+
declare type CORSOptions = {
|
|
3
|
+
origin: string;
|
|
4
|
+
allowMethods?: string[];
|
|
5
|
+
allowHeaders?: string[];
|
|
6
|
+
maxAge?: number;
|
|
7
|
+
credentials?: boolean;
|
|
8
|
+
exposeHeaders?: string[];
|
|
9
|
+
};
|
|
10
|
+
export declare const cors: (options?: CORSOptions) => (c: Context, next: Function) => Promise<void>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cors = void 0;
|
|
4
|
+
const cors = (options) => {
|
|
5
|
+
const defaults = {
|
|
6
|
+
origin: '*',
|
|
7
|
+
allowMethods: ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH'],
|
|
8
|
+
allowHeaders: [],
|
|
9
|
+
exposeHeaders: [],
|
|
10
|
+
};
|
|
11
|
+
const opts = Object.assign(Object.assign({}, defaults), options);
|
|
12
|
+
return async (c, next) => {
|
|
13
|
+
await next();
|
|
14
|
+
function set(key, value) {
|
|
15
|
+
c.res.headers.append(key, value);
|
|
16
|
+
}
|
|
17
|
+
set('Access-Control-Allow-Origin', opts.origin);
|
|
18
|
+
// Suppose the server sends a response with an Access-Control-Allow-Origin value with an explicit origin (rather than the "*" wildcard).
|
|
19
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
|
20
|
+
if (opts.origin !== '*') {
|
|
21
|
+
set('Vary', 'Origin');
|
|
22
|
+
}
|
|
23
|
+
if (opts.credentials) {
|
|
24
|
+
set('Access-Control-Allow-Credentials', 'true');
|
|
25
|
+
}
|
|
26
|
+
if (opts.exposeHeaders.length) {
|
|
27
|
+
set('Access-Control-Expose-Headers', opts.exposeHeaders.join(','));
|
|
28
|
+
}
|
|
29
|
+
if (c.req.method === 'OPTIONS') {
|
|
30
|
+
// Preflight
|
|
31
|
+
if (opts.maxAge != null) {
|
|
32
|
+
set('Access-Control-Max-Age', opts.maxAge.toString());
|
|
33
|
+
}
|
|
34
|
+
if (opts.allowMethods.length) {
|
|
35
|
+
set('Access-Control-Allow-Methods', opts.allowMethods.join(','));
|
|
36
|
+
}
|
|
37
|
+
let headers = opts.allowHeaders;
|
|
38
|
+
if (!headers.length) {
|
|
39
|
+
const requestHeaders = c.req.headers.get('Access-Control-Request-Headers');
|
|
40
|
+
if (requestHeaders) {
|
|
41
|
+
headers = requestHeaders.split(/\s*,\s*/);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (headers.length) {
|
|
45
|
+
set('Access-Control-Allow-Headers', headers.join(','));
|
|
46
|
+
set('Vary', 'Access-Control-Request-Headers');
|
|
47
|
+
}
|
|
48
|
+
c.res = new Response(null, {
|
|
49
|
+
headers: c.res.headers,
|
|
50
|
+
status: 204,
|
|
51
|
+
statusText: c.res.statusText,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
exports.cors = cors;
|
|
@@ -7,10 +7,20 @@ const defaultMiddleware = async (c, next) => {
|
|
|
7
7
|
const url = new URL(c.req.url);
|
|
8
8
|
return url.searchParams.get(key);
|
|
9
9
|
};
|
|
10
|
+
c.req.header = (name) => {
|
|
11
|
+
return c.req.headers.get(name);
|
|
12
|
+
};
|
|
10
13
|
await next();
|
|
11
14
|
if (c.res.body) {
|
|
12
|
-
|
|
13
|
-
c.res.
|
|
15
|
+
// Do not clone Response, ex: c.res.clone().arrayBuffer()
|
|
16
|
+
const buffer = await c.res.arrayBuffer();
|
|
17
|
+
const res = new Response(buffer, {
|
|
18
|
+
status: c.res.status,
|
|
19
|
+
statusText: c.res.statusText,
|
|
20
|
+
headers: c.res.headers,
|
|
21
|
+
});
|
|
22
|
+
res.headers.append('Content-Length', buffer.byteLength.toString());
|
|
23
|
+
c.res = res;
|
|
14
24
|
}
|
|
15
25
|
};
|
|
16
26
|
exports.defaultMiddleware = defaultMiddleware;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.logger = void 0;
|
|
4
|
-
const
|
|
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;
|