hono 2.0.6 → 2.0.7

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/dist/compose.d.ts CHANGED
@@ -1,6 +1,2 @@
1
1
  import type { ErrorHandler, NotFoundHandler } from './hono';
2
- export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler<{
3
- [x: string]: any;
4
- }> | undefined, onNotFound?: NotFoundHandler<{
5
- [x: string]: any;
6
- }> | undefined) => (context: C, next?: Function | undefined) => Promise<C>;
2
+ export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler, onNotFound?: NotFoundHandler) => (context: C, next?: Function) => Promise<C>;
package/dist/hono.d.ts CHANGED
@@ -50,7 +50,7 @@ export declare class Hono<E extends Env = Env, P extends string = '/'> extends H
50
50
  private matchRoute;
51
51
  private dispatch;
52
52
  handleEvent(event: FetchEvent): Promise<Response>;
53
- fetch: (request: Request, env?: E | undefined, executionCtx?: ExecutionContext | undefined) => Promise<Response>;
53
+ fetch: (request: Request, env?: E, executionCtx?: ExecutionContext) => Promise<Response>;
54
54
  request(input: RequestInfo, requestInit?: RequestInit): Promise<Response>;
55
55
  }
56
56
  export {};
@@ -4,5 +4,5 @@ declare type EncodingType = 'gzip' | 'deflate';
4
4
  interface CompressionOptions {
5
5
  encoding?: EncodingType;
6
6
  }
7
- export declare const compress: (options?: CompressionOptions | undefined) => (ctx: Context, next: Next) => Promise<void>;
7
+ export declare const compress: (options?: CompressionOptions) => (ctx: Context, next: Next) => Promise<void>;
8
8
  export {};
@@ -8,5 +8,5 @@ declare type CORSOptions = {
8
8
  credentials?: boolean;
9
9
  exposeHeaders?: string[];
10
10
  };
11
- export declare const cors: (options?: CORSOptions | undefined) => (c: Context, next: Next) => Promise<void>;
11
+ export declare const cors: (options?: CORSOptions) => (c: Context, next: Next) => Promise<void>;
12
12
  export {};
@@ -1,5 +1,3 @@
1
- export declare type HtmlEscapedString = string & {
2
- isEscaped: true;
3
- };
1
+ import type { HtmlEscapedString } from '../../utils/html';
4
2
  export declare const raw: (value: any) => HtmlEscapedString;
5
3
  export declare const html: (strings: TemplateStringsArray, ...values: any[]) => HtmlEscapedString;
@@ -9,24 +9,28 @@ const raw = (value) => {
9
9
  };
10
10
  exports.raw = raw;
11
11
  const html = (strings, ...values) => {
12
- let result = '';
12
+ const buffer = [''];
13
13
  for (let i = 0, len = strings.length - 1; i < len; i++) {
14
- result += strings[i];
14
+ buffer[0] += strings[i];
15
15
  const children = values[i] instanceof Array ? values[i].flat(Infinity) : [values[i]];
16
16
  for (let i = 0, len = children.length; i < len; i++) {
17
17
  const child = children[i];
18
- if (typeof child === 'boolean' || child === null || child === undefined) {
18
+ if (typeof child === 'string') {
19
+ (0, html_1.escapeToBuffer)(child, buffer);
20
+ }
21
+ else if (typeof child === 'boolean' || child === null || child === undefined) {
19
22
  continue;
20
23
  }
21
- else if (typeof child === 'object' && child.isEscaped) {
22
- result += child;
24
+ else if ((typeof child === 'object' && child.isEscaped) ||
25
+ typeof child === 'number') {
26
+ buffer[0] += child;
23
27
  }
24
28
  else {
25
- result += (0, html_1.escape)(child.toString());
29
+ (0, html_1.escapeToBuffer)(child.toString(), buffer);
26
30
  }
27
31
  }
28
32
  }
29
- result += strings[strings.length - 1];
30
- return (0, exports.raw)(result);
33
+ buffer[0] += strings[strings.length - 1];
34
+ return (0, exports.raw)(buffer[0]);
31
35
  };
32
36
  exports.html = html;
@@ -1,4 +1,4 @@
1
- import type { HtmlEscapedString } from '../../utils/html';
1
+ import type { StringBuffer, HtmlEscaped, HtmlEscapedString } from '../../utils/html';
2
2
  declare global {
3
3
  namespace jsx.JSX {
4
4
  interface IntrinsicElements {
@@ -6,11 +6,21 @@ declare global {
6
6
  }
7
7
  }
8
8
  }
9
+ declare type Child = string | number | JSXNode | Child[];
10
+ export declare class JSXNode implements HtmlEscaped {
11
+ tag: string | Function;
12
+ props: Record<string, any>;
13
+ children: Child[];
14
+ isEscaped: true;
15
+ constructor(tag: string | Function, props: Record<string, any>, children: Child[]);
16
+ toString(): string;
17
+ toStringToBuffer(buffer: StringBuffer): void;
18
+ }
9
19
  export { jsxFn as jsx };
10
- declare const jsxFn: (tag: string | Function, props: Record<string, any>, ...children: (string | HtmlEscapedString)[]) => HtmlEscapedString;
20
+ declare const jsxFn: (tag: string | Function, props: Record<string, any>, ...children: (string | HtmlEscapedString)[]) => JSXNode;
11
21
  declare type FC<T = Record<string, any>> = (props: T) => HtmlEscapedString;
12
22
  export declare const memo: <T>(component: FC<T>, propsAreEqual?: (prevProps: Readonly<T>, nextProps: Readonly<T>) => boolean) => FC<T>;
13
23
  export declare const Fragment: (props: {
14
24
  key?: string;
15
25
  children?: any;
16
- }) => HtmlEscapedString;
26
+ }) => JSXNode;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Fragment = exports.memo = exports.jsx = void 0;
3
+ exports.Fragment = exports.memo = exports.jsx = exports.JSXNode = void 0;
4
4
  const html_1 = require("../../utils/html");
5
5
  const emptyTags = [
6
6
  'area',
@@ -19,68 +19,144 @@ const emptyTags = [
19
19
  'track',
20
20
  'wbr',
21
21
  ];
22
- const booleanAttributes = ['checked', 'selected', 'disabled', 'readonly', 'multiple'];
23
- const newHtmlEscapedString = (str) => {
24
- const escapedString = new String(str);
25
- escapedString.isEscaped = true;
26
- return escapedString;
27
- };
28
- const jsxFn = (tag, props, ...children) => {
29
- if (typeof tag === 'function') {
30
- return tag.call(null, { ...props, children: children.length <= 1 ? children[0] : children });
31
- }
32
- let result = tag !== '' ? `<${tag}` : '';
33
- const propsKeys = Object.keys(props || {});
34
- for (let i = 0, len = propsKeys.length; i < len; i++) {
35
- const v = props[propsKeys[i]];
36
- if (typeof v === 'string') {
37
- result += ` ${propsKeys[i]}="${(0, html_1.escape)(v)}"`;
38
- }
39
- else if (typeof v === 'number') {
40
- result += ` ${propsKeys[i]}="${v}"`;
22
+ const booleanAttributes = [
23
+ 'allowfullscreen',
24
+ 'async',
25
+ 'autofocus',
26
+ 'autoplay',
27
+ 'checked',
28
+ 'controls',
29
+ 'default',
30
+ 'defer',
31
+ 'disabled',
32
+ 'formnovalidate',
33
+ 'hidden',
34
+ 'inert',
35
+ 'ismap',
36
+ 'itemscope',
37
+ 'loop',
38
+ 'multiple',
39
+ 'muted',
40
+ 'nomodule',
41
+ 'novalidate',
42
+ 'open',
43
+ 'playsinline',
44
+ 'readonly',
45
+ 'required',
46
+ 'reversed',
47
+ 'selected',
48
+ ];
49
+ const childrenToStringToBuffer = (children, buffer) => {
50
+ for (let i = 0, len = children.length; i < len; i++) {
51
+ const child = children[i];
52
+ if (typeof child === 'string') {
53
+ (0, html_1.escapeToBuffer)(child, buffer);
41
54
  }
42
- else if (v === null || v === undefined) {
43
- // Do nothing
55
+ else if (typeof child === 'boolean' || child === null || child === undefined) {
56
+ continue;
44
57
  }
45
- else if (typeof v === 'boolean' && booleanAttributes.includes(propsKeys[i])) {
46
- if (v) {
47
- result += ` ${propsKeys[i]}=""`;
48
- }
58
+ else if (child instanceof JSXNode) {
59
+ child.toStringToBuffer(buffer);
49
60
  }
50
- else if (propsKeys[i] === 'dangerouslySetInnerHTML') {
51
- if (children.length > 0) {
52
- throw 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.';
53
- }
54
- children = [newHtmlEscapedString(v.__html)];
61
+ else if (typeof child === 'number' || child.isEscaped) {
62
+ buffer[0] += child;
55
63
  }
56
64
  else {
57
- result += ` ${propsKeys[i]}="${(0, html_1.escape)(v.toString())}"`;
65
+ // `child` type is `Child[]`, so stringify recursively
66
+ childrenToStringToBuffer(child, buffer);
58
67
  }
59
68
  }
60
- if (emptyTags.includes(tag)) {
61
- result += '/>';
62
- return newHtmlEscapedString(result);
69
+ };
70
+ class JSXNode {
71
+ constructor(tag, props, children) {
72
+ this.isEscaped = true;
73
+ this.tag = tag;
74
+ this.props = props;
75
+ this.children = children;
63
76
  }
64
- if (tag !== '') {
65
- result += '>';
77
+ toString() {
78
+ const buffer = [''];
79
+ this.toStringToBuffer(buffer);
80
+ return buffer[0];
66
81
  }
67
- const flattenChildren = children.flat(Infinity);
68
- for (let i = 0, len = flattenChildren.length; i < len; i++) {
69
- const child = flattenChildren[i];
70
- if (typeof child === 'boolean' || child === null || child === undefined) {
71
- continue;
82
+ toStringToBuffer(buffer) {
83
+ const tag = this.tag;
84
+ const props = this.props;
85
+ let { children } = this;
86
+ buffer[0] += `<${tag}`;
87
+ const propsKeys = Object.keys(props || {});
88
+ for (let i = 0, len = propsKeys.length; i < len; i++) {
89
+ const v = props[propsKeys[i]];
90
+ if (typeof v === 'string') {
91
+ buffer[0] += ` ${propsKeys[i]}="`;
92
+ (0, html_1.escapeToBuffer)(v, buffer);
93
+ buffer[0] += '"';
94
+ }
95
+ else if (typeof v === 'number') {
96
+ buffer[0] += ` ${propsKeys[i]}="${v}"`;
97
+ }
98
+ else if (v === null || v === undefined) {
99
+ // Do nothing
100
+ }
101
+ else if (typeof v === 'boolean' && booleanAttributes.includes(propsKeys[i])) {
102
+ if (v) {
103
+ buffer[0] += ` ${propsKeys[i]}=""`;
104
+ }
105
+ }
106
+ else if (propsKeys[i] === 'dangerouslySetInnerHTML') {
107
+ if (children.length > 0) {
108
+ throw 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.';
109
+ }
110
+ const escapedString = new String(v.__html);
111
+ escapedString.isEscaped = true;
112
+ children = [escapedString];
113
+ }
114
+ else {
115
+ buffer[0] += ` ${propsKeys[i]}="`;
116
+ (0, html_1.escapeToBuffer)(v.toString(), buffer);
117
+ buffer[0] += '"';
118
+ }
119
+ }
120
+ if (emptyTags.includes(tag)) {
121
+ buffer[0] += '/>';
122
+ return;
72
123
  }
73
- else if (typeof child === 'object' && child.isEscaped) {
74
- result += child;
124
+ buffer[0] += '>';
125
+ childrenToStringToBuffer(children, buffer);
126
+ buffer[0] += `</${tag}>`;
127
+ }
128
+ }
129
+ exports.JSXNode = JSXNode;
130
+ class JSXFunctionNode extends JSXNode {
131
+ toStringToBuffer(buffer) {
132
+ const { children } = this;
133
+ const res = this.tag.call(null, {
134
+ ...this.props,
135
+ children: children.length <= 1 ? children[0] : children,
136
+ });
137
+ if (res instanceof JSXNode) {
138
+ res.toStringToBuffer(buffer);
139
+ }
140
+ else if (typeof res === 'number' || res.isEscaped) {
141
+ buffer[0] += res;
75
142
  }
76
143
  else {
77
- result += (0, html_1.escape)(child.toString());
144
+ (0, html_1.escapeToBuffer)(res, buffer);
78
145
  }
79
146
  }
80
- if (tag !== '') {
81
- result += `</${tag}>`;
147
+ }
148
+ class JSXFragmentNode extends JSXNode {
149
+ toStringToBuffer(buffer) {
150
+ childrenToStringToBuffer(this.children, buffer);
151
+ }
152
+ }
153
+ const jsxFn = (tag, props, ...children) => {
154
+ if (typeof tag === 'function') {
155
+ return new JSXFunctionNode(tag, props, children);
156
+ }
157
+ else {
158
+ return new JSXNode(tag, props, children);
82
159
  }
83
- return newHtmlEscapedString(result);
84
160
  };
85
161
  exports.jsx = jsxFn;
86
162
  const shallowEqual = (a, b) => {
@@ -112,6 +188,6 @@ const memo = (component, propsAreEqual = shallowEqual) => {
112
188
  };
113
189
  exports.memo = memo;
114
190
  const Fragment = (props) => {
115
- return jsxFn('', {}, ...(props.children || []));
191
+ return new JSXFragmentNode('', {}, props.children || []);
116
192
  };
117
193
  exports.Fragment = Fragment;
@@ -1,2 +1,2 @@
1
- import type { HtmlEscapedString } from '../html';
2
- export declare function jsxDEV(tag: string | Function, props: Record<string, any>): HtmlEscapedString;
1
+ import type { JSXNode } from '.';
2
+ export declare function jsxDEV(tag: string | Function, props: Record<string, any>): JSXNode;
@@ -2,5 +2,6 @@ import type { Context } from '../../context';
2
2
  import type { Next } from '../../hono';
3
3
  export declare const jwt: (options: {
4
4
  secret: string;
5
+ cookie?: string;
5
6
  alg?: string;
6
7
  }) => (ctx: Context, next: Next) => Promise<void>;
@@ -11,17 +11,26 @@ const jwt = (options) => {
11
11
  }
12
12
  return async (ctx, next) => {
13
13
  const credentials = ctx.req.headers.get('Authorization');
14
- if (!credentials) {
15
- ctx.res = new Response('Unauthorized', {
16
- status: 401,
17
- headers: {
18
- 'WWW-Authenticate': `Bearer realm="${ctx.req.url}",error="invalid_request",error_description="no authorization included in request"`,
19
- },
20
- });
21
- return;
14
+ let token;
15
+ if (credentials) {
16
+ const parts = credentials.split(/\s+/);
17
+ if (parts.length !== 2) {
18
+ ctx.res = new Response('Unauthorized', {
19
+ status: 401,
20
+ headers: {
21
+ 'WWW-Authenticate': `Bearer realm="${ctx.req.url}",error="invalid_request",error_description="invalid credentials structure"`,
22
+ },
23
+ });
24
+ return;
25
+ }
26
+ else {
27
+ token = parts[1];
28
+ }
29
+ }
30
+ else if (options.cookie) {
31
+ token = ctx.req.cookie(options.cookie);
22
32
  }
23
- const parts = credentials.split(/\s+/);
24
- if (parts.length !== 2) {
33
+ if (!token) {
25
34
  ctx.res = new Response('Unauthorized', {
26
35
  status: 401,
27
36
  headers: {
@@ -33,7 +42,7 @@ const jwt = (options) => {
33
42
  let authorized = false;
34
43
  let msg = '';
35
44
  try {
36
- authorized = await jwt_1.Jwt.verify(parts[1], options.secret, options.alg);
45
+ authorized = await jwt_1.Jwt.verify(token, options.secret, options.alg);
37
46
  }
38
47
  catch (e) {
39
48
  msg = `${e}`;
package/dist/request.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Body } from './utils/body';
1
2
  import type { Cookie } from './utils/cookie';
2
3
  declare global {
3
4
  interface Request<ParamKeyType extends string = string> {
@@ -22,9 +23,9 @@ declare global {
22
23
  (name: string): string;
23
24
  (): Cookie;
24
25
  };
25
- parsedBody?: Promise<any>;
26
+ parsedBody?: Promise<Body>;
26
27
  parseBody: {
27
- (): Promise<any>;
28
+ (): Promise<Body>;
28
29
  };
29
30
  }
30
31
  }
@@ -1 +1,2 @@
1
- export declare const parseBody: (r: Request | Response) => Promise<string | object | Record<string, string | File>>;
1
+ export declare type Body = string | object | Record<string, string | File> | ArrayBuffer;
2
+ export declare const parseBody: (r: Request | Response) => Promise<Body>;
@@ -25,6 +25,7 @@ const parseBody = async (r) => {
25
25
  }, form);
26
26
  return data;
27
27
  }
28
- return r.arrayBuffer();
28
+ const arrayBuffer = await r.arrayBuffer();
29
+ return arrayBuffer;
29
30
  };
30
31
  exports.parseBody = parseBody;
@@ -1,3 +1,3 @@
1
1
  export declare const equal: (a: ArrayBuffer, b: ArrayBuffer) => boolean;
2
- export declare const timingSafeEqual: (a: string | object | boolean, b: string | object | boolean, hashFunction?: Function | undefined) => Promise<boolean>;
2
+ export declare const timingSafeEqual: (a: string | object | boolean, b: string | object | boolean, hashFunction?: Function) => Promise<boolean>;
3
3
  export declare const bufferToString: (buffer: ArrayBuffer) => string;
@@ -3,4 +3,4 @@ export declare type KVAssetOptions = {
3
3
  manifest?: object | string;
4
4
  namespace?: KVNamespace;
5
5
  };
6
- export declare const getContentFromKVAsset: (path: string, options?: KVAssetOptions | undefined) => Promise<ArrayBuffer | null>;
6
+ export declare const getContentFromKVAsset: (path: string, options?: KVAssetOptions) => Promise<ArrayBuffer | null>;
@@ -2,7 +2,7 @@ declare type Algorithm = {
2
2
  name: string;
3
3
  alias: string;
4
4
  };
5
- declare type Data = string | object | boolean;
5
+ declare type Data = string | boolean | number | object | ArrayBufferView | ArrayBuffer;
6
6
  export declare const sha256: (data: Data) => Promise<string | null>;
7
7
  export declare const sha1: (data: Data) => Promise<string | null>;
8
8
  export declare const md5: (data: Data) => Promise<string | null>;
@@ -20,10 +20,20 @@ const md5 = async (data) => {
20
20
  };
21
21
  exports.md5 = md5;
22
22
  const createHash = async (data, algorithm) => {
23
+ let sourceBuffer;
24
+ if (ArrayBuffer.isView(data) || data instanceof ArrayBuffer) {
25
+ sourceBuffer = data;
26
+ }
27
+ else {
28
+ if (typeof data === 'object') {
29
+ data = JSON.stringify(data);
30
+ }
31
+ sourceBuffer = new TextEncoder().encode(String(data));
32
+ }
23
33
  if (crypto && crypto.subtle) {
24
34
  const buffer = await crypto.subtle.digest({
25
35
  name: algorithm.name,
26
- }, new TextEncoder().encode(String(data)));
36
+ }, sourceBuffer);
27
37
  const hash = Array.prototype.map
28
38
  .call(new Uint8Array(buffer), (x) => ('00' + x.toString(16)).slice(-2))
29
39
  .join('');
@@ -1,4 +1,6 @@
1
- export declare type HtmlEscapedString = string & {
1
+ export declare type HtmlEscaped = {
2
2
  isEscaped: true;
3
3
  };
4
- export declare const escape: (str: string) => string;
4
+ export declare type HtmlEscapedString = string & HtmlEscaped;
5
+ export declare type StringBuffer = [string];
6
+ export declare const escapeToBuffer: (str: string, buffer: StringBuffer) => void;
@@ -1,15 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.escape = void 0;
4
- const entityMap = {
5
- '&': '&amp;',
6
- '<': '&lt;',
7
- '>': '&gt;',
8
- '"': '&quot;',
3
+ exports.escapeToBuffer = void 0;
4
+ // The `escapeToBuffer` implementation is based on code from the MIT licensed `react-dom` package.
5
+ // https://github.com/facebook/react/blob/main/packages/react-dom/src/server/escapeTextForBrowser.js
6
+ const escapeRe = /[&<>"]/;
7
+ const escapeToBuffer = (str, buffer) => {
8
+ const match = str.search(escapeRe);
9
+ if (match === -1) {
10
+ buffer[0] += str;
11
+ return;
12
+ }
13
+ let escape;
14
+ let index;
15
+ let lastIndex = 0;
16
+ for (index = match; index < str.length; index++) {
17
+ switch (str.charCodeAt(index)) {
18
+ case 34: // "
19
+ escape = '&quot;';
20
+ break;
21
+ case 38: // &
22
+ escape = '&amp;';
23
+ break;
24
+ case 60: // <
25
+ escape = '&lt;';
26
+ break;
27
+ case 62: // >
28
+ escape = '&gt;';
29
+ break;
30
+ default:
31
+ continue;
32
+ }
33
+ buffer[0] += str.substring(lastIndex, index) + escape;
34
+ lastIndex = index + 1;
35
+ }
36
+ buffer[0] += str.substring(lastIndex, index);
9
37
  };
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;
38
+ exports.escapeToBuffer = escapeToBuffer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "Ultrafast web framework for Cloudflare Workers.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",