Projektstart

This commit is contained in:
2026-01-22 15:49:12 +01:00
parent 7212eb6f7a
commit 57e5f652f8
10637 changed files with 2598792 additions and 64 deletions

1138
backend/node_modules/fastify/lib/configValidator.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

442
backend/node_modules/fastify/lib/contentTypeParser.js generated vendored Normal file
View File

@@ -0,0 +1,442 @@
'use strict'
const { AsyncResource } = require('node:async_hooks')
const { FifoMap: Fifo } = require('toad-cache')
const { safeParse: safeParseContentType, defaultContentType } = require('fast-content-type-parse')
const secureJson = 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
} = require('./errors')
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 = [new ParserListItem('application/json'), new ParserListItem('text/plain')]
this.parserRegExpList = []
this.cache = new Fifo(100)
}
ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
const contentTypeIsString = typeof contentType === 'string'
if (!contentTypeIsString && !(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
if (contentTypeIsString && contentType.length === 0) throw new FST_ERR_CTP_EMPTY_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 (contentTypeIsString && contentType === '*') {
this.customParsers.set('', parser)
} else {
if (contentTypeIsString) {
this.parserList.unshift(new ParserListItem(contentType))
} else {
contentType.isEssence = contentType.source.indexOf(';') === -1
this.parserRegExpList.unshift(contentType)
}
this.customParsers.set(contentType.toString(), parser)
}
}
ContentTypeParser.prototype.hasParser = function (contentType) {
return this.customParsers.has(typeof contentType === 'string' ? contentType : contentType.toString())
}
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) {
if (this.hasParser(contentType)) {
return this.customParsers.get(contentType)
}
const parser = this.cache.get(contentType)
if (parser !== undefined) return parser
const parsed = safeParseContentType(contentType)
// dummyContentType always the same object
// we can use === for the comparison and return early
if (parsed === defaultContentType) {
return this.customParsers.get('')
}
// eslint-disable-next-line no-var
for (var i = 0; i !== this.parserList.length; ++i) {
const parserListItem = this.parserList[i]
if (compareContentType(parsed, parserListItem)) {
const parser = this.customParsers.get(parserListItem.name)
// we set request content-type in cache to reduce parsing of MIME type
this.cache.set(contentType, parser)
return parser
}
}
// eslint-disable-next-line no-var
for (var j = 0; j !== this.parserRegExpList.length; ++j) {
const parserRegExp = this.parserRegExpList[j]
if (compareRegExpContentType(contentType, parsed.type, parserRegExp)) {
const parser = this.customParsers.get(parserRegExp.toString())
// we set request content-type in cache to reduce parsing of MIME type
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) {
if (!(typeof contentType === 'string' || contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
const removed = this.customParsers.delete(contentType.toString())
const parsers = typeof contentType === 'string' ? this.parserList : this.parserRegExpList
const idx = parsers.findIndex(ct => ct.toString() === contentType.toString())
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) {
handler(request, reply)
} else {
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType || undefined))
}
// Early return to avoid allocating an AsyncResource if it's not needed
return
}
const resource = new AsyncResource('content-type-parser:run', request)
if (parser.asString === true || parser.asBuffer === true) {
rawBody(
request,
reply,
reply[kRouteContext]._parserOptions,
parser,
done
)
} else {
const result = parser.fn(request, request[kRequestPayloadStream], done)
if (result && typeof result.then === 'function') {
result.then(body => done(null, body), done)
}
}
function done (error, body) {
// We cannot use resource.bind() because it is broken in node v12 and v14
resource.runInAsyncScope(() => {
resource.emitDestroy()
if (error) {
reply[kReplyIsError] = true
reply.send(error)
} else {
request.body = body
handler(request, reply)
}
})
}
}
function rawBody (request, reply, options, parser, done) {
const asString = parser.asString
const limit = options.limit === null ? parser.bodyLimit : options.limit
const contentLength = request.headers['content-length'] === undefined
? NaN
: Number(request.headers['content-length'])
if (contentLength > limit) {
// We must close the connection as the client is going
// to send this data anyway
reply.header('connection', 'close')
reply.send(new FST_ERR_CTP_BODY_TOO_LARGE())
return
}
let receivedLength = 0
let body = asString === true ? '' : []
const payload = request[kRequestPayloadStream] || request.raw
if (asString === true) {
payload.setEncoding('utf8')
}
payload.on('data', onData)
payload.on('end', onEnd)
payload.on('error', onEnd)
payload.resume()
function onData (chunk) {
receivedLength += 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)
reply.send(new FST_ERR_CTP_BODY_TOO_LARGE())
return
}
if (asString === true) {
body += chunk
} else {
body.push(chunk)
}
}
function onEnd (err) {
payload.removeListener('data', onData)
payload.removeListener('end', onEnd)
payload.removeListener('error', onEnd)
if (err !== undefined) {
if (!(typeof err.statusCode === 'number' && err.statusCode >= 400)) {
err.statusCode = 400
}
reply[kReplyIsError] = true
reply.code(err.statusCode).send(err)
return
}
if (asString === true) {
receivedLength = Buffer.byteLength(body)
}
if (!Number.isNaN(contentLength) && (payload.receivedEncodedLength || receivedLength) !== contentLength) {
reply.header('connection', 'close')
reply.send(new FST_ERR_CTP_INVALID_CONTENT_LENGTH())
return
}
if (asString === false) {
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) {
return defaultJsonParser
function defaultJsonParser (req, body, done) {
if (body === '' || body == null || (Buffer.isBuffer(body) && body.length === 0)) {
return done(new FST_ERR_CTP_EMPTY_JSON_BODY(), undefined)
}
let json
try {
json = secureJson.parse(body, { protoAction: onProtoPoisoning, constructorAction: onConstructorPoisoning })
} catch (err) {
err.statusCode = 400
return done(err, undefined)
}
done(null, json)
}
}
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 compareContentType (contentType, parserListItem) {
if (parserListItem.isEssence) {
// we do essence check
return contentType.type.indexOf(parserListItem) !== -1
} else {
// when the content-type includes parameters
// we do a full-text search
// reject essence content-type before checking parameters
if (contentType.type.indexOf(parserListItem.type) === -1) return false
for (const key of parserListItem.parameterKeys) {
// reject when missing parameters
if (!(key in contentType.parameters)) return false
// reject when parameters do not match
if (contentType.parameters[key] !== parserListItem.parameters[key]) return false
}
return true
}
}
function compareRegExpContentType (contentType, essenceMIMEType, regexp) {
if (regexp.isEssence) {
// we do essence check
return regexp.test(essenceMIMEType)
} else {
// when the content-type includes parameters
// we do a full-text match
return regexp.test(contentType)
}
}
function ParserListItem (contentType) {
this.name = contentType
// we pre-calculate all the needed information
// before content-type comparison
const parsed = safeParseContentType(contentType)
this.isEssence = contentType.indexOf(';') === -1
// we should not allow empty string for parser list item
// because it would become a match-all handler
if (this.isEssence === false && parsed.type === '') {
// handle semicolon or empty string
const tmp = contentType.split(';', 1)[0]
this.type = tmp === '' ? contentType : tmp
} else {
this.type = parsed.type
}
this.parameters = parsed.parameters
this.parameterKeys = Object.keys(parsed.parameters)
}
// used in ContentTypeParser.remove
ParserListItem.prototype.toString = function () {
return this.name
}
module.exports = ContentTypeParser
module.exports.helpers = {
buildContentTypeParser,
addContentTypeParser,
hasContentTypeParser,
removeContentTypeParser,
removeAllContentTypeParsers
}
module.exports.defaultParsers = {
getDefaultJsonParser,
defaultTextParser: defaultPlainTextParser
}
module.exports[kTestInternals] = { rawBody }

117
backend/node_modules/fastify/lib/context.js generated vendored Normal file
View File

@@ -0,0 +1,117 @@
'use strict'
const {
kFourOhFourContext,
kReplySerializerDefault,
kSchemaErrorFormatter,
kErrorHandler,
kChildLoggerFactory,
kOptions,
kReply,
kRequest,
kBodyLimit,
kLogLevel,
kContentTypeParser,
kRouteByFastify,
kRequestCacheValidateFns,
kReplyCacheSerializeFns,
kPublicRouteContext
} = 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
// Route + Userland configurations for the route
this[kPublicRouteContext] = getPublicRouteContext(this)
this.server = server
}
function getPublicRouteContext (context) {
return Object.create(null, {
schema: {
enumerable: true,
get () {
return context.schema
}
},
config: {
enumerable: true,
get () {
return context.config
}
}
})
}
function defaultSchemaErrorFormatter (errors, dataVar) {
let text = ''
const separator = ', '
// eslint-disable-next-line no-var
for (var 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

141
backend/node_modules/fastify/lib/decorate.js generated vendored Normal file
View File

@@ -0,0 +1,141 @@
'use strict'
/* eslint no-prototype-builtins: 0 */
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_DEPENDENCY_INVALID_TYPE
} = require('./errors')
const { FSTDEP006 } = require('./warnings')
function decorate (instance, name, fn, dependencies) {
if (Object.prototype.hasOwnProperty.call(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 decorateConstructor (konstructor, name, fn, dependencies) {
const instance = konstructor.prototype
if (Object.prototype.hasOwnProperty.call(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')) {
FSTDEP006(name)
}
}
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)
}
// eslint-disable-next-line no-var
for (var 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
}

174
backend/node_modules/fastify/lib/error-handler.js generated vendored Normal file
View File

@@ -0,0 +1,174 @@
'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 && 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 && error.message
)
}
} else {
if (!reply.log[kDisableRequestLogging]) {
reply.log.error(
{ req: request, res: reply, err: error },
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'])
payload = (serializerFn === false)
? serializeError({
error: statusCodes[statusCode + ''],
code: error.code,
message: error.message,
statusCode
})
: 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
}

119
backend/node_modules/fastify/lib/error-serializer.js generated vendored Normal file
View File

@@ -0,0 +1,119 @@
// This file is autogenerated by build/build-error-serializer.js, do not edit
/* istanbul ignore file */
'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)

475
backend/node_modules/fastify/lib/errors.js generated vendored Normal file
View File

@@ -0,0 +1,475 @@
'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_VERSION_CONSTRAINT_NOT_STR: createError(
'FST_ERR_VERSION_CONSTRAINT_NOT_STR',
'Version constraint should be a string.',
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
),
/**
* 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_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!"
),
/**
* 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 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
),
/**
* 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_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" } }'
),
/**
* http2
*/
FST_ERR_HTTP2_INVALID_VERSION: createError(
'FST_ERR_HTTP2_INVALID_VERSION',
'HTTP2 is available only from node >= 8.8.1'
),
/**
* 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_DEFAULT_ROUTE_INVALID_TYPE: createError(
'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE',
'The defaultRoute type should be a function',
500,
TypeError
),
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"
),
/**
* 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
}

187
backend/node_modules/fastify/lib/fourOhFour.js generated vendored Normal file
View File

@@ -0,0 +1,187 @@
'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')
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

156
backend/node_modules/fastify/lib/handleRequest.js generated vendored Normal file
View File

@@ -0,0 +1,156 @@
'use strict'
const { validate: validateSchema } = require('./validation')
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
const wrapThenable = require('./wrapThenable')
const {
kReplyIsError,
kRouteContext
} = require('./symbols')
function handleRequest (err, request, reply) {
if (reply.sent === true) return
if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
return
}
const method = request.raw.method
const headers = request.headers
const context = request[kRouteContext]
if (method === 'GET' || method === 'HEAD') {
handler(request, reply)
return
}
const contentType = headers['content-type']
if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE' || method === 'SEARCH' ||
method === 'PROPFIND' || method === 'PROPPATCH' || method === 'LOCK' || method === 'COPY' || method === 'MOVE' ||
method === 'MKCOL' || method === 'REPORT' || method === 'MKCALENDAR') {
if (contentType === undefined) {
if (
headers['transfer-encoding'] === undefined &&
(headers['content-length'] === '0' || headers['content-length'] === undefined)
) { // Request has no body to parse
handler(request, reply)
} else {
context.contentTypeParser.run('', handler, request, reply)
}
} else {
context.contentTypeParser.run(contentType, handler, request, reply)
}
return
}
if (method === 'OPTIONS' || method === 'DELETE') {
if (
contentType !== undefined &&
(
headers['transfer-encoding'] !== undefined ||
headers['content-length'] !== undefined
)
) {
context.contentTypeParser.run(contentType, handler, request, reply)
} else {
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
if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
return
}
let result
try {
result = request[kRouteContext].handler(request, reply)
} catch (err) {
reply[kReplyIsError] = true
reply.send(err)
return
}
if (result !== undefined) {
if (result !== null && typeof result.then === 'function') {
wrapThenable(result, reply)
} else {
reply.send(result)
}
}
}
module.exports = handleRequest
module.exports[Symbol.for('internals')] = { handler, preHandlerCallback }

31
backend/node_modules/fastify/lib/headRoute.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
'use strict'
function headRouteOnSendHandler (req, reply, payload, done) {
// If payload is undefined
if (payload === undefined) {
reply.header('content-length', '0')
return done(null, null)
}
if (typeof payload.resume === 'function') {
payload.on('error', (err) => {
reply.log.error({ err }, 'Error on Stream found for HEAD route')
})
payload.resume()
return done(null, null)
}
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
}

426
backend/node_modules/fastify/lib/hooks.js generated vendored Normal file
View File

@@ -0,0 +1,426 @@
'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) {
if (err) {
if (err.code === 'AVV_ERR_READY_TIMEOUT') {
err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName))
} 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
}

24
backend/node_modules/fastify/lib/httpMethods.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
'use strict'
module.exports = {
supportedMethods: [
'DELETE',
'GET',
'HEAD',
'PATCH',
'POST',
'PUT',
'OPTIONS',
'PROPFIND',
'PROPPATCH',
'MKCOL',
'COPY',
'MOVE',
'LOCK',
'UNLOCK',
'TRACE',
'SEARCH',
'REPORT',
'MKCALENDAR'
]
}

View File

@@ -0,0 +1,37 @@
'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 }

170
backend/node_modules/fastify/lib/logger.js generated vendored Normal file
View File

@@ -0,0 +1,170 @@
'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 nullLogger = require('abstract-logging')
const pino = require('pino')
const { serializersSym } = pino.symbols
const {
FST_ERR_LOG_INVALID_DESTINATION,
FST_ERR_LOG_INVALID_LOGGER
} = 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'],
hostname: req.hostname,
remoteAddress: req.ip,
remotePort: req.socket ? req.socket.remotePort : undefined
}
},
err: pino.stdSerializers.err,
res: function asResValue (reply) {
return {
statusCode: reply.statusCode
}
}
}
function now () {
const ts = process.hrtime()
return (ts[0] * 1e3) + (ts[1] / 1e6)
}
function createLogger (options) {
if (!options.logger) {
const logger = nullLogger
logger.child = () => logger
return { logger, hasLogger: false }
}
if (validateLogger(options.logger)) {
const logger = createPinoLogger({
logger: options.logger,
serializers: Object.assign({}, serializers, options.logger.serializers)
})
return { logger, hasLogger: true }
}
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 }
}
/**
* 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(','))
}
}
/**
* 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
*/
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
}
/**
* @param {import('../fastify.js').FastifyBaseLogger} logger
* @param {import('../types/logger.js').Bindings} bindings
* @param {import('../types/logger.js').ChildLoggerOptions} opts
*/
function defaultChildLoggerFactory (logger, bindings, opts) {
return logger.child(bindings, opts)
}
module.exports = {
createLogger,
createChildLogger,
defaultChildLoggerFactory,
serializers,
now
}

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

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

88
backend/node_modules/fastify/lib/pluginOverride.js generated vendored Normal file
View File

@@ -0,0 +1,88 @@
'use strict'
const {
kAvvioBoot,
kChildren,
kRoutePrefix,
kLogLevel,
kLogSerializers,
kHooks,
kSchemaController,
kContentTypeParser,
kReply,
kRequest,
kFourOhFour,
kPluginNameChain
} = 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]
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(this, 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
}

167
backend/node_modules/fastify/lib/pluginUtils.js generated vendored Normal file
View File

@@ -0,0 +1,167 @@
'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
} = require('./errors')
const { FSTWRN002 } = require('./warnings.js')
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').slice(0, 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) return
const requiredVersion = meta.fastify
const fastifyRc = /-rc.+$/.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) {
FSTWRN002(pluginName || 'anonymous')
}
}
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
}

969
backend/node_modules/fastify/lib/reply.js generated vendored Normal file
View File

@@ -0,0 +1,969 @@
'use strict'
const eos = require('node:stream').finished
const Readable = require('node:stream').Readable
const {
kFourOhFourContext,
kPublicRouteContext,
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')
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_ALREADY_SENT,
FST_ERR_REP_SENT_VALUE,
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
} = require('./errors')
const { FSTDEP010, FSTDEP013, FSTDEP019, FSTDEP020, FSTDEP021 } = require('./warnings')
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]
}
},
// TODO: remove once v5 is done
// Is temporary to avoid constant conflicts between `next` and `main`
context: {
get () {
FSTDEP019()
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
},
set (value) {
FSTDEP010()
if (value !== true) {
throw new FST_ERR_REP_SENT_VALUE()
}
// We throw only if sent was overwritten from Fastify
if (this.sent && this[kReplyHijacked]) {
throw new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method)
}
this[kReplyHijacked] = true
}
},
statusCode: {
get () {
return this.raw.statusCode
},
set (value) {
this.code(value)
}
},
[kPublicRouteContext]: {
get () {
return this.request[kPublicRouteContext]
}
}
})
Reply.prototype.hijack = function () {
this[kReplyHijacked] = true
return this
}
Reply.prototype.send = function (payload) {
if (this[kReplyIsRunningOnErrorHook] === true) {
throw new FST_ERR_SEND_INSIDE_ONERR()
}
if (this.sent) {
this.log.warn({ err: new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method) })
return this
}
if (payload instanceof Error || this[kReplyIsError] === true) {
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 === false) {
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 === false && 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
} else {
payload = this[kReplySerializer](payload)
}
// The indexOf below also matches custom json mimetypes such as 'application/hal+json' or 'application/ld+json'
} else if (hasContentType === false || contentType.indexOf('json') > -1) {
if (hasContentType === false) {
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.JSON
} else {
// If user doesn't set charset, we will set charset to utf-8
if (contentType.indexOf('charset') === -1) {
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 res = this.raw
let value = this[kReplyHeaders][key]
if (value === undefined && res.hasHeader(key)) {
value = res.getHeader(key)
}
return value
}
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)
/* eslint-disable no-var */
for (var 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 intValue = Number(code)
if (isNaN(intValue) || intValue < 100 || intValue > 599) {
throw new FST_ERR_BAD_STATUS_CODE(code || String(code))
}
this.raw.statusCode = intValue
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 (typeof url === 'number') {
FSTDEP021()
const temp = code
code = url
url = temp
}
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
}
// TODO: should be removed in fastify@5
Reply.prototype.getResponseTime = function () {
FSTDEP020()
return this.elapsedTime
}
// 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()
}
})
}
function preSerializationHook (reply, payload) {
if (reply[kRouteContext].preSerialization !== null) {
preSerializationHookRunner(
reply[kRouteContext].preSerialization,
reply.request,
reply,
payload,
preSerializationHookEnd
)
} else {
preSerializationHookEnd(null, reply.request, 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) {
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)
} else if (result !== null && result !== undefined) {
// TODO: should be removed in fastify@5
FSTDEP013()
cb(null, result)
}
}
// 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
// eslint-disable-next-line no-var
var prop
// eslint-disable-next-line no-var
for (var 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

52
backend/node_modules/fastify/lib/reqIdGenFactory.js generated vendored Normal file
View File

@@ -0,0 +1,52 @@
'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
}

366
backend/node_modules/fastify/lib/request.js generated vendored Normal file
View File

@@ -0,0 +1,366 @@
'use strict'
const proxyAddr = require('proxy-addr')
const semver = require('semver')
const {
FSTDEP005,
FSTDEP012,
FSTDEP015,
FSTDEP016,
FSTDEP017,
FSTDEP018
} = require('./warnings')
const {
kHasBeenDecorated,
kSchemaBody,
kSchemaHeaders,
kSchemaParams,
kSchemaQuerystring,
kSchemaController,
kOptions,
kRequestCacheValidateFns,
kRouteContext,
kPublicRouteContext,
kRequestOriginalUrl
} = require('./symbols')
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION } = require('./errors')
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 plain true/false
return function () { return true }
}
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
// eslint-disable-next-line no-var
var prop
// eslint-disable-next-line no-var
for (var 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 () {
return proxyAddr(this.raw, proxyFn)
}
},
ips: {
get () {
return proxyAddr.all(this.raw, proxyFn)
}
},
hostname: {
get () {
if (this.ip !== undefined && this.headers['x-forwarded-host']) {
return getLastEntryInMultiHeaderValue(this.headers['x-forwarded-host'])
}
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
}
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
}
},
context: {
get () {
FSTDEP012()
return this[kRouteContext]
}
},
routerPath: {
get () {
FSTDEP017()
return this[kRouteContext].config?.url
}
},
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,
version
}
Object.defineProperties(options, {
config: {
get: () => context.config
},
schema: {
get: () => context.schema
}
})
return Object.freeze(options)
}
},
routerMethod: {
get () {
FSTDEP018()
return this[kRouteContext].config?.method
}
},
routeConfig: {
get () {
FSTDEP016()
return this[kRouteContext][kPublicRouteContext]?.config
}
},
routeSchema: {
get () {
FSTDEP015()
return this[kRouteContext][kPublicRouteContext].schema
}
},
is404: {
get () {
return this[kRouteContext].config?.url === undefined
}
},
connection: {
get () {
/* istanbul ignore next */
if (semver.gte(process.versions.node, '13.0.0')) {
FSTDEP005()
}
return this.raw.connection
}
},
socket: {
get () {
return this.raw.socket
}
},
ip: {
get () {
if (this.socket) {
return this.socket.remoteAddress
}
}
},
hostname: {
get () {
return this.raw.headers.host || this.raw.headers[':authority']
}
},
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)
}
}
})
module.exports = Request
module.exports.buildRequest = buildRequest

628
backend/node_modules/fastify/lib/route.js generated vendored Normal file
View File

@@ -0,0 +1,628 @@
'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 { supportedMethods } = require('./httpMethods')
const { normalizeSchema } = require('./schemas')
const { parseHeadOnSendHandlers } = require('./headRoute')
const {
FSTDEP007,
FSTDEP008,
FSTDEP014
} = require('./warnings')
const {
compileSchemasForValidation,
compileSchemasForSerialization
} = require('./validation')
const {
FST_ERR_SCH_VALIDATION_BUILD,
FST_ERR_SCH_SERIALIZATION_BUILD,
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE,
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 {
kRoutePrefix,
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')
const { getGenReqId } = require('./reqIdGenFactory.js')
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 validateHTTPVersion
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
validateHTTPVersion = fastifyArgs.validateHTTPVersion
globalExposeHeadRoutes = options.exposeHeadRoutes
disableRequestLogging = options.disableRequestLogging
ignoreTrailingSlash = options.ignoreTrailingSlash
ignoreDuplicateSlashes = options.ignoreDuplicateSlashes
return503OnClosing = Object.prototype.hasOwnProperty.call(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,
getDefaultRoute: function () {
FSTDEP014()
return router.defaultRoute
},
setDefaultRoute: function (defaultRoute) {
FSTDEP014()
if (typeof defaultRoute !== 'function') {
throw new FST_ERR_DEFAULT_ROUTE_INVALID_TYPE()
}
router.defaultRoute = defaultRoute
},
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 findRoute({
...options,
method: normalizedMethod
}) !== null
}
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 }) {
// 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 { exposeHeadRoute } = opts
const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null
const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes
const isGetRoute = opts.method === 'GET' ||
(Array.isArray(opts.method) && opts.method.includes('GET'))
const isHeadRoute = opts.method === 'HEAD' ||
(Array.isArray(opts.method) && opts.method.includes('HEAD'))
// we need to clone a set of initial options for HEAD route
const headOpts = shouldExposeHead && isGetRoute ? { ...options } : null
throwIfAlreadyStarted('Cannot add route!')
const path = opts.url || opts.path || ''
if (Array.isArray(opts.method)) {
// eslint-disable-next-line no-var
for (var i = 0; i < opts.method.length; ++i) {
opts.method[i] = normalizeAndValidateMethod(opts.method[i])
validateSchemaBodyOption(opts.method[i], path, opts.schema)
}
} else {
opts.method = normalizeAndValidateMethod(opts.method)
validateSchemaBodyOption(opts.method, path, opts.schema)
}
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 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
})
if (opts.version) {
FSTDEP008()
constraints.version = opts.version
}
const headHandler = router.findRoute('HEAD', opts.url, constraints)
const hasHEADHandler = headHandler !== null
// remove the head route created by fastify
if (isHeadRoute && hasHEADHandler && !context[kRouteByFastify] && headHandler.store[kRouteByFastify]) {
router.off('HEAD', opts.url, constraints)
}
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(opts, 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 })
} else if (hasHEADHandler && exposeHeadRoute) {
FSTDEP007()
}
}
}
// 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
// TODO: The check here should be removed once https://github.com/nodejs/node/issues/43115 resolve in core.
if (!validateHTTPVersion(req.httpVersion)) {
childLogger.info({ res: { statusCode: 505 } }, 'request aborted - invalid HTTP version')
const message = '{"error":"HTTP Version Not Supported","message":"HTTP Version Not Supported","statusCode":505}'
const headers = {
'Content-Type': 'application/json',
'Content-Length': message.length
}
res.writeHead(505, headers)
res.end(message)
return
}
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 (supportedMethods.indexOf(method) === -1) {
throw new FST_ERR_ROUTE_METHOD_NOT_SUPPORTED(method)
}
return method
}
function validateSchemaBodyOption (method, path, schema) {
if ((method === 'GET' || method === 'HEAD') && schema && 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)
} else {
handleRequest(null, request, reply)
}
}
/**
* 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 }

164
backend/node_modules/fastify/lib/schema-controller.js generated vendored Normal file
View File

@@ -0,0 +1,164 @@
'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

219
backend/node_modules/fastify/lib/schemas.js generated vendored Normal file
View File

@@ -0,0 +1,219 @@
'use strict'
const fastClone = require('rfdc')({ circles: false, proto: true })
const { kSchemaVisited, kSchemaResponse } = require('./symbols')
const kFluentSchema = Symbol.for('fluent-schema-object')
const {
FSTDEP022
} = require('./warnings')
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 (opts, 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)
}
routeSchemas.body.content[contentType].schema = getSchemaAnyway(opts.url, contentSchema, serverOptions.jsonShorthand)
}
continue
}
routeSchemas[key] = getSchemaAnyway(opts.url, schema, serverOptions.jsonShorthand)
}
}
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
let hasContentMultipleContentTypes = false
if (contentProperty) {
const keys = Object.keys(contentProperty)
for (let i = 0; i < keys.length; i++) {
const mediaName = keys[i]
if (!contentProperty[mediaName].schema) {
if (keys.length === 1) { break }
throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(mediaName)
}
routeSchemas.response[code].content[mediaName].schema = getSchemaAnyway(opts.url, contentProperty[mediaName].schema, serverOptions.jsonShorthand)
if (i === keys.length - 1) {
hasContentMultipleContentTypes = true
}
}
}
if (!hasContentMultipleContentTypes) {
routeSchemas.response[code] = getSchemaAnyway(opts.url, routeSchemas.response[code], serverOptions.jsonShorthand)
}
}
}
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()
}
}
}
}
function getSchemaAnyway (url, schema, jsonShorthand) {
if (!jsonShorthand || schema.$ref || schema.oneOf || schema.allOf || schema.anyOf || schema.$merge || schema.$patch) return schema
if (!schema.type && !schema.properties) {
FSTDEP022(url)
return {
type: 'object',
properties: schema
}
}
return schema
}
/**
* 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]
}
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]
}
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]
}
return false
}
return responseSchemaDef.default
}
return false
}
module.exports = {
buildSchemas (initStore) { return new Schemas(initStore) },
getSchemaSerializer,
normalizeSchema
}

447
backend/node_modules/fastify/lib/server.js generated vendored Normal file
View File

@@ -0,0 +1,447 @@
'use strict'
const http = require('node:http')
const https = require('node:https')
const dns = require('node:dns')
const { FSTDEP011 } = require('./warnings')
const { kState, kOptions, kServerBindings } = require('./symbols')
const { onListenHookRunner } = require('./hooks')
const {
FST_ERR_HTTP2_INVALID_VERSION,
FST_ERR_REOPENED_CLOSE_SERVER,
FST_ERR_REOPENED_SERVER,
FST_ERR_LISTEN_OPTIONS_INVALID
} = require('./errors')
module.exports.createServer = createServer
module.exports.compileValidateHTTPVersion = compileValidateHTTPVersion
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, ...args) {
let cb = args.slice(-1).pop()
// When the variadic signature deprecation is complete, the function
// declaration should become:
// function listen (listenOptions = { port: 0, host: 'localhost' }, cb = undefined)
// Upon doing so, the `normalizeListenArgs` function is no longer needed,
// and all of this preamble to feed it correctly also no longer needed.
const firstArgType = Object.prototype.toString.call(arguments[0])
if (arguments.length === 0) {
listenOptions = normalizeListenArgs([])
} else if (arguments.length > 0 && (firstArgType !== '[object Object]' && firstArgType !== '[object Function]')) {
FSTDEP011()
listenOptions = normalizeListenArgs(Array.from(arguments))
cb = listenOptions.cb
} else if (args.length > 1) {
// `.listen(obj, a, ..., n, callback )`
FSTDEP011()
// Deal with `.listen(port, host, backlog, [cb])`
const hostPath = listenOptions.path ? [listenOptions.path] : [listenOptions.port ?? 0, listenOptions.host ?? 'localhost']
Object.assign(listenOptions, normalizeListenArgs([...hostPath, ...args]))
} else {
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')
}
if (listenOptions.signal.aborted) {
this.close()
} else {
const onAborted = () => {
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.prototype.hasOwnProperty.call(listenOptions, 'host') === false ||
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)
/* istanbul ignore else */
return listening.then(address => {
return new Promise((resolve, reject) => {
if (host === 'localhost') {
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
this[kState].listening = true
resolve(address)
onListenHookRunner(this)
})
} else {
resolve(address)
onListenHookRunner(this)
}
})
})
}
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) {
// 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++
/* istanbul ignore next: the else won't be taken unless listening fails */
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 fall 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 (serverOpts.forceCloseConnections === 'idle') {
// Not needed in Node 19
secondaryServer.closeIdleConnections()
} else if (typeof secondaryServer.closeAllConnections === 'function' && serverOpts.forceCloseConnections) {
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
/* c8 ignore next 4 */
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)
} else 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())
} else if (this[kState].listening) {
return Promise.reject(new FST_ERR_REOPENED_SERVER())
}
return this.ready().then(() => {
let errEventHandler
let listeningEventHandler
function cleanup () {
server.removeListener('error', errEventHandler)
server.removeListener('listening', listeningEventHandler)
}
const errEvent = new Promise((resolve, reject) => {
errEventHandler = (err) => {
cleanup()
this[kState].listening = false
reject(err)
}
server.once('error', errEventHandler)
})
const listeningEvent = new Promise((resolve, reject) => {
listeningEventHandler = () => {
cleanup()
this[kState].listening = true
resolve(logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText))
}
server.once('listening', listeningEventHandler)
})
server.listen(listenOptions)
return Promise.race([
errEvent, // e.g invalid port range error is always emitted before the server listening
listeningEvent
])
})
}
/**
* Creates a function that, based upon initial configuration, will
* verify that every incoming request conforms to allowed
* HTTP versions for the Fastify instance, e.g. a Fastify HTTP/1.1
* server will not serve HTTP/2 requests upon the result of the
* verification function.
*
* @param {object} options fastify option
* @param {function} [options.serverFactory] If present, the
* validator function will skip all checks.
* @param {boolean} [options.http2 = false] If true, the validator
* function will allow HTTP/2 requests.
* @param {object} [options.https = null] https server options
* @param {boolean} [options.https.allowHTTP1] If true and use
* with options.http2 the validator function will allow HTTP/1
* request to http2 server.
*
* @returns {function} HTTP version validator function.
*/
function compileValidateHTTPVersion (options) {
let bypass = false
// key-value map to store valid http version
const map = new Map()
if (options.serverFactory) {
// When serverFactory is passed, we cannot identify how to check http version reliably
// So, we should skip the http version check
bypass = true
}
if (options.http2) {
// HTTP2 must serve HTTP/2.0
map.set('2.0', true)
if (options.https && options.https.allowHTTP1 === true) {
// HTTP2 with HTTPS.allowHTTP1 allow fallback to HTTP/1.1 and HTTP/1.0
map.set('1.1', true)
map.set('1.0', true)
}
} else {
// HTTP must server HTTP/1.1 and HTTP/1.0
map.set('1.1', true)
map.set('1.0', true)
}
// The compiled function here placed in one of the hottest path inside fastify
// the implementation here must be as performant as possible
return function validateHTTPVersion (httpVersion) {
// `bypass` skip the check when custom server factory provided
// `httpVersion in obj` check for the valid http version we should support
return bypass || map.has(httpVersion)
}
}
function getServerInstance (options, httpHandler) {
let server = null
// node@20 do not accepts options as boolean
// we need to provide proper https option
const httpsOptions = options.https === true ? {} : options.https
if (options.serverFactory) {
server = options.serverFactory(httpHandler, options)
} else if (options.http2) {
if (typeof httpsOptions === 'object') {
server = http2().createSecureServer(httpsOptions, httpHandler)
} else {
server = http2().createServer(httpHandler)
}
server.on('session', sessionTimeout(options.http2SessionTimeout))
} else {
// this is http1
if (httpsOptions) {
server = https.createServer(httpsOptions, httpHandler)
} else {
server = http.createServer(options.http, httpHandler)
}
server.keepAliveTimeout = options.keepAliveTimeout
server.requestTimeout = options.requestTimeout
// we treat zero as null
// and null is the default setting from nodejs
// so we do not pass the option to server
if (options.maxRequestsPerSocket > 0) {
server.maxRequestsPerSocket = options.maxRequestsPerSocket
}
}
if (!options.serverFactory) {
server.setTimeout(options.connectionTimeout)
}
return server
}
function normalizeListenArgs (args) {
if (args.length === 0) {
return { port: 0, host: 'localhost' }
}
const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
const options = { cb }
const firstArg = args[0]
const argsLength = args.length
const lastArg = args[argsLength - 1]
if (typeof firstArg === 'string' && isNaN(firstArg)) {
/* Deal with listen (pipe[, backlog]) */
options.path = firstArg
options.backlog = argsLength > 1 ? lastArg : undefined
} else {
/* Deal with listen ([port[, host[, backlog]]]) */
options.port = argsLength >= 1 && Number.isInteger(firstArg) ? firstArg : normalizePort(firstArg)
// This will listen to what localhost is.
// It can be 127.0.0.1 or ::1, depending on the operating system.
// Fixes https://github.com/fastify/fastify/issues/1022.
options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
options.backlog = argsLength >= 3 ? args[2] : undefined
}
return options
}
function normalizePort (firstArg) {
const port = Number(firstArg)
return port >= 0 && !Number.isNaN(port) && Number.isInteger(port) ? port : 0
}
function logServerAddress (server, listenTextResolver) {
let address = server.address()
const isUnixSocket = typeof address === 'string'
/* istanbul ignore next */
if (!isUnixSocket) {
if (address.address.indexOf(':') === -1) {
address = address.address + ':' + address.port
} else {
address = '[' + address.address + ']:' + address.port
}
}
/* istanbul ignore next */
address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
const serverListeningText = listenTextResolver(address)
this.log.info(serverListeningText)
return address
}
function http2 () {
try {
return require('node:http2')
} catch (err) {
throw new FST_ERR_HTTP2_INVALID_VERSION()
}
}
function sessionTimeout (timeout) {
return function (session) {
session.setTimeout(timeout, close)
}
}
function close () {
this.close()
}

65
backend/node_modules/fastify/lib/symbols.js generated vendored Normal file
View File

@@ -0,0 +1,65 @@
'use strict'
const keys = {
kAvvioBoot: Symbol('fastify.avvioBoot'),
kChildren: Symbol('fastify.children'),
kServerBindings: Symbol('fastify.serverBindings'),
kBodyLimit: Symbol('fastify.bodyLimit'),
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'),
kPublicRouteContext: Symbol('fastify.routeOptions'),
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'),
kChildLoggerFactory: Symbol('fastify.childLoggerFactory'),
kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'),
kKeepAliveConnections: Symbol('fastify.keepAliveConnections'),
kRouteByFastify: Symbol('fastify.routeByFastify')
}
module.exports = keys

272
backend/node_modules/fastify/lib/validation.js generated vendored Normal file
View File

@@ -0,0 +1,272 @@
'use strict'
const {
kSchemaHeaders: headersSchema,
kSchemaParams: paramsSchema,
kSchemaQuerystring: querystringSchema,
kSchemaBody: bodySchema,
kSchemaResponse: responseSchema
} = require('./symbols')
const scChecker = /^[1-5]{1}[0-9]{2}$|^[1-5]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.exec(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.prototype.hasOwnProperty.call(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.prototype.hasOwnProperty.call(schema, 'body')) {
FSTWRN001('body', method, url)
}
if (schema.querystring) {
context[querystringSchema] = compile({ schema: schema.querystring, method, url, httpPart: 'querystring' })
} else if (Object.prototype.hasOwnProperty.call(schema, 'querystring')) {
FSTWRN001('querystring', method, url)
}
if (schema.params) {
context[paramsSchema] = compile({ schema: schema.params, method, url, httpPart: 'params' })
} else if (Object.prototype.hasOwnProperty.call(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?.then) {
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
}

130
backend/node_modules/fastify/lib/warnings.js generated vendored Normal file
View File

@@ -0,0 +1,130 @@
'use strict'
const { createDeprecation, createWarning } = require('process-warning')
const FSTDEP005 = createDeprecation({
code: 'FSTDEP005',
message: 'You are accessing the deprecated "request.connection" property. Use "request.socket" instead.'
})
const FSTDEP006 = createDeprecation({
code: 'FSTDEP006',
message: 'You are decorating Request/Reply with a reference type. This reference is shared amongst all requests. Use onRequest hook instead. Property: %s'
})
const FSTDEP007 = createDeprecation({
code: 'FSTDEP007',
message: 'You are trying to set a HEAD route using "exposeHeadRoute" route flag when a sibling route is already set. See documentation for more info.'
})
const FSTDEP008 = createDeprecation({
code: 'FSTDEP008',
message: 'You are using route constraints via the route { version: "..." } option, use { constraints: { version: "..." } } option instead.'
})
const FSTDEP009 = createDeprecation({
code: 'FSTDEP009',
message: 'You are using a custom route versioning strategy via the server { versioning: "..." } option, use { constraints: { version: "..." } } option instead.'
})
const FSTDEP010 = createDeprecation({
code: 'FSTDEP010',
message: 'Modifying the "reply.sent" property is deprecated. Use the "reply.hijack()" method instead.'
})
const FSTDEP011 = createDeprecation({
code: 'FSTDEP011',
message: 'Variadic listen method is deprecated. Please use ".listen(optionsObject)" instead. The variadic signature will be removed in `fastify@5`.'
})
const FSTDEP012 = createDeprecation({
code: 'FSTDEP012',
message: 'request.context property access is deprecated. Please use "request.routeOptions.config" or "request.routeOptions.schema" instead for accessing Route settings. The "request.context" will be removed in `fastify@5`.'
})
const FSTDEP013 = createDeprecation({
code: 'FSTDEP013',
message: 'Direct return of "trailers" function is deprecated. Please use "callback" or "async-await" for return value. The support of direct return will removed in `fastify@5`.'
})
const FSTDEP014 = createDeprecation({
code: 'FSTDEP014',
message: 'You are trying to set/access the default route. This property is deprecated. Please, use setNotFoundHandler if you want to custom a 404 handler or the wildcard (*) to match all routes.'
})
const FSTDEP015 = createDeprecation({
code: 'FSTDEP015',
message: 'You are accessing the deprecated "request.routeSchema" property. Use "request.routeOptions.schema" instead. Property "req.routeSchema" will be removed in `fastify@5`.'
})
const FSTDEP016 = createDeprecation({
code: 'FSTDEP016',
message: 'You are accessing the deprecated "request.routeConfig" property. Use "request.routeOptions.config" instead. Property "req.routeConfig" will be removed in `fastify@5`.'
})
const FSTDEP017 = createDeprecation({
code: 'FSTDEP017',
message: 'You are accessing the deprecated "request.routerPath" property. Use "request.routeOptions.url" instead. Property "req.routerPath" will be removed in `fastify@5`.'
})
const FSTDEP018 = createDeprecation({
code: 'FSTDEP018',
message: 'You are accessing the deprecated "request.routerMethod" property. Use "request.routeOptions.method" instead. Property "req.routerMethod" will be removed in `fastify@5`.'
})
const FSTDEP019 = createDeprecation({
code: 'FSTDEP019',
message: 'reply.context property access is deprecated. Please use "request.routeOptions.config" or "request.routeOptions.schema" instead for accessing Route settings. The "reply.context" will be removed in `fastify@5`.'
})
const FSTDEP020 = createDeprecation({
code: 'FSTDEP020',
message: 'You are using the deprecated "reply.getResponseTime()" method. Use the "reply.elapsedTime" property instead. Method "reply.getResponseTime()" will be removed in `fastify@5`.'
})
const FSTDEP021 = createDeprecation({
code: 'FSTDEP021',
message: 'The `reply.redirect()` method has a new signature: `reply.redirect(url: string, code?: number)`. It will be enforced in `fastify@v5`'
})
const FSTDEP022 = createDeprecation({
code: 'FSTDEP021',
message: 'You are using the deprecated json shorthand schema on route %s. Specify full object schema instead. It will be removed in `fastify@v5`'
})
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 FSTWRN002 = createWarning({
name: 'FastifyWarning',
code: 'FSTWRN002',
message: 'The %s plugin being registered mixes async and callback styles, which will result in an error in `fastify@5`',
unlimited: true
})
module.exports = {
FSTDEP005,
FSTDEP006,
FSTDEP007,
FSTDEP008,
FSTDEP009,
FSTDEP010,
FSTDEP011,
FSTDEP012,
FSTDEP013,
FSTDEP014,
FSTDEP015,
FSTDEP016,
FSTDEP017,
FSTDEP018,
FSTDEP019,
FSTDEP020,
FSTDEP021,
FSTDEP022,
FSTWRN001,
FSTWRN002
}

50
backend/node_modules/fastify/lib/wrapThenable.js generated vendored Normal file
View File

@@ -0,0 +1,50 @@
'use strict'
const {
kReplyIsError,
kReplyHijacked
} = require('./symbols')
function wrapThenable (thenable, reply) {
thenable.then(function (payload) {
if (reply[kReplyHijacked] === true) {
return
}
// 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)) {
// 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)
}
}
}, function (err) {
if (reply.sent === true) {
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
return
}
reply[kReplyIsError] = true
// try-catch allow to re-throw error in error handler for async handler
try {
reply.send(err)
// The following should not happen
/* c8 ignore next 3 */
} catch (err) {
reply.send(err)
}
})
}
module.exports = wrapThenable