{"version":3,"file":"rpc-service-chain.mjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-service-chain.ts"],"names":[],"mappings":";;;;;;;;;;;;AAOA,OAAO,EAAE,UAAU,EAAE,0BAAsB;AAK3C;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IAG1B;;;;;;OAMG;IACH,YACE,wBAAsE;;QAV/D,4CAAwB;QAY/B,uBAAA,IAAI,6BAAa,uBAAA,IAAI,yEAAsB,MAA1B,IAAI,EAAuB,wBAAwB,CAAC,MAAA,CAAC;IACxE,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,QAA8C;QACpD,MAAM,WAAW,GAAG,uBAAA,IAAI,iCAAU,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACjD,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAC1B,CAAC;QAEF,OAAO;YACL,OAAO;gBACL,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5D,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,QAA8C;QACpD,MAAM,WAAW,GAAG,uBAAA,IAAI,iCAAU,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACjD,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAC1B,CAAC;QAEF,OAAO;YACL,OAAO;gBACL,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5D,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,QAAiD;QAC1D,MAAM,WAAW,GAAG,uBAAA,IAAI,iCAAU,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACjD,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAC7B,CAAC;QAEF,OAAO;YACL,OAAO;gBACL,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5D,CAAC;SACF,CAAC;IACJ,CAAC;IAgDD,KAAK,CAAC,OAAO,CACX,cAAsC,EACtC,eAA6B,EAAE;QAE/B,OAAO,uBAAA,IAAI,iCAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IACjE,CAAC;CA0BF;8KAbG,wBAAsE;IAEtE,OAAO,CAAC,GAAG,wBAAwB,CAAC;SACjC,OAAO,EAAE;SACT,MAAM,CAAC,CAAC,eAA6B,EAAE,oBAAoB,EAAE,KAAK,EAAE,EAAE;QACrE,MAAM,eAAe,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC;YAC7B,GAAG,oBAAoB;YACvB,eAAe;SAChB,CAAC,CAAC;QACH,OAAO,CAAC,OAAO,EAAE,GAAG,eAAe,CAAC,CAAC;IACvC,CAAC,EAAE,EAAE,CAAC,CAAC;AACX,CAAC","sourcesContent":["import type {\n  Json,\n  JsonRpcParams,\n  JsonRpcRequest,\n  JsonRpcResponse,\n} from '@metamask/utils';\n\nimport { RpcService } from './rpc-service';\nimport type { RpcServiceOptions } from './rpc-service';\nimport type { RpcServiceRequestable } from './rpc-service-requestable';\nimport type { FetchOptions } from './shared';\n\n/**\n * This class constructs a chain of RpcService objects which represent a\n * particular network. The first object in the chain is intended to be the\n * primary way of reaching the network and the remaining objects are used as\n * failovers.\n */\nexport class RpcServiceChain implements RpcServiceRequestable {\n  readonly #services: RpcService[];\n\n  /**\n   * Constructs a new RpcServiceChain object.\n   *\n   * @param rpcServiceConfigurations - The options for the RPC services\n   * that you want to construct. Each object in this array is the same as\n   * {@link RpcServiceOptions}.\n   */\n  constructor(\n    rpcServiceConfigurations: Omit<RpcServiceOptions, 'failoverService'>[],\n  ) {\n    this.#services = this.#buildRpcServiceChain(rpcServiceConfigurations);\n  }\n\n  /**\n   * Listens for when any of the RPC services retry a request.\n   *\n   * @param listener - The callback to be called when the retry occurs.\n   * @returns What {@link RpcService.onRetry} returns.\n   */\n  onRetry(listener: Parameters<RpcService['onRetry']>[0]) {\n    const disposables = this.#services.map((service) =>\n      service.onRetry(listener),\n    );\n\n    return {\n      dispose() {\n        disposables.forEach((disposable) => disposable.dispose());\n      },\n    };\n  }\n\n  /**\n   * Listens for when any of the RPC services retry the request too many times\n   * in a row.\n   *\n   * @param listener - The callback to be called when the retry occurs.\n   * @returns What {@link RpcService.onBreak} returns.\n   */\n  onBreak(listener: Parameters<RpcService['onBreak']>[0]) {\n    const disposables = this.#services.map((service) =>\n      service.onBreak(listener),\n    );\n\n    return {\n      dispose() {\n        disposables.forEach((disposable) => disposable.dispose());\n      },\n    };\n  }\n\n  /**\n   * Listens for when any of the RPC services send a slow request.\n   *\n   * @param listener - The callback to be called when the retry occurs.\n   * @returns What {@link RpcService.onRetry} returns.\n   */\n  onDegraded(listener: Parameters<RpcService['onDegraded']>[0]) {\n    const disposables = this.#services.map((service) =>\n      service.onDegraded(listener),\n    );\n\n    return {\n      dispose() {\n        disposables.forEach((disposable) => disposable.dispose());\n      },\n    };\n  }\n\n  /**\n   * Makes a request to the first RPC service in the chain. If this service is\n   * down, then the request is forwarded to the next service in the chain, etc.\n   *\n   * This overload is specifically designed for `eth_getBlockByNumber`, which\n   * can return a `result` of `null` despite an expected `Result` being\n   * provided.\n   *\n   * @param jsonRpcRequest - The JSON-RPC request to send to the endpoint.\n   * @param fetchOptions - An options bag for {@link fetch} which further\n   * specifies the request.\n   * @returns The decoded JSON-RPC response from the endpoint.\n   * @throws A \"method not found\" error if the response status is 405.\n   * @throws A rate limiting error if the response HTTP status is 429.\n   * @throws A timeout error if the response HTTP status is 503 or 504.\n   * @throws A generic error if the response HTTP status is not 2xx but also not\n   * 405, 429, 503, or 504.\n   */\n  async request<Params extends JsonRpcParams, Result extends Json>(\n    jsonRpcRequest: JsonRpcRequest<Params> & { method: 'eth_getBlockByNumber' },\n    fetchOptions?: FetchOptions,\n  ): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>>;\n\n  /**\n   * Makes a request to the first RPC service in the chain. If this service is\n   * down, then the request is forwarded to the next service in the chain, etc.\n   *\n   * This overload is designed for all RPC methods except for\n   * `eth_getBlockByNumber`, which are expected to return a `result` of the\n   * expected `Result`.\n   *\n   * @param jsonRpcRequest - The JSON-RPC request to send to the endpoint.\n   * @param fetchOptions - An options bag for {@link fetch} which further\n   * specifies the request.\n   * @returns The decoded JSON-RPC response from the endpoint.\n   * @throws A \"method not found\" error if the response status is 405.\n   * @throws A rate limiting error if the response HTTP status is 429.\n   * @throws A timeout error if the response HTTP status is 503 or 504.\n   * @throws A generic error if the response HTTP status is not 2xx but also not\n   * 405, 429, 503, or 504.\n   */\n  async request<Params extends JsonRpcParams, Result extends Json>(\n    jsonRpcRequest: JsonRpcRequest<Params>,\n    fetchOptions?: FetchOptions,\n  ): Promise<JsonRpcResponse<Result>>;\n\n  async request<Params extends JsonRpcParams, Result extends Json>(\n    jsonRpcRequest: JsonRpcRequest<Params>,\n    fetchOptions: FetchOptions = {},\n  ): Promise<JsonRpcResponse<Result | null>> {\n    return this.#services[0].request(jsonRpcRequest, fetchOptions);\n  }\n\n  /**\n   * Constructs the chain of RPC services. The second RPC service is\n   * configured as the failover for the first, the third service is\n   * configured as the failover for the second, etc.\n   *\n   * @param rpcServiceConfigurations - The options for the RPC services that\n   * you want to construct. Each object in this array is the same as\n   * {@link RpcServiceOptions}.\n   * @returns The constructed chain of RPC services.\n   */\n  #buildRpcServiceChain(\n    rpcServiceConfigurations: Omit<RpcServiceOptions, 'failoverService'>[],\n  ): RpcService[] {\n    return [...rpcServiceConfigurations]\n      .reverse()\n      .reduce((workingServices: RpcService[], serviceConfiguration, index) => {\n        const failoverService = index > 0 ? workingServices[0] : undefined;\n        const service = new RpcService({\n          ...serviceConfiguration,\n          failoverService,\n        });\n        return [service, ...workingServices];\n      }, []);\n  }\n}\n"]}