{"version":3,"file":"RemoteHttpInterceptor.cjs","names":["BatchInterceptor","ClientRequestInterceptor","XMLHttpRequestInterceptor","FetchInterceptor","handleParentMessage: NodeJS.MessageListener","FetchResponse","Interceptor","handleChildMessage: NodeJS.MessageListener","RequestController","isResponseError","handleRequest"],"sources":["../../src/RemoteHttpInterceptor.ts"],"sourcesContent":["import { ChildProcess } from 'child_process'\nimport { HttpRequestEventMap } from './glossary'\nimport { Interceptor } from './Interceptor'\nimport { BatchInterceptor } from './BatchInterceptor'\nimport { ClientRequestInterceptor } from './interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from './interceptors/XMLHttpRequest'\nimport { FetchInterceptor } from './interceptors/fetch'\nimport { handleRequest } from './utils/handleRequest'\nimport { RequestController } from './RequestController'\nimport { FetchResponse } from './utils/fetchUtils'\nimport { isResponseError } from './utils/responseUtils'\n\nexport interface SerializedRequest {\n  id: string\n  url: string\n  method: string\n  headers: Array<[string, string]>\n  credentials: RequestCredentials\n  body: string\n}\n\ninterface RevivedRequest extends Omit<SerializedRequest, 'url' | 'headers'> {\n  url: URL\n  headers: Headers\n}\n\nexport interface SerializedResponse {\n  status: number\n  statusText: string\n  headers: Array<[string, string]>\n  body: string\n}\n\nexport class RemoteHttpInterceptor extends BatchInterceptor<\n  [ClientRequestInterceptor, XMLHttpRequestInterceptor, FetchInterceptor]\n> {\n  constructor() {\n    super({\n      name: 'remote-interceptor',\n      interceptors: [\n        new ClientRequestInterceptor(),\n        new XMLHttpRequestInterceptor(),\n        new FetchInterceptor(),\n      ],\n    })\n  }\n\n  protected setup() {\n    super.setup()\n\n    let handleParentMessage: NodeJS.MessageListener\n\n    this.on('request', async ({ request, requestId, controller }) => {\n      // Send the stringified intercepted request to\n      // the parent process where the remote resolver is established.\n      const serializedRequest = JSON.stringify({\n        id: requestId,\n        method: request.method,\n        url: request.url,\n        headers: Array.from(request.headers.entries()),\n        credentials: request.credentials,\n        body: ['GET', 'HEAD'].includes(request.method)\n          ? null\n          : await request.text(),\n      } as SerializedRequest)\n\n      this.logger.info(\n        'sent serialized request to the child:',\n        serializedRequest\n      )\n\n      process.send?.(`request:${serializedRequest}`)\n\n      const responsePromise = new Promise<void>((resolve) => {\n        handleParentMessage = (message) => {\n          if (typeof message !== 'string') {\n            return resolve()\n          }\n\n          if (message.startsWith(`response:${requestId}`)) {\n            const [, serializedResponse] =\n              message.match(/^response:.+?:(.+)$/) || []\n\n            if (!serializedResponse) {\n              return resolve()\n            }\n\n            const responseInit = JSON.parse(\n              serializedResponse\n            ) as SerializedResponse\n\n            const mockedResponse = new FetchResponse(responseInit.body, {\n              url: request.url,\n              status: responseInit.status,\n              statusText: responseInit.statusText,\n              headers: responseInit.headers,\n            })\n\n            /**\n             * @todo Support \"errorWith\" as well.\n             * This response handling from the child is incomplete.\n             */\n\n            controller.respondWith(mockedResponse)\n            return resolve()\n          }\n        }\n      })\n\n      // Listen for the mocked response message from the parent.\n      this.logger.info(\n        'add \"message\" listener to the parent process',\n        handleParentMessage\n      )\n      process.addListener('message', handleParentMessage)\n\n      return responsePromise\n    })\n\n    this.subscriptions.push(() => {\n      process.removeListener('message', handleParentMessage)\n    })\n  }\n}\n\nexport function requestReviver(key: string, value: any) {\n  switch (key) {\n    case 'url':\n      return new URL(value)\n\n    case 'headers':\n      return new Headers(value)\n\n    default:\n      return value\n  }\n}\n\nexport interface RemoveResolverOptions {\n  process: ChildProcess\n}\n\nexport class RemoteHttpResolver extends Interceptor<HttpRequestEventMap> {\n  static symbol = Symbol('remote-resolver')\n  private process: ChildProcess\n\n  constructor(options: RemoveResolverOptions) {\n    super(RemoteHttpResolver.symbol)\n    this.process = options.process\n  }\n\n  protected setup() {\n    const logger = this.logger.extend('setup')\n\n    const handleChildMessage: NodeJS.MessageListener = async (message) => {\n      logger.info('received message from child!', message)\n\n      if (typeof message !== 'string' || !message.startsWith('request:')) {\n        logger.info('unknown message, ignoring...')\n        return\n      }\n\n      const [, serializedRequest] = message.match(/^request:(.+)$/) || []\n      if (!serializedRequest) {\n        return\n      }\n\n      const requestJson = JSON.parse(\n        serializedRequest,\n        requestReviver\n      ) as RevivedRequest\n\n      logger.info('parsed intercepted request', requestJson)\n\n      const request = new Request(requestJson.url, {\n        method: requestJson.method,\n        headers: new Headers(requestJson.headers),\n        credentials: requestJson.credentials,\n        body: requestJson.body,\n      })\n\n      const controller = new RequestController(request, {\n        passthrough: () => {},\n        respondWith: async (response) => {\n          if (isResponseError(response)) {\n            this.logger.info('received a network error!', { response })\n            throw new Error('Not implemented')\n          }\n\n          this.logger.info('received mocked response!', { response })\n\n          const responseClone = response.clone()\n          const responseText = await responseClone.text()\n\n          // // Send the mocked response to the child process.\n          const serializedResponse = JSON.stringify({\n            status: response.status,\n            statusText: response.statusText,\n            headers: Array.from(response.headers.entries()),\n            body: responseText,\n          } as SerializedResponse)\n\n          this.process.send(\n            `response:${requestJson.id}:${serializedResponse}`,\n            (error) => {\n              if (error) {\n                return\n              }\n\n              // Emit an optimistic \"response\" event at this point,\n              // not to rely on the back-and-forth signaling for the sake of the event.\n              this.emitter.emit('response', {\n                request,\n                requestId: requestJson.id,\n                response: responseClone,\n                isMockedResponse: true,\n              })\n            }\n          )\n\n          logger.info(\n            'sent serialized mocked response to the parent:',\n            serializedResponse\n          )\n        },\n        errorWith: (reason) => {\n          this.logger.info('request has errored!', { error: reason })\n          throw new Error('Not implemented')\n        },\n      })\n\n      await handleRequest({\n        request,\n        requestId: requestJson.id,\n        controller,\n        emitter: this.emitter,\n      })\n    }\n\n    this.subscriptions.push(() => {\n      this.process.removeListener('message', handleChildMessage)\n      logger.info('removed the \"message\" listener from the child process!')\n    })\n\n    logger.info('adding a \"message\" listener to the child process')\n    this.process.addListener('message', handleChildMessage)\n\n    this.process.once('error', () => this.dispose())\n    this.process.once('exit', () => this.dispose())\n  }\n}\n"],"mappings":";;;;;;;;;;AAiCA,IAAa,wBAAb,cAA2CA,0CAEzC;CACA,cAAc;AACZ,QAAM;GACJ,MAAM;GACN,cAAc;IACZ,IAAIC,gDAA0B;IAC9B,IAAIC,kDAA2B;IAC/B,IAAIC,gCAAkB;IACvB;GACF,CAAC;;CAGJ,AAAU,QAAQ;AAChB,QAAM,OAAO;EAEb,IAAIC;AAEJ,OAAK,GAAG,WAAW,OAAO,EAAE,SAAS,WAAW,iBAAiB;GAG/D,MAAM,oBAAoB,KAAK,UAAU;IACvC,IAAI;IACJ,QAAQ,QAAQ;IAChB,KAAK,QAAQ;IACb,SAAS,MAAM,KAAK,QAAQ,QAAQ,SAAS,CAAC;IAC9C,aAAa,QAAQ;IACrB,MAAM,CAAC,OAAO,OAAO,CAAC,SAAS,QAAQ,OAAO,GAC1C,OACA,MAAM,QAAQ,MAAM;IACzB,CAAsB;AAEvB,QAAK,OAAO,KACV,yCACA,kBACD;AAED,WAAQ,OAAO,WAAW,oBAAoB;GAE9C,MAAM,kBAAkB,IAAI,SAAe,YAAY;AACrD,2BAAuB,YAAY;AACjC,SAAI,OAAO,YAAY,SACrB,QAAO,SAAS;AAGlB,SAAI,QAAQ,WAAW,YAAY,YAAY,EAAE;MAC/C,MAAM,GAAG,sBACP,QAAQ,MAAM,sBAAsB,IAAI,EAAE;AAE5C,UAAI,CAAC,mBACH,QAAO,SAAS;MAGlB,MAAM,eAAe,KAAK,MACxB,mBACD;MAED,MAAM,iBAAiB,IAAIC,iCAAc,aAAa,MAAM;OAC1D,KAAK,QAAQ;OACb,QAAQ,aAAa;OACrB,YAAY,aAAa;OACzB,SAAS,aAAa;OACvB,CAAC;;;;;AAOF,iBAAW,YAAY,eAAe;AACtC,aAAO,SAAS;;;KAGpB;AAGF,QAAK,OAAO,KACV,kDACA,oBACD;AACD,WAAQ,YAAY,WAAW,oBAAoB;AAEnD,UAAO;IACP;AAEF,OAAK,cAAc,WAAW;AAC5B,WAAQ,eAAe,WAAW,oBAAoB;IACtD;;;AAIN,SAAgB,eAAe,KAAa,OAAY;AACtD,SAAQ,KAAR;EACE,KAAK,MACH,QAAO,IAAI,IAAI,MAAM;EAEvB,KAAK,UACH,QAAO,IAAI,QAAQ,MAAM;EAE3B,QACE,QAAO;;;AAQb,IAAa,qBAAb,MAAa,2BAA2BC,+BAAiC;;gBACvD,OAAO,kBAAkB;;CAGzC,YAAY,SAAgC;AAC1C,QAAM,mBAAmB,OAAO;AAChC,OAAK,UAAU,QAAQ;;CAGzB,AAAU,QAAQ;EAChB,MAAM,SAAS,KAAK,OAAO,OAAO,QAAQ;EAE1C,MAAMC,qBAA6C,OAAO,YAAY;AACpE,UAAO,KAAK,gCAAgC,QAAQ;AAEpD,OAAI,OAAO,YAAY,YAAY,CAAC,QAAQ,WAAW,WAAW,EAAE;AAClE,WAAO,KAAK,+BAA+B;AAC3C;;GAGF,MAAM,GAAG,qBAAqB,QAAQ,MAAM,iBAAiB,IAAI,EAAE;AACnE,OAAI,CAAC,kBACH;GAGF,MAAM,cAAc,KAAK,MACvB,mBACA,eACD;AAED,UAAO,KAAK,8BAA8B,YAAY;GAEtD,MAAM,UAAU,IAAI,QAAQ,YAAY,KAAK;IAC3C,QAAQ,YAAY;IACpB,SAAS,IAAI,QAAQ,YAAY,QAAQ;IACzC,aAAa,YAAY;IACzB,MAAM,YAAY;IACnB,CAAC;GAEF,MAAM,aAAa,IAAIC,qCAAkB,SAAS;IAChD,mBAAmB;IACnB,aAAa,OAAO,aAAa;AAC/B,SAAIC,sCAAgB,SAAS,EAAE;AAC7B,WAAK,OAAO,KAAK,6BAA6B,EAAE,UAAU,CAAC;AAC3D,YAAM,IAAI,MAAM,kBAAkB;;AAGpC,UAAK,OAAO,KAAK,6BAA6B,EAAE,UAAU,CAAC;KAE3D,MAAM,gBAAgB,SAAS,OAAO;KACtC,MAAM,eAAe,MAAM,cAAc,MAAM;KAG/C,MAAM,qBAAqB,KAAK,UAAU;MACxC,QAAQ,SAAS;MACjB,YAAY,SAAS;MACrB,SAAS,MAAM,KAAK,SAAS,QAAQ,SAAS,CAAC;MAC/C,MAAM;MACP,CAAuB;AAExB,UAAK,QAAQ,KACX,YAAY,YAAY,GAAG,GAAG,uBAC7B,UAAU;AACT,UAAI,MACF;AAKF,WAAK,QAAQ,KAAK,YAAY;OAC5B;OACA,WAAW,YAAY;OACvB,UAAU;OACV,kBAAkB;OACnB,CAAC;OAEL;AAED,YAAO,KACL,kDACA,mBACD;;IAEH,YAAY,WAAW;AACrB,UAAK,OAAO,KAAK,wBAAwB,EAAE,OAAO,QAAQ,CAAC;AAC3D,WAAM,IAAI,MAAM,kBAAkB;;IAErC,CAAC;AAEF,SAAMC,oCAAc;IAClB;IACA,WAAW,YAAY;IACvB;IACA,SAAS,KAAK;IACf,CAAC;;AAGJ,OAAK,cAAc,WAAW;AAC5B,QAAK,QAAQ,eAAe,WAAW,mBAAmB;AAC1D,UAAO,KAAK,2DAAyD;IACrE;AAEF,SAAO,KAAK,qDAAmD;AAC/D,OAAK,QAAQ,YAAY,WAAW,mBAAmB;AAEvD,OAAK,QAAQ,KAAK,eAAe,KAAK,SAAS,CAAC;AAChD,OAAK,QAAQ,KAAK,cAAc,KAAK,SAAS,CAAC"}