@metamask-previews/network-connection-banner-controller 0.1.0-preview-022b2ce8d → 0.1.0-preview-68794c0ff
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/README.md +2 -3
- package/dist/NetworkConnectionBannerController.cjs +75 -69
- package/dist/NetworkConnectionBannerController.cjs.map +1 -1
- package/dist/NetworkConnectionBannerController.d.cts +16 -19
- package/dist/NetworkConnectionBannerController.d.cts.map +1 -1
- package/dist/NetworkConnectionBannerController.d.mts +16 -19
- package/dist/NetworkConnectionBannerController.d.mts.map +1 -1
- package/dist/NetworkConnectionBannerController.mjs +76 -70
- package/dist/NetworkConnectionBannerController.mjs.map +1 -1
- package/dist/selectors.cjs +2 -2
- package/dist/selectors.cjs.map +1 -1
- package/dist/selectors.mjs +2 -2
- package/dist/selectors.mjs.map +1 -1
- package/dist/url-utils.cjs +1 -52
- package/dist/url-utils.cjs.map +1 -1
- package/dist/url-utils.d.cts +0 -23
- package/dist/url-utils.d.cts.map +1 -1
- package/dist/url-utils.d.mts +0 -23
- package/dist/url-utils.d.mts.map +1 -1
- package/dist/url-utils.mjs +0 -53
- package/dist/url-utils.mjs.map +1 -1
- package/package.json +2 -4
package/README.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# `@metamask/network-connection-banner-controller`
|
|
2
2
|
|
|
3
3
|
NetworkConnectionBannerController decides when and how to surface the network
|
|
4
|
-
connection banner based on RPC endpoint health. It encapsulates the rule
|
|
5
|
-
5s/30s timer state machine
|
|
6
|
-
wider provider outage is in play.
|
|
4
|
+
connection banner based on RPC endpoint health. It encapsulates the rule and
|
|
5
|
+
the 5s/30s timer state machine.
|
|
7
6
|
|
|
8
7
|
## Lifecycle
|
|
9
8
|
|
|
@@ -10,7 +10,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
11
11
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
12
|
};
|
|
13
|
-
var _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_pendingNetworkClientId, _NetworkConnectionBannerController_isStarted, _NetworkConnectionBannerController_refreshState, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetwork, _NetworkConnectionBannerController_getEnabledEvmChainIds,
|
|
13
|
+
var _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_pendingNetworkClientId, _NetworkConnectionBannerController_isStarted, _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
15
|
exports.NetworkConnectionBannerController = exports.getDefaultNetworkConnectionBannerControllerState = void 0;
|
|
16
16
|
const base_controller_1 = require("@metamask/base-controller");
|
|
@@ -71,13 +71,13 @@ const selectNetworkEnablementControllerFields = (0, reselect_1.createSelector)([
|
|
|
71
71
|
*/
|
|
72
72
|
const selectConnectivityControllerFields = (0, reselect_1.createSelector)([connectivity_controller_1.connectivityControllerSelectors.selectConnectivityStatus], (connectivityStatus) => ({ connectivityStatus }));
|
|
73
73
|
const networkConnectionBannerControllerMetadata = {
|
|
74
|
-
|
|
74
|
+
networkConnectionBannerStatus: {
|
|
75
75
|
persist: false,
|
|
76
76
|
includeInDebugSnapshot: true,
|
|
77
77
|
includeInStateLogs: true,
|
|
78
78
|
usedInUi: true,
|
|
79
79
|
},
|
|
80
|
-
|
|
80
|
+
networkConnectionBannerNetwork: {
|
|
81
81
|
persist: false,
|
|
82
82
|
includeInDebugSnapshot: true,
|
|
83
83
|
includeInStateLogs: true,
|
|
@@ -91,8 +91,8 @@ const networkConnectionBannerControllerMetadata = {
|
|
|
91
91
|
*/
|
|
92
92
|
function getDefaultNetworkConnectionBannerControllerState() {
|
|
93
93
|
return {
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
networkConnectionBannerStatus: 'available',
|
|
95
|
+
networkConnectionBannerNetwork: null,
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
98
|
exports.getDefaultNetworkConnectionBannerControllerState = getDefaultNetworkConnectionBannerControllerState;
|
|
@@ -115,22 +115,19 @@ const MESSENGER_EXPOSED_METHODS = [
|
|
|
115
115
|
/**
|
|
116
116
|
* NetworkConnectionBannerController decides whether the network connection
|
|
117
117
|
* banner should be shown for the user, and which failing network it should
|
|
118
|
-
* describe. It encapsulates the rule
|
|
119
|
-
* eTLD+1 grouping used to decide when a wider provider outage is in play.
|
|
118
|
+
* describe. It encapsulates the rule and the 5s / 30s timer escalation.
|
|
120
119
|
*
|
|
121
120
|
* The banner shows when:
|
|
122
121
|
*
|
|
123
|
-
* -
|
|
124
|
-
*
|
|
125
|
-
* -
|
|
126
|
-
*
|
|
127
|
-
* (escape hatch for single-network setups so they still get a signal).
|
|
122
|
+
* - A failing network's default RPC is a custom (non-Infura) endpoint —
|
|
123
|
+
* users always want to be informed about errors with RPCs they've chosen.
|
|
124
|
+
* - Every enabled EVM network is reporting a failed connectivity status
|
|
125
|
+
* (escape hatch so Infura-only setups still get a signal).
|
|
128
126
|
*
|
|
129
|
-
* A
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* can act on.
|
|
127
|
+
* A partial Infura outage alongside healthy peers is suppressed since it
|
|
128
|
+
* usually resolves on its own and the user cannot act on it. When a custom
|
|
129
|
+
* failure is present, it's surfaced first so the "Switch to MetaMask default
|
|
130
|
+
* RPC" CTA targets the network the user can act on.
|
|
134
131
|
*
|
|
135
132
|
* Clients only need to render the banner from the controller's state and wire
|
|
136
133
|
* click handlers to {@link dismissBanner} or {@link switchToDefaultInfuraRpcEndpoint}.
|
|
@@ -157,9 +154,21 @@ class NetworkConnectionBannerController extends base_controller_1.BaseController
|
|
|
157
154
|
// Upstream controllers still expose :stateChange; switch to :stateChanged
|
|
158
155
|
// once those packages migrate their event types.
|
|
159
156
|
/* eslint-disable no-restricted-syntax -- awaiting upstream :stateChanged migration */
|
|
160
|
-
this.messenger.subscribe('NetworkController:stateChange', (networkControllerState) => __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_refreshState).call(this, {
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
this.messenger.subscribe('NetworkController:stateChange', (networkControllerState) => __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_refreshState).call(this, {
|
|
158
|
+
networkControllerState,
|
|
159
|
+
networkEnablementControllerState: this.messenger.call('NetworkEnablementController:getState'),
|
|
160
|
+
connectivityControllerState: this.messenger.call('ConnectivityController:getState'),
|
|
161
|
+
}), selectNetworkControllerFields);
|
|
162
|
+
this.messenger.subscribe('NetworkEnablementController:stateChange', (networkEnablementControllerState) => __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_refreshState).call(this, {
|
|
163
|
+
networkControllerState: this.messenger.call('NetworkController:getState'),
|
|
164
|
+
networkEnablementControllerState,
|
|
165
|
+
connectivityControllerState: this.messenger.call('ConnectivityController:getState'),
|
|
166
|
+
}), selectNetworkEnablementControllerFields);
|
|
167
|
+
this.messenger.subscribe('ConnectivityController:stateChange', (connectivityControllerState) => __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_refreshState).call(this, {
|
|
168
|
+
networkControllerState: this.messenger.call('NetworkController:getState'),
|
|
169
|
+
networkEnablementControllerState: this.messenger.call('NetworkEnablementController:getState'),
|
|
170
|
+
connectivityControllerState,
|
|
171
|
+
}), selectConnectivityControllerFields);
|
|
163
172
|
/* eslint-enable no-restricted-syntax */
|
|
164
173
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
165
174
|
}
|
|
@@ -178,7 +187,11 @@ class NetworkConnectionBannerController extends base_controller_1.BaseController
|
|
|
178
187
|
return;
|
|
179
188
|
}
|
|
180
189
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_isStarted, true, "f");
|
|
181
|
-
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_refreshState).call(this
|
|
190
|
+
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_refreshState).call(this, {
|
|
191
|
+
networkControllerState: this.messenger.call('NetworkController:getState'),
|
|
192
|
+
networkEnablementControllerState: this.messenger.call('NetworkEnablementController:getState'),
|
|
193
|
+
connectivityControllerState: this.messenger.call('ConnectivityController:getState'),
|
|
194
|
+
});
|
|
182
195
|
}
|
|
183
196
|
/**
|
|
184
197
|
* Stops evaluating network connection state. Clears any pending banner
|
|
@@ -226,77 +239,79 @@ class NetworkConnectionBannerController extends base_controller_1.BaseController
|
|
|
226
239
|
}
|
|
227
240
|
}
|
|
228
241
|
exports.NetworkConnectionBannerController = NetworkConnectionBannerController;
|
|
229
|
-
_NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_pendingNetworkClientId = new WeakMap(), _NetworkConnectionBannerController_isStarted = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_refreshState = function _NetworkConnectionBannerController_refreshState({ networkControllerState, networkEnablementControllerState, connectivityControllerState, }
|
|
242
|
+
_NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_pendingNetworkClientId = new WeakMap(), _NetworkConnectionBannerController_isStarted = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_refreshState = function _NetworkConnectionBannerController_refreshState({ networkControllerState, networkEnablementControllerState, connectivityControllerState, }) {
|
|
230
243
|
if (!__classPrivateFieldGet(this, _NetworkConnectionBannerController_isStarted, "f")) {
|
|
231
244
|
return;
|
|
232
245
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (connectivityStatus === connectivity_controller_1.CONNECTIVITY_STATUSES.Offline) {
|
|
246
|
+
if (connectivityControllerState.connectivityStatus ===
|
|
247
|
+
connectivity_controller_1.CONNECTIVITY_STATUSES.Offline) {
|
|
236
248
|
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_resetBanner).call(this);
|
|
237
249
|
return;
|
|
238
250
|
}
|
|
239
|
-
const
|
|
240
|
-
this.messenger.call('NetworkController:getState');
|
|
241
|
-
const enablementState = networkEnablementControllerState ??
|
|
242
|
-
this.messenger.call('NetworkEnablementController:getState');
|
|
243
|
-
const failedNetwork = __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_findFailedNetwork).call(this, networkState, enablementState);
|
|
251
|
+
const failedNetwork = __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_findFailedNetwork).call(this, networkControllerState, networkEnablementControllerState);
|
|
244
252
|
if (!failedNetwork) {
|
|
245
253
|
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_resetBanner).call(this);
|
|
246
254
|
return;
|
|
247
255
|
}
|
|
248
|
-
if (this.state.
|
|
249
|
-
this.state.
|
|
256
|
+
if (this.state.networkConnectionBannerStatus !== 'available' &&
|
|
257
|
+
this.state.networkConnectionBannerNetwork?.networkClientId ===
|
|
258
|
+
failedNetwork.networkClientId) {
|
|
250
259
|
this.update((state) => {
|
|
251
|
-
|
|
260
|
+
// Even if the network client ID has not changed, save the current
|
|
261
|
+
// version of the failed network to state in case the user has updated
|
|
262
|
+
// its RPC URL.
|
|
263
|
+
state.networkConnectionBannerNetwork = failedNetwork;
|
|
252
264
|
});
|
|
253
265
|
return;
|
|
254
266
|
}
|
|
267
|
+
// A degraded timer is already counting down for this same network.
|
|
268
|
+
// Repeated `stateChange` events must not clear and restart it, or a
|
|
269
|
+
// steady stream of updates could postpone the banner indefinitely.
|
|
255
270
|
if (__classPrivateFieldGet(this, _NetworkConnectionBannerController_pendingNetworkClientId, "f") === failedNetwork.networkClientId) {
|
|
256
271
|
return;
|
|
257
272
|
}
|
|
258
273
|
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_clearTimers).call(this);
|
|
259
274
|
this.update((state) => {
|
|
260
|
-
state.
|
|
261
|
-
state.
|
|
275
|
+
state.networkConnectionBannerStatus = 'available';
|
|
276
|
+
state.networkConnectionBannerNetwork = null;
|
|
262
277
|
});
|
|
263
|
-
//
|
|
264
|
-
// called `stop()` re-entrantly. Bail before scheduling anything.
|
|
278
|
+
// If `stop` is called before scheduling timers, bail early.
|
|
265
279
|
if (!__classPrivateFieldGet(this, _NetworkConnectionBannerController_isStarted, "f")) {
|
|
266
280
|
return;
|
|
267
281
|
}
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
282
|
+
// Remember which network the pending timer is for (see the guard above)
|
|
283
|
+
// and capture the failing network at schedule time. If the failure
|
|
284
|
+
// resolves or a different network becomes the banner target while we
|
|
285
|
+
// wait, the subscription handlers re-enter this method and cancel or
|
|
286
|
+
// replace the timer before it fires.
|
|
272
287
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, failedNetwork.networkClientId, "f");
|
|
273
288
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedTimer, setTimeout(() => {
|
|
274
289
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedTimer, undefined, "f");
|
|
275
290
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, undefined, "f");
|
|
276
291
|
this.update((state) => {
|
|
277
|
-
state.
|
|
278
|
-
state.
|
|
292
|
+
state.networkConnectionBannerStatus = 'degraded';
|
|
293
|
+
state.networkConnectionBannerNetwork = failedNetwork;
|
|
279
294
|
});
|
|
280
|
-
//
|
|
281
|
-
// called `stop()` re-entrantly. Bail before scheduling the escalation.
|
|
295
|
+
// If `stop` is called before scheduling timers, bail early.
|
|
282
296
|
if (!__classPrivateFieldGet(this, _NetworkConnectionBannerController_isStarted, "f")) {
|
|
283
297
|
return;
|
|
284
298
|
}
|
|
285
299
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_unavailableTimer, setTimeout(() => {
|
|
286
300
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_unavailableTimer, undefined, "f");
|
|
287
301
|
this.update((state) => {
|
|
288
|
-
state.
|
|
289
|
-
state.
|
|
302
|
+
state.networkConnectionBannerStatus = 'unavailable';
|
|
303
|
+
state.networkConnectionBannerNetwork = failedNetwork;
|
|
290
304
|
});
|
|
291
305
|
}, UNAVAILABLE_BANNER_TIMEOUT - DEGRADED_BANNER_TIMEOUT), "f");
|
|
292
306
|
}, DEGRADED_BANNER_TIMEOUT), "f");
|
|
293
307
|
}, _NetworkConnectionBannerController_resetBanner = function _NetworkConnectionBannerController_resetBanner() {
|
|
294
308
|
__classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_clearTimers).call(this);
|
|
295
309
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, undefined, "f");
|
|
296
|
-
if (this.state.
|
|
310
|
+
if (this.state.networkConnectionBannerStatus !== 'available' ||
|
|
311
|
+
this.state.networkConnectionBannerNetwork !== null) {
|
|
297
312
|
this.update((state) => {
|
|
298
|
-
state.
|
|
299
|
-
state.
|
|
313
|
+
state.networkConnectionBannerStatus = 'available';
|
|
314
|
+
state.networkConnectionBannerNetwork = null;
|
|
300
315
|
});
|
|
301
316
|
}
|
|
302
317
|
}, _NetworkConnectionBannerController_clearTimers = function _NetworkConnectionBannerController_clearTimers() {
|
|
@@ -309,16 +324,17 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
|
|
|
309
324
|
__classPrivateFieldSet(this, _NetworkConnectionBannerController_unavailableTimer, undefined, "f");
|
|
310
325
|
}
|
|
311
326
|
}, _NetworkConnectionBannerController_findFailedNetwork = function _NetworkConnectionBannerController_findFailedNetwork(networkState, enablementState) {
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
327
|
+
const enabledNetworks = __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_collectEnabledNetworks).call(this, networkState, enablementState);
|
|
328
|
+
// Networks whose connectivity has not been looked up yet are not failed.
|
|
329
|
+
const failedNetworks = enabledNetworks
|
|
330
|
+
.filter(({ metadata }) => metadata !== undefined && metadata.status !== network_controller_1.NetworkStatus.Available)
|
|
315
331
|
.map((network) => __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_buildFailedNetwork).call(this, network));
|
|
316
|
-
return __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m",
|
|
332
|
+
return __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_pickFailedNetworkToDisplay).call(this, failedNetworks, enabledNetworks.length);
|
|
317
333
|
}, _NetworkConnectionBannerController_getEnabledEvmChainIds = function _NetworkConnectionBannerController_getEnabledEvmChainIds(enabledNetworkMap) {
|
|
318
334
|
return Object.entries(enabledNetworkMap[utils_1.KnownCaipNamespace.Eip155] ?? {})
|
|
319
335
|
.filter(([, enabled]) => enabled)
|
|
320
336
|
.map(([chainId]) => chainId);
|
|
321
|
-
},
|
|
337
|
+
}, _NetworkConnectionBannerController_collectEnabledNetworks = function _NetworkConnectionBannerController_collectEnabledNetworks({ networkConfigurationsByChainId, networksMetadata, }, { enabledNetworkMap, }) {
|
|
322
338
|
return __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_getEnabledEvmChainIds).call(this, enabledNetworkMap).flatMap((chainId) => {
|
|
323
339
|
const networkConfiguration = networkConfigurationsByChainId[chainId];
|
|
324
340
|
if (!networkConfiguration) {
|
|
@@ -329,10 +345,6 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
|
|
|
329
345
|
if (!defaultRpcEndpoint) {
|
|
330
346
|
return [];
|
|
331
347
|
}
|
|
332
|
-
const metadata = networksMetadata[defaultRpcEndpoint.networkClientId];
|
|
333
|
-
if (!metadata) {
|
|
334
|
-
return [];
|
|
335
|
-
}
|
|
336
348
|
return [
|
|
337
349
|
{
|
|
338
350
|
chainId,
|
|
@@ -340,7 +352,7 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
|
|
|
340
352
|
rpcEndpoints,
|
|
341
353
|
defaultRpcEndpointIndex,
|
|
342
354
|
defaultRpcEndpoint,
|
|
343
|
-
metadata,
|
|
355
|
+
metadata: networksMetadata[defaultRpcEndpoint.networkClientId],
|
|
344
356
|
},
|
|
345
357
|
];
|
|
346
358
|
});
|
|
@@ -361,20 +373,14 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
|
|
|
361
373
|
rpcUrl: defaultRpcEndpoint.url,
|
|
362
374
|
isInfuraEndpoint,
|
|
363
375
|
switchableInfuraNetworkClientId,
|
|
364
|
-
domain: (0, url_utils_1.getDomain)(defaultRpcEndpoint.url),
|
|
365
376
|
};
|
|
366
|
-
},
|
|
377
|
+
}, _NetworkConnectionBannerController_pickFailedNetworkToDisplay = function _NetworkConnectionBannerController_pickFailedNetworkToDisplay(failedNetworks, totalEnabledNetworks) {
|
|
367
378
|
if (failedNetworks.length === 0) {
|
|
368
379
|
return null;
|
|
369
380
|
}
|
|
370
381
|
const firstCustomFailed = failedNetworks.find((entry) => !entry.isInfuraEndpoint);
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
.filter((domain) => domain !== null)).size;
|
|
374
|
-
const areAllKnownNetworksFailed = failedNetworks.length === totalNetworksWithMetadata;
|
|
375
|
-
if (!firstCustomFailed &&
|
|
376
|
-
distinctDomains <= 1 &&
|
|
377
|
-
!areAllKnownNetworksFailed) {
|
|
382
|
+
const areAllEnabledNetworksFailed = failedNetworks.length === totalEnabledNetworks;
|
|
383
|
+
if (!firstCustomFailed && !areAllEnabledNetworksFailed) {
|
|
378
384
|
return null;
|
|
379
385
|
}
|
|
380
386
|
return firstCustomFailed ?? failedNetworks[0];
|
|
@@ -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 {\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 { Messenger } from '@metamask/messenger';\nimport type {\n NetworkConfiguration,\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\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 { getDomain, 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 * A network from `NetworkController` state that has a default RPC endpoint\n * with a known metadata status. Used as the input to the failed-network\n * detection pipeline.\n */\ntype NetworkWithMetadata = {\n chainId: Hex;\n name: string;\n rpcEndpoints: NetworkConfiguration['rpcEndpoints'];\n defaultRpcEndpointIndex: number;\n defaultRpcEndpoint: NetworkConfiguration['rpcEndpoints'][number];\n metadata: NetworkMetadata;\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 * The registrable domain (eTLD+1) of `rpcUrl`, used to group endpoints by\n * provider. `null` when the URL is invalid.\n */\n domain: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerState = {\n status: NetworkConnectionBannerStatus;\n network: FailedNetwork | null;\n};\n\nconst networkConnectionBannerControllerMetadata = {\n status: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n network: {\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 status: 'available',\n network: 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 'start',\n 'stop',\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 | 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 * Events from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} subscribes to.\n */\ntype AllowedEvents =\n | NetworkControllerStateChangeEvent\n | NetworkEnablementControllerStateChangeEvent\n | ConnectivityControllerStateChangeEvent;\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/**\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, the 5s / 30s timer escalation, and the\n * eTLD+1 grouping used to decide when a wider provider outage is in play.\n *\n * The banner shows when:\n *\n * - The first 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 * - Failed RPCs span more than one registrable domain (likely client-side).\n * - Every enabled EVM network with known connectivity status is failing\n * (escape hatch for single-network setups so they still get a signal).\n *\n * A wide single-provider outage (e.g. every `*.infura.io` network goes down at\n * once) collapses to one domain and is suppressed, except in the all-down\n * single-network case. When a custom failure is present, it's surfaced first\n * so the \"Switch to MetaMask default RPC\" CTA targets the network the user\n * can act on.\n *\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 /**\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 */\n constructor({ messenger }: NetworkConnectionBannerControllerOptions) {\n super({\n messenger,\n metadata: networkConnectionBannerControllerMetadata,\n name: CONTROLLER_NAME,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\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({ networkControllerState }),\n selectNetworkControllerFields,\n );\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n (networkEnablementControllerState) =>\n this.#refreshState({ networkEnablementControllerState }),\n selectNetworkEnablementControllerFields,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n (connectivityControllerState) =>\n this.#refreshState({ connectivityControllerState }),\n selectConnectivityControllerFields,\n );\n /* eslint-enable no-restricted-syntax */\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\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.\n *\n * Call this when the wallet UI that consumes the banner becomes active\n * (typically when the wallet is unlocked and the home surface mounts) so\n * timers do not run while the user is not looking at the wallet. Should\n * be called after `NetworkController`, `NetworkEnablementController`, and\n * `ConnectivityController` have been initialized. Idempotent.\n */\n start(): void {\n if (this.#isStarted) {\n return;\n }\n\n this.#isStarted = true;\n this.#refreshState();\n }\n\n /**\n * Stops evaluating network connection state. Clears any pending banner\n * timers and resets state to `available`. Call this when the UI\n * consuming the banner is no longer active. 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,\n * causing the banner to clear once the 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),\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 await this.messenger.call(\n 'NetworkController:updateNetwork',\n chainId,\n {\n ...networkConfiguration,\n defaultRpcEndpointIndex: infuraEndpointIndex,\n },\n { replacementSelectedRpcEndpointIndex: 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 const { connectivityStatus } =\n connectivityControllerState ??\n this.messenger.call('ConnectivityController:getState');\n if (connectivityStatus === CONNECTIVITY_STATUSES.Offline) {\n this.#resetBanner();\n return;\n }\n\n const networkState =\n networkControllerState ??\n this.messenger.call('NetworkController:getState');\n const enablementState =\n networkEnablementControllerState ??\n this.messenger.call('NetworkEnablementController:getState');\n\n const failedNetwork = this.#findFailedNetwork(\n networkState,\n enablementState,\n );\n if (!failedNetwork) {\n this.#resetBanner();\n return;\n }\n\n if (\n this.state.status !== 'available' &&\n this.state.network?.networkClientId === failedNetwork.networkClientId\n ) {\n this.update((state) => {\n state.network = failedNetwork;\n });\n return;\n }\n\n if (this.#pendingNetworkClientId === failedNetwork.networkClientId) {\n return;\n }\n\n this.#clearTimers();\n this.update((state) => {\n state.status = 'available';\n state.network = null;\n });\n\n // A synchronous listener on our `stateChanged` event above may have\n // called `stop()` re-entrantly. Bail before scheduling anything.\n if (!this.#isStarted) {\n return;\n }\n\n // Capture the failing network at schedule time. We trust the messenger\n // contract: if the failure resolves or the target changes during the\n // wait, our upstream subscriptions will have cancelled or replaced this\n // timer via `#clearTimers` 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.status = 'degraded';\n state.network = failedNetwork;\n });\n // A synchronous listener on our `stateChanged` event above may have\n // called `stop()` re-entrantly. Bail before scheduling the escalation.\n if (!this.#isStarted) {\n return;\n }\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n this.update((state) => {\n state.status = 'unavailable';\n state.network = 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 (this.state.status !== 'available' || this.state.network !== null) {\n this.update((state) => {\n state.status = 'available';\n state.network = 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 networksWithMetadata = this.#collectNetworksWithMetadata(\n networkState,\n enablementState,\n );\n const failedNetworks = networksWithMetadata\n .filter(({ metadata }) => metadata.status !== NetworkStatus.Available)\n .map((network) => this.#buildFailedNetwork(network));\n return this.#pickBannerNetwork(failedNetworks, networksWithMetadata.length);\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 #collectNetworksWithMetadata(\n {\n networkConfigurationsByChainId,\n networksMetadata,\n }: Pick<\n NetworkState,\n 'networkConfigurationsByChainId' | 'networksMetadata'\n >,\n {\n enabledNetworkMap,\n }: Pick<NetworkEnablementControllerState, 'enabledNetworkMap'>,\n ): NetworkWithMetadata[] {\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 const metadata = networksMetadata[defaultRpcEndpoint.networkClientId];\n if (!metadata) {\n return [];\n }\n return [\n {\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n metadata,\n },\n ];\n });\n }\n\n #buildFailedNetwork({\n chainId,\n name,\n rpcEndpoints,\n defaultRpcEndpointIndex,\n defaultRpcEndpoint,\n }: NetworkWithMetadata): FailedNetwork {\n const isInfuraEndpoint = getIsInfuraEndpoint(defaultRpcEndpoint.url);\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),\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 domain: getDomain(defaultRpcEndpoint.url),\n };\n }\n\n #pickBannerNetwork(\n failedNetworks: FailedNetwork[],\n totalNetworksWithMetadata: 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 distinctDomains = new Set(\n failedNetworks\n .map((entry) => entry.domain)\n .filter((domain): domain is string => domain !== null),\n ).size;\n const areAllKnownNetworksFailed =\n failedNetworks.length === totalNetworksWithMetadata;\n\n if (\n !firstCustomFailed &&\n distinctDomains <= 1 &&\n !areAllKnownNetworksFailed\n ) {\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 {\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 { Messenger } from '@metamask/messenger';\nimport type {\n NetworkConfiguration,\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\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 'start',\n 'stop',\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 | 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 * Events from other messengers that\n * {@link NetworkConnectionBannerControllerMessenger} subscribes to.\n */\ntype AllowedEvents =\n | NetworkControllerStateChangeEvent\n | NetworkEnablementControllerStateChangeEvent\n | ConnectivityControllerStateChangeEvent;\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/**\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 * 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 /**\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 */\n constructor({ messenger }: NetworkConnectionBannerControllerOptions) {\n super({\n messenger,\n metadata: networkConnectionBannerControllerMetadata,\n name: CONTROLLER_NAME,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\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 this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\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.\n *\n * Call this when the wallet UI that consumes the banner becomes active\n * (typically when the wallet is unlocked and the home surface mounts) so\n * timers do not run while the user is not looking at the wallet. Should\n * be called after `NetworkController`, `NetworkEnablementController`, and\n * `ConnectivityController` have been initialized. 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`. Call this when the UI\n * consuming the banner is no longer active. 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,\n * causing the banner to clear once the 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),\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 await this.messenger.call(\n 'NetworkController:updateNetwork',\n chainId,\n {\n ...networkConfiguration,\n defaultRpcEndpointIndex: infuraEndpointIndex,\n },\n { replacementSelectedRpcEndpointIndex: 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(defaultRpcEndpoint.url);\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),\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"]}
|
|
@@ -38,18 +38,18 @@ export type FailedNetwork = {
|
|
|
38
38
|
* no Infura alternative exists.
|
|
39
39
|
*/
|
|
40
40
|
switchableInfuraNetworkClientId: string | null;
|
|
41
|
-
/**
|
|
42
|
-
* The registrable domain (eTLD+1) of `rpcUrl`, used to group endpoints by
|
|
43
|
-
* provider. `null` when the URL is invalid.
|
|
44
|
-
*/
|
|
45
|
-
domain: string | null;
|
|
46
41
|
};
|
|
47
42
|
/**
|
|
48
43
|
* State for the {@link NetworkConnectionBannerController}.
|
|
44
|
+
*
|
|
45
|
+
* The keys carry the controller-domain prefix (like
|
|
46
|
+
* `ConnectivityController`'s `connectivityStatus`) because some clients merge
|
|
47
|
+
* all controller states into one flat object, where generic names like
|
|
48
|
+
* `status` collide across controllers.
|
|
49
49
|
*/
|
|
50
50
|
export type NetworkConnectionBannerControllerState = {
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
networkConnectionBannerStatus: NetworkConnectionBannerStatus;
|
|
52
|
+
networkConnectionBannerNetwork: FailedNetwork | null;
|
|
53
53
|
};
|
|
54
54
|
/**
|
|
55
55
|
* Constructs the default {@link NetworkConnectionBannerController} state.
|
|
@@ -103,22 +103,19 @@ export type NetworkConnectionBannerControllerOptions = {
|
|
|
103
103
|
/**
|
|
104
104
|
* NetworkConnectionBannerController decides whether the network connection
|
|
105
105
|
* banner should be shown for the user, and which failing network it should
|
|
106
|
-
* describe. It encapsulates the rule
|
|
107
|
-
* eTLD+1 grouping used to decide when a wider provider outage is in play.
|
|
106
|
+
* describe. It encapsulates the rule and the 5s / 30s timer escalation.
|
|
108
107
|
*
|
|
109
108
|
* The banner shows when:
|
|
110
109
|
*
|
|
111
|
-
* -
|
|
112
|
-
*
|
|
113
|
-
* -
|
|
114
|
-
*
|
|
115
|
-
* (escape hatch for single-network setups so they still get a signal).
|
|
110
|
+
* - A failing network's default RPC is a custom (non-Infura) endpoint —
|
|
111
|
+
* users always want to be informed about errors with RPCs they've chosen.
|
|
112
|
+
* - Every enabled EVM network is reporting a failed connectivity status
|
|
113
|
+
* (escape hatch so Infura-only setups still get a signal).
|
|
116
114
|
*
|
|
117
|
-
* A
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* can act on.
|
|
115
|
+
* A partial Infura outage alongside healthy peers is suppressed since it
|
|
116
|
+
* usually resolves on its own and the user cannot act on it. When a custom
|
|
117
|
+
* failure is present, it's surfaced first so the "Switch to MetaMask default
|
|
118
|
+
* RPC" CTA targets the network the user can act on.
|
|
122
119
|
*
|
|
123
120
|
* Clients only need to render the banner from the controller's state and wire
|
|
124
121
|
* click handlers to {@link dismissBanner} or {@link switchToDefaultInfuraRpcEndpoint}.
|
|
@@ -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;AAK3D,OAAO,KAAK,EACV,oCAAoC,EAEpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAEV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,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;
|
|
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;AAK3D,OAAO,KAAK,EACV,oCAAoC,EAEpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAEV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,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;AAqBD;;GAEG;AACH,MAAM,MAAM,+CAA+C,GACzD,wBAAwB,CACtB,OAAO,eAAe,EACtB,sCAAsC,CACvC,CAAC;AAEJ;;;GAGG;AACH,MAAM,MAAM,wCAAwC,GAChD,+CAA+C,GAC/C,8CAA8C,CAAC;AAEnD;;;GAGG;AACH,KAAK,cAAc,GACf,+BAA+B,GAC/B,uDAAuD,GACvD,oCAAoC,GACpC,yCAAyC,GACzC,oCAAoC,CAAC;AAEzC;;;GAGG;AACH,MAAM,MAAM,kDAAkD,GAC5D,2BAA2B,CACzB,OAAO,eAAe,EACtB,sCAAsC,CACvC,CAAC;AAEJ;;;GAGG;AACH,MAAM,MAAM,uCAAuC,GACjD,kDAAkD,CAAC;AAErD;;;GAGG;AACH,KAAK,aAAa,GACd,iCAAiC,GACjC,2CAA2C,GAC3C,sCAAsC,CAAC;AAE3C;;;GAGG;AACH,MAAM,MAAM,0CAA0C,GAAG,SAAS,CAChE,OAAO,eAAe,EACtB,wCAAwC,GAAG,cAAc,EACzD,uCAAuC,GAAG,aAAa,CACxD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,wCAAwC,GAAG;IACrD;;OAEG;IACH,SAAS,EAAE,0CAA0C,CAAC;CACvD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,iCAAkC,SAAQ,cAAc,CACnE,OAAO,eAAe,EACtB,sCAAsC,EACtC,0CAA0C,CAC3C;;IASC;;;;;OAKG;gBACS,EAAE,SAAS,EAAE,EAAE,wCAAwC;IA6DnE;;;;;;;;;OASG;IACH,KAAK,IAAI,IAAI;IAiBb;;;;OAIG;IACH,IAAI,IAAI,IAAI;IASZ;;OAEG;IACH,aAAa,IAAI,IAAI;IAIrB;;;;;;;OAOG;IACG,gCAAgC,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;CA4RpE"}
|
|
@@ -38,18 +38,18 @@ export type FailedNetwork = {
|
|
|
38
38
|
* no Infura alternative exists.
|
|
39
39
|
*/
|
|
40
40
|
switchableInfuraNetworkClientId: string | null;
|
|
41
|
-
/**
|
|
42
|
-
* The registrable domain (eTLD+1) of `rpcUrl`, used to group endpoints by
|
|
43
|
-
* provider. `null` when the URL is invalid.
|
|
44
|
-
*/
|
|
45
|
-
domain: string | null;
|
|
46
41
|
};
|
|
47
42
|
/**
|
|
48
43
|
* State for the {@link NetworkConnectionBannerController}.
|
|
44
|
+
*
|
|
45
|
+
* The keys carry the controller-domain prefix (like
|
|
46
|
+
* `ConnectivityController`'s `connectivityStatus`) because some clients merge
|
|
47
|
+
* all controller states into one flat object, where generic names like
|
|
48
|
+
* `status` collide across controllers.
|
|
49
49
|
*/
|
|
50
50
|
export type NetworkConnectionBannerControllerState = {
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
networkConnectionBannerStatus: NetworkConnectionBannerStatus;
|
|
52
|
+
networkConnectionBannerNetwork: FailedNetwork | null;
|
|
53
53
|
};
|
|
54
54
|
/**
|
|
55
55
|
* Constructs the default {@link NetworkConnectionBannerController} state.
|
|
@@ -103,22 +103,19 @@ export type NetworkConnectionBannerControllerOptions = {
|
|
|
103
103
|
/**
|
|
104
104
|
* NetworkConnectionBannerController decides whether the network connection
|
|
105
105
|
* banner should be shown for the user, and which failing network it should
|
|
106
|
-
* describe. It encapsulates the rule
|
|
107
|
-
* eTLD+1 grouping used to decide when a wider provider outage is in play.
|
|
106
|
+
* describe. It encapsulates the rule and the 5s / 30s timer escalation.
|
|
108
107
|
*
|
|
109
108
|
* The banner shows when:
|
|
110
109
|
*
|
|
111
|
-
* -
|
|
112
|
-
*
|
|
113
|
-
* -
|
|
114
|
-
*
|
|
115
|
-
* (escape hatch for single-network setups so they still get a signal).
|
|
110
|
+
* - A failing network's default RPC is a custom (non-Infura) endpoint —
|
|
111
|
+
* users always want to be informed about errors with RPCs they've chosen.
|
|
112
|
+
* - Every enabled EVM network is reporting a failed connectivity status
|
|
113
|
+
* (escape hatch so Infura-only setups still get a signal).
|
|
116
114
|
*
|
|
117
|
-
* A
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* can act on.
|
|
115
|
+
* A partial Infura outage alongside healthy peers is suppressed since it
|
|
116
|
+
* usually resolves on its own and the user cannot act on it. When a custom
|
|
117
|
+
* failure is present, it's surfaced first so the "Switch to MetaMask default
|
|
118
|
+
* RPC" CTA targets the network the user can act on.
|
|
122
119
|
*
|
|
123
120
|
* Clients only need to render the banner from the controller's state and wire
|
|
124
121
|
* click handlers to {@link dismissBanner} or {@link switchToDefaultInfuraRpcEndpoint}.
|
|
@@ -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;AAK3D,OAAO,KAAK,EACV,oCAAoC,EAEpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAEV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,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;
|
|
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;AAK3D,OAAO,KAAK,EACV,oCAAoC,EAEpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAEV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,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;AAqBD;;GAEG;AACH,MAAM,MAAM,+CAA+C,GACzD,wBAAwB,CACtB,OAAO,eAAe,EACtB,sCAAsC,CACvC,CAAC;AAEJ;;;GAGG;AACH,MAAM,MAAM,wCAAwC,GAChD,+CAA+C,GAC/C,8CAA8C,CAAC;AAEnD;;;GAGG;AACH,KAAK,cAAc,GACf,+BAA+B,GAC/B,uDAAuD,GACvD,oCAAoC,GACpC,yCAAyC,GACzC,oCAAoC,CAAC;AAEzC;;;GAGG;AACH,MAAM,MAAM,kDAAkD,GAC5D,2BAA2B,CACzB,OAAO,eAAe,EACtB,sCAAsC,CACvC,CAAC;AAEJ;;;GAGG;AACH,MAAM,MAAM,uCAAuC,GACjD,kDAAkD,CAAC;AAErD;;;GAGG;AACH,KAAK,aAAa,GACd,iCAAiC,GACjC,2CAA2C,GAC3C,sCAAsC,CAAC;AAE3C;;;GAGG;AACH,MAAM,MAAM,0CAA0C,GAAG,SAAS,CAChE,OAAO,eAAe,EACtB,wCAAwC,GAAG,cAAc,EACzD,uCAAuC,GAAG,aAAa,CACxD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,wCAAwC,GAAG;IACrD;;OAEG;IACH,SAAS,EAAE,0CAA0C,CAAC;CACvD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,iCAAkC,SAAQ,cAAc,CACnE,OAAO,eAAe,EACtB,sCAAsC,EACtC,0CAA0C,CAC3C;;IASC;;;;;OAKG;gBACS,EAAE,SAAS,EAAE,EAAE,wCAAwC;IA6DnE;;;;;;;;;OASG;IACH,KAAK,IAAI,IAAI;IAiBb;;;;OAIG;IACH,IAAI,IAAI,IAAI;IASZ;;OAEG;IACH,aAAa,IAAI,IAAI;IAIrB;;;;;;;OAOG;IACG,gCAAgC,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;CA4RpE"}
|