@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
@@ -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.
@@ -60,6 +60,7 @@ exports.FormoAnalytics = void 0;
60
60
  var mipd_1 = require("mipd");
61
61
  var constants_1 = require("./constants");
62
62
  var storage_1 = require("./storage");
63
+ var cookiePolicy_1 = require("./storage/cookiePolicy");
63
64
  var event_1 = require("./event");
64
65
  var queue_1 = require("./queue");
65
66
  var logger_1 = require("./logger");
@@ -68,7 +69,6 @@ var provider_1 = require("./provider");
68
69
  var session_1 = require("./session");
69
70
  var types_1 = require("./types");
70
71
  var address_1 = require("./utils/address");
71
- var builderCode_1 = require("./utils/builderCode");
72
72
  var validators_1 = require("./validators");
73
73
  var chain_1 = require("./utils/chain");
74
74
  var wagmi_1 = require("./wagmi");
@@ -85,7 +85,7 @@ var PROVIDER_SWITCH_REASONS = {
85
85
  var FormoAnalytics = /** @class */ (function () {
86
86
  function FormoAnalytics(writeKey, options) {
87
87
  if (options === void 0) { options = {}; }
88
- var _a, _b;
88
+ var _a, _b, _c;
89
89
  this.writeKey = writeKey;
90
90
  this.options = options;
91
91
  // Per-chain namespace state — isolates EVM and Solana connection state
@@ -124,6 +124,9 @@ var FormoAnalytics = /** @class */ (function () {
124
124
  this.options = options;
125
125
  // Check if Wagmi mode is enabled
126
126
  this.isWagmiMode = !!options.wagmi;
127
+ this.crossSubdomainCookies = (_a = options.crossSubdomainCookies) !== null && _a !== void 0 ? _a : true;
128
+ // Normalize so downstream consumers (EventFactory) read the resolved value.
129
+ options.crossSubdomainCookies = this.crossSubdomainCookies;
127
130
  this.session = new session_1.FormoAnalyticsSession();
128
131
  this.currentUserId =
129
132
  (0, storage_1.cookie)().get(constants_1.SESSION_USER_ID_KEY) || undefined;
@@ -138,8 +141,8 @@ var FormoAnalytics = /** @class */ (function () {
138
141
  this.isAutocaptureEnabled = this.isAutocaptureEnabled.bind(this);
139
142
  // Initialize logger with configuration from options
140
143
  logger_1.Logger.init({
141
- enabled: ((_a = options.logger) === null || _a === void 0 ? void 0 : _a.enabled) || false,
142
- enabledLevels: ((_b = options.logger) === null || _b === void 0 ? void 0 : _b.levels) || [],
144
+ enabled: ((_b = options.logger) === null || _b === void 0 ? void 0 : _b.enabled) || false,
145
+ enabledLevels: ((_c = options.logger) === null || _c === void 0 ? void 0 : _c.levels) || [],
143
146
  });
144
147
  this.eventManager = new event_1.EventManager(new queue_1.EventQueue(this.config.writeKey, {
145
148
  apiHost: options.apiHost || constants_1.EVENTS_API_HOST,
@@ -468,10 +471,10 @@ var FormoAnalytics = /** @class */ (function () {
468
471
  */
469
472
  FormoAnalytics.prototype.transaction = function (_a, properties_1, context_1, callback_1) {
470
473
  return __awaiter(this, arguments, void 0, function (_b, properties, context, callback) {
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, builder_codes = _b.builder_codes;
474
+ 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;
472
475
  return __generator(this, function (_c) {
473
476
  switch (_c.label) {
474
- case 0: return [4 /*yield*/, this.trackEvent(constants_1.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)];
477
+ case 0: return [4 /*yield*/, this.trackEvent(constants_1.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)];
475
478
  case 1:
476
479
  _c.sent();
477
480
  return [2 /*return*/];
@@ -509,7 +512,7 @@ var FormoAnalytics = /** @class */ (function () {
509
512
  */
510
513
  FormoAnalytics.prototype.identify = function (params, properties, context, callback) {
511
514
  return __awaiter(this, void 0, void 0, function () {
512
- var _i, _a, providerDetail, provider, address_2, validAddress_1, err_1, address, providerName, userId, rdns, validAddress, isAlreadyIdentified, e_1;
515
+ var _i, _a, providerDetail, provider, address_2, validAddress_1, err_1, address, providerName, userId, rdns, validAddress, domain, isAlreadyIdentified, e_1;
513
516
  var _b, _c;
514
517
  return __generator(this, function (_d) {
515
518
  switch (_d.label) {
@@ -588,7 +591,8 @@ var FormoAnalytics = /** @class */ (function () {
588
591
  }
589
592
  if (userId) {
590
593
  this.currentUserId = userId;
591
- (0, storage_1.cookie)().set(constants_1.SESSION_USER_ID_KEY, userId);
594
+ domain = (0, cookiePolicy_1.getIdentityCookieDomain)(this.crossSubdomainCookies);
595
+ (0, storage_1.cookie)().set(constants_1.SESSION_USER_ID_KEY, userId, __assign({ path: "/" }, (domain ? { domain: domain } : {})));
592
596
  }
593
597
  isAlreadyIdentified = this.session.isWalletIdentified(validAddress, rdns || "");
594
598
  logger_1.logger.debug("Identify: Checking deduplication", {
@@ -1903,7 +1907,7 @@ var FormoAnalytics = /** @class */ (function () {
1903
1907
  };
1904
1908
  FormoAnalytics.prototype.buildTransactionEventPayload = function (params, provider) {
1905
1909
  return __awaiter(this, void 0, void 0, function () {
1906
- var _a, data, from, to, value, validAddress, builder_codes, _b;
1910
+ var _a, data, from, to, value, validAddress, _b;
1907
1911
  var _c;
1908
1912
  return __generator(this, function (_d) {
1909
1913
  switch (_d.label) {
@@ -1913,7 +1917,6 @@ var FormoAnalytics = /** @class */ (function () {
1913
1917
  if (!validAddress) {
1914
1918
  throw new Error("Invalid address in transaction payload: ".concat(from));
1915
1919
  }
1916
- builder_codes = (0, builderCode_1.extractBuilderCodes)(data);
1917
1920
  _c = {};
1918
1921
  _b = this._evmChainId;
1919
1922
  if (_b) return [3 /*break*/, 2];
@@ -1921,7 +1924,12 @@ var FormoAnalytics = /** @class */ (function () {
1921
1924
  case 1:
1922
1925
  _b = (_d.sent());
1923
1926
  _d.label = 2;
1924
- 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 })])];
1927
+ case 2: return [2 /*return*/, (_c.chainId = _b,
1928
+ _c.data = data,
1929
+ _c.address = validAddress,
1930
+ _c.to = to,
1931
+ _c.value = value,
1932
+ _c)];
1925
1933
  }
1926
1934
  });
1927
1935
  });
@@ -99,6 +99,7 @@ var InitializedAnalytics = function (_a) {
99
99
  var serializableOptions = {
100
100
  tracking: options.tracking,
101
101
  autocapture: options.autocapture,
102
+ crossSubdomainCookies: options.crossSubdomainCookies,
102
103
  apiHost: options.apiHost,
103
104
  flushAt: options.flushAt,
104
105
  flushInterval: options.flushInterval,
@@ -12,6 +12,7 @@ exports.setConsentFlag = setConsentFlag;
12
12
  exports.getConsentFlag = getConsentFlag;
13
13
  exports.removeConsentFlag = removeConsentFlag;
14
14
  var hash_1 = require("../utils/hash");
15
+ var domain_1 = require("../utils/domain");
15
16
  /**
16
17
  * Generate a project-specific cookie key to avoid conflicts between different Formo projects
17
18
  * Uses hashed writeKey for privacy and security
@@ -41,7 +42,14 @@ function setConsentFlag(projectId, key, value) {
41
42
  var expires = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toUTCString(); // 1 year (GDPR compliant)
42
43
  var isSecure = ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.protocol) === 'https:';
43
44
  // Enhanced privacy settings: Secure (HTTPS), SameSite=Strict for consent cookies
44
- document.cookie = "".concat(projectSpecificKey, "=").concat(encodeURIComponent(value), "; expires=").concat(expires, "; path=/; SameSite=Strict").concat(isSecure ? '; Secure' : '');
45
+ var domain = (0, domain_1.getApexDomain)();
46
+ var domainAttr = domain ? "; domain=.".concat(domain) : '';
47
+ // Expire any legacy host-only cookie (pre-domain-attribute versions) so it
48
+ // doesn't shadow the new domain-wide cookie in document.cookie reads.
49
+ if (domain) {
50
+ document.cookie = "".concat(projectSpecificKey, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;");
51
+ }
52
+ document.cookie = "".concat(projectSpecificKey, "=").concat(encodeURIComponent(value), "; expires=").concat(expires, "; path=/").concat(domainAttr, "; SameSite=Strict").concat(isSecure ? '; Secure' : '');
45
53
  }
46
54
  }
47
55
  /**
@@ -88,15 +96,9 @@ function deleteCookieDirectly(cookieName) {
88
96
  // Clear from current domain/path
89
97
  document.cookie = "".concat(cookieName, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;");
90
98
  // Try to clear from parent domain if it's a proper multi-level domain
91
- if (typeof window !== 'undefined') {
92
- var hostname = window.location.hostname;
93
- var parts = hostname.split('.');
94
- // Only try parent domain deletion for proper domains with multiple parts
95
- // Skip localhost and single-level domains
96
- if (parts.length >= 2 && hostname !== 'localhost') {
97
- var domain = parts.slice(-2).join('.');
98
- document.cookie = "".concat(cookieName, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.").concat(domain, ";");
99
- }
99
+ var domain = (0, domain_1.getApexDomain)();
100
+ if (domain) {
101
+ document.cookie = "".concat(cookieName, "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.").concat(domain, ";");
100
102
  }
101
103
  }
102
104
  //# 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
  }
@@ -295,22 +295,22 @@ var EventFactory = /** @class */ (function () {
295
295
  return __awaiter(this, void 0, void 0, function () {
296
296
  var commonEventData, eventChainId, validAddress, processedEvent;
297
297
  var _a;
298
- var _b;
299
- return __generator(this, function (_c) {
300
- switch (_c.label) {
298
+ var _b, _c;
299
+ return __generator(this, function (_d) {
300
+ switch (_d.label) {
301
301
  case 0:
302
302
  _a = {};
303
303
  return [4 /*yield*/, this.generateContext(context)];
304
304
  case 1:
305
- commonEventData = (_a.context = _c.sent(),
305
+ commonEventData = (_a.context = _d.sent(),
306
306
  _a.original_timestamp = (0, timestamp_1.getCurrentTimeFormatted)(),
307
307
  _a.user_id = formoEvent.user_id,
308
308
  _a.type = formoEvent.type,
309
309
  _a.channel = constants_2.CHANNEL,
310
310
  _a.version = constants_2.VERSION,
311
311
  _a);
312
- commonEventData.anonymous_id = (0, utils_2.generateAnonymousId)(constants_1.LOCAL_ANONYMOUS_ID_KEY);
313
- eventChainId = (_b = formoEvent.properties) === null || _b === void 0 ? void 0 : _b.chainId;
312
+ commonEventData.anonymous_id = (0, utils_2.generateAnonymousId)(constants_1.LOCAL_ANONYMOUS_ID_KEY, (_b = this.options) === null || _b === void 0 ? void 0 : _b.crossSubdomainCookies);
313
+ eventChainId = (_c = formoEvent.properties) === null || _c === void 0 ? void 0 : _c.chainId;
314
314
  validAddress = this.validateEventAddress(formoEvent.address, eventChainId);
315
315
  commonEventData.address = validAddress;
316
316
  processedEvent = (0, mergeDeepRight_1.default)(formoEvent, commonEventData);
@@ -419,12 +419,12 @@ var EventFactory = /** @class */ (function () {
419
419
  });
420
420
  });
421
421
  };
422
- EventFactory.prototype.generateTransactionEvent = function (status, chainId, address, data, to, value, transactionHash, function_name, function_args, builder_codes, properties, context) {
422
+ EventFactory.prototype.generateTransactionEvent = function (status, chainId, address, data, to, value, transactionHash, function_name, function_args, properties, context) {
423
423
  return __awaiter(this, void 0, void 0, function () {
424
424
  var transactionEvent;
425
425
  return __generator(this, function (_a) {
426
426
  transactionEvent = {
427
- 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),
427
+ 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),
428
428
  address: address,
429
429
  type: "transaction",
430
430
  };
@@ -503,7 +503,7 @@ var EventFactory = /** @class */ (function () {
503
503
  case 14:
504
504
  formoEvent = _b.sent();
505
505
  return [3 /*break*/, 19];
506
- 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)];
506
+ 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)];
507
507
  case 16:
508
508
  formoEvent = _b.sent();
509
509
  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,33 +1,33 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  Object.defineProperty(exports, "__esModule", { value: true });
3
14
  exports.generateAnonymousId = void 0;
4
- exports.getCookieDomain = getCookieDomain;
5
15
  var utils_1 = require("../utils");
6
16
  var storage_1 = require("../storage");
7
- var generateAnonymousId = function (key) {
17
+ var cookiePolicy_1 = require("../storage/cookiePolicy");
18
+ var generateAnonymousId = function (key, crossSubdomainCookies) {
8
19
  var storedAnonymousId = (0, storage_1.cookie)().get(key);
9
- if (storedAnonymousId && typeof storedAnonymousId === "string")
10
- return storedAnonymousId;
11
- var newAnonymousId = (0, utils_1.generateNativeUUID)();
12
- (0, storage_1.cookie)().set(key, newAnonymousId, {
13
- maxAge: Date.now() + 1000 * 60 * 60 * 24 * 365, // 1 year
14
- domain: getCookieDomain(),
15
- path: "/",
16
- });
17
- return newAnonymousId;
20
+ var anonymousId = (storedAnonymousId && typeof storedAnonymousId === "string"
21
+ ? storedAnonymousId
22
+ : (0, utils_1.generateNativeUUID)());
23
+ var domain = (0, cookiePolicy_1.getIdentityCookieDomain)(crossSubdomainCookies);
24
+ // Re-set the cookie with the configured scope. When crossSubdomainCookies
25
+ // is true, this migrates legacy host-only cookies on the current host to the apex
26
+ // domain. Note: host-only cookies on other hosts (e.g. a cookie set on
27
+ // example.com is not visible from app.example.com) cannot be migrated
28
+ // until the user revisits that host.
29
+ (0, storage_1.cookie)().set(key, anonymousId, __assign({ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365).toUTCString(), path: "/" }, (domain ? { domain: domain } : {})));
30
+ return anonymousId;
18
31
  };
19
32
  exports.generateAnonymousId = generateAnonymousId;
20
- function getCookieDomain(hostname) {
21
- if (hostname === void 0) { hostname = window.location.hostname; }
22
- // Special cases
23
- if (hostname.includes("localhost") ||
24
- /^\d{1,3}(\.\d{1,3}){3}$/.test(hostname)) {
25
- // Localhost or IP address
26
- return "";
27
- }
28
- var parts = hostname.split(".");
29
- if (parts.includes("www"))
30
- parts.splice(parts.indexOf("www"), 1);
31
- return ".".concat(parts.join("."));
32
- }
33
33
  //# 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
@@ -124,12 +124,12 @@ var EventQueue = /** @class */ (function () {
124
124
  });
125
125
  // Catches the page being hidden, including scenarios like closing the tab.
126
126
  document.addEventListener("pagehide", function () {
127
- isAccessible = document.visibilityState === "hidden";
127
+ isAccessible = document.visibilityState !== "hidden";
128
128
  handleOnLeave();
129
129
  });
130
130
  // Catches visibility changes, such as switching tabs or minimizing the browser.
131
131
  document.addEventListener("visibilitychange", function () {
132
- isAccessible = true;
132
+ isAccessible = document.visibilityState !== "hidden";
133
133
  if (document.visibilityState === "hidden") {
134
134
  handleOnLeave();
135
135
  }
@@ -155,7 +155,7 @@ var EventQueue = /** @class */ (function () {
155
155
  switch (_a.label) {
156
156
  case 0:
157
157
  if (!(isAccessible === false)) return [3 /*break*/, 2];
158
- return [4 /*yield*/, this.flush()];
158
+ return [4 /*yield*/, this.flush(undefined, true)];
159
159
  case 1:
160
160
  _a.sent();
161
161
  _a.label = 2;
@@ -185,10 +185,8 @@ var EventQueue = /** @class */ (function () {
185
185
  return [4 /*yield*/, this.generateMessageId(event)];
186
186
  case 1:
187
187
  message_id = _a.sent();
188
- return [4 /*yield*/, this.isDuplicate(message_id)];
189
- case 2:
190
188
  // check if the message already exists
191
- if (_a.sent()) {
189
+ if (this.isDuplicate(message_id)) {
192
190
  logger_1.logger.warn("Event already enqueued, try again after ".concat((0, utils_1.millisecondsToSecond)(this.flushIntervalMs), " seconds."));
193
191
  return [2 /*return*/];
194
192
  }
@@ -217,10 +215,11 @@ var EventQueue = /** @class */ (function () {
217
215
  });
218
216
  });
219
217
  };
220
- EventQueue.prototype.flush = function (callback) {
221
- return __awaiter(this, void 0, void 0, function () {
222
- var items, sentAt, data, batches;
218
+ EventQueue.prototype.flush = function (callback_1) {
219
+ return __awaiter(this, arguments, void 0, function (callback, drainAll) {
220
+ var items, _i, items_1, item, sentAt, data, batches;
223
221
  var _this = this;
222
+ if (drainAll === void 0) { drainAll = false; }
224
223
  return __generator(this, function (_a) {
225
224
  switch (_a.label) {
226
225
  case 0:
@@ -234,13 +233,19 @@ var EventQueue = /** @class */ (function () {
234
233
  return [2 /*return*/, Promise.resolve()];
235
234
  }
236
235
  if (!this.pendingFlush) return [3 /*break*/, 2];
236
+ if (!!drainAll) return [3 /*break*/, 2];
237
237
  return [4 /*yield*/, this.pendingFlush];
238
238
  case 1:
239
239
  _a.sent();
240
240
  _a.label = 2;
241
241
  case 2:
242
- items = this.queue.splice(0, this.flushAt);
243
- this.payloadHashes.clear();
242
+ items = this.queue.splice(0, drainAll ? this.queue.length : this.flushAt);
243
+ // Only remove hashes for flushed items so duplicate detection remains
244
+ // active for events still in the queue.
245
+ for (_i = 0, items_1 = items; _i < items_1.length; _i++) {
246
+ item = items_1[_i];
247
+ this.payloadHashes.delete(item.message.message_id);
248
+ }
244
249
  sentAt = new Date().toISOString();
245
250
  data = items.map(function (item) { return (__assign(__assign({}, item.message), { sent_at: sentAt })); });
246
251
  batches = this.splitIntoBatches(items, data);
@@ -402,15 +407,11 @@ var EventQueue = /** @class */ (function () {
402
407
  return false;
403
408
  };
404
409
  EventQueue.prototype.isDuplicate = function (eventId) {
405
- return __awaiter(this, void 0, void 0, function () {
406
- return __generator(this, function (_a) {
407
- // check if exists a message with identical payload within 1 minute
408
- if (this.payloadHashes.has(eventId))
409
- return [2 /*return*/, true];
410
- this.payloadHashes.add(eventId);
411
- return [2 /*return*/, false];
412
- });
413
- });
410
+ // check if exists a message with identical payload within 1 minute
411
+ if (this.payloadHashes.has(eventId))
412
+ return true;
413
+ this.payloadHashes.add(eventId);
414
+ return false;
414
415
  };
415
416
  return EventQueue;
416
417
  }());
@@ -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
@@ -25,6 +25,7 @@ exports.SESSION_WALLET_IDENTIFIED_KEY = "wallet-identified";
25
25
  *
26
26
  * Session data expires at end of day (86400 seconds).
27
27
  */
28
+ var MAX_SESSION_ENTRIES = 20;
28
29
  var FormoAnalyticsSession = /** @class */ (function () {
29
30
  function FormoAnalyticsSession() {
30
31
  }
@@ -62,6 +63,9 @@ var FormoAnalyticsSession = /** @class */ (function () {
62
63
  var rdnses = ((_a = (0, storage_1.cookie)().get(exports.SESSION_WALLET_DETECTED_KEY)) === null || _a === void 0 ? void 0 : _a.split(",")) || [];
63
64
  if (!rdnses.includes(rdns)) {
64
65
  rdnses.push(rdns);
66
+ if (rdnses.length > MAX_SESSION_ENTRIES) {
67
+ rdnses.splice(0, rdnses.length - MAX_SESSION_ENTRIES);
68
+ }
65
69
  (0, storage_1.cookie)().set(exports.SESSION_WALLET_DETECTED_KEY, rdnses.join(","), {
66
70
  // Expires by the end of the day
67
71
  expires: new Date(Date.now() + 86400 * 1000).toUTCString(),
@@ -102,6 +106,9 @@ var FormoAnalyticsSession = /** @class */ (function () {
102
106
  var alreadyExists = identifiedWallets.includes(identifiedKey);
103
107
  if (!alreadyExists) {
104
108
  identifiedWallets.push(identifiedKey);
109
+ if (identifiedWallets.length > MAX_SESSION_ENTRIES) {
110
+ identifiedWallets.splice(0, identifiedWallets.length - MAX_SESSION_ENTRIES);
111
+ }
105
112
  var newValue = identifiedWallets.join(",");
106
113
  (0, storage_1.cookie)().set(exports.SESSION_WALLET_IDENTIFIED_KEY, newValue, {
107
114
  // 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.