{"version":3,"sources":["../../../src/frameworks/trpc/trpc.framework.ts"],"sourcesContent":["//#region\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { AnyRouter, DataTransformer } from '@trpc/server';\nimport {\n  type NodeHTTPCreateContextFn,\n  type NodeHTTPCreateContextFnOptions,\n  type NodeHTTPHandlerOptions,\n  nodeHTTPRequestHandler,\n} from '@trpc/server/adapters/node-http';\nimport type { SingleValueHeaders } from '../../@types';\nimport type { FrameworkContract } from '../../contracts';\nimport { getDefaultIfUndefined, getFlattenedHeadersMap } from '../../core';\n\n//#endregion\n\n/**\n * The transformer that is responsible to transform buffer's input to javascript objects\n *\n * @deprecated You should use {@link JsonBodyParserFramework} instead, is more reliable and enable you to use transformer of trpc to other things.\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport class BufferToJSObjectTransformer implements DataTransformer {\n  /**\n   * Deserialize unknown values to javascript objects\n   *\n   * @param value - The value to be deserialized\n   */\n  public deserialize(value?: unknown): any {\n    if (value instanceof Buffer) return JSON.parse(value.toString('utf-8'));\n\n    return value;\n  }\n\n  /**\n   * The value to be serialized, do nothing because tRPC can handle.\n   *\n   * @param value - The value to be serialized\n   */\n  public serialize(value: any): any {\n    return value;\n  }\n}\n\n/**\n * The context created by this library that allows getting some information from the request and setting the status and header of the response.\n *\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport interface TrpcAdapterBaseContext {\n  /**\n   * The request object that will be forward to your app\n   */\n  request: IncomingMessage;\n\n  /**\n   * The response object that will be forward to your app to output the response\n   */\n  response: ServerResponse;\n\n  /**\n   * The method to set response status.\n   *\n   * @param statusCode - The response status that you want\n   */\n  setStatus(statusCode: number): void;\n\n  /**\n   * The method to set some header in the response\n   *\n   * @param name - The name of the header\n   * @param value - The value to be set in the header\n   */\n  setHeader(name: string, value: number | string): void;\n\n  /**\n   * The method to remove some header from the response\n   *\n   * @param name - The name of the header\n   */\n  removeHeader(name: string): void;\n\n  /**\n   * The method to return the value of some header from the request\n   *\n   * @param name - The name of the header\n   */\n  getHeader(name: string): string | undefined;\n\n  /**\n   * The method to return the request headers\n   */\n  getHeaders(): SingleValueHeaders;\n\n  /**\n   * The method to return user's address\n   */\n  getIp(): string | undefined;\n\n  /**\n   * The method to return the URL called\n   */\n  getUrl(): string | undefined;\n\n  /**\n   * The method to return the HTTP Method in the request\n   */\n  getMethod(): string | undefined;\n}\n\n/**\n * This is the context merged between {@link TrpcAdapterBaseContext} and the {@link TContext} that you provided.\n *\n * This context will be merged with the context you created with `createContext` inside {@link TrpcFrameworkOptions}.\n * So to make the type work, just send the properties you've added inside {@link TContext}.\n *\n * @example\n * ```typescript\n * type MyCustomContext = { user: { name: string } };\n * type TrpcContext = TrpcAdapterContext<MyCustomContext>; // your final context type to put inside trpc.router\n * ```\n *\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport type TrpcAdapterContext<TContext> = TContext & TrpcAdapterBaseContext;\n\n/**\n * The options to customize the {@link TrpcFramework}\n *\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport type TrpcFrameworkOptions<TContext> = Omit<\n  NodeHTTPHandlerOptions<AnyRouter, IncomingMessage, ServerResponse>,\n  'router' | 'createContext'\n> & {\n  createContext?: (\n    opts: NodeHTTPCreateContextFnOptions<IncomingMessage, ServerResponse>,\n  ) =>\n    | Omit<TContext, keyof TrpcAdapterBaseContext>\n    | Promise<Omit<TContext, keyof TrpcAdapterBaseContext>>;\n};\n\n/**\n * The framework that forwards requests to TRPC handler\n *\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport class TrpcFramework<\n  TContext extends TrpcAdapterBaseContext,\n  TRouter extends AnyRouter = AnyRouter,\n> implements FrameworkContract<TRouter>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   */\n  constructor(protected readonly options?: TrpcFrameworkOptions<TContext>) {}\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest<TRouter extends AnyRouter>(\n    app: TRouter,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    const endpoint = this.getSafeUrlForTrpc(request);\n\n    nodeHTTPRequestHandler({\n      req: request,\n      res: response,\n      path: endpoint,\n      router: app,\n      ...this.options,\n      createContext: createContextOptions =>\n        this.mergeDefaultContextWithOptionsContext(createContextOptions),\n    });\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get safe url that can be used inside Trpc.\n   *\n   * @example\n   * ```typescript\n   * const url = getSafeUrlForTrpc('/users?input=hello');\n   * console.log(url); // users\n   * ```\n   *\n   * @param request - The request object that will be forward to your app\n   */\n  protected getSafeUrlForTrpc(request: IncomingMessage): string {\n    let url = request.url!;\n\n    if (url.startsWith('/')) url = url.slice(1);\n\n    if (url.includes('?')) url = url.split('?')[0];\n\n    return url;\n  }\n\n  /**\n   * Merge the default context ({@link TrpcAdapterContext}) with the context created by the user.\n   *\n   * @param createContextOptions - The options sent by trpc to create the context\n   */\n  protected mergeDefaultContextWithOptionsContext(\n    createContextOptions: NodeHTTPCreateContextFnOptions<\n      IncomingMessage,\n      ServerResponse\n    >,\n  ): TContext | Promise<TContext> {\n    const createContextFromOptions: NodeHTTPCreateContextFn<\n      AnyRouter,\n      IncomingMessage,\n      ServerResponse\n    > = getDefaultIfUndefined(\n      this.options?.createContext,\n      () =>\n        undefined as unknown as Omit<TContext, keyof TrpcAdapterBaseContext>,\n    );\n\n    const resolvedContext = createContextFromOptions(createContextOptions);\n\n    if (resolvedContext && resolvedContext.then) {\n      return resolvedContext.then(context =>\n        this.wrapResolvedContextWithDefaultContext(\n          context,\n          createContextOptions,\n        ),\n      );\n    }\n\n    return this.wrapResolvedContextWithDefaultContext(\n      resolvedContext,\n      createContextOptions,\n    );\n  }\n\n  /**\n   * Wraps the resolved context from the {@link TrpcFrameworkOptions} created with `createContext` and merge\n   * with the {@link TrpcAdapterContext} generated by the library.\n   *\n   * @param resolvedContext - The context created with `createContext` inside {@link TrpcFrameworkOptions}\n   * @param createContextOptions - The options sent by trpc to create the context\n   */\n  protected wrapResolvedContextWithDefaultContext(\n    resolvedContext: TContext,\n    createContextOptions: NodeHTTPCreateContextFnOptions<\n      IncomingMessage,\n      ServerResponse\n    >,\n  ): TContext {\n    const request = createContextOptions.req;\n    const response = createContextOptions.res;\n\n    return {\n      ...resolvedContext,\n      request,\n      response,\n      getUrl: () => request.url,\n      getMethod: () => request.method,\n      getHeaders: () => getFlattenedHeadersMap(request.headers, ',', true),\n      setHeader: (header, value) => {\n        response.setHeader(header, value);\n      },\n      removeHeader: header => {\n        response.removeHeader(header);\n      },\n      getHeader: (header: string) => {\n        return getFlattenedHeadersMap(request.headers, ',', true)[\n          header.toLowerCase()\n        ];\n      },\n      setStatus: (statusCode: number) => {\n        response.statusCode = statusCode;\n        // force undefined to get default message for the status code\n        // ref: https://nodejs.org/dist/latest-v16.x/docs/api/http.html#responsestatusmessage\n        response.statusMessage = undefined as any;\n      },\n      getIp: () => request.connection.remoteAddress,\n    };\n  }\n\n  //#endregion\n}\n"],"mappings":"iGAIA,OAIE,0BAAAA,MACK,kCAcA,IAAMC,EAAN,KAA6D,CAvBpE,MAuBoE,CAAAC,EAAA,oCAM3D,YAAYC,EAAsB,CACvC,OAAIA,aAAiB,OAAe,KAAK,MAAMA,EAAM,SAAS,OAAO,CAAC,EAE/DA,CACT,CAOO,UAAUA,EAAiB,CAChC,OAAOA,CACT,CACF,EA6GaC,EAAN,KAIP,CAME,YAA+BC,EAA0C,CAA1C,aAAAA,CAA2C,CAlK5E,MA4JA,CAAAH,EAAA,sBAeS,YACLI,EACAC,EACAC,EACM,CACN,IAAMC,EAAW,KAAK,kBAAkBF,CAAO,EAE/CG,EAAuB,CACrB,IAAKH,EACL,IAAKC,EACL,KAAMC,EACN,OAAQH,EACR,GAAG,KAAK,QACR,cAAeJ,EAAAS,GACb,KAAK,sCAAsCA,CAAoB,EADlD,gBAEjB,CAAC,CACH,CAiBU,kBAAkBJ,EAAkC,CAC5D,IAAIK,EAAML,EAAQ,IAElB,OAAIK,EAAI,WAAW,GAAG,IAAGA,EAAMA,EAAI,MAAM,CAAC,GAEtCA,EAAI,SAAS,GAAG,IAAGA,EAAMA,EAAI,MAAM,GAAG,EAAE,CAAC,GAEtCA,CACT,CAOU,sCACRD,EAI8B,CAW9B,IAAME,EANFC,EACF,KAAK,SAAS,cACd,IAAG,EAEL,EAEiDH,CAAoB,EAErE,OAAIE,GAAmBA,EAAgB,KAC9BA,EAAgB,KAAKE,GAC1B,KAAK,sCACHA,EACAJ,CACF,CACF,EAGK,KAAK,sCACVE,EACAF,CACF,CACF,CASU,sCACRE,EACAF,EAIU,CACV,IAAMJ,EAAUI,EAAqB,IAC/BH,EAAWG,EAAqB,IAEtC,MAAO,CACL,GAAGE,EACH,QAAAN,EACA,SAAAC,EACA,OAAQN,EAAA,IAAMK,EAAQ,IAAd,UACR,UAAWL,EAAA,IAAMK,EAAQ,OAAd,aACX,WAAYL,EAAA,IAAMc,EAAuBT,EAAQ,QAAS,IAAK,EAAI,EAAvD,cACZ,UAAWL,EAAA,CAACe,EAAQd,IAAU,CAC5BK,EAAS,UAAUS,EAAQd,CAAK,CAClC,EAFW,aAGX,aAAcD,EAAAe,GAAU,CACtBT,EAAS,aAAaS,CAAM,CAC9B,EAFc,gBAGd,UAAWf,EAACe,GACHD,EAAuBT,EAAQ,QAAS,IAAK,EAAI,EACtDU,EAAO,YAAY,CACrB,EAHS,aAKX,UAAWf,EAACgB,GAAuB,CACjCV,EAAS,WAAaU,EAGtBV,EAAS,cAAgB,MAC3B,EALW,aAMX,MAAON,EAAA,IAAMK,EAAQ,WAAW,cAAzB,QACT,CACF,CAGF","names":["nodeHTTPRequestHandler","BufferToJSObjectTransformer","__name","value","TrpcFramework","options","app","request","response","endpoint","nodeHTTPRequestHandler","createContextOptions","url","resolvedContext","getDefaultIfUndefined","context","getFlattenedHeadersMap","header","statusCode"]}