hono 1.4.3 → 1.4.6
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 +3 -0
- package/dist/compose.js +1 -1
- package/dist/context.d.ts +3 -2
- package/dist/hono.d.ts +1 -1
- package/dist/hono.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/middleware/bearer-auth/index.d.ts +8 -0
- package/dist/middleware/bearer-auth/index.js +61 -0
- package/dist/middleware/jsx/index.d.ts +17 -0
- package/dist/middleware/jsx/index.js +84 -0
- package/dist/middleware/jwt/index.js +2 -2
- package/dist/middleware/mustache/Context.d.ts +3 -0
- package/dist/middleware/mustache/Context.js +2 -0
- package/dist/middleware/mustache/module.d.mts +1 -1
- package/dist/middleware/mustache/mustache.d.ts +3 -2
- package/dist/utils/crypto.d.ts +1 -0
- package/dist/utils/crypto.js +7 -1
- package/dist/utils/html.d.ts +1 -0
- package/dist/utils/html.js +15 -0
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -73,6 +73,7 @@ Built-in middleware make _"**Write Less, do more**"_ in reality. You can use a l
|
|
|
73
73
|
- [CORS](https://github.com/honojs/hono/tree/master/src/middleware/cors/)
|
|
74
74
|
- [ETag](https://github.com/honojs/hono/tree/master/src/middleware/etag/)
|
|
75
75
|
- [GraphQL Server](https://github.com/honojs/hono/tree/master/src/middleware/graphql-server/)
|
|
76
|
+
- [JSX](https://github.com/honojs/hono/tree/master/src/middleware/jsx/)
|
|
76
77
|
- [JWT Authentication](https://github.com/honojs/hono/tree/master/src/middleware/jwt/)
|
|
77
78
|
- [Logger](https://github.com/honojs/hono/tree/master/src/middleware/logger/)
|
|
78
79
|
- [Mustache template engine](https://github.com/honojs/hono/tree/master/src/middleware/mustache/) (Only for Cloudflare Workers)
|
|
@@ -495,6 +496,8 @@ app.get('/foo', async (c) => {
|
|
|
495
496
|
|
|
496
497
|
### c.env
|
|
497
498
|
|
|
499
|
+
Environment variables, secrets, and KV namespaces are known as bindings. Regardless of type, bindings are always available as global variables and can be accessed via the context `c.env.BINDING_KEY`.
|
|
500
|
+
|
|
498
501
|
```ts
|
|
499
502
|
// Environment object for Cloudflare Workers
|
|
500
503
|
app.get('*', async c => {
|
package/dist/compose.js
CHANGED
|
@@ -17,7 +17,7 @@ const compose = (middleware, onError, onNotFound) => {
|
|
|
17
17
|
handler = next;
|
|
18
18
|
if (!handler) {
|
|
19
19
|
if (context instanceof context_1.Context && context.finalized === false && onNotFound) {
|
|
20
|
-
context.res = onNotFound(context);
|
|
20
|
+
context.res = await onNotFound(context);
|
|
21
21
|
}
|
|
22
22
|
return Promise.resolve(context);
|
|
23
23
|
}
|
package/dist/context.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
+
import type { NotFoundHandler } from './hono';
|
|
2
3
|
import type { StatusCode } from './utils/http-status';
|
|
3
4
|
declare type Headers = Record<string, string>;
|
|
4
5
|
export declare type Data = string | ArrayBuffer | ReadableStream;
|
|
@@ -15,8 +16,8 @@ export declare class Context<RequestParamKeyType extends string = string, E = En
|
|
|
15
16
|
private _headers;
|
|
16
17
|
private _res;
|
|
17
18
|
private notFoundHandler;
|
|
18
|
-
render: (
|
|
19
|
-
constructor(req: Request<RequestParamKeyType>, env?: E | undefined, event?: FetchEvent | undefined, notFoundHandler?:
|
|
19
|
+
render: (content: string, params?: object, options?: object) => Response | Promise<Response>;
|
|
20
|
+
constructor(req: Request<RequestParamKeyType>, env?: E | undefined, event?: FetchEvent | undefined, notFoundHandler?: NotFoundHandler);
|
|
20
21
|
get res(): Response;
|
|
21
22
|
set res(_res: Response);
|
|
22
23
|
header(name: string, value: string): void;
|
package/dist/hono.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Context } from './context';
|
|
|
3
3
|
import type { Env } from './context';
|
|
4
4
|
import type { Router } from './router';
|
|
5
5
|
export declare type Handler<RequestParamKeyType extends string = string, E = Env> = (c: Context<RequestParamKeyType, E>, next: Next) => Response | Promise<Response> | Promise<void> | Promise<Response | undefined>;
|
|
6
|
-
export declare type NotFoundHandler<E = Env> = (c: Context<string, E>) => Response
|
|
6
|
+
export declare type NotFoundHandler<E = Env> = (c: Context<string, E>) => Response | Promise<Response>;
|
|
7
7
|
export declare type ErrorHandler<E = Env> = (err: Error, c: Context<string, E>) => Response;
|
|
8
8
|
export declare type Next = () => Promise<void>;
|
|
9
9
|
declare type ParamKeyName<NameWithPattern> = NameWithPattern extends `${infer Name}{${infer _Pattern}` ? Name : NameWithPattern;
|
package/dist/hono.js
CHANGED
|
@@ -102,6 +102,9 @@ class Hono extends defineDynamicClass() {
|
|
|
102
102
|
let context;
|
|
103
103
|
try {
|
|
104
104
|
context = await composed(c);
|
|
105
|
+
if (!context.finalized) {
|
|
106
|
+
throw new Error('Context is not finalized. You may forget returning Response object or `await next()`');
|
|
107
|
+
}
|
|
105
108
|
}
|
|
106
109
|
catch (err) {
|
|
107
110
|
if (err instanceof Error) {
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
3
|
+
/// <reference path="./request.ts" /> Import "declare global" for the Request interface.
|
|
2
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
5
|
exports.Context = exports.Hono = void 0;
|
|
4
6
|
var hono_1 = require("./hono");
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context } from '../../context';
|
|
2
|
+
import type { Next } from '../../hono';
|
|
3
|
+
export declare const bearerAuth: (options: {
|
|
4
|
+
token: string;
|
|
5
|
+
realm?: string;
|
|
6
|
+
prefix?: string;
|
|
7
|
+
hashFunction?: Function;
|
|
8
|
+
}) => (c: Context, next: Next) => Promise<void>;
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
else {
|
|
53
|
+
// Authorize OK
|
|
54
|
+
await next();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
exports.bearerAuth = bearerAuth;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Context } from '../../context';
|
|
2
|
+
import type { Next } from '../../hono';
|
|
3
|
+
declare global {
|
|
4
|
+
namespace h.JSX {
|
|
5
|
+
interface IntrinsicElements {
|
|
6
|
+
[tagName: string]: Record<string, any>;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export declare const jsx: () => (c: Context, next: Next) => Promise<void>;
|
|
11
|
+
declare type EscapedString = string & {
|
|
12
|
+
isEscaped: true;
|
|
13
|
+
};
|
|
14
|
+
export declare const h: (tag: string | Function, props: Record<string, any>, ...children: (string | EscapedString)[]) => EscapedString;
|
|
15
|
+
declare type FC<T = Record<string, any>> = (props: T) => EscapedString;
|
|
16
|
+
export declare const memo: <T>(component: FC<T>, propsAreEqual?: (prevProps: Readonly<T>, nextProps: Readonly<T>) => boolean) => FC<T>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.memo = exports.h = exports.jsx = void 0;
|
|
4
|
+
const html_1 = require("../../utils/html");
|
|
5
|
+
const jsx = () => {
|
|
6
|
+
return async (c, next) => {
|
|
7
|
+
c.render = (content) => {
|
|
8
|
+
const output = `<!doctype html>${content.toString()}`;
|
|
9
|
+
return c.html(output);
|
|
10
|
+
};
|
|
11
|
+
await next();
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
exports.jsx = jsx;
|
|
15
|
+
const h = (tag, props, ...children) => {
|
|
16
|
+
if (typeof tag === 'function') {
|
|
17
|
+
return tag.call(null, { ...props, children: children.length <= 1 ? children[0] : children });
|
|
18
|
+
}
|
|
19
|
+
let result = `<${tag}`;
|
|
20
|
+
const propsKeys = Object.keys(props || {});
|
|
21
|
+
for (let i = 0, len = propsKeys.length; i < len; i++) {
|
|
22
|
+
const v = props[propsKeys[i]];
|
|
23
|
+
if (propsKeys[i] === 'dangerouslySetInnerHTML') {
|
|
24
|
+
if (children.length > 0) {
|
|
25
|
+
throw 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.';
|
|
26
|
+
}
|
|
27
|
+
const escapedString = new String(v.__html);
|
|
28
|
+
escapedString.isEscaped = true;
|
|
29
|
+
children = [escapedString];
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
else if (v === null || v === undefined) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
result += ` ${propsKeys[i]}="${(0, html_1.escape)(v.toString())}"`;
|
|
36
|
+
}
|
|
37
|
+
result += '>';
|
|
38
|
+
const flattenChildren = children.flat(Infinity);
|
|
39
|
+
for (let i = 0, len = flattenChildren.length; i < len; i++) {
|
|
40
|
+
const child = flattenChildren[i];
|
|
41
|
+
if (typeof child === 'boolean' || child === null || child === undefined) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
else if (typeof child === 'object' && child.isEscaped) {
|
|
45
|
+
result += child;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
result += (0, html_1.escape)(child.toString());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
result += `</${tag}>`;
|
|
52
|
+
const escapedString = new String(result);
|
|
53
|
+
escapedString.isEscaped = true;
|
|
54
|
+
return escapedString;
|
|
55
|
+
};
|
|
56
|
+
exports.h = h;
|
|
57
|
+
const shallowEqual = (a, b) => {
|
|
58
|
+
if (a === b) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
const aKeys = Object.keys(a);
|
|
62
|
+
const bKeys = Object.keys(b);
|
|
63
|
+
if (aKeys.length !== bKeys.length) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
for (let i = 0, len = aKeys.length; i < len; i++) {
|
|
67
|
+
if (a[aKeys[i]] !== b[aKeys[i]]) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
};
|
|
73
|
+
const memo = (component, propsAreEqual = shallowEqual) => {
|
|
74
|
+
let computed = undefined;
|
|
75
|
+
let prevProps = undefined;
|
|
76
|
+
return ((props) => {
|
|
77
|
+
if (prevProps && !propsAreEqual(prevProps, props)) {
|
|
78
|
+
computed = undefined;
|
|
79
|
+
}
|
|
80
|
+
prevProps = props;
|
|
81
|
+
return (computed || (computed = component(props)));
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
exports.memo = memo;
|
|
@@ -10,7 +10,7 @@ const jwt = (options) => {
|
|
|
10
10
|
const credentials = ctx.req.headers.get('Authorization');
|
|
11
11
|
if (!credentials) {
|
|
12
12
|
ctx.res = new Response('Unauthorized', {
|
|
13
|
-
status:
|
|
13
|
+
status: 401,
|
|
14
14
|
headers: {
|
|
15
15
|
'WWW-Authenticate': `Bearer realm="${ctx.req.url}",error="invalid_request",error_description="no authorization included in request"`,
|
|
16
16
|
},
|
|
@@ -20,7 +20,7 @@ const jwt = (options) => {
|
|
|
20
20
|
const parts = credentials.split(/\s+/);
|
|
21
21
|
if (parts.length !== 2) {
|
|
22
22
|
ctx.res = new Response('Unauthorized', {
|
|
23
|
-
status:
|
|
23
|
+
status: 401,
|
|
24
24
|
headers: {
|
|
25
25
|
'WWW-Authenticate': `Bearer realm="${ctx.req.url}",error="invalid_request",error_description="no authorization included in request"`,
|
|
26
26
|
},
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { MustacheOptions } from './mustache';
|
|
2
|
-
declare const module: (options?: MustacheOptions) => import("../../
|
|
2
|
+
declare const module: (options?: MustacheOptions) => (c: import("../../context").Context<string, import("../../context").Env>, next: import("../../hono").Next) => Promise<void>;
|
|
3
3
|
export { module as mustache };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
-
import type {
|
|
2
|
+
import type { Context } from '../../context';
|
|
3
|
+
import type { Next } from '../../hono';
|
|
3
4
|
export declare type MustacheOptions = {
|
|
4
5
|
root: string;
|
|
5
6
|
manifest?: object | string;
|
|
6
7
|
namespace?: KVNamespace;
|
|
7
8
|
};
|
|
8
|
-
export declare const mustache: (init?: MustacheOptions) =>
|
|
9
|
+
export declare const mustache: (init?: MustacheOptions) => (c: Context, next: Next) => Promise<void>;
|
package/dist/utils/crypto.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ declare type Algorithm = {
|
|
|
5
5
|
declare type Data = string | object | boolean;
|
|
6
6
|
export declare const sha256: (data: Data) => Promise<string | null>;
|
|
7
7
|
export declare const sha1: (data: Data) => Promise<string | null>;
|
|
8
|
+
export declare const md5: (data: Data) => Promise<string | null>;
|
|
8
9
|
export declare const createHash: (data: Data, algorithm: Algorithm) => Promise<string | null>;
|
|
9
10
|
export {};
|
package/dist/utils/crypto.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createHash = exports.sha1 = exports.sha256 = void 0;
|
|
3
|
+
exports.createHash = exports.md5 = exports.sha1 = exports.sha256 = void 0;
|
|
4
4
|
const sha256 = async (data) => {
|
|
5
5
|
const algorithm = { name: 'SHA-256', alias: 'sha256' };
|
|
6
6
|
const hash = await (0, exports.createHash)(data, algorithm);
|
|
@@ -13,6 +13,12 @@ const sha1 = async (data) => {
|
|
|
13
13
|
return hash;
|
|
14
14
|
};
|
|
15
15
|
exports.sha1 = sha1;
|
|
16
|
+
const md5 = async (data) => {
|
|
17
|
+
const algorithm = { name: 'MD5', alias: 'md5' };
|
|
18
|
+
const hash = await (0, exports.createHash)(data, algorithm);
|
|
19
|
+
return hash;
|
|
20
|
+
};
|
|
21
|
+
exports.md5 = md5;
|
|
16
22
|
const createHash = async (data, algorithm) => {
|
|
17
23
|
if (crypto && crypto.subtle) {
|
|
18
24
|
const buffer = await crypto.subtle.digest({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const escape: (str: string) => string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.escape = void 0;
|
|
4
|
+
const entityMap = {
|
|
5
|
+
'&': '&',
|
|
6
|
+
'<': '<',
|
|
7
|
+
'>': '>',
|
|
8
|
+
'"': '"',
|
|
9
|
+
};
|
|
10
|
+
const escapeRe = new RegExp(`[${Object.keys(entityMap).join('')}]`, 'g');
|
|
11
|
+
const replaceFn = (m) => entityMap[m];
|
|
12
|
+
const escape = (str) => {
|
|
13
|
+
return str.replace(escapeRe, replaceFn);
|
|
14
|
+
};
|
|
15
|
+
exports.escape = escape;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.6",
|
|
4
4
|
"description": "Ultrafast web framework for Cloudflare Workers.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
".": "./dist/index.js",
|
|
20
20
|
"./basic-auth": "./dist/middleware/basic-auth/index.js",
|
|
21
|
+
"./bearer-auth": "./dist/middleware/bearer-auth/index.js",
|
|
21
22
|
"./body-parse": "./dist/middleware/body-parse/index.js",
|
|
22
23
|
"./cookie": "./dist/middleware/cookie/index.js",
|
|
23
24
|
"./cors": "./dist/middleware/cors/index.js",
|
|
24
25
|
"./etag": "./dist/middleware/etag/index.js",
|
|
25
26
|
"./graphql-server": "./dist/middleware/graphql-server/index.js",
|
|
27
|
+
"./jsx": "./dist/middleware/jsx/index.js",
|
|
26
28
|
"./jwt": "./dist/middleware/jwt/index.js",
|
|
27
29
|
"./logger": "./dist/middleware/logger/index.js",
|
|
28
30
|
"./mustache": "./dist/middleware/mustache/index.js",
|
|
@@ -41,6 +43,9 @@
|
|
|
41
43
|
"basic-auth": [
|
|
42
44
|
"./dist/middleware/basic-auth"
|
|
43
45
|
],
|
|
46
|
+
"bearer-auth": [
|
|
47
|
+
"./dist/middleware/bearer-auth"
|
|
48
|
+
],
|
|
44
49
|
"body-parse": [
|
|
45
50
|
"./dist/middleware/body-parse"
|
|
46
51
|
],
|
|
@@ -56,6 +61,9 @@
|
|
|
56
61
|
"graphql-server": [
|
|
57
62
|
"./dist/middleware/graphql-server"
|
|
58
63
|
],
|
|
64
|
+
"jsx": [
|
|
65
|
+
"./dist/middleware/jsx"
|
|
66
|
+
],
|
|
59
67
|
"jwt": [
|
|
60
68
|
"./dist/middleware/jwt"
|
|
61
69
|
],
|