@metamask-previews/network-controller 25.0.0-preview-4cd9da8d → 26.0.0-preview-e3eb8eca

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 +32 -2
  2. package/dist/NetworkController.cjs +37 -10
  3. package/dist/NetworkController.cjs.map +1 -1
  4. package/dist/NetworkController.d.cts +146 -11
  5. package/dist/NetworkController.d.cts.map +1 -1
  6. package/dist/NetworkController.d.mts +146 -11
  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 +115 -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 +115 -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 +255 -39
  41. package/dist/rpc-service/rpc-service-chain.cjs.map +1 -1
  42. package/dist/rpc-service/rpc-service-chain.d.cts +117 -25
  43. package/dist/rpc-service/rpc-service-chain.d.cts.map +1 -1
  44. package/dist/rpc-service/rpc-service-chain.d.mts +117 -25
  45. package/dist/rpc-service/rpc-service-chain.d.mts.map +1 -1
  46. package/dist/rpc-service/rpc-service-chain.mjs +255 -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 +63 -33
  55. package/dist/rpc-service/rpc-service.cjs.map +1 -1
  56. package/dist/rpc-service/rpc-service.d.cts +35 -24
  57. package/dist/rpc-service/rpc-service.d.cts.map +1 -1
  58. package/dist/rpc-service/rpc-service.d.mts +35 -24
  59. package/dist/rpc-service/rpc-service.d.mts.map +1 -1
  60. package/dist/rpc-service/rpc-service.mjs +64 -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 +30 -3
  64. package/dist/rpc-service/shared.d.cts.map +1 -1
  65. package/dist/rpc-service/shared.d.mts +30 -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 +7 -6
@@ -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_lastError, _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,7 @@ 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);
196
+ _RpcService_lastError.set(this, void 0);
199
197
  /**
200
198
  * A `loglevel` logger.
201
199
  */
@@ -204,14 +202,13 @@ class RpcService {
204
202
  * The policy that wraps the request.
205
203
  */
206
204
  _RpcService_policy.set(this, void 0);
207
- const { btoa: givenBtoa, endpointUrl, failoverService, fetch: givenFetch, logger, fetchOptions = {}, policyOptions = {}, } = options;
205
+ const { btoa: givenBtoa, endpointUrl, fetch: givenFetch, logger, fetchOptions = {}, policyOptions = {}, } = options;
208
206
  __classPrivateFieldSet(this, _RpcService_fetch, givenFetch, "f");
209
207
  const normalizedUrl = getNormalizedEndpointUrl(endpointUrl);
210
208
  __classPrivateFieldSet(this, _RpcService_fetchOptions, __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_getDefaultFetchOptions).call(this, normalizedUrl, fetchOptions, givenBtoa), "f");
211
209
  this.endpointUrl = stripCredentialsFromUrl(normalizedUrl);
212
- __classPrivateFieldSet(this, _RpcService_failoverService, failoverService, "f");
213
210
  __classPrivateFieldSet(this, _RpcService_logger, logger, "f");
214
- const policy = (0, controller_utils_1.createServicePolicy)({
211
+ __classPrivateFieldSet(this, _RpcService_policy, (0, controller_utils_1.createServicePolicy)({
215
212
  maxRetries: exports.DEFAULT_MAX_RETRIES,
216
213
  maxConsecutiveFailures: exports.DEFAULT_MAX_CONSECUTIVE_FAILURES,
217
214
  ...policyOptions,
@@ -229,8 +226,32 @@ class RpcService {
229
226
  ((0, utils_1.hasProperty)(error, 'code') &&
230
227
  (error.code === 'ETIMEDOUT' || error.code === 'ECONNRESET')));
231
228
  }),
232
- });
233
- __classPrivateFieldSet(this, _RpcService_policy, policy, "f");
229
+ }), "f");
230
+ }
231
+ /**
232
+ * Resets the underlying composite Cockatiel policy.
233
+ *
234
+ * This is useful in a collection of RpcServices where some act as failovers
235
+ * for others where you effectively want to invalidate the failovers when the
236
+ * primary recovers.
237
+ */
238
+ resetPolicy() {
239
+ __classPrivateFieldGet(this, _RpcService_policy, "f").reset();
240
+ }
241
+ /**
242
+ * @returns The state of the underlying circuit.
243
+ */
244
+ getCircuitState() {
245
+ return __classPrivateFieldGet(this, _RpcService_policy, "f").getCircuitState();
246
+ }
247
+ /**
248
+ * @returns The last failure reason that the retry policy captured (or
249
+ * `undefined` if the last execution of the service was successful).
250
+ */
251
+ getLastInnerFailureReason() {
252
+ return __classPrivateFieldGet(this, _RpcService_lastError, "f") === undefined
253
+ ? undefined
254
+ : { error: __classPrivateFieldGet(this, _RpcService_lastError, "f") };
234
255
  }
235
256
  /**
236
257
  * Listens for when the RPC service retries the request.
@@ -246,7 +267,7 @@ class RpcService {
246
267
  }
247
268
  /**
248
269
  * Listens for when the RPC service retries the request too many times in a
249
- * row.
270
+ * row, causing the underlying circuit to break.
250
271
  *
251
272
  * @param listener - The callback to be called when the circuit is broken.
252
273
  * @returns What {@link ServicePolicy.onBreak} returns.
@@ -254,13 +275,9 @@ class RpcService {
254
275
  */
255
276
  onBreak(listener) {
256
277
  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
- });
278
+ if (!('isolated' in data)) {
279
+ listener({ ...data, endpointUrl: this.endpointUrl.toString() });
280
+ }
264
281
  });
265
282
  }
266
283
  /**
@@ -276,24 +293,27 @@ class RpcService {
276
293
  listener({ ...(data ?? {}), endpointUrl: this.endpointUrl.toString() });
277
294
  });
278
295
  }
296
+ /**
297
+ * Listens for when the policy underlying this RPC service is available.
298
+ *
299
+ * @param listener - The callback to be called when the request is available.
300
+ * @returns What {@link ServicePolicy.onAvailable} returns.
301
+ * @see {@link createServicePolicy}
302
+ */
303
+ onAvailable(listener) {
304
+ return __classPrivateFieldGet(this, _RpcService_policy, "f").onAvailable(() => {
305
+ listener({ endpointUrl: this.endpointUrl.toString() });
306
+ });
307
+ }
279
308
  async request(
280
309
  // The request object may be frozen and must not be mutated.
281
310
  jsonRpcRequest, fetchOptions = {}) {
282
311
  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
- }
312
+ return await __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_executeAndProcessRequest).call(this, completeFetchOptions);
293
313
  }
294
314
  }
295
315
  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) {
316
+ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _RpcService_lastError = new WeakMap(), _RpcService_logger = new WeakMap(), _RpcService_policy = new WeakMap(), _RpcService_instances = new WeakSet(), _RpcService_getDefaultFetchOptions = function _RpcService_getDefaultFetchOptions(endpointUrl, fetchOptions, givenBtoa) {
297
317
  if (endpointUrl.username && endpointUrl.password) {
298
318
  const authString = `${endpointUrl.username}:${endpointUrl.password}`;
299
319
  const encodedCredentials = givenBtoa(authString);
@@ -319,7 +339,7 @@ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _Rp
319
339
  params,
320
340
  });
321
341
  return { ...mergedOptions, body };
322
- }, _RpcService_processRequest =
342
+ }, _RpcService_executeAndProcessRequest =
323
343
  /**
324
344
  * Makes the request using the Cockatiel policy that this service creates.
325
345
  *
@@ -332,18 +352,28 @@ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _Rp
332
352
  * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.
333
353
  * @throws A "parse" JSON-RPC error (code -32700) if the response is not valid JSON.
334
354
  */
335
- async function _RpcService_processRequest(fetchOptions) {
355
+ async function _RpcService_executeAndProcessRequest(fetchOptions) {
336
356
  let response;
337
357
  try {
338
- return await __classPrivateFieldGet(this, _RpcService_policy, "f").execute(async () => {
358
+ log(`[RpcService: ${this.endpointUrl}] Circuit state`, __classPrivateFieldGet(this, _RpcService_policy, "f").getCircuitState());
359
+ const jsonDecodedResponse = await __classPrivateFieldGet(this, _RpcService_policy, "f").execute(async (data) => {
360
+ log('REQUEST INITIATED:', this.endpointUrl.toString(), '::', fetchOptions,
361
+ // @ts-expect-error This property _is_ here, the type of ServicePolicy
362
+ // is just wrong.
363
+ `(attempt ${data.attempt + 1})`);
339
364
  response = await __classPrivateFieldGet(this, _RpcService_fetch, "f").call(this, this.endpointUrl, fetchOptions);
340
365
  if (!response.ok) {
341
366
  throw new controller_utils_1.HttpError(response.status);
342
367
  }
368
+ log('REQUEST SUCCESSFUL:', this.endpointUrl.toString(), response.status);
343
369
  return await response.json();
344
370
  });
371
+ __classPrivateFieldSet(this, _RpcService_lastError, undefined, "f");
372
+ return jsonDecodedResponse;
345
373
  }
346
374
  catch (error) {
375
+ log('REQUEST ERROR:', this.endpointUrl.toString(), error);
376
+ __classPrivateFieldSet(this, _RpcService_lastError, error, "f");
347
377
  if (error instanceof controller_utils_1.HttpError) {
348
378
  const status = error.httpStatus;
349
379
  if (status === 401) {
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-service.cjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAIA,iEAMoC;AACpC,qDAA+D;AAE/D,2CAOyB;AACzB,0DAAkC;AA8ClC;;;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;;QApCtC;;WAEG;QACM,oCAAqB;QAO9B;;WAEG;QACM,2CAA4B;QAErC;;;WAGG;QACM,8CAAuD;QAEhE;;WAEG;QACM,qCAAqC;QAE9C;;WAEG;QACM,qCAAuB;QAQ9B,MAAM,EACJ,IAAI,EAAE,SAAS,EACf,WAAW,EACX,eAAe,EACf,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,+BAAoB,eAAe,MAAA,CAAC;QACxC,uBAAA,IAAI,sBAAW,MAAM,MAAA,CAAC;QAEtB,MAAM,MAAM,GAAG,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,CAAC;QACH,uBAAA,IAAI,sBAAW,MAAM,MAAA,CAAC;IACxB,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CACL,QAGC;QAED,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,CACL,QAGC;QAED,OAAO,uBAAA,IAAI,0BAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACnC,QAAQ,CAAC;gBACP,GAAG,IAAI;gBACP,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE;gBACxC,mBAAmB,EAAE,uBAAA,IAAI,mCAAiB;oBACxC,CAAC,CAAC,uBAAA,IAAI,mCAAiB,CAAC,WAAW,CAAC,QAAQ,EAAE;oBAC9C,CAAC,CAAC,SAAS;aACd,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,UAAU,CACR,QAGC;QAED,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;IAkDD,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;QAEF,IAAI,CAAC;YACH,OAAO,MAAM,uBAAA,IAAI,yDAAgB,MAApB,IAAI,EAAyB,oBAAoB,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IACE,uBAAA,IAAI,0BAAQ,CAAC,oBAAoB,CAAC,KAAK,KAAK,+BAAY,CAAC,IAAI;gBAC7D,uBAAA,IAAI,mCAAiB,KAAK,SAAS,EACnC,CAAC;gBACD,OAAO,MAAM,uBAAA,IAAI,mCAAiB,CAAC,OAAO,CACxC,cAAc,EACd,oBAAoB,CACrB,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CAmJF;AA3WD,gCA2WC;0TArIG,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,qCACH,YAA0B;IAE1B,IAAI,QAA8B,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,MAAM,uBAAA,IAAI,0BAAQ,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;YAC3C,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,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,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 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":"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","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 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 #lastError: unknown;\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 * @returns The last failure reason that the retry policy captured (or\n * `undefined` if the last execution of the service was successful).\n */\n getLastInnerFailureReason(): { error: unknown } | undefined {\n return this.#lastError === undefined\n ? undefined\n : { error: this.#lastError };\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 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 `[RpcService: ${this.endpointUrl}] Circuit state`,\n this.#policy.getCircuitState(),\n );\n const jsonDecodedResponse = await this.#policy.execute(async (data) => {\n log(\n 'REQUEST INITIATED:',\n this.endpointUrl.toString(),\n '::',\n fetchOptions,\n // @ts-expect-error This property _is_ here, the type of ServicePolicy\n // is just wrong.\n `(attempt ${data.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 this.#lastError = undefined;\n return jsonDecodedResponse;\n } catch (error) {\n log('REQUEST ERROR:', this.endpointUrl.toString(), error);\n\n this.#lastError = 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;
@@ -105,6 +100,25 @@ export declare class RpcService implements AbstractRpcService {
105
100
  * @param options - The options. See {@link RpcServiceOptions}.
106
101
  */
107
102
  constructor(options: RpcServiceOptions);
103
+ /**
104
+ * Resets the underlying composite Cockatiel policy.
105
+ *
106
+ * This is useful in a collection of RpcServices where some act as failovers
107
+ * for others where you effectively want to invalidate the failovers when the
108
+ * primary recovers.
109
+ */
110
+ resetPolicy(): void;
111
+ /**
112
+ * @returns The state of the underlying circuit.
113
+ */
114
+ getCircuitState(): import("@metamask/controller-utils").CircuitState;
115
+ /**
116
+ * @returns The last failure reason that the retry policy captured (or
117
+ * `undefined` if the last execution of the service was successful).
118
+ */
119
+ getLastInnerFailureReason(): {
120
+ error: unknown;
121
+ } | undefined;
108
122
  /**
109
123
  * Listens for when the RPC service retries the request.
110
124
  *
@@ -112,21 +126,16 @@ export declare class RpcService implements AbstractRpcService {
112
126
  * @returns What {@link ServicePolicy.onRetry} returns.
113
127
  * @see {@link createServicePolicy}
114
128
  */
115
- onRetry(listener: AddToCockatielEventData<Parameters<ServicePolicy['onRetry']>[0], {
116
- endpointUrl: string;
117
- }>): import("cockatiel").IDisposable;
129
+ onRetry(listener: Parameters<AbstractRpcService['onRetry']>[0]): import("cockatiel").IDisposable;
118
130
  /**
119
131
  * Listens for when the RPC service retries the request too many times in a
120
- * row.
132
+ * row, causing the underlying circuit to break.
121
133
  *
122
134
  * @param listener - The callback to be called when the circuit is broken.
123
135
  * @returns What {@link ServicePolicy.onBreak} returns.
124
136
  * @see {@link createServicePolicy}
125
137
  */
126
- onBreak(listener: AddToCockatielEventData<Parameters<ServicePolicy['onBreak']>[0], {
127
- endpointUrl: string;
128
- failoverEndpointUrl?: string;
129
- }>): import("cockatiel").IDisposable;
138
+ onBreak(listener: Parameters<AbstractRpcService['onBreak']>[0]): import("cockatiel").IDisposable;
130
139
  /**
131
140
  * Listens for when the policy underlying this RPC service detects a slow
132
141
  * request.
@@ -135,13 +144,17 @@ export declare class RpcService implements AbstractRpcService {
135
144
  * @returns What {@link ServicePolicy.onDegraded} returns.
136
145
  * @see {@link createServicePolicy}
137
146
  */
138
- onDegraded(listener: AddToCockatielEventData<Parameters<ServicePolicy['onDegraded']>[0], {
139
- endpointUrl: string;
140
- }>): import("cockatiel").IDisposable;
147
+ onDegraded(listener: Parameters<AbstractRpcService['onDegraded']>[0]): import("cockatiel").IDisposable;
148
+ /**
149
+ * Listens for when the policy underlying this RPC service is available.
150
+ *
151
+ * @param listener - The callback to be called when the request is available.
152
+ * @returns What {@link ServicePolicy.onAvailable} returns.
153
+ * @see {@link createServicePolicy}
154
+ */
155
+ onAvailable(listener: Parameters<AbstractRpcService['onAvailable']>[0]): import("cockatiel").IDisposable;
141
156
  /**
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).
157
+ * Makes a request to the RPC endpoint.
145
158
  *
146
159
  * This overload is specifically designed for `eth_getBlockByNumber`, which
147
160
  * can return a `result` of `null` despite an expected `Result` being
@@ -161,9 +174,7 @@ export declare class RpcService implements AbstractRpcService {
161
174
  method: 'eth_getBlockByNumber';
162
175
  }, fetchOptions?: FetchOptions): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>>;
163
176
  /**
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).
177
+ * Makes a request to the RPC endpoint.
167
178
  *
168
179
  * This overload is designed for all RPC methods except for
169
180
  * `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;IAwB1B;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IA0CtC;;;;;;OAMG;IACH,WAAW;IAIX;;OAEG;IACH,eAAe;IAIf;;;OAGG;IACH,yBAAyB,IAAI;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS;IAM3D;;;;;;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;IAQ9D;;;;;;;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;CAuLpC"}
@@ -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;
@@ -105,6 +100,25 @@ export declare class RpcService implements AbstractRpcService {
105
100
  * @param options - The options. See {@link RpcServiceOptions}.
106
101
  */
107
102
  constructor(options: RpcServiceOptions);
103
+ /**
104
+ * Resets the underlying composite Cockatiel policy.
105
+ *
106
+ * This is useful in a collection of RpcServices where some act as failovers
107
+ * for others where you effectively want to invalidate the failovers when the
108
+ * primary recovers.
109
+ */
110
+ resetPolicy(): void;
111
+ /**
112
+ * @returns The state of the underlying circuit.
113
+ */
114
+ getCircuitState(): import("@metamask/controller-utils").CircuitState;
115
+ /**
116
+ * @returns The last failure reason that the retry policy captured (or
117
+ * `undefined` if the last execution of the service was successful).
118
+ */
119
+ getLastInnerFailureReason(): {
120
+ error: unknown;
121
+ } | undefined;
108
122
  /**
109
123
  * Listens for when the RPC service retries the request.
110
124
  *
@@ -112,21 +126,16 @@ export declare class RpcService implements AbstractRpcService {
112
126
  * @returns What {@link ServicePolicy.onRetry} returns.
113
127
  * @see {@link createServicePolicy}
114
128
  */
115
- onRetry(listener: AddToCockatielEventData<Parameters<ServicePolicy['onRetry']>[0], {
116
- endpointUrl: string;
117
- }>): import("cockatiel").IDisposable;
129
+ onRetry(listener: Parameters<AbstractRpcService['onRetry']>[0]): import("cockatiel").IDisposable;
118
130
  /**
119
131
  * Listens for when the RPC service retries the request too many times in a
120
- * row.
132
+ * row, causing the underlying circuit to break.
121
133
  *
122
134
  * @param listener - The callback to be called when the circuit is broken.
123
135
  * @returns What {@link ServicePolicy.onBreak} returns.
124
136
  * @see {@link createServicePolicy}
125
137
  */
126
- onBreak(listener: AddToCockatielEventData<Parameters<ServicePolicy['onBreak']>[0], {
127
- endpointUrl: string;
128
- failoverEndpointUrl?: string;
129
- }>): import("cockatiel").IDisposable;
138
+ onBreak(listener: Parameters<AbstractRpcService['onBreak']>[0]): import("cockatiel").IDisposable;
130
139
  /**
131
140
  * Listens for when the policy underlying this RPC service detects a slow
132
141
  * request.
@@ -135,13 +144,17 @@ export declare class RpcService implements AbstractRpcService {
135
144
  * @returns What {@link ServicePolicy.onDegraded} returns.
136
145
  * @see {@link createServicePolicy}
137
146
  */
138
- onDegraded(listener: AddToCockatielEventData<Parameters<ServicePolicy['onDegraded']>[0], {
139
- endpointUrl: string;
140
- }>): import("cockatiel").IDisposable;
147
+ onDegraded(listener: Parameters<AbstractRpcService['onDegraded']>[0]): import("cockatiel").IDisposable;
148
+ /**
149
+ * Listens for when the policy underlying this RPC service is available.
150
+ *
151
+ * @param listener - The callback to be called when the request is available.
152
+ * @returns What {@link ServicePolicy.onAvailable} returns.
153
+ * @see {@link createServicePolicy}
154
+ */
155
+ onAvailable(listener: Parameters<AbstractRpcService['onAvailable']>[0]): import("cockatiel").IDisposable;
141
156
  /**
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).
157
+ * Makes a request to the RPC endpoint.
145
158
  *
146
159
  * This overload is specifically designed for `eth_getBlockByNumber`, which
147
160
  * can return a `result` of `null` despite an expected `Result` being
@@ -161,9 +174,7 @@ export declare class RpcService implements AbstractRpcService {
161
174
  method: 'eth_getBlockByNumber';
162
175
  }, fetchOptions?: FetchOptions): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>>;
163
176
  /**
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).
177
+ * Makes a request to the RPC endpoint.
167
178
  *
168
179
  * This overload is designed for all RPC methods except for
169
180
  * `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;IAwB1B;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IA0CtC;;;;;;OAMG;IACH,WAAW;IAIX;;OAEG;IACH,eAAe;IAIf;;;OAGG;IACH,yBAAyB,IAAI;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS;IAM3D;;;;;;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;IAQ9D;;;;;;;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;CAuLpC"}