@metamask-previews/assets-controller 0.2.0-preview-c3cd77f → 0.2.0-preview-d01b2f93d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/AssetsController-method-action-types.cjs +7 -0
  3. package/dist/AssetsController-method-action-types.cjs.map +1 -0
  4. package/dist/AssetsController-method-action-types.d.cts +78 -0
  5. package/dist/AssetsController-method-action-types.d.cts.map +1 -0
  6. package/dist/AssetsController-method-action-types.d.mts +78 -0
  7. package/dist/AssetsController-method-action-types.d.mts.map +1 -0
  8. package/dist/AssetsController-method-action-types.mjs +6 -0
  9. package/dist/AssetsController-method-action-types.mjs.map +1 -0
  10. package/dist/AssetsController.cjs +161 -116
  11. package/dist/AssetsController.cjs.map +1 -1
  12. package/dist/AssetsController.d.cts +23 -80
  13. package/dist/AssetsController.d.cts.map +1 -1
  14. package/dist/AssetsController.d.mts +23 -80
  15. package/dist/AssetsController.d.mts.map +1 -1
  16. package/dist/AssetsController.mjs +161 -116
  17. package/dist/AssetsController.mjs.map +1 -1
  18. package/dist/data-sources/AbstractDataSource.cjs.map +1 -1
  19. package/dist/data-sources/AbstractDataSource.d.cts +10 -1
  20. package/dist/data-sources/AbstractDataSource.d.cts.map +1 -1
  21. package/dist/data-sources/AbstractDataSource.d.mts +10 -1
  22. package/dist/data-sources/AbstractDataSource.d.mts.map +1 -1
  23. package/dist/data-sources/AbstractDataSource.mjs.map +1 -1
  24. package/dist/data-sources/AccountsApiDataSource.cjs +23 -99
  25. package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
  26. package/dist/data-sources/AccountsApiDataSource.d.cts +5 -67
  27. package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
  28. package/dist/data-sources/AccountsApiDataSource.d.mts +5 -67
  29. package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
  30. package/dist/data-sources/AccountsApiDataSource.mjs +22 -97
  31. package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
  32. package/dist/data-sources/BackendWebsocketDataSource.cjs +135 -45
  33. package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
  34. package/dist/data-sources/BackendWebsocketDataSource.d.cts +19 -66
  35. package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
  36. package/dist/data-sources/BackendWebsocketDataSource.d.mts +19 -66
  37. package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
  38. package/dist/data-sources/BackendWebsocketDataSource.mjs +135 -45
  39. package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
  40. package/dist/data-sources/PriceDataSource.cjs +22 -44
  41. package/dist/data-sources/PriceDataSource.cjs.map +1 -1
  42. package/dist/data-sources/PriceDataSource.d.cts +6 -89
  43. package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
  44. package/dist/data-sources/PriceDataSource.d.mts +6 -89
  45. package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
  46. package/dist/data-sources/PriceDataSource.mjs +22 -44
  47. package/dist/data-sources/PriceDataSource.mjs.map +1 -1
  48. package/dist/data-sources/RpcDataSource.cjs +57 -98
  49. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  50. package/dist/data-sources/RpcDataSource.d.cts +16 -55
  51. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  52. package/dist/data-sources/RpcDataSource.d.mts +16 -55
  53. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  54. package/dist/data-sources/RpcDataSource.mjs +57 -98
  55. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  56. package/dist/data-sources/SnapDataSource.cjs +30 -30
  57. package/dist/data-sources/SnapDataSource.cjs.map +1 -1
  58. package/dist/data-sources/SnapDataSource.d.cts +7 -44
  59. package/dist/data-sources/SnapDataSource.d.cts.map +1 -1
  60. package/dist/data-sources/SnapDataSource.d.mts +7 -44
  61. package/dist/data-sources/SnapDataSource.d.mts.map +1 -1
  62. package/dist/data-sources/SnapDataSource.mjs +30 -30
  63. package/dist/data-sources/SnapDataSource.mjs.map +1 -1
  64. package/dist/data-sources/TokenDataSource.cjs +3 -16
  65. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  66. package/dist/data-sources/TokenDataSource.d.cts +2 -25
  67. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  68. package/dist/data-sources/TokenDataSource.d.mts +2 -25
  69. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  70. package/dist/data-sources/TokenDataSource.mjs +3 -16
  71. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  72. package/dist/data-sources/index.cjs +1 -6
  73. package/dist/data-sources/index.cjs.map +1 -1
  74. package/dist/data-sources/index.d.cts +6 -7
  75. package/dist/data-sources/index.d.cts.map +1 -1
  76. package/dist/data-sources/index.d.mts +6 -7
  77. package/dist/data-sources/index.d.mts.map +1 -1
  78. package/dist/data-sources/index.mjs +1 -3
  79. package/dist/data-sources/index.mjs.map +1 -1
  80. package/dist/index.cjs +1 -6
  81. package/dist/index.cjs.map +1 -1
  82. package/dist/index.d.cts +9 -11
  83. package/dist/index.d.cts.map +1 -1
  84. package/dist/index.d.mts +9 -11
  85. package/dist/index.d.mts.map +1 -1
  86. package/dist/index.mjs +1 -3
  87. package/dist/index.mjs.map +1 -1
  88. package/dist/middlewares/DetectionMiddleware.cjs +4 -27
  89. package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
  90. package/dist/middlewares/DetectionMiddleware.d.cts +3 -26
  91. package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
  92. package/dist/middlewares/DetectionMiddleware.d.mts +3 -26
  93. package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
  94. package/dist/middlewares/DetectionMiddleware.mjs +4 -27
  95. package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
  96. package/dist/middlewares/index.cjs.map +1 -1
  97. package/dist/middlewares/index.d.cts +1 -1
  98. package/dist/middlewares/index.d.cts.map +1 -1
  99. package/dist/middlewares/index.d.mts +1 -1
  100. package/dist/middlewares/index.d.mts.map +1 -1
  101. package/dist/middlewares/index.mjs.map +1 -1
  102. package/dist/types.cjs.map +1 -1
  103. package/dist/types.d.cts +52 -3
  104. package/dist/types.d.cts.map +1 -1
  105. package/dist/types.d.mts +52 -3
  106. package/dist/types.d.mts.map +1 -1
  107. package/dist/types.mjs.map +1 -1
  108. package/package.json +1 -1
  109. package/dist/data-sources/initDataSources.cjs +0 -215
  110. package/dist/data-sources/initDataSources.cjs.map +0 -1
  111. package/dist/data-sources/initDataSources.d.cts +0 -140
  112. package/dist/data-sources/initDataSources.d.cts.map +0 -1
  113. package/dist/data-sources/initDataSources.d.mts +0 -140
  114. package/dist/data-sources/initDataSources.d.mts.map +0 -1
  115. package/dist/data-sources/initDataSources.mjs +0 -210
  116. package/dist/data-sources/initDataSources.mjs.map +0 -1
@@ -13,7 +13,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_defaultUpdateInterval, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_dataSources, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_registerActionHandlers, _AssetsController_executeMiddlewares, _AssetsController_assignChainsToDataSources, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeToDataSources, _AssetsController_subscribeAssetsBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_getAccountsForChains, _AssetsController_subscribeToDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged, _AssetsController_handleSubscriptionUpdate;
16
+ var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_defaultUpdateInterval, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_dataSources, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_tokenDataSource, _AssetsController_getBalanceDataSource, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_registerActionHandlers, _AssetsController_executeMiddlewares, _AssetsController_assignChainsToDataSources, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeToDataSources, _AssetsController_subscribeAssetsBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_getAccountsForChains, _AssetsController_subscribeToDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.AssetsController = exports.getDefaultAssetsControllerState = void 0;
19
19
  const base_controller_1 = require("@metamask/base-controller");
@@ -21,12 +21,31 @@ const utils_1 = require("@metamask/utils");
21
21
  const async_mutex_1 = require("async-mutex");
22
22
  const bignumber_js_1 = __importDefault(require("bignumber.js"));
23
23
  const lodash_1 = require("lodash");
24
+ const AccountsApiDataSource_1 = require("./data-sources/AccountsApiDataSource.cjs");
25
+ const BackendWebsocketDataSource_1 = require("./data-sources/BackendWebsocketDataSource.cjs");
26
+ const PriceDataSource_1 = require("./data-sources/PriceDataSource.cjs");
27
+ const RpcDataSource_1 = require("./data-sources/RpcDataSource.cjs");
28
+ const SnapDataSource_1 = require("./data-sources/SnapDataSource.cjs");
29
+ const TokenDataSource_1 = require("./data-sources/TokenDataSource.cjs");
24
30
  const logger_1 = require("./logger.cjs");
31
+ const DetectionMiddleware_1 = require("./middlewares/DetectionMiddleware.cjs");
25
32
  const utils_2 = require("./utils.cjs");
26
33
  // ============================================================================
27
34
  // CONTROLLER CONSTANTS
28
35
  // ============================================================================
29
36
  const CONTROLLER_NAME = 'AssetsController';
37
+ /** Method names exposed as messenger actions (AssetsController:getAssets, etc.) */
38
+ const MESSENGER_EXPOSED_METHODS = [
39
+ 'getAssets',
40
+ 'getAssetsBalance',
41
+ 'getAssetMetadata',
42
+ 'getAssetsPrice',
43
+ 'addCustomAsset',
44
+ 'removeCustomAsset',
45
+ 'getCustomAssets',
46
+ 'hideAsset',
47
+ 'unhideAsset',
48
+ ];
30
49
  /** Default polling interval hint for data sources (30 seconds) */
31
50
  const DEFAULT_POLLING_INTERVAL_MS = 30000;
32
51
  const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, CONTROLLER_NAME);
@@ -153,13 +172,8 @@ function normalizeResponse(response) {
153
172
  * based on which chains they support. When active chains change, the controller
154
173
  * dynamically adjusts subscriptions.
155
174
  *
156
- * 4. **App Lifecycle Management**: Listens to app open/close events via messenger
157
- * to start/stop subscriptions automatically, conserving resources when app is closed.
158
- *
159
- * ## App Lifecycle
160
- *
161
- * - **App Opened** (`AppStateController:appOpened`): Starts subscriptions, fetches initial data
162
- * - **App Closed** (`AppStateController:appClosed`): Stops all subscriptions to conserve resources
175
+ * 4. **Keyring Lifecycle**: Listens to KeyringController unlock/lock events to
176
+ * start/stop subscriptions when the wallet is unlocked or locked.
163
177
  *
164
178
  * ## Architecture
165
179
  *
@@ -168,7 +182,7 @@ function normalizeResponse(response) {
168
182
  * - The controller does NOT manage polling - it simply receives pushed updates
169
183
  */
170
184
  class AssetsController extends base_controller_1.BaseController {
171
- constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, }) {
185
+ constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, queryApiClient, rpcDataSourceConfig, }) {
172
186
  super({
173
187
  name: CONTROLLER_NAME,
174
188
  messenger,
@@ -199,25 +213,57 @@ class AssetsController extends base_controller_1.BaseController {
199
213
  * Key: sourceId, Value: Set of currently available chainIds
200
214
  */
201
215
  _AssetsController_dataSources.set(this, new Map());
216
+ _AssetsController_backendWebsocketDataSource.set(this, void 0);
217
+ _AssetsController_accountsApiDataSource.set(this, void 0);
218
+ _AssetsController_snapDataSource.set(this, void 0);
219
+ _AssetsController_rpcDataSource.set(this, void 0);
220
+ _AssetsController_priceDataSource.set(this, void 0);
221
+ _AssetsController_detectionMiddleware.set(this, void 0);
222
+ _AssetsController_tokenDataSource.set(this, void 0);
202
223
  __classPrivateFieldSet(this, _AssetsController_isEnabled, isEnabled(), "f");
203
224
  __classPrivateFieldSet(this, _AssetsController_defaultUpdateInterval, defaultUpdateInterval, "f");
225
+ const rpcConfig = rpcDataSourceConfig ?? {};
226
+ __classPrivateFieldSet(this, _AssetsController_backendWebsocketDataSource, new BackendWebsocketDataSource_1.BackendWebsocketDataSource({
227
+ messenger: this.messenger,
228
+ queryApiClient,
229
+ onActiveChainsUpdated: (chains) => this.handleActiveChainsUpdate('BackendWebsocketDataSource', chains),
230
+ }), "f");
231
+ __classPrivateFieldSet(this, _AssetsController_accountsApiDataSource, new AccountsApiDataSource_1.AccountsApiDataSource({
232
+ queryApiClient,
233
+ onActiveChainsUpdated: (chains) => {
234
+ this.handleActiveChainsUpdate('AccountsApiDataSource', chains);
235
+ },
236
+ }), "f");
237
+ __classPrivateFieldSet(this, _AssetsController_snapDataSource, new SnapDataSource_1.SnapDataSource({
238
+ messenger: this.messenger,
239
+ onActiveChainsUpdated: (chains) => this.handleActiveChainsUpdate('SnapDataSource', chains),
240
+ }), "f");
241
+ __classPrivateFieldSet(this, _AssetsController_rpcDataSource, new RpcDataSource_1.RpcDataSource({
242
+ messenger: this.messenger,
243
+ onActiveChainsUpdated: (chains) => this.handleActiveChainsUpdate('RpcDataSource', chains),
244
+ ...rpcConfig,
245
+ }), "f");
246
+ __classPrivateFieldSet(this, _AssetsController_tokenDataSource, new TokenDataSource_1.TokenDataSource({
247
+ queryApiClient,
248
+ }), "f");
249
+ __classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource_1.PriceDataSource({
250
+ queryApiClient,
251
+ }), "f");
252
+ __classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware_1.DetectionMiddleware(), "f");
253
+ __classPrivateFieldGet(this, _AssetsController_dataSources, "f").set('BackendWebsocketDataSource', new Set());
254
+ __classPrivateFieldGet(this, _AssetsController_dataSources, "f").set('AccountsApiDataSource', new Set());
255
+ __classPrivateFieldGet(this, _AssetsController_dataSources, "f").set('SnapDataSource', new Set());
256
+ __classPrivateFieldGet(this, _AssetsController_dataSources, "f").set('RpcDataSource', new Set());
204
257
  if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
205
258
  log('AssetsController is disabled, skipping initialization');
206
259
  return;
207
260
  }
208
261
  log('Initializing AssetsController', {
209
- defaultUpdateInterval,
262
+ defaultUpdateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
210
263
  });
211
264
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
212
265
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
213
266
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
214
- // Register data sources (order = subscription priority)
215
- this.registerDataSources([
216
- 'BackendWebsocketDataSource', // Real-time push updates
217
- 'AccountsApiDataSource', // HTTP polling fallback
218
- 'SnapDataSource', // Solana/Bitcoin/Tron snaps
219
- 'RpcDataSource', // Direct blockchain queries
220
- ]);
221
267
  }
222
268
  // ============================================================================
223
269
  // DATA SOURCE MANAGEMENT
@@ -226,7 +272,7 @@ class AssetsController extends base_controller_1.BaseController {
226
272
  * Register data sources with the controller.
227
273
  * Order of the array determines subscription order.
228
274
  *
229
- * Data sources report chain changes by calling `AssetsController:activeChainsUpdate` action.
275
+ * Data sources report chain changes via the onActiveChainsUpdated callback passed at construction.
230
276
  *
231
277
  * @param dataSourceIds - Array of data source identifiers to register.
232
278
  */
@@ -245,7 +291,7 @@ class AssetsController extends base_controller_1.BaseController {
245
291
  * Active chains are chains that are both supported AND available.
246
292
  * Updates centralized chain tracking and triggers re-selection if needed.
247
293
  *
248
- * Data sources should call this via `AssetsController:activeChainsUpdate` action.
294
+ * Called from the onActiveChainsUpdated callbacks passed to data sources at construction.
249
295
  *
250
296
  * @param dataSourceId - The identifier of the data source reporting the change.
251
297
  * @param activeChains - Array of currently active chain IDs for this source.
@@ -256,6 +302,10 @@ class AssetsController extends base_controller_1.BaseController {
256
302
  chainCount: activeChains.length,
257
303
  chains: activeChains,
258
304
  });
305
+ // When BackendWebsocketDataSource is updated via AccountsApiDataSource callback, sync its state
306
+ if (dataSourceId === 'BackendWebsocketDataSource') {
307
+ __classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f").setActiveChainsFromAccountsApi(activeChains);
308
+ }
259
309
  const previousChains = __classPrivateFieldGet(this, _AssetsController_dataSources, "f").get(dataSourceId) ?? new Set();
260
310
  const newChains = new Set(activeChains);
261
311
  // Update centralized available chains tracking
@@ -295,21 +345,20 @@ class AssetsController extends base_controller_1.BaseController {
295
345
  customAssets.push(...accountCustomAssets);
296
346
  }
297
347
  if (options?.forceUpdate) {
298
- const response = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
299
- this.messenger.call('AccountsApiDataSource:getAssetsMiddleware'),
300
- this.messenger.call('SnapDataSource:getAssetsMiddleware'),
301
- this.messenger.call('RpcDataSource:getAssetsMiddleware'),
302
- this.messenger.call('DetectionMiddleware:getAssetsMiddleware'),
303
- this.messenger.call('TokenDataSource:getAssetsMiddleware'),
304
- this.messenger.call('PriceDataSource:getAssetsMiddleware'),
305
- ], {
306
- accounts,
307
- chainIds,
348
+ const request = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chainIds, {
308
349
  assetTypes,
309
350
  dataTypes,
310
351
  customAssets: customAssets.length > 0 ? customAssets : undefined,
311
352
  forceUpdate: true,
312
353
  });
354
+ const response = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
355
+ __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f").assetsMiddleware,
356
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f").assetsMiddleware,
357
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").assetsMiddleware,
358
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f").assetsMiddleware,
359
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f").assetsMiddleware,
360
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").assetsMiddleware,
361
+ ], request);
313
362
  await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, response);
314
363
  }
315
364
  return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
@@ -477,19 +526,17 @@ class AssetsController extends base_controller_1.BaseController {
477
526
  const subscriptionKey = 'ds:PriceDataSource';
478
527
  const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
479
528
  const isUpdate = existingSubscription !== undefined;
480
- // Fire-and-forget - errors are handled internally by PriceDataSource
481
- this.messenger
482
- .call('PriceDataSource:subscribe', {
483
- request: {
484
- accounts,
485
- chainIds,
529
+ const subscribeReq = {
530
+ request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chainIds, {
486
531
  dataTypes: ['price'],
487
532
  updateInterval,
488
- },
533
+ }),
489
534
  subscriptionId: subscriptionKey,
490
535
  isUpdate,
491
- })
492
- .catch(console.error);
536
+ onAssetsUpdate: (response) => this.handleAssetsUpdate(response, 'PriceDataSource'),
537
+ getAssetsState: () => this.state,
538
+ };
539
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").subscribe(subscribeReq).catch(console.error);
493
540
  // Track subscription
494
541
  const subscription = {
495
542
  chains: chainIds,
@@ -511,26 +558,36 @@ class AssetsController extends base_controller_1.BaseController {
511
558
  if (!existingSubscription) {
512
559
  return;
513
560
  }
514
- // Fire-and-forget - errors are handled internally by PriceDataSource
515
- this.messenger
516
- .call('PriceDataSource:unsubscribe', subscriptionKey)
517
- .catch(console.error);
561
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").unsubscribe(subscriptionKey).catch(console.error);
518
562
  existingSubscription.unsubscribe();
519
563
  }
520
564
  /**
521
565
  * Handle assets updated from a data source.
522
- * Called via `AssetsController:assetsUpdate` action by data sources.
566
+ * Called via the onAssetsUpdate callback passed in SubscriptionRequest when the controller subscribes to a data source.
567
+ * Enriches the response with token metadata (via middlewares) before updating state.
523
568
  *
524
569
  * @param response - The data response with updated assets
525
570
  * @param sourceId - The data source ID reporting the update
571
+ * @param request - Optional original request for context when enriching
526
572
  */
527
- async handleAssetsUpdate(response, sourceId) {
573
+ async handleAssetsUpdate(response, sourceId, request) {
528
574
  log('Assets updated from data source', {
529
575
  sourceId,
530
576
  hasBalance: Boolean(response.assetsBalance),
531
577
  hasPrice: Boolean(response.assetsPrice),
532
578
  });
533
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleSubscriptionUpdate).call(this, response, sourceId);
579
+ // Run through enrichment middlewares (Event Stack: Detection → Token → Price)
580
+ // Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
581
+ const enrichedResponse = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
582
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f").assetsMiddleware,
583
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f").assetsMiddleware,
584
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").assetsMiddleware,
585
+ ], request ?? {
586
+ accountsWithSupportedChains: [],
587
+ chainIds: [],
588
+ dataTypes: ['balance', 'metadata', 'price'],
589
+ }, response);
590
+ await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
534
591
  }
535
592
  // ============================================================================
536
593
  // CLEANUP
@@ -540,6 +597,16 @@ class AssetsController extends base_controller_1.BaseController {
540
597
  dataSourceCount: __classPrivateFieldGet(this, _AssetsController_dataSources, "f").size,
541
598
  subscriptionCount: __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size,
542
599
  });
600
+ // Destroy instantiated data sources
601
+ __classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f")?.destroy?.();
602
+ __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f")?.destroy?.();
603
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f")?.destroy?.();
604
+ if (__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f") &&
605
+ 'destroy' in __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f") &&
606
+ typeof __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").destroy ===
607
+ 'function') {
608
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").destroy();
609
+ }
543
610
  // Clear data sources
544
611
  __classPrivateFieldGet(this, _AssetsController_dataSources, "f").clear();
545
612
  // Stop all active subscriptions
@@ -549,8 +616,6 @@ class AssetsController extends base_controller_1.BaseController {
549
616
  this.messenger.unregisterActionHandler('AssetsController:getAssetsBalance');
550
617
  this.messenger.unregisterActionHandler('AssetsController:getAssetMetadata');
551
618
  this.messenger.unregisterActionHandler('AssetsController:getAssetsPrice');
552
- this.messenger.unregisterActionHandler('AssetsController:activeChainsUpdate');
553
- this.messenger.unregisterActionHandler('AssetsController:assetsUpdate');
554
619
  this.messenger.unregisterActionHandler('AssetsController:addCustomAsset');
555
620
  this.messenger.unregisterActionHandler('AssetsController:removeCustomAsset');
556
621
  this.messenger.unregisterActionHandler('AssetsController:getCustomAssets');
@@ -559,8 +624,21 @@ class AssetsController extends base_controller_1.BaseController {
559
624
  }
560
625
  }
561
626
  exports.AssetsController = AssetsController;
562
- _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_dataSources = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
627
+ _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_dataSources = new WeakMap(), _AssetsController_backendWebsocketDataSource = new WeakMap(), _AssetsController_accountsApiDataSource = new WeakMap(), _AssetsController_snapDataSource = new WeakMap(), _AssetsController_rpcDataSource = new WeakMap(), _AssetsController_priceDataSource = new WeakMap(), _AssetsController_detectionMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
563
628
  return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
629
+ }, _AssetsController_getBalanceDataSource = function _AssetsController_getBalanceDataSource(sourceId) {
630
+ switch (sourceId) {
631
+ case 'BackendWebsocketDataSource':
632
+ return __classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f");
633
+ case 'AccountsApiDataSource':
634
+ return __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f");
635
+ case 'SnapDataSource':
636
+ return __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f");
637
+ case 'RpcDataSource':
638
+ return __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f");
639
+ default:
640
+ return undefined;
641
+ }
564
642
  }, _AssetsController_initializeState = function _AssetsController_initializeState() {
565
643
  const { enabledNetworkMap } = this.messenger.call('NetworkEnablementController:getState');
566
644
  __classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
@@ -602,24 +680,11 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInte
602
680
  this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
603
681
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
604
682
  });
605
- // App lifecycle: start when opened, stop when closed
606
- this.messenger.subscribe('AppStateController:appOpened', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
607
- this.messenger.subscribe('AppStateController:appClosed', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
608
683
  // Keyring lifecycle: start when unlocked, stop when locked
609
684
  this.messenger.subscribe('KeyringController:unlock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
610
685
  this.messenger.subscribe('KeyringController:lock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
611
686
  }, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
612
- this.messenger.registerActionHandler('AssetsController:getAssets', this.getAssets.bind(this));
613
- this.messenger.registerActionHandler('AssetsController:getAssetsBalance', this.getAssetsBalance.bind(this));
614
- this.messenger.registerActionHandler('AssetsController:getAssetMetadata', this.getAssetMetadata.bind(this));
615
- this.messenger.registerActionHandler('AssetsController:getAssetsPrice', this.getAssetsPrice.bind(this));
616
- this.messenger.registerActionHandler('AssetsController:activeChainsUpdate', this.handleActiveChainsUpdate.bind(this));
617
- this.messenger.registerActionHandler('AssetsController:assetsUpdate', this.handleAssetsUpdate.bind(this));
618
- this.messenger.registerActionHandler('AssetsController:addCustomAsset', this.addCustomAsset.bind(this));
619
- this.messenger.registerActionHandler('AssetsController:removeCustomAsset', this.removeCustomAsset.bind(this));
620
- this.messenger.registerActionHandler('AssetsController:getCustomAssets', this.getCustomAssets.bind(this));
621
- this.messenger.registerActionHandler('AssetsController:hideAsset', this.hideAsset.bind(this));
622
- this.messenger.registerActionHandler('AssetsController:unhideAsset', this.unhideAsset.bind(this));
687
+ this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
623
688
  }, _AssetsController_executeMiddlewares =
624
689
  // ============================================================================
625
690
  // MIDDLEWARE EXECUTION
@@ -969,31 +1034,30 @@ async function _AssetsController_updateState(response) {
969
1034
  accountCount: accounts.length,
970
1035
  chainCount: chains.length,
971
1036
  });
972
- // Call data source subscribe action via Messenger (fire-and-forget)
973
- (async () => {
974
- try {
975
- await this.messenger.call(`${sourceId}:subscribe`, {
976
- request: {
977
- accounts,
978
- chainIds: chains,
979
- assetTypes: ['fungible'],
980
- dataTypes: ['balance'],
981
- updateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
982
- },
983
- subscriptionId: subscriptionKey,
984
- isUpdate,
985
- });
986
- }
987
- catch (error) {
988
- console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
989
- }
990
- })().catch(console.error);
1037
+ const subscribeReq = {
1038
+ request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chains, {
1039
+ assetTypes: ['fungible'],
1040
+ dataTypes: ['balance'],
1041
+ updateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
1042
+ }),
1043
+ subscriptionId: subscriptionKey,
1044
+ isUpdate,
1045
+ onAssetsUpdate: (response) => this.handleAssetsUpdate(response, sourceId),
1046
+ getAssetsState: () => this.state,
1047
+ };
1048
+ const balanceDs = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getBalanceDataSource).call(this, sourceId);
1049
+ if (!balanceDs) {
1050
+ return;
1051
+ }
1052
+ balanceDs.subscribe(subscribeReq).catch((error) => {
1053
+ console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
1054
+ });
991
1055
  // Track subscription
992
1056
  const subscription = {
993
1057
  chains,
994
1058
  accountId: subscriptionKey,
995
1059
  assetTypes: ['fungible'],
996
- dataTypes: ['balance', 'price'],
1060
+ dataTypes: ['balance'],
997
1061
  unsubscribe: () => {
998
1062
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").delete(subscriptionKey);
999
1063
  },
@@ -1003,19 +1067,23 @@ async function _AssetsController_updateState(response) {
1003
1067
  const subscriptionKey = `ds:${sourceId}`;
1004
1068
  const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
1005
1069
  if (existingSubscription) {
1006
- // Fire-and-forget unsubscribe call
1007
- (async () => {
1008
- try {
1009
- await this.messenger.call(`${sourceId}:unsubscribe`, subscriptionKey);
1010
- }
1011
- catch {
1012
- // Ignore errors - source may not have been subscribed
1013
- }
1014
- })().catch(() => {
1015
- // Ignore errors - source may not have been subscribed
1016
- });
1070
+ const balanceDs = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getBalanceDataSource).call(this, sourceId);
1071
+ if (balanceDs) {
1072
+ balanceDs.unsubscribe(subscriptionKey).catch(() => undefined);
1073
+ }
1017
1074
  existingSubscription.unsubscribe();
1018
1075
  }
1076
+ }, _AssetsController_buildDataRequest = function _AssetsController_buildDataRequest(accounts, chainIds, partial = {}) {
1077
+ const chainIdSet = new Set(chainIds);
1078
+ const accountsWithSupportedChains = accounts.map((account) => ({
1079
+ account,
1080
+ supportedChains: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account).filter((chain) => chainIdSet.has(chain)),
1081
+ }));
1082
+ return {
1083
+ accountsWithSupportedChains,
1084
+ chainIds,
1085
+ ...partial,
1086
+ };
1019
1087
  }, _AssetsController_getEnabledChainsForAccount = function _AssetsController_getEnabledChainsForAccount(account) {
1020
1088
  // Account scopes are CAIP-2 chain IDs like "eip155:1", "solana:mainnet", "bip122:..."
1021
1089
  const scopes = account.scopes ?? [];
@@ -1092,28 +1160,5 @@ async function _AssetsController_handleAccountGroupChanged() {
1092
1160
  forceUpdate: true,
1093
1161
  });
1094
1162
  }
1095
- }, _AssetsController_handleSubscriptionUpdate =
1096
- /**
1097
- * Handle an async update from a data source subscription.
1098
- * Enriches response with token metadata before updating state.
1099
- *
1100
- * @param response - The data response from the data source.
1101
- * @param _sourceId - The source ID (unused but kept for logging context).
1102
- * @param request - Optional original request for context.
1103
- */
1104
- async function _AssetsController_handleSubscriptionUpdate(response, _sourceId, request) {
1105
- // Run through enrichment middlewares (Event Stack: Detection → Token → Price)
1106
- // Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
1107
- const enrichedResponse = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
1108
- this.messenger.call('DetectionMiddleware:getAssetsMiddleware'),
1109
- this.messenger.call('TokenDataSource:getAssetsMiddleware'),
1110
- this.messenger.call('PriceDataSource:getAssetsMiddleware'),
1111
- ], request ?? {
1112
- accounts: [],
1113
- chainIds: [],
1114
- dataTypes: ['balance', 'metadata', 'price'],
1115
- }, response);
1116
- // Update state
1117
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
1118
1163
  };
1119
1164
  //# sourceMappingURL=AssetsController.cjs.map