{"version":3,"file":"application.cjs","sources":["../../../../../packages/engine-http/src/application/application.ts"],"sourcesContent":["import { Key, pathToRegexp } from 'path-to-regexp'\nimport { KoaContext, KoaMiddleware } from './types'\nimport { AuthResult, HttpErrorResponse, HttpResponse } from '../common'\nimport Koa from 'koa'\nimport * as http from 'node:http'\nimport { IncomingMessage, Server, ServerResponse } from 'node:http'\nimport { WebSocket, WebSocketServer } from 'ws'\nimport { FingerCrossedLoggerHandler, Logger } from '@contember/logger'\nimport koaCompress from 'koa-compress'\nimport bodyParser from 'koa-bodyparser'\nimport { ServerConfig } from '../config/config'\nimport corsMiddleware from '@koa/cors'\nimport stream, { Duplex, Readable } from 'node:stream'\nimport { ProjectGroupResolver } from '../projectGroup/ProjectGroupResolver'\nimport { ProjectGroupContainer } from '../projectGroup/ProjectGroupContainer'\nimport { URL } from 'node:url'\n\ntype Route<C> = { match: RequestMatcher; controller: C; module: string }\nexport class Application {\n\n\tprivate middlewares: KoaMiddleware<any>[] = []\n\n\tprivate routes: Route<HttpController>[] = []\n\tprivate internalRoutes: Route<InternalHttpController>[] = []\n\tprivate websocketRoutes: Route<WebSocketController>[] = []\n\n\tprivate suppressAccessLog: boolean | RegExp\n\n\tconstructor(\n\t\tprivate readonly projectGroupResolver: ProjectGroupResolver,\n\t\tprivate readonly serverConfig: ServerConfig,\n\t\tprivate readonly debugMode: boolean,\n\t\tprivate readonly version: string | undefined,\n\t\tprivate readonly logger: Logger,\n\t) {\n\t\tconst suppressAccessLogRaw = serverConfig.http?.suppressAccessLog\n\t\tthis.suppressAccessLog = suppressAccessLogRaw === true ? true : suppressAccessLogRaw ? new RegExp(suppressAccessLogRaw) : false\n\t}\n\n\taddMiddleware(middleware: KoaMiddleware<any>) {\n\t\tthis.middlewares.push(middleware)\n\t}\n\n\tpublic addRoute(module: string, mask: string, controller: HttpController): void {\n\t\tthis.routes.push({\n\t\t\tmodule,\n\t\t\tcontroller,\n\t\t\tmatch: createRequestMatcher(mask),\n\t\t})\n\t}\n\n\tpublic addInternalRoute(module: string, mask: string, controller: InternalHttpController): void {\n\t\tthis.internalRoutes.push({\n\t\t\tmodule,\n\t\t\tcontroller,\n\t\t\tmatch: createRequestMatcher(mask),\n\t\t})\n\t}\n\n\tpublic addWebsocketRoute(module: string, mask: string, controller: WebSocketController): void {\n\t\tthis.websocketRoutes.push({\n\t\t\tmodule,\n\t\t\tcontroller,\n\t\t\tmatch: createRequestMatcher(mask),\n\t\t})\n\t}\n\n\tasync listen(): Promise<RunningApplication> {\n\t\tconst koa = new Koa()\n\t\tconst wss = new WebSocketServer({ noServer: true })\n\t\tfor (const middleware of this.middlewares) {\n\t\t\tkoa.use(middleware)\n\t\t}\n\t\tkoa.use(koaCompress({\n\t\t\tbr: false,\n\t\t}))\n\t\tkoa.use(bodyParser({\n\t\t\tjsonLimit: this.serverConfig.http?.requestBodySize || '1mb',\n\t\t}))\n\t\tkoa.use(corsMiddleware())\n\t\tconst versionMatch = this.version?.match(/^(0\\.\\d+|\\d+)/)\n\t\tconst versionSimplified = versionMatch?.[1] ?? 'unknown'\n\t\tkoa.use(async ctx => {\n\t\t\tctx.response.set('X-Powered-By', `Contember ${versionSimplified}` + (this.debugMode ? '-dev' : ''))\n\t\t\tawait this.handleHttpRequest(ctx)\n\t\t})\n\n\t\tconst server = http.createServer(koa.callback())\n\t\tconst abortController = new AbortController()\n\n\t\tconst wsRequests: (Promise<void>)[] = []\n\t\tserver.on('upgrade', (req, socket, head) => {\n\t\t\t wsRequests.push(this.handleWebsocketRequest(wss, abortController.signal, req, socket, head))\n\t\t})\n\t\tawait new Promise<void>(resolve => {\n\t\t\tserver.listen(this.serverConfig.port, () => resolve())\n\t\t})\n\n\t\treturn {\n\t\t\tserver,\n\t\t\tclose: async () => {\n\t\t\t\tabortController.abort()\n\t\t\t\tawait Promise.all(wsRequests)\n\t\t\t\tawait new Promise(resolve => server.close(resolve))\n\t\t\t},\n\t\t}\n\t}\n\n\tprivate async handleWebsocketRequest(\n\t\twss: WebSocketServer,\n\t\tabortSignal: AbortSignal,\n\t\treq: IncomingMessage,\n\t\tsocket: stream.Duplex,\n\t\thead: Buffer,\n\t): Promise<void> {\n\t\tlet webSocketContext: WebSocketContext | null = null\n\t\tlet requestLogger = this.logger\n\t\tconst { timer, send: sendTimer } = this.createTimer()\n\t\ttry {\n\t\t\tconst url = new URL(req.url ?? '/', `http://${req.headers.host}`)\n\t\t\tconst matchedRequest = this.matchRequest(this.websocketRoutes, url)\n\t\t\tif (!matchedRequest) {\n\t\t\t\tthrow new HttpErrorResponse(404, 'Route not found')\n\t\t\t}\n\t\t\trequestLogger = this.createRequestLogger(req, undefined, matchedRequest.module)\n\n\t\t\tconst groupContainer = await this.projectGroupResolver.resolveContainer({ request: req })\n\n\t\t\trequestLogger = requestLogger.child({\n\t\t\t\tprojectGroup: groupContainer.slug,\n\t\t\t})\n\n\t\t\tconst authResult = await groupContainer.authenticator.authenticate({ request: req, timer })\n\t\t\trequestLogger.debug('User authenticated', { authResult })\n\t\t\trequestLogger = requestLogger.child({\n\t\t\t\tuser: authResult?.identityId,\n\t\t\t})\n\n\t\t\tconst ws = await new Promise<WebSocket>(resolve => wss.handleUpgrade(req, socket, head, (ws, request) => {\n\t\t\t\tresolve(ws)\n\t\t\t}))\n\t\t\tconst wsEstablished = new Date().getTime()\n\t\t\twebSocketContext = {\n\t\t\t\tws,\n\t\t\t\tabortSignal,\n\t\t\t\tlogger: requestLogger,\n\t\t\t\ttimer,\n\t\t\t\turl,\n\t\t\t\trequest: req,\n\t\t\t\tauthResult,\n\t\t\t\tparams: matchedRequest.params,\n\t\t\t\tprojectGroup: groupContainer,\n\t\t\t}\n\t\t\tawait matchedRequest.controller(webSocketContext)\n\t\t\trequestLogger.debug('Websocket connection established')\n\t\t\tws.on('error', e => {\n\t\t\t\trequestLogger.error(e, {\n\t\t\t\t\twebsocketOpenMs: new Date().getTime() - wsEstablished,\n\t\t\t\t})\n\t\t\t})\n\n\t\t\treturn new Promise<void>(resolve => {\n\t\t\t\tws.on('close', () => {\n\t\t\t\t\trequestLogger.debug('Websocket connection closed', {\n\t\t\t\t\t\twebsocketOpenMs: new Date().getTime() - wsEstablished,\n\t\t\t\t\t})\n\t\t\t\t\tresolve()\n\t\t\t\t})\n\t\t\t})\n\t\t} catch (e) {\n\t\t\tif (e instanceof HttpResponse) {\n\t\t\t\tthis.sendRawHttpResponse(socket, e)\n\t\t\t} else {\n\t\t\t\tthis.sendRawHttpResponse(socket, new HttpErrorResponse(500, 'Internal server error'))\n\t\t\t\trequestLogger.error(e)\n\t\t\t}\n\t\t\trequestLogger.debug('Websocket connection failed')\n\t\t} finally {\n\t\t\tsendTimer({\n\t\t\t\treq,\n\t\t\t\trequestDebugMode: false,\n\t\t\t\tlogger: requestLogger,\n\t\t\t})\n\t\t}\n\t}\n\n\tprivate async handleHttpRequest(ctx: KoaContext<{ module?: string; projectGroup?: string; project?: string }>) {\n\t\tconst matchedRequest = this.matchRequest(this.routes, ctx.request.URL)\n\t\tif (!matchedRequest) {\n\t\t\tconst internalMatchedRequest = this.matchRequest(this.internalRoutes, ctx.request.URL)\n\t\t\tif (internalMatchedRequest) {\n\t\t\t\treturn await this.handleInternalRequest(internalMatchedRequest, ctx)\n\t\t\t}\n\t\t}\n\t\tlet httpContext: HttpContext | null = null\n\t\tlet requestLogger = this.createRequestLogger(ctx.req, ctx.request.body, matchedRequest?.module)\n\t\tconst { timer, send: sendTimer } = this.createTimer()\n\n\t\ttry {\n\t\t\tif (!matchedRequest) {\n\t\t\t\treturn this.sendHttpResponse(ctx, new HttpErrorResponse(404, 'Route not found'))\n\t\t\t}\n\t\t\trequestLogger.debug('Request processing started', {\n\t\t\t\tbody: ctx.request.body,\n\t\t\t\tquery: ctx.request.query,\n\t\t\t})\n\n\t\t\t// todo: solve without koa context (required by prom metrics)\n\t\t\tctx.state.module = matchedRequest.module\n\n\t\t\tconst groupContainer = await this.projectGroupResolver.resolveContainer({ request: ctx.req })\n\t\t\trequestLogger = requestLogger.child({\n\t\t\t\tprojectGroup: groupContainer.slug,\n\t\t\t})\n\t\t\tctx.state.projectGroup = groupContainer.slug\n\t\t\tctx.state.project = matchedRequest.params.projectSlug\n\n\t\t\tconst authResult = await groupContainer.authenticator.authenticate({ request: ctx.req, timer })\n\t\t\trequestLogger.debug('User authenticated', { authResult })\n\t\t\trequestLogger = requestLogger.child({\n\t\t\t\tuser: authResult?.identityId,\n\t\t\t})\n\n\n\t\t\tconst response = await requestLogger.scope(async logger => {\n\t\t\t\thttpContext = {\n\t\t\t\t\tkoa: ctx,\n\t\t\t\t\tbody: ctx.request.body,\n\t\t\t\t\turl: ctx.request.URL,\n\t\t\t\t\tlogger,\n\t\t\t\t\ttimer,\n\t\t\t\t\trequest: ctx.req,\n\t\t\t\t\tresponse: ctx.res,\n\t\t\t\t\trequestDebugMode: false,\n\t\t\t\t\tauthResult,\n\t\t\t\t\tparams: matchedRequest.params,\n\t\t\t\t\tprojectGroup: groupContainer,\n\t\t\t\t}\n\t\t\t\treturn await matchedRequest.controller(httpContext)\n\t\t\t})\n\t\t\tif (response) {\n\t\t\t\tthis.sendHttpResponse(ctx, response)\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tif (e instanceof HttpResponse) {\n\t\t\t\tthis.sendHttpResponse(ctx, e)\n\t\t\t} else {\n\t\t\t\tthis.sendHttpResponse(ctx, new HttpErrorResponse(500, 'Internal server error'))\n\t\t\t\trequestLogger.error(e)\n\t\t\t}\n\t\t} finally {\n\t\t\tsendTimer({\n\t\t\t\treq: ctx.req,\n\t\t\t\tresponse: ctx.res,\n\t\t\t\tbody: ctx.response.body,\n\t\t\t\trequestDebugMode: (httpContext as HttpContext | null)?.requestDebugMode ?? false,\n\t\t\t\tlogger: requestLogger,\n\t\t\t})\n\t\t\trequestLogger.debug('Request processing finished')\n\t\t}\n\t}\n\n\n\tprivate async handleInternalRequest(matchedRequest: MatchedRequest<InternalHttpController>, ctx: KoaContext<{ module?: string }>) {\n\t\ttry {\n\t\t\tconst response = await this.logger.scope(async logger => {\n\t\t\t\treturn await matchedRequest.controller({\n\t\t\t\t\tkoa: ctx,\n\t\t\t\t\tbody: ctx.request.body,\n\t\t\t\t\turl: ctx.request.URL,\n\t\t\t\t\tlogger,\n\t\t\t\t\trequest: ctx.req,\n\t\t\t\t\tresponse: ctx.res,\n\t\t\t\t\tparams: matchedRequest.params,\n\t\t\t\t})\n\t\t\t})\n\t\t\tif (response) {\n\t\t\t\tthis.sendHttpResponse(ctx, response)\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tif (e instanceof HttpResponse) {\n\t\t\t\tthis.sendHttpResponse(ctx, e)\n\t\t\t} else {\n\t\t\t\tthis.sendHttpResponse(ctx, new HttpErrorResponse(500, 'Internal server error'))\n\t\t\t\tthis.logger.error(e)\n\t\t\t}\n\t\t}\n\t}\n\n\n\tprivate sendHttpResponse(ctx: KoaContext<{}>, response: HttpResponse) {\n\t\tif (response.contentType) {\n\t\t\tctx.set('Content-type', response.contentType)\n\t\t}\n\t\tctx.status = response.code\n\t\tif (response.body !== undefined) {\n\t\t\tctx.body = response.body\n\t\t}\n\t}\n\n\tprivate sendRawHttpResponse(socket: Duplex, response: HttpResponse) {\n\t\tconst headers: Record<string, string> = {\n\t\t\t'Connection': 'close',\n\t\t\t'Content-Type': response.contentType ?? 'text/plain',\n\t\t\t'Content-Length': String(response.body?.length ?? 0),\n\t\t}\n\n\t\tsocket.once('finish', socket.destroy)\n\n\t\tsocket.end(\n\t\t\t`HTTP/1.1 ${response.code} ${http.STATUS_CODES[response.code]}\\r\\n` +\n\t\t\tObject.keys(headers)\n\t\t\t\t.map(h => `${h}: ${headers[h]}`)\n\t\t\t\t.join('\\r\\n') +\n\t\t\t'\\r\\n\\r\\n' +\n\t\t\t(response.body ?? ''),\n\t\t)\n\t}\n\n\tprivate createRequestLogger(request: IncomingMessage, body: any, module?: string): Logger {\n\t\treturn this.logger.child({\n\t\t\tmethod: request.method,\n\t\t\turi: request.url,\n\t\t\trequestId: Math.random().toString().substring(2),\n\t\t\tmodule,\n\t\t\t[LoggerRequestBody]: body,\n\t\t}, {\n\t\t\thandler: FingerCrossedLoggerHandler.factory(),\n\t\t})\n\t}\n\n\tprivate createTimer() {\n\t\tconst times: EventTime[] = []\n\t\tconst globalStart = new Date().getTime()\n\t\tconst timer: Timer = (name: string, cb) => {\n\t\t\tconst start = new Date().getTime()\n\t\t\tconst time: EventTime = { label: name, start: start - globalStart }\n\t\t\ttimes.push(time)\n\t\t\tconst res = cb()\n\n\t\t\tif (res instanceof Promise) {\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait res\n\t\t\t\t\t} catch {\n\t\t\t\t\t} finally {\n\t\t\t\t\t\ttime.duration = new Date().getTime() - start\n\t\t\t\t\t}\n\t\t\t\t})()\n\t\t\t}\n\t\t\treturn res\n\t\t}\n\n\t\tconst send = (ctx: { req: IncomingMessage; response?: ServerResponse; body?: unknown; requestDebugMode: boolean; logger: Logger }) => {\n\t\t\tif (ctx.response && !ctx.response.headersSent && (ctx.requestDebugMode || this.debugMode) && times.length) {\n\t\t\t\tctx.response.setHeader('server-timing', times.map(it => `${it.label};desc=\"${it.label} T+${it.start}\";dur=${it.duration ?? -1}`).join(', '))\n\t\t\t}\n\n\t\t\tconst emit = () => {\n\t\t\t\tconst total = new Date().getTime() - globalStart\n\t\t\t\tconst timeLabel = total > 500 ? 'TIME_SLOW' : 'TIME_OK'\n\t\t\t\tconst shouldSuppress = this.suppressAccessLog === true || !ctx.req.url || (this.suppressAccessLog !== false && this.suppressAccessLog.test(ctx.req.url))\n\n\t\t\t\tconst level = shouldSuppress ? 'debug' : 'info'\n\t\t\t\tctx.logger.log(level, !ctx.response ? 'Connection established' : ctx.response.statusCode < 400 ? `Request successful` : 'Request failed', {\n\t\t\t\t\tstatus: ctx.response?.statusCode,\n\t\t\t\t\ttimeLabel: timeLabel,\n\t\t\t\t\ttotalTimeMs: total,\n\t\t\t\t\tevents: times,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif (ctx.body instanceof Readable) {\n\t\t\t\tconst body = ctx.body\n\t\t\t\tconst streamTimer = timer('Stream', () => {\n\t\t\t\t\treturn new Promise(resolve => {\n\t\t\t\t\t\tbody.addListener('close', () => {\n\t\t\t\t\t\t\tresolve(null)\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\n\t\t\t\tstreamTimer.then(emit).catch(emit)\n\n\t\t\t} else {\n\t\t\t\temit()\n\t\t\t}\n\n\t\t}\n\t\treturn { timer, send }\n\t}\n\n\tprivate matchRequest<C>(routes: Route<C>[], url: URL): MatchedRequest<C> | null {\n\t\tfor (const route of routes) {\n\t\t\tconst params = route.match({ url })\n\t\t\tif (params !== null) {\n\t\t\t\treturn { params, controller: route.controller, module: route.module }\n\t\t\t}\n\t\t}\n\t\treturn null\n\t}\n}\n\n\ntype EventTime = { label: string; start: number; duration?: number }\n\nexport type Timer = <T>(event: string, cb: () => T) => T\n\nexport type MatchedRequest<C> = { params: Params; controller: C; module: string }\n\nexport type BaseRequestContext = {\n\tlogger: Logger\n\trequest: IncomingMessage\n\turl: URL\n\tparams: Params\n}\n\nexport type ApplicationContext =\n\t& BaseRequestContext\n\t& {\n\t\tprojectGroup: ProjectGroupContainer\n\t\tauthResult: AuthResult | null\n\t\ttimer: Timer\n\t}\n\nexport type BaseHttpRequestContext = {\n\tkoa: KoaContext<{}>\n\tbody: unknown\n\tresponse: ServerResponse\n}\n\nexport type HttpContext =\n\t& ApplicationContext\n\t& BaseHttpRequestContext\n\t& {\n\t\trequestDebugMode: boolean\n\t}\n\nexport type InternalHttpContext =\n\t& BaseRequestContext\n\t& BaseHttpRequestContext\n\nexport type WebSocketContext =\n\t& ApplicationContext\n\t& {\n\t\tws: WebSocket\n\t\tabortSignal: AbortSignal\n\t}\n\nexport type HttpControllerResponse = Promise<HttpErrorResponse | undefined | void> | HttpErrorResponse | undefined | void\nexport type HttpController = (context: HttpContext) => HttpControllerResponse\nexport type InternalHttpController = (context: InternalHttpContext) => HttpControllerResponse\n\nexport type WebSocketController = (context: WebSocketContext) => void\n\ntype Params = { [param: string]: string }\n\ntype RequestMatcher = (args: { url: URL }) => Params | null\nconst createRequestMatcher = (\n\tmask: string,\n): RequestMatcher => {\n\tconst keys: Key[] = []\n\tconst regexp: RegExp = pathToRegexp(mask, keys)\n\n\tconst match = function (url: string): Params | null {\n\t\tconst match = regexp.exec(url)\n\t\tif (match) {\n\t\t\treturn match.slice(1).reduce((acc, value, i) => ({ ...acc, [keys[i].name]: value }), {})\n\t\t}\n\t\treturn null\n\t}\n\n\treturn request => {\n\t\treturn match(request.url.pathname)\n\t}\n}\n\nexport const LoggerRequestBody = Symbol('RequestBody')\n\nexport interface RunningApplication {\n\tclose(): Promise<void>\n\treadonly server: Server\n}\n"],"names":["logger","module","WebSocketServer","http","URL","HttpErrorResponse","ws","HttpResponse","FingerCrossedLoggerHandler","Readable","pathToRegexp","match"],"mappings":"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"}