@metamask/network-controller 28.0.0 → 30.0.0

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 (40) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/dist/NetworkController.cjs +1 -2
  3. package/dist/NetworkController.cjs.map +1 -1
  4. package/dist/NetworkController.d.cts +13 -1
  5. package/dist/NetworkController.d.cts.map +1 -1
  6. package/dist/NetworkController.d.mts +13 -1
  7. package/dist/NetworkController.d.mts.map +1 -1
  8. package/dist/NetworkController.mjs +1 -2
  9. package/dist/NetworkController.mjs.map +1 -1
  10. package/dist/create-network-client.cjs +47 -4
  11. package/dist/create-network-client.cjs.map +1 -1
  12. package/dist/create-network-client.d.cts +15 -0
  13. package/dist/create-network-client.d.cts.map +1 -1
  14. package/dist/create-network-client.d.mts +15 -0
  15. package/dist/create-network-client.d.mts.map +1 -1
  16. package/dist/create-network-client.mjs +45 -3
  17. package/dist/create-network-client.mjs.map +1 -1
  18. package/dist/index.cjs +3 -1
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +2 -0
  21. package/dist/index.d.cts.map +1 -1
  22. package/dist/index.d.mts +2 -0
  23. package/dist/index.d.mts.map +1 -1
  24. package/dist/index.mjs +1 -0
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/rpc-service/rpc-service-requestable.cjs.map +1 -1
  27. package/dist/rpc-service/rpc-service-requestable.d.cts +1 -0
  28. package/dist/rpc-service/rpc-service-requestable.d.cts.map +1 -1
  29. package/dist/rpc-service/rpc-service-requestable.d.mts +1 -0
  30. package/dist/rpc-service/rpc-service-requestable.d.mts.map +1 -1
  31. package/dist/rpc-service/rpc-service-requestable.mjs.map +1 -1
  32. package/dist/rpc-service/rpc-service.cjs +107 -23
  33. package/dist/rpc-service/rpc-service.cjs.map +1 -1
  34. package/dist/rpc-service/rpc-service.d.cts +38 -0
  35. package/dist/rpc-service/rpc-service.d.cts.map +1 -1
  36. package/dist/rpc-service/rpc-service.d.mts +38 -0
  37. package/dist/rpc-service/rpc-service.d.mts.map +1 -1
  38. package/dist/rpc-service/rpc-service.mjs +103 -23
  39. package/dist/rpc-service/rpc-service.mjs.map +1 -1
  40. package/package.json +11 -10
@@ -38,6 +38,7 @@ export type RpcServiceRequestable = {
38
38
  */
39
39
  onDegraded(listener: CockatielEventToEventListenerWithData<ServicePolicy['onDegraded'], {
40
40
  endpointUrl: string;
41
+ rpcMethodName: string;
41
42
  }>): ReturnType<ServicePolicy['onDegraded']>;
42
43
  /**
43
44
  * Listens for when the policy underlying this RPC service is available.
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-service-requestable.d.cts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service-requestable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,wBAAwB;AAEzB,OAAO,KAAK,EACV,qCAAqC,EACrC,yBAAyB,EACzB,wBAAwB,EACxB,yBAAyB,EACzB,YAAY,EACb,qBAAiB;AAElB;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;OAMG;IACH,OAAO,CACL,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,SAAS,CAAC,EACxB;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,OAAO,CACL,QAAQ,EAAE,CACR,IAAI,EAAE,yBAAyB,CAC7B,wBAAwB,CACtB,yBAAyB,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EACnD;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,EACD,UAAU,CACX,KACE,IAAI,GACR,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,YAAY,CAAC,EAC3B;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAE3C;;;;;;OAMG;IACH,WAAW,CACT,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,aAAa,CAAC,EAC5B;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;IAE5C;;OAEG;IACH,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EACvD,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAChD,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;CAC5C,CAAC"}
1
+ {"version":3,"file":"rpc-service-requestable.d.cts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service-requestable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,wBAAwB;AAEzB,OAAO,KAAK,EACV,qCAAqC,EACrC,yBAAyB,EACzB,wBAAwB,EACxB,yBAAyB,EACzB,YAAY,EACb,qBAAiB;AAElB;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;OAMG;IACH,OAAO,CACL,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,SAAS,CAAC,EACxB;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,OAAO,CACL,QAAQ,EAAE,CACR,IAAI,EAAE,yBAAyB,CAC7B,wBAAwB,CACtB,yBAAyB,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EACnD;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,EACD,UAAU,CACX,KACE,IAAI,GACR,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,YAAY,CAAC,EAC3B;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAC/C,GACA,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAE3C;;;;;;OAMG;IACH,WAAW,CACT,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,aAAa,CAAC,EAC5B;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;IAE5C;;OAEG;IACH,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EACvD,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAChD,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;CAC5C,CAAC"}
@@ -38,6 +38,7 @@ export type RpcServiceRequestable = {
38
38
  */
39
39
  onDegraded(listener: CockatielEventToEventListenerWithData<ServicePolicy['onDegraded'], {
40
40
  endpointUrl: string;
41
+ rpcMethodName: string;
41
42
  }>): ReturnType<ServicePolicy['onDegraded']>;
42
43
  /**
43
44
  * Listens for when the policy underlying this RPC service is available.
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-service-requestable.d.mts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service-requestable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,wBAAwB;AAEzB,OAAO,KAAK,EACV,qCAAqC,EACrC,yBAAyB,EACzB,wBAAwB,EACxB,yBAAyB,EACzB,YAAY,EACb,qBAAiB;AAElB;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;OAMG;IACH,OAAO,CACL,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,SAAS,CAAC,EACxB;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,OAAO,CACL,QAAQ,EAAE,CACR,IAAI,EAAE,yBAAyB,CAC7B,wBAAwB,CACtB,yBAAyB,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EACnD;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,EACD,UAAU,CACX,KACE,IAAI,GACR,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,YAAY,CAAC,EAC3B;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAE3C;;;;;;OAMG;IACH,WAAW,CACT,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,aAAa,CAAC,EAC5B;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;IAE5C;;OAEG;IACH,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EACvD,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAChD,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;CAC5C,CAAC"}
1
+ {"version":3,"file":"rpc-service-requestable.d.mts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service-requestable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,wBAAwB;AAEzB,OAAO,KAAK,EACV,qCAAqC,EACrC,yBAAyB,EACzB,wBAAwB,EACxB,yBAAyB,EACzB,YAAY,EACb,qBAAiB;AAElB;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;OAMG;IACH,OAAO,CACL,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,SAAS,CAAC,EACxB;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,OAAO,CACL,QAAQ,EAAE,CACR,IAAI,EAAE,yBAAyB,CAC7B,wBAAwB,CACtB,yBAAyB,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EACnD;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,EACD,UAAU,CACX,KACE,IAAI,GACR,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,YAAY,CAAC,EAC3B;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAC/C,GACA,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAE3C;;;;;;OAMG;IACH,WAAW,CACT,QAAQ,EAAE,qCAAqC,CAC7C,aAAa,CAAC,aAAa,CAAC,EAC5B;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CACxB,GACA,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;IAE5C;;OAEG;IACH,OAAO,CAAC,MAAM,SAAS,aAAa,EAAE,MAAM,SAAS,IAAI,EACvD,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAChD,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;CAC5C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-service-requestable.mjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-service-requestable.ts"],"names":[],"mappings":"","sourcesContent":["import type { ServicePolicy } from '@metamask/controller-utils';\nimport type {\n Json,\n JsonRpcParams,\n JsonRpcRequest,\n JsonRpcResponse,\n} from '@metamask/utils';\n\nimport type {\n CockatielEventToEventListenerWithData,\n ExcludeCockatielEventData,\n ExtendCockatielEventData,\n ExtractCockatielEventData,\n FetchOptions,\n} from './shared';\n\n/**\n * The interface for a service class responsible for making a request to a\n * target, whether that is a single RPC endpoint or an RPC endpoint in an RPC\n * service chain.\n */\nexport type RpcServiceRequestable = {\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: CockatielEventToEventListenerWithData<\n ServicePolicy['onRetry'],\n { endpointUrl: string }\n >,\n ): ReturnType<ServicePolicy['onRetry']>;\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: (\n data: ExcludeCockatielEventData<\n ExtendCockatielEventData<\n ExtractCockatielEventData<ServicePolicy['onBreak']>,\n { endpointUrl: string }\n >,\n 'isolated'\n >,\n ) => void,\n ): ReturnType<ServicePolicy['onBreak']>;\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: CockatielEventToEventListenerWithData<\n ServicePolicy['onDegraded'],\n { endpointUrl: string }\n >,\n ): ReturnType<ServicePolicy['onDegraded']>;\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.onDegraded} returns.\n * @see {@link createServicePolicy}\n */\n onAvailable(\n listener: CockatielEventToEventListenerWithData<\n ServicePolicy['onAvailable'],\n { endpointUrl: string }\n >,\n ): ReturnType<ServicePolicy['onAvailable']>;\n\n /**\n * Makes a request to the target.\n */\n request<Params extends JsonRpcParams, Result extends Json>(\n jsonRpcRequest: Readonly<JsonRpcRequest<Params>>,\n fetchOptions?: FetchOptions,\n ): Promise<JsonRpcResponse<Result | null>>;\n};\n"]}
1
+ {"version":3,"file":"rpc-service-requestable.mjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-service-requestable.ts"],"names":[],"mappings":"","sourcesContent":["import type { ServicePolicy } from '@metamask/controller-utils';\nimport type {\n Json,\n JsonRpcParams,\n JsonRpcRequest,\n JsonRpcResponse,\n} from '@metamask/utils';\n\nimport type {\n CockatielEventToEventListenerWithData,\n ExcludeCockatielEventData,\n ExtendCockatielEventData,\n ExtractCockatielEventData,\n FetchOptions,\n} from './shared';\n\n/**\n * The interface for a service class responsible for making a request to a\n * target, whether that is a single RPC endpoint or an RPC endpoint in an RPC\n * service chain.\n */\nexport type RpcServiceRequestable = {\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: CockatielEventToEventListenerWithData<\n ServicePolicy['onRetry'],\n { endpointUrl: string }\n >,\n ): ReturnType<ServicePolicy['onRetry']>;\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: (\n data: ExcludeCockatielEventData<\n ExtendCockatielEventData<\n ExtractCockatielEventData<ServicePolicy['onBreak']>,\n { endpointUrl: string }\n >,\n 'isolated'\n >,\n ) => void,\n ): ReturnType<ServicePolicy['onBreak']>;\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: CockatielEventToEventListenerWithData<\n ServicePolicy['onDegraded'],\n { endpointUrl: string; rpcMethodName: string }\n >,\n ): ReturnType<ServicePolicy['onDegraded']>;\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.onDegraded} returns.\n * @see {@link createServicePolicy}\n */\n onAvailable(\n listener: CockatielEventToEventListenerWithData<\n ServicePolicy['onAvailable'],\n { endpointUrl: string }\n >,\n ): ReturnType<ServicePolicy['onAvailable']>;\n\n /**\n * Makes a request to the target.\n */\n request<Params extends JsonRpcParams, Result extends Json>(\n jsonRpcRequest: Readonly<JsonRpcRequest<Params>>,\n fetchOptions?: FetchOptions,\n ): Promise<JsonRpcResponse<Result | null>>;\n};\n"]}
@@ -13,9 +13,9 @@ 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_logger, _RpcService_policy, _RpcService_getDefaultFetchOptions, _RpcService_getCompleteFetchOptions, _RpcService_executeAndProcessRequest;
16
+ var _RpcService_instances, _RpcService_currentRpcMethodName, _RpcService_fetch, _RpcService_fetchOptions, _RpcService_logger, _RpcService_policy, _RpcService_getDefaultFetchOptions, _RpcService_getCompleteFetchOptions, _RpcService_executeAndProcessRequest;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.RpcService = exports.isConnectionError = exports.CUSTOM_RPC_ERRORS = exports.CONNECTION_ERRORS = exports.DEFAULT_MAX_CONSECUTIVE_FAILURES = exports.DEFAULT_MAX_RETRIES = void 0;
18
+ exports.RpcService = exports.isConnectionResetError = exports.isTimeoutError = exports.isHttpServerError = exports.isJsonParseError = 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");
@@ -147,6 +147,41 @@ function isJsonParseError(error) {
147
147
  return (error instanceof SyntaxError ||
148
148
  /invalid json/iu.test((0, utils_1.getErrorMessage)(error)));
149
149
  }
150
+ exports.isJsonParseError = isJsonParseError;
151
+ /**
152
+ * Determines whether the given error represents a HTTP server error
153
+ * (502, 503, or 504) that should be retried.
154
+ *
155
+ * @param error - The error object to test.
156
+ * @returns True if the error has an httpStatus of 502, 503, or 504.
157
+ */
158
+ function isHttpServerError(error) {
159
+ return ('httpStatus' in error &&
160
+ (error.httpStatus === 502 ||
161
+ error.httpStatus === 503 ||
162
+ error.httpStatus === 504));
163
+ }
164
+ exports.isHttpServerError = isHttpServerError;
165
+ /**
166
+ * Determines whether the given error has a `code` property of `ETIMEDOUT`.
167
+ *
168
+ * @param error - The error object to test.
169
+ * @returns True if the error code is `ETIMEDOUT`.
170
+ */
171
+ function isTimeoutError(error) {
172
+ return (0, utils_1.hasProperty)(error, 'code') && error.code === 'ETIMEDOUT';
173
+ }
174
+ exports.isTimeoutError = isTimeoutError;
175
+ /**
176
+ * Determines whether the given error has a `code` property of `ECONNRESET`.
177
+ *
178
+ * @param error - The error object to test.
179
+ * @returns True if the error code is `ECONNRESET`.
180
+ */
181
+ function isConnectionResetError(error) {
182
+ return (0, utils_1.hasProperty)(error, 'code') && error.code === 'ECONNRESET';
183
+ }
184
+ exports.isConnectionResetError = isConnectionResetError;
150
185
  /**
151
186
  * Guarantees a URL, even given a string. This is useful for checking components
152
187
  * of that URL.
@@ -186,6 +221,16 @@ class RpcService {
186
221
  */
187
222
  constructor(options) {
188
223
  _RpcService_instances.add(this);
224
+ /**
225
+ * The RPC method name of the current request being processed. This is passed
226
+ * to `onDegraded` event listeners.
227
+ *
228
+ * Initialised to `''` so the type is `string` throughout the event chain.
229
+ * The empty string is unreachable in practice because the method name is
230
+ * guaranteed to be set after the current request is completed but before
231
+ * any `onDegraded` callbacks are called.
232
+ */
233
+ _RpcService_currentRpcMethodName.set(this, '');
189
234
  /**
190
235
  * The function used to make an HTTP request.
191
236
  */
@@ -202,7 +247,7 @@ class RpcService {
202
247
  * The policy that wraps the request.
203
248
  */
204
249
  _RpcService_policy.set(this, void 0);
205
- const { btoa: givenBtoa, endpointUrl, fetch: givenFetch, logger, fetchOptions = {}, policyOptions = {}, } = options;
250
+ const { btoa: givenBtoa, endpointUrl, fetch: givenFetch, logger, fetchOptions = {}, policyOptions = {}, isOffline, } = options;
206
251
  __classPrivateFieldSet(this, _RpcService_fetch, givenFetch, "f");
207
252
  const normalizedUrl = getNormalizedEndpointUrl(endpointUrl);
208
253
  __classPrivateFieldSet(this, _RpcService_fetchOptions, __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_getDefaultFetchOptions).call(this, normalizedUrl, fetchOptions, givenBtoa), "f");
@@ -213,18 +258,22 @@ class RpcService {
213
258
  maxConsecutiveFailures: exports.DEFAULT_MAX_CONSECUTIVE_FAILURES,
214
259
  ...policyOptions,
215
260
  retryFilterPolicy: (0, controller_utils_1.handleWhen)((error) => {
261
+ // If user is offline, don't retry any errors
262
+ // This prevents degraded/break callbacks from being triggered
263
+ if (isOffline()) {
264
+ return false;
265
+ }
216
266
  return (
217
267
  // Ignore errors where the request failed to establish
218
268
  isConnectionError(error) ||
219
269
  // Ignore server sent HTML error pages or truncated JSON responses
220
270
  isJsonParseError(error) ||
221
271
  // Ignore server overload errors
222
- ('httpStatus' in error &&
223
- (error.httpStatus === 502 ||
224
- error.httpStatus === 503 ||
225
- error.httpStatus === 504)) ||
226
- ((0, utils_1.hasProperty)(error, 'code') &&
227
- (error.code === 'ETIMEDOUT' || error.code === 'ECONNRESET')));
272
+ isHttpServerError(error) ||
273
+ // Ignore timeout errors
274
+ isTimeoutError(error) ||
275
+ // Ignore connection reset errors
276
+ isConnectionResetError(error));
228
277
  }),
229
278
  }), "f");
230
279
  }
@@ -278,7 +327,10 @@ class RpcService {
278
327
  // RpcService. However, we are making a bet that we won't need to use it
279
328
  // other than how we are already using it.
280
329
  if (!('isolated' in data)) {
281
- listener({ ...data, endpointUrl: this.endpointUrl.toString() });
330
+ listener({
331
+ ...data,
332
+ endpointUrl: this.endpointUrl.toString(),
333
+ });
282
334
  }
283
335
  });
284
336
  }
@@ -292,7 +344,19 @@ class RpcService {
292
344
  */
293
345
  onDegraded(listener) {
294
346
  return __classPrivateFieldGet(this, _RpcService_policy, "f").onDegraded((data) => {
295
- listener({ ...(data ?? {}), endpointUrl: this.endpointUrl.toString() });
347
+ if (data === undefined) {
348
+ listener({
349
+ endpointUrl: this.endpointUrl.toString(),
350
+ rpcMethodName: __classPrivateFieldGet(this, _RpcService_currentRpcMethodName, "f"),
351
+ });
352
+ }
353
+ else {
354
+ listener({
355
+ ...data,
356
+ endpointUrl: this.endpointUrl.toString(),
357
+ rpcMethodName: __classPrivateFieldGet(this, _RpcService_currentRpcMethodName, "f"),
358
+ });
359
+ }
296
360
  });
297
361
  }
298
362
  /**
@@ -311,11 +375,11 @@ class RpcService {
311
375
  // The request object may be frozen and must not be mutated.
312
376
  jsonRpcRequest, fetchOptions = {}) {
313
377
  const completeFetchOptions = __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_getCompleteFetchOptions).call(this, jsonRpcRequest, fetchOptions);
314
- return await __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_executeAndProcessRequest).call(this, completeFetchOptions);
378
+ return await __classPrivateFieldGet(this, _RpcService_instances, "m", _RpcService_executeAndProcessRequest).call(this, completeFetchOptions, jsonRpcRequest.method);
315
379
  }
316
380
  }
317
381
  exports.RpcService = RpcService;
318
- _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) {
382
+ _RpcService_currentRpcMethodName = new WeakMap(), _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) {
319
383
  if (endpointUrl.username && endpointUrl.password) {
320
384
  const authString = `${endpointUrl.username}:${endpointUrl.password}`;
321
385
  const encodedCredentials = givenBtoa(authString);
@@ -347,6 +411,7 @@ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _Rp
347
411
  *
348
412
  * @param fetchOptions - The options for `fetch`; will be combined with the
349
413
  * fetch options passed to the constructor
414
+ * @param rpcMethodName - The JSON-RPC method name of the current request.
350
415
  * @returns The decoded JSON-RPC response from the endpoint.
351
416
  * @throws An "authorized" JSON-RPC error (code -32006) if the response HTTP status is 401.
352
417
  * @throws A "rate limiting" JSON-RPC error (code -32005) if the response HTTP status is 429.
@@ -354,21 +419,40 @@ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _Rp
354
419
  * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.
355
420
  * @throws A "parse" JSON-RPC error (code -32700) if the response is not valid JSON.
356
421
  */
357
- async function _RpcService_executeAndProcessRequest(fetchOptions) {
422
+ async function _RpcService_executeAndProcessRequest(fetchOptions, rpcMethodName) {
358
423
  let response;
359
424
  try {
360
425
  log(`[${this.endpointUrl}] Circuit state`, __classPrivateFieldGet(this, _RpcService_policy, "f").getCircuitState());
361
426
  const jsonDecodedResponse = await __classPrivateFieldGet(this, _RpcService_policy, "f").execute(async (context) => {
362
- log('REQUEST INITIATED:', this.endpointUrl.toString(), '::', fetchOptions,
363
- // @ts-expect-error This property _is_ here, the type of
364
- // ServicePolicy is just wrong.
365
- `(attempt ${context.attempt + 1})`);
366
- response = await __classPrivateFieldGet(this, _RpcService_fetch, "f").call(this, this.endpointUrl, fetchOptions);
367
- if (!response.ok) {
368
- throw new controller_utils_1.HttpError(response.status);
427
+ try {
428
+ log('REQUEST INITIATED:', this.endpointUrl.toString(), '::', fetchOptions,
429
+ // @ts-expect-error This property _is_ here, the type of
430
+ // ServicePolicy is just wrong.
431
+ `(attempt ${context.attempt + 1})`);
432
+ response = await __classPrivateFieldGet(this, _RpcService_fetch, "f").call(this, this.endpointUrl, fetchOptions);
433
+ if (!response.ok) {
434
+ throw new controller_utils_1.HttpError(response.status);
435
+ }
436
+ log('REQUEST SUCCESSFUL:', this.endpointUrl.toString(), response.status);
437
+ return await response.json();
438
+ }
439
+ finally {
440
+ // Track the RPC method for the request that has just taken place.
441
+ // We pass this property to `onDegraded` event listeners.
442
+ //
443
+ // We set this property after the request completes and not before
444
+ // the request starts to account for race conditions. That is, if
445
+ // there are two requests that are being performed concurrently, and
446
+ // the second request fails fast but the first request succeeds
447
+ // slowly, when `onDegraded` is called we want it to include the
448
+ // first request as the RPC method, not the second.
449
+ //
450
+ // Also, we set this property within a `finally` block inside of the
451
+ // function passed to `policy.execute` to ensure that it is set
452
+ // before `onDegraded` gets called, no matter the outcome of the
453
+ // request.
454
+ __classPrivateFieldSet(this, _RpcService_currentRpcMethodName, rpcMethodName, "f");
369
455
  }
370
- log('REQUEST SUCCESSFUL:', this.endpointUrl.toString(), response.status);
371
- return await response.json();
372
456
  });
373
457
  this.lastError = undefined;
374
458
  return jsonDecodedResponse;
@@ -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 HttpError,\n createServicePolicy,\n handleWhen,\n} from '@metamask/controller-utils';\nimport { JsonRpcError, rpcErrors } from '@metamask/rpc-errors';\nimport { Duration, getErrorMessage, hasProperty } from '@metamask/utils';\nimport type {\n Json,\n JsonRpcParams,\n JsonRpcRequest,\n JsonRpcResponse,\n} from '@metamask/utils';\nimport { CircuitState, IDisposable } from 'cockatiel';\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): boolean {\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): boolean {\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): boolean {\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(): void {\n this.#policy.reset();\n }\n\n /**\n * @returns The state of the underlying circuit.\n */\n getCircuitState(): CircuitState {\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]): IDisposable {\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]): IDisposable {\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(\n listener: Parameters<AbstractRpcService['onDegraded']>[0],\n ): IDisposable {\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(\n listener: Parameters<AbstractRpcService['onAvailable']>[0],\n ): IDisposable {\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
+ {"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 { Duration, getErrorMessage, hasProperty } from '@metamask/utils';\nimport type {\n Json,\n JsonRpcParams,\n JsonRpcRequest,\n JsonRpcResponse,\n} from '@metamask/utils';\nimport { CircuitState, IDisposable } from 'cockatiel';\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 * A function that checks if the user is currently offline. If it returns true,\n * connection errors will not be retried, preventing degraded and break\n * callbacks from being triggered.\n */\n isOffline: () => boolean;\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): boolean {\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): boolean {\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 */\nexport function isJsonParseError(error: unknown): boolean {\n return (\n error instanceof SyntaxError ||\n /invalid json/iu.test(getErrorMessage(error))\n );\n}\n\n/**\n * Determines whether the given error represents a HTTP server error\n * (502, 503, or 504) that should be retried.\n *\n * @param error - The error object to test.\n * @returns True if the error has an httpStatus of 502, 503, or 504.\n */\nexport function isHttpServerError(error: Error): boolean {\n return (\n 'httpStatus' in error &&\n (error.httpStatus === 502 ||\n error.httpStatus === 503 ||\n error.httpStatus === 504)\n );\n}\n\n/**\n * Determines whether the given error has a `code` property of `ETIMEDOUT`.\n *\n * @param error - The error object to test.\n * @returns True if the error code is `ETIMEDOUT`.\n */\nexport function isTimeoutError(error: Error): boolean {\n return hasProperty(error, 'code') && error.code === 'ETIMEDOUT';\n}\n\n/**\n * Determines whether the given error has a `code` property of `ECONNRESET`.\n *\n * @param error - The error object to test.\n * @returns True if the error code is `ECONNRESET`.\n */\nexport function isConnectionResetError(error: Error): boolean {\n return hasProperty(error, 'code') && error.code === 'ECONNRESET';\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 RPC method name of the current request being processed. This is passed\n * to `onDegraded` event listeners.\n *\n * Initialised to `''` so the type is `string` throughout the event chain.\n * The empty string is unreachable in practice because the method name is\n * guaranteed to be set after the current request is completed but before\n * any `onDegraded` callbacks are called.\n */\n #currentRpcMethodName = '';\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 isOffline,\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 // If user is offline, don't retry any errors\n // This prevents degraded/break callbacks from being triggered\n if (isOffline()) {\n return false;\n }\n\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 isHttpServerError(error) ||\n // Ignore timeout errors\n isTimeoutError(error) ||\n // Ignore connection reset errors\n isConnectionResetError(error)\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(): void {\n this.#policy.reset();\n }\n\n /**\n * @returns The state of the underlying circuit.\n */\n getCircuitState(): CircuitState {\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]): IDisposable {\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]): IDisposable {\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({\n ...data,\n endpointUrl: this.endpointUrl.toString(),\n });\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: Parameters<AbstractRpcService['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded((data) => {\n if (data === undefined) {\n listener({\n endpointUrl: this.endpointUrl.toString(),\n rpcMethodName: this.#currentRpcMethodName,\n });\n } else {\n listener({\n ...data,\n endpointUrl: this.endpointUrl.toString(),\n rpcMethodName: this.#currentRpcMethodName,\n });\n }\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(\n listener: Parameters<AbstractRpcService['onAvailable']>[0],\n ): IDisposable {\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>(\n completeFetchOptions,\n jsonRpcRequest.method,\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 * @param rpcMethodName - The JSON-RPC method name of the current 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 #executeAndProcessRequest<Result extends Json>(\n fetchOptions: FetchOptions,\n rpcMethodName: string,\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 try {\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 } finally {\n // Track the RPC method for the request that has just taken place.\n // We pass this property to `onDegraded` event listeners.\n //\n // We set this property after the request completes and not before\n // the request starts to account for race conditions. That is, if\n // there are two requests that are being performed concurrently, and\n // the second request fails fast but the first request succeeds\n // slowly, when `onDegraded` is called we want it to include the\n // first request as the RPC method, not the second.\n //\n // Also, we set this property within a `finally` block inside of the\n // function passed to `policy.execute` to ensure that it is set\n // before `onDegraded` gets called, no matter the outcome of the\n // request.\n this.#currentRpcMethodName = rpcMethodName;\n }\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"]}
@@ -37,6 +37,12 @@ export type RpcServiceOptions = {
37
37
  * not accepted, as it is overwritten. See {@link createServicePolicy}.
38
38
  */
39
39
  policyOptions?: Omit<CreateServicePolicyOptions, 'retryFilterPolicy'>;
40
+ /**
41
+ * A function that checks if the user is currently offline. If it returns true,
42
+ * connection errors will not be retried, preventing degraded and break
43
+ * callbacks from being triggered.
44
+ */
45
+ isOffline: () => boolean;
40
46
  };
41
47
  /**
42
48
  * The maximum number of times that a failing service should be re-run before
@@ -82,6 +88,38 @@ export declare const CUSTOM_RPC_ERRORS: {
82
88
  * and false otherwise.
83
89
  */
84
90
  export declare function isConnectionError(error: unknown): boolean;
91
+ /**
92
+ * Determine whether the given error message indicates a failure to parse JSON.
93
+ *
94
+ * This is different in tests vs. implementation code because it may manifest as
95
+ * a FetchError or a SyntaxError.
96
+ *
97
+ * @param error - The error object to test.
98
+ * @returns True if the error indicates a JSON parse error, false otherwise.
99
+ */
100
+ export declare function isJsonParseError(error: unknown): boolean;
101
+ /**
102
+ * Determines whether the given error represents a HTTP server error
103
+ * (502, 503, or 504) that should be retried.
104
+ *
105
+ * @param error - The error object to test.
106
+ * @returns True if the error has an httpStatus of 502, 503, or 504.
107
+ */
108
+ export declare function isHttpServerError(error: Error): boolean;
109
+ /**
110
+ * Determines whether the given error has a `code` property of `ETIMEDOUT`.
111
+ *
112
+ * @param error - The error object to test.
113
+ * @returns True if the error code is `ETIMEDOUT`.
114
+ */
115
+ export declare function isTimeoutError(error: Error): boolean;
116
+ /**
117
+ * Determines whether the given error has a `code` property of `ECONNRESET`.
118
+ *
119
+ * @param error - The error object to test.
120
+ * @returns True if the error code is `ECONNRESET`.
121
+ */
122
+ export declare function isConnectionResetError(error: Error): boolean;
85
123
  /**
86
124
  * This class is responsible for making a request to an endpoint that implements
87
125
  * the JSON-RPC protocol. It is designed to gracefully handle network and server
@@ -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,EAE3B,mCAAmC;AASpC,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,wBAAwB;AACzB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB;AAEtD,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,GAAG,OAAO,CAgBzD;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,IAAI,IAAI;IAInB;;OAEG;IACH,eAAe,IAAI,YAAY;IAI/B;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAM5E;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAmB5E;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GACxD,WAAW;IAMd;;;;;;OAMG;IACH,WAAW,CACT,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACzD,WAAW;IAMd;;;;;;;;;;;;;;;;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
+ {"version":3,"file":"rpc-service.d.cts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,12 @@ export type RpcServiceOptions = {
37
37
  * not accepted, as it is overwritten. See {@link createServicePolicy}.
38
38
  */
39
39
  policyOptions?: Omit<CreateServicePolicyOptions, 'retryFilterPolicy'>;
40
+ /**
41
+ * A function that checks if the user is currently offline. If it returns true,
42
+ * connection errors will not be retried, preventing degraded and break
43
+ * callbacks from being triggered.
44
+ */
45
+ isOffline: () => boolean;
40
46
  };
41
47
  /**
42
48
  * The maximum number of times that a failing service should be re-run before
@@ -82,6 +88,38 @@ export declare const CUSTOM_RPC_ERRORS: {
82
88
  * and false otherwise.
83
89
  */
84
90
  export declare function isConnectionError(error: unknown): boolean;
91
+ /**
92
+ * Determine whether the given error message indicates a failure to parse JSON.
93
+ *
94
+ * This is different in tests vs. implementation code because it may manifest as
95
+ * a FetchError or a SyntaxError.
96
+ *
97
+ * @param error - The error object to test.
98
+ * @returns True if the error indicates a JSON parse error, false otherwise.
99
+ */
100
+ export declare function isJsonParseError(error: unknown): boolean;
101
+ /**
102
+ * Determines whether the given error represents a HTTP server error
103
+ * (502, 503, or 504) that should be retried.
104
+ *
105
+ * @param error - The error object to test.
106
+ * @returns True if the error has an httpStatus of 502, 503, or 504.
107
+ */
108
+ export declare function isHttpServerError(error: Error): boolean;
109
+ /**
110
+ * Determines whether the given error has a `code` property of `ETIMEDOUT`.
111
+ *
112
+ * @param error - The error object to test.
113
+ * @returns True if the error code is `ETIMEDOUT`.
114
+ */
115
+ export declare function isTimeoutError(error: Error): boolean;
116
+ /**
117
+ * Determines whether the given error has a `code` property of `ECONNRESET`.
118
+ *
119
+ * @param error - The error object to test.
120
+ * @returns True if the error code is `ECONNRESET`.
121
+ */
122
+ export declare function isConnectionResetError(error: Error): boolean;
85
123
  /**
86
124
  * This class is responsible for making a request to an endpoint that implements
87
125
  * the JSON-RPC protocol. It is designed to gracefully handle network and server
@@ -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,EAE3B,mCAAmC;AASpC,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,wBAAwB;AACzB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB;AAEtD,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,GAAG,OAAO,CAgBzD;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,IAAI,IAAI;IAInB;;OAEG;IACH,eAAe,IAAI,YAAY;IAI/B;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAM5E;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAmB5E;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GACxD,WAAW;IAMd;;;;;;OAMG;IACH,WAAW,CACT,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACzD,WAAW;IAMd;;;;;;;;;;;;;;;;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
+ {"version":3,"file":"rpc-service.d.mts","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":"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"}