@formo/analytics 1.28.5 → 1.28.6
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 +7 -3
- package/dist/cjs/src/FormoAnalytics.js +24 -12
- package/dist/cjs/src/index.d.ts +3 -1
- package/dist/cjs/src/index.js +5 -1
- package/dist/cjs/src/solana/SolanaManager.d.ts +36 -11
- package/dist/cjs/src/solana/SolanaManager.js +47 -49
- package/dist/cjs/src/solana/SolanaStoreHandler.d.ts +88 -0
- package/dist/cjs/src/solana/SolanaStoreHandler.js +471 -0
- package/dist/cjs/src/solana/index.d.ts +8 -4
- package/dist/cjs/src/solana/index.js +10 -6
- package/dist/cjs/src/solana/storeTypes.d.ts +107 -0
- package/dist/cjs/src/solana/storeTypes.js +12 -0
- package/dist/cjs/src/solana/types.d.ts +23 -154
- package/dist/cjs/src/solana/types.js +4 -37
- package/dist/cjs/src/storage/StorageManager.d.ts +1 -0
- package/dist/cjs/src/storage/StorageManager.js +10 -2
- package/dist/cjs/src/types/base.d.ts +16 -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 +7 -3
- package/dist/esm/src/FormoAnalytics.js +24 -12
- package/dist/esm/src/index.d.ts +3 -1
- package/dist/esm/src/index.js +1 -0
- package/dist/esm/src/solana/SolanaManager.d.ts +36 -11
- package/dist/esm/src/solana/SolanaManager.js +47 -49
- package/dist/esm/src/solana/SolanaStoreHandler.d.ts +88 -0
- package/dist/esm/src/solana/SolanaStoreHandler.js +468 -0
- package/dist/esm/src/solana/index.d.ts +8 -4
- package/dist/esm/src/solana/index.js +8 -4
- package/dist/esm/src/solana/storeTypes.d.ts +107 -0
- package/dist/esm/src/solana/storeTypes.js +11 -0
- package/dist/esm/src/solana/types.d.ts +23 -154
- package/dist/esm/src/solana/types.js +3 -34
- package/dist/esm/src/storage/StorageManager.d.ts +1 -0
- package/dist/esm/src/storage/StorageManager.js +10 -2
- package/dist/esm/src/types/base.d.ts +16 -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 +3 -3
- package/dist/cjs/src/solana/SolanaAdapter.d.ts +0 -210
- package/dist/cjs/src/solana/SolanaAdapter.js +0 -988
- package/dist/esm/src/solana/SolanaAdapter.d.ts +0 -210
- package/dist/esm/src/solana/SolanaAdapter.js +0 -985
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SolanaStoreHandler
|
|
4
|
+
*
|
|
5
|
+
* Handles wallet event tracking by subscribing to framework-kit's zustand store.
|
|
6
|
+
* This provides automatic event capture (autocapture) for Solana wallets without
|
|
7
|
+
* wrapping any wallet methods — similar to how WagmiEventHandler subscribes to
|
|
8
|
+
* TanStack Query's mutation/query caches.
|
|
9
|
+
*
|
|
10
|
+
* Subscribes to:
|
|
11
|
+
* - `state.wallet` — connect/disconnect events
|
|
12
|
+
* - `state.transactions` — transaction lifecycle events (sending → confirmed/failed)
|
|
13
|
+
*
|
|
14
|
+
* @see https://github.com/solana-foundation/framework-kit
|
|
15
|
+
*/
|
|
16
|
+
var __assign = (this && this.__assign) || function () {
|
|
17
|
+
__assign = Object.assign || function(t) {
|
|
18
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
19
|
+
s = arguments[i];
|
|
20
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
21
|
+
t[p] = s[p];
|
|
22
|
+
}
|
|
23
|
+
return t;
|
|
24
|
+
};
|
|
25
|
+
return __assign.apply(this, arguments);
|
|
26
|
+
};
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.SolanaStoreHandler = void 0;
|
|
29
|
+
var events_1 = require("../types/events");
|
|
30
|
+
var logger_1 = require("../logger");
|
|
31
|
+
var types_1 = require("./types");
|
|
32
|
+
var address_1 = require("./address");
|
|
33
|
+
/**
|
|
34
|
+
* Clean up old entries from a Set to prevent memory leaks.
|
|
35
|
+
*/
|
|
36
|
+
function cleanupOldEntries(set, maxSize, removeCount) {
|
|
37
|
+
if (maxSize === void 0) { maxSize = 1000; }
|
|
38
|
+
if (removeCount === void 0) { removeCount = 500; }
|
|
39
|
+
if (set.size > maxSize) {
|
|
40
|
+
var entries = Array.from(set);
|
|
41
|
+
for (var i = 0; i < removeCount && i < entries.length; i++) {
|
|
42
|
+
set.delete(entries[i]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
var SolanaStoreHandler = /** @class */ (function () {
|
|
47
|
+
function SolanaStoreHandler(formoAnalytics, store, options) {
|
|
48
|
+
this.unsubscribers = [];
|
|
49
|
+
/**
|
|
50
|
+
* Track last known wallet status to detect transitions.
|
|
51
|
+
*/
|
|
52
|
+
this.lastWalletStatus = "disconnected";
|
|
53
|
+
/**
|
|
54
|
+
* Track processed transaction state changes to prevent duplicate events.
|
|
55
|
+
* Key format: `${signature}:${status}`
|
|
56
|
+
*/
|
|
57
|
+
this.processedTransactions = new Set();
|
|
58
|
+
/**
|
|
59
|
+
* Track transactions we've emitted STARTED for (status was "sending").
|
|
60
|
+
* Ensures we only emit STARTED once per transaction key.
|
|
61
|
+
*/
|
|
62
|
+
this.startedTransactions = new Set();
|
|
63
|
+
/**
|
|
64
|
+
* Per-transaction sender address captured at STARTED time.
|
|
65
|
+
* Ensures terminal events (confirmed/failed) are attributed correctly
|
|
66
|
+
* even if the wallet disconnects before the transaction settles.
|
|
67
|
+
*/
|
|
68
|
+
this.transactionSenders = new Map();
|
|
69
|
+
this.formo = formoAnalytics;
|
|
70
|
+
this.store = store;
|
|
71
|
+
this.explicitCluster = !!(options === null || options === void 0 ? void 0 : options.cluster);
|
|
72
|
+
this.cluster = (options === null || options === void 0 ? void 0 : options.cluster) || this.detectClusterFromStore(store) || "mainnet-beta";
|
|
73
|
+
this.chainId = types_1.SOLANA_CHAIN_IDS[this.cluster];
|
|
74
|
+
logger_1.logger.info("SolanaStoreHandler: Initializing framework-kit store integration", {
|
|
75
|
+
cluster: this.cluster,
|
|
76
|
+
chainId: this.chainId,
|
|
77
|
+
});
|
|
78
|
+
this.setupWalletSubscription();
|
|
79
|
+
this.setupTransactionSubscription();
|
|
80
|
+
this.setupClusterSubscription();
|
|
81
|
+
// Check initial wallet state
|
|
82
|
+
this.checkInitialWalletState();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Update the cluster/network.
|
|
86
|
+
*/
|
|
87
|
+
SolanaStoreHandler.prototype.setCluster = function (cluster) {
|
|
88
|
+
this.explicitCluster = true;
|
|
89
|
+
var previousCluster = this.cluster;
|
|
90
|
+
this.cluster = cluster;
|
|
91
|
+
this.chainId = types_1.SOLANA_CHAIN_IDS[cluster];
|
|
92
|
+
if (previousCluster !== cluster && this.lastAddress) {
|
|
93
|
+
this.lastChainId = this.chainId;
|
|
94
|
+
if (this.formo.isAutocaptureEnabled("chain")) {
|
|
95
|
+
this.formo.chain({
|
|
96
|
+
chainId: this.chainId,
|
|
97
|
+
address: this.lastAddress,
|
|
98
|
+
}).catch(function (error) {
|
|
99
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting chain event", error);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Get the current chain ID.
|
|
106
|
+
*/
|
|
107
|
+
SolanaStoreHandler.prototype.getChainId = function () {
|
|
108
|
+
return this.chainId;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Resolve the current chainId from the live store state.
|
|
112
|
+
* This ensures correctness when wallet and cluster change in the same tick
|
|
113
|
+
* (the cluster subscription may not have fired yet).
|
|
114
|
+
*/
|
|
115
|
+
SolanaStoreHandler.prototype.resolveCurrentChainId = function () {
|
|
116
|
+
// Don't auto-detect if the cluster was explicitly set
|
|
117
|
+
if (!this.explicitCluster) {
|
|
118
|
+
var detected = this.detectClusterFromStore(this.store);
|
|
119
|
+
if (detected) {
|
|
120
|
+
this.cluster = detected;
|
|
121
|
+
this.chainId = types_1.SOLANA_CHAIN_IDS[detected];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return this.chainId;
|
|
125
|
+
};
|
|
126
|
+
// ============================================================
|
|
127
|
+
// Wallet Subscription
|
|
128
|
+
// ============================================================
|
|
129
|
+
SolanaStoreHandler.prototype.setupWalletSubscription = function () {
|
|
130
|
+
var _this = this;
|
|
131
|
+
var prevWallet = this.store.getState().wallet;
|
|
132
|
+
var unsubscribe = this.store.subscribe(function (state) {
|
|
133
|
+
var wallet = state.wallet;
|
|
134
|
+
if (wallet !== prevWallet) {
|
|
135
|
+
var prev = prevWallet;
|
|
136
|
+
prevWallet = wallet;
|
|
137
|
+
_this.handleWalletChange(wallet, prev);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
this.unsubscribers.push(unsubscribe);
|
|
141
|
+
logger_1.logger.info("SolanaStoreHandler: Wallet subscription set up");
|
|
142
|
+
};
|
|
143
|
+
SolanaStoreHandler.prototype.checkInitialWalletState = function () {
|
|
144
|
+
var _a;
|
|
145
|
+
var state = this.store.getState();
|
|
146
|
+
var wallet = state.wallet;
|
|
147
|
+
if (wallet.status === "connected") {
|
|
148
|
+
var address = wallet.session.account.address;
|
|
149
|
+
if (address && !(0, address_1.isBlockedSolanaAddress)(address)) {
|
|
150
|
+
this.lastWalletStatus = "connected";
|
|
151
|
+
this.lastAddress = address;
|
|
152
|
+
this.lastChainId = this.chainId;
|
|
153
|
+
logger_1.logger.info("SolanaStoreHandler: Already connected on initialization", {
|
|
154
|
+
address: address,
|
|
155
|
+
chainId: this.chainId,
|
|
156
|
+
});
|
|
157
|
+
if (this.formo.isAutocaptureEnabled("connect")) {
|
|
158
|
+
var connectorName = ((_a = wallet.session.connector) === null || _a === void 0 ? void 0 : _a.name) || wallet.connectorId;
|
|
159
|
+
this.formo.connect({ chainId: this.chainId, address: address }, {
|
|
160
|
+
providerName: connectorName,
|
|
161
|
+
rdns: "sol.wallet.".concat(connectorName.toLowerCase().replace(/\s+/g, "")),
|
|
162
|
+
}).catch(function (error) {
|
|
163
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting initial connect", error);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
this.lastWalletStatus = wallet.status;
|
|
169
|
+
};
|
|
170
|
+
SolanaStoreHandler.prototype.handleWalletChange = function (wallet, prevWallet) {
|
|
171
|
+
// connected → any other state (disconnected, error, connecting)
|
|
172
|
+
if (prevWallet.status === "connected" &&
|
|
173
|
+
wallet.status !== "connected") {
|
|
174
|
+
this.handleDisconnect();
|
|
175
|
+
}
|
|
176
|
+
// * → connected (new connection)
|
|
177
|
+
if (wallet.status === "connected" && prevWallet.status !== "connected") {
|
|
178
|
+
this.handleConnect(wallet);
|
|
179
|
+
}
|
|
180
|
+
else if (wallet.status === "connected" &&
|
|
181
|
+
prevWallet.status === "connected") {
|
|
182
|
+
// connected → connected: check for account switch OR connector change
|
|
183
|
+
var addressChanged = wallet.session.account.address !== prevWallet.session.account.address;
|
|
184
|
+
var connectorChanged = wallet.connectorId !== prevWallet.connectorId;
|
|
185
|
+
if (addressChanged || connectorChanged) {
|
|
186
|
+
this.handleDisconnect();
|
|
187
|
+
this.handleConnect(wallet);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
this.lastWalletStatus = wallet.status;
|
|
191
|
+
};
|
|
192
|
+
SolanaStoreHandler.prototype.handleConnect = function (wallet) {
|
|
193
|
+
var _a;
|
|
194
|
+
var address = wallet.session.account.address;
|
|
195
|
+
if (!address || (0, address_1.isBlockedSolanaAddress)(address)) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// Resolve chainId from live store state so batched wallet+cluster
|
|
199
|
+
// updates use the correct network even if the cluster subscription
|
|
200
|
+
// hasn't fired yet.
|
|
201
|
+
var chainId = this.resolveCurrentChainId();
|
|
202
|
+
this.lastAddress = address;
|
|
203
|
+
this.lastChainId = chainId;
|
|
204
|
+
logger_1.logger.info("SolanaStoreHandler: Wallet connected", {
|
|
205
|
+
address: address,
|
|
206
|
+
chainId: chainId,
|
|
207
|
+
connector: wallet.connectorId,
|
|
208
|
+
});
|
|
209
|
+
if (this.formo.isAutocaptureEnabled("connect")) {
|
|
210
|
+
var connectorName = ((_a = wallet.session.connector) === null || _a === void 0 ? void 0 : _a.name) || wallet.connectorId;
|
|
211
|
+
this.formo.connect({ chainId: chainId, address: address }, {
|
|
212
|
+
providerName: connectorName,
|
|
213
|
+
rdns: "sol.wallet.".concat(connectorName.toLowerCase().replace(/\s+/g, "")),
|
|
214
|
+
}).catch(function (error) {
|
|
215
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting connect", error);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
SolanaStoreHandler.prototype.handleDisconnect = function () {
|
|
220
|
+
if (!this.lastAddress) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
logger_1.logger.info("SolanaStoreHandler: Wallet disconnected", {
|
|
224
|
+
address: this.lastAddress,
|
|
225
|
+
chainId: this.lastChainId,
|
|
226
|
+
});
|
|
227
|
+
if (this.formo.isAutocaptureEnabled("disconnect")) {
|
|
228
|
+
this.formo.disconnect({
|
|
229
|
+
chainId: this.lastChainId,
|
|
230
|
+
address: this.lastAddress,
|
|
231
|
+
}).catch(function (error) {
|
|
232
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting disconnect", error);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
this.lastAddress = undefined;
|
|
236
|
+
this.lastChainId = undefined;
|
|
237
|
+
};
|
|
238
|
+
// ============================================================
|
|
239
|
+
// Cluster Subscription
|
|
240
|
+
// ============================================================
|
|
241
|
+
SolanaStoreHandler.prototype.setupClusterSubscription = function () {
|
|
242
|
+
var _this = this;
|
|
243
|
+
var prevEndpoint = this.store.getState().cluster.endpoint;
|
|
244
|
+
var unsubscribe = this.store.subscribe(function (state) {
|
|
245
|
+
var endpoint = state.cluster.endpoint;
|
|
246
|
+
if (endpoint !== prevEndpoint) {
|
|
247
|
+
prevEndpoint = endpoint;
|
|
248
|
+
_this.handleClusterChange(endpoint);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
this.unsubscribers.push(unsubscribe);
|
|
252
|
+
logger_1.logger.info("SolanaStoreHandler: Cluster subscription set up");
|
|
253
|
+
};
|
|
254
|
+
SolanaStoreHandler.prototype.handleClusterChange = function (endpoint) {
|
|
255
|
+
// Don't auto-detect if the cluster was explicitly set
|
|
256
|
+
if (this.explicitCluster) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
var detected = this.detectClusterFromEndpoint(endpoint);
|
|
260
|
+
if (!detected) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
var previousCluster = this.cluster;
|
|
264
|
+
if (detected === previousCluster) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
this.cluster = detected;
|
|
268
|
+
this.chainId = types_1.SOLANA_CHAIN_IDS[detected];
|
|
269
|
+
logger_1.logger.info("SolanaStoreHandler: Cluster changed", {
|
|
270
|
+
from: previousCluster,
|
|
271
|
+
to: detected,
|
|
272
|
+
chainId: this.chainId,
|
|
273
|
+
});
|
|
274
|
+
if (this.lastAddress) {
|
|
275
|
+
this.lastChainId = this.chainId;
|
|
276
|
+
if (this.formo.isAutocaptureEnabled("chain")) {
|
|
277
|
+
this.formo.chain({
|
|
278
|
+
chainId: this.chainId,
|
|
279
|
+
address: this.lastAddress,
|
|
280
|
+
}).catch(function (error) {
|
|
281
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting chain event", error);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
// ============================================================
|
|
287
|
+
// Transaction Subscription
|
|
288
|
+
// ============================================================
|
|
289
|
+
SolanaStoreHandler.prototype.setupTransactionSubscription = function () {
|
|
290
|
+
var _this = this;
|
|
291
|
+
var prevTransactions = this.store.getState().transactions;
|
|
292
|
+
var unsubscribe = this.store.subscribe(function (state) {
|
|
293
|
+
var transactions = state.transactions;
|
|
294
|
+
if (transactions !== prevTransactions) {
|
|
295
|
+
var prev = prevTransactions;
|
|
296
|
+
prevTransactions = transactions;
|
|
297
|
+
_this.handleTransactionChanges(transactions, prev);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
this.unsubscribers.push(unsubscribe);
|
|
301
|
+
logger_1.logger.info("SolanaStoreHandler: Transaction subscription set up");
|
|
302
|
+
};
|
|
303
|
+
SolanaStoreHandler.prototype.handleTransactionChanges = function (transactions, prevTransactions) {
|
|
304
|
+
var _a;
|
|
305
|
+
// Check each transaction for status changes
|
|
306
|
+
for (var _i = 0, _b = Object.entries(transactions); _i < _b.length; _i++) {
|
|
307
|
+
var _c = _b[_i], key = _c[0], tx = _c[1];
|
|
308
|
+
var prevTx = prevTransactions[key];
|
|
309
|
+
// Skip if status hasn't changed
|
|
310
|
+
if (prevTx && prevTx.status === tx.status) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
// For new transactions (sending), use current address.
|
|
314
|
+
// For terminal states, fall back to the address captured at STARTED time.
|
|
315
|
+
var address = this.lastAddress || ((_a = this.transactionSenders.get(key)) === null || _a === void 0 ? void 0 : _a.address);
|
|
316
|
+
if (!address) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
this.handleTransactionStatusChange(key, tx, prevTx, address);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
SolanaStoreHandler.prototype.handleTransactionStatusChange = function (key, tx, prevTx, address) {
|
|
323
|
+
var chainId = this.chainId;
|
|
324
|
+
var dedupeKey = "".concat(key, ":").concat(tx.status);
|
|
325
|
+
// Deduplicate
|
|
326
|
+
if (this.processedTransactions.has(dedupeKey)) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
this.processedTransactions.add(dedupeKey);
|
|
330
|
+
cleanupOldEntries(this.processedTransactions);
|
|
331
|
+
if (!this.formo.isAutocaptureEnabled("transaction")) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
switch (tx.status) {
|
|
335
|
+
case "sending": {
|
|
336
|
+
// Emit STARTED when transaction enters "sending" state
|
|
337
|
+
if (!this.startedTransactions.has(key)) {
|
|
338
|
+
this.startedTransactions.add(key);
|
|
339
|
+
cleanupOldEntries(this.startedTransactions);
|
|
340
|
+
// Capture sender for this transaction so terminal events are attributed
|
|
341
|
+
// correctly even if the wallet disconnects before the tx settles.
|
|
342
|
+
this.transactionSenders.set(key, { address: address, chainId: chainId });
|
|
343
|
+
this.formo.transaction({
|
|
344
|
+
status: events_1.TransactionStatus.STARTED,
|
|
345
|
+
chainId: chainId,
|
|
346
|
+
address: address,
|
|
347
|
+
}).catch(function (error) {
|
|
348
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting transaction STARTED", error);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
case "waiting": {
|
|
354
|
+
// "waiting" means the tx was sent and we have a signature — emit BROADCASTED
|
|
355
|
+
var signature = tx.signature;
|
|
356
|
+
if (signature) {
|
|
357
|
+
// Ensure sender is captured (in case we missed "sending")
|
|
358
|
+
if (!this.transactionSenders.has(key)) {
|
|
359
|
+
this.transactionSenders.set(key, { address: address, chainId: chainId });
|
|
360
|
+
}
|
|
361
|
+
var sender = this.transactionSenders.get(key);
|
|
362
|
+
this.formo.transaction({
|
|
363
|
+
status: events_1.TransactionStatus.BROADCASTED,
|
|
364
|
+
chainId: sender.chainId,
|
|
365
|
+
address: sender.address,
|
|
366
|
+
transactionHash: signature,
|
|
367
|
+
}).catch(function (error) {
|
|
368
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting transaction BROADCASTED", error);
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
case "confirmed": {
|
|
374
|
+
var sender = this.transactionSenders.get(key);
|
|
375
|
+
var txAddress = (sender === null || sender === void 0 ? void 0 : sender.address) || address;
|
|
376
|
+
var txChainId = (sender === null || sender === void 0 ? void 0 : sender.chainId) || chainId;
|
|
377
|
+
var signature = tx.signature;
|
|
378
|
+
logger_1.logger.info("SolanaStoreHandler: Transaction confirmed", {
|
|
379
|
+
key: key,
|
|
380
|
+
signature: signature,
|
|
381
|
+
});
|
|
382
|
+
this.formo.transaction(__assign({ status: events_1.TransactionStatus.CONFIRMED, chainId: txChainId, address: txAddress }, (signature && { transactionHash: signature }))).catch(function (error) {
|
|
383
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting transaction CONFIRMED", error);
|
|
384
|
+
});
|
|
385
|
+
this.transactionSenders.delete(key);
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
case "failed": {
|
|
389
|
+
var sender = this.transactionSenders.get(key);
|
|
390
|
+
var txAddress = (sender === null || sender === void 0 ? void 0 : sender.address) || address;
|
|
391
|
+
var txChainId = (sender === null || sender === void 0 ? void 0 : sender.chainId) || chainId;
|
|
392
|
+
var signature = tx.signature;
|
|
393
|
+
var prevStatus = prevTx === null || prevTx === void 0 ? void 0 : prevTx.status;
|
|
394
|
+
// If it failed after being sent and confirmed as failed on-chain, emit REVERTED.
|
|
395
|
+
// Otherwise (rejected by user, build error, RPC rejection), emit REJECTED.
|
|
396
|
+
var status_1 = prevStatus === "waiting"
|
|
397
|
+
? events_1.TransactionStatus.REVERTED
|
|
398
|
+
: events_1.TransactionStatus.REJECTED;
|
|
399
|
+
logger_1.logger.info("SolanaStoreHandler: Transaction failed", {
|
|
400
|
+
key: key,
|
|
401
|
+
signature: signature,
|
|
402
|
+
status: status_1,
|
|
403
|
+
prevStatus: prevStatus,
|
|
404
|
+
});
|
|
405
|
+
this.formo.transaction(__assign({ status: status_1, chainId: txChainId, address: txAddress }, (signature && { transactionHash: signature }))).catch(function (error) {
|
|
406
|
+
logger_1.logger.error("SolanaStoreHandler: Error emitting transaction event", error);
|
|
407
|
+
});
|
|
408
|
+
this.transactionSenders.delete(key);
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
// "idle" — no event needed
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
// ============================================================
|
|
415
|
+
// Cluster Detection
|
|
416
|
+
// ============================================================
|
|
417
|
+
/**
|
|
418
|
+
* Attempt to detect the Solana cluster from the store's endpoint URL.
|
|
419
|
+
*/
|
|
420
|
+
SolanaStoreHandler.prototype.detectClusterFromStore = function (store) {
|
|
421
|
+
try {
|
|
422
|
+
var endpoint = store.getState().cluster.endpoint;
|
|
423
|
+
return this.detectClusterFromEndpoint(endpoint);
|
|
424
|
+
}
|
|
425
|
+
catch (_a) {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
/**
|
|
430
|
+
* Detect cluster from an RPC endpoint URL.
|
|
431
|
+
*/
|
|
432
|
+
SolanaStoreHandler.prototype.detectClusterFromEndpoint = function (endpoint) {
|
|
433
|
+
if (!endpoint)
|
|
434
|
+
return null;
|
|
435
|
+
var lower = endpoint.toLowerCase();
|
|
436
|
+
if (lower.includes("devnet"))
|
|
437
|
+
return "devnet";
|
|
438
|
+
if (lower.includes("testnet"))
|
|
439
|
+
return "testnet";
|
|
440
|
+
if (lower.includes("localhost") || lower.includes("127.0.0.1"))
|
|
441
|
+
return "localnet";
|
|
442
|
+
if (lower.includes("mainnet"))
|
|
443
|
+
return "mainnet-beta";
|
|
444
|
+
return null;
|
|
445
|
+
};
|
|
446
|
+
// ============================================================
|
|
447
|
+
// Cleanup
|
|
448
|
+
// ============================================================
|
|
449
|
+
SolanaStoreHandler.prototype.cleanup = function () {
|
|
450
|
+
logger_1.logger.debug("SolanaStoreHandler: Cleaning up");
|
|
451
|
+
for (var _i = 0, _a = this.unsubscribers; _i < _a.length; _i++) {
|
|
452
|
+
var unsubscribe = _a[_i];
|
|
453
|
+
try {
|
|
454
|
+
unsubscribe();
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
logger_1.logger.error("SolanaStoreHandler: Error during cleanup", error);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
this.unsubscribers = [];
|
|
461
|
+
this.processedTransactions.clear();
|
|
462
|
+
this.startedTransactions.clear();
|
|
463
|
+
this.transactionSenders.clear();
|
|
464
|
+
this.lastAddress = undefined;
|
|
465
|
+
this.lastChainId = undefined;
|
|
466
|
+
logger_1.logger.debug("SolanaStoreHandler: Cleanup complete");
|
|
467
|
+
};
|
|
468
|
+
return SolanaStoreHandler;
|
|
469
|
+
}());
|
|
470
|
+
exports.SolanaStoreHandler = SolanaStoreHandler;
|
|
471
|
+
//# sourceMappingURL=SolanaStoreHandler.js.map
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Solana integration module
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
5
|
-
*
|
|
4
|
+
* Provides automatic event capture for Solana wallets via framework-kit's
|
|
5
|
+
* zustand store. Connect/disconnect and transaction events are tracked
|
|
6
|
+
* automatically. Signature events (signMessage/signTransaction) require
|
|
7
|
+
* explicit tracking via formo.signature() since framework-kit
|
|
8
|
+
* doesn't track these in store state.
|
|
6
9
|
*
|
|
7
|
-
* @see https://github.com/
|
|
10
|
+
* @see https://github.com/solana-foundation/framework-kit
|
|
8
11
|
*/
|
|
9
|
-
export {
|
|
12
|
+
export { SolanaStoreHandler } from "./SolanaStoreHandler";
|
|
10
13
|
export { SolanaManager } from "./SolanaManager";
|
|
11
14
|
export * from "./types";
|
|
15
|
+
export * from "./storeTypes";
|
|
12
16
|
export * from "./address";
|
|
13
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Solana integration module
|
|
4
4
|
*
|
|
5
|
-
* Provides
|
|
6
|
-
*
|
|
5
|
+
* Provides automatic event capture for Solana wallets via framework-kit's
|
|
6
|
+
* zustand store. Connect/disconnect and transaction events are tracked
|
|
7
|
+
* automatically. Signature events (signMessage/signTransaction) require
|
|
8
|
+
* explicit tracking via formo.signature() since framework-kit
|
|
9
|
+
* doesn't track these in store state.
|
|
7
10
|
*
|
|
8
|
-
* @see https://github.com/
|
|
11
|
+
* @see https://github.com/solana-foundation/framework-kit
|
|
9
12
|
*/
|
|
10
13
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
14
|
if (k2 === undefined) k2 = k;
|
|
@@ -22,11 +25,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
22
25
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
26
|
};
|
|
24
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.SolanaManager = exports.
|
|
26
|
-
var
|
|
27
|
-
Object.defineProperty(exports, "
|
|
28
|
+
exports.SolanaManager = exports.SolanaStoreHandler = void 0;
|
|
29
|
+
var SolanaStoreHandler_1 = require("./SolanaStoreHandler");
|
|
30
|
+
Object.defineProperty(exports, "SolanaStoreHandler", { enumerable: true, get: function () { return SolanaStoreHandler_1.SolanaStoreHandler; } });
|
|
28
31
|
var SolanaManager_1 = require("./SolanaManager");
|
|
29
32
|
Object.defineProperty(exports, "SolanaManager", { enumerable: true, get: function () { return SolanaManager_1.SolanaManager; } });
|
|
30
33
|
__exportStar(require("./types"), exports);
|
|
34
|
+
__exportStar(require("./storeTypes"), exports);
|
|
31
35
|
__exportStar(require("./address"), exports);
|
|
32
36
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for framework-kit's zustand store integration.
|
|
3
|
+
*
|
|
4
|
+
* These types mirror the state shape of @solana-foundation/framework-kit's
|
|
5
|
+
* vanilla zustand store, allowing the SDK to subscribe to wallet and
|
|
6
|
+
* transaction state changes without wrapping any wallet methods.
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/solana-foundation/framework-kit
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The complete framework-kit client state shape.
|
|
12
|
+
* We only type the fields we subscribe to.
|
|
13
|
+
*/
|
|
14
|
+
export interface SolanaClientState {
|
|
15
|
+
transactions: SolanaTransactionState;
|
|
16
|
+
wallet: SolanaWalletStatus;
|
|
17
|
+
cluster: SolanaClusterState;
|
|
18
|
+
lastUpdatedAt: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Transaction records keyed by signature.
|
|
22
|
+
*/
|
|
23
|
+
export type SolanaTransactionState = Record<string, SolanaTransactionRecord>;
|
|
24
|
+
/**
|
|
25
|
+
* Individual transaction record in the store.
|
|
26
|
+
*/
|
|
27
|
+
export interface SolanaTransactionRecord {
|
|
28
|
+
readonly error?: unknown;
|
|
29
|
+
readonly lastUpdatedAt: number;
|
|
30
|
+
readonly signature?: string;
|
|
31
|
+
readonly status: "idle" | "sending" | "waiting" | "confirmed" | "failed";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Wallet status — discriminated union.
|
|
35
|
+
*/
|
|
36
|
+
export type SolanaWalletStatus = SolanaWalletDisconnected | SolanaWalletConnecting | SolanaWalletConnected | SolanaWalletError;
|
|
37
|
+
export interface SolanaWalletDisconnected {
|
|
38
|
+
readonly status: "disconnected";
|
|
39
|
+
}
|
|
40
|
+
export interface SolanaWalletConnecting {
|
|
41
|
+
readonly status: "connecting";
|
|
42
|
+
readonly connectorId: string;
|
|
43
|
+
readonly autoConnect?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface SolanaWalletConnected {
|
|
46
|
+
readonly status: "connected";
|
|
47
|
+
readonly connectorId: string;
|
|
48
|
+
readonly session: SolanaWalletSession;
|
|
49
|
+
readonly autoConnect?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface SolanaWalletError {
|
|
52
|
+
readonly status: "error";
|
|
53
|
+
readonly connectorId?: string;
|
|
54
|
+
readonly error: unknown;
|
|
55
|
+
readonly autoConnect?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Wallet session — carries the connected wallet's capabilities and account.
|
|
59
|
+
*/
|
|
60
|
+
export interface SolanaWalletSession {
|
|
61
|
+
readonly account: SolanaWalletAccount;
|
|
62
|
+
readonly connector: SolanaWalletConnectorMetadata;
|
|
63
|
+
disconnect(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
export interface SolanaWalletAccount {
|
|
66
|
+
readonly address: string;
|
|
67
|
+
readonly label?: string;
|
|
68
|
+
readonly publicKey?: unknown;
|
|
69
|
+
}
|
|
70
|
+
export interface SolanaWalletConnectorMetadata {
|
|
71
|
+
readonly id: string;
|
|
72
|
+
readonly name: string;
|
|
73
|
+
readonly icon?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Cluster state from the store.
|
|
77
|
+
*/
|
|
78
|
+
export interface SolanaClusterState {
|
|
79
|
+
readonly endpoint: string;
|
|
80
|
+
readonly commitment?: string;
|
|
81
|
+
readonly status: "idle" | "connecting" | "ready" | "error";
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The zustand vanilla store API that framework-kit exposes via `client.store`.
|
|
85
|
+
*
|
|
86
|
+
* Note: framework-kit's store uses vanilla zustand without the
|
|
87
|
+
* `subscribeWithSelector` middleware, so only the single-argument
|
|
88
|
+
* subscribe form (full-state listener) is supported.
|
|
89
|
+
*/
|
|
90
|
+
export interface SolanaClientStore {
|
|
91
|
+
getState(): SolanaClientState;
|
|
92
|
+
/**
|
|
93
|
+
* Subscribe to all state changes.
|
|
94
|
+
*/
|
|
95
|
+
subscribe(listener: (state: SolanaClientState, prevState: SolanaClientState) => void): () => void;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Options for configuring the store-based Solana integration.
|
|
99
|
+
*/
|
|
100
|
+
export interface SolanaStoreOptions {
|
|
101
|
+
/**
|
|
102
|
+
* The framework-kit client store (client.store).
|
|
103
|
+
* This is a vanilla zustand store that tracks wallet, transaction, and cluster state.
|
|
104
|
+
*/
|
|
105
|
+
store: SolanaClientStore;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=storeTypes.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Type definitions for framework-kit's zustand store integration.
|
|
4
|
+
*
|
|
5
|
+
* These types mirror the state shape of @solana-foundation/framework-kit's
|
|
6
|
+
* vanilla zustand store, allowing the SDK to subscribe to wallet and
|
|
7
|
+
* transaction state changes without wrapping any wallet methods.
|
|
8
|
+
*
|
|
9
|
+
* @see https://github.com/solana-foundation/framework-kit
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
//# sourceMappingURL=storeTypes.js.map
|