@metamask-previews/network-controller 26.0.0-preview-bc80feb8 → 27.0.0-preview-84f90603

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/dist/NetworkController.cjs +37 -10
  3. package/dist/NetworkController.cjs.map +1 -1
  4. package/dist/NetworkController.d.cts +135 -12
  5. package/dist/NetworkController.d.cts.map +1 -1
  6. package/dist/NetworkController.d.mts +135 -12
  7. package/dist/NetworkController.d.mts.map +1 -1
  8. package/dist/NetworkController.mjs +37 -10
  9. package/dist/NetworkController.mjs.map +1 -1
  10. package/dist/constants.cjs +18 -10
  11. package/dist/constants.cjs.map +1 -1
  12. package/dist/constants.d.cts +18 -10
  13. package/dist/constants.d.cts.map +1 -1
  14. package/dist/constants.d.mts +18 -10
  15. package/dist/constants.d.mts.map +1 -1
  16. package/dist/constants.mjs +18 -10
  17. package/dist/constants.mjs.map +1 -1
  18. package/dist/create-auto-managed-network-client.cjs +4 -1
  19. package/dist/create-auto-managed-network-client.cjs.map +1 -1
  20. package/dist/create-auto-managed-network-client.d.cts +5 -2
  21. package/dist/create-auto-managed-network-client.d.cts.map +1 -1
  22. package/dist/create-auto-managed-network-client.d.mts +5 -2
  23. package/dist/create-auto-managed-network-client.d.mts.map +1 -1
  24. package/dist/create-auto-managed-network-client.mjs +4 -1
  25. package/dist/create-auto-managed-network-client.mjs.map +1 -1
  26. package/dist/create-network-client.cjs +132 -42
  27. package/dist/create-network-client.cjs.map +1 -1
  28. package/dist/create-network-client.d.cts +5 -2
  29. package/dist/create-network-client.d.cts.map +1 -1
  30. package/dist/create-network-client.d.mts +5 -2
  31. package/dist/create-network-client.d.mts.map +1 -1
  32. package/dist/create-network-client.mjs +132 -42
  33. package/dist/create-network-client.mjs.map +1 -1
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +1 -1
  36. package/dist/index.d.cts.map +1 -1
  37. package/dist/index.d.mts +1 -1
  38. package/dist/index.d.mts.map +1 -1
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/rpc-service/rpc-service-chain.cjs +247 -39
  41. package/dist/rpc-service/rpc-service-chain.cjs.map +1 -1
  42. package/dist/rpc-service/rpc-service-chain.d.cts +106 -25
  43. package/dist/rpc-service/rpc-service-chain.d.cts.map +1 -1
  44. package/dist/rpc-service/rpc-service-chain.d.mts +106 -25
  45. package/dist/rpc-service/rpc-service-chain.d.mts.map +1 -1
  46. package/dist/rpc-service/rpc-service-chain.mjs +247 -39
  47. package/dist/rpc-service/rpc-service-chain.mjs.map +1 -1
  48. package/dist/rpc-service/rpc-service-requestable.cjs.map +1 -1
  49. package/dist/rpc-service/rpc-service-requestable.d.cts +15 -5
  50. package/dist/rpc-service/rpc-service-requestable.d.cts.map +1 -1
  51. package/dist/rpc-service/rpc-service-requestable.d.mts +15 -5
  52. package/dist/rpc-service/rpc-service-requestable.d.mts.map +1 -1
  53. package/dist/rpc-service/rpc-service-requestable.mjs.map +1 -1
  54. package/dist/rpc-service/rpc-service.cjs +65 -33
  55. package/dist/rpc-service/rpc-service.cjs.map +1 -1
  56. package/dist/rpc-service/rpc-service.d.cts +33 -24
  57. package/dist/rpc-service/rpc-service.d.cts.map +1 -1
  58. package/dist/rpc-service/rpc-service.d.mts +33 -24
  59. package/dist/rpc-service/rpc-service.d.mts.map +1 -1
  60. package/dist/rpc-service/rpc-service.mjs +66 -34
  61. package/dist/rpc-service/rpc-service.mjs.map +1 -1
  62. package/dist/rpc-service/shared.cjs.map +1 -1
  63. package/dist/rpc-service/shared.d.cts +25 -3
  64. package/dist/rpc-service/shared.d.cts.map +1 -1
  65. package/dist/rpc-service/shared.d.mts +25 -3
  66. package/dist/rpc-service/shared.d.mts.map +1 -1
  67. package/dist/rpc-service/shared.mjs.map +1 -1
  68. package/package.json +2 -1
@@ -13,13 +13,15 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _RpcService_instances, _RpcService_fetch, _RpcService_fetchOptions, _RpcService_failoverService, _RpcService_logger, _RpcService_policy, _RpcService_getDefaultFetchOptions, _RpcService_getCompleteFetchOptions, _RpcService_processRequest;
16
+ var _RpcService_instances, _RpcService_fetch, _RpcService_fetchOptions, _RpcService_logger, _RpcService_policy, _RpcService_getDefaultFetchOptions, _RpcService_getCompleteFetchOptions, _RpcService_executeAndProcessRequest;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.RpcService = exports.isConnectionError = exports.CUSTOM_RPC_ERRORS = exports.CONNECTION_ERRORS = exports.DEFAULT_MAX_CONSECUTIVE_FAILURES = exports.DEFAULT_MAX_RETRIES = void 0;
19
19
  const controller_utils_1 = require("@metamask/controller-utils");
20
20
  const rpc_errors_1 = require("@metamask/rpc-errors");
21
21
  const utils_1 = require("@metamask/utils");
22
22
  const deepmerge_1 = __importDefault(require("deepmerge"));
23
+ const logger_1 = require("../logger.cjs");
24
+ const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, 'RpcService');
23
25
  /**
24
26
  * The maximum number of times that a failing service should be re-run before
25
27
  * giving up.
@@ -191,11 +193,6 @@ class RpcService {
191
193
  * A common set of options that the request options will extend.
192
194
  */
193
195
  _RpcService_fetchOptions.set(this, void 0);
194
- /**
195
- * An RPC service that represents a failover endpoint which will be invoked
196
- * while the circuit for _this_ service is open.
197
- */
198
- _RpcService_failoverService.set(this, void 0);
199
196
  /**
200
197
  * A `loglevel` logger.
201
198
  */
@@ -204,14 +201,13 @@ class RpcService {
204
201
  * The policy that wraps the request.
205
202
  */
206
203
  _RpcService_policy.set(this, void 0);
207
- const { btoa: givenBtoa, endpointUrl, failoverService, fetch: givenFetch, logger, fetchOptions = {}, policyOptions = {}, } = options;
204
+ const { btoa: givenBtoa, endpointUrl, fetch: givenFetch, logger, fetchOptions = {}, policyOptions = {}, } = options;
208
205
  __classPrivateFieldSet(this, _RpcService_fetch, givenFetch, "f");
209
206
  const normalizedUrl = getNormalizedEndpointUrl(endpointUrl);
210
207
  __classPrivateFieldSet(this, _RpcService_fetchOptions, __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_getDefaultFetchOptions).call(this, normalizedUrl, fetchOptions, givenBtoa), "f");
211
208
  this.endpointUrl = stripCredentialsFromUrl(normalizedUrl);
212
- __classPrivateFieldSet(this, _RpcService_failoverService, failoverService, "f");
213
209
  __classPrivateFieldSet(this, _RpcService_logger, logger, "f");
214
- const policy = (0, controller_utils_1.createServicePolicy)({
210
+ __classPrivateFieldSet(this, _RpcService_policy, (0, controller_utils_1.createServicePolicy)({
215
211
  maxRetries: exports.DEFAULT_MAX_RETRIES,
216
212
  maxConsecutiveFailures: exports.DEFAULT_MAX_CONSECUTIVE_FAILURES,
217
213
  ...policyOptions,
@@ -229,8 +225,23 @@ class RpcService {
229
225
  ((0, utils_1.hasProperty)(error, 'code') &&
230
226
  (error.code === 'ETIMEDOUT' || error.code === 'ECONNRESET')));
231
227
  }),
232
- });
233
- __classPrivateFieldSet(this, _RpcService_policy, policy, "f");
228
+ }), "f");
229
+ }
230
+ /**
231
+ * Resets the underlying composite Cockatiel policy.
232
+ *
233
+ * This is useful in a collection of RpcServices where some act as failovers
234
+ * for others where you effectively want to invalidate the failovers when the
235
+ * primary recovers.
236
+ */
237
+ resetPolicy() {
238
+ __classPrivateFieldGet(this, _RpcService_policy, "f").reset();
239
+ }
240
+ /**
241
+ * @returns The state of the underlying circuit.
242
+ */
243
+ getCircuitState() {
244
+ return __classPrivateFieldGet(this, _RpcService_policy, "f").getCircuitState();
234
245
  }
235
246
  /**
236
247
  * Listens for when the RPC service retries the request.
@@ -246,7 +257,7 @@ class RpcService {
246
257
  }
247
258
  /**
248
259
  * Listens for when the RPC service retries the request too many times in a
249
- * row.
260
+ * row, causing the underlying circuit to break.
250
261
  *
251
262
  * @param listener - The callback to be called when the circuit is broken.
252
263
  * @returns What {@link ServicePolicy.onBreak} returns.
@@ -254,13 +265,20 @@ class RpcService {
254
265
  */
255
266
  onBreak(listener) {
256
267
  return __classPrivateFieldGet(this, _RpcService_policy, "f").onBreak((data) => {
257
- listener({
258
- ...data,
259
- endpointUrl: this.endpointUrl.toString(),
260
- failoverEndpointUrl: __classPrivateFieldGet(this, _RpcService_failoverService, "f")
261
- ? __classPrivateFieldGet(this, _RpcService_failoverService, "f").endpointUrl.toString()
262
- : undefined,
263
- });
268
+ // `{ isolated: true }` is a special object that shows up when `isolate`
269
+ // is called on the circuit breaker. Usually `isolate` is used to hold the
270
+ // circuit open, but we (ab)use this method in `createServicePolicy` to
271
+ // reset the circuit breaker policy. When we do this, we don't want to
272
+ // call `onBreak` handlers, because then it causes
273
+ // `NetworkController:rpcEndpointUnavailable` and
274
+ // `NetworkController:rpcEndpointChainUnavailable` to be published. So we
275
+ // have to ignore that object here. The consequence is that `isolate`
276
+ // doesn't function the way it is intended, at least in the context of an
277
+ // RpcService. However, we are making a bet that we won't need to use it
278
+ // other than how we are already using it.
279
+ if (!('isolated' in data)) {
280
+ listener({ ...data, endpointUrl: this.endpointUrl.toString() });
281
+ }
264
282
  });
265
283
  }
266
284
  /**
@@ -276,24 +294,27 @@ class RpcService {
276
294
  listener({ ...(data ?? {}), endpointUrl: this.endpointUrl.toString() });
277
295
  });
278
296
  }
297
+ /**
298
+ * Listens for when the policy underlying this RPC service is available.
299
+ *
300
+ * @param listener - The callback to be called when the request is available.
301
+ * @returns What {@link ServicePolicy.onAvailable} returns.
302
+ * @see {@link createServicePolicy}
303
+ */
304
+ onAvailable(listener) {
305
+ return __classPrivateFieldGet(this, _RpcService_policy, "f").onAvailable(() => {
306
+ listener({ endpointUrl: this.endpointUrl.toString() });
307
+ });
308
+ }
279
309
  async request(
280
310
  // The request object may be frozen and must not be mutated.
281
311
  jsonRpcRequest, fetchOptions = {}) {
282
312
  const completeFetchOptions = __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_getCompleteFetchOptions).call(this, jsonRpcRequest, fetchOptions);
283
- try {
284
- return await __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_processRequest).call(this, completeFetchOptions);
285
- }
286
- catch (error) {
287
- if (__classPrivateFieldGet(this, _RpcService_policy, "f").circuitBreakerPolicy.state === controller_utils_1.CircuitState.Open &&
288
- __classPrivateFieldGet(this, _RpcService_failoverService, "f") !== undefined) {
289
- return await __classPrivateFieldGet(this, _RpcService_failoverService, "f").request(jsonRpcRequest, completeFetchOptions);
290
- }
291
- throw error;
292
- }
313
+ return await __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_executeAndProcessRequest).call(this, completeFetchOptions);
293
314
  }
294
315
  }
295
316
  exports.RpcService = RpcService;
296
- _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _RpcService_failoverService = new WeakMap(), _RpcService_logger = new WeakMap(), _RpcService_policy = new WeakMap(), _RpcService_instances = new WeakSet(), _RpcService_getDefaultFetchOptions = function _RpcService_getDefaultFetchOptions(endpointUrl, fetchOptions, givenBtoa) {
317
+ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _RpcService_logger = new WeakMap(), _RpcService_policy = new WeakMap(), _RpcService_instances = new WeakSet(), _RpcService_getDefaultFetchOptions = function _RpcService_getDefaultFetchOptions(endpointUrl, fetchOptions, givenBtoa) {
297
318
  if (endpointUrl.username && endpointUrl.password) {
298
319
  const authString = `${endpointUrl.username}:${endpointUrl.password}`;
299
320
  const encodedCredentials = givenBtoa(authString);
@@ -319,7 +340,7 @@ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _Rp
319
340
  params,
320
341
  });
321
342
  return { ...mergedOptions, body };
322
- }, _RpcService_processRequest =
343
+ }, _RpcService_executeAndProcessRequest =
323
344
  /**
324
345
  * Makes the request using the Cockatiel policy that this service creates.
325
346
  *
@@ -332,18 +353,29 @@ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _Rp
332
353
  * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.
333
354
  * @throws A "parse" JSON-RPC error (code -32700) if the response is not valid JSON.
334
355
  */
335
- async function _RpcService_processRequest(fetchOptions) {
356
+ async function _RpcService_executeAndProcessRequest(fetchOptions) {
336
357
  let response;
337
358
  try {
338
- return await __classPrivateFieldGet(this, _RpcService_policy, "f").execute(async () => {
359
+ log(`[${this.endpointUrl}] Circuit state`, __classPrivateFieldGet(this, _RpcService_policy, "f").getCircuitState());
360
+ const jsonDecodedResponse = await __classPrivateFieldGet(this, _RpcService_policy, "f").execute(async (context) => {
361
+ log('REQUEST INITIATED:', this.endpointUrl.toString(), '::', fetchOptions,
362
+ // @ts-expect-error This property _is_ here, the type of
363
+ // ServicePolicy is just wrong.
364
+ `(attempt ${context.attempt + 1})`);
339
365
  response = await __classPrivateFieldGet(this, _RpcService_fetch, "f").call(this, this.endpointUrl, fetchOptions);
340
366
  if (!response.ok) {
341
367
  throw new controller_utils_1.HttpError(response.status);
342
368
  }
369
+ log('REQUEST SUCCESSFUL:', this.endpointUrl.toString(), response.status);
343
370
  return await response.json();
344
371
  });
372
+ this.lastError = undefined;
373
+ return jsonDecodedResponse;
345
374
  }
346
375
  catch (error) {
376
+ log('REQUEST ERROR:', this.endpointUrl.toString(), error);
377
+ this.lastError =
378
+ error instanceof Error ? error : new Error((0, utils_1.getErrorMessage)(error));
347
379
  if (error instanceof controller_utils_1.HttpError) {
348
380
  const status = error.httpStatus;
349
381
  if (status === 401) {
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-service.cjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport {\n BrokenCircuitError,\n CircuitState,\n HttpError,\n createServicePolicy,\n handleWhen,\n} from '@metamask/controller-utils';\nimport { JsonRpcError, rpcErrors } from '@metamask/rpc-errors';\nimport type { JsonRpcRequest } from '@metamask/utils';\nimport {\n Duration,\n getErrorMessage,\n hasProperty,\n type Json,\n type JsonRpcParams,\n type JsonRpcResponse,\n} from '@metamask/utils';\nimport deepmerge from 'deepmerge';\nimport type { Logger } from 'loglevel';\n\nimport type { AbstractRpcService } from './abstract-rpc-service';\nimport type { AddToCockatielEventData, FetchOptions } from './shared';\n\n/**\n * Options for the RpcService constructor.\n */\nexport type RpcServiceOptions = {\n /**\n * A function that can be used to convert a binary string into a\n * base64-encoded ASCII string. Used to encode authorization credentials.\n */\n btoa: typeof btoa;\n /**\n * The URL of the RPC endpoint to hit.\n */\n endpointUrl: URL | string;\n /**\n * An RPC service that represents a failover endpoint which will be invoked\n * while the circuit for _this_ service is open.\n */\n failoverService?: AbstractRpcService;\n /**\n * A function that can be used to make an HTTP request. If your JavaScript\n * environment supports `fetch` natively, you'll probably want to pass that;\n * otherwise you can pass an equivalent (such as `fetch` via `node-fetch`).\n */\n fetch: typeof fetch;\n /**\n * A common set of options that will be used to make every request. Can be\n * overridden on the request level (e.g. to add headers).\n */\n fetchOptions?: FetchOptions;\n /**\n * A `loglevel` logger.\n */\n logger?: Pick<Logger, 'warn'>;\n /**\n * Options to pass to `createServicePolicy`. Note that `retryFilterPolicy` is\n * not accepted, as it is overwritten. See {@link createServicePolicy}.\n */\n policyOptions?: Omit<CreateServicePolicyOptions, 'retryFilterPolicy'>;\n};\n\n/**\n * The maximum number of times that a failing service should be re-run before\n * giving up.\n */\nexport const DEFAULT_MAX_RETRIES = 4;\n\n/**\n * The maximum number of times that the service is allowed to fail before\n * pausing further retries. This is set to a value such that if given a\n * service that continually fails, the policy needs to be executed 3 times\n * before further retries are paused.\n */\nexport const DEFAULT_MAX_CONSECUTIVE_FAILURES = (1 + DEFAULT_MAX_RETRIES) * 3;\n\n/**\n * The list of error messages that represent a failure to connect to the network.\n *\n * This list was derived from Sindre Sorhus's `is-network-error` package:\n * <https://github.com/sindresorhus/is-network-error/blob/7bbfa8be9482ce1427a21fbff60e3ee1650dd091/index.js>\n */\nexport const CONNECTION_ERRORS = [\n // Chrome\n {\n constructorName: 'TypeError',\n pattern: /network error/u,\n },\n // Chrome\n {\n constructorName: 'TypeError',\n pattern: /Failed to fetch/u,\n },\n // Firefox\n {\n constructorName: 'TypeError',\n pattern: /NetworkError when attempting to fetch resource\\./u,\n },\n // Safari 16\n {\n constructorName: 'TypeError',\n pattern: /The Internet connection appears to be offline\\./u,\n },\n // Safari 17+\n {\n constructorName: 'TypeError',\n pattern: /Load failed/u,\n },\n // `cross-fetch`\n {\n constructorName: 'TypeError',\n pattern: /Network request failed/u,\n },\n // `node-fetch`\n {\n constructorName: 'FetchError',\n pattern: /request to (.+) failed/u,\n },\n // Undici (Node.js)\n {\n constructorName: 'TypeError',\n pattern: /fetch failed/u,\n },\n // Undici (Node.js)\n {\n constructorName: 'TypeError',\n pattern: /terminated/u,\n },\n];\n\n/**\n * Custom JSON-RPC error codes for specific cases.\n *\n * These should be moved to `@metamask/rpc-errors` eventually.\n */\nexport const CUSTOM_RPC_ERRORS = {\n unauthorized: -32006,\n httpClientError: -32080,\n} as const;\n\n/**\n * Determines whether the given error represents a failure to reach the network\n * after request parameters have been validated.\n *\n * This is somewhat difficult to verify because JavaScript engines (and in\n * some cases libraries) produce slightly different error messages for this\n * particular scenario, and we need to account for this.\n *\n * @param error - The error.\n * @returns True if the error indicates that the network cannot be connected to,\n * and false otherwise.\n */\nexport function isConnectionError(error: unknown) {\n if (!(typeof error === 'object' && error !== null && 'message' in error)) {\n return false;\n }\n\n const { message } = error;\n\n return (\n typeof message === 'string' &&\n !isNockError(message) &&\n CONNECTION_ERRORS.some(({ constructorName, pattern }) => {\n return (\n error.constructor.name === constructorName && pattern.test(message)\n );\n })\n );\n}\n\n/**\n * Determines whether the given error message refers to a Nock error.\n *\n * It's important that if we failed to mock a request in a test, the resulting\n * error does not cause the request to be retried so that we can see it right\n * away.\n *\n * @param message - The error message to test.\n * @returns True if the message indicates a missing Nock mock, false otherwise.\n */\nfunction isNockError(message: string) {\n return message.includes('Nock:');\n}\n\n/**\n * Determine whether the given error message indicates a failure to parse JSON.\n *\n * This is different in tests vs. implementation code because it may manifest as\n * a FetchError or a SyntaxError.\n *\n * @param error - The error object to test.\n * @returns True if the error indicates a JSON parse error, false otherwise.\n */\nfunction isJsonParseError(error: unknown) {\n return (\n error instanceof SyntaxError ||\n /invalid json/iu.test(getErrorMessage(error))\n );\n}\n\n/**\n * Guarantees a URL, even given a string. This is useful for checking components\n * of that URL.\n *\n * @param endpointUrlOrUrlString - Either a URL object or a string that\n * represents the URL of an endpoint.\n * @returns A URL object.\n */\nfunction getNormalizedEndpointUrl(endpointUrlOrUrlString: URL | string): URL {\n return endpointUrlOrUrlString instanceof URL\n ? endpointUrlOrUrlString\n : new URL(endpointUrlOrUrlString);\n}\n\n/**\n * Strips username and password from a URL.\n *\n * @param url - The URL to strip credentials from.\n * @returns A new URL object with credentials removed.\n */\nfunction stripCredentialsFromUrl(url: URL): URL {\n const strippedUrl = new URL(url.toString());\n strippedUrl.username = '';\n strippedUrl.password = '';\n return strippedUrl;\n}\n\n/**\n * This class is responsible for making a request to an endpoint that implements\n * the JSON-RPC protocol. It is designed to gracefully handle network and server\n * failures, retrying requests using exponential backoff. It also offers a hook\n * which can used to respond to slow requests.\n */\nexport class RpcService implements AbstractRpcService {\n /**\n * The function used to make an HTTP request.\n */\n readonly #fetch: typeof fetch;\n\n /**\n * The URL of the RPC endpoint.\n */\n readonly endpointUrl: URL;\n\n /**\n * A common set of options that the request options will extend.\n */\n readonly #fetchOptions: FetchOptions;\n\n /**\n * An RPC service that represents a failover endpoint which will be invoked\n * while the circuit for _this_ service is open.\n */\n readonly #failoverService: RpcServiceOptions['failoverService'];\n\n /**\n * A `loglevel` logger.\n */\n readonly #logger: RpcServiceOptions['logger'];\n\n /**\n * The policy that wraps the request.\n */\n readonly #policy: ServicePolicy;\n\n /**\n * Constructs a new RpcService object.\n *\n * @param options - The options. See {@link RpcServiceOptions}.\n */\n constructor(options: RpcServiceOptions) {\n const {\n btoa: givenBtoa,\n endpointUrl,\n failoverService,\n fetch: givenFetch,\n logger,\n fetchOptions = {},\n policyOptions = {},\n } = options;\n\n this.#fetch = givenFetch;\n const normalizedUrl = getNormalizedEndpointUrl(endpointUrl);\n this.#fetchOptions = this.#getDefaultFetchOptions(\n normalizedUrl,\n fetchOptions,\n givenBtoa,\n );\n this.endpointUrl = stripCredentialsFromUrl(normalizedUrl);\n this.#failoverService = failoverService;\n this.#logger = logger;\n\n const policy = createServicePolicy({\n maxRetries: DEFAULT_MAX_RETRIES,\n maxConsecutiveFailures: DEFAULT_MAX_CONSECUTIVE_FAILURES,\n ...policyOptions,\n retryFilterPolicy: handleWhen((error) => {\n return (\n // Ignore errors where the request failed to establish\n isConnectionError(error) ||\n // Ignore server sent HTML error pages or truncated JSON responses\n isJsonParseError(error) ||\n // Ignore server overload errors\n ('httpStatus' in error &&\n (error.httpStatus === 502 ||\n error.httpStatus === 503 ||\n error.httpStatus === 504)) ||\n (hasProperty(error, 'code') &&\n (error.code === 'ETIMEDOUT' || error.code === 'ECONNRESET'))\n );\n }),\n });\n this.#policy = policy;\n }\n\n /**\n * Listens for when the RPC service retries the request.\n *\n * @param listener - The callback to be called when the retry occurs.\n * @returns What {@link ServicePolicy.onRetry} returns.\n * @see {@link createServicePolicy}\n */\n onRetry(\n listener: AddToCockatielEventData<\n Parameters<ServicePolicy['onRetry']>[0],\n { endpointUrl: string }\n >,\n ) {\n return this.#policy.onRetry((data) => {\n listener({ ...data, endpointUrl: this.endpointUrl.toString() });\n });\n }\n\n /**\n * Listens for when the RPC service retries the request too many times in a\n * row.\n *\n * @param listener - The callback to be called when the circuit is broken.\n * @returns What {@link ServicePolicy.onBreak} returns.\n * @see {@link createServicePolicy}\n */\n onBreak(\n listener: AddToCockatielEventData<\n Parameters<ServicePolicy['onBreak']>[0],\n { endpointUrl: string; failoverEndpointUrl?: string }\n >,\n ) {\n return this.#policy.onBreak((data) => {\n listener({\n ...data,\n endpointUrl: this.endpointUrl.toString(),\n failoverEndpointUrl: this.#failoverService\n ? this.#failoverService.endpointUrl.toString()\n : undefined,\n });\n });\n }\n\n /**\n * Listens for when the policy underlying this RPC service detects a slow\n * request.\n *\n * @param listener - The callback to be called when the request is slow.\n * @returns What {@link ServicePolicy.onDegraded} returns.\n * @see {@link createServicePolicy}\n */\n onDegraded(\n listener: AddToCockatielEventData<\n Parameters<ServicePolicy['onDegraded']>[0],\n { endpointUrl: string }\n >,\n ) {\n return this.#policy.onDegraded((data) => {\n listener({ ...(data ?? {}), endpointUrl: this.endpointUrl.toString() });\n });\n }\n\n /**\n * Makes a request to the RPC endpoint. If the circuit is open because this\n * request has failed too many times, the request is forwarded to a failover\n * service (if provided).\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 An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\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 RPC endpoint. If the circuit is open because this\n * request has failed too many times, the request is forwarded to a failover\n * service (if provided).\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 An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\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 // The request object may be frozen and must not be mutated.\n jsonRpcRequest: Readonly<JsonRpcRequest<Params>>,\n fetchOptions: FetchOptions = {},\n ): Promise<JsonRpcResponse<Result | null>> {\n const completeFetchOptions = this.#getCompleteFetchOptions(\n jsonRpcRequest,\n fetchOptions,\n );\n\n try {\n return await this.#processRequest<Result>(completeFetchOptions);\n } catch (error) {\n if (\n this.#policy.circuitBreakerPolicy.state === CircuitState.Open &&\n this.#failoverService !== undefined\n ) {\n return await this.#failoverService.request(\n jsonRpcRequest,\n completeFetchOptions,\n );\n }\n throw error;\n }\n }\n\n /**\n * Constructs a default set of options to `fetch`.\n *\n * If a username and password are present in the URL, they are extracted to an\n * Authorization header.\n *\n * @param endpointUrl - The endpoint URL.\n * @param fetchOptions - The options to `fetch`.\n * @param givenBtoa - An implementation of `btoa`.\n * @returns The default fetch options.\n */\n #getDefaultFetchOptions(\n endpointUrl: URL,\n fetchOptions: FetchOptions,\n givenBtoa: (stringToEncode: string) => string,\n ): FetchOptions {\n if (endpointUrl.username && endpointUrl.password) {\n const authString = `${endpointUrl.username}:${endpointUrl.password}`;\n const encodedCredentials = givenBtoa(authString);\n return deepmerge(fetchOptions, {\n headers: { Authorization: `Basic ${encodedCredentials}` },\n });\n }\n\n return fetchOptions;\n }\n\n /**\n * Constructs a final set of options to pass to `fetch`. Note that the method\n * defaults to `post`, and the JSON-RPC request is automatically JSON-encoded.\n *\n * @param jsonRpcRequest - The JSON-RPC request.\n * @param fetchOptions - Custom `fetch` options.\n * @returns The complete set of `fetch` options.\n */\n #getCompleteFetchOptions<Params extends JsonRpcParams>(\n jsonRpcRequest: Readonly<JsonRpcRequest<Params>>,\n fetchOptions: FetchOptions,\n ): FetchOptions {\n const defaultOptions = {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n };\n const mergedOptions = deepmerge(\n defaultOptions,\n deepmerge(this.#fetchOptions, fetchOptions),\n );\n\n const { id, jsonrpc, method, params } = jsonRpcRequest;\n const body = JSON.stringify({\n id,\n jsonrpc,\n method,\n params,\n });\n\n return { ...mergedOptions, body };\n }\n\n /**\n * Makes the request using the Cockatiel policy that this service creates.\n *\n * @param fetchOptions - The options for `fetch`; will be combined with the\n * fetch options passed to the constructor\n * @returns The decoded JSON-RPC response from the endpoint.\n * @throws An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\n */\n async #processRequest<Result extends Json>(\n fetchOptions: FetchOptions,\n ): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>> {\n let response: Response | undefined;\n try {\n return await this.#policy.execute(async () => {\n response = await this.#fetch(this.endpointUrl, fetchOptions);\n if (!response.ok) {\n throw new HttpError(response.status);\n }\n return await response.json();\n });\n } catch (error) {\n if (error instanceof HttpError) {\n const status = error.httpStatus;\n if (status === 401) {\n throw new JsonRpcError(\n CUSTOM_RPC_ERRORS.unauthorized,\n 'Unauthorized.',\n {\n httpStatus: status,\n },\n );\n }\n if (status === 429) {\n throw rpcErrors.limitExceeded({\n message: 'Request is being rate limited.',\n data: {\n httpStatus: status,\n },\n });\n }\n if (status >= 500 || status === 402 || status === 404) {\n throw rpcErrors.resourceUnavailable({\n message: 'RPC endpoint not found or unavailable.',\n data: {\n httpStatus: status,\n },\n });\n }\n\n // Handle all other 4xx errors as generic HTTP client errors\n throw new JsonRpcError(\n CUSTOM_RPC_ERRORS.httpClientError,\n 'RPC endpoint returned HTTP client error.',\n {\n httpStatus: status,\n },\n );\n } else if (isJsonParseError(error)) {\n throw rpcErrors.parse({\n message: 'RPC endpoint did not return JSON.',\n });\n } else if (error instanceof BrokenCircuitError) {\n this.#logger?.warn(error);\n const remainingCircuitOpenDuration =\n this.#policy.getRemainingCircuitOpenDuration();\n const formattedRemainingCircuitOpenDuration = Intl.NumberFormat(\n undefined,\n { maximumFractionDigits: 2 },\n ).format(\n (remainingCircuitOpenDuration ?? this.#policy.circuitBreakDuration) /\n Duration.Minute,\n );\n throw rpcErrors.resourceUnavailable({\n message: `RPC endpoint returned too many errors, retrying in ${formattedRemainingCircuitOpenDuration} minutes. Consider using a different RPC endpoint.`,\n });\n }\n throw error;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"rpc-service.cjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAIA,iEAKoC;AACpC,qDAA+D;AAE/D,2CAOyB;AACzB,0DAAkC;AAKlC,0CAA8D;AAqC9D,MAAM,GAAG,GAAG,IAAA,2BAAkB,EAAC,sBAAa,EAAE,YAAY,CAAC,CAAC;AAE5D;;;GAGG;AACU,QAAA,mBAAmB,GAAG,CAAC,CAAC;AAErC;;;;;GAKG;AACU,QAAA,gCAAgC,GAAG,CAAC,CAAC,GAAG,2BAAmB,CAAC,GAAG,CAAC,CAAC;AAE9E;;;;;GAKG;AACU,QAAA,iBAAiB,GAAG;IAC/B,SAAS;IACT;QACE,eAAe,EAAE,WAAW;QAC5B,OAAO,EAAE,gBAAgB;KAC1B;IACD,SAAS;IACT;QACE,eAAe,EAAE,WAAW;QAC5B,OAAO,EAAE,kBAAkB;KAC5B;IACD,UAAU;IACV;QACE,eAAe,EAAE,WAAW;QAC5B,OAAO,EAAE,mDAAmD;KAC7D;IACD,YAAY;IACZ;QACE,eAAe,EAAE,WAAW;QAC5B,OAAO,EAAE,kDAAkD;KAC5D;IACD,aAAa;IACb;QACE,eAAe,EAAE,WAAW;QAC5B,OAAO,EAAE,cAAc;KACxB;IACD,gBAAgB;IAChB;QACE,eAAe,EAAE,WAAW;QAC5B,OAAO,EAAE,yBAAyB;KACnC;IACD,eAAe;IACf;QACE,eAAe,EAAE,YAAY;QAC7B,OAAO,EAAE,yBAAyB;KACnC;IACD,mBAAmB;IACnB;QACE,eAAe,EAAE,WAAW;QAC5B,OAAO,EAAE,eAAe;KACzB;IACD,mBAAmB;IACnB;QACE,eAAe,EAAE,WAAW;QAC5B,OAAO,EAAE,aAAa;KACvB;CACF,CAAC;AAEF;;;;GAIG;AACU,QAAA,iBAAiB,GAAG;IAC/B,YAAY,EAAE,CAAC,KAAK;IACpB,eAAe,EAAE,CAAC,KAAK;CACf,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,SAAgB,iBAAiB,CAAC,KAAc;IAC9C,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,SAAS,IAAI,KAAK,CAAC,EAAE,CAAC;QACzE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAE1B,OAAO,CACL,OAAO,OAAO,KAAK,QAAQ;QAC3B,CAAC,WAAW,CAAC,OAAO,CAAC;QACrB,yBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,EAAE,EAAE,EAAE;YACtD,OAAO,CACL,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CACpE,CAAC;QACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAhBD,8CAgBC;AAED;;;;;;;;;GASG;AACH,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,CACL,KAAK,YAAY,WAAW;QAC5B,gBAAgB,CAAC,IAAI,CAAC,IAAA,uBAAe,EAAC,KAAK,CAAC,CAAC,CAC9C,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,wBAAwB,CAAC,sBAAoC;IACpE,OAAO,sBAAsB,YAAY,GAAG;QAC1C,CAAC,CAAC,sBAAsB;QACxB,CAAC,CAAC,IAAI,GAAG,CAAC,sBAAsB,CAAC,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,SAAS,uBAAuB,CAAC,GAAQ;IACvC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5C,WAAW,CAAC,QAAQ,GAAG,EAAE,CAAC;IAC1B,WAAW,CAAC,QAAQ,GAAG,EAAE,CAAC;IAC1B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAa,UAAU;IAgCrB;;;;OAIG;IACH,YAAY,OAA0B;;QAzBtC;;WAEG;QACM,oCAAqB;QAE9B;;WAEG;QACM,2CAA4B;QAErC;;WAEG;QACM,qCAAqC;QAE9C;;WAEG;QACM,qCAAuB;QAQ9B,MAAM,EACJ,IAAI,EAAE,SAAS,EACf,WAAW,EACX,KAAK,EAAE,UAAU,EACjB,MAAM,EACN,YAAY,GAAG,EAAE,EACjB,aAAa,GAAG,EAAE,GACnB,GAAG,OAAO,CAAC;QAEZ,uBAAA,IAAI,qBAAU,UAAU,MAAA,CAAC;QACzB,MAAM,aAAa,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC;QAC5D,uBAAA,IAAI,4BAAiB,uBAAA,IAAI,iEAAwB,MAA5B,IAAI,EACvB,aAAa,EACb,YAAY,EACZ,SAAS,CACV,MAAA,CAAC;QACF,IAAI,CAAC,WAAW,GAAG,uBAAuB,CAAC,aAAa,CAAC,CAAC;QAC1D,uBAAA,IAAI,sBAAW,MAAM,MAAA,CAAC;QAEtB,uBAAA,IAAI,sBAAW,IAAA,sCAAmB,EAAC;YACjC,UAAU,EAAE,2BAAmB;YAC/B,sBAAsB,EAAE,wCAAgC;YACxD,GAAG,aAAa;YAChB,iBAAiB,EAAE,IAAA,6BAAU,EAAC,CAAC,KAAK,EAAE,EAAE;gBACtC,OAAO;gBACL,sDAAsD;gBACtD,iBAAiB,CAAC,KAAK,CAAC;oBACxB,kEAAkE;oBAClE,gBAAgB,CAAC,KAAK,CAAC;oBACvB,gCAAgC;oBAChC,CAAC,YAAY,IAAI,KAAK;wBACpB,CAAC,KAAK,CAAC,UAAU,KAAK,GAAG;4BACvB,KAAK,CAAC,UAAU,KAAK,GAAG;4BACxB,KAAK,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC;oBAC9B,CAAC,IAAA,mBAAW,EAAC,KAAK,EAAE,MAAM,CAAC;wBACzB,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAC/D,CAAC;YACJ,CAAC,CAAC;SACH,CAAC,MAAA,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,WAAW;QACT,uBAAA,IAAI,0BAAQ,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,uBAAA,IAAI,0BAAQ,CAAC,eAAe,EAAE,CAAC;IACxC,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,QAAsD;QAC5D,OAAO,uBAAA,IAAI,0BAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACnC,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,QAAsD;QAC5D,OAAO,uBAAA,IAAI,0BAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACnC,wEAAwE;YACxE,0EAA0E;YAC1E,uEAAuE;YACvE,sEAAsE;YACtE,kDAAkD;YAClD,iDAAiD;YACjD,yEAAyE;YACzE,qEAAqE;YACrE,yEAAyE;YACzE,wEAAwE;YACxE,0CAA0C;YAC1C,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,EAAE,CAAC;gBAC1B,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,UAAU,CAAC,QAAyD;QAClE,OAAO,uBAAA,IAAI,0BAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE;YACtC,QAAQ,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,QAA0D;QACpE,OAAO,uBAAA,IAAI,0BAAQ,CAAC,WAAW,CAAC,GAAG,EAAE;YACnC,QAAQ,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACL,CAAC;IA8CD,KAAK,CAAC,OAAO;IACX,4DAA4D;IAC5D,cAAgD,EAChD,eAA6B,EAAE;QAE/B,MAAM,oBAAoB,GAAG,uBAAA,IAAI,kEAAyB,MAA7B,IAAI,EAC/B,cAAc,EACd,YAAY,CACb,CAAC;QACF,OAAO,MAAM,uBAAA,IAAI,mEAA0B,MAA9B,IAAI,EAAmC,oBAAoB,CAAC,CAAC;IAC5E,CAAC;CA8KF;AAxYD,gCAwYC;6QAhKG,WAAgB,EAChB,YAA0B,EAC1B,SAA6C;IAE7C,IAAI,WAAW,CAAC,QAAQ,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;QACjD,MAAM,UAAU,GAAG,GAAG,WAAW,CAAC,QAAQ,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;QACrE,MAAM,kBAAkB,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;QACjD,OAAO,IAAA,mBAAS,EAAC,YAAY,EAAE;YAC7B,OAAO,EAAE,EAAE,aAAa,EAAE,SAAS,kBAAkB,EAAE,EAAE;SAC1D,CAAC,CAAC;IACL,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC,qFAWC,cAAgD,EAChD,YAA0B;IAE1B,MAAM,cAAc,GAAG;QACrB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,cAAc,EAAE,kBAAkB;SACnC;KACF,CAAC;IACF,MAAM,aAAa,GAAG,IAAA,mBAAS,EAC7B,cAAc,EACd,IAAA,mBAAS,EAAC,uBAAA,IAAI,gCAAc,EAAE,YAAY,CAAC,CAC5C,CAAC;IAEF,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC;IACvD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1B,EAAE;QACF,OAAO;QACP,MAAM;QACN,MAAM;KACP,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,aAAa,EAAE,IAAI,EAAE,CAAC;AACpC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,KAAK,+CACH,YAA0B;IAE1B,IAAI,QAA8B,CAAC;IACnC,IAAI,CAAC;QACH,GAAG,CACD,IAAI,IAAI,CAAC,WAAW,iBAAiB,EACrC,uBAAA,IAAI,0BAAQ,CAAC,eAAe,EAAE,CAC/B,CAAC;QACF,MAAM,mBAAmB,GAAG,MAAM,uBAAA,IAAI,0BAAQ,CAAC,OAAO,CACpD,KAAK,EAAE,OAAO,EAAE,EAAE;YAChB,GAAG,CACD,oBAAoB,EACpB,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAC3B,IAAI,EACJ,YAAY;YACZ,wDAAwD;YACxD,+BAA+B;YAC/B,YAAY,OAAO,CAAC,OAAO,GAAG,CAAC,GAAG,CACnC,CAAC;YACF,QAAQ,GAAG,MAAM,uBAAA,IAAI,yBAAO,MAAX,IAAI,EAAQ,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;YAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,4BAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACvC,CAAC;YACD,GAAG,CACD,qBAAqB,EACrB,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAC3B,QAAQ,CAAC,MAAM,CAChB,CAAC;YACF,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC,CACF,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC;QAE1D,IAAI,CAAC,SAAS;YACZ,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAA,uBAAe,EAAC,KAAK,CAAC,CAAC,CAAC;QAErE,IAAI,KAAK,YAAY,4BAAS,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC;YAChC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM,IAAI,yBAAY,CACpB,yBAAiB,CAAC,YAAY,EAC9B,eAAe,EACf;oBACE,UAAU,EAAE,MAAM;iBACnB,CACF,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM,sBAAS,CAAC,aAAa,CAAC;oBAC5B,OAAO,EAAE,gCAAgC;oBACzC,IAAI,EAAE;wBACJ,UAAU,EAAE,MAAM;qBACnB;iBACF,CAAC,CAAC;YACL,CAAC;YACD,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACtD,MAAM,sBAAS,CAAC,mBAAmB,CAAC;oBAClC,OAAO,EAAE,wCAAwC;oBACjD,IAAI,EAAE;wBACJ,UAAU,EAAE,MAAM;qBACnB;iBACF,CAAC,CAAC;YACL,CAAC;YAED,4DAA4D;YAC5D,MAAM,IAAI,yBAAY,CACpB,yBAAiB,CAAC,eAAe,EACjC,0CAA0C,EAC1C;gBACE,UAAU,EAAE,MAAM;aACnB,CACF,CAAC;QACJ,CAAC;aAAM,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,sBAAS,CAAC,KAAK,CAAC;gBACpB,OAAO,EAAE,mCAAmC;aAC7C,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,YAAY,qCAAkB,EAAE,CAAC;YAC/C,uBAAA,IAAI,0BAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,MAAM,4BAA4B,GAChC,uBAAA,IAAI,0BAAQ,CAAC,+BAA+B,EAAE,CAAC;YACjD,MAAM,qCAAqC,GAAG,IAAI,CAAC,YAAY,CAC7D,SAAS,EACT,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAC7B,CAAC,MAAM,CACN,CAAC,4BAA4B,IAAI,uBAAA,IAAI,0BAAQ,CAAC,oBAAoB,CAAC;gBACjE,gBAAQ,CAAC,MAAM,CAClB,CAAC;YACF,MAAM,sBAAS,CAAC,mBAAmB,CAAC;gBAClC,OAAO,EAAE,sDAAsD,qCAAqC,oDAAoD;aACzJ,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport {\n BrokenCircuitError,\n HttpError,\n createServicePolicy,\n handleWhen,\n} from '@metamask/controller-utils';\nimport { JsonRpcError, rpcErrors } from '@metamask/rpc-errors';\nimport type { JsonRpcRequest } from '@metamask/utils';\nimport {\n Duration,\n getErrorMessage,\n hasProperty,\n type Json,\n type JsonRpcParams,\n type JsonRpcResponse,\n} from '@metamask/utils';\nimport deepmerge from 'deepmerge';\nimport type { Logger } from 'loglevel';\n\nimport type { AbstractRpcService } from './abstract-rpc-service';\nimport type { FetchOptions } from './shared';\nimport { projectLogger, createModuleLogger } from '../logger';\n\n/**\n * Options for the RpcService constructor.\n */\nexport type RpcServiceOptions = {\n /**\n * A function that can be used to convert a binary string into a\n * base64-encoded ASCII string. Used to encode authorization credentials.\n */\n btoa: typeof btoa;\n /**\n * The URL of the RPC endpoint to hit.\n */\n endpointUrl: URL | string;\n /**\n * A function that can be used to make an HTTP request. If your JavaScript\n * environment supports `fetch` natively, you'll probably want to pass that;\n * otherwise you can pass an equivalent (such as `fetch` via `node-fetch`).\n */\n fetch: typeof fetch;\n /**\n * A common set of options that will be used to make every request. Can be\n * overridden on the request level (e.g. to add headers).\n */\n fetchOptions?: FetchOptions;\n /**\n * A `loglevel` logger.\n */\n logger?: Pick<Logger, 'warn'>;\n /**\n * Options to pass to `createServicePolicy`. Note that `retryFilterPolicy` is\n * not accepted, as it is overwritten. See {@link createServicePolicy}.\n */\n policyOptions?: Omit<CreateServicePolicyOptions, 'retryFilterPolicy'>;\n};\n\nconst log = createModuleLogger(projectLogger, 'RpcService');\n\n/**\n * The maximum number of times that a failing service should be re-run before\n * giving up.\n */\nexport const DEFAULT_MAX_RETRIES = 4;\n\n/**\n * The maximum number of times that the service is allowed to fail before\n * pausing further retries. This is set to a value such that if given a\n * service that continually fails, the policy needs to be executed 3 times\n * before further retries are paused.\n */\nexport const DEFAULT_MAX_CONSECUTIVE_FAILURES = (1 + DEFAULT_MAX_RETRIES) * 3;\n\n/**\n * The list of error messages that represent a failure to connect to the network.\n *\n * This list was derived from Sindre Sorhus's `is-network-error` package:\n * <https://github.com/sindresorhus/is-network-error/blob/7bbfa8be9482ce1427a21fbff60e3ee1650dd091/index.js>\n */\nexport const CONNECTION_ERRORS = [\n // Chrome\n {\n constructorName: 'TypeError',\n pattern: /network error/u,\n },\n // Chrome\n {\n constructorName: 'TypeError',\n pattern: /Failed to fetch/u,\n },\n // Firefox\n {\n constructorName: 'TypeError',\n pattern: /NetworkError when attempting to fetch resource\\./u,\n },\n // Safari 16\n {\n constructorName: 'TypeError',\n pattern: /The Internet connection appears to be offline\\./u,\n },\n // Safari 17+\n {\n constructorName: 'TypeError',\n pattern: /Load failed/u,\n },\n // `cross-fetch`\n {\n constructorName: 'TypeError',\n pattern: /Network request failed/u,\n },\n // `node-fetch`\n {\n constructorName: 'FetchError',\n pattern: /request to (.+) failed/u,\n },\n // Undici (Node.js)\n {\n constructorName: 'TypeError',\n pattern: /fetch failed/u,\n },\n // Undici (Node.js)\n {\n constructorName: 'TypeError',\n pattern: /terminated/u,\n },\n];\n\n/**\n * Custom JSON-RPC error codes for specific cases.\n *\n * These should be moved to `@metamask/rpc-errors` eventually.\n */\nexport const CUSTOM_RPC_ERRORS = {\n unauthorized: -32006,\n httpClientError: -32080,\n} as const;\n\n/**\n * Determines whether the given error represents a failure to reach the network\n * after request parameters have been validated.\n *\n * This is somewhat difficult to verify because JavaScript engines (and in\n * some cases libraries) produce slightly different error messages for this\n * particular scenario, and we need to account for this.\n *\n * @param error - The error.\n * @returns True if the error indicates that the network cannot be connected to,\n * and false otherwise.\n */\nexport function isConnectionError(error: unknown) {\n if (!(typeof error === 'object' && error !== null && 'message' in error)) {\n return false;\n }\n\n const { message } = error;\n\n return (\n typeof message === 'string' &&\n !isNockError(message) &&\n CONNECTION_ERRORS.some(({ constructorName, pattern }) => {\n return (\n error.constructor.name === constructorName && pattern.test(message)\n );\n })\n );\n}\n\n/**\n * Determines whether the given error message refers to a Nock error.\n *\n * It's important that if we failed to mock a request in a test, the resulting\n * error does not cause the request to be retried so that we can see it right\n * away.\n *\n * @param message - The error message to test.\n * @returns True if the message indicates a missing Nock mock, false otherwise.\n */\nfunction isNockError(message: string) {\n return message.includes('Nock:');\n}\n\n/**\n * Determine whether the given error message indicates a failure to parse JSON.\n *\n * This is different in tests vs. implementation code because it may manifest as\n * a FetchError or a SyntaxError.\n *\n * @param error - The error object to test.\n * @returns True if the error indicates a JSON parse error, false otherwise.\n */\nfunction isJsonParseError(error: unknown) {\n return (\n error instanceof SyntaxError ||\n /invalid json/iu.test(getErrorMessage(error))\n );\n}\n\n/**\n * Guarantees a URL, even given a string. This is useful for checking components\n * of that URL.\n *\n * @param endpointUrlOrUrlString - Either a URL object or a string that\n * represents the URL of an endpoint.\n * @returns A URL object.\n */\nfunction getNormalizedEndpointUrl(endpointUrlOrUrlString: URL | string): URL {\n return endpointUrlOrUrlString instanceof URL\n ? endpointUrlOrUrlString\n : new URL(endpointUrlOrUrlString);\n}\n\n/**\n * Strips username and password from a URL.\n *\n * @param url - The URL to strip credentials from.\n * @returns A new URL object with credentials removed.\n */\nfunction stripCredentialsFromUrl(url: URL): URL {\n const strippedUrl = new URL(url.toString());\n strippedUrl.username = '';\n strippedUrl.password = '';\n return strippedUrl;\n}\n\n/**\n * This class is responsible for making a request to an endpoint that implements\n * the JSON-RPC protocol. It is designed to gracefully handle network and server\n * failures, retrying requests using exponential backoff. It also offers a hook\n * which can used to respond to slow requests.\n */\nexport class RpcService implements AbstractRpcService {\n /**\n * The URL of the RPC endpoint.\n */\n readonly endpointUrl: URL;\n\n /**\n * The last error that the retry policy captured (or `undefined` if the last\n * execution of the service was successful).\n */\n lastError: Error | undefined;\n\n /**\n * The function used to make an HTTP request.\n */\n readonly #fetch: typeof fetch;\n\n /**\n * A common set of options that the request options will extend.\n */\n readonly #fetchOptions: FetchOptions;\n\n /**\n * A `loglevel` logger.\n */\n readonly #logger: RpcServiceOptions['logger'];\n\n /**\n * The policy that wraps the request.\n */\n readonly #policy: ServicePolicy;\n\n /**\n * Constructs a new RpcService object.\n *\n * @param options - The options. See {@link RpcServiceOptions}.\n */\n constructor(options: RpcServiceOptions) {\n const {\n btoa: givenBtoa,\n endpointUrl,\n fetch: givenFetch,\n logger,\n fetchOptions = {},\n policyOptions = {},\n } = options;\n\n this.#fetch = givenFetch;\n const normalizedUrl = getNormalizedEndpointUrl(endpointUrl);\n this.#fetchOptions = this.#getDefaultFetchOptions(\n normalizedUrl,\n fetchOptions,\n givenBtoa,\n );\n this.endpointUrl = stripCredentialsFromUrl(normalizedUrl);\n this.#logger = logger;\n\n this.#policy = createServicePolicy({\n maxRetries: DEFAULT_MAX_RETRIES,\n maxConsecutiveFailures: DEFAULT_MAX_CONSECUTIVE_FAILURES,\n ...policyOptions,\n retryFilterPolicy: handleWhen((error) => {\n return (\n // Ignore errors where the request failed to establish\n isConnectionError(error) ||\n // Ignore server sent HTML error pages or truncated JSON responses\n isJsonParseError(error) ||\n // Ignore server overload errors\n ('httpStatus' in error &&\n (error.httpStatus === 502 ||\n error.httpStatus === 503 ||\n error.httpStatus === 504)) ||\n (hasProperty(error, 'code') &&\n (error.code === 'ETIMEDOUT' || error.code === 'ECONNRESET'))\n );\n }),\n });\n }\n\n /**\n * Resets the underlying composite Cockatiel policy.\n *\n * This is useful in a collection of RpcServices where some act as failovers\n * for others where you effectively want to invalidate the failovers when the\n * primary recovers.\n */\n resetPolicy() {\n this.#policy.reset();\n }\n\n /**\n * @returns The state of the underlying circuit.\n */\n getCircuitState() {\n return this.#policy.getCircuitState();\n }\n\n /**\n * Listens for when the RPC service retries the request.\n *\n * @param listener - The callback to be called when the retry occurs.\n * @returns What {@link ServicePolicy.onRetry} returns.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<AbstractRpcService['onRetry']>[0]) {\n return this.#policy.onRetry((data) => {\n listener({ ...data, endpointUrl: this.endpointUrl.toString() });\n });\n }\n\n /**\n * Listens for when the RPC service retries the request too many times in a\n * row, causing the underlying circuit to break.\n *\n * @param listener - The callback to be called when the circuit is broken.\n * @returns What {@link ServicePolicy.onBreak} returns.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<AbstractRpcService['onBreak']>[0]) {\n return this.#policy.onBreak((data) => {\n // `{ isolated: true }` is a special object that shows up when `isolate`\n // is called on the circuit breaker. Usually `isolate` is used to hold the\n // circuit open, but we (ab)use this method in `createServicePolicy` to\n // reset the circuit breaker policy. When we do this, we don't want to\n // call `onBreak` handlers, because then it causes\n // `NetworkController:rpcEndpointUnavailable` and\n // `NetworkController:rpcEndpointChainUnavailable` to be published. So we\n // have to ignore that object here. The consequence is that `isolate`\n // doesn't function the way it is intended, at least in the context of an\n // RpcService. However, we are making a bet that we won't need to use it\n // other than how we are already using it.\n if (!('isolated' in data)) {\n listener({ ...data, endpointUrl: this.endpointUrl.toString() });\n }\n });\n }\n\n /**\n * Listens for when the policy underlying this RPC service detects a slow\n * request.\n *\n * @param listener - The callback to be called when the request is slow.\n * @returns What {@link ServicePolicy.onDegraded} returns.\n * @see {@link createServicePolicy}\n */\n onDegraded(listener: Parameters<AbstractRpcService['onDegraded']>[0]) {\n return this.#policy.onDegraded((data) => {\n listener({ ...(data ?? {}), endpointUrl: this.endpointUrl.toString() });\n });\n }\n\n /**\n * Listens for when the policy underlying this RPC service is available.\n *\n * @param listener - The callback to be called when the request is available.\n * @returns What {@link ServicePolicy.onAvailable} returns.\n * @see {@link createServicePolicy}\n */\n onAvailable(listener: Parameters<AbstractRpcService['onAvailable']>[0]) {\n return this.#policy.onAvailable(() => {\n listener({ endpointUrl: this.endpointUrl.toString() });\n });\n }\n\n /**\n * Makes a request to the RPC endpoint.\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 An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\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 RPC endpoint.\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 An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\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 // The request object may be frozen and must not be mutated.\n jsonRpcRequest: Readonly<JsonRpcRequest<Params>>,\n fetchOptions: FetchOptions = {},\n ): Promise<JsonRpcResponse<Result | null>> {\n const completeFetchOptions = this.#getCompleteFetchOptions(\n jsonRpcRequest,\n fetchOptions,\n );\n return await this.#executeAndProcessRequest<Result>(completeFetchOptions);\n }\n\n /**\n * Constructs a default set of options to `fetch`.\n *\n * If a username and password are present in the URL, they are extracted to an\n * Authorization header.\n *\n * @param endpointUrl - The endpoint URL.\n * @param fetchOptions - The options to `fetch`.\n * @param givenBtoa - An implementation of `btoa`.\n * @returns The default fetch options.\n */\n #getDefaultFetchOptions(\n endpointUrl: URL,\n fetchOptions: FetchOptions,\n givenBtoa: (stringToEncode: string) => string,\n ): FetchOptions {\n if (endpointUrl.username && endpointUrl.password) {\n const authString = `${endpointUrl.username}:${endpointUrl.password}`;\n const encodedCredentials = givenBtoa(authString);\n return deepmerge(fetchOptions, {\n headers: { Authorization: `Basic ${encodedCredentials}` },\n });\n }\n\n return fetchOptions;\n }\n\n /**\n * Constructs a final set of options to pass to `fetch`. Note that the method\n * defaults to `post`, and the JSON-RPC request is automatically JSON-encoded.\n *\n * @param jsonRpcRequest - The JSON-RPC request.\n * @param fetchOptions - Custom `fetch` options.\n * @returns The complete set of `fetch` options.\n */\n #getCompleteFetchOptions<Params extends JsonRpcParams>(\n jsonRpcRequest: Readonly<JsonRpcRequest<Params>>,\n fetchOptions: FetchOptions,\n ): FetchOptions {\n const defaultOptions = {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n };\n const mergedOptions = deepmerge(\n defaultOptions,\n deepmerge(this.#fetchOptions, fetchOptions),\n );\n\n const { id, jsonrpc, method, params } = jsonRpcRequest;\n const body = JSON.stringify({\n id,\n jsonrpc,\n method,\n params,\n });\n\n return { ...mergedOptions, body };\n }\n\n /**\n * Makes the request using the Cockatiel policy that this service creates.\n *\n * @param fetchOptions - The options for `fetch`; will be combined with the\n * fetch options passed to the constructor\n * @returns The decoded JSON-RPC response from the endpoint.\n * @throws An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\n */\n async #executeAndProcessRequest<Result extends Json>(\n fetchOptions: FetchOptions,\n ): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>> {\n let response: Response | undefined;\n try {\n log(\n `[${this.endpointUrl}] Circuit state`,\n this.#policy.getCircuitState(),\n );\n const jsonDecodedResponse = await this.#policy.execute(\n async (context) => {\n log(\n 'REQUEST INITIATED:',\n this.endpointUrl.toString(),\n '::',\n fetchOptions,\n // @ts-expect-error This property _is_ here, the type of\n // ServicePolicy is just wrong.\n `(attempt ${context.attempt + 1})`,\n );\n response = await this.#fetch(this.endpointUrl, fetchOptions);\n if (!response.ok) {\n throw new HttpError(response.status);\n }\n log(\n 'REQUEST SUCCESSFUL:',\n this.endpointUrl.toString(),\n response.status,\n );\n return await response.json();\n },\n );\n this.lastError = undefined;\n return jsonDecodedResponse;\n } catch (error) {\n log('REQUEST ERROR:', this.endpointUrl.toString(), error);\n\n this.lastError =\n error instanceof Error ? error : new Error(getErrorMessage(error));\n\n if (error instanceof HttpError) {\n const status = error.httpStatus;\n if (status === 401) {\n throw new JsonRpcError(\n CUSTOM_RPC_ERRORS.unauthorized,\n 'Unauthorized.',\n {\n httpStatus: status,\n },\n );\n }\n if (status === 429) {\n throw rpcErrors.limitExceeded({\n message: 'Request is being rate limited.',\n data: {\n httpStatus: status,\n },\n });\n }\n if (status >= 500 || status === 402 || status === 404) {\n throw rpcErrors.resourceUnavailable({\n message: 'RPC endpoint not found or unavailable.',\n data: {\n httpStatus: status,\n },\n });\n }\n\n // Handle all other 4xx errors as generic HTTP client errors\n throw new JsonRpcError(\n CUSTOM_RPC_ERRORS.httpClientError,\n 'RPC endpoint returned HTTP client error.',\n {\n httpStatus: status,\n },\n );\n } else if (isJsonParseError(error)) {\n throw rpcErrors.parse({\n message: 'RPC endpoint did not return JSON.',\n });\n } else if (error instanceof BrokenCircuitError) {\n this.#logger?.warn(error);\n const remainingCircuitOpenDuration =\n this.#policy.getRemainingCircuitOpenDuration();\n const formattedRemainingCircuitOpenDuration = Intl.NumberFormat(\n undefined,\n { maximumFractionDigits: 2 },\n ).format(\n (remainingCircuitOpenDuration ?? this.#policy.circuitBreakDuration) /\n Duration.Minute,\n );\n throw rpcErrors.resourceUnavailable({\n message: `RPC endpoint returned too many errors, retrying in ${formattedRemainingCircuitOpenDuration} minutes. Consider using a different RPC endpoint.`,\n });\n }\n throw error;\n }\n }\n}\n"]}
@@ -1,9 +1,9 @@
1
- import type { CreateServicePolicyOptions, ServicePolicy } from "@metamask/controller-utils";
1
+ import type { CreateServicePolicyOptions } from "@metamask/controller-utils";
2
2
  import type { JsonRpcRequest } from "@metamask/utils";
3
3
  import { type Json, type JsonRpcParams, type JsonRpcResponse } from "@metamask/utils";
4
4
  import type { Logger } from "loglevel";
5
5
  import type { AbstractRpcService } from "./abstract-rpc-service.cjs";
6
- import type { AddToCockatielEventData, FetchOptions } from "./shared.cjs";
6
+ import type { FetchOptions } from "./shared.cjs";
7
7
  /**
8
8
  * Options for the RpcService constructor.
9
9
  */
@@ -17,11 +17,6 @@ export type RpcServiceOptions = {
17
17
  * The URL of the RPC endpoint to hit.
18
18
  */
19
19
  endpointUrl: URL | string;
20
- /**
21
- * An RPC service that represents a failover endpoint which will be invoked
22
- * while the circuit for _this_ service is open.
23
- */
24
- failoverService?: AbstractRpcService;
25
20
  /**
26
21
  * A function that can be used to make an HTTP request. If your JavaScript
27
22
  * environment supports `fetch` natively, you'll probably want to pass that;
@@ -99,12 +94,29 @@ export declare class RpcService implements AbstractRpcService {
99
94
  * The URL of the RPC endpoint.
100
95
  */
101
96
  readonly endpointUrl: URL;
97
+ /**
98
+ * The last error that the retry policy captured (or `undefined` if the last
99
+ * execution of the service was successful).
100
+ */
101
+ lastError: Error | undefined;
102
102
  /**
103
103
  * Constructs a new RpcService object.
104
104
  *
105
105
  * @param options - The options. See {@link RpcServiceOptions}.
106
106
  */
107
107
  constructor(options: RpcServiceOptions);
108
+ /**
109
+ * Resets the underlying composite Cockatiel policy.
110
+ *
111
+ * This is useful in a collection of RpcServices where some act as failovers
112
+ * for others where you effectively want to invalidate the failovers when the
113
+ * primary recovers.
114
+ */
115
+ resetPolicy(): void;
116
+ /**
117
+ * @returns The state of the underlying circuit.
118
+ */
119
+ getCircuitState(): import("@metamask/controller-utils").CircuitState;
108
120
  /**
109
121
  * Listens for when the RPC service retries the request.
110
122
  *
@@ -112,21 +124,16 @@ export declare class RpcService implements AbstractRpcService {
112
124
  * @returns What {@link ServicePolicy.onRetry} returns.
113
125
  * @see {@link createServicePolicy}
114
126
  */
115
- onRetry(listener: AddToCockatielEventData<Parameters<ServicePolicy['onRetry']>[0], {
116
- endpointUrl: string;
117
- }>): import("cockatiel").IDisposable;
127
+ onRetry(listener: Parameters<AbstractRpcService['onRetry']>[0]): import("cockatiel").IDisposable;
118
128
  /**
119
129
  * Listens for when the RPC service retries the request too many times in a
120
- * row.
130
+ * row, causing the underlying circuit to break.
121
131
  *
122
132
  * @param listener - The callback to be called when the circuit is broken.
123
133
  * @returns What {@link ServicePolicy.onBreak} returns.
124
134
  * @see {@link createServicePolicy}
125
135
  */
126
- onBreak(listener: AddToCockatielEventData<Parameters<ServicePolicy['onBreak']>[0], {
127
- endpointUrl: string;
128
- failoverEndpointUrl?: string;
129
- }>): import("cockatiel").IDisposable;
136
+ onBreak(listener: Parameters<AbstractRpcService['onBreak']>[0]): import("cockatiel").IDisposable;
130
137
  /**
131
138
  * Listens for when the policy underlying this RPC service detects a slow
132
139
  * request.
@@ -135,13 +142,17 @@ export declare class RpcService implements AbstractRpcService {
135
142
  * @returns What {@link ServicePolicy.onDegraded} returns.
136
143
  * @see {@link createServicePolicy}
137
144
  */
138
- onDegraded(listener: AddToCockatielEventData<Parameters<ServicePolicy['onDegraded']>[0], {
139
- endpointUrl: string;
140
- }>): import("cockatiel").IDisposable;
145
+ onDegraded(listener: Parameters<AbstractRpcService['onDegraded']>[0]): import("cockatiel").IDisposable;
146
+ /**
147
+ * Listens for when the policy underlying this RPC service is available.
148
+ *
149
+ * @param listener - The callback to be called when the request is available.
150
+ * @returns What {@link ServicePolicy.onAvailable} returns.
151
+ * @see {@link createServicePolicy}
152
+ */
153
+ onAvailable(listener: Parameters<AbstractRpcService['onAvailable']>[0]): import("cockatiel").IDisposable;
141
154
  /**
142
- * Makes a request to the RPC endpoint. If the circuit is open because this
143
- * request has failed too many times, the request is forwarded to a failover
144
- * service (if provided).
155
+ * Makes a request to the RPC endpoint.
145
156
  *
146
157
  * This overload is specifically designed for `eth_getBlockByNumber`, which
147
158
  * can return a `result` of `null` despite an expected `Result` being
@@ -161,9 +172,7 @@ export declare class RpcService implements AbstractRpcService {
161
172
  method: 'eth_getBlockByNumber';
162
173
  }, fetchOptions?: FetchOptions): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>>;
163
174
  /**
164
- * Makes a request to the RPC endpoint. If the circuit is open because this
165
- * request has failed too many times, the request is forwarded to a failover
166
- * service (if provided).
175
+ * Makes a request to the RPC endpoint.
167
176
  *
168
177
  * This overload is designed for all RPC methods except for
169
178
  * `eth_getBlockByNumber`, which are expected to return a `result` of the
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-service.d.cts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AASpC,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB;AACtD,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,wBAAwB;AAEzB,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,mCAA+B;AACjE,OAAO,KAAK,EAAE,uBAAuB,EAAE,YAAY,EAAE,qBAAiB;AAEtE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB;;OAEG;IACH,WAAW,EAAE,GAAG,GAAG,MAAM,CAAC;IAC1B;;;OAGG;IACH,eAAe,CAAC,EAAE,kBAAkB,CAAC;IACrC;;;;OAIG;IACH,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;OAEG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B;;;OAGG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC,0BAA0B,EAAE,mBAAmB,CAAC,CAAC;CACvE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,QAAgC,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;GA8C7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,WAgB/C;AA2DD;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,kBAAkB;;IAMnD;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC;IAuB1B;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IA6CtC;;;;;;OAMG;IACH,OAAO,CACL,QAAQ,EAAE,uBAAuB,CAC/B,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACvC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB;IAOH;;;;;;;OAOG;IACH,OAAO,CACL,QAAQ,EAAE,uBAAuB,CAC/B,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACvC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE,CACtD;IAaH;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,uBAAuB,CAC/B,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAC1C;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB;IAOH;;;;;;;;;;;;;;;;;;OAkBG;IACG,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EAC7D,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG;QAAE,MAAM,EAAE,sBAAsB,CAAA;KAAE,EAC3E,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;;;;;;;;;;;;;;;OAkBG;IACG,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EAC7D,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,EACtC,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;CA6KpC"}
1
+ {"version":3,"file":"rpc-service.d.cts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAE3B,mCAAmC;AAQpC,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB;AACtD,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,wBAAwB;AAEzB,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,mCAA+B;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAiB;AAG7C;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB;;OAEG;IACH,WAAW,EAAE,GAAG,GAAG,MAAM,CAAC;IAC1B;;;;OAIG;IACH,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;OAEG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B;;;OAGG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC,0BAA0B,EAAE,mBAAmB,CAAC,CAAC;CACvE,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,QAAgC,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;GA8C7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,WAgB/C;AA2DD;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,kBAAkB;;IACnD;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC;IAE1B;;;OAGG;IACH,SAAS,EAAE,KAAK,GAAG,SAAS,CAAC;IAsB7B;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IA0CtC;;;;;;OAMG;IACH,WAAW;IAIX;;OAEG;IACH,eAAe;IAIf;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAM9D;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAmB9D;;;;;;;OAOG;IACH,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAMpE;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAMtE;;;;;;;;;;;;;;;;OAgBG;IACG,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EAC7D,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG;QAAE,MAAM,EAAE,sBAAsB,CAAA;KAAE,EAC3E,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;;;;;;;;;;;;;OAgBG;IACG,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EAC7D,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,EACtC,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;CA0LpC"}
@@ -1,9 +1,9 @@
1
- import type { CreateServicePolicyOptions, ServicePolicy } from "@metamask/controller-utils";
1
+ import type { CreateServicePolicyOptions } from "@metamask/controller-utils";
2
2
  import type { JsonRpcRequest } from "@metamask/utils";
3
3
  import { type Json, type JsonRpcParams, type JsonRpcResponse } from "@metamask/utils";
4
4
  import type { Logger } from "loglevel";
5
5
  import type { AbstractRpcService } from "./abstract-rpc-service.mjs";
6
- import type { AddToCockatielEventData, FetchOptions } from "./shared.mjs";
6
+ import type { FetchOptions } from "./shared.mjs";
7
7
  /**
8
8
  * Options for the RpcService constructor.
9
9
  */
@@ -17,11 +17,6 @@ export type RpcServiceOptions = {
17
17
  * The URL of the RPC endpoint to hit.
18
18
  */
19
19
  endpointUrl: URL | string;
20
- /**
21
- * An RPC service that represents a failover endpoint which will be invoked
22
- * while the circuit for _this_ service is open.
23
- */
24
- failoverService?: AbstractRpcService;
25
20
  /**
26
21
  * A function that can be used to make an HTTP request. If your JavaScript
27
22
  * environment supports `fetch` natively, you'll probably want to pass that;
@@ -99,12 +94,29 @@ export declare class RpcService implements AbstractRpcService {
99
94
  * The URL of the RPC endpoint.
100
95
  */
101
96
  readonly endpointUrl: URL;
97
+ /**
98
+ * The last error that the retry policy captured (or `undefined` if the last
99
+ * execution of the service was successful).
100
+ */
101
+ lastError: Error | undefined;
102
102
  /**
103
103
  * Constructs a new RpcService object.
104
104
  *
105
105
  * @param options - The options. See {@link RpcServiceOptions}.
106
106
  */
107
107
  constructor(options: RpcServiceOptions);
108
+ /**
109
+ * Resets the underlying composite Cockatiel policy.
110
+ *
111
+ * This is useful in a collection of RpcServices where some act as failovers
112
+ * for others where you effectively want to invalidate the failovers when the
113
+ * primary recovers.
114
+ */
115
+ resetPolicy(): void;
116
+ /**
117
+ * @returns The state of the underlying circuit.
118
+ */
119
+ getCircuitState(): import("@metamask/controller-utils").CircuitState;
108
120
  /**
109
121
  * Listens for when the RPC service retries the request.
110
122
  *
@@ -112,21 +124,16 @@ export declare class RpcService implements AbstractRpcService {
112
124
  * @returns What {@link ServicePolicy.onRetry} returns.
113
125
  * @see {@link createServicePolicy}
114
126
  */
115
- onRetry(listener: AddToCockatielEventData<Parameters<ServicePolicy['onRetry']>[0], {
116
- endpointUrl: string;
117
- }>): import("cockatiel").IDisposable;
127
+ onRetry(listener: Parameters<AbstractRpcService['onRetry']>[0]): import("cockatiel").IDisposable;
118
128
  /**
119
129
  * Listens for when the RPC service retries the request too many times in a
120
- * row.
130
+ * row, causing the underlying circuit to break.
121
131
  *
122
132
  * @param listener - The callback to be called when the circuit is broken.
123
133
  * @returns What {@link ServicePolicy.onBreak} returns.
124
134
  * @see {@link createServicePolicy}
125
135
  */
126
- onBreak(listener: AddToCockatielEventData<Parameters<ServicePolicy['onBreak']>[0], {
127
- endpointUrl: string;
128
- failoverEndpointUrl?: string;
129
- }>): import("cockatiel").IDisposable;
136
+ onBreak(listener: Parameters<AbstractRpcService['onBreak']>[0]): import("cockatiel").IDisposable;
130
137
  /**
131
138
  * Listens for when the policy underlying this RPC service detects a slow
132
139
  * request.
@@ -135,13 +142,17 @@ export declare class RpcService implements AbstractRpcService {
135
142
  * @returns What {@link ServicePolicy.onDegraded} returns.
136
143
  * @see {@link createServicePolicy}
137
144
  */
138
- onDegraded(listener: AddToCockatielEventData<Parameters<ServicePolicy['onDegraded']>[0], {
139
- endpointUrl: string;
140
- }>): import("cockatiel").IDisposable;
145
+ onDegraded(listener: Parameters<AbstractRpcService['onDegraded']>[0]): import("cockatiel").IDisposable;
146
+ /**
147
+ * Listens for when the policy underlying this RPC service is available.
148
+ *
149
+ * @param listener - The callback to be called when the request is available.
150
+ * @returns What {@link ServicePolicy.onAvailable} returns.
151
+ * @see {@link createServicePolicy}
152
+ */
153
+ onAvailable(listener: Parameters<AbstractRpcService['onAvailable']>[0]): import("cockatiel").IDisposable;
141
154
  /**
142
- * Makes a request to the RPC endpoint. If the circuit is open because this
143
- * request has failed too many times, the request is forwarded to a failover
144
- * service (if provided).
155
+ * Makes a request to the RPC endpoint.
145
156
  *
146
157
  * This overload is specifically designed for `eth_getBlockByNumber`, which
147
158
  * can return a `result` of `null` despite an expected `Result` being
@@ -161,9 +172,7 @@ export declare class RpcService implements AbstractRpcService {
161
172
  method: 'eth_getBlockByNumber';
162
173
  }, fetchOptions?: FetchOptions): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>>;
163
174
  /**
164
- * Makes a request to the RPC endpoint. If the circuit is open because this
165
- * request has failed too many times, the request is forwarded to a failover
166
- * service (if provided).
175
+ * Makes a request to the RPC endpoint.
167
176
  *
168
177
  * This overload is designed for all RPC methods except for
169
178
  * `eth_getBlockByNumber`, which are expected to return a `result` of the
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-service.d.mts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AASpC,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB;AACtD,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,wBAAwB;AAEzB,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,mCAA+B;AACjE,OAAO,KAAK,EAAE,uBAAuB,EAAE,YAAY,EAAE,qBAAiB;AAEtE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB;;OAEG;IACH,WAAW,EAAE,GAAG,GAAG,MAAM,CAAC;IAC1B;;;OAGG;IACH,eAAe,CAAC,EAAE,kBAAkB,CAAC;IACrC;;;;OAIG;IACH,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;OAEG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B;;;OAGG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC,0BAA0B,EAAE,mBAAmB,CAAC,CAAC;CACvE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,QAAgC,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;GA8C7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,WAgB/C;AA2DD;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,kBAAkB;;IAMnD;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC;IAuB1B;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IA6CtC;;;;;;OAMG;IACH,OAAO,CACL,QAAQ,EAAE,uBAAuB,CAC/B,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACvC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB;IAOH;;;;;;;OAOG;IACH,OAAO,CACL,QAAQ,EAAE,uBAAuB,CAC/B,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACvC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE,CACtD;IAaH;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,uBAAuB,CAC/B,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAC1C;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB;IAOH;;;;;;;;;;;;;;;;;;OAkBG;IACG,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EAC7D,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG;QAAE,MAAM,EAAE,sBAAsB,CAAA;KAAE,EAC3E,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;;;;;;;;;;;;;;;OAkBG;IACG,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EAC7D,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,EACtC,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;CA6KpC"}
1
+ {"version":3,"file":"rpc-service.d.mts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAE3B,mCAAmC;AAQpC,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB;AACtD,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,wBAAwB;AAEzB,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,mCAA+B;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAiB;AAG7C;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB;;OAEG;IACH,WAAW,EAAE,GAAG,GAAG,MAAM,CAAC;IAC1B;;;;OAIG;IACH,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;OAEG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B;;;OAGG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC,0BAA0B,EAAE,mBAAmB,CAAC,CAAC;CACvE,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,QAAgC,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;GA8C7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,WAgB/C;AA2DD;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,kBAAkB;;IACnD;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC;IAE1B;;;OAGG;IACH,SAAS,EAAE,KAAK,GAAG,SAAS,CAAC;IAsB7B;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IA0CtC;;;;;;OAMG;IACH,WAAW;IAIX;;OAEG;IACH,eAAe;IAIf;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAM9D;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAmB9D;;;;;;;OAOG;IACH,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAMpE;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAMtE;;;;;;;;;;;;;;;;OAgBG;IACG,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EAC7D,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG;QAAE,MAAM,EAAE,sBAAsB,CAAA;KAAE,EAC3E,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;;;;;;;;;;;;;OAgBG;IACG,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EAC7D,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,EACtC,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;CA0LpC"}