@formo/analytics 1.29.0 → 1.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/src/FormoAnalytics.d.ts +52 -3
- package/dist/cjs/src/FormoAnalytics.js +262 -51
- package/dist/cjs/src/constants/base.d.ts +9 -0
- package/dist/cjs/src/constants/base.js +10 -1
- package/dist/cjs/src/constants/config.d.ts +3 -58
- package/dist/cjs/src/constants/config.js +3 -73
- package/dist/cjs/src/event/EventFactory.d.ts +1 -1
- package/dist/cjs/src/event/EventFactory.js +12 -6
- package/dist/cjs/src/event/EventManager.d.ts +2 -0
- package/dist/cjs/src/event/EventManager.js +4 -0
- package/dist/cjs/src/event/type.d.ts +1 -0
- package/dist/cjs/src/event/utils.js +1 -1
- package/dist/cjs/src/queue/EventQueue.d.ts +8 -0
- package/dist/cjs/src/queue/EventQueue.js +52 -6
- package/dist/cjs/src/queue/type.d.ts +1 -0
- package/dist/cjs/src/session/index.js +16 -8
- package/dist/cjs/src/storage/cookiePolicy.d.ts +16 -0
- package/dist/cjs/src/storage/cookiePolicy.js +19 -0
- package/dist/cjs/src/types/base.d.ts +0 -1
- package/dist/cjs/src/types/events.d.ts +0 -1
- package/dist/cjs/src/version.d.ts +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/cjs/src/wagmi/WagmiEventHandler.js +38 -15
- package/dist/esm/src/FormoAnalytics.d.ts +52 -3
- package/dist/esm/src/FormoAnalytics.js +265 -54
- package/dist/esm/src/constants/base.d.ts +9 -0
- package/dist/esm/src/constants/base.js +9 -0
- package/dist/esm/src/constants/config.d.ts +3 -58
- package/dist/esm/src/constants/config.js +3 -73
- package/dist/esm/src/event/EventFactory.d.ts +1 -1
- package/dist/esm/src/event/EventFactory.js +12 -6
- package/dist/esm/src/event/EventManager.d.ts +2 -0
- package/dist/esm/src/event/EventManager.js +4 -0
- package/dist/esm/src/event/type.d.ts +1 -0
- package/dist/esm/src/event/utils.js +2 -2
- package/dist/esm/src/queue/EventQueue.d.ts +8 -0
- package/dist/esm/src/queue/EventQueue.js +52 -6
- package/dist/esm/src/queue/type.d.ts +1 -0
- package/dist/esm/src/session/index.js +16 -8
- package/dist/esm/src/storage/cookiePolicy.d.ts +16 -0
- package/dist/esm/src/storage/cookiePolicy.js +18 -0
- package/dist/esm/src/types/base.d.ts +0 -1
- package/dist/esm/src/types/events.d.ts +0 -1
- package/dist/esm/src/version.d.ts +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/esm/src/wagmi/WagmiEventHandler.js +38 -15
- package/dist/index.umd.min.js +1 -1
- package/package.json +13 -23
|
@@ -55,9 +55,9 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
55
55
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
56
56
|
};
|
|
57
57
|
import { createStore } from "mipd";
|
|
58
|
-
import { EVENTS_API_HOST, EventType, LOCAL_ANONYMOUS_ID_KEY, SESSION_USER_ID_KEY, CONSENT_OPT_OUT_KEY, } from "./constants";
|
|
59
|
-
import { cookie, initStorageManager } from "./storage";
|
|
60
|
-
import { getIdentityCookieDomain } from "./storage/cookiePolicy";
|
|
58
|
+
import { EVENTS_API_HOST, EventType, LOCAL_ANONYMOUS_ID_KEY, SESSION_USER_ID_KEY, SESSION_TRAFFIC_SOURCE_KEY, ACTIVE_WALLET_KEY, ACTIVE_WALLET_TTL_MS, CONSENT_OPT_OUT_KEY, } from "./constants";
|
|
59
|
+
import { cookie, session, initStorageManager } from "./storage";
|
|
60
|
+
import { getIdentityCookieDomain, getIdentityCookieSecurity, } from "./storage/cookiePolicy";
|
|
61
61
|
import { EventManager } from "./event";
|
|
62
62
|
import { EventQueue } from "./queue";
|
|
63
63
|
import { logger, Logger } from "./logger";
|
|
@@ -82,6 +82,7 @@ var PROVIDER_SWITCH_REASONS = {
|
|
|
82
82
|
var FormoAnalytics = /** @class */ (function () {
|
|
83
83
|
function FormoAnalytics(writeKey, options) {
|
|
84
84
|
if (options === void 0) { options = {}; }
|
|
85
|
+
var _this = this;
|
|
85
86
|
var _a, _b, _c;
|
|
86
87
|
this.writeKey = writeKey;
|
|
87
88
|
this.options = options;
|
|
@@ -121,6 +122,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
121
122
|
this.isEvmDisabled = false;
|
|
122
123
|
/** In-memory URL used to deduplicate SPA pageview events. */
|
|
123
124
|
this._currentUrl = "";
|
|
125
|
+
this._pageHooksDisposed = false;
|
|
124
126
|
this.currentUserId = "";
|
|
125
127
|
this.config = {
|
|
126
128
|
writeKey: writeKey,
|
|
@@ -156,6 +158,10 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
156
158
|
maxQueueSize: options.maxQueueSize,
|
|
157
159
|
flushInterval: options.flushInterval,
|
|
158
160
|
errorHandler: options.errorHandler,
|
|
161
|
+
// Hard consent gate at the queue boundary: nothing buffered is
|
|
162
|
+
// ever sent once the user has opted out, even via a timer or
|
|
163
|
+
// pagehide flush scheduled before opt-out.
|
|
164
|
+
canSend: function () { return !_this.hasOptedOutTracking(); },
|
|
159
165
|
}), options);
|
|
160
166
|
// Check consent status on initialization
|
|
161
167
|
if (this.hasOptedOutTracking()) {
|
|
@@ -188,6 +194,10 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
188
194
|
this.solanaManager = new SolanaManager(this, options.solana);
|
|
189
195
|
}
|
|
190
196
|
this._currentUrl = window.location.href;
|
|
197
|
+
// Seed currentAddress/currentChainId from the persisted snapshot before
|
|
198
|
+
// the first page hit queues so reload-time track()/page() carry the
|
|
199
|
+
// wallet even before wagmi/EIP-1193 reconnection completes.
|
|
200
|
+
this.loadActiveWallet();
|
|
191
201
|
this.trackPageHit();
|
|
192
202
|
this.trackPageHits();
|
|
193
203
|
}
|
|
@@ -289,10 +299,25 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
289
299
|
*/
|
|
290
300
|
FormoAnalytics.prototype.reset = function () {
|
|
291
301
|
this.currentUserId = undefined;
|
|
302
|
+
// Clear in-memory wallet identity too. Without this, a logout/reset
|
|
303
|
+
// (also triggered by optOutTracking) still leaks the previous wallet
|
|
304
|
+
// address on subsequent track()/page() events for the rest of the
|
|
305
|
+
// page lifetime, because they fall back to currentAddress. Keep the
|
|
306
|
+
// EVM provider reference so tracking can resume on the next connect.
|
|
307
|
+
this.currentAddress = undefined;
|
|
308
|
+
this.currentChainId = undefined;
|
|
309
|
+
var evmProvider = this._chainState.evm.provider;
|
|
310
|
+
this._chainState = { evm: { provider: evmProvider }, solana: {} };
|
|
311
|
+
this._activeNamespace = undefined;
|
|
292
312
|
cookie().remove(LOCAL_ANONYMOUS_ID_KEY);
|
|
293
313
|
cookie().remove(SESSION_USER_ID_KEY);
|
|
294
314
|
cookie().remove(SESSION_WALLET_DETECTED_KEY);
|
|
295
315
|
cookie().remove(SESSION_WALLET_IDENTIFIED_KEY);
|
|
316
|
+
cookie().remove(ACTIVE_WALLET_KEY);
|
|
317
|
+
// Stored traffic-source attribution (referrer/UTM) is tracking data;
|
|
318
|
+
// clear it too so reset()/optOutTracking() don't leave it to be
|
|
319
|
+
// re-attached to the next session's events.
|
|
320
|
+
session().remove(SESSION_TRAFFIC_SOURCE_KEY);
|
|
296
321
|
};
|
|
297
322
|
/**
|
|
298
323
|
* Clean up resources and event listeners
|
|
@@ -301,6 +326,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
301
326
|
*/
|
|
302
327
|
FormoAnalytics.prototype.cleanup = function () {
|
|
303
328
|
logger.debug("FormoAnalytics: Cleaning up resources");
|
|
329
|
+
// Drop buffered events so a torn-down instance can't flush later.
|
|
330
|
+
this.eventManager.clear();
|
|
304
331
|
// Clean up Wagmi handler if present
|
|
305
332
|
if (this.wagmiHandler) {
|
|
306
333
|
this.wagmiHandler.cleanup();
|
|
@@ -318,6 +345,21 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
318
345
|
this.untrackProvider(provider);
|
|
319
346
|
}
|
|
320
347
|
}
|
|
348
|
+
// Tear down page-hit hooks: remove window listeners and silence the
|
|
349
|
+
// history.pushState/replaceState wrappers so an orphaned instance (e.g.
|
|
350
|
+
// from a re-mount in React Strict Mode / HMR) stops emitting page events
|
|
351
|
+
// with stale state.
|
|
352
|
+
this._pageHooksDisposed = true;
|
|
353
|
+
if (typeof window !== "undefined") {
|
|
354
|
+
if (this._onPopStateListener) {
|
|
355
|
+
window.removeEventListener("popstate", this._onPopStateListener);
|
|
356
|
+
this._onPopStateListener = undefined;
|
|
357
|
+
}
|
|
358
|
+
if (this._onLocationChangeListener) {
|
|
359
|
+
window.removeEventListener("locationchange", this._onLocationChangeListener);
|
|
360
|
+
this._onLocationChangeListener = undefined;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
321
363
|
logger.debug("FormoAnalytics: Cleanup complete");
|
|
322
364
|
};
|
|
323
365
|
/**
|
|
@@ -449,7 +491,6 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
449
491
|
* @param {ChainID} params.chainId
|
|
450
492
|
* @param {Address} params.address
|
|
451
493
|
* @param {string} params.message
|
|
452
|
-
* @param {string} params.signatureHash - only provided if status is confirmed
|
|
453
494
|
* @param {IFormoEventProperties} properties
|
|
454
495
|
* @param {IFormoEventContext} context
|
|
455
496
|
* @param {(...args: unknown[]) => void} callback
|
|
@@ -457,10 +498,15 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
457
498
|
*/
|
|
458
499
|
FormoAnalytics.prototype.signature = function (_a, properties_1, context_1, callback_1) {
|
|
459
500
|
return __awaiter(this, arguments, void 0, function (_b, properties, context, callback) {
|
|
460
|
-
var status = _b.status, chainId = _b.chainId, address = _b.address, message = _b.message
|
|
501
|
+
var status = _b.status, chainId = _b.chainId, address = _b.address, message = _b.message;
|
|
461
502
|
return __generator(this, function (_c) {
|
|
462
503
|
switch (_c.label) {
|
|
463
|
-
case 0: return [4 /*yield*/, this.trackEvent(EventType.SIGNATURE,
|
|
504
|
+
case 0: return [4 /*yield*/, this.trackEvent(EventType.SIGNATURE, {
|
|
505
|
+
status: status,
|
|
506
|
+
chainId: chainId,
|
|
507
|
+
address: address,
|
|
508
|
+
message: message,
|
|
509
|
+
}, properties, context, callback)];
|
|
464
510
|
case 1:
|
|
465
511
|
_c.sent();
|
|
466
512
|
return [2 /*return*/];
|
|
@@ -531,6 +577,13 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
531
577
|
switch (_d.label) {
|
|
532
578
|
case 0:
|
|
533
579
|
_d.trys.push([0, 12, , 13]);
|
|
580
|
+
// identify() writes the user-id cookie and marks wallet
|
|
581
|
+
// identification before trackEvent's consent check — gate the
|
|
582
|
+
// whole method so an opted-out user gets no identity persistence.
|
|
583
|
+
if (this.hasOptedOutTracking()) {
|
|
584
|
+
logger.info("identify() skipped: user has opted out of tracking");
|
|
585
|
+
return [2 /*return*/];
|
|
586
|
+
}
|
|
534
587
|
if (!!params) return [3 /*break*/, 10];
|
|
535
588
|
// If no params provided, auto-identify
|
|
536
589
|
logger.info("Auto-identifying with providers:", this._providers.map(function (p) { return p.info.name; }));
|
|
@@ -597,6 +650,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
597
650
|
validAddress = validateAddress(address);
|
|
598
651
|
if (validAddress) {
|
|
599
652
|
this.currentAddress = validAddress;
|
|
653
|
+
this.persistActiveWallet();
|
|
600
654
|
}
|
|
601
655
|
else {
|
|
602
656
|
(_c = logger.warn) === null || _c === void 0 ? void 0 : _c.call(logger, "Invalid address provided to identify:", address);
|
|
@@ -605,7 +659,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
605
659
|
if (userId) {
|
|
606
660
|
this.currentUserId = userId;
|
|
607
661
|
domain = getIdentityCookieDomain(this.crossSubdomainCookies);
|
|
608
|
-
cookie().set(SESSION_USER_ID_KEY, userId, __assign({ path: "/" }, (domain ? { domain: domain } : {})));
|
|
662
|
+
cookie().set(SESSION_USER_ID_KEY, userId, __assign(__assign({ path: "/" }, getIdentityCookieSecurity()), (domain ? { domain: domain } : {})));
|
|
609
663
|
}
|
|
610
664
|
isAlreadyIdentified = this.session.isWalletIdentified(validAddress, rdns || "");
|
|
611
665
|
logger.debug("Identify: Checking deduplication", {
|
|
@@ -654,6 +708,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
654
708
|
return __generator(this, function (_c) {
|
|
655
709
|
switch (_c.label) {
|
|
656
710
|
case 0:
|
|
711
|
+
// detect() marks wallet detection (a cookie write) before
|
|
712
|
+
// trackEvent's consent check — gate it on opt-out.
|
|
713
|
+
if (this.hasOptedOutTracking()) {
|
|
714
|
+
logger.info("detect() skipped: user has opted out of tracking");
|
|
715
|
+
return [2 /*return*/];
|
|
716
|
+
}
|
|
657
717
|
if (this.session.isWalletDetected(rdns))
|
|
658
718
|
return [2 /*return*/, logger.warn("Detect: Wallet ".concat(providerName, " already detected in this session"))];
|
|
659
719
|
this.session.markWalletDetected(rdns);
|
|
@@ -700,6 +760,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
700
760
|
// Set opt-out flag in persistent storage using direct cookie access
|
|
701
761
|
// This must be done before switching storage to ensure persistence
|
|
702
762
|
setConsentFlag(this.writeKey, CONSENT_OPT_OUT_KEY, "true");
|
|
763
|
+
// Drop anything already buffered so a pending timer/pagehide flush
|
|
764
|
+
// cannot ship events after consent withdrawal.
|
|
765
|
+
this.eventManager.clear();
|
|
703
766
|
this.reset();
|
|
704
767
|
logger.info("Successfully opted out of tracking");
|
|
705
768
|
};
|
|
@@ -1450,35 +1513,52 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1450
1513
|
});
|
|
1451
1514
|
};
|
|
1452
1515
|
FormoAnalytics.prototype.trackPageHits = function () {
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1516
|
+
var _this = this;
|
|
1517
|
+
// Install a single, instance-agnostic wrapper around history.pushState /
|
|
1518
|
+
// replaceState so concurrent SDK instances (React Strict Mode, HMR) don't
|
|
1519
|
+
// each stack their own wrapper — which would dispatch N synthetic events
|
|
1520
|
+
// per navigation and produce O(N^2) onLocationChange calls. The wrapper
|
|
1521
|
+
// dispatches once; per-instance bookkeeping is done by per-instance
|
|
1522
|
+
// listeners that each register/unregister themselves.
|
|
1523
|
+
FormoAnalytics.installHistoryHooksOnce();
|
|
1524
|
+
this._onPopStateListener = function () { return _this.onLocationChange(); };
|
|
1525
|
+
this._onLocationChangeListener = function () { return _this.onLocationChange(); };
|
|
1526
|
+
window.addEventListener("popstate", this._onPopStateListener);
|
|
1527
|
+
window.addEventListener("locationchange", this._onLocationChangeListener);
|
|
1528
|
+
};
|
|
1529
|
+
/**
|
|
1530
|
+
* Wrap history.pushState / replaceState exactly once per `history` object,
|
|
1531
|
+
* regardless of how many SDK instances are constructed. Uses a Symbol
|
|
1532
|
+
* marker so we recognize our own wrapper across module reloads in HMR.
|
|
1533
|
+
*/
|
|
1534
|
+
FormoAnalytics.installHistoryHooksOnce = function () {
|
|
1535
|
+
if (typeof history === "undefined" || typeof window === "undefined")
|
|
1536
|
+
return;
|
|
1537
|
+
var marker = Symbol.for("formo.historyWrapped");
|
|
1538
|
+
if (history[marker])
|
|
1539
|
+
return;
|
|
1540
|
+
history[marker] = true;
|
|
1541
|
+
var dispatch = function () { return window.dispatchEvent(new window.Event("locationchange")); };
|
|
1542
|
+
var oldPushState = history.pushState;
|
|
1543
|
+
history.pushState = function pushState() {
|
|
1544
|
+
var args = [];
|
|
1545
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
1546
|
+
args[_i] = arguments[_i];
|
|
1547
|
+
}
|
|
1548
|
+
var ret = oldPushState.apply(this, args);
|
|
1549
|
+
dispatch();
|
|
1550
|
+
return ret;
|
|
1551
|
+
};
|
|
1552
|
+
var oldReplaceState = history.replaceState;
|
|
1553
|
+
history.replaceState = function replaceState() {
|
|
1554
|
+
var args = [];
|
|
1555
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
1556
|
+
args[_i] = arguments[_i];
|
|
1557
|
+
}
|
|
1558
|
+
var ret = oldReplaceState.apply(this, args);
|
|
1559
|
+
dispatch();
|
|
1560
|
+
return ret;
|
|
1561
|
+
};
|
|
1482
1562
|
};
|
|
1483
1563
|
FormoAnalytics.prototype.trackPageHit = function (category, name, properties, context, callback) {
|
|
1484
1564
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -1489,6 +1569,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1489
1569
|
return [2 /*return*/];
|
|
1490
1570
|
}
|
|
1491
1571
|
setTimeout(function () {
|
|
1572
|
+
// Drop in-flight page hits from an SDK instance that was torn down
|
|
1573
|
+
// between scheduling and firing (e.g. provider remount in React Strict
|
|
1574
|
+
// Mode / HMR). Otherwise the orphan instance would queue a page event
|
|
1575
|
+
// here with its stale, never-populated `currentAddress`.
|
|
1576
|
+
if (_this._pageHooksDisposed)
|
|
1577
|
+
return;
|
|
1492
1578
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1493
1579
|
var e_7;
|
|
1494
1580
|
return __generator(this, function (_a) {
|
|
@@ -1896,7 +1982,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1896
1982
|
});
|
|
1897
1983
|
});
|
|
1898
1984
|
};
|
|
1899
|
-
FormoAnalytics.prototype.buildSignatureEventPayload = function (method, params,
|
|
1985
|
+
FormoAnalytics.prototype.buildSignatureEventPayload = function (method, params,
|
|
1986
|
+
// Intentionally not read. Kept for positional call-site arity.
|
|
1987
|
+
_response, chainId) {
|
|
1900
1988
|
var _a;
|
|
1901
1989
|
var rawAddress = method === "personal_sign"
|
|
1902
1990
|
? params[1]
|
|
@@ -1905,45 +1993,63 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1905
1993
|
if (!validAddress) {
|
|
1906
1994
|
throw new Error("Invalid address in signature payload: ".concat(rawAddress));
|
|
1907
1995
|
}
|
|
1996
|
+
var effectiveChainId = (_a = chainId !== null && chainId !== void 0 ? chainId : this._evmChainId) !== null && _a !== void 0 ? _a : undefined;
|
|
1997
|
+
this.backfillActiveWallet(validAddress, effectiveChainId);
|
|
1908
1998
|
var basePayload = {
|
|
1909
|
-
chainId:
|
|
1999
|
+
chainId: effectiveChainId,
|
|
1910
2000
|
address: validAddress,
|
|
1911
2001
|
};
|
|
1912
2002
|
if (method === "personal_sign") {
|
|
1913
2003
|
var message = Buffer.from(params[0].slice(2), "hex").toString("utf8");
|
|
1914
|
-
return __assign(__assign(
|
|
2004
|
+
return __assign(__assign({}, basePayload), { message: message });
|
|
1915
2005
|
}
|
|
1916
|
-
|
|
2006
|
+
// eth_signTypedData*: params[1] is the full EIP-712 struct.
|
|
2007
|
+
return __assign(__assign({}, basePayload), { message: params[1] });
|
|
1917
2008
|
};
|
|
1918
2009
|
FormoAnalytics.prototype.buildTransactionEventPayload = function (params, provider) {
|
|
1919
2010
|
return __awaiter(this, void 0, void 0, function () {
|
|
1920
|
-
var _a, data, from, to, value, validAddress, _b;
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
switch (_d.label) {
|
|
2011
|
+
var _a, data, from, to, value, validAddress, chainId, _b;
|
|
2012
|
+
return __generator(this, function (_c) {
|
|
2013
|
+
switch (_c.label) {
|
|
1924
2014
|
case 0:
|
|
1925
2015
|
_a = params[0], data = _a.data, from = _a.from, to = _a.to, value = _a.value;
|
|
1926
2016
|
validAddress = validateAndChecksumAddress(from);
|
|
1927
2017
|
if (!validAddress) {
|
|
1928
2018
|
throw new Error("Invalid address in transaction payload: ".concat(from));
|
|
1929
2019
|
}
|
|
1930
|
-
_c = {};
|
|
1931
2020
|
_b = this._evmChainId;
|
|
1932
2021
|
if (_b) return [3 /*break*/, 2];
|
|
1933
2022
|
return [4 /*yield*/, this.getCurrentChainId(provider)];
|
|
1934
2023
|
case 1:
|
|
1935
|
-
_b = (
|
|
1936
|
-
|
|
1937
|
-
case 2:
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
2024
|
+
_b = (_c.sent());
|
|
2025
|
+
_c.label = 2;
|
|
2026
|
+
case 2:
|
|
2027
|
+
chainId = _b;
|
|
2028
|
+
this.backfillActiveWallet(validAddress, chainId);
|
|
2029
|
+
return [2 /*return*/, {
|
|
2030
|
+
chainId: chainId,
|
|
2031
|
+
data: data,
|
|
2032
|
+
address: validAddress,
|
|
2033
|
+
to: to,
|
|
2034
|
+
value: value,
|
|
2035
|
+
}];
|
|
1943
2036
|
}
|
|
1944
2037
|
});
|
|
1945
2038
|
});
|
|
1946
2039
|
};
|
|
2040
|
+
/**
|
|
2041
|
+
* Persist an EVM address discovered through autocapture (signature / transaction)
|
|
2042
|
+
* as the current EVM address when none is currently set. This lets subsequent
|
|
2043
|
+
* track()/page() calls carry the address even when the underlying wallet never
|
|
2044
|
+
* fires an EIP-1193 `accountsChanged` event (embedded wallets, smart accounts,
|
|
2045
|
+
* social-login wrappers). If `accountsChanged` later fires it overwrites this
|
|
2046
|
+
* value in the normal way; existing connections are never clobbered.
|
|
2047
|
+
*/
|
|
2048
|
+
FormoAnalytics.prototype.backfillActiveWallet = function (address, chainId) {
|
|
2049
|
+
if (this._evmAddress)
|
|
2050
|
+
return;
|
|
2051
|
+
this.setChainState('evm', { address: address, chainId: chainId });
|
|
2052
|
+
};
|
|
1947
2053
|
/**
|
|
1948
2054
|
* Polls for transaction receipt and emits tx.status = CONFIRMED or REVERTED.
|
|
1949
2055
|
*/
|
|
@@ -2014,7 +2120,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2014
2120
|
}
|
|
2015
2121
|
this._providerListenersMap.delete(provider);
|
|
2016
2122
|
};
|
|
2017
|
-
// Explicitly untrack a provider: remove listeners, clear wrapper flag
|
|
2123
|
+
// Explicitly untrack a provider: remove listeners, clear wrapper flag
|
|
2124
|
+
// and tracking
|
|
2018
2125
|
FormoAnalytics.prototype.untrackProvider = function (provider) {
|
|
2019
2126
|
try {
|
|
2020
2127
|
this.removeProviderListeners(provider);
|
|
@@ -2132,6 +2239,42 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2132
2239
|
}
|
|
2133
2240
|
this.syncDerivedState();
|
|
2134
2241
|
};
|
|
2242
|
+
/**
|
|
2243
|
+
* Sync validated wallet/chain state into the SDK's central state
|
|
2244
|
+
* WITHOUT emitting an event.
|
|
2245
|
+
*
|
|
2246
|
+
* Integrations (e.g. the wagmi handler) must call this on every
|
|
2247
|
+
* connect / chain-change / disconnect — even when the corresponding
|
|
2248
|
+
* autocapture event is disabled. Otherwise `currentChainId` stays
|
|
2249
|
+
* stale/undefined and `shouldTrack()`'s `tracking.excludeChains`
|
|
2250
|
+
* check (which keys off `currentChainId`, not the event payload) can
|
|
2251
|
+
* be bypassed, letting wallet activity on an excluded chain still be
|
|
2252
|
+
* collected.
|
|
2253
|
+
*
|
|
2254
|
+
* - valid `address` present → record per-chain + derived state
|
|
2255
|
+
* - `address` absent → clear chain state (disconnect)
|
|
2256
|
+
*/
|
|
2257
|
+
FormoAnalytics.prototype.syncWalletState = function (params) {
|
|
2258
|
+
var chainId = params.chainId, address = params.address;
|
|
2259
|
+
if (!address) {
|
|
2260
|
+
if (chainId !== undefined && chainId !== null) {
|
|
2261
|
+
this.clearChainState(chainId);
|
|
2262
|
+
}
|
|
2263
|
+
else {
|
|
2264
|
+
this.clearChainState("evm");
|
|
2265
|
+
this.clearChainState("solana");
|
|
2266
|
+
}
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
if (chainId === null || chainId === undefined)
|
|
2270
|
+
return;
|
|
2271
|
+
var validAddress = validateAddress(address, chainId);
|
|
2272
|
+
if (!validAddress) {
|
|
2273
|
+
logger.warn("syncWalletState: invalid address (\"".concat(address, "\") for chain ").concat(chainId));
|
|
2274
|
+
return;
|
|
2275
|
+
}
|
|
2276
|
+
this.setChainState(chainId, { address: validAddress });
|
|
2277
|
+
};
|
|
2135
2278
|
/**
|
|
2136
2279
|
* Synchronize currentAddress/currentChainId from the active namespace.
|
|
2137
2280
|
* Last-connected-chain-wins: _activeNamespace takes precedence.
|
|
@@ -2143,6 +2286,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2143
2286
|
if (state.address || state.chainId) {
|
|
2144
2287
|
this.currentAddress = state.address;
|
|
2145
2288
|
this.currentChainId = state.chainId;
|
|
2289
|
+
this.persistActiveWallet();
|
|
2146
2290
|
return;
|
|
2147
2291
|
}
|
|
2148
2292
|
}
|
|
@@ -2153,10 +2297,77 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2153
2297
|
this.currentAddress = otherState.address;
|
|
2154
2298
|
this.currentChainId = otherState.chainId;
|
|
2155
2299
|
this._activeNamespace = other;
|
|
2300
|
+
this.persistActiveWallet();
|
|
2156
2301
|
return;
|
|
2157
2302
|
}
|
|
2158
2303
|
this.currentAddress = undefined;
|
|
2159
2304
|
this.currentChainId = undefined;
|
|
2305
|
+
this.persistActiveWallet();
|
|
2306
|
+
};
|
|
2307
|
+
/**
|
|
2308
|
+
* Persist (or clear) the current wallet snapshot in a cookie so that the
|
|
2309
|
+
* SDK can repopulate `currentAddress`/`currentChainId` at init on the next
|
|
2310
|
+
* page load — closing the gap between page-show and wagmi/EIP-1193
|
|
2311
|
+
* reconnection during which track()/page() events would otherwise ship
|
|
2312
|
+
* with an empty address.
|
|
2313
|
+
*/
|
|
2314
|
+
FormoAnalytics.prototype.persistActiveWallet = function () {
|
|
2315
|
+
try {
|
|
2316
|
+
// Never write an identity cookie for an opted-out user; ensure any
|
|
2317
|
+
// prior snapshot is removed instead.
|
|
2318
|
+
if (this.hasOptedOutTracking()) {
|
|
2319
|
+
cookie().remove(ACTIVE_WALLET_KEY);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
if (this.currentAddress) {
|
|
2323
|
+
var value = JSON.stringify(__assign({ address: this.currentAddress }, (this.currentChainId !== undefined && { chainId: this.currentChainId })));
|
|
2324
|
+
var domain = getIdentityCookieDomain(this.crossSubdomainCookies);
|
|
2325
|
+
cookie().set(ACTIVE_WALLET_KEY, value, __assign(__assign({ path: "/", expires: new Date(Date.now() + ACTIVE_WALLET_TTL_MS).toUTCString() }, getIdentityCookieSecurity()), (domain ? { domain: domain } : {})));
|
|
2326
|
+
}
|
|
2327
|
+
else {
|
|
2328
|
+
cookie().remove(ACTIVE_WALLET_KEY);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
catch (err) {
|
|
2332
|
+
logger.warn("Failed to persist current wallet snapshot", err);
|
|
2333
|
+
}
|
|
2334
|
+
};
|
|
2335
|
+
/**
|
|
2336
|
+
* Seed `currentAddress`/`currentChainId` from the persisted snapshot, if
|
|
2337
|
+
* any. Called once during construction before the first page hit fires.
|
|
2338
|
+
*/
|
|
2339
|
+
FormoAnalytics.prototype.loadActiveWallet = function () {
|
|
2340
|
+
try {
|
|
2341
|
+
// Never restore wallet identity into memory for an opted-out user
|
|
2342
|
+
// (mirrors persistActiveWallet's guard); drop any stale snapshot.
|
|
2343
|
+
if (this.hasOptedOutTracking()) {
|
|
2344
|
+
cookie().remove(ACTIVE_WALLET_KEY);
|
|
2345
|
+
return;
|
|
2346
|
+
}
|
|
2347
|
+
var raw = cookie().get(ACTIVE_WALLET_KEY);
|
|
2348
|
+
if (!raw)
|
|
2349
|
+
return;
|
|
2350
|
+
var parsed = JSON.parse(raw);
|
|
2351
|
+
if (!(parsed === null || parsed === void 0 ? void 0 : parsed.address))
|
|
2352
|
+
return;
|
|
2353
|
+
var namespace = isSolanaChainId(parsed.chainId) ? "solana" : "evm";
|
|
2354
|
+
var validated = validateAddress(parsed.address, parsed.chainId);
|
|
2355
|
+
if (!validated) {
|
|
2356
|
+
cookie().remove(ACTIVE_WALLET_KEY);
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
var ns = this._chainState[namespace];
|
|
2360
|
+
ns.address = validated;
|
|
2361
|
+
if (parsed.chainId !== undefined)
|
|
2362
|
+
ns.chainId = parsed.chainId;
|
|
2363
|
+
this._activeNamespace = namespace;
|
|
2364
|
+
this.currentAddress = validated;
|
|
2365
|
+
this.currentChainId = parsed.chainId;
|
|
2366
|
+
}
|
|
2367
|
+
catch (err) {
|
|
2368
|
+
logger.warn("Failed to restore persisted wallet snapshot", err);
|
|
2369
|
+
cookie().remove(ACTIVE_WALLET_KEY);
|
|
2370
|
+
}
|
|
2160
2371
|
};
|
|
2161
2372
|
/**
|
|
2162
2373
|
* Helper method to clear the active provider state
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
export declare const SESSION_TRAFFIC_SOURCE_KEY = "traffic-source";
|
|
2
2
|
export declare const SESSION_USER_ID_KEY = "user-id";
|
|
3
|
+
/**
|
|
4
|
+
* Persisted snapshot of the currently-active EVM/Solana wallet
|
|
5
|
+
* (address + chainId). Lets the SDK seed `currentAddress`/`currentChainId`
|
|
6
|
+
* at init so the first page hit after a reload carries the address, without
|
|
7
|
+
* having to wait for wagmi/EIP-1193 reconnection to fire.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ACTIVE_WALLET_KEY = "active-wallet";
|
|
10
|
+
/** TTL for the persisted active-wallet snapshot cookie. */
|
|
11
|
+
export declare const ACTIVE_WALLET_TTL_MS: number;
|
|
3
12
|
export declare const LOCAL_ANONYMOUS_ID_KEY = "anonymous-id";
|
|
4
13
|
export declare const CONSENT_OPT_OUT_KEY = "opt-out-tracking";
|
|
5
14
|
export declare const DEFAULT_PROVIDER_ICON = "data:image/svg+xml;base64,";
|
|
@@ -2,6 +2,15 @@ export var SESSION_TRAFFIC_SOURCE_KEY = "traffic-source";
|
|
|
2
2
|
// SESSION_WALLET_DETECTED_KEY and SESSION_WALLET_IDENTIFIED_KEY
|
|
3
3
|
// are now defined in src/session/index.ts
|
|
4
4
|
export var SESSION_USER_ID_KEY = "user-id";
|
|
5
|
+
/**
|
|
6
|
+
* Persisted snapshot of the currently-active EVM/Solana wallet
|
|
7
|
+
* (address + chainId). Lets the SDK seed `currentAddress`/`currentChainId`
|
|
8
|
+
* at init so the first page hit after a reload carries the address, without
|
|
9
|
+
* having to wait for wagmi/EIP-1193 reconnection to fire.
|
|
10
|
+
*/
|
|
11
|
+
export var ACTIVE_WALLET_KEY = "active-wallet";
|
|
12
|
+
/** TTL for the persisted active-wallet snapshot cookie. */
|
|
13
|
+
export var ACTIVE_WALLET_TTL_MS = 24 * 60 * 60 * 1000;
|
|
5
14
|
export var LOCAL_ANONYMOUS_ID_KEY = "anonymous-id";
|
|
6
15
|
// Consent management keys
|
|
7
16
|
export var CONSENT_OPT_OUT_KEY = "opt-out-tracking";
|