{"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":["fastifyCookie","fastifyCors","fastifyFormBody","fastifyHelmet","fastifyMultipart","fastifyRateLimit","fastifyStatic","Fastify","qs","ValidationError","Instance","getMediaDuration","Request","StatusCodes","Server","FastifyServer","config","instance","app","errors","data","error","req","body","files","excludeBufferKeys","res","response","key","value","opts","method","path","cb","inst","port","str","f","buffer","parsed","_","context","entries","isFile","val","fileEntries","nonFileEntries"]}