{"version":3,"sources":["../../src/CompiledRoute.mts"],"sourcesContent":["import { isClass } from '@devbro/neko-helper';\nimport { Stream } from 'stream';\nimport { Middleware } from './Middleware.mjs';\nimport { MiddlewareFactory } from './MiddlewareFactory.mjs';\nimport type { Route } from './Route.mjs';\nimport type { HandlerType, MiddlewareProvider, Request, Response } from './types.mjs';\n\nexport class CompiledRoute {\n  constructor(\n    public route: Route,\n    public request: Request,\n    public response: Response,\n    public globalMiddlewares: MiddlewareProvider[] = []\n  ) {\n    this.prepareMiddlewares();\n  }\n\n  private middlewares: Middleware[] = [];\n\n  getMiddlewares() {\n    return this.middlewares;\n  }\n\n  private prepareMiddlewares() {\n    this.middlewares = [];\n    for (const middleware of [...this.globalMiddlewares, ...this.route.getMiddlewares()]) {\n      if (middleware instanceof Middleware) {\n        this.middlewares.push(middleware);\n      } else if (isClass(middleware)) {\n        this.middlewares.push((middleware as any).getInstance({}));\n      } else if (typeof middleware === 'function') {\n        this.middlewares.push(MiddlewareFactory.create(middleware as HandlerType));\n      } else {\n        throw new Error('Invalid middleware type');\n      }\n    }\n  }\n\n  async run() {\n    return await this.runMiddlewares(this.middlewares, this.request, this.response);\n  }\n\n  prepareOutputJsonFormat<T>(obj: object | Array<any>): T {\n    function traverse(value: any): any {\n      if (value === undefined || value === null) {\n        return null;\n      }\n\n      if (!value || typeof value !== 'object') {\n        return value;\n      }\n\n      if (typeof value.toJson === 'function') {\n        return traverse(value.toJson());\n      }\n\n      // to handle Date and other built-in types\n      if (typeof value.toJSON === 'function') {\n        return traverse(value.toJSON());\n      }\n\n      if (Array.isArray(value)) {\n        return value.map(traverse);\n      }\n\n      const result: Record<string, any> = {};\n      for (const key in value) {\n        if (Object.hasOwn(value, key)) {\n          result[key] = traverse(value[key]);\n        }\n      }\n      return result;\n    }\n\n    return traverse(obj);\n  }\n\n  convertToString(obj: any) {\n    if (typeof obj === 'string') {\n      return obj;\n    } else if (obj instanceof Buffer) {\n      return obj.toString();\n    } else if (typeof obj === 'object') {\n      return JSON.stringify(this.prepareOutputJsonFormat(obj));\n    }\n    return String(obj);\n  }\n\n  async processResponseBody(res: Response, controller_rc: any) {\n    if (controller_rc && res.writableEnded) {\n      throw new Error('cannot write to response, response has already ended');\n    }\n\n    if (res.writableEnded) {\n      return;\n    }\n\n    if (controller_rc) {\n      const header_content_type = res.getHeader('Content-Type');\n      if (controller_rc instanceof Stream || Buffer.isBuffer(controller_rc)) {\n        await this.writeAsync(res, controller_rc);\n      } else if (!header_content_type && typeof controller_rc === 'object') {\n        res.setHeader('Content-Type', 'application/json');\n        res.write(this.convertToString(controller_rc));\n      } else if (!header_content_type) {\n        res.setHeader('Content-Type', 'text/plain');\n        res.write(this.convertToString(controller_rc));\n      } else {\n        res.write(this.convertToString(controller_rc));\n      }\n      return;\n    } else {\n      res.statusCode = [200].includes(res.statusCode) ? 204 : res.statusCode;\n    }\n  }\n\n  async writeAsync(res: any, chunk: any) {\n    return new Promise((resolve, reject) => {\n      const ok = res.write(chunk, (err: any) => {\n        if (err) reject(err);\n      });\n      if (ok) {\n        // write went through immediately\n        resolve(0);\n      } else {\n        // wait for 'drain' when buffer is flushed\n        res.once('drain', resolve);\n      }\n    });\n  }\n\n  async runMiddlewares(middlewares: Middleware[], req: Request, res: Response) {\n    let index = 0;\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    const me = this;\n\n    async function next() {\n      if (index >= middlewares.length) {\n        const controller_rc = await me.route.callHanlder(req, res);\n        await me.processResponseBody(res, controller_rc);\n        return;\n      }\n\n      const middleware: Middleware | any = middlewares[index++];\n\n      if (middleware instanceof Middleware) {\n        await middleware.call(req, res, next);\n      } else if (typeof middleware === 'function') {\n        await middleware(req, res, next);\n      } else {\n        throw new Error('does not know how to run middleware');\n      }\n    }\n\n    await next();\n  }\n}\n"],"mappings":"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","names":[]}