@bepalo/spine 2.6.18 → 2.8.20

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 +173 -21
  5. package/dist/cjs/middlewares.d.ts.map +1 -1
  6. package/dist/cjs/middlewares.js +628 -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 +173 -21
  26. package/dist/middlewares.d.ts.map +1 -1
  27. package/dist/middlewares.js +628 -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 +10 -3
@@ -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,590 @@ 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.paramsMutation] Modify object with validated return value of the params validator function
390
+ * @param {boolean} [config.queryMutation] Modify object with validated return value of the query validator function
391
+ * @param {boolean} [config.cookieMutation] Modify object with validated return value of the cookie validator function
392
+ * @param {boolean} [config.bodyMutation] Modify object with 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
+ * - If false excludes strange properties from the mutated object.
395
+ * @param {boolean|{<Target extends Record<string, unknown>>(target: Target,key: string,):void|any;}} [config.strangeQuery] Handle strange or unexpected properties.
396
+ * - If false excludes strange properties from the mutated object.
397
+ * @param {boolean|{<Target extends Record<string, unknown>>(target: Target,key: string,):void|any;}} [config.strangeCookie] Handle strange or unexpected properties.
398
+ * - If false excludes strange properties from the mutated object.
399
+ * @param {boolean|{<Target extends Record<string, unknown>>(target: Target,key: string,):void|any;}} [config.strangeBody] Handle strange or unexpected properties.
400
+ * - If false excludes strange properties from the mutated object.
401
+ * @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.
402
+ * - If false excludes strange properties from the mutated object.
403
+ * @param {"status"|"text"|"json"} [config.responseType="text"] Response type.
404
+ * - Note: 'status' type will omit content
405
+ * @param {boolean} [config.breakPipeline=false] If true, returns Break_Pipeline
406
+ * @returns {HandlerReturn}
407
+ */
408
+ const validate = ({ responseType = "text", errors, paramsMutation = false, params: paramsValidator, paramsErrors, strangeParams, queryParse, queryMutation = false, query: queryValidator, queryErrors, strangeQuery, cookieParse, cookieMutation = false, cookie: cookieValidator, cookieErrors, strangeCookie, bodyParse, bodyParseOptions, bodyMutation = false, body: bodyValidator, bodyErrors, strangeBody, strange, breakPipeline = false, }) => {
409
+ paramsErrors = paramsErrors !== null && paramsErrors !== void 0 ? paramsErrors : errors;
410
+ queryErrors = queryErrors !== null && queryErrors !== void 0 ? queryErrors : errors;
411
+ cookieErrors = cookieErrors !== null && cookieErrors !== void 0 ? cookieErrors : errors;
412
+ bodyErrors = bodyErrors !== null && bodyErrors !== void 0 ? bodyErrors : errors;
413
+ const errorMatches = (target, errors) => {
414
+ for (const error of errors) {
415
+ if (target instanceof error) {
416
+ return true;
417
+ }
418
+ }
419
+ return false;
420
+ };
421
+ // Validate error instance types
422
+ if (errors) {
423
+ for (let i = 0; i < errors.length; i++) {
424
+ const error = errors[i];
425
+ if (!(typeof error === "function")) {
426
+ throw new TypeError(`Validator errors type at index ${i} is invalid`);
427
+ }
428
+ }
429
+ }
430
+ if (paramsErrors) {
431
+ for (let i = 0; i < paramsErrors.length; i++) {
432
+ const error = paramsErrors[i];
433
+ if (!(typeof error === "function")) {
434
+ throw new TypeError(`Validator paramsErrors type at index ${i} is invalid`);
435
+ }
436
+ }
437
+ }
438
+ if (queryErrors) {
439
+ for (let i = 0; i < queryErrors.length; i++) {
440
+ const error = queryErrors[i];
441
+ if (!(typeof error === "function")) {
442
+ throw new TypeError(`Validator queryErrors type at index ${i} is invalid`);
443
+ }
444
+ }
445
+ }
446
+ if (cookieErrors) {
447
+ for (let i = 0; i < cookieErrors.length; i++) {
448
+ const error = cookieErrors[i];
449
+ if (!(typeof error === "function")) {
450
+ throw new TypeError(`Validator cookieErrors type at index ${i} is invalid`);
451
+ }
452
+ }
453
+ }
454
+ if (bodyErrors) {
455
+ for (let i = 0; i < bodyErrors.length; i++) {
456
+ const error = bodyErrors[i];
457
+ if (!(typeof error === "function")) {
458
+ throw new TypeError(`Validator bodyErrors type at index ${i} is invalid`);
459
+ }
460
+ }
461
+ }
462
+ //
463
+ strangeParams = strangeParams !== null && strangeParams !== void 0 ? strangeParams : strange;
464
+ strangeQuery = strangeQuery !== null && strangeQuery !== void 0 ? strangeQuery : strange;
465
+ strangeCookie = strangeCookie !== null && strangeCookie !== void 0 ? strangeCookie : strange;
466
+ strangeBody = strangeBody !== null && strangeBody !== void 0 ? strangeBody : strange;
467
+ // Validate strangeParams
468
+ if (strangeParams != undefined &&
469
+ typeof strangeParams !== "boolean" &&
470
+ typeof strangeParams !== "function") {
471
+ throw new TypeError("Validator strangeParams type must be either boolean, undefined or a function");
472
+ }
473
+ // Validate strangeQuery
474
+ if (strangeQuery != undefined &&
475
+ typeof strangeQuery !== "boolean" &&
476
+ typeof strangeQuery !== "function") {
477
+ throw new TypeError("Validator strangeQuery type must be either boolean, undefined or a function");
478
+ }
479
+ // Validate strangeCookie
480
+ if (strangeCookie != undefined &&
481
+ typeof strangeCookie !== "boolean" &&
482
+ typeof strangeCookie !== "function") {
483
+ throw new TypeError("Validator strangeCookie type must be either boolean, undefined or a function");
484
+ }
485
+ // Validate strangeBody
486
+ if (strangeBody != undefined &&
487
+ typeof strangeBody !== "boolean" &&
488
+ typeof strangeBody !== "function") {
489
+ throw new TypeError("Validator strangeBody type must be either boolean, undefined or a function");
490
+ }
491
+ // Validate query parser
492
+ if (queryParse != undefined &&
493
+ typeof queryParse !== "boolean" &&
494
+ typeof queryParse !== "function") {
495
+ throw new TypeError("Validator queryParse type must be either boolean, undefined or a function");
496
+ }
497
+ // Validate cookie parser
498
+ if (cookieParse != undefined &&
499
+ typeof cookieParse !== "boolean" &&
500
+ typeof cookieParse !== "function") {
501
+ throw new TypeError("Validator cookieParse type must be either boolean, undefined or a function");
502
+ }
503
+ // Validate body parser
504
+ if (bodyParse != undefined &&
505
+ typeof bodyParse !== "boolean" &&
506
+ typeof bodyParse !== "function") {
507
+ throw new TypeError("Validator bodyParse type must be either boolean, undefined or a function");
508
+ }
509
+ const respond = responseType === "json"
510
+ ? (code, content, key, tag, init) => (0, helpers_ts_1.json)({ [key]: `${tag}: ${content}`, tag }, Object.assign(Object.assign({}, init), { status: code }))
511
+ : responseType === "text"
512
+ ? (code, content, key, tag, init) => (0, helpers_ts_1.text)(`[${key}] ${tag}: ${content}`, Object.assign(Object.assign({}, init), { status: code }))
513
+ : (code, _content, _key, _tag, init) => (0, helpers_ts_1.status)(code, null, init);
514
+ //
515
+ // Prepare parsers
516
+ //
517
+ const queryParser = queryParse === true
518
+ ? ((ctx) => {
519
+ if (ctx.query == null) {
520
+ ctx.query = {};
521
+ }
522
+ const searchParams = ctx.url.searchParams;
523
+ for (const key of searchParams.keys()) {
524
+ const values = searchParams.getAll(key);
525
+ ctx.query[key] =
526
+ values.length > 1 ? values[values.length - 1] : values[0];
527
+ }
528
+ })
529
+ : queryParse || undefined;
530
+ const cookieParser = cookieParse === true
531
+ ? ((ctx) => {
532
+ if (ctx.cookie == null) {
533
+ ctx.cookie = {};
534
+ }
535
+ (0, parsers_ts_1.parseCookieFromRequest)(ctx.request, ctx.cookie);
536
+ })
537
+ : cookieParse || undefined;
538
+ const bodyParser = bodyParse === true
539
+ ? (0, parsers_ts_1.parseBody)(bodyParseOptions)
540
+ : bodyParse || undefined;
541
+ ///////////////////////////////////////////////////////////////////////////
542
+ // Validate params validators
543
+ const paramsValidatorIsFunction = typeof paramsValidator === "function";
544
+ const paramsValidatorIsObject = typeof paramsValidator === "object" && !Array.isArray(paramsValidator);
545
+ if (paramsValidator) {
546
+ if (!paramsValidatorIsFunction && !paramsValidatorIsObject) {
547
+ throw new TypeError("Params validator type must be function or object");
548
+ }
549
+ else if (paramsValidatorIsObject) {
550
+ for (const key of Object.keys(paramsValidator)) {
551
+ if (typeof paramsValidator[key] !== "function") {
552
+ throw new TypeError(`Params validator property type must be function at '${key}'`);
553
+ }
554
+ }
555
+ }
556
+ }
557
+ // Validate query validators
558
+ const queryValidatorIsFunction = typeof queryValidator === "function";
559
+ const queryValidatorIsObject = typeof queryValidator === "object" && !Array.isArray(queryValidator);
560
+ if (queryValidator) {
561
+ if (!queryValidatorIsFunction && !queryValidatorIsObject) {
562
+ throw new TypeError("Query validator type must be function or object");
563
+ }
564
+ else if (queryValidatorIsObject) {
565
+ for (const key of Object.keys(queryValidator)) {
566
+ if (typeof queryValidator[key] !== "function") {
567
+ throw new TypeError(`Query validator property type must be function at '${key}'`);
568
+ }
569
+ }
570
+ }
571
+ }
572
+ // Validate cookie validators
573
+ const cookieValidatorIsFunction = typeof cookieValidator === "function";
574
+ const cookieValidatorIsObject = typeof cookieValidator === "object" && !Array.isArray(cookieValidator);
575
+ if (cookieValidator) {
576
+ if (!cookieValidatorIsFunction && !cookieValidatorIsObject) {
577
+ throw new TypeError("Cookie validator type must be function or object");
578
+ }
579
+ else if (cookieValidatorIsObject) {
580
+ for (const key of Object.keys(cookieValidator)) {
581
+ if (typeof cookieValidator[key] !== "function") {
582
+ throw new TypeError(`Cookie validator property type must be function at '${key}'`);
583
+ }
584
+ }
585
+ }
586
+ }
587
+ // Validate body validators
588
+ const bodyValidatorIsFunction = typeof bodyValidator === "function";
589
+ const bodyValidatorIsArray = Array.isArray(bodyValidator);
590
+ const bodyValidatorIsObject = typeof bodyValidator === "object" && !bodyValidatorIsArray;
591
+ const bodyValidators = bodyValidator
592
+ ? Array.isArray(bodyValidator)
593
+ ? bodyValidator
594
+ : [bodyValidator]
595
+ : undefined;
596
+ if (bodyValidators) {
597
+ if (!bodyValidatorIsFunction &&
598
+ !bodyValidatorIsObject &&
599
+ !bodyValidatorIsArray) {
600
+ throw new TypeError("Body validator type must be function or object or array of objects");
601
+ }
602
+ else if (bodyValidatorIsArray && bodyValidators.length === 0) {
603
+ throw new TypeError("Body validator must not be an empty array");
604
+ }
605
+ for (let i = 0; i < bodyValidators.length; i++) {
606
+ const validator = bodyValidators[i];
607
+ const bodyValidatorIsFunction = typeof validator === "function";
608
+ const validatorIsObject = typeof validator === "object" && !Array.isArray(validator);
609
+ if (!bodyValidatorIsFunction && !validatorIsObject) {
610
+ throw new TypeError(bodyValidators.length > 0
611
+ ? `Body validator must be a valid function or object at ${i}`
612
+ : "Body validator must be a valid function or object");
613
+ }
614
+ else if (validatorIsObject) {
615
+ for (const key of Object.keys(validator)) {
616
+ if (typeof validator[key] !== "function") {
617
+ throw new TypeError(bodyValidatorIsArray
618
+ ? `Body validator property type must be function at index ${i} '${key}'`
619
+ : `Body validator property type must be function at '${key}'`);
620
+ }
621
+ }
622
+ }
623
+ }
624
+ }
625
+ ////////////////////////////////////////////////////////////////////////
626
+ return (ctx) => __awaiter(void 0, void 0, void 0, function* () {
627
+ const params = ctx.params;
628
+ // Validate Params
629
+ if (paramsValidatorIsFunction) {
630
+ const result = paramsValidator.bind
631
+ ? paramsValidator.bind(ctx)(params)
632
+ : paramsValidator(params);
633
+ if (result instanceof Error) {
634
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "params-validator");
635
+ }
636
+ else if (paramsErrors && errorMatches(result, paramsErrors)) {
637
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "params-validator");
638
+ }
639
+ else if (result instanceof Response ||
640
+ result === types_ts_1.Break_Pipe ||
641
+ result === types_ts_1.Break_Pipeline) {
642
+ return result;
643
+ }
644
+ else if (paramsMutation) {
645
+ ctx.params = result;
646
+ }
647
+ }
648
+ else if (paramsValidator) {
649
+ const keys = Object.keys(paramsValidator);
650
+ for (const key of Object.keys(params)) {
651
+ if (!(key in paramsValidator)) {
652
+ keys.push(key);
653
+ }
654
+ }
655
+ for (const key of keys) {
656
+ const validator = paramsValidator[key];
657
+ if (validator == null && !strangeParams) {
658
+ continue;
659
+ }
660
+ const result = validator == null
661
+ ? typeof strangeParams === "function"
662
+ ? strangeParams(key, params)
663
+ : params[key]
664
+ : validator.bind
665
+ ? validator.bind(ctx)(params[key])
666
+ : validator(params[key]);
667
+ if (result instanceof Error) {
668
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "params-validator");
669
+ }
670
+ else if (paramsErrors && errorMatches(result, paramsErrors)) {
671
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "params-validator");
672
+ }
673
+ else if (result instanceof Response ||
674
+ result === types_ts_1.Break_Pipe ||
675
+ result === types_ts_1.Break_Pipeline) {
676
+ return result;
677
+ }
678
+ else if (paramsMutation) {
679
+ params[key] = result;
680
+ }
681
+ }
682
+ }
683
+ // Parse query
684
+ if (queryParser) {
685
+ yield queryParser(ctx);
686
+ }
687
+ const query = ctx.query;
688
+ // Validate Query
689
+ if (queryValidatorIsFunction) {
690
+ const result = queryValidator.bind
691
+ ? queryValidator.bind(ctx)(query)
692
+ : queryValidator(query);
693
+ if (result instanceof Error) {
694
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "query-validator");
695
+ }
696
+ else if (queryErrors && errorMatches(result, queryErrors)) {
697
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "query-validator");
698
+ }
699
+ else if (result instanceof Response ||
700
+ result === types_ts_1.Break_Pipe ||
701
+ result === types_ts_1.Break_Pipeline) {
702
+ return result;
703
+ }
704
+ else if (queryMutation) {
705
+ ctx.query = result;
706
+ }
707
+ }
708
+ else if (queryValidator) {
709
+ const keys = Object.keys(queryValidator);
710
+ for (const key of Object.keys(query)) {
711
+ if (!(key in queryValidator)) {
712
+ keys.push(key);
713
+ }
714
+ }
715
+ for (const key of keys) {
716
+ const validator = queryValidator[key];
717
+ if (validator == null && !strangeQuery) {
718
+ continue;
719
+ }
720
+ const result = validator == null
721
+ ? typeof strangeQuery === "function"
722
+ ? strangeQuery(key, query)
723
+ : query[key]
724
+ : validator.bind
725
+ ? validator.bind(ctx)(query[key])
726
+ : validator(query[key]);
727
+ if (result instanceof Error) {
728
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "query-validator");
729
+ }
730
+ else if (queryErrors && errorMatches(result, queryErrors)) {
731
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "query-validator");
732
+ }
733
+ else if (result instanceof Response ||
734
+ result === types_ts_1.Break_Pipe ||
735
+ result === types_ts_1.Break_Pipeline) {
736
+ return result;
737
+ }
738
+ else if (queryMutation) {
739
+ query[key] = result;
740
+ }
741
+ }
742
+ }
743
+ // Parse cookie
744
+ if (cookieParser) {
745
+ yield cookieParser(ctx);
746
+ }
747
+ const cookie = ctx.cookie;
748
+ // Validate Cookie
749
+ if (cookieValidatorIsFunction) {
750
+ const result = cookieValidator.bind
751
+ ? cookieValidator.bind(ctx)(cookie)
752
+ : cookieValidator(cookie);
753
+ if (result instanceof Error) {
754
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "cookie-validator");
755
+ }
756
+ else if (cookieErrors && errorMatches(result, cookieErrors)) {
757
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "cookie-validator");
758
+ }
759
+ else if (result instanceof Response ||
760
+ result === types_ts_1.Break_Pipe ||
761
+ result === types_ts_1.Break_Pipeline) {
762
+ return result;
763
+ }
764
+ else if (cookieMutation) {
765
+ ctx.cookie = result;
766
+ }
767
+ }
768
+ else if (cookieValidator) {
769
+ const keys = Object.keys(cookieValidator);
770
+ for (const key of Object.keys(cookie)) {
771
+ if (!(key in cookieValidator)) {
772
+ keys.push(key);
773
+ }
774
+ }
775
+ for (const key of keys) {
776
+ const validator = cookieValidator[key];
777
+ if (validator == null && !strangeCookie) {
778
+ continue;
779
+ }
780
+ const result = validator == null
781
+ ? typeof strangeCookie === "function"
782
+ ? strangeCookie(key, cookie)
783
+ : cookie[key]
784
+ : validator.bind
785
+ ? validator.bind(ctx)(cookie[key])
786
+ : validator(cookie[key]);
787
+ if (result instanceof Error) {
788
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "cookie-validator");
789
+ }
790
+ else if (cookieErrors && errorMatches(result, cookieErrors)) {
791
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "cookie-validator");
792
+ }
793
+ else if (result instanceof Response ||
794
+ result === types_ts_1.Break_Pipe ||
795
+ result === types_ts_1.Break_Pipeline) {
796
+ return result;
797
+ }
798
+ else if (cookieMutation) {
799
+ cookie[key] = result;
800
+ }
801
+ }
802
+ }
803
+ // Parse body
804
+ if (bodyParser) {
805
+ yield bodyParser(ctx);
806
+ }
807
+ const body = ctx.body;
808
+ // Validate Body
809
+ if (bodyValidators) {
810
+ const bodyIsArray = Array.isArray(body);
811
+ if (bodyValidatorIsArray && !bodyIsArray) {
812
+ return respond(status_ts_1.Status._400_BadRequest, "array body type expected", "error", "body-validator");
813
+ }
814
+ else if (!bodyValidatorIsArray && bodyIsArray) {
815
+ return respond(status_ts_1.Status._400_BadRequest, "object body type expected", "error", "body-validator");
816
+ }
817
+ if (bodyIsArray) {
818
+ for (let i = 0; i < body.length; i++) {
819
+ const validator = bodyValidators[i % bodyValidators.length];
820
+ const activeBody = body[i];
821
+ if (typeof validator === "function") {
822
+ const result = validator.bind
823
+ ? validator.bind(ctx)(activeBody, i)
824
+ : validator(activeBody, i);
825
+ if (result instanceof Error) {
826
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "body-validator");
827
+ }
828
+ else if (bodyErrors && errorMatches(result, bodyErrors)) {
829
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "body-validator");
830
+ }
831
+ else if (result instanceof Response ||
832
+ result === types_ts_1.Break_Pipe ||
833
+ result === types_ts_1.Break_Pipeline) {
834
+ return result;
835
+ }
836
+ else if (bodyMutation) {
837
+ body[i] = result;
838
+ }
839
+ }
840
+ else if (validator) {
841
+ if (activeBody &&
842
+ typeof activeBody === "object" &&
843
+ !Array.isArray(activeBody)) {
844
+ const keys = Object.keys(validator);
845
+ for (const key of Object.keys(activeBody)) {
846
+ if (!(key in validator)) {
847
+ keys.push(key);
848
+ }
849
+ }
850
+ for (const key of keys) {
851
+ const propValidator = validator[key];
852
+ if (propValidator == null && !strangeBody) {
853
+ if (bodyMutation) {
854
+ delete activeBody[key];
855
+ }
856
+ continue;
857
+ }
858
+ const result = propValidator == null
859
+ ? typeof strangeBody === "function"
860
+ ? strangeBody(key, activeBody, i)
861
+ : activeBody[key]
862
+ : propValidator.bind
863
+ ? propValidator.bind(ctx)(activeBody[key], i)
864
+ : propValidator(activeBody[key], i);
865
+ if (result instanceof Error) {
866
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "body-validator");
867
+ }
868
+ else if (bodyErrors && errorMatches(result, bodyErrors)) {
869
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "body-validator");
870
+ }
871
+ else if (result instanceof Response ||
872
+ result === types_ts_1.Break_Pipe ||
873
+ result === types_ts_1.Break_Pipeline) {
874
+ return result;
875
+ }
876
+ else if (bodyMutation) {
877
+ activeBody[key] = result;
878
+ }
879
+ }
880
+ }
881
+ else {
882
+ return respond(status_ts_1.Status._400_BadRequest, `Invalid body type at index ${i}`, "error", "body-validator");
883
+ }
884
+ }
885
+ }
886
+ }
887
+ else {
888
+ const validator = bodyValidators[0];
889
+ if (typeof validator === "function") {
890
+ const result = validator.bind
891
+ ? validator.bind(ctx)(body)
892
+ : validator(body);
893
+ if (result instanceof Error) {
894
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "body-validator");
895
+ }
896
+ else if (bodyErrors && errorMatches(result, bodyErrors)) {
897
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "body-validator");
898
+ }
899
+ else if (result instanceof Response ||
900
+ result === types_ts_1.Break_Pipe ||
901
+ result === types_ts_1.Break_Pipeline) {
902
+ return result;
903
+ }
904
+ else if (bodyMutation) {
905
+ ctx.body = result;
906
+ }
907
+ }
908
+ else if (validator) {
909
+ if (body && typeof body === "object" && !Array.isArray(body)) {
910
+ const keys = Object.keys(validator);
911
+ for (const key of Object.keys(body)) {
912
+ if (!(key in validator)) {
913
+ keys.push(key);
914
+ }
915
+ }
916
+ for (const key of keys) {
917
+ const propValidator = validator[key];
918
+ if (propValidator == null && !strangeBody) {
919
+ if (bodyMutation) {
920
+ delete body[key];
921
+ }
922
+ continue;
923
+ }
924
+ const result = propValidator == null
925
+ ? typeof strangeBody === "function"
926
+ ? strangeBody(key, body)
927
+ : body[key]
928
+ : propValidator.bind
929
+ ? propValidator.bind(ctx)(body[key])
930
+ : propValidator(body[key]);
931
+ if (result instanceof Error) {
932
+ return respond(result.status || status_ts_1.Status._400_BadRequest, result.message, "error", "body-validator");
933
+ }
934
+ else if (bodyErrors && errorMatches(result, bodyErrors)) {
935
+ return respond(result.status || status_ts_1.Status._400_BadRequest, String(result), "error", "body-validator");
936
+ }
937
+ else if (result instanceof Response ||
938
+ result === types_ts_1.Break_Pipe ||
939
+ result === types_ts_1.Break_Pipeline) {
940
+ return result;
941
+ }
942
+ else if (bodyMutation) {
943
+ body[key] = result;
944
+ }
945
+ }
946
+ }
947
+ else {
948
+ return respond(status_ts_1.Status._400_BadRequest, "Invalid body type", "error", "body-validator");
949
+ }
950
+ }
951
+ }
952
+ }
953
+ if (breakPipeline) {
954
+ return types_ts_1.Break_Pipeline;
955
+ }
956
+ });
957
+ };
958
+ exports.validate = validate;
359
959
  //# sourceMappingURL=middlewares.js.map