@formo/analytics 1.39.0 → 1.40.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 +4 -1
- package/dist/cjs/src/FormoAnalytics.js +47 -32
- package/dist/cjs/src/event/EventFactory.d.ts +9 -1
- package/dist/cjs/src/event/EventFactory.js +31 -16
- package/dist/cjs/src/event/EventManager.d.ts +3 -1
- package/dist/cjs/src/event/EventManager.js +33 -4
- package/dist/cjs/src/event/cancellation.d.ts +4 -0
- package/dist/cjs/src/event/cancellation.js +7 -0
- package/dist/cjs/src/event/type.d.ts +1 -0
- package/dist/cjs/src/event/utils.d.ts +5 -1
- package/dist/cjs/src/event/utils.js +57 -2
- package/dist/cjs/src/evm/EvmEventTracker.d.ts +7 -0
- package/dist/cjs/src/evm/EvmEventTracker.js +31 -5
- package/dist/cjs/src/queue/EventQueue.d.ts +1 -0
- package/dist/cjs/src/queue/EventQueue.js +11 -6
- package/dist/cjs/src/storage/StorageManager.d.ts +2 -0
- package/dist/cjs/src/storage/StorageManager.js +6 -0
- package/dist/cjs/src/storage/index.d.ts +1 -0
- package/dist/cjs/src/storage/index.js +7 -1
- package/dist/cjs/src/version.d.ts +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/esm/src/FormoAnalytics.d.ts +4 -1
- package/dist/esm/src/FormoAnalytics.js +45 -30
- package/dist/esm/src/event/EventFactory.d.ts +9 -1
- package/dist/esm/src/event/EventFactory.js +31 -16
- package/dist/esm/src/event/EventManager.d.ts +3 -1
- package/dist/esm/src/event/EventManager.js +33 -4
- package/dist/esm/src/event/cancellation.d.ts +4 -0
- package/dist/esm/src/event/cancellation.js +4 -0
- package/dist/esm/src/event/type.d.ts +1 -0
- package/dist/esm/src/event/utils.d.ts +5 -1
- package/dist/esm/src/event/utils.js +56 -3
- package/dist/esm/src/evm/EvmEventTracker.d.ts +7 -0
- package/dist/esm/src/evm/EvmEventTracker.js +31 -5
- package/dist/esm/src/queue/EventQueue.d.ts +1 -0
- package/dist/esm/src/queue/EventQueue.js +11 -6
- package/dist/esm/src/storage/StorageManager.d.ts +2 -0
- package/dist/esm/src/storage/StorageManager.js +6 -0
- package/dist/esm/src/storage/index.d.ts +1 -0
- package/dist/esm/src/storage/index.js +5 -0
- package/dist/esm/src/version.d.ts +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +2 -2
|
@@ -270,7 +270,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
270
270
|
};
|
|
271
271
|
/** Stop listening for wallet announcements. Called from SDK teardown. */
|
|
272
272
|
EvmEventTracker.prototype.cleanup = function () {
|
|
273
|
-
var _a;
|
|
273
|
+
var _a, _b;
|
|
274
274
|
// A replay in flight (awaiting the active wallet's accounts) must not
|
|
275
275
|
// resume into a torn-down instance and commit a session there.
|
|
276
276
|
this.disposed = true;
|
|
@@ -280,11 +280,13 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
280
280
|
this.retryRequested = false;
|
|
281
281
|
try {
|
|
282
282
|
(_a = this.unsubscribeDiscovery) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
283
|
+
(_b = this.discoveryStore) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
283
284
|
}
|
|
284
285
|
catch (e) {
|
|
285
286
|
logger_1.logger.warn("Failed to unsubscribe from provider discovery", e);
|
|
286
287
|
}
|
|
287
288
|
this.unsubscribeDiscovery = undefined;
|
|
289
|
+
this.discoveryStore = undefined;
|
|
288
290
|
};
|
|
289
291
|
EvmEventTracker.prototype.sessionGeneration = function (provider) {
|
|
290
292
|
var _a;
|
|
@@ -1018,6 +1020,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1018
1020
|
this.wallet.provider = provider;
|
|
1019
1021
|
}
|
|
1020
1022
|
this.wallet.set('evm', { chainId: nextChainId });
|
|
1023
|
+
this.deps.retryDetection();
|
|
1021
1024
|
_a.label = 1;
|
|
1022
1025
|
case 1:
|
|
1023
1026
|
_a.trys.push([1, 5, , 6]);
|
|
@@ -1335,12 +1338,17 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1335
1338
|
});
|
|
1336
1339
|
});
|
|
1337
1340
|
};
|
|
1341
|
+
/** Whether Formo owns provider lifecycle tracking. */
|
|
1342
|
+
EvmEventTracker.prototype.tracksDiscovered = function () {
|
|
1343
|
+
return !this.deps.isWagmiMode();
|
|
1344
|
+
};
|
|
1338
1345
|
EvmEventTracker.prototype.getProviders = function () {
|
|
1339
1346
|
return __awaiter(this, void 0, void 0, function () {
|
|
1340
1347
|
var store, providers, injected, injectedProviderInfo, injectedDetail, uniqueProviders, _i, uniqueProviders_1, detail;
|
|
1341
1348
|
var _this = this;
|
|
1342
1349
|
return __generator(this, function (_a) {
|
|
1343
1350
|
store = (0, mipd_1.createStore)();
|
|
1351
|
+
this.discoveryStore = store;
|
|
1344
1352
|
providers = store.getProviders();
|
|
1345
1353
|
this.unsubscribeDiscovery = store.subscribe(function (providerDetails) {
|
|
1346
1354
|
providers = providerDetails;
|
|
@@ -1359,8 +1367,12 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1359
1367
|
var p = detail === null || detail === void 0 ? void 0 : detail.provider;
|
|
1360
1368
|
return !!p && !_this.registry.isTracked(p);
|
|
1361
1369
|
});
|
|
1362
|
-
|
|
1370
|
+
// Wagmi detects only providers added by this announcement.
|
|
1371
|
+
var toDetect = _this.tracksDiscovered() ? newDetails : newlyAddedDetails;
|
|
1372
|
+
if (_this.tracksDiscovered() && newDetails.length > 0) {
|
|
1363
1373
|
_this.trackProviders(newDetails);
|
|
1374
|
+
}
|
|
1375
|
+
if (toDetect.length > 0) {
|
|
1364
1376
|
// Detect newly discovered wallets (session de-dupes) with error handling
|
|
1365
1377
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1366
1378
|
var e_3;
|
|
@@ -1368,7 +1380,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1368
1380
|
switch (_a.label) {
|
|
1369
1381
|
case 0:
|
|
1370
1382
|
_a.trys.push([0, 2, , 3]);
|
|
1371
|
-
return [4 /*yield*/, this.detectWallets(
|
|
1383
|
+
return [4 /*yield*/, this.detectWallets(toDetect)];
|
|
1372
1384
|
case 1:
|
|
1373
1385
|
_a.sent();
|
|
1374
1386
|
return [3 /*break*/, 3];
|
|
@@ -1394,7 +1406,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1394
1406
|
if (this.registry.injected &&
|
|
1395
1407
|
this.registry.injected.provider === injected) {
|
|
1396
1408
|
// Ensure it's tracked
|
|
1397
|
-
if (!this.registry.isTracked(injected)) {
|
|
1409
|
+
if (this.tracksDiscovered() && !this.registry.isTracked(injected)) {
|
|
1398
1410
|
this.trackEIP1193Provider(injected);
|
|
1399
1411
|
}
|
|
1400
1412
|
// Merge with existing providers instead of overwriting
|
|
@@ -1402,7 +1414,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1402
1414
|
return [2 /*return*/, this.registry.all];
|
|
1403
1415
|
}
|
|
1404
1416
|
// Re-check if the injected provider is already tracked just before tracking
|
|
1405
|
-
if (!this.registry.isTracked(injected)) {
|
|
1417
|
+
if (this.tracksDiscovered() && !this.registry.isTracked(injected)) {
|
|
1406
1418
|
this.trackEIP1193Provider(injected);
|
|
1407
1419
|
}
|
|
1408
1420
|
injectedProviderInfo = (0, provider_1.detectInjectedProviderInfo)(injected);
|
|
@@ -1462,6 +1474,20 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1462
1474
|
});
|
|
1463
1475
|
});
|
|
1464
1476
|
};
|
|
1477
|
+
EvmEventTracker.prototype.detectableProviders = function () {
|
|
1478
|
+
var _a;
|
|
1479
|
+
var available = new Set();
|
|
1480
|
+
(_a = this.discoveryStore) === null || _a === void 0 ? void 0 : _a.getProviders().forEach(function (detail) {
|
|
1481
|
+
return available.add(detail.provider);
|
|
1482
|
+
});
|
|
1483
|
+
var injected = typeof window !== "undefined" ? window.ethereum : undefined;
|
|
1484
|
+
if (injected)
|
|
1485
|
+
available.add(injected);
|
|
1486
|
+
this.externallyRegistered.forEach(function (provider) { return available.add(provider); });
|
|
1487
|
+
return this.registry.all.filter(function (detail) {
|
|
1488
|
+
return available.has(detail.provider);
|
|
1489
|
+
});
|
|
1490
|
+
};
|
|
1465
1491
|
/**
|
|
1466
1492
|
* Seed a provider's chain from whatever it already exposes synchronously.
|
|
1467
1493
|
*
|
|
@@ -89,6 +89,7 @@ var EventQueue = /** @class */ (function () {
|
|
|
89
89
|
this.queue = [];
|
|
90
90
|
this.queueByteSize = 0; // running total of queued items' byteSize
|
|
91
91
|
this.payloadHashes = new Set();
|
|
92
|
+
this.generation = 0;
|
|
92
93
|
// Terminal shutdown flag. Once set, enqueue() and flush() are no-ops for
|
|
93
94
|
// the rest of this instance's life. See close().
|
|
94
95
|
this.closed = false;
|
|
@@ -222,6 +223,7 @@ var EventQueue = /** @class */ (function () {
|
|
|
222
223
|
* withdrawal / SDK teardown so nothing buffered can be sent later.
|
|
223
224
|
*/
|
|
224
225
|
EventQueue.prototype.clear = function () {
|
|
226
|
+
this.generation++;
|
|
225
227
|
if (this.timer) {
|
|
226
228
|
clearTimeout(this.timer);
|
|
227
229
|
this.timer = null;
|
|
@@ -229,6 +231,8 @@ var EventQueue = /** @class */ (function () {
|
|
|
229
231
|
this.queue = [];
|
|
230
232
|
this.queueByteSize = 0;
|
|
231
233
|
this.payloadHashes.clear();
|
|
234
|
+
this.flushed = false;
|
|
235
|
+
this.pendingFlush = null;
|
|
232
236
|
};
|
|
233
237
|
/**
|
|
234
238
|
* Terminal shutdown. Unlike clear(), which only empties the buffer and can
|
|
@@ -265,11 +269,12 @@ var EventQueue = /** @class */ (function () {
|
|
|
265
269
|
});
|
|
266
270
|
EventQueue.prototype.enqueue = function (event, callback) {
|
|
267
271
|
return __awaiter(this, void 0, void 0, function () {
|
|
268
|
-
var message_id, queueItem, hasReachedFlushAt, hasReachedQueueSize;
|
|
272
|
+
var generation, message_id, queueItem, hasReachedFlushAt, hasReachedQueueSize;
|
|
269
273
|
return __generator(this, function (_a) {
|
|
270
274
|
switch (_a.label) {
|
|
271
275
|
case 0:
|
|
272
276
|
callback = callback || noop;
|
|
277
|
+
generation = this.generation;
|
|
273
278
|
// A torn-down instance must never buffer, however late the caller
|
|
274
279
|
// arrives. See close().
|
|
275
280
|
if (this.closed)
|
|
@@ -282,12 +287,12 @@ var EventQueue = /** @class */ (function () {
|
|
|
282
287
|
return [4 /*yield*/, this.generateMessageId(event)];
|
|
283
288
|
case 1:
|
|
284
289
|
message_id = _a.sent();
|
|
285
|
-
|
|
286
|
-
// suspended here, and on a queue that has not flushed yet its event
|
|
287
|
-
// would push and flush immediately - the exact shape of the bug close()
|
|
288
|
-
// exists to stop.
|
|
289
|
-
if (this.closed)
|
|
290
|
+
if (this.closed || generation !== this.generation)
|
|
290
291
|
return [2 /*return*/];
|
|
292
|
+
if (this.canSend && !this.canSend()) {
|
|
293
|
+
this.clear();
|
|
294
|
+
return [2 /*return*/];
|
|
295
|
+
}
|
|
291
296
|
// check if the message already exists
|
|
292
297
|
if (this.isDuplicate(message_id)) {
|
|
293
298
|
logger_1.logger.warn("Event already enqueued, try again after ".concat((0, utils_1.millisecondsToSecond)(this.flushIntervalMs), " seconds."));
|
|
@@ -2,8 +2,10 @@ import { IStorage, StorageType } from "./type";
|
|
|
2
2
|
export declare class StorageManager {
|
|
3
3
|
private readonly writeKey;
|
|
4
4
|
private storages;
|
|
5
|
+
private resolvedTypes;
|
|
5
6
|
constructor(writeKey: string);
|
|
6
7
|
getStorage(type: StorageType): IStorage;
|
|
8
|
+
getResolvedType(type: StorageType): StorageType;
|
|
7
9
|
private createStorage;
|
|
8
10
|
private getWebStorage;
|
|
9
11
|
}
|
|
@@ -19,6 +19,7 @@ var StorageManager = /** @class */ (function () {
|
|
|
19
19
|
function StorageManager(writeKey) {
|
|
20
20
|
this.writeKey = writeKey;
|
|
21
21
|
this.storages = new Map();
|
|
22
|
+
this.resolvedTypes = new Map();
|
|
22
23
|
}
|
|
23
24
|
StorageManager.prototype.getStorage = function (type) {
|
|
24
25
|
if (!this.storages.has(type)) {
|
|
@@ -39,9 +40,14 @@ var StorageManager = /** @class */ (function () {
|
|
|
39
40
|
}
|
|
40
41
|
// Add to cache
|
|
41
42
|
this.storages.set(type, storage);
|
|
43
|
+
this.resolvedTypes.set(type, currentType);
|
|
42
44
|
}
|
|
43
45
|
return this.storages.get(type);
|
|
44
46
|
};
|
|
47
|
+
StorageManager.prototype.getResolvedType = function (type) {
|
|
48
|
+
this.getStorage(type);
|
|
49
|
+
return this.resolvedTypes.get(type);
|
|
50
|
+
};
|
|
45
51
|
StorageManager.prototype.createStorage = function (type) {
|
|
46
52
|
switch (type) {
|
|
47
53
|
case "cookieStorage":
|
|
@@ -5,4 +5,5 @@ export declare const cookie: () => IStorage;
|
|
|
5
5
|
export declare const local: () => IStorage;
|
|
6
6
|
export declare const session: () => IStorage;
|
|
7
7
|
export declare const memory: () => IStorage;
|
|
8
|
+
export declare const usesCookieStorage: () => boolean;
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.memory = exports.session = exports.local = exports.cookie = void 0;
|
|
17
|
+
exports.usesCookieStorage = exports.memory = exports.session = exports.local = exports.cookie = void 0;
|
|
18
18
|
exports.initStorageManager = initStorageManager;
|
|
19
19
|
var StorageManager_1 = require("./StorageManager");
|
|
20
20
|
__exportStar(require("./type"), exports);
|
|
@@ -38,4 +38,10 @@ var session = function () { return getStorageInstance("sessionStorage"); };
|
|
|
38
38
|
exports.session = session;
|
|
39
39
|
var memory = function () { return getStorageInstance("memoryStorage"); };
|
|
40
40
|
exports.memory = memory;
|
|
41
|
+
var usesCookieStorage = function () {
|
|
42
|
+
if (!globalManager)
|
|
43
|
+
return false;
|
|
44
|
+
return globalManager.getResolvedType("cookieStorage") === "cookieStorage";
|
|
45
|
+
};
|
|
46
|
+
exports.usesCookieStorage = usesCookieStorage;
|
|
41
47
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.
|
|
1
|
+
export declare const version = "1.40.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cjs/src/version.js
CHANGED
|
@@ -3,5 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.version = void 0;
|
|
4
4
|
// This file is auto-generated by scripts/update-version.js during npm version
|
|
5
5
|
// Do not edit manually - it will be overwritten
|
|
6
|
-
exports.version = '1.
|
|
6
|
+
exports.version = '1.40.0';
|
|
7
7
|
//# sourceMappingURL=version.js.map
|
|
@@ -54,6 +54,7 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
54
54
|
private _onPopStateListener?;
|
|
55
55
|
private _onLocationChangeListener?;
|
|
56
56
|
private _pageHooksDisposed;
|
|
57
|
+
private _pageGeneration;
|
|
57
58
|
config: Config;
|
|
58
59
|
/**
|
|
59
60
|
* The wallet later events are attributed to, derived from whichever
|
|
@@ -87,7 +88,8 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
87
88
|
*/
|
|
88
89
|
page(category?: string, name?: string, properties?: IFormoEventProperties, context?: IFormoEventContext, callback?: (...args: unknown[]) => void): Promise<void>;
|
|
89
90
|
/**
|
|
90
|
-
* Reset the
|
|
91
|
+
* Reset user and wallet state while preserving the browser's anonymous id.
|
|
92
|
+
* Use `optOutTracking()` to clear the anonymous id and the attribution.
|
|
91
93
|
* @returns {void}
|
|
92
94
|
*/
|
|
93
95
|
reset(): void;
|
|
@@ -142,6 +144,7 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
142
144
|
chainId?: ChainID;
|
|
143
145
|
address?: Address;
|
|
144
146
|
}): void;
|
|
147
|
+
private retryWalletDetection;
|
|
145
148
|
/** @see WalletStateStore.clearProvider */
|
|
146
149
|
private clearActiveProvider;
|
|
147
150
|
/** @see WalletStateStore.backfill */
|
|
@@ -49,6 +49,7 @@ import { EVENTS_API_HOST, EventType, LOCAL_ANONYMOUS_ID_KEY, SESSION_USER_ID_KEY
|
|
|
49
49
|
import { cookie, session, initStorageManager } from "./storage";
|
|
50
50
|
import { getIdentityCookieDomain, getIdentityCookieSecurity, } from "./storage/cookiePolicy";
|
|
51
51
|
import { EventManager } from "./event";
|
|
52
|
+
import { clearAnonymousId } from "./event/utils";
|
|
52
53
|
import { EventQueue } from "./queue";
|
|
53
54
|
import { logger, Logger } from "./logger";
|
|
54
55
|
import { setConsentFlag, getConsentFlag, removeConsentFlag, } from "./consent";
|
|
@@ -90,6 +91,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
90
91
|
/** In-memory URL used to deduplicate SPA pageview events. */
|
|
91
92
|
this._currentUrl = "";
|
|
92
93
|
this._pageHooksDisposed = false;
|
|
94
|
+
this._pageGeneration = 0;
|
|
93
95
|
this.currentUserId = "";
|
|
94
96
|
/**
|
|
95
97
|
* Clean up resources and event listeners
|
|
@@ -187,6 +189,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
187
189
|
isAutocaptureEnabled: function (t) { return _this.isAutocaptureEnabled(t); },
|
|
188
190
|
isTrackingSuppressed: function () { return _this.isTrackingSuppressed(); },
|
|
189
191
|
willTrackEvent: function (chainId) { return _this.willTrackEvent(chainId); },
|
|
192
|
+
retryDetection: function () { return _this.retryWalletDetection(); },
|
|
190
193
|
isWagmiMode: function () { return _this.isWagmiMode; },
|
|
191
194
|
connect: function (params, properties) { return _this.connect(params, properties); },
|
|
192
195
|
disconnect: function (params) { return _this.disconnect(params); },
|
|
@@ -215,7 +218,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
215
218
|
// ever sent once the user has opted out, even via a timer or
|
|
216
219
|
// pagehide flush scheduled before opt-out.
|
|
217
220
|
canSend: function () { return !_this.hasOptedOutTracking(); },
|
|
218
|
-
}), options);
|
|
221
|
+
}), options, function () { return !_this.hasOptedOutTracking(); });
|
|
219
222
|
// Check consent status on initialization
|
|
220
223
|
if (this.hasOptedOutTracking()) {
|
|
221
224
|
logger.info("User has previously opted out of tracking");
|
|
@@ -317,7 +320,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
317
320
|
});
|
|
318
321
|
FormoAnalytics.init = function (writeKey, options) {
|
|
319
322
|
return __awaiter(this, void 0, void 0, function () {
|
|
320
|
-
var analytics, discovered;
|
|
323
|
+
var analytics, discovered, error_1;
|
|
321
324
|
return __generator(this, function (_a) {
|
|
322
325
|
switch (_a.label) {
|
|
323
326
|
case 0:
|
|
@@ -327,18 +330,21 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
327
330
|
logger.info("FormoAnalytics: Skipping provider detection (EVM disabled)");
|
|
328
331
|
return [3 /*break*/, 5];
|
|
329
332
|
case 1:
|
|
330
|
-
|
|
333
|
+
_a.trys.push([1, 4, , 5]);
|
|
331
334
|
return [4 /*yield*/, analytics.evmEvents.getProviders()];
|
|
332
335
|
case 2:
|
|
333
336
|
discovered = _a.sent();
|
|
334
337
|
return [4 /*yield*/, analytics.evmEvents.detectWallets(discovered)];
|
|
335
338
|
case 3:
|
|
336
339
|
_a.sent();
|
|
337
|
-
analytics.
|
|
340
|
+
if (!analytics.isWagmiMode) {
|
|
341
|
+
analytics.evmEvents.trackProviders(discovered);
|
|
342
|
+
}
|
|
338
343
|
return [3 /*break*/, 5];
|
|
339
344
|
case 4:
|
|
340
|
-
|
|
341
|
-
|
|
345
|
+
error_1 = _a.sent();
|
|
346
|
+
logger.warn("FormoAnalytics: Provider discovery failed", error_1);
|
|
347
|
+
return [3 /*break*/, 5];
|
|
342
348
|
case 5: return [2 /*return*/, analytics];
|
|
343
349
|
}
|
|
344
350
|
});
|
|
@@ -369,7 +375,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
369
375
|
});
|
|
370
376
|
};
|
|
371
377
|
/**
|
|
372
|
-
* Reset the
|
|
378
|
+
* Reset user and wallet state while preserving the browser's anonymous id.
|
|
379
|
+
* Use `optOutTracking()` to clear the anonymous id and the attribution.
|
|
373
380
|
* @returns {void}
|
|
374
381
|
*/
|
|
375
382
|
FormoAnalytics.prototype.reset = function () {
|
|
@@ -380,15 +387,11 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
380
387
|
// page lifetime, because they fall back to currentAddress. Keep the
|
|
381
388
|
// EVM provider reference so tracking can resume on the next connect.
|
|
382
389
|
this.wallet.reset();
|
|
383
|
-
cookie().remove(LOCAL_ANONYMOUS_ID_KEY);
|
|
384
390
|
cookie().remove(SESSION_USER_ID_KEY);
|
|
385
391
|
cookie().remove(SESSION_WALLET_DETECTED_KEY);
|
|
386
392
|
cookie().remove(SESSION_WALLET_IDENTIFIED_KEY);
|
|
387
393
|
cookie().remove(ACTIVE_WALLET_KEY);
|
|
388
|
-
//
|
|
389
|
-
// clear it too so reset()/optOutTracking() don't leave it to be
|
|
390
|
-
// re-attached to the next session's events.
|
|
391
|
-
session().remove(SESSION_TRAFFIC_SOURCE_KEY);
|
|
394
|
+
// Attribution belongs to the visit, so reset preserves it.
|
|
392
395
|
};
|
|
393
396
|
FormoAnalytics.prototype.cleanup = function () {
|
|
394
397
|
this.isCleanedUp = true;
|
|
@@ -572,6 +575,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
572
575
|
*/
|
|
573
576
|
FormoAnalytics.prototype.syncWalletState = function (params) {
|
|
574
577
|
this.wallet.syncWalletState(params);
|
|
578
|
+
this.retryWalletDetection();
|
|
579
|
+
};
|
|
580
|
+
FormoAnalytics.prototype.retryWalletDetection = function () {
|
|
581
|
+
if (this.isCleanedUp)
|
|
582
|
+
return;
|
|
583
|
+
void this.evmEvents.detectWallets(this.evmEvents.detectableProviders());
|
|
575
584
|
};
|
|
576
585
|
/** @see WalletStateStore.clearProvider */
|
|
577
586
|
FormoAnalytics.prototype.clearActiveProvider = function () {
|
|
@@ -771,6 +780,11 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
771
780
|
return [2 /*return*/];
|
|
772
781
|
}
|
|
773
782
|
if (!!params) return [3 /*break*/, 12];
|
|
783
|
+
// Wagmi owns wallet identification.
|
|
784
|
+
if (this.isWagmiMode) {
|
|
785
|
+
logger.info("identify() without params is a no-op in Wagmi mode");
|
|
786
|
+
return [2 /*return*/];
|
|
787
|
+
}
|
|
774
788
|
// If no params provided, auto-identify
|
|
775
789
|
logger.info("Auto-identifying with providers:", this.evm.all.map(function (p) { return p.info.name; }));
|
|
776
790
|
_i = 0, _a = this.evm.all;
|
|
@@ -950,10 +964,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
950
964
|
return __generator(this, function (_c) {
|
|
951
965
|
switch (_c.label) {
|
|
952
966
|
case 0:
|
|
953
|
-
//
|
|
954
|
-
|
|
955
|
-
// excluded environment (opt-out / timezone / host / path).
|
|
956
|
-
if (this.isTrackingSuppressed()) {
|
|
967
|
+
// Apply all policy checks before persisting the detection marker.
|
|
968
|
+
if (!this.shouldTrack()) {
|
|
957
969
|
logger.info("detect() skipped: tracking is suppressed for this visitor or environment");
|
|
958
970
|
return [2 /*return*/];
|
|
959
971
|
}
|
|
@@ -1015,6 +1027,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1015
1027
|
// Set opt-out flag in persistent storage using direct cookie access
|
|
1016
1028
|
// This must be done before switching storage to ensure persistence
|
|
1017
1029
|
setConsentFlag(this.writeKey, CONSENT_OPT_OUT_KEY, "true");
|
|
1030
|
+
this._pageGeneration++;
|
|
1018
1031
|
// Drop anything already buffered so a pending timer/pagehide flush
|
|
1019
1032
|
// cannot ship events after consent withdrawal.
|
|
1020
1033
|
this.eventManager.clear();
|
|
@@ -1022,6 +1035,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1022
1035
|
// on opt-in, and nothing else would retry an already-adopted one.
|
|
1023
1036
|
this.evmEvents.markRegisteredAdoptionsPending();
|
|
1024
1037
|
this.reset();
|
|
1038
|
+
// Consent withdrawal also clears the browser id and the attribution.
|
|
1039
|
+
clearAnonymousId(LOCAL_ANONYMOUS_ID_KEY);
|
|
1040
|
+
session().remove(SESSION_TRAFFIC_SOURCE_KEY);
|
|
1025
1041
|
logger.info("Successfully opted out of tracking");
|
|
1026
1042
|
};
|
|
1027
1043
|
/**
|
|
@@ -1048,11 +1064,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1048
1064
|
logger.info("Opting back into tracking");
|
|
1049
1065
|
// Remove opt-out flag
|
|
1050
1066
|
removeConsentFlag(this.writeKey, CONSENT_OPT_OUT_KEY);
|
|
1051
|
-
//
|
|
1052
|
-
// an unchanged wagmi connection produces no status or chain update to
|
|
1053
|
-
// retry on. Without this, opting back in leaves that wallet invisible for
|
|
1054
|
-
// the rest of the page load.
|
|
1067
|
+
// Retry wallet adoption skipped while opted out.
|
|
1055
1068
|
(_a = this.wagmiHandler) === null || _a === void 0 ? void 0 : _a.retryAdoption();
|
|
1069
|
+
this.retryWalletDetection();
|
|
1056
1070
|
logger.info("Successfully opted back into tracking");
|
|
1057
1071
|
};
|
|
1058
1072
|
/**
|
|
@@ -1133,29 +1147,30 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1133
1147
|
};
|
|
1134
1148
|
FormoAnalytics.prototype.trackPageHit = function (category, name, properties, context, callback) {
|
|
1135
1149
|
return __awaiter(this, void 0, void 0, function () {
|
|
1150
|
+
var canTrack, generation;
|
|
1136
1151
|
var _this = this;
|
|
1137
1152
|
return __generator(this, function (_a) {
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
// Idempotent and cheap when nothing is pending.
|
|
1141
|
-
if (!this.isCleanedUp) {
|
|
1153
|
+
canTrack = this.shouldTrack();
|
|
1154
|
+
if (!this.isCleanedUp && canTrack) {
|
|
1142
1155
|
try {
|
|
1143
1156
|
this.evmEvents.retryExternalAdoptions();
|
|
1157
|
+
this.retryWalletDetection();
|
|
1144
1158
|
}
|
|
1145
1159
|
catch (_b) {
|
|
1146
|
-
|
|
1160
|
+
// Detection retries must not break page tracking.
|
|
1147
1161
|
}
|
|
1148
1162
|
}
|
|
1149
|
-
if (!
|
|
1163
|
+
if (!canTrack) {
|
|
1150
1164
|
logger.info("Track page hit: Skipping event due to tracking configuration");
|
|
1151
1165
|
return [2 /*return*/];
|
|
1152
1166
|
}
|
|
1167
|
+
generation = this._pageGeneration;
|
|
1153
1168
|
setTimeout(function () {
|
|
1154
1169
|
// Drop in-flight page hits from an SDK instance that was torn down
|
|
1155
1170
|
// between scheduling and firing (e.g. provider remount in React Strict
|
|
1156
1171
|
// Mode / HMR). Otherwise the orphan instance would queue a page event
|
|
1157
1172
|
// here with its stale, never-populated `currentAddress`.
|
|
1158
|
-
if (_this._pageHooksDisposed)
|
|
1173
|
+
if (_this._pageHooksDisposed || generation !== _this._pageGeneration)
|
|
1159
1174
|
return;
|
|
1160
1175
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1161
1176
|
var e_2;
|
|
@@ -1185,7 +1200,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1185
1200
|
};
|
|
1186
1201
|
FormoAnalytics.prototype.trackEvent = function (type, payload, properties, context, callback) {
|
|
1187
1202
|
return __awaiter(this, void 0, void 0, function () {
|
|
1188
|
-
var
|
|
1203
|
+
var error_2;
|
|
1189
1204
|
return __generator(this, function (_a) {
|
|
1190
1205
|
switch (_a.label) {
|
|
1191
1206
|
case 0:
|
|
@@ -1204,8 +1219,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1204
1219
|
_a.sent();
|
|
1205
1220
|
return [3 /*break*/, 3];
|
|
1206
1221
|
case 2:
|
|
1207
|
-
|
|
1208
|
-
logger.error("Error tracking event:",
|
|
1222
|
+
error_2 = _a.sent();
|
|
1223
|
+
logger.error("Error tracking event:", error_2);
|
|
1209
1224
|
return [3 /*break*/, 3];
|
|
1210
1225
|
case 3: return [2 /*return*/];
|
|
1211
1226
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Address, APIEvent, ChainID, IFormoEvent, IFormoEventContext, IFormoEventProperties, Nullable, Options, SignatureStatus, TransactionStatus } from "../types";
|
|
2
2
|
import { IEventFactory } from "./type";
|
|
3
3
|
declare class EventFactory implements IEventFactory {
|
|
4
|
+
/** Consulted once per event, after the only await in creation. */
|
|
5
|
+
private readonly canCreate;
|
|
4
6
|
private options?;
|
|
5
7
|
private compiledPathPattern?;
|
|
6
8
|
private excludedQueryParams;
|
|
7
|
-
|
|
9
|
+
/** Bumped by invalidate(); an event created across a bump is dropped. */
|
|
10
|
+
private generation;
|
|
11
|
+
constructor(options?: Options,
|
|
12
|
+
/** Consulted once per event, after the only await in creation. */
|
|
13
|
+
canCreate?: () => boolean);
|
|
8
14
|
/**
|
|
9
15
|
* Validate an address for both EVM and Solana chains.
|
|
10
16
|
* Uses chainId for strict validation when available.
|
|
@@ -56,6 +62,8 @@ declare class EventFactory implements IEventFactory {
|
|
|
56
62
|
private redactStoredTrafficSources;
|
|
57
63
|
private getTrafficSources;
|
|
58
64
|
private getScreen;
|
|
65
|
+
/** Drop every event still being created. Called on clear() and close(). */
|
|
66
|
+
invalidate(): void;
|
|
59
67
|
private generateContext;
|
|
60
68
|
/**
|
|
61
69
|
* Add any missing default page properties using values from options and defaults
|
|
@@ -67,11 +67,18 @@ import { CHANNEL, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, DEFAULT_REFERR
|
|
|
67
67
|
import { sanitizeTrafficSources } from "./sanitize";
|
|
68
68
|
import { generateAnonymousId } from "./utils";
|
|
69
69
|
import { detectBrowser } from "../browser/browsers";
|
|
70
|
+
import { EVENT_CREATION_CANCELLED } from "./cancellation";
|
|
70
71
|
var ISO_3166_ALPHA_2_REGEX = /^[A-Z]{2}$/;
|
|
71
72
|
var EventFactory = /** @class */ (function () {
|
|
72
|
-
function EventFactory(options
|
|
73
|
+
function EventFactory(options,
|
|
74
|
+
/** Consulted once per event, after the only await in creation. */
|
|
75
|
+
canCreate) {
|
|
76
|
+
if (canCreate === void 0) { canCreate = function () { return true; }; }
|
|
73
77
|
var _this = this;
|
|
74
78
|
var _a, _b;
|
|
79
|
+
this.canCreate = canCreate;
|
|
80
|
+
/** Bumped by invalidate(); an event created across a bump is dropped. */
|
|
81
|
+
this.generation = 0;
|
|
75
82
|
this.extractUTMParameters = function (url) {
|
|
76
83
|
var result = {
|
|
77
84
|
utm_campaign: "",
|
|
@@ -404,6 +411,10 @@ var EventFactory = /** @class */ (function () {
|
|
|
404
411
|
return safeDefaults;
|
|
405
412
|
}
|
|
406
413
|
};
|
|
414
|
+
/** Drop every event still being created. Called on clear() and close(). */
|
|
415
|
+
EventFactory.prototype.invalidate = function () {
|
|
416
|
+
this.generation++;
|
|
417
|
+
};
|
|
407
418
|
// Contextual fields that are automatically collected and populated by the Formo SDK
|
|
408
419
|
EventFactory.prototype.generateContext = function (context) {
|
|
409
420
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -427,24 +438,28 @@ var EventFactory = /** @class */ (function () {
|
|
|
427
438
|
};
|
|
428
439
|
EventFactory.prototype.getEnrichedEvent = function (formoEvent, context) {
|
|
429
440
|
return __awaiter(this, void 0, void 0, function () {
|
|
430
|
-
var commonEventData, eventChainId, validAddress, processedEvent;
|
|
431
|
-
var _a;
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
switch (_d.label) {
|
|
441
|
+
var generation, enrichedContext, commonEventData, eventChainId, validAddress, processedEvent;
|
|
442
|
+
var _a, _b;
|
|
443
|
+
return __generator(this, function (_c) {
|
|
444
|
+
switch (_c.label) {
|
|
435
445
|
case 0:
|
|
436
|
-
|
|
446
|
+
generation = this.generation;
|
|
437
447
|
return [4 /*yield*/, this.generateContext(context)];
|
|
438
448
|
case 1:
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
449
|
+
enrichedContext = _c.sent();
|
|
450
|
+
if (generation !== this.generation || !this.canCreate()) {
|
|
451
|
+
throw EVENT_CREATION_CANCELLED;
|
|
452
|
+
}
|
|
453
|
+
commonEventData = {
|
|
454
|
+
context: enrichedContext,
|
|
455
|
+
original_timestamp: getCurrentTimeFormatted(),
|
|
456
|
+
user_id: formoEvent.user_id,
|
|
457
|
+
type: formoEvent.type,
|
|
458
|
+
channel: CHANNEL,
|
|
459
|
+
version: VERSION,
|
|
460
|
+
};
|
|
461
|
+
commonEventData.anonymous_id = generateAnonymousId(LOCAL_ANONYMOUS_ID_KEY, (_a = this.options) === null || _a === void 0 ? void 0 : _a.crossSubdomainCookies);
|
|
462
|
+
eventChainId = (_b = formoEvent.properties) === null || _b === void 0 ? void 0 : _b.chainId;
|
|
448
463
|
validAddress = this.validateEventAddress(formoEvent.address, eventChainId);
|
|
449
464
|
commonEventData.address = validAddress;
|
|
450
465
|
processedEvent = mergeDeepRight(formoEvent, commonEventData);
|
|
@@ -5,14 +5,16 @@ import { IEventFactory, IEventManager } from "./type";
|
|
|
5
5
|
* A service to generate valid event payloads and queue them for processing
|
|
6
6
|
*/
|
|
7
7
|
declare class EventManager implements IEventManager {
|
|
8
|
+
private readonly canAcceptEvent;
|
|
8
9
|
eventQueue: IEventQueue;
|
|
9
10
|
eventFactory: IEventFactory;
|
|
11
|
+
private generation;
|
|
10
12
|
/**
|
|
11
13
|
*
|
|
12
14
|
* @param eventQueue Event queue instance
|
|
13
15
|
* @param options Optional configuration (referral parsing, etc.)
|
|
14
16
|
*/
|
|
15
|
-
constructor(eventQueue: IEventQueue, options?: Options);
|
|
17
|
+
constructor(eventQueue: IEventQueue, options?: Options, canAcceptEvent?: () => boolean);
|
|
16
18
|
/**
|
|
17
19
|
* Consumes a new incoming event
|
|
18
20
|
* @param event Incoming event data
|