hono 2.2.1 → 2.2.3

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/cjs/hono.js CHANGED
@@ -29,13 +29,20 @@ class Hono extends defineDynamicClass() {
29
29
  return c.text('404 Not Found', 404);
30
30
  };
31
31
  this.errorHandler = (err, c) => {
32
- console.error(`${err.stack || err.message}`);
32
+ console.trace(err.message);
33
33
  const message = 'Internal Server Error';
34
34
  return c.text(message, 500);
35
35
  };
36
+ this.handleEvent = (event) => {
37
+ return this.dispatch(event.request, event);
38
+ };
36
39
  this.fetch = (request, Environment, executionCtx) => {
37
40
  return this.dispatch(request, executionCtx, Environment);
38
41
  };
42
+ this.request = async (input, requestInit) => {
43
+ const req = input instanceof Request ? input : new Request(input, requestInit);
44
+ return await this.fetch(req);
45
+ };
39
46
  (0, request_1.extendRequestPrototype)();
40
47
  const allMethods = [...router_1.METHODS, router_2.METHOD_NAME_ALL_LOWERCASE];
41
48
  allMethods.map((method) => {
@@ -98,7 +105,13 @@ class Hono extends defineDynamicClass() {
98
105
  matchRoute(method, path) {
99
106
  return this.router.match(method, path);
100
107
  }
101
- async dispatch(request, eventOrExecutionCtx, env) {
108
+ handleError(err, c) {
109
+ if (err instanceof Error) {
110
+ return this.errorHandler(err, c);
111
+ }
112
+ throw err;
113
+ }
114
+ dispatch(request, eventOrExecutionCtx, env) {
102
115
  const path = (0, url_1.getPathFromURL)(request.url, this.strict);
103
116
  const method = request.method;
104
117
  const result = this.matchRoute(method, path);
@@ -107,46 +120,46 @@ class Hono extends defineDynamicClass() {
107
120
  // Do not `compose` if it has only one handler
108
121
  if (result && result.handlers.length === 1) {
109
122
  const handler = result.handlers[0];
123
+ let res;
110
124
  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);
125
+ res = handler(c, async () => { });
126
+ if (!res)
127
+ return this.notFoundHandler(c);
118
128
  }
119
129
  catch (err) {
120
- if (err instanceof Error) {
121
- return this.errorHandler(err, c);
122
- }
123
- throw err;
130
+ return this.handleError(err, c);
124
131
  }
132
+ if (res instanceof Response)
133
+ return res;
134
+ return (async () => {
135
+ let awaited;
136
+ try {
137
+ awaited = await res;
138
+ }
139
+ catch (err) {
140
+ return this.handleError(err, c);
141
+ }
142
+ if (!awaited) {
143
+ return this.notFoundHandler(c);
144
+ }
145
+ return awaited;
146
+ })();
125
147
  }
126
148
  const handlers = result ? result.handlers : [this.notFoundHandler];
127
149
  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()`');
150
+ return (async () => {
151
+ try {
152
+ const tmp = composed(c);
153
+ const context = tmp instanceof Promise ? await tmp : tmp;
154
+ if (!context.finalized) {
155
+ throw new Error('Context is not finalized. You may forget returning Response object or `await next()`');
156
+ }
157
+ return context.res;
134
158
  }
135
- }
136
- catch (err) {
137
- if (err instanceof Error) {
138
- return this.errorHandler(err, c);
159
+ catch (err) {
160
+ return this.handleError(err, c);
139
161
  }
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);
162
+ })();
150
163
  }
151
164
  }
152
165
  exports.Hono = Hono;
@@ -2,21 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validatorMiddleware = void 0;
4
4
  const validator_1 = require("./validator");
5
- function getValidatorList(schema) {
6
- const map = [];
7
- for (const [key, value] of Object.entries(schema)) {
8
- if (value instanceof validator_1.VBase) {
9
- map.push([[key], value]);
10
- }
11
- else {
12
- const children = getValidatorList(value);
13
- for (const [keys, validator] of children) {
14
- map.push([[key, ...keys], validator]);
15
- }
16
- }
17
- }
18
- return map;
19
- }
20
5
  const validatorMiddleware = (validationFunction, options) => {
21
6
  const v = new validator_1.Validator();
22
7
  const handler = async (c, next) => {
@@ -54,3 +39,18 @@ const validatorMiddleware = (validationFunction, options) => {
54
39
  return handler;
55
40
  };
56
41
  exports.validatorMiddleware = validatorMiddleware;
42
+ function getValidatorList(schema) {
43
+ const map = [];
44
+ for (const [key, value] of Object.entries(schema)) {
45
+ if (value instanceof validator_1.VBase) {
46
+ map.push([[key], value]);
47
+ }
48
+ else {
49
+ const children = getValidatorList(value);
50
+ for (const [keys, validator] of children) {
51
+ map.push([[key, ...keys], validator]);
52
+ }
53
+ }
54
+ }
55
+ return map;
56
+ }
@@ -31,6 +31,7 @@ class VBase {
31
31
  });
32
32
  };
33
33
  this.isOptional = () => {
34
+ this._optional = true;
34
35
  return this.addRule(() => true);
35
36
  };
36
37
  this.isEqual = (comparison) => {
@@ -101,7 +102,13 @@ class VBase {
101
102
  this.validateValue = (value) => {
102
103
  // Check type
103
104
  if (typeof value !== this.type) {
104
- return false;
105
+ if (this._optional && typeof value === 'undefined') {
106
+ // Do nothing.
107
+ // The value is allowed to be `undefined` if it is `optional`
108
+ }
109
+ else {
110
+ return false;
111
+ }
105
112
  }
106
113
  // Sanitize
107
114
  for (const sanitizer of this.sanitizers) {
@@ -119,6 +126,7 @@ class VBase {
119
126
  this.type = options.type || 'string';
120
127
  this.rules = [];
121
128
  this.sanitizers = [];
129
+ this._optional = false;
122
130
  }
123
131
  message(value) {
124
132
  this._message = value;
package/dist/hono.d.ts CHANGED
@@ -18,28 +18,28 @@ export declare type Next = () => Promise<void>;
18
18
  declare type ParamKeyName<NameWithPattern> = NameWithPattern extends `${infer Name}{${infer _Pattern}` ? Name : NameWithPattern;
19
19
  declare type ParamKey<Component> = Component extends `:${infer NameWithPattern}` ? ParamKeyName<NameWithPattern> : never;
20
20
  declare type ParamKeys<Path> = Path extends `${infer Component}/${infer Rest}` ? ParamKey<Component> | ParamKeys<Rest> : ParamKey<Path>;
21
- interface HandlerInterface<T extends string, E extends Partial<Environment>, D extends ValidatedData, U = Hono<E, T, D>> {
22
- <Path extends string, Env extends Partial<Environment>, Data extends ValidatedData = D>(...handlers: Handler<ParamKeys<Path> extends never ? string : ParamKeys<Path>, Env, Data>[]): U;
23
- (...handlers: Handler<string, E, D>[]): U;
24
- <Path extends string, Env extends Partial<Environment> = E, Data extends ValidatedData = D>(path: Path, ...handlers: Handler<ParamKeys<Path> extends never ? string : ParamKeys<Path>, Env, Data>[]): U;
25
- (path: string, ...handlers: Handler<string, E, D>[]): U;
21
+ interface HandlerInterface<T extends string, E extends Partial<Environment>, U = Hono<E, T>> {
22
+ <Path extends string, Data extends ValidatedData>(...handlers: Handler<ParamKeys<Path> extends never ? string : ParamKeys<Path>, E, Data>[]): U;
23
+ (...handlers: Handler<string, E>[]): U;
24
+ <Path extends string, Data extends ValidatedData>(path: Path, ...handlers: Handler<ParamKeys<Path> extends never ? string : ParamKeys<Path>, E, Data>[]): U;
25
+ (path: string, ...handlers: Handler<string, E>[]): U;
26
26
  }
27
27
  interface Route<E extends Partial<Environment> = Environment, D extends ValidatedData = ValidatedData> {
28
28
  path: string;
29
29
  method: string;
30
30
  handler: Handler<string, E, D>;
31
31
  }
32
- declare const Hono_base: new <E_1 extends Partial<Environment> = Environment, T extends string = string, D_1 extends ValidatedData = ValidatedData, U = Hono<E_1, T, D_1>>() => {
33
- all: HandlerInterface<T, E_1, D_1, U>;
34
- get: HandlerInterface<T, E_1, D_1, U>;
35
- post: HandlerInterface<T, E_1, D_1, U>;
36
- put: HandlerInterface<T, E_1, D_1, U>;
37
- delete: HandlerInterface<T, E_1, D_1, U>;
38
- head: HandlerInterface<T, E_1, D_1, U>;
39
- options: HandlerInterface<T, E_1, D_1, U>;
40
- patch: HandlerInterface<T, E_1, D_1, U>;
32
+ declare const Hono_base: new <E_1 extends Partial<Environment> = Environment, T extends string = string, U = Hono<E_1, T, ValidatedData>>() => {
33
+ all: HandlerInterface<T, E_1, U>;
34
+ get: HandlerInterface<T, E_1, U>;
35
+ post: HandlerInterface<T, E_1, U>;
36
+ put: HandlerInterface<T, E_1, U>;
37
+ delete: HandlerInterface<T, E_1, U>;
38
+ head: HandlerInterface<T, E_1, U>;
39
+ options: HandlerInterface<T, E_1, U>;
40
+ patch: HandlerInterface<T, E_1, U>;
41
41
  };
42
- export declare class Hono<E extends Partial<Environment> = Environment, P extends string = '/', D extends ValidatedData = ValidatedData> extends Hono_base<E, P, D, Hono<E, P, D>> {
42
+ export declare class Hono<E extends Partial<Environment> = Environment, P extends string = '/', D extends ValidatedData = ValidatedData> extends Hono_base<E, P, Hono<E, P, D>> {
43
43
  readonly router: Router<Handler<string, E, D>>;
44
44
  readonly strict: boolean;
45
45
  private _tempPath;
@@ -49,15 +49,16 @@ export declare class Hono<E extends Partial<Environment> = Environment, P extend
49
49
  private notFoundHandler;
50
50
  private errorHandler;
51
51
  route(path: string, app?: Hono<any>): Hono<E, P, D>;
52
- use<Path extends string = string, Env extends Partial<Environment> = E, Data extends ValidatedData = D>(...middleware: Handler<Path, Env, Data>[]): Hono<Env, Path, Data>;
53
- use<Path extends string = string, Env extends Partial<Environment> = E, Data extends ValidatedData = D>(arg1: string, ...middleware: Handler<Path, Env, Data>[]): Hono<Env, Path, D>;
52
+ use<Path extends string = string, Data extends ValidatedData = D>(...middleware: Handler<Path, E, Data>[]): Hono<E, Path, Data>;
53
+ use<Path extends string = string, Data extends ValidatedData = D>(arg1: string, ...middleware: Handler<Path, E, Data>[]): Hono<E, Path, D>;
54
54
  onError(handler: ErrorHandler<E>): Hono<E, P, D>;
55
55
  notFound(handler: NotFoundHandler<E>): Hono<E, P, D>;
56
56
  private addRoute;
57
57
  private matchRoute;
58
+ private handleError;
58
59
  private dispatch;
59
- handleEvent(event: FetchEvent): Promise<Response>;
60
- fetch: (request: Request, Environment?: E['Bindings'], executionCtx?: ExecutionContext) => Promise<Response>;
61
- request(input: RequestInfo, requestInit?: RequestInit): Promise<Response>;
60
+ handleEvent: (event: FetchEvent) => Response | Promise<Response>;
61
+ fetch: (request: Request, Environment?: E['Bindings'], executionCtx?: ExecutionContext) => Response | Promise<Response>;
62
+ request: (input: RequestInfo, requestInit?: RequestInit) => Promise<Response>;
62
63
  }
63
64
  export {};
package/dist/hono.js CHANGED
@@ -26,13 +26,20 @@ export class Hono extends defineDynamicClass() {
26
26
  return c.text('404 Not Found', 404);
27
27
  };
28
28
  this.errorHandler = (err, c) => {
29
- console.error(`${err.stack || err.message}`);
29
+ console.trace(err.message);
30
30
  const message = 'Internal Server Error';
31
31
  return c.text(message, 500);
32
32
  };
33
+ this.handleEvent = (event) => {
34
+ return this.dispatch(event.request, event);
35
+ };
33
36
  this.fetch = (request, Environment, executionCtx) => {
34
37
  return this.dispatch(request, executionCtx, Environment);
35
38
  };
39
+ this.request = async (input, requestInit) => {
40
+ const req = input instanceof Request ? input : new Request(input, requestInit);
41
+ return await this.fetch(req);
42
+ };
36
43
  extendRequestPrototype();
37
44
  const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE];
38
45
  allMethods.map((method) => {
@@ -95,7 +102,13 @@ export class Hono extends defineDynamicClass() {
95
102
  matchRoute(method, path) {
96
103
  return this.router.match(method, path);
97
104
  }
98
- async dispatch(request, eventOrExecutionCtx, env) {
105
+ handleError(err, c) {
106
+ if (err instanceof Error) {
107
+ return this.errorHandler(err, c);
108
+ }
109
+ throw err;
110
+ }
111
+ dispatch(request, eventOrExecutionCtx, env) {
99
112
  const path = getPathFromURL(request.url, this.strict);
100
113
  const method = request.method;
101
114
  const result = this.matchRoute(method, path);
@@ -104,45 +117,45 @@ export class Hono extends defineDynamicClass() {
104
117
  // Do not `compose` if it has only one handler
105
118
  if (result && result.handlers.length === 1) {
106
119
  const handler = result.handlers[0];
120
+ let res;
107
121
  try {
108
- const res = handler(c, async () => { });
109
- if (res) {
110
- const awaited = res instanceof Promise ? await res : res;
111
- if (awaited)
112
- return awaited;
113
- }
114
- return this.notFoundHandler(c);
122
+ res = handler(c, async () => { });
123
+ if (!res)
124
+ return this.notFoundHandler(c);
115
125
  }
116
126
  catch (err) {
117
- if (err instanceof Error) {
118
- return this.errorHandler(err, c);
119
- }
120
- throw err;
127
+ return this.handleError(err, c);
121
128
  }
129
+ if (res instanceof Response)
130
+ return res;
131
+ return (async () => {
132
+ let awaited;
133
+ try {
134
+ awaited = await res;
135
+ }
136
+ catch (err) {
137
+ return this.handleError(err, c);
138
+ }
139
+ if (!awaited) {
140
+ return this.notFoundHandler(c);
141
+ }
142
+ return awaited;
143
+ })();
122
144
  }
123
145
  const handlers = result ? result.handlers : [this.notFoundHandler];
124
146
  const composed = compose(handlers, this.notFoundHandler);
125
- let context;
126
- try {
127
- const tmp = composed(c);
128
- context = tmp instanceof Promise ? await tmp : tmp;
129
- if (!context.finalized) {
130
- throw new Error('Context is not finalized. You may forget returning Response object or `await next()`');
147
+ return (async () => {
148
+ try {
149
+ const tmp = composed(c);
150
+ const context = tmp instanceof Promise ? await tmp : tmp;
151
+ if (!context.finalized) {
152
+ throw new Error('Context is not finalized. You may forget returning Response object or `await next()`');
153
+ }
154
+ return context.res;
131
155
  }
132
- }
133
- catch (err) {
134
- if (err instanceof Error) {
135
- return this.errorHandler(err, c);
156
+ catch (err) {
157
+ return this.handleError(err, c);
136
158
  }
137
- throw err;
138
- }
139
- return context.res;
140
- }
141
- handleEvent(event) {
142
- return this.dispatch(event.request, event);
143
- }
144
- request(input, requestInit) {
145
- const req = input instanceof Request ? input : new Request(input, requestInit);
146
- return this.dispatch(req);
159
+ })();
147
160
  }
148
161
  }
@@ -1,6 +1,7 @@
1
- import type { MiddlewareHandler } from '../../hono';
1
+ import type { Context } from '../../context';
2
+ import type { Next } from '../../hono';
2
3
  export declare type ServeStaticOptions = {
3
4
  root?: string;
4
5
  path?: string;
5
6
  };
6
- export declare const serveStatic: (options?: ServeStaticOptions) => MiddlewareHandler;
7
+ export declare const serveStatic: (options?: ServeStaticOptions) => (c: Context, next: Next) => Promise<Response | undefined>;
@@ -1,3 +1,3 @@
1
1
  import type { ServeStaticOptions } from './serve-static';
2
- declare const module: (options?: ServeStaticOptions) => import("../../hono").MiddlewareHandler;
2
+ declare const module: (options?: ServeStaticOptions) => (c: import("../..").Context<string, any, import("../../hono").ValidatedData>, next: import("../..").Next) => Promise<Response | undefined>;
3
3
  export { module as serveStatic };
@@ -1,9 +1,10 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import type { MiddlewareHandler } from '../../hono';
2
+ import type { Context } from '../../context';
3
+ import type { Next } from '../../hono';
3
4
  export declare type ServeStaticOptions = {
4
5
  root?: string;
5
6
  path?: string;
6
7
  manifest?: object | string;
7
8
  namespace?: KVNamespace;
8
9
  };
9
- export declare const serveStatic: (options?: ServeStaticOptions) => MiddlewareHandler;
10
+ export declare const serveStatic: (options?: ServeStaticOptions) => (c: Context, next: Next) => Promise<Response | undefined>;
@@ -1,8 +1,7 @@
1
1
  import type { Context } from '../../context';
2
- import type { Environment, Handler } from '../../hono';
2
+ import type { Environment, Next, ValidatedData } from '../../hono';
3
3
  import { Validator } from './validator';
4
4
  import type { VString, VNumber, VBoolean, VObject, ValidateResult } from './validator';
5
- declare type ValidationFunction<T> = (v: Validator, c: Context) => T;
6
5
  declare type Schema = {
7
6
  [key: string]: VString | VNumber | VBoolean | VObject | Schema;
8
7
  };
@@ -14,8 +13,10 @@ declare type ResultSet = {
14
13
  messages: string[];
15
14
  results: ValidateResult[];
16
15
  };
17
- declare type Done = (resultSet: ResultSet, context: Context) => Response | void;
18
- export declare const validatorMiddleware: <T extends Schema>(validationFunction: ValidationFunction<T>, options?: {
19
- done?: Done;
20
- }) => Handler<string, Environment, SchemaToProp<T>>;
16
+ declare type Done<Env extends Partial<Environment>> = (resultSet: ResultSet, context: Context<string, Env>) => Response | void;
17
+ declare type ValidationFunction<T, Env extends Partial<Environment>> = (v: Validator, c: Context<string, Env>) => T;
18
+ declare type MiddlewareHandler<Data extends ValidatedData = ValidatedData, Env extends Partial<Environment> = Environment> = (c: Context<string, Env, Data>, next: Next) => Promise<void> | Promise<Response | undefined>;
19
+ export declare const validatorMiddleware: <T extends Schema, Env extends Partial<Environment>>(validationFunction: ValidationFunction<T, Env>, options?: {
20
+ done?: Done<Env> | undefined;
21
+ } | undefined) => MiddlewareHandler<SchemaToProp<T>, Env>;
21
22
  export {};
@@ -1,19 +1,4 @@
1
1
  import { VBase, Validator } from './validator';
2
- function getValidatorList(schema) {
3
- const map = [];
4
- for (const [key, value] of Object.entries(schema)) {
5
- if (value instanceof VBase) {
6
- map.push([[key], value]);
7
- }
8
- else {
9
- const children = getValidatorList(value);
10
- for (const [keys, validator] of children) {
11
- map.push([[key, ...keys], validator]);
12
- }
13
- }
14
- }
15
- return map;
16
- }
17
2
  export const validatorMiddleware = (validationFunction, options) => {
18
3
  const v = new Validator();
19
4
  const handler = async (c, next) => {
@@ -50,3 +35,18 @@ export const validatorMiddleware = (validationFunction, options) => {
50
35
  };
51
36
  return handler;
52
37
  };
38
+ function getValidatorList(schema) {
39
+ const map = [];
40
+ for (const [key, value] of Object.entries(schema)) {
41
+ if (value instanceof VBase) {
42
+ map.push([[key], value]);
43
+ }
44
+ else {
45
+ const children = getValidatorList(value);
46
+ for (const [keys, validator] of children) {
47
+ map.push([[key, ...keys], validator]);
48
+ }
49
+ }
50
+ }
51
+ return map;
52
+ }
@@ -27,6 +27,7 @@ export declare abstract class VBase {
27
27
  rules: Rule[];
28
28
  sanitizers: Sanitizer[];
29
29
  private _message;
30
+ private _optional;
30
31
  constructor(options: VOptions);
31
32
  addRule: (rule: Rule) => this;
32
33
  addSanitizer: (sanitizer: Sanitizer) => this;
@@ -27,6 +27,7 @@ export class VBase {
27
27
  });
28
28
  };
29
29
  this.isOptional = () => {
30
+ this._optional = true;
30
31
  return this.addRule(() => true);
31
32
  };
32
33
  this.isEqual = (comparison) => {
@@ -97,7 +98,13 @@ export class VBase {
97
98
  this.validateValue = (value) => {
98
99
  // Check type
99
100
  if (typeof value !== this.type) {
100
- return false;
101
+ if (this._optional && typeof value === 'undefined') {
102
+ // Do nothing.
103
+ // The value is allowed to be `undefined` if it is `optional`
104
+ }
105
+ else {
106
+ return false;
107
+ }
101
108
  }
102
109
  // Sanitize
103
110
  for (const sanitizer of this.sanitizers) {
@@ -115,6 +122,7 @@ export class VBase {
115
122
  this.type = options.type || 'string';
116
123
  this.rules = [];
117
124
  this.sanitizers = [];
125
+ this._optional = false;
118
126
  }
119
127
  message(value) {
120
128
  this._message = value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "Ultrafast web framework for Cloudflare Workers.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",