@formo/analytics 1.38.2 → 1.39.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.js +9 -4
- package/dist/cjs/src/FormoAnalyticsProvider.js +20 -0
- 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/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.js +9 -4
- package/dist/esm/src/FormoAnalyticsProvider.js +20 -0
- 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/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
|
@@ -245,9 +245,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
245
245
|
this.evmEvents.trackEIP1193Provider(provider);
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
// Solana wallets are discovered through the Wallet Standard
|
|
249
|
+
// unconditionally, the way EVM wallets are through EIP-6963: an app
|
|
250
|
+
// that never configures Solana still gets its connects. `solana: false`
|
|
251
|
+
// is the opt-out; an object adds framework-kit's store or a cluster.
|
|
252
|
+
if (options.solana !== false) {
|
|
253
|
+
this.solanaManager = new SolanaManager_1.SolanaManager(this, typeof options.solana === "object" ? options.solana : undefined);
|
|
251
254
|
}
|
|
252
255
|
this._currentUrl = window.location.href;
|
|
253
256
|
// Seed currentAddress/currentChainId from the persisted snapshot before
|
|
@@ -1271,7 +1274,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1271
1274
|
*/
|
|
1272
1275
|
get: function () {
|
|
1273
1276
|
if (!this.solanaManager) {
|
|
1274
|
-
|
|
1277
|
+
// Only reachable after `solana: false` (or after cleanup). The host
|
|
1278
|
+
// opted out of discovery, so this manager serves the store path only.
|
|
1279
|
+
this.solanaManager = new SolanaManager_1.SolanaManager(this, undefined, false);
|
|
1275
1280
|
}
|
|
1276
1281
|
return this.solanaManager;
|
|
1277
1282
|
},
|
|
@@ -72,6 +72,18 @@ var defaultContext = {
|
|
|
72
72
|
hasOptedOutTracking: function () { return false; },
|
|
73
73
|
};
|
|
74
74
|
exports.FormoAnalyticsContext = (0, react_1.createContext)(defaultContext);
|
|
75
|
+
var optionObjectIds = new WeakMap();
|
|
76
|
+
var nextOptionObjectId = 1;
|
|
77
|
+
var optionObjectId = function (value) {
|
|
78
|
+
if (!value)
|
|
79
|
+
return undefined;
|
|
80
|
+
var id = optionObjectIds.get(value);
|
|
81
|
+
if (id === undefined) {
|
|
82
|
+
id = nextOptionObjectId++;
|
|
83
|
+
optionObjectIds.set(value, id);
|
|
84
|
+
}
|
|
85
|
+
return id;
|
|
86
|
+
};
|
|
75
87
|
/**
|
|
76
88
|
* A stable key over the serializable parts of Options. The provider effect
|
|
77
89
|
* re-initialises the SDK when this key changes; anything that alters SDK
|
|
@@ -95,6 +107,14 @@ var computeOptionsKey = function (options) {
|
|
|
95
107
|
logger: options.logger,
|
|
96
108
|
referral: options.referral,
|
|
97
109
|
evm: options.evm,
|
|
110
|
+
// `solana` is a boolean or an options object. A store is a live event
|
|
111
|
+
// source, so replacing it must reinitialize the SDK even when both the
|
|
112
|
+
// old and new options contain a store.
|
|
113
|
+
solana: typeof options.solana === "object" ? undefined : options.solana,
|
|
114
|
+
solanaStoreId: typeof options.solana === "object"
|
|
115
|
+
? optionObjectId(options.solana.store)
|
|
116
|
+
: undefined,
|
|
117
|
+
solanaCluster: typeof options.solana === "object" ? options.solana.cluster : undefined,
|
|
98
118
|
// For complex objects, just track their presence, not their content
|
|
99
119
|
hasProvider: !!options.provider,
|
|
100
120
|
hasWagmi: !!options.wagmi,
|
|
@@ -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
|
});
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SolanaWalletStandardRegistry
|
|
3
|
+
*
|
|
4
|
+
* Which Solana wallets exist, and whether each is connected. The Solana
|
|
5
|
+
* analogue of `EvmProviderRegistry` + EIP-6963.
|
|
6
|
+
*
|
|
7
|
+
* Compatible wallets (Phantom, Solflare, Backpack, ...) announce themselves
|
|
8
|
+
* through the Wallet Standard's window-event handshake. Solana Kit,
|
|
9
|
+
* wallet-adapter, and framework-kit use these registered wallets. Observing
|
|
10
|
+
* the handshake covers those wallets without coupling Formo to the host
|
|
11
|
+
* library: the registry announces `wallet-standard:app-ready`, listens for
|
|
12
|
+
* `wallet-standard:register-wallet`, and subscribes to each wallet's
|
|
13
|
+
* `standard:events` `change` event.
|
|
14
|
+
*
|
|
15
|
+
* What it reports:
|
|
16
|
+
* - `detect` when a wallet registers (session-deduped by the SDK on rdns).
|
|
17
|
+
* - `connect` when a wallet's Solana accounts go from none to some, or the
|
|
18
|
+
* first account changes; `disconnect` when they go from some to none.
|
|
19
|
+
* - `chain` when the configured cluster changes while a wallet is connected.
|
|
20
|
+
*
|
|
21
|
+
* What it does not do: wrap any wallet method, issue any request to a
|
|
22
|
+
* wallet, or depend on `@wallet-standard/*` (the handshake is a few lines,
|
|
23
|
+
* and the SDK's dependency policy is two runtime dependencies, forever).
|
|
24
|
+
*
|
|
25
|
+
* Cluster: the Wallet Standard lists every cluster a wallet SUPPORTS, not
|
|
26
|
+
* the one the app is using, so the cluster is `options.solana.cluster` when
|
|
27
|
+
* given, else mainnet-beta when the wallet supports it, else the first
|
|
28
|
+
* Solana cluster it lists. A framework-kit app gets the cluster from its
|
|
29
|
+
* store instead, through `SolanaStoreHandler`.
|
|
30
|
+
*
|
|
31
|
+
* @see https://github.com/wallet-standard/wallet-standard
|
|
32
|
+
*/
|
|
33
|
+
import type { AutocaptureEventType } from "../tracking/TrackingPolicy";
|
|
34
|
+
import { SolanaCluster, UnsubscribeFn } from "./types";
|
|
35
|
+
/** What the registry needs from the SDK that owns it. */
|
|
36
|
+
export interface SolanaWalletStandardRegistryDeps {
|
|
37
|
+
isAutocaptureEnabled(eventType: AutocaptureEventType): boolean;
|
|
38
|
+
willTrackEvent(chainId: number): boolean;
|
|
39
|
+
detect(params: {
|
|
40
|
+
providerName: string;
|
|
41
|
+
rdns: string;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
connect(params: {
|
|
44
|
+
chainId: number;
|
|
45
|
+
address: string;
|
|
46
|
+
}, properties: {
|
|
47
|
+
providerName: string;
|
|
48
|
+
rdns: string;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
disconnect(params: {
|
|
51
|
+
chainId: number;
|
|
52
|
+
address: string;
|
|
53
|
+
}): Promise<void>;
|
|
54
|
+
chain(params: {
|
|
55
|
+
chainId: number;
|
|
56
|
+
address: string;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Record wallet and chain state centrally WITHOUT emitting an event.
|
|
60
|
+
*
|
|
61
|
+
* Observing a chain is not the same as reporting one: the exclusion gate
|
|
62
|
+
* keys off the central chain, so a cluster switch has to land there even
|
|
63
|
+
* when `autocapture.chain` is off. The EVM tracker separates the two the
|
|
64
|
+
* same way.
|
|
65
|
+
* @see FormoAnalytics.syncWalletState
|
|
66
|
+
*/
|
|
67
|
+
syncWalletState(params: {
|
|
68
|
+
chainId: number;
|
|
69
|
+
address: string;
|
|
70
|
+
}): void;
|
|
71
|
+
/** The wallet the SDK currently treats as active, across namespaces. */
|
|
72
|
+
currentAddress(): string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Whether THIS registry reports connections.
|
|
75
|
+
*
|
|
76
|
+
* A framework-kit app connects through the very same Wallet Standard
|
|
77
|
+
* wallet, so its store and this registry both see every connection. The
|
|
78
|
+
* store is the better witness there (it knows the cluster and connector),
|
|
79
|
+
* so once it has observed or adopted a connection the registry keeps
|
|
80
|
+
* discovering wallets and emitting `detect`, but leaves connect and
|
|
81
|
+
* disconnect to the store. Exactly one connect per connection, either way.
|
|
82
|
+
*/
|
|
83
|
+
ownsWalletEvents(): boolean;
|
|
84
|
+
}
|
|
85
|
+
export interface SolanaWalletStandardRegistryOptions {
|
|
86
|
+
/** The cluster the app uses. Overrides what is derived from the wallet. */
|
|
87
|
+
cluster?: SolanaCluster;
|
|
88
|
+
}
|
|
89
|
+
export declare class SolanaWalletStandardRegistry {
|
|
90
|
+
private readonly deps;
|
|
91
|
+
private wallets;
|
|
92
|
+
private cluster?;
|
|
93
|
+
private removeWindowListener?;
|
|
94
|
+
/** Set by cleanup(); a torn-down registry refuses late registrations. */
|
|
95
|
+
private isCleanedUp;
|
|
96
|
+
/**
|
|
97
|
+
* Handed to every wallet. Wallets keep it and may call `register` long
|
|
98
|
+
* after the handshake, which is why `register` checks `isCleanedUp`.
|
|
99
|
+
*/
|
|
100
|
+
private readonly api;
|
|
101
|
+
constructor(deps: SolanaWalletStandardRegistryDeps, options?: SolanaWalletStandardRegistryOptions);
|
|
102
|
+
/**
|
|
103
|
+
* The Wallet Standard handshake, both directions.
|
|
104
|
+
*
|
|
105
|
+
* A wallet injected before us hears `app-ready` and registers at once; a
|
|
106
|
+
* wallet injected after us dispatches `register-wallet`, which we answer.
|
|
107
|
+
* Neither is optional: an extension's content script and the app's bundle
|
|
108
|
+
* race, and which one wins differs per page load.
|
|
109
|
+
*/
|
|
110
|
+
private listen;
|
|
111
|
+
/**
|
|
112
|
+
* Add wallets once. Returns an unregister function, as the standard asks.
|
|
113
|
+
*
|
|
114
|
+
* Public so an integration that already holds a wallet object (its own
|
|
115
|
+
* `getWallets()` call, say) can hand it over without the window handshake.
|
|
116
|
+
*/
|
|
117
|
+
register(...wallets: unknown[]): UnsubscribeFn;
|
|
118
|
+
private track;
|
|
119
|
+
private untrack;
|
|
120
|
+
private onChange;
|
|
121
|
+
/**
|
|
122
|
+
* Compare what the wallet now authorizes with what was last reported.
|
|
123
|
+
*
|
|
124
|
+
* none → some is a connect, some → none a disconnect, and a different
|
|
125
|
+
* first account is a disconnect followed by a connect, matching what the
|
|
126
|
+
* framework-kit store handler reports for the same transitions.
|
|
127
|
+
*/
|
|
128
|
+
private reconcile;
|
|
129
|
+
private reportConnect;
|
|
130
|
+
private reportDisconnect;
|
|
131
|
+
/**
|
|
132
|
+
* The chain id to report for a wallet.
|
|
133
|
+
*
|
|
134
|
+
* The Wallet Standard cannot say which cluster the app is on, only which
|
|
135
|
+
* ones the wallet supports, so an explicit cluster wins, then mainnet-beta
|
|
136
|
+
* if supported (nearly every wallet lists every cluster, and production
|
|
137
|
+
* traffic is mainnet), then the first cluster listed.
|
|
138
|
+
*/
|
|
139
|
+
private chainIdFor;
|
|
140
|
+
/**
|
|
141
|
+
* Set the cluster the app uses. A connected wallet's chain id follows,
|
|
142
|
+
* with a `chain` event, the same as the store handler on a cluster switch.
|
|
143
|
+
*/
|
|
144
|
+
setCluster(cluster: SolanaCluster): void;
|
|
145
|
+
/** Names of every wallet discovered so far, for the debug helpers. */
|
|
146
|
+
get walletNames(): string[];
|
|
147
|
+
/**
|
|
148
|
+
* The rdns this registry reported a still-live connect for `address`
|
|
149
|
+
* under, if any. Lets a failed store adoption name both identities.
|
|
150
|
+
*/
|
|
151
|
+
reportedConnectionRdns(address: string): string | undefined;
|
|
152
|
+
/**
|
|
153
|
+
* Transfer a connect already emitted by this registry to a store handler.
|
|
154
|
+
* The state remains connected, but the same transition must not be emitted
|
|
155
|
+
* a second time when framework-kit's store catches up.
|
|
156
|
+
*/
|
|
157
|
+
takeReportedConnection(address: string, rdns: string): {
|
|
158
|
+
address: string;
|
|
159
|
+
chainId: number;
|
|
160
|
+
} | undefined;
|
|
161
|
+
cleanup(): void;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=SolanaWalletStandardRegistry.d.ts.map
|