@metamask-previews/network-connection-banner-controller 0.1.0-preview-c4108f3eb → 0.1.0-preview-14c30de
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 +4 -1
- package/README.md +5 -1
- package/dist/NetworkConnectionBannerController.cjs +56 -29
- package/dist/NetworkConnectionBannerController.cjs.map +1 -1
- package/dist/NetworkConnectionBannerController.d.cts +61 -18
- package/dist/NetworkConnectionBannerController.d.cts.map +1 -1
- package/dist/NetworkConnectionBannerController.d.mts +61 -18
- package/dist/NetworkConnectionBannerController.d.mts.map +1 -1
- package/dist/NetworkConnectionBannerController.mjs +55 -28
- package/dist/NetworkConnectionBannerController.mjs.map +1 -1
- package/dist/index.cjs +3 -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 +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.0]
|
|
11
|
+
|
|
10
12
|
### Added
|
|
11
13
|
|
|
12
14
|
- Add `NetworkConnectionBannerController`, which evaluates enabled network RPC
|
|
@@ -14,4 +16,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
14
16
|
dismissal, and switching custom RPC endpoints to an available Infura endpoint
|
|
15
17
|
([#9041](https://github.com/MetaMask/core/pull/9041))
|
|
16
18
|
|
|
17
|
-
[Unreleased]: https://github.com/MetaMask/core/
|
|
19
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/network-connection-banner-controller@0.1.0...HEAD
|
|
20
|
+
[0.1.0]: https://github.com/MetaMask/core/releases/tag/@metamask/network-connection-banner-controller@0.1.0
|
package/README.md
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
NetworkConnectionBannerController decides when and how to surface the network
|
|
4
4
|
connection banner based on RPC endpoint health. It encapsulates the rule and
|
|
5
|
-
the 5s/30s timer state machine.
|
|
5
|
+
the 5s/30s timer state machine. Both timeouts are configurable via the
|
|
6
|
+
`degradedBannerTimeout` and `unavailableBannerTimeout` constructor options
|
|
7
|
+
(defaults exported as `DEFAULT_DEGRADED_BANNER_TIMEOUT` and
|
|
8
|
+
`DEFAULT_UNAVAILABLE_BANNER_TIMEOUT`); the unavailable timeout is measured
|
|
9
|
+
from the same failure start and must be greater than the degraded one.
|
|
6
10
|
|
|
7
11
|
## Lifecycle
|
|
8
12
|
|
|
@@ -10,9 +10,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
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");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_pendingNetworkClientId, _NetworkConnectionBannerController_isStarted, _NetworkConnectionBannerController_isUiOpen, _NetworkConnectionBannerController_isUnlocked, _NetworkConnectionBannerController_infuraProjectId, _NetworkConnectionBannerController_updateLifecycle, _NetworkConnectionBannerController_start, _NetworkConnectionBannerController_stop, _NetworkConnectionBannerController_refreshState, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetwork, _NetworkConnectionBannerController_getEnabledEvmChainIds, _NetworkConnectionBannerController_collectEnabledNetworks, _NetworkConnectionBannerController_buildFailedNetwork, _NetworkConnectionBannerController_pickFailedNetworkToDisplay;
|
|
13
|
+
var _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_pendingNetworkClientId, _NetworkConnectionBannerController_isStarted, _NetworkConnectionBannerController_isUiOpen, _NetworkConnectionBannerController_isUnlocked, _NetworkConnectionBannerController_infuraProjectId, _NetworkConnectionBannerController_degradedBannerTimeout, _NetworkConnectionBannerController_unavailableBannerTimeout, _NetworkConnectionBannerController_updateLifecycle, _NetworkConnectionBannerController_start, _NetworkConnectionBannerController_stop, _NetworkConnectionBannerController_refreshState, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetwork, _NetworkConnectionBannerController_getEnabledEvmChainIds, _NetworkConnectionBannerController_collectEnabledNetworks, _NetworkConnectionBannerController_buildFailedNetwork, _NetworkConnectionBannerController_pickFailedNetworkToDisplay;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.NetworkConnectionBannerController = exports.getDefaultNetworkConnectionBannerControllerState = void 0;
|
|
15
|
+
exports.NetworkConnectionBannerController = exports.DEFAULT_UNAVAILABLE_BANNER_TIMEOUT = exports.DEFAULT_DEGRADED_BANNER_TIMEOUT = exports.getDefaultNetworkConnectionBannerControllerState = void 0;
|
|
16
16
|
const base_controller_1 = require("@metamask/base-controller");
|
|
17
17
|
const client_controller_1 = require("@metamask/client-controller");
|
|
18
18
|
const connectivity_controller_1 = require("@metamask/connectivity-controller");
|
|
@@ -98,41 +98,54 @@ function getDefaultNetworkConnectionBannerControllerState() {
|
|
|
98
98
|
}
|
|
99
99
|
exports.getDefaultNetworkConnectionBannerControllerState = getDefaultNetworkConnectionBannerControllerState;
|
|
100
100
|
/**
|
|
101
|
-
*
|
|
102
|
-
* status ("degraded" or "unavailable") before the degraded
|
|
101
|
+
* The default for how long (in milliseconds) a failing network must remain
|
|
102
|
+
* in a "failed" status ("degraded" or "unavailable") before the degraded
|
|
103
|
+
* banner appears.
|
|
103
104
|
*/
|
|
104
|
-
|
|
105
|
+
exports.DEFAULT_DEGRADED_BANNER_TIMEOUT = 5000;
|
|
105
106
|
/**
|
|
106
|
-
*
|
|
107
|
-
* status before the banner escalates to "unavailable".
|
|
107
|
+
* The default for how long (in milliseconds) a failing network must remain
|
|
108
|
+
* in a "failed" status before the banner escalates to "unavailable".
|
|
108
109
|
*/
|
|
109
|
-
|
|
110
|
+
exports.DEFAULT_UNAVAILABLE_BANNER_TIMEOUT = 30000;
|
|
110
111
|
const MESSENGER_EXPOSED_METHODS = [
|
|
111
112
|
'dismissBanner',
|
|
112
113
|
'switchToDefaultInfuraRpcEndpoint',
|
|
113
114
|
];
|
|
114
115
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
116
|
+
* Drives the "network connection banner", a notice that appears within clients
|
|
117
|
+
* whose goal is to inform users about networks which have exhibited repeated
|
|
118
|
+
* request failures and offer potential workarounds.
|
|
118
119
|
*
|
|
119
|
-
*
|
|
120
|
+
* Some terminology: A "network" in this case is an RPC endpoint, and a network
|
|
121
|
+
* that has exhibited repeated request failures has entered a "failed" state (or
|
|
122
|
+
* is a "failed network").
|
|
120
123
|
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
* (escape hatch so Infura-only setups still get a signal).
|
|
124
|
+
* For simplicity, the banner always represents a single failed network. If
|
|
125
|
+
* multiple networks are failing, the first custom network takes priority over
|
|
126
|
+
* the first Infura network.
|
|
125
127
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* RPC" CTA targets the network the user can act on.
|
|
128
|
+
* To ensure that the banner is actionable, the banner does not always appear
|
|
129
|
+
* even if there is a failed network to display. Instead it appears under these
|
|
130
|
+
* conditions:
|
|
130
131
|
*
|
|
131
|
-
* The
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
132
|
+
* - The failed network is a custom (non-Infura) endpoint (we want to inform
|
|
133
|
+
* users about endpoints they've added so they don't cast blame on MetaMask).
|
|
134
|
+
* - Every enabled EVM network has entered a failed state (this indicates a
|
|
135
|
+
* broad connectivity issue).
|
|
136
|
+
*
|
|
137
|
+
* Assuming that these conditions have been met, there are two variants of the
|
|
138
|
+
* banner which will be displayed at different times.
|
|
139
|
+
*
|
|
140
|
+
* - A "degraded" variant which will appear when 5 seconds has elapsed and there
|
|
141
|
+
* is an eligible failed network to display
|
|
142
|
+
* - An "unavailable" variant which will appear when 30 seconds have elapsed and
|
|
143
|
+
* there is an eligible failed network to display
|
|
144
|
+
*
|
|
145
|
+
* Finally, the controller contains actions that drive interactions with the
|
|
146
|
+
* banner. Namely, if the banner represents a custom network, then it will offer
|
|
147
|
+
* the user a way to switch to the default Infura network. The controller
|
|
148
|
+
* contains the logic to carry out that action.
|
|
136
149
|
*/
|
|
137
150
|
class NetworkConnectionBannerController extends base_controller_1.BaseController {
|
|
138
151
|
/**
|
|
@@ -141,8 +154,15 @@ class NetworkConnectionBannerController extends base_controller_1.BaseController
|
|
|
141
154
|
* @param args - The arguments to this controller.
|
|
142
155
|
* @param args.messenger - The messenger suited for this controller.
|
|
143
156
|
* @param args.infuraProjectId - The wallet's Infura project id.
|
|
157
|
+
* @param args.degradedBannerTimeout - How long (in milliseconds) a failing
|
|
158
|
+
* network must remain failed before the degraded banner appears.
|
|
159
|
+
* @param args.unavailableBannerTimeout - How long (in milliseconds) before
|
|
160
|
+
* the banner escalates to "unavailable". Must be greater than
|
|
161
|
+
* `degradedBannerTimeout`.
|
|
162
|
+
* @throws If `unavailableBannerTimeout` is not greater than
|
|
163
|
+
* `degradedBannerTimeout`.
|
|
144
164
|
*/
|
|
145
|
-
constructor({ messenger, infuraProjectId, }) {
|
|
165
|
+
constructor({ messenger, infuraProjectId, degradedBannerTimeout = exports.DEFAULT_DEGRADED_BANNER_TIMEOUT, unavailableBannerTimeout = exports.DEFAULT_UNAVAILABLE_BANNER_TIMEOUT, }) {
|
|
146
166
|
super({
|
|
147
167
|
messenger,
|
|
148
168
|
metadata: networkConnectionBannerControllerMetadata,
|
|
@@ -159,7 +179,14 @@ class NetworkConnectionBannerController extends base_controller_1.BaseController
|
|
|
159
179
|
/** Whether the keyring is unlocked. Combined with {@link #isUiOpen}. */
|
|
160
180
|
_NetworkConnectionBannerController_isUnlocked.set(this, false);
|
|
161
181
|
_NetworkConnectionBannerController_infuraProjectId.set(this, void 0);
|
|
182
|
+
_NetworkConnectionBannerController_degradedBannerTimeout.set(this, void 0);
|
|
183
|
+
_NetworkConnectionBannerController_unavailableBannerTimeout.set(this, void 0);
|
|
184
|
+
if (unavailableBannerTimeout <= degradedBannerTimeout) {
|
|
185
|
+
throw new Error(`\`unavailableBannerTimeout\` (${unavailableBannerTimeout}) must be greater than \`degradedBannerTimeout\` (${degradedBannerTimeout}).`);
|
|
186
|
+
}
|
|
162
187
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_infuraProjectId, infuraProjectId, "f");
|
|
188
|
+
__classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedBannerTimeout, degradedBannerTimeout, "f");
|
|
189
|
+
__classPrivateFieldSet(this, _NetworkConnectionBannerController_unavailableBannerTimeout, unavailableBannerTimeout, "f");
|
|
163
190
|
// Upstream controllers still expose :stateChange; switch to :stateChanged
|
|
164
191
|
// once those packages migrate their event types.
|
|
165
192
|
/* eslint-disable no-restricted-syntax -- awaiting upstream :stateChanged migration */
|
|
@@ -239,7 +266,7 @@ class NetworkConnectionBannerController extends base_controller_1.BaseController
|
|
|
239
266
|
}
|
|
240
267
|
}
|
|
241
268
|
exports.NetworkConnectionBannerController = NetworkConnectionBannerController;
|
|
242
|
-
_NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_pendingNetworkClientId = new WeakMap(), _NetworkConnectionBannerController_isStarted = new WeakMap(), _NetworkConnectionBannerController_isUiOpen = new WeakMap(), _NetworkConnectionBannerController_isUnlocked = new WeakMap(), _NetworkConnectionBannerController_infuraProjectId = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_updateLifecycle = function _NetworkConnectionBannerController_updateLifecycle() {
|
|
269
|
+
_NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_pendingNetworkClientId = new WeakMap(), _NetworkConnectionBannerController_isStarted = new WeakMap(), _NetworkConnectionBannerController_isUiOpen = new WeakMap(), _NetworkConnectionBannerController_isUnlocked = new WeakMap(), _NetworkConnectionBannerController_infuraProjectId = new WeakMap(), _NetworkConnectionBannerController_degradedBannerTimeout = new WeakMap(), _NetworkConnectionBannerController_unavailableBannerTimeout = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_updateLifecycle = function _NetworkConnectionBannerController_updateLifecycle() {
|
|
243
270
|
if (__classPrivateFieldGet(this, _NetworkConnectionBannerController_isUiOpen, "f") && __classPrivateFieldGet(this, _NetworkConnectionBannerController_isUnlocked, "f")) {
|
|
244
271
|
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_start).call(this);
|
|
245
272
|
}
|
|
@@ -325,8 +352,8 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
|
|
|
325
352
|
state.networkConnectionBannerStatus = 'unavailable';
|
|
326
353
|
state.networkConnectionBannerNetwork = failedNetwork;
|
|
327
354
|
});
|
|
328
|
-
},
|
|
329
|
-
},
|
|
355
|
+
}, __classPrivateFieldGet(this, _NetworkConnectionBannerController_unavailableBannerTimeout, "f") - __classPrivateFieldGet(this, _NetworkConnectionBannerController_degradedBannerTimeout, "f")), "f");
|
|
356
|
+
}, __classPrivateFieldGet(this, _NetworkConnectionBannerController_degradedBannerTimeout, "f")), "f");
|
|
330
357
|
}, _NetworkConnectionBannerController_resetBanner = function _NetworkConnectionBannerController_resetBanner() {
|
|
331
358
|
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_clearTimers).call(this);
|
|
332
359
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, undefined, "f");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkConnectionBannerController.cjs","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { clientControllerSelectors } from '@metamask/client-controller';\nimport type { ClientControllerState } from '@metamask/client-controller';\nimport {\n CONNECTIVITY_STATUSES,\n connectivityControllerSelectors,\n} from '@metamask/connectivity-controller';\nimport type {\n ConnectivityControllerGetStateAction,\n ConnectivityControllerState,\n ConnectivityControllerStateChangeEvent,\n} from '@metamask/connectivity-controller';\nimport type {\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkConfiguration,\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\n NetworkControllerSetActiveNetworkAction,\n NetworkControllerStateChangeEvent,\n NetworkMetadata,\n NetworkState,\n} from '@metamask/network-controller';\nimport { NetworkStatus } from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerState,\n NetworkEnablementControllerStateChangeEvent,\n} from '@metamask/network-enablement-controller';\nimport { selectEnabledNetworkMap } from '@metamask/network-enablement-controller';\nimport type { Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\nimport { createSelector } from 'reselect';\n\nimport type { NetworkConnectionBannerControllerMethodActions } from './NetworkConnectionBannerController-method-action-types';\nimport { getIsInfuraEndpoint } from './url-utils';\n\n/**\n * The name of the {@link NetworkConnectionBannerController}, used to namespace\n * the controller's actions and events and to namespace the controller's state\n * data when composed with other controllers.\n */\nconst CONTROLLER_NAME = 'NetworkConnectionBannerController';\n\n/**\n * Selects `networksMetadata` from the `NetworkController` state.\n *\n * @param state - The `NetworkController` state.\n * @returns The networks metadata map keyed by network client id.\n */\nconst selectNetworksMetadata = (\n state: NetworkState,\n): NetworkState['networksMetadata'] => state.networksMetadata;\n\n/**\n * Selects `networkConfigurationsByChainId` from the `NetworkController`\n * state.\n *\n * @param state - The `NetworkController` state.\n * @returns The network configurations keyed by chain id.\n */\nconst selectNetworkConfigurationsByChainId = (\n state: NetworkState,\n): NetworkState['networkConfigurationsByChainId'] =>\n state.networkConfigurationsByChainId;\n\n/**\n * Selects the `NetworkController` state fields that influence the banner\n * rule. Composed with `createSelector` so the return object stays reference\n * stable while unrelated `NetworkController` state (e.g.\n * `selectedNetworkClientId`) changes.\n *\n * @param state - The `NetworkController` state.\n * @returns The relevant network fields.\n */\nconst selectNetworkControllerFields = createSelector(\n [selectNetworksMetadata, selectNetworkConfigurationsByChainId],\n (networksMetadata, networkConfigurationsByChainId) => ({\n networksMetadata,\n networkConfigurationsByChainId,\n }),\n);\n\n/**\n * Selects the `NetworkEnablementController` state field that influences the\n * banner rule.\n *\n * @param state - The `NetworkEnablementController` state.\n * @returns The relevant enablement fields.\n */\nconst selectNetworkEnablementControllerFields = createSelector(\n [selectEnabledNetworkMap],\n (enabledNetworkMap) => ({ enabledNetworkMap }),\n);\n\n/**\n * Selects the `ConnectivityController` state field that influences the\n * banner rule.\n *\n * @param state - The `ConnectivityController` state.\n * @returns The relevant connectivity fields.\n */\nconst selectConnectivityControllerFields = createSelector(\n [connectivityControllerSelectors.selectConnectivityStatus],\n (connectivityStatus) => ({ connectivityStatus }),\n);\n\n/**\n * Status the banner can be in. `available` means no banner is shown; the\n * `degraded` and `unavailable` values mirror the two-tier escalation that the\n * UI renders.\n */\nexport type NetworkConnectionBannerStatus =\n | 'available'\n | 'degraded'\n | 'unavailable';\n\n/**\n * An enabled network from `NetworkController` state with a default RPC\n * endpoint. Used as the input to the failed-network detection pipeline.\n * `metadata` is missing until the network's connectivity has been looked up.\n */\ntype EnabledNetwork = {\n chainId: Hex;\n name: string;\n rpcEndpoints: NetworkConfiguration['rpcEndpoints'];\n defaultRpcEndpointIndex: number;\n defaultRpcEndpoint: NetworkConfiguration['rpcEndpoints'][number];\n metadata: NetworkMetadata | undefined;\n};\n\n/**\n * Details of a failing network the banner describes.\n */\nexport type FailedNetwork = {\n /** The chain id of the failing network. */\n chainId: Hex;\n /** The `networkClientId` of the failing default RPC endpoint. */\n networkClientId: string;\n /** The display name for the failing network. */\n name: string;\n /** The URL of the failing default RPC endpoint. */\n rpcUrl: string;\n /** Whether the failing endpoint is a MetaMask Infura endpoint. */\n isInfuraEndpoint: boolean;\n /**\n * The networkClientId of an Infura endpoint on the same chain that the user\n * can switch to. `null` when the failing endpoint is already Infura or when\n * no Infura alternative exists.\n */\n switchableInfuraNetworkClientId: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n *\n * The keys carry the controller-domain prefix (like\n * `ConnectivityController`'s `connectivityStatus`) because some clients merge\n * all controller states into one flat object, where generic names like\n * `status` collide across controllers.\n */\nexport type NetworkConnectionBannerControllerState = {\n networkConnectionBannerStatus: NetworkConnectionBannerStatus;\n networkConnectionBannerNetwork: FailedNetwork | null;\n};\n\nconst networkConnectionBannerControllerMetadata = {\n networkConnectionBannerStatus: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n networkConnectionBannerNetwork: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n} satisfies StateMetadata<NetworkConnectionBannerControllerState>;\n\n/**\n * Constructs the default {@link NetworkConnectionBannerController} state.\n *\n * @returns The default state.\n */\nexport function getDefaultNetworkConnectionBannerControllerState(): NetworkConnectionBannerControllerState {\n return {\n networkConnectionBannerStatus: 'available',\n networkConnectionBannerNetwork: null,\n };\n}\n\n/**\n * How long (in milliseconds) a failing network must remain in a \"failed\"\n * status (\"degraded\" or \"unavailable\") before the degraded banner appears.\n */\nconst DEGRADED_BANNER_TIMEOUT = 5_000;\n\n/**\n * How long (in milliseconds) a failing network must remain in a \"failed\"\n * status before the banner escalates to \"unavailable\".\n */\nconst UNAVAILABLE_BANNER_TIMEOUT = 30_000;\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'dismissBanner',\n 'switchToDefaultInfuraRpcEndpoint',\n] as const;\n\n/**\n * Retrieves the state of the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerGetStateAction =\n ControllerGetStateAction<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState\n >;\n\n/**\n * Actions that {@link NetworkConnectionBannerControllerMessenger} exposes to\n * other consumers.\n */\nexport type NetworkConnectionBannerControllerActions =\n | NetworkConnectionBannerControllerGetStateAction\n | NetworkConnectionBannerControllerMethodActions;\n\n/**\n * Actions from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} calls.\n */\ntype AllowedActions =\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkConfigurationByChainIdAction\n | NetworkControllerUpdateNetworkAction\n | NetworkControllerSetActiveNetworkAction\n | NetworkEnablementControllerGetStateAction\n | ConnectivityControllerGetStateAction;\n\n/**\n * Published when the state of {@link NetworkConnectionBannerController}\n * changes.\n */\nexport type NetworkConnectionBannerControllerStateChangedEvent =\n ControllerStateChangedEvent<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState\n >;\n\n/**\n * Events that {@link NetworkConnectionBannerControllerMessenger} exposes to\n * other consumers.\n */\nexport type NetworkConnectionBannerControllerEvents =\n NetworkConnectionBannerControllerStateChangedEvent;\n\n/**\n * Published when the state of `ClientController` changes. Defined here\n * because the `client-controller` package still exports the legacy\n * `:stateChange` event type.\n */\ntype ClientControllerStateChangedEvent = ControllerStateChangedEvent<\n 'ClientController',\n ClientControllerState\n>;\n\n/**\n * Events from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} subscribes to.\n */\ntype AllowedEvents =\n | NetworkControllerStateChangeEvent\n | NetworkEnablementControllerStateChangeEvent\n | ConnectivityControllerStateChangeEvent\n | ClientControllerStateChangedEvent\n | KeyringControllerUnlockEvent\n | KeyringControllerLockEvent;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerMessenger = Messenger<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerActions | AllowedActions,\n NetworkConnectionBannerControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerOptions = {\n /**\n * The messenger for inter-controller communication.\n */\n messenger: NetworkConnectionBannerControllerMessenger;\n\n /**\n * The wallet's Infura project id, used to recognize MetaMask Infura\n * endpoints whose URL was persisted with the id already substituted.\n */\n infuraProjectId: string;\n};\n\n/**\n * NetworkConnectionBannerController decides whether the network connection\n * banner should be shown for the user, and which failing network it should\n * describe. It encapsulates the rule and the 5s / 30s timer escalation.\n *\n * The banner shows when:\n *\n * - A failing network's default RPC is a custom (non-Infura) endpoint —\n * users always want to be informed about errors with RPCs they've chosen.\n * - Every enabled EVM network is reporting a failed connectivity status\n * (escape hatch so Infura-only setups still get a signal).\n *\n * A partial Infura outage alongside healthy peers is suppressed since it\n * usually resolves on its own and the user cannot act on it. When a custom\n * failure is present, it's surfaced first so the \"Switch to MetaMask default\n * RPC\" CTA targets the network the user can act on.\n *\n * The controller manages its own lifecycle: it evaluates RPC health (and\n * runs the escalation timers) only while the client UI is open\n * (`ClientController`) and the wallet is unlocked (`KeyringController`).\n * Clients only need to render the banner from the controller's state and wire\n * click handlers to {@link dismissBanner} or {@link switchToDefaultInfuraRpcEndpoint}.\n */\nexport class NetworkConnectionBannerController extends BaseController<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerMessenger\n> {\n #degradedTimer: ReturnType<typeof setTimeout> | undefined;\n\n #unavailableTimer: ReturnType<typeof setTimeout> | undefined;\n\n #pendingNetworkClientId: string | undefined;\n\n #isStarted = false;\n\n /** Whether the client UI is open. Combined with {@link #isUnlocked}. */\n #isUiOpen = false;\n\n /** Whether the keyring is unlocked. Combined with {@link #isUiOpen}. */\n #isUnlocked = false;\n\n readonly #infuraProjectId: string;\n\n /**\n * Constructs a new {@link NetworkConnectionBannerController}.\n *\n * @param args - The arguments to this controller.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.infuraProjectId - The wallet's Infura project id.\n */\n constructor({\n messenger,\n infuraProjectId,\n }: NetworkConnectionBannerControllerOptions) {\n super({\n messenger,\n metadata: networkConnectionBannerControllerMetadata,\n name: CONTROLLER_NAME,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\n\n this.#infuraProjectId = infuraProjectId;\n\n // Upstream controllers still expose :stateChange; switch to :stateChanged\n // once those packages migrate their event types.\n /* eslint-disable no-restricted-syntax -- awaiting upstream :stateChanged migration */\n this.messenger.subscribe(\n 'NetworkController:stateChange',\n (networkControllerState) =>\n this.#refreshState({\n networkControllerState,\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n }),\n selectNetworkControllerFields,\n );\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n (networkEnablementControllerState) =>\n this.#refreshState({\n networkControllerState: this.messenger.call(\n 'NetworkController:getState',\n ),\n networkEnablementControllerState,\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n }),\n selectNetworkEnablementControllerFields,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n (connectivityControllerState) =>\n this.#refreshState({\n networkControllerState: this.messenger.call(\n 'NetworkController:getState',\n ),\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState,\n }),\n selectConnectivityControllerFields,\n );\n /* eslint-enable no-restricted-syntax */\n\n // Lifecycle: evaluate RPC health (and run the banner escalation timers)\n // only while the client UI is open on an unlocked wallet.\n this.messenger.subscribe(\n 'ClientController:stateChanged',\n (isUiOpen) => {\n this.#isUiOpen = isUiOpen;\n this.#updateLifecycle();\n },\n clientControllerSelectors.selectIsUiOpen,\n );\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n this.#updateLifecycle();\n });\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n this.#updateLifecycle();\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n #updateLifecycle(): void {\n if (this.#isUiOpen && this.#isUnlocked) {\n this.#start();\n } else {\n this.#stop();\n }\n }\n\n /**\n * Look for a failed network, if any, and populate the initial state of the\n * banner. Reacts to upstream state changes from this point on. Idempotent.\n */\n #start(): void {\n if (this.#isStarted) {\n return;\n }\n\n this.#isStarted = true;\n this.#refreshState({\n networkControllerState: this.messenger.call('NetworkController:getState'),\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n });\n }\n\n /**\n * Stops evaluating network connection state. Clears any pending banner\n * timers and resets state to `available`. Idempotent.\n */\n #stop(): void {\n if (!this.#isStarted) {\n return;\n }\n\n this.#isStarted = false;\n this.#resetBanner();\n }\n\n /**\n * Clears the banner state such that the banner will be hidden.\n */\n dismissBanner(): void {\n this.#resetBanner();\n }\n\n /**\n * Switches the chain's default RPC endpoint to its Infura endpoint and\n * makes it the active network, causing the banner to clear once the\n * network becomes available again.\n *\n * @param chainId - The chain whose default RPC endpoint should be switched.\n * @throws If the chain configuration cannot be found, or if it has no\n * Infura endpoint to switch to, or if the default is already Infura.\n */\n async switchToDefaultInfuraRpcEndpoint(chainId: Hex): Promise<void> {\n const networkConfiguration = this.messenger.call(\n 'NetworkController:getNetworkConfigurationByChainId',\n chainId,\n );\n if (!networkConfiguration) {\n throw new Error(\n `No network configuration found for chain ID \"${chainId}\".`,\n );\n }\n\n const infuraEndpointIndex = networkConfiguration.rpcEndpoints.findIndex(\n (endpoint) => getIsInfuraEndpoint(endpoint.url, this.#infuraProjectId),\n );\n if (infuraEndpointIndex === -1) {\n throw new Error(\n `No Infura endpoint available for chain ID \"${chainId}\".`,\n );\n }\n if (infuraEndpointIndex === networkConfiguration.defaultRpcEndpointIndex) {\n // The default is already Infura; nothing to do.\n return;\n }\n\n // Move the active connection onto the Infura endpoint first, then make\n // it the default. In this order a partial failure leaves the failing\n // default in place and the banner visible, rather than hiding the banner\n // while the wallet is still connected to the broken endpoint.\n const infuraNetworkClientId =\n networkConfiguration.rpcEndpoints[infuraEndpointIndex].networkClientId;\n const { selectedNetworkClientId } = this.messenger.call(\n 'NetworkController:getState',\n );\n if (infuraNetworkClientId !== selectedNetworkClientId) {\n await this.messenger.call(\n 'NetworkController:setActiveNetwork',\n infuraNetworkClientId,\n );\n }\n\n await this.messenger.call('NetworkController:updateNetwork', chainId, {\n ...networkConfiguration,\n defaultRpcEndpointIndex: infuraEndpointIndex,\n });\n }\n\n #refreshState({\n networkControllerState,\n networkEnablementControllerState,\n connectivityControllerState,\n }: {\n networkControllerState: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >;\n networkEnablementControllerState: Pick<\n NetworkEnablementControllerState,\n 'enabledNetworkMap'\n >;\n connectivityControllerState: Pick<\n ConnectivityControllerState,\n 'connectivityStatus'\n >;\n }): void {\n if (!this.#isStarted) {\n return;\n }\n\n if (\n connectivityControllerState.connectivityStatus ===\n CONNECTIVITY_STATUSES.Offline\n ) {\n this.#resetBanner();\n return;\n }\n\n const failedNetwork = this.#findFailedNetwork(\n networkControllerState,\n networkEnablementControllerState,\n );\n if (!failedNetwork) {\n this.#resetBanner();\n return;\n }\n\n if (\n this.state.networkConnectionBannerStatus !== 'available' &&\n this.state.networkConnectionBannerNetwork?.networkClientId ===\n failedNetwork.networkClientId\n ) {\n this.update((state) => {\n // Even if the network client ID has not changed, save the current\n // version of the failed network to state in case the user has updated\n // its RPC URL.\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n return;\n }\n\n // A degraded timer is already counting down for this same network.\n // Repeated `stateChange` events must not clear and restart it, or a\n // steady stream of updates could postpone the banner indefinitely.\n if (this.#pendingNetworkClientId === failedNetwork.networkClientId) {\n return;\n }\n\n this.#clearTimers();\n this.update((state) => {\n state.networkConnectionBannerStatus = 'available';\n state.networkConnectionBannerNetwork = null;\n });\n\n // If `stop` is called before scheduling timers, bail early.\n if (!this.#isStarted) {\n return;\n }\n\n // Remember which network the pending timer is for (see the guard above)\n // and capture the failing network at schedule time. If the failure\n // resolves or a different network becomes the banner target while we\n // wait, the subscription handlers re-enter this method and cancel or\n // replace the timer before it fires.\n this.#pendingNetworkClientId = failedNetwork.networkClientId;\n this.#degradedTimer = setTimeout(() => {\n this.#degradedTimer = undefined;\n this.#pendingNetworkClientId = undefined;\n this.update((state) => {\n state.networkConnectionBannerStatus = 'degraded';\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n // If `stop` is called before scheduling timers, bail early.\n if (!this.#isStarted) {\n return;\n }\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n this.update((state) => {\n state.networkConnectionBannerStatus = 'unavailable';\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n }, UNAVAILABLE_BANNER_TIMEOUT - DEGRADED_BANNER_TIMEOUT);\n }, DEGRADED_BANNER_TIMEOUT);\n }\n\n /**\n * Clears timers and resets banner state to {@link NetworkConnectionBannerStatus|`available`}\n * if it isn't there already.\n */\n #resetBanner(): void {\n this.#clearTimers();\n this.#pendingNetworkClientId = undefined;\n if (\n this.state.networkConnectionBannerStatus !== 'available' ||\n this.state.networkConnectionBannerNetwork !== null\n ) {\n this.update((state) => {\n state.networkConnectionBannerStatus = 'available';\n state.networkConnectionBannerNetwork = null;\n });\n }\n }\n\n #clearTimers(): void {\n if (this.#degradedTimer !== undefined) {\n clearTimeout(this.#degradedTimer);\n this.#degradedTimer = undefined;\n }\n if (this.#unavailableTimer !== undefined) {\n clearTimeout(this.#unavailableTimer);\n this.#unavailableTimer = undefined;\n }\n }\n\n #findFailedNetwork(\n networkState: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n enablementState: Pick<\n NetworkEnablementControllerState,\n 'enabledNetworkMap'\n >,\n ): FailedNetwork | null {\n const enabledNetworks = this.#collectEnabledNetworks(\n networkState,\n enablementState,\n );\n // Networks whose connectivity has not been looked up yet are not failed.\n const failedNetworks = enabledNetworks\n .filter(\n ({ metadata }) =>\n metadata !== undefined && metadata.status !== NetworkStatus.Available,\n )\n .map((network) => this.#buildFailedNetwork(network));\n return this.#pickFailedNetworkToDisplay(\n failedNetworks,\n enabledNetworks.length,\n );\n }\n\n #getEnabledEvmChainIds(\n enabledNetworkMap: NetworkEnablementControllerState['enabledNetworkMap'],\n ): Hex[] {\n return Object.entries(enabledNetworkMap[KnownCaipNamespace.Eip155] ?? {})\n .filter(([, enabled]) => enabled)\n .map(([chainId]) => chainId as Hex);\n }\n\n #collectEnabledNetworks(\n {\n networkConfigurationsByChainId,\n networksMetadata,\n }: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n {\n enabledNetworkMap,\n }: Pick<NetworkEnablementControllerState, 'enabledNetworkMap'>,\n ): EnabledNetwork[] {\n return this.#getEnabledEvmChainIds(enabledNetworkMap).flatMap((chainId) => {\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n return [];\n }\n const { rpcEndpoints, defaultRpcEndpointIndex, name } =\n networkConfiguration;\n const defaultRpcEndpoint = rpcEndpoints[defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n return [];\n }\n return [\n {\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n metadata: networksMetadata[defaultRpcEndpoint.networkClientId],\n },\n ];\n });\n }\n\n #buildFailedNetwork({\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n }: EnabledNetwork): FailedNetwork {\n const isInfuraEndpoint = getIsInfuraEndpoint(\n defaultRpcEndpoint.url,\n this.#infuraProjectId,\n );\n\n // For custom endpoints (non-Infura), find an Infura endpoint on this\n // chain that we could offer to switch to.\n let switchableInfuraNetworkClientId: string | null = null;\n if (!isInfuraEndpoint) {\n const infuraEndpoint = rpcEndpoints.find(\n (endpoint, index) =>\n index !== defaultRpcEndpointIndex &&\n getIsInfuraEndpoint(endpoint.url, this.#infuraProjectId),\n );\n switchableInfuraNetworkClientId = infuraEndpoint?.networkClientId ?? null;\n }\n\n return {\n chainId,\n networkClientId: defaultRpcEndpoint.networkClientId,\n name,\n rpcUrl: defaultRpcEndpoint.url,\n isInfuraEndpoint,\n switchableInfuraNetworkClientId,\n };\n }\n\n #pickFailedNetworkToDisplay(\n failedNetworks: FailedNetwork[],\n totalEnabledNetworks: number,\n ): FailedNetwork | null {\n if (failedNetworks.length === 0) {\n return null;\n }\n\n const firstCustomFailed = failedNetworks.find(\n (entry) => !entry.isInfuraEndpoint,\n );\n const areAllEnabledNetworksFailed =\n failedNetworks.length === totalEnabledNetworks;\n\n if (!firstCustomFailed && !areAllEnabledNetworksFailed) {\n return null;\n }\n\n return firstCustomFailed ?? failedNetworks[0];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"NetworkConnectionBannerController.cjs","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { clientControllerSelectors } from '@metamask/client-controller';\nimport type { ClientControllerState } from '@metamask/client-controller';\nimport {\n CONNECTIVITY_STATUSES,\n connectivityControllerSelectors,\n} from '@metamask/connectivity-controller';\nimport type {\n ConnectivityControllerGetStateAction,\n ConnectivityControllerState,\n ConnectivityControllerStateChangeEvent,\n} from '@metamask/connectivity-controller';\nimport type {\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkConfiguration,\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\n NetworkControllerSetActiveNetworkAction,\n NetworkControllerStateChangeEvent,\n NetworkMetadata,\n NetworkState,\n} from '@metamask/network-controller';\nimport { NetworkStatus } from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerState,\n NetworkEnablementControllerStateChangeEvent,\n} from '@metamask/network-enablement-controller';\nimport { selectEnabledNetworkMap } from '@metamask/network-enablement-controller';\nimport type { Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\nimport { createSelector } from 'reselect';\n\nimport type { NetworkConnectionBannerControllerMethodActions } from './NetworkConnectionBannerController-method-action-types';\nimport { getIsInfuraEndpoint } from './url-utils';\n\n/**\n * The name of the {@link NetworkConnectionBannerController}, used to namespace\n * the controller's actions and events and to namespace the controller's state\n * data when composed with other controllers.\n */\nconst CONTROLLER_NAME = 'NetworkConnectionBannerController';\n\n/**\n * Selects `networksMetadata` from the `NetworkController` state.\n *\n * @param state - The `NetworkController` state.\n * @returns The networks metadata map keyed by network client id.\n */\nconst selectNetworksMetadata = (\n state: NetworkState,\n): NetworkState['networksMetadata'] => state.networksMetadata;\n\n/**\n * Selects `networkConfigurationsByChainId` from the `NetworkController`\n * state.\n *\n * @param state - The `NetworkController` state.\n * @returns The network configurations keyed by chain id.\n */\nconst selectNetworkConfigurationsByChainId = (\n state: NetworkState,\n): NetworkState['networkConfigurationsByChainId'] =>\n state.networkConfigurationsByChainId;\n\n/**\n * Selects the `NetworkController` state fields that influence the banner\n * rule. Composed with `createSelector` so the return object stays reference\n * stable while unrelated `NetworkController` state (e.g.\n * `selectedNetworkClientId`) changes.\n *\n * @param state - The `NetworkController` state.\n * @returns The relevant network fields.\n */\nconst selectNetworkControllerFields = createSelector(\n [selectNetworksMetadata, selectNetworkConfigurationsByChainId],\n (networksMetadata, networkConfigurationsByChainId) => ({\n networksMetadata,\n networkConfigurationsByChainId,\n }),\n);\n\n/**\n * Selects the `NetworkEnablementController` state field that influences the\n * banner rule.\n *\n * @param state - The `NetworkEnablementController` state.\n * @returns The relevant enablement fields.\n */\nconst selectNetworkEnablementControllerFields = createSelector(\n [selectEnabledNetworkMap],\n (enabledNetworkMap) => ({ enabledNetworkMap }),\n);\n\n/**\n * Selects the `ConnectivityController` state field that influences the\n * banner rule.\n *\n * @param state - The `ConnectivityController` state.\n * @returns The relevant connectivity fields.\n */\nconst selectConnectivityControllerFields = createSelector(\n [connectivityControllerSelectors.selectConnectivityStatus],\n (connectivityStatus) => ({ connectivityStatus }),\n);\n\n/**\n * Status the banner can be in. `available` means no banner is shown; the\n * `degraded` and `unavailable` values mirror the two-tier escalation that the\n * UI renders.\n */\nexport type NetworkConnectionBannerStatus =\n | 'available'\n | 'degraded'\n | 'unavailable';\n\n/**\n * An enabled network from `NetworkController` state with a default RPC\n * endpoint. Used as the input to the failed-network detection pipeline.\n * `metadata` is missing until the network's connectivity has been looked up.\n */\ntype EnabledNetwork = {\n chainId: Hex;\n name: string;\n rpcEndpoints: NetworkConfiguration['rpcEndpoints'];\n defaultRpcEndpointIndex: number;\n defaultRpcEndpoint: NetworkConfiguration['rpcEndpoints'][number];\n metadata: NetworkMetadata | undefined;\n};\n\n/**\n * Details of a failing network the banner describes.\n */\nexport type FailedNetwork = {\n /** The chain id of the failing network. */\n chainId: Hex;\n /** The `networkClientId` of the failing default RPC endpoint. */\n networkClientId: string;\n /** The display name for the failing network. */\n name: string;\n /** The URL of the failing default RPC endpoint. */\n rpcUrl: string;\n /** Whether the failing endpoint is a MetaMask Infura endpoint. */\n isInfuraEndpoint: boolean;\n /**\n * The networkClientId of an Infura endpoint on the same chain that the user\n * can switch to. `null` when the failing endpoint is already Infura or when\n * no Infura alternative exists.\n */\n switchableInfuraNetworkClientId: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n *\n * The keys carry the controller-domain prefix (like\n * `ConnectivityController`'s `connectivityStatus`) because some clients merge\n * all controller states into one flat object, where generic names like\n * `status` collide across controllers.\n */\nexport type NetworkConnectionBannerControllerState = {\n networkConnectionBannerStatus: NetworkConnectionBannerStatus;\n networkConnectionBannerNetwork: FailedNetwork | null;\n};\n\nconst networkConnectionBannerControllerMetadata = {\n networkConnectionBannerStatus: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n networkConnectionBannerNetwork: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n} satisfies StateMetadata<NetworkConnectionBannerControllerState>;\n\n/**\n * Constructs the default {@link NetworkConnectionBannerController} state.\n *\n * @returns The default state.\n */\nexport function getDefaultNetworkConnectionBannerControllerState(): NetworkConnectionBannerControllerState {\n return {\n networkConnectionBannerStatus: 'available',\n networkConnectionBannerNetwork: null,\n };\n}\n\n/**\n * The default for how long (in milliseconds) a failing network must remain\n * in a \"failed\" status (\"degraded\" or \"unavailable\") before the degraded\n * banner appears.\n */\nexport const DEFAULT_DEGRADED_BANNER_TIMEOUT = 5_000;\n\n/**\n * The default for how long (in milliseconds) a failing network must remain\n * in a \"failed\" status before the banner escalates to \"unavailable\".\n */\nexport const DEFAULT_UNAVAILABLE_BANNER_TIMEOUT = 30_000;\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'dismissBanner',\n 'switchToDefaultInfuraRpcEndpoint',\n] as const;\n\n/**\n * Retrieves the state of the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerGetStateAction =\n ControllerGetStateAction<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState\n >;\n\n/**\n * Actions that {@link NetworkConnectionBannerControllerMessenger} exposes to\n * other consumers.\n */\nexport type NetworkConnectionBannerControllerActions =\n | NetworkConnectionBannerControllerGetStateAction\n | NetworkConnectionBannerControllerMethodActions;\n\n/**\n * Actions from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} calls.\n */\ntype AllowedActions =\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkConfigurationByChainIdAction\n | NetworkControllerUpdateNetworkAction\n | NetworkControllerSetActiveNetworkAction\n | NetworkEnablementControllerGetStateAction\n | ConnectivityControllerGetStateAction;\n\n/**\n * Published when the state of {@link NetworkConnectionBannerController}\n * changes.\n */\nexport type NetworkConnectionBannerControllerStateChangedEvent =\n ControllerStateChangedEvent<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState\n >;\n\n/**\n * Events that {@link NetworkConnectionBannerControllerMessenger} exposes to\n * other consumers.\n */\nexport type NetworkConnectionBannerControllerEvents =\n NetworkConnectionBannerControllerStateChangedEvent;\n\n/**\n * Published when the state of `ClientController` changes. Defined here\n * because the `client-controller` package still exports the legacy\n * `:stateChange` event type.\n */\ntype ClientControllerStateChangedEvent = ControllerStateChangedEvent<\n 'ClientController',\n ClientControllerState\n>;\n\n/**\n * Events from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} subscribes to.\n */\ntype AllowedEvents =\n | NetworkControllerStateChangeEvent\n | NetworkEnablementControllerStateChangeEvent\n | ConnectivityControllerStateChangeEvent\n | ClientControllerStateChangedEvent\n | KeyringControllerUnlockEvent\n | KeyringControllerLockEvent;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerMessenger = Messenger<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerActions | AllowedActions,\n NetworkConnectionBannerControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerOptions = {\n /**\n * The messenger for inter-controller communication.\n */\n messenger: NetworkConnectionBannerControllerMessenger;\n\n /**\n * The wallet's Infura project id, used to recognize MetaMask Infura\n * endpoints whose URL was persisted with the id already substituted.\n */\n infuraProjectId: string;\n\n /**\n * How long (in milliseconds) a failing network must remain in a \"failed\"\n * status before the degraded banner appears. Defaults to\n * {@link DEFAULT_DEGRADED_BANNER_TIMEOUT}.\n */\n degradedBannerTimeout?: number;\n\n /**\n * How long (in milliseconds), measured from the same failure start as\n * `degradedBannerTimeout`, before the banner escalates to \"unavailable\".\n * Must be greater than `degradedBannerTimeout`. Defaults to\n * {@link DEFAULT_UNAVAILABLE_BANNER_TIMEOUT}.\n */\n unavailableBannerTimeout?: number;\n};\n\n/**\n * Drives the \"network connection banner\", a notice that appears within clients\n * whose goal is to inform users about networks which have exhibited repeated\n * request failures and offer potential workarounds.\n *\n * Some terminology: A \"network\" in this case is an RPC endpoint, and a network\n * that has exhibited repeated request failures has entered a \"failed\" state (or\n * is a \"failed network\").\n *\n * For simplicity, the banner always represents a single failed network. If\n * multiple networks are failing, the first custom network takes priority over\n * the first Infura network.\n *\n * To ensure that the banner is actionable, the banner does not always appear\n * even if there is a failed network to display. Instead it appears under these\n * conditions:\n *\n * - The failed network is a custom (non-Infura) endpoint (we want to inform\n * users about endpoints they've added so they don't cast blame on MetaMask).\n * - Every enabled EVM network has entered a failed state (this indicates a\n * broad connectivity issue).\n *\n * Assuming that these conditions have been met, there are two variants of the\n * banner which will be displayed at different times.\n *\n * - A \"degraded\" variant which will appear when 5 seconds has elapsed and there\n * is an eligible failed network to display\n * - An \"unavailable\" variant which will appear when 30 seconds have elapsed and\n * there is an eligible failed network to display\n *\n * Finally, the controller contains actions that drive interactions with the\n * banner. Namely, if the banner represents a custom network, then it will offer\n * the user a way to switch to the default Infura network. The controller\n * contains the logic to carry out that action.\n */\nexport class NetworkConnectionBannerController extends BaseController<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerMessenger\n> {\n #degradedTimer: ReturnType<typeof setTimeout> | undefined;\n\n #unavailableTimer: ReturnType<typeof setTimeout> | undefined;\n\n #pendingNetworkClientId: string | undefined;\n\n #isStarted = false;\n\n /** Whether the client UI is open. Combined with {@link #isUnlocked}. */\n #isUiOpen = false;\n\n /** Whether the keyring is unlocked. Combined with {@link #isUiOpen}. */\n #isUnlocked = false;\n\n readonly #infuraProjectId: string;\n\n readonly #degradedBannerTimeout: number;\n\n readonly #unavailableBannerTimeout: number;\n\n /**\n * Constructs a new {@link NetworkConnectionBannerController}.\n *\n * @param args - The arguments to this controller.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.infuraProjectId - The wallet's Infura project id.\n * @param args.degradedBannerTimeout - How long (in milliseconds) a failing\n * network must remain failed before the degraded banner appears.\n * @param args.unavailableBannerTimeout - How long (in milliseconds) before\n * the banner escalates to \"unavailable\". Must be greater than\n * `degradedBannerTimeout`.\n * @throws If `unavailableBannerTimeout` is not greater than\n * `degradedBannerTimeout`.\n */\n constructor({\n messenger,\n infuraProjectId,\n degradedBannerTimeout = DEFAULT_DEGRADED_BANNER_TIMEOUT,\n unavailableBannerTimeout = DEFAULT_UNAVAILABLE_BANNER_TIMEOUT,\n }: NetworkConnectionBannerControllerOptions) {\n super({\n messenger,\n metadata: networkConnectionBannerControllerMetadata,\n name: CONTROLLER_NAME,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\n\n if (unavailableBannerTimeout <= degradedBannerTimeout) {\n throw new Error(\n `\\`unavailableBannerTimeout\\` (${unavailableBannerTimeout}) must be greater than \\`degradedBannerTimeout\\` (${degradedBannerTimeout}).`,\n );\n }\n\n this.#infuraProjectId = infuraProjectId;\n this.#degradedBannerTimeout = degradedBannerTimeout;\n this.#unavailableBannerTimeout = unavailableBannerTimeout;\n\n // Upstream controllers still expose :stateChange; switch to :stateChanged\n // once those packages migrate their event types.\n /* eslint-disable no-restricted-syntax -- awaiting upstream :stateChanged migration */\n this.messenger.subscribe(\n 'NetworkController:stateChange',\n (networkControllerState) =>\n this.#refreshState({\n networkControllerState,\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n }),\n selectNetworkControllerFields,\n );\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n (networkEnablementControllerState) =>\n this.#refreshState({\n networkControllerState: this.messenger.call(\n 'NetworkController:getState',\n ),\n networkEnablementControllerState,\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n }),\n selectNetworkEnablementControllerFields,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n (connectivityControllerState) =>\n this.#refreshState({\n networkControllerState: this.messenger.call(\n 'NetworkController:getState',\n ),\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState,\n }),\n selectConnectivityControllerFields,\n );\n /* eslint-enable no-restricted-syntax */\n\n // Lifecycle: evaluate RPC health (and run the banner escalation timers)\n // only while the client UI is open on an unlocked wallet.\n this.messenger.subscribe(\n 'ClientController:stateChanged',\n (isUiOpen) => {\n this.#isUiOpen = isUiOpen;\n this.#updateLifecycle();\n },\n clientControllerSelectors.selectIsUiOpen,\n );\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n this.#updateLifecycle();\n });\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n this.#updateLifecycle();\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n #updateLifecycle(): void {\n if (this.#isUiOpen && this.#isUnlocked) {\n this.#start();\n } else {\n this.#stop();\n }\n }\n\n /**\n * Look for a failed network, if any, and populate the initial state of the\n * banner. Reacts to upstream state changes from this point on. Idempotent.\n */\n #start(): void {\n if (this.#isStarted) {\n return;\n }\n\n this.#isStarted = true;\n this.#refreshState({\n networkControllerState: this.messenger.call('NetworkController:getState'),\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n });\n }\n\n /**\n * Stops evaluating network connection state. Clears any pending banner\n * timers and resets state to `available`. Idempotent.\n */\n #stop(): void {\n if (!this.#isStarted) {\n return;\n }\n\n this.#isStarted = false;\n this.#resetBanner();\n }\n\n /**\n * Clears the banner state such that the banner will be hidden.\n */\n dismissBanner(): void {\n this.#resetBanner();\n }\n\n /**\n * Switches the chain's default RPC endpoint to its Infura endpoint and\n * makes it the active network, causing the banner to clear once the\n * network becomes available again.\n *\n * @param chainId - The chain whose default RPC endpoint should be switched.\n * @throws If the chain configuration cannot be found, or if it has no\n * Infura endpoint to switch to, or if the default is already Infura.\n */\n async switchToDefaultInfuraRpcEndpoint(chainId: Hex): Promise<void> {\n const networkConfiguration = this.messenger.call(\n 'NetworkController:getNetworkConfigurationByChainId',\n chainId,\n );\n if (!networkConfiguration) {\n throw new Error(\n `No network configuration found for chain ID \"${chainId}\".`,\n );\n }\n\n const infuraEndpointIndex = networkConfiguration.rpcEndpoints.findIndex(\n (endpoint) => getIsInfuraEndpoint(endpoint.url, this.#infuraProjectId),\n );\n if (infuraEndpointIndex === -1) {\n throw new Error(\n `No Infura endpoint available for chain ID \"${chainId}\".`,\n );\n }\n if (infuraEndpointIndex === networkConfiguration.defaultRpcEndpointIndex) {\n // The default is already Infura; nothing to do.\n return;\n }\n\n // Move the active connection onto the Infura endpoint first, then make\n // it the default. In this order a partial failure leaves the failing\n // default in place and the banner visible, rather than hiding the banner\n // while the wallet is still connected to the broken endpoint.\n const infuraNetworkClientId =\n networkConfiguration.rpcEndpoints[infuraEndpointIndex].networkClientId;\n const { selectedNetworkClientId } = this.messenger.call(\n 'NetworkController:getState',\n );\n if (infuraNetworkClientId !== selectedNetworkClientId) {\n await this.messenger.call(\n 'NetworkController:setActiveNetwork',\n infuraNetworkClientId,\n );\n }\n\n await this.messenger.call('NetworkController:updateNetwork', chainId, {\n ...networkConfiguration,\n defaultRpcEndpointIndex: infuraEndpointIndex,\n });\n }\n\n #refreshState({\n networkControllerState,\n networkEnablementControllerState,\n connectivityControllerState,\n }: {\n networkControllerState: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >;\n networkEnablementControllerState: Pick<\n NetworkEnablementControllerState,\n 'enabledNetworkMap'\n >;\n connectivityControllerState: Pick<\n ConnectivityControllerState,\n 'connectivityStatus'\n >;\n }): void {\n if (!this.#isStarted) {\n return;\n }\n\n if (\n connectivityControllerState.connectivityStatus ===\n CONNECTIVITY_STATUSES.Offline\n ) {\n this.#resetBanner();\n return;\n }\n\n const failedNetwork = this.#findFailedNetwork(\n networkControllerState,\n networkEnablementControllerState,\n );\n if (!failedNetwork) {\n this.#resetBanner();\n return;\n }\n\n if (\n this.state.networkConnectionBannerStatus !== 'available' &&\n this.state.networkConnectionBannerNetwork?.networkClientId ===\n failedNetwork.networkClientId\n ) {\n this.update((state) => {\n // Even if the network client ID has not changed, save the current\n // version of the failed network to state in case the user has updated\n // its RPC URL.\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n return;\n }\n\n // A degraded timer is already counting down for this same network.\n // Repeated `stateChange` events must not clear and restart it, or a\n // steady stream of updates could postpone the banner indefinitely.\n if (this.#pendingNetworkClientId === failedNetwork.networkClientId) {\n return;\n }\n\n this.#clearTimers();\n this.update((state) => {\n state.networkConnectionBannerStatus = 'available';\n state.networkConnectionBannerNetwork = null;\n });\n\n // If `stop` is called before scheduling timers, bail early.\n if (!this.#isStarted) {\n return;\n }\n\n // Remember which network the pending timer is for (see the guard above)\n // and capture the failing network at schedule time. If the failure\n // resolves or a different network becomes the banner target while we\n // wait, the subscription handlers re-enter this method and cancel or\n // replace the timer before it fires.\n this.#pendingNetworkClientId = failedNetwork.networkClientId;\n this.#degradedTimer = setTimeout(() => {\n this.#degradedTimer = undefined;\n this.#pendingNetworkClientId = undefined;\n this.update((state) => {\n state.networkConnectionBannerStatus = 'degraded';\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n // If `stop` is called before scheduling timers, bail early.\n if (!this.#isStarted) {\n return;\n }\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n this.update((state) => {\n state.networkConnectionBannerStatus = 'unavailable';\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n }, this.#unavailableBannerTimeout - this.#degradedBannerTimeout);\n }, this.#degradedBannerTimeout);\n }\n\n /**\n * Clears timers and resets banner state to {@link NetworkConnectionBannerStatus|`available`}\n * if it isn't there already.\n */\n #resetBanner(): void {\n this.#clearTimers();\n this.#pendingNetworkClientId = undefined;\n if (\n this.state.networkConnectionBannerStatus !== 'available' ||\n this.state.networkConnectionBannerNetwork !== null\n ) {\n this.update((state) => {\n state.networkConnectionBannerStatus = 'available';\n state.networkConnectionBannerNetwork = null;\n });\n }\n }\n\n #clearTimers(): void {\n if (this.#degradedTimer !== undefined) {\n clearTimeout(this.#degradedTimer);\n this.#degradedTimer = undefined;\n }\n if (this.#unavailableTimer !== undefined) {\n clearTimeout(this.#unavailableTimer);\n this.#unavailableTimer = undefined;\n }\n }\n\n #findFailedNetwork(\n networkState: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n enablementState: Pick<\n NetworkEnablementControllerState,\n 'enabledNetworkMap'\n >,\n ): FailedNetwork | null {\n const enabledNetworks = this.#collectEnabledNetworks(\n networkState,\n enablementState,\n );\n // Networks whose connectivity has not been looked up yet are not failed.\n const failedNetworks = enabledNetworks\n .filter(\n ({ metadata }) =>\n metadata !== undefined && metadata.status !== NetworkStatus.Available,\n )\n .map((network) => this.#buildFailedNetwork(network));\n return this.#pickFailedNetworkToDisplay(\n failedNetworks,\n enabledNetworks.length,\n );\n }\n\n #getEnabledEvmChainIds(\n enabledNetworkMap: NetworkEnablementControllerState['enabledNetworkMap'],\n ): Hex[] {\n return Object.entries(enabledNetworkMap[KnownCaipNamespace.Eip155] ?? {})\n .filter(([, enabled]) => enabled)\n .map(([chainId]) => chainId as Hex);\n }\n\n #collectEnabledNetworks(\n {\n networkConfigurationsByChainId,\n networksMetadata,\n }: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n {\n enabledNetworkMap,\n }: Pick<NetworkEnablementControllerState, 'enabledNetworkMap'>,\n ): EnabledNetwork[] {\n return this.#getEnabledEvmChainIds(enabledNetworkMap).flatMap((chainId) => {\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n return [];\n }\n const { rpcEndpoints, defaultRpcEndpointIndex, name } =\n networkConfiguration;\n const defaultRpcEndpoint = rpcEndpoints[defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n return [];\n }\n return [\n {\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n metadata: networksMetadata[defaultRpcEndpoint.networkClientId],\n },\n ];\n });\n }\n\n #buildFailedNetwork({\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n }: EnabledNetwork): FailedNetwork {\n const isInfuraEndpoint = getIsInfuraEndpoint(\n defaultRpcEndpoint.url,\n this.#infuraProjectId,\n );\n\n // For custom endpoints (non-Infura), find an Infura endpoint on this\n // chain that we could offer to switch to.\n let switchableInfuraNetworkClientId: string | null = null;\n if (!isInfuraEndpoint) {\n const infuraEndpoint = rpcEndpoints.find(\n (endpoint, index) =>\n index !== defaultRpcEndpointIndex &&\n getIsInfuraEndpoint(endpoint.url, this.#infuraProjectId),\n );\n switchableInfuraNetworkClientId = infuraEndpoint?.networkClientId ?? null;\n }\n\n return {\n chainId,\n networkClientId: defaultRpcEndpoint.networkClientId,\n name,\n rpcUrl: defaultRpcEndpoint.url,\n isInfuraEndpoint,\n switchableInfuraNetworkClientId,\n };\n }\n\n #pickFailedNetworkToDisplay(\n failedNetworks: FailedNetwork[],\n totalEnabledNetworks: number,\n ): FailedNetwork | null {\n if (failedNetworks.length === 0) {\n return null;\n }\n\n const firstCustomFailed = failedNetworks.find(\n (entry) => !entry.isInfuraEndpoint,\n );\n const areAllEnabledNetworksFailed =\n failedNetworks.length === totalEnabledNetworks;\n\n if (!firstCustomFailed && !areAllEnabledNetworksFailed) {\n return null;\n }\n\n return firstCustomFailed ?? failedNetworks[0];\n }\n}\n"]}
|
|
@@ -59,6 +59,17 @@ export type NetworkConnectionBannerControllerState = {
|
|
|
59
59
|
* @returns The default state.
|
|
60
60
|
*/
|
|
61
61
|
export declare function getDefaultNetworkConnectionBannerControllerState(): NetworkConnectionBannerControllerState;
|
|
62
|
+
/**
|
|
63
|
+
* The default for how long (in milliseconds) a failing network must remain
|
|
64
|
+
* in a "failed" status ("degraded" or "unavailable") before the degraded
|
|
65
|
+
* banner appears.
|
|
66
|
+
*/
|
|
67
|
+
export declare const DEFAULT_DEGRADED_BANNER_TIMEOUT = 5000;
|
|
68
|
+
/**
|
|
69
|
+
* The default for how long (in milliseconds) a failing network must remain
|
|
70
|
+
* in a "failed" status before the banner escalates to "unavailable".
|
|
71
|
+
*/
|
|
72
|
+
export declare const DEFAULT_UNAVAILABLE_BANNER_TIMEOUT = 30000;
|
|
62
73
|
/**
|
|
63
74
|
* Retrieves the state of the {@link NetworkConnectionBannerController}.
|
|
64
75
|
*/
|
|
@@ -112,29 +123,54 @@ export type NetworkConnectionBannerControllerOptions = {
|
|
|
112
123
|
* endpoints whose URL was persisted with the id already substituted.
|
|
113
124
|
*/
|
|
114
125
|
infuraProjectId: string;
|
|
126
|
+
/**
|
|
127
|
+
* How long (in milliseconds) a failing network must remain in a "failed"
|
|
128
|
+
* status before the degraded banner appears. Defaults to
|
|
129
|
+
* {@link DEFAULT_DEGRADED_BANNER_TIMEOUT}.
|
|
130
|
+
*/
|
|
131
|
+
degradedBannerTimeout?: number;
|
|
132
|
+
/**
|
|
133
|
+
* How long (in milliseconds), measured from the same failure start as
|
|
134
|
+
* `degradedBannerTimeout`, before the banner escalates to "unavailable".
|
|
135
|
+
* Must be greater than `degradedBannerTimeout`. Defaults to
|
|
136
|
+
* {@link DEFAULT_UNAVAILABLE_BANNER_TIMEOUT}.
|
|
137
|
+
*/
|
|
138
|
+
unavailableBannerTimeout?: number;
|
|
115
139
|
};
|
|
116
140
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
141
|
+
* Drives the "network connection banner", a notice that appears within clients
|
|
142
|
+
* whose goal is to inform users about networks which have exhibited repeated
|
|
143
|
+
* request failures and offer potential workarounds.
|
|
144
|
+
*
|
|
145
|
+
* Some terminology: A "network" in this case is an RPC endpoint, and a network
|
|
146
|
+
* that has exhibited repeated request failures has entered a "failed" state (or
|
|
147
|
+
* is a "failed network").
|
|
148
|
+
*
|
|
149
|
+
* For simplicity, the banner always represents a single failed network. If
|
|
150
|
+
* multiple networks are failing, the first custom network takes priority over
|
|
151
|
+
* the first Infura network.
|
|
152
|
+
*
|
|
153
|
+
* To ensure that the banner is actionable, the banner does not always appear
|
|
154
|
+
* even if there is a failed network to display. Instead it appears under these
|
|
155
|
+
* conditions:
|
|
120
156
|
*
|
|
121
|
-
* The
|
|
157
|
+
* - The failed network is a custom (non-Infura) endpoint (we want to inform
|
|
158
|
+
* users about endpoints they've added so they don't cast blame on MetaMask).
|
|
159
|
+
* - Every enabled EVM network has entered a failed state (this indicates a
|
|
160
|
+
* broad connectivity issue).
|
|
122
161
|
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* - Every enabled EVM network is reporting a failed connectivity status
|
|
126
|
-
* (escape hatch so Infura-only setups still get a signal).
|
|
162
|
+
* Assuming that these conditions have been met, there are two variants of the
|
|
163
|
+
* banner which will be displayed at different times.
|
|
127
164
|
*
|
|
128
|
-
* A
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
165
|
+
* - A "degraded" variant which will appear when 5 seconds has elapsed and there
|
|
166
|
+
* is an eligible failed network to display
|
|
167
|
+
* - An "unavailable" variant which will appear when 30 seconds have elapsed and
|
|
168
|
+
* there is an eligible failed network to display
|
|
132
169
|
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* click handlers to {@link dismissBanner} or {@link switchToDefaultInfuraRpcEndpoint}.
|
|
170
|
+
* Finally, the controller contains actions that drive interactions with the
|
|
171
|
+
* banner. Namely, if the banner represents a custom network, then it will offer
|
|
172
|
+
* the user a way to switch to the default Infura network. The controller
|
|
173
|
+
* contains the logic to carry out that action.
|
|
138
174
|
*/
|
|
139
175
|
export declare class NetworkConnectionBannerController extends BaseController<typeof CONTROLLER_NAME, NetworkConnectionBannerControllerState, NetworkConnectionBannerControllerMessenger> {
|
|
140
176
|
#private;
|
|
@@ -144,8 +180,15 @@ export declare class NetworkConnectionBannerController extends BaseController<ty
|
|
|
144
180
|
* @param args - The arguments to this controller.
|
|
145
181
|
* @param args.messenger - The messenger suited for this controller.
|
|
146
182
|
* @param args.infuraProjectId - The wallet's Infura project id.
|
|
183
|
+
* @param args.degradedBannerTimeout - How long (in milliseconds) a failing
|
|
184
|
+
* network must remain failed before the degraded banner appears.
|
|
185
|
+
* @param args.unavailableBannerTimeout - How long (in milliseconds) before
|
|
186
|
+
* the banner escalates to "unavailable". Must be greater than
|
|
187
|
+
* `degradedBannerTimeout`.
|
|
188
|
+
* @throws If `unavailableBannerTimeout` is not greater than
|
|
189
|
+
* `degradedBannerTimeout`.
|
|
147
190
|
*/
|
|
148
|
-
constructor({ messenger, infuraProjectId, }: NetworkConnectionBannerControllerOptions);
|
|
191
|
+
constructor({ messenger, infuraProjectId, degradedBannerTimeout, unavailableBannerTimeout, }: NetworkConnectionBannerControllerOptions);
|
|
149
192
|
/**
|
|
150
193
|
* Clears the banner state such that the banner will be hidden.
|
|
151
194
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkConnectionBannerController.d.cts","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,2BAA2B,EAE5B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAE3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,oCAAoC;AAKzE,OAAO,KAAK,EACV,oCAAoC,EAEpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC7B,qCAAqC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAEV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,uCAAuC,EACvC,iCAAiC,EAGlC,qCAAqC;AAEtC,OAAO,KAAK,EACV,yCAAyC,EAEzC,2CAA2C,EAC5C,gDAAgD;AAEjD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAI3C,OAAO,KAAK,EAAE,8CAA8C,EAAE,oEAAgE;AAG9H;;;;GAIG;AACH,QAAA,MAAM,eAAe,sCAAsC,CAAC;AAiE5D;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACrC,WAAW,GACX,UAAU,GACV,aAAa,CAAC;AAgBlB;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,2CAA2C;IAC3C,OAAO,EAAE,GAAG,CAAC;IACb,iEAAiE;IACjE,eAAe,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,+BAA+B,EAAE,MAAM,GAAG,IAAI,CAAC;CAChD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,sCAAsC,GAAG;IACnD,6BAA6B,EAAE,6BAA6B,CAAC;IAC7D,8BAA8B,EAAE,aAAa,GAAG,IAAI,CAAC;CACtD,CAAC;AAiBF;;;;GAIG;AACH,wBAAgB,gDAAgD,IAAI,sCAAsC,CAKzG;
|
|
1
|
+
{"version":3,"file":"NetworkConnectionBannerController.d.cts","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":"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"}
|
|
@@ -59,6 +59,17 @@ export type NetworkConnectionBannerControllerState = {
|
|
|
59
59
|
* @returns The default state.
|
|
60
60
|
*/
|
|
61
61
|
export declare function getDefaultNetworkConnectionBannerControllerState(): NetworkConnectionBannerControllerState;
|
|
62
|
+
/**
|
|
63
|
+
* The default for how long (in milliseconds) a failing network must remain
|
|
64
|
+
* in a "failed" status ("degraded" or "unavailable") before the degraded
|
|
65
|
+
* banner appears.
|
|
66
|
+
*/
|
|
67
|
+
export declare const DEFAULT_DEGRADED_BANNER_TIMEOUT = 5000;
|
|
68
|
+
/**
|
|
69
|
+
* The default for how long (in milliseconds) a failing network must remain
|
|
70
|
+
* in a "failed" status before the banner escalates to "unavailable".
|
|
71
|
+
*/
|
|
72
|
+
export declare const DEFAULT_UNAVAILABLE_BANNER_TIMEOUT = 30000;
|
|
62
73
|
/**
|
|
63
74
|
* Retrieves the state of the {@link NetworkConnectionBannerController}.
|
|
64
75
|
*/
|
|
@@ -112,29 +123,54 @@ export type NetworkConnectionBannerControllerOptions = {
|
|
|
112
123
|
* endpoints whose URL was persisted with the id already substituted.
|
|
113
124
|
*/
|
|
114
125
|
infuraProjectId: string;
|
|
126
|
+
/**
|
|
127
|
+
* How long (in milliseconds) a failing network must remain in a "failed"
|
|
128
|
+
* status before the degraded banner appears. Defaults to
|
|
129
|
+
* {@link DEFAULT_DEGRADED_BANNER_TIMEOUT}.
|
|
130
|
+
*/
|
|
131
|
+
degradedBannerTimeout?: number;
|
|
132
|
+
/**
|
|
133
|
+
* How long (in milliseconds), measured from the same failure start as
|
|
134
|
+
* `degradedBannerTimeout`, before the banner escalates to "unavailable".
|
|
135
|
+
* Must be greater than `degradedBannerTimeout`. Defaults to
|
|
136
|
+
* {@link DEFAULT_UNAVAILABLE_BANNER_TIMEOUT}.
|
|
137
|
+
*/
|
|
138
|
+
unavailableBannerTimeout?: number;
|
|
115
139
|
};
|
|
116
140
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
141
|
+
* Drives the "network connection banner", a notice that appears within clients
|
|
142
|
+
* whose goal is to inform users about networks which have exhibited repeated
|
|
143
|
+
* request failures and offer potential workarounds.
|
|
144
|
+
*
|
|
145
|
+
* Some terminology: A "network" in this case is an RPC endpoint, and a network
|
|
146
|
+
* that has exhibited repeated request failures has entered a "failed" state (or
|
|
147
|
+
* is a "failed network").
|
|
148
|
+
*
|
|
149
|
+
* For simplicity, the banner always represents a single failed network. If
|
|
150
|
+
* multiple networks are failing, the first custom network takes priority over
|
|
151
|
+
* the first Infura network.
|
|
152
|
+
*
|
|
153
|
+
* To ensure that the banner is actionable, the banner does not always appear
|
|
154
|
+
* even if there is a failed network to display. Instead it appears under these
|
|
155
|
+
* conditions:
|
|
120
156
|
*
|
|
121
|
-
* The
|
|
157
|
+
* - The failed network is a custom (non-Infura) endpoint (we want to inform
|
|
158
|
+
* users about endpoints they've added so they don't cast blame on MetaMask).
|
|
159
|
+
* - Every enabled EVM network has entered a failed state (this indicates a
|
|
160
|
+
* broad connectivity issue).
|
|
122
161
|
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* - Every enabled EVM network is reporting a failed connectivity status
|
|
126
|
-
* (escape hatch so Infura-only setups still get a signal).
|
|
162
|
+
* Assuming that these conditions have been met, there are two variants of the
|
|
163
|
+
* banner which will be displayed at different times.
|
|
127
164
|
*
|
|
128
|
-
* A
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
165
|
+
* - A "degraded" variant which will appear when 5 seconds has elapsed and there
|
|
166
|
+
* is an eligible failed network to display
|
|
167
|
+
* - An "unavailable" variant which will appear when 30 seconds have elapsed and
|
|
168
|
+
* there is an eligible failed network to display
|
|
132
169
|
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* click handlers to {@link dismissBanner} or {@link switchToDefaultInfuraRpcEndpoint}.
|
|
170
|
+
* Finally, the controller contains actions that drive interactions with the
|
|
171
|
+
* banner. Namely, if the banner represents a custom network, then it will offer
|
|
172
|
+
* the user a way to switch to the default Infura network. The controller
|
|
173
|
+
* contains the logic to carry out that action.
|
|
138
174
|
*/
|
|
139
175
|
export declare class NetworkConnectionBannerController extends BaseController<typeof CONTROLLER_NAME, NetworkConnectionBannerControllerState, NetworkConnectionBannerControllerMessenger> {
|
|
140
176
|
#private;
|
|
@@ -144,8 +180,15 @@ export declare class NetworkConnectionBannerController extends BaseController<ty
|
|
|
144
180
|
* @param args - The arguments to this controller.
|
|
145
181
|
* @param args.messenger - The messenger suited for this controller.
|
|
146
182
|
* @param args.infuraProjectId - The wallet's Infura project id.
|
|
183
|
+
* @param args.degradedBannerTimeout - How long (in milliseconds) a failing
|
|
184
|
+
* network must remain failed before the degraded banner appears.
|
|
185
|
+
* @param args.unavailableBannerTimeout - How long (in milliseconds) before
|
|
186
|
+
* the banner escalates to "unavailable". Must be greater than
|
|
187
|
+
* `degradedBannerTimeout`.
|
|
188
|
+
* @throws If `unavailableBannerTimeout` is not greater than
|
|
189
|
+
* `degradedBannerTimeout`.
|
|
147
190
|
*/
|
|
148
|
-
constructor({ messenger, infuraProjectId, }: NetworkConnectionBannerControllerOptions);
|
|
191
|
+
constructor({ messenger, infuraProjectId, degradedBannerTimeout, unavailableBannerTimeout, }: NetworkConnectionBannerControllerOptions);
|
|
149
192
|
/**
|
|
150
193
|
* Clears the banner state such that the banner will be hidden.
|
|
151
194
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkConnectionBannerController.d.mts","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,2BAA2B,EAE5B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAE3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,oCAAoC;AAKzE,OAAO,KAAK,EACV,oCAAoC,EAEpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC7B,qCAAqC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAEV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,uCAAuC,EACvC,iCAAiC,EAGlC,qCAAqC;AAEtC,OAAO,KAAK,EACV,yCAAyC,EAEzC,2CAA2C,EAC5C,gDAAgD;AAEjD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAI3C,OAAO,KAAK,EAAE,8CAA8C,EAAE,oEAAgE;AAG9H;;;;GAIG;AACH,QAAA,MAAM,eAAe,sCAAsC,CAAC;AAiE5D;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACrC,WAAW,GACX,UAAU,GACV,aAAa,CAAC;AAgBlB;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,2CAA2C;IAC3C,OAAO,EAAE,GAAG,CAAC;IACb,iEAAiE;IACjE,eAAe,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,+BAA+B,EAAE,MAAM,GAAG,IAAI,CAAC;CAChD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,sCAAsC,GAAG;IACnD,6BAA6B,EAAE,6BAA6B,CAAC;IAC7D,8BAA8B,EAAE,aAAa,GAAG,IAAI,CAAC;CACtD,CAAC;AAiBF;;;;GAIG;AACH,wBAAgB,gDAAgD,IAAI,sCAAsC,CAKzG;
|
|
1
|
+
{"version":3,"file":"NetworkConnectionBannerController.d.mts","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ 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 _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_pendingNetworkClientId, _NetworkConnectionBannerController_isStarted, _NetworkConnectionBannerController_isUiOpen, _NetworkConnectionBannerController_isUnlocked, _NetworkConnectionBannerController_infuraProjectId, _NetworkConnectionBannerController_updateLifecycle, _NetworkConnectionBannerController_start, _NetworkConnectionBannerController_stop, _NetworkConnectionBannerController_refreshState, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetwork, _NetworkConnectionBannerController_getEnabledEvmChainIds, _NetworkConnectionBannerController_collectEnabledNetworks, _NetworkConnectionBannerController_buildFailedNetwork, _NetworkConnectionBannerController_pickFailedNetworkToDisplay;
|
|
12
|
+
var _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_pendingNetworkClientId, _NetworkConnectionBannerController_isStarted, _NetworkConnectionBannerController_isUiOpen, _NetworkConnectionBannerController_isUnlocked, _NetworkConnectionBannerController_infuraProjectId, _NetworkConnectionBannerController_degradedBannerTimeout, _NetworkConnectionBannerController_unavailableBannerTimeout, _NetworkConnectionBannerController_updateLifecycle, _NetworkConnectionBannerController_start, _NetworkConnectionBannerController_stop, _NetworkConnectionBannerController_refreshState, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetwork, _NetworkConnectionBannerController_getEnabledEvmChainIds, _NetworkConnectionBannerController_collectEnabledNetworks, _NetworkConnectionBannerController_buildFailedNetwork, _NetworkConnectionBannerController_pickFailedNetworkToDisplay;
|
|
13
13
|
import { BaseController } from "@metamask/base-controller";
|
|
14
14
|
import { clientControllerSelectors } from "@metamask/client-controller";
|
|
15
15
|
import { CONNECTIVITY_STATUSES, connectivityControllerSelectors } from "@metamask/connectivity-controller";
|
|
@@ -94,41 +94,54 @@ export function getDefaultNetworkConnectionBannerControllerState() {
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
98
|
-
* status ("degraded" or "unavailable") before the degraded
|
|
97
|
+
* The default for how long (in milliseconds) a failing network must remain
|
|
98
|
+
* in a "failed" status ("degraded" or "unavailable") before the degraded
|
|
99
|
+
* banner appears.
|
|
99
100
|
*/
|
|
100
|
-
const
|
|
101
|
+
export const DEFAULT_DEGRADED_BANNER_TIMEOUT = 5000;
|
|
101
102
|
/**
|
|
102
|
-
*
|
|
103
|
-
* status before the banner escalates to "unavailable".
|
|
103
|
+
* The default for how long (in milliseconds) a failing network must remain
|
|
104
|
+
* in a "failed" status before the banner escalates to "unavailable".
|
|
104
105
|
*/
|
|
105
|
-
const
|
|
106
|
+
export const DEFAULT_UNAVAILABLE_BANNER_TIMEOUT = 30000;
|
|
106
107
|
const MESSENGER_EXPOSED_METHODS = [
|
|
107
108
|
'dismissBanner',
|
|
108
109
|
'switchToDefaultInfuraRpcEndpoint',
|
|
109
110
|
];
|
|
110
111
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
112
|
+
* Drives the "network connection banner", a notice that appears within clients
|
|
113
|
+
* whose goal is to inform users about networks which have exhibited repeated
|
|
114
|
+
* request failures and offer potential workarounds.
|
|
114
115
|
*
|
|
115
|
-
*
|
|
116
|
+
* Some terminology: A "network" in this case is an RPC endpoint, and a network
|
|
117
|
+
* that has exhibited repeated request failures has entered a "failed" state (or
|
|
118
|
+
* is a "failed network").
|
|
116
119
|
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* (escape hatch so Infura-only setups still get a signal).
|
|
120
|
+
* For simplicity, the banner always represents a single failed network. If
|
|
121
|
+
* multiple networks are failing, the first custom network takes priority over
|
|
122
|
+
* the first Infura network.
|
|
121
123
|
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* RPC" CTA targets the network the user can act on.
|
|
124
|
+
* To ensure that the banner is actionable, the banner does not always appear
|
|
125
|
+
* even if there is a failed network to display. Instead it appears under these
|
|
126
|
+
* conditions:
|
|
126
127
|
*
|
|
127
|
-
* The
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
128
|
+
* - The failed network is a custom (non-Infura) endpoint (we want to inform
|
|
129
|
+
* users about endpoints they've added so they don't cast blame on MetaMask).
|
|
130
|
+
* - Every enabled EVM network has entered a failed state (this indicates a
|
|
131
|
+
* broad connectivity issue).
|
|
132
|
+
*
|
|
133
|
+
* Assuming that these conditions have been met, there are two variants of the
|
|
134
|
+
* banner which will be displayed at different times.
|
|
135
|
+
*
|
|
136
|
+
* - A "degraded" variant which will appear when 5 seconds has elapsed and there
|
|
137
|
+
* is an eligible failed network to display
|
|
138
|
+
* - An "unavailable" variant which will appear when 30 seconds have elapsed and
|
|
139
|
+
* there is an eligible failed network to display
|
|
140
|
+
*
|
|
141
|
+
* Finally, the controller contains actions that drive interactions with the
|
|
142
|
+
* banner. Namely, if the banner represents a custom network, then it will offer
|
|
143
|
+
* the user a way to switch to the default Infura network. The controller
|
|
144
|
+
* contains the logic to carry out that action.
|
|
132
145
|
*/
|
|
133
146
|
export class NetworkConnectionBannerController extends BaseController {
|
|
134
147
|
/**
|
|
@@ -137,8 +150,15 @@ export class NetworkConnectionBannerController extends BaseController {
|
|
|
137
150
|
* @param args - The arguments to this controller.
|
|
138
151
|
* @param args.messenger - The messenger suited for this controller.
|
|
139
152
|
* @param args.infuraProjectId - The wallet's Infura project id.
|
|
153
|
+
* @param args.degradedBannerTimeout - How long (in milliseconds) a failing
|
|
154
|
+
* network must remain failed before the degraded banner appears.
|
|
155
|
+
* @param args.unavailableBannerTimeout - How long (in milliseconds) before
|
|
156
|
+
* the banner escalates to "unavailable". Must be greater than
|
|
157
|
+
* `degradedBannerTimeout`.
|
|
158
|
+
* @throws If `unavailableBannerTimeout` is not greater than
|
|
159
|
+
* `degradedBannerTimeout`.
|
|
140
160
|
*/
|
|
141
|
-
constructor({ messenger, infuraProjectId, }) {
|
|
161
|
+
constructor({ messenger, infuraProjectId, degradedBannerTimeout = DEFAULT_DEGRADED_BANNER_TIMEOUT, unavailableBannerTimeout = DEFAULT_UNAVAILABLE_BANNER_TIMEOUT, }) {
|
|
142
162
|
super({
|
|
143
163
|
messenger,
|
|
144
164
|
metadata: networkConnectionBannerControllerMetadata,
|
|
@@ -155,7 +175,14 @@ export class NetworkConnectionBannerController extends BaseController {
|
|
|
155
175
|
/** Whether the keyring is unlocked. Combined with {@link #isUiOpen}. */
|
|
156
176
|
_NetworkConnectionBannerController_isUnlocked.set(this, false);
|
|
157
177
|
_NetworkConnectionBannerController_infuraProjectId.set(this, void 0);
|
|
178
|
+
_NetworkConnectionBannerController_degradedBannerTimeout.set(this, void 0);
|
|
179
|
+
_NetworkConnectionBannerController_unavailableBannerTimeout.set(this, void 0);
|
|
180
|
+
if (unavailableBannerTimeout <= degradedBannerTimeout) {
|
|
181
|
+
throw new Error(`\`unavailableBannerTimeout\` (${unavailableBannerTimeout}) must be greater than \`degradedBannerTimeout\` (${degradedBannerTimeout}).`);
|
|
182
|
+
}
|
|
158
183
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_infuraProjectId, infuraProjectId, "f");
|
|
184
|
+
__classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedBannerTimeout, degradedBannerTimeout, "f");
|
|
185
|
+
__classPrivateFieldSet(this, _NetworkConnectionBannerController_unavailableBannerTimeout, unavailableBannerTimeout, "f");
|
|
159
186
|
// Upstream controllers still expose :stateChange; switch to :stateChanged
|
|
160
187
|
// once those packages migrate their event types.
|
|
161
188
|
/* eslint-disable no-restricted-syntax -- awaiting upstream :stateChanged migration */
|
|
@@ -234,7 +261,7 @@ export class NetworkConnectionBannerController extends BaseController {
|
|
|
234
261
|
});
|
|
235
262
|
}
|
|
236
263
|
}
|
|
237
|
-
_NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_pendingNetworkClientId = new WeakMap(), _NetworkConnectionBannerController_isStarted = new WeakMap(), _NetworkConnectionBannerController_isUiOpen = new WeakMap(), _NetworkConnectionBannerController_isUnlocked = new WeakMap(), _NetworkConnectionBannerController_infuraProjectId = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_updateLifecycle = function _NetworkConnectionBannerController_updateLifecycle() {
|
|
264
|
+
_NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_pendingNetworkClientId = new WeakMap(), _NetworkConnectionBannerController_isStarted = new WeakMap(), _NetworkConnectionBannerController_isUiOpen = new WeakMap(), _NetworkConnectionBannerController_isUnlocked = new WeakMap(), _NetworkConnectionBannerController_infuraProjectId = new WeakMap(), _NetworkConnectionBannerController_degradedBannerTimeout = new WeakMap(), _NetworkConnectionBannerController_unavailableBannerTimeout = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_updateLifecycle = function _NetworkConnectionBannerController_updateLifecycle() {
|
|
238
265
|
if (__classPrivateFieldGet(this, _NetworkConnectionBannerController_isUiOpen, "f") && __classPrivateFieldGet(this, _NetworkConnectionBannerController_isUnlocked, "f")) {
|
|
239
266
|
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_start).call(this);
|
|
240
267
|
}
|
|
@@ -320,8 +347,8 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
|
|
|
320
347
|
state.networkConnectionBannerStatus = 'unavailable';
|
|
321
348
|
state.networkConnectionBannerNetwork = failedNetwork;
|
|
322
349
|
});
|
|
323
|
-
},
|
|
324
|
-
},
|
|
350
|
+
}, __classPrivateFieldGet(this, _NetworkConnectionBannerController_unavailableBannerTimeout, "f") - __classPrivateFieldGet(this, _NetworkConnectionBannerController_degradedBannerTimeout, "f")), "f");
|
|
351
|
+
}, __classPrivateFieldGet(this, _NetworkConnectionBannerController_degradedBannerTimeout, "f")), "f");
|
|
325
352
|
}, _NetworkConnectionBannerController_resetBanner = function _NetworkConnectionBannerController_resetBanner() {
|
|
326
353
|
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_clearTimers).call(this);
|
|
327
354
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, undefined, "f");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkConnectionBannerController.mjs","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { clientControllerSelectors } from '@metamask/client-controller';\nimport type { ClientControllerState } from '@metamask/client-controller';\nimport {\n CONNECTIVITY_STATUSES,\n connectivityControllerSelectors,\n} from '@metamask/connectivity-controller';\nimport type {\n ConnectivityControllerGetStateAction,\n ConnectivityControllerState,\n ConnectivityControllerStateChangeEvent,\n} from '@metamask/connectivity-controller';\nimport type {\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkConfiguration,\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\n NetworkControllerSetActiveNetworkAction,\n NetworkControllerStateChangeEvent,\n NetworkMetadata,\n NetworkState,\n} from '@metamask/network-controller';\nimport { NetworkStatus } from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerState,\n NetworkEnablementControllerStateChangeEvent,\n} from '@metamask/network-enablement-controller';\nimport { selectEnabledNetworkMap } from '@metamask/network-enablement-controller';\nimport type { Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\nimport { createSelector } from 'reselect';\n\nimport type { NetworkConnectionBannerControllerMethodActions } from './NetworkConnectionBannerController-method-action-types';\nimport { getIsInfuraEndpoint } from './url-utils';\n\n/**\n * The name of the {@link NetworkConnectionBannerController}, used to namespace\n * the controller's actions and events and to namespace the controller's state\n * data when composed with other controllers.\n */\nconst CONTROLLER_NAME = 'NetworkConnectionBannerController';\n\n/**\n * Selects `networksMetadata` from the `NetworkController` state.\n *\n * @param state - The `NetworkController` state.\n * @returns The networks metadata map keyed by network client id.\n */\nconst selectNetworksMetadata = (\n state: NetworkState,\n): NetworkState['networksMetadata'] => state.networksMetadata;\n\n/**\n * Selects `networkConfigurationsByChainId` from the `NetworkController`\n * state.\n *\n * @param state - The `NetworkController` state.\n * @returns The network configurations keyed by chain id.\n */\nconst selectNetworkConfigurationsByChainId = (\n state: NetworkState,\n): NetworkState['networkConfigurationsByChainId'] =>\n state.networkConfigurationsByChainId;\n\n/**\n * Selects the `NetworkController` state fields that influence the banner\n * rule. Composed with `createSelector` so the return object stays reference\n * stable while unrelated `NetworkController` state (e.g.\n * `selectedNetworkClientId`) changes.\n *\n * @param state - The `NetworkController` state.\n * @returns The relevant network fields.\n */\nconst selectNetworkControllerFields = createSelector(\n [selectNetworksMetadata, selectNetworkConfigurationsByChainId],\n (networksMetadata, networkConfigurationsByChainId) => ({\n networksMetadata,\n networkConfigurationsByChainId,\n }),\n);\n\n/**\n * Selects the `NetworkEnablementController` state field that influences the\n * banner rule.\n *\n * @param state - The `NetworkEnablementController` state.\n * @returns The relevant enablement fields.\n */\nconst selectNetworkEnablementControllerFields = createSelector(\n [selectEnabledNetworkMap],\n (enabledNetworkMap) => ({ enabledNetworkMap }),\n);\n\n/**\n * Selects the `ConnectivityController` state field that influences the\n * banner rule.\n *\n * @param state - The `ConnectivityController` state.\n * @returns The relevant connectivity fields.\n */\nconst selectConnectivityControllerFields = createSelector(\n [connectivityControllerSelectors.selectConnectivityStatus],\n (connectivityStatus) => ({ connectivityStatus }),\n);\n\n/**\n * Status the banner can be in. `available` means no banner is shown; the\n * `degraded` and `unavailable` values mirror the two-tier escalation that the\n * UI renders.\n */\nexport type NetworkConnectionBannerStatus =\n | 'available'\n | 'degraded'\n | 'unavailable';\n\n/**\n * An enabled network from `NetworkController` state with a default RPC\n * endpoint. Used as the input to the failed-network detection pipeline.\n * `metadata` is missing until the network's connectivity has been looked up.\n */\ntype EnabledNetwork = {\n chainId: Hex;\n name: string;\n rpcEndpoints: NetworkConfiguration['rpcEndpoints'];\n defaultRpcEndpointIndex: number;\n defaultRpcEndpoint: NetworkConfiguration['rpcEndpoints'][number];\n metadata: NetworkMetadata | undefined;\n};\n\n/**\n * Details of a failing network the banner describes.\n */\nexport type FailedNetwork = {\n /** The chain id of the failing network. */\n chainId: Hex;\n /** The `networkClientId` of the failing default RPC endpoint. */\n networkClientId: string;\n /** The display name for the failing network. */\n name: string;\n /** The URL of the failing default RPC endpoint. */\n rpcUrl: string;\n /** Whether the failing endpoint is a MetaMask Infura endpoint. */\n isInfuraEndpoint: boolean;\n /**\n * The networkClientId of an Infura endpoint on the same chain that the user\n * can switch to. `null` when the failing endpoint is already Infura or when\n * no Infura alternative exists.\n */\n switchableInfuraNetworkClientId: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n *\n * The keys carry the controller-domain prefix (like\n * `ConnectivityController`'s `connectivityStatus`) because some clients merge\n * all controller states into one flat object, where generic names like\n * `status` collide across controllers.\n */\nexport type NetworkConnectionBannerControllerState = {\n networkConnectionBannerStatus: NetworkConnectionBannerStatus;\n networkConnectionBannerNetwork: FailedNetwork | null;\n};\n\nconst networkConnectionBannerControllerMetadata = {\n networkConnectionBannerStatus: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n networkConnectionBannerNetwork: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n} satisfies StateMetadata<NetworkConnectionBannerControllerState>;\n\n/**\n * Constructs the default {@link NetworkConnectionBannerController} state.\n *\n * @returns The default state.\n */\nexport function getDefaultNetworkConnectionBannerControllerState(): NetworkConnectionBannerControllerState {\n return {\n networkConnectionBannerStatus: 'available',\n networkConnectionBannerNetwork: null,\n };\n}\n\n/**\n * How long (in milliseconds) a failing network must remain in a \"failed\"\n * status (\"degraded\" or \"unavailable\") before the degraded banner appears.\n */\nconst DEGRADED_BANNER_TIMEOUT = 5_000;\n\n/**\n * How long (in milliseconds) a failing network must remain in a \"failed\"\n * status before the banner escalates to \"unavailable\".\n */\nconst UNAVAILABLE_BANNER_TIMEOUT = 30_000;\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'dismissBanner',\n 'switchToDefaultInfuraRpcEndpoint',\n] as const;\n\n/**\n * Retrieves the state of the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerGetStateAction =\n ControllerGetStateAction<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState\n >;\n\n/**\n * Actions that {@link NetworkConnectionBannerControllerMessenger} exposes to\n * other consumers.\n */\nexport type NetworkConnectionBannerControllerActions =\n | NetworkConnectionBannerControllerGetStateAction\n | NetworkConnectionBannerControllerMethodActions;\n\n/**\n * Actions from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} calls.\n */\ntype AllowedActions =\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkConfigurationByChainIdAction\n | NetworkControllerUpdateNetworkAction\n | NetworkControllerSetActiveNetworkAction\n | NetworkEnablementControllerGetStateAction\n | ConnectivityControllerGetStateAction;\n\n/**\n * Published when the state of {@link NetworkConnectionBannerController}\n * changes.\n */\nexport type NetworkConnectionBannerControllerStateChangedEvent =\n ControllerStateChangedEvent<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState\n >;\n\n/**\n * Events that {@link NetworkConnectionBannerControllerMessenger} exposes to\n * other consumers.\n */\nexport type NetworkConnectionBannerControllerEvents =\n NetworkConnectionBannerControllerStateChangedEvent;\n\n/**\n * Published when the state of `ClientController` changes. Defined here\n * because the `client-controller` package still exports the legacy\n * `:stateChange` event type.\n */\ntype ClientControllerStateChangedEvent = ControllerStateChangedEvent<\n 'ClientController',\n ClientControllerState\n>;\n\n/**\n * Events from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} subscribes to.\n */\ntype AllowedEvents =\n | NetworkControllerStateChangeEvent\n | NetworkEnablementControllerStateChangeEvent\n | ConnectivityControllerStateChangeEvent\n | ClientControllerStateChangedEvent\n | KeyringControllerUnlockEvent\n | KeyringControllerLockEvent;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerMessenger = Messenger<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerActions | AllowedActions,\n NetworkConnectionBannerControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerOptions = {\n /**\n * The messenger for inter-controller communication.\n */\n messenger: NetworkConnectionBannerControllerMessenger;\n\n /**\n * The wallet's Infura project id, used to recognize MetaMask Infura\n * endpoints whose URL was persisted with the id already substituted.\n */\n infuraProjectId: string;\n};\n\n/**\n * NetworkConnectionBannerController decides whether the network connection\n * banner should be shown for the user, and which failing network it should\n * describe. It encapsulates the rule and the 5s / 30s timer escalation.\n *\n * The banner shows when:\n *\n * - A failing network's default RPC is a custom (non-Infura) endpoint —\n * users always want to be informed about errors with RPCs they've chosen.\n * - Every enabled EVM network is reporting a failed connectivity status\n * (escape hatch so Infura-only setups still get a signal).\n *\n * A partial Infura outage alongside healthy peers is suppressed since it\n * usually resolves on its own and the user cannot act on it. When a custom\n * failure is present, it's surfaced first so the \"Switch to MetaMask default\n * RPC\" CTA targets the network the user can act on.\n *\n * The controller manages its own lifecycle: it evaluates RPC health (and\n * runs the escalation timers) only while the client UI is open\n * (`ClientController`) and the wallet is unlocked (`KeyringController`).\n * Clients only need to render the banner from the controller's state and wire\n * click handlers to {@link dismissBanner} or {@link switchToDefaultInfuraRpcEndpoint}.\n */\nexport class NetworkConnectionBannerController extends BaseController<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerMessenger\n> {\n #degradedTimer: ReturnType<typeof setTimeout> | undefined;\n\n #unavailableTimer: ReturnType<typeof setTimeout> | undefined;\n\n #pendingNetworkClientId: string | undefined;\n\n #isStarted = false;\n\n /** Whether the client UI is open. Combined with {@link #isUnlocked}. */\n #isUiOpen = false;\n\n /** Whether the keyring is unlocked. Combined with {@link #isUiOpen}. */\n #isUnlocked = false;\n\n readonly #infuraProjectId: string;\n\n /**\n * Constructs a new {@link NetworkConnectionBannerController}.\n *\n * @param args - The arguments to this controller.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.infuraProjectId - The wallet's Infura project id.\n */\n constructor({\n messenger,\n infuraProjectId,\n }: NetworkConnectionBannerControllerOptions) {\n super({\n messenger,\n metadata: networkConnectionBannerControllerMetadata,\n name: CONTROLLER_NAME,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\n\n this.#infuraProjectId = infuraProjectId;\n\n // Upstream controllers still expose :stateChange; switch to :stateChanged\n // once those packages migrate their event types.\n /* eslint-disable no-restricted-syntax -- awaiting upstream :stateChanged migration */\n this.messenger.subscribe(\n 'NetworkController:stateChange',\n (networkControllerState) =>\n this.#refreshState({\n networkControllerState,\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n }),\n selectNetworkControllerFields,\n );\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n (networkEnablementControllerState) =>\n this.#refreshState({\n networkControllerState: this.messenger.call(\n 'NetworkController:getState',\n ),\n networkEnablementControllerState,\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n }),\n selectNetworkEnablementControllerFields,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n (connectivityControllerState) =>\n this.#refreshState({\n networkControllerState: this.messenger.call(\n 'NetworkController:getState',\n ),\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState,\n }),\n selectConnectivityControllerFields,\n );\n /* eslint-enable no-restricted-syntax */\n\n // Lifecycle: evaluate RPC health (and run the banner escalation timers)\n // only while the client UI is open on an unlocked wallet.\n this.messenger.subscribe(\n 'ClientController:stateChanged',\n (isUiOpen) => {\n this.#isUiOpen = isUiOpen;\n this.#updateLifecycle();\n },\n clientControllerSelectors.selectIsUiOpen,\n );\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n this.#updateLifecycle();\n });\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n this.#updateLifecycle();\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n #updateLifecycle(): void {\n if (this.#isUiOpen && this.#isUnlocked) {\n this.#start();\n } else {\n this.#stop();\n }\n }\n\n /**\n * Look for a failed network, if any, and populate the initial state of the\n * banner. Reacts to upstream state changes from this point on. Idempotent.\n */\n #start(): void {\n if (this.#isStarted) {\n return;\n }\n\n this.#isStarted = true;\n this.#refreshState({\n networkControllerState: this.messenger.call('NetworkController:getState'),\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n });\n }\n\n /**\n * Stops evaluating network connection state. Clears any pending banner\n * timers and resets state to `available`. Idempotent.\n */\n #stop(): void {\n if (!this.#isStarted) {\n return;\n }\n\n this.#isStarted = false;\n this.#resetBanner();\n }\n\n /**\n * Clears the banner state such that the banner will be hidden.\n */\n dismissBanner(): void {\n this.#resetBanner();\n }\n\n /**\n * Switches the chain's default RPC endpoint to its Infura endpoint and\n * makes it the active network, causing the banner to clear once the\n * network becomes available again.\n *\n * @param chainId - The chain whose default RPC endpoint should be switched.\n * @throws If the chain configuration cannot be found, or if it has no\n * Infura endpoint to switch to, or if the default is already Infura.\n */\n async switchToDefaultInfuraRpcEndpoint(chainId: Hex): Promise<void> {\n const networkConfiguration = this.messenger.call(\n 'NetworkController:getNetworkConfigurationByChainId',\n chainId,\n );\n if (!networkConfiguration) {\n throw new Error(\n `No network configuration found for chain ID \"${chainId}\".`,\n );\n }\n\n const infuraEndpointIndex = networkConfiguration.rpcEndpoints.findIndex(\n (endpoint) => getIsInfuraEndpoint(endpoint.url, this.#infuraProjectId),\n );\n if (infuraEndpointIndex === -1) {\n throw new Error(\n `No Infura endpoint available for chain ID \"${chainId}\".`,\n );\n }\n if (infuraEndpointIndex === networkConfiguration.defaultRpcEndpointIndex) {\n // The default is already Infura; nothing to do.\n return;\n }\n\n // Move the active connection onto the Infura endpoint first, then make\n // it the default. In this order a partial failure leaves the failing\n // default in place and the banner visible, rather than hiding the banner\n // while the wallet is still connected to the broken endpoint.\n const infuraNetworkClientId =\n networkConfiguration.rpcEndpoints[infuraEndpointIndex].networkClientId;\n const { selectedNetworkClientId } = this.messenger.call(\n 'NetworkController:getState',\n );\n if (infuraNetworkClientId !== selectedNetworkClientId) {\n await this.messenger.call(\n 'NetworkController:setActiveNetwork',\n infuraNetworkClientId,\n );\n }\n\n await this.messenger.call('NetworkController:updateNetwork', chainId, {\n ...networkConfiguration,\n defaultRpcEndpointIndex: infuraEndpointIndex,\n });\n }\n\n #refreshState({\n networkControllerState,\n networkEnablementControllerState,\n connectivityControllerState,\n }: {\n networkControllerState: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >;\n networkEnablementControllerState: Pick<\n NetworkEnablementControllerState,\n 'enabledNetworkMap'\n >;\n connectivityControllerState: Pick<\n ConnectivityControllerState,\n 'connectivityStatus'\n >;\n }): void {\n if (!this.#isStarted) {\n return;\n }\n\n if (\n connectivityControllerState.connectivityStatus ===\n CONNECTIVITY_STATUSES.Offline\n ) {\n this.#resetBanner();\n return;\n }\n\n const failedNetwork = this.#findFailedNetwork(\n networkControllerState,\n networkEnablementControllerState,\n );\n if (!failedNetwork) {\n this.#resetBanner();\n return;\n }\n\n if (\n this.state.networkConnectionBannerStatus !== 'available' &&\n this.state.networkConnectionBannerNetwork?.networkClientId ===\n failedNetwork.networkClientId\n ) {\n this.update((state) => {\n // Even if the network client ID has not changed, save the current\n // version of the failed network to state in case the user has updated\n // its RPC URL.\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n return;\n }\n\n // A degraded timer is already counting down for this same network.\n // Repeated `stateChange` events must not clear and restart it, or a\n // steady stream of updates could postpone the banner indefinitely.\n if (this.#pendingNetworkClientId === failedNetwork.networkClientId) {\n return;\n }\n\n this.#clearTimers();\n this.update((state) => {\n state.networkConnectionBannerStatus = 'available';\n state.networkConnectionBannerNetwork = null;\n });\n\n // If `stop` is called before scheduling timers, bail early.\n if (!this.#isStarted) {\n return;\n }\n\n // Remember which network the pending timer is for (see the guard above)\n // and capture the failing network at schedule time. If the failure\n // resolves or a different network becomes the banner target while we\n // wait, the subscription handlers re-enter this method and cancel or\n // replace the timer before it fires.\n this.#pendingNetworkClientId = failedNetwork.networkClientId;\n this.#degradedTimer = setTimeout(() => {\n this.#degradedTimer = undefined;\n this.#pendingNetworkClientId = undefined;\n this.update((state) => {\n state.networkConnectionBannerStatus = 'degraded';\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n // If `stop` is called before scheduling timers, bail early.\n if (!this.#isStarted) {\n return;\n }\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n this.update((state) => {\n state.networkConnectionBannerStatus = 'unavailable';\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n }, UNAVAILABLE_BANNER_TIMEOUT - DEGRADED_BANNER_TIMEOUT);\n }, DEGRADED_BANNER_TIMEOUT);\n }\n\n /**\n * Clears timers and resets banner state to {@link NetworkConnectionBannerStatus|`available`}\n * if it isn't there already.\n */\n #resetBanner(): void {\n this.#clearTimers();\n this.#pendingNetworkClientId = undefined;\n if (\n this.state.networkConnectionBannerStatus !== 'available' ||\n this.state.networkConnectionBannerNetwork !== null\n ) {\n this.update((state) => {\n state.networkConnectionBannerStatus = 'available';\n state.networkConnectionBannerNetwork = null;\n });\n }\n }\n\n #clearTimers(): void {\n if (this.#degradedTimer !== undefined) {\n clearTimeout(this.#degradedTimer);\n this.#degradedTimer = undefined;\n }\n if (this.#unavailableTimer !== undefined) {\n clearTimeout(this.#unavailableTimer);\n this.#unavailableTimer = undefined;\n }\n }\n\n #findFailedNetwork(\n networkState: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n enablementState: Pick<\n NetworkEnablementControllerState,\n 'enabledNetworkMap'\n >,\n ): FailedNetwork | null {\n const enabledNetworks = this.#collectEnabledNetworks(\n networkState,\n enablementState,\n );\n // Networks whose connectivity has not been looked up yet are not failed.\n const failedNetworks = enabledNetworks\n .filter(\n ({ metadata }) =>\n metadata !== undefined && metadata.status !== NetworkStatus.Available,\n )\n .map((network) => this.#buildFailedNetwork(network));\n return this.#pickFailedNetworkToDisplay(\n failedNetworks,\n enabledNetworks.length,\n );\n }\n\n #getEnabledEvmChainIds(\n enabledNetworkMap: NetworkEnablementControllerState['enabledNetworkMap'],\n ): Hex[] {\n return Object.entries(enabledNetworkMap[KnownCaipNamespace.Eip155] ?? {})\n .filter(([, enabled]) => enabled)\n .map(([chainId]) => chainId as Hex);\n }\n\n #collectEnabledNetworks(\n {\n networkConfigurationsByChainId,\n networksMetadata,\n }: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n {\n enabledNetworkMap,\n }: Pick<NetworkEnablementControllerState, 'enabledNetworkMap'>,\n ): EnabledNetwork[] {\n return this.#getEnabledEvmChainIds(enabledNetworkMap).flatMap((chainId) => {\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n return [];\n }\n const { rpcEndpoints, defaultRpcEndpointIndex, name } =\n networkConfiguration;\n const defaultRpcEndpoint = rpcEndpoints[defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n return [];\n }\n return [\n {\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n metadata: networksMetadata[defaultRpcEndpoint.networkClientId],\n },\n ];\n });\n }\n\n #buildFailedNetwork({\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n }: EnabledNetwork): FailedNetwork {\n const isInfuraEndpoint = getIsInfuraEndpoint(\n defaultRpcEndpoint.url,\n this.#infuraProjectId,\n );\n\n // For custom endpoints (non-Infura), find an Infura endpoint on this\n // chain that we could offer to switch to.\n let switchableInfuraNetworkClientId: string | null = null;\n if (!isInfuraEndpoint) {\n const infuraEndpoint = rpcEndpoints.find(\n (endpoint, index) =>\n index !== defaultRpcEndpointIndex &&\n getIsInfuraEndpoint(endpoint.url, this.#infuraProjectId),\n );\n switchableInfuraNetworkClientId = infuraEndpoint?.networkClientId ?? null;\n }\n\n return {\n chainId,\n networkClientId: defaultRpcEndpoint.networkClientId,\n name,\n rpcUrl: defaultRpcEndpoint.url,\n isInfuraEndpoint,\n switchableInfuraNetworkClientId,\n };\n }\n\n #pickFailedNetworkToDisplay(\n failedNetworks: FailedNetwork[],\n totalEnabledNetworks: number,\n ): FailedNetwork | null {\n if (failedNetworks.length === 0) {\n return null;\n }\n\n const firstCustomFailed = failedNetworks.find(\n (entry) => !entry.isInfuraEndpoint,\n );\n const areAllEnabledNetworksFailed =\n failedNetworks.length === totalEnabledNetworks;\n\n if (!firstCustomFailed && !areAllEnabledNetworksFailed) {\n return null;\n }\n\n return firstCustomFailed ?? failedNetworks[0];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"NetworkConnectionBannerController.mjs","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { clientControllerSelectors } from '@metamask/client-controller';\nimport type { ClientControllerState } from '@metamask/client-controller';\nimport {\n CONNECTIVITY_STATUSES,\n connectivityControllerSelectors,\n} from '@metamask/connectivity-controller';\nimport type {\n ConnectivityControllerGetStateAction,\n ConnectivityControllerState,\n ConnectivityControllerStateChangeEvent,\n} from '@metamask/connectivity-controller';\nimport type {\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkConfiguration,\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\n NetworkControllerSetActiveNetworkAction,\n NetworkControllerStateChangeEvent,\n NetworkMetadata,\n NetworkState,\n} from '@metamask/network-controller';\nimport { NetworkStatus } from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerState,\n NetworkEnablementControllerStateChangeEvent,\n} from '@metamask/network-enablement-controller';\nimport { selectEnabledNetworkMap } from '@metamask/network-enablement-controller';\nimport type { Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\nimport { createSelector } from 'reselect';\n\nimport type { NetworkConnectionBannerControllerMethodActions } from './NetworkConnectionBannerController-method-action-types';\nimport { getIsInfuraEndpoint } from './url-utils';\n\n/**\n * The name of the {@link NetworkConnectionBannerController}, used to namespace\n * the controller's actions and events and to namespace the controller's state\n * data when composed with other controllers.\n */\nconst CONTROLLER_NAME = 'NetworkConnectionBannerController';\n\n/**\n * Selects `networksMetadata` from the `NetworkController` state.\n *\n * @param state - The `NetworkController` state.\n * @returns The networks metadata map keyed by network client id.\n */\nconst selectNetworksMetadata = (\n state: NetworkState,\n): NetworkState['networksMetadata'] => state.networksMetadata;\n\n/**\n * Selects `networkConfigurationsByChainId` from the `NetworkController`\n * state.\n *\n * @param state - The `NetworkController` state.\n * @returns The network configurations keyed by chain id.\n */\nconst selectNetworkConfigurationsByChainId = (\n state: NetworkState,\n): NetworkState['networkConfigurationsByChainId'] =>\n state.networkConfigurationsByChainId;\n\n/**\n * Selects the `NetworkController` state fields that influence the banner\n * rule. Composed with `createSelector` so the return object stays reference\n * stable while unrelated `NetworkController` state (e.g.\n * `selectedNetworkClientId`) changes.\n *\n * @param state - The `NetworkController` state.\n * @returns The relevant network fields.\n */\nconst selectNetworkControllerFields = createSelector(\n [selectNetworksMetadata, selectNetworkConfigurationsByChainId],\n (networksMetadata, networkConfigurationsByChainId) => ({\n networksMetadata,\n networkConfigurationsByChainId,\n }),\n);\n\n/**\n * Selects the `NetworkEnablementController` state field that influences the\n * banner rule.\n *\n * @param state - The `NetworkEnablementController` state.\n * @returns The relevant enablement fields.\n */\nconst selectNetworkEnablementControllerFields = createSelector(\n [selectEnabledNetworkMap],\n (enabledNetworkMap) => ({ enabledNetworkMap }),\n);\n\n/**\n * Selects the `ConnectivityController` state field that influences the\n * banner rule.\n *\n * @param state - The `ConnectivityController` state.\n * @returns The relevant connectivity fields.\n */\nconst selectConnectivityControllerFields = createSelector(\n [connectivityControllerSelectors.selectConnectivityStatus],\n (connectivityStatus) => ({ connectivityStatus }),\n);\n\n/**\n * Status the banner can be in. `available` means no banner is shown; the\n * `degraded` and `unavailable` values mirror the two-tier escalation that the\n * UI renders.\n */\nexport type NetworkConnectionBannerStatus =\n | 'available'\n | 'degraded'\n | 'unavailable';\n\n/**\n * An enabled network from `NetworkController` state with a default RPC\n * endpoint. Used as the input to the failed-network detection pipeline.\n * `metadata` is missing until the network's connectivity has been looked up.\n */\ntype EnabledNetwork = {\n chainId: Hex;\n name: string;\n rpcEndpoints: NetworkConfiguration['rpcEndpoints'];\n defaultRpcEndpointIndex: number;\n defaultRpcEndpoint: NetworkConfiguration['rpcEndpoints'][number];\n metadata: NetworkMetadata | undefined;\n};\n\n/**\n * Details of a failing network the banner describes.\n */\nexport type FailedNetwork = {\n /** The chain id of the failing network. */\n chainId: Hex;\n /** The `networkClientId` of the failing default RPC endpoint. */\n networkClientId: string;\n /** The display name for the failing network. */\n name: string;\n /** The URL of the failing default RPC endpoint. */\n rpcUrl: string;\n /** Whether the failing endpoint is a MetaMask Infura endpoint. */\n isInfuraEndpoint: boolean;\n /**\n * The networkClientId of an Infura endpoint on the same chain that the user\n * can switch to. `null` when the failing endpoint is already Infura or when\n * no Infura alternative exists.\n */\n switchableInfuraNetworkClientId: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n *\n * The keys carry the controller-domain prefix (like\n * `ConnectivityController`'s `connectivityStatus`) because some clients merge\n * all controller states into one flat object, where generic names like\n * `status` collide across controllers.\n */\nexport type NetworkConnectionBannerControllerState = {\n networkConnectionBannerStatus: NetworkConnectionBannerStatus;\n networkConnectionBannerNetwork: FailedNetwork | null;\n};\n\nconst networkConnectionBannerControllerMetadata = {\n networkConnectionBannerStatus: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n networkConnectionBannerNetwork: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n} satisfies StateMetadata<NetworkConnectionBannerControllerState>;\n\n/**\n * Constructs the default {@link NetworkConnectionBannerController} state.\n *\n * @returns The default state.\n */\nexport function getDefaultNetworkConnectionBannerControllerState(): NetworkConnectionBannerControllerState {\n return {\n networkConnectionBannerStatus: 'available',\n networkConnectionBannerNetwork: null,\n };\n}\n\n/**\n * The default for how long (in milliseconds) a failing network must remain\n * in a \"failed\" status (\"degraded\" or \"unavailable\") before the degraded\n * banner appears.\n */\nexport const DEFAULT_DEGRADED_BANNER_TIMEOUT = 5_000;\n\n/**\n * The default for how long (in milliseconds) a failing network must remain\n * in a \"failed\" status before the banner escalates to \"unavailable\".\n */\nexport const DEFAULT_UNAVAILABLE_BANNER_TIMEOUT = 30_000;\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'dismissBanner',\n 'switchToDefaultInfuraRpcEndpoint',\n] as const;\n\n/**\n * Retrieves the state of the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerGetStateAction =\n ControllerGetStateAction<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState\n >;\n\n/**\n * Actions that {@link NetworkConnectionBannerControllerMessenger} exposes to\n * other consumers.\n */\nexport type NetworkConnectionBannerControllerActions =\n | NetworkConnectionBannerControllerGetStateAction\n | NetworkConnectionBannerControllerMethodActions;\n\n/**\n * Actions from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} calls.\n */\ntype AllowedActions =\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkConfigurationByChainIdAction\n | NetworkControllerUpdateNetworkAction\n | NetworkControllerSetActiveNetworkAction\n | NetworkEnablementControllerGetStateAction\n | ConnectivityControllerGetStateAction;\n\n/**\n * Published when the state of {@link NetworkConnectionBannerController}\n * changes.\n */\nexport type NetworkConnectionBannerControllerStateChangedEvent =\n ControllerStateChangedEvent<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState\n >;\n\n/**\n * Events that {@link NetworkConnectionBannerControllerMessenger} exposes to\n * other consumers.\n */\nexport type NetworkConnectionBannerControllerEvents =\n NetworkConnectionBannerControllerStateChangedEvent;\n\n/**\n * Published when the state of `ClientController` changes. Defined here\n * because the `client-controller` package still exports the legacy\n * `:stateChange` event type.\n */\ntype ClientControllerStateChangedEvent = ControllerStateChangedEvent<\n 'ClientController',\n ClientControllerState\n>;\n\n/**\n * Events from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} subscribes to.\n */\ntype AllowedEvents =\n | NetworkControllerStateChangeEvent\n | NetworkEnablementControllerStateChangeEvent\n | ConnectivityControllerStateChangeEvent\n | ClientControllerStateChangedEvent\n | KeyringControllerUnlockEvent\n | KeyringControllerLockEvent;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerMessenger = Messenger<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerActions | AllowedActions,\n NetworkConnectionBannerControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerOptions = {\n /**\n * The messenger for inter-controller communication.\n */\n messenger: NetworkConnectionBannerControllerMessenger;\n\n /**\n * The wallet's Infura project id, used to recognize MetaMask Infura\n * endpoints whose URL was persisted with the id already substituted.\n */\n infuraProjectId: string;\n\n /**\n * How long (in milliseconds) a failing network must remain in a \"failed\"\n * status before the degraded banner appears. Defaults to\n * {@link DEFAULT_DEGRADED_BANNER_TIMEOUT}.\n */\n degradedBannerTimeout?: number;\n\n /**\n * How long (in milliseconds), measured from the same failure start as\n * `degradedBannerTimeout`, before the banner escalates to \"unavailable\".\n * Must be greater than `degradedBannerTimeout`. Defaults to\n * {@link DEFAULT_UNAVAILABLE_BANNER_TIMEOUT}.\n */\n unavailableBannerTimeout?: number;\n};\n\n/**\n * Drives the \"network connection banner\", a notice that appears within clients\n * whose goal is to inform users about networks which have exhibited repeated\n * request failures and offer potential workarounds.\n *\n * Some terminology: A \"network\" in this case is an RPC endpoint, and a network\n * that has exhibited repeated request failures has entered a \"failed\" state (or\n * is a \"failed network\").\n *\n * For simplicity, the banner always represents a single failed network. If\n * multiple networks are failing, the first custom network takes priority over\n * the first Infura network.\n *\n * To ensure that the banner is actionable, the banner does not always appear\n * even if there is a failed network to display. Instead it appears under these\n * conditions:\n *\n * - The failed network is a custom (non-Infura) endpoint (we want to inform\n * users about endpoints they've added so they don't cast blame on MetaMask).\n * - Every enabled EVM network has entered a failed state (this indicates a\n * broad connectivity issue).\n *\n * Assuming that these conditions have been met, there are two variants of the\n * banner which will be displayed at different times.\n *\n * - A \"degraded\" variant which will appear when 5 seconds has elapsed and there\n * is an eligible failed network to display\n * - An \"unavailable\" variant which will appear when 30 seconds have elapsed and\n * there is an eligible failed network to display\n *\n * Finally, the controller contains actions that drive interactions with the\n * banner. Namely, if the banner represents a custom network, then it will offer\n * the user a way to switch to the default Infura network. The controller\n * contains the logic to carry out that action.\n */\nexport class NetworkConnectionBannerController extends BaseController<\n typeof CONTROLLER_NAME,\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerMessenger\n> {\n #degradedTimer: ReturnType<typeof setTimeout> | undefined;\n\n #unavailableTimer: ReturnType<typeof setTimeout> | undefined;\n\n #pendingNetworkClientId: string | undefined;\n\n #isStarted = false;\n\n /** Whether the client UI is open. Combined with {@link #isUnlocked}. */\n #isUiOpen = false;\n\n /** Whether the keyring is unlocked. Combined with {@link #isUiOpen}. */\n #isUnlocked = false;\n\n readonly #infuraProjectId: string;\n\n readonly #degradedBannerTimeout: number;\n\n readonly #unavailableBannerTimeout: number;\n\n /**\n * Constructs a new {@link NetworkConnectionBannerController}.\n *\n * @param args - The arguments to this controller.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.infuraProjectId - The wallet's Infura project id.\n * @param args.degradedBannerTimeout - How long (in milliseconds) a failing\n * network must remain failed before the degraded banner appears.\n * @param args.unavailableBannerTimeout - How long (in milliseconds) before\n * the banner escalates to \"unavailable\". Must be greater than\n * `degradedBannerTimeout`.\n * @throws If `unavailableBannerTimeout` is not greater than\n * `degradedBannerTimeout`.\n */\n constructor({\n messenger,\n infuraProjectId,\n degradedBannerTimeout = DEFAULT_DEGRADED_BANNER_TIMEOUT,\n unavailableBannerTimeout = DEFAULT_UNAVAILABLE_BANNER_TIMEOUT,\n }: NetworkConnectionBannerControllerOptions) {\n super({\n messenger,\n metadata: networkConnectionBannerControllerMetadata,\n name: CONTROLLER_NAME,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\n\n if (unavailableBannerTimeout <= degradedBannerTimeout) {\n throw new Error(\n `\\`unavailableBannerTimeout\\` (${unavailableBannerTimeout}) must be greater than \\`degradedBannerTimeout\\` (${degradedBannerTimeout}).`,\n );\n }\n\n this.#infuraProjectId = infuraProjectId;\n this.#degradedBannerTimeout = degradedBannerTimeout;\n this.#unavailableBannerTimeout = unavailableBannerTimeout;\n\n // Upstream controllers still expose :stateChange; switch to :stateChanged\n // once those packages migrate their event types.\n /* eslint-disable no-restricted-syntax -- awaiting upstream :stateChanged migration */\n this.messenger.subscribe(\n 'NetworkController:stateChange',\n (networkControllerState) =>\n this.#refreshState({\n networkControllerState,\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n }),\n selectNetworkControllerFields,\n );\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n (networkEnablementControllerState) =>\n this.#refreshState({\n networkControllerState: this.messenger.call(\n 'NetworkController:getState',\n ),\n networkEnablementControllerState,\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n }),\n selectNetworkEnablementControllerFields,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n (connectivityControllerState) =>\n this.#refreshState({\n networkControllerState: this.messenger.call(\n 'NetworkController:getState',\n ),\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState,\n }),\n selectConnectivityControllerFields,\n );\n /* eslint-enable no-restricted-syntax */\n\n // Lifecycle: evaluate RPC health (and run the banner escalation timers)\n // only while the client UI is open on an unlocked wallet.\n this.messenger.subscribe(\n 'ClientController:stateChanged',\n (isUiOpen) => {\n this.#isUiOpen = isUiOpen;\n this.#updateLifecycle();\n },\n clientControllerSelectors.selectIsUiOpen,\n );\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n this.#updateLifecycle();\n });\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n this.#updateLifecycle();\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n #updateLifecycle(): void {\n if (this.#isUiOpen && this.#isUnlocked) {\n this.#start();\n } else {\n this.#stop();\n }\n }\n\n /**\n * Look for a failed network, if any, and populate the initial state of the\n * banner. Reacts to upstream state changes from this point on. Idempotent.\n */\n #start(): void {\n if (this.#isStarted) {\n return;\n }\n\n this.#isStarted = true;\n this.#refreshState({\n networkControllerState: this.messenger.call('NetworkController:getState'),\n networkEnablementControllerState: this.messenger.call(\n 'NetworkEnablementController:getState',\n ),\n connectivityControllerState: this.messenger.call(\n 'ConnectivityController:getState',\n ),\n });\n }\n\n /**\n * Stops evaluating network connection state. Clears any pending banner\n * timers and resets state to `available`. Idempotent.\n */\n #stop(): void {\n if (!this.#isStarted) {\n return;\n }\n\n this.#isStarted = false;\n this.#resetBanner();\n }\n\n /**\n * Clears the banner state such that the banner will be hidden.\n */\n dismissBanner(): void {\n this.#resetBanner();\n }\n\n /**\n * Switches the chain's default RPC endpoint to its Infura endpoint and\n * makes it the active network, causing the banner to clear once the\n * network becomes available again.\n *\n * @param chainId - The chain whose default RPC endpoint should be switched.\n * @throws If the chain configuration cannot be found, or if it has no\n * Infura endpoint to switch to, or if the default is already Infura.\n */\n async switchToDefaultInfuraRpcEndpoint(chainId: Hex): Promise<void> {\n const networkConfiguration = this.messenger.call(\n 'NetworkController:getNetworkConfigurationByChainId',\n chainId,\n );\n if (!networkConfiguration) {\n throw new Error(\n `No network configuration found for chain ID \"${chainId}\".`,\n );\n }\n\n const infuraEndpointIndex = networkConfiguration.rpcEndpoints.findIndex(\n (endpoint) => getIsInfuraEndpoint(endpoint.url, this.#infuraProjectId),\n );\n if (infuraEndpointIndex === -1) {\n throw new Error(\n `No Infura endpoint available for chain ID \"${chainId}\".`,\n );\n }\n if (infuraEndpointIndex === networkConfiguration.defaultRpcEndpointIndex) {\n // The default is already Infura; nothing to do.\n return;\n }\n\n // Move the active connection onto the Infura endpoint first, then make\n // it the default. In this order a partial failure leaves the failing\n // default in place and the banner visible, rather than hiding the banner\n // while the wallet is still connected to the broken endpoint.\n const infuraNetworkClientId =\n networkConfiguration.rpcEndpoints[infuraEndpointIndex].networkClientId;\n const { selectedNetworkClientId } = this.messenger.call(\n 'NetworkController:getState',\n );\n if (infuraNetworkClientId !== selectedNetworkClientId) {\n await this.messenger.call(\n 'NetworkController:setActiveNetwork',\n infuraNetworkClientId,\n );\n }\n\n await this.messenger.call('NetworkController:updateNetwork', chainId, {\n ...networkConfiguration,\n defaultRpcEndpointIndex: infuraEndpointIndex,\n });\n }\n\n #refreshState({\n networkControllerState,\n networkEnablementControllerState,\n connectivityControllerState,\n }: {\n networkControllerState: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >;\n networkEnablementControllerState: Pick<\n NetworkEnablementControllerState,\n 'enabledNetworkMap'\n >;\n connectivityControllerState: Pick<\n ConnectivityControllerState,\n 'connectivityStatus'\n >;\n }): void {\n if (!this.#isStarted) {\n return;\n }\n\n if (\n connectivityControllerState.connectivityStatus ===\n CONNECTIVITY_STATUSES.Offline\n ) {\n this.#resetBanner();\n return;\n }\n\n const failedNetwork = this.#findFailedNetwork(\n networkControllerState,\n networkEnablementControllerState,\n );\n if (!failedNetwork) {\n this.#resetBanner();\n return;\n }\n\n if (\n this.state.networkConnectionBannerStatus !== 'available' &&\n this.state.networkConnectionBannerNetwork?.networkClientId ===\n failedNetwork.networkClientId\n ) {\n this.update((state) => {\n // Even if the network client ID has not changed, save the current\n // version of the failed network to state in case the user has updated\n // its RPC URL.\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n return;\n }\n\n // A degraded timer is already counting down for this same network.\n // Repeated `stateChange` events must not clear and restart it, or a\n // steady stream of updates could postpone the banner indefinitely.\n if (this.#pendingNetworkClientId === failedNetwork.networkClientId) {\n return;\n }\n\n this.#clearTimers();\n this.update((state) => {\n state.networkConnectionBannerStatus = 'available';\n state.networkConnectionBannerNetwork = null;\n });\n\n // If `stop` is called before scheduling timers, bail early.\n if (!this.#isStarted) {\n return;\n }\n\n // Remember which network the pending timer is for (see the guard above)\n // and capture the failing network at schedule time. If the failure\n // resolves or a different network becomes the banner target while we\n // wait, the subscription handlers re-enter this method and cancel or\n // replace the timer before it fires.\n this.#pendingNetworkClientId = failedNetwork.networkClientId;\n this.#degradedTimer = setTimeout(() => {\n this.#degradedTimer = undefined;\n this.#pendingNetworkClientId = undefined;\n this.update((state) => {\n state.networkConnectionBannerStatus = 'degraded';\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n // If `stop` is called before scheduling timers, bail early.\n if (!this.#isStarted) {\n return;\n }\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n this.update((state) => {\n state.networkConnectionBannerStatus = 'unavailable';\n state.networkConnectionBannerNetwork = failedNetwork;\n });\n }, this.#unavailableBannerTimeout - this.#degradedBannerTimeout);\n }, this.#degradedBannerTimeout);\n }\n\n /**\n * Clears timers and resets banner state to {@link NetworkConnectionBannerStatus|`available`}\n * if it isn't there already.\n */\n #resetBanner(): void {\n this.#clearTimers();\n this.#pendingNetworkClientId = undefined;\n if (\n this.state.networkConnectionBannerStatus !== 'available' ||\n this.state.networkConnectionBannerNetwork !== null\n ) {\n this.update((state) => {\n state.networkConnectionBannerStatus = 'available';\n state.networkConnectionBannerNetwork = null;\n });\n }\n }\n\n #clearTimers(): void {\n if (this.#degradedTimer !== undefined) {\n clearTimeout(this.#degradedTimer);\n this.#degradedTimer = undefined;\n }\n if (this.#unavailableTimer !== undefined) {\n clearTimeout(this.#unavailableTimer);\n this.#unavailableTimer = undefined;\n }\n }\n\n #findFailedNetwork(\n networkState: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n enablementState: Pick<\n NetworkEnablementControllerState,\n 'enabledNetworkMap'\n >,\n ): FailedNetwork | null {\n const enabledNetworks = this.#collectEnabledNetworks(\n networkState,\n enablementState,\n );\n // Networks whose connectivity has not been looked up yet are not failed.\n const failedNetworks = enabledNetworks\n .filter(\n ({ metadata }) =>\n metadata !== undefined && metadata.status !== NetworkStatus.Available,\n )\n .map((network) => this.#buildFailedNetwork(network));\n return this.#pickFailedNetworkToDisplay(\n failedNetworks,\n enabledNetworks.length,\n );\n }\n\n #getEnabledEvmChainIds(\n enabledNetworkMap: NetworkEnablementControllerState['enabledNetworkMap'],\n ): Hex[] {\n return Object.entries(enabledNetworkMap[KnownCaipNamespace.Eip155] ?? {})\n .filter(([, enabled]) => enabled)\n .map(([chainId]) => chainId as Hex);\n }\n\n #collectEnabledNetworks(\n {\n networkConfigurationsByChainId,\n networksMetadata,\n }: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n {\n enabledNetworkMap,\n }: Pick<NetworkEnablementControllerState, 'enabledNetworkMap'>,\n ): EnabledNetwork[] {\n return this.#getEnabledEvmChainIds(enabledNetworkMap).flatMap((chainId) => {\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n return [];\n }\n const { rpcEndpoints, defaultRpcEndpointIndex, name } =\n networkConfiguration;\n const defaultRpcEndpoint = rpcEndpoints[defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n return [];\n }\n return [\n {\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n metadata: networksMetadata[defaultRpcEndpoint.networkClientId],\n },\n ];\n });\n }\n\n #buildFailedNetwork({\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n }: EnabledNetwork): FailedNetwork {\n const isInfuraEndpoint = getIsInfuraEndpoint(\n defaultRpcEndpoint.url,\n this.#infuraProjectId,\n );\n\n // For custom endpoints (non-Infura), find an Infura endpoint on this\n // chain that we could offer to switch to.\n let switchableInfuraNetworkClientId: string | null = null;\n if (!isInfuraEndpoint) {\n const infuraEndpoint = rpcEndpoints.find(\n (endpoint, index) =>\n index !== defaultRpcEndpointIndex &&\n getIsInfuraEndpoint(endpoint.url, this.#infuraProjectId),\n );\n switchableInfuraNetworkClientId = infuraEndpoint?.networkClientId ?? null;\n }\n\n return {\n chainId,\n networkClientId: defaultRpcEndpoint.networkClientId,\n name,\n rpcUrl: defaultRpcEndpoint.url,\n isInfuraEndpoint,\n switchableInfuraNetworkClientId,\n };\n }\n\n #pickFailedNetworkToDisplay(\n failedNetworks: FailedNetwork[],\n totalEnabledNetworks: number,\n ): FailedNetwork | null {\n if (failedNetworks.length === 0) {\n return null;\n }\n\n const firstCustomFailed = failedNetworks.find(\n (entry) => !entry.isInfuraEndpoint,\n );\n const areAllEnabledNetworksFailed =\n failedNetworks.length === totalEnabledNetworks;\n\n if (!firstCustomFailed && !areAllEnabledNetworksFailed) {\n return null;\n }\n\n return firstCustomFailed ?? failedNetworks[0];\n }\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.networkConnectionBannerControllerSelectors = exports.getDefaultNetworkConnectionBannerControllerState = exports.NetworkConnectionBannerController = void 0;
|
|
3
|
+
exports.networkConnectionBannerControllerSelectors = exports.DEFAULT_UNAVAILABLE_BANNER_TIMEOUT = exports.DEFAULT_DEGRADED_BANNER_TIMEOUT = exports.getDefaultNetworkConnectionBannerControllerState = exports.NetworkConnectionBannerController = void 0;
|
|
4
4
|
var NetworkConnectionBannerController_1 = require("./NetworkConnectionBannerController.cjs");
|
|
5
5
|
Object.defineProperty(exports, "NetworkConnectionBannerController", { enumerable: true, get: function () { return NetworkConnectionBannerController_1.NetworkConnectionBannerController; } });
|
|
6
6
|
Object.defineProperty(exports, "getDefaultNetworkConnectionBannerControllerState", { enumerable: true, get: function () { return NetworkConnectionBannerController_1.getDefaultNetworkConnectionBannerControllerState; } });
|
|
7
|
+
Object.defineProperty(exports, "DEFAULT_DEGRADED_BANNER_TIMEOUT", { enumerable: true, get: function () { return NetworkConnectionBannerController_1.DEFAULT_DEGRADED_BANNER_TIMEOUT; } });
|
|
8
|
+
Object.defineProperty(exports, "DEFAULT_UNAVAILABLE_BANNER_TIMEOUT", { enumerable: true, get: function () { return NetworkConnectionBannerController_1.DEFAULT_UNAVAILABLE_BANNER_TIMEOUT; } });
|
|
7
9
|
var selectors_1 = require("./selectors.cjs");
|
|
8
10
|
Object.defineProperty(exports, "networkConnectionBannerControllerSelectors", { enumerable: true, get: function () { return selectors_1.networkConnectionBannerControllerSelectors; } });
|
|
9
11
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAeA,
|
|
1
|
+
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAeA,6FAK6C;AAJ3C,sJAAA,iCAAiC,OAAA;AACjC,qKAAA,gDAAgD,OAAA;AAChD,oJAAA,+BAA+B,OAAA;AAC/B,uJAAA,kCAAkC,OAAA;AAEpC,6CAAyE;AAAhE,uIAAA,0CAA0C,OAAA","sourcesContent":["export type {\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerGetStateAction,\n NetworkConnectionBannerControllerActions,\n NetworkConnectionBannerControllerStateChangedEvent,\n NetworkConnectionBannerControllerEvents,\n NetworkConnectionBannerControllerMessenger,\n NetworkConnectionBannerControllerOptions,\n FailedNetwork,\n NetworkConnectionBannerStatus,\n} from './NetworkConnectionBannerController';\nexport type {\n NetworkConnectionBannerControllerDismissBannerAction,\n NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcEndpointAction,\n} from './NetworkConnectionBannerController-method-action-types';\nexport {\n NetworkConnectionBannerController,\n getDefaultNetworkConnectionBannerControllerState,\n DEFAULT_DEGRADED_BANNER_TIMEOUT,\n DEFAULT_UNAVAILABLE_BANNER_TIMEOUT,\n} from './NetworkConnectionBannerController';\nexport { networkConnectionBannerControllerSelectors } from './selectors';\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { NetworkConnectionBannerControllerState, NetworkConnectionBannerControllerGetStateAction, NetworkConnectionBannerControllerActions, NetworkConnectionBannerControllerStateChangedEvent, NetworkConnectionBannerControllerEvents, NetworkConnectionBannerControllerMessenger, NetworkConnectionBannerControllerOptions, FailedNetwork, NetworkConnectionBannerStatus, } from "./NetworkConnectionBannerController.cjs";
|
|
2
2
|
export type { NetworkConnectionBannerControllerDismissBannerAction, NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcEndpointAction, } from "./NetworkConnectionBannerController-method-action-types.cjs";
|
|
3
|
-
export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState, } from "./NetworkConnectionBannerController.cjs";
|
|
3
|
+
export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState, DEFAULT_DEGRADED_BANNER_TIMEOUT, DEFAULT_UNAVAILABLE_BANNER_TIMEOUT, } from "./NetworkConnectionBannerController.cjs";
|
|
4
4
|
export { networkConnectionBannerControllerSelectors } from "./selectors.cjs";
|
|
5
5
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sCAAsC,EACtC,+CAA+C,EAC/C,wCAAwC,EACxC,kDAAkD,EAClD,uCAAuC,EACvC,0CAA0C,EAC1C,wCAAwC,EACxC,aAAa,EACb,6BAA6B,GAC9B,gDAA4C;AAC7C,YAAY,EACV,oDAAoD,EACpD,uEAAuE,GACxE,oEAAgE;AACjE,OAAO,EACL,iCAAiC,EACjC,gDAAgD,
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sCAAsC,EACtC,+CAA+C,EAC/C,wCAAwC,EACxC,kDAAkD,EAClD,uCAAuC,EACvC,0CAA0C,EAC1C,wCAAwC,EACxC,aAAa,EACb,6BAA6B,GAC9B,gDAA4C;AAC7C,YAAY,EACV,oDAAoD,EACpD,uEAAuE,GACxE,oEAAgE;AACjE,OAAO,EACL,iCAAiC,EACjC,gDAAgD,EAChD,+BAA+B,EAC/B,kCAAkC,GACnC,gDAA4C;AAC7C,OAAO,EAAE,0CAA0C,EAAE,wBAAoB"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { NetworkConnectionBannerControllerState, NetworkConnectionBannerControllerGetStateAction, NetworkConnectionBannerControllerActions, NetworkConnectionBannerControllerStateChangedEvent, NetworkConnectionBannerControllerEvents, NetworkConnectionBannerControllerMessenger, NetworkConnectionBannerControllerOptions, FailedNetwork, NetworkConnectionBannerStatus, } from "./NetworkConnectionBannerController.mjs";
|
|
2
2
|
export type { NetworkConnectionBannerControllerDismissBannerAction, NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcEndpointAction, } from "./NetworkConnectionBannerController-method-action-types.mjs";
|
|
3
|
-
export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState, } from "./NetworkConnectionBannerController.mjs";
|
|
3
|
+
export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState, DEFAULT_DEGRADED_BANNER_TIMEOUT, DEFAULT_UNAVAILABLE_BANNER_TIMEOUT, } from "./NetworkConnectionBannerController.mjs";
|
|
4
4
|
export { networkConnectionBannerControllerSelectors } from "./selectors.mjs";
|
|
5
5
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sCAAsC,EACtC,+CAA+C,EAC/C,wCAAwC,EACxC,kDAAkD,EAClD,uCAAuC,EACvC,0CAA0C,EAC1C,wCAAwC,EACxC,aAAa,EACb,6BAA6B,GAC9B,gDAA4C;AAC7C,YAAY,EACV,oDAAoD,EACpD,uEAAuE,GACxE,oEAAgE;AACjE,OAAO,EACL,iCAAiC,EACjC,gDAAgD,
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sCAAsC,EACtC,+CAA+C,EAC/C,wCAAwC,EACxC,kDAAkD,EAClD,uCAAuC,EACvC,0CAA0C,EAC1C,wCAAwC,EACxC,aAAa,EACb,6BAA6B,GAC9B,gDAA4C;AAC7C,YAAY,EACV,oDAAoD,EACpD,uEAAuE,GACxE,oEAAgE;AACjE,OAAO,EACL,iCAAiC,EACjC,gDAAgD,EAChD,+BAA+B,EAC/B,kCAAkC,GACnC,gDAA4C;AAC7C,OAAO,EAAE,0CAA0C,EAAE,wBAAoB"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState } from "./NetworkConnectionBannerController.mjs";
|
|
1
|
+
export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState, DEFAULT_DEGRADED_BANNER_TIMEOUT, DEFAULT_UNAVAILABLE_BANNER_TIMEOUT } from "./NetworkConnectionBannerController.mjs";
|
|
2
2
|
export { networkConnectionBannerControllerSelectors } from "./selectors.mjs";
|
|
3
3
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,iCAAiC,EACjC,gDAAgD,
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,iCAAiC,EACjC,gDAAgD,EAChD,+BAA+B,EAC/B,kCAAkC,EACnC,gDAA4C;AAC7C,OAAO,EAAE,0CAA0C,EAAE,wBAAoB","sourcesContent":["export type {\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerGetStateAction,\n NetworkConnectionBannerControllerActions,\n NetworkConnectionBannerControllerStateChangedEvent,\n NetworkConnectionBannerControllerEvents,\n NetworkConnectionBannerControllerMessenger,\n NetworkConnectionBannerControllerOptions,\n FailedNetwork,\n NetworkConnectionBannerStatus,\n} from './NetworkConnectionBannerController';\nexport type {\n NetworkConnectionBannerControllerDismissBannerAction,\n NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcEndpointAction,\n} from './NetworkConnectionBannerController-method-action-types';\nexport {\n NetworkConnectionBannerController,\n getDefaultNetworkConnectionBannerControllerState,\n DEFAULT_DEGRADED_BANNER_TIMEOUT,\n DEFAULT_UNAVAILABLE_BANNER_TIMEOUT,\n} from './NetworkConnectionBannerController';\nexport { networkConnectionBannerControllerSelectors } from './selectors';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/network-connection-banner-controller",
|
|
3
|
-
"version": "0.1.0-preview-
|
|
3
|
+
"version": "0.1.0-preview-14c30de",
|
|
4
4
|
"description": "Decides when and how to surface the network connection banner based on RPC endpoint health",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@metamask/base-controller": "^9.1.0",
|
|
57
57
|
"@metamask/client-controller": "^1.0.1",
|
|
58
|
-
"@metamask/connectivity-controller": "^0.
|
|
58
|
+
"@metamask/connectivity-controller": "^0.3.0",
|
|
59
59
|
"@metamask/keyring-controller": "^27.1.0",
|
|
60
60
|
"@metamask/messenger": "^2.0.0",
|
|
61
61
|
"@metamask/network-controller": "^34.0.0",
|