fastify 5.4.0 → 5.6.0

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 (98) hide show
  1. package/LICENSE +1 -1
  2. package/SECURITY.md +158 -2
  3. package/build/build-validation.js +19 -1
  4. package/docs/Guides/Delay-Accepting-Requests.md +8 -5
  5. package/docs/Guides/Ecosystem.md +11 -0
  6. package/docs/Guides/Migration-Guide-V5.md +6 -10
  7. package/docs/Guides/Recommendations.md +1 -1
  8. package/docs/Reference/Errors.md +3 -1
  9. package/docs/Reference/Hooks.md +2 -6
  10. package/docs/Reference/Lifecycle.md +2 -2
  11. package/docs/Reference/Request.md +1 -1
  12. package/docs/Reference/Routes.md +5 -5
  13. package/docs/Reference/Server.md +306 -179
  14. package/docs/Reference/TypeScript.md +3 -5
  15. package/docs/Reference/Validation-and-Serialization.md +55 -3
  16. package/docs/Reference/Warnings.md +2 -1
  17. package/fastify.d.ts +19 -2
  18. package/fastify.js +34 -33
  19. package/lib/configValidator.js +196 -28
  20. package/lib/contentTypeParser.js +41 -48
  21. package/lib/error-handler.js +3 -3
  22. package/lib/errors.js +5 -0
  23. package/lib/handleRequest.js +13 -17
  24. package/lib/promise.js +23 -0
  25. package/lib/reply.js +17 -19
  26. package/lib/route.js +37 -3
  27. package/lib/server.js +36 -35
  28. package/lib/warnings.js +11 -1
  29. package/package.json +7 -7
  30. package/test/async-await.test.js +81 -134
  31. package/test/async_hooks.test.js +18 -37
  32. package/test/body-limit.test.js +51 -0
  33. package/test/buffer.test.js +22 -0
  34. package/test/case-insensitive.test.js +44 -65
  35. package/test/check.test.js +17 -21
  36. package/test/close-pipelining.test.js +24 -15
  37. package/test/constrained-routes.test.js +231 -0
  38. package/test/custom-http-server.test.js +7 -15
  39. package/test/custom-parser.0.test.js +267 -348
  40. package/test/custom-parser.1.test.js +141 -191
  41. package/test/custom-parser.2.test.js +34 -44
  42. package/test/custom-parser.3.test.js +56 -104
  43. package/test/custom-parser.4.test.js +106 -144
  44. package/test/custom-parser.5.test.js +56 -75
  45. package/test/custom-querystring-parser.test.js +51 -77
  46. package/test/decorator.test.js +76 -259
  47. package/test/delete.test.js +101 -110
  48. package/test/diagnostics-channel/404.test.js +7 -15
  49. package/test/diagnostics-channel/async-request.test.js +8 -16
  50. package/test/diagnostics-channel/error-request.test.js +7 -15
  51. package/test/diagnostics-channel/sync-request-reply.test.js +9 -16
  52. package/test/diagnostics-channel/sync-request.test.js +9 -16
  53. package/test/fastify-instance.test.js +1 -1
  54. package/test/header-overflow.test.js +18 -29
  55. package/test/helper.js +138 -134
  56. package/test/hooks-async.test.js +26 -32
  57. package/test/hooks.test.js +261 -447
  58. package/test/http-methods/copy.test.js +14 -19
  59. package/test/http-methods/get.test.js +131 -143
  60. package/test/http-methods/head.test.js +53 -84
  61. package/test/http-methods/mkcalendar.test.js +45 -72
  62. package/test/http-methods/move.test.js +6 -10
  63. package/test/http-methods/propfind.test.js +34 -44
  64. package/test/http-methods/unlock.test.js +5 -9
  65. package/test/http2/secure-with-fallback.test.js +3 -1
  66. package/test/https/custom-https-server.test.js +9 -13
  67. package/test/input-validation.js +139 -150
  68. package/test/internals/errors.test.js +50 -1
  69. package/test/internals/handle-request.test.js +29 -5
  70. package/test/internals/promise.test.js +63 -0
  71. package/test/internals/reply.test.js +277 -496
  72. package/test/plugin.1.test.js +40 -68
  73. package/test/plugin.2.test.js +40 -70
  74. package/test/plugin.3.test.js +25 -68
  75. package/test/promises.test.js +42 -63
  76. package/test/register.test.js +8 -18
  77. package/test/request-error.test.js +57 -100
  78. package/test/request-id.test.js +30 -49
  79. package/test/route-hooks.test.js +12 -16
  80. package/test/route-shorthand.test.js +9 -27
  81. package/test/route.1.test.js +74 -131
  82. package/test/route.8.test.js +9 -17
  83. package/test/router-options.test.js +450 -0
  84. package/test/schema-validation.test.js +30 -31
  85. package/test/server.test.js +143 -5
  86. package/test/stream.1.test.js +33 -50
  87. package/test/stream.4.test.js +18 -28
  88. package/test/stream.5.test.js +11 -19
  89. package/test/types/errors.test-d.ts +13 -1
  90. package/test/types/instance.test-d.ts +18 -1
  91. package/test/types/type-provider.test-d.ts +55 -0
  92. package/test/use-semicolon-delimiter.test.js +117 -59
  93. package/test/versioned-routes.test.js +39 -56
  94. package/types/errors.d.ts +11 -1
  95. package/types/hooks.d.ts +1 -1
  96. package/types/instance.d.ts +3 -1
  97. package/types/logger.d.ts +16 -14
  98. package/types/reply.d.ts +2 -2
@@ -22,6 +22,13 @@ specification.
22
22
  > it should not be used for initial validation. Accessing databases during
23
23
  > validation may lead to Denial of Service attacks. Use
24
24
  > [Fastify's hooks](./Hooks.md) like `preHandler` for `async` tasks after validation.
25
+ >
26
+ > When using custom validators with async `preValidation` hooks,
27
+ > validators **must return** `{error}` objects instead of throwing errors.
28
+ > Throwing errors from custom validators will cause unhandled promise rejections
29
+ > that crash the application when combined with async hooks. See the
30
+ > [custom validator examples](#using-other-validation-libraries) below for the
31
+ > correct pattern.
25
32
 
26
33
  ### Core concepts
27
34
  Validation and serialization are handled by two customizable dependencies:
@@ -446,14 +453,25 @@ JavaScript validation libraries like [joi](https://github.com/hapijs/joi/) or
446
453
  ```js
447
454
  const Joi = require('joi')
448
455
 
456
+ fastify.setValidatorCompiler(({ schema }) => {
457
+ return (data) => {
458
+ try {
459
+ const { error, value } = schema.validate(data)
460
+ if (error) {
461
+ return { error } // Return the error, do not throw it
462
+ }
463
+ return { value }
464
+ } catch (e) {
465
+ return { error: e } // Catch any unexpected errors too
466
+ }
467
+ }
468
+ })
469
+
449
470
  fastify.post('/the/url', {
450
471
  schema: {
451
472
  body: Joi.object().keys({
452
473
  hello: Joi.string().required()
453
474
  }).required()
454
- },
455
- validatorCompiler: ({ schema, method, url, httpPart }) => {
456
- return data => schema.validate(data)
457
475
  }
458
476
  }, handler)
459
477
  ```
@@ -492,6 +510,40 @@ fastify.post('/the/url', {
492
510
  }, handler)
493
511
  ```
494
512
 
513
+ ##### Custom Validator Best Practices
514
+
515
+ When implementing custom validators, follow these patterns to ensure compatibility
516
+ with all Fastify features:
517
+
518
+ ** Always return objects, never throw:**
519
+ ```js
520
+ return { value: validatedData } // On success
521
+ return { error: validationError } // On failure
522
+ ```
523
+
524
+ ** Use try-catch for safety:**
525
+ ```js
526
+ fastify.setValidatorCompiler(({ schema }) => {
527
+ return (data) => {
528
+ try {
529
+ // Validation logic here
530
+ const result = schema.validate(data)
531
+ if (result.error) {
532
+ return { error: result.error }
533
+ }
534
+ return { value: result.value }
535
+ } catch (e) {
536
+ // Catch any unexpected errors
537
+ return { error: e }
538
+ }
539
+ }
540
+ })
541
+ ```
542
+
543
+ This pattern ensures validators work correctly with both sync and async
544
+ `preValidation` hooks, preventing unhandled promise rejections that can crash
545
+ an application.
546
+
495
547
  ##### .statusCode property
496
548
 
497
549
  All validation errors have a `.statusCode` property set to `400`, ensuring the
@@ -8,7 +8,7 @@
8
8
  - [FSTWRN001](#FSTWRN001)
9
9
  - [FSTWRN002](#FSTWRN002)
10
10
  - [Fastify Deprecation Codes](#fastify-deprecation-codes)
11
-
11
+ - [FSTDEP022](#FSTDEP022)
12
12
 
13
13
  ## Warnings
14
14
 
@@ -55,3 +55,4 @@ Deprecation codes are supported by the Node.js CLI options:
55
55
 
56
56
  | Code | Description | How to solve | Discussion |
57
57
  | ---- | ----------- | ------------ | ---------- |
58
+ | <a id="FSTDEP022">FSTDEP022</a> | You are trying to access the deprecated router options on top option properties. | Use `options.routerOptions`. | [#5985](https://github.com/fastify/fastify/pull/5985)
package/fastify.d.ts CHANGED
@@ -28,7 +28,7 @@ import { FastifyRegister, FastifyRegisterOptions, RegisterOptions } from './type
28
28
  import { FastifyReply } from './types/reply'
29
29
  import { FastifyRequest, RequestGenericInterface } from './types/request'
30
30
  import { RouteGenericInterface, RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
31
- import { FastifySchema, FastifySchemaCompiler, FastifySchemaValidationError, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
31
+ import { FastifySchema, FastifySchemaValidationError, FastifySchemaCompiler, FastifySerializerCompiler, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
32
32
  import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/serverFactory'
33
33
  import { FastifyTypeProvider, FastifyTypeProviderDefault, SafePromiseLike } from './types/type-provider'
34
34
  import { ContextConfigDefault, HTTPMethods, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, RequestBodyDefault, RequestHeadersDefault, RequestParamsDefault, RequestQuerystringDefault } from './types/utils'
@@ -89,6 +89,22 @@ declare namespace fastify {
89
89
 
90
90
  type TrustProxyFunction = (address: string, hop: number) => boolean
91
91
 
92
+ export type FastifyRouterOptions<RawServer extends RawServerBase> = {
93
+ allowUnsafeRegex?: boolean,
94
+ buildPrettyMeta?: (route: { [k: string]: unknown, store: { [k: string]: unknown } }) => object,
95
+ caseSensitive?: boolean,
96
+ constraints?: {
97
+ [name: string]: ConstraintStrategy<FindMyWayVersion<RawServer>, unknown>,
98
+ },
99
+ defaultRoute?: (req: FastifyRequest, res: FastifyReply) => void,
100
+ ignoreDuplicateSlashes?: boolean,
101
+ ignoreTrailingSlash?: boolean,
102
+ maxParamLength?: number,
103
+ onBadUrl?: (path: string, req: FastifyRequest, res: FastifyReply) => void,
104
+ querystringParser?: (str: string) => { [key: string]: unknown },
105
+ useSemicolonDelimiter?: boolean,
106
+ }
107
+
92
108
  /**
93
109
  * Options for a fastify server instance. Utilizes conditional logic on the generic server parameter to enforce certain https and http2
94
110
  */
@@ -159,6 +175,7 @@ declare namespace fastify {
159
175
  clientErrorHandler?: (error: ConnectionError, socket: Socket) => void,
160
176
  childLoggerFactory?: FastifyChildLoggerFactory,
161
177
  allowErrorHandlerOverride?: boolean
178
+ routerOptions?: FastifyRouterOptions<RawServer>,
162
179
  }
163
180
 
164
181
  /**
@@ -179,7 +196,7 @@ declare namespace fastify {
179
196
  FastifyRegister, FastifyRegisterOptions, RegisterOptions, // './types/register'
180
197
  FastifyBodyParser, FastifyContentTypeParser, AddContentTypeParser, hasContentTypeParser, getDefaultJsonParser, ProtoAction, ConstructorAction, // './types/content-type-parser'
181
198
  FastifyError, // '@fastify/error'
182
- FastifySchema, FastifySchemaCompiler, // './types/schema'
199
+ FastifySchema, FastifySchemaValidationError, FastifySchemaCompiler, FastifySerializerCompiler, // './types/schema'
183
200
  HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaultExpression, RawServerDefault, ContextConfigDefault, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault, // './types/utils'
184
201
  DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onListenAsyncHookHandler, onListenHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, onRequestAbortHookHandler, onRequestAbortAsyncHookHandler, preCloseAsyncHookHandler, preCloseHookHandler, // './types/hooks'
185
202
  FastifyServerFactory, FastifyServerFactoryHandler, // './types/serverFactory'
package/fastify.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '5.4.0'
3
+ const VERSION = '5.6.0'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('node:http')
@@ -46,7 +46,7 @@ const { Hooks, hookRunnerApplication, supportedHooks } = require('./lib/hooks')
46
46
  const { createChildLogger, defaultChildLoggerFactory, createLogger } = require('./lib/logger-factory')
47
47
  const pluginUtils = require('./lib/pluginUtils')
48
48
  const { getGenReqId, reqIdGenFactory } = require('./lib/reqIdGenFactory')
49
- const { buildRouting, validateBodyLimitOption } = require('./lib/route')
49
+ const { buildRouting, validateBodyLimitOption, buildRouterOptions } = require('./lib/route')
50
50
  const build404 = require('./lib/fourOhFour')
51
51
  const getSecuredInitialConfig = require('./lib/initialConfigValidation')
52
52
  const override = require('./lib/pluginOverride')
@@ -56,6 +56,7 @@ const {
56
56
  AVVIO_ERRORS_MAP,
57
57
  ...errorCodes
58
58
  } = require('./lib/errors')
59
+ const PonyPromise = require('./lib/promise')
59
60
 
60
61
  const { defaultInitOptions } = getSecuredInitialConfig
61
62
 
@@ -107,8 +108,14 @@ function fastify (options) {
107
108
  options = Object.assign({}, options)
108
109
  }
109
110
 
110
- if (options.querystringParser && typeof options.querystringParser !== 'function') {
111
- throw new FST_ERR_QSP_NOT_FN(typeof options.querystringParser)
111
+ if (
112
+ (options.querystringParser && typeof options.querystringParser !== 'function') ||
113
+ (
114
+ options.routerOptions?.querystringParser &&
115
+ typeof options.routerOptions.querystringParser !== 'function'
116
+ )
117
+ ) {
118
+ throw new FST_ERR_QSP_NOT_FN(typeof (options.querystringParser ?? options.routerOptions.querystringParser))
112
119
  }
113
120
 
114
121
  if (options.schemaController && options.schemaController.bucket && typeof options.schemaController.bucket !== 'function') {
@@ -159,21 +166,20 @@ function fastify (options) {
159
166
  // exposeHeadRoutes have its default set from the validator
160
167
  options.exposeHeadRoutes = initialConfig.exposeHeadRoutes
161
168
 
169
+ options.routerOptions = buildRouterOptions(options, {
170
+ defaultRoute,
171
+ onBadUrl,
172
+ ignoreTrailingSlash: defaultInitOptions.ignoreTrailingSlash,
173
+ ignoreDuplicateSlashes: defaultInitOptions.ignoreDuplicateSlashes,
174
+ maxParamLength: defaultInitOptions.maxParamLength,
175
+ allowUnsafeRegex: defaultInitOptions.allowUnsafeRegex,
176
+ buildPrettyMeta: defaultBuildPrettyMeta,
177
+ useSemicolonDelimiter: defaultInitOptions.useSemicolonDelimiter
178
+ })
179
+
162
180
  // Default router
163
181
  const router = buildRouting({
164
- config: {
165
- defaultRoute,
166
- onBadUrl,
167
- constraints: options.constraints,
168
- ignoreTrailingSlash: options.ignoreTrailingSlash || defaultInitOptions.ignoreTrailingSlash,
169
- ignoreDuplicateSlashes: options.ignoreDuplicateSlashes || defaultInitOptions.ignoreDuplicateSlashes,
170
- maxParamLength: options.maxParamLength || defaultInitOptions.maxParamLength,
171
- caseSensitive: options.caseSensitive,
172
- allowUnsafeRegex: options.allowUnsafeRegex || defaultInitOptions.allowUnsafeRegex,
173
- buildPrettyMeta: defaultBuildPrettyMeta,
174
- querystringParser: options.querystringParser,
175
- useSemicolonDelimiter: options.useSemicolonDelimiter ?? defaultInitOptions.useSemicolonDelimiter
176
- }
182
+ config: options.routerOptions
177
183
  })
178
184
 
179
185
  // 404 router, used for handling encapsulated 404 handlers
@@ -211,7 +217,8 @@ function fastify (options) {
211
217
  started: false,
212
218
  ready: false,
213
219
  booting: false,
214
- readyPromise: null
220
+ aborted: false,
221
+ readyResolver: null
215
222
  },
216
223
  [kKeepAliveConnections]: keepAliveConnections,
217
224
  [kSupportedHTTPMethods]: {
@@ -587,18 +594,15 @@ function fastify (options) {
587
594
  }
588
595
 
589
596
  function ready (cb) {
590
- if (this[kState].readyPromise !== null) {
597
+ if (this[kState].readyResolver !== null) {
591
598
  if (cb != null) {
592
- this[kState].readyPromise.then(() => cb(null, fastify), cb)
599
+ this[kState].readyResolver.promise.then(() => cb(null, fastify), cb)
593
600
  return
594
601
  }
595
602
 
596
- return this[kState].readyPromise
603
+ return this[kState].readyResolver.promise
597
604
  }
598
605
 
599
- let resolveReady
600
- let rejectReady
601
-
602
606
  // run the hooks after returning the promise
603
607
  process.nextTick(runHooks)
604
608
 
@@ -606,15 +610,12 @@ function fastify (options) {
606
610
  // It will work as a barrier for all the .ready() calls (ensuring single hook execution)
607
611
  // as well as a flow control mechanism to chain cbs and further
608
612
  // promises
609
- this[kState].readyPromise = new Promise(function (resolve, reject) {
610
- resolveReady = resolve
611
- rejectReady = reject
612
- })
613
+ this[kState].readyResolver = PonyPromise.withResolvers()
613
614
 
614
615
  if (!cb) {
615
- return this[kState].readyPromise
616
+ return this[kState].readyResolver.promise
616
617
  } else {
617
- this[kState].readyPromise.then(() => cb(null, fastify), cb)
618
+ this[kState].readyResolver.promise.then(() => cb(null, fastify), cb)
618
619
  }
619
620
 
620
621
  function runHooks () {
@@ -639,13 +640,13 @@ function fastify (options) {
639
640
  : err
640
641
 
641
642
  if (err) {
642
- return rejectReady(err)
643
+ return fastify[kState].readyResolver.reject(err)
643
644
  }
644
645
 
645
- resolveReady(fastify)
646
+ fastify[kState].readyResolver.resolve(fastify)
646
647
  fastify[kState].booting = false
647
648
  fastify[kState].ready = true
648
- fastify[kState].readyPromise = null
649
+ fastify[kState].readyResolver = null
649
650
  }
650
651
  }
651
652
 
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
  module.exports = validate10;
5
5
  module.exports.default = validate10;
6
- const schema11 = {"type":"object","additionalProperties":false,"properties":{"connectionTimeout":{"type":"integer","default":0},"keepAliveTimeout":{"type":"integer","default":72000},"forceCloseConnections":{"oneOf":[{"type":"string","pattern":"idle"},{"type":"boolean"}]},"maxRequestsPerSocket":{"type":"integer","default":0,"nullable":true},"requestTimeout":{"type":"integer","default":0},"bodyLimit":{"type":"integer","default":1048576},"caseSensitive":{"type":"boolean","default":true},"allowUnsafeRegex":{"type":"boolean","default":false},"http2":{"type":"boolean"},"https":{"if":{"not":{"oneOf":[{"type":"boolean"},{"type":"null"},{"type":"object","additionalProperties":false,"required":["allowHTTP1"],"properties":{"allowHTTP1":{"type":"boolean"}}}]}},"then":{"setDefaultValue":true}},"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"disableRequestLogging":{"type":"boolean","default":false},"maxParamLength":{"type":"integer","default":100},"onProtoPoisoning":{"type":"string","default":"error"},"onConstructorPoisoning":{"type":"string","default":"error"},"pluginTimeout":{"type":"integer","default":10000},"requestIdHeader":{"anyOf":[{"type":"boolean"},{"type":"string"}],"default":false},"requestIdLogLabel":{"type":"string","default":"reqId"},"http2SessionTimeout":{"type":"integer","default":72000},"exposeHeadRoutes":{"type":"boolean","default":true},"useSemicolonDelimiter":{"type":"boolean","default":false},"constraints":{"type":"object","additionalProperties":{"type":"object","required":["name","storage","validate","deriveConstraint"],"additionalProperties":true,"properties":{"name":{"type":"string"},"storage":{},"validate":{},"deriveConstraint":{}}}}}};
6
+ const schema11 = {"type":"object","additionalProperties":false,"properties":{"connectionTimeout":{"type":"integer","default":0},"keepAliveTimeout":{"type":"integer","default":72000},"forceCloseConnections":{"oneOf":[{"type":"string","pattern":"idle"},{"type":"boolean"}]},"maxRequestsPerSocket":{"type":"integer","default":0,"nullable":true},"requestTimeout":{"type":"integer","default":0},"bodyLimit":{"type":"integer","default":1048576},"caseSensitive":{"type":"boolean","default":true},"allowUnsafeRegex":{"type":"boolean","default":false},"http2":{"type":"boolean"},"https":{"if":{"not":{"oneOf":[{"type":"boolean"},{"type":"null"},{"type":"object","additionalProperties":false,"required":["allowHTTP1"],"properties":{"allowHTTP1":{"type":"boolean"}}}]}},"then":{"setDefaultValue":true}},"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"disableRequestLogging":{"type":"boolean","default":false},"maxParamLength":{"type":"integer","default":100},"onProtoPoisoning":{"type":"string","default":"error"},"onConstructorPoisoning":{"type":"string","default":"error"},"pluginTimeout":{"type":"integer","default":10000},"requestIdHeader":{"anyOf":[{"type":"boolean"},{"type":"string"}],"default":false},"requestIdLogLabel":{"type":"string","default":"reqId"},"http2SessionTimeout":{"type":"integer","default":72000},"exposeHeadRoutes":{"type":"boolean","default":true},"useSemicolonDelimiter":{"type":"boolean","default":false},"routerOptions":{"type":"object","additionalProperties":false,"properties":{"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"maxParamLength":{"type":"integer","default":100},"allowUnsafeRegex":{"type":"boolean","default":false},"useSemicolonDelimiter":{"type":"boolean","default":false}}},"constraints":{"type":"object","additionalProperties":{"type":"object","required":["name","storage","validate","deriveConstraint"],"additionalProperties":true,"properties":{"name":{"type":"string"},"storage":{},"validate":{},"deriveConstraint":{}}}}}};
7
7
  const func2 = Object.prototype.hasOwnProperty;
8
8
  const pattern0 = new RegExp("idle", "u");
9
9
 
@@ -1002,43 +1002,210 @@ data["useSemicolonDelimiter"] = coerced25;
1002
1002
  }
1003
1003
  var valid0 = _errs67 === errors;
1004
1004
  if(valid0){
1005
- if(data.constraints !== undefined){
1006
- let data23 = data.constraints;
1005
+ if(data.routerOptions !== undefined){
1006
+ let data23 = data.routerOptions;
1007
1007
  const _errs69 = errors;
1008
1008
  if(errors === _errs69){
1009
1009
  if(data23 && typeof data23 == "object" && !Array.isArray(data23)){
1010
+ if(data23.ignoreTrailingSlash === undefined){
1011
+ data23.ignoreTrailingSlash = false;
1012
+ }
1013
+ if(data23.ignoreDuplicateSlashes === undefined){
1014
+ data23.ignoreDuplicateSlashes = false;
1015
+ }
1016
+ if(data23.maxParamLength === undefined){
1017
+ data23.maxParamLength = 100;
1018
+ }
1019
+ if(data23.allowUnsafeRegex === undefined){
1020
+ data23.allowUnsafeRegex = false;
1021
+ }
1022
+ if(data23.useSemicolonDelimiter === undefined){
1023
+ data23.useSemicolonDelimiter = false;
1024
+ }
1025
+ const _errs71 = errors;
1010
1026
  for(const key2 in data23){
1011
- let data24 = data23[key2];
1027
+ if(!(((((key2 === "ignoreTrailingSlash") || (key2 === "ignoreDuplicateSlashes")) || (key2 === "maxParamLength")) || (key2 === "allowUnsafeRegex")) || (key2 === "useSemicolonDelimiter"))){
1028
+ delete data23[key2];
1029
+ }
1030
+ }
1031
+ if(_errs71 === errors){
1032
+ let data24 = data23.ignoreTrailingSlash;
1012
1033
  const _errs72 = errors;
1013
- if(errors === _errs72){
1014
- if(data24 && typeof data24 == "object" && !Array.isArray(data24)){
1034
+ if(typeof data24 !== "boolean"){
1035
+ let coerced26 = undefined;
1036
+ if(!(coerced26 !== undefined)){
1037
+ if(data24 === "false" || data24 === 0 || data24 === null){
1038
+ coerced26 = false;
1039
+ }
1040
+ else if(data24 === "true" || data24 === 1){
1041
+ coerced26 = true;
1042
+ }
1043
+ else {
1044
+ validate10.errors = [{instancePath:instancePath+"/routerOptions/ignoreTrailingSlash",schemaPath:"#/properties/routerOptions/properties/ignoreTrailingSlash/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
1045
+ return false;
1046
+ }
1047
+ }
1048
+ if(coerced26 !== undefined){
1049
+ data24 = coerced26;
1050
+ if(data23 !== undefined){
1051
+ data23["ignoreTrailingSlash"] = coerced26;
1052
+ }
1053
+ }
1054
+ }
1055
+ var valid7 = _errs72 === errors;
1056
+ if(valid7){
1057
+ let data25 = data23.ignoreDuplicateSlashes;
1058
+ const _errs74 = errors;
1059
+ if(typeof data25 !== "boolean"){
1060
+ let coerced27 = undefined;
1061
+ if(!(coerced27 !== undefined)){
1062
+ if(data25 === "false" || data25 === 0 || data25 === null){
1063
+ coerced27 = false;
1064
+ }
1065
+ else if(data25 === "true" || data25 === 1){
1066
+ coerced27 = true;
1067
+ }
1068
+ else {
1069
+ validate10.errors = [{instancePath:instancePath+"/routerOptions/ignoreDuplicateSlashes",schemaPath:"#/properties/routerOptions/properties/ignoreDuplicateSlashes/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
1070
+ return false;
1071
+ }
1072
+ }
1073
+ if(coerced27 !== undefined){
1074
+ data25 = coerced27;
1075
+ if(data23 !== undefined){
1076
+ data23["ignoreDuplicateSlashes"] = coerced27;
1077
+ }
1078
+ }
1079
+ }
1080
+ var valid7 = _errs74 === errors;
1081
+ if(valid7){
1082
+ let data26 = data23.maxParamLength;
1083
+ const _errs76 = errors;
1084
+ if(!(((typeof data26 == "number") && (!(data26 % 1) && !isNaN(data26))) && (isFinite(data26)))){
1085
+ let dataType28 = typeof data26;
1086
+ let coerced28 = undefined;
1087
+ if(!(coerced28 !== undefined)){
1088
+ if(dataType28 === "boolean" || data26 === null
1089
+ || (dataType28 === "string" && data26 && data26 == +data26 && !(data26 % 1))){
1090
+ coerced28 = +data26;
1091
+ }
1092
+ else {
1093
+ validate10.errors = [{instancePath:instancePath+"/routerOptions/maxParamLength",schemaPath:"#/properties/routerOptions/properties/maxParamLength/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
1094
+ return false;
1095
+ }
1096
+ }
1097
+ if(coerced28 !== undefined){
1098
+ data26 = coerced28;
1099
+ if(data23 !== undefined){
1100
+ data23["maxParamLength"] = coerced28;
1101
+ }
1102
+ }
1103
+ }
1104
+ var valid7 = _errs76 === errors;
1105
+ if(valid7){
1106
+ let data27 = data23.allowUnsafeRegex;
1107
+ const _errs78 = errors;
1108
+ if(typeof data27 !== "boolean"){
1109
+ let coerced29 = undefined;
1110
+ if(!(coerced29 !== undefined)){
1111
+ if(data27 === "false" || data27 === 0 || data27 === null){
1112
+ coerced29 = false;
1113
+ }
1114
+ else if(data27 === "true" || data27 === 1){
1115
+ coerced29 = true;
1116
+ }
1117
+ else {
1118
+ validate10.errors = [{instancePath:instancePath+"/routerOptions/allowUnsafeRegex",schemaPath:"#/properties/routerOptions/properties/allowUnsafeRegex/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
1119
+ return false;
1120
+ }
1121
+ }
1122
+ if(coerced29 !== undefined){
1123
+ data27 = coerced29;
1124
+ if(data23 !== undefined){
1125
+ data23["allowUnsafeRegex"] = coerced29;
1126
+ }
1127
+ }
1128
+ }
1129
+ var valid7 = _errs78 === errors;
1130
+ if(valid7){
1131
+ let data28 = data23.useSemicolonDelimiter;
1132
+ const _errs80 = errors;
1133
+ if(typeof data28 !== "boolean"){
1134
+ let coerced30 = undefined;
1135
+ if(!(coerced30 !== undefined)){
1136
+ if(data28 === "false" || data28 === 0 || data28 === null){
1137
+ coerced30 = false;
1138
+ }
1139
+ else if(data28 === "true" || data28 === 1){
1140
+ coerced30 = true;
1141
+ }
1142
+ else {
1143
+ validate10.errors = [{instancePath:instancePath+"/routerOptions/useSemicolonDelimiter",schemaPath:"#/properties/routerOptions/properties/useSemicolonDelimiter/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
1144
+ return false;
1145
+ }
1146
+ }
1147
+ if(coerced30 !== undefined){
1148
+ data28 = coerced30;
1149
+ if(data23 !== undefined){
1150
+ data23["useSemicolonDelimiter"] = coerced30;
1151
+ }
1152
+ }
1153
+ }
1154
+ var valid7 = _errs80 === errors;
1155
+ }
1156
+ }
1157
+ }
1158
+ }
1159
+ }
1160
+ }
1161
+ else {
1162
+ validate10.errors = [{instancePath:instancePath+"/routerOptions",schemaPath:"#/properties/routerOptions/type",keyword:"type",params:{type: "object"},message:"must be object"}];
1163
+ return false;
1164
+ }
1165
+ }
1166
+ var valid0 = _errs69 === errors;
1167
+ }
1168
+ else {
1169
+ var valid0 = true;
1170
+ }
1171
+ if(valid0){
1172
+ if(data.constraints !== undefined){
1173
+ let data29 = data.constraints;
1174
+ const _errs82 = errors;
1175
+ if(errors === _errs82){
1176
+ if(data29 && typeof data29 == "object" && !Array.isArray(data29)){
1177
+ for(const key3 in data29){
1178
+ let data30 = data29[key3];
1179
+ const _errs85 = errors;
1180
+ if(errors === _errs85){
1181
+ if(data30 && typeof data30 == "object" && !Array.isArray(data30)){
1015
1182
  let missing1;
1016
- if(((((data24.name === undefined) && (missing1 = "name")) || ((data24.storage === undefined) && (missing1 = "storage"))) || ((data24.validate === undefined) && (missing1 = "validate"))) || ((data24.deriveConstraint === undefined) && (missing1 = "deriveConstraint"))){
1017
- validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/constraints/additionalProperties/required",keyword:"required",params:{missingProperty: missing1},message:"must have required property '"+missing1+"'"}];
1183
+ if(((((data30.name === undefined) && (missing1 = "name")) || ((data30.storage === undefined) && (missing1 = "storage"))) || ((data30.validate === undefined) && (missing1 = "validate"))) || ((data30.deriveConstraint === undefined) && (missing1 = "deriveConstraint"))){
1184
+ validate10.errors = [{instancePath:instancePath+"/constraints/" + key3.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/constraints/additionalProperties/required",keyword:"required",params:{missingProperty: missing1},message:"must have required property '"+missing1+"'"}];
1018
1185
  return false;
1019
1186
  }
1020
1187
  else {
1021
- if(data24.name !== undefined){
1022
- let data25 = data24.name;
1023
- if(typeof data25 !== "string"){
1024
- let dataType26 = typeof data25;
1025
- let coerced26 = undefined;
1026
- if(!(coerced26 !== undefined)){
1027
- if(dataType26 == "number" || dataType26 == "boolean"){
1028
- coerced26 = "" + data25;
1188
+ if(data30.name !== undefined){
1189
+ let data31 = data30.name;
1190
+ if(typeof data31 !== "string"){
1191
+ let dataType31 = typeof data31;
1192
+ let coerced31 = undefined;
1193
+ if(!(coerced31 !== undefined)){
1194
+ if(dataType31 == "number" || dataType31 == "boolean"){
1195
+ coerced31 = "" + data31;
1029
1196
  }
1030
- else if(data25 === null){
1031
- coerced26 = "";
1197
+ else if(data31 === null){
1198
+ coerced31 = "";
1032
1199
  }
1033
1200
  else {
1034
- validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1")+"/name",schemaPath:"#/properties/constraints/additionalProperties/properties/name/type",keyword:"type",params:{type: "string"},message:"must be string"}];
1201
+ validate10.errors = [{instancePath:instancePath+"/constraints/" + key3.replace(/~/g, "~0").replace(/\//g, "~1")+"/name",schemaPath:"#/properties/constraints/additionalProperties/properties/name/type",keyword:"type",params:{type: "string"},message:"must be string"}];
1035
1202
  return false;
1036
1203
  }
1037
1204
  }
1038
- if(coerced26 !== undefined){
1039
- data25 = coerced26;
1040
- if(data24 !== undefined){
1041
- data24["name"] = coerced26;
1205
+ if(coerced31 !== undefined){
1206
+ data31 = coerced31;
1207
+ if(data30 !== undefined){
1208
+ data30["name"] = coerced31;
1042
1209
  }
1043
1210
  }
1044
1211
  }
@@ -1046,12 +1213,12 @@ data24["name"] = coerced26;
1046
1213
  }
1047
1214
  }
1048
1215
  else {
1049
- validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/constraints/additionalProperties/type",keyword:"type",params:{type: "object"},message:"must be object"}];
1216
+ validate10.errors = [{instancePath:instancePath+"/constraints/" + key3.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/constraints/additionalProperties/type",keyword:"type",params:{type: "object"},message:"must be object"}];
1050
1217
  return false;
1051
1218
  }
1052
1219
  }
1053
- var valid7 = _errs72 === errors;
1054
- if(!valid7){
1220
+ var valid8 = _errs85 === errors;
1221
+ if(!valid8){
1055
1222
  break;
1056
1223
  }
1057
1224
  }
@@ -1061,7 +1228,7 @@ validate10.errors = [{instancePath:instancePath+"/constraints",schemaPath:"#/pro
1061
1228
  return false;
1062
1229
  }
1063
1230
  }
1064
- var valid0 = _errs69 === errors;
1231
+ var valid0 = _errs82 === errors;
1065
1232
  }
1066
1233
  else {
1067
1234
  var valid0 = true;
@@ -1090,6 +1257,7 @@ var valid0 = true;
1090
1257
  }
1091
1258
  }
1092
1259
  }
1260
+ }
1093
1261
  else {
1094
1262
  validate10.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}];
1095
1263
  return false;
@@ -1100,5 +1268,5 @@ return errors === 0;
1100
1268
  }
1101
1269
 
1102
1270
 
1103
- module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":false,"requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":false,"allowErrorHandlerOverride":true}
1271
+ module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":false,"requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":false,"allowErrorHandlerOverride":true,"routerOptions":{"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"allowUnsafeRegex":false,"useSemicolonDelimiter":false}}
1104
1272
  /* c8 ignore stop */