{"version":3,"sources":["../../../../src/server/impls/fastify.ts"],"sourcesContent":["import fastifyCookie from '@fastify/cookie'\nimport fastifyCors from '@fastify/cors'\nimport fastifyFormBody from '@fastify/formbody'\nimport fastifyHelmet from '@fastify/helmet'\nimport fastifyMultipart from '@fastify/multipart'\nimport fastifyRateLimit from '@fastify/rate-limit'\nimport fastifyStatic from '@fastify/static'\nimport type { FastifyReply, FastifyRequest } from 'fastify'\nimport Fastify from 'fastify'\n// import fastifySlowDown from 'fastify-slow-down'\nimport qs from 'qs'\n\nimport { ValidationError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class FastifyServer extends Server<FastifyRequest, FastifyReply> {\n\tconstructor(config: ServerConfig) {\n\t\tconst instance = Instance.get()\n\t\tconst app = Fastify({\n\t\t\tdisableRequestLogging: !config.requests.log,\n\t\t\tloggerInstance: config.requests.log ? instance.log : undefined,\n\t\t\tajv: { customOptions: { coerceTypes: false } },\n\t\t\trouterOptions: {\n\t\t\t\tignoreTrailingSlash: true,\n\t\t\t\tcaseSensitive: false,\n\t\t\t},\n\t\t\tschemaErrorFormatter: (errors, data) =>\n\t\t\t\tnew ValidationError(\n\t\t\t\t\terrors.map((error) => ({\n\t\t\t\t\t\tmessages: [error.message ?? ''],\n\t\t\t\t\t\tfield: `${data}${error.instancePath}`.replaceAll('/', '.'),\n\t\t\t\t\t})),\n\t\t\t\t),\n\t\t})\n\t\tsuper(app.server, config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst { body, files } = excludeBufferKeys(req.body ?? {})\n\n\t\t\t\treturn new Request({\n\t\t\t\t\tip: req.ip,\n\t\t\t\t\tbody,\n\t\t\t\t\tcookies: req.cookies ?? {},\n\t\t\t\t\tparams: req.params ?? <any>{},\n\t\t\t\t\tquery: req.query ?? {},\n\t\t\t\t\tmethod: <any>req.method,\n\t\t\t\t\tpath: req.url,\n\t\t\t\t\theaders: req.headers,\n\t\t\t\t\tfiles,\n\t\t\t\t})\n\t\t\t},\n\t\t\thandleResponse: async (res, response) => {\n\t\t\t\tfor (const [key, { value, ...opts }] of Object.entries(response.cookies)) res = res.setCookie(key, value, opts)\n\t\t\t\tawait res.status(response.status).headers(response.headers).send(response.body)\n\t\t\t},\n\t\t\tregisterRoute: (method, path, cb) => {\n\t\t\t\tapp.register(async (inst) => {\n\t\t\t\t\tinst.route({ url: path, method, handler: cb })\n\t\t\t\t})\n\t\t\t},\n\t\t\tregisterErrorHandler: (cb) => {\n\t\t\t\tapp.setErrorHandler(cb)\n\t\t\t},\n\t\t\tregisterNotFoundHandler: (cb) => {\n\t\t\t\tapp.setNotFoundHandler(cb)\n\t\t\t},\n\t\t\tstart: async (port) => {\n\t\t\t\tawait app.ready()\n\t\t\t\tawait app.listen({ port, host: '0.0.0.0' })\n\t\t\t\tInstance.on('close', app.close, 1)\n\t\t\t\treturn true\n\t\t\t},\n\t\t})\n\n\t\tapp.decorateRequest('savedReq', null)\n\t\tapp.setValidatorCompiler(() => () => true)\n\t\tapp.setSerializerCompiler(() => (data) => JSON.stringify(data))\n\t\tif (config.publicPath) app.register(fastifyStatic, { root: config.publicPath })\n\t\tapp.register(fastifyCookie, {})\n\t\tapp.register(fastifyCors, this.cors)\n\t\tapp.register(fastifyFormBody, { parser: (str) => qs.parse(str) })\n\t\tapp.register(fastifyHelmet, { crossOriginResourcePolicy: { policy: 'cross-origin' }, contentSecurityPolicy: false })\n\t\tapp.register(fastifyMultipart, {\n\t\t\tattachFieldsToBody: 'keyValues',\n\t\t\tthrowFileSizeLimit: false,\n\t\t\tlimits: { fileSize: instance.settings.utils.maxFileUploadSizeInMb * 1024 * 1024 },\n\t\t\tonFile: async (f) => {\n\t\t\t\tconst buffer = await f.toBuffer()\n\t\t\t\tconst parsed: IncomingFile = {\n\t\t\t\t\tname: f.filename,\n\t\t\t\t\ttype: f.mimetype,\n\t\t\t\t\tsize: buffer.byteLength,\n\t\t\t\t\tisTruncated: f.file.truncated,\n\t\t\t\t\tdata: buffer,\n\t\t\t\t\tduration: await getMediaDuration(buffer),\n\t\t\t\t}\n\t\t\t\t// @ts-ignore\n\t\t\t\tf.value = parsed\n\t\t\t},\n\t\t})\n\t\t/* if (this.settings.slowdown.enabled) app.register(fastifySlowDown, {\n\t\t\ttimeWindow: this.settings.slowdown.periodInMs,\n\t\t\tdelayAfter: this.settings.slowdown.delayAfter,\n\t\t\tdelay: this.settings.slowdown.delayInMs\n\t\t}) */\n\t\tif (config.requests.rateLimit.enabled)\n\t\t\tapp.register(fastifyRateLimit, {\n\t\t\t\tmax: config.requests.rateLimit.limit,\n\t\t\t\ttimeWindow: config.requests.rateLimit.periodInMs,\n\t\t\t\terrorResponseBuilder: (_, context) => ({\n\t\t\t\t\tstatusCode: StatusCodes.TooManyRequests,\n\t\t\t\t\tmessage: JSON.stringify([{ message: `Too Many Requests. Retry in ${context.after}` }]),\n\t\t\t\t}),\n\t\t\t})\n\t}\n}\n\nfunction excludeBufferKeys<T>(body: T) {\n\tif (typeof body !== 'object') return { body, files: {} }\n\tconst entries = Object.entries(body ?? {})\n\tconst isFile = (val: any) => (Array.isArray(val) ? isFile(val.at(0)) : Buffer.isBuffer(val?.data))\n\tconst fileEntries = entries.filter(([_, value]) => isFile(value)).map(([key, value]) => [key, Array.isArray(value) ? value : [value]])\n\tconst nonFileEntries = entries.filter(([_, value]) => !isFile(value))\n\treturn {\n\t\tbody: <T>Object.fromEntries(nonFileEntries),\n\t\tfiles: <Record<string, IncomingFile[]>>Object.fromEntries(fileEntries),\n\t}\n}\n"],"mappings":"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","names":[]}