@metamask-previews/network-connection-banner-controller 0.1.0-preview-69c25f142 → 0.1.0-preview-51b287c55

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.
@@ -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_evaluate, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetworkForBanner;
13
+ var _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_pendingNetworkClientId, _NetworkConnectionBannerController_evaluate, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetworkForBanner;
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");
@@ -96,6 +96,7 @@ class NetworkConnectionBannerController extends base_controller_1.BaseController
96
96
  _NetworkConnectionBannerController_instances.add(this);
97
97
  _NetworkConnectionBannerController_degradedTimer.set(this, void 0);
98
98
  _NetworkConnectionBannerController_unavailableTimer.set(this, void 0);
99
+ _NetworkConnectionBannerController_pendingNetworkClientId.set(this, void 0);
99
100
  const onStateChange = () => __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_evaluate).call(this);
100
101
  // Upstream controllers still expose :stateChange; switch to :stateChanged
101
102
  // once those packages migrate their event types.
@@ -143,7 +144,7 @@ class NetworkConnectionBannerController extends base_controller_1.BaseController
143
144
  }
144
145
  }
145
146
  exports.NetworkConnectionBannerController = NetworkConnectionBannerController;
146
- _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_evaluate = function _NetworkConnectionBannerController_evaluate() {
147
+ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_pendingNetworkClientId = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_evaluate = function _NetworkConnectionBannerController_evaluate() {
147
148
  const { connectivityStatus } = this.messenger.call('ConnectivityController:getState');
148
149
  if (connectivityStatus === connectivity_controller_1.CONNECTIVITY_STATUSES.Offline) {
149
150
  __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_resetBanner).call(this);
@@ -154,9 +155,6 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
154
155
  __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_resetBanner).call(this);
155
156
  return;
156
157
  }
157
- // If the banner is currently showing for a different network or status,
158
- // restart the escalation timeline for the new one. Otherwise let the
159
- // existing timers continue.
160
158
  if (this.state.status !== 'available' &&
161
159
  this.state.network?.networkClientId === failed.networkClientId) {
162
160
  this.update((draft) => {
@@ -164,13 +162,18 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
164
162
  });
165
163
  return;
166
164
  }
165
+ if (__classPrivateFieldGet(this, _NetworkConnectionBannerController_pendingNetworkClientId, "f") === failed.networkClientId) {
166
+ return;
167
+ }
167
168
  __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_clearTimers).call(this);
168
169
  this.update((draft) => {
169
170
  draft.status = 'available';
170
171
  draft.network = null;
171
172
  });
173
+ __classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, failed.networkClientId, "f");
172
174
  __classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedTimer, setTimeout(() => {
173
175
  __classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedTimer, undefined, "f");
176
+ __classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, undefined, "f");
174
177
  const stillFailed = __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_findFailedNetworkForBanner).call(this);
175
178
  if (!stillFailed) {
176
179
  return;
@@ -200,6 +203,7 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
200
203
  });
201
204
  }
202
205
  }, _NetworkConnectionBannerController_clearTimers = function _NetworkConnectionBannerController_clearTimers() {
206
+ __classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, undefined, "f");
203
207
  if (__classPrivateFieldGet(this, _NetworkConnectionBannerController_degradedTimer, "f") !== undefined) {
204
208
  clearTimeout(__classPrivateFieldGet(this, _NetworkConnectionBannerController_degradedTimer, "f"));
205
209
  __classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedTimer, 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 { CONNECTIVITY_STATUSES } from '@metamask/connectivity-controller';\nimport type {\n ConnectivityControllerGetStateAction,\n ConnectivityControllerStateChangeEvent,\n} from '@metamask/connectivity-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport { NetworkStatus } from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerStateChangeEvent,\n} from '@metamask/network-enablement-controller';\nimport type { Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\n\nimport type { NetworkConnectionBannerControllerMethodActions } from './NetworkConnectionBannerController-method-action-types';\nimport { getDomain } 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 controllerName = 'NetworkConnectionBannerController';\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 * Details of the failing network the banner should describe. Populated when\n * {@link NetworkConnectionBannerControllerState.status} is `degraded` or\n * `unavailable`, `null` otherwise.\n *\n * `infuraNetworkClientId` is the networkClientId of an Infura endpoint on the\n * same chain that the user can switch to. `null` when the failing endpoint is\n * already Infura, or when no Infura alternative exists.\n */\nexport type NetworkConnectionBannerFailedNetwork = {\n chainId: Hex;\n networkClientId: string;\n networkName: string;\n rpcUrl: string;\n isInfuraEndpoint: boolean;\n infuraNetworkClientId: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerState = {\n status: NetworkConnectionBannerStatus;\n network: NetworkConnectionBannerFailedNetwork | 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\nconst DEGRADED_BANNER_TIMEOUT_MS = 5_000;\nconst UNAVAILABLE_BANNER_TIMEOUT_MS = 30_000;\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'dismissBanner',\n 'switchToDefaultInfuraRpc',\n] as const;\n\n/**\n * Retrieves the state of the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\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 controllerName,\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 controllerName,\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 that was previously duplicated across MetaMask clients.\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 is failing (escape hatch for single-network\n * 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 switchToDefaultInfuraRpc}.\n */\nexport class NetworkConnectionBannerController extends BaseController<\n typeof controllerName,\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerMessenger\n> {\n #degradedTimer: ReturnType<typeof setTimeout> | undefined;\n\n #unavailableTimer: ReturnType<typeof setTimeout> | undefined;\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: controllerName,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\n\n const onStateChange = (): void => this.#evaluate();\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('NetworkController:stateChange', onStateChange);\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n onStateChange,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n onStateChange,\n );\n /* eslint-enable no-restricted-syntax */\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Clears the banner state regardless of the current rule outcome. The next\n * subscription-driven evaluation will re-show the banner if the conditions\n * still hold.\n */\n dismissBanner(): void {\n this.#resetBanner();\n }\n\n /**\n * Switches the chain's default RPC endpoint to its first Infura endpoint,\n * causing the banner to clear once the network becomes available again.\n *\n * @param args - The arguments to this action.\n * @param args.chainId - The chain whose default RPC 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 switchToDefaultInfuraRpc({ chainId }: { 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) => isInfuraEndpoint(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 #evaluate(): void {\n const { connectivityStatus } = this.messenger.call(\n 'ConnectivityController:getState',\n );\n if (connectivityStatus === CONNECTIVITY_STATUSES.Offline) {\n this.#resetBanner();\n return;\n }\n\n const failed = this.#findFailedNetworkForBanner();\n\n if (!failed) {\n this.#resetBanner();\n return;\n }\n\n // If the banner is currently showing for a different network or status,\n // restart the escalation timeline for the new one. Otherwise let the\n // existing timers continue.\n if (\n this.state.status !== 'available' &&\n this.state.network?.networkClientId === failed.networkClientId\n ) {\n this.update((draft) => {\n draft.network = failed;\n });\n return;\n }\n\n this.#clearTimers();\n this.update((draft) => {\n draft.status = 'available';\n draft.network = null;\n });\n\n this.#degradedTimer = setTimeout(() => {\n this.#degradedTimer = undefined;\n const stillFailed = this.#findFailedNetworkForBanner();\n if (!stillFailed) {\n return;\n }\n this.update((draft) => {\n draft.status = 'degraded';\n draft.network = stillFailed;\n });\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n const stillFailedAtEscalation = this.#findFailedNetworkForBanner();\n if (!stillFailedAtEscalation) {\n return;\n }\n this.update((draft) => {\n draft.status = 'unavailable';\n draft.network = stillFailedAtEscalation;\n });\n }, UNAVAILABLE_BANNER_TIMEOUT_MS - DEGRADED_BANNER_TIMEOUT_MS);\n }, DEGRADED_BANNER_TIMEOUT_MS);\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 if (this.state.status !== 'available' || this.state.network !== null) {\n this.update((draft) => {\n draft.status = 'available';\n draft.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 #findFailedNetworkForBanner(): NetworkConnectionBannerFailedNetwork | null {\n const { enabledNetworkMap } = this.messenger.call(\n 'NetworkEnablementController:getState',\n );\n const enabledEvmChainIds = Object.entries(\n enabledNetworkMap[KnownCaipNamespace.Eip155] ?? {},\n )\n .filter(([, enabled]) => enabled)\n .map(([chainId]) => chainId as Hex);\n const { networkConfigurationsByChainId, networksMetadata } =\n this.messenger.call('NetworkController:getState');\n\n type EnrichedFailedNetwork = NetworkConnectionBannerFailedNetwork & {\n domain: string | null;\n };\n const failedNetworks: EnrichedFailedNetwork[] = [];\n let totalEnabled = 0;\n\n for (const chainId of enabledEvmChainIds) {\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n continue;\n }\n\n const { rpcEndpoints, defaultRpcEndpointIndex, name } =\n networkConfiguration;\n const defaultRpcEndpoint = rpcEndpoints[defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n continue;\n }\n\n totalEnabled += 1;\n\n const metadata = networksMetadata[defaultRpcEndpoint.networkClientId];\n if (\n metadata === undefined ||\n metadata.status === NetworkStatus.Available\n ) {\n continue;\n }\n\n const endpointIsInfura = isInfuraEndpoint(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 infuraNetworkClientId: string | null = null;\n if (!endpointIsInfura) {\n const otherInfura = rpcEndpoints.find(\n (endpoint, index) =>\n index !== defaultRpcEndpointIndex && isInfuraEndpoint(endpoint.url),\n );\n infuraNetworkClientId = otherInfura?.networkClientId ?? null;\n }\n\n failedNetworks.push({\n chainId,\n networkClientId: defaultRpcEndpoint.networkClientId,\n networkName: name,\n rpcUrl: defaultRpcEndpoint.url,\n isInfuraEndpoint: endpointIsInfura,\n infuraNetworkClientId,\n domain: getDomain(defaultRpcEndpoint.url),\n });\n }\n\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 areAllEnabledNetworksFailed = failedNetworks.length === totalEnabled;\n\n if (\n !firstCustomFailed &&\n distinctDomains <= 1 &&\n !areAllEnabledNetworksFailed\n ) {\n return null;\n }\n\n const selected = firstCustomFailed ?? failedNetworks[0];\n return {\n chainId: selected.chainId,\n networkClientId: selected.networkClientId,\n networkName: selected.networkName,\n rpcUrl: selected.rpcUrl,\n isInfuraEndpoint: selected.isInfuraEndpoint,\n infuraNetworkClientId: selected.infuraNetworkClientId,\n };\n }\n}\n\n/**\n * Checks if an RPC URL is hosted on the Infura service. Detection is by\n * hostname suffix rather than the exact MetaMask-key URL pattern, so any\n * `*.infura.io` URL counts. That's the right shape for grouping by provider.\n *\n * @param url - The RPC URL to check.\n * @returns True if the URL's host is on `infura.io`.\n */\nfunction isInfuraEndpoint(url: string): boolean {\n try {\n return new URL(url).hostname.toLowerCase().endsWith('.infura.io');\n } catch {\n return false;\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 { CONNECTIVITY_STATUSES } from '@metamask/connectivity-controller';\nimport type {\n ConnectivityControllerGetStateAction,\n ConnectivityControllerStateChangeEvent,\n} from '@metamask/connectivity-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport { NetworkStatus } from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerStateChangeEvent,\n} from '@metamask/network-enablement-controller';\nimport type { Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\n\nimport type { NetworkConnectionBannerControllerMethodActions } from './NetworkConnectionBannerController-method-action-types';\nimport { getDomain } 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 controllerName = 'NetworkConnectionBannerController';\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 * Details of the failing network the banner should describe. Populated when\n * {@link NetworkConnectionBannerControllerState.status} is `degraded` or\n * `unavailable`, `null` otherwise.\n *\n * `infuraNetworkClientId` is the networkClientId of an Infura endpoint on the\n * same chain that the user can switch to. `null` when the failing endpoint is\n * already Infura, or when no Infura alternative exists.\n */\nexport type NetworkConnectionBannerFailedNetwork = {\n chainId: Hex;\n networkClientId: string;\n networkName: string;\n rpcUrl: string;\n isInfuraEndpoint: boolean;\n infuraNetworkClientId: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerState = {\n status: NetworkConnectionBannerStatus;\n network: NetworkConnectionBannerFailedNetwork | 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\nconst DEGRADED_BANNER_TIMEOUT_MS = 5_000;\nconst UNAVAILABLE_BANNER_TIMEOUT_MS = 30_000;\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'dismissBanner',\n 'switchToDefaultInfuraRpc',\n] as const;\n\n/**\n * Retrieves the state of the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\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 controllerName,\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 controllerName,\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 that was previously duplicated across MetaMask clients.\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 is failing (escape hatch for single-network\n * 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 switchToDefaultInfuraRpc}.\n */\nexport class NetworkConnectionBannerController extends BaseController<\n typeof controllerName,\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 /**\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: controllerName,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\n\n const onStateChange = (): void => this.#evaluate();\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('NetworkController:stateChange', onStateChange);\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n onStateChange,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n onStateChange,\n );\n /* eslint-enable no-restricted-syntax */\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Clears the banner state regardless of the current rule outcome. The next\n * subscription-driven evaluation will re-show the banner if the conditions\n * still hold.\n */\n dismissBanner(): void {\n this.#resetBanner();\n }\n\n /**\n * Switches the chain's default RPC endpoint to its first Infura endpoint,\n * causing the banner to clear once the network becomes available again.\n *\n * @param args - The arguments to this action.\n * @param args.chainId - The chain whose default RPC 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 switchToDefaultInfuraRpc({ chainId }: { 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) => isInfuraEndpoint(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 #evaluate(): void {\n const { connectivityStatus } = this.messenger.call(\n 'ConnectivityController:getState',\n );\n if (connectivityStatus === CONNECTIVITY_STATUSES.Offline) {\n this.#resetBanner();\n return;\n }\n\n const failed = this.#findFailedNetworkForBanner();\n\n if (!failed) {\n this.#resetBanner();\n return;\n }\n\n if (\n this.state.status !== 'available' &&\n this.state.network?.networkClientId === failed.networkClientId\n ) {\n this.update((draft) => {\n draft.network = failed;\n });\n return;\n }\n\n if (this.#pendingNetworkClientId === failed.networkClientId) {\n return;\n }\n\n this.#clearTimers();\n this.update((draft) => {\n draft.status = 'available';\n draft.network = null;\n });\n\n this.#pendingNetworkClientId = failed.networkClientId;\n this.#degradedTimer = setTimeout(() => {\n this.#degradedTimer = undefined;\n this.#pendingNetworkClientId = undefined;\n const stillFailed = this.#findFailedNetworkForBanner();\n if (!stillFailed) {\n return;\n }\n this.update((draft) => {\n draft.status = 'degraded';\n draft.network = stillFailed;\n });\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n const stillFailedAtEscalation = this.#findFailedNetworkForBanner();\n if (!stillFailedAtEscalation) {\n return;\n }\n this.update((draft) => {\n draft.status = 'unavailable';\n draft.network = stillFailedAtEscalation;\n });\n }, UNAVAILABLE_BANNER_TIMEOUT_MS - DEGRADED_BANNER_TIMEOUT_MS);\n }, DEGRADED_BANNER_TIMEOUT_MS);\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 if (this.state.status !== 'available' || this.state.network !== null) {\n this.update((draft) => {\n draft.status = 'available';\n draft.network = null;\n });\n }\n }\n\n #clearTimers(): void {\n this.#pendingNetworkClientId = undefined;\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 #findFailedNetworkForBanner(): NetworkConnectionBannerFailedNetwork | null {\n const { enabledNetworkMap } = this.messenger.call(\n 'NetworkEnablementController:getState',\n );\n const enabledEvmChainIds = Object.entries(\n enabledNetworkMap[KnownCaipNamespace.Eip155] ?? {},\n )\n .filter(([, enabled]) => enabled)\n .map(([chainId]) => chainId as Hex);\n const { networkConfigurationsByChainId, networksMetadata } =\n this.messenger.call('NetworkController:getState');\n\n type EnrichedFailedNetwork = NetworkConnectionBannerFailedNetwork & {\n domain: string | null;\n };\n const failedNetworks: EnrichedFailedNetwork[] = [];\n let totalEnabled = 0;\n\n for (const chainId of enabledEvmChainIds) {\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n continue;\n }\n\n const { rpcEndpoints, defaultRpcEndpointIndex, name } =\n networkConfiguration;\n const defaultRpcEndpoint = rpcEndpoints[defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n continue;\n }\n\n totalEnabled += 1;\n\n const metadata = networksMetadata[defaultRpcEndpoint.networkClientId];\n if (\n metadata === undefined ||\n metadata.status === NetworkStatus.Available\n ) {\n continue;\n }\n\n const endpointIsInfura = isInfuraEndpoint(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 infuraNetworkClientId: string | null = null;\n if (!endpointIsInfura) {\n const otherInfura = rpcEndpoints.find(\n (endpoint, index) =>\n index !== defaultRpcEndpointIndex && isInfuraEndpoint(endpoint.url),\n );\n infuraNetworkClientId = otherInfura?.networkClientId ?? null;\n }\n\n failedNetworks.push({\n chainId,\n networkClientId: defaultRpcEndpoint.networkClientId,\n networkName: name,\n rpcUrl: defaultRpcEndpoint.url,\n isInfuraEndpoint: endpointIsInfura,\n infuraNetworkClientId,\n domain: getDomain(defaultRpcEndpoint.url),\n });\n }\n\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 areAllEnabledNetworksFailed = failedNetworks.length === totalEnabled;\n\n if (\n !firstCustomFailed &&\n distinctDomains <= 1 &&\n !areAllEnabledNetworksFailed\n ) {\n return null;\n }\n\n const selected = firstCustomFailed ?? failedNetworks[0];\n return {\n chainId: selected.chainId,\n networkClientId: selected.networkClientId,\n networkName: selected.networkName,\n rpcUrl: selected.rpcUrl,\n isInfuraEndpoint: selected.isInfuraEndpoint,\n infuraNetworkClientId: selected.infuraNetworkClientId,\n };\n }\n}\n\n/**\n * Checks if an RPC URL is hosted on the Infura service. Detection is by\n * hostname suffix rather than the exact MetaMask-key URL pattern, so any\n * `*.infura.io` URL counts. That's the right shape for grouping by provider.\n *\n * @param url - The RPC URL to check.\n * @returns True if the URL's host is on `infura.io`.\n */\nfunction isInfuraEndpoint(url: string): boolean {\n try {\n return new URL(url).hostname.toLowerCase().endsWith('.infura.io');\n } catch {\n return false;\n }\n}\n"]}
@@ -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,EACV,oCAAoC,EACpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,iCAAiC,EAClC,qCAAqC;AAEtC,OAAO,KAAK,EACV,yCAAyC,EACzC,2CAA2C,EAC5C,gDAAgD;AACjD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAG3C,OAAO,KAAK,EAAE,8CAA8C,EAAE,oEAAgE;AAG9H;;;;GAIG;AACH,QAAA,MAAM,cAAc,sCAAsC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACrC,WAAW,GACX,UAAU,GACV,aAAa,CAAC;AAElB;;;;;;;;GAQG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,OAAO,EAAE,GAAG,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAAG;IACnD,MAAM,EAAE,6BAA6B,CAAC;IACtC,OAAO,EAAE,oCAAoC,GAAG,IAAI,CAAC;CACtD,CAAC;AAiBF;;;;GAIG;AACH,wBAAgB,gDAAgD,IAAI,sCAAsC,CAKzG;AAUD;;GAEG;AACH,MAAM,MAAM,+CAA+C,GACzD,wBAAwB,CACtB,OAAO,cAAc,EACrB,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,cAAc,EACrB,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,cAAc,EACrB,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;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,iCAAkC,SAAQ,cAAc,CACnE,OAAO,cAAc,EACrB,sCAAsC,EACtC,0CAA0C,CAC3C;;IAKC;;;;;OAKG;gBACS,EAAE,SAAS,EAAE,EAAE,wCAAwC;IA6BnE;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAIrB;;;;;;;;OAQG;IACG,wBAAwB,CAAC,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAwN7E"}
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,EACV,oCAAoC,EACpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,iCAAiC,EAClC,qCAAqC;AAEtC,OAAO,KAAK,EACV,yCAAyC,EACzC,2CAA2C,EAC5C,gDAAgD;AACjD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAG3C,OAAO,KAAK,EAAE,8CAA8C,EAAE,oEAAgE;AAG9H;;;;GAIG;AACH,QAAA,MAAM,cAAc,sCAAsC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACrC,WAAW,GACX,UAAU,GACV,aAAa,CAAC;AAElB;;;;;;;;GAQG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,OAAO,EAAE,GAAG,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAAG;IACnD,MAAM,EAAE,6BAA6B,CAAC;IACtC,OAAO,EAAE,oCAAoC,GAAG,IAAI,CAAC;CACtD,CAAC;AAiBF;;;;GAIG;AACH,wBAAgB,gDAAgD,IAAI,sCAAsC,CAKzG;AAUD;;GAEG;AACH,MAAM,MAAM,+CAA+C,GACzD,wBAAwB,CACtB,OAAO,cAAc,EACrB,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,cAAc,EACrB,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,cAAc,EACrB,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;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,iCAAkC,SAAQ,cAAc,CACnE,OAAO,cAAc,EACrB,sCAAsC,EACtC,0CAA0C,CAC3C;;IAOC;;;;;OAKG;gBACS,EAAE,SAAS,EAAE,EAAE,wCAAwC;IA6BnE;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAIrB;;;;;;;;OAQG;IACG,wBAAwB,CAAC,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA4N7E"}
@@ -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,EACV,oCAAoC,EACpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,iCAAiC,EAClC,qCAAqC;AAEtC,OAAO,KAAK,EACV,yCAAyC,EACzC,2CAA2C,EAC5C,gDAAgD;AACjD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAG3C,OAAO,KAAK,EAAE,8CAA8C,EAAE,oEAAgE;AAG9H;;;;GAIG;AACH,QAAA,MAAM,cAAc,sCAAsC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACrC,WAAW,GACX,UAAU,GACV,aAAa,CAAC;AAElB;;;;;;;;GAQG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,OAAO,EAAE,GAAG,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAAG;IACnD,MAAM,EAAE,6BAA6B,CAAC;IACtC,OAAO,EAAE,oCAAoC,GAAG,IAAI,CAAC;CACtD,CAAC;AAiBF;;;;GAIG;AACH,wBAAgB,gDAAgD,IAAI,sCAAsC,CAKzG;AAUD;;GAEG;AACH,MAAM,MAAM,+CAA+C,GACzD,wBAAwB,CACtB,OAAO,cAAc,EACrB,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,cAAc,EACrB,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,cAAc,EACrB,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;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,iCAAkC,SAAQ,cAAc,CACnE,OAAO,cAAc,EACrB,sCAAsC,EACtC,0CAA0C,CAC3C;;IAKC;;;;;OAKG;gBACS,EAAE,SAAS,EAAE,EAAE,wCAAwC;IA6BnE;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAIrB;;;;;;;;OAQG;IACG,wBAAwB,CAAC,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAwN7E"}
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,EACV,oCAAoC,EACpC,sCAAsC,EACvC,0CAA0C;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,uDAAuD,EACvD,+BAA+B,EAC/B,oCAAoC,EACpC,iCAAiC,EAClC,qCAAqC;AAEtC,OAAO,KAAK,EACV,yCAAyC,EACzC,2CAA2C,EAC5C,gDAAgD;AACjD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAG3C,OAAO,KAAK,EAAE,8CAA8C,EAAE,oEAAgE;AAG9H;;;;GAIG;AACH,QAAA,MAAM,cAAc,sCAAsC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACrC,WAAW,GACX,UAAU,GACV,aAAa,CAAC;AAElB;;;;;;;;GAQG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,OAAO,EAAE,GAAG,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAAG;IACnD,MAAM,EAAE,6BAA6B,CAAC;IACtC,OAAO,EAAE,oCAAoC,GAAG,IAAI,CAAC;CACtD,CAAC;AAiBF;;;;GAIG;AACH,wBAAgB,gDAAgD,IAAI,sCAAsC,CAKzG;AAUD;;GAEG;AACH,MAAM,MAAM,+CAA+C,GACzD,wBAAwB,CACtB,OAAO,cAAc,EACrB,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,cAAc,EACrB,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,cAAc,EACrB,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;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,iCAAkC,SAAQ,cAAc,CACnE,OAAO,cAAc,EACrB,sCAAsC,EACtC,0CAA0C,CAC3C;;IAOC;;;;;OAKG;gBACS,EAAE,SAAS,EAAE,EAAE,wCAAwC;IA6BnE;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAIrB;;;;;;;;OAQG;IACG,wBAAwB,CAAC,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA4N7E"}
@@ -9,7 +9,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
9
9
  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");
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
- var _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_evaluate, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetworkForBanner;
12
+ var _NetworkConnectionBannerController_instances, _NetworkConnectionBannerController_degradedTimer, _NetworkConnectionBannerController_unavailableTimer, _NetworkConnectionBannerController_pendingNetworkClientId, _NetworkConnectionBannerController_evaluate, _NetworkConnectionBannerController_resetBanner, _NetworkConnectionBannerController_clearTimers, _NetworkConnectionBannerController_findFailedNetworkForBanner;
13
13
  import { BaseController } from "@metamask/base-controller";
14
14
  import { CONNECTIVITY_STATUSES } from "@metamask/connectivity-controller";
15
15
  import { NetworkStatus } from "@metamask/network-controller";
@@ -92,6 +92,7 @@ export class NetworkConnectionBannerController extends BaseController {
92
92
  _NetworkConnectionBannerController_instances.add(this);
93
93
  _NetworkConnectionBannerController_degradedTimer.set(this, void 0);
94
94
  _NetworkConnectionBannerController_unavailableTimer.set(this, void 0);
95
+ _NetworkConnectionBannerController_pendingNetworkClientId.set(this, void 0);
95
96
  const onStateChange = () => __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_evaluate).call(this);
96
97
  // Upstream controllers still expose :stateChange; switch to :stateChanged
97
98
  // once those packages migrate their event types.
@@ -138,7 +139,7 @@ export class NetworkConnectionBannerController extends BaseController {
138
139
  }, { replacementSelectedRpcEndpointIndex: infuraEndpointIndex });
139
140
  }
140
141
  }
141
- _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_evaluate = function _NetworkConnectionBannerController_evaluate() {
142
+ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnectionBannerController_unavailableTimer = new WeakMap(), _NetworkConnectionBannerController_pendingNetworkClientId = new WeakMap(), _NetworkConnectionBannerController_instances = new WeakSet(), _NetworkConnectionBannerController_evaluate = function _NetworkConnectionBannerController_evaluate() {
142
143
  const { connectivityStatus } = this.messenger.call('ConnectivityController:getState');
143
144
  if (connectivityStatus === CONNECTIVITY_STATUSES.Offline) {
144
145
  __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_resetBanner).call(this);
@@ -149,9 +150,6 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
149
150
  __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_resetBanner).call(this);
150
151
  return;
151
152
  }
152
- // If the banner is currently showing for a different network or status,
153
- // restart the escalation timeline for the new one. Otherwise let the
154
- // existing timers continue.
155
153
  if (this.state.status !== 'available' &&
156
154
  this.state.network?.networkClientId === failed.networkClientId) {
157
155
  this.update((draft) => {
@@ -159,13 +157,18 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
159
157
  });
160
158
  return;
161
159
  }
160
+ if (__classPrivateFieldGet(this, _NetworkConnectionBannerController_pendingNetworkClientId, "f") === failed.networkClientId) {
161
+ return;
162
+ }
162
163
  __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_clearTimers).call(this);
163
164
  this.update((draft) => {
164
165
  draft.status = 'available';
165
166
  draft.network = null;
166
167
  });
168
+ __classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, failed.networkClientId, "f");
167
169
  __classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedTimer, setTimeout(() => {
168
170
  __classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedTimer, undefined, "f");
171
+ __classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, undefined, "f");
169
172
  const stillFailed = __classPrivateFieldGet(this, _NetworkConnectionBannerController_instances, "m", _NetworkConnectionBannerController_findFailedNetworkForBanner).call(this);
170
173
  if (!stillFailed) {
171
174
  return;
@@ -195,6 +198,7 @@ _NetworkConnectionBannerController_degradedTimer = new WeakMap(), _NetworkConnec
195
198
  });
196
199
  }
197
200
  }, _NetworkConnectionBannerController_clearTimers = function _NetworkConnectionBannerController_clearTimers() {
201
+ __classPrivateFieldSet(this, _NetworkConnectionBannerController_pendingNetworkClientId, undefined, "f");
198
202
  if (__classPrivateFieldGet(this, _NetworkConnectionBannerController_degradedTimer, "f") !== undefined) {
199
203
  clearTimeout(__classPrivateFieldGet(this, _NetworkConnectionBannerController_degradedTimer, "f"));
200
204
  __classPrivateFieldSet(this, _NetworkConnectionBannerController_degradedTimer, undefined, "f");
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkConnectionBannerController.mjs","sourceRoot":"","sources":["../src/NetworkConnectionBannerController.ts"],"names":[],"mappings":";;;;;;;;;;;;AAKA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,0CAA0C;AAY1E,OAAO,EAAE,aAAa,EAAE,qCAAqC;AAM7D,OAAO,EAAE,kBAAkB,EAAE,wBAAwB;AAGrD,OAAO,EAAE,SAAS,EAAE,wBAAoB;AAExC;;;;GAIG;AACH,MAAM,cAAc,GAAG,mCAAmC,CAAC;AAsC3D,MAAM,yCAAyC,GAAG;IAChD,MAAM,EAAE;QACN,OAAO,EAAE,KAAK;QACd,sBAAsB,EAAE,IAAI;QAC5B,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,IAAI;KACf;IACD,OAAO,EAAE;QACP,OAAO,EAAE,KAAK;QACd,sBAAsB,EAAE,IAAI;QAC5B,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,IAAI;KACf;CAC8D,CAAC;AAElE;;;;GAIG;AACH,MAAM,UAAU,gDAAgD;IAC9D,OAAO;QACL,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,MAAM,0BAA0B,GAAG,IAAK,CAAC;AACzC,MAAM,6BAA6B,GAAG,KAAM,CAAC;AAE7C,MAAM,yBAAyB,GAAG;IAChC,eAAe;IACf,0BAA0B;CAClB,CAAC;AA4EX;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,iCAAkC,SAAQ,cAItD;IAKC;;;;;OAKG;IACH,YAAY,EAAE,SAAS,EAA4C;QACjE,KAAK,CAAC;YACJ,SAAS;YACT,QAAQ,EAAE,yCAAyC;YACnD,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE,gDAAgD,EAAE;SAC1D,CAAC,CAAC;;QAhBL,mEAA0D;QAE1D,sEAA6D;QAgB3D,MAAM,aAAa,GAAG,GAAS,EAAE,CAAC,uBAAA,IAAI,iGAAU,MAAd,IAAI,CAAY,CAAC;QACnD,0EAA0E;QAC1E,iDAAiD;QACjD,sFAAsF;QACtF,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,+BAA+B,EAAE,aAAa,CAAC,CAAC;QACzE,IAAI,CAAC,SAAS,CAAC,SAAS,CACtB,yCAAyC,EACzC,aAAa,CACd,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,SAAS,CACtB,oCAAoC,EACpC,aAAa,CACd,CAAC;QACF,wCAAwC;QAExC,IAAI,CAAC,SAAS,CAAC,4BAA4B,CACzC,IAAI,EACJ,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,aAAa;QACX,uBAAA,IAAI,oGAAa,MAAjB,IAAI,CAAe,CAAC;IACtB,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,wBAAwB,CAAC,EAAE,OAAO,EAAoB;QAC1D,MAAM,oBAAoB,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,oDAAoD,EACpD,OAAO,CACR,CAAC;QACF,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,gDAAgD,OAAO,IAAI,CAC5D,CAAC;QACJ,CAAC;QAED,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,YAAY,CAAC,SAAS,CACrE,CAAC,QAAQ,EAAE,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAC7C,CAAC;QACF,IAAI,mBAAmB,KAAK,CAAC,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,8CAA8C,OAAO,IAAI,CAC1D,CAAC;QACJ,CAAC;QACD,IAAI,mBAAmB,KAAK,oBAAoB,CAAC,uBAAuB,EAAE,CAAC;YACzE,gDAAgD;YAChD,OAAO;QACT,CAAC;QAED,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACvB,iCAAiC,EACjC,OAAO,EACP;YACE,GAAG,oBAAoB;YACvB,uBAAuB,EAAE,mBAAmB;SAC7C,EACD,EAAE,mCAAmC,EAAE,mBAAmB,EAAE,CAC7D,CAAC;IACJ,CAAC;CAuLF;;IApLG,MAAM,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAChD,iCAAiC,CAClC,CAAC;IACF,IAAI,kBAAkB,KAAK,qBAAqB,CAAC,OAAO,EAAE,CAAC;QACzD,uBAAA,IAAI,oGAAa,MAAjB,IAAI,CAAe,CAAC;QACpB,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,uBAAA,IAAI,mHAA4B,MAAhC,IAAI,CAA8B,CAAC;IAElD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,uBAAA,IAAI,oGAAa,MAAjB,IAAI,CAAe,CAAC;QACpB,OAAO;IACT,CAAC;IAED,wEAAwE;IACxE,qEAAqE;IACrE,4BAA4B;IAC5B,IACE,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW;QACjC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,CAAC,eAAe,EAC9D,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,uBAAA,IAAI,oGAAa,MAAjB,IAAI,CAAe,CAAC;IACpB,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QACpB,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC;QAC3B,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,uBAAA,IAAI,oDAAkB,UAAU,CAAC,GAAG,EAAE;QACpC,uBAAA,IAAI,oDAAkB,SAAS,MAAA,CAAC;QAChC,MAAM,WAAW,GAAG,uBAAA,IAAI,mHAA4B,MAAhC,IAAI,CAA8B,CAAC;QACvD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;YAC1B,KAAK,CAAC,OAAO,GAAG,WAAW,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,uBAAA,IAAI,uDAAqB,UAAU,CAAC,GAAG,EAAE;YACvC,uBAAA,IAAI,uDAAqB,SAAS,MAAA,CAAC;YACnC,MAAM,uBAAuB,GAAG,uBAAA,IAAI,mHAA4B,MAAhC,IAAI,CAA8B,CAAC;YACnE,IAAI,CAAC,uBAAuB,EAAE,CAAC;gBAC7B,OAAO;YACT,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpB,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC;gBAC7B,KAAK,CAAC,OAAO,GAAG,uBAAuB,CAAC;YAC1C,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,6BAA6B,GAAG,0BAA0B,CAAC,MAAA,CAAC;IACjE,CAAC,EAAE,0BAA0B,CAAC,MAAA,CAAC;AACjC,CAAC;IAOC,uBAAA,IAAI,oGAAa,MAAjB,IAAI,CAAe,CAAC;IACpB,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QACrE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC;YAC3B,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;IAGC,IAAI,uBAAA,IAAI,wDAAe,KAAK,SAAS,EAAE,CAAC;QACtC,YAAY,CAAC,uBAAA,IAAI,wDAAe,CAAC,CAAC;QAClC,uBAAA,IAAI,oDAAkB,SAAS,MAAA,CAAC;IAClC,CAAC;IACD,IAAI,uBAAA,IAAI,2DAAkB,KAAK,SAAS,EAAE,CAAC;QACzC,YAAY,CAAC,uBAAA,IAAI,2DAAkB,CAAC,CAAC;QACrC,uBAAA,IAAI,uDAAqB,SAAS,MAAA,CAAC;IACrC,CAAC;AACH,CAAC;IAGC,MAAM,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAC/C,sCAAsC,CACvC,CAAC;IACF,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,CACvC,iBAAiB,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,EAAE,CACnD;SACE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,OAAc,CAAC,CAAC;IACtC,MAAM,EAAE,8BAA8B,EAAE,gBAAgB,EAAE,GACxD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAKpD,MAAM,cAAc,GAA4B,EAAE,CAAC;IACnD,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;QACzC,MAAM,oBAAoB,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC;QACrE,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QAED,MAAM,EAAE,YAAY,EAAE,uBAAuB,EAAE,IAAI,EAAE,GACnD,oBAAoB,CAAC;QACvB,MAAM,kBAAkB,GAAG,YAAY,CAAC,uBAAuB,CAAC,CAAC;QACjE,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,SAAS;QACX,CAAC;QAED,YAAY,IAAI,CAAC,CAAC;QAElB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;QACtE,IACE,QAAQ,KAAK,SAAS;YACtB,QAAQ,CAAC,MAAM,KAAK,aAAa,CAAC,SAAS,EAC3C,CAAC;YACD,SAAS;QACX,CAAC;QAED,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAElE,qEAAqE;QACrE,0CAA0C;QAC1C,IAAI,qBAAqB,GAAkB,IAAI,CAAC;QAChD,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CACnC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAClB,KAAK,KAAK,uBAAuB,IAAI,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,CACtE,CAAC;YACF,qBAAqB,GAAG,WAAW,EAAE,eAAe,IAAI,IAAI,CAAC;QAC/D,CAAC;QAED,cAAc,CAAC,IAAI,CAAC;YAClB,OAAO;YACP,eAAe,EAAE,kBAAkB,CAAC,eAAe;YACnD,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,kBAAkB,CAAC,GAAG;YAC9B,gBAAgB,EAAE,gBAAgB;YAClC,qBAAqB;YACrB,MAAM,EAAE,SAAS,CAAC,kBAAkB,CAAC,GAAG,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,iBAAiB,GAAG,cAAc,CAAC,IAAI,CAC3C,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CACnC,CAAC;IACF,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,cAAc;SACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;SAC5B,MAAM,CAAC,CAAC,MAAM,EAAoB,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,CACzD,CAAC,IAAI,CAAC;IACP,MAAM,2BAA2B,GAAG,cAAc,CAAC,MAAM,KAAK,YAAY,CAAC;IAE3E,IACE,CAAC,iBAAiB;QAClB,eAAe,IAAI,CAAC;QACpB,CAAC,2BAA2B,EAC5B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,iBAAiB,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO;QACL,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,eAAe,EAAE,QAAQ,CAAC,eAAe;QACzC,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;QAC3C,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB;KACtD,CAAC;AACJ,CAAC;AAGH;;;;;;;GAOG;AACH,SAAS,gBAAgB,CAAC,GAAW;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { CONNECTIVITY_STATUSES } from '@metamask/connectivity-controller';\nimport type {\n ConnectivityControllerGetStateAction,\n ConnectivityControllerStateChangeEvent,\n} from '@metamask/connectivity-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport { NetworkStatus } from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerStateChangeEvent,\n} from '@metamask/network-enablement-controller';\nimport type { Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\n\nimport type { NetworkConnectionBannerControllerMethodActions } from './NetworkConnectionBannerController-method-action-types';\nimport { getDomain } 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 controllerName = 'NetworkConnectionBannerController';\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 * Details of the failing network the banner should describe. Populated when\n * {@link NetworkConnectionBannerControllerState.status} is `degraded` or\n * `unavailable`, `null` otherwise.\n *\n * `infuraNetworkClientId` is the networkClientId of an Infura endpoint on the\n * same chain that the user can switch to. `null` when the failing endpoint is\n * already Infura, or when no Infura alternative exists.\n */\nexport type NetworkConnectionBannerFailedNetwork = {\n chainId: Hex;\n networkClientId: string;\n networkName: string;\n rpcUrl: string;\n isInfuraEndpoint: boolean;\n infuraNetworkClientId: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerState = {\n status: NetworkConnectionBannerStatus;\n network: NetworkConnectionBannerFailedNetwork | 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\nconst DEGRADED_BANNER_TIMEOUT_MS = 5_000;\nconst UNAVAILABLE_BANNER_TIMEOUT_MS = 30_000;\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'dismissBanner',\n 'switchToDefaultInfuraRpc',\n] as const;\n\n/**\n * Retrieves the state of the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\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 controllerName,\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 controllerName,\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 that was previously duplicated across MetaMask clients.\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 is failing (escape hatch for single-network\n * 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 switchToDefaultInfuraRpc}.\n */\nexport class NetworkConnectionBannerController extends BaseController<\n typeof controllerName,\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerMessenger\n> {\n #degradedTimer: ReturnType<typeof setTimeout> | undefined;\n\n #unavailableTimer: ReturnType<typeof setTimeout> | undefined;\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: controllerName,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\n\n const onStateChange = (): void => this.#evaluate();\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('NetworkController:stateChange', onStateChange);\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n onStateChange,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n onStateChange,\n );\n /* eslint-enable no-restricted-syntax */\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Clears the banner state regardless of the current rule outcome. The next\n * subscription-driven evaluation will re-show the banner if the conditions\n * still hold.\n */\n dismissBanner(): void {\n this.#resetBanner();\n }\n\n /**\n * Switches the chain's default RPC endpoint to its first Infura endpoint,\n * causing the banner to clear once the network becomes available again.\n *\n * @param args - The arguments to this action.\n * @param args.chainId - The chain whose default RPC 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 switchToDefaultInfuraRpc({ chainId }: { 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) => isInfuraEndpoint(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 #evaluate(): void {\n const { connectivityStatus } = this.messenger.call(\n 'ConnectivityController:getState',\n );\n if (connectivityStatus === CONNECTIVITY_STATUSES.Offline) {\n this.#resetBanner();\n return;\n }\n\n const failed = this.#findFailedNetworkForBanner();\n\n if (!failed) {\n this.#resetBanner();\n return;\n }\n\n // If the banner is currently showing for a different network or status,\n // restart the escalation timeline for the new one. Otherwise let the\n // existing timers continue.\n if (\n this.state.status !== 'available' &&\n this.state.network?.networkClientId === failed.networkClientId\n ) {\n this.update((draft) => {\n draft.network = failed;\n });\n return;\n }\n\n this.#clearTimers();\n this.update((draft) => {\n draft.status = 'available';\n draft.network = null;\n });\n\n this.#degradedTimer = setTimeout(() => {\n this.#degradedTimer = undefined;\n const stillFailed = this.#findFailedNetworkForBanner();\n if (!stillFailed) {\n return;\n }\n this.update((draft) => {\n draft.status = 'degraded';\n draft.network = stillFailed;\n });\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n const stillFailedAtEscalation = this.#findFailedNetworkForBanner();\n if (!stillFailedAtEscalation) {\n return;\n }\n this.update((draft) => {\n draft.status = 'unavailable';\n draft.network = stillFailedAtEscalation;\n });\n }, UNAVAILABLE_BANNER_TIMEOUT_MS - DEGRADED_BANNER_TIMEOUT_MS);\n }, DEGRADED_BANNER_TIMEOUT_MS);\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 if (this.state.status !== 'available' || this.state.network !== null) {\n this.update((draft) => {\n draft.status = 'available';\n draft.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 #findFailedNetworkForBanner(): NetworkConnectionBannerFailedNetwork | null {\n const { enabledNetworkMap } = this.messenger.call(\n 'NetworkEnablementController:getState',\n );\n const enabledEvmChainIds = Object.entries(\n enabledNetworkMap[KnownCaipNamespace.Eip155] ?? {},\n )\n .filter(([, enabled]) => enabled)\n .map(([chainId]) => chainId as Hex);\n const { networkConfigurationsByChainId, networksMetadata } =\n this.messenger.call('NetworkController:getState');\n\n type EnrichedFailedNetwork = NetworkConnectionBannerFailedNetwork & {\n domain: string | null;\n };\n const failedNetworks: EnrichedFailedNetwork[] = [];\n let totalEnabled = 0;\n\n for (const chainId of enabledEvmChainIds) {\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n continue;\n }\n\n const { rpcEndpoints, defaultRpcEndpointIndex, name } =\n networkConfiguration;\n const defaultRpcEndpoint = rpcEndpoints[defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n continue;\n }\n\n totalEnabled += 1;\n\n const metadata = networksMetadata[defaultRpcEndpoint.networkClientId];\n if (\n metadata === undefined ||\n metadata.status === NetworkStatus.Available\n ) {\n continue;\n }\n\n const endpointIsInfura = isInfuraEndpoint(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 infuraNetworkClientId: string | null = null;\n if (!endpointIsInfura) {\n const otherInfura = rpcEndpoints.find(\n (endpoint, index) =>\n index !== defaultRpcEndpointIndex && isInfuraEndpoint(endpoint.url),\n );\n infuraNetworkClientId = otherInfura?.networkClientId ?? null;\n }\n\n failedNetworks.push({\n chainId,\n networkClientId: defaultRpcEndpoint.networkClientId,\n networkName: name,\n rpcUrl: defaultRpcEndpoint.url,\n isInfuraEndpoint: endpointIsInfura,\n infuraNetworkClientId,\n domain: getDomain(defaultRpcEndpoint.url),\n });\n }\n\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 areAllEnabledNetworksFailed = failedNetworks.length === totalEnabled;\n\n if (\n !firstCustomFailed &&\n distinctDomains <= 1 &&\n !areAllEnabledNetworksFailed\n ) {\n return null;\n }\n\n const selected = firstCustomFailed ?? failedNetworks[0];\n return {\n chainId: selected.chainId,\n networkClientId: selected.networkClientId,\n networkName: selected.networkName,\n rpcUrl: selected.rpcUrl,\n isInfuraEndpoint: selected.isInfuraEndpoint,\n infuraNetworkClientId: selected.infuraNetworkClientId,\n };\n }\n}\n\n/**\n * Checks if an RPC URL is hosted on the Infura service. Detection is by\n * hostname suffix rather than the exact MetaMask-key URL pattern, so any\n * `*.infura.io` URL counts. That's the right shape for grouping by provider.\n *\n * @param url - The RPC URL to check.\n * @returns True if the URL's host is on `infura.io`.\n */\nfunction isInfuraEndpoint(url: string): boolean {\n try {\n return new URL(url).hostname.toLowerCase().endsWith('.infura.io');\n } catch {\n return false;\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 { CONNECTIVITY_STATUSES } from '@metamask/connectivity-controller';\nimport type {\n ConnectivityControllerGetStateAction,\n ConnectivityControllerStateChangeEvent,\n} from '@metamask/connectivity-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkConfigurationByChainIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerUpdateNetworkAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport { NetworkStatus } from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerStateChangeEvent,\n} from '@metamask/network-enablement-controller';\nimport type { Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\n\nimport type { NetworkConnectionBannerControllerMethodActions } from './NetworkConnectionBannerController-method-action-types';\nimport { getDomain } 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 controllerName = 'NetworkConnectionBannerController';\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 * Details of the failing network the banner should describe. Populated when\n * {@link NetworkConnectionBannerControllerState.status} is `degraded` or\n * `unavailable`, `null` otherwise.\n *\n * `infuraNetworkClientId` is the networkClientId of an Infura endpoint on the\n * same chain that the user can switch to. `null` when the failing endpoint is\n * already Infura, or when no Infura alternative exists.\n */\nexport type NetworkConnectionBannerFailedNetwork = {\n chainId: Hex;\n networkClientId: string;\n networkName: string;\n rpcUrl: string;\n isInfuraEndpoint: boolean;\n infuraNetworkClientId: string | null;\n};\n\n/**\n * State for the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerState = {\n status: NetworkConnectionBannerStatus;\n network: NetworkConnectionBannerFailedNetwork | 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\nconst DEGRADED_BANNER_TIMEOUT_MS = 5_000;\nconst UNAVAILABLE_BANNER_TIMEOUT_MS = 30_000;\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'dismissBanner',\n 'switchToDefaultInfuraRpc',\n] as const;\n\n/**\n * Retrieves the state of the {@link NetworkConnectionBannerController}.\n */\nexport type NetworkConnectionBannerControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\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 controllerName,\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 controllerName,\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 that was previously duplicated across MetaMask clients.\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 is failing (escape hatch for single-network\n * 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 switchToDefaultInfuraRpc}.\n */\nexport class NetworkConnectionBannerController extends BaseController<\n typeof controllerName,\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 /**\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: controllerName,\n state: getDefaultNetworkConnectionBannerControllerState(),\n });\n\n const onStateChange = (): void => this.#evaluate();\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('NetworkController:stateChange', onStateChange);\n this.messenger.subscribe(\n 'NetworkEnablementController:stateChange',\n onStateChange,\n );\n this.messenger.subscribe(\n 'ConnectivityController:stateChange',\n onStateChange,\n );\n /* eslint-enable no-restricted-syntax */\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Clears the banner state regardless of the current rule outcome. The next\n * subscription-driven evaluation will re-show the banner if the conditions\n * still hold.\n */\n dismissBanner(): void {\n this.#resetBanner();\n }\n\n /**\n * Switches the chain's default RPC endpoint to its first Infura endpoint,\n * causing the banner to clear once the network becomes available again.\n *\n * @param args - The arguments to this action.\n * @param args.chainId - The chain whose default RPC 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 switchToDefaultInfuraRpc({ chainId }: { 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) => isInfuraEndpoint(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 #evaluate(): void {\n const { connectivityStatus } = this.messenger.call(\n 'ConnectivityController:getState',\n );\n if (connectivityStatus === CONNECTIVITY_STATUSES.Offline) {\n this.#resetBanner();\n return;\n }\n\n const failed = this.#findFailedNetworkForBanner();\n\n if (!failed) {\n this.#resetBanner();\n return;\n }\n\n if (\n this.state.status !== 'available' &&\n this.state.network?.networkClientId === failed.networkClientId\n ) {\n this.update((draft) => {\n draft.network = failed;\n });\n return;\n }\n\n if (this.#pendingNetworkClientId === failed.networkClientId) {\n return;\n }\n\n this.#clearTimers();\n this.update((draft) => {\n draft.status = 'available';\n draft.network = null;\n });\n\n this.#pendingNetworkClientId = failed.networkClientId;\n this.#degradedTimer = setTimeout(() => {\n this.#degradedTimer = undefined;\n this.#pendingNetworkClientId = undefined;\n const stillFailed = this.#findFailedNetworkForBanner();\n if (!stillFailed) {\n return;\n }\n this.update((draft) => {\n draft.status = 'degraded';\n draft.network = stillFailed;\n });\n this.#unavailableTimer = setTimeout(() => {\n this.#unavailableTimer = undefined;\n const stillFailedAtEscalation = this.#findFailedNetworkForBanner();\n if (!stillFailedAtEscalation) {\n return;\n }\n this.update((draft) => {\n draft.status = 'unavailable';\n draft.network = stillFailedAtEscalation;\n });\n }, UNAVAILABLE_BANNER_TIMEOUT_MS - DEGRADED_BANNER_TIMEOUT_MS);\n }, DEGRADED_BANNER_TIMEOUT_MS);\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 if (this.state.status !== 'available' || this.state.network !== null) {\n this.update((draft) => {\n draft.status = 'available';\n draft.network = null;\n });\n }\n }\n\n #clearTimers(): void {\n this.#pendingNetworkClientId = undefined;\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 #findFailedNetworkForBanner(): NetworkConnectionBannerFailedNetwork | null {\n const { enabledNetworkMap } = this.messenger.call(\n 'NetworkEnablementController:getState',\n );\n const enabledEvmChainIds = Object.entries(\n enabledNetworkMap[KnownCaipNamespace.Eip155] ?? {},\n )\n .filter(([, enabled]) => enabled)\n .map(([chainId]) => chainId as Hex);\n const { networkConfigurationsByChainId, networksMetadata } =\n this.messenger.call('NetworkController:getState');\n\n type EnrichedFailedNetwork = NetworkConnectionBannerFailedNetwork & {\n domain: string | null;\n };\n const failedNetworks: EnrichedFailedNetwork[] = [];\n let totalEnabled = 0;\n\n for (const chainId of enabledEvmChainIds) {\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n continue;\n }\n\n const { rpcEndpoints, defaultRpcEndpointIndex, name } =\n networkConfiguration;\n const defaultRpcEndpoint = rpcEndpoints[defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n continue;\n }\n\n totalEnabled += 1;\n\n const metadata = networksMetadata[defaultRpcEndpoint.networkClientId];\n if (\n metadata === undefined ||\n metadata.status === NetworkStatus.Available\n ) {\n continue;\n }\n\n const endpointIsInfura = isInfuraEndpoint(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 infuraNetworkClientId: string | null = null;\n if (!endpointIsInfura) {\n const otherInfura = rpcEndpoints.find(\n (endpoint, index) =>\n index !== defaultRpcEndpointIndex && isInfuraEndpoint(endpoint.url),\n );\n infuraNetworkClientId = otherInfura?.networkClientId ?? null;\n }\n\n failedNetworks.push({\n chainId,\n networkClientId: defaultRpcEndpoint.networkClientId,\n networkName: name,\n rpcUrl: defaultRpcEndpoint.url,\n isInfuraEndpoint: endpointIsInfura,\n infuraNetworkClientId,\n domain: getDomain(defaultRpcEndpoint.url),\n });\n }\n\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 areAllEnabledNetworksFailed = failedNetworks.length === totalEnabled;\n\n if (\n !firstCustomFailed &&\n distinctDomains <= 1 &&\n !areAllEnabledNetworksFailed\n ) {\n return null;\n }\n\n const selected = firstCustomFailed ?? failedNetworks[0];\n return {\n chainId: selected.chainId,\n networkClientId: selected.networkClientId,\n networkName: selected.networkName,\n rpcUrl: selected.rpcUrl,\n isInfuraEndpoint: selected.isInfuraEndpoint,\n infuraNetworkClientId: selected.infuraNetworkClientId,\n };\n }\n}\n\n/**\n * Checks if an RPC URL is hosted on the Infura service. Detection is by\n * hostname suffix rather than the exact MetaMask-key URL pattern, so any\n * `*.infura.io` URL counts. That's the right shape for grouping by provider.\n *\n * @param url - The RPC URL to check.\n * @returns True if the URL's host is on `infura.io`.\n */\nfunction isInfuraEndpoint(url: string): boolean {\n try {\n return new URL(url).hostname.toLowerCase().endsWith('.infura.io');\n } catch {\n return false;\n }\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isLocalhostOrIPAddress = exports.getDomain = exports.getDefaultNetworkConnectionBannerControllerState = exports.NetworkConnectionBannerController = void 0;
3
+ exports.networkConnectionBannerControllerSelectors = exports.isLocalhostOrIPAddress = exports.getDomain = 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
7
  var url_utils_1 = require("./url-utils.cjs");
8
8
  Object.defineProperty(exports, "getDomain", { enumerable: true, get: function () { return url_utils_1.getDomain; } });
9
9
  Object.defineProperty(exports, "isLocalhostOrIPAddress", { enumerable: true, get: function () { return url_utils_1.isLocalhostOrIPAddress; } });
10
+ var selectors_1 = require("./selectors.cjs");
11
+ Object.defineProperty(exports, "networkConnectionBannerControllerSelectors", { enumerable: true, get: function () { return selectors_1.networkConnectionBannerControllerSelectors; } });
10
12
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAeA,6FAG6C;AAF3C,sJAAA,iCAAiC,OAAA;AACjC,qKAAA,gDAAgD,OAAA;AAElD,6CAAgE;AAAvD,sGAAA,SAAS,OAAA;AAAE,mHAAA,sBAAsB,OAAA","sourcesContent":["export type {\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerGetStateAction,\n NetworkConnectionBannerControllerActions,\n NetworkConnectionBannerControllerStateChangedEvent,\n NetworkConnectionBannerControllerEvents,\n NetworkConnectionBannerControllerMessenger,\n NetworkConnectionBannerControllerOptions,\n NetworkConnectionBannerFailedNetwork,\n NetworkConnectionBannerStatus,\n} from './NetworkConnectionBannerController';\nexport type {\n NetworkConnectionBannerControllerDismissBannerAction,\n NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcAction,\n} from './NetworkConnectionBannerController-method-action-types';\nexport {\n NetworkConnectionBannerController,\n getDefaultNetworkConnectionBannerControllerState,\n} from './NetworkConnectionBannerController';\nexport { getDomain, isLocalhostOrIPAddress } from './url-utils';\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAeA,6FAG6C;AAF3C,sJAAA,iCAAiC,OAAA;AACjC,qKAAA,gDAAgD,OAAA;AAElD,6CAAgE;AAAvD,sGAAA,SAAS,OAAA;AAAE,mHAAA,sBAAsB,OAAA;AAC1C,6CAAyE;AAAhE,uIAAA,0CAA0C,OAAA","sourcesContent":["export type {\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerGetStateAction,\n NetworkConnectionBannerControllerActions,\n NetworkConnectionBannerControllerStateChangedEvent,\n NetworkConnectionBannerControllerEvents,\n NetworkConnectionBannerControllerMessenger,\n NetworkConnectionBannerControllerOptions,\n NetworkConnectionBannerFailedNetwork,\n NetworkConnectionBannerStatus,\n} from './NetworkConnectionBannerController';\nexport type {\n NetworkConnectionBannerControllerDismissBannerAction,\n NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcAction,\n} from './NetworkConnectionBannerController-method-action-types';\nexport {\n NetworkConnectionBannerController,\n getDefaultNetworkConnectionBannerControllerState,\n} from './NetworkConnectionBannerController';\nexport { getDomain, isLocalhostOrIPAddress } from './url-utils';\nexport { networkConnectionBannerControllerSelectors } from './selectors';\n"]}
package/dist/index.d.cts CHANGED
@@ -2,4 +2,5 @@ export type { NetworkConnectionBannerControllerState, NetworkConnectionBannerCon
2
2
  export type { NetworkConnectionBannerControllerDismissBannerAction, NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcAction, } from "./NetworkConnectionBannerController-method-action-types.cjs";
3
3
  export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState, } from "./NetworkConnectionBannerController.cjs";
4
4
  export { getDomain, isLocalhostOrIPAddress } from "./url-utils.cjs";
5
+ export { networkConnectionBannerControllerSelectors } from "./selectors.cjs";
5
6
  //# sourceMappingURL=index.d.cts.map
@@ -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,oCAAoC,EACpC,6BAA6B,GAC9B,gDAA4C;AAC7C,YAAY,EACV,oDAAoD,EACpD,+DAA+D,GAChE,oEAAgE;AACjE,OAAO,EACL,iCAAiC,EACjC,gDAAgD,GACjD,gDAA4C;AAC7C,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,wBAAoB"}
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,oCAAoC,EACpC,6BAA6B,GAC9B,gDAA4C;AAC7C,YAAY,EACV,oDAAoD,EACpD,+DAA+D,GAChE,oEAAgE;AACjE,OAAO,EACL,iCAAiC,EACjC,gDAAgD,GACjD,gDAA4C;AAC7C,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,wBAAoB;AAChE,OAAO,EAAE,0CAA0C,EAAE,wBAAoB"}
package/dist/index.d.mts CHANGED
@@ -2,4 +2,5 @@ export type { NetworkConnectionBannerControllerState, NetworkConnectionBannerCon
2
2
  export type { NetworkConnectionBannerControllerDismissBannerAction, NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcAction, } from "./NetworkConnectionBannerController-method-action-types.mjs";
3
3
  export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState, } from "./NetworkConnectionBannerController.mjs";
4
4
  export { getDomain, isLocalhostOrIPAddress } from "./url-utils.mjs";
5
+ export { networkConnectionBannerControllerSelectors } from "./selectors.mjs";
5
6
  //# sourceMappingURL=index.d.mts.map
@@ -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,oCAAoC,EACpC,6BAA6B,GAC9B,gDAA4C;AAC7C,YAAY,EACV,oDAAoD,EACpD,+DAA+D,GAChE,oEAAgE;AACjE,OAAO,EACL,iCAAiC,EACjC,gDAAgD,GACjD,gDAA4C;AAC7C,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,wBAAoB"}
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,oCAAoC,EACpC,6BAA6B,GAC9B,gDAA4C;AAC7C,YAAY,EACV,oDAAoD,EACpD,+DAA+D,GAChE,oEAAgE;AACjE,OAAO,EACL,iCAAiC,EACjC,gDAAgD,GACjD,gDAA4C;AAC7C,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,wBAAoB;AAChE,OAAO,EAAE,0CAA0C,EAAE,wBAAoB"}
package/dist/index.mjs CHANGED
@@ -1,3 +1,4 @@
1
1
  export { NetworkConnectionBannerController, getDefaultNetworkConnectionBannerControllerState } from "./NetworkConnectionBannerController.mjs";
2
2
  export { getDomain, isLocalhostOrIPAddress } from "./url-utils.mjs";
3
+ export { networkConnectionBannerControllerSelectors } from "./selectors.mjs";
3
4
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,iCAAiC,EACjC,gDAAgD,EACjD,gDAA4C;AAC7C,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,wBAAoB","sourcesContent":["export type {\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerGetStateAction,\n NetworkConnectionBannerControllerActions,\n NetworkConnectionBannerControllerStateChangedEvent,\n NetworkConnectionBannerControllerEvents,\n NetworkConnectionBannerControllerMessenger,\n NetworkConnectionBannerControllerOptions,\n NetworkConnectionBannerFailedNetwork,\n NetworkConnectionBannerStatus,\n} from './NetworkConnectionBannerController';\nexport type {\n NetworkConnectionBannerControllerDismissBannerAction,\n NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcAction,\n} from './NetworkConnectionBannerController-method-action-types';\nexport {\n NetworkConnectionBannerController,\n getDefaultNetworkConnectionBannerControllerState,\n} from './NetworkConnectionBannerController';\nexport { getDomain, isLocalhostOrIPAddress } from './url-utils';\n"]}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,iCAAiC,EACjC,gDAAgD,EACjD,gDAA4C;AAC7C,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,wBAAoB;AAChE,OAAO,EAAE,0CAA0C,EAAE,wBAAoB","sourcesContent":["export type {\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerControllerGetStateAction,\n NetworkConnectionBannerControllerActions,\n NetworkConnectionBannerControllerStateChangedEvent,\n NetworkConnectionBannerControllerEvents,\n NetworkConnectionBannerControllerMessenger,\n NetworkConnectionBannerControllerOptions,\n NetworkConnectionBannerFailedNetwork,\n NetworkConnectionBannerStatus,\n} from './NetworkConnectionBannerController';\nexport type {\n NetworkConnectionBannerControllerDismissBannerAction,\n NetworkConnectionBannerControllerSwitchToDefaultInfuraRpcAction,\n} from './NetworkConnectionBannerController-method-action-types';\nexport {\n NetworkConnectionBannerController,\n getDefaultNetworkConnectionBannerControllerState,\n} from './NetworkConnectionBannerController';\nexport { getDomain, isLocalhostOrIPAddress } from './url-utils';\nexport { networkConnectionBannerControllerSelectors } from './selectors';\n"]}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.networkConnectionBannerControllerSelectors = void 0;
4
+ const reselect_1 = require("reselect");
5
+ /**
6
+ * Selects the banner status from the controller state.
7
+ *
8
+ * @param state - The controller state
9
+ * @returns The banner status
10
+ */
11
+ const selectNetworkConnectionBannerStatus = (state) => state.status;
12
+ /**
13
+ * Selects the failing network the banner describes, or `null` when no banner
14
+ * is shown.
15
+ *
16
+ * @param state - The controller state
17
+ * @returns The failing network details, or `null`
18
+ */
19
+ const selectNetworkConnectionBannerNetwork = (state) => state.network;
20
+ /**
21
+ * Selects whether the banner is visible (status is `degraded` or
22
+ * `unavailable`).
23
+ *
24
+ * @param state - The controller state
25
+ * @returns Whether the banner is visible
26
+ */
27
+ const selectIsNetworkConnectionBannerVisible = (0, reselect_1.createSelector)([selectNetworkConnectionBannerStatus], (status) => status === 'degraded' || status === 'unavailable');
28
+ /**
29
+ * Selectors for the NetworkConnectionBannerController state.
30
+ * These can be used with Redux or directly with controller state.
31
+ */
32
+ exports.networkConnectionBannerControllerSelectors = {
33
+ selectNetworkConnectionBannerStatus,
34
+ selectNetworkConnectionBannerNetwork,
35
+ selectIsNetworkConnectionBannerVisible,
36
+ };
37
+ //# sourceMappingURL=selectors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.cjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":";;;AAAA,uCAA0C;AAQ1C;;;;;GAKG;AACH,MAAM,mCAAmC,GAAG,CAC1C,KAA6C,EACd,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,oCAAoC,GAAG,CAC3C,KAA6C,EACA,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,sCAAsC,GAAG,IAAA,yBAAc,EAC3D,CAAC,mCAAmC,CAAC,EACrC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,aAAa,CAC9D,CAAC;AAEF;;;GAGG;AACU,QAAA,0CAA0C,GAAG;IACxD,mCAAmC;IACnC,oCAAoC;IACpC,sCAAsC;CACvC,CAAC","sourcesContent":["import { createSelector } from 'reselect';\n\nimport type {\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerFailedNetwork,\n NetworkConnectionBannerStatus,\n} from './NetworkConnectionBannerController';\n\n/**\n * Selects the banner status from the controller state.\n *\n * @param state - The controller state\n * @returns The banner status\n */\nconst selectNetworkConnectionBannerStatus = (\n state: NetworkConnectionBannerControllerState,\n): NetworkConnectionBannerStatus => state.status;\n\n/**\n * Selects the failing network the banner describes, or `null` when no banner\n * is shown.\n *\n * @param state - The controller state\n * @returns The failing network details, or `null`\n */\nconst selectNetworkConnectionBannerNetwork = (\n state: NetworkConnectionBannerControllerState,\n): NetworkConnectionBannerFailedNetwork | null => state.network;\n\n/**\n * Selects whether the banner is visible (status is `degraded` or\n * `unavailable`).\n *\n * @param state - The controller state\n * @returns Whether the banner is visible\n */\nconst selectIsNetworkConnectionBannerVisible = createSelector(\n [selectNetworkConnectionBannerStatus],\n (status) => status === 'degraded' || status === 'unavailable',\n);\n\n/**\n * Selectors for the NetworkConnectionBannerController state.\n * These can be used with Redux or directly with controller state.\n */\nexport const networkConnectionBannerControllerSelectors = {\n selectNetworkConnectionBannerStatus,\n selectNetworkConnectionBannerNetwork,\n selectIsNetworkConnectionBannerVisible,\n};\n"]}
@@ -0,0 +1,31 @@
1
+ import type { NetworkConnectionBannerControllerState, NetworkConnectionBannerFailedNetwork, NetworkConnectionBannerStatus } from "./NetworkConnectionBannerController.cjs";
2
+ /**
3
+ * Selectors for the NetworkConnectionBannerController state.
4
+ * These can be used with Redux or directly with controller state.
5
+ */
6
+ export declare const networkConnectionBannerControllerSelectors: {
7
+ selectNetworkConnectionBannerStatus: (state: NetworkConnectionBannerControllerState) => NetworkConnectionBannerStatus;
8
+ selectNetworkConnectionBannerNetwork: (state: NetworkConnectionBannerControllerState) => NetworkConnectionBannerFailedNetwork | null;
9
+ selectIsNetworkConnectionBannerVisible: ((state: NetworkConnectionBannerControllerState) => boolean) & {
10
+ clearCache: () => void;
11
+ resultsCount: () => number;
12
+ resetResultsCount: () => void;
13
+ } & {
14
+ resultFunc: (resultFuncArgs_0: NetworkConnectionBannerStatus) => boolean;
15
+ memoizedResultFunc: ((resultFuncArgs_0: NetworkConnectionBannerStatus) => boolean) & {
16
+ clearCache: () => void;
17
+ resultsCount: () => number;
18
+ resetResultsCount: () => void;
19
+ };
20
+ lastResult: () => boolean;
21
+ dependencies: [(state: NetworkConnectionBannerControllerState) => NetworkConnectionBannerStatus];
22
+ recomputations: () => number;
23
+ resetRecomputations: () => void;
24
+ dependencyRecomputations: () => number;
25
+ resetDependencyRecomputations: () => void;
26
+ } & {
27
+ memoize: typeof import("reselect").weakMapMemoize;
28
+ argsMemoize: typeof import("reselect").weakMapMemoize;
29
+ };
30
+ };
31
+ //# sourceMappingURL=selectors.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.cts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,sCAAsC,EACtC,oCAAoC,EACpC,6BAA6B,EAC9B,gDAA4C;AAmC7C;;;GAGG;AACH,eAAO,MAAM,0CAA0C;iDA9B9C,sCAAsC,KAC5C,6BAA6B;kDAUvB,sCAAsC,KAC5C,oCAAoC,GAAG,IAAI;;;;;;;;;;;;;+BAZrC,sCAAsC,KAC5C,6BAA6B;;;;;;;;;CAiC/B,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { NetworkConnectionBannerControllerState, NetworkConnectionBannerFailedNetwork, NetworkConnectionBannerStatus } from "./NetworkConnectionBannerController.mjs";
2
+ /**
3
+ * Selectors for the NetworkConnectionBannerController state.
4
+ * These can be used with Redux or directly with controller state.
5
+ */
6
+ export declare const networkConnectionBannerControllerSelectors: {
7
+ selectNetworkConnectionBannerStatus: (state: NetworkConnectionBannerControllerState) => NetworkConnectionBannerStatus;
8
+ selectNetworkConnectionBannerNetwork: (state: NetworkConnectionBannerControllerState) => NetworkConnectionBannerFailedNetwork | null;
9
+ selectIsNetworkConnectionBannerVisible: ((state: NetworkConnectionBannerControllerState) => boolean) & {
10
+ clearCache: () => void;
11
+ resultsCount: () => number;
12
+ resetResultsCount: () => void;
13
+ } & {
14
+ resultFunc: (resultFuncArgs_0: NetworkConnectionBannerStatus) => boolean;
15
+ memoizedResultFunc: ((resultFuncArgs_0: NetworkConnectionBannerStatus) => boolean) & {
16
+ clearCache: () => void;
17
+ resultsCount: () => number;
18
+ resetResultsCount: () => void;
19
+ };
20
+ lastResult: () => boolean;
21
+ dependencies: [(state: NetworkConnectionBannerControllerState) => NetworkConnectionBannerStatus];
22
+ recomputations: () => number;
23
+ resetRecomputations: () => void;
24
+ dependencyRecomputations: () => number;
25
+ resetDependencyRecomputations: () => void;
26
+ } & {
27
+ memoize: typeof import("reselect").weakMapMemoize;
28
+ argsMemoize: typeof import("reselect").weakMapMemoize;
29
+ };
30
+ };
31
+ //# sourceMappingURL=selectors.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.mts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,sCAAsC,EACtC,oCAAoC,EACpC,6BAA6B,EAC9B,gDAA4C;AAmC7C;;;GAGG;AACH,eAAO,MAAM,0CAA0C;iDA9B9C,sCAAsC,KAC5C,6BAA6B;kDAUvB,sCAAsC,KAC5C,oCAAoC,GAAG,IAAI;;;;;;;;;;;;;+BAZrC,sCAAsC,KAC5C,6BAA6B;;;;;;;;;CAiC/B,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { createSelector } from "reselect";
2
+ /**
3
+ * Selects the banner status from the controller state.
4
+ *
5
+ * @param state - The controller state
6
+ * @returns The banner status
7
+ */
8
+ const selectNetworkConnectionBannerStatus = (state) => state.status;
9
+ /**
10
+ * Selects the failing network the banner describes, or `null` when no banner
11
+ * is shown.
12
+ *
13
+ * @param state - The controller state
14
+ * @returns The failing network details, or `null`
15
+ */
16
+ const selectNetworkConnectionBannerNetwork = (state) => state.network;
17
+ /**
18
+ * Selects whether the banner is visible (status is `degraded` or
19
+ * `unavailable`).
20
+ *
21
+ * @param state - The controller state
22
+ * @returns Whether the banner is visible
23
+ */
24
+ const selectIsNetworkConnectionBannerVisible = createSelector([selectNetworkConnectionBannerStatus], (status) => status === 'degraded' || status === 'unavailable');
25
+ /**
26
+ * Selectors for the NetworkConnectionBannerController state.
27
+ * These can be used with Redux or directly with controller state.
28
+ */
29
+ export const networkConnectionBannerControllerSelectors = {
30
+ selectNetworkConnectionBannerStatus,
31
+ selectNetworkConnectionBannerNetwork,
32
+ selectIsNetworkConnectionBannerVisible,
33
+ };
34
+ //# sourceMappingURL=selectors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.mjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB;AAQ1C;;;;;GAKG;AACH,MAAM,mCAAmC,GAAG,CAC1C,KAA6C,EACd,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,oCAAoC,GAAG,CAC3C,KAA6C,EACA,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,sCAAsC,GAAG,cAAc,CAC3D,CAAC,mCAAmC,CAAC,EACrC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,aAAa,CAC9D,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,0CAA0C,GAAG;IACxD,mCAAmC;IACnC,oCAAoC;IACpC,sCAAsC;CACvC,CAAC","sourcesContent":["import { createSelector } from 'reselect';\n\nimport type {\n NetworkConnectionBannerControllerState,\n NetworkConnectionBannerFailedNetwork,\n NetworkConnectionBannerStatus,\n} from './NetworkConnectionBannerController';\n\n/**\n * Selects the banner status from the controller state.\n *\n * @param state - The controller state\n * @returns The banner status\n */\nconst selectNetworkConnectionBannerStatus = (\n state: NetworkConnectionBannerControllerState,\n): NetworkConnectionBannerStatus => state.status;\n\n/**\n * Selects the failing network the banner describes, or `null` when no banner\n * is shown.\n *\n * @param state - The controller state\n * @returns The failing network details, or `null`\n */\nconst selectNetworkConnectionBannerNetwork = (\n state: NetworkConnectionBannerControllerState,\n): NetworkConnectionBannerFailedNetwork | null => state.network;\n\n/**\n * Selects whether the banner is visible (status is `degraded` or\n * `unavailable`).\n *\n * @param state - The controller state\n * @returns Whether the banner is visible\n */\nconst selectIsNetworkConnectionBannerVisible = createSelector(\n [selectNetworkConnectionBannerStatus],\n (status) => status === 'degraded' || status === 'unavailable',\n);\n\n/**\n * Selectors for the NetworkConnectionBannerController state.\n * These can be used with Redux or directly with controller state.\n */\nexport const networkConnectionBannerControllerSelectors = {\n selectNetworkConnectionBannerStatus,\n selectNetworkConnectionBannerNetwork,\n selectIsNetworkConnectionBannerVisible,\n};\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-69c25f142",
3
+ "version": "0.1.0-preview-51b287c55",
4
4
  "description": "Decides when and how to surface the network connection banner based on RPC endpoint health",
5
5
  "keywords": [
6
6
  "Ethereum",
@@ -60,7 +60,8 @@
60
60
  "@metamask/network-enablement-controller": "^5.3.0",
61
61
  "@metamask/utils": "^11.9.0",
62
62
  "ip-regex": "^4.3.0",
63
- "psl": "^1.15.0"
63
+ "psl": "^1.15.0",
64
+ "reselect": "^5.1.1"
64
65
  },
65
66
  "devDependencies": {
66
67
  "@metamask/auto-changelog": "^6.1.0",