hono 2.2.0 → 2.2.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.
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HonoContext = void 0;
4
- const hono_1 = require("./hono");
5
4
  const cookie_1 = require("./utils/cookie");
6
5
  class HonoContext {
7
6
  constructor(req, env = undefined, executionCtx = undefined, notFoundHandler = () => new Response()) {
@@ -31,7 +30,7 @@ class HonoContext {
31
30
  }
32
31
  }
33
32
  get res() {
34
- return (this._res || (this._res = new Response(hono_1.defaultNotFoundMessage, { status: 404 })));
33
+ return (this._res || (this._res = new Response('404 Not Found', { status: 404 })));
35
34
  }
36
35
  set res(_res) {
37
36
  this._res = _res;
package/dist/cjs/hono.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Hono = exports.defaultNotFoundMessage = void 0;
3
+ exports.Hono = void 0;
4
4
  const compose_1 = require("./compose");
5
5
  const context_1 = require("./context");
6
6
  const request_1 = require("./request");
@@ -11,7 +11,6 @@ const smart_router_1 = require("./router/smart-router");
11
11
  const static_router_1 = require("./router/static-router");
12
12
  const trie_router_1 = require("./router/trie-router");
13
13
  const url_1 = require("./utils/url");
14
- exports.defaultNotFoundMessage = '404 Not Found';
15
14
  function defineDynamicClass() {
16
15
  return class {
17
16
  };
@@ -27,17 +26,23 @@ class Hono extends defineDynamicClass() {
27
26
  this.path = '/';
28
27
  this.routes = [];
29
28
  this.notFoundHandler = (c) => {
30
- const message = exports.defaultNotFoundMessage;
31
- return c.text(message, 404);
29
+ return c.text('404 Not Found', 404);
32
30
  };
33
31
  this.errorHandler = (err, c) => {
34
- console.error(`${err.stack || err.message}`);
32
+ console.trace(err.message);
35
33
  const message = 'Internal Server Error';
36
34
  return c.text(message, 500);
37
35
  };
36
+ this.handleEvent = (event) => {
37
+ return this.fetch(event.request, event);
38
+ };
38
39
  this.fetch = (request, Environment, executionCtx) => {
39
40
  return this.dispatch(request, executionCtx, Environment);
40
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
+ };
41
46
  (0, request_1.extendRequestPrototype)();
42
47
  const allMethods = [...router_1.METHODS, router_2.METHOD_NAME_ALL_LOWERCASE];
43
48
  allMethods.map((method) => {
@@ -100,7 +105,13 @@ class Hono extends defineDynamicClass() {
100
105
  matchRoute(method, path) {
101
106
  return this.router.match(method, path);
102
107
  }
103
- 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) {
104
115
  const path = (0, url_1.getPathFromURL)(request.url, this.strict);
105
116
  const method = request.method;
106
117
  const result = this.matchRoute(method, path);
@@ -109,46 +120,46 @@ class Hono extends defineDynamicClass() {
109
120
  // Do not `compose` if it has only one handler
110
121
  if (result && result.handlers.length === 1) {
111
122
  const handler = result.handlers[0];
123
+ let res;
112
124
  try {
113
- const res = handler(c, async () => { });
114
- if (res) {
115
- const awaited = res instanceof Promise ? await res : res;
116
- if (awaited)
117
- return awaited;
118
- }
119
- return this.notFoundHandler(c);
125
+ res = handler(c, async () => { });
126
+ if (!res)
127
+ return this.notFoundHandler(c);
120
128
  }
121
129
  catch (err) {
122
- if (err instanceof Error) {
123
- return this.errorHandler(err, c);
124
- }
125
- throw err;
130
+ return this.handleError(err, c);
126
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
+ })();
127
147
  }
128
148
  const handlers = result ? result.handlers : [this.notFoundHandler];
129
149
  const composed = (0, compose_1.compose)(handlers, this.notFoundHandler);
130
- let context;
131
- try {
132
- const tmp = composed(c);
133
- context = tmp instanceof Promise ? await tmp : tmp;
134
- if (!context.finalized) {
135
- 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;
136
158
  }
137
- }
138
- catch (err) {
139
- if (err instanceof Error) {
140
- return this.errorHandler(err, c);
159
+ catch (err) {
160
+ return this.handleError(err, c);
141
161
  }
142
- throw err;
143
- }
144
- return context.res;
145
- }
146
- handleEvent(event) {
147
- return this.dispatch(event.request, event);
148
- }
149
- request(input, requestInit) {
150
- const req = input instanceof Request ? input : new Request(input, requestInit);
151
- return this.dispatch(req);
162
+ })();
152
163
  }
153
164
  }
154
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/context.js CHANGED
@@ -1,4 +1,3 @@
1
- import { defaultNotFoundMessage } from './hono';
2
1
  import { serialize } from './utils/cookie';
3
2
  export class HonoContext {
4
3
  constructor(req, env = undefined, executionCtx = undefined, notFoundHandler = () => new Response()) {
@@ -28,7 +27,7 @@ export class HonoContext {
28
27
  }
29
28
  }
30
29
  get res() {
31
- return (this._res || (this._res = new Response(defaultNotFoundMessage, { status: 404 })));
30
+ return (this._res || (this._res = new Response('404 Not Found', { status: 404 })));
32
31
  }
33
32
  set res(_res) {
34
33
  this._res = _res;
package/dist/hono.d.ts CHANGED
@@ -15,32 +15,31 @@ export declare type MiddlewareHandler = <E extends Partial<Environment> = Enviro
15
15
  export declare type NotFoundHandler<E extends Partial<Environment> = Environment> = (c: Context<string, E>) => Response | Promise<Response>;
16
16
  export declare type ErrorHandler<E extends Partial<Environment> = Environment> = (err: Error, c: Context<string, E>) => Response;
17
17
  export declare type Next = () => Promise<void>;
18
- export declare const defaultNotFoundMessage = "404 Not Found";
19
18
  declare type ParamKeyName<NameWithPattern> = NameWithPattern extends `${infer Name}{${infer _Pattern}` ? Name : NameWithPattern;
20
19
  declare type ParamKey<Component> = Component extends `:${infer NameWithPattern}` ? ParamKeyName<NameWithPattern> : never;
21
20
  declare type ParamKeys<Path> = Path extends `${infer Component}/${infer Rest}` ? ParamKey<Component> | ParamKeys<Rest> : ParamKey<Path>;
22
- interface HandlerInterface<T extends string, E extends Partial<Environment>, D extends ValidatedData, U = Hono<E, T, D>> {
23
- <Path extends string, Env extends Partial<Environment>, Data extends ValidatedData = D>(...handlers: Handler<ParamKeys<Path> extends never ? string : ParamKeys<Path>, Env, Data>[]): U;
24
- (...handlers: Handler<string, E, D>[]): U;
25
- <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;
26
- (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;
27
26
  }
28
27
  interface Route<E extends Partial<Environment> = Environment, D extends ValidatedData = ValidatedData> {
29
28
  path: string;
30
29
  method: string;
31
30
  handler: Handler<string, E, D>;
32
31
  }
33
- 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>>() => {
34
- all: HandlerInterface<T, E_1, D_1, U>;
35
- get: HandlerInterface<T, E_1, D_1, U>;
36
- post: HandlerInterface<T, E_1, D_1, U>;
37
- put: HandlerInterface<T, E_1, D_1, U>;
38
- delete: HandlerInterface<T, E_1, D_1, U>;
39
- head: HandlerInterface<T, E_1, D_1, U>;
40
- options: HandlerInterface<T, E_1, D_1, U>;
41
- 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>;
42
41
  };
43
- 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>> {
44
43
  readonly router: Router<Handler<string, E, D>>;
45
44
  readonly strict: boolean;
46
45
  private _tempPath;
@@ -50,15 +49,16 @@ export declare class Hono<E extends Partial<Environment> = Environment, P extend
50
49
  private notFoundHandler;
51
50
  private errorHandler;
52
51
  route(path: string, app?: Hono<any>): Hono<E, P, D>;
53
- use<Path extends string = string, Env extends Partial<Environment> = E, Data extends ValidatedData = D>(...middleware: Handler<Path, Env, Data>[]): Hono<Env, Path, Data>;
54
- 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>;
55
54
  onError(handler: ErrorHandler<E>): Hono<E, P, D>;
56
55
  notFound(handler: NotFoundHandler<E>): Hono<E, P, D>;
57
56
  private addRoute;
58
57
  private matchRoute;
58
+ private handleError;
59
59
  private dispatch;
60
- handleEvent(event: FetchEvent): Promise<Response>;
61
- fetch: (request: Request, Environment?: E['Bindings'], executionCtx?: ExecutionContext) => Promise<Response>;
62
- 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>;
63
63
  }
64
64
  export {};
package/dist/hono.js CHANGED
@@ -8,7 +8,6 @@ import { SmartRouter } from './router/smart-router';
8
8
  import { StaticRouter } from './router/static-router';
9
9
  import { TrieRouter } from './router/trie-router';
10
10
  import { getPathFromURL, mergePath } from './utils/url';
11
- export const defaultNotFoundMessage = '404 Not Found';
12
11
  function defineDynamicClass() {
13
12
  return class {
14
13
  };
@@ -24,17 +23,23 @@ export class Hono extends defineDynamicClass() {
24
23
  this.path = '/';
25
24
  this.routes = [];
26
25
  this.notFoundHandler = (c) => {
27
- const message = defaultNotFoundMessage;
28
- return c.text(message, 404);
26
+ return c.text('404 Not Found', 404);
29
27
  };
30
28
  this.errorHandler = (err, c) => {
31
- console.error(`${err.stack || err.message}`);
29
+ console.trace(err.message);
32
30
  const message = 'Internal Server Error';
33
31
  return c.text(message, 500);
34
32
  };
33
+ this.handleEvent = (event) => {
34
+ return this.fetch(event.request, event);
35
+ };
35
36
  this.fetch = (request, Environment, executionCtx) => {
36
37
  return this.dispatch(request, executionCtx, Environment);
37
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
+ };
38
43
  extendRequestPrototype();
39
44
  const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE];
40
45
  allMethods.map((method) => {
@@ -97,7 +102,13 @@ export class Hono extends defineDynamicClass() {
97
102
  matchRoute(method, path) {
98
103
  return this.router.match(method, path);
99
104
  }
100
- 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) {
101
112
  const path = getPathFromURL(request.url, this.strict);
102
113
  const method = request.method;
103
114
  const result = this.matchRoute(method, path);
@@ -106,45 +117,45 @@ export class Hono extends defineDynamicClass() {
106
117
  // Do not `compose` if it has only one handler
107
118
  if (result && result.handlers.length === 1) {
108
119
  const handler = result.handlers[0];
120
+ let res;
109
121
  try {
110
- const res = handler(c, async () => { });
111
- if (res) {
112
- const awaited = res instanceof Promise ? await res : res;
113
- if (awaited)
114
- return awaited;
115
- }
116
- return this.notFoundHandler(c);
122
+ res = handler(c, async () => { });
123
+ if (!res)
124
+ return this.notFoundHandler(c);
117
125
  }
118
126
  catch (err) {
119
- if (err instanceof Error) {
120
- return this.errorHandler(err, c);
121
- }
122
- throw err;
127
+ return this.handleError(err, c);
123
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
+ })();
124
144
  }
125
145
  const handlers = result ? result.handlers : [this.notFoundHandler];
126
146
  const composed = compose(handlers, this.notFoundHandler);
127
- let context;
128
- try {
129
- const tmp = composed(c);
130
- context = tmp instanceof Promise ? await tmp : tmp;
131
- if (!context.finalized) {
132
- 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;
133
155
  }
134
- }
135
- catch (err) {
136
- if (err instanceof Error) {
137
- return this.errorHandler(err, c);
156
+ catch (err) {
157
+ return this.handleError(err, c);
138
158
  }
139
- throw err;
140
- }
141
- return context.res;
142
- }
143
- handleEvent(event) {
144
- return this.dispatch(event.request, event);
145
- }
146
- request(input, requestInit) {
147
- const req = input instanceof Request ? input : new Request(input, requestInit);
148
- return this.dispatch(req);
159
+ })();
149
160
  }
150
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.0",
3
+ "version": "2.2.2",
4
4
  "description": "Ultrafast web framework for Cloudflare Workers.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",