@formo/analytics 1.19.6 → 1.19.8
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 +97 -4
- package/dist/cjs/src/FormoAnalytics.js +915 -274
- package/dist/cjs/src/constants/base.d.ts +1 -0
- package/dist/cjs/src/constants/base.js +3 -1
- package/dist/cjs/src/lib/event/EventFactory.d.ts +1 -1
- package/dist/cjs/src/lib/event/EventFactory.js +1 -1
- package/dist/cjs/src/lib/version.d.ts +1 -1
- package/dist/cjs/src/lib/version.js +1 -1
- package/dist/cjs/src/types/events.d.ts +2 -2
- package/dist/cjs/src/types/provider.d.ts +8 -0
- package/dist/cjs/src/types/provider.js +3 -0
- package/dist/cjs/src/utils/base.js +10 -1
- package/dist/esm/src/FormoAnalytics.d.ts +97 -4
- package/dist/esm/src/FormoAnalytics.js +917 -276
- package/dist/esm/src/constants/base.d.ts +1 -0
- package/dist/esm/src/constants/base.js +2 -0
- package/dist/esm/src/lib/event/EventFactory.d.ts +1 -1
- package/dist/esm/src/lib/event/EventFactory.js +1 -1
- package/dist/esm/src/lib/version.d.ts +1 -1
- package/dist/esm/src/lib/version.js +1 -1
- package/dist/esm/src/types/events.d.ts +2 -2
- package/dist/esm/src/types/provider.d.ts +8 -0
- package/dist/esm/src/types/provider.js +2 -1
- package/dist/esm/src/utils/base.js +10 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +2 -2
|
@@ -46,6 +46,15 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
46
46
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
50
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
51
|
+
if (ar || !(i in from)) {
|
|
52
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
53
|
+
ar[i] = from[i];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
57
|
+
};
|
|
49
58
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
59
|
exports.FormoAnalytics = void 0;
|
|
51
60
|
var mipd_1 = require("mipd");
|
|
@@ -56,14 +65,39 @@ var utils_1 = require("./utils");
|
|
|
56
65
|
var address_1 = require("./utils/address");
|
|
57
66
|
var validators_1 = require("./validators");
|
|
58
67
|
var chain_1 = require("./utils/chain");
|
|
68
|
+
/**
|
|
69
|
+
* Constants for provider switching reasons
|
|
70
|
+
*/
|
|
71
|
+
var PROVIDER_SWITCH_REASONS = {
|
|
72
|
+
ADDRESS_MISMATCH: "Address mismatch indicates wallet switch",
|
|
73
|
+
NO_ACCOUNTS: "Current provider has no accounts",
|
|
74
|
+
CHECK_FAILED: "Could not check current provider accounts"
|
|
75
|
+
};
|
|
59
76
|
var FormoAnalytics = /** @class */ (function () {
|
|
60
77
|
function FormoAnalytics(writeKey, options) {
|
|
61
78
|
if (options === void 0) { options = {}; }
|
|
62
79
|
var _a, _b;
|
|
63
80
|
this.writeKey = writeKey;
|
|
64
81
|
this.options = options;
|
|
65
|
-
this.
|
|
82
|
+
this._providerListenersMap = new Map();
|
|
83
|
+
/**
|
|
84
|
+
* EIP-6963 provider details discovered through the browser
|
|
85
|
+
* This array contains all available providers with their metadata
|
|
86
|
+
*/
|
|
66
87
|
this._providers = [];
|
|
88
|
+
/**
|
|
89
|
+
* Set of providers that have been tracked with event listeners
|
|
90
|
+
* This is separate from _providers because:
|
|
91
|
+
* - _providers contains all discovered providers (EIP-6963)
|
|
92
|
+
* - _trackedProviders contains only providers that have been set up with listeners
|
|
93
|
+
* - A provider can be discovered but not yet tracked (e.g., during initialization)
|
|
94
|
+
* - A provider can be tracked but later removed from discovery
|
|
95
|
+
*/
|
|
96
|
+
this._trackedProviders = new Set();
|
|
97
|
+
// Flag to prevent concurrent processing of accountsChanged events
|
|
98
|
+
this._processingAccountsChanged = false;
|
|
99
|
+
// Set to efficiently track seen providers for deduplication and O(1) lookup
|
|
100
|
+
this._seenProviders = new Set();
|
|
67
101
|
this.currentUserId = "";
|
|
68
102
|
this.config = {
|
|
69
103
|
writeKey: writeKey,
|
|
@@ -92,14 +126,43 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
92
126
|
maxQueueSize: options.maxQueueSize,
|
|
93
127
|
flushInterval: options.flushInterval,
|
|
94
128
|
}));
|
|
95
|
-
//
|
|
96
|
-
var provider =
|
|
129
|
+
// Handle initial provider (injected) as fallback; listeners for EIP-6963 are added later
|
|
130
|
+
var provider = undefined;
|
|
131
|
+
var optProvider = options.provider;
|
|
132
|
+
if (optProvider) {
|
|
133
|
+
provider = optProvider;
|
|
134
|
+
}
|
|
135
|
+
else if (typeof window !== 'undefined' && window.ethereum) {
|
|
136
|
+
provider = window.ethereum;
|
|
137
|
+
}
|
|
97
138
|
if (provider) {
|
|
98
139
|
this.trackProvider(provider);
|
|
99
140
|
}
|
|
100
141
|
this.trackPageHit();
|
|
101
142
|
this.trackPageHits();
|
|
102
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Helper method to check if a provider is different from the currently active one
|
|
146
|
+
* @param provider The provider to check
|
|
147
|
+
* @returns true if there's a provider mismatch, false otherwise
|
|
148
|
+
*/
|
|
149
|
+
FormoAnalytics.prototype.isProviderMismatch = function (provider) {
|
|
150
|
+
// Only consider it a mismatch if we have an active provider AND the provider is different
|
|
151
|
+
// This allows legitimate provider switching while preventing race conditions
|
|
152
|
+
return this._provider != null && this._provider !== provider;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Check if a provider is in a valid state for switching
|
|
156
|
+
* @param provider The provider to validate
|
|
157
|
+
* @returns true if the provider is in a valid state
|
|
158
|
+
*/
|
|
159
|
+
FormoAnalytics.prototype.isProviderInValidState = function (provider) {
|
|
160
|
+
// Basic validation: ensure provider exists and has required methods
|
|
161
|
+
return (provider &&
|
|
162
|
+
typeof provider.request === 'function' &&
|
|
163
|
+
typeof provider.on === 'function' &&
|
|
164
|
+
typeof provider.removeListener === 'function');
|
|
165
|
+
};
|
|
103
166
|
FormoAnalytics.init = function (writeKey, options) {
|
|
104
167
|
return __awaiter(this, void 0, void 0, function () {
|
|
105
168
|
var analytics, _a;
|
|
@@ -117,6 +180,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
117
180
|
return [4 /*yield*/, analytics.detectWallets(analytics._providers)];
|
|
118
181
|
case 2:
|
|
119
182
|
_b.sent();
|
|
183
|
+
analytics.trackProviders(analytics._providers);
|
|
120
184
|
return [2 /*return*/, analytics];
|
|
121
185
|
}
|
|
122
186
|
});
|
|
@@ -154,6 +218,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
154
218
|
this.currentUserId = undefined;
|
|
155
219
|
(0, lib_1.cookie)().remove(constants_1.LOCAL_ANONYMOUS_ID_KEY);
|
|
156
220
|
(0, lib_1.cookie)().remove(constants_1.SESSION_USER_ID_KEY);
|
|
221
|
+
(0, lib_1.cookie)().remove(constants_1.SESSION_WALLET_DETECTED_KEY);
|
|
157
222
|
};
|
|
158
223
|
/**
|
|
159
224
|
* Emits a connect wallet event.
|
|
@@ -162,25 +227,30 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
162
227
|
* @param {IFormoEventProperties} properties
|
|
163
228
|
* @param {IFormoEventContext} context
|
|
164
229
|
* @param {(...args: unknown[]) => void} callback
|
|
165
|
-
* @throws {Error} If chainId or address is empty
|
|
166
230
|
* @returns {Promise<void>}
|
|
167
231
|
*/
|
|
168
232
|
FormoAnalytics.prototype.connect = function (_a, properties_1, context_1, callback_1) {
|
|
169
233
|
return __awaiter(this, arguments, void 0, function (_b, properties, context, callback) {
|
|
170
|
-
var
|
|
234
|
+
var checksummedAddress;
|
|
171
235
|
var chainId = _b.chainId, address = _b.address;
|
|
172
236
|
return __generator(this, function (_c) {
|
|
173
237
|
switch (_c.label) {
|
|
174
238
|
case 0:
|
|
175
|
-
if (
|
|
176
|
-
lib_1.logger.warn("Connect: Chain ID cannot be
|
|
239
|
+
if (chainId === null || chainId === undefined) {
|
|
240
|
+
lib_1.logger.warn("Connect: Chain ID cannot be null or undefined");
|
|
241
|
+
return [2 /*return*/];
|
|
177
242
|
}
|
|
178
243
|
if (!address) {
|
|
179
244
|
lib_1.logger.warn("Connect: Address cannot be empty");
|
|
245
|
+
return [2 /*return*/];
|
|
180
246
|
}
|
|
181
247
|
this.currentChainId = chainId;
|
|
182
|
-
|
|
183
|
-
|
|
248
|
+
checksummedAddress = this.validateAndChecksumAddress(address);
|
|
249
|
+
if (!checksummedAddress) {
|
|
250
|
+
lib_1.logger.warn("Connect: Invalid address provided (\"".concat(address, "\"). Please provide a valid Ethereum address in checksum format."));
|
|
251
|
+
return [2 /*return*/];
|
|
252
|
+
}
|
|
253
|
+
this.currentAddress = checksummedAddress;
|
|
184
254
|
return [4 /*yield*/, this.trackEvent(constants_1.EventType.CONNECT, {
|
|
185
255
|
chainId: chainId,
|
|
186
256
|
address: this.currentAddress,
|
|
@@ -203,21 +273,30 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
203
273
|
*/
|
|
204
274
|
FormoAnalytics.prototype.disconnect = function (params, properties, context, callback) {
|
|
205
275
|
return __awaiter(this, void 0, void 0, function () {
|
|
206
|
-
var chainId, address;
|
|
276
|
+
var chainId, address, providerInfo, disconnectProperties;
|
|
207
277
|
return __generator(this, function (_a) {
|
|
208
278
|
switch (_a.label) {
|
|
209
279
|
case 0:
|
|
210
280
|
chainId = (params === null || params === void 0 ? void 0 : params.chainId) || this.currentChainId;
|
|
211
281
|
address = (params === null || params === void 0 ? void 0 : params.address) || this.currentAddress;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
282
|
+
providerInfo = this._provider ? this.getProviderInfo(this._provider) : null;
|
|
283
|
+
lib_1.logger.info("Disconnect: Emitting disconnect event with:", {
|
|
284
|
+
chainId: chainId,
|
|
285
|
+
address: address,
|
|
286
|
+
providerName: providerInfo === null || providerInfo === void 0 ? void 0 : providerInfo.name,
|
|
287
|
+
rdns: providerInfo === null || providerInfo === void 0 ? void 0 : providerInfo.rdns
|
|
288
|
+
});
|
|
289
|
+
disconnectProperties = __assign(__assign({}, (providerInfo && {
|
|
290
|
+
providerName: providerInfo.name,
|
|
291
|
+
rdns: providerInfo.rdns
|
|
292
|
+
})), properties);
|
|
293
|
+
return [4 /*yield*/, this.trackEvent(constants_1.EventType.DISCONNECT, __assign(__assign({}, (chainId && { chainId: chainId })), (address && { address: address })), disconnectProperties, context, callback)];
|
|
216
294
|
case 1:
|
|
217
295
|
_a.sent();
|
|
218
296
|
this.currentAddress = undefined;
|
|
219
297
|
this.currentChainId = undefined;
|
|
220
|
-
|
|
298
|
+
this._provider = undefined;
|
|
299
|
+
lib_1.logger.info("Wallet disconnected: Cleared currentAddress, currentChainId, and provider");
|
|
221
300
|
return [2 /*return*/];
|
|
222
301
|
}
|
|
223
302
|
});
|
|
@@ -230,8 +309,6 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
230
309
|
* @param {IFormoEventProperties} properties
|
|
231
310
|
* @param {IFormoEventContext} context
|
|
232
311
|
* @param {(...args: unknown[]) => void} callback
|
|
233
|
-
* @throws {Error} If chainId is empty, zero, or not a valid number
|
|
234
|
-
* @throws {Error} If no address is provided and no previous address is recorded
|
|
235
312
|
* @returns {Promise<void>}
|
|
236
313
|
*/
|
|
237
314
|
FormoAnalytics.prototype.chain = function (_a, properties_1, context_1, callback_1) {
|
|
@@ -241,13 +318,16 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
241
318
|
switch (_c.label) {
|
|
242
319
|
case 0:
|
|
243
320
|
if (!chainId || Number(chainId) === 0) {
|
|
244
|
-
|
|
321
|
+
lib_1.logger.warn("FormoAnalytics::chain: chainId cannot be empty or 0");
|
|
322
|
+
return [2 /*return*/];
|
|
245
323
|
}
|
|
246
324
|
if (isNaN(Number(chainId))) {
|
|
247
|
-
|
|
325
|
+
lib_1.logger.warn("FormoAnalytics::chain: chainId must be a valid decimal number");
|
|
326
|
+
return [2 /*return*/];
|
|
248
327
|
}
|
|
249
328
|
if (!address && !this.currentAddress) {
|
|
250
|
-
|
|
329
|
+
lib_1.logger.warn("FormoAnalytics::chain: address was empty and no previous address has been recorded");
|
|
330
|
+
return [2 /*return*/];
|
|
251
331
|
}
|
|
252
332
|
this.currentChainId = chainId;
|
|
253
333
|
return [4 /*yield*/, this.trackEvent(constants_1.EventType.CHAIN, {
|
|
@@ -327,27 +407,28 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
327
407
|
FormoAnalytics.prototype.identify = function (params, properties, context, callback) {
|
|
328
408
|
return __awaiter(this, void 0, void 0, function () {
|
|
329
409
|
var _i, _a, providerDetail, provider, address_2, err_1, userId, address, providerName, rdns, validAddress, e_1;
|
|
330
|
-
|
|
331
|
-
|
|
410
|
+
var _b;
|
|
411
|
+
return __generator(this, function (_c) {
|
|
412
|
+
switch (_c.label) {
|
|
332
413
|
case 0:
|
|
333
|
-
|
|
414
|
+
_c.trys.push([0, 11, , 12]);
|
|
334
415
|
if (!!params) return [3 /*break*/, 9];
|
|
335
416
|
// If no params provided, auto-identify
|
|
336
417
|
lib_1.logger.info("Auto-identifying with providers:", this._providers.map(function (p) { return p.info.name; }));
|
|
337
418
|
_i = 0, _a = this._providers;
|
|
338
|
-
|
|
419
|
+
_c.label = 1;
|
|
339
420
|
case 1:
|
|
340
421
|
if (!(_i < _a.length)) return [3 /*break*/, 8];
|
|
341
422
|
providerDetail = _a[_i];
|
|
342
423
|
provider = providerDetail.provider;
|
|
343
424
|
if (!provider)
|
|
344
425
|
return [3 /*break*/, 7];
|
|
345
|
-
|
|
426
|
+
_c.label = 2;
|
|
346
427
|
case 2:
|
|
347
|
-
|
|
428
|
+
_c.trys.push([2, 6, , 7]);
|
|
348
429
|
return [4 /*yield*/, this.getAddress(provider)];
|
|
349
430
|
case 3:
|
|
350
|
-
address_2 =
|
|
431
|
+
address_2 = _c.sent();
|
|
351
432
|
if (!address_2) return [3 /*break*/, 5];
|
|
352
433
|
lib_1.logger.info("Auto-identifying", address_2, providerDetail.info.name, providerDetail.info.rdns);
|
|
353
434
|
// NOTE: do not set this.currentAddress without explicit connect or identify
|
|
@@ -358,11 +439,11 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
358
439
|
}, properties, context, callback)];
|
|
359
440
|
case 4:
|
|
360
441
|
// NOTE: do not set this.currentAddress without explicit connect or identify
|
|
361
|
-
|
|
362
|
-
|
|
442
|
+
_c.sent();
|
|
443
|
+
_c.label = 5;
|
|
363
444
|
case 5: return [3 /*break*/, 7];
|
|
364
445
|
case 6:
|
|
365
|
-
err_1 =
|
|
446
|
+
err_1 = _c.sent();
|
|
366
447
|
lib_1.logger.error("Failed to identify provider ".concat(providerDetail.info.name, ":"), err_1);
|
|
367
448
|
return [3 /*break*/, 7];
|
|
368
449
|
case 7:
|
|
@@ -372,24 +453,32 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
372
453
|
case 9:
|
|
373
454
|
userId = params.userId, address = params.address, providerName = params.providerName, rdns = params.rdns;
|
|
374
455
|
lib_1.logger.info("Identify", address, userId, providerName, rdns);
|
|
375
|
-
validAddress =
|
|
376
|
-
if (
|
|
377
|
-
|
|
456
|
+
validAddress = undefined;
|
|
457
|
+
if (address) {
|
|
458
|
+
validAddress = this.validateAndChecksumAddress(address);
|
|
459
|
+
this.currentAddress = validAddress || undefined;
|
|
460
|
+
if (!validAddress) {
|
|
461
|
+
(_b = lib_1.logger.warn) === null || _b === void 0 ? void 0 : _b.call(lib_1.logger, "Invalid address provided to identify:", address);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
this.currentAddress = undefined;
|
|
466
|
+
}
|
|
378
467
|
if (userId) {
|
|
379
468
|
this.currentUserId = userId;
|
|
380
469
|
(0, lib_1.cookie)().set(constants_1.SESSION_USER_ID_KEY, userId);
|
|
381
470
|
}
|
|
382
471
|
return [4 /*yield*/, this.trackEvent(constants_1.EventType.IDENTIFY, {
|
|
383
|
-
address: validAddress
|
|
472
|
+
address: validAddress,
|
|
384
473
|
providerName: providerName,
|
|
385
474
|
userId: userId,
|
|
386
475
|
rdns: rdns,
|
|
387
476
|
}, properties, context, callback)];
|
|
388
477
|
case 10:
|
|
389
|
-
|
|
478
|
+
_c.sent();
|
|
390
479
|
return [3 /*break*/, 12];
|
|
391
480
|
case 11:
|
|
392
|
-
e_1 =
|
|
481
|
+
e_1 = _c.sent();
|
|
393
482
|
lib_1.logger.log("identify error", e_1);
|
|
394
483
|
return [3 /*break*/, 12];
|
|
395
484
|
case 12: return [2 /*return*/];
|
|
@@ -452,138 +541,314 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
452
541
|
FormoAnalytics.prototype.trackProvider = function (provider) {
|
|
453
542
|
lib_1.logger.info("trackProvider", provider);
|
|
454
543
|
try {
|
|
455
|
-
if (provider
|
|
544
|
+
if (!provider)
|
|
545
|
+
return;
|
|
546
|
+
if (this._trackedProviders.has(provider)) {
|
|
456
547
|
lib_1.logger.warn("TrackProvider: Provider already tracked.");
|
|
457
548
|
return;
|
|
458
549
|
}
|
|
459
|
-
this
|
|
460
|
-
this.
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
550
|
+
// Register listeners for this provider first
|
|
551
|
+
this.registerAccountsChangedListener(provider);
|
|
552
|
+
this.registerChainChangedListener(provider);
|
|
553
|
+
this.registerConnectListener(provider);
|
|
554
|
+
this.registerRequestListeners(provider);
|
|
555
|
+
this.registerDisconnectListener(provider);
|
|
556
|
+
// Only add to tracked providers after all listeners are successfully registered
|
|
557
|
+
this._trackedProviders.add(provider);
|
|
558
|
+
}
|
|
559
|
+
catch (error) {
|
|
560
|
+
lib_1.logger.error("Error tracking provider:", error);
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
FormoAnalytics.prototype.trackProviders = function (providers) {
|
|
564
|
+
try {
|
|
565
|
+
for (var _i = 0, providers_1 = providers; _i < providers_1.length; _i++) {
|
|
566
|
+
var eip6963ProviderDetail = providers_1[_i];
|
|
567
|
+
var provider = eip6963ProviderDetail === null || eip6963ProviderDetail === void 0 ? void 0 : eip6963ProviderDetail.provider;
|
|
568
|
+
if (provider && !this._trackedProviders.has(provider)) {
|
|
569
|
+
this.trackProvider(provider);
|
|
467
570
|
}
|
|
468
571
|
}
|
|
469
|
-
this._provider = provider;
|
|
470
|
-
// Register listeners for web3 provider events
|
|
471
|
-
this.registerAccountsChangedListener();
|
|
472
|
-
this.registerChainChangedListener();
|
|
473
|
-
this.registerConnectListener();
|
|
474
|
-
this.registerRequestListeners();
|
|
475
572
|
}
|
|
476
573
|
catch (error) {
|
|
477
|
-
lib_1.logger.error("
|
|
574
|
+
lib_1.logger.error("Failed to track EIP-6963 providers during initialization:", error);
|
|
478
575
|
}
|
|
479
576
|
};
|
|
480
|
-
FormoAnalytics.prototype.
|
|
577
|
+
FormoAnalytics.prototype.addProviderListener = function (provider, event, listener) {
|
|
578
|
+
var map = this._providerListenersMap.get(provider) || {};
|
|
579
|
+
map[event] = listener;
|
|
580
|
+
this._providerListenersMap.set(provider, map);
|
|
581
|
+
};
|
|
582
|
+
FormoAnalytics.prototype.registerAccountsChangedListener = function (provider) {
|
|
481
583
|
var _this = this;
|
|
482
|
-
var _a;
|
|
483
584
|
lib_1.logger.info("registerAccountsChangedListener");
|
|
484
585
|
var listener = function () {
|
|
485
586
|
var args = [];
|
|
486
587
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
487
588
|
args[_i] = arguments[_i];
|
|
488
589
|
}
|
|
489
|
-
return _this.onAccountsChanged(args[0]);
|
|
590
|
+
return _this.onAccountsChanged(provider, args[0]);
|
|
490
591
|
};
|
|
491
|
-
|
|
492
|
-
this.
|
|
592
|
+
provider.on("accountsChanged", listener);
|
|
593
|
+
this.addProviderListener(provider, "accountsChanged", listener);
|
|
493
594
|
};
|
|
494
|
-
FormoAnalytics.prototype.onAccountsChanged = function (accounts) {
|
|
595
|
+
FormoAnalytics.prototype.onAccountsChanged = function (provider, accounts) {
|
|
495
596
|
return __awaiter(this, void 0, void 0, function () {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
switch (_b.label) {
|
|
597
|
+
return __generator(this, function (_a) {
|
|
598
|
+
switch (_a.label) {
|
|
499
599
|
case 0:
|
|
500
600
|
lib_1.logger.info("onAccountsChanged", accounts);
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
601
|
+
// Prevent concurrent processing of accountsChanged events to avoid race conditions
|
|
602
|
+
if (this._processingAccountsChanged) {
|
|
603
|
+
lib_1.logger.debug("OnAccountsChanged: Already processing accountsChanged, skipping", {
|
|
604
|
+
provider: this.getProviderInfo(provider).name
|
|
605
|
+
});
|
|
606
|
+
return [2 /*return*/];
|
|
607
|
+
}
|
|
608
|
+
this._processingAccountsChanged = true;
|
|
609
|
+
_a.label = 1;
|
|
504
610
|
case 1:
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
return [2 /*return*/];
|
|
611
|
+
_a.trys.push([1, , 3, 4]);
|
|
612
|
+
return [4 /*yield*/, this._handleAccountsChanged(provider, accounts)];
|
|
508
613
|
case 2:
|
|
509
|
-
|
|
510
|
-
|
|
614
|
+
_a.sent();
|
|
615
|
+
return [3 /*break*/, 4];
|
|
616
|
+
case 3:
|
|
617
|
+
this._processingAccountsChanged = false;
|
|
618
|
+
return [7 /*endfinally*/];
|
|
619
|
+
case 4: return [2 /*return*/];
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
});
|
|
623
|
+
};
|
|
624
|
+
/**
|
|
625
|
+
* Handles changes to the accounts of a given EIP-1193 provider.
|
|
626
|
+
*
|
|
627
|
+
* @param provider - The EIP-1193 provider whose accounts have changed.
|
|
628
|
+
* @param accounts - The new array of account addresses. An empty array indicates a disconnect.
|
|
629
|
+
* @returns A promise that resolves when the account change has been processed.
|
|
630
|
+
*
|
|
631
|
+
* If the accounts array is empty and the provider is the active provider, this method triggers
|
|
632
|
+
* a disconnect flow. Otherwise, it updates the state to reflect the new accounts as needed.
|
|
633
|
+
*/
|
|
634
|
+
FormoAnalytics.prototype._handleAccountsChanged = function (provider, accounts) {
|
|
635
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
636
|
+
var error_1, address, currentStoredAddress, newProviderAddress, activeProviderAccounts, error_2, nextChainId, wasDisconnected, providerInfo, effectiveChainId;
|
|
637
|
+
return __generator(this, function (_a) {
|
|
638
|
+
switch (_a.label) {
|
|
639
|
+
case 0:
|
|
640
|
+
if (!(accounts.length === 0)) return [3 /*break*/, 7];
|
|
641
|
+
if (!(this._provider === provider)) return [3 /*break*/, 5];
|
|
642
|
+
lib_1.logger.info("OnAccountsChanged: Detecting disconnect, current state:", {
|
|
643
|
+
currentAddress: this.currentAddress,
|
|
644
|
+
currentChainId: this.currentChainId,
|
|
645
|
+
providerMatch: this._provider === provider
|
|
646
|
+
});
|
|
647
|
+
_a.label = 1;
|
|
648
|
+
case 1:
|
|
649
|
+
_a.trys.push([1, 3, , 4]);
|
|
650
|
+
// Pass current state explicitly to ensure we have the data for the disconnect event
|
|
651
|
+
return [4 /*yield*/, this.disconnect({
|
|
652
|
+
chainId: this.currentChainId,
|
|
653
|
+
address: this.currentAddress
|
|
654
|
+
})];
|
|
655
|
+
case 2:
|
|
656
|
+
// Pass current state explicitly to ensure we have the data for the disconnect event
|
|
657
|
+
_a.sent();
|
|
658
|
+
return [3 /*break*/, 4];
|
|
659
|
+
case 3:
|
|
660
|
+
error_1 = _a.sent();
|
|
661
|
+
lib_1.logger.error("Failed to disconnect provider on accountsChanged", error_1);
|
|
662
|
+
return [3 /*break*/, 4];
|
|
663
|
+
case 4: return [3 /*break*/, 6];
|
|
664
|
+
case 5:
|
|
665
|
+
lib_1.logger.info("OnAccountsChanged: Ignoring disconnect for non-active provider");
|
|
666
|
+
_a.label = 6;
|
|
667
|
+
case 6: return [2 /*return*/];
|
|
668
|
+
case 7:
|
|
669
|
+
address = this.validateAndChecksumAddress(accounts[0]);
|
|
670
|
+
if (!address) {
|
|
511
671
|
lib_1.logger.warn("onAccountsChanged: Invalid address received", accounts[0]);
|
|
512
672
|
return [2 /*return*/];
|
|
513
673
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
674
|
+
if (!(this._provider && this._provider !== provider)) return [3 /*break*/, 18];
|
|
675
|
+
currentStoredAddress = this.currentAddress;
|
|
676
|
+
newProviderAddress = this.validateAndChecksumAddress(address);
|
|
677
|
+
lib_1.logger.info("OnAccountsChanged: Different provider attempting to connect", {
|
|
678
|
+
activeProvider: this.getProviderInfo(this._provider).name,
|
|
679
|
+
eventProvider: this.getProviderInfo(provider).name,
|
|
680
|
+
currentStoredAddress: currentStoredAddress,
|
|
681
|
+
newProviderAddress: newProviderAddress
|
|
682
|
+
});
|
|
683
|
+
_a.label = 8;
|
|
684
|
+
case 8:
|
|
685
|
+
_a.trys.push([8, 16, , 18]);
|
|
686
|
+
return [4 /*yield*/, this.getAccounts(this._provider)];
|
|
687
|
+
case 9:
|
|
688
|
+
activeProviderAccounts = _a.sent();
|
|
689
|
+
lib_1.logger.info("OnAccountsChanged: Checking current provider accounts", {
|
|
690
|
+
activeProvider: this.getProviderInfo(this._provider).name,
|
|
691
|
+
accountsLength: activeProviderAccounts ? activeProviderAccounts.length : 0,
|
|
692
|
+
accounts: activeProviderAccounts
|
|
693
|
+
});
|
|
694
|
+
if (!(activeProviderAccounts && activeProviderAccounts.length > 0)) return [3 /*break*/, 13];
|
|
695
|
+
if (!(newProviderAddress && currentStoredAddress && newProviderAddress !== currentStoredAddress)) return [3 /*break*/, 11];
|
|
696
|
+
lib_1.logger.info("OnAccountsChanged: Different address detected, switching providers despite current provider having accounts", {
|
|
697
|
+
activeProvider: this.getProviderInfo(this._provider).name,
|
|
698
|
+
eventProvider: this.getProviderInfo(provider).name,
|
|
699
|
+
currentAddress: currentStoredAddress,
|
|
700
|
+
newAddress: newProviderAddress,
|
|
701
|
+
reason: PROVIDER_SWITCH_REASONS.ADDRESS_MISMATCH
|
|
702
|
+
});
|
|
703
|
+
// Emit disconnect for the old provider
|
|
704
|
+
return [4 /*yield*/, this.disconnect({
|
|
705
|
+
chainId: this.currentChainId,
|
|
706
|
+
address: this.currentAddress
|
|
707
|
+
})];
|
|
708
|
+
case 10:
|
|
709
|
+
// Emit disconnect for the old provider
|
|
710
|
+
_a.sent();
|
|
711
|
+
// Clear state and let the new provider become active
|
|
712
|
+
this._provider = undefined;
|
|
713
|
+
return [3 /*break*/, 12];
|
|
714
|
+
case 11:
|
|
715
|
+
lib_1.logger.info("OnAccountsChanged: Current provider still has accounts and same address, ignoring new provider", {
|
|
716
|
+
activeProvider: this.getProviderInfo(this._provider).name,
|
|
717
|
+
eventProvider: this.getProviderInfo(provider).name,
|
|
718
|
+
activeProviderAccountsCount: activeProviderAccounts.length,
|
|
719
|
+
currentAddress: currentStoredAddress,
|
|
720
|
+
newAddress: newProviderAddress
|
|
721
|
+
});
|
|
722
|
+
return [2 /*return*/];
|
|
723
|
+
case 12: return [3 /*break*/, 15];
|
|
724
|
+
case 13:
|
|
725
|
+
lib_1.logger.info("OnAccountsChanged: Current provider has no accounts, switching to new provider", {
|
|
726
|
+
oldProvider: this.getProviderInfo(this._provider).name,
|
|
727
|
+
newProvider: this.getProviderInfo(provider).name,
|
|
728
|
+
reason: PROVIDER_SWITCH_REASONS.NO_ACCOUNTS
|
|
729
|
+
});
|
|
730
|
+
// Emit disconnect for the old provider that didn't signal properly
|
|
731
|
+
return [4 /*yield*/, this.disconnect({
|
|
732
|
+
chainId: this.currentChainId,
|
|
733
|
+
address: this.currentAddress
|
|
734
|
+
})];
|
|
735
|
+
case 14:
|
|
736
|
+
// Emit disconnect for the old provider that didn't signal properly
|
|
737
|
+
_a.sent();
|
|
738
|
+
// Clear state and let the new provider become active
|
|
739
|
+
this._provider = undefined;
|
|
740
|
+
_a.label = 15;
|
|
741
|
+
case 15: return [3 /*break*/, 18];
|
|
742
|
+
case 16:
|
|
743
|
+
error_2 = _a.sent();
|
|
744
|
+
lib_1.logger.warn("OnAccountsChanged: Could not check current provider accounts, switching to new provider", {
|
|
745
|
+
error: error_2 instanceof Error ? error_2.message : String(error_2),
|
|
746
|
+
errorType: error_2 instanceof Error ? error_2.constructor.name : typeof error_2,
|
|
747
|
+
oldProvider: this._provider ? this.getProviderInfo(this._provider).name : 'unknown',
|
|
748
|
+
newProvider: this.getProviderInfo(provider).name,
|
|
749
|
+
reason: PROVIDER_SWITCH_REASONS.CHECK_FAILED
|
|
750
|
+
});
|
|
751
|
+
// If we can't check the current provider, assume it's disconnected
|
|
752
|
+
return [4 /*yield*/, this.disconnect({
|
|
753
|
+
chainId: this.currentChainId,
|
|
754
|
+
address: this.currentAddress
|
|
755
|
+
})];
|
|
756
|
+
case 17:
|
|
757
|
+
// If we can't check the current provider, assume it's disconnected
|
|
758
|
+
_a.sent();
|
|
759
|
+
this._provider = undefined;
|
|
760
|
+
return [3 /*break*/, 18];
|
|
761
|
+
case 18:
|
|
762
|
+
// Set provider if none exists (first connection)
|
|
763
|
+
if (!this._provider) {
|
|
764
|
+
this._provider = provider;
|
|
765
|
+
}
|
|
766
|
+
// If both the provider and address are the same, no-op
|
|
767
|
+
if (this._provider === provider && address === this.currentAddress) {
|
|
517
768
|
return [2 /*return*/];
|
|
518
769
|
}
|
|
519
|
-
|
|
770
|
+
return [4 /*yield*/, this.getCurrentChainId(provider)];
|
|
771
|
+
case 19:
|
|
772
|
+
nextChainId = _a.sent();
|
|
773
|
+
wasDisconnected = !this.currentAddress;
|
|
520
774
|
this.currentAddress = address;
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
775
|
+
this.currentChainId = nextChainId;
|
|
776
|
+
providerInfo = this.getProviderInfo(provider);
|
|
777
|
+
lib_1.logger.info("OnAccountsChanged: Detected wallet connection, emitting connect event", {
|
|
778
|
+
chainId: nextChainId,
|
|
779
|
+
address: address,
|
|
780
|
+
wasDisconnected: wasDisconnected,
|
|
781
|
+
providerName: providerInfo.name,
|
|
782
|
+
rdns: providerInfo.rdns,
|
|
783
|
+
hasChainId: !!nextChainId
|
|
784
|
+
});
|
|
785
|
+
effectiveChainId = nextChainId || 0;
|
|
786
|
+
if (effectiveChainId === 0) {
|
|
787
|
+
lib_1.logger.info("OnAccountsChanged: Using fallback chainId 0 for connect event");
|
|
788
|
+
}
|
|
789
|
+
this.connect({
|
|
790
|
+
chainId: effectiveChainId,
|
|
791
|
+
address: address
|
|
792
|
+
}, {
|
|
793
|
+
providerName: providerInfo.name,
|
|
794
|
+
rdns: providerInfo.rdns
|
|
795
|
+
}).catch(function (error) {
|
|
796
|
+
lib_1.logger.error("Failed to track connect event during account change:", error);
|
|
797
|
+
});
|
|
526
798
|
return [2 /*return*/];
|
|
527
799
|
}
|
|
528
800
|
});
|
|
529
801
|
});
|
|
530
802
|
};
|
|
531
|
-
FormoAnalytics.prototype.registerChainChangedListener = function () {
|
|
803
|
+
FormoAnalytics.prototype.registerChainChangedListener = function (provider) {
|
|
532
804
|
var _this = this;
|
|
533
|
-
var _a;
|
|
534
805
|
lib_1.logger.info("registerChainChangedListener");
|
|
535
806
|
var listener = function () {
|
|
536
807
|
var args = [];
|
|
537
808
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
538
809
|
args[_i] = arguments[_i];
|
|
539
810
|
}
|
|
540
|
-
return _this.onChainChanged(args[0]);
|
|
811
|
+
return _this.onChainChanged(provider, args[0]);
|
|
541
812
|
};
|
|
542
|
-
|
|
543
|
-
this.
|
|
813
|
+
provider.on("chainChanged", listener);
|
|
814
|
+
this.addProviderListener(provider, "chainChanged", listener);
|
|
544
815
|
};
|
|
545
|
-
FormoAnalytics.prototype.onChainChanged = function (chainIdHex) {
|
|
816
|
+
FormoAnalytics.prototype.onChainChanged = function (provider, chainIdHex) {
|
|
546
817
|
return __awaiter(this, void 0, void 0, function () {
|
|
547
|
-
var
|
|
818
|
+
var nextChainId;
|
|
548
819
|
return __generator(this, function (_a) {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
return [2 /*return*/, this.chain({
|
|
572
|
-
chainId: this.currentChainId,
|
|
573
|
-
address: this.currentAddress,
|
|
574
|
-
})];
|
|
575
|
-
}
|
|
576
|
-
else {
|
|
577
|
-
lib_1.logger.info("OnChainChanged: Current connected address is null despite fetch attempt");
|
|
578
|
-
}
|
|
579
|
-
return [2 /*return*/];
|
|
820
|
+
lib_1.logger.info("onChainChanged", chainIdHex);
|
|
821
|
+
nextChainId = (0, chain_1.parseChainId)(chainIdHex);
|
|
822
|
+
// Only handle chain changes for the active provider (or if none is set yet)
|
|
823
|
+
if (this.isProviderMismatch(provider)) {
|
|
824
|
+
this.handleProviderMismatch(provider);
|
|
825
|
+
}
|
|
826
|
+
// Chain changes only matter for connected users
|
|
827
|
+
if (!this.currentAddress) {
|
|
828
|
+
lib_1.logger.info("OnChainChanged: No current address, user appears disconnected");
|
|
829
|
+
return [2 /*return*/, Promise.resolve()];
|
|
830
|
+
}
|
|
831
|
+
// Set provider if none exists
|
|
832
|
+
if (!this._provider) {
|
|
833
|
+
this._provider = provider;
|
|
834
|
+
}
|
|
835
|
+
this.currentChainId = nextChainId;
|
|
836
|
+
try {
|
|
837
|
+
// This is just a chain change since we already confirmed currentAddress exists
|
|
838
|
+
return [2 /*return*/, this.chain({
|
|
839
|
+
chainId: this.currentChainId,
|
|
840
|
+
address: this.currentAddress,
|
|
841
|
+
})];
|
|
580
842
|
}
|
|
843
|
+
catch (error) {
|
|
844
|
+
lib_1.logger.error("OnChainChanged: Failed to emit chain event:", error);
|
|
845
|
+
}
|
|
846
|
+
return [2 /*return*/];
|
|
581
847
|
});
|
|
582
848
|
});
|
|
583
849
|
};
|
|
584
|
-
FormoAnalytics.prototype.registerConnectListener = function () {
|
|
850
|
+
FormoAnalytics.prototype.registerConnectListener = function (provider) {
|
|
585
851
|
var _this = this;
|
|
586
|
-
var _a;
|
|
587
852
|
lib_1.logger.info("registerConnectListener");
|
|
588
853
|
var listener = function () {
|
|
589
854
|
var args = [];
|
|
@@ -591,14 +856,51 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
591
856
|
args[_i] = arguments[_i];
|
|
592
857
|
}
|
|
593
858
|
var connection = args[0];
|
|
594
|
-
_this.onConnected(connection);
|
|
859
|
+
_this.onConnected(provider, connection);
|
|
595
860
|
};
|
|
596
|
-
|
|
597
|
-
this.
|
|
861
|
+
provider.on("connect", listener);
|
|
862
|
+
this.addProviderListener(provider, "connect", listener);
|
|
863
|
+
};
|
|
864
|
+
FormoAnalytics.prototype.registerDisconnectListener = function (provider) {
|
|
865
|
+
var _this = this;
|
|
866
|
+
lib_1.logger.info("registerDisconnectListener");
|
|
867
|
+
var listener = function (_error) { return __awaiter(_this, void 0, void 0, function () {
|
|
868
|
+
var e_2;
|
|
869
|
+
return __generator(this, function (_a) {
|
|
870
|
+
switch (_a.label) {
|
|
871
|
+
case 0:
|
|
872
|
+
if (this._provider !== provider)
|
|
873
|
+
return [2 /*return*/];
|
|
874
|
+
lib_1.logger.info("OnDisconnect: Wallet disconnect event received, current state:", {
|
|
875
|
+
currentAddress: this.currentAddress,
|
|
876
|
+
currentChainId: this.currentChainId
|
|
877
|
+
});
|
|
878
|
+
_a.label = 1;
|
|
879
|
+
case 1:
|
|
880
|
+
_a.trys.push([1, 3, , 4]);
|
|
881
|
+
// Pass current state explicitly to ensure we have the data for the disconnect event
|
|
882
|
+
return [4 /*yield*/, this.disconnect({
|
|
883
|
+
chainId: this.currentChainId,
|
|
884
|
+
address: this.currentAddress
|
|
885
|
+
})];
|
|
886
|
+
case 2:
|
|
887
|
+
// Pass current state explicitly to ensure we have the data for the disconnect event
|
|
888
|
+
_a.sent();
|
|
889
|
+
return [3 /*break*/, 4];
|
|
890
|
+
case 3:
|
|
891
|
+
e_2 = _a.sent();
|
|
892
|
+
lib_1.logger.error("Error during disconnect in disconnect listener", e_2);
|
|
893
|
+
return [3 /*break*/, 4];
|
|
894
|
+
case 4: return [2 /*return*/];
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
}); };
|
|
898
|
+
provider.on("disconnect", listener);
|
|
899
|
+
this.addProviderListener(provider, "disconnect", listener);
|
|
598
900
|
};
|
|
599
|
-
FormoAnalytics.prototype.onConnected = function (connection) {
|
|
901
|
+
FormoAnalytics.prototype.onConnected = function (provider, connection) {
|
|
600
902
|
return __awaiter(this, void 0, void 0, function () {
|
|
601
|
-
var chainId, address,
|
|
903
|
+
var chainId, address, wasDisconnected, isActiveProvider, providerInfo, effectiveChainId, providerInfo, e_3;
|
|
602
904
|
return __generator(this, function (_a) {
|
|
603
905
|
switch (_a.label) {
|
|
604
906
|
case 0:
|
|
@@ -606,53 +908,105 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
606
908
|
_a.label = 1;
|
|
607
909
|
case 1:
|
|
608
910
|
_a.trys.push([1, 3, , 4]);
|
|
609
|
-
if (!connection || typeof connection.chainId !== 'string')
|
|
911
|
+
if (!(connection === null || connection === void 0 ? void 0 : connection.chainId) || typeof connection.chainId !== 'string')
|
|
610
912
|
return [2 /*return*/];
|
|
611
913
|
chainId = (0, chain_1.parseChainId)(connection.chainId);
|
|
612
|
-
return [4 /*yield*/, this.getAddress()];
|
|
914
|
+
return [4 /*yield*/, this.getAddress(provider)];
|
|
613
915
|
case 2:
|
|
614
916
|
address = _a.sent();
|
|
615
|
-
if (chainId
|
|
616
|
-
this.
|
|
917
|
+
if (chainId && address) {
|
|
918
|
+
wasDisconnected = !this.currentAddress;
|
|
919
|
+
// Set provider if none exists
|
|
920
|
+
if (!this._provider) {
|
|
921
|
+
this._provider = provider;
|
|
922
|
+
}
|
|
923
|
+
isActiveProvider = this._provider === provider;
|
|
924
|
+
// Only update global state (chainId/address) from the active provider
|
|
925
|
+
if (isActiveProvider) {
|
|
926
|
+
this.currentChainId = chainId;
|
|
927
|
+
this.currentAddress = this.validateAndChecksumAddress(address) || undefined;
|
|
928
|
+
}
|
|
929
|
+
if (isActiveProvider && this.currentAddress) {
|
|
930
|
+
providerInfo = this.getProviderInfo(provider);
|
|
931
|
+
lib_1.logger.info("OnConnected: Detected wallet connection, emitting connect event", {
|
|
932
|
+
chainId: chainId,
|
|
933
|
+
wasDisconnected: wasDisconnected,
|
|
934
|
+
providerName: providerInfo.name,
|
|
935
|
+
rdns: providerInfo.rdns,
|
|
936
|
+
hasChainId: !!chainId,
|
|
937
|
+
isActiveProvider: isActiveProvider
|
|
938
|
+
});
|
|
939
|
+
effectiveChainId = chainId || 0;
|
|
940
|
+
if (effectiveChainId === 0) {
|
|
941
|
+
lib_1.logger.info("OnConnected: Using fallback chainId 0 for connect event");
|
|
942
|
+
}
|
|
943
|
+
this.connect({
|
|
944
|
+
chainId: effectiveChainId,
|
|
945
|
+
address: address
|
|
946
|
+
}, {
|
|
947
|
+
providerName: providerInfo.name,
|
|
948
|
+
rdns: providerInfo.rdns
|
|
949
|
+
}).catch(function (error) {
|
|
950
|
+
lib_1.logger.error("Failed to track connect event during provider connection:", error);
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
else if (address && !isActiveProvider) {
|
|
954
|
+
providerInfo = this.getProviderInfo(provider);
|
|
955
|
+
lib_1.logger.debug("OnConnected: Skipping connect event for non-active provider", {
|
|
956
|
+
chainId: chainId,
|
|
957
|
+
providerName: providerInfo.name,
|
|
958
|
+
rdns: providerInfo.rdns,
|
|
959
|
+
isActiveProvider: isActiveProvider,
|
|
960
|
+
activeProviderInfo: this._provider ? this.getProviderInfo(this._provider) : null
|
|
961
|
+
});
|
|
962
|
+
}
|
|
617
963
|
}
|
|
618
964
|
return [3 /*break*/, 4];
|
|
619
965
|
case 3:
|
|
620
|
-
|
|
621
|
-
lib_1.logger.error("Error handling connect event",
|
|
966
|
+
e_3 = _a.sent();
|
|
967
|
+
lib_1.logger.error("Error handling connect event", e_3);
|
|
622
968
|
return [3 /*break*/, 4];
|
|
623
969
|
case 4: return [2 /*return*/];
|
|
624
970
|
}
|
|
625
971
|
});
|
|
626
972
|
});
|
|
627
973
|
};
|
|
628
|
-
FormoAnalytics.prototype.registerRequestListeners = function () {
|
|
974
|
+
FormoAnalytics.prototype.registerRequestListeners = function (provider) {
|
|
629
975
|
var _this = this;
|
|
630
|
-
var _a;
|
|
631
976
|
lib_1.logger.info("registerRequestListeners");
|
|
632
|
-
if (!
|
|
977
|
+
if (!provider) {
|
|
633
978
|
lib_1.logger.error("Provider not found for request (signature, transaction) tracking");
|
|
634
979
|
return;
|
|
635
980
|
}
|
|
636
|
-
if
|
|
637
|
-
|
|
638
|
-
|
|
981
|
+
// Check if the provider is already wrapped with our SDK's wrapper
|
|
982
|
+
var currentRequest = provider.request;
|
|
983
|
+
if (this.isProviderAlreadyWrapped(provider, currentRequest)) {
|
|
984
|
+
lib_1.logger.info("Provider already wrapped with our SDK; skipping request wrapping.");
|
|
639
985
|
return;
|
|
640
986
|
}
|
|
641
|
-
var request =
|
|
642
|
-
|
|
643
|
-
var response_1,
|
|
987
|
+
var request = provider.request.bind(provider);
|
|
988
|
+
var wrappedRequest = function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
|
|
989
|
+
var capturedChainId_1, _c, response_1, error_3, rpcError, transactionHash_1, error_4, rpcError;
|
|
644
990
|
var _this = this;
|
|
645
991
|
var method = _b.method, params = _b.params;
|
|
646
|
-
return __generator(this, function (
|
|
647
|
-
switch (
|
|
992
|
+
return __generator(this, function (_d) {
|
|
993
|
+
switch (_d.label) {
|
|
648
994
|
case 0:
|
|
649
995
|
if (!(Array.isArray(params) &&
|
|
650
|
-
["eth_signTypedData_v4", "personal_sign"].includes(method))) return [3 /*break*/,
|
|
996
|
+
["eth_signTypedData_v4", "personal_sign"].includes(method))) return [3 /*break*/, 6];
|
|
997
|
+
_c = this.currentChainId;
|
|
998
|
+
if (_c) return [3 /*break*/, 2];
|
|
999
|
+
return [4 /*yield*/, this.getCurrentChainId(provider)];
|
|
1000
|
+
case 1:
|
|
1001
|
+
_c = (_d.sent());
|
|
1002
|
+
_d.label = 2;
|
|
1003
|
+
case 2:
|
|
1004
|
+
capturedChainId_1 = _c;
|
|
651
1005
|
// Fire-and-forget tracking
|
|
652
1006
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
653
1007
|
return __generator(this, function (_a) {
|
|
654
1008
|
try {
|
|
655
|
-
this.signature(__assign({ status: types_1.SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params)));
|
|
1009
|
+
this.signature(__assign({ status: types_1.SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1)));
|
|
656
1010
|
}
|
|
657
1011
|
catch (e) {
|
|
658
1012
|
lib_1.logger.error("Formo: Failed to track signature request", e);
|
|
@@ -660,127 +1014,139 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
660
1014
|
return [2 /*return*/];
|
|
661
1015
|
});
|
|
662
1016
|
}); })();
|
|
663
|
-
|
|
664
|
-
case
|
|
665
|
-
|
|
1017
|
+
_d.label = 3;
|
|
1018
|
+
case 3:
|
|
1019
|
+
_d.trys.push([3, 5, , 6]);
|
|
666
1020
|
return [4 /*yield*/, request({ method: method, params: params })];
|
|
667
|
-
case
|
|
668
|
-
response_1 = (
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
1021
|
+
case 4:
|
|
1022
|
+
response_1 = (_d.sent());
|
|
1023
|
+
// Track signature confirmation only for truthy responses
|
|
1024
|
+
if (response_1) {
|
|
1025
|
+
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1026
|
+
return __generator(this, function (_a) {
|
|
1027
|
+
try {
|
|
1028
|
+
this.signature(__assign({ status: types_1.SignatureStatus.CONFIRMED }, this.buildSignatureEventPayload(method, params, response_1, capturedChainId_1)));
|
|
674
1029
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
});
|
|
681
|
-
}
|
|
1030
|
+
catch (e) {
|
|
1031
|
+
lib_1.logger.error("Formo: Failed to track signature confirmation", e);
|
|
1032
|
+
}
|
|
1033
|
+
return [2 /*return*/];
|
|
1034
|
+
});
|
|
1035
|
+
}); })();
|
|
1036
|
+
}
|
|
682
1037
|
return [2 /*return*/, response_1];
|
|
683
|
-
case
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
this.signature(__assign({ status: types_1.SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params)));
|
|
1038
|
+
case 5:
|
|
1039
|
+
error_3 = _d.sent();
|
|
1040
|
+
rpcError = error_3;
|
|
1041
|
+
if ((rpcError === null || rpcError === void 0 ? void 0 : rpcError.code) === 4001) {
|
|
1042
|
+
// Use the already cast rpcError to avoid duplication
|
|
1043
|
+
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1044
|
+
return __generator(this, function (_a) {
|
|
1045
|
+
try {
|
|
1046
|
+
this.signature(__assign({ status: types_1.SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1)));
|
|
692
1047
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
});
|
|
699
|
-
}
|
|
700
|
-
throw
|
|
701
|
-
case
|
|
1048
|
+
catch (e) {
|
|
1049
|
+
lib_1.logger.error("Formo: Failed to track signature rejection", e);
|
|
1050
|
+
}
|
|
1051
|
+
return [2 /*return*/];
|
|
1052
|
+
});
|
|
1053
|
+
}); })();
|
|
1054
|
+
}
|
|
1055
|
+
throw error_3;
|
|
1056
|
+
case 6:
|
|
702
1057
|
if (!(Array.isArray(params) &&
|
|
703
1058
|
method === "eth_sendTransaction" &&
|
|
704
|
-
params[0])) return [3 /*break*/,
|
|
1059
|
+
params[0])) return [3 /*break*/, 10];
|
|
705
1060
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
706
|
-
var payload,
|
|
1061
|
+
var payload, e_4;
|
|
707
1062
|
return __generator(this, function (_a) {
|
|
708
1063
|
switch (_a.label) {
|
|
709
1064
|
case 0:
|
|
710
1065
|
_a.trys.push([0, 2, , 3]);
|
|
711
|
-
return [4 /*yield*/, this.buildTransactionEventPayload(params)];
|
|
1066
|
+
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider)];
|
|
712
1067
|
case 1:
|
|
713
1068
|
payload = _a.sent();
|
|
714
1069
|
this.transaction(__assign({ status: types_1.TransactionStatus.STARTED }, payload));
|
|
715
1070
|
return [3 /*break*/, 3];
|
|
716
1071
|
case 2:
|
|
717
|
-
|
|
718
|
-
lib_1.logger.error("Formo: Failed to track transaction start",
|
|
1072
|
+
e_4 = _a.sent();
|
|
1073
|
+
lib_1.logger.error("Formo: Failed to track transaction start", e_4);
|
|
719
1074
|
return [3 /*break*/, 3];
|
|
720
1075
|
case 3: return [2 /*return*/];
|
|
721
1076
|
}
|
|
722
1077
|
});
|
|
723
1078
|
}); })();
|
|
724
|
-
|
|
725
|
-
case
|
|
726
|
-
|
|
1079
|
+
_d.label = 7;
|
|
1080
|
+
case 7:
|
|
1081
|
+
_d.trys.push([7, 9, , 10]);
|
|
727
1082
|
return [4 /*yield*/, request({
|
|
728
1083
|
method: method,
|
|
729
1084
|
params: params,
|
|
730
1085
|
})];
|
|
731
|
-
case
|
|
732
|
-
transactionHash_1 = (
|
|
1086
|
+
case 8:
|
|
1087
|
+
transactionHash_1 = (_d.sent());
|
|
733
1088
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
734
|
-
var payload,
|
|
1089
|
+
var payload, e_5;
|
|
735
1090
|
return __generator(this, function (_a) {
|
|
736
1091
|
switch (_a.label) {
|
|
737
1092
|
case 0:
|
|
738
1093
|
_a.trys.push([0, 2, , 3]);
|
|
739
|
-
return [4 /*yield*/, this.buildTransactionEventPayload(params)];
|
|
1094
|
+
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider)];
|
|
740
1095
|
case 1:
|
|
741
1096
|
payload = _a.sent();
|
|
742
1097
|
this.transaction(__assign(__assign({ status: types_1.TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }));
|
|
743
1098
|
// Start async polling for transaction receipt
|
|
744
|
-
this.pollTransactionReceipt(transactionHash_1, payload);
|
|
1099
|
+
this.pollTransactionReceipt(provider, transactionHash_1, payload);
|
|
745
1100
|
return [3 /*break*/, 3];
|
|
746
1101
|
case 2:
|
|
747
|
-
|
|
748
|
-
lib_1.logger.error("Formo: Failed to track transaction broadcast",
|
|
1102
|
+
e_5 = _a.sent();
|
|
1103
|
+
lib_1.logger.error("Formo: Failed to track transaction broadcast", e_5);
|
|
749
1104
|
return [3 /*break*/, 3];
|
|
750
1105
|
case 3: return [2 /*return*/];
|
|
751
1106
|
}
|
|
752
1107
|
});
|
|
753
1108
|
}); })();
|
|
754
1109
|
return [2 /*return*/, transactionHash_1];
|
|
755
|
-
case
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1110
|
+
case 9:
|
|
1111
|
+
error_4 = _d.sent();
|
|
1112
|
+
rpcError = error_4;
|
|
1113
|
+
if ((rpcError === null || rpcError === void 0 ? void 0 : rpcError.code) === 4001) {
|
|
1114
|
+
// Use the already cast rpcError to avoid duplication
|
|
1115
|
+
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1116
|
+
var payload, e_6;
|
|
1117
|
+
return __generator(this, function (_a) {
|
|
1118
|
+
switch (_a.label) {
|
|
1119
|
+
case 0:
|
|
1120
|
+
_a.trys.push([0, 2, , 3]);
|
|
1121
|
+
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider)];
|
|
1122
|
+
case 1:
|
|
1123
|
+
payload = _a.sent();
|
|
1124
|
+
this.transaction(__assign({ status: types_1.TransactionStatus.REJECTED }, payload));
|
|
1125
|
+
return [3 /*break*/, 3];
|
|
1126
|
+
case 2:
|
|
1127
|
+
e_6 = _a.sent();
|
|
1128
|
+
lib_1.logger.error("Formo: Failed to track transaction rejection", e_6);
|
|
1129
|
+
return [3 /*break*/, 3];
|
|
1130
|
+
case 3: return [2 /*return*/];
|
|
1131
|
+
}
|
|
1132
|
+
});
|
|
1133
|
+
}); })();
|
|
1134
|
+
}
|
|
1135
|
+
throw error_4;
|
|
1136
|
+
case 10: return [2 /*return*/, request({ method: method, params: params })];
|
|
781
1137
|
}
|
|
782
1138
|
});
|
|
783
1139
|
}); };
|
|
1140
|
+
// Mark the wrapper so we can detect if request is replaced externally and keep a reference on provider
|
|
1141
|
+
wrappedRequest[types_1.WRAPPED_REQUEST_SYMBOL] = true;
|
|
1142
|
+
provider[types_1.WRAPPED_REQUEST_REF_SYMBOL] = wrappedRequest;
|
|
1143
|
+
try {
|
|
1144
|
+
// Attempt to assign the wrapped request function (rely on try-catch for mutability errors)
|
|
1145
|
+
provider.request = wrappedRequest;
|
|
1146
|
+
}
|
|
1147
|
+
catch (e) {
|
|
1148
|
+
lib_1.logger.warn("Failed to wrap provider.request; skipping", e);
|
|
1149
|
+
}
|
|
784
1150
|
};
|
|
785
1151
|
FormoAnalytics.prototype.onLocationChange = function () {
|
|
786
1152
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -834,15 +1200,29 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
834
1200
|
lib_1.logger.info("Track page hit: Skipping event due to tracking configuration");
|
|
835
1201
|
return [2 /*return*/];
|
|
836
1202
|
}
|
|
837
|
-
setTimeout(function () {
|
|
838
|
-
return
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1203
|
+
setTimeout(function () {
|
|
1204
|
+
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1205
|
+
var e_7;
|
|
1206
|
+
return __generator(this, function (_a) {
|
|
1207
|
+
switch (_a.label) {
|
|
1208
|
+
case 0:
|
|
1209
|
+
_a.trys.push([0, 2, , 3]);
|
|
1210
|
+
return [4 /*yield*/, this.trackEvent(constants_1.EventType.PAGE, {
|
|
1211
|
+
category: category,
|
|
1212
|
+
name: name,
|
|
1213
|
+
}, properties, context, callback)];
|
|
1214
|
+
case 1:
|
|
1215
|
+
_a.sent();
|
|
1216
|
+
return [3 /*break*/, 3];
|
|
1217
|
+
case 2:
|
|
1218
|
+
e_7 = _a.sent();
|
|
1219
|
+
lib_1.logger.error("Formo: Failed to track page hit", e_7);
|
|
1220
|
+
return [3 /*break*/, 3];
|
|
1221
|
+
case 3: return [2 /*return*/];
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1224
|
+
}); })();
|
|
1225
|
+
}, 300);
|
|
846
1226
|
return [2 /*return*/];
|
|
847
1227
|
});
|
|
848
1228
|
});
|
|
@@ -907,24 +1287,167 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
907
1287
|
/*
|
|
908
1288
|
Utility functions
|
|
909
1289
|
*/
|
|
1290
|
+
/**
|
|
1291
|
+
* Get provider information for a given provider
|
|
1292
|
+
* @param provider The provider to get info for
|
|
1293
|
+
* @returns Provider information
|
|
1294
|
+
*/
|
|
1295
|
+
FormoAnalytics.prototype.getProviderInfo = function (provider) {
|
|
1296
|
+
// First check if provider is in our EIP-6963 providers list
|
|
1297
|
+
var eip6963Provider = this._providers.find(function (p) { return p.provider === provider; });
|
|
1298
|
+
if (eip6963Provider) {
|
|
1299
|
+
return {
|
|
1300
|
+
name: eip6963Provider.info.name,
|
|
1301
|
+
rdns: eip6963Provider.info.rdns
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
// Fallback to injected provider detection
|
|
1305
|
+
var injectedInfo = this.detectInjectedProviderInfo(provider);
|
|
1306
|
+
return {
|
|
1307
|
+
name: injectedInfo.name,
|
|
1308
|
+
rdns: injectedInfo.rdns
|
|
1309
|
+
};
|
|
1310
|
+
};
|
|
1311
|
+
/**
|
|
1312
|
+
* Attempts to detect information about an injected provider
|
|
1313
|
+
* @param provider The injected provider to analyze
|
|
1314
|
+
* @returns Provider information with fallback values
|
|
1315
|
+
*/
|
|
1316
|
+
FormoAnalytics.prototype.detectInjectedProviderInfo = function (provider) {
|
|
1317
|
+
// Try to detect provider type from common properties
|
|
1318
|
+
var name = 'Injected Provider';
|
|
1319
|
+
var rdns = 'io.injected.provider';
|
|
1320
|
+
// Use WalletProviderFlags interface for type safety
|
|
1321
|
+
var flags = provider;
|
|
1322
|
+
// Check if it's MetaMask
|
|
1323
|
+
if (flags.isMetaMask) {
|
|
1324
|
+
name = 'MetaMask';
|
|
1325
|
+
rdns = 'io.metamask';
|
|
1326
|
+
}
|
|
1327
|
+
// Check if it's Coinbase Wallet
|
|
1328
|
+
else if (flags.isCoinbaseWallet) {
|
|
1329
|
+
name = 'Coinbase Wallet';
|
|
1330
|
+
rdns = 'com.coinbase.wallet';
|
|
1331
|
+
}
|
|
1332
|
+
// Check if it's WalletConnect
|
|
1333
|
+
else if (flags.isWalletConnect) {
|
|
1334
|
+
name = 'WalletConnect';
|
|
1335
|
+
rdns = 'com.walletconnect';
|
|
1336
|
+
}
|
|
1337
|
+
// Check if it's Trust Wallet
|
|
1338
|
+
else if (flags.isTrust) {
|
|
1339
|
+
name = 'Trust Wallet';
|
|
1340
|
+
rdns = 'com.trustwallet';
|
|
1341
|
+
}
|
|
1342
|
+
// Check if it's Brave Wallet
|
|
1343
|
+
else if (flags.isBraveWallet) {
|
|
1344
|
+
name = 'Brave Wallet';
|
|
1345
|
+
rdns = 'com.brave.wallet';
|
|
1346
|
+
}
|
|
1347
|
+
// Check if it's Phantom
|
|
1348
|
+
else if (flags.isPhantom) {
|
|
1349
|
+
name = 'Phantom';
|
|
1350
|
+
rdns = 'app.phantom';
|
|
1351
|
+
}
|
|
1352
|
+
return {
|
|
1353
|
+
name: name,
|
|
1354
|
+
rdns: rdns,
|
|
1355
|
+
uuid: "injected-".concat(rdns.replace(/[^a-zA-Z0-9]/g, '-')),
|
|
1356
|
+
icon: constants_1.DEFAULT_PROVIDER_ICON
|
|
1357
|
+
};
|
|
1358
|
+
};
|
|
910
1359
|
FormoAnalytics.prototype.getProviders = function () {
|
|
911
1360
|
return __awaiter(this, void 0, void 0, function () {
|
|
912
|
-
var store, providers;
|
|
1361
|
+
var store, providers, injected_1, injectedProviderInfo, injectedDetail, uniqueProviders, _i, uniqueProviders_1, detail;
|
|
913
1362
|
var _this = this;
|
|
914
1363
|
return __generator(this, function (_a) {
|
|
915
1364
|
store = (0, mipd_1.createStore)();
|
|
916
1365
|
providers = store.getProviders();
|
|
917
1366
|
store.subscribe(function (providerDetails) {
|
|
918
1367
|
providers = providerDetails;
|
|
919
|
-
|
|
1368
|
+
// Process newly added providers with proper deduplication
|
|
1369
|
+
var newlyAddedDetails = providerDetails.filter(function (detail) {
|
|
1370
|
+
var provider = detail === null || detail === void 0 ? void 0 : detail.provider;
|
|
1371
|
+
return provider && !_this._seenProviders.has(provider);
|
|
1372
|
+
});
|
|
1373
|
+
// Add new providers to the array without overwriting existing ones
|
|
1374
|
+
for (var _i = 0, newlyAddedDetails_1 = newlyAddedDetails; _i < newlyAddedDetails_1.length; _i++) {
|
|
1375
|
+
var detail = newlyAddedDetails_1[_i];
|
|
1376
|
+
_this.safeAddProviderDetail(detail);
|
|
1377
|
+
}
|
|
1378
|
+
// Track listeners for newly discovered providers only
|
|
1379
|
+
var newDetails = providerDetails.filter(function (detail) {
|
|
1380
|
+
var p = detail === null || detail === void 0 ? void 0 : detail.provider;
|
|
1381
|
+
return !!p && !_this._trackedProviders.has(p);
|
|
1382
|
+
});
|
|
1383
|
+
if (newDetails.length > 0) {
|
|
1384
|
+
_this.trackProviders(newDetails);
|
|
1385
|
+
// Detect newly discovered wallets (session de-dupes) with error handling
|
|
1386
|
+
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1387
|
+
var e_8;
|
|
1388
|
+
return __generator(this, function (_a) {
|
|
1389
|
+
switch (_a.label) {
|
|
1390
|
+
case 0:
|
|
1391
|
+
_a.trys.push([0, 2, , 3]);
|
|
1392
|
+
return [4 /*yield*/, this.detectWallets(newDetails)];
|
|
1393
|
+
case 1:
|
|
1394
|
+
_a.sent();
|
|
1395
|
+
return [3 /*break*/, 3];
|
|
1396
|
+
case 2:
|
|
1397
|
+
e_8 = _a.sent();
|
|
1398
|
+
lib_1.logger.error("Formo: Failed to detect wallets", e_8);
|
|
1399
|
+
return [3 /*break*/, 3];
|
|
1400
|
+
case 3: return [2 /*return*/];
|
|
1401
|
+
}
|
|
1402
|
+
});
|
|
1403
|
+
}); })();
|
|
1404
|
+
}
|
|
1405
|
+
// Clean up providers that are no longer available
|
|
1406
|
+
_this.cleanupUnavailableProviders();
|
|
920
1407
|
});
|
|
921
1408
|
// Fallback to injected provider if no providers are found
|
|
922
1409
|
if (providers.length === 0) {
|
|
923
|
-
|
|
1410
|
+
injected_1 = typeof window !== 'undefined' ? window.ethereum : undefined;
|
|
1411
|
+
if (injected_1) {
|
|
1412
|
+
// If we have already detected and cached the injected provider, and it's the same instance, return the cached result
|
|
1413
|
+
if (this._injectedProviderDetail &&
|
|
1414
|
+
this._injectedProviderDetail.provider === injected_1) {
|
|
1415
|
+
// Ensure it's tracked
|
|
1416
|
+
if (!this._trackedProviders.has(injected_1)) {
|
|
1417
|
+
this.trackProvider(injected_1);
|
|
1418
|
+
}
|
|
1419
|
+
// Merge with existing providers instead of overwriting
|
|
1420
|
+
if (!this._providers.some(function (existing) { return existing.provider === injected_1; })) {
|
|
1421
|
+
this._providers = __spreadArray(__spreadArray([], this._providers, true), [this._injectedProviderDetail], false);
|
|
1422
|
+
}
|
|
1423
|
+
return [2 /*return*/, this._providers];
|
|
1424
|
+
}
|
|
1425
|
+
// Re-check if the injected provider is already tracked just before tracking
|
|
1426
|
+
if (!this._trackedProviders.has(injected_1)) {
|
|
1427
|
+
this.trackProvider(injected_1);
|
|
1428
|
+
}
|
|
1429
|
+
injectedProviderInfo = this.detectInjectedProviderInfo(injected_1);
|
|
1430
|
+
injectedDetail = {
|
|
1431
|
+
provider: injected_1,
|
|
1432
|
+
info: injectedProviderInfo
|
|
1433
|
+
};
|
|
1434
|
+
// Cache the detected injected provider detail
|
|
1435
|
+
this._injectedProviderDetail = injectedDetail;
|
|
1436
|
+
// Merge with existing providers instead of overwriting
|
|
1437
|
+
this.safeAddProviderDetail(injectedDetail);
|
|
1438
|
+
}
|
|
924
1439
|
return [2 /*return*/, this._providers];
|
|
925
1440
|
}
|
|
926
|
-
|
|
927
|
-
|
|
1441
|
+
uniqueProviders = providers.filter(function (detail) {
|
|
1442
|
+
var provider = detail === null || detail === void 0 ? void 0 : detail.provider;
|
|
1443
|
+
return provider && !_this._seenProviders.has(provider);
|
|
1444
|
+
});
|
|
1445
|
+
// Add to seen providers and instances, ensuring no duplicates in _providers
|
|
1446
|
+
for (_i = 0, uniqueProviders_1 = uniqueProviders; _i < uniqueProviders_1.length; _i++) {
|
|
1447
|
+
detail = uniqueProviders_1[_i];
|
|
1448
|
+
this.safeAddProviderDetail(detail);
|
|
1449
|
+
}
|
|
1450
|
+
return [2 /*return*/, this._providers];
|
|
928
1451
|
});
|
|
929
1452
|
});
|
|
930
1453
|
};
|
|
@@ -937,16 +1460,16 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
937
1460
|
});
|
|
938
1461
|
FormoAnalytics.prototype.detectWallets = function (providers) {
|
|
939
1462
|
return __awaiter(this, void 0, void 0, function () {
|
|
940
|
-
var _i,
|
|
1463
|
+
var _i, providers_2, eip6963ProviderDetail, err_2;
|
|
941
1464
|
return __generator(this, function (_a) {
|
|
942
1465
|
switch (_a.label) {
|
|
943
1466
|
case 0:
|
|
944
1467
|
_a.trys.push([0, 5, , 6]);
|
|
945
|
-
_i = 0,
|
|
1468
|
+
_i = 0, providers_2 = providers;
|
|
946
1469
|
_a.label = 1;
|
|
947
1470
|
case 1:
|
|
948
|
-
if (!(_i <
|
|
949
|
-
eip6963ProviderDetail =
|
|
1471
|
+
if (!(_i < providers_2.length)) return [3 /*break*/, 4];
|
|
1472
|
+
eip6963ProviderDetail = providers_2[_i];
|
|
950
1473
|
return [4 /*yield*/, this.detect({
|
|
951
1474
|
providerName: eip6963ProviderDetail === null || eip6963ProviderDetail === void 0 ? void 0 : eip6963ProviderDetail.info.name,
|
|
952
1475
|
rdns: eip6963ProviderDetail === null || eip6963ProviderDetail === void 0 ? void 0 : eip6963ProviderDetail.info.rdns,
|
|
@@ -976,7 +1499,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
976
1499
|
});
|
|
977
1500
|
FormoAnalytics.prototype.getAddress = function (provider) {
|
|
978
1501
|
return __awaiter(this, void 0, void 0, function () {
|
|
979
|
-
var p, accounts,
|
|
1502
|
+
var p, accounts, err_3, code;
|
|
980
1503
|
return __generator(this, function (_a) {
|
|
981
1504
|
switch (_a.label) {
|
|
982
1505
|
case 0:
|
|
@@ -994,15 +1517,15 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
994
1517
|
case 2:
|
|
995
1518
|
accounts = _a.sent();
|
|
996
1519
|
if (accounts && accounts.length > 0) {
|
|
997
|
-
|
|
998
|
-
if (validAddress) {
|
|
999
|
-
return [2 /*return*/, (0, utils_1.toChecksumAddress)(validAddress)];
|
|
1000
|
-
}
|
|
1520
|
+
return [2 /*return*/, this.validateAndChecksumAddress(accounts[0]) || null];
|
|
1001
1521
|
}
|
|
1002
1522
|
return [3 /*break*/, 4];
|
|
1003
1523
|
case 3:
|
|
1004
1524
|
err_3 = _a.sent();
|
|
1005
|
-
|
|
1525
|
+
code = err_3 === null || err_3 === void 0 ? void 0 : err_3.code;
|
|
1526
|
+
if (code !== 4001) {
|
|
1527
|
+
lib_1.logger.error("FormoAnalytics::getAccounts: eth_accounts threw an error", err_3);
|
|
1528
|
+
}
|
|
1006
1529
|
return [2 /*return*/, null];
|
|
1007
1530
|
case 4: return [2 /*return*/, null];
|
|
1008
1531
|
}
|
|
@@ -1011,7 +1534,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1011
1534
|
};
|
|
1012
1535
|
FormoAnalytics.prototype.getAccounts = function (provider) {
|
|
1013
1536
|
return __awaiter(this, void 0, void 0, function () {
|
|
1014
|
-
var p, res, err_4;
|
|
1537
|
+
var p, res, err_4, code;
|
|
1538
|
+
var _this = this;
|
|
1015
1539
|
return __generator(this, function (_a) {
|
|
1016
1540
|
switch (_a.label) {
|
|
1017
1541
|
case 0:
|
|
@@ -1027,12 +1551,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1027
1551
|
if (!res || res.length === 0)
|
|
1028
1552
|
return [2 /*return*/, null];
|
|
1029
1553
|
return [2 /*return*/, res
|
|
1030
|
-
.map(function (e) { return
|
|
1031
|
-
.filter(function (e) { return e !==
|
|
1032
|
-
.map(utils_1.toChecksumAddress)];
|
|
1554
|
+
.map(function (e) { return _this.validateAndChecksumAddress(e); })
|
|
1555
|
+
.filter(function (e) { return e !== undefined; })];
|
|
1033
1556
|
case 3:
|
|
1034
1557
|
err_4 = _a.sent();
|
|
1035
|
-
|
|
1558
|
+
code = err_4 === null || err_4 === void 0 ? void 0 : err_4.code;
|
|
1559
|
+
if (code !== 4001) {
|
|
1036
1560
|
lib_1.logger.error("FormoAnalytics::getAccounts: eth_accounts threw an error", err_4);
|
|
1037
1561
|
}
|
|
1038
1562
|
return [2 /*return*/, null];
|
|
@@ -1041,31 +1565,32 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1041
1565
|
});
|
|
1042
1566
|
});
|
|
1043
1567
|
};
|
|
1044
|
-
FormoAnalytics.prototype.getCurrentChainId = function () {
|
|
1568
|
+
FormoAnalytics.prototype.getCurrentChainId = function (provider) {
|
|
1045
1569
|
return __awaiter(this, void 0, void 0, function () {
|
|
1046
|
-
var chainIdHex, err_5;
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
switch (_b.label) {
|
|
1570
|
+
var p, chainIdHex, err_5;
|
|
1571
|
+
return __generator(this, function (_a) {
|
|
1572
|
+
switch (_a.label) {
|
|
1050
1573
|
case 0:
|
|
1051
|
-
|
|
1574
|
+
p = provider || this.provider;
|
|
1575
|
+
if (!p) {
|
|
1052
1576
|
lib_1.logger.error("Provider not set for chain ID");
|
|
1577
|
+
return [2 /*return*/, 0];
|
|
1053
1578
|
}
|
|
1054
|
-
|
|
1579
|
+
_a.label = 1;
|
|
1055
1580
|
case 1:
|
|
1056
|
-
|
|
1057
|
-
return [4 /*yield*/,
|
|
1581
|
+
_a.trys.push([1, 3, , 4]);
|
|
1582
|
+
return [4 /*yield*/, p.request({
|
|
1058
1583
|
method: "eth_chainId",
|
|
1059
|
-
})
|
|
1584
|
+
})];
|
|
1060
1585
|
case 2:
|
|
1061
|
-
chainIdHex =
|
|
1586
|
+
chainIdHex = _a.sent();
|
|
1062
1587
|
if (!chainIdHex) {
|
|
1063
1588
|
lib_1.logger.info("Chain id not found");
|
|
1064
1589
|
return [2 /*return*/, 0];
|
|
1065
1590
|
}
|
|
1066
1591
|
return [2 /*return*/, (0, chain_1.parseChainId)(chainIdHex)];
|
|
1067
1592
|
case 3:
|
|
1068
|
-
err_5 =
|
|
1593
|
+
err_5 = _a.sent();
|
|
1069
1594
|
lib_1.logger.error("eth_chainId threw an error:", err_5);
|
|
1070
1595
|
return [2 /*return*/, 0];
|
|
1071
1596
|
case 4: return [2 /*return*/];
|
|
@@ -1073,17 +1598,18 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1073
1598
|
});
|
|
1074
1599
|
});
|
|
1075
1600
|
};
|
|
1076
|
-
FormoAnalytics.prototype.buildSignatureEventPayload = function (method, params, response) {
|
|
1601
|
+
FormoAnalytics.prototype.buildSignatureEventPayload = function (method, params, response, chainId) {
|
|
1602
|
+
var _a;
|
|
1077
1603
|
var rawAddress = method === "personal_sign"
|
|
1078
1604
|
? params[1]
|
|
1079
1605
|
: params[0];
|
|
1080
|
-
var validAddress =
|
|
1606
|
+
var validAddress = this.validateAndChecksumAddress(rawAddress);
|
|
1081
1607
|
if (!validAddress) {
|
|
1082
1608
|
throw new Error("Invalid address in signature payload: ".concat(rawAddress));
|
|
1083
1609
|
}
|
|
1084
1610
|
var basePayload = {
|
|
1085
|
-
chainId: this.currentChainId,
|
|
1086
|
-
address:
|
|
1611
|
+
chainId: (_a = chainId !== null && chainId !== void 0 ? chainId : this.currentChainId) !== null && _a !== void 0 ? _a : undefined,
|
|
1612
|
+
address: validAddress,
|
|
1087
1613
|
};
|
|
1088
1614
|
if (method === "personal_sign") {
|
|
1089
1615
|
var message = Buffer.from(params[0].slice(2), "hex").toString("utf8");
|
|
@@ -1091,7 +1617,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1091
1617
|
}
|
|
1092
1618
|
return __assign(__assign(__assign({}, basePayload), { message: params[1] }), (response ? { signatureHash: response } : {}));
|
|
1093
1619
|
};
|
|
1094
|
-
FormoAnalytics.prototype.buildTransactionEventPayload = function (params) {
|
|
1620
|
+
FormoAnalytics.prototype.buildTransactionEventPayload = function (params, provider) {
|
|
1095
1621
|
return __awaiter(this, void 0, void 0, function () {
|
|
1096
1622
|
var _a, data, from, to, value, validAddress, _b;
|
|
1097
1623
|
var _c;
|
|
@@ -1099,20 +1625,20 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1099
1625
|
switch (_d.label) {
|
|
1100
1626
|
case 0:
|
|
1101
1627
|
_a = params[0], data = _a.data, from = _a.from, to = _a.to, value = _a.value;
|
|
1102
|
-
validAddress =
|
|
1628
|
+
validAddress = this.validateAndChecksumAddress(from);
|
|
1103
1629
|
if (!validAddress) {
|
|
1104
1630
|
throw new Error("Invalid address in transaction payload: ".concat(from));
|
|
1105
1631
|
}
|
|
1106
1632
|
_c = {};
|
|
1107
1633
|
_b = this.currentChainId;
|
|
1108
1634
|
if (_b) return [3 /*break*/, 2];
|
|
1109
|
-
return [4 /*yield*/, this.getCurrentChainId()];
|
|
1635
|
+
return [4 /*yield*/, this.getCurrentChainId(provider)];
|
|
1110
1636
|
case 1:
|
|
1111
1637
|
_b = (_d.sent());
|
|
1112
1638
|
_d.label = 2;
|
|
1113
1639
|
case 2: return [2 /*return*/, (_c.chainId = _b,
|
|
1114
1640
|
_c.data = data,
|
|
1115
|
-
_c.address =
|
|
1641
|
+
_c.address = validAddress,
|
|
1116
1642
|
_c.to = to,
|
|
1117
1643
|
_c.value = value,
|
|
1118
1644
|
_c)];
|
|
@@ -1123,19 +1649,18 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1123
1649
|
/**
|
|
1124
1650
|
* Polls for transaction receipt and emits tx.status = CONFIRMED or REVERTED.
|
|
1125
1651
|
*/
|
|
1126
|
-
FormoAnalytics.prototype.pollTransactionReceipt = function (transactionHash_2, payload_1) {
|
|
1127
|
-
return __awaiter(this, arguments, void 0, function (transactionHash, payload, maxAttempts, intervalMs) {
|
|
1128
|
-
var attempts,
|
|
1652
|
+
FormoAnalytics.prototype.pollTransactionReceipt = function (provider_1, transactionHash_2, payload_1) {
|
|
1653
|
+
return __awaiter(this, arguments, void 0, function (provider, transactionHash, payload, maxAttempts, intervalMs) {
|
|
1654
|
+
var attempts, poll;
|
|
1129
1655
|
var _this = this;
|
|
1130
1656
|
if (maxAttempts === void 0) { maxAttempts = 10; }
|
|
1131
1657
|
if (intervalMs === void 0) { intervalMs = 3000; }
|
|
1132
1658
|
return __generator(this, function (_a) {
|
|
1133
1659
|
attempts = 0;
|
|
1134
|
-
provider = this.provider;
|
|
1135
1660
|
if (!provider)
|
|
1136
1661
|
return [2 /*return*/];
|
|
1137
1662
|
poll = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1138
|
-
var receipt,
|
|
1663
|
+
var receipt, e_9;
|
|
1139
1664
|
return __generator(this, function (_a) {
|
|
1140
1665
|
switch (_a.label) {
|
|
1141
1666
|
case 0:
|
|
@@ -1159,8 +1684,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1159
1684
|
}
|
|
1160
1685
|
return [3 /*break*/, 3];
|
|
1161
1686
|
case 2:
|
|
1162
|
-
|
|
1163
|
-
lib_1.logger.error("Error polling transaction receipt",
|
|
1687
|
+
e_9 = _a.sent();
|
|
1688
|
+
lib_1.logger.error("Error polling transaction receipt", e_9);
|
|
1164
1689
|
return [3 /*break*/, 3];
|
|
1165
1690
|
case 3:
|
|
1166
1691
|
attempts++;
|
|
@@ -1176,6 +1701,122 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1176
1701
|
});
|
|
1177
1702
|
});
|
|
1178
1703
|
};
|
|
1704
|
+
FormoAnalytics.prototype.removeProviderListeners = function (provider) {
|
|
1705
|
+
var listeners = this._providerListenersMap.get(provider);
|
|
1706
|
+
if (!listeners)
|
|
1707
|
+
return;
|
|
1708
|
+
for (var _i = 0, _a = Object.entries(listeners); _i < _a.length; _i++) {
|
|
1709
|
+
var _b = _a[_i], event_1 = _b[0], fn = _b[1];
|
|
1710
|
+
try {
|
|
1711
|
+
provider.removeListener(event_1, fn);
|
|
1712
|
+
}
|
|
1713
|
+
catch (e) {
|
|
1714
|
+
lib_1.logger.warn("Failed to remove listener for ".concat(String(event_1)), e);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
this._providerListenersMap.delete(provider);
|
|
1718
|
+
};
|
|
1719
|
+
// Explicitly untrack a provider: remove listeners, clear wrapper flag and tracking
|
|
1720
|
+
FormoAnalytics.prototype.untrackProvider = function (provider) {
|
|
1721
|
+
try {
|
|
1722
|
+
this.removeProviderListeners(provider);
|
|
1723
|
+
this._trackedProviders.delete(provider);
|
|
1724
|
+
if (this._provider === provider) {
|
|
1725
|
+
this._provider = undefined;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
catch (e) {
|
|
1729
|
+
lib_1.logger.warn("Failed to untrack provider", e);
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1732
|
+
// Debug/monitoring helpers
|
|
1733
|
+
FormoAnalytics.prototype.getTrackedProvidersCount = function () {
|
|
1734
|
+
return this._trackedProviders.size;
|
|
1735
|
+
};
|
|
1736
|
+
/**
|
|
1737
|
+
* Get current provider state for debugging
|
|
1738
|
+
* @returns Object containing current provider state information
|
|
1739
|
+
*/
|
|
1740
|
+
FormoAnalytics.prototype.getProviderState = function () {
|
|
1741
|
+
return {
|
|
1742
|
+
totalProviders: this._providers.length,
|
|
1743
|
+
trackedProviders: this._trackedProviders.size,
|
|
1744
|
+
seenProviders: this._seenProviders.size,
|
|
1745
|
+
activeProvider: !!this._provider,
|
|
1746
|
+
};
|
|
1747
|
+
};
|
|
1748
|
+
/**
|
|
1749
|
+
* Clean up providers that are no longer available
|
|
1750
|
+
* This helps maintain consistent state and prevents memory leaks
|
|
1751
|
+
*/
|
|
1752
|
+
FormoAnalytics.prototype.cleanupUnavailableProviders = function () {
|
|
1753
|
+
// Remove providers that are no longer in the current providers list
|
|
1754
|
+
var currentProviderInstances = new Set(this._providers.map(function (detail) { return detail.provider; }));
|
|
1755
|
+
for (var _i = 0, _a = Array.from(this._trackedProviders); _i < _a.length; _i++) {
|
|
1756
|
+
var provider = _a[_i];
|
|
1757
|
+
if (!currentProviderInstances.has(provider)) {
|
|
1758
|
+
lib_1.logger.info("Cleaning up unavailable provider: ".concat(provider.constructor.name));
|
|
1759
|
+
this.untrackProvider(provider);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
/**
|
|
1764
|
+
* Helper method to check if a provider is already wrapped
|
|
1765
|
+
* @param provider The provider to check
|
|
1766
|
+
* @param currentRequest The current request function
|
|
1767
|
+
* @returns true if the provider is already wrapped
|
|
1768
|
+
*/
|
|
1769
|
+
FormoAnalytics.prototype.isProviderAlreadyWrapped = function (provider, currentRequest) {
|
|
1770
|
+
return !!(currentRequest &&
|
|
1771
|
+
typeof currentRequest === 'function' &&
|
|
1772
|
+
currentRequest[types_1.WRAPPED_REQUEST_SYMBOL] &&
|
|
1773
|
+
provider[types_1.WRAPPED_REQUEST_REF_SYMBOL] === currentRequest);
|
|
1774
|
+
};
|
|
1775
|
+
/**
|
|
1776
|
+
* Handle provider mismatch by switching to the new provider and invalidating old tokens
|
|
1777
|
+
* @param provider The new provider to switch to
|
|
1778
|
+
*/
|
|
1779
|
+
FormoAnalytics.prototype.handleProviderMismatch = function (provider) {
|
|
1780
|
+
// If this is a different provider, allow the switch
|
|
1781
|
+
if (this._provider) {
|
|
1782
|
+
// Clear any provider-specific state when switching
|
|
1783
|
+
this.currentChainId = undefined;
|
|
1784
|
+
this.currentAddress = undefined;
|
|
1785
|
+
}
|
|
1786
|
+
this._provider = provider;
|
|
1787
|
+
};
|
|
1788
|
+
/**
|
|
1789
|
+
* Helper method to validate and checksum an address
|
|
1790
|
+
* @param address The address to validate and checksum
|
|
1791
|
+
* @returns The checksummed address or undefined if invalid
|
|
1792
|
+
*/
|
|
1793
|
+
FormoAnalytics.prototype.validateAndChecksumAddress = function (address) {
|
|
1794
|
+
var validAddress = (0, address_1.getValidAddress)(address);
|
|
1795
|
+
return validAddress ? (0, utils_1.toChecksumAddress)(validAddress) : undefined;
|
|
1796
|
+
};
|
|
1797
|
+
/**
|
|
1798
|
+
* Helper method to safely add a provider detail to _providers array, ensuring no duplicates
|
|
1799
|
+
* @param detail The provider detail to add
|
|
1800
|
+
* @returns true if the provider was added, false if it was already present
|
|
1801
|
+
*/
|
|
1802
|
+
FormoAnalytics.prototype.safeAddProviderDetail = function (detail) {
|
|
1803
|
+
var provider = detail === null || detail === void 0 ? void 0 : detail.provider;
|
|
1804
|
+
if (!provider)
|
|
1805
|
+
return false;
|
|
1806
|
+
// Check if provider already exists in _providers array
|
|
1807
|
+
var alreadyExists = this._providers.some(function (existing) { return existing.provider === provider; });
|
|
1808
|
+
if (!alreadyExists) {
|
|
1809
|
+
// Add to providers array and mark as seen
|
|
1810
|
+
this._providers = __spreadArray(__spreadArray([], this._providers, true), [detail], false);
|
|
1811
|
+
this._seenProviders.add(provider);
|
|
1812
|
+
return true;
|
|
1813
|
+
}
|
|
1814
|
+
else {
|
|
1815
|
+
// Ensure provider is marked as seen even if it already exists in _providers
|
|
1816
|
+
this._seenProviders.add(provider);
|
|
1817
|
+
return false;
|
|
1818
|
+
}
|
|
1819
|
+
};
|
|
1179
1820
|
return FormoAnalytics;
|
|
1180
1821
|
}());
|
|
1181
1822
|
exports.FormoAnalytics = FormoAnalytics;
|