@metamask-previews/network-controller 26.0.0-preview-4ed214fa → 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.
- package/CHANGELOG.md +19 -0
- package/dist/NetworkController.cjs +37 -10
- package/dist/NetworkController.cjs.map +1 -1
- package/dist/NetworkController.d.cts +146 -11
- package/dist/NetworkController.d.cts.map +1 -1
- package/dist/NetworkController.d.mts +146 -11
- package/dist/NetworkController.d.mts.map +1 -1
- package/dist/NetworkController.mjs +37 -10
- package/dist/NetworkController.mjs.map +1 -1
- package/dist/constants.cjs +18 -10
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +18 -10
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts +18 -10
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +18 -10
- package/dist/constants.mjs.map +1 -1
- package/dist/create-auto-managed-network-client.cjs +4 -1
- package/dist/create-auto-managed-network-client.cjs.map +1 -1
- package/dist/create-auto-managed-network-client.d.cts +5 -2
- package/dist/create-auto-managed-network-client.d.cts.map +1 -1
- package/dist/create-auto-managed-network-client.d.mts +5 -2
- package/dist/create-auto-managed-network-client.d.mts.map +1 -1
- package/dist/create-auto-managed-network-client.mjs +4 -1
- package/dist/create-auto-managed-network-client.mjs.map +1 -1
- package/dist/create-network-client.cjs +115 -42
- package/dist/create-network-client.cjs.map +1 -1
- package/dist/create-network-client.d.cts +5 -2
- package/dist/create-network-client.d.cts.map +1 -1
- package/dist/create-network-client.d.mts +5 -2
- package/dist/create-network-client.d.mts.map +1 -1
- package/dist/create-network-client.mjs +115 -42
- package/dist/create-network-client.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/rpc-service/rpc-service-chain.cjs +255 -39
- package/dist/rpc-service/rpc-service-chain.cjs.map +1 -1
- package/dist/rpc-service/rpc-service-chain.d.cts +117 -25
- package/dist/rpc-service/rpc-service-chain.d.cts.map +1 -1
- package/dist/rpc-service/rpc-service-chain.d.mts +117 -25
- package/dist/rpc-service/rpc-service-chain.d.mts.map +1 -1
- package/dist/rpc-service/rpc-service-chain.mjs +255 -39
- package/dist/rpc-service/rpc-service-chain.mjs.map +1 -1
- package/dist/rpc-service/rpc-service-requestable.cjs.map +1 -1
- package/dist/rpc-service/rpc-service-requestable.d.cts +15 -5
- package/dist/rpc-service/rpc-service-requestable.d.cts.map +1 -1
- package/dist/rpc-service/rpc-service-requestable.d.mts +15 -5
- package/dist/rpc-service/rpc-service-requestable.d.mts.map +1 -1
- package/dist/rpc-service/rpc-service-requestable.mjs.map +1 -1
- package/dist/rpc-service/rpc-service.cjs +63 -33
- package/dist/rpc-service/rpc-service.cjs.map +1 -1
- package/dist/rpc-service/rpc-service.d.cts +35 -24
- package/dist/rpc-service/rpc-service.d.cts.map +1 -1
- package/dist/rpc-service/rpc-service.d.mts +35 -24
- package/dist/rpc-service/rpc-service.d.mts.map +1 -1
- package/dist/rpc-service/rpc-service.mjs +64 -34
- package/dist/rpc-service/rpc-service.mjs.map +1 -1
- package/dist/rpc-service/shared.cjs.map +1 -1
- package/dist/rpc-service/shared.d.cts +30 -3
- package/dist/rpc-service/shared.d.cts.map +1 -1
- package/dist/rpc-service/shared.d.mts +30 -3
- package/dist/rpc-service/shared.d.mts.map +1 -1
- package/dist/rpc-service/shared.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -9,18 +9,20 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _RpcService_instances, _RpcService_fetch, _RpcService_fetchOptions,
|
|
12
|
+
var _RpcService_instances, _RpcService_fetch, _RpcService_fetchOptions, _RpcService_lastError, _RpcService_logger, _RpcService_policy, _RpcService_getDefaultFetchOptions, _RpcService_getCompleteFetchOptions, _RpcService_executeAndProcessRequest;
|
|
13
13
|
function $importDefault(module) {
|
|
14
14
|
if (module?.__esModule) {
|
|
15
15
|
return module.default;
|
|
16
16
|
}
|
|
17
17
|
return module;
|
|
18
18
|
}
|
|
19
|
-
import { BrokenCircuitError,
|
|
19
|
+
import { BrokenCircuitError, HttpError, createServicePolicy, handleWhen } from "@metamask/controller-utils";
|
|
20
20
|
import { JsonRpcError, rpcErrors } from "@metamask/rpc-errors";
|
|
21
21
|
import { Duration, getErrorMessage, hasProperty } from "@metamask/utils";
|
|
22
22
|
import $deepmerge from "deepmerge";
|
|
23
23
|
const deepmerge = $importDefault($deepmerge);
|
|
24
|
+
import { projectLogger, createModuleLogger } from "../logger.mjs";
|
|
25
|
+
const log = createModuleLogger(projectLogger, 'RpcService');
|
|
24
26
|
/**
|
|
25
27
|
* The maximum number of times that a failing service should be re-run before
|
|
26
28
|
* giving up.
|
|
@@ -191,11 +193,7 @@ export 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 @@ export 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,
|
|
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
|
-
|
|
211
|
+
__classPrivateFieldSet(this, _RpcService_policy, createServicePolicy({
|
|
215
212
|
maxRetries: DEFAULT_MAX_RETRIES,
|
|
216
213
|
maxConsecutiveFailures: DEFAULT_MAX_CONSECUTIVE_FAILURES,
|
|
217
214
|
...policyOptions,
|
|
@@ -229,8 +226,32 @@ export class RpcService {
|
|
|
229
226
|
(hasProperty(error, 'code') &&
|
|
230
227
|
(error.code === 'ETIMEDOUT' || error.code === 'ECONNRESET')));
|
|
231
228
|
}),
|
|
232
|
-
});
|
|
233
|
-
|
|
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 @@ export 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 @@ export class RpcService {
|
|
|
254
275
|
*/
|
|
255
276
|
onBreak(listener) {
|
|
256
277
|
return __classPrivateFieldGet(this, _RpcService_policy, "f").onBreak((data) => {
|
|
257
|
-
|
|
258
|
-
...data,
|
|
259
|
-
|
|
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,23 +293,26 @@ export 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
|
-
|
|
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 === 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
|
-
_RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(),
|
|
315
|
+
_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) {
|
|
296
316
|
if (endpointUrl.username && endpointUrl.password) {
|
|
297
317
|
const authString = `${endpointUrl.username}:${endpointUrl.password}`;
|
|
298
318
|
const encodedCredentials = givenBtoa(authString);
|
|
@@ -318,7 +338,7 @@ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _Rp
|
|
|
318
338
|
params,
|
|
319
339
|
});
|
|
320
340
|
return { ...mergedOptions, body };
|
|
321
|
-
},
|
|
341
|
+
}, _RpcService_executeAndProcessRequest =
|
|
322
342
|
/**
|
|
323
343
|
* Makes the request using the Cockatiel policy that this service creates.
|
|
324
344
|
*
|
|
@@ -331,18 +351,28 @@ _RpcService_fetch = new WeakMap(), _RpcService_fetchOptions = new WeakMap(), _Rp
|
|
|
331
351
|
* @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.
|
|
332
352
|
* @throws A "parse" JSON-RPC error (code -32700) if the response is not valid JSON.
|
|
333
353
|
*/
|
|
334
|
-
async function
|
|
354
|
+
async function _RpcService_executeAndProcessRequest(fetchOptions) {
|
|
335
355
|
let response;
|
|
336
356
|
try {
|
|
337
|
-
|
|
357
|
+
log(`[RpcService: ${this.endpointUrl}] Circuit state`, __classPrivateFieldGet(this, _RpcService_policy, "f").getCircuitState());
|
|
358
|
+
const jsonDecodedResponse = await __classPrivateFieldGet(this, _RpcService_policy, "f").execute(async (data) => {
|
|
359
|
+
log('REQUEST INITIATED:', this.endpointUrl.toString(), '::', fetchOptions,
|
|
360
|
+
// @ts-expect-error This property _is_ here, the type of ServicePolicy
|
|
361
|
+
// is just wrong.
|
|
362
|
+
`(attempt ${data.attempt + 1})`);
|
|
338
363
|
response = await __classPrivateFieldGet(this, _RpcService_fetch, "f").call(this, this.endpointUrl, fetchOptions);
|
|
339
364
|
if (!response.ok) {
|
|
340
365
|
throw new HttpError(response.status);
|
|
341
366
|
}
|
|
367
|
+
log('REQUEST SUCCESSFUL:', this.endpointUrl.toString(), response.status);
|
|
342
368
|
return await response.json();
|
|
343
369
|
});
|
|
370
|
+
__classPrivateFieldSet(this, _RpcService_lastError, undefined, "f");
|
|
371
|
+
return jsonDecodedResponse;
|
|
344
372
|
}
|
|
345
373
|
catch (error) {
|
|
374
|
+
log('REQUEST ERROR:', this.endpointUrl.toString(), error);
|
|
375
|
+
__classPrivateFieldSet(this, _RpcService_lastError, error, "f");
|
|
346
376
|
if (error instanceof HttpError) {
|
|
347
377
|
const status = error.httpStatus;
|
|
348
378
|
if (status === 401) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-service.mjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-service.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport {\n BrokenCircuitError,\n CircuitState,\n HttpError,\n createServicePolicy,\n handleWhen,\n} from '@metamask/controller-utils';\nimport { JsonRpcError, rpcErrors } from '@metamask/rpc-errors';\nimport type { JsonRpcRequest } from '@metamask/utils';\nimport {\n Duration,\n getErrorMessage,\n hasProperty,\n type Json,\n type JsonRpcParams,\n type JsonRpcResponse,\n} from '@metamask/utils';\nimport deepmerge from 'deepmerge';\nimport type { Logger } from 'loglevel';\n\nimport type { AbstractRpcService } from './abstract-rpc-service';\nimport type { AddToCockatielEventData, FetchOptions } from './shared';\n\n/**\n * Options for the RpcService constructor.\n */\nexport type RpcServiceOptions = {\n /**\n * A function that can be used to convert a binary string into a\n * base64-encoded ASCII string. Used to encode authorization credentials.\n */\n btoa: typeof btoa;\n /**\n * The URL of the RPC endpoint to hit.\n */\n endpointUrl: URL | string;\n /**\n * An RPC service that represents a failover endpoint which will be invoked\n * while the circuit for _this_ service is open.\n */\n failoverService?: AbstractRpcService;\n /**\n * A function that can be used to make an HTTP request. If your JavaScript\n * environment supports `fetch` natively, you'll probably want to pass that;\n * otherwise you can pass an equivalent (such as `fetch` via `node-fetch`).\n */\n fetch: typeof fetch;\n /**\n * A common set of options that will be used to make every request. Can be\n * overridden on the request level (e.g. to add headers).\n */\n fetchOptions?: FetchOptions;\n /**\n * A `loglevel` logger.\n */\n logger?: Pick<Logger, 'warn'>;\n /**\n * Options to pass to `createServicePolicy`. Note that `retryFilterPolicy` is\n * not accepted, as it is overwritten. See {@link createServicePolicy}.\n */\n policyOptions?: Omit<CreateServicePolicyOptions, 'retryFilterPolicy'>;\n};\n\n/**\n * The maximum number of times that a failing service should be re-run before\n * giving up.\n */\nexport const DEFAULT_MAX_RETRIES = 4;\n\n/**\n * The maximum number of times that the service is allowed to fail before\n * pausing further retries. This is set to a value such that if given a\n * service that continually fails, the policy needs to be executed 3 times\n * before further retries are paused.\n */\nexport const DEFAULT_MAX_CONSECUTIVE_FAILURES = (1 + DEFAULT_MAX_RETRIES) * 3;\n\n/**\n * The list of error messages that represent a failure to connect to the network.\n *\n * This list was derived from Sindre Sorhus's `is-network-error` package:\n * <https://github.com/sindresorhus/is-network-error/blob/7bbfa8be9482ce1427a21fbff60e3ee1650dd091/index.js>\n */\nexport const CONNECTION_ERRORS = [\n // Chrome\n {\n constructorName: 'TypeError',\n pattern: /network error/u,\n },\n // Chrome\n {\n constructorName: 'TypeError',\n pattern: /Failed to fetch/u,\n },\n // Firefox\n {\n constructorName: 'TypeError',\n pattern: /NetworkError when attempting to fetch resource\\./u,\n },\n // Safari 16\n {\n constructorName: 'TypeError',\n pattern: /The Internet connection appears to be offline\\./u,\n },\n // Safari 17+\n {\n constructorName: 'TypeError',\n pattern: /Load failed/u,\n },\n // `cross-fetch`\n {\n constructorName: 'TypeError',\n pattern: /Network request failed/u,\n },\n // `node-fetch`\n {\n constructorName: 'FetchError',\n pattern: /request to (.+) failed/u,\n },\n // Undici (Node.js)\n {\n constructorName: 'TypeError',\n pattern: /fetch failed/u,\n },\n // Undici (Node.js)\n {\n constructorName: 'TypeError',\n pattern: /terminated/u,\n },\n];\n\n/**\n * Custom JSON-RPC error codes for specific cases.\n *\n * These should be moved to `@metamask/rpc-errors` eventually.\n */\nexport const CUSTOM_RPC_ERRORS = {\n unauthorized: -32006,\n httpClientError: -32080,\n} as const;\n\n/**\n * Determines whether the given error represents a failure to reach the network\n * after request parameters have been validated.\n *\n * This is somewhat difficult to verify because JavaScript engines (and in\n * some cases libraries) produce slightly different error messages for this\n * particular scenario, and we need to account for this.\n *\n * @param error - The error.\n * @returns True if the error indicates that the network cannot be connected to,\n * and false otherwise.\n */\nexport function isConnectionError(error: unknown) {\n if (!(typeof error === 'object' && error !== null && 'message' in error)) {\n return false;\n }\n\n const { message } = error;\n\n return (\n typeof message === 'string' &&\n !isNockError(message) &&\n CONNECTION_ERRORS.some(({ constructorName, pattern }) => {\n return (\n error.constructor.name === constructorName && pattern.test(message)\n );\n })\n );\n}\n\n/**\n * Determines whether the given error message refers to a Nock error.\n *\n * It's important that if we failed to mock a request in a test, the resulting\n * error does not cause the request to be retried so that we can see it right\n * away.\n *\n * @param message - The error message to test.\n * @returns True if the message indicates a missing Nock mock, false otherwise.\n */\nfunction isNockError(message: string) {\n return message.includes('Nock:');\n}\n\n/**\n * Determine whether the given error message indicates a failure to parse JSON.\n *\n * This is different in tests vs. implementation code because it may manifest as\n * a FetchError or a SyntaxError.\n *\n * @param error - The error object to test.\n * @returns True if the error indicates a JSON parse error, false otherwise.\n */\nfunction isJsonParseError(error: unknown) {\n return (\n error instanceof SyntaxError ||\n /invalid json/iu.test(getErrorMessage(error))\n );\n}\n\n/**\n * Guarantees a URL, even given a string. This is useful for checking components\n * of that URL.\n *\n * @param endpointUrlOrUrlString - Either a URL object or a string that\n * represents the URL of an endpoint.\n * @returns A URL object.\n */\nfunction getNormalizedEndpointUrl(endpointUrlOrUrlString: URL | string): URL {\n return endpointUrlOrUrlString instanceof URL\n ? endpointUrlOrUrlString\n : new URL(endpointUrlOrUrlString);\n}\n\n/**\n * Strips username and password from a URL.\n *\n * @param url - The URL to strip credentials from.\n * @returns A new URL object with credentials removed.\n */\nfunction stripCredentialsFromUrl(url: URL): URL {\n const strippedUrl = new URL(url.toString());\n strippedUrl.username = '';\n strippedUrl.password = '';\n return strippedUrl;\n}\n\n/**\n * This class is responsible for making a request to an endpoint that implements\n * the JSON-RPC protocol. It is designed to gracefully handle network and server\n * failures, retrying requests using exponential backoff. It also offers a hook\n * which can used to respond to slow requests.\n */\nexport class RpcService implements AbstractRpcService {\n /**\n * The function used to make an HTTP request.\n */\n readonly #fetch: typeof fetch;\n\n /**\n * The URL of the RPC endpoint.\n */\n readonly endpointUrl: URL;\n\n /**\n * A common set of options that the request options will extend.\n */\n readonly #fetchOptions: FetchOptions;\n\n /**\n * An RPC service that represents a failover endpoint which will be invoked\n * while the circuit for _this_ service is open.\n */\n readonly #failoverService: RpcServiceOptions['failoverService'];\n\n /**\n * A `loglevel` logger.\n */\n readonly #logger: RpcServiceOptions['logger'];\n\n /**\n * The policy that wraps the request.\n */\n readonly #policy: ServicePolicy;\n\n /**\n * Constructs a new RpcService object.\n *\n * @param options - The options. See {@link RpcServiceOptions}.\n */\n constructor(options: RpcServiceOptions) {\n const {\n btoa: givenBtoa,\n endpointUrl,\n failoverService,\n fetch: givenFetch,\n logger,\n fetchOptions = {},\n policyOptions = {},\n } = options;\n\n this.#fetch = givenFetch;\n const normalizedUrl = getNormalizedEndpointUrl(endpointUrl);\n this.#fetchOptions = this.#getDefaultFetchOptions(\n normalizedUrl,\n fetchOptions,\n givenBtoa,\n );\n this.endpointUrl = stripCredentialsFromUrl(normalizedUrl);\n this.#failoverService = failoverService;\n this.#logger = logger;\n\n const policy = createServicePolicy({\n maxRetries: DEFAULT_MAX_RETRIES,\n maxConsecutiveFailures: DEFAULT_MAX_CONSECUTIVE_FAILURES,\n ...policyOptions,\n retryFilterPolicy: handleWhen((error) => {\n return (\n // Ignore errors where the request failed to establish\n isConnectionError(error) ||\n // Ignore server sent HTML error pages or truncated JSON responses\n isJsonParseError(error) ||\n // Ignore server overload errors\n ('httpStatus' in error &&\n (error.httpStatus === 502 ||\n error.httpStatus === 503 ||\n error.httpStatus === 504)) ||\n (hasProperty(error, 'code') &&\n (error.code === 'ETIMEDOUT' || error.code === 'ECONNRESET'))\n );\n }),\n });\n this.#policy = policy;\n }\n\n /**\n * Listens for when the RPC service retries the request.\n *\n * @param listener - The callback to be called when the retry occurs.\n * @returns What {@link ServicePolicy.onRetry} returns.\n * @see {@link createServicePolicy}\n */\n onRetry(\n listener: AddToCockatielEventData<\n Parameters<ServicePolicy['onRetry']>[0],\n { endpointUrl: string }\n >,\n ) {\n return this.#policy.onRetry((data) => {\n listener({ ...data, endpointUrl: this.endpointUrl.toString() });\n });\n }\n\n /**\n * Listens for when the RPC service retries the request too many times in a\n * row.\n *\n * @param listener - The callback to be called when the circuit is broken.\n * @returns What {@link ServicePolicy.onBreak} returns.\n * @see {@link createServicePolicy}\n */\n onBreak(\n listener: AddToCockatielEventData<\n Parameters<ServicePolicy['onBreak']>[0],\n { endpointUrl: string; failoverEndpointUrl?: string }\n >,\n ) {\n return this.#policy.onBreak((data) => {\n listener({\n ...data,\n endpointUrl: this.endpointUrl.toString(),\n failoverEndpointUrl: this.#failoverService\n ? this.#failoverService.endpointUrl.toString()\n : undefined,\n });\n });\n }\n\n /**\n * Listens for when the policy underlying this RPC service detects a slow\n * request.\n *\n * @param listener - The callback to be called when the request is slow.\n * @returns What {@link ServicePolicy.onDegraded} returns.\n * @see {@link createServicePolicy}\n */\n onDegraded(\n listener: AddToCockatielEventData<\n Parameters<ServicePolicy['onDegraded']>[0],\n { endpointUrl: string }\n >,\n ) {\n return this.#policy.onDegraded((data) => {\n listener({ ...(data ?? {}), endpointUrl: this.endpointUrl.toString() });\n });\n }\n\n /**\n * Makes a request to the RPC endpoint. If the circuit is open because this\n * request has failed too many times, the request is forwarded to a failover\n * service (if provided).\n *\n * This overload is specifically designed for `eth_getBlockByNumber`, which\n * can return a `result` of `null` despite an expected `Result` being\n * provided.\n *\n * @param jsonRpcRequest - The JSON-RPC request to send to the endpoint.\n * @param fetchOptions - An options bag for {@link fetch} which further\n * specifies the request.\n * @returns The decoded JSON-RPC response from the endpoint.\n * @throws An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\n */\n async request<Params extends JsonRpcParams, Result extends Json>(\n jsonRpcRequest: JsonRpcRequest<Params> & { method: 'eth_getBlockByNumber' },\n fetchOptions?: FetchOptions,\n ): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>>;\n\n /**\n * Makes a request to the RPC endpoint. If the circuit is open because this\n * request has failed too many times, the request is forwarded to a failover\n * service (if provided).\n *\n * This overload is designed for all RPC methods except for\n * `eth_getBlockByNumber`, which are expected to return a `result` of the\n * expected `Result`.\n *\n * @param jsonRpcRequest - The JSON-RPC request to send to the endpoint.\n * @param fetchOptions - An options bag for {@link fetch} which further\n * specifies the request.\n * @returns The decoded JSON-RPC response from the endpoint.\n * @throws An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\n */\n async request<Params extends JsonRpcParams, Result extends Json>(\n jsonRpcRequest: JsonRpcRequest<Params>,\n fetchOptions?: FetchOptions,\n ): Promise<JsonRpcResponse<Result>>;\n\n async request<Params extends JsonRpcParams, Result extends Json>(\n // The request object may be frozen and must not be mutated.\n jsonRpcRequest: Readonly<JsonRpcRequest<Params>>,\n fetchOptions: FetchOptions = {},\n ): Promise<JsonRpcResponse<Result | null>> {\n const completeFetchOptions = this.#getCompleteFetchOptions(\n jsonRpcRequest,\n fetchOptions,\n );\n\n try {\n return await this.#processRequest<Result>(completeFetchOptions);\n } catch (error) {\n if (\n this.#policy.circuitBreakerPolicy.state === CircuitState.Open &&\n this.#failoverService !== undefined\n ) {\n return await this.#failoverService.request(\n jsonRpcRequest,\n completeFetchOptions,\n );\n }\n throw error;\n }\n }\n\n /**\n * Constructs a default set of options to `fetch`.\n *\n * If a username and password are present in the URL, they are extracted to an\n * Authorization header.\n *\n * @param endpointUrl - The endpoint URL.\n * @param fetchOptions - The options to `fetch`.\n * @param givenBtoa - An implementation of `btoa`.\n * @returns The default fetch options.\n */\n #getDefaultFetchOptions(\n endpointUrl: URL,\n fetchOptions: FetchOptions,\n givenBtoa: (stringToEncode: string) => string,\n ): FetchOptions {\n if (endpointUrl.username && endpointUrl.password) {\n const authString = `${endpointUrl.username}:${endpointUrl.password}`;\n const encodedCredentials = givenBtoa(authString);\n return deepmerge(fetchOptions, {\n headers: { Authorization: `Basic ${encodedCredentials}` },\n });\n }\n\n return fetchOptions;\n }\n\n /**\n * Constructs a final set of options to pass to `fetch`. Note that the method\n * defaults to `post`, and the JSON-RPC request is automatically JSON-encoded.\n *\n * @param jsonRpcRequest - The JSON-RPC request.\n * @param fetchOptions - Custom `fetch` options.\n * @returns The complete set of `fetch` options.\n */\n #getCompleteFetchOptions<Params extends JsonRpcParams>(\n jsonRpcRequest: Readonly<JsonRpcRequest<Params>>,\n fetchOptions: FetchOptions,\n ): FetchOptions {\n const defaultOptions = {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n };\n const mergedOptions = deepmerge(\n defaultOptions,\n deepmerge(this.#fetchOptions, fetchOptions),\n );\n\n const { id, jsonrpc, method, params } = jsonRpcRequest;\n const body = JSON.stringify({\n id,\n jsonrpc,\n method,\n params,\n });\n\n return { ...mergedOptions, body };\n }\n\n /**\n * Makes the request using the Cockatiel policy that this service creates.\n *\n * @param fetchOptions - The options for `fetch`; will be combined with the\n * fetch options passed to the constructor\n * @returns The decoded JSON-RPC response from the endpoint.\n * @throws An \"authorized\" JSON-RPC error (code -32006) if the response HTTP status is 401.\n * @throws A \"rate limiting\" JSON-RPC error (code -32005) if the response HTTP status is 429.\n * @throws A \"resource unavailable\" JSON-RPC error (code -32002) if the response HTTP status is 402, 404, or any 5xx.\n * @throws A generic HTTP client JSON-RPC error (code -32050) for any other 4xx HTTP status codes.\n * @throws A \"parse\" JSON-RPC error (code -32700) if the response is not valid JSON.\n */\n async #processRequest<Result extends Json>(\n fetchOptions: FetchOptions,\n ): Promise<JsonRpcResponse<Result> | JsonRpcResponse<null>> {\n let response: Response | undefined;\n try {\n return await this.#policy.execute(async () => {\n response = await this.#fetch(this.endpointUrl, fetchOptions);\n if (!response.ok) {\n throw new HttpError(response.status);\n }\n return await response.json();\n });\n } catch (error) {\n if (error instanceof HttpError) {\n const status = error.httpStatus;\n if (status === 401) {\n throw new JsonRpcError(\n CUSTOM_RPC_ERRORS.unauthorized,\n 'Unauthorized.',\n {\n httpStatus: status,\n },\n );\n }\n if (status === 429) {\n throw rpcErrors.limitExceeded({\n message: 'Request is being rate limited.',\n data: {\n httpStatus: status,\n },\n });\n }\n if (status >= 500 || status === 402 || status === 404) {\n throw rpcErrors.resourceUnavailable({\n message: 'RPC endpoint not found or unavailable.',\n data: {\n httpStatus: status,\n },\n });\n }\n\n // Handle all other 4xx errors as generic HTTP client errors\n throw new JsonRpcError(\n CUSTOM_RPC_ERRORS.httpClientError,\n 'RPC endpoint returned HTTP client error.',\n {\n httpStatus: status,\n },\n );\n } else if (isJsonParseError(error)) {\n throw rpcErrors.parse({\n message: 'RPC endpoint did not return JSON.',\n });\n } else if (error instanceof BrokenCircuitError) {\n this.#logger?.warn(error);\n const remainingCircuitOpenDuration =\n this.#policy.getRemainingCircuitOpenDuration();\n const formattedRemainingCircuitOpenDuration = Intl.NumberFormat(\n undefined,\n { maximumFractionDigits: 2 },\n ).format(\n (remainingCircuitOpenDuration ?? this.#policy.circuitBreakDuration) /\n Duration.Minute,\n );\n throw rpcErrors.resourceUnavailable({\n message: `RPC endpoint returned too many errors, retrying in ${formattedRemainingCircuitOpenDuration} minutes. Consider using a different RPC endpoint.`,\n });\n }\n throw error;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rpc-service.mjs","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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.cjs","sourceRoot":"","sources":["../../src/rpc-service/shared.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Equivalent to the built-in `FetchOptions` type, but renamed for clarity.\n */\nexport type FetchOptions = RequestInit;\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"shared.cjs","sourceRoot":"","sources":["../../src/rpc-service/shared.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n CockatielEvent,\n CockatielEventEmitter,\n} from '@metamask/controller-utils';\n\n/**\n * Equivalent to the built-in `FetchOptions` type, but renamed for clarity.\n */\nexport type FetchOptions = RequestInit;\n\n/**\n * Converts a Cockatiel event type to an event emitter type.\n */\nexport type CockatielEventToEventEmitter<Event> =\n Event extends CockatielEvent<infer EventData>\n ? CockatielEventEmitter<EventData>\n : never;\n\n/**\n * Obtains the event data type from a Cockatiel event or event listener type.\n */\nexport type ExtractCockatielEventData<CockatielEventOrEventListener> =\n CockatielEventOrEventListener extends CockatielEvent<infer Data>\n ? Data\n : CockatielEventOrEventListener extends (data: infer Data) => void\n ? Data\n : never;\n\n/**\n * Extends the data that a Cockatiel event listener is called with additional\n * data.\n */\nexport type ExtendCockatielEventData<OriginalData, AdditionalData> =\n OriginalData extends void ? AdditionalData : OriginalData & AdditionalData;\n\n/**\n * Removes keys from the data that a Cockatiel event listner is called with.\n */\nexport type ExcludeCockatielEventData<\n OriginalData,\n Keys extends PropertyKey,\n> = OriginalData extends void ? void : Omit<OriginalData, Keys>;\n\n/**\n * Converts a Cockatiel event type to an event listener type, but adding the\n * requested data.\n */\nexport type CockatielEventToEventListenerWithData<Event, Data> = (\n data: ExtendCockatielEventData<ExtractCockatielEventData<Event>, Data>,\n) => void;\n\n/**\n * Converts a Cockatiel event type to an event listener type, but removing the\n * requested keys from the data.\n */\nexport type CockatielEventToEventListenerWithoutData<\n Event,\n Keys extends PropertyKey,\n> = (\n data: ExcludeCockatielEventData<ExtractCockatielEventData<Event>, Keys>,\n) => void;\n\n/**\n * Converts a Cockatiel event listener type to an event emitter type.\n */\nexport type CockatielEventToEventEmitterWithData<Event, Data> =\n CockatielEventEmitter<\n ExtendCockatielEventData<ExtractCockatielEventData<Event>, Data>\n >;\n"]}
|
|
@@ -1,10 +1,37 @@
|
|
|
1
|
+
import type { CockatielEvent, CockatielEventEmitter } from "@metamask/controller-utils";
|
|
1
2
|
/**
|
|
2
3
|
* Equivalent to the built-in `FetchOptions` type, but renamed for clarity.
|
|
3
4
|
*/
|
|
4
5
|
export type FetchOptions = RequestInit;
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
* data can be supplied in the event object.
|
|
7
|
+
* Converts a Cockatiel event type to an event emitter type.
|
|
8
8
|
*/
|
|
9
|
-
export type
|
|
9
|
+
export type CockatielEventToEventEmitter<Event> = Event extends CockatielEvent<infer EventData> ? CockatielEventEmitter<EventData> : never;
|
|
10
|
+
/**
|
|
11
|
+
* Obtains the event data type from a Cockatiel event or event listener type.
|
|
12
|
+
*/
|
|
13
|
+
export type ExtractCockatielEventData<CockatielEventOrEventListener> = CockatielEventOrEventListener extends CockatielEvent<infer Data> ? Data : CockatielEventOrEventListener extends (data: infer Data) => void ? Data : never;
|
|
14
|
+
/**
|
|
15
|
+
* Extends the data that a Cockatiel event listener is called with additional
|
|
16
|
+
* data.
|
|
17
|
+
*/
|
|
18
|
+
export type ExtendCockatielEventData<OriginalData, AdditionalData> = OriginalData extends void ? AdditionalData : OriginalData & AdditionalData;
|
|
19
|
+
/**
|
|
20
|
+
* Removes keys from the data that a Cockatiel event listner is called with.
|
|
21
|
+
*/
|
|
22
|
+
export type ExcludeCockatielEventData<OriginalData, Keys extends PropertyKey> = OriginalData extends void ? void : Omit<OriginalData, Keys>;
|
|
23
|
+
/**
|
|
24
|
+
* Converts a Cockatiel event type to an event listener type, but adding the
|
|
25
|
+
* requested data.
|
|
26
|
+
*/
|
|
27
|
+
export type CockatielEventToEventListenerWithData<Event, Data> = (data: ExtendCockatielEventData<ExtractCockatielEventData<Event>, Data>) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Converts a Cockatiel event type to an event listener type, but removing the
|
|
30
|
+
* requested keys from the data.
|
|
31
|
+
*/
|
|
32
|
+
export type CockatielEventToEventListenerWithoutData<Event, Keys extends PropertyKey> = (data: ExcludeCockatielEventData<ExtractCockatielEventData<Event>, Keys>) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Converts a Cockatiel event listener type to an event emitter type.
|
|
35
|
+
*/
|
|
36
|
+
export type CockatielEventToEventEmitterWithData<Event, Data> = CockatielEventEmitter<ExtendCockatielEventData<ExtractCockatielEventData<Event>, Data>>;
|
|
10
37
|
//# sourceMappingURL=shared.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.cts","sourceRoot":"","sources":["../../src/rpc-service/shared.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC;AAEvC;;;GAGG;AACH,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"shared.d.cts","sourceRoot":"","sources":["../../src/rpc-service/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACtB,mCAAmC;AAEpC;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC;AAEvC;;GAEG;AACH,MAAM,MAAM,4BAA4B,CAAC,KAAK,IAC5C,KAAK,SAAS,cAAc,CAAC,MAAM,SAAS,CAAC,GACzC,qBAAqB,CAAC,SAAS,CAAC,GAChC,KAAK,CAAC;AAEZ;;GAEG;AACH,MAAM,MAAM,yBAAyB,CAAC,6BAA6B,IACjE,6BAA6B,SAAS,cAAc,CAAC,MAAM,IAAI,CAAC,GAC5D,IAAI,GACJ,6BAA6B,SAAS,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,GAC9D,IAAI,GACJ,KAAK,CAAC;AAEd;;;GAGG;AACH,MAAM,MAAM,wBAAwB,CAAC,YAAY,EAAE,cAAc,IAC/D,YAAY,SAAS,IAAI,GAAG,cAAc,GAAG,YAAY,GAAG,cAAc,CAAC;AAE7E;;GAEG;AACH,MAAM,MAAM,yBAAyB,CACnC,YAAY,EACZ,IAAI,SAAS,WAAW,IACtB,YAAY,SAAS,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;AAEhE;;;GAGG;AACH,MAAM,MAAM,qCAAqC,CAAC,KAAK,EAAE,IAAI,IAAI,CAC/D,IAAI,EAAE,wBAAwB,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KACnE,IAAI,CAAC;AAEV;;;GAGG;AACH,MAAM,MAAM,wCAAwC,CAClD,KAAK,EACL,IAAI,SAAS,WAAW,IACtB,CACF,IAAI,EAAE,yBAAyB,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KACpE,IAAI,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,oCAAoC,CAAC,KAAK,EAAE,IAAI,IAC1D,qBAAqB,CACnB,wBAAwB,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CACjE,CAAC"}
|
|
@@ -1,10 +1,37 @@
|
|
|
1
|
+
import type { CockatielEvent, CockatielEventEmitter } from "@metamask/controller-utils";
|
|
1
2
|
/**
|
|
2
3
|
* Equivalent to the built-in `FetchOptions` type, but renamed for clarity.
|
|
3
4
|
*/
|
|
4
5
|
export type FetchOptions = RequestInit;
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
* data can be supplied in the event object.
|
|
7
|
+
* Converts a Cockatiel event type to an event emitter type.
|
|
8
8
|
*/
|
|
9
|
-
export type
|
|
9
|
+
export type CockatielEventToEventEmitter<Event> = Event extends CockatielEvent<infer EventData> ? CockatielEventEmitter<EventData> : never;
|
|
10
|
+
/**
|
|
11
|
+
* Obtains the event data type from a Cockatiel event or event listener type.
|
|
12
|
+
*/
|
|
13
|
+
export type ExtractCockatielEventData<CockatielEventOrEventListener> = CockatielEventOrEventListener extends CockatielEvent<infer Data> ? Data : CockatielEventOrEventListener extends (data: infer Data) => void ? Data : never;
|
|
14
|
+
/**
|
|
15
|
+
* Extends the data that a Cockatiel event listener is called with additional
|
|
16
|
+
* data.
|
|
17
|
+
*/
|
|
18
|
+
export type ExtendCockatielEventData<OriginalData, AdditionalData> = OriginalData extends void ? AdditionalData : OriginalData & AdditionalData;
|
|
19
|
+
/**
|
|
20
|
+
* Removes keys from the data that a Cockatiel event listner is called with.
|
|
21
|
+
*/
|
|
22
|
+
export type ExcludeCockatielEventData<OriginalData, Keys extends PropertyKey> = OriginalData extends void ? void : Omit<OriginalData, Keys>;
|
|
23
|
+
/**
|
|
24
|
+
* Converts a Cockatiel event type to an event listener type, but adding the
|
|
25
|
+
* requested data.
|
|
26
|
+
*/
|
|
27
|
+
export type CockatielEventToEventListenerWithData<Event, Data> = (data: ExtendCockatielEventData<ExtractCockatielEventData<Event>, Data>) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Converts a Cockatiel event type to an event listener type, but removing the
|
|
30
|
+
* requested keys from the data.
|
|
31
|
+
*/
|
|
32
|
+
export type CockatielEventToEventListenerWithoutData<Event, Keys extends PropertyKey> = (data: ExcludeCockatielEventData<ExtractCockatielEventData<Event>, Keys>) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Converts a Cockatiel event listener type to an event emitter type.
|
|
35
|
+
*/
|
|
36
|
+
export type CockatielEventToEventEmitterWithData<Event, Data> = CockatielEventEmitter<ExtendCockatielEventData<ExtractCockatielEventData<Event>, Data>>;
|
|
10
37
|
//# sourceMappingURL=shared.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.mts","sourceRoot":"","sources":["../../src/rpc-service/shared.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC;AAEvC;;;GAGG;AACH,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"shared.d.mts","sourceRoot":"","sources":["../../src/rpc-service/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACtB,mCAAmC;AAEpC;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC;AAEvC;;GAEG;AACH,MAAM,MAAM,4BAA4B,CAAC,KAAK,IAC5C,KAAK,SAAS,cAAc,CAAC,MAAM,SAAS,CAAC,GACzC,qBAAqB,CAAC,SAAS,CAAC,GAChC,KAAK,CAAC;AAEZ;;GAEG;AACH,MAAM,MAAM,yBAAyB,CAAC,6BAA6B,IACjE,6BAA6B,SAAS,cAAc,CAAC,MAAM,IAAI,CAAC,GAC5D,IAAI,GACJ,6BAA6B,SAAS,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,GAC9D,IAAI,GACJ,KAAK,CAAC;AAEd;;;GAGG;AACH,MAAM,MAAM,wBAAwB,CAAC,YAAY,EAAE,cAAc,IAC/D,YAAY,SAAS,IAAI,GAAG,cAAc,GAAG,YAAY,GAAG,cAAc,CAAC;AAE7E;;GAEG;AACH,MAAM,MAAM,yBAAyB,CACnC,YAAY,EACZ,IAAI,SAAS,WAAW,IACtB,YAAY,SAAS,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;AAEhE;;;GAGG;AACH,MAAM,MAAM,qCAAqC,CAAC,KAAK,EAAE,IAAI,IAAI,CAC/D,IAAI,EAAE,wBAAwB,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KACnE,IAAI,CAAC;AAEV;;;GAGG;AACH,MAAM,MAAM,wCAAwC,CAClD,KAAK,EACL,IAAI,SAAS,WAAW,IACtB,CACF,IAAI,EAAE,yBAAyB,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KACpE,IAAI,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,oCAAoC,CAAC,KAAK,EAAE,IAAI,IAC1D,qBAAqB,CACnB,wBAAwB,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CACjE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.mjs","sourceRoot":"","sources":["../../src/rpc-service/shared.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Equivalent to the built-in `FetchOptions` type, but renamed for clarity.\n */\nexport type FetchOptions = RequestInit;\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"shared.mjs","sourceRoot":"","sources":["../../src/rpc-service/shared.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n CockatielEvent,\n CockatielEventEmitter,\n} from '@metamask/controller-utils';\n\n/**\n * Equivalent to the built-in `FetchOptions` type, but renamed for clarity.\n */\nexport type FetchOptions = RequestInit;\n\n/**\n * Converts a Cockatiel event type to an event emitter type.\n */\nexport type CockatielEventToEventEmitter<Event> =\n Event extends CockatielEvent<infer EventData>\n ? CockatielEventEmitter<EventData>\n : never;\n\n/**\n * Obtains the event data type from a Cockatiel event or event listener type.\n */\nexport type ExtractCockatielEventData<CockatielEventOrEventListener> =\n CockatielEventOrEventListener extends CockatielEvent<infer Data>\n ? Data\n : CockatielEventOrEventListener extends (data: infer Data) => void\n ? Data\n : never;\n\n/**\n * Extends the data that a Cockatiel event listener is called with additional\n * data.\n */\nexport type ExtendCockatielEventData<OriginalData, AdditionalData> =\n OriginalData extends void ? AdditionalData : OriginalData & AdditionalData;\n\n/**\n * Removes keys from the data that a Cockatiel event listner is called with.\n */\nexport type ExcludeCockatielEventData<\n OriginalData,\n Keys extends PropertyKey,\n> = OriginalData extends void ? void : Omit<OriginalData, Keys>;\n\n/**\n * Converts a Cockatiel event type to an event listener type, but adding the\n * requested data.\n */\nexport type CockatielEventToEventListenerWithData<Event, Data> = (\n data: ExtendCockatielEventData<ExtractCockatielEventData<Event>, Data>,\n) => void;\n\n/**\n * Converts a Cockatiel event type to an event listener type, but removing the\n * requested keys from the data.\n */\nexport type CockatielEventToEventListenerWithoutData<\n Event,\n Keys extends PropertyKey,\n> = (\n data: ExcludeCockatielEventData<ExtractCockatielEventData<Event>, Keys>,\n) => void;\n\n/**\n * Converts a Cockatiel event listener type to an event emitter type.\n */\nexport type CockatielEventToEventEmitterWithData<Event, Data> =\n CockatielEventEmitter<\n ExtendCockatielEventData<ExtractCockatielEventData<Event>, Data>\n >;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/network-controller",
|
|
3
|
-
"version": "26.0.0-preview-
|
|
3
|
+
"version": "26.0.0-preview-e3eb8eca",
|
|
4
4
|
"description": "Provides an interface to the currently selected network via a MetaMask-compatible provider object",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"MetaMask",
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"@types/jest-when": "^2.7.3",
|
|
79
79
|
"@types/lodash": "^4.14.191",
|
|
80
80
|
"@types/node-fetch": "^2.6.12",
|
|
81
|
+
"cockatiel": "^3.1.2",
|
|
81
82
|
"deep-freeze-strict": "^1.1.1",
|
|
82
83
|
"deepmerge": "^4.2.2",
|
|
83
84
|
"jest": "^27.5.1",
|