{"version":3,"sources":["../../../../../src/server/adapters/express/index.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../../instance'\nimport { configurable, getMediaDuration } from '../../../utilities'\nimport { Request, Response } from '../../requests'\nimport { StatusCodes, type IncomingFile, type MethodsEnum } from '../../types'\nimport { type RawResponder, Server, serverConfigPipe } from '../base'\n\nexport class ExpressServer extends configurable(serverConfigPipe, Server) {\n\t#app: express.Express\n\t#httpServer: http.Server\n\n\tprotected constructor(config: typeof ExpressServer.Config) {\n\t\tsuper(config)\n\t\tconst app = express()\n\t\tconst instance = Instance.get()\n\t\tconst httpServer = http.createServer(app)\n\t\tthis.#app = app\n\t\tthis.#httpServer = httpServer\n\n\t\tthis.setup(httpServer, config)\n\n\t\tapp.disable('x-powered-by')\n\t\tif (config.requests.log) app.use(pinoHttp({ logger: instance.log }))\n\t\tapp.use(express.json())\n\t\tapp.use(express.text())\n\t\tapp.use(cookie())\n\t\tapp.use(\n\t\t\thelmet({\n\t\t\t\tcrossOriginResourcePolicy: { policy: 'cross-origin' },\n\t\t\t\tcontentSecurityPolicy: false,\n\t\t\t}),\n\t\t)\n\t\tapp.use(cors(this.cors))\n\t\tapp.use(express.urlencoded({ extended: false }))\n\t\tif (config.publicPath) app.use(express.static(config.publicPath))\n\t\tapp.use(\n\t\t\tfileUpload({\n\t\t\t\tlimits: { fileSize: instance.settings.utils.maxFileUploadSizeInMb * 1024 * 1024 },\n\t\t\t\tuseTempFiles: false,\n\t\t\t}),\n\t\t)\n\t\tif (config.requests.rateLimit.enabled)\n\t\t\tapp.use(\n\t\t\t\trateLimit({\n\t\t\t\t\twindowMs: config.requests.rateLimit.periodInMs,\n\t\t\t\t\tlimit: config.requests.rateLimit.limit,\n\t\t\t\t\thandler: (_: express.Request, res: express.Response) =>\n\t\t\t\t\t\tres.status(StatusCodes.TooManyRequests).json([{ message: 'Too Many Requests' }]),\n\t\t\t\t}),\n\t\t\t)\n\t\t/* if (this.settings.slowdown.enabled) app.use(slowDown({\n\t\t\t\twindowMs: this.settings.slowdown.periodInMs,\n\t\t\t\tdelayAfter: this.settings.slowdown.delayAfter,\n\t\t\t\tdelayMs: this.settings.slowdown.delayInMs\n\t\t\t})) */\n\t}\n\n\tprotected async parseRequest(req: any) {\n\t\tconst files = Object.fromEntries(\n\t\t\tawait Promise.all(\n\t\t\t\tObject.entries(req.files ?? {}).map(async ([key, file]) => {\n\t\t\t\t\tconst uploads = Array.isArray(file) ? file : [file]\n\t\t\t\t\tconst fileArray: IncomingFile[] = await Promise.all(\n\t\t\t\t\t\tuploads.map(async (f: any) => ({\n\t\t\t\t\t\t\tname: f.name,\n\t\t\t\t\t\t\ttype: f.mimetype,\n\t\t\t\t\t\t\tsize: f.size,\n\t\t\t\t\t\t\tisTruncated: f.truncated,\n\t\t\t\t\t\t\tdata: f.data,\n\t\t\t\t\t\t\tduration: await getMediaDuration(f.data),\n\t\t\t\t\t\t})),\n\t\t\t\t\t)\n\t\t\t\t\treturn <const>[key, fileArray]\n\t\t\t\t}),\n\t\t\t),\n\t\t)\n\n\t\treturn new Request<any>({\n\t\t\tip: req.ip,\n\t\t\tbody: req.body ?? {},\n\t\t\tcookies: req.cookies ?? {},\n\t\t\tparams: req.params ?? {},\n\t\t\tquery: req.query ?? {},\n\t\t\tmethod: <any>req.method,\n\t\t\tpath: req.path,\n\t\t\theaders: req.headers,\n\t\t\tfiles,\n\t\t})\n\t}\n\n\tprotected async handleResponse(res: any, response: Response<any>) {\n\t\tif (!response.piped) {\n\t\t\tObject.entries(response.headers).forEach(([key, value]) => res.header(key, value as string))\n\t\t\tObject.entries(response.cookies).forEach(([key, { value, ...opts }]) => res.cookie(key, value, opts))\n\t\t\tconst type = response.body === null || response.body === undefined ? 'json' : 'send'\n\t\t\tres.status(response.status)[type](response.body).end()\n\t\t} else {\n\t\t\tresponse.body.pipe(res)\n\t\t}\n\t}\n\n\tprotected createRawResponder(req: express.Request, res: express.Response): RawResponder {\n\t\treturn this.createNodeRawResponder({ request: req, response: res })\n\t}\n\n\tprotected registerRoute(method: MethodsEnum, path: string, cb: (req: any, res: any) => Promise<void>) {\n\t\tthis.#app[method]?.(path, async (req: any, res: any) => cb(req, res))\n\t}\n\n\tprotected registerErrorHandler(cb: (error: Error, req: any, res: any) => Promise<void>) {\n\t\tthis.#app.use(async (err: any, req: any, res: any, _next: any) => cb(err, req, res))\n\t}\n\n\tprotected registerNotFoundHandler(cb: (req: any, res: any) => Promise<void>) {\n\t\tthis.#app.use(async (req: any, res: any, _next: any) => cb(req, res))\n\t}\n\n\tprotected startServer(port: number) {\n\t\treturn new Promise<boolean>((resolve: (s: boolean) => void, reject: (e: Error) => void) => {\n\t\t\ttry {\n\t\t\t\tconst server = this.#httpServer.listen({ host: '0.0.0.0', port }, async () => resolve(true))\n\t\t\t\tInstance.on('close', server.close)\n\t\t\t} catch (err) {\n\t\t\t\treject(<Error>err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, expect, test, vi } = import.meta.vitest\n\n\tconst testInstanceState = globalThis as typeof globalThis & { __equippedTestInstanceAliased?: boolean }\n\n\tfunction ensureTestInstance() {\n\t\tconst instance = Instance.maybeGet() ?? Instance.create({ app: { name: 'equipped-test' }, log: { level: 'silent' } })\n\t\tif (!testInstanceState.__equippedTestInstanceAliased) {\n\t\t\tinstance.alias('equipped-test')\n\t\t\ttestInstanceState.__equippedTestInstanceAliased = true\n\t\t}\n\t}\n\n\tfunction createExpressResponse() {\n\t\treturn {\n\t\t\tstatusCode: 200,\n\t\t\theadersSent: false,\n\t\t\twritableEnded: false,\n\t\t\tsetHeader: vi.fn(),\n\t\t\tend(chunk?: unknown) {\n\t\t\t\tvoid chunk\n\t\t\t\tthis.headersSent = true\n\t\t\t\tthis.writableEnded = true\n\t\t\t},\n\t\t}\n\t}\n\n\tclass TestExpressServer extends ExpressServer {\n\t\texposeRawResponder(req: express.Request, res: express.Response) {\n\t\t\treturn this.createRawResponder(req, res)\n\t\t}\n\t}\n\n\tdescribe('ExpressServer raw responder', () => {\n\t\ttest('passes the Express request and response to the raw Node handler', async () => {\n\t\t\tensureTestInstance()\n\t\t\tconst server = TestExpressServer.create({ port: 0, requests: { log: false } })\n\t\t\tconst req = { marker: 'request' } as unknown as express.Request\n\t\t\tconst res = createExpressResponse() as unknown as express.Response\n\t\t\tlet received: { request: unknown; response: unknown } | null = null\n\n\t\t\tawait server.exposeRawResponder(\n\t\t\t\treq,\n\t\t\t\tres,\n\t\t\t)(async (request, response) => {\n\t\t\t\treceived = { request, response }\n\t\t\t\tresponse.end('ok')\n\t\t\t})\n\n\t\t\texpect(received).toEqual({ request: req, response: res })\n\t\t})\n\t})\n}\n"],"mappings":"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","names":["ensureTestInstance","createExpressResponse"]}