@formo/analytics 1.29.1 → 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 +20 -3
- package/dist/cjs/src/FormoAnalytics.js +102 -9
- package/dist/cjs/src/event/EventFactory.d.ts +1 -1
- package/dist/cjs/src/event/EventFactory.js +3 -3
- 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 +20 -3
- package/dist/esm/src/FormoAnalytics.js +105 -12
- package/dist/esm/src/event/EventFactory.d.ts +1 -1
- package/dist/esm/src/event/EventFactory.js +3 -3
- 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 +7 -18
|
@@ -4,7 +4,19 @@
|
|
|
4
4
|
* Handles tracking of detected wallets and identified wallet-address pairs
|
|
5
5
|
* using cookies to maintain state across page loads within a session.
|
|
6
6
|
*/
|
|
7
|
+
var __assign = (this && this.__assign) || function () {
|
|
8
|
+
__assign = Object.assign || function(t) {
|
|
9
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
10
|
+
s = arguments[i];
|
|
11
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
12
|
+
t[p] = s[p];
|
|
13
|
+
}
|
|
14
|
+
return t;
|
|
15
|
+
};
|
|
16
|
+
return __assign.apply(this, arguments);
|
|
17
|
+
};
|
|
7
18
|
import { cookie } from "../storage";
|
|
19
|
+
import { getIdentityCookieSecurity } from "../storage/cookiePolicy";
|
|
8
20
|
import { logger } from "../logger";
|
|
9
21
|
/**
|
|
10
22
|
* Cookie keys for session tracking
|
|
@@ -63,11 +75,9 @@ var FormoAnalyticsSession = /** @class */ (function () {
|
|
|
63
75
|
if (rdnses.length > MAX_SESSION_ENTRIES) {
|
|
64
76
|
rdnses.splice(0, rdnses.length - MAX_SESSION_ENTRIES);
|
|
65
77
|
}
|
|
66
|
-
cookie().set(SESSION_WALLET_DETECTED_KEY, rdnses.join(","), {
|
|
78
|
+
cookie().set(SESSION_WALLET_DETECTED_KEY, rdnses.join(","), __assign({
|
|
67
79
|
// Expires by the end of the day
|
|
68
|
-
expires: new Date(Date.now() + 86400 * 1000).toUTCString(),
|
|
69
|
-
path: "/",
|
|
70
|
-
});
|
|
80
|
+
expires: new Date(Date.now() + 86400 * 1000).toUTCString(), path: "/" }, getIdentityCookieSecurity()));
|
|
71
81
|
}
|
|
72
82
|
};
|
|
73
83
|
/**
|
|
@@ -107,11 +117,9 @@ var FormoAnalyticsSession = /** @class */ (function () {
|
|
|
107
117
|
identifiedWallets.splice(0, identifiedWallets.length - MAX_SESSION_ENTRIES);
|
|
108
118
|
}
|
|
109
119
|
var newValue = identifiedWallets.join(",");
|
|
110
|
-
cookie().set(SESSION_WALLET_IDENTIFIED_KEY, newValue, {
|
|
120
|
+
cookie().set(SESSION_WALLET_IDENTIFIED_KEY, newValue, __assign({
|
|
111
121
|
// Expires by the end of the day
|
|
112
|
-
expires: new Date(Date.now() + 86400 * 1000).toUTCString(),
|
|
113
|
-
path: "/",
|
|
114
|
-
});
|
|
122
|
+
expires: new Date(Date.now() + 86400 * 1000).toUTCString(), path: "/" }, getIdentityCookieSecurity()));
|
|
115
123
|
logger.debug("Session: Marked wallet as identified", {
|
|
116
124
|
identifiedKey: identifiedKey,
|
|
117
125
|
hasRdns: !!rdns,
|
|
@@ -7,4 +7,20 @@
|
|
|
7
7
|
* @param crossSubdomain Whether cookies should be shared across subdomains.
|
|
8
8
|
*/
|
|
9
9
|
export declare function getIdentityCookieDomain(crossSubdomain?: boolean): string;
|
|
10
|
+
/**
|
|
11
|
+
* Security attributes for identity/session cookies (user-id,
|
|
12
|
+
* active-wallet, wallet-detected/identified).
|
|
13
|
+
*
|
|
14
|
+
* - `sameSite: "lax"` — first-party analytics identity. Lax keeps the
|
|
15
|
+
* cookie on top-level navigations (so attribution survives a click-in
|
|
16
|
+
* from another site) while blocking it on cross-site subrequests.
|
|
17
|
+
* Strict would silently drop identity on inbound navigation.
|
|
18
|
+
* - `secure` — only on HTTPS. Setting Secure over plain HTTP (local dev)
|
|
19
|
+
* makes the browser reject the cookie outright, so it must be
|
|
20
|
+
* conditional.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getIdentityCookieSecurity(): {
|
|
23
|
+
sameSite: "lax";
|
|
24
|
+
secure: boolean;
|
|
25
|
+
};
|
|
10
26
|
//# sourceMappingURL=cookiePolicy.d.ts.map
|
|
@@ -21,4 +21,22 @@ export function getIdentityCookieDomain(crossSubdomain) {
|
|
|
21
21
|
var domain = getApexDomain();
|
|
22
22
|
return domain ? ".".concat(domain) : "";
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Security attributes for identity/session cookies (user-id,
|
|
26
|
+
* active-wallet, wallet-detected/identified).
|
|
27
|
+
*
|
|
28
|
+
* - `sameSite: "lax"` — first-party analytics identity. Lax keeps the
|
|
29
|
+
* cookie on top-level navigations (so attribution survives a click-in
|
|
30
|
+
* from another site) while blocking it on cross-site subrequests.
|
|
31
|
+
* Strict would silently drop identity on inbound navigation.
|
|
32
|
+
* - `secure` — only on HTTPS. Setting Secure over plain HTTP (local dev)
|
|
33
|
+
* makes the browser reject the cookie outright, so it must be
|
|
34
|
+
* conditional.
|
|
35
|
+
*/
|
|
36
|
+
export function getIdentityCookieSecurity() {
|
|
37
|
+
var _a;
|
|
38
|
+
var isHttps = typeof window !== "undefined" &&
|
|
39
|
+
((_a = window.location) === null || _a === void 0 ? void 0 : _a.protocol) === "https:";
|
|
40
|
+
return { sameSite: "lax", secure: isHttps };
|
|
41
|
+
}
|
|
24
42
|
//# sourceMappingURL=cookiePolicy.js.map
|
|
@@ -40,7 +40,6 @@ export interface IFormoAnalytics {
|
|
|
40
40
|
chainId?: ChainID;
|
|
41
41
|
address: Address;
|
|
42
42
|
message: string;
|
|
43
|
-
signatureHash?: string;
|
|
44
43
|
}, properties?: IFormoEventProperties, context?: IFormoEventContext, callback?: (...args: unknown[]) => void): Promise<void>;
|
|
45
44
|
transaction(params: {
|
|
46
45
|
status: TransactionStatus;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.
|
|
1
|
+
export declare const version = "1.30.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/esm/src/version.js
CHANGED
|
@@ -170,6 +170,11 @@ var WagmiEventHandler = /** @class */ (function () {
|
|
|
170
170
|
chainId: chainId,
|
|
171
171
|
});
|
|
172
172
|
if (!(status === "disconnected" && prevStatus === "connected")) return [3 /*break*/, 4];
|
|
173
|
+
// Clear central chain state regardless of autocapture so a later
|
|
174
|
+
// event can't carry a stale excluded/!excluded chainId.
|
|
175
|
+
this.formo.syncWalletState({
|
|
176
|
+
chainId: this.trackingState.lastChainId,
|
|
177
|
+
});
|
|
173
178
|
if (!this.formo.isAutocaptureEnabled("disconnect")) return [3 /*break*/, 3];
|
|
174
179
|
return [4 /*yield*/, this.formo.disconnect({
|
|
175
180
|
chainId: this.trackingState.lastChainId,
|
|
@@ -187,6 +192,9 @@ var WagmiEventHandler = /** @class */ (function () {
|
|
|
187
192
|
if (!(address && chainId !== undefined)) return [3 /*break*/, 6];
|
|
188
193
|
this.trackingState.lastAddress = address;
|
|
189
194
|
this.trackingState.lastChainId = chainId;
|
|
195
|
+
// Sync central state unconditionally so tracking.excludeChains
|
|
196
|
+
// is enforced even when connect autocapture is disabled.
|
|
197
|
+
this.formo.syncWalletState({ chainId: chainId, address: address });
|
|
190
198
|
if (!this.formo.isAutocaptureEnabled("connect")) return [3 /*break*/, 6];
|
|
191
199
|
connectorName = this.getConnectorName(state);
|
|
192
200
|
return [4 /*yield*/, this.formo.connect({ chainId: chainId, address: address }, __assign({}, (connectorName && { providerName: connectorName })))];
|
|
@@ -235,6 +243,9 @@ var WagmiEventHandler = /** @class */ (function () {
|
|
|
235
243
|
address: address,
|
|
236
244
|
});
|
|
237
245
|
this.trackingState.lastChainId = chainId;
|
|
246
|
+
// Sync central state unconditionally so a chain switch to an
|
|
247
|
+
// excluded chain is honored even when chain autocapture is disabled.
|
|
248
|
+
this.formo.syncWalletState({ chainId: chainId, address: address });
|
|
238
249
|
if (!this.formo.isAutocaptureEnabled("chain")) return [3 /*break*/, 4];
|
|
239
250
|
_a.label = 1;
|
|
240
251
|
case 1:
|
|
@@ -356,14 +367,21 @@ var WagmiEventHandler = /** @class */ (function () {
|
|
|
356
367
|
logger.warn("WagmiEventHandler: Transaction receipt query but no hash found");
|
|
357
368
|
return;
|
|
358
369
|
}
|
|
359
|
-
// Retrieve stored transaction details from BROADCASTED event
|
|
360
|
-
// Normalize hash to lowercase for consistent lookup
|
|
370
|
+
// Retrieve stored transaction details from the BROADCASTED event.
|
|
371
|
+
// Normalize hash to lowercase for consistent lookup.
|
|
361
372
|
var normalizedHash = transactionHash.toLowerCase();
|
|
362
373
|
var pendingTx = this.pendingTransactions.get(normalizedHash);
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
|
|
374
|
+
// Only emit receipt-derived events for a hash we actually observed
|
|
375
|
+
// being broadcast through this handler. The QueryClient is supplied
|
|
376
|
+
// by the host app and its cache can be written by app code or other
|
|
377
|
+
// deps, so without this gate a forged waitForTransactionReceipt
|
|
378
|
+
// entry could fabricate a confirmed/reverted transaction for an
|
|
379
|
+
// arbitrary hash. No pendingTx → not our broadcast → ignore.
|
|
380
|
+
if (!pendingTx) {
|
|
381
|
+
logger.debug("WagmiEventHandler: Receipt for unobserved tx hash; ignoring", { transactionHash: transactionHash });
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
var address = pendingTx.address;
|
|
367
385
|
if (!address) {
|
|
368
386
|
logger.warn("WagmiEventHandler: Transaction receipt query but no address available");
|
|
369
387
|
return;
|
|
@@ -371,9 +389,13 @@ var WagmiEventHandler = /** @class */ (function () {
|
|
|
371
389
|
try {
|
|
372
390
|
// Extract receipt data
|
|
373
391
|
var receipt = state.data;
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
|
|
392
|
+
// Only act on an explicit on-chain outcome. A missing/unknown
|
|
393
|
+
// status must NOT be treated as a confirmation.
|
|
394
|
+
if ((receipt === null || receipt === void 0 ? void 0 : receipt.status) !== "success" && (receipt === null || receipt === void 0 ? void 0 : receipt.status) !== "reverted") {
|
|
395
|
+
logger.debug("WagmiEventHandler: Receipt without explicit success/reverted status; ignoring", { transactionHash: transactionHash, status: receipt === null || receipt === void 0 ? void 0 : receipt.status });
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
var txStatus = receipt.status === "reverted"
|
|
377
399
|
? TransactionStatus.REVERTED
|
|
378
400
|
: TransactionStatus.CONFIRMED;
|
|
379
401
|
logger.info("WagmiEventHandler: Tracking transaction confirmation", {
|
|
@@ -452,15 +474,13 @@ var WagmiEventHandler = /** @class */ (function () {
|
|
|
452
474
|
return;
|
|
453
475
|
}
|
|
454
476
|
try {
|
|
455
|
-
// Map Wagmi mutation status to Formo signature status
|
|
477
|
+
// Map Wagmi mutation status to Formo signature status.
|
|
456
478
|
var status_1;
|
|
457
|
-
var signatureHash = void 0;
|
|
458
479
|
if (state.status === "pending") {
|
|
459
480
|
status_1 = SignatureStatus.REQUESTED;
|
|
460
481
|
}
|
|
461
482
|
else if (state.status === "success") {
|
|
462
483
|
status_1 = SignatureStatus.CONFIRMED;
|
|
463
|
-
signatureHash = state.data;
|
|
464
484
|
}
|
|
465
485
|
else if (state.status === "error") {
|
|
466
486
|
status_1 = SignatureStatus.REJECTED;
|
|
@@ -468,13 +488,11 @@ var WagmiEventHandler = /** @class */ (function () {
|
|
|
468
488
|
else {
|
|
469
489
|
return; // Ignore idle state
|
|
470
490
|
}
|
|
471
|
-
// Extract message from variables
|
|
472
491
|
var message = void 0;
|
|
473
492
|
if (mutationType === "signMessage") {
|
|
474
493
|
message = variables.message || "";
|
|
475
494
|
}
|
|
476
495
|
else {
|
|
477
|
-
// For signTypedData, stringify the typed data
|
|
478
496
|
message = JSON.stringify(variables.message || variables.types || {});
|
|
479
497
|
}
|
|
480
498
|
logger.info("WagmiEventHandler: Tracking signature event", {
|
|
@@ -483,7 +501,12 @@ var WagmiEventHandler = /** @class */ (function () {
|
|
|
483
501
|
address: address,
|
|
484
502
|
chainId: chainId,
|
|
485
503
|
});
|
|
486
|
-
this.formo.signature(
|
|
504
|
+
this.formo.signature({
|
|
505
|
+
status: status_1,
|
|
506
|
+
chainId: chainId,
|
|
507
|
+
address: address,
|
|
508
|
+
message: message,
|
|
509
|
+
});
|
|
487
510
|
}
|
|
488
511
|
catch (error) {
|
|
489
512
|
logger.error("WagmiEventHandler: Error handling signature mutation:", error);
|