@formo/analytics 1.38.1 → 1.39.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.
- package/dist/cjs/src/FormoAnalytics.d.ts +10 -1
- package/dist/cjs/src/FormoAnalytics.js +20 -5
- package/dist/cjs/src/FormoAnalyticsProvider.js +20 -0
- package/dist/cjs/src/evm/EvmEventTracker.d.ts +100 -9
- package/dist/cjs/src/evm/EvmEventTracker.js +357 -19
- package/dist/cjs/src/evm/EvmProviderRegistry.d.ts +34 -2
- package/dist/cjs/src/evm/EvmProviderRegistry.js +61 -4
- package/dist/cjs/src/evm/EvmRequestTracker.d.ts +9 -4
- package/dist/cjs/src/evm/EvmRequestTracker.js +26 -16
- package/dist/cjs/src/solana/SolanaManager.d.ts +37 -9
- package/dist/cjs/src/solana/SolanaManager.js +135 -20
- package/dist/cjs/src/solana/SolanaStoreHandler.d.ts +6 -0
- package/dist/cjs/src/solana/SolanaStoreHandler.js +17 -8
- package/dist/cjs/src/solana/SolanaWalletStandardRegistry.d.ts +163 -0
- package/dist/cjs/src/solana/SolanaWalletStandardRegistry.js +447 -0
- package/dist/cjs/src/solana/index.d.ts +10 -5
- package/dist/cjs/src/solana/index.js +12 -6
- package/dist/cjs/src/solana/storeTypes.d.ts +20 -1
- package/dist/cjs/src/solana/types.d.ts +32 -9
- package/dist/cjs/src/solana/types.js +15 -0
- package/dist/cjs/src/solana/walletStandardTypes.d.ts +54 -0
- package/dist/cjs/src/solana/walletStandardTypes.js +21 -0
- package/dist/cjs/src/types/base.d.ts +15 -5
- package/dist/cjs/src/version.d.ts +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/cjs/src/wagmi/WagmiEventHandler.d.ts +30 -1
- package/dist/cjs/src/wagmi/WagmiEventHandler.js +80 -1
- package/dist/cjs/src/wagmi/types.d.ts +6 -0
- package/dist/cjs/src/wagmi/utils.js +9 -1
- package/dist/esm/src/FormoAnalytics.d.ts +10 -1
- package/dist/esm/src/FormoAnalytics.js +20 -5
- package/dist/esm/src/FormoAnalyticsProvider.js +20 -0
- package/dist/esm/src/evm/EvmEventTracker.d.ts +100 -9
- package/dist/esm/src/evm/EvmEventTracker.js +357 -19
- package/dist/esm/src/evm/EvmProviderRegistry.d.ts +34 -2
- package/dist/esm/src/evm/EvmProviderRegistry.js +61 -4
- package/dist/esm/src/evm/EvmRequestTracker.d.ts +9 -4
- package/dist/esm/src/evm/EvmRequestTracker.js +26 -16
- package/dist/esm/src/solana/SolanaManager.d.ts +37 -9
- package/dist/esm/src/solana/SolanaManager.js +135 -20
- package/dist/esm/src/solana/SolanaStoreHandler.d.ts +6 -0
- package/dist/esm/src/solana/SolanaStoreHandler.js +18 -9
- package/dist/esm/src/solana/SolanaWalletStandardRegistry.d.ts +163 -0
- package/dist/esm/src/solana/SolanaWalletStandardRegistry.js +444 -0
- package/dist/esm/src/solana/index.d.ts +10 -5
- package/dist/esm/src/solana/index.js +10 -5
- package/dist/esm/src/solana/storeTypes.d.ts +20 -1
- package/dist/esm/src/solana/types.d.ts +32 -9
- package/dist/esm/src/solana/types.js +14 -0
- package/dist/esm/src/solana/walletStandardTypes.d.ts +54 -0
- package/dist/esm/src/solana/walletStandardTypes.js +18 -0
- package/dist/esm/src/types/base.d.ts +15 -5
- package/dist/esm/src/version.d.ts +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/esm/src/wagmi/WagmiEventHandler.d.ts +30 -1
- package/dist/esm/src/wagmi/WagmiEventHandler.js +80 -1
- package/dist/esm/src/wagmi/types.d.ts +6 -0
- package/dist/esm/src/wagmi/utils.js +9 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +2 -2
|
@@ -428,8 +428,17 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
428
428
|
* gap. Lifecycle (connect/chain/disconnect) stays store-driven: only the
|
|
429
429
|
* request wrapper installs here. Double counting is prevented in the
|
|
430
430
|
* wrapper via `shouldSkipRequestCapture`.
|
|
431
|
+
*
|
|
432
|
+
* `attribution` resolves, live, the name and rdns of the connector this
|
|
433
|
+
* provider was wrapped for. Request-derived events are named from the
|
|
434
|
+
* registry, which for an unannounced provider falls back to flag
|
|
435
|
+
* sniffing; recording the connector's resolver here keeps them in
|
|
436
|
+
* agreement with the hook-driven events for that connector.
|
|
431
437
|
*/
|
|
432
|
-
_wrapWagmiProvider(provider: EIP1193Provider, chainId?: number)
|
|
438
|
+
_wrapWagmiProvider(provider: EIP1193Provider, chainId?: number, attribution?: () => {
|
|
439
|
+
name: string;
|
|
440
|
+
rdns?: string;
|
|
441
|
+
} | undefined): boolean;
|
|
433
442
|
/** INTERNAL. Chain updates for the fallback-wrapped provider. */
|
|
434
443
|
_rememberWagmiProviderChain(provider: EIP1193Provider, chainId: number | undefined): void;
|
|
435
444
|
registerProvider(provider: EIP1193Provider, info?: {
|
|
@@ -245,9 +245,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
245
245
|
this.evmEvents.trackEIP1193Provider(provider);
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
// Solana wallets are discovered through the Wallet Standard
|
|
249
|
+
// unconditionally, the way EVM wallets are through EIP-6963: an app
|
|
250
|
+
// that never configures Solana still gets its connects. `solana: false`
|
|
251
|
+
// is the opt-out; an object adds framework-kit's store or a cluster.
|
|
252
|
+
if (options.solana !== false) {
|
|
253
|
+
this.solanaManager = new SolanaManager_1.SolanaManager(this, typeof options.solana === "object" ? options.solana : undefined);
|
|
251
254
|
}
|
|
252
255
|
this._currentUrl = window.location.href;
|
|
253
256
|
// Seed currentAddress/currentChainId from the persisted snapshot before
|
|
@@ -1018,6 +1021,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1018
1021
|
// Drop anything already buffered so a pending timer/pagehide flush
|
|
1019
1022
|
// cannot ship events after consent withdrawal.
|
|
1020
1023
|
this.eventManager.clear();
|
|
1024
|
+
// Identity is purged below; registered sessions must be re-learned
|
|
1025
|
+
// on opt-in, and nothing else would retry an already-adopted one.
|
|
1026
|
+
this.evmEvents.markRegisteredAdoptionsPending();
|
|
1021
1027
|
this.reset();
|
|
1022
1028
|
logger_1.logger.info("Successfully opted out of tracking");
|
|
1023
1029
|
};
|
|
@@ -1268,7 +1274,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1268
1274
|
*/
|
|
1269
1275
|
get: function () {
|
|
1270
1276
|
if (!this.solanaManager) {
|
|
1271
|
-
|
|
1277
|
+
// Only reachable after `solana: false` (or after cleanup). The host
|
|
1278
|
+
// opted out of discovery, so this manager serves the store path only.
|
|
1279
|
+
this.solanaManager = new SolanaManager_1.SolanaManager(this, undefined, false);
|
|
1272
1280
|
}
|
|
1273
1281
|
return this.solanaManager;
|
|
1274
1282
|
},
|
|
@@ -1363,8 +1371,14 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1363
1371
|
* gap. Lifecycle (connect/chain/disconnect) stays store-driven: only the
|
|
1364
1372
|
* request wrapper installs here. Double counting is prevented in the
|
|
1365
1373
|
* wrapper via `shouldSkipRequestCapture`.
|
|
1374
|
+
*
|
|
1375
|
+
* `attribution` resolves, live, the name and rdns of the connector this
|
|
1376
|
+
* provider was wrapped for. Request-derived events are named from the
|
|
1377
|
+
* registry, which for an unannounced provider falls back to flag
|
|
1378
|
+
* sniffing; recording the connector's resolver here keeps them in
|
|
1379
|
+
* agreement with the hook-driven events for that connector.
|
|
1366
1380
|
*/
|
|
1367
|
-
FormoAnalytics.prototype._wrapWagmiProvider = function (provider, chainId) {
|
|
1381
|
+
FormoAnalytics.prototype._wrapWagmiProvider = function (provider, chainId, attribution) {
|
|
1368
1382
|
if (this.isCleanedUp || !(0, provider_1.isValidProvider)(provider))
|
|
1369
1383
|
return false;
|
|
1370
1384
|
try {
|
|
@@ -1374,6 +1388,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1374
1388
|
if (!this.evmRequests.registerRequestListeners(provider)) {
|
|
1375
1389
|
return false;
|
|
1376
1390
|
}
|
|
1391
|
+
this.evm.rememberAttribution(provider, attribution);
|
|
1377
1392
|
if (chainId !== undefined) {
|
|
1378
1393
|
this.evm.rememberChain(provider, chainId);
|
|
1379
1394
|
}
|
|
@@ -72,6 +72,18 @@ var defaultContext = {
|
|
|
72
72
|
hasOptedOutTracking: function () { return false; },
|
|
73
73
|
};
|
|
74
74
|
exports.FormoAnalyticsContext = (0, react_1.createContext)(defaultContext);
|
|
75
|
+
var optionObjectIds = new WeakMap();
|
|
76
|
+
var nextOptionObjectId = 1;
|
|
77
|
+
var optionObjectId = function (value) {
|
|
78
|
+
if (!value)
|
|
79
|
+
return undefined;
|
|
80
|
+
var id = optionObjectIds.get(value);
|
|
81
|
+
if (id === undefined) {
|
|
82
|
+
id = nextOptionObjectId++;
|
|
83
|
+
optionObjectIds.set(value, id);
|
|
84
|
+
}
|
|
85
|
+
return id;
|
|
86
|
+
};
|
|
75
87
|
/**
|
|
76
88
|
* A stable key over the serializable parts of Options. The provider effect
|
|
77
89
|
* re-initialises the SDK when this key changes; anything that alters SDK
|
|
@@ -95,6 +107,14 @@ var computeOptionsKey = function (options) {
|
|
|
95
107
|
logger: options.logger,
|
|
96
108
|
referral: options.referral,
|
|
97
109
|
evm: options.evm,
|
|
110
|
+
// `solana` is a boolean or an options object. A store is a live event
|
|
111
|
+
// source, so replacing it must reinitialize the SDK even when both the
|
|
112
|
+
// old and new options contain a store.
|
|
113
|
+
solana: typeof options.solana === "object" ? undefined : options.solana,
|
|
114
|
+
solanaStoreId: typeof options.solana === "object"
|
|
115
|
+
? optionObjectId(options.solana.store)
|
|
116
|
+
: undefined,
|
|
117
|
+
solanaCluster: typeof options.solana === "object" ? options.solana.cluster : undefined,
|
|
98
118
|
// For complex objects, just track their presence, not their content
|
|
99
119
|
hasProvider: !!options.provider,
|
|
100
120
|
hasWagmi: !!options.wagmi,
|
|
@@ -52,10 +52,91 @@ export declare class EvmEventTracker {
|
|
|
52
52
|
* Announcement-driven cleanup must not touch them: they are never in an
|
|
53
53
|
* announcement list, so "missing from the announcement" is their normal
|
|
54
54
|
* state, not evidence of removal. A Set rather than a WeakSet because
|
|
55
|
-
*
|
|
56
|
-
* strongly
|
|
55
|
+
* the corrected-detect pass iterates it; the registry's detail list
|
|
56
|
+
* holds these providers strongly for the instance's life anyway.
|
|
57
57
|
*/
|
|
58
58
|
private externallyRegistered;
|
|
59
|
+
/**
|
|
60
|
+
* Registered providers whose session this SDK has NOT yet learned.
|
|
61
|
+
*
|
|
62
|
+
* Only these are retried on page hits and opt-in. Re-running adoption for
|
|
63
|
+
* every registered provider looked idempotent but was not: adoption is
|
|
64
|
+
* the same path a live `accountsChanged` takes, and that path treats a
|
|
65
|
+
* provider with a different address from the active one as a wallet
|
|
66
|
+
* switch. With two registered providers, or one registered next to a
|
|
67
|
+
* discovered wallet, every page hit emitted a disconnect and a connect
|
|
68
|
+
* that no user action caused.
|
|
69
|
+
*
|
|
70
|
+
* A provider enters at registration (it may have no session yet, or be
|
|
71
|
+
* refused because tracking is suppressed), again whenever a handler
|
|
72
|
+
* refuses its signal while suppressed (noted on entry AND at the
|
|
73
|
+
* suppressed commit, since the handlers gate on the active provider and
|
|
74
|
+
* re-check suppression after an await), and again for all of them when
|
|
75
|
+
* an opt-out purges identity. It leaves the first time a handler commits
|
|
76
|
+
* its session unsuppressed, or when it is untracked. Retrying reads the
|
|
77
|
+
* provider's SYNCHRONOUS accounts only - no RPC - so a registered
|
|
78
|
+
* provider whose session never fires `accountsChanged` (a wallet that
|
|
79
|
+
* signals `connect` alone while `autocapture.connect` is off, which
|
|
80
|
+
* installs a chain-only observer) is still adopted on the next hit. "No
|
|
81
|
+
* RPC" holds for the pending provider itself; the handler's switch
|
|
82
|
+
* arbitration may still ask the ACTIVE provider for its accounts, as it
|
|
83
|
+
* does for any live signal.
|
|
84
|
+
*
|
|
85
|
+
* Replay goes through the accounts handler, which has live wallet-switch
|
|
86
|
+
* semantics: a different provider with a different address is a switch.
|
|
87
|
+
* So a pending provider is replayed only while no OTHER wallet is active
|
|
88
|
+
* and known - it waits, at no cost, until that wallet is gone - unless
|
|
89
|
+
* its own signal was refused (`latestRefused`): then the replay does
|
|
90
|
+
* exactly what the live signal would have done, switch included.
|
|
91
|
+
*/
|
|
92
|
+
private pendingAdoptions;
|
|
93
|
+
/**
|
|
94
|
+
* The pending provider whose own live signal was refused while
|
|
95
|
+
* suppressed, LATEST only. The SDK follows one active wallet and the
|
|
96
|
+
* newest signal wins, so replaying only the last refused signal reaches
|
|
97
|
+
* the state the live signals would have reached, without the switches
|
|
98
|
+
* in between; an earlier refused provider stays pending, unprivileged.
|
|
99
|
+
*/
|
|
100
|
+
private latestRefused?;
|
|
101
|
+
private dropRefusal;
|
|
102
|
+
/**
|
|
103
|
+
* An opt-out purges wallet identity. Every registered session is then
|
|
104
|
+
* unknown again (pending; no refusal is ADDED, so the opt-in replay of a
|
|
105
|
+
* merely connected wallet does not switch, while a refusal already
|
|
106
|
+
* standing from an excluded route keeps its meaning), and the
|
|
107
|
+
* opt-in retry must re-learn all of them: with the active wallet's
|
|
108
|
+
* address gone, the accounts handler cannot even tell a second wallet's
|
|
109
|
+
* accounts apart from the active one's, and would ignore them.
|
|
110
|
+
*/
|
|
111
|
+
markRegisteredAdoptionsPending(): void;
|
|
112
|
+
/**
|
|
113
|
+
* Remember a registered provider's signal that suppression refuses.
|
|
114
|
+
*
|
|
115
|
+
* Replay privilege (`latestRefused`) goes only to a provider whose
|
|
116
|
+
* session the replay can actually read - synchronous accounts - so an
|
|
117
|
+
* accountless `connect` (a chain-only observation, or a session still
|
|
118
|
+
* pairing) cannot displace an earlier refusal that is adoptable.
|
|
119
|
+
*/
|
|
120
|
+
private noteRefusalIfSuppressed;
|
|
121
|
+
/**
|
|
122
|
+
* Registered providers whose session ended and have not signalled a
|
|
123
|
+
* new one. Some providers keep stale synchronous `accounts` after a
|
|
124
|
+
* disconnect; replaying those would re-install a session that is over.
|
|
125
|
+
* Any later session signal (connect, accountsChanged) lifts this.
|
|
126
|
+
*/
|
|
127
|
+
private awaitingNewSession;
|
|
128
|
+
/** A handler has learned this provider's session; nothing is pending. */
|
|
129
|
+
private settleAdoption;
|
|
130
|
+
/**
|
|
131
|
+
* A registered provider's session has ended. Its NEXT session is not
|
|
132
|
+
* yet learned, and may announce itself in a way no handler adopts (a
|
|
133
|
+
* `connect` alone while `autocapture.connect` is off installs a
|
|
134
|
+
* chain-only observer), so it is pending again for the page-hit retry.
|
|
135
|
+
*/
|
|
136
|
+
private reopenAdoption;
|
|
137
|
+
/** One retry scan at a time; a call during a scan queues one more. */
|
|
138
|
+
private retryInFlight;
|
|
139
|
+
private retryRequested;
|
|
59
140
|
/**
|
|
60
141
|
* The connect this SDK has already reported for a provider.
|
|
61
142
|
*
|
|
@@ -74,6 +155,11 @@ export declare class EvmEventTracker {
|
|
|
74
155
|
constructor(wallet: WalletStateStore, registry: EvmProviderRegistry, deps: EvmEventTrackerDeps);
|
|
75
156
|
/** Stop listening for wallet announcements. Called from SDK teardown. */
|
|
76
157
|
cleanup(): void;
|
|
158
|
+
/** Set by `cleanup()`; every awaited continuation checks it. */
|
|
159
|
+
private disposed;
|
|
160
|
+
/** Bumped when a registered provider's session ends. See reopenAdoption. */
|
|
161
|
+
private sessionGenerations;
|
|
162
|
+
private sessionGeneration;
|
|
77
163
|
/** Drop a provider's reported connect. Called when it stops being active. */
|
|
78
164
|
forgetAnnouncedConnect(provider: EIP1193Provider): void;
|
|
79
165
|
/**
|
|
@@ -109,14 +195,19 @@ export declare class EvmEventTracker {
|
|
|
109
195
|
*/
|
|
110
196
|
adoptExternalProvider(detail: EIP6963ProviderDetail): boolean;
|
|
111
197
|
/**
|
|
112
|
-
*
|
|
198
|
+
* Finish what registration could not.
|
|
199
|
+
*
|
|
200
|
+
* A registered provider's session may not have existed at registration,
|
|
201
|
+
* or its adoption was refused because tracking was suppressed (opt-out,
|
|
202
|
+
* excluded route) - and an existing session may never emit another
|
|
203
|
+
* accountsChanged, so nothing else would ever retry. Called when
|
|
204
|
+
* suppression can have ended (opt-in, page navigation).
|
|
113
205
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* deduplicated by the same state and markers as any repeated signal.
|
|
206
|
+
* Adoption is retried ONLY for providers not yet adopted
|
|
207
|
+
* (`pendingAdoptions`), only from their synchronous accounts, and only
|
|
208
|
+
* once suppression has actually ended. The corrected-detect pass below
|
|
209
|
+
* runs for every registered provider: it is deduplicated per session by
|
|
210
|
+
* rdns, so repeating it is free.
|
|
120
211
|
*/
|
|
121
212
|
retryExternalAdoptions(): void;
|
|
122
213
|
private registerAccountsChangedListener;
|