@formo/analytics 1.28.2 → 1.28.3
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 +2 -0
- package/dist/cjs/src/FormoAnalytics.js +10 -5
- package/dist/cjs/src/FormoAnalyticsProvider.js +1 -0
- package/dist/cjs/src/consent/index.js +12 -10
- package/dist/cjs/src/event/EventFactory.js +6 -6
- package/dist/cjs/src/event/utils.d.ts +2 -3
- package/dist/cjs/src/event/utils.js +24 -24
- package/dist/cjs/src/queue/EventQueue.d.ts +1 -1
- package/dist/cjs/src/queue/EventQueue.js +21 -20
- package/dist/cjs/src/session/index.d.ts +0 -9
- package/dist/cjs/src/session/index.js +7 -0
- package/dist/cjs/src/solana/SolanaAdapter.d.ts +3 -4
- package/dist/cjs/src/solana/SolanaAdapter.js +42 -29
- package/dist/cjs/src/storage/StorageManager.js +11 -3
- package/dist/cjs/src/storage/built-in/cookie.js +29 -3
- package/dist/cjs/src/storage/cookiePolicy.d.ts +10 -0
- package/dist/cjs/src/storage/cookiePolicy.js +27 -0
- package/dist/cjs/src/types/base.d.ts +12 -0
- package/dist/cjs/src/utils/address.js +4 -6
- package/dist/cjs/src/utils/domain.d.ts +27 -0
- package/dist/cjs/src/utils/domain.js +74 -0
- package/dist/cjs/src/utils/generate.js +23 -11
- package/dist/cjs/src/validators/network.js +7 -2
- package/dist/cjs/src/version.d.ts +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/esm/src/FormoAnalytics.d.ts +2 -0
- package/dist/esm/src/FormoAnalytics.js +10 -5
- package/dist/esm/src/FormoAnalyticsProvider.js +1 -0
- package/dist/esm/src/consent/index.js +12 -10
- package/dist/esm/src/event/EventFactory.js +6 -6
- package/dist/esm/src/event/utils.d.ts +2 -3
- package/dist/esm/src/event/utils.js +25 -24
- package/dist/esm/src/queue/EventQueue.d.ts +1 -1
- package/dist/esm/src/queue/EventQueue.js +21 -20
- package/dist/esm/src/session/index.d.ts +0 -9
- package/dist/esm/src/session/index.js +7 -0
- package/dist/esm/src/solana/SolanaAdapter.d.ts +3 -4
- package/dist/esm/src/solana/SolanaAdapter.js +42 -29
- package/dist/esm/src/storage/StorageManager.js +11 -3
- package/dist/esm/src/storage/built-in/cookie.js +29 -3
- package/dist/esm/src/storage/cookiePolicy.d.ts +10 -0
- package/dist/esm/src/storage/cookiePolicy.js +24 -0
- package/dist/esm/src/types/base.d.ts +12 -0
- package/dist/esm/src/utils/address.js +4 -6
- package/dist/esm/src/utils/domain.d.ts +27 -0
- package/dist/esm/src/utils/domain.js +70 -0
- package/dist/esm/src/utils/generate.js +23 -11
- package/dist/esm/src/validators/network.js +7 -2
- 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 +1 -1
|
@@ -19,6 +19,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
var blueprint_1 = __importDefault(require("./blueprint"));
|
|
22
|
+
var domain_1 = require("../../utils/domain");
|
|
22
23
|
var CookieStorage = /** @class */ (function (_super) {
|
|
23
24
|
__extends(CookieStorage, _super);
|
|
24
25
|
function CookieStorage() {
|
|
@@ -31,10 +32,27 @@ var CookieStorage = /** @class */ (function (_super) {
|
|
|
31
32
|
var expires = options === null || options === void 0 ? void 0 : options.expires;
|
|
32
33
|
var maxAge = options === null || options === void 0 ? void 0 : options.maxAge;
|
|
33
34
|
var path = (options === null || options === void 0 ? void 0 : options.path) || "/";
|
|
34
|
-
var domain = options === null || options === void 0 ? void 0 : options.domain;
|
|
35
|
+
var domain = (options === null || options === void 0 ? void 0 : options.domain) || "";
|
|
35
36
|
var sameSite = options === null || options === void 0 ? void 0 : options.sameSite;
|
|
36
37
|
var secure = (options === null || options === void 0 ? void 0 : options.secure) || false;
|
|
37
|
-
var
|
|
38
|
+
var encodedKey = encodeURIComponent(this.getKey(key));
|
|
39
|
+
// When writing a domain-wide cookie, expire any legacy host-only cookie
|
|
40
|
+
// on the current host so it doesn't shadow the domain-wide cookie in
|
|
41
|
+
// document.cookie reads. This only clears the cookie on the current host;
|
|
42
|
+
// host-only cookies on sibling hosts are not visible and cannot be cleared.
|
|
43
|
+
if (domain) {
|
|
44
|
+
document.cookie = "".concat(encodedKey, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=").concat(path, ";");
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// When writing a host-only cookie (no domain), expire any previously
|
|
48
|
+
// written apex-domain cookie so it doesn't shadow the new host cookie.
|
|
49
|
+
// This handles the transition from crossSubdomainCookies: true to false.
|
|
50
|
+
var apexDomain = (0, domain_1.getApexDomain)();
|
|
51
|
+
if (apexDomain) {
|
|
52
|
+
document.cookie = "".concat(encodedKey, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=").concat(path, "; domain=.").concat(apexDomain);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
var cookie = "".concat(encodedKey, "=").concat(encodeURIComponent(value));
|
|
38
56
|
if (maxAge) {
|
|
39
57
|
cookie += "; max-age=" + maxAge;
|
|
40
58
|
}
|
|
@@ -60,7 +78,15 @@ var CookieStorage = /** @class */ (function (_super) {
|
|
|
60
78
|
return match ? decodeURIComponent(match[1]) : null;
|
|
61
79
|
};
|
|
62
80
|
CookieStorage.prototype.remove = function (key) {
|
|
63
|
-
|
|
81
|
+
var encodedKey = encodeURIComponent(this.getKey(key));
|
|
82
|
+
// Always expire host-only cookie
|
|
83
|
+
document.cookie = "".concat(encodedKey, "=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT");
|
|
84
|
+
// Also expire apex-domain cookie if a valid apex domain exists,
|
|
85
|
+
// so that remove() works regardless of crossSubdomainCookies.
|
|
86
|
+
var domain = (0, domain_1.getApexDomain)();
|
|
87
|
+
if (domain) {
|
|
88
|
+
document.cookie = "".concat(encodedKey, "=; path=/; domain=.").concat(domain, "; expires=Thu, 01 Jan 1970 00:00:00 GMT");
|
|
89
|
+
}
|
|
64
90
|
};
|
|
65
91
|
return CookieStorage;
|
|
66
92
|
}(blueprint_1.default));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the domain attribute string for identity cookies.
|
|
3
|
+
* - false → "" (no domain attribute, host-only)
|
|
4
|
+
* - true → ".example.com" when a valid apex domain is detected,
|
|
5
|
+
* or "" on localhost / IP / single-label hosts
|
|
6
|
+
*
|
|
7
|
+
* @param crossSubdomain Whether cookies should be shared across subdomains.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getIdentityCookieDomain(crossSubdomain?: boolean): string;
|
|
10
|
+
//# sourceMappingURL=cookiePolicy.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getIdentityCookieDomain = getIdentityCookieDomain;
|
|
4
|
+
/**
|
|
5
|
+
* Cookie domain policy — centralizes the decision of whether identity
|
|
6
|
+
* cookies should be host-scoped or apex-scoped.
|
|
7
|
+
*
|
|
8
|
+
* - true (default): domain set to .apexDomain → shared across subdomains
|
|
9
|
+
* - false: no domain attribute → cookie scoped to current host
|
|
10
|
+
*/
|
|
11
|
+
var domain_1 = require("../utils/domain");
|
|
12
|
+
/**
|
|
13
|
+
* Returns the domain attribute string for identity cookies.
|
|
14
|
+
* - false → "" (no domain attribute, host-only)
|
|
15
|
+
* - true → ".example.com" when a valid apex domain is detected,
|
|
16
|
+
* or "" on localhost / IP / single-label hosts
|
|
17
|
+
*
|
|
18
|
+
* @param crossSubdomain Whether cookies should be shared across subdomains.
|
|
19
|
+
*/
|
|
20
|
+
function getIdentityCookieDomain(crossSubdomain) {
|
|
21
|
+
if (crossSubdomain === void 0) { crossSubdomain = true; }
|
|
22
|
+
if (!crossSubdomain)
|
|
23
|
+
return "";
|
|
24
|
+
var domain = (0, domain_1.getApexDomain)();
|
|
25
|
+
return domain ? ".".concat(domain) : "";
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=cookiePolicy.js.map
|
|
@@ -144,6 +144,18 @@ export interface WagmiOptions {
|
|
|
144
144
|
export interface Options {
|
|
145
145
|
provider?: EIP1193Provider;
|
|
146
146
|
tracking?: boolean | TrackingOptions;
|
|
147
|
+
/**
|
|
148
|
+
* When `true`, identity cookies (anonymous ID, user ID) are set on the
|
|
149
|
+
* apex/root domain (e.g. `.example.com`), enabling cross-subdomain identity
|
|
150
|
+
* sharing between app.example.com and www.example.com.
|
|
151
|
+
*
|
|
152
|
+
* When `false`, cookies are scoped to the current host only.
|
|
153
|
+
*
|
|
154
|
+
* Session cookies (wallet detection, current URL) always remain host-scoped.
|
|
155
|
+
* Consent cookies are always apex-scoped independently for compliance.
|
|
156
|
+
* @default true
|
|
157
|
+
*/
|
|
158
|
+
crossSubdomainCookies?: boolean;
|
|
147
159
|
/**
|
|
148
160
|
* Control wallet event autocapture
|
|
149
161
|
* - `false`: Disable all wallet autocapture
|
|
@@ -51,15 +51,13 @@ exports.getValidAddress = getValidAddress;
|
|
|
51
51
|
* @returns true if the address is blocked, false otherwise
|
|
52
52
|
*/
|
|
53
53
|
var isBlockedAddress = function (address) {
|
|
54
|
-
if (!address)
|
|
54
|
+
if (!address || typeof address !== 'string')
|
|
55
55
|
return false;
|
|
56
|
-
var
|
|
57
|
-
if (!
|
|
56
|
+
var normalized = address.trim().toLowerCase();
|
|
57
|
+
if (!normalized || !normalized.startsWith('0x') || normalized.length !== 42)
|
|
58
58
|
return false;
|
|
59
|
-
// Normalize to checksum format for comparison
|
|
60
|
-
var checksumAddress = (0, exports.toChecksumAddress)(validAddress);
|
|
61
59
|
return constants_1.BLOCKED_ADDRESSES.some(function (blockedAddr) {
|
|
62
|
-
return
|
|
60
|
+
return blockedAddr.toLowerCase() === normalized;
|
|
63
61
|
});
|
|
64
62
|
};
|
|
65
63
|
exports.isBlockedAddress = isBlockedAddress;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain utilities for cross-subdomain cookie sharing.
|
|
3
|
+
*
|
|
4
|
+
* Uses a cookie-probe approach: tries setting a test cookie on progressively
|
|
5
|
+
* shorter domain candidates until the browser accepts one. This is
|
|
6
|
+
* self-maintaining — no hardcoded public suffix lists to keep up to date.
|
|
7
|
+
* The browser itself is the authority on which domains accept cookies.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Extract the apex (registrable) domain for cookie sharing across subdomains.
|
|
11
|
+
*
|
|
12
|
+
* Walks up the hostname labels from shortest candidate to longest, probing
|
|
13
|
+
* with a test cookie. The shortest domain the browser accepts is the apex.
|
|
14
|
+
*
|
|
15
|
+
* Returns null for localhost, IP addresses, single-label hosts, SSR, or
|
|
16
|
+
* when no candidate domain accepts cookies (e.g. public suffix hosts like
|
|
17
|
+
* vercel.app or github.io).
|
|
18
|
+
*
|
|
19
|
+
* Results are cached for the lifetime of the page.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getApexDomain(): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Reset the cached apex domain. Exposed for testing only.
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export declare function _resetApexDomainCache(): void;
|
|
27
|
+
//# sourceMappingURL=domain.d.ts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Domain utilities for cross-subdomain cookie sharing.
|
|
4
|
+
*
|
|
5
|
+
* Uses a cookie-probe approach: tries setting a test cookie on progressively
|
|
6
|
+
* shorter domain candidates until the browser accepts one. This is
|
|
7
|
+
* self-maintaining — no hardcoded public suffix lists to keep up to date.
|
|
8
|
+
* The browser itself is the authority on which domains accept cookies.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.getApexDomain = getApexDomain;
|
|
12
|
+
exports._resetApexDomainCache = _resetApexDomainCache;
|
|
13
|
+
var TEST_COOKIE_NAME = '__formo_domain_probe';
|
|
14
|
+
/** Cached result so we only probe once per page load. */
|
|
15
|
+
var cachedApexDomain;
|
|
16
|
+
/**
|
|
17
|
+
* Try to set a test cookie on the given domain. Returns true if the browser
|
|
18
|
+
* accepted it (i.e. the cookie is readable back).
|
|
19
|
+
*/
|
|
20
|
+
function canSetCookieOnDomain(domain) {
|
|
21
|
+
var cookieVal = 'probe';
|
|
22
|
+
document.cookie = "".concat(TEST_COOKIE_NAME, "=").concat(cookieVal, "; domain=.").concat(domain, "; path=/; max-age=10");
|
|
23
|
+
var accepted = document.cookie.indexOf("".concat(TEST_COOKIE_NAME, "=").concat(cookieVal)) !== -1;
|
|
24
|
+
// Clean up regardless of result
|
|
25
|
+
document.cookie = "".concat(TEST_COOKIE_NAME, "=; domain=.").concat(domain, "; path=/; max-age=0");
|
|
26
|
+
return accepted;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extract the apex (registrable) domain for cookie sharing across subdomains.
|
|
30
|
+
*
|
|
31
|
+
* Walks up the hostname labels from shortest candidate to longest, probing
|
|
32
|
+
* with a test cookie. The shortest domain the browser accepts is the apex.
|
|
33
|
+
*
|
|
34
|
+
* Returns null for localhost, IP addresses, single-label hosts, SSR, or
|
|
35
|
+
* when no candidate domain accepts cookies (e.g. public suffix hosts like
|
|
36
|
+
* vercel.app or github.io).
|
|
37
|
+
*
|
|
38
|
+
* Results are cached for the lifetime of the page.
|
|
39
|
+
*/
|
|
40
|
+
function getApexDomain() {
|
|
41
|
+
if (typeof window === 'undefined')
|
|
42
|
+
return null;
|
|
43
|
+
if (cachedApexDomain !== undefined)
|
|
44
|
+
return cachedApexDomain;
|
|
45
|
+
var hostname = window.location.hostname;
|
|
46
|
+
if (hostname === 'localhost' || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
|
47
|
+
cachedApexDomain = null;
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
var parts = hostname.split('.');
|
|
51
|
+
if (parts.length < 2) {
|
|
52
|
+
cachedApexDomain = null;
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
// Walk from the shortest candidate (last 2 labels) to the full hostname.
|
|
56
|
+
// The shortest domain the browser accepts is the apex domain.
|
|
57
|
+
for (var i = 2; i <= parts.length; i++) {
|
|
58
|
+
var candidate = parts.slice(-i).join('.');
|
|
59
|
+
if (canSetCookieOnDomain(candidate)) {
|
|
60
|
+
cachedApexDomain = candidate;
|
|
61
|
+
return candidate;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
cachedApexDomain = null;
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reset the cached apex domain. Exposed for testing only.
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
function _resetApexDomainCache() {
|
|
72
|
+
cachedApexDomain = undefined;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=domain.js.map
|
|
@@ -38,23 +38,35 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.hash = hash;
|
|
40
40
|
exports.generateNativeUUID = generateNativeUUID;
|
|
41
|
+
var sha256_1 = require("ethereum-cryptography/sha256");
|
|
42
|
+
var utils_1 = require("ethereum-cryptography/utils");
|
|
41
43
|
function hash(input) {
|
|
42
44
|
return __awaiter(this, void 0, void 0, function () {
|
|
43
|
-
var
|
|
45
|
+
var bytes, hashBytes;
|
|
44
46
|
return __generator(this, function (_a) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
hashBuffer = _a.sent();
|
|
49
|
-
byteArray = new Uint8Array(hashBuffer);
|
|
50
|
-
return [2 /*return*/, Array.from(byteArray)
|
|
51
|
-
.map(function (byte) { return byte.toString(16).padStart(2, "0"); })
|
|
52
|
-
.join("")];
|
|
53
|
-
}
|
|
47
|
+
bytes = (0, utils_1.utf8ToBytes)(input);
|
|
48
|
+
hashBytes = (0, sha256_1.sha256)(bytes);
|
|
49
|
+
return [2 /*return*/, (0, utils_1.bytesToHex)(hashBytes)];
|
|
54
50
|
});
|
|
55
51
|
});
|
|
56
52
|
}
|
|
57
53
|
function generateNativeUUID() {
|
|
58
|
-
|
|
54
|
+
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
55
|
+
return crypto.randomUUID();
|
|
56
|
+
}
|
|
57
|
+
// Fallback using crypto.getRandomValues (available in insecure contexts)
|
|
58
|
+
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
|
|
59
|
+
var bytes = new Uint8Array(16);
|
|
60
|
+
crypto.getRandomValues(bytes);
|
|
61
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
|
|
62
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 1
|
|
63
|
+
var hex = Array.from(bytes).map(function (b) { return b.toString(16).padStart(2, '0'); }).join('');
|
|
64
|
+
return "".concat(hex.slice(0, 8), "-").concat(hex.slice(8, 12), "-").concat(hex.slice(12, 16), "-").concat(hex.slice(16, 20), "-").concat(hex.slice(20));
|
|
65
|
+
}
|
|
66
|
+
// Last resort: Math.random (not cryptographically secure, but functional)
|
|
67
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
68
|
+
var r = (Math.random() * 16) | 0;
|
|
69
|
+
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
|
70
|
+
});
|
|
59
71
|
}
|
|
60
72
|
//# sourceMappingURL=generate.js.map
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isNetworkError = isNetworkError;
|
|
4
4
|
var objectToString = Object.prototype.toString;
|
|
5
|
-
var isError = function (value) {
|
|
5
|
+
var isError = function (value) {
|
|
6
|
+
var tag = objectToString.call(value);
|
|
7
|
+
return tag === "[object Error]" || tag === "[object DOMException]";
|
|
8
|
+
};
|
|
9
|
+
var errorNames = new Set(["TypeError", "TimeoutError", "NetworkError"]);
|
|
6
10
|
var errorMessages = new Set([
|
|
7
11
|
"network error", // Chrome
|
|
8
12
|
"Failed to fetch", // Chrome
|
|
@@ -12,11 +16,12 @@ var errorMessages = new Set([
|
|
|
12
16
|
"Network request failed", // `cross-fetch`
|
|
13
17
|
"fetch failed", // Undici (Node.js)
|
|
14
18
|
"terminated", // Undici (Node.js)
|
|
19
|
+
"The operation was aborted due to timeout", // AbortSignal.timeout()
|
|
15
20
|
]);
|
|
16
21
|
function isNetworkError(error) {
|
|
17
22
|
var isValid = error &&
|
|
18
23
|
isError(error) &&
|
|
19
|
-
error.name
|
|
24
|
+
errorNames.has(error.name) &&
|
|
20
25
|
typeof error.message === "string";
|
|
21
26
|
if (!isValid) {
|
|
22
27
|
return false;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.28.
|
|
1
|
+
export declare const version = "1.28.3";
|
|
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.28.
|
|
6
|
+
exports.version = '1.28.3';
|
|
7
7
|
//# sourceMappingURL=version.js.map
|
|
@@ -45,6 +45,8 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
45
45
|
* When true, EIP-1193 provider wrapping is skipped
|
|
46
46
|
*/
|
|
47
47
|
private isWagmiMode;
|
|
48
|
+
/** Instance-level flag so multiple SDK instances don't interfere. */
|
|
49
|
+
private crossSubdomainCookies;
|
|
48
50
|
config: Config;
|
|
49
51
|
currentChainId?: ChainID;
|
|
50
52
|
currentAddress?: Address;
|
|
@@ -57,6 +57,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
57
57
|
import { createStore } from "mipd";
|
|
58
58
|
import { EVENTS_API_HOST, EventType, LOCAL_ANONYMOUS_ID_KEY, SESSION_CURRENT_URL_KEY, SESSION_USER_ID_KEY, CONSENT_OPT_OUT_KEY, } from "./constants";
|
|
59
59
|
import { cookie, initStorageManager } from "./storage";
|
|
60
|
+
import { getIdentityCookieDomain } from "./storage/cookiePolicy";
|
|
60
61
|
import { EventManager } from "./event";
|
|
61
62
|
import { EventQueue } from "./queue";
|
|
62
63
|
import { logger, Logger } from "./logger";
|
|
@@ -81,7 +82,7 @@ var PROVIDER_SWITCH_REASONS = {
|
|
|
81
82
|
var FormoAnalytics = /** @class */ (function () {
|
|
82
83
|
function FormoAnalytics(writeKey, options) {
|
|
83
84
|
if (options === void 0) { options = {}; }
|
|
84
|
-
var _a, _b;
|
|
85
|
+
var _a, _b, _c;
|
|
85
86
|
this.writeKey = writeKey;
|
|
86
87
|
this.options = options;
|
|
87
88
|
// Per-chain namespace state — isolates EVM and Solana connection state
|
|
@@ -120,6 +121,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
120
121
|
this.options = options;
|
|
121
122
|
// Check if Wagmi mode is enabled
|
|
122
123
|
this.isWagmiMode = !!options.wagmi;
|
|
124
|
+
this.crossSubdomainCookies = (_a = options.crossSubdomainCookies) !== null && _a !== void 0 ? _a : true;
|
|
125
|
+
// Normalize so downstream consumers (EventFactory) read the resolved value.
|
|
126
|
+
options.crossSubdomainCookies = this.crossSubdomainCookies;
|
|
123
127
|
this.session = new FormoAnalyticsSession();
|
|
124
128
|
this.currentUserId =
|
|
125
129
|
cookie().get(SESSION_USER_ID_KEY) || undefined;
|
|
@@ -134,8 +138,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
134
138
|
this.isAutocaptureEnabled = this.isAutocaptureEnabled.bind(this);
|
|
135
139
|
// Initialize logger with configuration from options
|
|
136
140
|
Logger.init({
|
|
137
|
-
enabled: ((
|
|
138
|
-
enabledLevels: ((
|
|
141
|
+
enabled: ((_b = options.logger) === null || _b === void 0 ? void 0 : _b.enabled) || false,
|
|
142
|
+
enabledLevels: ((_c = options.logger) === null || _c === void 0 ? void 0 : _c.levels) || [],
|
|
139
143
|
});
|
|
140
144
|
this.eventManager = new EventManager(new EventQueue(this.config.writeKey, {
|
|
141
145
|
apiHost: options.apiHost || EVENTS_API_HOST,
|
|
@@ -505,7 +509,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
505
509
|
*/
|
|
506
510
|
FormoAnalytics.prototype.identify = function (params, properties, context, callback) {
|
|
507
511
|
return __awaiter(this, void 0, void 0, function () {
|
|
508
|
-
var _i, _a, providerDetail, provider, address_1, validAddress_1, err_1, address, providerName, userId, rdns, validAddress, isAlreadyIdentified, e_1;
|
|
512
|
+
var _i, _a, providerDetail, provider, address_1, validAddress_1, err_1, address, providerName, userId, rdns, validAddress, domain, isAlreadyIdentified, e_1;
|
|
509
513
|
var _b, _c;
|
|
510
514
|
return __generator(this, function (_d) {
|
|
511
515
|
switch (_d.label) {
|
|
@@ -584,7 +588,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
584
588
|
}
|
|
585
589
|
if (userId) {
|
|
586
590
|
this.currentUserId = userId;
|
|
587
|
-
|
|
591
|
+
domain = getIdentityCookieDomain(this.crossSubdomainCookies);
|
|
592
|
+
cookie().set(SESSION_USER_ID_KEY, userId, __assign({ path: "/" }, (domain ? { domain: domain } : {})));
|
|
588
593
|
}
|
|
589
594
|
isAlreadyIdentified = this.session.isWalletIdentified(validAddress, rdns || "");
|
|
590
595
|
logger.debug("Identify: Checking deduplication", {
|
|
@@ -95,6 +95,7 @@ var InitializedAnalytics = function (_a) {
|
|
|
95
95
|
var serializableOptions = {
|
|
96
96
|
tracking: options.tracking,
|
|
97
97
|
autocapture: options.autocapture,
|
|
98
|
+
crossSubdomainCookies: options.crossSubdomainCookies,
|
|
98
99
|
apiHost: options.apiHost,
|
|
99
100
|
flushAt: options.flushAt,
|
|
100
101
|
flushInterval: options.flushInterval,
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Formo projects on the same domain.
|
|
8
8
|
*/
|
|
9
9
|
import { secureHash } from '../utils/hash';
|
|
10
|
+
import { getApexDomain } from '../utils/domain';
|
|
10
11
|
/**
|
|
11
12
|
* Generate a project-specific cookie key to avoid conflicts between different Formo projects
|
|
12
13
|
* Uses hashed writeKey for privacy and security
|
|
@@ -36,7 +37,14 @@ export function setConsentFlag(projectId, key, value) {
|
|
|
36
37
|
var expires = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toUTCString(); // 1 year (GDPR compliant)
|
|
37
38
|
var isSecure = ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.protocol) === 'https:';
|
|
38
39
|
// Enhanced privacy settings: Secure (HTTPS), SameSite=Strict for consent cookies
|
|
39
|
-
|
|
40
|
+
var domain = getApexDomain();
|
|
41
|
+
var domainAttr = domain ? "; domain=.".concat(domain) : '';
|
|
42
|
+
// Expire any legacy host-only cookie (pre-domain-attribute versions) so it
|
|
43
|
+
// doesn't shadow the new domain-wide cookie in document.cookie reads.
|
|
44
|
+
if (domain) {
|
|
45
|
+
document.cookie = "".concat(projectSpecificKey, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;");
|
|
46
|
+
}
|
|
47
|
+
document.cookie = "".concat(projectSpecificKey, "=").concat(encodeURIComponent(value), "; expires=").concat(expires, "; path=/").concat(domainAttr, "; SameSite=Strict").concat(isSecure ? '; Secure' : '');
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
/**
|
|
@@ -83,15 +91,9 @@ function deleteCookieDirectly(cookieName) {
|
|
|
83
91
|
// Clear from current domain/path
|
|
84
92
|
document.cookie = "".concat(cookieName, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;");
|
|
85
93
|
// Try to clear from parent domain if it's a proper multi-level domain
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// Only try parent domain deletion for proper domains with multiple parts
|
|
90
|
-
// Skip localhost and single-level domains
|
|
91
|
-
if (parts.length >= 2 && hostname !== 'localhost') {
|
|
92
|
-
var domain = parts.slice(-2).join('.');
|
|
93
|
-
document.cookie = "".concat(cookieName, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.").concat(domain, ";");
|
|
94
|
-
}
|
|
94
|
+
var domain = getApexDomain();
|
|
95
|
+
if (domain) {
|
|
96
|
+
document.cookie = "".concat(cookieName, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.").concat(domain, ";");
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
//# sourceMappingURL=index.js.map
|
|
@@ -289,22 +289,22 @@ var EventFactory = /** @class */ (function () {
|
|
|
289
289
|
return __awaiter(this, void 0, void 0, function () {
|
|
290
290
|
var commonEventData, eventChainId, validAddress, processedEvent;
|
|
291
291
|
var _a;
|
|
292
|
-
var _b;
|
|
293
|
-
return __generator(this, function (
|
|
294
|
-
switch (
|
|
292
|
+
var _b, _c;
|
|
293
|
+
return __generator(this, function (_d) {
|
|
294
|
+
switch (_d.label) {
|
|
295
295
|
case 0:
|
|
296
296
|
_a = {};
|
|
297
297
|
return [4 /*yield*/, this.generateContext(context)];
|
|
298
298
|
case 1:
|
|
299
|
-
commonEventData = (_a.context =
|
|
299
|
+
commonEventData = (_a.context = _d.sent(),
|
|
300
300
|
_a.original_timestamp = getCurrentTimeFormatted(),
|
|
301
301
|
_a.user_id = formoEvent.user_id,
|
|
302
302
|
_a.type = formoEvent.type,
|
|
303
303
|
_a.channel = CHANNEL,
|
|
304
304
|
_a.version = VERSION,
|
|
305
305
|
_a);
|
|
306
|
-
commonEventData.anonymous_id = generateAnonymousId(LOCAL_ANONYMOUS_ID_KEY);
|
|
307
|
-
eventChainId = (
|
|
306
|
+
commonEventData.anonymous_id = generateAnonymousId(LOCAL_ANONYMOUS_ID_KEY, (_b = this.options) === null || _b === void 0 ? void 0 : _b.crossSubdomainCookies);
|
|
307
|
+
eventChainId = (_c = formoEvent.properties) === null || _c === void 0 ? void 0 : _c.chainId;
|
|
308
308
|
validAddress = this.validateEventAddress(formoEvent.address, eventChainId);
|
|
309
309
|
commonEventData.address = validAddress;
|
|
310
310
|
processedEvent = mergeDeepRight(formoEvent, commonEventData);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AnonymousID } from "../types";
|
|
2
|
-
declare const generateAnonymousId: (key: string) => AnonymousID;
|
|
3
|
-
|
|
4
|
-
export { generateAnonymousId, getCookieDomain };
|
|
2
|
+
declare const generateAnonymousId: (key: string, crossSubdomainCookies?: boolean) => AnonymousID;
|
|
3
|
+
export { generateAnonymousId };
|
|
5
4
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1,29 +1,30 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
1
12
|
import { generateNativeUUID } from "../utils";
|
|
2
13
|
import { cookie } from "../storage";
|
|
3
|
-
|
|
14
|
+
import { getIdentityCookieDomain } from "../storage/cookiePolicy";
|
|
15
|
+
var generateAnonymousId = function (key, crossSubdomainCookies) {
|
|
4
16
|
var storedAnonymousId = cookie().get(key);
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
var anonymousId = (storedAnonymousId && typeof storedAnonymousId === "string"
|
|
18
|
+
? storedAnonymousId
|
|
19
|
+
: generateNativeUUID());
|
|
20
|
+
var domain = getIdentityCookieDomain(crossSubdomainCookies);
|
|
21
|
+
// Re-set the cookie with the configured scope. When crossSubdomainCookies
|
|
22
|
+
// is true, this migrates legacy host-only cookies on the current host to the apex
|
|
23
|
+
// domain. Note: host-only cookies on other hosts (e.g. a cookie set on
|
|
24
|
+
// example.com is not visible from app.example.com) cannot be migrated
|
|
25
|
+
// until the user revisits that host.
|
|
26
|
+
cookie().set(key, anonymousId, __assign({ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365).toUTCString(), path: "/" }, (domain ? { domain: domain } : {})));
|
|
27
|
+
return anonymousId;
|
|
14
28
|
};
|
|
15
|
-
|
|
16
|
-
if (hostname === void 0) { hostname = window.location.hostname; }
|
|
17
|
-
// Special cases
|
|
18
|
-
if (hostname.includes("localhost") ||
|
|
19
|
-
/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname)) {
|
|
20
|
-
// Localhost or IP address
|
|
21
|
-
return "";
|
|
22
|
-
}
|
|
23
|
-
var parts = hostname.split(".");
|
|
24
|
-
if (parts.includes("www"))
|
|
25
|
-
parts.splice(parts.indexOf("www"), 1);
|
|
26
|
-
return ".".concat(parts.join("."));
|
|
27
|
-
}
|
|
28
|
-
export { generateAnonymousId, getCookieDomain };
|
|
29
|
+
export { generateAnonymousId };
|
|
29
30
|
//# sourceMappingURL=utils.js.map
|
|
@@ -28,7 +28,7 @@ export declare class EventQueue implements IEventQueue {
|
|
|
28
28
|
constructor(writeKey: string, options: Options);
|
|
29
29
|
private generateMessageId;
|
|
30
30
|
enqueue(event: IFormoEvent, callback?: (...args: any) => void): Promise<void>;
|
|
31
|
-
flush(callback?: (...args: any) => void): Promise<void | IFormoEventFlushPayload[]>;
|
|
31
|
+
flush(callback?: (...args: any) => void, drainAll?: boolean): Promise<void | IFormoEventFlushPayload[]>;
|
|
32
32
|
/**
|
|
33
33
|
* Returns the UTF-8 byte length of a string. The browser's keepalive limit
|
|
34
34
|
* is enforced on the wire (UTF-8 bytes), not on JS string length (UTF-16
|