@metamask-previews/assets-controller 9.1.0-preview-773e4e83d → 9.1.0-preview-1ec310ea7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -6
- package/dist/AssetsController.cjs +25 -113
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +25 -113
- package/dist/AssetsController.mjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.cjs +1 -4
- package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.mjs +1 -4
- package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.cjs +103 -214
- package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.cts +0 -7
- package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.mts +0 -7
- package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.mjs +103 -214
- package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +0 -7
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +0 -7
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackendWebsocketDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAM9B,+BAA+B;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAQhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAId,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B,QAAA,MAAM,eAAe,+BAA+B,CAAC;AAUrD,MAAM,MAAM,wCAAwC,GAClD,8BAA8B,CAAC;AAGjC,MAAM,MAAM,uCAAuC,GACjD,6BAA6B,CAAC;AAMhC,MAAM,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAU9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,iGAAiG;IACjG,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,wFAAwF;IACxF,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAClD,CAAC;
|
|
1
|
+
{"version":3,"file":"BackendWebsocketDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAM9B,+BAA+B;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAQhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAId,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B,QAAA,MAAM,eAAe,+BAA+B,CAAC;AAUrD,MAAM,MAAM,wCAAwC,GAClD,8BAA8B,CAAC;AAGjC,MAAM,MAAM,uCAAuC,GACjD,6BAA6B,CAAC;AAMhC,MAAM,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAU9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,iGAAiG;IACjG,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,wFAAwF;IACxF,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAClD,CAAC;AAqIF,qBAAa,0BAA2B,SAAQ,kBAAkB,CAChE,OAAO,eAAe,EACtB,+BAA+B,CAChC;;gBAiCa,OAAO,EAAE,iCAAiC;IAsGtD;;;;;;OAMG;IACH,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IA0EvD;;;;OAIG;IACH,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IAWxC,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+OxE,OAAO,IAAI,IAAI;CAwBhB;AAMD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,iCAAiC,GACzC,0BAA0B,CAE5B"}
|
|
@@ -37,13 +37,6 @@ export declare class BackendWebsocketDataSource extends AbstractDataSource<typeo
|
|
|
37
37
|
*/
|
|
38
38
|
updateSupportedChains(chains: ChainId[]): void;
|
|
39
39
|
subscribe(subscriptionRequest: SubscriptionRequest): Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* Unsubscribe and await server-side teardown so a re-subscribe does not race
|
|
42
|
-
* with stale subscription IDs on incoming notifications.
|
|
43
|
-
*
|
|
44
|
-
* @param subscriptionId - The ID of the subscription to cancel.
|
|
45
|
-
*/
|
|
46
|
-
unsubscribe(subscriptionId: string): Promise<void>;
|
|
47
40
|
destroy(): void;
|
|
48
41
|
}
|
|
49
42
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackendWebsocketDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAM9B,+BAA+B;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAQhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAId,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B,QAAA,MAAM,eAAe,+BAA+B,CAAC;AAUrD,MAAM,MAAM,wCAAwC,GAClD,8BAA8B,CAAC;AAGjC,MAAM,MAAM,uCAAuC,GACjD,6BAA6B,CAAC;AAMhC,MAAM,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAU9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,iGAAiG;IACjG,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,wFAAwF;IACxF,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAClD,CAAC;
|
|
1
|
+
{"version":3,"file":"BackendWebsocketDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAM9B,+BAA+B;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAQhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAId,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B,QAAA,MAAM,eAAe,+BAA+B,CAAC;AAUrD,MAAM,MAAM,wCAAwC,GAClD,8BAA8B,CAAC;AAGjC,MAAM,MAAM,uCAAuC,GACjD,6BAA6B,CAAC;AAMhC,MAAM,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAU9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,iGAAiG;IACjG,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,wFAAwF;IACxF,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAClD,CAAC;AAqIF,qBAAa,0BAA2B,SAAQ,kBAAkB,CAChE,OAAO,eAAe,EACtB,+BAA+B,CAChC;;gBAiCa,OAAO,EAAE,iCAAiC;IAsGtD;;;;;;OAMG;IACH,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IA0EvD;;;;OAIG;IACH,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IAWxC,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+OxE,OAAO,IAAI,IAAI;CAwBhB;AAMD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,iCAAiC,GACzC,0BAA0B,CAE5B"}
|
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _BackendWebsocketDataSource_instances, _BackendWebsocketDataSource_messenger, _BackendWebsocketDataSource_apiClient, _BackendWebsocketDataSource_onActiveChainsUpdated, _BackendWebsocketDataSource_getAssetType, _BackendWebsocketDataSource_chainsRefreshTimer, _BackendWebsocketDataSource_supportedChains, _BackendWebsocketDataSource_isConnected, _BackendWebsocketDataSource_wsSubscriptions, _BackendWebsocketDataSource_pendingSubscriptions, _BackendWebsocketDataSource_subscriptionRequests,
|
|
12
|
+
var _BackendWebsocketDataSource_instances, _BackendWebsocketDataSource_messenger, _BackendWebsocketDataSource_apiClient, _BackendWebsocketDataSource_onActiveChainsUpdated, _BackendWebsocketDataSource_getAssetType, _BackendWebsocketDataSource_chainsRefreshTimer, _BackendWebsocketDataSource_supportedChains, _BackendWebsocketDataSource_isConnected, _BackendWebsocketDataSource_wsSubscriptions, _BackendWebsocketDataSource_pendingSubscriptions, _BackendWebsocketDataSource_subscriptionRequests, _BackendWebsocketDataSource_initializeActiveChains, _BackendWebsocketDataSource_refreshActiveChains, _BackendWebsocketDataSource_fetchActiveChains, _BackendWebsocketDataSource_subscribeToEvents, _BackendWebsocketDataSource_handleDisconnect, _BackendWebsocketDataSource_handleReconnect, _BackendWebsocketDataSource_handleNotification, _BackendWebsocketDataSource_processBalanceUpdates;
|
|
13
13
|
import { isCaipChainId, KnownCaipNamespace, toCaipChainId } from "@metamask/utils";
|
|
14
14
|
import BigNumberJS from "bignumber.js";
|
|
15
15
|
import { projectLogger, createModuleLogger } from "../logger.mjs";
|
|
@@ -89,34 +89,6 @@ function buildAccountActivityChannel(namespace, address) {
|
|
|
89
89
|
const formatted = namespace === 'eip155' ? address.toLowerCase() : address;
|
|
90
90
|
return `${CHANNEL_TYPE}.${namespace}:0:${formatted}`;
|
|
91
91
|
}
|
|
92
|
-
/**
|
|
93
|
-
* Normalize addresses for stable comparison when detecting account changes.
|
|
94
|
-
*
|
|
95
|
-
* @param address - Account address (hex or base58).
|
|
96
|
-
* @returns Normalized address for comparison.
|
|
97
|
-
*/
|
|
98
|
-
function normalizeAddressForComparison(address) {
|
|
99
|
-
return address.startsWith('0x') ? address.toLowerCase() : address;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Check whether subscribed account addresses changed (case-insensitive for EVM).
|
|
103
|
-
*
|
|
104
|
-
* @param nextAddresses - Addresses from the incoming subscribe request.
|
|
105
|
-
* @param existingAddresses - Addresses from the active subscription.
|
|
106
|
-
* @returns True when the address sets differ.
|
|
107
|
-
*/
|
|
108
|
-
function haveAddressesChanged(nextAddresses, existingAddresses) {
|
|
109
|
-
if (nextAddresses.length !== existingAddresses.length) {
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
const normalizedNext = nextAddresses
|
|
113
|
-
.map(normalizeAddressForComparison)
|
|
114
|
-
.sort();
|
|
115
|
-
const normalizedExisting = existingAddresses
|
|
116
|
-
.map(normalizeAddressForComparison)
|
|
117
|
-
.sort();
|
|
118
|
-
return normalizedNext.some((address, index) => address !== normalizedExisting[index]);
|
|
119
|
-
}
|
|
120
92
|
/**
|
|
121
93
|
* Normalize API chain identifier to CAIP-2 ChainId.
|
|
122
94
|
* Passes through strings already in CAIP-2 form (e.g. eip155:1, solana:5eykt...).
|
|
@@ -164,8 +136,6 @@ function toChainId(chainIdOrDecimal) {
|
|
|
164
136
|
* - BackendWebSocketService:subscribe
|
|
165
137
|
* - BackendWebSocketService:getConnectionInfo
|
|
166
138
|
* - BackendWebSocketService:findSubscriptionsByChannelPrefix
|
|
167
|
-
* - BackendWebSocketService:addChannelCallback
|
|
168
|
-
* - BackendWebSocketService:removeChannelCallback
|
|
169
139
|
*/
|
|
170
140
|
const DEFAULT_CHAINS_REFRESH_INTERVAL_MS = 20 * 60 * 1000; // 20 minutes
|
|
171
141
|
export class BackendWebsocketDataSource extends AbstractDataSource {
|
|
@@ -191,10 +161,6 @@ export class BackendWebsocketDataSource extends AbstractDataSource {
|
|
|
191
161
|
_BackendWebsocketDataSource_pendingSubscriptions.set(this, new Map());
|
|
192
162
|
/** Store original subscription requests for reconnection */
|
|
193
163
|
_BackendWebsocketDataSource_subscriptionRequests.set(this, new Map());
|
|
194
|
-
/** Channels with registered BackendWebSocketService channel callbacks */
|
|
195
|
-
_BackendWebsocketDataSource_registeredChannelCallbacks.set(this, new Set());
|
|
196
|
-
/** Serializes subscribe/unsubscribe so account switches cannot interleave. */
|
|
197
|
-
_BackendWebsocketDataSource_subscribeLock.set(this, Promise.resolve());
|
|
198
164
|
__classPrivateFieldSet(this, _BackendWebsocketDataSource_messenger, options.messenger, "f");
|
|
199
165
|
__classPrivateFieldSet(this, _BackendWebsocketDataSource_apiClient, options.queryApiClient, "f");
|
|
200
166
|
__classPrivateFieldSet(this, _BackendWebsocketDataSource_onActiveChainsUpdated, options.onActiveChainsUpdated, "f");
|
|
@@ -228,40 +194,96 @@ export class BackendWebsocketDataSource extends AbstractDataSource {
|
|
|
228
194
|
// SUBSCRIBE
|
|
229
195
|
// ============================================================================
|
|
230
196
|
async subscribe(subscriptionRequest) {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
197
|
+
const { request, subscriptionId, isUpdate } = subscriptionRequest;
|
|
198
|
+
// Filter to active chains only
|
|
199
|
+
const chainsToSubscribe = request.chainIds.filter((chainId) => this.state.activeChains.includes(chainId));
|
|
200
|
+
const addresses = request.accountsWithSupportedChains.map((a) => a.account.address);
|
|
201
|
+
if (addresses.length === 0) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// Check WebSocket connection status
|
|
237
205
|
try {
|
|
238
|
-
|
|
206
|
+
const connectionInfo = __classPrivateFieldGet(this, _BackendWebsocketDataSource_messenger, "f").call('BackendWebSocketService:getConnectionInfo');
|
|
207
|
+
if (connectionInfo.state !== 'connected') {
|
|
208
|
+
// Store the subscription request to process when WebSocket connects
|
|
209
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_pendingSubscriptions, "f").set(subscriptionId, subscriptionRequest);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
239
212
|
}
|
|
240
|
-
|
|
241
|
-
|
|
213
|
+
catch {
|
|
214
|
+
// Store anyway - will be processed when we can connect
|
|
215
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_pendingSubscriptions, "f").set(subscriptionId, subscriptionRequest);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
// Remove from pending if it was there (we're processing it now)
|
|
219
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_pendingSubscriptions, "f").delete(subscriptionId);
|
|
220
|
+
// Handle subscription update
|
|
221
|
+
if (isUpdate) {
|
|
222
|
+
const existing = this.activeSubscriptions.get(subscriptionId);
|
|
223
|
+
if (existing) {
|
|
224
|
+
// Check if accounts changed - if so, we need to re-subscribe to different channels
|
|
225
|
+
const existingAddresses = existing.addresses ?? [];
|
|
226
|
+
const addressesChanged = addresses.length !== existingAddresses.length ||
|
|
227
|
+
addresses.some((addr) => !existingAddresses.includes(addr));
|
|
228
|
+
if (!addressesChanged) {
|
|
229
|
+
// Only chains changed - just update chains and return
|
|
230
|
+
existing.chains = chainsToSubscribe;
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// Accounts changed - fall through to re-subscribe with new channels
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Clean up existing subscription if any
|
|
237
|
+
await this.unsubscribe(subscriptionId);
|
|
238
|
+
// Always subscribe to eip155 and solana account activity, plus any namespaces from requested chains
|
|
239
|
+
const namespaces = getNamespacesForAccountActivity(chainsToSubscribe);
|
|
240
|
+
// Build channel names: use namespace-appropriate address per account (eip155 = hex, solana = base58)
|
|
241
|
+
const channels = [];
|
|
242
|
+
for (const namespace of namespaces) {
|
|
243
|
+
for (const { account } of request.accountsWithSupportedChains) {
|
|
244
|
+
const address = getAddressForAccountActivity(account, namespace);
|
|
245
|
+
if (address) {
|
|
246
|
+
channels.push(buildAccountActivityChannel(namespace, address));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
242
249
|
}
|
|
243
|
-
}
|
|
244
|
-
// ============================================================================
|
|
245
|
-
// UNSUBSCRIBE
|
|
246
|
-
// ============================================================================
|
|
247
|
-
/**
|
|
248
|
-
* Unsubscribe and await server-side teardown so a re-subscribe does not race
|
|
249
|
-
* with stale subscription IDs on incoming notifications.
|
|
250
|
-
*
|
|
251
|
-
* @param subscriptionId - The ID of the subscription to cancel.
|
|
252
|
-
*/
|
|
253
|
-
async unsubscribe(subscriptionId) {
|
|
254
|
-
const previousLock = __classPrivateFieldGet(this, _BackendWebsocketDataSource_subscribeLock, "f");
|
|
255
|
-
let releaseLock = () => undefined;
|
|
256
|
-
__classPrivateFieldSet(this, _BackendWebsocketDataSource_subscribeLock, new Promise((resolve) => {
|
|
257
|
-
releaseLock = resolve;
|
|
258
|
-
}), "f");
|
|
259
|
-
await previousLock;
|
|
260
250
|
try {
|
|
261
|
-
|
|
251
|
+
// Create WebSocket subscription
|
|
252
|
+
const wsSubscription = await __classPrivateFieldGet(this, _BackendWebsocketDataSource_messenger, "f").call('BackendWebSocketService:subscribe', {
|
|
253
|
+
channels,
|
|
254
|
+
channelType: CHANNEL_TYPE,
|
|
255
|
+
callback: (notification) => {
|
|
256
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_handleNotification).call(this, notification, subscriptionId);
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
// Store WebSocket subscription
|
|
260
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_wsSubscriptions, "f").set(subscriptionId, wsSubscription);
|
|
261
|
+
// Store in abstract class tracking
|
|
262
|
+
this.activeSubscriptions.set(subscriptionId, {
|
|
263
|
+
cleanup: () => {
|
|
264
|
+
const wsSub = __classPrivateFieldGet(this, _BackendWebsocketDataSource_wsSubscriptions, "f").get(subscriptionId);
|
|
265
|
+
if (wsSub) {
|
|
266
|
+
wsSub.unsubscribe().catch((unsubErr) => {
|
|
267
|
+
log('Error unsubscribing', { subscriptionId, error: unsubErr });
|
|
268
|
+
});
|
|
269
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_wsSubscriptions, "f").delete(subscriptionId);
|
|
270
|
+
}
|
|
271
|
+
// Also clean up the stored request
|
|
272
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_subscriptionRequests, "f").delete(subscriptionId);
|
|
273
|
+
},
|
|
274
|
+
chains: chainsToSubscribe,
|
|
275
|
+
addresses,
|
|
276
|
+
onAssetsUpdate: subscriptionRequest.onAssetsUpdate,
|
|
277
|
+
});
|
|
278
|
+
// Store original request for reconnection
|
|
279
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_subscriptionRequests, "f").set(subscriptionId, subscriptionRequest);
|
|
262
280
|
}
|
|
263
|
-
|
|
264
|
-
|
|
281
|
+
catch (error) {
|
|
282
|
+
log('WebSocket subscription FAILED', {
|
|
283
|
+
subscriptionId,
|
|
284
|
+
error,
|
|
285
|
+
chains: chainsToSubscribe,
|
|
286
|
+
});
|
|
265
287
|
}
|
|
266
288
|
}
|
|
267
289
|
// ============================================================================
|
|
@@ -272,20 +294,26 @@ export class BackendWebsocketDataSource extends AbstractDataSource {
|
|
|
272
294
|
clearInterval(__classPrivateFieldGet(this, _BackendWebsocketDataSource_chainsRefreshTimer, "f"));
|
|
273
295
|
__classPrivateFieldSet(this, _BackendWebsocketDataSource_chainsRefreshTimer, null, "f");
|
|
274
296
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
297
|
+
// Clean up WebSocket subscriptions
|
|
298
|
+
// Convert to array first to avoid modifying map during iteration
|
|
299
|
+
const subscriptions = [...__classPrivateFieldGet(this, _BackendWebsocketDataSource_wsSubscriptions, "f").values()];
|
|
300
|
+
for (const wsSub of subscriptions) {
|
|
301
|
+
try {
|
|
302
|
+
// Fire and forget - don't await in destroy
|
|
303
|
+
wsSub.unsubscribe().catch(() => {
|
|
304
|
+
// Ignore errors during cleanup
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Ignore errors during cleanup
|
|
309
|
+
}
|
|
283
310
|
}
|
|
284
|
-
|
|
311
|
+
__classPrivateFieldGet(this, _BackendWebsocketDataSource_wsSubscriptions, "f").clear();
|
|
312
|
+
// Clean up base class subscriptions
|
|
285
313
|
super.destroy();
|
|
286
314
|
}
|
|
287
315
|
}
|
|
288
|
-
_BackendWebsocketDataSource_messenger = new WeakMap(), _BackendWebsocketDataSource_apiClient = new WeakMap(), _BackendWebsocketDataSource_onActiveChainsUpdated = new WeakMap(), _BackendWebsocketDataSource_getAssetType = new WeakMap(), _BackendWebsocketDataSource_chainsRefreshTimer = new WeakMap(), _BackendWebsocketDataSource_supportedChains = new WeakMap(), _BackendWebsocketDataSource_isConnected = new WeakMap(), _BackendWebsocketDataSource_wsSubscriptions = new WeakMap(), _BackendWebsocketDataSource_pendingSubscriptions = new WeakMap(), _BackendWebsocketDataSource_subscriptionRequests = new WeakMap(),
|
|
316
|
+
_BackendWebsocketDataSource_messenger = new WeakMap(), _BackendWebsocketDataSource_apiClient = new WeakMap(), _BackendWebsocketDataSource_onActiveChainsUpdated = new WeakMap(), _BackendWebsocketDataSource_getAssetType = new WeakMap(), _BackendWebsocketDataSource_chainsRefreshTimer = new WeakMap(), _BackendWebsocketDataSource_supportedChains = new WeakMap(), _BackendWebsocketDataSource_isConnected = new WeakMap(), _BackendWebsocketDataSource_wsSubscriptions = new WeakMap(), _BackendWebsocketDataSource_pendingSubscriptions = new WeakMap(), _BackendWebsocketDataSource_subscriptionRequests = new WeakMap(), _BackendWebsocketDataSource_instances = new WeakSet(), _BackendWebsocketDataSource_initializeActiveChains =
|
|
289
317
|
// ============================================================================
|
|
290
318
|
// INITIALIZATION
|
|
291
319
|
// ============================================================================
|
|
@@ -384,99 +412,6 @@ async function _BackendWebsocketDataSource_initializeActiveChains() {
|
|
|
384
412
|
const previous = [...this.state.activeChains];
|
|
385
413
|
this.updateActiveChains(__classPrivateFieldGet(this, _BackendWebsocketDataSource_supportedChains, "f"), (updatedChains) => __classPrivateFieldGet(this, _BackendWebsocketDataSource_onActiveChainsUpdated, "f").call(this, this.getName(), updatedChains, previous));
|
|
386
414
|
}
|
|
387
|
-
}, _BackendWebsocketDataSource_subscribeInternal = async function _BackendWebsocketDataSource_subscribeInternal(subscriptionRequest) {
|
|
388
|
-
const { request, subscriptionId, isUpdate } = subscriptionRequest;
|
|
389
|
-
// Filter to active chains only
|
|
390
|
-
const chainsToSubscribe = request.chainIds.filter((chainId) => this.state.activeChains.includes(chainId));
|
|
391
|
-
const addresses = request.accountsWithSupportedChains.map((a) => a.account.address);
|
|
392
|
-
if (addresses.length === 0) {
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
// Check WebSocket connection status
|
|
396
|
-
try {
|
|
397
|
-
const connectionInfo = __classPrivateFieldGet(this, _BackendWebsocketDataSource_messenger, "f").call('BackendWebSocketService:getConnectionInfo');
|
|
398
|
-
if (connectionInfo.state !== 'connected') {
|
|
399
|
-
// Store the subscription request to process when WebSocket connects
|
|
400
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_pendingSubscriptions, "f").set(subscriptionId, subscriptionRequest);
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
catch {
|
|
405
|
-
// Store anyway - will be processed when we can connect
|
|
406
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_pendingSubscriptions, "f").set(subscriptionId, subscriptionRequest);
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
// Remove from pending if it was there (we're processing it now)
|
|
410
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_pendingSubscriptions, "f").delete(subscriptionId);
|
|
411
|
-
// Handle subscription update
|
|
412
|
-
if (isUpdate) {
|
|
413
|
-
const existing = this.activeSubscriptions.get(subscriptionId);
|
|
414
|
-
if (existing) {
|
|
415
|
-
// Check if accounts changed - if so, we need to re-subscribe to different channels
|
|
416
|
-
const existingAddresses = existing.addresses ?? [];
|
|
417
|
-
const addressesChanged = haveAddressesChanged(addresses, existingAddresses);
|
|
418
|
-
if (!addressesChanged) {
|
|
419
|
-
// Only chains changed - update chains, request, and callback
|
|
420
|
-
existing.chains = chainsToSubscribe;
|
|
421
|
-
existing.onAssetsUpdate = subscriptionRequest.onAssetsUpdate;
|
|
422
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_subscriptionRequests, "f").set(subscriptionId, subscriptionRequest);
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
// Accounts changed - fall through to re-subscribe with new channels
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
// Clean up existing subscription if any (inline teardown — subscribe holds the lock)
|
|
429
|
-
await __classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_teardownSubscription).call(this, subscriptionId);
|
|
430
|
-
// Always subscribe to eip155 and solana account activity, plus any namespaces from requested chains
|
|
431
|
-
const namespaces = getNamespacesForAccountActivity(chainsToSubscribe);
|
|
432
|
-
// Build channel names: use namespace-appropriate address per account (eip155 = hex, solana = base58)
|
|
433
|
-
const channels = [];
|
|
434
|
-
for (const namespace of namespaces) {
|
|
435
|
-
for (const { account } of request.accountsWithSupportedChains) {
|
|
436
|
-
const address = getAddressForAccountActivity(account, namespace);
|
|
437
|
-
if (address) {
|
|
438
|
-
channels.push(buildAccountActivityChannel(namespace, address));
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
if (channels.length === 0) {
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
try {
|
|
446
|
-
// Create WebSocket subscription
|
|
447
|
-
const wsSubscription = await __classPrivateFieldGet(this, _BackendWebsocketDataSource_messenger, "f").call('BackendWebSocketService:subscribe', {
|
|
448
|
-
channels,
|
|
449
|
-
channelType: CHANNEL_TYPE,
|
|
450
|
-
callback: (notification) => {
|
|
451
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_handleNotification).call(this, notification, subscriptionId);
|
|
452
|
-
},
|
|
453
|
-
});
|
|
454
|
-
// Store WebSocket subscription and subscription state before optional
|
|
455
|
-
// channel callbacks — wsCallback routing works without them.
|
|
456
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_wsSubscriptions, "f").set(subscriptionId, wsSubscription);
|
|
457
|
-
this.activeSubscriptions.set(subscriptionId, {
|
|
458
|
-
cleanup: () => {
|
|
459
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_teardownSubscription).call(this, subscriptionId).catch(() => undefined);
|
|
460
|
-
},
|
|
461
|
-
chains: chainsToSubscribe,
|
|
462
|
-
addresses,
|
|
463
|
-
onAssetsUpdate: subscriptionRequest.onAssetsUpdate,
|
|
464
|
-
});
|
|
465
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_subscriptionRequests, "f").set(subscriptionId, subscriptionRequest);
|
|
466
|
-
try {
|
|
467
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_registerChannelCallbacks).call(this, subscriptionId, channels);
|
|
468
|
-
}
|
|
469
|
-
catch (channelCallbackError) {
|
|
470
|
-
log('Channel callback registration failed; ws subscription still active', { subscriptionId, error: channelCallbackError });
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
catch (error) {
|
|
474
|
-
log('WebSocket subscription FAILED', {
|
|
475
|
-
subscriptionId,
|
|
476
|
-
error,
|
|
477
|
-
chains: chainsToSubscribe,
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
415
|
}, _BackendWebsocketDataSource_handleNotification = function _BackendWebsocketDataSource_handleNotification(notification, subscriptionId) {
|
|
481
416
|
try {
|
|
482
417
|
const subscription = this.activeSubscriptions.get(subscriptionId);
|
|
@@ -504,7 +439,7 @@ async function _BackendWebsocketDataSource_initializeActiveChains() {
|
|
|
504
439
|
// Process all balance updates from the activity message
|
|
505
440
|
const response = __classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_processBalanceUpdates).call(this, updates, chainId, accountId);
|
|
506
441
|
if (Object.keys(response).length > 0 && subscription) {
|
|
507
|
-
Promise.resolve(subscription.onAssetsUpdate(response
|
|
442
|
+
Promise.resolve(subscription.onAssetsUpdate(response)).catch(console.error);
|
|
508
443
|
}
|
|
509
444
|
}
|
|
510
445
|
catch (error) {
|
|
@@ -551,52 +486,6 @@ async function _BackendWebsocketDataSource_initializeActiveChains() {
|
|
|
551
486
|
response.assetsInfo = assetsMetadata;
|
|
552
487
|
}
|
|
553
488
|
return response;
|
|
554
|
-
}, _BackendWebsocketDataSource_teardownSubscription = async function _BackendWebsocketDataSource_teardownSubscription(subscriptionId) {
|
|
555
|
-
const wsSub = __classPrivateFieldGet(this, _BackendWebsocketDataSource_wsSubscriptions, "f").get(subscriptionId);
|
|
556
|
-
if (wsSub) {
|
|
557
|
-
const channels = [...wsSub.channels];
|
|
558
|
-
try {
|
|
559
|
-
await wsSub.unsubscribe();
|
|
560
|
-
}
|
|
561
|
-
catch (unsubErr) {
|
|
562
|
-
log('Error unsubscribing', { subscriptionId, error: unsubErr });
|
|
563
|
-
}
|
|
564
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_wsSubscriptions, "f").delete(subscriptionId);
|
|
565
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_removeChannelCallbacks).call(this, channels);
|
|
566
|
-
}
|
|
567
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_subscriptionRequests, "f").delete(subscriptionId);
|
|
568
|
-
this.activeSubscriptions.delete(subscriptionId);
|
|
569
|
-
}, _BackendWebsocketDataSource_registerChannelCallbacks = function _BackendWebsocketDataSource_registerChannelCallbacks(subscriptionId, channels) {
|
|
570
|
-
for (const channel of channels) {
|
|
571
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_unregisterChannelCallback).call(this, channel);
|
|
572
|
-
try {
|
|
573
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_messenger, "f").call('BackendWebSocketService:addChannelCallback', {
|
|
574
|
-
channelName: channel,
|
|
575
|
-
callback: (notification) => {
|
|
576
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_handleNotification).call(this, notification, subscriptionId);
|
|
577
|
-
},
|
|
578
|
-
});
|
|
579
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_registeredChannelCallbacks, "f").add(channel);
|
|
580
|
-
}
|
|
581
|
-
catch {
|
|
582
|
-
// Channel callbacks are optional; ws subscription still works without them.
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
}, _BackendWebsocketDataSource_unregisterChannelCallback = function _BackendWebsocketDataSource_unregisterChannelCallback(channel) {
|
|
586
|
-
if (!__classPrivateFieldGet(this, _BackendWebsocketDataSource_registeredChannelCallbacks, "f").has(channel)) {
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
try {
|
|
590
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_messenger, "f").call('BackendWebSocketService:removeChannelCallback', channel);
|
|
591
|
-
}
|
|
592
|
-
catch {
|
|
593
|
-
// Best-effort cleanup when the channel callback was never registered.
|
|
594
|
-
}
|
|
595
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_registeredChannelCallbacks, "f").delete(channel);
|
|
596
|
-
}, _BackendWebsocketDataSource_removeChannelCallbacks = function _BackendWebsocketDataSource_removeChannelCallbacks(channels) {
|
|
597
|
-
for (const channel of channels) {
|
|
598
|
-
__classPrivateFieldGet(this, _BackendWebsocketDataSource_instances, "m", _BackendWebsocketDataSource_unregisterChannelCallback).call(this, channel);
|
|
599
|
-
}
|
|
600
489
|
};
|
|
601
490
|
// ============================================================================
|
|
602
491
|
// FACTORY FUNCTION
|