@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.
Files changed (52) hide show
  1. package/dist/cjs/src/FormoAnalytics.d.ts +2 -0
  2. package/dist/cjs/src/FormoAnalytics.js +10 -5
  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.js +6 -6
  6. package/dist/cjs/src/event/utils.d.ts +2 -3
  7. package/dist/cjs/src/event/utils.js +24 -24
  8. package/dist/cjs/src/queue/EventQueue.d.ts +1 -1
  9. package/dist/cjs/src/queue/EventQueue.js +21 -20
  10. package/dist/cjs/src/session/index.d.ts +0 -9
  11. package/dist/cjs/src/session/index.js +7 -0
  12. package/dist/cjs/src/solana/SolanaAdapter.d.ts +3 -4
  13. package/dist/cjs/src/solana/SolanaAdapter.js +42 -29
  14. package/dist/cjs/src/storage/StorageManager.js +11 -3
  15. package/dist/cjs/src/storage/built-in/cookie.js +29 -3
  16. package/dist/cjs/src/storage/cookiePolicy.d.ts +10 -0
  17. package/dist/cjs/src/storage/cookiePolicy.js +27 -0
  18. package/dist/cjs/src/types/base.d.ts +12 -0
  19. package/dist/cjs/src/utils/address.js +4 -6
  20. package/dist/cjs/src/utils/domain.d.ts +27 -0
  21. package/dist/cjs/src/utils/domain.js +74 -0
  22. package/dist/cjs/src/utils/generate.js +23 -11
  23. package/dist/cjs/src/validators/network.js +7 -2
  24. package/dist/cjs/src/version.d.ts +1 -1
  25. package/dist/cjs/src/version.js +1 -1
  26. package/dist/esm/src/FormoAnalytics.d.ts +2 -0
  27. package/dist/esm/src/FormoAnalytics.js +10 -5
  28. package/dist/esm/src/FormoAnalyticsProvider.js +1 -0
  29. package/dist/esm/src/consent/index.js +12 -10
  30. package/dist/esm/src/event/EventFactory.js +6 -6
  31. package/dist/esm/src/event/utils.d.ts +2 -3
  32. package/dist/esm/src/event/utils.js +25 -24
  33. package/dist/esm/src/queue/EventQueue.d.ts +1 -1
  34. package/dist/esm/src/queue/EventQueue.js +21 -20
  35. package/dist/esm/src/session/index.d.ts +0 -9
  36. package/dist/esm/src/session/index.js +7 -0
  37. package/dist/esm/src/solana/SolanaAdapter.d.ts +3 -4
  38. package/dist/esm/src/solana/SolanaAdapter.js +42 -29
  39. package/dist/esm/src/storage/StorageManager.js +11 -3
  40. package/dist/esm/src/storage/built-in/cookie.js +29 -3
  41. package/dist/esm/src/storage/cookiePolicy.d.ts +10 -0
  42. package/dist/esm/src/storage/cookiePolicy.js +24 -0
  43. package/dist/esm/src/types/base.d.ts +12 -0
  44. package/dist/esm/src/utils/address.js +4 -6
  45. package/dist/esm/src/utils/domain.d.ts +27 -0
  46. package/dist/esm/src/utils/domain.js +70 -0
  47. package/dist/esm/src/utils/generate.js +23 -11
  48. package/dist/esm/src/validators/network.js +7 -2
  49. package/dist/esm/src/version.d.ts +1 -1
  50. package/dist/esm/src/version.js +1 -1
  51. package/dist/index.umd.min.js +1 -1
  52. package/package.json +1 -1
@@ -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;
@@ -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");
@@ -84,7 +85,7 @@ var PROVIDER_SWITCH_REASONS = {
84
85
  var FormoAnalytics = /** @class */ (function () {
85
86
  function FormoAnalytics(writeKey, options) {
86
87
  if (options === void 0) { options = {}; }
87
- var _a, _b;
88
+ var _a, _b, _c;
88
89
  this.writeKey = writeKey;
89
90
  this.options = options;
90
91
  // Per-chain namespace state — isolates EVM and Solana connection state
@@ -123,6 +124,9 @@ var FormoAnalytics = /** @class */ (function () {
123
124
  this.options = options;
124
125
  // Check if Wagmi mode is enabled
125
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;
126
130
  this.session = new session_1.FormoAnalyticsSession();
127
131
  this.currentUserId =
128
132
  (0, storage_1.cookie)().get(constants_1.SESSION_USER_ID_KEY) || undefined;
@@ -137,8 +141,8 @@ var FormoAnalytics = /** @class */ (function () {
137
141
  this.isAutocaptureEnabled = this.isAutocaptureEnabled.bind(this);
138
142
  // Initialize logger with configuration from options
139
143
  logger_1.Logger.init({
140
- enabled: ((_a = options.logger) === null || _a === void 0 ? void 0 : _a.enabled) || false,
141
- 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) || [],
142
146
  });
143
147
  this.eventManager = new event_1.EventManager(new queue_1.EventQueue(this.config.writeKey, {
144
148
  apiHost: options.apiHost || constants_1.EVENTS_API_HOST,
@@ -508,7 +512,7 @@ var FormoAnalytics = /** @class */ (function () {
508
512
  */
509
513
  FormoAnalytics.prototype.identify = function (params, properties, context, callback) {
510
514
  return __awaiter(this, void 0, void 0, function () {
511
- 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;
512
516
  var _b, _c;
513
517
  return __generator(this, function (_d) {
514
518
  switch (_d.label) {
@@ -587,7 +591,8 @@ var FormoAnalytics = /** @class */ (function () {
587
591
  }
588
592
  if (userId) {
589
593
  this.currentUserId = userId;
590
- (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 } : {})));
591
596
  }
592
597
  isAlreadyIdentified = this.session.isWalletIdentified(validAddress, rdns || "");
593
598
  logger_1.logger.debug("Identify: Checking deduplication", {
@@ -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
@@ -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);
@@ -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.
@@ -118,6 +118,11 @@ var SolanaAdapter = /** @class */ (function () {
118
118
  * Key: transaction signature, Value: transaction details
119
119
  */
120
120
  this.pendingTransactions = new Map();
121
+ /**
122
+ * Per-adapter original methods stored in a WeakMap to prevent routing
123
+ * to the wrong wallet after switching adapters.
124
+ */
125
+ this.adapterOriginals = new WeakMap();
121
126
  /**
122
127
  * Track active polling timeout IDs for cleanup
123
128
  */
@@ -147,21 +152,22 @@ var SolanaAdapter = /** @class */ (function () {
147
152
  SolanaAdapter.prototype.restoreOriginalMethods = function () {
148
153
  // Restore adapter methods
149
154
  if (this.wrappedAdapter) {
150
- if (this.originalAdapterSendTransaction) {
151
- this.wrappedAdapter.sendTransaction = this.originalAdapterSendTransaction;
152
- }
153
- if (this.originalAdapterSignMessage) {
154
- this.wrappedAdapter.signMessage = this.originalAdapterSignMessage;
155
- }
156
- if (this.originalAdapterSignTransaction) {
157
- this.wrappedAdapter.signTransaction = this.originalAdapterSignTransaction;
155
+ var originals = this.adapterOriginals.get(this.wrappedAdapter);
156
+ if (originals) {
157
+ if (originals.sendTransaction) {
158
+ this.wrappedAdapter.sendTransaction = originals.sendTransaction;
159
+ }
160
+ if (originals.signMessage) {
161
+ this.wrappedAdapter.signMessage = originals.signMessage;
162
+ }
163
+ if (originals.signTransaction) {
164
+ this.wrappedAdapter.signTransaction = originals.signTransaction;
165
+ }
166
+ this.adapterOriginals.delete(this.wrappedAdapter);
158
167
  }
159
168
  this.wrappedAdapter = undefined;
160
169
  }
161
- // Clear original and bound wrapper references
162
- this.originalAdapterSendTransaction = undefined;
163
- this.originalAdapterSignMessage = undefined;
164
- this.originalAdapterSignTransaction = undefined;
170
+ // Clear bound wrapper references
165
171
  this.boundWrappedSendTransaction = undefined;
166
172
  this.boundWrappedSignMessage = undefined;
167
173
  this.boundWrappedSignTransaction = undefined;
@@ -390,24 +396,26 @@ var SolanaAdapter = /** @class */ (function () {
390
396
  }
391
397
  // Store reference to adapter for cleanup
392
398
  this.wrappedAdapter = adapter;
399
+ var originals = {};
393
400
  // Wrap sendTransaction
394
401
  if (adapter.sendTransaction) {
395
- this.originalAdapterSendTransaction = adapter.sendTransaction.bind(adapter);
402
+ originals.sendTransaction = adapter.sendTransaction.bind(adapter);
396
403
  this.boundWrappedSendTransaction = this.wrappedSendTransaction.bind(this);
397
404
  adapter.sendTransaction = this.boundWrappedSendTransaction;
398
405
  }
399
406
  // Wrap signMessage
400
407
  if (adapter.signMessage) {
401
- this.originalAdapterSignMessage = adapter.signMessage.bind(adapter);
408
+ originals.signMessage = adapter.signMessage.bind(adapter);
402
409
  this.boundWrappedSignMessage = this.wrappedSignMessage.bind(this);
403
410
  adapter.signMessage = this.boundWrappedSignMessage;
404
411
  }
405
412
  // Wrap signTransaction
406
413
  if (adapter.signTransaction) {
407
- this.originalAdapterSignTransaction = adapter.signTransaction.bind(adapter);
414
+ originals.signTransaction = adapter.signTransaction.bind(adapter);
408
415
  this.boundWrappedSignTransaction = this.wrappedSignTransaction.bind(this);
409
416
  adapter.signTransaction = this.boundWrappedSignTransaction;
410
417
  }
418
+ this.adapterOriginals.set(adapter, originals);
411
419
  };
412
420
  /**
413
421
  * Re-wrap methods that were overwritten by external code.
@@ -419,9 +427,10 @@ var SolanaAdapter = /** @class */ (function () {
419
427
  */
420
428
  SolanaAdapter.prototype.rewrapOverwrittenMethods = function (adapter) {
421
429
  var rewrapped = false;
430
+ var originals = this.adapterOriginals.get(adapter) || {};
422
431
  // signMessage
423
432
  if (adapter.signMessage && adapter.signMessage !== this.boundWrappedSignMessage) {
424
- this.originalAdapterSignMessage = adapter.signMessage.bind(adapter);
433
+ originals.signMessage = adapter.signMessage.bind(adapter);
425
434
  if (!this.boundWrappedSignMessage) {
426
435
  this.boundWrappedSignMessage = this.wrappedSignMessage.bind(this);
427
436
  }
@@ -429,11 +438,11 @@ var SolanaAdapter = /** @class */ (function () {
429
438
  rewrapped = true;
430
439
  }
431
440
  else if (!adapter.signMessage && this.boundWrappedSignMessage) {
432
- this.originalAdapterSignMessage = undefined;
441
+ originals.signMessage = undefined;
433
442
  }
434
443
  // signTransaction
435
444
  if (adapter.signTransaction && adapter.signTransaction !== this.boundWrappedSignTransaction) {
436
- this.originalAdapterSignTransaction = adapter.signTransaction.bind(adapter);
445
+ originals.signTransaction = adapter.signTransaction.bind(adapter);
437
446
  if (!this.boundWrappedSignTransaction) {
438
447
  this.boundWrappedSignTransaction = this.wrappedSignTransaction.bind(this);
439
448
  }
@@ -441,17 +450,18 @@ var SolanaAdapter = /** @class */ (function () {
441
450
  rewrapped = true;
442
451
  }
443
452
  else if (!adapter.signTransaction && this.boundWrappedSignTransaction) {
444
- this.originalAdapterSignTransaction = undefined;
453
+ originals.signTransaction = undefined;
445
454
  }
446
455
  // sendTransaction — unlikely to be overwritten but check for completeness
447
456
  if (adapter.sendTransaction && adapter.sendTransaction !== this.boundWrappedSendTransaction) {
448
- this.originalAdapterSendTransaction = adapter.sendTransaction.bind(adapter);
457
+ originals.sendTransaction = adapter.sendTransaction.bind(adapter);
449
458
  if (!this.boundWrappedSendTransaction) {
450
459
  this.boundWrappedSendTransaction = this.wrappedSendTransaction.bind(this);
451
460
  }
452
461
  adapter.sendTransaction = this.boundWrappedSendTransaction;
453
462
  rewrapped = true;
454
463
  }
464
+ this.adapterOriginals.set(adapter, originals);
455
465
  if (rewrapped) {
456
466
  logger_1.logger.debug("SolanaAdapter: Re-wrapped overwritten adapter methods");
457
467
  }
@@ -461,12 +471,13 @@ var SolanaAdapter = /** @class */ (function () {
461
471
  */
462
472
  SolanaAdapter.prototype.wrappedSendTransaction = function (transaction, connection, options) {
463
473
  return __awaiter(this, void 0, void 0, function () {
464
- var chainId, address, signature, error_1;
474
+ var originals, chainId, address, signature, error_1;
465
475
  return __generator(this, function (_a) {
466
476
  switch (_a.label) {
467
477
  case 0:
468
478
  this.checkAndRebindContextAdapter();
469
- if (!this.originalAdapterSendTransaction) {
479
+ originals = this.wrappedAdapter ? this.adapterOriginals.get(this.wrappedAdapter) : undefined;
480
+ if (!(originals === null || originals === void 0 ? void 0 : originals.sendTransaction)) {
470
481
  throw new Error("sendTransaction not available");
471
482
  }
472
483
  chainId = this.chainId;
@@ -475,7 +486,7 @@ var SolanaAdapter = /** @class */ (function () {
475
486
  _a.label = 1;
476
487
  case 1:
477
488
  _a.trys.push([1, 3, , 4]);
478
- return [4 /*yield*/, this.originalAdapterSendTransaction(transaction, connection, options)];
489
+ return [4 /*yield*/, originals.sendTransaction(transaction, connection, options)];
479
490
  case 2:
480
491
  signature = _a.sent();
481
492
  this.emitTransactionEvent(events_1.TransactionStatus.BROADCASTED, address, chainId, signature);
@@ -501,12 +512,13 @@ var SolanaAdapter = /** @class */ (function () {
501
512
  */
502
513
  SolanaAdapter.prototype.wrappedSignMessage = function (message) {
503
514
  return __awaiter(this, void 0, void 0, function () {
504
- var chainId, address, messageString, signature, signatureHex, error_2;
515
+ var originals, chainId, address, messageString, signature, signatureHex, error_2;
505
516
  return __generator(this, function (_a) {
506
517
  switch (_a.label) {
507
518
  case 0:
508
519
  this.checkAndRebindContextAdapter();
509
- if (!this.originalAdapterSignMessage) {
520
+ originals = this.wrappedAdapter ? this.adapterOriginals.get(this.wrappedAdapter) : undefined;
521
+ if (!(originals === null || originals === void 0 ? void 0 : originals.signMessage)) {
510
522
  throw new Error("signMessage not available");
511
523
  }
512
524
  chainId = this.chainId;
@@ -516,7 +528,7 @@ var SolanaAdapter = /** @class */ (function () {
516
528
  _a.label = 1;
517
529
  case 1:
518
530
  _a.trys.push([1, 3, , 4]);
519
- return [4 /*yield*/, this.originalAdapterSignMessage(message)];
531
+ return [4 /*yield*/, originals.signMessage(message)];
520
532
  case 2:
521
533
  signature = _a.sent();
522
534
  signatureHex = uint8ArrayToHex(signature);
@@ -536,12 +548,13 @@ var SolanaAdapter = /** @class */ (function () {
536
548
  */
537
549
  SolanaAdapter.prototype.wrappedSignTransaction = function (transaction) {
538
550
  return __awaiter(this, void 0, void 0, function () {
539
- var chainId, address, message, signedTx, error_3;
551
+ var originals, chainId, address, message, signedTx, error_3;
540
552
  return __generator(this, function (_a) {
541
553
  switch (_a.label) {
542
554
  case 0:
543
555
  this.checkAndRebindContextAdapter();
544
- if (!this.originalAdapterSignTransaction) {
556
+ originals = this.wrappedAdapter ? this.adapterOriginals.get(this.wrappedAdapter) : undefined;
557
+ if (!(originals === null || originals === void 0 ? void 0 : originals.signTransaction)) {
545
558
  throw new Error("signTransaction not available");
546
559
  }
547
560
  chainId = this.chainId;
@@ -551,7 +564,7 @@ var SolanaAdapter = /** @class */ (function () {
551
564
  _a.label = 1;
552
565
  case 1:
553
566
  _a.trys.push([1, 3, , 4]);
554
- return [4 /*yield*/, this.originalAdapterSignTransaction(transaction)];
567
+ return [4 /*yield*/, originals.signTransaction(transaction)];
555
568
  case 2:
556
569
  signedTx = _a.sent();
557
570
  this.emitSignatureEvent(events_1.SignatureStatus.CONFIRMED, address, chainId, message);
@@ -23,11 +23,19 @@ var StorageManager = /** @class */ (function () {
23
23
  StorageManager.prototype.getStorage = function (type) {
24
24
  if (!this.storages.has(type)) {
25
25
  var storage = this.createStorage(type);
26
+ var currentType = type;
26
27
  // If storage is not available, try next
27
28
  while (!storage.isAvailable()) {
28
- var index = TYPES.indexOf(type);
29
- logger_1.logger.warn("Storage ".concat(type, " is not available, trying ").concat(TYPES[index + 1]));
30
- storage = this.createStorage(TYPES[index + 1]);
29
+ var index = TYPES.indexOf(currentType);
30
+ if (index === -1 || index + 1 >= TYPES.length) {
31
+ // No more fallbacks, use memory storage as last resort
32
+ storage = this.createStorage("memoryStorage");
33
+ break;
34
+ }
35
+ var prevType = currentType;
36
+ currentType = TYPES[index + 1];
37
+ logger_1.logger.warn("Storage ".concat(prevType, " is not available, trying ").concat(currentType));
38
+ storage = this.createStorage(currentType);
31
39
  }
32
40
  // Add to cache
33
41
  this.storages.set(type, storage);