{"version":3,"sources":["../../../../src/core/experimental/frames/http-frame.ts"],"sourcesContent":["import { TypedEvent } from 'rettime'\nimport { until } from 'until-async'\nimport { createRequestId } from '@mswjs/interceptors'\nimport {\n  NetworkFrame,\n  type NetworkFrameResolutionContext,\n} from './network-frame'\nimport { toPublicUrl } from '../../utils/request/toPublicUrl'\nimport { executeHandlers } from '../../utils/executeHandlers'\nimport { storeResponseCookies } from '../../utils/request/storeResponseCookies'\nimport { isPassthroughResponse, shouldBypassRequest } from '../request-utils'\nimport { devUtils } from '../../utils/internal/devUtils'\nimport {\n  executeUnhandledFrameHandle,\n  type UnhandledFrameHandle,\n} from '../on-unhandled-frame'\nimport type { HandlersController } from '../handlers-controller'\nimport { type AnyHandler } from '../handlers-controller'\nimport { type RequestHandler } from '../../handlers/RequestHandler'\n\ninterface HttpNetworkFrameOptions {\n  id?: string\n  request: Request\n}\n\nexport class RequestEvent<\n  DataType extends { requestId: string; request: Request } = {\n    requestId: string\n    request: Request\n  },\n  ReturnType = void,\n  EventType extends string = string,\n> extends TypedEvent<DataType, ReturnType, EventType> {\n  public readonly requestId: string\n  public readonly request: Request\n\n  constructor(type: EventType, data: DataType) {\n    super(...([type, {}] as any))\n    this.requestId = data.requestId\n    this.request = data.request\n  }\n}\n\nexport class ResponseEvent<\n  DataType extends {\n    requestId: string\n    request: Request\n    response: Response\n  } = {\n    requestId: string\n    request: Request\n    response: Response\n  },\n  ReturnType = void,\n  EventType extends string = string,\n> extends TypedEvent<DataType, ReturnType, EventType> {\n  public readonly requestId: string\n  public readonly request: Request\n  public readonly response: Response\n\n  constructor(type: EventType, data: DataType) {\n    super(...([type, {}] as any))\n    this.requestId = data.requestId\n    this.request = data.request\n    this.response = data.response\n  }\n}\n\nexport class UnhandledExceptionEvent<\n  DataType extends {\n    error: Error\n    requestId: string\n    request: Request\n  } = {\n    error: Error\n    requestId: string\n    request: Request\n  },\n  ReturnType = void,\n  EventType extends string = string,\n> extends TypedEvent<DataType, ReturnType, EventType> {\n  public readonly error: Error\n  public readonly requestId: string\n  public readonly request: Request\n\n  constructor(type: EventType, data: DataType) {\n    super(...([type, {}] as any))\n    this.error = data.error\n    this.requestId = data.requestId\n    this.request = data.request\n  }\n}\n\nexport type HttpNetworkFrameEventMap = {\n  'request:start': RequestEvent\n  'request:match': RequestEvent\n  'request:unhandled': RequestEvent\n  'request:end': RequestEvent\n  'response:mocked': ResponseEvent\n  'response:bypass': ResponseEvent\n  unhandledException: UnhandledExceptionEvent\n}\n\nexport abstract class HttpNetworkFrame extends NetworkFrame<\n  'http',\n  {\n    id: string\n    request: Request\n  },\n  HttpNetworkFrameEventMap\n> {\n  constructor(options: HttpNetworkFrameOptions) {\n    const id = options.id || createRequestId()\n    super('http', { id, request: options.request })\n  }\n\n  public getHandlers(controller: HandlersController): Array<AnyHandler> {\n    return controller.getHandlersByKind('request')\n  }\n\n  public abstract respondWith(response?: Response): void\n\n  public async getUnhandledMessage(): Promise<string> {\n    const { request } = this.data\n\n    const url = new URL(request.url)\n    const publicUrl = toPublicUrl(url) + url.search\n    const requestBody =\n      request.body == null ? null : await request.clone().text()\n\n    const details = `\\n\\n  \\u2022 ${request.method} ${publicUrl}\\n\\n${requestBody ? `  \\u2022 Request body: ${requestBody}\\n\\n` : ''}`\n    const message = `intercepted a request without a matching request handler:${details}If you still wish to intercept this unhandled request, please create a request handler for it.\\nRead more: https://mswjs.io/docs/http/intercepting-requests`\n\n    return message\n  }\n\n  public async resolve(\n    handlers: Array<RequestHandler>,\n    onUnhandledFrame: UnhandledFrameHandle,\n    resolutionContext?: NetworkFrameResolutionContext,\n  ): Promise<boolean | null> {\n    const { id: requestId, request } = this.data\n    const requestCloneForLogs = resolutionContext?.quiet\n      ? null\n      : request.clone()\n\n    this.events.emit(new RequestEvent('request:start', { requestId, request }))\n\n    // Requests wrapped in explicit \"bypass(request)\".\n    if (shouldBypassRequest(request)) {\n      this.events.emit(new RequestEvent('request:end', { requestId, request }))\n      this.passthrough()\n      return null\n    }\n\n    const [lookupError, lookupResult] = await until(() => {\n      return executeHandlers({\n        requestId,\n        request,\n        handlers,\n        resolutionContext: {\n          baseUrl: resolutionContext?.baseUrl?.toString(),\n          quiet: resolutionContext?.quiet,\n        },\n      })\n    })\n\n    if (lookupError != null) {\n      if (\n        !this.events.emit(\n          new UnhandledExceptionEvent('unhandledException', {\n            error: lookupError,\n            requestId,\n            request,\n          }),\n        )\n      ) {\n        // Surface the error to the developer since they haven't handled it.\n        console.error(lookupError)\n        devUtils.error(\n          'Encountered an unhandled exception during the handler lookup for \"%s %s\". Please see the original error above.',\n          request.method,\n          request.url,\n        )\n      }\n\n      this.errorWith(lookupError)\n      return null\n    }\n\n    // No matching handlers.\n    if (lookupResult == null) {\n      this.events.emit(\n        new RequestEvent('request:unhandled', {\n          requestId,\n          request,\n        }),\n      )\n\n      /**\n       * @note The unhandled frame handle must be executed during the request resolution\n       * since it can influence it (e.g. error the request if the \"error\" startegy was used).\n       */\n      await executeUnhandledFrameHandle(this, onUnhandledFrame).then(\n        () => this.passthrough(),\n        (error) => this.errorWith(error),\n      )\n\n      this.events.emit(\n        new RequestEvent('request:end', {\n          requestId,\n          request,\n        }),\n      )\n\n      return false\n    }\n\n    const { response, handler, parsedResult } = lookupResult\n\n    this.events.emit(\n      new RequestEvent('request:match', {\n        requestId,\n        request,\n      }),\n    )\n\n    // Handlers that returned no mocked response.\n    if (response == null) {\n      this.events.emit(\n        new RequestEvent('request:end', {\n          requestId,\n          request,\n        }),\n      )\n\n      this.passthrough()\n      return null\n    }\n\n    // Handlers that returned explicit `passthrough()`.\n    if (isPassthroughResponse(response)) {\n      this.events.emit(\n        new RequestEvent('request:end', {\n          requestId,\n          request,\n        }),\n      )\n\n      this.passthrough()\n      return null\n    }\n\n    const responseCloneForLogs = resolutionContext?.quiet\n      ? null\n      : response.clone()\n\n    await storeResponseCookies(request, response)\n\n    this.respondWith(response)\n\n    this.events.emit(\n      new RequestEvent('request:end', {\n        requestId,\n        request,\n      }),\n    )\n\n    if (!resolutionContext?.quiet) {\n      handler.log({\n        request: requestCloneForLogs!,\n        response: responseCloneForLogs!,\n        parsedResult,\n      })\n    }\n\n    return true\n  }\n}\n"],"mappings":"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","names":[]}