@formo/analytics 1.38.2 → 1.40.0
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/dist/cjs/src/FormoAnalytics.d.ts +4 -1
- package/dist/cjs/src/FormoAnalytics.js +56 -36
- package/dist/cjs/src/FormoAnalyticsProvider.js +20 -0
- package/dist/cjs/src/event/EventFactory.d.ts +9 -1
- package/dist/cjs/src/event/EventFactory.js +31 -16
- package/dist/cjs/src/event/EventManager.d.ts +3 -1
- package/dist/cjs/src/event/EventManager.js +33 -4
- package/dist/cjs/src/event/cancellation.d.ts +4 -0
- package/dist/cjs/src/event/cancellation.js +7 -0
- package/dist/cjs/src/event/type.d.ts +1 -0
- package/dist/cjs/src/event/utils.d.ts +5 -1
- package/dist/cjs/src/event/utils.js +57 -2
- package/dist/cjs/src/evm/EvmEventTracker.d.ts +7 -0
- package/dist/cjs/src/evm/EvmEventTracker.js +31 -5
- package/dist/cjs/src/queue/EventQueue.d.ts +1 -0
- package/dist/cjs/src/queue/EventQueue.js +11 -6
- package/dist/cjs/src/solana/SolanaManager.d.ts +37 -9
- package/dist/cjs/src/solana/SolanaManager.js +135 -20
- package/dist/cjs/src/solana/SolanaStoreHandler.d.ts +6 -0
- package/dist/cjs/src/solana/SolanaStoreHandler.js +17 -8
- package/dist/cjs/src/solana/SolanaWalletStandardRegistry.d.ts +163 -0
- package/dist/cjs/src/solana/SolanaWalletStandardRegistry.js +447 -0
- package/dist/cjs/src/solana/index.d.ts +10 -5
- package/dist/cjs/src/solana/index.js +12 -6
- package/dist/cjs/src/solana/storeTypes.d.ts +20 -1
- package/dist/cjs/src/solana/types.d.ts +32 -9
- package/dist/cjs/src/solana/types.js +15 -0
- package/dist/cjs/src/solana/walletStandardTypes.d.ts +54 -0
- package/dist/cjs/src/solana/walletStandardTypes.js +21 -0
- package/dist/cjs/src/storage/StorageManager.d.ts +2 -0
- package/dist/cjs/src/storage/StorageManager.js +6 -0
- package/dist/cjs/src/storage/index.d.ts +1 -0
- package/dist/cjs/src/storage/index.js +7 -1
- package/dist/cjs/src/types/base.d.ts +15 -5
- package/dist/cjs/src/version.d.ts +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/esm/src/FormoAnalytics.d.ts +4 -1
- package/dist/esm/src/FormoAnalytics.js +54 -34
- package/dist/esm/src/FormoAnalyticsProvider.js +20 -0
- package/dist/esm/src/event/EventFactory.d.ts +9 -1
- package/dist/esm/src/event/EventFactory.js +31 -16
- package/dist/esm/src/event/EventManager.d.ts +3 -1
- package/dist/esm/src/event/EventManager.js +33 -4
- package/dist/esm/src/event/cancellation.d.ts +4 -0
- package/dist/esm/src/event/cancellation.js +4 -0
- package/dist/esm/src/event/type.d.ts +1 -0
- package/dist/esm/src/event/utils.d.ts +5 -1
- package/dist/esm/src/event/utils.js +56 -3
- package/dist/esm/src/evm/EvmEventTracker.d.ts +7 -0
- package/dist/esm/src/evm/EvmEventTracker.js +31 -5
- package/dist/esm/src/queue/EventQueue.d.ts +1 -0
- package/dist/esm/src/queue/EventQueue.js +11 -6
- package/dist/esm/src/solana/SolanaManager.d.ts +37 -9
- package/dist/esm/src/solana/SolanaManager.js +135 -20
- package/dist/esm/src/solana/SolanaStoreHandler.d.ts +6 -0
- package/dist/esm/src/solana/SolanaStoreHandler.js +18 -9
- package/dist/esm/src/solana/SolanaWalletStandardRegistry.d.ts +163 -0
- package/dist/esm/src/solana/SolanaWalletStandardRegistry.js +444 -0
- package/dist/esm/src/solana/index.d.ts +10 -5
- package/dist/esm/src/solana/index.js +10 -5
- package/dist/esm/src/solana/storeTypes.d.ts +20 -1
- package/dist/esm/src/solana/types.d.ts +32 -9
- package/dist/esm/src/solana/types.js +14 -0
- package/dist/esm/src/solana/walletStandardTypes.d.ts +54 -0
- package/dist/esm/src/solana/walletStandardTypes.js +18 -0
- package/dist/esm/src/storage/StorageManager.d.ts +2 -0
- package/dist/esm/src/storage/StorageManager.js +6 -0
- package/dist/esm/src/storage/index.d.ts +1 -0
- package/dist/esm/src/storage/index.js +5 -0
- package/dist/esm/src/types/base.d.ts +15 -5
- package/dist/esm/src/version.d.ts +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +2 -2
|
@@ -11,6 +11,8 @@ export interface EvmEventTrackerDeps {
|
|
|
11
11
|
isTrackingSuppressed(): boolean;
|
|
12
12
|
/** Whether an event on this chain would actually be sent. */
|
|
13
13
|
willTrackEvent(chainId?: ChainID): boolean;
|
|
14
|
+
/** Retry detect events after the active chain changes. */
|
|
15
|
+
retryDetection(): void;
|
|
14
16
|
/** In wagmi mode the SDK does not wrap providers itself. */
|
|
15
17
|
isWagmiMode(): boolean;
|
|
16
18
|
/** Emission. The tracker decides WHEN; the SDK owns the event API. */
|
|
@@ -152,6 +154,8 @@ export declare class EvmEventTracker {
|
|
|
152
154
|
* had already replaced.
|
|
153
155
|
*/
|
|
154
156
|
private unsubscribeDiscovery?;
|
|
157
|
+
/** Discovery store retained for complete listener cleanup. */
|
|
158
|
+
private discoveryStore?;
|
|
155
159
|
constructor(wallet: WalletStateStore, registry: EvmProviderRegistry, deps: EvmEventTrackerDeps);
|
|
156
160
|
/** Stop listening for wallet announcements. Called from SDK teardown. */
|
|
157
161
|
cleanup(): void;
|
|
@@ -259,8 +263,11 @@ export declare class EvmEventTracker {
|
|
|
259
263
|
private registerConnectListener;
|
|
260
264
|
private registerDisconnectListener;
|
|
261
265
|
private onConnected;
|
|
266
|
+
/** Whether Formo owns provider lifecycle tracking. */
|
|
267
|
+
private tracksDiscovered;
|
|
262
268
|
getProviders(): Promise<readonly EIP6963ProviderDetail[]>;
|
|
263
269
|
detectWallets(providers: readonly EIP6963ProviderDetail[]): Promise<void>;
|
|
270
|
+
detectableProviders(): readonly EIP6963ProviderDetail[];
|
|
264
271
|
/**
|
|
265
272
|
* Seed a provider's chain from whatever it already exposes synchronously.
|
|
266
273
|
*
|
|
@@ -270,7 +270,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
270
270
|
};
|
|
271
271
|
/** Stop listening for wallet announcements. Called from SDK teardown. */
|
|
272
272
|
EvmEventTracker.prototype.cleanup = function () {
|
|
273
|
-
var _a;
|
|
273
|
+
var _a, _b;
|
|
274
274
|
// A replay in flight (awaiting the active wallet's accounts) must not
|
|
275
275
|
// resume into a torn-down instance and commit a session there.
|
|
276
276
|
this.disposed = true;
|
|
@@ -280,11 +280,13 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
280
280
|
this.retryRequested = false;
|
|
281
281
|
try {
|
|
282
282
|
(_a = this.unsubscribeDiscovery) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
283
|
+
(_b = this.discoveryStore) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
283
284
|
}
|
|
284
285
|
catch (e) {
|
|
285
286
|
logger_1.logger.warn("Failed to unsubscribe from provider discovery", e);
|
|
286
287
|
}
|
|
287
288
|
this.unsubscribeDiscovery = undefined;
|
|
289
|
+
this.discoveryStore = undefined;
|
|
288
290
|
};
|
|
289
291
|
EvmEventTracker.prototype.sessionGeneration = function (provider) {
|
|
290
292
|
var _a;
|
|
@@ -1018,6 +1020,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1018
1020
|
this.wallet.provider = provider;
|
|
1019
1021
|
}
|
|
1020
1022
|
this.wallet.set('evm', { chainId: nextChainId });
|
|
1023
|
+
this.deps.retryDetection();
|
|
1021
1024
|
_a.label = 1;
|
|
1022
1025
|
case 1:
|
|
1023
1026
|
_a.trys.push([1, 5, , 6]);
|
|
@@ -1335,12 +1338,17 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1335
1338
|
});
|
|
1336
1339
|
});
|
|
1337
1340
|
};
|
|
1341
|
+
/** Whether Formo owns provider lifecycle tracking. */
|
|
1342
|
+
EvmEventTracker.prototype.tracksDiscovered = function () {
|
|
1343
|
+
return !this.deps.isWagmiMode();
|
|
1344
|
+
};
|
|
1338
1345
|
EvmEventTracker.prototype.getProviders = function () {
|
|
1339
1346
|
return __awaiter(this, void 0, void 0, function () {
|
|
1340
1347
|
var store, providers, injected, injectedProviderInfo, injectedDetail, uniqueProviders, _i, uniqueProviders_1, detail;
|
|
1341
1348
|
var _this = this;
|
|
1342
1349
|
return __generator(this, function (_a) {
|
|
1343
1350
|
store = (0, mipd_1.createStore)();
|
|
1351
|
+
this.discoveryStore = store;
|
|
1344
1352
|
providers = store.getProviders();
|
|
1345
1353
|
this.unsubscribeDiscovery = store.subscribe(function (providerDetails) {
|
|
1346
1354
|
providers = providerDetails;
|
|
@@ -1359,8 +1367,12 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1359
1367
|
var p = detail === null || detail === void 0 ? void 0 : detail.provider;
|
|
1360
1368
|
return !!p && !_this.registry.isTracked(p);
|
|
1361
1369
|
});
|
|
1362
|
-
|
|
1370
|
+
// Wagmi detects only providers added by this announcement.
|
|
1371
|
+
var toDetect = _this.tracksDiscovered() ? newDetails : newlyAddedDetails;
|
|
1372
|
+
if (_this.tracksDiscovered() && newDetails.length > 0) {
|
|
1363
1373
|
_this.trackProviders(newDetails);
|
|
1374
|
+
}
|
|
1375
|
+
if (toDetect.length > 0) {
|
|
1364
1376
|
// Detect newly discovered wallets (session de-dupes) with error handling
|
|
1365
1377
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1366
1378
|
var e_3;
|
|
@@ -1368,7 +1380,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1368
1380
|
switch (_a.label) {
|
|
1369
1381
|
case 0:
|
|
1370
1382
|
_a.trys.push([0, 2, , 3]);
|
|
1371
|
-
return [4 /*yield*/, this.detectWallets(
|
|
1383
|
+
return [4 /*yield*/, this.detectWallets(toDetect)];
|
|
1372
1384
|
case 1:
|
|
1373
1385
|
_a.sent();
|
|
1374
1386
|
return [3 /*break*/, 3];
|
|
@@ -1394,7 +1406,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1394
1406
|
if (this.registry.injected &&
|
|
1395
1407
|
this.registry.injected.provider === injected) {
|
|
1396
1408
|
// Ensure it's tracked
|
|
1397
|
-
if (!this.registry.isTracked(injected)) {
|
|
1409
|
+
if (this.tracksDiscovered() && !this.registry.isTracked(injected)) {
|
|
1398
1410
|
this.trackEIP1193Provider(injected);
|
|
1399
1411
|
}
|
|
1400
1412
|
// Merge with existing providers instead of overwriting
|
|
@@ -1402,7 +1414,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1402
1414
|
return [2 /*return*/, this.registry.all];
|
|
1403
1415
|
}
|
|
1404
1416
|
// Re-check if the injected provider is already tracked just before tracking
|
|
1405
|
-
if (!this.registry.isTracked(injected)) {
|
|
1417
|
+
if (this.tracksDiscovered() && !this.registry.isTracked(injected)) {
|
|
1406
1418
|
this.trackEIP1193Provider(injected);
|
|
1407
1419
|
}
|
|
1408
1420
|
injectedProviderInfo = (0, provider_1.detectInjectedProviderInfo)(injected);
|
|
@@ -1462,6 +1474,20 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1462
1474
|
});
|
|
1463
1475
|
});
|
|
1464
1476
|
};
|
|
1477
|
+
EvmEventTracker.prototype.detectableProviders = function () {
|
|
1478
|
+
var _a;
|
|
1479
|
+
var available = new Set();
|
|
1480
|
+
(_a = this.discoveryStore) === null || _a === void 0 ? void 0 : _a.getProviders().forEach(function (detail) {
|
|
1481
|
+
return available.add(detail.provider);
|
|
1482
|
+
});
|
|
1483
|
+
var injected = typeof window !== "undefined" ? window.ethereum : undefined;
|
|
1484
|
+
if (injected)
|
|
1485
|
+
available.add(injected);
|
|
1486
|
+
this.externallyRegistered.forEach(function (provider) { return available.add(provider); });
|
|
1487
|
+
return this.registry.all.filter(function (detail) {
|
|
1488
|
+
return available.has(detail.provider);
|
|
1489
|
+
});
|
|
1490
|
+
};
|
|
1465
1491
|
/**
|
|
1466
1492
|
* Seed a provider's chain from whatever it already exposes synchronously.
|
|
1467
1493
|
*
|
|
@@ -89,6 +89,7 @@ var EventQueue = /** @class */ (function () {
|
|
|
89
89
|
this.queue = [];
|
|
90
90
|
this.queueByteSize = 0; // running total of queued items' byteSize
|
|
91
91
|
this.payloadHashes = new Set();
|
|
92
|
+
this.generation = 0;
|
|
92
93
|
// Terminal shutdown flag. Once set, enqueue() and flush() are no-ops for
|
|
93
94
|
// the rest of this instance's life. See close().
|
|
94
95
|
this.closed = false;
|
|
@@ -222,6 +223,7 @@ var EventQueue = /** @class */ (function () {
|
|
|
222
223
|
* withdrawal / SDK teardown so nothing buffered can be sent later.
|
|
223
224
|
*/
|
|
224
225
|
EventQueue.prototype.clear = function () {
|
|
226
|
+
this.generation++;
|
|
225
227
|
if (this.timer) {
|
|
226
228
|
clearTimeout(this.timer);
|
|
227
229
|
this.timer = null;
|
|
@@ -229,6 +231,8 @@ var EventQueue = /** @class */ (function () {
|
|
|
229
231
|
this.queue = [];
|
|
230
232
|
this.queueByteSize = 0;
|
|
231
233
|
this.payloadHashes.clear();
|
|
234
|
+
this.flushed = false;
|
|
235
|
+
this.pendingFlush = null;
|
|
232
236
|
};
|
|
233
237
|
/**
|
|
234
238
|
* Terminal shutdown. Unlike clear(), which only empties the buffer and can
|
|
@@ -265,11 +269,12 @@ var EventQueue = /** @class */ (function () {
|
|
|
265
269
|
});
|
|
266
270
|
EventQueue.prototype.enqueue = function (event, callback) {
|
|
267
271
|
return __awaiter(this, void 0, void 0, function () {
|
|
268
|
-
var message_id, queueItem, hasReachedFlushAt, hasReachedQueueSize;
|
|
272
|
+
var generation, message_id, queueItem, hasReachedFlushAt, hasReachedQueueSize;
|
|
269
273
|
return __generator(this, function (_a) {
|
|
270
274
|
switch (_a.label) {
|
|
271
275
|
case 0:
|
|
272
276
|
callback = callback || noop;
|
|
277
|
+
generation = this.generation;
|
|
273
278
|
// A torn-down instance must never buffer, however late the caller
|
|
274
279
|
// arrives. See close().
|
|
275
280
|
if (this.closed)
|
|
@@ -282,12 +287,12 @@ var EventQueue = /** @class */ (function () {
|
|
|
282
287
|
return [4 /*yield*/, this.generateMessageId(event)];
|
|
283
288
|
case 1:
|
|
284
289
|
message_id = _a.sent();
|
|
285
|
-
|
|
286
|
-
// suspended here, and on a queue that has not flushed yet its event
|
|
287
|
-
// would push and flush immediately - the exact shape of the bug close()
|
|
288
|
-
// exists to stop.
|
|
289
|
-
if (this.closed)
|
|
290
|
+
if (this.closed || generation !== this.generation)
|
|
290
291
|
return [2 /*return*/];
|
|
292
|
+
if (this.canSend && !this.canSend()) {
|
|
293
|
+
this.clear();
|
|
294
|
+
return [2 /*return*/];
|
|
295
|
+
}
|
|
291
296
|
// check if the message already exists
|
|
292
297
|
if (this.isDuplicate(message_id)) {
|
|
293
298
|
logger_1.logger.warn("Event already enqueued, try again after ".concat((0, utils_1.millisecondsToSecond)(this.flushIntervalMs), " seconds."));
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SolanaManager
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Subscribes to framework-kit's zustand store for automatic event capture
|
|
6
|
-
* of wallet connect/disconnect and transaction lifecycle events.
|
|
4
|
+
* Owns the two ways the SDK learns about Solana wallets:
|
|
7
5
|
*
|
|
8
|
-
*
|
|
6
|
+
* 1. `SolanaWalletStandardRegistry`: discovers wallets through the Wallet
|
|
7
|
+
* Standard and reports detect / connect / disconnect. On by default, so
|
|
8
|
+
* compatible wallets registered by Solana Kit, wallet-adapter,
|
|
9
|
+
* framework-kit, or another host are covered with no configuration,
|
|
10
|
+
* exactly like EVM wallets through EIP-6963. `solana: false` turns it off.
|
|
11
|
+
* 2. `SolanaStoreHandler`: subscribes to framework-kit's zustand store for
|
|
12
|
+
* connect / disconnect / cluster changes AND the transaction lifecycle.
|
|
13
|
+
* Opt-in through `solana: { store }` or `formo.solana.setStore()`.
|
|
14
|
+
*
|
|
15
|
+
* Both observe the same Wallet Standard connection when a framework-kit app
|
|
16
|
+
* connects. A store supplied at initialization owns wallet events; a store
|
|
17
|
+
* attached later takes ownership when it observes its first connection and
|
|
18
|
+
* adopts any connect the registry already reported. One connect per
|
|
19
|
+
* connection, whichever path an app is on.
|
|
20
|
+
*
|
|
21
|
+
* For signMessage/signTransaction tracking (not captured by either path),
|
|
9
22
|
* use formo.signature() directly with the address and chainId.
|
|
10
23
|
*
|
|
11
|
-
* For manual event tracking
|
|
24
|
+
* For manual event tracking, use the core API directly:
|
|
12
25
|
* formo.transaction(), formo.signature(), formo.connect(), formo.disconnect().
|
|
13
26
|
*/
|
|
14
27
|
import { FormoAnalytics } from "../FormoAnalytics";
|
|
@@ -16,9 +29,19 @@ import { SolanaCluster, SolanaOptions } from "./types";
|
|
|
16
29
|
import { SolanaClientStore } from "./storeTypes";
|
|
17
30
|
export declare class SolanaManager {
|
|
18
31
|
private formo;
|
|
32
|
+
private readonly enabled;
|
|
19
33
|
private storeHandler?;
|
|
34
|
+
private registry?;
|
|
20
35
|
private pendingCluster?;
|
|
21
|
-
|
|
36
|
+
private storeOwnsWalletEvents;
|
|
37
|
+
/**
|
|
38
|
+
* @param formo - The SDK instance events are reported to.
|
|
39
|
+
* @param options - `options.solana` as passed to the SDK, if an object.
|
|
40
|
+
* @param enabled - Whether Solana tracking is enabled. False only when the
|
|
41
|
+
* host app passed `solana: false`; both discovery and stores then stay off.
|
|
42
|
+
*/
|
|
43
|
+
constructor(formo: FormoAnalytics, options?: SolanaOptions, enabled?: boolean);
|
|
44
|
+
private attachStore;
|
|
22
45
|
/**
|
|
23
46
|
* Set the framework-kit zustand store for automatic event tracking.
|
|
24
47
|
* This enables autocapture mode — connect/disconnect and transaction events
|
|
@@ -39,11 +62,16 @@ export declare class SolanaManager {
|
|
|
39
62
|
cluster?: SolanaCluster;
|
|
40
63
|
}): void;
|
|
41
64
|
/**
|
|
42
|
-
* Update the cluster/network.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
65
|
+
* Update the cluster/network.
|
|
66
|
+
*
|
|
67
|
+
* With a framework-kit store, only needed if the store endpoint doesn't
|
|
68
|
+
* contain a recognizable cluster name (e.g. custom RPC URLs). Without one,
|
|
69
|
+
* this is how a non-mainnet app tells the SDK which cluster its Wallet
|
|
70
|
+
* Standard connections are on, since the standard itself cannot say.
|
|
45
71
|
*/
|
|
46
72
|
setCluster(cluster: SolanaCluster): void;
|
|
73
|
+
/** Names of the Wallet Standard wallets discovered so far. */
|
|
74
|
+
get discoveredWallets(): string[];
|
|
47
75
|
cleanup(): void;
|
|
48
76
|
}
|
|
49
77
|
//# sourceMappingURL=SolanaManager.d.ts.map
|
|
@@ -2,34 +2,126 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* SolanaManager
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* Subscribes to framework-kit's zustand store for automatic event capture
|
|
7
|
-
* of wallet connect/disconnect and transaction lifecycle events.
|
|
5
|
+
* Owns the two ways the SDK learns about Solana wallets:
|
|
8
6
|
*
|
|
9
|
-
*
|
|
7
|
+
* 1. `SolanaWalletStandardRegistry`: discovers wallets through the Wallet
|
|
8
|
+
* Standard and reports detect / connect / disconnect. On by default, so
|
|
9
|
+
* compatible wallets registered by Solana Kit, wallet-adapter,
|
|
10
|
+
* framework-kit, or another host are covered with no configuration,
|
|
11
|
+
* exactly like EVM wallets through EIP-6963. `solana: false` turns it off.
|
|
12
|
+
* 2. `SolanaStoreHandler`: subscribes to framework-kit's zustand store for
|
|
13
|
+
* connect / disconnect / cluster changes AND the transaction lifecycle.
|
|
14
|
+
* Opt-in through `solana: { store }` or `formo.solana.setStore()`.
|
|
15
|
+
*
|
|
16
|
+
* Both observe the same Wallet Standard connection when a framework-kit app
|
|
17
|
+
* connects. A store supplied at initialization owns wallet events; a store
|
|
18
|
+
* attached later takes ownership when it observes its first connection and
|
|
19
|
+
* adopts any connect the registry already reported. One connect per
|
|
20
|
+
* connection, whichever path an app is on.
|
|
21
|
+
*
|
|
22
|
+
* For signMessage/signTransaction tracking (not captured by either path),
|
|
10
23
|
* use formo.signature() directly with the address and chainId.
|
|
11
24
|
*
|
|
12
|
-
* For manual event tracking
|
|
25
|
+
* For manual event tracking, use the core API directly:
|
|
13
26
|
* formo.transaction(), formo.signature(), formo.connect(), formo.disconnect().
|
|
14
27
|
*/
|
|
15
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
29
|
exports.SolanaManager = void 0;
|
|
17
30
|
var logger_1 = require("../logger");
|
|
18
31
|
var SolanaStoreHandler_1 = require("./SolanaStoreHandler");
|
|
32
|
+
var SolanaWalletStandardRegistry_1 = require("./SolanaWalletStandardRegistry");
|
|
33
|
+
var types_1 = require("./types");
|
|
19
34
|
var SolanaManager = /** @class */ (function () {
|
|
20
|
-
|
|
35
|
+
/**
|
|
36
|
+
* @param formo - The SDK instance events are reported to.
|
|
37
|
+
* @param options - `options.solana` as passed to the SDK, if an object.
|
|
38
|
+
* @param enabled - Whether Solana tracking is enabled. False only when the
|
|
39
|
+
* host app passed `solana: false`; both discovery and stores then stay off.
|
|
40
|
+
*/
|
|
41
|
+
function SolanaManager(formo, options, enabled) {
|
|
42
|
+
if (enabled === void 0) { enabled = true; }
|
|
43
|
+
var _this = this;
|
|
21
44
|
this.formo = formo;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
else if (options === null || options === void 0 ? void 0 : options.cluster) {
|
|
45
|
+
this.enabled = enabled;
|
|
46
|
+
this.storeOwnsWalletEvents = false;
|
|
47
|
+
if (!enabled)
|
|
48
|
+
return;
|
|
49
|
+
if (options === null || options === void 0 ? void 0 : options.cluster) {
|
|
29
50
|
// Store pending cluster for when setStore is called later
|
|
30
51
|
this.pendingCluster = options.cluster;
|
|
31
52
|
}
|
|
53
|
+
// A store supplied at initialization owns wallet events from the outset:
|
|
54
|
+
// unlike a store attached later, it has not missed any prior registry
|
|
55
|
+
// state and it knows the cluster more precisely.
|
|
56
|
+
this.storeOwnsWalletEvents = !!(options === null || options === void 0 ? void 0 : options.store);
|
|
57
|
+
this.registry = new SolanaWalletStandardRegistry_1.SolanaWalletStandardRegistry({
|
|
58
|
+
isAutocaptureEnabled: function (t) { return _this.formo.isAutocaptureEnabled(t); },
|
|
59
|
+
willTrackEvent: function (chainId) { return _this.formo.willTrackEvent(chainId); },
|
|
60
|
+
detect: function (params) { return _this.formo.detect(params); },
|
|
61
|
+
connect: function (params, properties) {
|
|
62
|
+
return _this.formo.connect(params, properties);
|
|
63
|
+
},
|
|
64
|
+
disconnect: function (params) { return _this.formo.disconnect(params); },
|
|
65
|
+
chain: function (params) { return _this.formo.chain(params); },
|
|
66
|
+
syncWalletState: function (params) { return _this.formo.syncWalletState(params); },
|
|
67
|
+
currentAddress: function () { return _this.formo.currentAddress; },
|
|
68
|
+
ownsWalletEvents: function () { return !_this.storeOwnsWalletEvents; },
|
|
69
|
+
}, { cluster: options === null || options === void 0 ? void 0 : options.cluster });
|
|
70
|
+
if (options === null || options === void 0 ? void 0 : options.store) {
|
|
71
|
+
logger_1.logger.info("SolanaManager: Initializing store-based Solana tracking");
|
|
72
|
+
this.attachStore(options.store, options.cluster);
|
|
73
|
+
}
|
|
32
74
|
}
|
|
75
|
+
SolanaManager.prototype.attachStore = function (store, cluster) {
|
|
76
|
+
var _this = this;
|
|
77
|
+
var _a;
|
|
78
|
+
this.storeHandler = new SolanaStoreHandler_1.SolanaStoreHandler(this.formo, store, {
|
|
79
|
+
cluster: cluster,
|
|
80
|
+
beforeWalletConnect: function (connection) {
|
|
81
|
+
var _a, _b;
|
|
82
|
+
// The store's cluster is authoritative even when chain autocapture is
|
|
83
|
+
// disabled. Keep central attribution correct without manufacturing a
|
|
84
|
+
// chain event in that mode.
|
|
85
|
+
_this.formo.syncWalletState({
|
|
86
|
+
address: connection.address,
|
|
87
|
+
chainId: connection.chainId,
|
|
88
|
+
});
|
|
89
|
+
if (_this.storeOwnsWalletEvents)
|
|
90
|
+
return true;
|
|
91
|
+
var reported = (_a = _this.registry) === null || _a === void 0 ? void 0 : _a.takeReportedConnection(connection.address, connection.rdns);
|
|
92
|
+
_this.storeOwnsWalletEvents = true;
|
|
93
|
+
// If Wallet Standard got there first, the store adopts that live
|
|
94
|
+
// connection instead of emitting it again. Correct its cluster if
|
|
95
|
+
// the store has more precise information.
|
|
96
|
+
if (!reported) {
|
|
97
|
+
// Nothing to adopt. Either the registry never reported this
|
|
98
|
+
// connection, or it reported it under another identity, in which
|
|
99
|
+
// case the store is about to emit a second connect for the same
|
|
100
|
+
// live connection. Both paths derive the rdns from the wallet's
|
|
101
|
+
// own name, so a mismatch means the store's connector is labelled
|
|
102
|
+
// differently from the registered wallet.
|
|
103
|
+
var held = (_b = _this.registry) === null || _b === void 0 ? void 0 : _b.reportedConnectionRdns(connection.address);
|
|
104
|
+
if (held) {
|
|
105
|
+
logger_1.logger.warn("SolanaManager: Store connector does not match the discovered wallet; the connection is reported twice", { storeRdns: connection.rdns, walletRdns: held });
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (reported.chainId !== connection.chainId &&
|
|
110
|
+
_this.formo.isAutocaptureEnabled("chain")) {
|
|
111
|
+
_this.formo.chain(connection).catch(function (error) {
|
|
112
|
+
logger_1.logger.error("SolanaManager: Error correcting cluster during store handoff", error);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
// Keep the registry's snapshot on the store's detected cluster. This is
|
|
119
|
+
// silent once the store owns events; during a late handoff it corrects a
|
|
120
|
+
// registry-reported connection before the store adopts it.
|
|
121
|
+
var detectedCluster = types_1.SOLANA_CLUSTERS_BY_ID[this.storeHandler.getChainId()];
|
|
122
|
+
if (detectedCluster)
|
|
123
|
+
(_a = this.registry) === null || _a === void 0 ? void 0 : _a.setCluster(detectedCluster);
|
|
124
|
+
};
|
|
33
125
|
/**
|
|
34
126
|
* Set the framework-kit zustand store for automatic event tracking.
|
|
35
127
|
* This enables autocapture mode — connect/disconnect and transaction events
|
|
@@ -48,29 +140,52 @@ var SolanaManager = /** @class */ (function () {
|
|
|
48
140
|
*/
|
|
49
141
|
SolanaManager.prototype.setStore = function (store, options) {
|
|
50
142
|
var _a;
|
|
143
|
+
if (!this.enabled) {
|
|
144
|
+
logger_1.logger.warn("SolanaManager: Ignoring setStore. Solana tracking is off for this instance (solana: false, or the SDK was cleaned up)");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
51
147
|
(_a = this.storeHandler) === null || _a === void 0 ? void 0 : _a.cleanup();
|
|
52
|
-
this.storeHandler =
|
|
53
|
-
|
|
54
|
-
|
|
148
|
+
this.storeHandler = undefined;
|
|
149
|
+
this.storeOwnsWalletEvents = false;
|
|
150
|
+
this.attachStore(store, (options === null || options === void 0 ? void 0 : options.cluster) || this.pendingCluster);
|
|
55
151
|
this.pendingCluster = undefined;
|
|
56
152
|
};
|
|
57
153
|
/**
|
|
58
|
-
* Update the cluster/network.
|
|
59
|
-
*
|
|
60
|
-
*
|
|
154
|
+
* Update the cluster/network.
|
|
155
|
+
*
|
|
156
|
+
* With a framework-kit store, only needed if the store endpoint doesn't
|
|
157
|
+
* contain a recognizable cluster name (e.g. custom RPC URLs). Without one,
|
|
158
|
+
* this is how a non-mainnet app tells the SDK which cluster its Wallet
|
|
159
|
+
* Standard connections are on, since the standard itself cannot say.
|
|
61
160
|
*/
|
|
62
161
|
SolanaManager.prototype.setCluster = function (cluster) {
|
|
162
|
+
var _a;
|
|
163
|
+
if (!this.enabled)
|
|
164
|
+
return;
|
|
63
165
|
if (this.storeHandler) {
|
|
64
166
|
this.storeHandler.setCluster(cluster);
|
|
65
167
|
}
|
|
66
168
|
else {
|
|
67
169
|
this.pendingCluster = cluster;
|
|
68
170
|
}
|
|
171
|
+
(_a = this.registry) === null || _a === void 0 ? void 0 : _a.setCluster(cluster);
|
|
69
172
|
};
|
|
173
|
+
Object.defineProperty(SolanaManager.prototype, "discoveredWallets", {
|
|
174
|
+
/** Names of the Wallet Standard wallets discovered so far. */
|
|
175
|
+
get: function () {
|
|
176
|
+
var _a, _b;
|
|
177
|
+
return (_b = (_a = this.registry) === null || _a === void 0 ? void 0 : _a.walletNames) !== null && _b !== void 0 ? _b : [];
|
|
178
|
+
},
|
|
179
|
+
enumerable: false,
|
|
180
|
+
configurable: true
|
|
181
|
+
});
|
|
70
182
|
SolanaManager.prototype.cleanup = function () {
|
|
71
|
-
var _a;
|
|
183
|
+
var _a, _b;
|
|
72
184
|
(_a = this.storeHandler) === null || _a === void 0 ? void 0 : _a.cleanup();
|
|
73
185
|
this.storeHandler = undefined;
|
|
186
|
+
this.storeOwnsWalletEvents = false;
|
|
187
|
+
(_b = this.registry) === null || _b === void 0 ? void 0 : _b.cleanup();
|
|
188
|
+
this.registry = undefined;
|
|
74
189
|
};
|
|
75
190
|
return SolanaManager;
|
|
76
191
|
}());
|
|
@@ -48,8 +48,14 @@ export declare class SolanaStoreHandler {
|
|
|
48
48
|
* When true, auto-detection from the store endpoint is disabled.
|
|
49
49
|
*/
|
|
50
50
|
private explicitCluster;
|
|
51
|
+
private beforeWalletConnect?;
|
|
51
52
|
constructor(formoAnalytics: FormoAnalytics, store: SolanaClientStore, options?: {
|
|
52
53
|
cluster?: SolanaCluster;
|
|
54
|
+
beforeWalletConnect?: (connection: {
|
|
55
|
+
address: string;
|
|
56
|
+
chainId: number;
|
|
57
|
+
rdns: string;
|
|
58
|
+
}) => boolean;
|
|
53
59
|
});
|
|
54
60
|
/**
|
|
55
61
|
* Update the cluster/network.
|
|
@@ -69,6 +69,7 @@ var SolanaStoreHandler = /** @class */ (function () {
|
|
|
69
69
|
this.formo = formoAnalytics;
|
|
70
70
|
this.store = store;
|
|
71
71
|
this.explicitCluster = !!(options === null || options === void 0 ? void 0 : options.cluster);
|
|
72
|
+
this.beforeWalletConnect = options === null || options === void 0 ? void 0 : options.beforeWalletConnect;
|
|
72
73
|
this.cluster = (options === null || options === void 0 ? void 0 : options.cluster) || this.detectClusterFromStore(store) || "mainnet-beta";
|
|
73
74
|
this.chainId = types_1.SOLANA_CHAIN_IDS[this.cluster];
|
|
74
75
|
logger_1.logger.info("SolanaStoreHandler: Initializing framework-kit store integration", {
|
|
@@ -141,7 +142,7 @@ var SolanaStoreHandler = /** @class */ (function () {
|
|
|
141
142
|
logger_1.logger.info("SolanaStoreHandler: Wallet subscription set up");
|
|
142
143
|
};
|
|
143
144
|
SolanaStoreHandler.prototype.checkInitialWalletState = function () {
|
|
144
|
-
var _a;
|
|
145
|
+
var _a, _b, _c;
|
|
145
146
|
var state = this.store.getState();
|
|
146
147
|
var wallet = state.wallet;
|
|
147
148
|
if (wallet.status === "connected") {
|
|
@@ -154,11 +155,17 @@ var SolanaStoreHandler = /** @class */ (function () {
|
|
|
154
155
|
address: address,
|
|
155
156
|
chainId: this.chainId,
|
|
156
157
|
});
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
var connectorName = ((_a = wallet.session.connector) === null || _a === void 0 ? void 0 : _a.name) || wallet.connectorId;
|
|
159
|
+
var rdns = (0, types_1.solanaWalletRdns)(connectorName);
|
|
160
|
+
var shouldEmit = (_c = (_b = this.beforeWalletConnect) === null || _b === void 0 ? void 0 : _b.call(this, {
|
|
161
|
+
address: address,
|
|
162
|
+
chainId: this.chainId,
|
|
163
|
+
rdns: rdns,
|
|
164
|
+
})) !== null && _c !== void 0 ? _c : true;
|
|
165
|
+
if (shouldEmit && this.formo.isAutocaptureEnabled("connect")) {
|
|
159
166
|
this.formo.connect({ chainId: this.chainId, address: address }, {
|
|
160
167
|
providerName: connectorName,
|
|
161
|
-
rdns:
|
|
168
|
+
rdns: rdns,
|
|
162
169
|
}).catch(function (error) {
|
|
163
170
|
logger_1.logger.error("SolanaStoreHandler: Error emitting initial connect", error);
|
|
164
171
|
});
|
|
@@ -190,7 +197,7 @@ var SolanaStoreHandler = /** @class */ (function () {
|
|
|
190
197
|
this.lastWalletStatus = wallet.status;
|
|
191
198
|
};
|
|
192
199
|
SolanaStoreHandler.prototype.handleConnect = function (wallet) {
|
|
193
|
-
var _a;
|
|
200
|
+
var _a, _b, _c;
|
|
194
201
|
var address = wallet.session.account.address;
|
|
195
202
|
if (!address || (0, address_1.isBlockedSolanaAddress)(address)) {
|
|
196
203
|
return;
|
|
@@ -206,11 +213,13 @@ var SolanaStoreHandler = /** @class */ (function () {
|
|
|
206
213
|
chainId: chainId,
|
|
207
214
|
connector: wallet.connectorId,
|
|
208
215
|
});
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
var connectorName = ((_a = wallet.session.connector) === null || _a === void 0 ? void 0 : _a.name) || wallet.connectorId;
|
|
217
|
+
var rdns = (0, types_1.solanaWalletRdns)(connectorName);
|
|
218
|
+
var shouldEmit = (_c = (_b = this.beforeWalletConnect) === null || _b === void 0 ? void 0 : _b.call(this, { address: address, chainId: chainId, rdns: rdns })) !== null && _c !== void 0 ? _c : true;
|
|
219
|
+
if (shouldEmit && this.formo.isAutocaptureEnabled("connect")) {
|
|
211
220
|
this.formo.connect({ chainId: chainId, address: address }, {
|
|
212
221
|
providerName: connectorName,
|
|
213
|
-
rdns:
|
|
222
|
+
rdns: rdns,
|
|
214
223
|
}).catch(function (error) {
|
|
215
224
|
logger_1.logger.error("SolanaStoreHandler: Error emitting connect", error);
|
|
216
225
|
});
|