@formo/analytics 1.28.4 → 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.
Files changed (45) hide show
  1. package/README.md +1 -2
  2. package/dist/cjs/src/FormoAnalytics.d.ts +7 -3
  3. package/dist/cjs/src/FormoAnalytics.js +24 -12
  4. package/dist/cjs/src/index.d.ts +3 -1
  5. package/dist/cjs/src/index.js +5 -1
  6. package/dist/cjs/src/solana/SolanaManager.d.ts +36 -11
  7. package/dist/cjs/src/solana/SolanaManager.js +47 -49
  8. package/dist/cjs/src/solana/SolanaStoreHandler.d.ts +88 -0
  9. package/dist/cjs/src/solana/SolanaStoreHandler.js +471 -0
  10. package/dist/cjs/src/solana/index.d.ts +8 -4
  11. package/dist/cjs/src/solana/index.js +10 -6
  12. package/dist/cjs/src/solana/storeTypes.d.ts +107 -0
  13. package/dist/cjs/src/solana/storeTypes.js +12 -0
  14. package/dist/cjs/src/solana/types.d.ts +23 -154
  15. package/dist/cjs/src/solana/types.js +4 -37
  16. package/dist/cjs/src/storage/StorageManager.d.ts +1 -0
  17. package/dist/cjs/src/storage/StorageManager.js +10 -2
  18. package/dist/cjs/src/types/base.d.ts +16 -5
  19. package/dist/cjs/src/version.d.ts +1 -1
  20. package/dist/cjs/src/version.js +1 -1
  21. package/dist/esm/src/FormoAnalytics.d.ts +7 -3
  22. package/dist/esm/src/FormoAnalytics.js +24 -12
  23. package/dist/esm/src/index.d.ts +3 -1
  24. package/dist/esm/src/index.js +1 -0
  25. package/dist/esm/src/solana/SolanaManager.d.ts +36 -11
  26. package/dist/esm/src/solana/SolanaManager.js +47 -49
  27. package/dist/esm/src/solana/SolanaStoreHandler.d.ts +88 -0
  28. package/dist/esm/src/solana/SolanaStoreHandler.js +468 -0
  29. package/dist/esm/src/solana/index.d.ts +8 -4
  30. package/dist/esm/src/solana/index.js +8 -4
  31. package/dist/esm/src/solana/storeTypes.d.ts +107 -0
  32. package/dist/esm/src/solana/storeTypes.js +11 -0
  33. package/dist/esm/src/solana/types.d.ts +23 -154
  34. package/dist/esm/src/solana/types.js +3 -34
  35. package/dist/esm/src/storage/StorageManager.d.ts +1 -0
  36. package/dist/esm/src/storage/StorageManager.js +10 -2
  37. package/dist/esm/src/types/base.d.ts +16 -5
  38. package/dist/esm/src/version.d.ts +1 -1
  39. package/dist/esm/src/version.js +1 -1
  40. package/dist/index.umd.min.js +1 -1
  41. package/package.json +5 -16
  42. package/dist/cjs/src/solana/SolanaAdapter.d.ts +0 -210
  43. package/dist/cjs/src/solana/SolanaAdapter.js +0 -988
  44. package/dist/esm/src/solana/SolanaAdapter.d.ts +0 -210
  45. package/dist/esm/src/solana/SolanaAdapter.js +0 -985
@@ -1,988 +0,0 @@
1
- "use strict";
2
- /**
3
- * SolanaAdapter
4
- *
5
- * Handles wallet event tracking by hooking into Solana Wallet Adapter events.
6
- * This provides integration with the @solana/wallet-adapter ecosystem.
7
- *
8
- * @see https://github.com/anza-xyz/wallet-adapter
9
- */
10
- var __assign = (this && this.__assign) || function () {
11
- __assign = Object.assign || function(t) {
12
- for (var s, i = 1, n = arguments.length; i < n; i++) {
13
- s = arguments[i];
14
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
15
- t[p] = s[p];
16
- }
17
- return t;
18
- };
19
- return __assign.apply(this, arguments);
20
- };
21
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
- return new (P || (P = Promise))(function (resolve, reject) {
24
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
- step((generator = generator.apply(thisArg, _arguments || [])).next());
28
- });
29
- };
30
- var __generator = (this && this.__generator) || function (thisArg, body) {
31
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
32
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
33
- function verb(n) { return function (v) { return step([n, v]); }; }
34
- function step(op) {
35
- if (f) throw new TypeError("Generator is already executing.");
36
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
37
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
38
- if (y = 0, t) op = [op[0] & 2, t.value];
39
- switch (op[0]) {
40
- case 0: case 1: t = op; break;
41
- case 4: _.label++; return { value: op[1], done: false };
42
- case 5: _.label++; y = op[1]; op = [0]; continue;
43
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
44
- default:
45
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
46
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
47
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
48
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
49
- if (t[2]) _.ops.pop();
50
- _.trys.pop(); continue;
51
- }
52
- op = body.call(thisArg, _);
53
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
54
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
55
- }
56
- };
57
- Object.defineProperty(exports, "__esModule", { value: true });
58
- exports.SolanaAdapter = void 0;
59
- var events_1 = require("../types/events");
60
- var logger_1 = require("../logger");
61
- var types_1 = require("./types");
62
- var address_1 = require("./address");
63
- /**
64
- * Clean up old entries from a Set to prevent memory leaks.
65
- */
66
- function cleanupOldEntries(set, maxSize, removeCount) {
67
- if (maxSize === void 0) { maxSize = 1000; }
68
- if (removeCount === void 0) { removeCount = 500; }
69
- if (set.size > maxSize) {
70
- var entries = Array.from(set);
71
- for (var i = 0; i < removeCount && i < entries.length; i++) {
72
- set.delete(entries[i]);
73
- }
74
- }
75
- }
76
- /**
77
- * Convert a Uint8Array to a hex string (browser-compatible alternative to Buffer.from().toString('hex'))
78
- */
79
- function uint8ArrayToHex(bytes) {
80
- return Array.from(bytes)
81
- .map(function (b) { return b.toString(16).padStart(2, "0"); })
82
- .join("");
83
- }
84
- /**
85
- * Safely decode a Uint8Array message to string.
86
- * Falls back to hex representation if TextDecoder is unavailable (some Node environments).
87
- */
88
- function safeDecodeMessage(message) {
89
- try {
90
- if (typeof TextDecoder !== "undefined") {
91
- return new TextDecoder().decode(message);
92
- }
93
- // Fallback for Node environments without TextDecoder global
94
- if (typeof Buffer !== "undefined") {
95
- return Buffer.from(message).toString("utf-8");
96
- }
97
- // Last resort: hex representation
98
- return "0x".concat(uint8ArrayToHex(message));
99
- }
100
- catch (_a) {
101
- return "0x".concat(uint8ArrayToHex(message));
102
- }
103
- }
104
- var SolanaAdapter = /** @class */ (function () {
105
- function SolanaAdapter(formoAnalytics, options) {
106
- this.wallet = null;
107
- this.connection = null;
108
- this.unsubscribers = [];
109
- this.connectionState = {
110
- isProcessing: false,
111
- };
112
- /**
113
- * Track processed signatures to prevent duplicate event emissions
114
- */
115
- this.processedSignatures = new Set();
116
- /**
117
- * Store pending transaction details for confirmation tracking
118
- * Key: transaction signature, Value: transaction details
119
- */
120
- this.pendingTransactions = new Map();
121
- /**
122
- * Per-adapter original methods stored in a WeakMap to prevent routing
123
- * to the wrong wallet after switching adapters.
124
- */
125
- this.adapterOriginals = new WeakMap();
126
- /**
127
- * Track active polling timeout IDs for cleanup
128
- */
129
- this.pollingTimeouts = new Set();
130
- /**
131
- * Flag to prevent new polls after cleanup is initiated
132
- */
133
- this.isCleanedUp = false;
134
- this.formo = formoAnalytics;
135
- this.wallet = options.wallet || null;
136
- this.connection = options.connection || null;
137
- this.cluster = options.cluster || "mainnet-beta";
138
- this.chainId = types_1.SOLANA_CHAIN_IDS[this.cluster];
139
- logger_1.logger.info("SolanaAdapter: Initializing Solana integration", {
140
- cluster: this.cluster,
141
- chainId: this.chainId,
142
- hasWallet: !!this.wallet,
143
- hasConnection: !!this.connection,
144
- });
145
- if (this.wallet) {
146
- this.setupWalletListeners();
147
- }
148
- }
149
- /**
150
- * Restore original methods on the wrapped adapter
151
- */
152
- SolanaAdapter.prototype.restoreOriginalMethods = function () {
153
- // Restore adapter methods
154
- if (this.wrappedAdapter) {
155
- var originals = this.adapterOriginals.get(this.wrappedAdapter);
156
- if (originals) {
157
- if (originals.sendTransaction) {
158
- this.wrappedAdapter.sendTransaction = originals.sendTransaction;
159
- }
160
- if (originals.signMessage) {
161
- this.wrappedAdapter.signMessage = originals.signMessage;
162
- }
163
- if (originals.signTransaction) {
164
- this.wrappedAdapter.signTransaction = originals.signTransaction;
165
- }
166
- this.adapterOriginals.delete(this.wrappedAdapter);
167
- }
168
- this.wrappedAdapter = undefined;
169
- }
170
- // Clear bound wrapper references
171
- this.boundWrappedSendTransaction = undefined;
172
- this.boundWrappedSignMessage = undefined;
173
- this.boundWrappedSignTransaction = undefined;
174
- };
175
- /**
176
- * Update the wallet instance (useful for React context updates)
177
- */
178
- SolanaAdapter.prototype.setWallet = function (wallet) {
179
- // For context-based wallets, if the inner adapter hasn't changed,
180
- // just update the context reference without tearing down wrapping.
181
- // This prevents React re-renders from clearing our method wraps.
182
- if (wallet &&
183
- (0, types_1.isSolanaWalletContext)(wallet) &&
184
- this.wallet &&
185
- (0, types_1.isSolanaWalletContext)(this.wallet)) {
186
- var newAdapter = this.getAdapterFromContext(wallet);
187
- if (newAdapter && newAdapter === this.wrappedAdapter) {
188
- // Same adapter, just update the context reference
189
- this.wallet = wallet;
190
- return;
191
- }
192
- }
193
- // For raw adapters, skip teardown if it's the same object
194
- if (wallet && wallet === this.wrappedAdapter) {
195
- return;
196
- }
197
- // Restore original methods on previous wallet before cleaning up
198
- this.restoreOriginalMethods();
199
- // Clear stale connection state to prevent the old adapter's
200
- // address/chainId from leaking into disconnect events
201
- this.connectionState.lastAddress = undefined;
202
- this.connectionState.lastChainId = undefined;
203
- // Clean up previous wallet listeners
204
- this.cleanupWalletListeners();
205
- this.wallet = wallet;
206
- if (this.wallet) {
207
- // Reset cleanup flag when setting a new wallet to enable polling
208
- this.isCleanedUp = false;
209
- this.setupWalletListeners();
210
- }
211
- };
212
- /**
213
- * Check if the wallet adapter has changed (for context-based wallets) and rebind if needed.
214
- * Call this in React effects when you know the wallet context may have changed but the
215
- * context object reference stayed the same (e.g., user switched wallets in the wallet selector).
216
- *
217
- * This ensures connect/disconnect events from the new wallet are properly tracked without
218
- * waiting for the next transaction or signature call.
219
- *
220
- * @example
221
- * ```tsx
222
- * const wallet = useWallet();
223
- * useEffect(() => {
224
- * formo.solana.syncWalletState();
225
- * }, [wallet.wallet]); // Trigger when inner wallet changes
226
- * ```
227
- */
228
- SolanaAdapter.prototype.syncWalletState = function () {
229
- this.checkAndRebindContextAdapter();
230
- };
231
- /**
232
- * Update the connection instance
233
- */
234
- SolanaAdapter.prototype.setConnection = function (connection) {
235
- this.connection = connection;
236
- };
237
- /**
238
- * Update the cluster/network
239
- */
240
- SolanaAdapter.prototype.setCluster = function (cluster) {
241
- var previousCluster = this.cluster;
242
- this.cluster = cluster;
243
- this.chainId = types_1.SOLANA_CHAIN_IDS[cluster];
244
- // Update connectionState and emit chain event if connected and cluster changed
245
- if (previousCluster !== cluster && this.connectionState.lastAddress) {
246
- // Always update connectionState to keep lastChainId in sync for future disconnect events
247
- this.connectionState.lastChainId = this.chainId;
248
- if (this.formo.isAutocaptureEnabled("chain")) {
249
- this.formo.chain({
250
- chainId: this.chainId,
251
- address: this.connectionState.lastAddress,
252
- }).catch(function (error) {
253
- logger_1.logger.error("SolanaAdapter: Error emitting chain event", error);
254
- });
255
- }
256
- }
257
- };
258
- /**
259
- * Get the current chain ID
260
- */
261
- SolanaAdapter.prototype.getChainId = function () {
262
- return this.chainId;
263
- };
264
- /**
265
- * Set up listeners for wallet events
266
- */
267
- SolanaAdapter.prototype.setupWalletListeners = function () {
268
- if (!this.wallet) {
269
- return;
270
- }
271
- logger_1.logger.info("SolanaAdapter: Setting up wallet listeners");
272
- // Handle both WalletContext (from useWallet) and direct WalletAdapter
273
- if ((0, types_1.isSolanaWalletContext)(this.wallet)) {
274
- this.setupContextListeners(this.wallet);
275
- }
276
- else if ((0, types_1.isSolanaAdapter)(this.wallet)) {
277
- this.setupAdapterListeners(this.wallet);
278
- }
279
- // Check if already connected
280
- this.checkInitialConnection().catch(function (error) {
281
- logger_1.logger.error("SolanaAdapter: Error checking initial connection", error);
282
- });
283
- logger_1.logger.info("SolanaAdapter: Wallet listeners set up successfully");
284
- };
285
- /**
286
- * Set up listeners for a wallet context (useWallet)
287
- */
288
- SolanaAdapter.prototype.setupContextListeners = function (context) {
289
- // The wallet-adapter-react useWallet() returns wallet as { adapter, readyState },
290
- // so we need to extract the actual adapter which has .on()/.off() methods.
291
- //
292
- // IMPORTANT: We wrap methods on the adapter (not the context) because
293
- // useWallet() returns a new object reference on each render. Components
294
- // that call useWallet() independently get their own sendTransaction/signMessage
295
- // callbacks that delegate to adapter.sendTransaction/adapter.signMessage.
296
- // Wrapping the context object only mutates the FormoProvider's reference,
297
- // not what other components receive from useWallet().
298
- var adapter = this.getAdapterFromContext(context);
299
- if (adapter) {
300
- this.setupAdapterEventListenersOnly(adapter);
301
- // Wrap adapter methods so all components using useWallet() are tracked
302
- this.wrapAdapterMethods(adapter);
303
- }
304
- };
305
- /**
306
- * Check if the adapter inside a wallet context has changed (e.g., user switched wallets).
307
- * If so, rebind event listeners and rewrap methods on the new adapter.
308
- * This handles the case where context.wallet changes but the context object reference stays the same.
309
- */
310
- SolanaAdapter.prototype.checkAndRebindContextAdapter = function () {
311
- if (!this.wallet || !(0, types_1.isSolanaWalletContext)(this.wallet)) {
312
- return;
313
- }
314
- var currentAdapter = this.getAdapterFromContext(this.wallet);
315
- // If adapter changed, rebind listeners and rewrap methods
316
- if (currentAdapter !== this.currentBoundAdapter) {
317
- logger_1.logger.info("SolanaAdapter: Detected wallet adapter change, rebinding");
318
- // Restore methods on old adapter and clean up listeners
319
- this.restoreOriginalMethods();
320
- this.cleanupAdapterListenersOnly();
321
- // Set up on new adapter
322
- if (currentAdapter) {
323
- this.setupAdapterEventListenersOnly(currentAdapter);
324
- this.wrapAdapterMethods(currentAdapter);
325
- // Check if new adapter is already connected
326
- this.checkInitialConnection().catch(function (error) {
327
- logger_1.logger.error("SolanaAdapter: Error checking initial connection after adapter change", error);
328
- });
329
- }
330
- else {
331
- // No adapter means disconnected
332
- this.currentBoundAdapter = undefined;
333
- if (this.connectionState.lastAddress) {
334
- this.handleDisconnect();
335
- }
336
- }
337
- }
338
- };
339
- /**
340
- * Clean up only adapter event listeners (not the full cleanup)
341
- */
342
- SolanaAdapter.prototype.cleanupAdapterListenersOnly = function () {
343
- for (var _i = 0, _a = this.unsubscribers; _i < _a.length; _i++) {
344
- var unsubscribe = _a[_i];
345
- try {
346
- unsubscribe();
347
- }
348
- catch (error) {
349
- logger_1.logger.error("SolanaAdapter: Error cleaning up adapter listener", error);
350
- }
351
- }
352
- this.unsubscribers = [];
353
- this.currentBoundAdapter = undefined;
354
- };
355
- /**
356
- * Register a listener on an adapter and track its unsubscriber
357
- */
358
- SolanaAdapter.prototype.registerAdapterListener = function (adapter, event, handler) {
359
- // Use 'any' cast to handle the overloaded on/off signatures
360
- adapter.on(event, handler);
361
- this.unsubscribers.push(function () { return adapter.off(event, handler); });
362
- };
363
- /**
364
- * Set up event listeners on an adapter (connect/disconnect events)
365
- */
366
- SolanaAdapter.prototype.setupAdapterEventListenersOnly = function (adapter) {
367
- var _this = this;
368
- this.currentBoundAdapter = adapter;
369
- this.registerAdapterListener(adapter, "connect", function (publicKey) {
370
- return _this.handleConnect(publicKey);
371
- });
372
- this.registerAdapterListener(adapter, "disconnect", function () {
373
- return _this.handleDisconnect();
374
- });
375
- this.registerAdapterListener(adapter, "error", function (error) {
376
- return logger_1.logger.error("SolanaAdapter: Wallet error", error);
377
- });
378
- };
379
- /**
380
- * Set up listeners for a direct wallet adapter
381
- */
382
- SolanaAdapter.prototype.setupAdapterListeners = function (adapter) {
383
- this.setupAdapterEventListenersOnly(adapter);
384
- this.wrapAdapterMethods(adapter);
385
- };
386
- /**
387
- * Wrap wallet adapter methods for transaction/signature tracking
388
- */
389
- SolanaAdapter.prototype.wrapAdapterMethods = function (adapter) {
390
- // If we already wrapped this adapter, check if our wraps are still in place.
391
- // StandardWalletAdapter._reset() overwrites signMessage/signTransaction
392
- // on every connect/disconnect/feature-change, so we need to re-wrap those methods.
393
- if (this.wrappedAdapter === adapter) {
394
- this.rewrapOverwrittenMethods(adapter);
395
- return;
396
- }
397
- // Store reference to adapter for cleanup
398
- this.wrappedAdapter = adapter;
399
- var originals = {};
400
- // Wrap sendTransaction
401
- if (adapter.sendTransaction) {
402
- originals.sendTransaction = adapter.sendTransaction.bind(adapter);
403
- this.boundWrappedSendTransaction = this.wrappedSendTransaction.bind(this);
404
- adapter.sendTransaction = this.boundWrappedSendTransaction;
405
- }
406
- // Wrap signMessage
407
- if (adapter.signMessage) {
408
- originals.signMessage = adapter.signMessage.bind(adapter);
409
- this.boundWrappedSignMessage = this.wrappedSignMessage.bind(this);
410
- adapter.signMessage = this.boundWrappedSignMessage;
411
- }
412
- // Wrap signTransaction
413
- if (adapter.signTransaction) {
414
- originals.signTransaction = adapter.signTransaction.bind(adapter);
415
- this.boundWrappedSignTransaction = this.wrappedSignTransaction.bind(this);
416
- adapter.signTransaction = this.boundWrappedSignTransaction;
417
- }
418
- this.adapterOriginals.set(adapter, originals);
419
- };
420
- /**
421
- * Re-wrap methods that were overwritten by external code.
422
- *
423
- * StandardWalletAdapter._reset() overwrites signMessage and signTransaction
424
- * as own properties on every connect/disconnect/
425
- * feature-change event. This method detects which wraps were overwritten
426
- * and re-applies them, capturing the new original methods.
427
- */
428
- SolanaAdapter.prototype.rewrapOverwrittenMethods = function (adapter) {
429
- var rewrapped = false;
430
- var originals = this.adapterOriginals.get(adapter) || {};
431
- // signMessage
432
- if (adapter.signMessage && adapter.signMessage !== this.boundWrappedSignMessage) {
433
- originals.signMessage = adapter.signMessage.bind(adapter);
434
- if (!this.boundWrappedSignMessage) {
435
- this.boundWrappedSignMessage = this.wrappedSignMessage.bind(this);
436
- }
437
- adapter.signMessage = this.boundWrappedSignMessage;
438
- rewrapped = true;
439
- }
440
- else if (!adapter.signMessage && this.boundWrappedSignMessage) {
441
- originals.signMessage = undefined;
442
- }
443
- // signTransaction
444
- if (adapter.signTransaction && adapter.signTransaction !== this.boundWrappedSignTransaction) {
445
- originals.signTransaction = adapter.signTransaction.bind(adapter);
446
- if (!this.boundWrappedSignTransaction) {
447
- this.boundWrappedSignTransaction = this.wrappedSignTransaction.bind(this);
448
- }
449
- adapter.signTransaction = this.boundWrappedSignTransaction;
450
- rewrapped = true;
451
- }
452
- else if (!adapter.signTransaction && this.boundWrappedSignTransaction) {
453
- originals.signTransaction = undefined;
454
- }
455
- // sendTransaction — unlikely to be overwritten but check for completeness
456
- if (adapter.sendTransaction && adapter.sendTransaction !== this.boundWrappedSendTransaction) {
457
- originals.sendTransaction = adapter.sendTransaction.bind(adapter);
458
- if (!this.boundWrappedSendTransaction) {
459
- this.boundWrappedSendTransaction = this.wrappedSendTransaction.bind(this);
460
- }
461
- adapter.sendTransaction = this.boundWrappedSendTransaction;
462
- rewrapped = true;
463
- }
464
- this.adapterOriginals.set(adapter, originals);
465
- if (rewrapped) {
466
- logger_1.logger.debug("SolanaAdapter: Re-wrapped overwritten adapter methods");
467
- }
468
- };
469
- /**
470
- * Wrapped sendTransaction method for direct adapter
471
- */
472
- SolanaAdapter.prototype.wrappedSendTransaction = function (transaction, connection, options) {
473
- return __awaiter(this, void 0, void 0, function () {
474
- var originals, chainId, address, signature, error_1;
475
- return __generator(this, function (_a) {
476
- switch (_a.label) {
477
- case 0:
478
- this.checkAndRebindContextAdapter();
479
- originals = this.wrappedAdapter ? this.adapterOriginals.get(this.wrappedAdapter) : undefined;
480
- if (!(originals === null || originals === void 0 ? void 0 : originals.sendTransaction)) {
481
- throw new Error("sendTransaction not available");
482
- }
483
- chainId = this.chainId;
484
- address = this.getCurrentAddress();
485
- this.emitTransactionEvent(events_1.TransactionStatus.STARTED, address, chainId);
486
- _a.label = 1;
487
- case 1:
488
- _a.trys.push([1, 3, , 4]);
489
- return [4 /*yield*/, originals.sendTransaction(transaction, connection, options)];
490
- case 2:
491
- signature = _a.sent();
492
- this.emitTransactionEvent(events_1.TransactionStatus.BROADCASTED, address, chainId, signature);
493
- if (address && this.formo.isAutocaptureEnabled("transaction")) {
494
- this.pendingTransactions.set(signature, {
495
- address: address,
496
- startTime: Date.now(),
497
- });
498
- this.pollTransactionConfirmation(signature, address, chainId, connection);
499
- }
500
- return [2 /*return*/, signature];
501
- case 3:
502
- error_1 = _a.sent();
503
- this.emitTransactionEvent(events_1.TransactionStatus.REJECTED, address, chainId);
504
- throw error_1;
505
- case 4: return [2 /*return*/];
506
- }
507
- });
508
- });
509
- };
510
- /**
511
- * Wrapped signMessage method for direct adapter
512
- */
513
- SolanaAdapter.prototype.wrappedSignMessage = function (message) {
514
- return __awaiter(this, void 0, void 0, function () {
515
- var originals, chainId, address, messageString, signature, signatureHex, error_2;
516
- return __generator(this, function (_a) {
517
- switch (_a.label) {
518
- case 0:
519
- this.checkAndRebindContextAdapter();
520
- originals = this.wrappedAdapter ? this.adapterOriginals.get(this.wrappedAdapter) : undefined;
521
- if (!(originals === null || originals === void 0 ? void 0 : originals.signMessage)) {
522
- throw new Error("signMessage not available");
523
- }
524
- chainId = this.chainId;
525
- address = this.getCurrentAddress();
526
- messageString = safeDecodeMessage(message);
527
- this.emitSignatureEvent(events_1.SignatureStatus.REQUESTED, address, chainId, messageString);
528
- _a.label = 1;
529
- case 1:
530
- _a.trys.push([1, 3, , 4]);
531
- return [4 /*yield*/, originals.signMessage(message)];
532
- case 2:
533
- signature = _a.sent();
534
- signatureHex = uint8ArrayToHex(signature);
535
- this.emitSignatureEvent(events_1.SignatureStatus.CONFIRMED, address, chainId, messageString, signatureHex);
536
- return [2 /*return*/, signature];
537
- case 3:
538
- error_2 = _a.sent();
539
- this.emitSignatureEvent(events_1.SignatureStatus.REJECTED, address, chainId, messageString);
540
- throw error_2;
541
- case 4: return [2 /*return*/];
542
- }
543
- });
544
- });
545
- };
546
- /**
547
- * Wrapped signTransaction method for direct adapter
548
- */
549
- SolanaAdapter.prototype.wrappedSignTransaction = function (transaction) {
550
- return __awaiter(this, void 0, void 0, function () {
551
- var originals, chainId, address, message, signedTx, error_3;
552
- return __generator(this, function (_a) {
553
- switch (_a.label) {
554
- case 0:
555
- this.checkAndRebindContextAdapter();
556
- originals = this.wrappedAdapter ? this.adapterOriginals.get(this.wrappedAdapter) : undefined;
557
- if (!(originals === null || originals === void 0 ? void 0 : originals.signTransaction)) {
558
- throw new Error("signTransaction not available");
559
- }
560
- chainId = this.chainId;
561
- address = this.getCurrentAddress();
562
- message = "[Transaction Signature]";
563
- this.emitSignatureEvent(events_1.SignatureStatus.REQUESTED, address, chainId, message);
564
- _a.label = 1;
565
- case 1:
566
- _a.trys.push([1, 3, , 4]);
567
- return [4 /*yield*/, originals.signTransaction(transaction)];
568
- case 2:
569
- signedTx = _a.sent();
570
- this.emitSignatureEvent(events_1.SignatureStatus.CONFIRMED, address, chainId, message);
571
- return [2 /*return*/, signedTx];
572
- case 3:
573
- error_3 = _a.sent();
574
- this.emitSignatureEvent(events_1.SignatureStatus.REJECTED, address, chainId, message);
575
- throw error_3;
576
- case 4: return [2 /*return*/];
577
- }
578
- });
579
- });
580
- };
581
- /**
582
- * Check initial connection state
583
- */
584
- SolanaAdapter.prototype.checkInitialConnection = function () {
585
- return __awaiter(this, void 0, void 0, function () {
586
- var publicKey, address;
587
- return __generator(this, function (_a) {
588
- switch (_a.label) {
589
- case 0:
590
- publicKey = this.getPublicKey();
591
- if (!publicKey) return [3 /*break*/, 2];
592
- address = (0, address_1.publicKeyToAddress)(publicKey);
593
- if (!(address && !(0, address_1.isBlockedSolanaAddress)(address))) return [3 /*break*/, 2];
594
- // Skip if we already tracked this address to avoid duplicate connect events
595
- // (e.g., when setWallet is called repeatedly with the same connected wallet)
596
- if (this.connectionState.lastAddress === address &&
597
- this.connectionState.lastChainId === this.chainId) {
598
- logger_1.logger.debug("SolanaAdapter: Already tracking this address, skipping duplicate connect", { address: address, chainId: this.chainId });
599
- return [2 /*return*/];
600
- }
601
- this.connectionState.lastAddress = address;
602
- this.connectionState.lastChainId = this.chainId;
603
- logger_1.logger.info("SolanaAdapter: Already connected on initialization", {
604
- address: address,
605
- chainId: this.chainId,
606
- });
607
- if (!this.formo.isAutocaptureEnabled("connect")) return [3 /*break*/, 2];
608
- return [4 /*yield*/, this.formo.connect({
609
- chainId: this.chainId,
610
- address: address,
611
- }, {
612
- providerName: this.getWalletName(),
613
- rdns: this.getWalletRdns(),
614
- })];
615
- case 1:
616
- _a.sent();
617
- _a.label = 2;
618
- case 2: return [2 /*return*/];
619
- }
620
- });
621
- });
622
- };
623
- /**
624
- * Handle wallet connect event
625
- */
626
- SolanaAdapter.prototype.handleConnect = function (publicKey) {
627
- return __awaiter(this, void 0, void 0, function () {
628
- var address, error_4;
629
- return __generator(this, function (_a) {
630
- switch (_a.label) {
631
- case 0:
632
- if (this.connectionState.isProcessing) {
633
- logger_1.logger.debug("SolanaAdapter: Already processing, skipping connect");
634
- return [2 /*return*/];
635
- }
636
- this.connectionState.isProcessing = true;
637
- _a.label = 1;
638
- case 1:
639
- _a.trys.push([1, 4, 5, 6]);
640
- // Re-wrap methods that may have been overwritten.
641
- // StandardWalletAdapter._reset() runs before emitting "connect",
642
- // so signMessage/signTransaction may have been
643
- // replaced with new own properties by the time we get here.
644
- if (this.wrappedAdapter) {
645
- this.rewrapOverwrittenMethods(this.wrappedAdapter);
646
- }
647
- address = (0, address_1.publicKeyToAddress)(publicKey);
648
- if (!address) {
649
- logger_1.logger.warn("SolanaAdapter: Invalid public key on connect");
650
- return [2 /*return*/];
651
- }
652
- if ((0, address_1.isBlockedSolanaAddress)(address)) {
653
- logger_1.logger.debug("SolanaAdapter: Blocked address, skipping connect event");
654
- return [2 /*return*/];
655
- }
656
- logger_1.logger.info("SolanaAdapter: Wallet connected", {
657
- address: address,
658
- chainId: this.chainId,
659
- walletName: this.getWalletName(),
660
- });
661
- this.connectionState.lastAddress = address;
662
- this.connectionState.lastChainId = this.chainId;
663
- if (!this.formo.isAutocaptureEnabled("connect")) return [3 /*break*/, 3];
664
- return [4 /*yield*/, this.formo.connect({
665
- chainId: this.chainId,
666
- address: address,
667
- }, {
668
- providerName: this.getWalletName(),
669
- rdns: this.getWalletRdns(),
670
- })];
671
- case 2:
672
- _a.sent();
673
- _a.label = 3;
674
- case 3: return [3 /*break*/, 6];
675
- case 4:
676
- error_4 = _a.sent();
677
- logger_1.logger.error("SolanaAdapter: Error handling connect", error_4);
678
- return [3 /*break*/, 6];
679
- case 5:
680
- this.connectionState.isProcessing = false;
681
- return [7 /*endfinally*/];
682
- case 6: return [2 /*return*/];
683
- }
684
- });
685
- });
686
- };
687
- /**
688
- * Handle wallet disconnect event
689
- */
690
- SolanaAdapter.prototype.handleDisconnect = function () {
691
- return __awaiter(this, void 0, void 0, function () {
692
- var error_5;
693
- return __generator(this, function (_a) {
694
- switch (_a.label) {
695
- case 0:
696
- if (this.connectionState.isProcessing) {
697
- logger_1.logger.debug("SolanaAdapter: Already processing, skipping disconnect");
698
- return [2 /*return*/];
699
- }
700
- // Only emit disconnect if we have a prior tracked connection
701
- // This prevents emitting events with undefined address/chainId
702
- if (!this.connectionState.lastAddress) {
703
- logger_1.logger.debug("SolanaAdapter: No prior connection tracked, skipping disconnect event");
704
- return [2 /*return*/];
705
- }
706
- this.connectionState.isProcessing = true;
707
- _a.label = 1;
708
- case 1:
709
- _a.trys.push([1, 4, 5, 6]);
710
- logger_1.logger.info("SolanaAdapter: Wallet disconnected", {
711
- address: this.connectionState.lastAddress,
712
- chainId: this.connectionState.lastChainId,
713
- });
714
- if (!this.formo.isAutocaptureEnabled("disconnect")) return [3 /*break*/, 3];
715
- return [4 /*yield*/, this.formo.disconnect({
716
- chainId: this.connectionState.lastChainId,
717
- address: this.connectionState.lastAddress,
718
- })];
719
- case 2:
720
- _a.sent();
721
- _a.label = 3;
722
- case 3:
723
- this.connectionState.lastAddress = undefined;
724
- this.connectionState.lastChainId = undefined;
725
- return [3 /*break*/, 6];
726
- case 4:
727
- error_5 = _a.sent();
728
- logger_1.logger.error("SolanaAdapter: Error handling disconnect", error_5);
729
- return [3 /*break*/, 6];
730
- case 5:
731
- this.connectionState.isProcessing = false;
732
- return [7 /*endfinally*/];
733
- case 6: return [2 /*return*/];
734
- }
735
- });
736
- });
737
- };
738
- /**
739
- * Poll for transaction confirmation
740
- */
741
- SolanaAdapter.prototype.pollTransactionConfirmation = function (signature_1, address_2, chainId_1, connection_1) {
742
- return __awaiter(this, arguments, void 0, function (signature, address, chainId, connection, maxAttempts, intervalMs) {
743
- var conn, attempts, currentTimeoutId, poll;
744
- var _this = this;
745
- if (maxAttempts === void 0) { maxAttempts = 30; }
746
- if (intervalMs === void 0) { intervalMs = 2000; }
747
- return __generator(this, function (_a) {
748
- // Don't start polling if already cleaned up
749
- if (this.isCleanedUp) {
750
- return [2 /*return*/];
751
- }
752
- conn = connection || this.connection;
753
- // Prefer getSignatureStatuses (standard web3.js API) over getSignatureStatus (custom wrapper)
754
- if (!conn || (!conn.getSignatureStatuses && !conn.getSignatureStatus)) {
755
- logger_1.logger.debug("SolanaAdapter: No connection for confirmation polling");
756
- // Clean up pendingTransactions entry since we can't poll for confirmation
757
- this.pendingTransactions.delete(signature);
758
- return [2 /*return*/];
759
- }
760
- attempts = 0;
761
- currentTimeoutId = null;
762
- poll = function () { return __awaiter(_this, void 0, void 0, function () {
763
- var status_1, result, result, signatureKey, isTerminalState, error_6;
764
- return __generator(this, function (_a) {
765
- switch (_a.label) {
766
- case 0:
767
- // Remove the current timeout ID from tracking since it has fired
768
- if (currentTimeoutId) {
769
- this.pollingTimeouts.delete(currentTimeoutId);
770
- currentTimeoutId = null;
771
- }
772
- // Stop polling if cleaned up
773
- if (this.isCleanedUp) {
774
- this.pendingTransactions.delete(signature);
775
- return [2 /*return*/];
776
- }
777
- _a.label = 1;
778
- case 1:
779
- _a.trys.push([1, 6, , 7]);
780
- status_1 = null;
781
- if (!conn.getSignatureStatuses) return [3 /*break*/, 3];
782
- return [4 /*yield*/, conn.getSignatureStatuses([signature])];
783
- case 2:
784
- result = _a.sent();
785
- status_1 = result.value[0];
786
- return [3 /*break*/, 5];
787
- case 3:
788
- if (!conn.getSignatureStatus) return [3 /*break*/, 5];
789
- return [4 /*yield*/, conn.getSignatureStatus(signature)];
790
- case 4:
791
- result = _a.sent();
792
- status_1 = result.value;
793
- _a.label = 5;
794
- case 5:
795
- if (status_1) {
796
- signatureKey = "".concat(signature, ":").concat(status_1.confirmationStatus);
797
- isTerminalState = !!status_1.err ||
798
- status_1.confirmationStatus === "confirmed" ||
799
- status_1.confirmationStatus === "finalized";
800
- // Check for duplicate processing of terminal states only
801
- if (isTerminalState && this.processedSignatures.has(signatureKey)) {
802
- return [2 /*return*/];
803
- }
804
- if (isTerminalState) {
805
- this.processedSignatures.add(signatureKey);
806
- }
807
- if (status_1.err) {
808
- // Transaction failed
809
- logger_1.logger.info("SolanaAdapter: Transaction reverted", {
810
- signature: signature,
811
- error: status_1.err,
812
- });
813
- this.formo.transaction({
814
- status: events_1.TransactionStatus.REVERTED,
815
- chainId: chainId,
816
- address: address,
817
- transactionHash: signature,
818
- });
819
- this.pendingTransactions.delete(signature);
820
- return [2 /*return*/];
821
- }
822
- if (status_1.confirmationStatus === "confirmed" ||
823
- status_1.confirmationStatus === "finalized") {
824
- // Transaction confirmed
825
- logger_1.logger.info("SolanaAdapter: Transaction confirmed", {
826
- signature: signature,
827
- confirmationStatus: status_1.confirmationStatus,
828
- });
829
- this.formo.transaction({
830
- status: events_1.TransactionStatus.CONFIRMED,
831
- chainId: chainId,
832
- address: address,
833
- transactionHash: signature,
834
- });
835
- this.pendingTransactions.delete(signature);
836
- return [2 /*return*/];
837
- }
838
- }
839
- return [3 /*break*/, 7];
840
- case 6:
841
- error_6 = _a.sent();
842
- logger_1.logger.error("SolanaAdapter: Error polling transaction status", error_6);
843
- return [3 /*break*/, 7];
844
- case 7:
845
- attempts++;
846
- if (attempts < maxAttempts && !this.isCleanedUp) {
847
- currentTimeoutId = setTimeout(poll, intervalMs);
848
- this.pollingTimeouts.add(currentTimeoutId);
849
- }
850
- else {
851
- // Cleanup after max attempts
852
- this.pendingTransactions.delete(signature);
853
- }
854
- return [2 /*return*/];
855
- }
856
- });
857
- }); };
858
- // Start polling
859
- currentTimeoutId = setTimeout(poll, intervalMs);
860
- this.pollingTimeouts.add(currentTimeoutId);
861
- // Clean up old processed signatures
862
- cleanupOldEntries(this.processedSignatures);
863
- return [2 /*return*/];
864
- });
865
- });
866
- };
867
- /**
868
- * Get current wallet public key
869
- */
870
- SolanaAdapter.prototype.getPublicKey = function () {
871
- var _a, _b;
872
- return (_b = (_a = this.wallet) === null || _a === void 0 ? void 0 : _a.publicKey) !== null && _b !== void 0 ? _b : null;
873
- };
874
- /**
875
- * Get current address
876
- */
877
- SolanaAdapter.prototype.getCurrentAddress = function () {
878
- // First check tracking state
879
- if (this.connectionState.lastAddress) {
880
- return this.connectionState.lastAddress;
881
- }
882
- // Then check wallet, filtering out blocked addresses (system programs, etc.)
883
- var publicKey = this.getPublicKey();
884
- var address = publicKey ? (0, address_1.publicKeyToAddress)(publicKey) : null;
885
- if (address && (0, address_1.isBlockedSolanaAddress)(address)) {
886
- return null;
887
- }
888
- return address;
889
- };
890
- // ============================================================
891
- // Event Emission Helpers
892
- // ============================================================
893
- /**
894
- * Emit a transaction event if address is valid and autocapture is enabled
895
- */
896
- SolanaAdapter.prototype.emitTransactionEvent = function (status, address, chainId, transactionHash) {
897
- if (address && this.formo.isAutocaptureEnabled("transaction")) {
898
- this.formo.transaction(__assign({ status: status, chainId: chainId, address: address }, (transactionHash && { transactionHash: transactionHash })));
899
- }
900
- };
901
- /**
902
- * Emit a signature event if address is valid and autocapture is enabled
903
- */
904
- SolanaAdapter.prototype.emitSignatureEvent = function (status, address, chainId, message, signatureHash) {
905
- if (address && this.formo.isAutocaptureEnabled("signature")) {
906
- this.formo.signature(__assign({ status: status, chainId: chainId, address: address, message: message }, (signatureHash && { signatureHash: signatureHash })));
907
- }
908
- };
909
- /**
910
- * Extract the actual adapter (with .on/.off) from a wallet context.
911
- * In @solana/wallet-adapter-react, context.wallet is { adapter, readyState },
912
- * not a direct adapter.
913
- */
914
- SolanaAdapter.prototype.getAdapterFromContext = function (context) {
915
- var wallet = context.wallet;
916
- if (!wallet)
917
- return null;
918
- // wallet-adapter-react: wallet is { adapter, readyState }
919
- if (wallet.adapter && typeof wallet.adapter.on === "function") {
920
- return wallet.adapter;
921
- }
922
- return null;
923
- };
924
- /**
925
- * Get wallet name
926
- */
927
- SolanaAdapter.prototype.getWalletName = function () {
928
- if (!this.wallet) {
929
- return "Unknown Solana Wallet";
930
- }
931
- if ((0, types_1.isSolanaWalletContext)(this.wallet)) {
932
- var adapter = this.getAdapterFromContext(this.wallet);
933
- return (adapter === null || adapter === void 0 ? void 0 : adapter.name) || "Unknown Solana Wallet";
934
- }
935
- return this.wallet.name;
936
- };
937
- /**
938
- * Get wallet RDNS (reverse domain name)
939
- * For Solana wallets, we construct an RDNS-like identifier
940
- */
941
- SolanaAdapter.prototype.getWalletRdns = function () {
942
- var name = this.getWalletName().toLowerCase().replace(/\s+/g, "");
943
- return "sol.wallet.".concat(name);
944
- };
945
- /**
946
- * Clean up wallet listeners
947
- */
948
- SolanaAdapter.prototype.cleanupWalletListeners = function () {
949
- for (var _i = 0, _a = this.unsubscribers; _i < _a.length; _i++) {
950
- var unsubscribe = _a[_i];
951
- try {
952
- unsubscribe();
953
- }
954
- catch (error) {
955
- logger_1.logger.error("SolanaAdapter: Error during listener cleanup", error);
956
- }
957
- }
958
- this.unsubscribers = [];
959
- this.currentBoundAdapter = undefined;
960
- };
961
- /**
962
- * Clean up all resources
963
- */
964
- SolanaAdapter.prototype.cleanup = function () {
965
- logger_1.logger.debug("SolanaAdapter: Cleaning up");
966
- // Set cleanup flag to stop any ongoing polls
967
- this.isCleanedUp = true;
968
- // Cancel all active polling timeouts
969
- Array.from(this.pollingTimeouts).forEach(function (timeoutId) {
970
- clearTimeout(timeoutId);
971
- });
972
- this.pollingTimeouts.clear();
973
- this.cleanupWalletListeners();
974
- this.processedSignatures.clear();
975
- this.pendingTransactions.clear();
976
- // Clear connection state to prevent stale data
977
- this.connectionState.lastAddress = undefined;
978
- this.connectionState.lastChainId = undefined;
979
- // Restore original methods on wrapped adapter
980
- this.restoreOriginalMethods();
981
- this.wallet = null;
982
- this.connection = null;
983
- logger_1.logger.debug("SolanaAdapter: Cleanup complete");
984
- };
985
- return SolanaAdapter;
986
- }());
987
- exports.SolanaAdapter = SolanaAdapter;
988
- //# sourceMappingURL=SolanaAdapter.js.map