revert one
This commit is contained in:
2025-09-20 13:26:52 +00:00
parent c74f28caa7
commit a2271529a8
2539 changed files with 0 additions and 365006 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,402 +0,0 @@
'use strict'
const { AsyncResource } = require('node:async_hooks')
const { FifoMap: Fifo } = require('toad-cache')
const { parse: secureJsonParse } = require('secure-json-parse')
const {
kDefaultJsonParse,
kContentTypeParser,
kBodyLimit,
kRequestPayloadStream,
kState,
kTestInternals,
kReplyIsError,
kRouteContext
} = require('./symbols')
const {
FST_ERR_CTP_INVALID_TYPE,
FST_ERR_CTP_EMPTY_TYPE,
FST_ERR_CTP_ALREADY_PRESENT,
FST_ERR_CTP_INVALID_HANDLER,
FST_ERR_CTP_INVALID_PARSE_TYPE,
FST_ERR_CTP_BODY_TOO_LARGE,
FST_ERR_CTP_INVALID_MEDIA_TYPE,
FST_ERR_CTP_INVALID_CONTENT_LENGTH,
FST_ERR_CTP_EMPTY_JSON_BODY,
FST_ERR_CTP_INSTANCE_ALREADY_STARTED,
FST_ERR_CTP_INVALID_JSON_BODY
} = require('./errors')
const { FSTSEC001 } = require('./warnings')
function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning) {
this[kDefaultJsonParse] = getDefaultJsonParser(onProtoPoisoning, onConstructorPoisoning)
// using a map instead of a plain object to avoid prototype hijack attacks
this.customParsers = new Map()
this.customParsers.set('application/json', new Parser(true, false, bodyLimit, this[kDefaultJsonParse]))
this.customParsers.set('text/plain', new Parser(true, false, bodyLimit, defaultPlainTextParser))
this.parserList = ['application/json', 'text/plain']
this.parserRegExpList = []
this.cache = new Fifo(100)
}
ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
const contentTypeIsString = typeof contentType === 'string'
if (contentTypeIsString) {
contentType = contentType.trim().toLowerCase()
if (contentType.length === 0) throw new FST_ERR_CTP_EMPTY_TYPE()
} else if (!(contentType instanceof RegExp)) {
throw new FST_ERR_CTP_INVALID_TYPE()
}
if (typeof parserFn !== 'function') {
throw new FST_ERR_CTP_INVALID_HANDLER()
}
if (this.existingParser(contentType)) {
throw new FST_ERR_CTP_ALREADY_PRESENT(contentType)
}
if (opts.parseAs !== undefined) {
if (opts.parseAs !== 'string' && opts.parseAs !== 'buffer') {
throw new FST_ERR_CTP_INVALID_PARSE_TYPE(opts.parseAs)
}
}
const parser = new Parser(
opts.parseAs === 'string',
opts.parseAs === 'buffer',
opts.bodyLimit,
parserFn
)
if (contentType === '*') {
this.customParsers.set('', parser)
} else {
if (contentTypeIsString) {
this.parserList.unshift(contentType)
this.customParsers.set(contentType, parser)
} else {
validateRegExp(contentType)
this.parserRegExpList.unshift(contentType)
this.customParsers.set(contentType.toString(), parser)
}
}
}
ContentTypeParser.prototype.hasParser = function (contentType) {
if (typeof contentType === 'string') {
contentType = contentType.trim().toLowerCase()
} else {
if (!(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
contentType = contentType.toString()
}
return this.customParsers.has(contentType)
}
ContentTypeParser.prototype.existingParser = function (contentType) {
if (contentType === 'application/json' && this.customParsers.has(contentType)) {
return this.customParsers.get(contentType).fn !== this[kDefaultJsonParse]
}
if (contentType === 'text/plain' && this.customParsers.has(contentType)) {
return this.customParsers.get(contentType).fn !== defaultPlainTextParser
}
return this.hasParser(contentType)
}
ContentTypeParser.prototype.getParser = function (contentType) {
let parser = this.customParsers.get(contentType)
if (parser !== undefined) return parser
parser = this.cache.get(contentType)
if (parser !== undefined) return parser
const caseInsensitiveContentType = contentType.toLowerCase()
for (let i = 0; i !== this.parserList.length; ++i) {
const parserListItem = this.parserList[i]
if (
caseInsensitiveContentType.slice(0, parserListItem.length) === parserListItem &&
(
caseInsensitiveContentType.length === parserListItem.length ||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 59 /* `;` */ ||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 32 /* ` ` */
)
) {
parser = this.customParsers.get(parserListItem)
this.cache.set(contentType, parser)
return parser
}
}
for (let j = 0; j !== this.parserRegExpList.length; ++j) {
const parserRegExp = this.parserRegExpList[j]
if (parserRegExp.test(contentType)) {
parser = this.customParsers.get(parserRegExp.toString())
this.cache.set(contentType, parser)
return parser
}
}
return this.customParsers.get('')
}
ContentTypeParser.prototype.removeAll = function () {
this.customParsers = new Map()
this.parserRegExpList = []
this.parserList = []
this.cache = new Fifo(100)
}
ContentTypeParser.prototype.remove = function (contentType) {
let parsers
if (typeof contentType === 'string') {
contentType = contentType.trim().toLowerCase()
parsers = this.parserList
} else {
if (!(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
contentType = contentType.toString()
parsers = this.parserRegExpList
}
const removed = this.customParsers.delete(contentType)
const idx = parsers.findIndex(ct => ct.toString() === contentType)
if (idx > -1) {
parsers.splice(idx, 1)
}
return removed || idx > -1
}
ContentTypeParser.prototype.run = function (contentType, handler, request, reply) {
const parser = this.getParser(contentType)
if (parser === undefined) {
if (request.is404 === true) {
handler(request, reply)
return
}
reply[kReplyIsError] = true
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType || undefined))
return
}
const resource = new AsyncResource('content-type-parser:run', request)
const done = resource.bind(onDone)
if (parser.asString === true || parser.asBuffer === true) {
rawBody(
request,
reply,
reply[kRouteContext]._parserOptions,
parser,
done
)
return
}
const result = parser.fn(request, request[kRequestPayloadStream], done)
if (result && typeof result.then === 'function') {
result.then(body => { done(null, body) }, done)
}
function onDone (error, body) {
resource.emitDestroy()
if (error != null) {
// We must close the connection as the client may
// send more data
reply.header('connection', 'close')
reply[kReplyIsError] = true
reply.send(error)
return
}
request.body = body
handler(request, reply)
}
}
function rawBody (request, reply, options, parser, done) {
const asString = parser.asString === true
const limit = options.limit === null ? parser.bodyLimit : options.limit
const contentLength = Number(request.headers['content-length'])
if (contentLength > limit) {
done(new FST_ERR_CTP_BODY_TOO_LARGE(), undefined)
return
}
let receivedLength = 0
let body = asString ? '' : []
const payload = request[kRequestPayloadStream] || request.raw
if (asString) {
payload.setEncoding('utf8')
}
payload.on('data', onData)
payload.on('end', onEnd)
payload.on('error', onEnd)
payload.resume()
function onData (chunk) {
receivedLength += asString ? Buffer.byteLength(chunk) : chunk.length
const { receivedEncodedLength = 0 } = payload
// The resulting body length must not exceed bodyLimit (see "zip bomb").
// The case when encoded length is larger than received length is rather theoretical,
// unless the stream returned by preParsing hook is broken and reports wrong value.
if (receivedLength > limit || receivedEncodedLength > limit) {
payload.removeListener('data', onData)
payload.removeListener('end', onEnd)
payload.removeListener('error', onEnd)
done(new FST_ERR_CTP_BODY_TOO_LARGE(), undefined)
return
}
if (asString) {
body += chunk
} else {
body.push(chunk)
}
}
function onEnd (err) {
payload.removeListener('data', onData)
payload.removeListener('end', onEnd)
payload.removeListener('error', onEnd)
if (err != null) {
if (!(typeof err.statusCode === 'number' && err.statusCode >= 400)) {
err.statusCode = 400
}
done(err, undefined)
return
}
if (!Number.isNaN(contentLength) && (payload.receivedEncodedLength || receivedLength) !== contentLength) {
done(new FST_ERR_CTP_INVALID_CONTENT_LENGTH(), undefined)
return
}
if (!asString) {
body = Buffer.concat(body)
}
const result = parser.fn(request, body, done)
if (result && typeof result.then === 'function') {
result.then(body => { done(null, body) }, done)
}
}
}
function getDefaultJsonParser (onProtoPoisoning, onConstructorPoisoning) {
const parseOptions = { protoAction: onProtoPoisoning, constructorAction: onConstructorPoisoning }
return defaultJsonParser
function defaultJsonParser (req, body, done) {
if (body.length === 0) {
done(new FST_ERR_CTP_EMPTY_JSON_BODY(), undefined)
return
}
try {
done(null, secureJsonParse(body, parseOptions))
} catch {
done(new FST_ERR_CTP_INVALID_JSON_BODY(), undefined)
}
}
}
function defaultPlainTextParser (req, body, done) {
done(null, body)
}
function Parser (asString, asBuffer, bodyLimit, fn) {
this.asString = asString
this.asBuffer = asBuffer
this.bodyLimit = bodyLimit
this.fn = fn
}
function buildContentTypeParser (c) {
const contentTypeParser = new ContentTypeParser()
contentTypeParser[kDefaultJsonParse] = c[kDefaultJsonParse]
contentTypeParser.customParsers = new Map(c.customParsers.entries())
contentTypeParser.parserList = c.parserList.slice()
contentTypeParser.parserRegExpList = c.parserRegExpList.slice()
return contentTypeParser
}
function addContentTypeParser (contentType, opts, parser) {
if (this[kState].started) {
throw new FST_ERR_CTP_INSTANCE_ALREADY_STARTED('addContentTypeParser')
}
if (typeof opts === 'function') {
parser = opts
opts = {}
}
if (!opts) opts = {}
if (!opts.bodyLimit) opts.bodyLimit = this[kBodyLimit]
if (Array.isArray(contentType)) {
contentType.forEach((type) => this[kContentTypeParser].add(type, opts, parser))
} else {
this[kContentTypeParser].add(contentType, opts, parser)
}
return this
}
function hasContentTypeParser (contentType) {
return this[kContentTypeParser].hasParser(contentType)
}
function removeContentTypeParser (contentType) {
if (this[kState].started) {
throw new FST_ERR_CTP_INSTANCE_ALREADY_STARTED('removeContentTypeParser')
}
if (Array.isArray(contentType)) {
for (const type of contentType) {
this[kContentTypeParser].remove(type)
}
} else {
this[kContentTypeParser].remove(contentType)
}
}
function removeAllContentTypeParsers () {
if (this[kState].started) {
throw new FST_ERR_CTP_INSTANCE_ALREADY_STARTED('removeAllContentTypeParsers')
}
this[kContentTypeParser].removeAll()
}
function validateRegExp (regexp) {
// RegExp should either start with ^ or include ;?
// It can ensure the user is properly detect the essence
// MIME types.
if (regexp.source[0] !== '^' && regexp.source.includes(';?') === false) {
FSTSEC001(regexp.source)
}
}
module.exports = ContentTypeParser
module.exports.helpers = {
buildContentTypeParser,
addContentTypeParser,
hasContentTypeParser,
removeContentTypeParser,
removeAllContentTypeParsers
}
module.exports.defaultParsers = {
getDefaultJsonParser,
defaultTextParser: defaultPlainTextParser
}
module.exports[kTestInternals] = { rawBody }

95
node_modules/fastify/lib/context.js generated vendored
View File

@@ -1,95 +0,0 @@
'use strict'
const {
kFourOhFourContext,
kReplySerializerDefault,
kSchemaErrorFormatter,
kErrorHandler,
kChildLoggerFactory,
kOptions,
kReply,
kRequest,
kBodyLimit,
kLogLevel,
kContentTypeParser,
kRouteByFastify,
kRequestCacheValidateFns,
kReplyCacheSerializeFns
} = require('./symbols.js')
// Object that holds the context of every request
// Every route holds an instance of this object.
function Context ({
schema,
handler,
config,
requestIdLogLabel,
childLoggerFactory,
errorHandler,
bodyLimit,
logLevel,
logSerializers,
attachValidation,
validatorCompiler,
serializerCompiler,
replySerializer,
schemaErrorFormatter,
exposeHeadRoute,
prefixTrailingSlash,
server,
isFastify
}) {
this.schema = schema
this.handler = handler
this.Reply = server[kReply]
this.Request = server[kRequest]
this.contentTypeParser = server[kContentTypeParser]
this.onRequest = null
this.onSend = null
this.onError = null
this.onTimeout = null
this.preHandler = null
this.onResponse = null
this.preSerialization = null
this.onRequestAbort = null
this.config = config
this.errorHandler = errorHandler || server[kErrorHandler]
this.requestIdLogLabel = requestIdLogLabel || server[kOptions].requestIdLogLabel
this.childLoggerFactory = childLoggerFactory || server[kChildLoggerFactory]
this._middie = null
this._parserOptions = {
limit: bodyLimit || server[kBodyLimit]
}
this.exposeHeadRoute = exposeHeadRoute
this.prefixTrailingSlash = prefixTrailingSlash
this.logLevel = logLevel || server[kLogLevel]
this.logSerializers = logSerializers
this[kFourOhFourContext] = null
this.attachValidation = attachValidation
this[kReplySerializerDefault] = replySerializer
this.schemaErrorFormatter =
schemaErrorFormatter ||
server[kSchemaErrorFormatter] ||
defaultSchemaErrorFormatter
this[kRouteByFastify] = isFastify
this[kRequestCacheValidateFns] = null
this[kReplyCacheSerializeFns] = null
this.validatorCompiler = validatorCompiler || null
this.serializerCompiler = serializerCompiler || null
this.server = server
}
function defaultSchemaErrorFormatter (errors, dataVar) {
let text = ''
const separator = ', '
for (let i = 0; i !== errors.length; ++i) {
const e = errors[i]
text += dataVar + (e.instancePath || '') + ' ' + e.message + separator
}
return new Error(text.slice(0, -separator.length))
}
module.exports = Context

152
node_modules/fastify/lib/decorate.js generated vendored
View File

@@ -1,152 +0,0 @@
'use strict'
const {
kReply,
kRequest,
kState,
kHasBeenDecorated
} = require('./symbols.js')
const {
FST_ERR_DEC_ALREADY_PRESENT,
FST_ERR_DEC_MISSING_DEPENDENCY,
FST_ERR_DEC_AFTER_START,
FST_ERR_DEC_REFERENCE_TYPE,
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE,
FST_ERR_DEC_UNDECLARED
} = require('./errors')
function decorate (instance, name, fn, dependencies) {
if (Object.hasOwn(instance, name)) {
throw new FST_ERR_DEC_ALREADY_PRESENT(name)
}
checkDependencies(instance, name, dependencies)
if (fn && (typeof fn.getter === 'function' || typeof fn.setter === 'function')) {
Object.defineProperty(instance, name, {
get: fn.getter,
set: fn.setter
})
} else {
instance[name] = fn
}
}
function getInstanceDecorator (name) {
if (!checkExistence(this, name)) {
throw new FST_ERR_DEC_UNDECLARED(name, 'instance')
}
if (typeof this[name] === 'function') {
return this[name].bind(this)
}
return this[name]
}
function decorateConstructor (konstructor, name, fn, dependencies) {
const instance = konstructor.prototype
if (Object.hasOwn(instance, name) || hasKey(konstructor, name)) {
throw new FST_ERR_DEC_ALREADY_PRESENT(name)
}
konstructor[kHasBeenDecorated] = true
checkDependencies(konstructor, name, dependencies)
if (fn && (typeof fn.getter === 'function' || typeof fn.setter === 'function')) {
Object.defineProperty(instance, name, {
get: fn.getter,
set: fn.setter
})
} else if (typeof fn === 'function') {
instance[name] = fn
} else {
konstructor.props.push({ key: name, value: fn })
}
}
function checkReferenceType (name, fn) {
if (typeof fn === 'object' && fn && !(typeof fn.getter === 'function' || typeof fn.setter === 'function')) {
throw new FST_ERR_DEC_REFERENCE_TYPE(name, typeof fn)
}
}
function decorateFastify (name, fn, dependencies) {
assertNotStarted(this, name)
decorate(this, name, fn, dependencies)
return this
}
function checkExistence (instance, name) {
if (name) {
return name in instance || (instance.prototype && name in instance.prototype) || hasKey(instance, name)
}
return instance in this
}
function hasKey (fn, name) {
if (fn.props) {
return fn.props.find(({ key }) => key === name)
}
return false
}
function checkRequestExistence (name) {
if (name && hasKey(this[kRequest], name)) return true
return checkExistence(this[kRequest].prototype, name)
}
function checkReplyExistence (name) {
if (name && hasKey(this[kReply], name)) return true
return checkExistence(this[kReply].prototype, name)
}
function checkDependencies (instance, name, deps) {
if (deps === undefined || deps === null) {
return
}
if (!Array.isArray(deps)) {
throw new FST_ERR_DEC_DEPENDENCY_INVALID_TYPE(name)
}
for (let i = 0; i !== deps.length; ++i) {
if (!checkExistence(instance, deps[i])) {
throw new FST_ERR_DEC_MISSING_DEPENDENCY(deps[i])
}
}
}
function decorateReply (name, fn, dependencies) {
assertNotStarted(this, name)
checkReferenceType(name, fn)
decorateConstructor(this[kReply], name, fn, dependencies)
return this
}
function decorateRequest (name, fn, dependencies) {
assertNotStarted(this, name)
checkReferenceType(name, fn)
decorateConstructor(this[kRequest], name, fn, dependencies)
return this
}
function assertNotStarted (instance, name) {
if (instance[kState].started) {
throw new FST_ERR_DEC_AFTER_START(name)
}
}
module.exports = {
add: decorateFastify,
exist: checkExistence,
existRequest: checkRequestExistence,
existReply: checkReplyExistence,
dependencies: checkDependencies,
decorateReply,
decorateRequest,
getInstanceDecorator,
hasKey
}

View File

@@ -1,176 +0,0 @@
'use strict'
const statusCodes = require('node:http').STATUS_CODES
const wrapThenable = require('./wrapThenable')
const {
kReplyHeaders,
kReplyNextErrorHandler,
kReplyIsRunningOnErrorHook,
kReplyHasStatusCode,
kRouteContext,
kDisableRequestLogging
} = require('./symbols.js')
const {
FST_ERR_REP_INVALID_PAYLOAD_TYPE,
FST_ERR_FAILED_ERROR_SERIALIZATION
} = require('./errors')
const { getSchemaSerializer } = require('./schemas')
const serializeError = require('./error-serializer')
const rootErrorHandler = {
func: defaultErrorHandler,
toJSON () {
return this.func.name.toString() + '()'
}
}
function handleError (reply, error, cb) {
reply[kReplyIsRunningOnErrorHook] = false
const context = reply[kRouteContext]
if (reply[kReplyNextErrorHandler] === false) {
fallbackErrorHandler(error, reply, function (reply, payload) {
try {
reply.raw.writeHead(reply.raw.statusCode, reply[kReplyHeaders])
} catch (error) {
if (!reply.log[kDisableRequestLogging]) {
reply.log.warn(
{ req: reply.request, res: reply, err: error },
error?.message
)
}
reply.raw.writeHead(reply.raw.statusCode)
}
reply.raw.end(payload)
})
return
}
const errorHandler = reply[kReplyNextErrorHandler] || context.errorHandler
// In case the error handler throws, we set the next errorHandler so we can error again
reply[kReplyNextErrorHandler] = Object.getPrototypeOf(errorHandler)
// we need to remove content-type to allow content-type guessing for serialization
delete reply[kReplyHeaders]['content-type']
delete reply[kReplyHeaders]['content-length']
const func = errorHandler.func
if (!func) {
reply[kReplyNextErrorHandler] = false
fallbackErrorHandler(error, reply, cb)
return
}
try {
const result = func(error, reply.request, reply)
if (result !== undefined) {
if (result !== null && typeof result.then === 'function') {
wrapThenable(result, reply)
} else {
reply.send(result)
}
}
} catch (err) {
reply.send(err)
}
}
function defaultErrorHandler (error, request, reply) {
setErrorHeaders(error, reply)
if (!reply[kReplyHasStatusCode] || reply.statusCode === 200) {
const statusCode = error.statusCode || error.status
reply.code(statusCode >= 400 ? statusCode : 500)
}
if (reply.statusCode < 500) {
if (!reply.log[kDisableRequestLogging]) {
reply.log.info(
{ res: reply, err: error },
error?.message
)
}
} else {
if (!reply.log[kDisableRequestLogging]) {
reply.log.error(
{ req: request, res: reply, err: error },
error?.message
)
}
}
reply.send(error)
}
function fallbackErrorHandler (error, reply, cb) {
const res = reply.raw
const statusCode = reply.statusCode
reply[kReplyHeaders]['content-type'] = reply[kReplyHeaders]['content-type'] ?? 'application/json; charset=utf-8'
let payload
try {
const serializerFn = getSchemaSerializer(reply[kRouteContext], statusCode, reply[kReplyHeaders]['content-type'])
if (serializerFn === false) {
payload = serializeError({
error: statusCodes[statusCode + ''],
code: error.code,
message: error.message,
statusCode
})
} else {
payload = serializerFn(Object.create(error, {
error: { value: statusCodes[statusCode + ''] },
message: { value: error.message },
statusCode: { value: statusCode }
}))
}
} catch (err) {
if (!reply.log[kDisableRequestLogging]) {
// error is always FST_ERR_SCH_SERIALIZATION_BUILD because this is called from route/compileSchemasForSerialization
reply.log.error({ err, statusCode: res.statusCode }, 'The serializer for the given status code failed')
}
reply.code(500)
payload = serializeError(new FST_ERR_FAILED_ERROR_SERIALIZATION(err.message, error.message))
}
if (typeof payload !== 'string' && !Buffer.isBuffer(payload)) {
payload = serializeError(new FST_ERR_REP_INVALID_PAYLOAD_TYPE(typeof payload))
}
reply[kReplyHeaders]['content-length'] = '' + Buffer.byteLength(payload)
cb(reply, payload)
}
function buildErrorHandler (parent = rootErrorHandler, func) {
if (!func) {
return parent
}
const errorHandler = Object.create(parent)
errorHandler.func = func
return errorHandler
}
function setErrorHeaders (error, reply) {
const res = reply.raw
let statusCode = res.statusCode
statusCode = (statusCode >= 400) ? statusCode : 500
// treat undefined and null as same
if (error != null) {
if (error.headers !== undefined) {
reply.headers(error.headers)
}
if (error.status >= 400) {
statusCode = error.status
} else if (error.statusCode >= 400) {
statusCode = error.statusCode
}
}
res.statusCode = statusCode
}
module.exports = {
buildErrorHandler,
handleError
}

View File

@@ -1,120 +0,0 @@
// This file is autogenerated by build/build-error-serializer.js, do not edit
/* c8 ignore start */
'use strict'
const Serializer = require('fast-json-stringify/lib/serializer')
const serializerState = {"mode":"standalone"}
const serializer = Serializer.restoreFromState(serializerState)
const validator = null
module.exports = function anonymous(validator,serializer
) {
const JSON_STR_BEGIN_OBJECT = '{'
const JSON_STR_END_OBJECT = '}'
const JSON_STR_BEGIN_ARRAY = '['
const JSON_STR_END_ARRAY = ']'
const JSON_STR_COMMA = ','
const JSON_STR_COLONS = ':'
const JSON_STR_QUOTE = '"'
const JSON_STR_EMPTY_OBJECT = JSON_STR_BEGIN_OBJECT + JSON_STR_END_OBJECT
const JSON_STR_EMPTY_ARRAY = JSON_STR_BEGIN_ARRAY + JSON_STR_END_ARRAY
const JSON_STR_EMPTY_STRING = JSON_STR_QUOTE + JSON_STR_QUOTE
const JSON_STR_NULL = 'null'
// #
function anonymous0 (input) {
const obj = (input && typeof input.toJSON === 'function')
? input.toJSON()
: input
if (obj === null) return JSON_STR_EMPTY_OBJECT
let value
let json = JSON_STR_BEGIN_OBJECT
let addComma = false
value = obj["statusCode"]
if (value !== undefined) {
!addComma && (addComma = true) || (json += JSON_STR_COMMA)
json += "\"statusCode\":"
json += serializer.asNumber(value)
}
value = obj["code"]
if (value !== undefined) {
!addComma && (addComma = true) || (json += JSON_STR_COMMA)
json += "\"code\":"
if (typeof value !== 'string') {
if (value === null) {
json += JSON_STR_EMPTY_STRING
} else if (value instanceof Date) {
json += JSON_STR_QUOTE + value.toISOString() + JSON_STR_QUOTE
} else if (value instanceof RegExp) {
json += serializer.asString(value.source)
} else {
json += serializer.asString(value.toString())
}
} else {
json += serializer.asString(value)
}
}
value = obj["error"]
if (value !== undefined) {
!addComma && (addComma = true) || (json += JSON_STR_COMMA)
json += "\"error\":"
if (typeof value !== 'string') {
if (value === null) {
json += JSON_STR_EMPTY_STRING
} else if (value instanceof Date) {
json += JSON_STR_QUOTE + value.toISOString() + JSON_STR_QUOTE
} else if (value instanceof RegExp) {
json += serializer.asString(value.source)
} else {
json += serializer.asString(value.toString())
}
} else {
json += serializer.asString(value)
}
}
value = obj["message"]
if (value !== undefined) {
!addComma && (addComma = true) || (json += JSON_STR_COMMA)
json += "\"message\":"
if (typeof value !== 'string') {
if (value === null) {
json += JSON_STR_EMPTY_STRING
} else if (value instanceof Date) {
json += JSON_STR_QUOTE + value.toISOString() + JSON_STR_QUOTE
} else if (value instanceof RegExp) {
json += serializer.asString(value.source)
} else {
json += serializer.asString(value.toString())
}
} else {
json += serializer.asString(value)
}
}
return json + JSON_STR_END_OBJECT
}
const main = anonymous0
return main
}(validator, serializer)
/* c8 ignore stop */

505
node_modules/fastify/lib/errors.js generated vendored
View File

@@ -1,505 +0,0 @@
'use strict'
const createError = require('@fastify/error')
const codes = {
/**
* Basic
*/
FST_ERR_NOT_FOUND: createError(
'FST_ERR_NOT_FOUND',
'Not Found',
404
),
FST_ERR_OPTIONS_NOT_OBJ: createError(
'FST_ERR_OPTIONS_NOT_OBJ',
'Options must be an object',
500,
TypeError
),
FST_ERR_QSP_NOT_FN: createError(
'FST_ERR_QSP_NOT_FN',
"querystringParser option should be a function, instead got '%s'",
500,
TypeError
),
FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN: createError(
'FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN',
"schemaController.bucket option should be a function, instead got '%s'",
500,
TypeError
),
FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN: createError(
'FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN',
"schemaErrorFormatter option should be a non async function. Instead got '%s'.",
500,
TypeError
),
FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ: createError(
'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ',
"ajv.customOptions option should be an object, instead got '%s'",
500,
TypeError
),
FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR: createError(
'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR',
"ajv.plugins option should be an array, instead got '%s'",
500,
TypeError
),
FST_ERR_VALIDATION: createError(
'FST_ERR_VALIDATION',
'%s',
400
),
FST_ERR_LISTEN_OPTIONS_INVALID: createError(
'FST_ERR_LISTEN_OPTIONS_INVALID',
"Invalid listen options: '%s'",
500,
TypeError
),
FST_ERR_ERROR_HANDLER_NOT_FN: createError(
'FST_ERR_ERROR_HANDLER_NOT_FN',
'Error Handler must be a function',
500,
TypeError
),
FST_ERR_ERROR_HANDLER_ALREADY_SET: createError(
'FST_ERR_ERROR_HANDLER_ALREADY_SET',
"Error Handler already set in this scope. Set 'allowErrorHandlerOverride: true' to allow overriding.",
500,
TypeError
),
/**
* ContentTypeParser
*/
FST_ERR_CTP_ALREADY_PRESENT: createError(
'FST_ERR_CTP_ALREADY_PRESENT',
"Content type parser '%s' already present."
),
FST_ERR_CTP_INVALID_TYPE: createError(
'FST_ERR_CTP_INVALID_TYPE',
'The content type should be a string or a RegExp',
500,
TypeError
),
FST_ERR_CTP_EMPTY_TYPE: createError(
'FST_ERR_CTP_EMPTY_TYPE',
'The content type cannot be an empty string',
500,
TypeError
),
FST_ERR_CTP_INVALID_HANDLER: createError(
'FST_ERR_CTP_INVALID_HANDLER',
'The content type handler should be a function',
500,
TypeError
),
FST_ERR_CTP_INVALID_PARSE_TYPE: createError(
'FST_ERR_CTP_INVALID_PARSE_TYPE',
"The body parser can only parse your data as 'string' or 'buffer', you asked '%s' which is not supported.",
500,
TypeError
),
FST_ERR_CTP_BODY_TOO_LARGE: createError(
'FST_ERR_CTP_BODY_TOO_LARGE',
'Request body is too large',
413,
RangeError
),
FST_ERR_CTP_INVALID_MEDIA_TYPE: createError(
'FST_ERR_CTP_INVALID_MEDIA_TYPE',
'Unsupported Media Type: %s',
415
),
FST_ERR_CTP_INVALID_CONTENT_LENGTH: createError(
'FST_ERR_CTP_INVALID_CONTENT_LENGTH',
'Request body size did not match Content-Length',
400,
RangeError
),
FST_ERR_CTP_EMPTY_JSON_BODY: createError(
'FST_ERR_CTP_EMPTY_JSON_BODY',
"Body cannot be empty when content-type is set to 'application/json'",
400
),
FST_ERR_CTP_INVALID_JSON_BODY: createError(
'FST_ERR_CTP_INVALID_JSON_BODY',
"Body is not valid JSON but content-type is set to 'application/json'",
400
),
FST_ERR_CTP_INSTANCE_ALREADY_STARTED: createError(
'FST_ERR_CTP_INSTANCE_ALREADY_STARTED',
'Cannot call "%s" when fastify instance is already started!',
400
),
/**
* decorate
*/
FST_ERR_DEC_ALREADY_PRESENT: createError(
'FST_ERR_DEC_ALREADY_PRESENT',
"The decorator '%s' has already been added!"
),
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE: createError(
'FST_ERR_DEC_DEPENDENCY_INVALID_TYPE',
"The dependencies of decorator '%s' must be of type Array.",
500,
TypeError
),
FST_ERR_DEC_MISSING_DEPENDENCY: createError(
'FST_ERR_DEC_MISSING_DEPENDENCY',
"The decorator is missing dependency '%s'."
),
FST_ERR_DEC_AFTER_START: createError(
'FST_ERR_DEC_AFTER_START',
"The decorator '%s' has been added after start!"
),
FST_ERR_DEC_REFERENCE_TYPE: createError(
'FST_ERR_DEC_REFERENCE_TYPE',
"The decorator '%s' of type '%s' is a reference type. Use the { getter, setter } interface instead."
),
FST_ERR_DEC_UNDECLARED: createError(
'FST_ERR_DEC_UNDECLARED',
"No decorator '%s' has been declared on %s."
),
/**
* hooks
*/
FST_ERR_HOOK_INVALID_TYPE: createError(
'FST_ERR_HOOK_INVALID_TYPE',
'The hook name must be a string',
500,
TypeError
),
FST_ERR_HOOK_INVALID_HANDLER: createError(
'FST_ERR_HOOK_INVALID_HANDLER',
'%s hook should be a function, instead got %s',
500,
TypeError
),
FST_ERR_HOOK_INVALID_ASYNC_HANDLER: createError(
'FST_ERR_HOOK_INVALID_ASYNC_HANDLER',
'Async function has too many arguments. Async hooks should not use the \'done\' argument.',
500,
TypeError
),
FST_ERR_HOOK_NOT_SUPPORTED: createError(
'FST_ERR_HOOK_NOT_SUPPORTED',
'%s hook not supported!',
500,
TypeError
),
/**
* Middlewares
*/
FST_ERR_MISSING_MIDDLEWARE: createError(
'FST_ERR_MISSING_MIDDLEWARE',
'You must register a plugin for handling middlewares, visit fastify.dev/docs/latest/Reference/Middleware/ for more info.',
500
),
FST_ERR_HOOK_TIMEOUT: createError(
'FST_ERR_HOOK_TIMEOUT',
"A callback for '%s' hook%s timed out. You may have forgotten to call 'done' function or to resolve a Promise"
),
/**
* logger
*/
FST_ERR_LOG_INVALID_DESTINATION: createError(
'FST_ERR_LOG_INVALID_DESTINATION',
'Cannot specify both logger.stream and logger.file options'
),
FST_ERR_LOG_INVALID_LOGGER: createError(
'FST_ERR_LOG_INVALID_LOGGER',
"Invalid logger object provided. The logger instance should have these functions(s): '%s'.",
500,
TypeError
),
FST_ERR_LOG_INVALID_LOGGER_INSTANCE: createError(
'FST_ERR_LOG_INVALID_LOGGER_INSTANCE',
'loggerInstance only accepts a logger instance.',
500,
TypeError
),
FST_ERR_LOG_INVALID_LOGGER_CONFIG: createError(
'FST_ERR_LOG_INVALID_LOGGER_CONFIG',
'logger options only accepts a configuration object.',
500,
TypeError
),
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED: createError(
'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED',
'You cannot provide both logger and loggerInstance. Please provide only one.',
500,
TypeError
),
/**
* reply
*/
FST_ERR_REP_INVALID_PAYLOAD_TYPE: createError(
'FST_ERR_REP_INVALID_PAYLOAD_TYPE',
"Attempted to send payload of invalid type '%s'. Expected a string or Buffer.",
500,
TypeError
),
FST_ERR_REP_RESPONSE_BODY_CONSUMED: createError(
'FST_ERR_REP_RESPONSE_BODY_CONSUMED',
'Response.body is already consumed.'
),
FST_ERR_REP_READABLE_STREAM_LOCKED: createError(
'FST_ERR_REP_READABLE_STREAM_LOCKED',
'ReadableStream was locked. You should call releaseLock() method on reader before sending.'
),
FST_ERR_REP_ALREADY_SENT: createError(
'FST_ERR_REP_ALREADY_SENT',
'Reply was already sent, did you forget to "return reply" in "%s" (%s)?'
),
FST_ERR_REP_SENT_VALUE: createError(
'FST_ERR_REP_SENT_VALUE',
'The only possible value for reply.sent is true.',
500,
TypeError
),
FST_ERR_SEND_INSIDE_ONERR: createError(
'FST_ERR_SEND_INSIDE_ONERR',
'You cannot use `send` inside the `onError` hook'
),
FST_ERR_SEND_UNDEFINED_ERR: createError(
'FST_ERR_SEND_UNDEFINED_ERR',
'Undefined error has occurred'
),
FST_ERR_BAD_STATUS_CODE: createError(
'FST_ERR_BAD_STATUS_CODE',
'Called reply with an invalid status code: %s'
),
FST_ERR_BAD_TRAILER_NAME: createError(
'FST_ERR_BAD_TRAILER_NAME',
'Called reply.trailer with an invalid header name: %s'
),
FST_ERR_BAD_TRAILER_VALUE: createError(
'FST_ERR_BAD_TRAILER_VALUE',
"Called reply.trailer('%s', fn) with an invalid type: %s. Expected a function."
),
FST_ERR_FAILED_ERROR_SERIALIZATION: createError(
'FST_ERR_FAILED_ERROR_SERIALIZATION',
'Failed to serialize an error. Error: %s. Original error: %s'
),
FST_ERR_MISSING_SERIALIZATION_FN: createError(
'FST_ERR_MISSING_SERIALIZATION_FN',
'Missing serialization function. Key "%s"'
),
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN: createError(
'FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN',
'Missing serialization function. Key "%s:%s"'
),
FST_ERR_REQ_INVALID_VALIDATION_INVOCATION: createError(
'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION',
'Invalid validation invocation. Missing validation function for HTTP part "%s" nor schema provided.'
),
/**
* schemas
*/
FST_ERR_SCH_MISSING_ID: createError(
'FST_ERR_SCH_MISSING_ID',
'Missing schema $id property'
),
FST_ERR_SCH_ALREADY_PRESENT: createError(
'FST_ERR_SCH_ALREADY_PRESENT',
"Schema with id '%s' already declared!"
),
FST_ERR_SCH_CONTENT_MISSING_SCHEMA: createError(
'FST_ERR_SCH_CONTENT_MISSING_SCHEMA',
"Schema is missing for the content type '%s'"
),
FST_ERR_SCH_DUPLICATE: createError(
'FST_ERR_SCH_DUPLICATE',
"Schema with '%s' already present!"
),
FST_ERR_SCH_VALIDATION_BUILD: createError(
'FST_ERR_SCH_VALIDATION_BUILD',
'Failed building the validation schema for %s: %s, due to error %s'
),
FST_ERR_SCH_SERIALIZATION_BUILD: createError(
'FST_ERR_SCH_SERIALIZATION_BUILD',
'Failed building the serialization schema for %s: %s, due to error %s'
),
FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX: createError(
'FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX',
'response schemas should be nested under a valid status code, e.g { 2xx: { type: "object" } }'
),
/**
* initialConfig
*/
FST_ERR_INIT_OPTS_INVALID: createError(
'FST_ERR_INIT_OPTS_INVALID',
"Invalid initialization options: '%s'"
),
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE: createError(
'FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE',
"Cannot set forceCloseConnections to 'idle' as your HTTP server does not support closeIdleConnections method"
),
/**
* router
*/
FST_ERR_DUPLICATED_ROUTE: createError(
'FST_ERR_DUPLICATED_ROUTE',
"Method '%s' already declared for route '%s'"
),
FST_ERR_BAD_URL: createError(
'FST_ERR_BAD_URL',
"'%s' is not a valid url component",
400,
URIError
),
FST_ERR_ASYNC_CONSTRAINT: createError(
'FST_ERR_ASYNC_CONSTRAINT',
'Unexpected error from async constraint',
500
),
FST_ERR_INVALID_URL: createError(
'FST_ERR_INVALID_URL',
"URL must be a string. Received '%s'",
400,
TypeError
),
FST_ERR_ROUTE_OPTIONS_NOT_OBJ: createError(
'FST_ERR_ROUTE_OPTIONS_NOT_OBJ',
'Options for "%s:%s" route must be an object',
500,
TypeError
),
FST_ERR_ROUTE_DUPLICATED_HANDLER: createError(
'FST_ERR_ROUTE_DUPLICATED_HANDLER',
'Duplicate handler for "%s:%s" route is not allowed!',
500
),
FST_ERR_ROUTE_HANDLER_NOT_FN: createError(
'FST_ERR_ROUTE_HANDLER_NOT_FN',
'Error Handler for %s:%s route, if defined, must be a function',
500,
TypeError
),
FST_ERR_ROUTE_MISSING_HANDLER: createError(
'FST_ERR_ROUTE_MISSING_HANDLER',
'Missing handler function for "%s:%s" route.',
500
),
FST_ERR_ROUTE_METHOD_INVALID: createError(
'FST_ERR_ROUTE_METHOD_INVALID',
'Provided method is invalid!',
500,
TypeError
),
FST_ERR_ROUTE_METHOD_NOT_SUPPORTED: createError(
'FST_ERR_ROUTE_METHOD_NOT_SUPPORTED',
'%s method is not supported.',
500
),
FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED: createError(
'FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED',
'Body validation schema for %s:%s route is not supported!',
500
),
FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT: createError(
'FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT',
"'bodyLimit' option must be an integer > 0. Got '%s'",
500,
TypeError
),
FST_ERR_ROUTE_REWRITE_NOT_STR: createError(
'FST_ERR_ROUTE_REWRITE_NOT_STR',
'Rewrite url for "%s" needs to be of type "string" but received "%s"',
500,
TypeError
),
/**
* again listen when close server
*/
FST_ERR_REOPENED_CLOSE_SERVER: createError(
'FST_ERR_REOPENED_CLOSE_SERVER',
'Fastify has already been closed and cannot be reopened'
),
FST_ERR_REOPENED_SERVER: createError(
'FST_ERR_REOPENED_SERVER',
'Fastify is already listening'
),
FST_ERR_INSTANCE_ALREADY_LISTENING: createError(
'FST_ERR_INSTANCE_ALREADY_LISTENING',
'Fastify instance is already listening. %s'
),
/**
* plugin
*/
FST_ERR_PLUGIN_VERSION_MISMATCH: createError(
'FST_ERR_PLUGIN_VERSION_MISMATCH',
"fastify-plugin: %s - expected '%s' fastify version, '%s' is installed"
),
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE: createError(
'FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE',
"The decorator '%s'%s is not present in %s"
),
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER: createError(
'FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER',
'The %s plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.',
500,
TypeError
),
/**
* Avvio Errors
*/
FST_ERR_PLUGIN_CALLBACK_NOT_FN: createError(
'FST_ERR_PLUGIN_CALLBACK_NOT_FN',
'fastify-plugin: %s',
500,
TypeError
),
FST_ERR_PLUGIN_NOT_VALID: createError(
'FST_ERR_PLUGIN_NOT_VALID',
'fastify-plugin: %s'
),
FST_ERR_ROOT_PLG_BOOTED: createError(
'FST_ERR_ROOT_PLG_BOOTED',
'fastify-plugin: %s'
),
FST_ERR_PARENT_PLUGIN_BOOTED: createError(
'FST_ERR_PARENT_PLUGIN_BOOTED',
'fastify-plugin: %s'
),
FST_ERR_PLUGIN_TIMEOUT: createError(
'FST_ERR_PLUGIN_TIMEOUT',
'fastify-plugin: %s'
)
}
function appendStackTrace (oldErr, newErr) {
newErr.cause = oldErr
return newErr
}
module.exports = codes
module.exports.appendStackTrace = appendStackTrace
module.exports.AVVIO_ERRORS_MAP = {
AVV_ERR_CALLBACK_NOT_FN: codes.FST_ERR_PLUGIN_CALLBACK_NOT_FN,
AVV_ERR_PLUGIN_NOT_VALID: codes.FST_ERR_PLUGIN_NOT_VALID,
AVV_ERR_ROOT_PLG_BOOTED: codes.FST_ERR_ROOT_PLG_BOOTED,
AVV_ERR_PARENT_PLG_LOADED: codes.FST_ERR_PARENT_PLUGIN_BOOTED,
AVV_ERR_READY_TIMEOUT: codes.FST_ERR_PLUGIN_TIMEOUT,
AVV_ERR_PLUGIN_EXEC_TIMEOUT: codes.FST_ERR_PLUGIN_TIMEOUT
}

View File

@@ -1,187 +0,0 @@
'use strict'
const FindMyWay = require('find-my-way')
const Reply = require('./reply')
const Request = require('./request')
const Context = require('./context')
const {
kRoutePrefix,
kCanSetNotFoundHandler,
kFourOhFourLevelInstance,
kFourOhFourContext,
kHooks,
kErrorHandler
} = require('./symbols.js')
const { lifecycleHooks } = require('./hooks')
const { buildErrorHandler } = require('./error-handler.js')
const {
FST_ERR_NOT_FOUND
} = require('./errors')
const { createChildLogger } = require('./logger-factory')
const { getGenReqId } = require('./reqIdGenFactory.js')
/**
* Each fastify instance have a:
* kFourOhFourLevelInstance: point to a fastify instance that has the 404 handler set
* kCanSetNotFoundHandler: bool to track if the 404 handler has already been set
* kFourOhFour: the singleton instance of this 404 module
* kFourOhFourContext: the context in the reply object where the handler will be executed
*/
function fourOhFour (options) {
const { logger, disableRequestLogging } = options
// 404 router, used for handling encapsulated 404 handlers
const router = FindMyWay({ onBadUrl: createOnBadUrl(), defaultRoute: fourOhFourFallBack })
let _onBadUrlHandler = null
return { router, setNotFoundHandler, setContext, arrange404 }
function arrange404 (instance) {
// Change the pointer of the fastify instance to itself, so register + prefix can add new 404 handler
instance[kFourOhFourLevelInstance] = instance
instance[kCanSetNotFoundHandler] = true
// we need to bind instance for the context
router.onBadUrl = router.onBadUrl.bind(instance)
router.defaultRoute = router.defaultRoute.bind(instance)
}
function basic404 (request, reply) {
const { url, method } = request.raw
const message = `Route ${method}:${url} not found`
if (!disableRequestLogging) {
request.log.info(message)
}
reply.code(404).send({
message,
error: 'Not Found',
statusCode: 404
})
}
function createOnBadUrl () {
return function onBadUrl (path, req, res) {
const fourOhFourContext = this[kFourOhFourLevelInstance][kFourOhFourContext]
const id = getGenReqId(fourOhFourContext.server, req)
const childLogger = createChildLogger(fourOhFourContext, logger, req, id)
const request = new Request(id, null, req, null, childLogger, fourOhFourContext)
const reply = new Reply(res, request, childLogger)
_onBadUrlHandler(request, reply)
}
}
function setContext (instance, context) {
const _404Context = Object.assign({}, instance[kFourOhFourContext])
_404Context.onSend = context.onSend
context[kFourOhFourContext] = _404Context
}
function setNotFoundHandler (opts, handler, avvio, routeHandler) {
// First initialization of the fastify root instance
if (this[kCanSetNotFoundHandler] === undefined) {
this[kCanSetNotFoundHandler] = true
}
if (this[kFourOhFourContext] === undefined) {
this[kFourOhFourContext] = null
}
const _fastify = this
const prefix = this[kRoutePrefix] || '/'
if (this[kCanSetNotFoundHandler] === false) {
throw new Error(`Not found handler already set for Fastify instance with prefix: '${prefix}'`)
}
if (typeof opts === 'object') {
if (opts.preHandler) {
if (Array.isArray(opts.preHandler)) {
opts.preHandler = opts.preHandler.map(hook => hook.bind(_fastify))
} else {
opts.preHandler = opts.preHandler.bind(_fastify)
}
}
if (opts.preValidation) {
if (Array.isArray(opts.preValidation)) {
opts.preValidation = opts.preValidation.map(hook => hook.bind(_fastify))
} else {
opts.preValidation = opts.preValidation.bind(_fastify)
}
}
}
if (typeof opts === 'function') {
handler = opts
opts = undefined
}
opts = opts || {}
if (handler) {
this[kFourOhFourLevelInstance][kCanSetNotFoundHandler] = false
handler = handler.bind(this)
// update onBadUrl handler
_onBadUrlHandler = handler
} else {
handler = basic404
// update onBadUrl handler
_onBadUrlHandler = basic404
}
this.after((notHandledErr, done) => {
_setNotFoundHandler.call(this, prefix, opts, handler, avvio, routeHandler)
done(notHandledErr)
})
}
function _setNotFoundHandler (prefix, opts, handler, avvio, routeHandler) {
const context = new Context({
schema: opts.schema,
handler,
config: opts.config || {},
server: this
})
avvio.once('preReady', () => {
const context = this[kFourOhFourContext]
for (const hook of lifecycleHooks) {
const toSet = this[kHooks][hook]
.concat(opts[hook] || [])
.map(h => h.bind(this))
context[hook] = toSet.length ? toSet : null
}
context.errorHandler = opts.errorHandler ? buildErrorHandler(this[kErrorHandler], opts.errorHandler) : this[kErrorHandler]
})
if (this[kFourOhFourContext] !== null && prefix === '/') {
Object.assign(this[kFourOhFourContext], context) // Replace the default 404 handler
return
}
this[kFourOhFourLevelInstance][kFourOhFourContext] = context
router.all(prefix + (prefix.endsWith('/') ? '*' : '/*'), routeHandler, context)
router.all(prefix, routeHandler, context)
}
function fourOhFourFallBack (req, res) {
// if this happen, we have a very bad bug
// we might want to do some hard debugging
// here, let's print out as much info as
// we can
const fourOhFourContext = this[kFourOhFourLevelInstance][kFourOhFourContext]
const id = getGenReqId(fourOhFourContext.server, req)
const childLogger = createChildLogger(fourOhFourContext, logger, req, id)
childLogger.info({ req }, 'incoming request')
const request = new Request(id, null, req, null, childLogger, fourOhFourContext)
const reply = new Reply(res, request, childLogger)
request.log.warn('the default handler for 404 did not catch this, this is likely a fastify bug, please report it')
request.log.warn(router.prettyPrint())
reply.code(404).send(new FST_ERR_NOT_FOUND())
}
}
module.exports = fourOhFour

View File

@@ -1,182 +0,0 @@
'use strict'
const diagnostics = require('node:diagnostics_channel')
const { validate: validateSchema } = require('./validation')
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
const wrapThenable = require('./wrapThenable')
const {
kReplyIsError,
kRouteContext,
kFourOhFourContext,
kSupportedHTTPMethods
} = require('./symbols')
const channels = diagnostics.tracingChannel('fastify.request.handler')
function handleRequest (err, request, reply) {
if (reply.sent === true) return
if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
return
}
const method = request.method
if (this[kSupportedHTTPMethods].bodyless.has(method)) {
handler(request, reply)
return
}
if (this[kSupportedHTTPMethods].bodywith.has(method)) {
const headers = request.headers
const contentType = headers['content-type']
if (contentType === undefined) {
const contentLength = headers['content-length']
const transferEncoding = headers['transfer-encoding']
const isEmptyBody = transferEncoding === undefined &&
(contentLength === undefined || contentLength === '0')
if (isEmptyBody) {
// Request has no body to parse
handler(request, reply)
return
}
request[kRouteContext].contentTypeParser.run('', handler, request, reply)
return
}
request[kRouteContext].contentTypeParser.run(contentType, handler, request, reply)
return
}
// Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion
handler(request, reply)
}
function handler (request, reply) {
try {
if (request[kRouteContext].preValidation !== null) {
preValidationHookRunner(
request[kRouteContext].preValidation,
request,
reply,
preValidationCallback
)
} else {
preValidationCallback(null, request, reply)
}
} catch (err) {
preValidationCallback(err, request, reply)
}
}
function preValidationCallback (err, request, reply) {
if (reply.sent === true) return
if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
return
}
const validationErr = validateSchema(reply[kRouteContext], request)
const isAsync = (validationErr && typeof validationErr.then === 'function') || false
if (isAsync) {
const cb = validationCompleted.bind(null, request, reply)
validationErr.then(cb, cb)
} else {
validationCompleted(request, reply, validationErr)
}
}
function validationCompleted (request, reply, validationErr) {
if (validationErr) {
if (reply[kRouteContext].attachValidation === false) {
reply.send(validationErr)
return
}
reply.request.validationError = validationErr
}
// preHandler hook
if (request[kRouteContext].preHandler !== null) {
preHandlerHookRunner(
request[kRouteContext].preHandler,
request,
reply,
preHandlerCallback
)
} else {
preHandlerCallback(null, request, reply)
}
}
function preHandlerCallback (err, request, reply) {
if (reply.sent) return
const context = request[kRouteContext]
if (!channels.hasSubscribers || context[kFourOhFourContext] === null) {
preHandlerCallbackInner(err, request, reply)
} else {
const store = {
request,
reply,
async: false,
route: {
url: context.config.url,
method: context.config.method
}
}
channels.start.runStores(store, preHandlerCallbackInner, undefined, err, request, reply, store)
}
}
function preHandlerCallbackInner (err, request, reply, store) {
const context = request[kRouteContext]
try {
if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
if (store) {
store.error = err
channels.error.publish(store)
}
return
}
let result
try {
result = context.handler(request, reply)
} catch (err) {
if (store) {
store.error = err
channels.error.publish(store)
}
reply[kReplyIsError] = true
reply.send(err)
return
}
if (result !== undefined) {
if (result !== null && typeof result.then === 'function') {
wrapThenable(result, reply, store)
} else {
reply.send(result)
}
}
} finally {
if (store) channels.end.publish(store)
}
}
module.exports = handleRequest
module.exports[Symbol.for('internals')] = { handler, preHandlerCallback }

View File

@@ -1,33 +0,0 @@
'use strict'
function headRouteOnSendHandler (req, reply, payload, done) {
// If payload is undefined
if (payload === undefined) {
reply.header('content-length', '0')
done(null, null)
return
}
if (typeof payload.resume === 'function') {
payload.on('error', (err) => {
reply.log.error({ err }, 'Error on Stream found for HEAD route')
})
payload.resume()
done(null, null)
return
}
const size = '' + Buffer.byteLength(payload)
reply.header('content-length', size)
done(null, null)
}
function parseHeadOnSendHandlers (onSendHandlers) {
if (onSendHandlers == null) return headRouteOnSendHandler
return Array.isArray(onSendHandlers) ? [...onSendHandlers, headRouteOnSendHandler] : [onSendHandlers, headRouteOnSendHandler]
}
module.exports = {
parseHeadOnSendHandlers
}

429
node_modules/fastify/lib/hooks.js generated vendored
View File

@@ -1,429 +0,0 @@
'use strict'
const applicationHooks = [
'onRoute',
'onRegister',
'onReady',
'onListen',
'preClose',
'onClose'
]
const lifecycleHooks = [
'onTimeout',
'onRequest',
'preParsing',
'preValidation',
'preSerialization',
'preHandler',
'onSend',
'onResponse',
'onError',
'onRequestAbort'
]
const supportedHooks = lifecycleHooks.concat(applicationHooks)
const {
FST_ERR_HOOK_INVALID_TYPE,
FST_ERR_HOOK_INVALID_HANDLER,
FST_ERR_SEND_UNDEFINED_ERR,
FST_ERR_HOOK_TIMEOUT,
FST_ERR_HOOK_NOT_SUPPORTED,
AVVIO_ERRORS_MAP,
appendStackTrace
} = require('./errors')
const {
kChildren,
kHooks,
kRequestPayloadStream
} = require('./symbols')
function Hooks () {
this.onRequest = []
this.preParsing = []
this.preValidation = []
this.preSerialization = []
this.preHandler = []
this.onResponse = []
this.onSend = []
this.onError = []
this.onRoute = []
this.onRegister = []
this.onReady = []
this.onListen = []
this.onTimeout = []
this.onRequestAbort = []
this.preClose = []
}
Hooks.prototype = Object.create(null)
Hooks.prototype.validate = function (hook, fn) {
if (typeof hook !== 'string') throw new FST_ERR_HOOK_INVALID_TYPE()
if (Array.isArray(this[hook]) === false) {
throw new FST_ERR_HOOK_NOT_SUPPORTED(hook)
}
if (typeof fn !== 'function') throw new FST_ERR_HOOK_INVALID_HANDLER(hook, Object.prototype.toString.call(fn))
}
Hooks.prototype.add = function (hook, fn) {
this.validate(hook, fn)
this[hook].push(fn)
}
function buildHooks (h) {
const hooks = new Hooks()
hooks.onRequest = h.onRequest.slice()
hooks.preParsing = h.preParsing.slice()
hooks.preValidation = h.preValidation.slice()
hooks.preSerialization = h.preSerialization.slice()
hooks.preHandler = h.preHandler.slice()
hooks.onSend = h.onSend.slice()
hooks.onResponse = h.onResponse.slice()
hooks.onError = h.onError.slice()
hooks.onRoute = h.onRoute.slice()
hooks.onRegister = h.onRegister.slice()
hooks.onTimeout = h.onTimeout.slice()
hooks.onRequestAbort = h.onRequestAbort.slice()
hooks.onReady = []
hooks.onListen = []
hooks.preClose = []
return hooks
}
function hookRunnerApplication (hookName, boot, server, cb) {
const hooks = server[kHooks][hookName]
let i = 0
let c = 0
next()
function exit (err) {
const hookFnName = hooks[i - 1]?.name
const hookFnFragment = hookFnName ? ` "${hookFnName}"` : ''
if (err) {
if (err.code === 'AVV_ERR_READY_TIMEOUT') {
err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName, hookFnFragment))
} else {
err = AVVIO_ERRORS_MAP[err.code] != null
? appendStackTrace(err, new AVVIO_ERRORS_MAP[err.code](err.message))
: err
}
cb(err)
return
}
cb()
}
function next (err) {
if (err) {
exit(err)
return
}
if (i === hooks.length && c === server[kChildren].length) {
if (i === 0 && c === 0) { // speed up start
exit()
} else {
// This is the last function executed for every fastify instance
boot(function manageTimeout (err, done) {
// this callback is needed by fastify to provide an hook interface without the error
// as first parameter and managing it on behalf the user
exit(err)
// this callback is needed by avvio to continue the loading of the next `register` plugins
done(err)
})
}
return
}
if (i === hooks.length && c < server[kChildren].length) {
const child = server[kChildren][c++]
hookRunnerApplication(hookName, boot, child, next)
return
}
boot(wrap(hooks[i++], server))
next()
}
function wrap (fn, server) {
return function (err, done) {
if (err) {
done(err)
return
}
if (fn.length === 1) {
try {
fn.call(server, done)
} catch (error) {
done(error)
}
return
}
try {
const ret = fn.call(server)
if (ret && typeof ret.then === 'function') {
ret.then(done, done)
return
}
} catch (error) {
err = error
}
done(err) // auto done
}
}
}
function onListenHookRunner (server) {
const hooks = server[kHooks].onListen
const hooksLen = hooks.length
let i = 0
let c = 0
next()
function next (err) {
err && server.log.error(err)
if (
i === hooksLen
) {
while (c < server[kChildren].length) {
const child = server[kChildren][c++]
onListenHookRunner(child)
}
return
}
wrap(hooks[i++], server, next)
}
async function wrap (fn, server, done) {
if (fn.length === 1) {
try {
fn.call(server, done)
} catch (e) {
done(e)
}
return
}
try {
const ret = fn.call(server)
if (ret && typeof ret.then === 'function') {
ret.then(done, done)
return
}
done()
} catch (error) {
done(error)
}
}
}
function hookRunnerGenerator (iterator) {
return function hookRunner (functions, request, reply, cb) {
let i = 0
function next (err) {
if (err || i === functions.length) {
cb(err, request, reply)
return
}
let result
try {
result = iterator(functions[i++], request, reply, next)
} catch (error) {
cb(error, request, reply)
return
}
if (result && typeof result.then === 'function') {
result.then(handleResolve, handleReject)
}
}
function handleResolve () {
next()
}
function handleReject (err) {
if (!err) {
err = new FST_ERR_SEND_UNDEFINED_ERR()
}
cb(err, request, reply)
}
next()
}
}
function onResponseHookIterator (fn, request, reply, next) {
return fn(request, reply, next)
}
const onResponseHookRunner = hookRunnerGenerator(onResponseHookIterator)
const preValidationHookRunner = hookRunnerGenerator(hookIterator)
const preHandlerHookRunner = hookRunnerGenerator(hookIterator)
const onTimeoutHookRunner = hookRunnerGenerator(hookIterator)
const onRequestHookRunner = hookRunnerGenerator(hookIterator)
function onSendHookRunner (functions, request, reply, payload, cb) {
let i = 0
function next (err, newPayload) {
if (err) {
cb(err, request, reply, payload)
return
}
if (newPayload !== undefined) {
payload = newPayload
}
if (i === functions.length) {
cb(null, request, reply, payload)
return
}
let result
try {
result = functions[i++](request, reply, payload, next)
} catch (error) {
cb(error, request, reply)
return
}
if (result && typeof result.then === 'function') {
result.then(handleResolve, handleReject)
}
}
function handleResolve (newPayload) {
next(null, newPayload)
}
function handleReject (err) {
if (!err) {
err = new FST_ERR_SEND_UNDEFINED_ERR()
}
cb(err, request, reply, payload)
}
next()
}
const preSerializationHookRunner = onSendHookRunner
function preParsingHookRunner (functions, request, reply, cb) {
let i = 0
function next (err, newPayload) {
if (reply.sent) {
return
}
if (newPayload !== undefined) {
request[kRequestPayloadStream] = newPayload
}
if (err || i === functions.length) {
cb(err, request, reply)
return
}
let result
try {
result = functions[i++](request, reply, request[kRequestPayloadStream], next)
} catch (error) {
cb(error, request, reply)
return
}
if (result && typeof result.then === 'function') {
result.then(handleResolve, handleReject)
}
}
function handleResolve (newPayload) {
next(null, newPayload)
}
function handleReject (err) {
if (!err) {
err = new FST_ERR_SEND_UNDEFINED_ERR()
}
cb(err, request, reply)
}
next()
}
function onRequestAbortHookRunner (functions, request, cb) {
let i = 0
function next (err) {
if (err || i === functions.length) {
cb(err, request)
return
}
let result
try {
result = functions[i++](request, next)
} catch (error) {
cb(error, request)
return
}
if (result && typeof result.then === 'function') {
result.then(handleResolve, handleReject)
}
}
function handleResolve () {
next()
}
function handleReject (err) {
if (!err) {
err = new FST_ERR_SEND_UNDEFINED_ERR()
}
cb(err, request)
}
next()
}
function hookIterator (fn, request, reply, next) {
if (reply.sent === true) return undefined
return fn(request, reply, next)
}
module.exports = {
Hooks,
buildHooks,
hookRunnerGenerator,
preParsingHookRunner,
onResponseHookRunner,
onSendHookRunner,
preSerializationHookRunner,
onRequestAbortHookRunner,
hookIterator,
hookRunnerApplication,
onListenHookRunner,
preHandlerHookRunner,
preValidationHookRunner,
onRequestHookRunner,
onTimeoutHookRunner,
lifecycleHooks,
supportedHooks
}

View File

@@ -1,37 +0,0 @@
'use strict'
const validate = require('./configValidator')
const deepClone = require('rfdc')({ circles: true, proto: false })
const { FST_ERR_INIT_OPTS_INVALID } = require('./errors')
function validateInitialConfig (options) {
const opts = deepClone(options)
if (!validate(opts)) {
const error = new FST_ERR_INIT_OPTS_INVALID(JSON.stringify(validate.errors.map(e => e.message)))
error.errors = validate.errors
throw error
}
return deepFreezeObject(opts)
}
function deepFreezeObject (object) {
const properties = Object.getOwnPropertyNames(object)
for (const name of properties) {
const value = object[name]
if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
continue
}
object[name] = value && typeof value === 'object' ? deepFreezeObject(value) : value
}
return Object.freeze(object)
}
module.exports = validateInitialConfig
module.exports.defaultInitOptions = validate.defaultInitOptions
module.exports.utils = { deepFreezeObject }

View File

@@ -1,136 +0,0 @@
'use strict'
const {
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED,
FST_ERR_LOG_INVALID_LOGGER_CONFIG,
FST_ERR_LOG_INVALID_LOGGER_INSTANCE,
FST_ERR_LOG_INVALID_LOGGER
} = require('./errors')
/**
* Utility for creating a child logger with the appropriate bindings, logger factory
* and validation.
* @param {object} context
* @param {import('../fastify').FastifyBaseLogger} logger
* @param {import('../fastify').RawRequestDefaultExpression<any>} req
* @param {string} reqId
* @param {import('../types/logger.js').ChildLoggerOptions?} loggerOpts
*
* @returns {object} New logger instance, inheriting all parent bindings,
* with child bindings added.
*/
function createChildLogger (context, logger, req, reqId, loggerOpts) {
const loggerBindings = {
[context.requestIdLogLabel]: reqId
}
const child = context.childLoggerFactory.call(context.server, logger, loggerBindings, loggerOpts || {}, req)
// Optimization: bypass validation if the factory is our own default factory
if (context.childLoggerFactory !== defaultChildLoggerFactory) {
validateLogger(child, true) // throw if the child is not a valid logger
}
return child
}
/** Default factory to create child logger instance
*
* @param {import('../fastify.js').FastifyBaseLogger} logger
* @param {import('../types/logger.js').Bindings} bindings
* @param {import('../types/logger.js').ChildLoggerOptions} opts
*
* @returns {import('../types/logger.js').FastifyBaseLogger}
*/
function defaultChildLoggerFactory (logger, bindings, opts) {
return logger.child(bindings, opts)
}
/**
* Determines if a provided logger object meets the requirements
* of a Fastify compatible logger.
*
* @param {object} logger Object to validate.
* @param {boolean?} strict `true` if the object must be a logger (always throw if any methods missing)
*
* @returns {boolean} `true` when the logger meets the requirements.
*
* @throws {FST_ERR_LOG_INVALID_LOGGER} When the logger object is
* missing required methods.
*/
function validateLogger (logger, strict) {
const methods = ['info', 'error', 'debug', 'fatal', 'warn', 'trace', 'child']
const missingMethods = logger
? methods.filter(method => !logger[method] || typeof logger[method] !== 'function')
: methods
if (!missingMethods.length) {
return true
} else if ((missingMethods.length === methods.length) && !strict) {
return false
} else {
throw FST_ERR_LOG_INVALID_LOGGER(missingMethods.join(','))
}
}
function createLogger (options) {
if (options.logger && options.loggerInstance) {
throw new FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
}
if (!options.loggerInstance && !options.logger) {
const nullLogger = require('abstract-logging')
const logger = nullLogger
logger.child = () => logger
return { logger, hasLogger: false }
}
const { createPinoLogger, serializers } = require('./logger-pino.js')
// check if the logger instance has all required properties
if (validateLogger(options.loggerInstance)) {
const logger = createPinoLogger({
logger: options.loggerInstance,
serializers: Object.assign({}, serializers, options.loggerInstance.serializers)
})
return { logger, hasLogger: true }
}
// if a logger instance is passed to logger, throw an exception
if (validateLogger(options.logger)) {
throw FST_ERR_LOG_INVALID_LOGGER_CONFIG()
}
if (options.loggerInstance) {
throw FST_ERR_LOG_INVALID_LOGGER_INSTANCE()
}
const localLoggerOptions = {}
if (Object.prototype.toString.call(options.logger) === '[object Object]') {
Reflect.ownKeys(options.logger).forEach(prop => {
Object.defineProperty(localLoggerOptions, prop, {
value: options.logger[prop],
writable: true,
enumerable: true,
configurable: true
})
})
}
localLoggerOptions.level = localLoggerOptions.level || 'info'
localLoggerOptions.serializers = Object.assign({}, serializers, localLoggerOptions.serializers)
options.logger = localLoggerOptions
const logger = createPinoLogger(options.logger)
return { logger, hasLogger: true }
}
function now () {
const ts = process.hrtime()
return (ts[0] * 1e3) + (ts[1] / 1e6)
}
module.exports = {
createChildLogger,
defaultChildLoggerFactory,
createLogger,
validateLogger,
now
}

View File

@@ -1,68 +0,0 @@
'use strict'
/**
* Code imported from `pino-http`
* Repo: https://github.com/pinojs/pino-http
* License: MIT (https://raw.githubusercontent.com/pinojs/pino-http/master/LICENSE)
*/
const pino = require('pino')
const { serializersSym } = pino.symbols
const {
FST_ERR_LOG_INVALID_DESTINATION
} = require('./errors')
function createPinoLogger (opts) {
if (opts.stream && opts.file) {
throw new FST_ERR_LOG_INVALID_DESTINATION()
} else if (opts.file) {
// we do not have stream
opts.stream = pino.destination(opts.file)
delete opts.file
}
const prevLogger = opts.logger
const prevGenReqId = opts.genReqId
let logger = null
if (prevLogger) {
opts.logger = undefined
opts.genReqId = undefined
// we need to tap into pino internals because in v5 it supports
// adding serializers in child loggers
if (prevLogger[serializersSym]) {
opts.serializers = Object.assign({}, opts.serializers, prevLogger[serializersSym])
}
logger = prevLogger.child({}, opts)
opts.logger = prevLogger
opts.genReqId = prevGenReqId
} else {
logger = pino(opts, opts.stream)
}
return logger
}
const serializers = {
req: function asReqValue (req) {
return {
method: req.method,
url: req.url,
version: req.headers && req.headers['accept-version'],
host: req.host,
remoteAddress: req.ip,
remotePort: req.socket ? req.socket.remotePort : undefined
}
},
err: pino.stdSerializers.err,
res: function asResValue (reply) {
return {
statusCode: reply.statusCode
}
}
}
module.exports = {
serializers,
createPinoLogger
}

10
node_modules/fastify/lib/noop-set.js generated vendored
View File

@@ -1,10 +0,0 @@
'use strict'
module.exports = function noopSet () {
return {
[Symbol.iterator]: function * () {},
add () {},
delete () {},
has () { return true }
}
}

View File

@@ -1,90 +0,0 @@
'use strict'
const {
kAvvioBoot,
kChildren,
kRoutePrefix,
kLogLevel,
kLogSerializers,
kHooks,
kSchemaController,
kContentTypeParser,
kReply,
kRequest,
kFourOhFour,
kPluginNameChain,
kErrorHandlerAlreadySet
} = require('./symbols.js')
const Reply = require('./reply')
const Request = require('./request')
const SchemaController = require('./schema-controller')
const ContentTypeParser = require('./contentTypeParser')
const { buildHooks } = require('./hooks')
const pluginUtils = require('./pluginUtils')
// Function that runs the encapsulation magic.
// Everything that need to be encapsulated must be handled in this function.
module.exports = function override (old, fn, opts) {
const shouldSkipOverride = pluginUtils.registerPlugin.call(old, fn)
const fnName = pluginUtils.getPluginName(fn) || pluginUtils.getFuncPreview(fn)
if (shouldSkipOverride) {
// after every plugin registration we will enter a new name
old[kPluginNameChain].push(fnName)
return old
}
const instance = Object.create(old)
old[kChildren].push(instance)
instance.ready = old[kAvvioBoot].bind(instance)
instance[kChildren] = []
instance[kReply] = Reply.buildReply(instance[kReply])
instance[kRequest] = Request.buildRequest(instance[kRequest])
instance[kContentTypeParser] = ContentTypeParser.helpers.buildContentTypeParser(instance[kContentTypeParser])
instance[kHooks] = buildHooks(instance[kHooks])
instance[kRoutePrefix] = buildRoutePrefix(instance[kRoutePrefix], opts.prefix)
instance[kLogLevel] = opts.logLevel || instance[kLogLevel]
instance[kSchemaController] = SchemaController.buildSchemaController(old[kSchemaController])
instance.getSchema = instance[kSchemaController].getSchema.bind(instance[kSchemaController])
instance.getSchemas = instance[kSchemaController].getSchemas.bind(instance[kSchemaController])
// Track the registered and loaded plugins since the root instance.
// It does not track the current encapsulated plugin.
instance[pluginUtils.kRegisteredPlugins] = Object.create(instance[pluginUtils.kRegisteredPlugins])
// Track the plugin chain since the root instance.
// When an non-encapsulated plugin is added, the chain will be updated.
instance[kPluginNameChain] = [fnName]
instance[kErrorHandlerAlreadySet] = false
if (instance[kLogSerializers] || opts.logSerializers) {
instance[kLogSerializers] = Object.assign(Object.create(instance[kLogSerializers]), opts.logSerializers)
}
if (opts.prefix) {
instance[kFourOhFour].arrange404(instance)
}
for (const hook of instance[kHooks].onRegister) hook.call(old, instance, opts)
return instance
}
function buildRoutePrefix (instancePrefix, pluginPrefix) {
if (!pluginPrefix) {
return instancePrefix
}
// Ensure that there is a '/' between the prefixes
if (instancePrefix.endsWith('/') && pluginPrefix[0] === '/') {
// Remove the extra '/' to avoid: '/first//second'
pluginPrefix = pluginPrefix.slice(1)
} else if (pluginPrefix[0] !== '/') {
pluginPrefix = '/' + pluginPrefix
}
return instancePrefix + pluginPrefix
}

View File

@@ -1,169 +0,0 @@
'use strict'
const semver = require('semver')
const assert = require('node:assert')
const kRegisteredPlugins = Symbol.for('registered-plugin')
const {
kTestInternals
} = require('./symbols.js')
const { exist, existReply, existRequest } = require('./decorate')
const {
FST_ERR_PLUGIN_VERSION_MISMATCH,
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE,
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER
} = require('./errors')
const rcRegex = /-(?:rc|pre|alpha).+$/u
function getMeta (fn) {
return fn[Symbol.for('plugin-meta')]
}
function getPluginName (func) {
const display = getDisplayName(func)
if (display) {
return display
}
// let's see if this is a file, and in that case use that
// this is common for plugins
const cache = require.cache
// cache is undefined inside SEA
if (cache) {
const keys = Object.keys(cache)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (cache[key].exports === func) {
return key
}
}
}
// if not maybe it's a named function, so use that
if (func.name) {
return func.name
}
return null
}
function getFuncPreview (func) {
// takes the first two lines of the function if nothing else works
return func.toString().split('\n', 2).map(s => s.trim()).join(' -- ')
}
function getDisplayName (fn) {
return fn[Symbol.for('fastify.display-name')]
}
function shouldSkipOverride (fn) {
return !!fn[Symbol.for('skip-override')]
}
function checkDependencies (fn) {
const meta = getMeta(fn)
if (!meta) return
const dependencies = meta.dependencies
if (!dependencies) return
assert(Array.isArray(dependencies), 'The dependencies should be an array of strings')
dependencies.forEach(dependency => {
assert(
this[kRegisteredPlugins].indexOf(dependency) > -1,
`The dependency '${dependency}' of plugin '${meta.name}' is not registered`
)
})
}
function checkDecorators (fn) {
const meta = getMeta(fn)
if (!meta) return
const { decorators, name } = meta
if (!decorators) return
if (decorators.fastify) _checkDecorators(this, 'Fastify', decorators.fastify, name)
if (decorators.reply) _checkDecorators(this, 'Reply', decorators.reply, name)
if (decorators.request) _checkDecorators(this, 'Request', decorators.request, name)
}
const checks = {
Fastify: exist,
Request: existRequest,
Reply: existReply
}
function _checkDecorators (that, instance, decorators, name) {
assert(Array.isArray(decorators), 'The decorators should be an array of strings')
decorators.forEach(decorator => {
const withPluginName = typeof name === 'string' ? ` required by '${name}'` : ''
if (!checks[instance].call(that, decorator)) {
throw new FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE(decorator, withPluginName, instance)
}
})
}
function checkVersion (fn) {
const meta = getMeta(fn)
if (meta?.fastify == null) return
const requiredVersion = meta.fastify
const fastifyRc = rcRegex.test(this.version)
if (fastifyRc === true && semver.gt(this.version, semver.coerce(requiredVersion)) === true) {
// A Fastify release candidate phase is taking place. In order to reduce
// the effort needed to test plugins with the RC, we allow plugins targeting
// the prior Fastify release to be loaded.
return
}
if (requiredVersion && semver.satisfies(this.version, requiredVersion, { includePrerelease: fastifyRc }) === false) {
// We are not in a release candidate phase. Thus, we must honor the semver
// ranges defined by the plugin's metadata. Which is to say, if the plugin
// expects an older version of Fastify than the _current_ version, we will
// throw an error.
throw new FST_ERR_PLUGIN_VERSION_MISMATCH(meta.name, requiredVersion, this.version)
}
}
function registerPluginName (fn) {
const meta = getMeta(fn)
if (!meta) return
const name = meta.name
if (!name) return
this[kRegisteredPlugins].push(name)
return name
}
function checkPluginHealthiness (fn, pluginName) {
if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
throw new FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER(pluginName)
}
}
function registerPlugin (fn) {
const pluginName = registerPluginName.call(this, fn) || getPluginName(fn)
checkPluginHealthiness.call(this, fn, pluginName)
checkVersion.call(this, fn)
checkDecorators.call(this, fn)
checkDependencies.call(this, fn)
return shouldSkipOverride(fn)
}
module.exports = {
getPluginName,
getFuncPreview,
kRegisteredPlugins,
getDisplayName,
registerPlugin
}
module.exports[kTestInternals] = {
shouldSkipOverride,
getMeta,
checkDecorators,
checkDependencies
}

23
node_modules/fastify/lib/promise.js generated vendored
View File

@@ -1,23 +0,0 @@
'use strict'
const { kTestInternals } = require('./symbols')
function withResolvers () {
let res, rej
const promise = new Promise((resolve, reject) => {
res = resolve
rej = reject
})
return { promise, resolve: res, reject: rej }
}
module.exports = {
// TODO(20.x): remove when node@20 is not supported
withResolvers: typeof Promise.withResolvers === 'function'
? Promise.withResolvers.bind(Promise) // Promise.withResolvers must bind to itself
/* c8 ignore next */
: withResolvers, // Tested using the kTestInternals
[kTestInternals]: {
withResolvers
}
}

942
node_modules/fastify/lib/reply.js generated vendored
View File

@@ -1,942 +0,0 @@
'use strict'
const eos = require('node:stream').finished
const Readable = require('node:stream').Readable
const {
kFourOhFourContext,
kReplyErrorHandlerCalled,
kReplyHijacked,
kReplyStartTime,
kReplyEndTime,
kReplySerializer,
kReplySerializerDefault,
kReplyIsError,
kReplyHeaders,
kReplyTrailers,
kReplyHasStatusCode,
kReplyIsRunningOnErrorHook,
kReplyNextErrorHandler,
kDisableRequestLogging,
kSchemaResponse,
kReplyCacheSerializeFns,
kSchemaController,
kOptions,
kRouteContext
} = require('./symbols.js')
const {
onSendHookRunner,
onResponseHookRunner,
preHandlerHookRunner,
preSerializationHookRunner
} = require('./hooks')
const internals = require('./handleRequest')[Symbol.for('internals')]
const loggerUtils = require('./logger-factory')
const now = loggerUtils.now
const { handleError } = require('./error-handler')
const { getSchemaSerializer } = require('./schemas')
const CONTENT_TYPE = {
JSON: 'application/json; charset=utf-8',
PLAIN: 'text/plain; charset=utf-8',
OCTET: 'application/octet-stream'
}
const {
FST_ERR_REP_INVALID_PAYLOAD_TYPE,
FST_ERR_REP_RESPONSE_BODY_CONSUMED,
FST_ERR_REP_READABLE_STREAM_LOCKED,
FST_ERR_REP_ALREADY_SENT,
FST_ERR_SEND_INSIDE_ONERR,
FST_ERR_BAD_STATUS_CODE,
FST_ERR_BAD_TRAILER_NAME,
FST_ERR_BAD_TRAILER_VALUE,
FST_ERR_MISSING_SERIALIZATION_FN,
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN,
FST_ERR_DEC_UNDECLARED
} = require('./errors')
const decorators = require('./decorate')
const toString = Object.prototype.toString
function Reply (res, request, log) {
this.raw = res
this[kReplySerializer] = null
this[kReplyErrorHandlerCalled] = false
this[kReplyIsError] = false
this[kReplyIsRunningOnErrorHook] = false
this.request = request
this[kReplyHeaders] = {}
this[kReplyTrailers] = null
this[kReplyHasStatusCode] = false
this[kReplyStartTime] = undefined
this.log = log
}
Reply.props = []
Object.defineProperties(Reply.prototype, {
[kRouteContext]: {
get () {
return this.request[kRouteContext]
}
},
elapsedTime: {
get () {
if (this[kReplyStartTime] === undefined) {
return 0
}
return (this[kReplyEndTime] || now()) - this[kReplyStartTime]
}
},
server: {
get () {
return this.request[kRouteContext].server
}
},
sent: {
enumerable: true,
get () {
// We are checking whether reply was hijacked or the response has ended.
return (this[kReplyHijacked] || this.raw.writableEnded) === true
}
},
statusCode: {
get () {
return this.raw.statusCode
},
set (value) {
this.code(value)
}
},
routeOptions: {
get () {
return this.request.routeOptions
}
}
})
Reply.prototype.writeEarlyHints = function (hints, callback) {
this.raw.writeEarlyHints(hints, callback)
return this
}
Reply.prototype.hijack = function () {
this[kReplyHijacked] = true
return this
}
Reply.prototype.send = function (payload) {
if (this[kReplyIsRunningOnErrorHook]) {
throw new FST_ERR_SEND_INSIDE_ONERR()
}
if (this.sent === true) {
this.log.warn({ err: new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method) })
return this
}
if (this[kReplyIsError] || payload instanceof Error) {
this[kReplyIsError] = false
onErrorHook(this, payload, onSendHook)
return this
}
if (payload === undefined) {
onSendHook(this, payload)
return this
}
const contentType = this.getHeader('content-type')
const hasContentType = contentType !== undefined
if (payload !== null) {
if (
// node:stream
typeof payload.pipe === 'function' ||
// node:stream/web
typeof payload.getReader === 'function' ||
// Response
toString.call(payload) === '[object Response]'
) {
onSendHook(this, payload)
return this
}
if (payload.buffer instanceof ArrayBuffer) {
if (!hasContentType) {
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.OCTET
}
const payloadToSend = Buffer.isBuffer(payload) ? payload : Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength)
onSendHook(this, payloadToSend)
return this
}
if (!hasContentType && typeof payload === 'string') {
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.PLAIN
onSendHook(this, payload)
return this
}
}
if (this[kReplySerializer] !== null) {
if (typeof payload !== 'string') {
preSerializationHook(this, payload)
return this
}
payload = this[kReplySerializer](payload)
// The indexOf below also matches custom json mimetypes such as 'application/hal+json' or 'application/ld+json'
} else if (!hasContentType || contentType.indexOf('json') !== -1) {
if (!hasContentType) {
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.JSON
} else if (contentType.indexOf('charset') === -1) {
// If user doesn't set charset, we will set charset to utf-8
const customContentType = contentType.trim()
if (customContentType.endsWith(';')) {
// custom content-type is ended with ';'
this[kReplyHeaders]['content-type'] = `${customContentType} charset=utf-8`
} else {
this[kReplyHeaders]['content-type'] = `${customContentType}; charset=utf-8`
}
}
if (typeof payload !== 'string') {
preSerializationHook(this, payload)
return this
}
}
onSendHook(this, payload)
return this
}
Reply.prototype.getHeader = function (key) {
key = key.toLowerCase()
const value = this[kReplyHeaders][key]
return value !== undefined ? value : this.raw.getHeader(key)
}
Reply.prototype.getHeaders = function () {
return {
...this.raw.getHeaders(),
...this[kReplyHeaders]
}
}
Reply.prototype.hasHeader = function (key) {
key = key.toLowerCase()
return this[kReplyHeaders][key] !== undefined || this.raw.hasHeader(key)
}
Reply.prototype.removeHeader = function (key) {
// Node.js does not like headers with keys set to undefined,
// so we have to delete the key.
delete this[kReplyHeaders][key.toLowerCase()]
return this
}
Reply.prototype.header = function (key, value = '') {
key = key.toLowerCase()
if (this[kReplyHeaders][key] && key === 'set-cookie') {
// https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.2
if (typeof this[kReplyHeaders][key] === 'string') {
this[kReplyHeaders][key] = [this[kReplyHeaders][key]]
}
if (Array.isArray(value)) {
Array.prototype.push.apply(this[kReplyHeaders][key], value)
} else {
this[kReplyHeaders][key].push(value)
}
} else {
this[kReplyHeaders][key] = value
}
return this
}
Reply.prototype.headers = function (headers) {
const keys = Object.keys(headers)
for (let i = 0; i !== keys.length; ++i) {
const key = keys[i]
this.header(key, headers[key])
}
return this
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer#directives
// https://datatracker.ietf.org/doc/html/rfc7230.html#chunked.trailer.part
const INVALID_TRAILERS = new Set([
'transfer-encoding',
'content-length',
'host',
'cache-control',
'max-forwards',
'te',
'authorization',
'set-cookie',
'content-encoding',
'content-type',
'content-range',
'trailer'
])
Reply.prototype.trailer = function (key, fn) {
key = key.toLowerCase()
if (INVALID_TRAILERS.has(key)) {
throw new FST_ERR_BAD_TRAILER_NAME(key)
}
if (typeof fn !== 'function') {
throw new FST_ERR_BAD_TRAILER_VALUE(key, typeof fn)
}
if (this[kReplyTrailers] === null) this[kReplyTrailers] = {}
this[kReplyTrailers][key] = fn
return this
}
Reply.prototype.hasTrailer = function (key) {
return this[kReplyTrailers]?.[key.toLowerCase()] !== undefined
}
Reply.prototype.removeTrailer = function (key) {
if (this[kReplyTrailers] === null) return this
this[kReplyTrailers][key.toLowerCase()] = undefined
return this
}
Reply.prototype.code = function (code) {
const statusCode = +code
if (!(statusCode >= 100 && statusCode <= 599)) {
throw new FST_ERR_BAD_STATUS_CODE(code || String(code))
}
this.raw.statusCode = statusCode
this[kReplyHasStatusCode] = true
return this
}
Reply.prototype.status = Reply.prototype.code
Reply.prototype.getSerializationFunction = function (schemaOrStatus, contentType) {
let serialize
if (typeof schemaOrStatus === 'string' || typeof schemaOrStatus === 'number') {
if (typeof contentType === 'string') {
serialize = this[kRouteContext][kSchemaResponse]?.[schemaOrStatus]?.[contentType]
} else {
serialize = this[kRouteContext][kSchemaResponse]?.[schemaOrStatus]
}
} else if (typeof schemaOrStatus === 'object') {
serialize = this[kRouteContext][kReplyCacheSerializeFns]?.get(schemaOrStatus)
}
return serialize
}
Reply.prototype.compileSerializationSchema = function (schema, httpStatus = null, contentType = null) {
const { request } = this
const { method, url } = request
// Check if serialize function already compiled
if (this[kRouteContext][kReplyCacheSerializeFns]?.has(schema)) {
return this[kRouteContext][kReplyCacheSerializeFns].get(schema)
}
const serializerCompiler = this[kRouteContext].serializerCompiler ||
this.server[kSchemaController].serializerCompiler ||
(
// We compile the schemas if no custom serializerCompiler is provided
// nor set
this.server[kSchemaController].setupSerializer(this.server[kOptions]) ||
this.server[kSchemaController].serializerCompiler
)
const serializeFn = serializerCompiler({
schema,
method,
url,
httpStatus,
contentType
})
// We create a WeakMap to compile the schema only once
// Its done lazily to avoid add overhead by creating the WeakMap
// if it is not used
// TODO: Explore a central cache for all the schemas shared across
// encapsulated contexts
if (this[kRouteContext][kReplyCacheSerializeFns] == null) {
this[kRouteContext][kReplyCacheSerializeFns] = new WeakMap()
}
this[kRouteContext][kReplyCacheSerializeFns].set(schema, serializeFn)
return serializeFn
}
Reply.prototype.serializeInput = function (input, schema, httpStatus, contentType) {
const possibleContentType = httpStatus
let serialize
httpStatus = typeof schema === 'string' || typeof schema === 'number'
? schema
: httpStatus
contentType = httpStatus && possibleContentType !== httpStatus
? possibleContentType
: contentType
if (httpStatus != null) {
if (contentType != null) {
serialize = this[kRouteContext][kSchemaResponse]?.[httpStatus]?.[contentType]
} else {
serialize = this[kRouteContext][kSchemaResponse]?.[httpStatus]
}
if (serialize == null) {
if (contentType) throw new FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN(httpStatus, contentType)
throw new FST_ERR_MISSING_SERIALIZATION_FN(httpStatus)
}
} else {
// Check if serialize function already compiled
if (this[kRouteContext][kReplyCacheSerializeFns]?.has(schema)) {
serialize = this[kRouteContext][kReplyCacheSerializeFns].get(schema)
} else {
serialize = this.compileSerializationSchema(schema, httpStatus, contentType)
}
}
return serialize(input)
}
Reply.prototype.serialize = function (payload) {
if (this[kReplySerializer] !== null) {
return this[kReplySerializer](payload)
} else {
if (this[kRouteContext] && this[kRouteContext][kReplySerializerDefault]) {
return this[kRouteContext][kReplySerializerDefault](payload, this.raw.statusCode)
} else {
return serialize(this[kRouteContext], payload, this.raw.statusCode)
}
}
}
Reply.prototype.serializer = function (fn) {
this[kReplySerializer] = fn
return this
}
Reply.prototype.type = function (type) {
this[kReplyHeaders]['content-type'] = type
return this
}
Reply.prototype.redirect = function (url, code) {
if (!code) {
code = this[kReplyHasStatusCode] ? this.raw.statusCode : 302
}
return this.header('location', url).code(code).send()
}
Reply.prototype.callNotFound = function () {
notFound(this)
return this
}
// Make reply a thenable, so it could be used with async/await.
// See
// - https://github.com/fastify/fastify/issues/1864 for the discussions
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then for the signature
Reply.prototype.then = function (fulfilled, rejected) {
if (this.sent) {
fulfilled()
return
}
eos(this.raw, (err) => {
// We must not treat ERR_STREAM_PREMATURE_CLOSE as
// an error because it is created by eos, not by the stream.
if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
if (rejected) {
rejected(err)
} else {
this.log && this.log.warn('unhandled rejection on reply.then')
}
} else {
fulfilled()
}
})
}
Reply.prototype.getDecorator = function (name) {
if (!decorators.hasKey(this, name) && !decorators.exist(this, name)) {
throw new FST_ERR_DEC_UNDECLARED(name, 'reply')
}
const decorator = this[name]
if (typeof decorator === 'function') {
return decorator.bind(this)
}
return decorator
}
function preSerializationHook (reply, payload) {
if (reply[kRouteContext].preSerialization !== null) {
preSerializationHookRunner(
reply[kRouteContext].preSerialization,
reply.request,
reply,
payload,
preSerializationHookEnd
)
} else {
preSerializationHookEnd(null, undefined, reply, payload)
}
}
function preSerializationHookEnd (err, _request, reply, payload) {
if (err != null) {
onErrorHook(reply, err)
return
}
try {
if (reply[kReplySerializer] !== null) {
payload = reply[kReplySerializer](payload)
} else if (reply[kRouteContext] && reply[kRouteContext][kReplySerializerDefault]) {
payload = reply[kRouteContext][kReplySerializerDefault](payload, reply.raw.statusCode)
} else {
payload = serialize(reply[kRouteContext], payload, reply.raw.statusCode, reply[kReplyHeaders]['content-type'])
}
} catch (e) {
wrapSerializationError(e, reply)
onErrorHook(reply, e)
return
}
onSendHook(reply, payload)
}
function wrapSerializationError (error, reply) {
error.serialization = reply[kRouteContext].config
}
function onSendHook (reply, payload) {
if (reply[kRouteContext].onSend !== null) {
onSendHookRunner(
reply[kRouteContext].onSend,
reply.request,
reply,
payload,
wrapOnSendEnd
)
} else {
onSendEnd(reply, payload)
}
}
function wrapOnSendEnd (err, request, reply, payload) {
if (err != null) {
onErrorHook(reply, err)
} else {
onSendEnd(reply, payload)
}
}
function safeWriteHead (reply, statusCode) {
const res = reply.raw
try {
res.writeHead(statusCode, reply[kReplyHeaders])
} catch (err) {
if (err.code === 'ERR_HTTP_HEADERS_SENT') {
reply.log.warn(`Reply was already sent, did you forget to "return reply" in the "${reply.request.raw.url}" (${reply.request.raw.method}) route?`)
}
throw err
}
}
function onSendEnd (reply, payload) {
const res = reply.raw
const req = reply.request
// we check if we need to update the trailers header and set it
if (reply[kReplyTrailers] !== null) {
const trailerHeaders = Object.keys(reply[kReplyTrailers])
let header = ''
for (const trailerName of trailerHeaders) {
if (typeof reply[kReplyTrailers][trailerName] !== 'function') continue
header += ' '
header += trailerName
}
// it must be chunked for trailer to work
reply.header('Transfer-Encoding', 'chunked')
reply.header('Trailer', header.trim())
}
// since Response contain status code, headers and body,
// we need to update the status, add the headers and use it's body as payload
// before continuing
if (toString.call(payload) === '[object Response]') {
// https://developer.mozilla.org/en-US/docs/Web/API/Response/status
if (typeof payload.status === 'number') {
reply.code(payload.status)
}
// https://developer.mozilla.org/en-US/docs/Web/API/Response/headers
if (typeof payload.headers === 'object' && typeof payload.headers.forEach === 'function') {
for (const [headerName, headerValue] of payload.headers) {
reply.header(headerName, headerValue)
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/Response/body
if (payload.body !== null) {
if (payload.bodyUsed) {
throw new FST_ERR_REP_RESPONSE_BODY_CONSUMED()
}
}
// Keep going, body is either null or ReadableStream
payload = payload.body
}
const statusCode = res.statusCode
if (payload === undefined || payload === null) {
// according to https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
// we cannot send a content-length for 304 and 204, and all status code
// < 200
// A sender MUST NOT send a Content-Length header field in any message
// that contains a Transfer-Encoding header field.
// For HEAD we don't overwrite the `content-length`
if (statusCode >= 200 && statusCode !== 204 && statusCode !== 304 && req.method !== 'HEAD' && reply[kReplyTrailers] === null) {
reply[kReplyHeaders]['content-length'] = '0'
}
safeWriteHead(reply, statusCode)
sendTrailer(payload, res, reply)
return
}
if ((statusCode >= 100 && statusCode < 200) || statusCode === 204) {
// Responses without a content body must not send content-type
// or content-length headers.
// See https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6.
reply.removeHeader('content-type')
reply.removeHeader('content-length')
safeWriteHead(reply, statusCode)
sendTrailer(undefined, res, reply)
if (typeof payload.resume === 'function') {
payload.on('error', noop)
payload.resume()
}
return
}
// node:stream
if (typeof payload.pipe === 'function') {
sendStream(payload, res, reply)
return
}
// node:stream/web
if (typeof payload.getReader === 'function') {
sendWebStream(payload, res, reply)
return
}
if (typeof payload !== 'string' && !Buffer.isBuffer(payload)) {
throw new FST_ERR_REP_INVALID_PAYLOAD_TYPE(typeof payload)
}
if (reply[kReplyTrailers] === null) {
const contentLength = reply[kReplyHeaders]['content-length']
if (!contentLength ||
(req.raw.method !== 'HEAD' &&
Number(contentLength) !== Buffer.byteLength(payload)
)
) {
reply[kReplyHeaders]['content-length'] = '' + Buffer.byteLength(payload)
}
}
safeWriteHead(reply, statusCode)
// write payload first
res.write(payload)
// then send trailers
sendTrailer(payload, res, reply)
}
function logStreamError (logger, err, res) {
if (err.code === 'ERR_STREAM_PREMATURE_CLOSE') {
if (!logger[kDisableRequestLogging]) {
logger.info({ res }, 'stream closed prematurely')
}
} else {
logger.warn({ err }, 'response terminated with an error with headers already sent')
}
}
function sendWebStream (payload, res, reply) {
if (payload.locked) {
throw FST_ERR_REP_READABLE_STREAM_LOCKED()
}
const nodeStream = Readable.fromWeb(payload)
sendStream(nodeStream, res, reply)
}
function sendStream (payload, res, reply) {
let sourceOpen = true
let errorLogged = false
// set trailer when stream ended
sendStreamTrailer(payload, res, reply)
eos(payload, { readable: true, writable: false }, function (err) {
sourceOpen = false
if (err != null) {
if (res.headersSent || reply.request.raw.aborted === true) {
if (!errorLogged) {
errorLogged = true
logStreamError(reply.log, err, reply)
}
res.destroy()
} else {
onErrorHook(reply, err)
}
}
// there is nothing to do if there is not an error
})
eos(res, function (err) {
if (sourceOpen) {
if (err != null && res.headersSent && !errorLogged) {
errorLogged = true
logStreamError(reply.log, err, res)
}
if (typeof payload.destroy === 'function') {
payload.destroy()
} else if (typeof payload.close === 'function') {
payload.close(noop)
} else if (typeof payload.abort === 'function') {
payload.abort()
} else {
reply.log.warn('stream payload does not end properly')
}
}
})
// streams will error asynchronously, and we want to handle that error
// appropriately, e.g. a 404 for a missing file. So we cannot use
// writeHead, and we need to resort to setHeader, which will trigger
// a writeHead when there is data to send.
if (!res.headersSent) {
for (const key in reply[kReplyHeaders]) {
res.setHeader(key, reply[kReplyHeaders][key])
}
} else {
reply.log.warn('response will send, but you shouldn\'t use res.writeHead in stream mode')
}
payload.pipe(res)
}
function sendTrailer (payload, res, reply) {
if (reply[kReplyTrailers] === null) {
// when no trailer, we close the stream
res.end(null, null, null) // avoid ArgumentsAdaptorTrampoline from V8
return
}
const trailerHeaders = Object.keys(reply[kReplyTrailers])
const trailers = {}
let handled = 0
let skipped = true
function send () {
// add trailers when all handler handled
/* istanbul ignore else */
if (handled === 0) {
res.addTrailers(trailers)
// we need to properly close the stream
// after trailers sent
res.end(null, null, null) // avoid ArgumentsAdaptorTrampoline from V8
}
}
for (const trailerName of trailerHeaders) {
if (typeof reply[kReplyTrailers][trailerName] !== 'function') continue
skipped = false
handled--
function cb (err, value) {
// TODO: we may protect multiple callback calls
// or mixing async-await with callback
handled++
// we can safely ignore error for trailer
// since it does affect the client
// we log in here only for debug usage
if (err) reply.log.debug(err)
else trailers[trailerName] = value
// we push the check to the end of event
// loop, so the registration continue to
// process.
process.nextTick(send)
}
const result = reply[kReplyTrailers][trailerName](reply, payload, cb)
if (typeof result === 'object' && typeof result.then === 'function') {
result.then((v) => cb(null, v), cb)
}
}
// when all trailers are skipped
// we need to close the stream
if (skipped) res.end(null, null, null) // avoid ArgumentsAdaptorTrampoline from V8
}
function sendStreamTrailer (payload, res, reply) {
if (reply[kReplyTrailers] === null) return
payload.on('end', () => sendTrailer(null, res, reply))
}
function onErrorHook (reply, error, cb) {
if (reply[kRouteContext].onError !== null && !reply[kReplyNextErrorHandler]) {
reply[kReplyIsRunningOnErrorHook] = true
onSendHookRunner(
reply[kRouteContext].onError,
reply.request,
reply,
error,
() => handleError(reply, error, cb)
)
} else {
handleError(reply, error, cb)
}
}
function setupResponseListeners (reply) {
reply[kReplyStartTime] = now()
const onResFinished = err => {
reply[kReplyEndTime] = now()
reply.raw.removeListener('finish', onResFinished)
reply.raw.removeListener('error', onResFinished)
const ctx = reply[kRouteContext]
if (ctx && ctx.onResponse !== null) {
onResponseHookRunner(
ctx.onResponse,
reply.request,
reply,
onResponseCallback
)
} else {
onResponseCallback(err, reply.request, reply)
}
}
reply.raw.on('finish', onResFinished)
reply.raw.on('error', onResFinished)
}
function onResponseCallback (err, request, reply) {
if (reply.log[kDisableRequestLogging]) {
return
}
const responseTime = reply.elapsedTime
if (err != null) {
reply.log.error({
res: reply,
err,
responseTime
}, 'request errored')
return
}
reply.log.info({
res: reply,
responseTime
}, 'request completed')
}
function buildReply (R) {
const props = R.props.slice()
function _Reply (res, request, log) {
this.raw = res
this[kReplyIsError] = false
this[kReplyErrorHandlerCalled] = false
this[kReplyHijacked] = false
this[kReplySerializer] = null
this.request = request
this[kReplyHeaders] = {}
this[kReplyTrailers] = null
this[kReplyStartTime] = undefined
this[kReplyEndTime] = undefined
this.log = log
let prop
for (let i = 0; i < props.length; i++) {
prop = props[i]
this[prop.key] = prop.value
}
}
Object.setPrototypeOf(_Reply.prototype, R.prototype)
Object.setPrototypeOf(_Reply, R)
_Reply.parent = R
_Reply.props = props
return _Reply
}
function notFound (reply) {
if (reply[kRouteContext][kFourOhFourContext] === null) {
reply.log.warn('Trying to send a NotFound error inside a 404 handler. Sending basic 404 response.')
reply.code(404).send('404 Not Found')
return
}
reply.request[kRouteContext] = reply[kRouteContext][kFourOhFourContext]
// preHandler hook
if (reply[kRouteContext].preHandler !== null) {
preHandlerHookRunner(
reply[kRouteContext].preHandler,
reply.request,
reply,
internals.preHandlerCallback
)
} else {
internals.preHandlerCallback(null, reply.request, reply)
}
}
/**
* This function runs when a payload that is not a string|buffer|stream or null
* should be serialized to be streamed to the response.
* This is the default serializer that can be customized by the user using the replySerializer
*
* @param {object} context the request context
* @param {object} data the JSON payload to serialize
* @param {number} statusCode the http status code
* @param {string} [contentType] the reply content type
* @returns {string} the serialized payload
*/
function serialize (context, data, statusCode, contentType) {
const fnSerialize = getSchemaSerializer(context, statusCode, contentType)
if (fnSerialize) {
return fnSerialize(data)
}
return JSON.stringify(data)
}
function noop () { }
module.exports = Reply
module.exports.buildReply = buildReply
module.exports.setupResponseListeners = setupResponseListeners

View File

@@ -1,52 +0,0 @@
'use strict'
/**
* @callback GenerateRequestId
* @param {Object} req
* @returns {string}
*/
/**
* @param {string} [requestIdHeader]
* @param {GenerateRequestId} [optGenReqId]
* @returns {GenerateRequestId}
*/
function reqIdGenFactory (requestIdHeader, optGenReqId) {
const genReqId = optGenReqId || buildDefaultGenReqId()
if (requestIdHeader) {
return buildOptionalHeaderReqId(requestIdHeader, genReqId)
}
return genReqId
}
function getGenReqId (contextServer, req) {
return contextServer.genReqId(req)
}
function buildDefaultGenReqId () {
// 2,147,483,647 (2^31 1) stands for max SMI value (an internal optimization of V8).
// With this upper bound, if you'll be generating 1k ids/sec, you're going to hit it in ~25 days.
// This is very likely to happen in real-world applications, hence the limit is enforced.
// Growing beyond this value will make the id generation slower and cause a deopt.
// In the worst cases, it will become a float, losing accuracy.
const maxInt = 2147483647
let nextReqId = 0
return function defaultGenReqId () {
nextReqId = (nextReqId + 1) & maxInt
return `req-${nextReqId.toString(36)}`
}
}
function buildOptionalHeaderReqId (requestIdHeader, genReqId) {
return function (req) {
return req.headers[requestIdHeader] || genReqId(req)
}
}
module.exports = {
getGenReqId,
reqIdGenFactory
}

369
node_modules/fastify/lib/request.js generated vendored
View File

@@ -1,369 +0,0 @@
'use strict'
const proxyAddr = require('@fastify/proxy-addr')
const {
kHasBeenDecorated,
kSchemaBody,
kSchemaHeaders,
kSchemaParams,
kSchemaQuerystring,
kSchemaController,
kOptions,
kRequestCacheValidateFns,
kRouteContext,
kRequestOriginalUrl
} = require('./symbols')
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION, FST_ERR_DEC_UNDECLARED } = require('./errors')
const decorators = require('./decorate')
const HTTP_PART_SYMBOL_MAP = {
body: kSchemaBody,
headers: kSchemaHeaders,
params: kSchemaParams,
querystring: kSchemaQuerystring,
query: kSchemaQuerystring
}
function Request (id, params, req, query, log, context) {
this.id = id
this[kRouteContext] = context
this.params = params
this.raw = req
this.query = query
this.log = log
this.body = undefined
}
Request.props = []
function getTrustProxyFn (tp) {
if (typeof tp === 'function') {
return tp
}
if (tp === true) {
// Support trusting everything
return null
}
if (typeof tp === 'number') {
// Support trusting hop count
return function (a, i) { return i < tp }
}
if (typeof tp === 'string') {
// Support comma-separated tps
const values = tp.split(',').map(it => it.trim())
return proxyAddr.compile(values)
}
return proxyAddr.compile(tp)
}
function buildRequest (R, trustProxy) {
if (trustProxy) {
return buildRequestWithTrustProxy(R, trustProxy)
}
return buildRegularRequest(R)
}
function buildRegularRequest (R) {
const props = R.props.slice()
function _Request (id, params, req, query, log, context) {
this.id = id
this[kRouteContext] = context
this.params = params
this.raw = req
this.query = query
this.log = log
this.body = undefined
let prop
for (let i = 0; i < props.length; i++) {
prop = props[i]
this[prop.key] = prop.value
}
}
Object.setPrototypeOf(_Request.prototype, R.prototype)
Object.setPrototypeOf(_Request, R)
_Request.props = props
_Request.parent = R
return _Request
}
function getLastEntryInMultiHeaderValue (headerValue) {
// we use the last one if the header is set more than once
const lastIndex = headerValue.lastIndexOf(',')
return lastIndex === -1 ? headerValue.trim() : headerValue.slice(lastIndex + 1).trim()
}
function buildRequestWithTrustProxy (R, trustProxy) {
const _Request = buildRegularRequest(R)
const proxyFn = getTrustProxyFn(trustProxy)
// This is a more optimized version of decoration
_Request[kHasBeenDecorated] = true
Object.defineProperties(_Request.prototype, {
ip: {
get () {
const addrs = proxyAddr.all(this.raw, proxyFn)
return addrs[addrs.length - 1]
}
},
ips: {
get () {
return proxyAddr.all(this.raw, proxyFn)
}
},
host: {
get () {
if (this.ip !== undefined && this.headers['x-forwarded-host']) {
return getLastEntryInMultiHeaderValue(this.headers['x-forwarded-host'])
}
/**
* The last fallback supports the following cases:
* 1. http.requireHostHeader === false
* 2. HTTP/1.0 without a Host Header
* 3. Headers schema that may remove the Host Header
*/
return this.headers.host ?? this.headers[':authority'] ?? ''
}
},
protocol: {
get () {
if (this.headers['x-forwarded-proto']) {
return getLastEntryInMultiHeaderValue(this.headers['x-forwarded-proto'])
}
if (this.socket) {
return this.socket.encrypted ? 'https' : 'http'
}
}
}
})
return _Request
}
function assertsRequestDecoration (request, name) {
if (!decorators.hasKey(request, name) && !decorators.exist(request, name)) {
throw new FST_ERR_DEC_UNDECLARED(name, 'request')
}
}
Object.defineProperties(Request.prototype, {
server: {
get () {
return this[kRouteContext].server
}
},
url: {
get () {
return this.raw.url
}
},
originalUrl: {
get () {
/* istanbul ignore else */
if (!this[kRequestOriginalUrl]) {
this[kRequestOriginalUrl] = this.raw.originalUrl || this.raw.url
}
return this[kRequestOriginalUrl]
}
},
method: {
get () {
return this.raw.method
}
},
routeOptions: {
get () {
const context = this[kRouteContext]
const routeLimit = context._parserOptions.limit
const serverLimit = context.server.initialConfig.bodyLimit
const version = context.server.hasConstraintStrategy('version') ? this.raw.headers['accept-version'] : undefined
const options = {
method: context.config?.method,
url: context.config?.url,
bodyLimit: (routeLimit || serverLimit),
attachValidation: context.attachValidation,
logLevel: context.logLevel,
exposeHeadRoute: context.exposeHeadRoute,
prefixTrailingSlash: context.prefixTrailingSlash,
handler: context.handler,
config: context.config,
schema: context.schema,
version
}
return options
}
},
is404: {
get () {
return this[kRouteContext].config?.url === undefined
}
},
socket: {
get () {
return this.raw.socket
}
},
ip: {
get () {
if (this.socket) {
return this.socket.remoteAddress
}
}
},
host: {
get () {
/**
* The last fallback supports the following cases:
* 1. http.requireHostHeader === false
* 2. HTTP/1.0 without a Host Header
* 3. Headers schema that may remove the Host Header
*/
return this.raw.headers.host ?? this.raw.headers[':authority'] ?? ''
}
},
hostname: {
get () {
return this.host.split(':', 1)[0]
}
},
port: {
get () {
// first try taking port from host
const portFromHost = parseInt(this.host.split(':').slice(-1)[0])
if (!isNaN(portFromHost)) {
return portFromHost
}
// now fall back to port from host/:authority header
const host = (this.headers.host ?? this.headers[':authority'] ?? '')
const portFromHeader = parseInt(host.split(':').slice(-1)[0])
if (!isNaN(portFromHeader)) {
return portFromHeader
}
// fall back to null
return null
}
},
protocol: {
get () {
if (this.socket) {
return this.socket.encrypted ? 'https' : 'http'
}
}
},
headers: {
get () {
if (this.additionalHeaders) {
return Object.assign({}, this.raw.headers, this.additionalHeaders)
}
return this.raw.headers
},
set (headers) {
this.additionalHeaders = headers
}
},
getValidationFunction: {
value: function (httpPartOrSchema) {
if (typeof httpPartOrSchema === 'string') {
const symbol = HTTP_PART_SYMBOL_MAP[httpPartOrSchema]
return this[kRouteContext][symbol]
} else if (typeof httpPartOrSchema === 'object') {
return this[kRouteContext][kRequestCacheValidateFns]?.get(httpPartOrSchema)
}
}
},
compileValidationSchema: {
value: function (schema, httpPart = null) {
const { method, url } = this
if (this[kRouteContext][kRequestCacheValidateFns]?.has(schema)) {
return this[kRouteContext][kRequestCacheValidateFns].get(schema)
}
const validatorCompiler = this[kRouteContext].validatorCompiler ||
this.server[kSchemaController].validatorCompiler ||
(
// We compile the schemas if no custom validatorCompiler is provided
// nor set
this.server[kSchemaController].setupValidator(this.server[kOptions]) ||
this.server[kSchemaController].validatorCompiler
)
const validateFn = validatorCompiler({
schema,
method,
url,
httpPart
})
// We create a WeakMap to compile the schema only once
// Its done lazily to avoid add overhead by creating the WeakMap
// if it is not used
// TODO: Explore a central cache for all the schemas shared across
// encapsulated contexts
if (this[kRouteContext][kRequestCacheValidateFns] == null) {
this[kRouteContext][kRequestCacheValidateFns] = new WeakMap()
}
this[kRouteContext][kRequestCacheValidateFns].set(schema, validateFn)
return validateFn
}
},
validateInput: {
value: function (input, schema, httpPart) {
httpPart = typeof schema === 'string' ? schema : httpPart
const symbol = (httpPart != null && typeof httpPart === 'string') && HTTP_PART_SYMBOL_MAP[httpPart]
let validate
if (symbol) {
// Validate using the HTTP Request Part schema
validate = this[kRouteContext][symbol]
}
// We cannot compile if the schema is missed
if (validate == null && (schema == null ||
typeof schema !== 'object' ||
Array.isArray(schema))
) {
throw new FST_ERR_REQ_INVALID_VALIDATION_INVOCATION(httpPart)
}
if (validate == null) {
if (this[kRouteContext][kRequestCacheValidateFns]?.has(schema)) {
validate = this[kRouteContext][kRequestCacheValidateFns].get(schema)
} else {
// We proceed to compile if there's no validate function yet
validate = this.compileValidationSchema(schema, httpPart)
}
}
return validate(input)
}
},
getDecorator: {
value: function (name) {
assertsRequestDecoration(this, name)
const decorator = this[name]
if (typeof decorator === 'function') {
return decorator.bind(this)
}
return decorator
}
},
setDecorator: {
value: function (name, value) {
assertsRequestDecoration(this, name)
this[name] = value
}
}
})
module.exports = Request
module.exports.buildRequest = buildRequest

620
node_modules/fastify/lib/route.js generated vendored
View File

@@ -1,620 +0,0 @@
'use strict'
const FindMyWay = require('find-my-way')
const Context = require('./context')
const handleRequest = require('./handleRequest')
const { onRequestAbortHookRunner, lifecycleHooks, preParsingHookRunner, onTimeoutHookRunner, onRequestHookRunner } = require('./hooks')
const { normalizeSchema } = require('./schemas')
const { parseHeadOnSendHandlers } = require('./headRoute')
const {
compileSchemasForValidation,
compileSchemasForSerialization
} = require('./validation')
const {
FST_ERR_SCH_VALIDATION_BUILD,
FST_ERR_SCH_SERIALIZATION_BUILD,
FST_ERR_DUPLICATED_ROUTE,
FST_ERR_INVALID_URL,
FST_ERR_HOOK_INVALID_HANDLER,
FST_ERR_ROUTE_OPTIONS_NOT_OBJ,
FST_ERR_ROUTE_DUPLICATED_HANDLER,
FST_ERR_ROUTE_HANDLER_NOT_FN,
FST_ERR_ROUTE_MISSING_HANDLER,
FST_ERR_ROUTE_METHOD_NOT_SUPPORTED,
FST_ERR_ROUTE_METHOD_INVALID,
FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED,
FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT,
FST_ERR_HOOK_INVALID_ASYNC_HANDLER
} = require('./errors')
const { FSTDEP022 } = require('./warnings')
const {
kRoutePrefix,
kSupportedHTTPMethods,
kLogLevel,
kLogSerializers,
kHooks,
kSchemaController,
kOptions,
kReplySerializerDefault,
kReplyIsError,
kRequestPayloadStream,
kDisableRequestLogging,
kSchemaErrorFormatter,
kErrorHandler,
kHasBeenDecorated,
kRequestAcceptVersion,
kRouteByFastify,
kRouteContext
} = require('./symbols.js')
const { buildErrorHandler } = require('./error-handler')
const { createChildLogger } = require('./logger-factory.js')
const { getGenReqId } = require('./reqIdGenFactory.js')
const routerKeys = [
'allowUnsafeRegex',
'buildPrettyMeta',
'caseSensitive',
'constraints',
'defaultRoute',
'ignoreDuplicateSlashes',
'ignoreTrailingSlash',
'maxParamLength',
'onBadUrl',
'querystringParser',
'useSemicolonDelimiter'
]
function buildRouting (options) {
const router = FindMyWay(options.config)
let avvio
let fourOhFour
let logger
let hasLogger
let setupResponseListeners
let throwIfAlreadyStarted
let disableRequestLogging
let ignoreTrailingSlash
let ignoreDuplicateSlashes
let return503OnClosing
let globalExposeHeadRoutes
let keepAliveConnections
let closing = false
return {
/**
* @param {import('../fastify').FastifyServerOptions} options
* @param {*} fastifyArgs
*/
setup (options, fastifyArgs) {
avvio = fastifyArgs.avvio
fourOhFour = fastifyArgs.fourOhFour
logger = fastifyArgs.logger
hasLogger = fastifyArgs.hasLogger
setupResponseListeners = fastifyArgs.setupResponseListeners
throwIfAlreadyStarted = fastifyArgs.throwIfAlreadyStarted
globalExposeHeadRoutes = options.exposeHeadRoutes
disableRequestLogging = options.disableRequestLogging
ignoreTrailingSlash = options.routerOptions.ignoreTrailingSlash
ignoreDuplicateSlashes = options.routerOptions.ignoreDuplicateSlashes
return503OnClosing = Object.hasOwn(options, 'return503OnClosing') ? options.return503OnClosing : true
keepAliveConnections = fastifyArgs.keepAliveConnections
},
routing: router.lookup.bind(router), // router func to find the right handler to call
route, // configure a route in the fastify instance
hasRoute,
prepareRoute,
routeHandler,
closeRoutes: () => { closing = true },
printRoutes: router.prettyPrint.bind(router),
addConstraintStrategy,
hasConstraintStrategy,
isAsyncConstraint,
findRoute
}
function addConstraintStrategy (strategy) {
throwIfAlreadyStarted('Cannot add constraint strategy!')
return router.addConstraintStrategy(strategy)
}
function hasConstraintStrategy (strategyName) {
return router.hasConstraintStrategy(strategyName)
}
function isAsyncConstraint () {
return router.constrainer.asyncStrategiesInUse.size > 0
}
// Convert shorthand to extended route declaration
function prepareRoute ({ method, url, options, handler, isFastify }) {
if (typeof url !== 'string') {
throw new FST_ERR_INVALID_URL(typeof url)
}
if (!handler && typeof options === 'function') {
handler = options // for support over direct function calls such as fastify.get() options are reused as the handler
options = {}
} else if (handler && typeof handler === 'function') {
if (Object.prototype.toString.call(options) !== '[object Object]') {
throw new FST_ERR_ROUTE_OPTIONS_NOT_OBJ(method, url)
} else if (options.handler) {
if (typeof options.handler === 'function') {
throw new FST_ERR_ROUTE_DUPLICATED_HANDLER(method, url)
} else {
throw new FST_ERR_ROUTE_HANDLER_NOT_FN(method, url)
}
}
}
options = Object.assign({}, options, {
method,
url,
path: url,
handler: handler || (options && options.handler)
})
return route.call(this, { options, isFastify })
}
function hasRoute ({ options }) {
const normalizedMethod = options.method?.toUpperCase() ?? ''
return router.hasRoute(
normalizedMethod,
options.url || '',
options.constraints
)
}
function findRoute (options) {
const route = router.find(
options.method,
options.url || '',
options.constraints
)
if (route) {
// we must reduce the expose surface, otherwise
// we provide the ability for the user to modify
// all the route and server information in runtime
return {
handler: route.handler,
params: route.params,
searchParams: route.searchParams
}
} else {
return null
}
}
/**
* Route management
* @param {{ options: import('../fastify').RouteOptions, isFastify: boolean }}
*/
function route ({ options, isFastify }) {
throwIfAlreadyStarted('Cannot add route!')
// Since we are mutating/assigning only top level props, it is fine to have a shallow copy using the spread operator
const opts = { ...options }
const path = opts.url || opts.path || ''
if (!opts.handler) {
throw new FST_ERR_ROUTE_MISSING_HANDLER(opts.method, path)
}
if (opts.errorHandler !== undefined && typeof opts.errorHandler !== 'function') {
throw new FST_ERR_ROUTE_HANDLER_NOT_FN(opts.method, path)
}
validateBodyLimitOption(opts.bodyLimit)
const shouldExposeHead = opts.exposeHeadRoute ?? globalExposeHeadRoutes
let isGetRoute = false
let isHeadRoute = false
if (Array.isArray(opts.method)) {
for (let i = 0; i < opts.method.length; ++i) {
opts.method[i] = normalizeAndValidateMethod.call(this, opts.method[i])
validateSchemaBodyOption.call(this, opts.method[i], path, opts.schema)
isGetRoute = opts.method.includes('GET')
isHeadRoute = opts.method.includes('HEAD')
}
} else {
opts.method = normalizeAndValidateMethod.call(this, opts.method)
validateSchemaBodyOption.call(this, opts.method, path, opts.schema)
isGetRoute = opts.method === 'GET'
isHeadRoute = opts.method === 'HEAD'
}
// we need to clone a set of initial options for HEAD route
const headOpts = shouldExposeHead && isGetRoute ? { ...options } : null
const prefix = this[kRoutePrefix]
if (path === '/' && prefix.length > 0 && opts.method !== 'HEAD') {
switch (opts.prefixTrailingSlash) {
case 'slash':
addNewRoute.call(this, { path, isFastify })
break
case 'no-slash':
addNewRoute.call(this, { path: '', isFastify })
break
case 'both':
default:
addNewRoute.call(this, { path: '', isFastify })
// If ignoreTrailingSlash is set to true we need to add only the '' route to prevent adding an incomplete one.
if (ignoreTrailingSlash !== true && (ignoreDuplicateSlashes !== true || !prefix.endsWith('/'))) {
addNewRoute.call(this, { path, prefixing: true, isFastify })
}
}
} else if (path[0] === '/' && prefix.endsWith('/')) {
// Ensure that '/prefix/' + '/route' gets registered as '/prefix/route'
addNewRoute.call(this, { path: path.slice(1), isFastify })
} else {
addNewRoute.call(this, { path, isFastify })
}
// chainable api
return this
function addNewRoute ({ path, prefixing = false, isFastify = false }) {
const url = prefix + path
opts.url = url
opts.path = url
opts.routePath = path
opts.prefix = prefix
opts.logLevel = opts.logLevel || this[kLogLevel]
if (this[kLogSerializers] || opts.logSerializers) {
opts.logSerializers = Object.assign(Object.create(this[kLogSerializers]), opts.logSerializers)
}
if (opts.attachValidation == null) {
opts.attachValidation = false
}
if (prefixing === false) {
// run 'onRoute' hooks
for (const hook of this[kHooks].onRoute) {
hook.call(this, opts)
}
}
for (const hook of lifecycleHooks) {
if (opts && hook in opts) {
if (Array.isArray(opts[hook])) {
for (const func of opts[hook]) {
if (typeof func !== 'function') {
throw new FST_ERR_HOOK_INVALID_HANDLER(hook, Object.prototype.toString.call(func))
}
if (hook === 'onSend' || hook === 'preSerialization' || hook === 'onError' || hook === 'preParsing') {
if (func.constructor.name === 'AsyncFunction' && func.length === 4) {
throw new FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
}
} else if (hook === 'onRequestAbort') {
if (func.constructor.name === 'AsyncFunction' && func.length !== 1) {
throw new FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
}
} else {
if (func.constructor.name === 'AsyncFunction' && func.length === 3) {
throw new FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
}
}
}
} else if (opts[hook] !== undefined && typeof opts[hook] !== 'function') {
throw new FST_ERR_HOOK_INVALID_HANDLER(hook, Object.prototype.toString.call(opts[hook]))
}
}
}
const constraints = opts.constraints || {}
const config = {
...opts.config,
url,
method: opts.method
}
const context = new Context({
schema: opts.schema,
handler: opts.handler.bind(this),
config,
errorHandler: opts.errorHandler,
childLoggerFactory: opts.childLoggerFactory,
bodyLimit: opts.bodyLimit,
logLevel: opts.logLevel,
logSerializers: opts.logSerializers,
attachValidation: opts.attachValidation,
schemaErrorFormatter: opts.schemaErrorFormatter,
replySerializer: this[kReplySerializerDefault],
validatorCompiler: opts.validatorCompiler,
serializerCompiler: opts.serializerCompiler,
exposeHeadRoute: shouldExposeHead,
prefixTrailingSlash: (opts.prefixTrailingSlash || 'both'),
server: this,
isFastify
})
const headHandler = router.findRoute('HEAD', opts.url, constraints)
const hasHEADHandler = headHandler !== null
try {
router.on(opts.method, opts.url, { constraints }, routeHandler, context)
} catch (error) {
// any route insertion error created by fastify can be safely ignore
// because it only duplicate route for head
if (!context[kRouteByFastify]) {
const isDuplicatedRoute = error.message.includes(`Method '${opts.method}' already declared for route`)
if (isDuplicatedRoute) {
throw new FST_ERR_DUPLICATED_ROUTE(opts.method, opts.url)
}
throw error
}
}
this.after((notHandledErr, done) => {
// Send context async
context.errorHandler = opts.errorHandler ? buildErrorHandler(this[kErrorHandler], opts.errorHandler) : this[kErrorHandler]
context._parserOptions.limit = opts.bodyLimit || null
context.logLevel = opts.logLevel
context.logSerializers = opts.logSerializers
context.attachValidation = opts.attachValidation
context[kReplySerializerDefault] = this[kReplySerializerDefault]
context.schemaErrorFormatter = opts.schemaErrorFormatter || this[kSchemaErrorFormatter] || context.schemaErrorFormatter
// Run hooks and more
avvio.once('preReady', () => {
for (const hook of lifecycleHooks) {
const toSet = this[kHooks][hook]
.concat(opts[hook] || [])
.map(h => h.bind(this))
context[hook] = toSet.length ? toSet : null
}
// Optimization: avoid encapsulation if no decoration has been done.
while (!context.Request[kHasBeenDecorated] && context.Request.parent) {
context.Request = context.Request.parent
}
while (!context.Reply[kHasBeenDecorated] && context.Reply.parent) {
context.Reply = context.Reply.parent
}
// Must store the 404 Context in 'preReady' because it is only guaranteed to
// be available after all of the plugins and routes have been loaded.
fourOhFour.setContext(this, context)
if (opts.schema) {
context.schema = normalizeSchema(context.schema, this.initialConfig)
const schemaController = this[kSchemaController]
if (!opts.validatorCompiler && (opts.schema.body || opts.schema.headers || opts.schema.querystring || opts.schema.params)) {
schemaController.setupValidator(this[kOptions])
}
try {
const isCustom = typeof opts?.validatorCompiler === 'function' || schemaController.isCustomValidatorCompiler
compileSchemasForValidation(context, opts.validatorCompiler || schemaController.validatorCompiler, isCustom)
} catch (error) {
throw new FST_ERR_SCH_VALIDATION_BUILD(opts.method, url, error.message)
}
if (opts.schema.response && !opts.serializerCompiler) {
schemaController.setupSerializer(this[kOptions])
}
try {
compileSchemasForSerialization(context, opts.serializerCompiler || schemaController.serializerCompiler)
} catch (error) {
throw new FST_ERR_SCH_SERIALIZATION_BUILD(opts.method, url, error.message)
}
}
})
done(notHandledErr)
})
// register head route in sync
// we must place it after the `this.after`
if (shouldExposeHead && isGetRoute && !isHeadRoute && !hasHEADHandler) {
const onSendHandlers = parseHeadOnSendHandlers(headOpts.onSend)
prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...headOpts, onSend: onSendHandlers }, isFastify: true })
}
}
}
// HTTP request entry point, the routing has already been executed
function routeHandler (req, res, params, context, query) {
const id = getGenReqId(context.server, req)
const loggerOpts = {
level: context.logLevel
}
if (context.logSerializers) {
loggerOpts.serializers = context.logSerializers
}
const childLogger = createChildLogger(context, logger, req, id, loggerOpts)
childLogger[kDisableRequestLogging] = disableRequestLogging
if (closing === true) {
/* istanbul ignore next mac, windows */
if (req.httpVersionMajor !== 2) {
res.setHeader('Connection', 'close')
}
// TODO remove return503OnClosing after Node v18 goes EOL
/* istanbul ignore else */
if (return503OnClosing) {
// On Node v19 we cannot test this behavior as it won't be necessary
// anymore. It will close all the idle connections before they reach this
// stage.
const headers = {
'Content-Type': 'application/json',
'Content-Length': '80'
}
res.writeHead(503, headers)
res.end('{"error":"Service Unavailable","message":"Service Unavailable","statusCode":503}')
childLogger.info({ res: { statusCode: 503 } }, 'request aborted - refusing to accept new requests as server is closing')
return
}
}
// When server.forceCloseConnections is true, we will collect any requests
// that have indicated they want persistence so that they can be reaped
// on server close. Otherwise, the container is a noop container.
const connHeader = String.prototype.toLowerCase.call(req.headers.connection || '')
if (connHeader === 'keep-alive') {
if (keepAliveConnections.has(req.socket) === false) {
keepAliveConnections.add(req.socket)
req.socket.on('close', removeTrackedSocket.bind({ keepAliveConnections, socket: req.socket }))
}
}
// we revert the changes in defaultRoute
if (req.headers[kRequestAcceptVersion] !== undefined) {
req.headers['accept-version'] = req.headers[kRequestAcceptVersion]
req.headers[kRequestAcceptVersion] = undefined
}
const request = new context.Request(id, params, req, query, childLogger, context)
const reply = new context.Reply(res, request, childLogger)
if (disableRequestLogging === false) {
childLogger.info({ req: request }, 'incoming request')
}
if (hasLogger === true || context.onResponse !== null) {
setupResponseListeners(reply)
}
if (context.onRequest !== null) {
onRequestHookRunner(
context.onRequest,
request,
reply,
runPreParsing
)
} else {
runPreParsing(null, request, reply)
}
if (context.onRequestAbort !== null) {
req.on('close', () => {
/* istanbul ignore else */
if (req.aborted) {
onRequestAbortHookRunner(
context.onRequestAbort,
request,
handleOnRequestAbortHooksErrors.bind(null, reply)
)
}
})
}
if (context.onTimeout !== null) {
if (!request.raw.socket._meta) {
request.raw.socket.on('timeout', handleTimeout)
}
request.raw.socket._meta = { context, request, reply }
}
}
}
function handleOnRequestAbortHooksErrors (reply, err) {
if (err) {
reply.log.error({ err }, 'onRequestAborted hook failed')
}
}
function handleTimeout () {
const { context, request, reply } = this._meta
onTimeoutHookRunner(
context.onTimeout,
request,
reply,
noop
)
}
function normalizeAndValidateMethod (method) {
if (typeof method !== 'string') {
throw new FST_ERR_ROUTE_METHOD_INVALID()
}
method = method.toUpperCase()
if (!this[kSupportedHTTPMethods].bodyless.has(method) &&
!this[kSupportedHTTPMethods].bodywith.has(method)) {
throw new FST_ERR_ROUTE_METHOD_NOT_SUPPORTED(method)
}
return method
}
function validateSchemaBodyOption (method, path, schema) {
if (this[kSupportedHTTPMethods].bodyless.has(method) && schema?.body) {
throw new FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED(method, path)
}
}
function validateBodyLimitOption (bodyLimit) {
if (bodyLimit === undefined) return
if (!Number.isInteger(bodyLimit) || bodyLimit <= 0) {
throw new FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT(bodyLimit)
}
}
function runPreParsing (err, request, reply) {
if (reply.sent === true) return
if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
return
}
request[kRequestPayloadStream] = request.raw
if (request[kRouteContext].preParsing !== null) {
preParsingHookRunner(request[kRouteContext].preParsing, request, reply, handleRequest.bind(request.server))
} else {
handleRequest.call(request.server, null, request, reply)
}
}
function buildRouterOptions (options, defaultOptions) {
const routerOptions = options.routerOptions || Object.create(null)
const usedDeprecatedOptions = routerKeys.filter(key => Object.hasOwn(options, key))
if (usedDeprecatedOptions.length > 0) {
FSTDEP022(usedDeprecatedOptions.join(', '))
}
for (const key of routerKeys) {
if (!Object.hasOwn(routerOptions, key)) {
routerOptions[key] = options[key] ?? defaultOptions[key]
}
}
return routerOptions
}
/**
* Used within the route handler as a `net.Socket.close` event handler.
* The purpose is to remove a socket from the tracked sockets collection when
* the socket has naturally timed out.
*/
function removeTrackedSocket () {
this.keepAliveConnections.delete(this.socket)
}
function noop () { }
module.exports = { buildRouting, validateBodyLimitOption, buildRouterOptions }

View File

@@ -1,164 +0,0 @@
'use strict'
const { buildSchemas } = require('./schemas')
const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
const ValidatorSelector = require('@fastify/ajv-compiler')
/**
* Called at every fastify context that is being created.
* @param {object} parentSchemaCtrl: the SchemaController instance of the Fastify parent context
* @param {object} opts: the `schemaController` server option. It can be undefined when a parentSchemaCtrl is set
* @return {object}:a new SchemaController
*/
function buildSchemaController (parentSchemaCtrl, opts) {
if (parentSchemaCtrl) {
return new SchemaController(parentSchemaCtrl, opts)
}
const compilersFactory = Object.assign({
buildValidator: null,
buildSerializer: null
}, opts?.compilersFactory)
if (!compilersFactory.buildValidator) {
compilersFactory.buildValidator = ValidatorSelector()
}
if (!compilersFactory.buildSerializer) {
compilersFactory.buildSerializer = SerializerSelector()
}
const option = {
bucket: (opts && opts.bucket) || buildSchemas,
compilersFactory,
isCustomValidatorCompiler: typeof opts?.compilersFactory?.buildValidator === 'function',
isCustomSerializerCompiler: typeof opts?.compilersFactory?.buildValidator === 'function'
}
return new SchemaController(undefined, option)
}
class SchemaController {
constructor (parent, options) {
this.opts = options || parent?.opts
this.addedSchemas = false
this.compilersFactory = this.opts.compilersFactory
if (parent) {
this.schemaBucket = this.opts.bucket(parent.getSchemas())
this.validatorCompiler = parent.getValidatorCompiler()
this.serializerCompiler = parent.getSerializerCompiler()
this.isCustomValidatorCompiler = parent.isCustomValidatorCompiler
this.isCustomSerializerCompiler = parent.isCustomSerializerCompiler
this.parent = parent
} else {
this.schemaBucket = this.opts.bucket()
this.isCustomValidatorCompiler = this.opts.isCustomValidatorCompiler || false
this.isCustomSerializerCompiler = this.opts.isCustomSerializerCompiler || false
}
}
// Bucket interface
add (schema) {
this.addedSchemas = true
return this.schemaBucket.add(schema)
}
getSchema (schemaId) {
return this.schemaBucket.getSchema(schemaId)
}
getSchemas () {
return this.schemaBucket.getSchemas()
}
setValidatorCompiler (validatorCompiler) {
// Set up as if the fixed validator compiler had been provided
// by a custom 'options.compilersFactory.buildValidator' that
// always returns the same compiler object. This is required because:
//
// - setValidatorCompiler must immediately install a compiler to preserve
// legacy behavior
// - setupValidator will recreate compilers from builders in some
// circumstances, so we have to install this adapter to make it
// behave the same if the legacy API is used
//
// The cloning of the compilersFactory object is necessary because
// we are aliasing the parent compilersFactory if none was provided
// to us (see constructor.)
this.compilersFactory = Object.assign(
{},
this.compilersFactory,
{ buildValidator: () => validatorCompiler })
this.validatorCompiler = validatorCompiler
this.isCustomValidatorCompiler = true
}
setSerializerCompiler (serializerCompiler) {
// Set up as if the fixed serializer compiler had been provided
// by a custom 'options.compilersFactory.buildSerializer' that
// always returns the same compiler object. This is required because:
//
// - setSerializerCompiler must immediately install a compiler to preserve
// legacy behavior
// - setupSerializer will recreate compilers from builders in some
// circumstances, so we have to install this adapter to make it
// behave the same if the legacy API is used
//
// The cloning of the compilersFactory object is necessary because
// we are aliasing the parent compilersFactory if none was provided
// to us (see constructor.)
this.compilersFactory = Object.assign(
{},
this.compilersFactory,
{ buildSerializer: () => serializerCompiler })
this.serializerCompiler = serializerCompiler
this.isCustomSerializerCompiler = true
}
getValidatorCompiler () {
return this.validatorCompiler || (this.parent && this.parent.getValidatorCompiler())
}
getSerializerCompiler () {
return this.serializerCompiler || (this.parent && this.parent.getSerializerCompiler())
}
getSerializerBuilder () {
return this.compilersFactory.buildSerializer || (this.parent && this.parent.getSerializerBuilder())
}
getValidatorBuilder () {
return this.compilersFactory.buildValidator || (this.parent && this.parent.getValidatorBuilder())
}
/**
* This method will be called when a validator must be setup.
* Do not setup the compiler more than once
* @param {object} serverOptions the fastify server options
*/
setupValidator (serverOptions) {
const isReady = this.validatorCompiler !== undefined && !this.addedSchemas
if (isReady) {
return
}
this.validatorCompiler = this.getValidatorBuilder()(this.schemaBucket.getSchemas(), serverOptions.ajv)
}
/**
* This method will be called when a serializer must be setup.
* Do not setup the compiler more than once
* @param {object} serverOptions the fastify server options
*/
setupSerializer (serverOptions) {
const isReady = this.serializerCompiler !== undefined && !this.addedSchemas
if (isReady) {
return
}
this.serializerCompiler = this.getSerializerBuilder()(this.schemaBucket.getSchemas(), serverOptions.serializerOpts)
}
}
SchemaController.buildSchemaController = buildSchemaController
module.exports = SchemaController

207
node_modules/fastify/lib/schemas.js generated vendored
View File

@@ -1,207 +0,0 @@
'use strict'
const fastClone = require('rfdc')({ circles: false, proto: true })
const { kSchemaVisited, kSchemaResponse } = require('./symbols')
const kFluentSchema = Symbol.for('fluent-schema-object')
const {
FST_ERR_SCH_MISSING_ID,
FST_ERR_SCH_ALREADY_PRESENT,
FST_ERR_SCH_DUPLICATE,
FST_ERR_SCH_CONTENT_MISSING_SCHEMA
} = require('./errors')
const SCHEMAS_SOURCE = ['params', 'body', 'querystring', 'query', 'headers']
function Schemas (initStore) {
this.store = initStore || {}
}
Schemas.prototype.add = function (inputSchema) {
const schema = fastClone((inputSchema.isFluentSchema || inputSchema.isFluentJSONSchema || inputSchema[kFluentSchema])
? inputSchema.valueOf()
: inputSchema
)
// developers can add schemas without $id, but with $def instead
const id = schema.$id
if (!id) {
throw new FST_ERR_SCH_MISSING_ID()
}
if (this.store[id]) {
throw new FST_ERR_SCH_ALREADY_PRESENT(id)
}
this.store[id] = schema
}
Schemas.prototype.getSchemas = function () {
return Object.assign({}, this.store)
}
Schemas.prototype.getSchema = function (schemaId) {
return this.store[schemaId]
}
/**
* Checks whether a schema is a non-plain object.
*
* @param {*} schema the schema to check
* @returns {boolean} true if schema has a custom prototype
*/
function isCustomSchemaPrototype (schema) {
return typeof schema === 'object' && Object.getPrototypeOf(schema) !== Object.prototype
}
function normalizeSchema (routeSchemas, serverOptions) {
if (routeSchemas[kSchemaVisited]) {
return routeSchemas
}
// alias query to querystring schema
if (routeSchemas.query) {
// check if our schema has both querystring and query
if (routeSchemas.querystring) {
throw new FST_ERR_SCH_DUPLICATE('querystring')
}
routeSchemas.querystring = routeSchemas.query
}
generateFluentSchema(routeSchemas)
for (const key of SCHEMAS_SOURCE) {
const schema = routeSchemas[key]
if (schema && !isCustomSchemaPrototype(schema)) {
if (key === 'body' && schema.content) {
const contentProperty = schema.content
const keys = Object.keys(contentProperty)
for (let i = 0; i < keys.length; i++) {
const contentType = keys[i]
const contentSchema = contentProperty[contentType].schema
if (!contentSchema) {
throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(contentType)
}
}
continue
}
}
}
if (routeSchemas.response) {
const httpCodes = Object.keys(routeSchemas.response)
for (const code of httpCodes) {
if (isCustomSchemaPrototype(routeSchemas.response[code])) {
continue
}
const contentProperty = routeSchemas.response[code].content
if (contentProperty) {
const keys = Object.keys(contentProperty)
for (let i = 0; i < keys.length; i++) {
const mediaName = keys[i]
if (!contentProperty[mediaName].schema) {
throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(mediaName)
}
}
}
}
}
routeSchemas[kSchemaVisited] = true
return routeSchemas
}
function generateFluentSchema (schema) {
for (const key of SCHEMAS_SOURCE) {
if (schema[key] && (schema[key].isFluentSchema || schema[key][kFluentSchema])) {
schema[key] = schema[key].valueOf()
}
}
if (schema.response) {
const httpCodes = Object.keys(schema.response)
for (const code of httpCodes) {
if (schema.response[code].isFluentSchema || schema.response[code][kFluentSchema]) {
schema.response[code] = schema.response[code].valueOf()
}
}
}
}
/**
* Search for the right JSON schema compiled function in the request context
* setup by the route configuration `schema.response`.
* It will look for the exact match (eg 200) or generic (eg 2xx)
*
* @param {object} context the request context
* @param {number} statusCode the http status code
* @param {string} [contentType] the reply content type
* @returns {function|false} the right JSON Schema function to serialize
* the reply or false if it is not set
*/
function getSchemaSerializer (context, statusCode, contentType) {
const responseSchemaDef = context[kSchemaResponse]
if (!responseSchemaDef) {
return false
}
if (responseSchemaDef[statusCode]) {
if (responseSchemaDef[statusCode].constructor === Object && contentType) {
const mediaName = contentType.split(';', 1)[0]
if (responseSchemaDef[statusCode][mediaName]) {
return responseSchemaDef[statusCode][mediaName]
}
// fallback to match all media-type
if (responseSchemaDef[statusCode]['*/*']) {
return responseSchemaDef[statusCode]['*/*']
}
return false
}
return responseSchemaDef[statusCode]
}
const fallbackStatusCode = (statusCode + '')[0] + 'xx'
if (responseSchemaDef[fallbackStatusCode]) {
if (responseSchemaDef[fallbackStatusCode].constructor === Object && contentType) {
const mediaName = contentType.split(';', 1)[0]
if (responseSchemaDef[fallbackStatusCode][mediaName]) {
return responseSchemaDef[fallbackStatusCode][mediaName]
}
// fallback to match all media-type
if (responseSchemaDef[fallbackStatusCode]['*/*']) {
return responseSchemaDef[fallbackStatusCode]['*/*']
}
return false
}
return responseSchemaDef[fallbackStatusCode]
}
if (responseSchemaDef.default) {
if (responseSchemaDef.default.constructor === Object && contentType) {
const mediaName = contentType.split(';', 1)[0]
if (responseSchemaDef.default[mediaName]) {
return responseSchemaDef.default[mediaName]
}
// fallback to match all media-type
if (responseSchemaDef.default['*/*']) {
return responseSchemaDef.default['*/*']
}
return false
}
return responseSchemaDef.default
}
return false
}
module.exports = {
buildSchemas (initStore) { return new Schemas(initStore) },
getSchemaSerializer,
normalizeSchema
}

355
node_modules/fastify/lib/server.js generated vendored
View File

@@ -1,355 +0,0 @@
'use strict'
const http = require('node:http')
const https = require('node:https')
const http2 = require('node:http2')
const dns = require('node:dns')
const os = require('node:os')
const { kState, kOptions, kServerBindings } = require('./symbols')
const { FSTWRN003 } = require('./warnings')
const { onListenHookRunner } = require('./hooks')
const {
FST_ERR_REOPENED_CLOSE_SERVER,
FST_ERR_REOPENED_SERVER,
FST_ERR_LISTEN_OPTIONS_INVALID
} = require('./errors')
const PonyPromise = require('./promise')
module.exports.createServer = createServer
function defaultResolveServerListeningText (address) {
return `Server listening at ${address}`
}
function createServer (options, httpHandler) {
const server = getServerInstance(options, httpHandler)
// `this` is the Fastify object
function listen (
listenOptions = { port: 0, host: 'localhost' },
cb = undefined
) {
if (typeof cb === 'function') {
if (cb.constructor.name === 'AsyncFunction') {
FSTWRN003('listen method')
}
listenOptions.cb = cb
}
if (listenOptions.signal) {
if (typeof listenOptions.signal.on !== 'function' && typeof listenOptions.signal.addEventListener !== 'function') {
throw new FST_ERR_LISTEN_OPTIONS_INVALID('Invalid options.signal')
}
// copy the current signal state
this[kState].aborted = listenOptions.signal.aborted
if (this[kState].aborted) {
return this.close()
} else {
const onAborted = () => {
this[kState].aborted = true
this.close()
}
listenOptions.signal.addEventListener('abort', onAborted, { once: true })
}
}
// If we have a path specified, don't default host to 'localhost' so we don't end up listening
// on both path and host
// See https://github.com/fastify/fastify/issues/4007
let host
if (listenOptions.path == null) {
host = listenOptions.host ?? 'localhost'
} else {
host = listenOptions.host
}
if (!Object.hasOwn(listenOptions, 'host') ||
listenOptions.host == null) {
listenOptions.host = host
}
if (host === 'localhost') {
listenOptions.cb = (err, address) => {
if (err) {
// the server did not start
cb(err, address)
return
}
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
this[kState].listening = true
cb(null, address)
onListenHookRunner(this)
})
}
} else {
listenOptions.cb = (err, address) => {
// the server did not start
if (err) {
cb(err, address)
return
}
this[kState].listening = true
cb(null, address)
onListenHookRunner(this)
}
}
// https://github.com/nodejs/node/issues/9390
// If listening to 'localhost', listen to both 127.0.0.1 or ::1 if they are available.
// If listening to 127.0.0.1, only listen to 127.0.0.1.
// If listening to ::1, only listen to ::1.
if (cb === undefined) {
const listening = listenPromise.call(this, server, listenOptions)
return listening.then(address => {
const { promise, resolve } = PonyPromise.withResolvers()
if (host === 'localhost') {
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
this[kState].listening = true
resolve(address)
onListenHookRunner(this)
})
} else {
resolve(address)
onListenHookRunner(this)
}
return promise
})
}
this.ready(listenCallback.call(this, server, listenOptions))
}
return { server, listen }
}
function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, onListen) {
// the main server is started, we need to start the secondary servers
this[kState].listening = false
// let's check if we need to bind additional addresses
dns.lookup(listenOptions.host, { all: true }, (dnsErr, addresses) => {
if (dnsErr || this[kState].aborted) {
// not blocking the main server listening
// this.log.warn('dns.lookup error:', dnsErr)
onListen()
return
}
const isMainServerListening = mainServer.listening && serverOpts.serverFactory
let binding = 0
let bound = 0
if (!isMainServerListening) {
const primaryAddress = mainServer.address()
for (const adr of addresses) {
if (adr.address !== primaryAddress.address) {
binding++
const secondaryOpts = Object.assign({}, listenOptions, {
host: adr.address,
port: primaryAddress.port,
cb: (_ignoreErr) => {
bound++
if (!_ignoreErr) {
this[kServerBindings].push(secondaryServer)
}
if (bound === binding) {
// regardless of the error, we are done
onListen()
}
}
})
const secondaryServer = getServerInstance(serverOpts, httpHandler)
const closeSecondary = () => {
// To avoid falling into situations where the close of the
// secondary server is triggered before the preClose hook
// is done running, we better wait until the main server is closed.
// No new TCP connections are accepted
// We swallow any error from the secondary server
secondaryServer.close(() => {})
if (typeof secondaryServer.closeAllConnections === 'function' && serverOpts.forceCloseConnections === true) {
secondaryServer.closeAllConnections()
}
}
secondaryServer.on('upgrade', mainServer.emit.bind(mainServer, 'upgrade'))
mainServer.on('unref', closeSecondary)
mainServer.on('close', closeSecondary)
mainServer.on('error', closeSecondary)
this[kState].listening = false
listenCallback.call(this, secondaryServer, secondaryOpts)()
}
}
}
// no extra bindings are necessary
if (binding === 0) {
onListen()
return
}
// in test files we are using unref so we need to propagate the unref event
// to the secondary servers. It is valid only when the user is
// listening on localhost
const originUnref = mainServer.unref
mainServer.unref = function () {
originUnref.call(mainServer)
mainServer.emit('unref')
}
})
}
function listenCallback (server, listenOptions) {
const wrap = (err) => {
server.removeListener('error', wrap)
server.removeListener('listening', wrap)
if (!err) {
const address = logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText)
listenOptions.cb(null, address)
} else {
this[kState].listening = false
listenOptions.cb(err, null)
}
}
return (err) => {
if (err != null) return listenOptions.cb(err)
if (this[kState].listening && this[kState].closing) {
return listenOptions.cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
}
if (this[kState].listening) {
return listenOptions.cb(new FST_ERR_REOPENED_SERVER(), null)
}
server.once('error', wrap)
if (!this[kState].closing) {
server.once('listening', wrap)
server.listen(listenOptions)
this[kState].listening = true
}
}
}
function listenPromise (server, listenOptions) {
if (this[kState].listening && this[kState].closing) {
return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
}
if (this[kState].listening) {
return Promise.reject(new FST_ERR_REOPENED_SERVER())
}
return this.ready().then(() => {
// skip listen when aborted during ready
if (this[kState].aborted) return
const { promise, resolve, reject } = PonyPromise.withResolvers()
const errEventHandler = (err) => {
cleanup()
this[kState].listening = false
reject(err)
}
const listeningEventHandler = () => {
cleanup()
this[kState].listening = true
resolve(logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText))
}
function cleanup () {
server.removeListener('error', errEventHandler)
server.removeListener('listening', listeningEventHandler)
}
server.once('error', errEventHandler)
server.once('listening', listeningEventHandler)
server.listen(listenOptions)
return promise
})
}
function getServerInstance (options, httpHandler) {
if (options.serverFactory) {
// User provided server instance
return options.serverFactory(httpHandler, options)
}
// We have accepted true as a valid way to init https but node requires an options obj
const httpsOptions = options.https === true ? {} : options.https
if (options.http2) {
const server = typeof httpsOptions === 'object' ? http2.createSecureServer(httpsOptions, httpHandler) : http2.createServer(options.http, httpHandler)
server.on('session', (session) => session.setTimeout(options.http2SessionTimeout, function closeSession () {
this.close()
}))
server.setTimeout(options.connectionTimeout)
return server
}
// HTTP1 server instance
const server = httpsOptions ? https.createServer(httpsOptions, httpHandler) : http.createServer(options.http, httpHandler)
server.keepAliveTimeout = options.keepAliveTimeout
server.requestTimeout = options.requestTimeout
server.setTimeout(options.connectionTimeout)
// We treat zero as null(node default) so we do not pass zero to the server instance
if (options.maxRequestsPerSocket > 0) {
server.maxRequestsPerSocket = options.maxRequestsPerSocket
}
return server
}
/**
* Inspects the provided `server.address` object and returns a
* normalized list of IP address strings. Normalization in this
* case refers to mapping wildcard `0.0.0.0` to the list of IP
* addresses the wildcard refers to.
*
* @see https://nodejs.org/docs/latest/api/net.html#serveraddress
*
* @param {object} A server address object as described in the
* linked docs.
*
* @returns {string[]}
*/
function getAddresses (address) {
if (address.address === '0.0.0.0') {
return Object.values(os.networkInterfaces()).flatMap((iface) => {
return iface.filter((iface) => iface.family === 'IPv4')
}).sort((iface) => {
/* c8 ignore next 2 */
// Order the interfaces so that internal ones come first
return iface.internal ? -1 : 1
}).map((iface) => { return iface.address })
}
return [address.address]
}
function logServerAddress (server, listenTextResolver) {
let addresses
const isUnixSocket = typeof server.address() === 'string'
if (!isUnixSocket) {
if (server.address().address.indexOf(':') === -1) {
// IPv4
addresses = getAddresses(server.address()).map((address) => address + ':' + server.address().port)
} else {
// IPv6
addresses = ['[' + server.address().address + ']:' + server.address().port]
}
addresses = addresses.map((address) => ('http' + (this[kOptions].https ? 's' : '') + '://') + address)
} else {
addresses = [server.address()]
}
for (const address of addresses) {
this.log.info(listenTextResolver(address))
}
return addresses[0]
}

66
node_modules/fastify/lib/symbols.js generated vendored
View File

@@ -1,66 +0,0 @@
'use strict'
const keys = {
kAvvioBoot: Symbol('fastify.avvioBoot'),
kChildren: Symbol('fastify.children'),
kServerBindings: Symbol('fastify.serverBindings'),
kBodyLimit: Symbol('fastify.bodyLimit'),
kSupportedHTTPMethods: Symbol('fastify.acceptedHTTPMethods'),
kRoutePrefix: Symbol('fastify.routePrefix'),
kLogLevel: Symbol('fastify.logLevel'),
kLogSerializers: Symbol('fastify.logSerializers'),
kHooks: Symbol('fastify.hooks'),
kContentTypeParser: Symbol('fastify.contentTypeParser'),
kState: Symbol('fastify.state'),
kOptions: Symbol('fastify.options'),
kDisableRequestLogging: Symbol('fastify.disableRequestLogging'),
kPluginNameChain: Symbol('fastify.pluginNameChain'),
kRouteContext: Symbol('fastify.context'),
kGenReqId: Symbol('fastify.genReqId'),
// Schema
kSchemaController: Symbol('fastify.schemaController'),
kSchemaHeaders: Symbol('headers-schema'),
kSchemaParams: Symbol('params-schema'),
kSchemaQuerystring: Symbol('querystring-schema'),
kSchemaBody: Symbol('body-schema'),
kSchemaResponse: Symbol('response-schema'),
kSchemaErrorFormatter: Symbol('fastify.schemaErrorFormatter'),
kSchemaVisited: Symbol('fastify.schemas.visited'),
// Request
kRequest: Symbol('fastify.Request'),
kRequestPayloadStream: Symbol('fastify.RequestPayloadStream'),
kRequestAcceptVersion: Symbol('fastify.RequestAcceptVersion'),
kRequestCacheValidateFns: Symbol('fastify.request.cache.validateFns'),
kRequestOriginalUrl: Symbol('fastify.request.originalUrl'),
// 404
kFourOhFour: Symbol('fastify.404'),
kCanSetNotFoundHandler: Symbol('fastify.canSetNotFoundHandler'),
kFourOhFourLevelInstance: Symbol('fastify.404LogLevelInstance'),
kFourOhFourContext: Symbol('fastify.404ContextKey'),
kDefaultJsonParse: Symbol('fastify.defaultJSONParse'),
// Reply
kReply: Symbol('fastify.Reply'),
kReplySerializer: Symbol('fastify.reply.serializer'),
kReplyIsError: Symbol('fastify.reply.isError'),
kReplyHeaders: Symbol('fastify.reply.headers'),
kReplyTrailers: Symbol('fastify.reply.trailers'),
kReplyHasStatusCode: Symbol('fastify.reply.hasStatusCode'),
kReplyHijacked: Symbol('fastify.reply.hijacked'),
kReplyStartTime: Symbol('fastify.reply.startTime'),
kReplyNextErrorHandler: Symbol('fastify.reply.nextErrorHandler'),
kReplyEndTime: Symbol('fastify.reply.endTime'),
kReplyErrorHandlerCalled: Symbol('fastify.reply.errorHandlerCalled'),
kReplyIsRunningOnErrorHook: Symbol('fastify.reply.isRunningOnErrorHook'),
kReplySerializerDefault: Symbol('fastify.replySerializerDefault'),
kReplyCacheSerializeFns: Symbol('fastify.reply.cache.serializeFns'),
// This symbol is only meant to be used for fastify tests and should not be used for any other purpose
kTestInternals: Symbol('fastify.testInternals'),
kErrorHandler: Symbol('fastify.errorHandler'),
kErrorHandlerAlreadySet: Symbol('fastify.errorHandlerAlreadySet'),
kChildLoggerFactory: Symbol('fastify.childLoggerFactory'),
kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'),
kKeepAliveConnections: Symbol('fastify.keepAliveConnections'),
kRouteByFastify: Symbol('fastify.routeByFastify')
}
module.exports = keys

View File

@@ -1,272 +0,0 @@
'use strict'
const {
kSchemaHeaders: headersSchema,
kSchemaParams: paramsSchema,
kSchemaQuerystring: querystringSchema,
kSchemaBody: bodySchema,
kSchemaResponse: responseSchema
} = require('./symbols')
const scChecker = /^[1-5](?:\d{2}|xx)$|^default$/
const {
FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX
} = require('./errors')
const { FSTWRN001 } = require('./warnings')
function compileSchemasForSerialization (context, compile) {
if (!context.schema || !context.schema.response) {
return
}
const { method, url } = context.config || {}
context[responseSchema] = Object.keys(context.schema.response)
.reduce(function (acc, statusCode) {
const schema = context.schema.response[statusCode]
statusCode = statusCode.toLowerCase()
if (!scChecker.test(statusCode)) {
throw new FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX()
}
if (schema.content) {
const contentTypesSchemas = {}
for (const mediaName of Object.keys(schema.content)) {
const contentSchema = schema.content[mediaName].schema
contentTypesSchemas[mediaName] = compile({
schema: contentSchema,
url,
method,
httpStatus: statusCode,
contentType: mediaName
})
}
acc[statusCode] = contentTypesSchemas
} else {
acc[statusCode] = compile({
schema,
url,
method,
httpStatus: statusCode
})
}
return acc
}, {})
}
function compileSchemasForValidation (context, compile, isCustom) {
const { schema } = context
if (!schema) {
return
}
const { method, url } = context.config || {}
const headers = schema.headers
// the or part is used for backward compatibility
if (headers && (isCustom || Object.getPrototypeOf(headers) !== Object.prototype)) {
// do not mess with schema when custom validator applied, e.g. Joi, Typebox
context[headersSchema] = compile({ schema: headers, method, url, httpPart: 'headers' })
} else if (headers) {
// The header keys are case insensitive
// https://datatracker.ietf.org/doc/html/rfc2616#section-4.2
const headersSchemaLowerCase = {}
Object.keys(headers).forEach(k => { headersSchemaLowerCase[k] = headers[k] })
if (headersSchemaLowerCase.required instanceof Array) {
headersSchemaLowerCase.required = headersSchemaLowerCase.required.map(h => h.toLowerCase())
}
if (headers.properties) {
headersSchemaLowerCase.properties = {}
Object.keys(headers.properties).forEach(k => {
headersSchemaLowerCase.properties[k.toLowerCase()] = headers.properties[k]
})
}
context[headersSchema] = compile({ schema: headersSchemaLowerCase, method, url, httpPart: 'headers' })
} else if (Object.hasOwn(schema, 'headers')) {
FSTWRN001('headers', method, url)
}
if (schema.body) {
const contentProperty = schema.body.content
if (contentProperty) {
const contentTypeSchemas = {}
for (const contentType of Object.keys(contentProperty)) {
const contentSchema = contentProperty[contentType].schema
contentTypeSchemas[contentType] = compile({ schema: contentSchema, method, url, httpPart: 'body', contentType })
}
context[bodySchema] = contentTypeSchemas
} else {
context[bodySchema] = compile({ schema: schema.body, method, url, httpPart: 'body' })
}
} else if (Object.hasOwn(schema, 'body')) {
FSTWRN001('body', method, url)
}
if (schema.querystring) {
context[querystringSchema] = compile({ schema: schema.querystring, method, url, httpPart: 'querystring' })
} else if (Object.hasOwn(schema, 'querystring')) {
FSTWRN001('querystring', method, url)
}
if (schema.params) {
context[paramsSchema] = compile({ schema: schema.params, method, url, httpPart: 'params' })
} else if (Object.hasOwn(schema, 'params')) {
FSTWRN001('params', method, url)
}
}
function validateParam (validatorFunction, request, paramName) {
const isUndefined = request[paramName] === undefined
const ret = validatorFunction && validatorFunction(isUndefined ? null : request[paramName])
if (ret && typeof ret.then === 'function') {
return ret
.then((res) => { return answer(res) })
.catch(err => { return err }) // return as simple error (not throw)
}
return answer(ret)
function answer (ret) {
if (ret === false) return validatorFunction.errors
if (ret && ret.error) return ret.error
if (ret && ret.value) request[paramName] = ret.value
return false
}
}
function validate (context, request, execution) {
const runExecution = execution === undefined
if (runExecution || !execution.skipParams) {
const params = validateParam(context[paramsSchema], request, 'params')
if (params) {
if (typeof params.then !== 'function') {
return wrapValidationError(params, 'params', context.schemaErrorFormatter)
} else {
return validateAsyncParams(params, context, request)
}
}
}
if (runExecution || !execution.skipBody) {
let validatorFunction = null
if (typeof context[bodySchema] === 'function') {
validatorFunction = context[bodySchema]
} else if (context[bodySchema]) {
// TODO: add request.contentType and reuse it here
const contentType = getEssenceMediaType(request.headers['content-type'])
const contentSchema = context[bodySchema][contentType]
if (contentSchema) {
validatorFunction = contentSchema
}
}
const body = validateParam(validatorFunction, request, 'body')
if (body) {
if (typeof body.then !== 'function') {
return wrapValidationError(body, 'body', context.schemaErrorFormatter)
} else {
return validateAsyncBody(body, context, request)
}
}
}
if (runExecution || !execution.skipQuery) {
const query = validateParam(context[querystringSchema], request, 'query')
if (query) {
if (typeof query.then !== 'function') {
return wrapValidationError(query, 'querystring', context.schemaErrorFormatter)
} else {
return validateAsyncQuery(query, context, request)
}
}
}
const headers = validateParam(context[headersSchema], request, 'headers')
if (headers) {
if (typeof headers.then !== 'function') {
return wrapValidationError(headers, 'headers', context.schemaErrorFormatter)
} else {
return validateAsyncHeaders(headers, context, request)
}
}
return false
}
function validateAsyncParams (validatePromise, context, request) {
return validatePromise
.then((paramsResult) => {
if (paramsResult) {
return wrapValidationError(paramsResult, 'params', context.schemaErrorFormatter)
}
return validate(context, request, { skipParams: true })
})
}
function validateAsyncBody (validatePromise, context, request) {
return validatePromise
.then((bodyResult) => {
if (bodyResult) {
return wrapValidationError(bodyResult, 'body', context.schemaErrorFormatter)
}
return validate(context, request, { skipParams: true, skipBody: true })
})
}
function validateAsyncQuery (validatePromise, context, request) {
return validatePromise
.then((queryResult) => {
if (queryResult) {
return wrapValidationError(queryResult, 'querystring', context.schemaErrorFormatter)
}
return validate(context, request, { skipParams: true, skipBody: true, skipQuery: true })
})
}
function validateAsyncHeaders (validatePromise, context, request) {
return validatePromise
.then((headersResult) => {
if (headersResult) {
return wrapValidationError(headersResult, 'headers', context.schemaErrorFormatter)
}
return false
})
}
function wrapValidationError (result, dataVar, schemaErrorFormatter) {
if (result instanceof Error) {
result.statusCode = result.statusCode || 400
result.code = result.code || 'FST_ERR_VALIDATION'
result.validationContext = result.validationContext || dataVar
return result
}
const error = schemaErrorFormatter(result, dataVar)
error.statusCode = error.statusCode || 400
error.code = error.code || 'FST_ERR_VALIDATION'
error.validation = result
error.validationContext = dataVar
return error
}
/**
* simple function to retrieve the essence media type
* @param {string} header
* @returns {string} Mimetype string.
*/
function getEssenceMediaType (header) {
if (!header) return ''
return header.split(/[ ;]/, 1)[0].trim().toLowerCase()
}
module.exports = {
symbols: { bodySchema, querystringSchema, responseSchema, paramsSchema, headersSchema },
compileSchemasForValidation,
compileSchemasForSerialization,
validate
}

57
node_modules/fastify/lib/warnings.js generated vendored
View File

@@ -1,57 +0,0 @@
'use strict'
const { createWarning } = require('process-warning')
/**
* Deprecation codes:
* - FSTWRN001
* - FSTSEC001
* - FSTDEP022
*
* Deprecation Codes FSTDEP001 - FSTDEP021 were used by v4 and MUST NOT not be reused.
* - FSTDEP022 is used by v5 and MUST NOT be reused.
* Warning Codes FSTWRN001 - FSTWRN002 were used by v4 and MUST NOT not be reused.
*/
const FSTWRN001 = createWarning({
name: 'FastifyWarning',
code: 'FSTWRN001',
message: 'The %s schema for %s: %s is missing. This may indicate the schema is not well specified.',
unlimited: true
})
const FSTWRN003 = createWarning({
name: 'FastifyWarning',
code: 'FSTWRN003',
message: 'The %s mixes async and callback styles that may lead to unhandled rejections. Please use only one of them.',
unlimited: true
})
const FSTWRN004 = createWarning({
name: 'FastifyWarning',
code: 'FSTWRN004',
message: 'It seems that you are overriding an errorHandler in the same scope, which can lead to subtle bugs.',
unlimited: true
})
const FSTSEC001 = createWarning({
name: 'FastifySecurity',
code: 'FSTSEC001',
message: 'You are using /%s/ Content-Type which may be vulnerable to CORS attack. Please make sure your RegExp start with "^" or include ";?" to proper detection of the essence MIME type.',
unlimited: true
})
const FSTDEP022 = createWarning({
name: 'FastifyWarning',
code: 'FSTDPE022',
message: 'The router options for %s property access is deprecated. Please use "options.routerOptions" instead for accessing router options. The router options will be removed in `fastify@6`.',
unlimited: true
})
module.exports = {
FSTWRN001,
FSTWRN003,
FSTWRN004,
FSTSEC001,
FSTDEP022
}

View File

@@ -1,81 +0,0 @@
'use strict'
const {
kReplyIsError,
kReplyHijacked
} = require('./symbols')
const diagnostics = require('node:diagnostics_channel')
const channels = diagnostics.tracingChannel('fastify.request.handler')
function wrapThenable (thenable, reply, store) {
if (store) store.async = true
thenable.then(function (payload) {
if (reply[kReplyHijacked] === true) {
return
}
if (store) {
channels.asyncStart.publish(store)
}
try {
// this is for async functions that are using reply.send directly
//
// since wrap-thenable will be called when using reply.send directly
// without actual return. the response can be sent already or
// the request may be terminated during the reply. in this situation,
// it require an extra checking of request.aborted to see whether
// the request is killed by client.
if (payload !== undefined || //
(reply.sent === false && //
reply.raw.headersSent === false &&
reply.request.raw.aborted === false &&
reply.request.socket &&
!reply.request.socket.destroyed
)
) {
// we use a try-catch internally to avoid adding a catch to another
// promise, increase promise perf by 10%
try {
reply.send(payload)
} catch (err) {
reply[kReplyIsError] = true
reply.send(err)
}
}
} finally {
if (store) {
channels.asyncEnd.publish(store)
}
}
}, function (err) {
if (store) {
store.error = err
channels.error.publish(store) // note that error happens before asyncStart
channels.asyncStart.publish(store)
}
try {
if (reply.sent === true) {
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
return
}
reply[kReplyIsError] = true
reply.send(err)
// The following should not happen
/* c8 ignore next 3 */
} catch (err) {
// try-catch allow to re-throw error in error handler for async handler
reply.send(err)
} finally {
if (store) {
channels.asyncEnd.publish(store)
}
}
})
}
module.exports = wrapThenable