@formo/analytics 1.35.2 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/cjs/src/FormoAnalytics.d.ts +79 -363
  2. package/dist/cjs/src/FormoAnalytics.js +368 -2234
  3. package/dist/cjs/src/event/EventManager.d.ts +3 -1
  4. package/dist/cjs/src/event/EventManager.js +5 -1
  5. package/dist/cjs/src/event/type.d.ts +1 -0
  6. package/dist/cjs/src/evm/EvmEventTracker.d.ts +175 -0
  7. package/dist/cjs/src/evm/EvmEventTracker.js +1030 -0
  8. package/dist/cjs/src/evm/EvmProviderRegistry.d.ts +132 -0
  9. package/dist/cjs/src/evm/EvmProviderRegistry.js +348 -0
  10. package/dist/cjs/src/evm/EvmRequestTracker.d.ts +98 -0
  11. package/dist/cjs/src/evm/EvmRequestTracker.js +713 -0
  12. package/dist/cjs/src/evm/batch.d.ts +94 -0
  13. package/dist/cjs/src/evm/batch.js +130 -0
  14. package/dist/cjs/src/queue/EventQueue.d.ts +28 -0
  15. package/dist/cjs/src/queue/EventQueue.js +97 -19
  16. package/dist/cjs/src/queue/type.d.ts +1 -0
  17. package/dist/cjs/src/tracking/TrackingPolicy.d.ts +146 -0
  18. package/dist/cjs/src/tracking/TrackingPolicy.js +200 -0
  19. package/dist/cjs/src/validators/address.d.ts +1 -1
  20. package/dist/cjs/src/version.d.ts +1 -1
  21. package/dist/cjs/src/version.js +1 -1
  22. package/dist/cjs/src/wagmi/WagmiEventHandler.d.ts +43 -0
  23. package/dist/cjs/src/wagmi/WagmiEventHandler.js +253 -2
  24. package/dist/cjs/src/wallet/WalletStateStore.d.ts +223 -0
  25. package/dist/cjs/src/wallet/WalletStateStore.js +515 -0
  26. package/dist/esm/src/FormoAnalytics.d.ts +79 -363
  27. package/dist/esm/src/FormoAnalytics.js +369 -2235
  28. package/dist/esm/src/event/EventManager.d.ts +3 -1
  29. package/dist/esm/src/event/EventManager.js +5 -1
  30. package/dist/esm/src/event/type.d.ts +1 -0
  31. package/dist/esm/src/evm/EvmEventTracker.d.ts +175 -0
  32. package/dist/esm/src/evm/EvmEventTracker.js +1027 -0
  33. package/dist/esm/src/evm/EvmProviderRegistry.d.ts +132 -0
  34. package/dist/esm/src/evm/EvmProviderRegistry.js +345 -0
  35. package/dist/esm/src/evm/EvmRequestTracker.d.ts +98 -0
  36. package/dist/esm/src/evm/EvmRequestTracker.js +710 -0
  37. package/dist/esm/src/evm/batch.d.ts +94 -0
  38. package/dist/esm/src/evm/batch.js +123 -0
  39. package/dist/esm/src/queue/EventQueue.d.ts +28 -0
  40. package/dist/esm/src/queue/EventQueue.js +97 -19
  41. package/dist/esm/src/queue/type.d.ts +1 -0
  42. package/dist/esm/src/tracking/TrackingPolicy.d.ts +146 -0
  43. package/dist/esm/src/tracking/TrackingPolicy.js +197 -0
  44. package/dist/esm/src/version.d.ts +1 -1
  45. package/dist/esm/src/version.js +1 -1
  46. package/dist/esm/src/wagmi/WagmiEventHandler.d.ts +43 -0
  47. package/dist/esm/src/wagmi/WagmiEventHandler.js +253 -2
  48. package/dist/esm/src/wallet/WalletStateStore.d.ts +223 -0
  49. package/dist/esm/src/wallet/WalletStateStore.js +512 -0
  50. package/dist/index.umd.min.js +1 -1
  51. package/package.json +6 -4
@@ -0,0 +1,515 @@
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
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.WalletStateStore = void 0;
15
+ var constants_1 = require("../constants");
16
+ var storage_1 = require("../storage");
17
+ var cookiePolicy_1 = require("../storage/cookiePolicy");
18
+ var logger_1 = require("../logger");
19
+ var address_1 = require("../utils/address");
20
+ var solana_1 = require("../solana");
21
+ /**
22
+ * Wallet identity and chain state, and the cookie that outlives the page.
23
+ *
24
+ * Split out of `FormoAnalytics` so there is one owner for "which wallet is
25
+ * active, on which chain". Before this, `_chainState`, the derived
26
+ * `currentAddress`/`currentChainId`, the active-wallet cookie and the session
27
+ * generation were manipulated from a dozen places across a 3400-line class,
28
+ * which is what made the ordering races in #341 possible to write.
29
+ */
30
+ var WalletStateStore = /** @class */ (function () {
31
+ function WalletStateStore(deps) {
32
+ this.deps = deps;
33
+ this.state = {
34
+ evm: {},
35
+ solana: {},
36
+ };
37
+ /**
38
+ * Ticket counter for wallet observations.
39
+ *
40
+ * Every signal from a wallet is handled asynchronously: resolving an
41
+ * address, emitting an event. Between the moment a handler decides what to
42
+ * do and the moment it commits, a newer signal can arrive and be fully
43
+ * processed. Whichever handler resumes last then writes its captured data
44
+ * over the newer state.
45
+ *
46
+ * Bespoke guards were added for each case as it was found - a per-provider
47
+ * disconnect count, a per-namespace session generation, a "currently
48
+ * processing" flag - and a fourth review round kept producing new ones,
49
+ * because each guard answers one question and none establishes an order.
50
+ *
51
+ * A ticket does. A handler takes one before its first await; anything it
52
+ * commits afterwards is refused if a newer observation has claimed the
53
+ * namespace since.
54
+ */
55
+ this.observationSeq = 0;
56
+ this.newestObservation = {
57
+ evm: 0,
58
+ solana: 0,
59
+ };
60
+ /**
61
+ * How many disconnects a namespace has begun.
62
+ *
63
+ * Separate from the observation ticket on purpose, because they answer
64
+ * different questions. A ticket asks "is the state I captured still the
65
+ * newest?", which is what a switch or a probe needs. This asks "did the
66
+ * wallet go away after I started?", which is what a connect handler needs.
67
+ *
68
+ * Conflating them loses connects: a connect observation superseded by a
69
+ * NEWER connect must still be reported by somebody, and the ticket cannot
70
+ * tell that apart from being superseded by a disconnect.
71
+ */
72
+ this.disconnectCount = {
73
+ evm: 0,
74
+ solana: 0,
75
+ };
76
+ }
77
+ Object.defineProperty(WalletStateStore.prototype, "activeNamespace", {
78
+ /** Which namespace currently owns the derived values, if any. */
79
+ get: function () {
80
+ return this._activeNamespace;
81
+ },
82
+ enumerable: false,
83
+ configurable: true
84
+ });
85
+ // ── reads ────────────────────────────────────────────────────────────────
86
+ /** Which namespace a chain id belongs to. */
87
+ WalletStateStore.prototype.namespaceOf = function (chainId) {
88
+ return (0, solana_1.isSolanaChainId)(chainId) ? "solana" : "evm";
89
+ };
90
+ Object.defineProperty(WalletStateStore.prototype, "evmAddress", {
91
+ get: function () {
92
+ return this.state.evm.address;
93
+ },
94
+ enumerable: false,
95
+ configurable: true
96
+ });
97
+ Object.defineProperty(WalletStateStore.prototype, "evmChainId", {
98
+ get: function () {
99
+ return this.state.evm.chainId;
100
+ },
101
+ enumerable: false,
102
+ configurable: true
103
+ });
104
+ Object.defineProperty(WalletStateStore.prototype, "provider", {
105
+ get: function () {
106
+ return this.state.evm.provider;
107
+ },
108
+ // ── writes ───────────────────────────────────────────────────────────────
109
+ set: function (next) {
110
+ this.displaceProvider(this.state.evm.provider, next);
111
+ this.state.evm.provider = next;
112
+ },
113
+ enumerable: false,
114
+ configurable: true
115
+ });
116
+ /**
117
+ * Take a ticket for an observation about to be processed.
118
+ *
119
+ * MUST be called before the handler's first await, so the order recorded is
120
+ * the order the signals arrived in, not the order their async work happens
121
+ * to finish in.
122
+ */
123
+ WalletStateStore.prototype.observe = function (namespace) {
124
+ var id = ++this.observationSeq;
125
+ this.newestObservation[namespace] = id;
126
+ return { id: id, namespace: namespace };
127
+ };
128
+ /**
129
+ * Record that a namespace's wallet is being torn down.
130
+ *
131
+ * Called at EVERY teardown site before anything is awaited, and whether or
132
+ * not a disconnect event will be emitted: whether the app opted into
133
+ * disconnect autocapture has no bearing on ordering.
134
+ */
135
+ WalletStateStore.prototype.beginDisconnect = function (namespace) {
136
+ this.disconnectCount[namespace]++;
137
+ };
138
+ /** How many disconnects this namespace has begun so far. */
139
+ WalletStateStore.prototype.disconnectsSoFar = function (namespace) {
140
+ return this.disconnectCount[namespace];
141
+ };
142
+ /**
143
+ * The newest observation for a namespace, for a caller that must NOT
144
+ * supersede its own caller.
145
+ *
146
+ * `disconnect()` is reached both directly by a consumer and from a handler
147
+ * that already holds a ticket. Taking a fresh ticket there would invalidate
148
+ * the handler that called it. Reading the current value and checking it
149
+ * later asks the same question without changing the answer for anyone else.
150
+ */
151
+ WalletStateStore.prototype.snapshot = function (namespace) {
152
+ return this.newestObservation[namespace];
153
+ };
154
+ /** Whether nothing newer has claimed the namespace since `snapshot`. */
155
+ WalletStateStore.prototype.isUnchangedSince = function (namespace, snapshot) {
156
+ return this.newestObservation[namespace] === snapshot;
157
+ };
158
+ /**
159
+ * The current newest observation, as a ticket, WITHOUT taking a new one.
160
+ *
161
+ * For a handler that must respect the order but has nothing to claim: it
162
+ * still abandons its work if something newer arrives, but it does not
163
+ * supersede whatever is already in flight.
164
+ */
165
+ WalletStateStore.prototype.currentObservation = function (namespace) {
166
+ return { id: this.newestObservation[namespace], namespace: namespace };
167
+ };
168
+ /**
169
+ * Whether this observation is still the newest for its namespace.
170
+ *
171
+ * False means a newer signal arrived while this handler was suspended, and
172
+ * it must abandon whatever it captured rather than write it over the newer
173
+ * state. Superseding, not dropping: the newer handler is already running.
174
+ */
175
+ WalletStateStore.prototype.isCurrent = function (observation) {
176
+ return this.newestObservation[observation.namespace] === observation.id;
177
+ };
178
+ /**
179
+ * Update a namespace and re-derive `address`/`chainId`.
180
+ *
181
+ * Accepts a namespace or a chain id. A chain id is also stored as the
182
+ * namespace's chain unless the update names one explicitly.
183
+ */
184
+ WalletStateStore.prototype.set = function (namespaceOrChainId, update) {
185
+ var namespace = typeof namespaceOrChainId === "string"
186
+ ? namespaceOrChainId
187
+ : this.namespaceOf(namespaceOrChainId);
188
+ var ns = this.state[namespace];
189
+ // A plain write. Whether this transition is still the newest is decided
190
+ // by the observation ticket its caller holds, not by comparing addresses
191
+ // here: re-adopting the SAME wallet is a real transition, and no
192
+ // comparison of the values can tell that apart from nothing happening.
193
+ if ("address" in update)
194
+ ns.address = update.address;
195
+ if ("chainId" in update) {
196
+ ns.chainId = update.chainId;
197
+ }
198
+ else if (typeof namespaceOrChainId === "number") {
199
+ ns.chainId = namespaceOrChainId;
200
+ }
201
+ if (namespace === "evm" && "provider" in update) {
202
+ this.displaceProvider(ns.provider, update.provider);
203
+ ns.provider = update.provider;
204
+ }
205
+ this._activeNamespace = namespace;
206
+ this.syncDerived();
207
+ };
208
+ /** Wipe a namespace. Per-namespace so a Solana disconnect spares EVM. */
209
+ WalletStateStore.prototype.clear = function (namespaceOrChainId) {
210
+ var namespace = typeof namespaceOrChainId === "string"
211
+ ? namespaceOrChainId
212
+ : this.namespaceOf(namespaceOrChainId);
213
+ if (namespace === "evm") {
214
+ // Wiping the namespace drops the active provider with it.
215
+ this.displaceProvider(this.state.evm.provider, undefined);
216
+ this.state.evm = {};
217
+ }
218
+ else {
219
+ this.state.solana = {};
220
+ }
221
+ this.syncDerived();
222
+ };
223
+ /** Both namespaces, keeping the EVM provider so tracking can resume. */
224
+ WalletStateStore.prototype.reset = function () {
225
+ var evmProvider = this.state.evm.provider;
226
+ this.state = { evm: { provider: evmProvider }, solana: {} };
227
+ this._activeNamespace = undefined;
228
+ this.address = undefined;
229
+ this.chainId = undefined;
230
+ };
231
+ /** Drop the active provider without touching identity. */
232
+ WalletStateStore.prototype.clearProvider = function () {
233
+ this.provider = undefined;
234
+ };
235
+ /**
236
+ * Repoint the active identity at a wallet, as `identify(setActive)` does,
237
+ * without disturbing per-namespace chain state.
238
+ *
239
+ * Deliberately transient. The next wallet event for either namespace
240
+ * re-derives from namespace state and replaces this, which is the intended
241
+ * order: a wallet that actually connects outranks one merely named by
242
+ * `identify()`. The alternative, making an identify sticky until another
243
+ * identify, would silently mis-attribute every event after a connect.
244
+ */
245
+ WalletStateStore.prototype.setActiveAddress = function (address) {
246
+ this.address = address;
247
+ this.persist();
248
+ };
249
+ /** Repoint (or forget) the derived chain while keeping the wallet. */
250
+ WalletStateStore.prototype.setActiveChainId = function (chainId) {
251
+ this.chainId = chainId;
252
+ this.persist();
253
+ };
254
+ /** Forget the derived chain while keeping the wallet. */
255
+ WalletStateStore.prototype.clearActiveChainId = function () {
256
+ this.setActiveChainId(undefined);
257
+ };
258
+ // ── higher-level operations ──────────────────────────────────────────────
259
+ /**
260
+ * Record validated wallet/chain state WITHOUT emitting an event.
261
+ *
262
+ * Integrations (the wagmi handler among them) must call this on every
263
+ * connect / chain change / disconnect, even when the matching autocapture
264
+ * event is disabled. Otherwise `chainId` stays stale and the exclusion gate,
265
+ * which keys off it rather than the event payload, can be bypassed.
266
+ */
267
+ WalletStateStore.prototype.syncWalletState = function (params) {
268
+ var chainId = params.chainId, address = params.address;
269
+ // An integration adopting or dropping a wallet is a wallet signal like
270
+ // any other, so it takes its place in the order. Without this, a
271
+ // disconnect still in flight could not tell that the wagmi handler had
272
+ // already adopted a replacement.
273
+ this.observe(this.namespaceOf(chainId));
274
+ if (this.deps.isTrackingSuppressed()) {
275
+ // While suppressed we must never LEARN a new wallet, but we must still
276
+ // CLEAR a stale one. Otherwise a disconnect or switch observed on a
277
+ // suppressed route leaves the previous address in memory and in the
278
+ // cookie, ready to attach to later allowed-page events.
279
+ if (!address) {
280
+ this.clearForChain(chainId);
281
+ return;
282
+ }
283
+ if (chainId === null || chainId === undefined)
284
+ return;
285
+ var namespace = this.namespaceOf(chainId);
286
+ var known = this.state[namespace].address;
287
+ var incoming = (0, address_1.validateAddress)(address, chainId);
288
+ if (known && incoming && incoming !== known) {
289
+ // A switch away from the learned wallet invalidates it. Drop the
290
+ // stale one without learning the new address.
291
+ this.clear(chainId);
292
+ }
293
+ return;
294
+ }
295
+ if (!address) {
296
+ this.clearForChain(chainId);
297
+ return;
298
+ }
299
+ if (chainId === null || chainId === undefined)
300
+ return;
301
+ var valid = (0, address_1.validateAddress)(address, chainId);
302
+ if (!valid) {
303
+ logger_1.logger.warn("syncWalletState: invalid address (\"".concat(address, "\") for chain ").concat(chainId));
304
+ return;
305
+ }
306
+ this.set(chainId, { address: valid });
307
+ };
308
+ /**
309
+ * Learn an EVM wallet observed on an autocaptured signature or transaction,
310
+ * when nothing is known yet.
311
+ *
312
+ * Deliberately conservative: it never overwrites a different wallet, and it
313
+ * corrects only a stale chain for the wallet already known.
314
+ */
315
+ WalletStateStore.prototype.backfill = function (address, chainId, provider) {
316
+ // Refuse a chain the provider has since moved off.
317
+ //
318
+ // A request captures its chain once and reuses that snapshot for every
319
+ // status it emits, which is right for the payload: a confirmation must
320
+ // not be relabelled mid-flight. Writing that captured value back into
321
+ // central state on a LATER status restored a chain the wallet had already
322
+ // left, and the unscoped events that fall back to it then bypassed an
323
+ // exclusion that should have caught them.
324
+ if (provider && chainId !== undefined && chainId !== 0) {
325
+ var live = this.deps.providerChainId(provider);
326
+ if (live !== undefined && live !== chainId)
327
+ chainId = live;
328
+ }
329
+ // `0` is kept deliberately. It means "could not resolve", and persisting
330
+ // it is what lets the exclusion gate refuse the unscoped events (page,
331
+ // track, identify) that carry no chain of their own. Erasing it to
332
+ // `undefined` looked tidier but removed the only marker distinguishing
333
+ // "unknown" from "no wallet yet".
334
+ // Never learn identity while suppressed. A signature observed on an
335
+ // excluded route must not populate the address for later allowed pages.
336
+ if (this.deps.isTrackingSuppressed())
337
+ return;
338
+ var known = this.evmAddress;
339
+ if (known) {
340
+ // Same wallet, newer chain: correct it rather than returning. A
341
+ // persisted wallet restores a chain from a previous session, and if the
342
+ // provider has since moved, the stale restored chain would stay in the
343
+ // derived value and carry the unscoped events past an exclusion.
344
+ // `0` means "could not resolve". Correcting a stale chain with a real
345
+ // one is the point of this branch; replacing a chain we already know
346
+ // with "unknown" only makes attribution worse, and would trip the
347
+ // exclusion gate's fail-closed rule against a wallet we can place.
348
+ var usable = chainId !== undefined && !(chainId === 0 && this.evmChainId);
349
+ if (usable &&
350
+ known.toLowerCase() === address.toLowerCase() &&
351
+ this.evmChainId !== chainId) {
352
+ this.set("evm", { address: known, chainId: chainId });
353
+ }
354
+ // A DIFFERENT address is another wallet's business; never overwrite.
355
+ return;
356
+ }
357
+ this.set("evm", { address: address, chainId: chainId });
358
+ };
359
+ /**
360
+ * Apply an EVM connect/switch seen while tracking is suppressed: never
361
+ * learn the wallet, but if it is a switch away from one already learned,
362
+ * drop the stale one so it cannot attach to a later allowed-page event.
363
+ */
364
+ WalletStateStore.prototype.clearStaleEvmWalletOnSwitchWhileSuppressed = function (address) {
365
+ var known = this.state.evm.address;
366
+ var incoming = (0, address_1.validateAndChecksumAddress)(address);
367
+ if (known && incoming && incoming !== known)
368
+ this.clear("evm");
369
+ };
370
+ // ── persistence ──────────────────────────────────────────────────────────
371
+ /**
372
+ * Persist (or clear) the wallet snapshot, so the next page load can
373
+ * repopulate identity before the wallet reconnects. Without it, every
374
+ * `track()` / `page()` between page-show and reconnection ships with no
375
+ * address.
376
+ */
377
+ WalletStateStore.prototype.persist = function () {
378
+ try {
379
+ // Visitor-level suppression is stable for the session, so purging is
380
+ // safe and prevents a stale snapshot outliving an opt-out.
381
+ if (this.deps.isPersistedIdentityPurgeRequired()) {
382
+ (0, storage_1.cookie)().remove(constants_1.ACTIVE_WALLET_KEY);
383
+ return;
384
+ }
385
+ if (this.address) {
386
+ // Page-level exclusion: do not write while on an excluded route, but
387
+ // leave any existing cookie alone. One written on an allowed page
388
+ // must survive a transient visit here.
389
+ if (this.deps.isPageExcluded())
390
+ return;
391
+ var value = JSON.stringify(__assign({ address: this.address }, (this.chainId !== undefined && { chainId: this.chainId })));
392
+ var domain = (0, cookiePolicy_1.getIdentityCookieDomain)(this.deps.crossSubdomainCookies());
393
+ (0, storage_1.cookie)().set(constants_1.ACTIVE_WALLET_KEY, value, __assign(__assign({ path: "/", expires: new Date(Date.now() + constants_1.ACTIVE_WALLET_TTL_MS).toUTCString() }, (0, cookiePolicy_1.getIdentityCookieSecurity)()), (domain ? { domain: domain } : {})));
394
+ }
395
+ else {
396
+ // No active wallet: clear the snapshot. This runs even on an excluded
397
+ // route, so a disconnect observed while suppressed actively removes
398
+ // stale identity rather than leaving it for later.
399
+ (0, storage_1.cookie)().remove(constants_1.ACTIVE_WALLET_KEY);
400
+ }
401
+ }
402
+ catch (err) {
403
+ logger_1.logger.warn("Failed to persist current wallet snapshot", err);
404
+ }
405
+ };
406
+ /** Seed identity from the persisted snapshot, once, during construction. */
407
+ WalletStateStore.prototype.load = function () {
408
+ try {
409
+ if (this.deps.isPersistedIdentityPurgeRequired()) {
410
+ (0, storage_1.cookie)().remove(constants_1.ACTIVE_WALLET_KEY);
411
+ return;
412
+ }
413
+ // Page-level exclusion: don't restore into memory here, but keep the
414
+ // cookie so a later allowed-page load can.
415
+ if (this.deps.isPageExcluded())
416
+ return;
417
+ var raw = (0, storage_1.cookie)().get(constants_1.ACTIVE_WALLET_KEY);
418
+ if (!raw)
419
+ return;
420
+ var parsed = JSON.parse(raw);
421
+ if (!(parsed === null || parsed === void 0 ? void 0 : parsed.address))
422
+ return;
423
+ // A cookie is attacker-writable and survives across SDK versions, so
424
+ // the chain has to be a real number before anything trusts it. A string
425
+ // "137" restored as-is would never match a numeric exclusion list, so
426
+ // an excluded chain would silently start reporting again.
427
+ //
428
+ // A present-but-unusable chain rejects the WHOLE snapshot rather than
429
+ // being downgraded to "chainless". Downgrading looks harmless and is
430
+ // not: the namespace is derived from the chain, so a Solana wallet with
431
+ // a corrupt chain would be filed under EVM, and a later Solana
432
+ // disconnect would fall through to that phantom entry and keep
433
+ // attributing events to a wallet that had gone.
434
+ var rawChain = parsed.chainId;
435
+ var chainMissing = rawChain === undefined || rawChain === null;
436
+ if (!chainMissing &&
437
+ (typeof rawChain !== "number" || !Number.isFinite(rawChain))) {
438
+ (0, storage_1.cookie)().remove(constants_1.ACTIVE_WALLET_KEY);
439
+ return;
440
+ }
441
+ var chainId = chainMissing ? undefined : rawChain;
442
+ // With no chain to go on, the address shape decides. Defaulting to EVM
443
+ // filed a chainless Solana wallet under EVM, where later EVM handlers
444
+ // read it as `evmAddress` and emitted EVM state for a Solana wallet.
445
+ var namespace = chainId === undefined
446
+ ? (0, address_1.validateAndChecksumAddress)(parsed.address)
447
+ ? "evm"
448
+ : "solana"
449
+ : this.namespaceOf(chainId);
450
+ var validated = (0, address_1.validateAddress)(parsed.address, chainId);
451
+ if (!validated) {
452
+ (0, storage_1.cookie)().remove(constants_1.ACTIVE_WALLET_KEY);
453
+ return;
454
+ }
455
+ var ns = this.state[namespace];
456
+ ns.address = validated;
457
+ if (chainId !== undefined)
458
+ ns.chainId = chainId;
459
+ this._activeNamespace = namespace;
460
+ this.address = validated;
461
+ this.chainId = chainId;
462
+ }
463
+ catch (err) {
464
+ logger_1.logger.warn("Failed to restore persisted wallet snapshot", err);
465
+ (0, storage_1.cookie)().remove(constants_1.ACTIVE_WALLET_KEY);
466
+ }
467
+ };
468
+ // ── internals ────────────────────────────────────────────────────────────
469
+ WalletStateStore.prototype.clearForChain = function (chainId) {
470
+ if (chainId !== undefined && chainId !== null) {
471
+ this.clear(chainId);
472
+ }
473
+ else {
474
+ this.clear("evm");
475
+ this.clear("solana");
476
+ }
477
+ };
478
+ WalletStateStore.prototype.displaceProvider = function (previous, next) {
479
+ if (previous && previous !== next)
480
+ this.deps.onProviderDisplaced(previous);
481
+ };
482
+ /**
483
+ * Re-derive `address`/`chainId` from the active namespace.
484
+ *
485
+ * Last-connected wins, then fall through to the other namespace so a
486
+ * still-connected wallet keeps attribution when its neighbour disconnects.
487
+ */
488
+ WalletStateStore.prototype.syncDerived = function () {
489
+ var active = this._activeNamespace;
490
+ if (active) {
491
+ var state = this.state[active];
492
+ if (state.address || state.chainId) {
493
+ this.address = state.address;
494
+ this.chainId = state.chainId;
495
+ this.persist();
496
+ return;
497
+ }
498
+ }
499
+ var other = active === "evm" ? "solana" : "evm";
500
+ var otherState = this.state[other];
501
+ if (otherState.address || otherState.chainId) {
502
+ this.address = otherState.address;
503
+ this.chainId = otherState.chainId;
504
+ this._activeNamespace = other;
505
+ this.persist();
506
+ return;
507
+ }
508
+ this.address = undefined;
509
+ this.chainId = undefined;
510
+ this.persist();
511
+ };
512
+ return WalletStateStore;
513
+ }());
514
+ exports.WalletStateStore = WalletStateStore;
515
+ //# sourceMappingURL=WalletStateStore.js.map