@bepalo/spine 2.6.18 → 2.7.19

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.
Files changed (43) hide show
  1. package/dist/cjs/generator.d.ts.map +1 -1
  2. package/dist/cjs/generator.js +1 -1
  3. package/dist/cjs/generator.js.map +1 -1
  4. package/dist/cjs/middlewares.d.ts +167 -21
  5. package/dist/cjs/middlewares.d.ts.map +1 -1
  6. package/dist/cjs/middlewares.js +578 -28
  7. package/dist/cjs/middlewares.js.map +1 -1
  8. package/dist/cjs/parsers.d.ts +32 -10
  9. package/dist/cjs/parsers.d.ts.map +1 -1
  10. package/dist/cjs/parsers.js +83 -46
  11. package/dist/cjs/parsers.js.map +1 -1
  12. package/dist/cjs/router.d.ts.map +1 -1
  13. package/dist/cjs/router.js +1 -1
  14. package/dist/cjs/router.js.map +1 -1
  15. package/dist/cjs/utils.d.ts +1 -0
  16. package/dist/cjs/utils.d.ts.map +1 -1
  17. package/dist/cjs/utils.js.map +1 -1
  18. package/dist/cjs/utils.node.d.ts +1 -1
  19. package/dist/cjs/utils.node.d.ts.map +1 -1
  20. package/dist/cjs/utils.node.js +30 -7
  21. package/dist/cjs/utils.node.js.map +1 -1
  22. package/dist/generator.d.ts.map +1 -1
  23. package/dist/generator.js +1 -1
  24. package/dist/generator.js.map +1 -1
  25. package/dist/middlewares.d.ts +167 -21
  26. package/dist/middlewares.d.ts.map +1 -1
  27. package/dist/middlewares.js +578 -28
  28. package/dist/middlewares.js.map +1 -1
  29. package/dist/parsers.d.ts +32 -10
  30. package/dist/parsers.d.ts.map +1 -1
  31. package/dist/parsers.js +83 -46
  32. package/dist/parsers.js.map +1 -1
  33. package/dist/router.d.ts.map +1 -1
  34. package/dist/router.js +1 -1
  35. package/dist/router.js.map +1 -1
  36. package/dist/utils.d.ts +1 -0
  37. package/dist/utils.d.ts.map +1 -1
  38. package/dist/utils.js.map +1 -1
  39. package/dist/utils.node.d.ts +1 -1
  40. package/dist/utils.node.d.ts.map +1 -1
  41. package/dist/utils.node.js +30 -7
  42. package/dist/utils.node.js.map +1 -1
  43. package/package.json +6 -2
@@ -10,8 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  });
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.cors = exports.limitRate = exports.securityHeaders = exports.forceHttps = void 0;
13
+ exports.validate = exports.cors = exports.limitRate = exports.securityHeaders = exports.forceHttps = void 0;
14
14
  const helpers_ts_1 = require("./helpers.js");
15
+ const parsers_ts_1 = require("./parsers.js");
16
+ const status_ts_1 = require("./status.js");
15
17
  const types_ts_1 = require("./types.js");
16
18
  /**
17
19
  * Force http into https
@@ -113,16 +115,17 @@ exports.securityHeaders = securityHeaders;
113
115
  * Creates a rate limiting middleware using token bucket algorithm.
114
116
  * Supports both fixed interval refill and continuous rate-based refill.
115
117
  *
116
- * @template {Record<string, unknown>} ExtendContext - Extend Router Context
117
- * @param {Object} config - Rate limiting configuration
118
- * @param {Function} [config.key] - Function to generate cache key from request and context
119
- * @param {number} [config.maxTokens] - Maximum number of tokens in the bucket
120
- * @param {number} [config.refillInterval] - Fixed interval in seconds for token refill
121
- * @param {number} [config.refillRate] - Continuous refill rate in tokens per second
122
- * @param {number} [config.cleanUpInterval] - Interval in seconds for cleanup timer
123
- * @param {number} [config.cleanUpIdleDelay] - Time in seconds to delay cleanup of filled token buckets
124
- * @param {boolean} [config.setXRateLimitHeaders=false] - Whether to set X-RateLimit headers in response
125
- * @param {boolean} [config.breakPipeline=false] - If true, returns Break_Pipeline
118
+ * @template {Record<string, unknown>} ExtendContext Extend Router Context
119
+ * @property {Object} config Rate limiting configuration
120
+ * @property {Function} [config.key] Function to generate cache key from request and context
121
+ * @property {number} [config.maxTokens] Maximum number of tokens in the bucket
122
+ * @property {number} [config.refillInterval] Fixed interval in seconds for token refill
123
+ * @property {number} [config.refillRate] Continuous refill rate in tokens per second
124
+ * @property {number} [config.cleanUpInterval] Interval in seconds for cleanup timer
125
+ * @property {number} [config.cleanUpIdleDelay] Time in seconds to delay cleanup of filled token buckets
126
+ * @property {boolean} [config.setXRateLimitHeaders=false] Whether to set X-RateLimit headers in response
127
+ * @property {boolean} [config.breakPipeline=false] If true, returns Break_Pipeline
128
+ * @property {"status"|"text"|"json"} [config.responseType="text"] Response type
126
129
  * @returns {Handler<ExtendContext>} Middleware function that enforces rate limits
127
130
  *
128
131
  * @example
@@ -147,7 +150,12 @@ exports.securityHeaders = securityHeaders;
147
150
  */
148
151
  const limitRate = (config) => {
149
152
  var _a;
150
- const { key, maxTokens, refillInterval, refillRate, cleanUpInterval, setXRateLimitHeaders = false, breakPipeline = false, } = config;
153
+ const { key, maxTokens, refillInterval, refillRate, cleanUpInterval, setXRateLimitHeaders = false, breakPipeline = false, responseType = "text", } = config;
154
+ const respond = responseType === "json"
155
+ ? (code, content, key, tag, init) => (0, helpers_ts_1.json)({ [key]: `${tag}: ${content}`, tag }, Object.assign(Object.assign({}, init), { status: code }))
156
+ : responseType === "text"
157
+ ? (code, content, key, tag, init) => (0, helpers_ts_1.text)(`[${key}] ${tag}: ${content}`, Object.assign(Object.assign({}, init), { status: code }))
158
+ : (code, _content, _key, _tag, init) => (0, helpers_ts_1.status)(code, null, init);
151
159
  const cleanUpIdleDelay = -((_a = config.cleanUpIdleDelay) !== null && _a !== void 0 ? _a : 0);
152
160
  const rateLimits = new Map();
153
161
  const now = () => performance.now() / 1000;
@@ -215,7 +223,7 @@ const limitRate = (config) => {
215
223
  }
216
224
  if (entry.tokens <= 0) {
217
225
  ctx.headers.set("Retry-After", Math.ceil(refillInterval - timeElapsed).toFixed());
218
- return (0, helpers_ts_1.status)(429);
226
+ return respond(status_ts_1.Status._429_TooManyRequests, "Rate Limited", "message", "rate-limit");
219
227
  }
220
228
  else {
221
229
  entry.tokens--;
@@ -241,7 +249,7 @@ const limitRate = (config) => {
241
249
  entry.lastRefill = now();
242
250
  if (entry.tokens <= 0) {
243
251
  ctx.headers.set("Retry-After", Math.ceil(1 / refillRate).toFixed());
244
- return (0, helpers_ts_1.status)(429);
252
+ return respond(status_ts_1.Status._429_TooManyRequests, "Rate Limited", "message", "rate-limit");
245
253
  }
246
254
  else {
247
255
  entry.tokens--;
@@ -263,16 +271,17 @@ exports.limitRate = limitRate;
263
271
  * Creates a CORS (Cross-Origin Resource Sharing) middleware.
264
272
  * Supports preflight requests and configurable CORS headers.
265
273
  *
266
- * @template {Record<string, unknown>} ExtendContext - Extend Router Context
267
- * @param {Object} [config] - CORS configuration
268
- * @param {string|string[]|"*"} [config.origins="*"] - Allowed origins (wildcard "*", single origin, or array)
269
- * @param {(HttpMethod|HttpMethodUpper|HttpMethodLower)[]} [config.methods=["Get","Head","Put","Patch","Post","Delete"]] - Allowed HTTP methods
270
- * @param {string[]} [config.allowedHeaders=["Content-Type","Authorization"]] - Allowed request headers
271
- * @param {string[]} [config.exposedHeaders] - Headers exposed to the browser
272
- * @param {boolean} [config.credentials=false] - Allow credentials (cookies, authorization headers)
273
- * @param {number} [config.maxAge=86400] - Maximum age for preflight cache in seconds
274
- * @param {boolean} [config.varyOrigin=true] - Add Vary: Origin header for caching
275
- * @param {boolean} [config.breakPipeline=false] - If true, returns Break_Pipeline
274
+ * @template {Record<string, unknown>} ExtendContext Extend Router Context
275
+ * @param {Object} [config] CORS configuration
276
+ * @param {string|string[]|"*"} [config.origins="*"] Allowed origins (wildcard "*", single origin, or array)
277
+ * @param {(HttpMethod|HttpMethodUpper|HttpMethodLower)[]} [config.methods=["Get","Head","Put","Patch","Post","Delete"]] Allowed HTTP methods
278
+ * @param {string[]} [config.allowedHeaders=["Content-Type","Authorization"]] Allowed request headers
279
+ * @param {string[]} [config.exposedHeaders] Headers exposed to the browser
280
+ * @param {boolean} [config.credentials=false] Allow credentials (cookies, authorization headers)
281
+ * @param {number} [config.maxAge=86400] Maximum age for preflight cache in seconds
282
+ * @param {boolean} [config.varyOrigin=true] Add Vary: Origin header for caching
283
+ * @param {boolean} [config.breakPipeline=false] If true, returns Break_Pipeline
284
+ * @param {"status"|"text"|"json"} [config.responseType="text"] Response type
276
285
  * @returns {Handler<ExtendContext>} Middleware function that handles CORS headers
277
286
  *
278
287
  * @throws {HttpError} If credentials is enabled with wildcard origin ("*")
@@ -292,7 +301,12 @@ exports.limitRate = limitRate;
292
301
  *
293
302
  */
294
303
  const cors = (config) => {
295
- const { origins = "*", methods: methods_ = ["Get", "Head", "Put", "Patch", "Post", "Delete"], allowedHeaders = ["Content-Type", "Authorization"], exposedHeaders, credentials = false, maxAge = 86400, varyOrigin = true, breakPipeline = false, } = config !== null && config !== void 0 ? config : {};
304
+ const { origins = "*", methods: methods_ = ["Get", "Head", "Put", "Patch", "Post", "Delete"], allowedHeaders = ["Content-Type", "Authorization"], exposedHeaders, credentials = false, maxAge = 86400, varyOrigin = true, breakPipeline = false, responseType = "text", } = config !== null && config !== void 0 ? config : {};
305
+ const respond = responseType === "json"
306
+ ? (code, content, key, tag, init) => (0, helpers_ts_1.json)({ [key]: `${tag}: ${content}`, tag }, Object.assign(Object.assign({}, init), { status: code }))
307
+ : responseType === "text"
308
+ ? (code, content, key, tag, init) => (0, helpers_ts_1.text)(`[${key}] ${tag}: ${content}`, Object.assign(Object.assign({}, init), { status: code }))
309
+ : (code, _content, _key, _tag, init) => (0, helpers_ts_1.status)(code, null, init);
296
310
  const globOrigin = origins === "*" ? "*" : null;
297
311
  const originsSet = new Set(origins === "*" ? [] : typeof origins === "string" ? [origins] : origins);
298
312
  const methods = methods_ === null || methods_ === void 0 ? void 0 : methods_.map((m) => m.toUpperCase());
@@ -324,7 +338,7 @@ const cors = (config) => {
324
338
  headers.set("Access-Control-Allow-Origin", corsOrigin);
325
339
  if (credentials) {
326
340
  if (corsOrigin === "*")
327
- throw new types_ts_1.HttpError(403, "CORS: Cannot use credentials with wildcard origin");
341
+ throw new types_ts_1.HttpError(status_ts_1.Status._403_Forbidden, "CORS: Cannot use credentials with wildcard origin");
328
342
  headers.set("Access-Control-Allow-Credentials", "true");
329
343
  }
330
344
  if (exposedHeaders && exposedHeaders.length > 0) {
@@ -338,7 +352,7 @@ const cors = (config) => {
338
352
  const requestMethod = request.headers.get("Access-Control-Request-Method");
339
353
  if (requestMethod &&
340
354
  !methods.includes(requestMethod)) {
341
- return (0, helpers_ts_1.status)(405, `Method ${requestMethod} not allowed`);
355
+ return respond(status_ts_1.Status._405_MethodNotAllowed, `Method ${requestMethod} not allowed`, "error", "CORS");
342
356
  }
343
357
  headers.set("Access-Control-Allow-Methods", methods.join(", "));
344
358
  }
@@ -348,7 +362,7 @@ const cors = (config) => {
348
362
  if (maxAge != null) {
349
363
  headers.set("Access-Control-Max-Age", maxAge.toString());
350
364
  }
351
- return (0, helpers_ts_1.status)(204, null);
365
+ return (0, helpers_ts_1.status)(status_ts_1.Status._204_NoContent, null);
352
366
  }
353
367
  if (breakPipeline) {
354
368
  return types_ts_1.Break_Pipeline;
@@ -356,4 +370,540 @@ const cors = (config) => {
356
370
  };
357
371
  };
358
372
  exports.cors = cors;
373
+ /**
374
+ * Creates a request params, query and body validator middleware function
375
+ *
376
+ * @param {Validator<Record<string, string>,ExtendContext>} [config.params] Parameters validator
377
+ * @param {CustomErrorType} [config.paramsErrors] Parameters validator's expected error instance types other than Error derivatives
378
+ * @param {boolean|ValidateQueryParser<ExtendContext>} [config.queryParse] Parse query before validation. 'true' for default parser or provide a custom parser
379
+ * @param {Validator<Record<string, string>,ExtendContext>} [config.query] Query validator
380
+ * @param {CustomErrorType} [config.queryErrors] Query validator's expected error instance types other than Error derivatives
381
+ * @param {boolean|ValidateCookieParser<ExtendContext>} [config.cookieParse] Parse cookie before validation. 'true' for default parser or provide a custom parser
382
+ * @param {Validator<Record<string, string>,ExtendContext>} [config.cookie] Cookie validator
383
+ * @param {CustomErrorType} [config.cookieErrors] Cookie validator's expected error instance types other than Error derivatives
384
+ * @param {ParseBodyOptions} [config.bodyParseOptions] Body parser options
385
+ * @param {boolean|ValidateBodyParser<ExtendContext>} [config.bodyParse] Parse body before validation. 'true' for default parser or provide a custom parser
386
+ * @param {ValidatorFnIt<ParsedBody,ExtendContext>|Array<ValidatorIt<ParsedBody,ExtendContext>>} [config.body] Body validator
387
+ * @param {CustomErrorType} [config.bodyErrors] Body validator's expected error instance types other than Error derivatives
388
+ * @param {Array<CustomErrorType>} [config.errors] All validator's expected error instance types other than Error derivatives. Can be overridden.
389
+ * @param {boolean} [config.paramsReassign] Reassign validated return value of the params validator function
390
+ * @param {boolean} [config.queryReassign] Reassign validated return value of the query validator function
391
+ * @param {boolean} [config.cookieReassign] Reassign validated return value of the cookie validator function
392
+ * @param {boolean} [config.bodyReassign] Reassign validated return value of the body validator function
393
+ * @param {boolean|{<Target extends Record<string, unknown>>(target: Target,key: string,):void|any;}} [config.strangeParams] Handle strange or unexpected properties
394
+ * @param {boolean|{<Target extends Record<string, unknown>>(target: Target,key: string,):void|any;}} [config.strangeQuery] Handle strange or unexpected properties
395
+ * @param {boolean|{<Target extends Record<string, unknown>>(target: Target,key: string,):void|any;}} [config.strangeCookie] Handle strange or unexpected properties
396
+ * @param {boolean|{<Target extends Record<string, unknown>>(target: Target,key: string,):void|any;}} [config.strangeBody] Handle strange or unexpected properties
397
+ * @param {boolean|{<Target extends Record<string, unknown>>(target: Target,key: string,):void|any;}} [config.strange] A default common option to handle strange or unexpected properties
398
+ * @param {"status"|"text"|"json"} [config.responseType="text"] Response type.
399
+ * - Note: 'status' type will omit content
400
+ * @param {boolean} [config.breakPipeline=false] If true, returns Break_Pipeline
401
+ * @returns {HandlerReturn}
402
+ */
403
+ const validate = ({ responseType = "text", errors, paramsReassign = false, params: paramsValidator, paramsErrors, strangeParams, queryParse, queryReassign = false, query: queryValidator, queryErrors, strangeQuery, cookieParse, cookieReassign = false, cookie: cookieValidator, cookieErrors, strangeCookie, bodyParse, bodyParseOptions, bodyReassign = false, body: bodyValidator, bodyErrors, strangeBody, strange, breakPipeline = false, }) => {
404
+ paramsErrors = paramsErrors !== null && paramsErrors !== void 0 ? paramsErrors : errors;
405
+ queryErrors = queryErrors !== null && queryErrors !== void 0 ? queryErrors : errors;
406
+ cookieErrors = cookieErrors !== null && cookieErrors !== void 0 ? cookieErrors : errors;
407
+ bodyErrors = bodyErrors !== null && bodyErrors !== void 0 ? bodyErrors : errors;
408
+ const errorMatches = (target, errors) => {
409
+ for (const error of errors) {
410
+ if (target instanceof error) {
411
+ return true;
412
+ }
413
+ }
414
+ return false;
415
+ };
416
+ // Validate error instance types
417
+ if (errors) {
418
+ for (let i = 0; i < errors.length; i++) {
419
+ const error = errors[i];
420
+ if (!(typeof error === "function")) {
421
+ throw new TypeError(`Validator errors type at index ${i} is invalid`);
422
+ }
423
+ }
424
+ }
425
+ if (paramsErrors) {
426
+ for (let i = 0; i < paramsErrors.length; i++) {
427
+ const error = paramsErrors[i];
428
+ if (!(typeof error === "function")) {
429
+ throw new TypeError(`Validator paramsErrors type at index ${i} is invalid`);
430
+ }
431
+ }
432
+ }
433
+ if (queryErrors) {
434
+ for (let i = 0; i < queryErrors.length; i++) {
435
+ const error = queryErrors[i];
436
+ if (!(typeof error === "function")) {
437
+ throw new TypeError(`Validator queryErrors type at index ${i} is invalid`);
438
+ }
439
+ }
440
+ }
441
+ if (cookieErrors) {
442
+ for (let i = 0; i < cookieErrors.length; i++) {
443
+ const error = cookieErrors[i];
444
+ if (!(typeof error === "function")) {
445
+ throw new TypeError(`Validator cookieErrors type at index ${i} is invalid`);
446
+ }
447
+ }
448
+ }
449
+ if (bodyErrors) {
450
+ for (let i = 0; i < bodyErrors.length; i++) {
451
+ const error = bodyErrors[i];
452
+ if (!(typeof error === "function")) {
453
+ throw new TypeError(`Validator bodyErrors type at index ${i} is invalid`);
454
+ }
455
+ }
456
+ }
457
+ //
458
+ strangeParams = strangeParams !== null && strangeParams !== void 0 ? strangeParams : strange;
459
+ strangeQuery = strangeQuery !== null && strangeQuery !== void 0 ? strangeQuery : strange;
460
+ strangeCookie = strangeCookie !== null && strangeCookie !== void 0 ? strangeCookie : strange;
461
+ strangeBody = strangeBody !== null && strangeBody !== void 0 ? strangeBody : strange;
462
+ // Validate strangeParams
463
+ if (strangeParams != undefined &&
464
+ typeof strangeParams !== "boolean" &&
465
+ typeof strangeParams !== "function") {
466
+ throw new TypeError("Validator strangeParams type must be either boolean, undefined or a function");
467
+ }
468
+ // Validate strangeQuery
469
+ if (strangeQuery != undefined &&
470
+ typeof strangeQuery !== "boolean" &&
471
+ typeof strangeQuery !== "function") {
472
+ throw new TypeError("Validator strangeQuery type must be either boolean, undefined or a function");
473
+ }
474
+ // Validate strangeCookie
475
+ if (strangeCookie != undefined &&
476
+ typeof strangeCookie !== "boolean" &&
477
+ typeof strangeCookie !== "function") {
478
+ throw new TypeError("Validator strangeCookie type must be either boolean, undefined or a function");
479
+ }
480
+ // Validate strangeBody
481
+ if (strangeBody != undefined &&
482
+ typeof strangeBody !== "boolean" &&
483
+ typeof strangeBody !== "function") {
484
+ throw new TypeError("Validator strangeBody type must be either boolean, undefined or a function");
485
+ }
486
+ // Validate query parser
487
+ if (queryParse != undefined &&
488
+ typeof queryParse !== "boolean" &&
489
+ typeof queryParse !== "function") {
490
+ throw new TypeError("Validator queryParse type must be either boolean, undefined or a function");
491
+ }
492
+ // Validate cookie parser
493
+ if (cookieParse != undefined &&
494
+ typeof cookieParse !== "boolean" &&
495
+ typeof cookieParse !== "function") {
496
+ throw new TypeError("Validator cookieParse type must be either boolean, undefined or a function");
497
+ }
498
+ // Validate body parser
499
+ if (parsers_ts_1.parseBody != undefined &&
500
+ typeof parsers_ts_1.parseBody !== "boolean" &&
501
+ typeof parsers_ts_1.parseBody !== "function") {
502
+ throw new TypeError("Validator parseBody type must be either boolean, undefined or a function");
503
+ }
504
+ const respond = responseType === "json"
505
+ ? (code, content, key, tag, init) => (0, helpers_ts_1.json)({ [key]: `${tag}: ${content}`, tag }, Object.assign(Object.assign({}, init), { status: code }))
506
+ : responseType === "text"
507
+ ? (code, content, key, tag, init) => (0, helpers_ts_1.text)(`[${key}] ${tag}: ${content}`, Object.assign(Object.assign({}, init), { status: code }))
508
+ : (code, _content, _key, _tag, init) => (0, helpers_ts_1.status)(code, null, init);
509
+ //
510
+ // Prepare parsers
511
+ //
512
+ const queryParser = queryParse === true
513
+ ? ((ctx) => {
514
+ if (ctx.query == null) {
515
+ ctx.query = {};
516
+ }
517
+ const searchParams = ctx.url.searchParams;
518
+ for (const key of searchParams.keys()) {
519
+ const values = searchParams.getAll(key);
520
+ ctx.query[key] =
521
+ values.length > 1 ? values[values.length - 1] : values[0];
522
+ }
523
+ })
524
+ : queryParse || undefined;
525
+ const cookieParser = cookieParse === true
526
+ ? ((ctx) => {
527
+ if (ctx.cookie == null) {
528
+ ctx.cookie = {};
529
+ }
530
+ (0, parsers_ts_1.parseCookieFromRequest)(ctx.request, ctx.cookie);
531
+ })
532
+ : cookieParse || undefined;
533
+ const bodyParser = bodyParse === true
534
+ ? (0, parsers_ts_1.parseBody)(bodyParseOptions)
535
+ : bodyParse || undefined;
536
+ ///////////////////////////////////////////////////////////////////////////
537
+ // Validate params validators
538
+ const paramsValidatorIsFunction = typeof paramsValidator === "function";
539
+ const paramsValidatorIsObject = typeof paramsValidator === "object" && !Array.isArray(paramsValidator);
540
+ if (paramsValidator) {
541
+ if (!paramsValidatorIsFunction && !paramsValidatorIsObject) {
542
+ throw new TypeError("Params validator type must be function or object");
543
+ }
544
+ else if (paramsValidatorIsObject) {
545
+ for (const key of Object.keys(paramsValidator)) {
546
+ if (typeof paramsValidator[key] !== "function") {
547
+ throw new TypeError(`Params validator property type must be function at '${key}'`);
548
+ }
549
+ }
550
+ }
551
+ }
552
+ // Validate query validators
553
+ const queryValidatorIsFunction = typeof queryValidator === "function";
554
+ const queryValidatorIsObject = typeof queryValidator === "object" && !Array.isArray(queryValidator);
555
+ if (queryValidator) {
556
+ if (!queryValidatorIsFunction && !queryValidatorIsObject) {
557
+ throw new TypeError("Query validator type must be function or object");
558
+ }
559
+ else if (queryValidatorIsObject) {
560
+ for (const key of Object.keys(queryValidator)) {
561
+ if (typeof queryValidator[key] !== "function") {
562
+ throw new TypeError(`Query validator property type must be function at '${key}'`);
563
+ }
564
+ }
565
+ }
566
+ }
567
+ // Validate cookie validators
568
+ const cookieValidatorIsFunction = typeof cookieValidator === "function";
569
+ const cookieValidatorIsObject = typeof cookieValidator === "object" && !Array.isArray(cookieValidator);
570
+ if (cookieValidator) {
571
+ if (!cookieValidatorIsFunction && !cookieValidatorIsObject) {
572
+ throw new TypeError("Cookie validator type must be function or object");
573
+ }
574
+ else if (cookieValidatorIsObject) {
575
+ for (const key of Object.keys(cookieValidator)) {
576
+ if (typeof cookieValidator[key] !== "function") {
577
+ throw new TypeError(`Cookie validator property type must be function at '${key}'`);
578
+ }
579
+ }
580
+ }
581
+ }
582
+ // Validate body validators
583
+ const bodyValidatorIsFunction = typeof bodyValidator === "function";
584
+ const bodyValidatorIsArray = Array.isArray(bodyValidator);
585
+ const bodyValidatorIsObject = typeof bodyValidator === "object" && !bodyValidatorIsArray;
586
+ const bodyValidators = bodyValidator
587
+ ? Array.isArray(bodyValidator)
588
+ ? bodyValidator
589
+ : [bodyValidator]
590
+ : undefined;
591
+ if (bodyValidators) {
592
+ if (!bodyValidatorIsFunction &&
593
+ !bodyValidatorIsObject &&
594
+ !bodyValidatorIsArray) {
595
+ throw new TypeError("Body validator type must be function or object or array of objects");
596
+ }
597
+ else if (bodyValidatorIsArray && bodyValidators.length === 0) {
598
+ throw new TypeError("Body validator must not be an empty array");
599
+ }
600
+ for (let i = 0; i < bodyValidators.length; i++) {
601
+ const validator = bodyValidators[i];
602
+ const bodyValidatorIsFunction = typeof validator === "function";
603
+ const validatorIsObject = typeof validator === "object" && !Array.isArray(validator);
604
+ if (!bodyValidatorIsFunction && !validatorIsObject) {
605
+ throw new TypeError(bodyValidators.length > 0
606
+ ? `Body validator must be a valid function or object at ${i}`
607
+ : "Body validator must be a valid function or object");
608
+ }
609
+ else if (validatorIsObject) {
610
+ for (const key of Object.keys(validator)) {
611
+ if (typeof validator[key] !== "function") {
612
+ throw new TypeError(bodyValidatorIsArray
613
+ ? `Body validator property type must be function at index ${i} '${key}'`
614
+ : `Body validator property type must be function at '${key}'`);
615
+ }
616
+ }
617
+ }
618
+ }
619
+ }
620
+ ////////////////////////////////////////////////////////////////////////
621
+ return (ctx) => __awaiter(void 0, void 0, void 0, function* () {
622
+ const params = ctx.params;
623
+ // Validate Params
624
+ if (paramsValidatorIsFunction) {
625
+ const result = paramsValidator.apply
626
+ ? paramsValidator.apply(ctx, params)
627
+ : paramsValidator(params);
628
+ if (result instanceof Error) {
629
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "params", "error");
630
+ }
631
+ else if (paramsErrors && errorMatches(result, paramsErrors)) {
632
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "params");
633
+ }
634
+ else if (result instanceof Response ||
635
+ result === types_ts_1.Break_Pipe ||
636
+ result === types_ts_1.Break_Pipeline) {
637
+ return result;
638
+ }
639
+ else if (paramsReassign) {
640
+ ctx.params = result;
641
+ }
642
+ }
643
+ else if (paramsValidatorIsObject) {
644
+ for (const key of Object.keys(params)) {
645
+ const validator = paramsValidator[key];
646
+ if (validator == null && !strangeParams) {
647
+ continue;
648
+ }
649
+ const result = validator == null
650
+ ? typeof strangeParams === "function"
651
+ ? strangeParams(params, key)
652
+ : params[key]
653
+ : validator.apply
654
+ ? validator.apply(ctx, params[key])
655
+ : validator(params[key]);
656
+ if (result instanceof Error) {
657
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "params");
658
+ }
659
+ else if (paramsErrors && errorMatches(result, paramsErrors)) {
660
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "params");
661
+ }
662
+ else if (result instanceof Response ||
663
+ result === types_ts_1.Break_Pipe ||
664
+ result === types_ts_1.Break_Pipeline) {
665
+ return result;
666
+ }
667
+ else if (paramsReassign) {
668
+ params[key] = result;
669
+ }
670
+ }
671
+ }
672
+ // Parse query
673
+ if (queryParser) {
674
+ yield queryParser(ctx);
675
+ }
676
+ const query = ctx.query;
677
+ // Validate Query
678
+ if (queryValidatorIsFunction) {
679
+ const result = queryValidator.apply
680
+ ? queryValidator.apply(ctx, query)
681
+ : queryValidator(query);
682
+ if (result instanceof Error) {
683
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "query");
684
+ }
685
+ else if (queryErrors && errorMatches(result, queryErrors)) {
686
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "query");
687
+ }
688
+ else if (result instanceof Response ||
689
+ result === types_ts_1.Break_Pipe ||
690
+ result === types_ts_1.Break_Pipeline) {
691
+ return result;
692
+ }
693
+ else if (queryReassign) {
694
+ ctx.query = result;
695
+ }
696
+ }
697
+ else if (queryValidatorIsObject) {
698
+ for (const key of Object.keys(query)) {
699
+ const validator = queryValidator[key];
700
+ if (validator == null && !strangeQuery) {
701
+ continue;
702
+ }
703
+ const result = validator == null
704
+ ? typeof strangeQuery === "function"
705
+ ? strangeQuery(query, key)
706
+ : query[key]
707
+ : validator.apply
708
+ ? validator.apply(ctx, query[key])
709
+ : validator(query[key]);
710
+ if (result instanceof Error) {
711
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "query");
712
+ }
713
+ else if (queryErrors && errorMatches(result, queryErrors)) {
714
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "query");
715
+ }
716
+ else if (result instanceof Response ||
717
+ result === types_ts_1.Break_Pipe ||
718
+ result === types_ts_1.Break_Pipeline) {
719
+ return result;
720
+ }
721
+ else if (queryReassign) {
722
+ query[key] = result;
723
+ }
724
+ }
725
+ }
726
+ // Parse cookie
727
+ if (cookieParser) {
728
+ yield cookieParser(ctx);
729
+ }
730
+ const cookie = ctx.cookie;
731
+ // Validate Cookie
732
+ if (cookieValidatorIsFunction) {
733
+ const result = cookieValidator.apply
734
+ ? cookieValidator.apply(ctx, cookie)
735
+ : cookieValidator(cookie);
736
+ if (result instanceof Error) {
737
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "cookie");
738
+ }
739
+ else if (cookieErrors && errorMatches(result, cookieErrors)) {
740
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "cookie");
741
+ }
742
+ else if (result instanceof Response ||
743
+ result === types_ts_1.Break_Pipe ||
744
+ result === types_ts_1.Break_Pipeline) {
745
+ return result;
746
+ }
747
+ else if (cookieReassign) {
748
+ ctx.cookie = result;
749
+ }
750
+ }
751
+ else if (cookieValidatorIsObject) {
752
+ for (const key of Object.keys(cookie)) {
753
+ const validator = cookieValidator[key];
754
+ if (validator == null && !strangeCookie) {
755
+ continue;
756
+ }
757
+ const result = validator == null
758
+ ? typeof strangeCookie === "function"
759
+ ? strangeCookie(cookie, key)
760
+ : cookie[key]
761
+ : validator.apply
762
+ ? validator.apply(ctx, cookie[key])
763
+ : validator(cookie[key]);
764
+ if (result instanceof Error) {
765
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "cookie");
766
+ }
767
+ else if (cookieErrors && errorMatches(result, cookieErrors)) {
768
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "cookie");
769
+ }
770
+ else if (result instanceof Response ||
771
+ result === types_ts_1.Break_Pipe ||
772
+ result === types_ts_1.Break_Pipeline) {
773
+ return result;
774
+ }
775
+ else if (cookieReassign) {
776
+ cookie[key] = result;
777
+ }
778
+ }
779
+ }
780
+ // Parse body
781
+ if (bodyParser) {
782
+ yield bodyParser(ctx);
783
+ }
784
+ const body = ctx.body;
785
+ // Validate Body
786
+ if (bodyValidators) {
787
+ if (Array.isArray(body)) {
788
+ for (let i = 0; i < body.length; i++) {
789
+ const validator = bodyValidators[i % bodyValidators.length];
790
+ const activeBody = body[i];
791
+ if (typeof validator === "function") {
792
+ const result = validator.apply(ctx, activeBody);
793
+ if (result instanceof Error) {
794
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "body");
795
+ }
796
+ else if (bodyErrors && errorMatches(result, bodyErrors)) {
797
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "body");
798
+ }
799
+ else if (result instanceof Response ||
800
+ result === types_ts_1.Break_Pipe ||
801
+ result === types_ts_1.Break_Pipeline) {
802
+ return result;
803
+ }
804
+ else if (bodyReassign) {
805
+ body[i] = result;
806
+ }
807
+ }
808
+ else if (validator) {
809
+ if (activeBody &&
810
+ typeof activeBody === "object" &&
811
+ !Array.isArray(activeBody)) {
812
+ for (const key of Object.keys(activeBody)) {
813
+ const propValidator = validator[key];
814
+ if (propValidator == null && !strangeBody) {
815
+ continue;
816
+ }
817
+ const result = propValidator == null
818
+ ? typeof strangeBody === "function"
819
+ ? strangeBody(activeBody, key)
820
+ : activeBody[key]
821
+ : propValidator.apply
822
+ ? propValidator.apply(ctx, activeBody[key])
823
+ : propValidator(activeBody[key]);
824
+ if (result instanceof Error) {
825
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "body");
826
+ }
827
+ else if (bodyErrors && errorMatches(result, bodyErrors)) {
828
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "body");
829
+ }
830
+ else if (result instanceof Response ||
831
+ result === types_ts_1.Break_Pipe ||
832
+ result === types_ts_1.Break_Pipeline) {
833
+ return result;
834
+ }
835
+ else if (bodyReassign) {
836
+ activeBody[key] = result;
837
+ }
838
+ }
839
+ }
840
+ else {
841
+ return respond(status_ts_1.Status._400_BadRequest, `Invalid body type at index ${i}`, "error", "body");
842
+ }
843
+ }
844
+ }
845
+ }
846
+ else {
847
+ const validator = bodyValidators[0];
848
+ if (typeof validator === "function") {
849
+ const result = validator.apply
850
+ ? validator.apply(ctx, body)
851
+ : validator(body);
852
+ if (result instanceof Error) {
853
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "body");
854
+ }
855
+ else if (bodyErrors && errorMatches(result, bodyErrors)) {
856
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "body");
857
+ }
858
+ else if (result instanceof Response ||
859
+ result === types_ts_1.Break_Pipe ||
860
+ result === types_ts_1.Break_Pipeline) {
861
+ return result;
862
+ }
863
+ else if (bodyReassign) {
864
+ ctx.body = result;
865
+ }
866
+ }
867
+ else if (validator) {
868
+ if (body && typeof body === "object" && !Array.isArray(body)) {
869
+ for (const key of Object.keys(body)) {
870
+ const propValidator = validator[key];
871
+ if (propValidator == null && !strangeBody) {
872
+ continue;
873
+ }
874
+ const result = propValidator == null
875
+ ? typeof strangeBody === "function"
876
+ ? strangeBody(body, key)
877
+ : body
878
+ : propValidator.apply
879
+ ? propValidator.apply(ctx, body[key])
880
+ : propValidator(body[key]);
881
+ if (result instanceof Error) {
882
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "body");
883
+ }
884
+ else if (bodyErrors && errorMatches(result, bodyErrors)) {
885
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "body");
886
+ }
887
+ else if (result instanceof Response ||
888
+ result === types_ts_1.Break_Pipe ||
889
+ result === types_ts_1.Break_Pipeline) {
890
+ return result;
891
+ }
892
+ else if (bodyReassign) {
893
+ body[key] = result;
894
+ }
895
+ }
896
+ }
897
+ else {
898
+ return respond(status_ts_1.Status._400_BadRequest, "Invalid body type", "error", "body");
899
+ }
900
+ }
901
+ }
902
+ }
903
+ if (breakPipeline) {
904
+ return types_ts_1.Break_Pipeline;
905
+ }
906
+ });
907
+ };
908
+ exports.validate = validate;
359
909
  //# sourceMappingURL=middlewares.js.map