|  |  |  | 'use strict' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const VERSION = '3.29.5' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const Avvio = require('avvio') | 
					
						
							|  |  |  | const http = require('http') | 
					
						
							|  |  |  | const querystring = require('querystring') | 
					
						
							|  |  |  | let lightMyRequest | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { | 
					
						
							|  |  |  |   kAvvioBoot, | 
					
						
							|  |  |  |   kChildren, | 
					
						
							|  |  |  |   kBodyLimit, | 
					
						
							|  |  |  |   kRoutePrefix, | 
					
						
							|  |  |  |   kLogLevel, | 
					
						
							|  |  |  |   kLogSerializers, | 
					
						
							|  |  |  |   kHooks, | 
					
						
							|  |  |  |   kSchemaController, | 
					
						
							|  |  |  |   kRequestAcceptVersion, | 
					
						
							|  |  |  |   kReplySerializerDefault, | 
					
						
							|  |  |  |   kContentTypeParser, | 
					
						
							|  |  |  |   kReply, | 
					
						
							|  |  |  |   kRequest, | 
					
						
							|  |  |  |   kFourOhFour, | 
					
						
							|  |  |  |   kState, | 
					
						
							|  |  |  |   kOptions, | 
					
						
							|  |  |  |   kPluginNameChain, | 
					
						
							|  |  |  |   kSchemaErrorFormatter, | 
					
						
							|  |  |  |   kErrorHandler, | 
					
						
							|  |  |  |   kKeepAliveConnections, | 
					
						
							|  |  |  |   kFourOhFourContext | 
					
						
							|  |  |  | } = require('./lib/symbols.js') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { createServer } = require('./lib/server') | 
					
						
							|  |  |  | const Reply = require('./lib/reply') | 
					
						
							|  |  |  | const Request = require('./lib/request') | 
					
						
							|  |  |  | const supportedMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS'] | 
					
						
							|  |  |  | const decorator = require('./lib/decorate') | 
					
						
							|  |  |  | const ContentTypeParser = require('./lib/contentTypeParser') | 
					
						
							|  |  |  | const SchemaController = require('./lib/schema-controller') | 
					
						
							|  |  |  | const { Hooks, hookRunnerApplication, supportedHooks } = require('./lib/hooks') | 
					
						
							|  |  |  | const { createLogger } = require('./lib/logger') | 
					
						
							|  |  |  | const pluginUtils = require('./lib/pluginUtils') | 
					
						
							|  |  |  | const reqIdGenFactory = require('./lib/reqIdGenFactory') | 
					
						
							|  |  |  | const { buildRouting, validateBodyLimitOption } = require('./lib/route') | 
					
						
							|  |  |  | const build404 = require('./lib/fourOhFour') | 
					
						
							|  |  |  | const getSecuredInitialConfig = require('./lib/initialConfigValidation') | 
					
						
							|  |  |  | const override = require('./lib/pluginOverride') | 
					
						
							|  |  |  | const warning = require('./lib/warnings') | 
					
						
							|  |  |  | const noopSet = require('./lib/noop-set') | 
					
						
							|  |  |  | const { defaultInitOptions } = getSecuredInitialConfig | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { | 
					
						
							|  |  |  |   FST_ERR_BAD_URL, | 
					
						
							|  |  |  |   FST_ERR_MISSING_MIDDLEWARE | 
					
						
							|  |  |  | } = require('./lib/errors') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const onBadUrlContext = { | 
					
						
							|  |  |  |   config: { | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   onSend: [], | 
					
						
							|  |  |  |   onError: [], | 
					
						
							|  |  |  |   [kFourOhFourContext]: null | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function defaultBuildPrettyMeta (route) { | 
					
						
							|  |  |  |   // return a shallow copy of route's sanitized context
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const cleanKeys = {} | 
					
						
							|  |  |  |   const allowedProps = ['errorHandler', 'logLevel', 'logSerializers'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   allowedProps.concat(supportedHooks).forEach(k => { | 
					
						
							|  |  |  |     cleanKeys[k] = route.store[k] | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return Object.assign({}, cleanKeys) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function defaultErrorHandler (error, request, reply) { | 
					
						
							|  |  |  |   if (reply.statusCode < 500) { | 
					
						
							|  |  |  |     reply.log.info( | 
					
						
							|  |  |  |       { res: reply, err: error }, | 
					
						
							|  |  |  |       error && error.message | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     reply.log.error( | 
					
						
							|  |  |  |       { req: request, res: reply, err: error }, | 
					
						
							|  |  |  |       error && error.message | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   reply.send(error) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function fastify (options) { | 
					
						
							|  |  |  |   // Options validations
 | 
					
						
							|  |  |  |   options = options || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (typeof options !== 'object') { | 
					
						
							|  |  |  |     throw new TypeError('Options must be an object') | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (options.querystringParser && typeof options.querystringParser !== 'function') { | 
					
						
							|  |  |  |     throw new Error(`querystringParser option should be a function, instead got '${typeof options.querystringParser}'`) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (options.schemaController && options.schemaController.bucket && typeof options.schemaController.bucket !== 'function') { | 
					
						
							|  |  |  |     throw new Error(`schemaController.bucket option should be a function, instead got '${typeof options.schemaController.bucket}'`) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   validateBodyLimitOption(options.bodyLimit) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const requestIdHeader = options.requestIdHeader || defaultInitOptions.requestIdHeader | 
					
						
							|  |  |  |   const querystringParser = options.querystringParser || querystring.parse | 
					
						
							|  |  |  |   const genReqId = options.genReqId || reqIdGenFactory() | 
					
						
							|  |  |  |   const requestIdLogLabel = options.requestIdLogLabel || 'reqId' | 
					
						
							|  |  |  |   const bodyLimit = options.bodyLimit || defaultInitOptions.bodyLimit | 
					
						
							|  |  |  |   const disableRequestLogging = options.disableRequestLogging || false | 
					
						
							|  |  |  |   const exposeHeadRoutes = options.exposeHeadRoutes != null ? options.exposeHeadRoutes : false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const ajvOptions = Object.assign({ | 
					
						
							|  |  |  |     customOptions: {}, | 
					
						
							|  |  |  |     plugins: [] | 
					
						
							|  |  |  |   }, options.ajv) | 
					
						
							|  |  |  |   const frameworkErrors = options.frameworkErrors | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Ajv options
 | 
					
						
							|  |  |  |   if (!ajvOptions.customOptions || Object.prototype.toString.call(ajvOptions.customOptions) !== '[object Object]') { | 
					
						
							|  |  |  |     throw new Error(`ajv.customOptions option should be an object, instead got '${typeof ajvOptions.customOptions}'`) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!ajvOptions.plugins || !Array.isArray(ajvOptions.plugins)) { | 
					
						
							|  |  |  |     throw new Error(`ajv.plugins option should be an array, instead got '${typeof ajvOptions.plugins}'`) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Instance Fastify components
 | 
					
						
							|  |  |  |   const { logger, hasLogger } = createLogger(options) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Update the options with the fixed values
 | 
					
						
							|  |  |  |   options.connectionTimeout = options.connectionTimeout || defaultInitOptions.connectionTimeout | 
					
						
							|  |  |  |   options.keepAliveTimeout = options.keepAliveTimeout || defaultInitOptions.keepAliveTimeout | 
					
						
							|  |  |  |   options.forceCloseConnections = typeof options.forceCloseConnections === 'boolean' ? options.forceCloseConnections : defaultInitOptions.forceCloseConnections | 
					
						
							|  |  |  |   options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket | 
					
						
							|  |  |  |   options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout | 
					
						
							|  |  |  |   options.logger = logger | 
					
						
							|  |  |  |   options.genReqId = genReqId | 
					
						
							|  |  |  |   options.requestIdHeader = requestIdHeader | 
					
						
							|  |  |  |   options.querystringParser = querystringParser | 
					
						
							|  |  |  |   options.requestIdLogLabel = requestIdLogLabel | 
					
						
							|  |  |  |   options.disableRequestLogging = disableRequestLogging | 
					
						
							|  |  |  |   options.ajv = ajvOptions | 
					
						
							|  |  |  |   options.clientErrorHandler = options.clientErrorHandler || defaultClientErrorHandler | 
					
						
							|  |  |  |   options.exposeHeadRoutes = exposeHeadRoutes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const initialConfig = getSecuredInitialConfig(options) | 
					
						
							|  |  |  |   const keepAliveConnections = options.forceCloseConnections === true ? new Set() : noopSet() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let constraints = options.constraints | 
					
						
							|  |  |  |   if (options.versioning) { | 
					
						
							|  |  |  |     warning.emit('FSTDEP009') | 
					
						
							|  |  |  |     constraints = { | 
					
						
							|  |  |  |       ...constraints, | 
					
						
							|  |  |  |       version: { | 
					
						
							|  |  |  |         name: 'version', | 
					
						
							|  |  |  |         mustMatchWhenDerived: true, | 
					
						
							|  |  |  |         storage: options.versioning.storage, | 
					
						
							|  |  |  |         deriveConstraint: options.versioning.deriveVersion, | 
					
						
							|  |  |  |         validate (value) { | 
					
						
							|  |  |  |           if (typeof value !== 'string') { | 
					
						
							|  |  |  |             throw new Error('Version constraint should be a string.') | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Default router
 | 
					
						
							|  |  |  |   const router = buildRouting({ | 
					
						
							|  |  |  |     config: { | 
					
						
							|  |  |  |       defaultRoute, | 
					
						
							|  |  |  |       onBadUrl, | 
					
						
							|  |  |  |       constraints, | 
					
						
							|  |  |  |       ignoreTrailingSlash: options.ignoreTrailingSlash || defaultInitOptions.ignoreTrailingSlash, | 
					
						
							|  |  |  |       maxParamLength: options.maxParamLength || defaultInitOptions.maxParamLength, | 
					
						
							|  |  |  |       caseSensitive: options.caseSensitive, | 
					
						
							|  |  |  |       buildPrettyMeta: defaultBuildPrettyMeta | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     keepAliveConnections | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 404 router, used for handling encapsulated 404 handlers
 | 
					
						
							|  |  |  |   const fourOhFour = build404(options) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // HTTP server and its handler
 | 
					
						
							|  |  |  |   const httpHandler = wrapRouting(router.routing, options) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // we need to set this before calling createServer
 | 
					
						
							|  |  |  |   options.http2SessionTimeout = initialConfig.http2SessionTimeout | 
					
						
							|  |  |  |   const { server, listen } = createServer(options, httpHandler) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const setupResponseListeners = Reply.setupResponseListeners | 
					
						
							|  |  |  |   const schemaController = SchemaController.buildSchemaController(null, options.schemaController) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Public API
 | 
					
						
							|  |  |  |   const fastify = { | 
					
						
							|  |  |  |     // Fastify internals
 | 
					
						
							|  |  |  |     [kState]: { | 
					
						
							|  |  |  |       listening: false, | 
					
						
							|  |  |  |       closing: false, | 
					
						
							|  |  |  |       started: false | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [kKeepAliveConnections]: keepAliveConnections, | 
					
						
							|  |  |  |     [kOptions]: options, | 
					
						
							|  |  |  |     [kChildren]: [], | 
					
						
							|  |  |  |     [kBodyLimit]: bodyLimit, | 
					
						
							|  |  |  |     [kRoutePrefix]: '', | 
					
						
							|  |  |  |     [kLogLevel]: '', | 
					
						
							|  |  |  |     [kLogSerializers]: null, | 
					
						
							|  |  |  |     [kHooks]: new Hooks(), | 
					
						
							|  |  |  |     [kSchemaController]: schemaController, | 
					
						
							|  |  |  |     [kSchemaErrorFormatter]: null, | 
					
						
							|  |  |  |     [kErrorHandler]: defaultErrorHandler, | 
					
						
							|  |  |  |     [kReplySerializerDefault]: null, | 
					
						
							|  |  |  |     [kContentTypeParser]: new ContentTypeParser( | 
					
						
							|  |  |  |       bodyLimit, | 
					
						
							|  |  |  |       (options.onProtoPoisoning || defaultInitOptions.onProtoPoisoning), | 
					
						
							|  |  |  |       (options.onConstructorPoisoning || defaultInitOptions.onConstructorPoisoning) | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     [kReply]: Reply.buildReply(Reply), | 
					
						
							|  |  |  |     [kRequest]: Request.buildRequest(Request, options.trustProxy), | 
					
						
							|  |  |  |     [kFourOhFour]: fourOhFour, | 
					
						
							|  |  |  |     [pluginUtils.registeredPlugins]: [], | 
					
						
							|  |  |  |     [kPluginNameChain]: [], | 
					
						
							|  |  |  |     [kAvvioBoot]: null, | 
					
						
							|  |  |  |     // routing method
 | 
					
						
							|  |  |  |     routing: httpHandler, | 
					
						
							|  |  |  |     getDefaultRoute: router.getDefaultRoute.bind(router), | 
					
						
							|  |  |  |     setDefaultRoute: router.setDefaultRoute.bind(router), | 
					
						
							|  |  |  |     // routes shorthand methods
 | 
					
						
							|  |  |  |     delete: function _delete (url, opts, handler) { | 
					
						
							|  |  |  |       return router.prepareRoute.call(this, 'DELETE', url, opts, handler) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     get: function _get (url, opts, handler) { | 
					
						
							|  |  |  |       return router.prepareRoute.call(this, 'GET', url, opts, handler) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     head: function _head (url, opts, handler) { | 
					
						
							|  |  |  |       return router.prepareRoute.call(this, 'HEAD', url, opts, handler) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     patch: function _patch (url, opts, handler) { | 
					
						
							|  |  |  |       return router.prepareRoute.call(this, 'PATCH', url, opts, handler) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     post: function _post (url, opts, handler) { | 
					
						
							|  |  |  |       return router.prepareRoute.call(this, 'POST', url, opts, handler) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     put: function _put (url, opts, handler) { | 
					
						
							|  |  |  |       return router.prepareRoute.call(this, 'PUT', url, opts, handler) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     options: function _options (url, opts, handler) { | 
					
						
							|  |  |  |       return router.prepareRoute.call(this, 'OPTIONS', url, opts, handler) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     all: function _all (url, opts, handler) { | 
					
						
							|  |  |  |       return router.prepareRoute.call(this, supportedMethods, url, opts, handler) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     // extended route
 | 
					
						
							|  |  |  |     route: function _route (opts) { | 
					
						
							|  |  |  |       // we need the fastify object that we are producing so we apply a lazy loading of the function,
 | 
					
						
							|  |  |  |       // otherwise we should bind it after the declaration
 | 
					
						
							|  |  |  |       return router.route.call(this, opts) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     // expose logger instance
 | 
					
						
							|  |  |  |     log: logger, | 
					
						
							|  |  |  |     // hooks
 | 
					
						
							|  |  |  |     addHook, | 
					
						
							|  |  |  |     // schemas
 | 
					
						
							|  |  |  |     addSchema, | 
					
						
							|  |  |  |     getSchema: schemaController.getSchema.bind(schemaController), | 
					
						
							|  |  |  |     getSchemas: schemaController.getSchemas.bind(schemaController), | 
					
						
							|  |  |  |     setValidatorCompiler, | 
					
						
							|  |  |  |     setSerializerCompiler, | 
					
						
							|  |  |  |     setSchemaController, | 
					
						
							|  |  |  |     setReplySerializer, | 
					
						
							|  |  |  |     setSchemaErrorFormatter, | 
					
						
							|  |  |  |     // custom parsers
 | 
					
						
							|  |  |  |     addContentTypeParser: ContentTypeParser.helpers.addContentTypeParser, | 
					
						
							|  |  |  |     hasContentTypeParser: ContentTypeParser.helpers.hasContentTypeParser, | 
					
						
							|  |  |  |     getDefaultJsonParser: ContentTypeParser.defaultParsers.getDefaultJsonParser, | 
					
						
							|  |  |  |     defaultTextParser: ContentTypeParser.defaultParsers.defaultTextParser, | 
					
						
							|  |  |  |     removeContentTypeParser: ContentTypeParser.helpers.removeContentTypeParser, | 
					
						
							|  |  |  |     removeAllContentTypeParsers: ContentTypeParser.helpers.removeAllContentTypeParsers, | 
					
						
							|  |  |  |     // Fastify architecture methods (initialized by Avvio)
 | 
					
						
							|  |  |  |     register: null, | 
					
						
							|  |  |  |     after: null, | 
					
						
							|  |  |  |     ready: null, | 
					
						
							|  |  |  |     onClose: null, | 
					
						
							|  |  |  |     close: null, | 
					
						
							|  |  |  |     printPlugins: null, | 
					
						
							|  |  |  |     // http server
 | 
					
						
							|  |  |  |     listen, | 
					
						
							|  |  |  |     server, | 
					
						
							|  |  |  |     // extend fastify objects
 | 
					
						
							|  |  |  |     decorate: decorator.add, | 
					
						
							|  |  |  |     hasDecorator: decorator.exist, | 
					
						
							|  |  |  |     decorateReply: decorator.decorateReply, | 
					
						
							|  |  |  |     decorateRequest: decorator.decorateRequest, | 
					
						
							|  |  |  |     hasRequestDecorator: decorator.existRequest, | 
					
						
							|  |  |  |     hasReplyDecorator: decorator.existReply, | 
					
						
							|  |  |  |     // fake http injection
 | 
					
						
							|  |  |  |     inject, | 
					
						
							|  |  |  |     // pretty print of the registered routes
 | 
					
						
							|  |  |  |     printRoutes, | 
					
						
							|  |  |  |     // custom error handling
 | 
					
						
							|  |  |  |     setNotFoundHandler, | 
					
						
							|  |  |  |     setErrorHandler, | 
					
						
							|  |  |  |     // Set fastify initial configuration options read-only object
 | 
					
						
							|  |  |  |     initialConfig | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fastify[kReply].prototype.server = fastify | 
					
						
							|  |  |  |   fastify[kRequest].prototype.server = fastify | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Object.defineProperties(fastify, { | 
					
						
							|  |  |  |     pluginName: { | 
					
						
							|  |  |  |       get () { | 
					
						
							|  |  |  |         if (this[kPluginNameChain].length > 1) { | 
					
						
							|  |  |  |           return this[kPluginNameChain].join(' -> ') | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return this[kPluginNameChain][0] | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     prefix: { | 
					
						
							|  |  |  |       get () { return this[kRoutePrefix] } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     validatorCompiler: { | 
					
						
							|  |  |  |       get () { return this[kSchemaController].getValidatorCompiler() } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     serializerCompiler: { | 
					
						
							|  |  |  |       get () { return this[kSchemaController].getSerializerCompiler() } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     version: { | 
					
						
							|  |  |  |       get () { return VERSION } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     errorHandler: { | 
					
						
							|  |  |  |       get () { | 
					
						
							|  |  |  |         return this[kErrorHandler] | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // We are adding `use` to the fastify prototype so the user
 | 
					
						
							|  |  |  |   // can still access it (and get the expected error), but `decorate`
 | 
					
						
							|  |  |  |   // will not detect it, and allow the user to override it.
 | 
					
						
							|  |  |  |   Object.setPrototypeOf(fastify, { use }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (options.schemaErrorFormatter) { | 
					
						
							|  |  |  |     validateSchemaErrorFormatter(options.schemaErrorFormatter) | 
					
						
							|  |  |  |     fastify[kSchemaErrorFormatter] = options.schemaErrorFormatter.bind(fastify) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Install and configure Avvio
 | 
					
						
							|  |  |  |   // Avvio will update the following Fastify methods:
 | 
					
						
							|  |  |  |   // - register
 | 
					
						
							|  |  |  |   // - after
 | 
					
						
							|  |  |  |   // - ready
 | 
					
						
							|  |  |  |   // - onClose
 | 
					
						
							|  |  |  |   // - close
 | 
					
						
							|  |  |  |   const avvio = Avvio(fastify, { | 
					
						
							|  |  |  |     autostart: false, | 
					
						
							|  |  |  |     timeout: Number(options.pluginTimeout) || defaultInitOptions.pluginTimeout, | 
					
						
							|  |  |  |     expose: { | 
					
						
							|  |  |  |       use: 'register' | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  |   // Override to allow the plugin encapsulation
 | 
					
						
							|  |  |  |   avvio.override = override | 
					
						
							|  |  |  |   avvio.on('start', () => (fastify[kState].started = true)) | 
					
						
							|  |  |  |   fastify[kAvvioBoot] = fastify.ready // the avvio ready function
 | 
					
						
							|  |  |  |   fastify.ready = ready // overwrite the avvio ready function
 | 
					
						
							|  |  |  |   fastify.printPlugins = avvio.prettyPrint.bind(avvio) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // cache the closing value, since we are checking it in an hot path
 | 
					
						
							|  |  |  |   avvio.once('preReady', () => { | 
					
						
							|  |  |  |     fastify.onClose((instance, done) => { | 
					
						
							|  |  |  |       fastify[kState].closing = true | 
					
						
							|  |  |  |       router.closeRoutes() | 
					
						
							|  |  |  |       if (fastify[kState].listening) { | 
					
						
							|  |  |  |         // No new TCP connections are accepted
 | 
					
						
							|  |  |  |         instance.server.close(done) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const conn of fastify[kKeepAliveConnections]) { | 
					
						
							|  |  |  |           // We must invoke the destroy method instead of merely unreffing
 | 
					
						
							|  |  |  |           // the sockets. If we only unref, then the callback passed to
 | 
					
						
							|  |  |  |           // `fastify.close` will never be invoked; nor will any of the
 | 
					
						
							|  |  |  |           // registered `onClose` hooks.
 | 
					
						
							|  |  |  |           conn.destroy() | 
					
						
							|  |  |  |           fastify[kKeepAliveConnections].delete(conn) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         done(null) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Set the default 404 handler
 | 
					
						
							|  |  |  |   fastify.setNotFoundHandler() | 
					
						
							|  |  |  |   fourOhFour.arrange404(fastify) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   router.setup(options, { | 
					
						
							|  |  |  |     avvio, | 
					
						
							|  |  |  |     fourOhFour, | 
					
						
							|  |  |  |     logger, | 
					
						
							|  |  |  |     hasLogger, | 
					
						
							|  |  |  |     setupResponseListeners, | 
					
						
							|  |  |  |     throwIfAlreadyStarted | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Delay configuring clientError handler so that it can access fastify state.
 | 
					
						
							|  |  |  |   server.on('clientError', options.clientErrorHandler.bind(fastify)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     const dc = require('diagnostics_channel') | 
					
						
							|  |  |  |     const initChannel = dc.channel('fastify.initialization') | 
					
						
							|  |  |  |     if (initChannel.hasSubscribers) { | 
					
						
							|  |  |  |       initChannel.publish({ fastify }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							|  |  |  |     // This only happens if `diagnostics_channel` isn't available, i.e. earlier
 | 
					
						
							|  |  |  |     // versions of Node.js. In that event, we don't care, so ignore the error.
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return fastify | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function throwIfAlreadyStarted (msg) { | 
					
						
							|  |  |  |     if (fastify[kState].started) throw new Error(msg) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // HTTP injection handling
 | 
					
						
							|  |  |  |   // If the server is not ready yet, this
 | 
					
						
							|  |  |  |   // utility will automatically force it.
 | 
					
						
							|  |  |  |   function inject (opts, cb) { | 
					
						
							|  |  |  |     // lightMyRequest is dynamically loaded as it seems very expensive
 | 
					
						
							|  |  |  |     // because of Ajv
 | 
					
						
							|  |  |  |     if (lightMyRequest === undefined) { | 
					
						
							|  |  |  |       lightMyRequest = require('light-my-request') | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (fastify[kState].started) { | 
					
						
							|  |  |  |       if (fastify[kState].closing) { | 
					
						
							|  |  |  |         // Force to return an error
 | 
					
						
							|  |  |  |         const error = new Error('Server is closed') | 
					
						
							|  |  |  |         if (cb) { | 
					
						
							|  |  |  |           cb(error) | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           return Promise.reject(error) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return lightMyRequest(httpHandler, opts, cb) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (cb) { | 
					
						
							|  |  |  |       this.ready(err => { | 
					
						
							|  |  |  |         if (err) cb(err, null) | 
					
						
							|  |  |  |         else lightMyRequest(httpHandler, opts, cb) | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return lightMyRequest((req, res) => { | 
					
						
							|  |  |  |         this.ready(function (err) { | 
					
						
							|  |  |  |           if (err) { | 
					
						
							|  |  |  |             res.emit('error', err) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           httpHandler(req, res) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       }, opts) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function ready (cb) { | 
					
						
							|  |  |  |     let resolveReady | 
					
						
							|  |  |  |     let rejectReady | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // run the hooks after returning the promise
 | 
					
						
							|  |  |  |     process.nextTick(runHooks) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!cb) { | 
					
						
							|  |  |  |       return new Promise(function (resolve, reject) { | 
					
						
							|  |  |  |         resolveReady = resolve | 
					
						
							|  |  |  |         rejectReady = reject | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function runHooks () { | 
					
						
							|  |  |  |       // start loading
 | 
					
						
							|  |  |  |       fastify[kAvvioBoot]((err, done) => { | 
					
						
							|  |  |  |         if (err || fastify[kState].started) { | 
					
						
							|  |  |  |           manageErr(err) | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           hookRunnerApplication('onReady', fastify[kAvvioBoot], fastify, manageErr) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         done() | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function manageErr (err) { | 
					
						
							|  |  |  |       if (cb) { | 
					
						
							|  |  |  |         if (err) { | 
					
						
							|  |  |  |           cb(err) | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           cb(undefined, fastify) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         if (err) { | 
					
						
							|  |  |  |           return rejectReady(err) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         resolveReady(fastify) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function use () { | 
					
						
							|  |  |  |     throw new FST_ERR_MISSING_MIDDLEWARE() | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // wrapper that we expose to the user for hooks handling
 | 
					
						
							|  |  |  |   function addHook (name, fn) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "addHook" when fastify instance is already started!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (name === 'onSend' || name === 'preSerialization' || name === 'onError') { | 
					
						
							|  |  |  |       if (fn.constructor.name === 'AsyncFunction' && fn.length === 4) { | 
					
						
							|  |  |  |         throw new Error('Async function has too many arguments. Async hooks should not use the \'done\' argument.') | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else if (name === 'onReady') { | 
					
						
							|  |  |  |       if (fn.constructor.name === 'AsyncFunction' && fn.length !== 0) { | 
					
						
							|  |  |  |         throw new Error('Async function has too many arguments. Async hooks should not use the \'done\' argument.') | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else if (name !== 'preParsing') { | 
					
						
							|  |  |  |       if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) { | 
					
						
							|  |  |  |         throw new Error('Async function has too many arguments. Async hooks should not use the \'done\' argument.') | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (name === 'onClose') { | 
					
						
							|  |  |  |       this.onClose(fn) | 
					
						
							|  |  |  |     } else if (name === 'onReady') { | 
					
						
							|  |  |  |       this[kHooks].add(name, fn) | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       this.after((err, done) => { | 
					
						
							|  |  |  |         _addHook.call(this, name, fn) | 
					
						
							|  |  |  |         done(err) | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function _addHook (name, fn) { | 
					
						
							|  |  |  |       this[kHooks].add(name, fn) | 
					
						
							|  |  |  |       this[kChildren].forEach(child => _addHook.call(child, name, fn)) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // wrapper that we expose to the user for schemas handling
 | 
					
						
							|  |  |  |   function addSchema (schema) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "addSchema" when fastify instance is already started!') | 
					
						
							|  |  |  |     this[kSchemaController].add(schema) | 
					
						
							|  |  |  |     this[kChildren].forEach(child => child.addSchema(schema)) | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function defaultClientErrorHandler (err, socket) { | 
					
						
							|  |  |  |     // In case of a connection reset, the socket has been destroyed and there is nothing that needs to be done.
 | 
					
						
							|  |  |  |     // https://nodejs.org/api/http.html#http_event_clienterror
 | 
					
						
							|  |  |  |     if (err.code === 'ECONNRESET' || socket.destroyed) { | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const body = JSON.stringify({ | 
					
						
							|  |  |  |       error: http.STATUS_CODES['400'], | 
					
						
							|  |  |  |       message: 'Client Error', | 
					
						
							|  |  |  |       statusCode: 400 | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Most devs do not know what to do with this error.
 | 
					
						
							|  |  |  |     // In the vast majority of cases, it's a network error and/or some
 | 
					
						
							|  |  |  |     // config issue on the load balancer side.
 | 
					
						
							|  |  |  |     this.log.trace({ err }, 'client error') | 
					
						
							|  |  |  |     // Copying standard node behaviour
 | 
					
						
							|  |  |  |     // https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // If the socket is not writable, there is no reason to try to send data.
 | 
					
						
							|  |  |  |     if (socket.writable) { | 
					
						
							|  |  |  |       socket.write(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     socket.destroy(err) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // If the router does not match any route, every request will land here
 | 
					
						
							|  |  |  |   // req and res are Node.js core objects
 | 
					
						
							|  |  |  |   function defaultRoute (req, res) { | 
					
						
							|  |  |  |     if (req.headers['accept-version'] !== undefined) { | 
					
						
							|  |  |  |       // we remove the accept-version header for performance result
 | 
					
						
							|  |  |  |       // because we do not want to go through the constraint checking
 | 
					
						
							|  |  |  |       // the usage of symbol here to prevent any colision on custom header name
 | 
					
						
							|  |  |  |       req.headers[kRequestAcceptVersion] = req.headers['accept-version'] | 
					
						
							|  |  |  |       req.headers['accept-version'] = undefined | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     fourOhFour.router.lookup(req, res) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function onBadUrl (path, req, res) { | 
					
						
							|  |  |  |     if (frameworkErrors) { | 
					
						
							|  |  |  |       const id = genReqId(req) | 
					
						
							|  |  |  |       const childLogger = logger.child({ reqId: id }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       childLogger.info({ req }, 'incoming request') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const request = new Request(id, null, req, null, childLogger, onBadUrlContext) | 
					
						
							|  |  |  |       const reply = new Reply(res, request, childLogger) | 
					
						
							|  |  |  |       return frameworkErrors(new FST_ERR_BAD_URL(path), request, reply) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const body = `{"error":"Bad Request","message":"'${path}' is not a valid url component","statusCode":400}` | 
					
						
							|  |  |  |     res.writeHead(400, { | 
					
						
							|  |  |  |       'Content-Type': 'application/json', | 
					
						
							|  |  |  |       'Content-Length': body.length | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     res.end(body) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function setNotFoundHandler (opts, handler) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "setNotFoundHandler" when fastify instance is already started!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fourOhFour.setNotFoundHandler.call(this, opts, handler, avvio, router.routeHandler) | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function setValidatorCompiler (validatorCompiler) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "setValidatorCompiler" when fastify instance is already started!') | 
					
						
							|  |  |  |     this[kSchemaController].setValidatorCompiler(validatorCompiler) | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function setSchemaErrorFormatter (errorFormatter) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "setSchemaErrorFormatter" when fastify instance is already started!') | 
					
						
							|  |  |  |     validateSchemaErrorFormatter(errorFormatter) | 
					
						
							|  |  |  |     this[kSchemaErrorFormatter] = errorFormatter.bind(this) | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function setSerializerCompiler (serializerCompiler) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "setSerializerCompiler" when fastify instance is already started!') | 
					
						
							|  |  |  |     this[kSchemaController].setSerializerCompiler(serializerCompiler) | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function setSchemaController (schemaControllerOpts) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "setSchemaController" when fastify instance is already started!') | 
					
						
							|  |  |  |     const old = this[kSchemaController] | 
					
						
							|  |  |  |     const schemaController = SchemaController.buildSchemaController(old, Object.assign({}, old.opts, schemaControllerOpts)) | 
					
						
							|  |  |  |     this[kSchemaController] = schemaController | 
					
						
							|  |  |  |     this.getSchema = schemaController.getSchema.bind(schemaController) | 
					
						
							|  |  |  |     this.getSchemas = schemaController.getSchemas.bind(schemaController) | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function setReplySerializer (replySerializer) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "setReplySerializer" when fastify instance is already started!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this[kReplySerializerDefault] = replySerializer | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // wrapper that we expose to the user for configure the custom error handler
 | 
					
						
							|  |  |  |   function setErrorHandler (func) { | 
					
						
							|  |  |  |     throwIfAlreadyStarted('Cannot call "setErrorHandler" when fastify instance is already started!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this[kErrorHandler] = func.bind(this) | 
					
						
							|  |  |  |     return this | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function printRoutes (opts = {}) { | 
					
						
							|  |  |  |     // includeHooks:true - shortcut to include all supported hooks exported by fastify.Hooks
 | 
					
						
							|  |  |  |     opts.includeMeta = opts.includeHooks ? opts.includeMeta ? supportedHooks.concat(opts.includeMeta) : supportedHooks : opts.includeMeta | 
					
						
							|  |  |  |     return router.printRoutes(opts) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function validateSchemaErrorFormatter (schemaErrorFormatter) { | 
					
						
							|  |  |  |   if (typeof schemaErrorFormatter !== 'function') { | 
					
						
							|  |  |  |     throw new Error(`schemaErrorFormatter option should be a function, instead got ${typeof schemaErrorFormatter}`) | 
					
						
							|  |  |  |   } else if (schemaErrorFormatter.constructor.name === 'AsyncFunction') { | 
					
						
							|  |  |  |     throw new Error('schemaErrorFormatter option should not be an async function') | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function wrapRouting (httpHandler, { rewriteUrl, logger }) { | 
					
						
							|  |  |  |   if (!rewriteUrl) { | 
					
						
							|  |  |  |     return httpHandler | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return function preRouting (req, res) { | 
					
						
							|  |  |  |     const originalUrl = req.url | 
					
						
							|  |  |  |     const url = rewriteUrl(req) | 
					
						
							|  |  |  |     if (originalUrl !== url) { | 
					
						
							|  |  |  |       logger.debug({ originalUrl, url }, 'rewrite url') | 
					
						
							|  |  |  |       if (typeof url === 'string') { | 
					
						
							|  |  |  |         req.url = url | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         req.destroy(new Error(`Rewrite url for "${req.url}" needs to be of type "string" but received "${typeof url}"`)) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     httpHandler(req, res) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * These export configurations enable JS and TS developers | 
					
						
							|  |  |  |  * to consumer fastify in whatever way best suits their needs. | 
					
						
							|  |  |  |  * Some examples of supported import syntax includes: | 
					
						
							|  |  |  |  * - `const fastify = require('fastify')` | 
					
						
							|  |  |  |  * - `const { fastify } = require('fastify')` | 
					
						
							|  |  |  |  * - `import * as Fastify from 'fastify'` | 
					
						
							|  |  |  |  * - `import { fastify, TSC_definition } from 'fastify'` | 
					
						
							|  |  |  |  * - `import fastify from 'fastify'` | 
					
						
							|  |  |  |  * - `import fastify, { TSC_definition } from 'fastify'` | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | module.exports = fastify | 
					
						
							|  |  |  | module.exports.fastify = fastify | 
					
						
							|  |  |  | module.exports.default = fastify |