@formo/analytics 1.28.1 → 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.
Files changed (66) hide show
  1. package/dist/cjs/src/FormoAnalytics.d.ts +3 -2
  2. package/dist/cjs/src/FormoAnalytics.js +19 -11
  3. package/dist/cjs/src/FormoAnalyticsProvider.js +1 -0
  4. package/dist/cjs/src/consent/index.js +12 -10
  5. package/dist/cjs/src/event/EventFactory.d.ts +1 -1
  6. package/dist/cjs/src/event/EventFactory.js +9 -9
  7. package/dist/cjs/src/event/utils.d.ts +2 -3
  8. package/dist/cjs/src/event/utils.js +24 -24
  9. package/dist/cjs/src/queue/EventQueue.d.ts +1 -1
  10. package/dist/cjs/src/queue/EventQueue.js +21 -20
  11. package/dist/cjs/src/session/index.d.ts +0 -9
  12. package/dist/cjs/src/session/index.js +7 -0
  13. package/dist/cjs/src/solana/SolanaAdapter.d.ts +3 -4
  14. package/dist/cjs/src/solana/SolanaAdapter.js +42 -29
  15. package/dist/cjs/src/storage/StorageManager.js +11 -3
  16. package/dist/cjs/src/storage/built-in/cookie.js +29 -3
  17. package/dist/cjs/src/storage/cookiePolicy.d.ts +10 -0
  18. package/dist/cjs/src/storage/cookiePolicy.js +27 -0
  19. package/dist/cjs/src/types/base.d.ts +12 -0
  20. package/dist/cjs/src/types/events.d.ts +0 -1
  21. package/dist/cjs/src/utils/address.js +4 -6
  22. package/dist/cjs/src/utils/domain.d.ts +27 -0
  23. package/dist/cjs/src/utils/domain.js +74 -0
  24. package/dist/cjs/src/utils/generate.js +23 -11
  25. package/dist/cjs/src/utils/index.d.ts +0 -1
  26. package/dist/cjs/src/utils/index.js +0 -1
  27. package/dist/cjs/src/validators/network.js +7 -2
  28. package/dist/cjs/src/version.d.ts +1 -1
  29. package/dist/cjs/src/version.js +1 -1
  30. package/dist/cjs/src/wagmi/WagmiEventHandler.js +12 -9
  31. package/dist/esm/src/FormoAnalytics.d.ts +3 -2
  32. package/dist/esm/src/FormoAnalytics.js +19 -11
  33. package/dist/esm/src/FormoAnalyticsProvider.js +1 -0
  34. package/dist/esm/src/consent/index.js +12 -10
  35. package/dist/esm/src/event/EventFactory.d.ts +1 -1
  36. package/dist/esm/src/event/EventFactory.js +9 -9
  37. package/dist/esm/src/event/utils.d.ts +2 -3
  38. package/dist/esm/src/event/utils.js +25 -24
  39. package/dist/esm/src/queue/EventQueue.d.ts +1 -1
  40. package/dist/esm/src/queue/EventQueue.js +21 -20
  41. package/dist/esm/src/session/index.d.ts +0 -9
  42. package/dist/esm/src/session/index.js +7 -0
  43. package/dist/esm/src/solana/SolanaAdapter.d.ts +3 -4
  44. package/dist/esm/src/solana/SolanaAdapter.js +42 -29
  45. package/dist/esm/src/storage/StorageManager.js +11 -3
  46. package/dist/esm/src/storage/built-in/cookie.js +29 -3
  47. package/dist/esm/src/storage/cookiePolicy.d.ts +10 -0
  48. package/dist/esm/src/storage/cookiePolicy.js +24 -0
  49. package/dist/esm/src/types/base.d.ts +12 -0
  50. package/dist/esm/src/types/events.d.ts +0 -1
  51. package/dist/esm/src/utils/address.js +4 -6
  52. package/dist/esm/src/utils/domain.d.ts +27 -0
  53. package/dist/esm/src/utils/domain.js +70 -0
  54. package/dist/esm/src/utils/generate.js +23 -11
  55. package/dist/esm/src/utils/index.d.ts +0 -1
  56. package/dist/esm/src/utils/index.js +0 -1
  57. package/dist/esm/src/validators/network.js +7 -2
  58. package/dist/esm/src/version.d.ts +1 -1
  59. package/dist/esm/src/version.js +1 -1
  60. package/dist/esm/src/wagmi/WagmiEventHandler.js +12 -9
  61. package/dist/index.umd.min.js +1 -1
  62. package/package.json +1 -1
  63. package/dist/cjs/src/utils/builderCode.d.ts +0 -30
  64. package/dist/cjs/src/utils/builderCode.js +0 -143
  65. package/dist/esm/src/utils/builderCode.d.ts +0 -30
  66. package/dist/esm/src/utils/builderCode.js +0 -140
@@ -58,7 +58,6 @@ exports.WagmiEventHandler = void 0;
58
58
  var events_1 = require("../types/events");
59
59
  var logger_1 = require("../logger");
60
60
  var utils_1 = require("./utils");
61
- var builderCode_1 = require("../utils/builderCode");
62
61
  /**
63
62
  * Built-in transaction fields that could collide with function args.
64
63
  * Defined at module level to avoid recreating on every method call.
@@ -73,7 +72,6 @@ var RESERVED_FIELDS = new Set([
73
72
  "transactionHash",
74
73
  "function_name",
75
74
  "function_args",
76
- "builder_codes",
77
75
  ]);
78
76
  /**
79
77
  * Clean up old entries from a Set to prevent memory leaks.
@@ -388,7 +386,7 @@ var WagmiEventHandler = /** @class */ (function () {
388
386
  chainId: chainId,
389
387
  blockNumber: (_a = receipt === null || receipt === void 0 ? void 0 : receipt.blockNumber) === null || _a === void 0 ? void 0 : _a.toString(),
390
388
  });
391
- this.formo.transaction(__assign(__assign(__assign(__assign(__assign(__assign({ status: txStatus, chainId: chainId || 0, address: address, transactionHash: transactionHash }, ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.data) && { data: pendingTx.data })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.to) && { to: pendingTx.to })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.value) && { value: pendingTx.value })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.function_name) && { function_name: pendingTx.function_name })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.function_args) && { function_args: pendingTx.function_args })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.builder_codes) && { builder_codes: pendingTx.builder_codes })),
389
+ this.formo.transaction(__assign(__assign(__assign(__assign(__assign({ status: txStatus, chainId: chainId || 0, address: address, transactionHash: transactionHash }, ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.data) && { data: pendingTx.data })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.to) && { to: pendingTx.to })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.value) && { value: pendingTx.value })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.function_name) && { function_name: pendingTx.function_name })), ((pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.function_args) && { function_args: pendingTx.function_args })),
392
390
  // Spread function args as additional properties (only colliding keys are prefixed)
393
391
  pendingTx === null || pendingTx === void 0 ? void 0 : pendingTx.safeFunctionArgs);
394
392
  // Clean up the pending transaction after confirmation
@@ -551,7 +549,7 @@ var WagmiEventHandler = /** @class */ (function () {
551
549
  // Encode the function data synchronously if viem is available
552
550
  var encodedData = (0, utils_1.encodeWriteContractData)(abi, fnName, args);
553
551
  if (encodedData) {
554
- // Include dataSuffix (ERC-8021 builder code) so extractBuilderCodes sees full calldata
552
+ // Include dataSuffix (e.g. ERC-8021 builder code) so full calldata is sent to server
555
553
  data = (0, utils_1.concatCalldataWithSuffix)(encodedData, dataSuffix);
556
554
  logger_1.logger.debug("WagmiEventHandler: Encoded writeContract data", data.substring(0, 10));
557
555
  }
@@ -563,9 +561,14 @@ var WagmiEventHandler = /** @class */ (function () {
563
561
  data = variables.data;
564
562
  to = variables.to;
565
563
  }
566
- // Extract builder codes from transaction data (ERC-8021)
567
- var builder_codes = (0, builderCode_1.extractBuilderCodes)(data);
568
- logger_1.logger.info("WagmiEventHandler: Tracking transaction event", __assign({ status: status_2, mutationType: mutationType, address: userAddress, chainId: chainId, transactionHash: transactionHash, function_name: function_name }, (builder_codes && { builder_codes: builder_codes })));
564
+ logger_1.logger.info("WagmiEventHandler: Tracking transaction event", {
565
+ status: status_2,
566
+ mutationType: mutationType,
567
+ address: userAddress,
568
+ chainId: chainId,
569
+ transactionHash: transactionHash,
570
+ function_name: function_name,
571
+ });
569
572
  // Build safeFunctionArgs with collision handling and struct flattening
570
573
  var safeFunctionArgs = (0, utils_1.buildSafeFunctionArgs)(function_args, RESERVED_FIELDS);
571
574
  // Store transaction details for BROADCASTED status to use in CONFIRMED/REVERTED
@@ -573,7 +576,7 @@ var WagmiEventHandler = /** @class */ (function () {
573
576
  // Include the sender address to handle wallet switches between broadcast and confirmation
574
577
  if (status_2 === events_1.TransactionStatus.BROADCASTED && transactionHash) {
575
578
  var normalizedHash = transactionHash.toLowerCase();
576
- var txDetails = __assign(__assign(__assign(__assign(__assign(__assign(__assign({ address: userAddress }, (data && { data: data })), (to && { to: to })), (value && { value: value })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), (builder_codes && { builder_codes: builder_codes })), (safeFunctionArgs && { safeFunctionArgs: safeFunctionArgs }));
579
+ var txDetails = __assign(__assign(__assign(__assign(__assign(__assign({ address: userAddress }, (data && { data: data })), (to && { to: to })), (value && { value: value })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), (safeFunctionArgs && { safeFunctionArgs: safeFunctionArgs }));
577
580
  this.pendingTransactions.set(normalizedHash, txDetails);
578
581
  logger_1.logger.debug("WagmiEventHandler: Stored pending transaction for confirmation", {
579
582
  transactionHash: normalizedHash,
@@ -587,7 +590,7 @@ var WagmiEventHandler = /** @class */ (function () {
587
590
  }
588
591
  }
589
592
  }
590
- this.formo.transaction(__assign(__assign(__assign(__assign(__assign(__assign(__assign({ status: status_2, chainId: chainId || 0, address: userAddress }, (data && { data: data })), (to && { to: to })), (value && { value: value })), (transactionHash && { transactionHash: transactionHash })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), (builder_codes && { builder_codes: builder_codes })),
593
+ this.formo.transaction(__assign(__assign(__assign(__assign(__assign(__assign({ status: status_2, chainId: chainId || 0, address: userAddress }, (data && { data: data })), (to && { to: to })), (value && { value: value })), (transactionHash && { transactionHash: transactionHash })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })),
591
594
  // Spread function args as additional properties (only colliding keys are prefixed)
592
595
  safeFunctionArgs);
593
596
  }
@@ -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;
@@ -150,7 +152,7 @@ export declare class FormoAnalytics implements IFormoAnalytics {
150
152
  * @param {(...args: unknown[]) => void} callback
151
153
  * @returns {Promise<void>}
152
154
  */
153
- transaction({ status, chainId, address, data, to, value, transactionHash, function_name, function_args, builder_codes, }: {
155
+ transaction({ status, chainId, address, data, to, value, transactionHash, function_name, function_args, }: {
154
156
  status: TransactionStatus;
155
157
  chainId: ChainID;
156
158
  address: Address;
@@ -160,7 +162,6 @@ export declare class FormoAnalytics implements IFormoAnalytics {
160
162
  transactionHash?: string;
161
163
  function_name?: string;
162
164
  function_args?: Record<string, unknown>;
163
- builder_codes?: string;
164
165
  }, properties?: IFormoEventProperties, context?: IFormoEventContext, callback?: (...args: unknown[]) => void): Promise<void>;
165
166
  /**
166
167
  * Emits an identify event with current wallet address and provider info.
@@ -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";
@@ -65,7 +66,6 @@ import { detectInjectedProviderInfo, isValidProvider } from "./provider";
65
66
  import { FormoAnalyticsSession, SESSION_WALLET_DETECTED_KEY, SESSION_WALLET_IDENTIFIED_KEY, } from "./session";
66
67
  import { SignatureStatus, TransactionStatus, WRAPPED_REQUEST_SYMBOL, WRAPPED_REQUEST_REF_SYMBOL, } from "./types";
67
68
  import { validateAddress, validateAndChecksumAddress } from "./utils/address";
68
- import { extractBuilderCodes } from "./utils/builderCode";
69
69
  import { isLocalhost } from "./validators";
70
70
  import { parseChainId } from "./utils/chain";
71
71
  import { WagmiEventHandler } from "./wagmi";
@@ -82,7 +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 _a, _b;
85
+ var _a, _b, _c;
86
86
  this.writeKey = writeKey;
87
87
  this.options = options;
88
88
  // Per-chain namespace state — isolates EVM and Solana connection state
@@ -121,6 +121,9 @@ var FormoAnalytics = /** @class */ (function () {
121
121
  this.options = options;
122
122
  // Check if Wagmi mode is enabled
123
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;
124
127
  this.session = new FormoAnalyticsSession();
125
128
  this.currentUserId =
126
129
  cookie().get(SESSION_USER_ID_KEY) || undefined;
@@ -135,8 +138,8 @@ var FormoAnalytics = /** @class */ (function () {
135
138
  this.isAutocaptureEnabled = this.isAutocaptureEnabled.bind(this);
136
139
  // Initialize logger with configuration from options
137
140
  Logger.init({
138
- enabled: ((_a = options.logger) === null || _a === void 0 ? void 0 : _a.enabled) || false,
139
- enabledLevels: ((_b = options.logger) === null || _b === void 0 ? void 0 : _b.levels) || [],
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) || [],
140
143
  });
141
144
  this.eventManager = new EventManager(new EventQueue(this.config.writeKey, {
142
145
  apiHost: options.apiHost || EVENTS_API_HOST,
@@ -465,10 +468,10 @@ var FormoAnalytics = /** @class */ (function () {
465
468
  */
466
469
  FormoAnalytics.prototype.transaction = function (_a, properties_1, context_1, callback_1) {
467
470
  return __awaiter(this, arguments, void 0, function (_b, properties, context, callback) {
468
- var status = _b.status, chainId = _b.chainId, address = _b.address, data = _b.data, to = _b.to, value = _b.value, transactionHash = _b.transactionHash, function_name = _b.function_name, function_args = _b.function_args, builder_codes = _b.builder_codes;
471
+ var status = _b.status, chainId = _b.chainId, address = _b.address, data = _b.data, to = _b.to, value = _b.value, transactionHash = _b.transactionHash, function_name = _b.function_name, function_args = _b.function_args;
469
472
  return __generator(this, function (_c) {
470
473
  switch (_c.label) {
471
- case 0: return [4 /*yield*/, this.trackEvent(EventType.TRANSACTION, __assign(__assign(__assign(__assign({ status: status, chainId: chainId, address: address, data: data, to: to, value: value }, (transactionHash && { transactionHash: transactionHash })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), (builder_codes && { builder_codes: builder_codes })), properties, context, callback)];
474
+ case 0: return [4 /*yield*/, this.trackEvent(EventType.TRANSACTION, __assign(__assign(__assign({ status: status, chainId: chainId, address: address, data: data, to: to, value: value }, (transactionHash && { transactionHash: transactionHash })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), properties, context, callback)];
472
475
  case 1:
473
476
  _c.sent();
474
477
  return [2 /*return*/];
@@ -506,7 +509,7 @@ var FormoAnalytics = /** @class */ (function () {
506
509
  */
507
510
  FormoAnalytics.prototype.identify = function (params, properties, context, callback) {
508
511
  return __awaiter(this, void 0, void 0, function () {
509
- 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;
510
513
  var _b, _c;
511
514
  return __generator(this, function (_d) {
512
515
  switch (_d.label) {
@@ -585,7 +588,8 @@ var FormoAnalytics = /** @class */ (function () {
585
588
  }
586
589
  if (userId) {
587
590
  this.currentUserId = userId;
588
- cookie().set(SESSION_USER_ID_KEY, userId);
591
+ domain = getIdentityCookieDomain(this.crossSubdomainCookies);
592
+ cookie().set(SESSION_USER_ID_KEY, userId, __assign({ path: "/" }, (domain ? { domain: domain } : {})));
589
593
  }
590
594
  isAlreadyIdentified = this.session.isWalletIdentified(validAddress, rdns || "");
591
595
  logger.debug("Identify: Checking deduplication", {
@@ -1900,7 +1904,7 @@ var FormoAnalytics = /** @class */ (function () {
1900
1904
  };
1901
1905
  FormoAnalytics.prototype.buildTransactionEventPayload = function (params, provider) {
1902
1906
  return __awaiter(this, void 0, void 0, function () {
1903
- var _a, data, from, to, value, validAddress, builder_codes, _b;
1907
+ var _a, data, from, to, value, validAddress, _b;
1904
1908
  var _c;
1905
1909
  return __generator(this, function (_d) {
1906
1910
  switch (_d.label) {
@@ -1910,7 +1914,6 @@ var FormoAnalytics = /** @class */ (function () {
1910
1914
  if (!validAddress) {
1911
1915
  throw new Error("Invalid address in transaction payload: ".concat(from));
1912
1916
  }
1913
- builder_codes = extractBuilderCodes(data);
1914
1917
  _c = {};
1915
1918
  _b = this._evmChainId;
1916
1919
  if (_b) return [3 /*break*/, 2];
@@ -1918,7 +1921,12 @@ var FormoAnalytics = /** @class */ (function () {
1918
1921
  case 1:
1919
1922
  _b = (_d.sent());
1920
1923
  _d.label = 2;
1921
- case 2: return [2 /*return*/, __assign.apply(void 0, [(_c.chainId = _b, _c.data = data, _c.address = validAddress, _c.to = to, _c.value = value, _c), (builder_codes && { builder_codes: builder_codes })])];
1924
+ case 2: return [2 /*return*/, (_c.chainId = _b,
1925
+ _c.data = data,
1926
+ _c.address = validAddress,
1927
+ _c.to = to,
1928
+ _c.value = value,
1929
+ _c)];
1922
1930
  }
1923
1931
  });
1924
1932
  });
@@ -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
- document.cookie = "".concat(projectSpecificKey, "=").concat(encodeURIComponent(value), "; expires=").concat(expires, "; path=/; SameSite=Strict").concat(isSecure ? '; Secure' : '');
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
- if (typeof window !== 'undefined') {
87
- var hostname = window.location.hostname;
88
- var parts = hostname.split('.');
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
@@ -35,7 +35,7 @@ declare class EventFactory implements IEventFactory {
35
35
  generateDisconnectEvent(chainId?: ChainID, address?: Address, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
36
36
  generateChainChangedEvent(chainId: ChainID, address: Address, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
37
37
  generateSignatureEvent(status: SignatureStatus, chainId: ChainID, address: Address, message: string, signatureHash?: string, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
38
- generateTransactionEvent(status: TransactionStatus, chainId: ChainID, address: Address, data?: string, to?: string, value?: string, transactionHash?: string, function_name?: string, function_args?: Record<string, unknown>, builder_codes?: string, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
38
+ generateTransactionEvent(status: TransactionStatus, chainId: ChainID, address: Address, data?: string, to?: string, value?: string, transactionHash?: string, function_name?: string, function_args?: Record<string, unknown>, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
39
39
  generateTrackEvent(event: string, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
40
40
  create(event: APIEvent, address?: Address, userId?: string): Promise<IFormoEvent>;
41
41
  }
@@ -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 (_c) {
294
- switch (_c.label) {
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 = _c.sent(),
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 = (_b = formoEvent.properties) === null || _b === void 0 ? void 0 : _b.chainId;
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);
@@ -413,12 +413,12 @@ var EventFactory = /** @class */ (function () {
413
413
  });
414
414
  });
415
415
  };
416
- EventFactory.prototype.generateTransactionEvent = function (status, chainId, address, data, to, value, transactionHash, function_name, function_args, builder_codes, properties, context) {
416
+ EventFactory.prototype.generateTransactionEvent = function (status, chainId, address, data, to, value, transactionHash, function_name, function_args, properties, context) {
417
417
  return __awaiter(this, void 0, void 0, function () {
418
418
  var transactionEvent;
419
419
  return __generator(this, function (_a) {
420
420
  transactionEvent = {
421
- properties: __assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign({ status: status, chainId: chainId }, (data && { data: data })), (to && { to: to })), (value && { value: value })), (transactionHash && { transactionHash: transactionHash })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), (builder_codes && { builder_codes: builder_codes })), properties),
421
+ properties: __assign(__assign(__assign(__assign(__assign(__assign(__assign({ status: status, chainId: chainId }, (data && { data: data })), (to && { to: to })), (value && { value: value })), (transactionHash && { transactionHash: transactionHash })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), properties),
422
422
  address: address,
423
423
  type: "transaction",
424
424
  };
@@ -497,7 +497,7 @@ var EventFactory = /** @class */ (function () {
497
497
  case 14:
498
498
  formoEvent = _b.sent();
499
499
  return [3 /*break*/, 19];
500
- case 15: return [4 /*yield*/, this.generateTransactionEvent(event.status, event.chainId, event.address, event.data, event.to, event.value, event.transactionHash, event.function_name, event.function_args, event.builder_codes, event.properties, event.context)];
500
+ case 15: return [4 /*yield*/, this.generateTransactionEvent(event.status, event.chainId, event.address, event.data, event.to, event.value, event.transactionHash, event.function_name, event.function_args, event.properties, event.context)];
501
501
  case 16:
502
502
  formoEvent = _b.sent();
503
503
  return [3 /*break*/, 19];
@@ -1,5 +1,4 @@
1
1
  import { AnonymousID } from "../types";
2
- declare const generateAnonymousId: (key: string) => AnonymousID;
3
- declare function getCookieDomain(hostname?: string): string;
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
- var generateAnonymousId = function (key) {
14
+ import { getIdentityCookieDomain } from "../storage/cookiePolicy";
15
+ var generateAnonymousId = function (key, crossSubdomainCookies) {
4
16
  var storedAnonymousId = cookie().get(key);
5
- if (storedAnonymousId && typeof storedAnonymousId === "string")
6
- return storedAnonymousId;
7
- var newAnonymousId = generateNativeUUID();
8
- cookie().set(key, newAnonymousId, {
9
- maxAge: Date.now() + 1000 * 60 * 60 * 24 * 365, // 1 year
10
- domain: getCookieDomain(),
11
- path: "/",
12
- });
13
- return newAnonymousId;
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
- function getCookieDomain(hostname) {
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
@@ -118,12 +118,12 @@ var EventQueue = /** @class */ (function () {
118
118
  });
119
119
  // Catches the page being hidden, including scenarios like closing the tab.
120
120
  document.addEventListener("pagehide", function () {
121
- isAccessible = document.visibilityState === "hidden";
121
+ isAccessible = document.visibilityState !== "hidden";
122
122
  handleOnLeave();
123
123
  });
124
124
  // Catches visibility changes, such as switching tabs or minimizing the browser.
125
125
  document.addEventListener("visibilitychange", function () {
126
- isAccessible = true;
126
+ isAccessible = document.visibilityState !== "hidden";
127
127
  if (document.visibilityState === "hidden") {
128
128
  handleOnLeave();
129
129
  }
@@ -149,7 +149,7 @@ var EventQueue = /** @class */ (function () {
149
149
  switch (_a.label) {
150
150
  case 0:
151
151
  if (!(isAccessible === false)) return [3 /*break*/, 2];
152
- return [4 /*yield*/, this.flush()];
152
+ return [4 /*yield*/, this.flush(undefined, true)];
153
153
  case 1:
154
154
  _a.sent();
155
155
  _a.label = 2;
@@ -179,10 +179,8 @@ var EventQueue = /** @class */ (function () {
179
179
  return [4 /*yield*/, this.generateMessageId(event)];
180
180
  case 1:
181
181
  message_id = _a.sent();
182
- return [4 /*yield*/, this.isDuplicate(message_id)];
183
- case 2:
184
182
  // check if the message already exists
185
- if (_a.sent()) {
183
+ if (this.isDuplicate(message_id)) {
186
184
  logger.warn("Event already enqueued, try again after ".concat(millisecondsToSecond(this.flushIntervalMs), " seconds."));
187
185
  return [2 /*return*/];
188
186
  }
@@ -211,10 +209,11 @@ var EventQueue = /** @class */ (function () {
211
209
  });
212
210
  });
213
211
  };
214
- EventQueue.prototype.flush = function (callback) {
215
- return __awaiter(this, void 0, void 0, function () {
216
- var items, sentAt, data, batches;
212
+ EventQueue.prototype.flush = function (callback_1) {
213
+ return __awaiter(this, arguments, void 0, function (callback, drainAll) {
214
+ var items, _i, items_1, item, sentAt, data, batches;
217
215
  var _this = this;
216
+ if (drainAll === void 0) { drainAll = false; }
218
217
  return __generator(this, function (_a) {
219
218
  switch (_a.label) {
220
219
  case 0:
@@ -228,13 +227,19 @@ var EventQueue = /** @class */ (function () {
228
227
  return [2 /*return*/, Promise.resolve()];
229
228
  }
230
229
  if (!this.pendingFlush) return [3 /*break*/, 2];
230
+ if (!!drainAll) return [3 /*break*/, 2];
231
231
  return [4 /*yield*/, this.pendingFlush];
232
232
  case 1:
233
233
  _a.sent();
234
234
  _a.label = 2;
235
235
  case 2:
236
- items = this.queue.splice(0, this.flushAt);
237
- this.payloadHashes.clear();
236
+ items = this.queue.splice(0, drainAll ? this.queue.length : this.flushAt);
237
+ // Only remove hashes for flushed items so duplicate detection remains
238
+ // active for events still in the queue.
239
+ for (_i = 0, items_1 = items; _i < items_1.length; _i++) {
240
+ item = items_1[_i];
241
+ this.payloadHashes.delete(item.message.message_id);
242
+ }
238
243
  sentAt = new Date().toISOString();
239
244
  data = items.map(function (item) { return (__assign(__assign({}, item.message), { sent_at: sentAt })); });
240
245
  batches = this.splitIntoBatches(items, data);
@@ -396,15 +401,11 @@ var EventQueue = /** @class */ (function () {
396
401
  return false;
397
402
  };
398
403
  EventQueue.prototype.isDuplicate = function (eventId) {
399
- return __awaiter(this, void 0, void 0, function () {
400
- return __generator(this, function (_a) {
401
- // check if exists a message with identical payload within 1 minute
402
- if (this.payloadHashes.has(eventId))
403
- return [2 /*return*/, true];
404
- this.payloadHashes.add(eventId);
405
- return [2 /*return*/, false];
406
- });
407
- });
404
+ // check if exists a message with identical payload within 1 minute
405
+ if (this.payloadHashes.has(eventId))
406
+ return true;
407
+ this.payloadHashes.add(eventId);
408
+ return false;
408
409
  };
409
410
  return EventQueue;
410
411
  }());
@@ -38,15 +38,6 @@ export interface IFormoAnalyticsSession {
38
38
  */
39
39
  markWalletIdentified(address: string, rdns: string): void;
40
40
  }
41
- /**
42
- * Implementation of session management using cookies
43
- *
44
- * Tracks:
45
- * - Detected wallets (by RDNS) - to prevent duplicate detection events
46
- * - Identified wallet-address pairs - to prevent duplicate identification events
47
- *
48
- * Session data expires at end of day (86400 seconds).
49
- */
50
41
  export declare class FormoAnalyticsSession implements IFormoAnalyticsSession {
51
42
  /**
52
43
  * Generate a unique key for wallet identification tracking
@@ -22,6 +22,7 @@ export var SESSION_WALLET_IDENTIFIED_KEY = "wallet-identified";
22
22
  *
23
23
  * Session data expires at end of day (86400 seconds).
24
24
  */
25
+ var MAX_SESSION_ENTRIES = 20;
25
26
  var FormoAnalyticsSession = /** @class */ (function () {
26
27
  function FormoAnalyticsSession() {
27
28
  }
@@ -59,6 +60,9 @@ var FormoAnalyticsSession = /** @class */ (function () {
59
60
  var rdnses = ((_a = cookie().get(SESSION_WALLET_DETECTED_KEY)) === null || _a === void 0 ? void 0 : _a.split(",")) || [];
60
61
  if (!rdnses.includes(rdns)) {
61
62
  rdnses.push(rdns);
63
+ if (rdnses.length > MAX_SESSION_ENTRIES) {
64
+ rdnses.splice(0, rdnses.length - MAX_SESSION_ENTRIES);
65
+ }
62
66
  cookie().set(SESSION_WALLET_DETECTED_KEY, rdnses.join(","), {
63
67
  // Expires by the end of the day
64
68
  expires: new Date(Date.now() + 86400 * 1000).toUTCString(),
@@ -99,6 +103,9 @@ var FormoAnalyticsSession = /** @class */ (function () {
99
103
  var alreadyExists = identifiedWallets.includes(identifiedKey);
100
104
  if (!alreadyExists) {
101
105
  identifiedWallets.push(identifiedKey);
106
+ if (identifiedWallets.length > MAX_SESSION_ENTRIES) {
107
+ identifiedWallets.splice(0, identifiedWallets.length - MAX_SESSION_ENTRIES);
108
+ }
102
109
  var newValue = identifiedWallets.join(",");
103
110
  cookie().set(SESSION_WALLET_IDENTIFIED_KEY, newValue, {
104
111
  // Expires by the end of the day
@@ -26,11 +26,10 @@ export declare class SolanaAdapter {
26
26
  */
27
27
  private pendingTransactions;
28
28
  /**
29
- * Original adapter methods that we wrap for tracking
29
+ * Per-adapter original methods stored in a WeakMap to prevent routing
30
+ * to the wrong wallet after switching adapters.
30
31
  */
31
- private originalAdapterSendTransaction?;
32
- private originalAdapterSignMessage?;
33
- private originalAdapterSignTransaction?;
32
+ private adapterOriginals;
34
33
  /**
35
34
  * Bound wrapper references — used to detect when external code (e.g. StandardWalletAdapter._reset())
36
35
  * overwrites our wraps so we can re-apply them.