@formo/analytics 1.38.2 → 1.40.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 +4 -1
- package/dist/cjs/src/FormoAnalytics.js +56 -36
- package/dist/cjs/src/FormoAnalyticsProvider.js +20 -0
- package/dist/cjs/src/event/EventFactory.d.ts +9 -1
- package/dist/cjs/src/event/EventFactory.js +31 -16
- package/dist/cjs/src/event/EventManager.d.ts +3 -1
- package/dist/cjs/src/event/EventManager.js +33 -4
- package/dist/cjs/src/event/cancellation.d.ts +4 -0
- package/dist/cjs/src/event/cancellation.js +7 -0
- package/dist/cjs/src/event/type.d.ts +1 -0
- package/dist/cjs/src/event/utils.d.ts +5 -1
- package/dist/cjs/src/event/utils.js +57 -2
- package/dist/cjs/src/evm/EvmEventTracker.d.ts +7 -0
- package/dist/cjs/src/evm/EvmEventTracker.js +31 -5
- package/dist/cjs/src/queue/EventQueue.d.ts +1 -0
- package/dist/cjs/src/queue/EventQueue.js +11 -6
- 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/storage/StorageManager.d.ts +2 -0
- package/dist/cjs/src/storage/StorageManager.js +6 -0
- package/dist/cjs/src/storage/index.d.ts +1 -0
- package/dist/cjs/src/storage/index.js +7 -1
- 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/esm/src/FormoAnalytics.d.ts +4 -1
- package/dist/esm/src/FormoAnalytics.js +54 -34
- package/dist/esm/src/FormoAnalyticsProvider.js +20 -0
- package/dist/esm/src/event/EventFactory.d.ts +9 -1
- package/dist/esm/src/event/EventFactory.js +31 -16
- package/dist/esm/src/event/EventManager.d.ts +3 -1
- package/dist/esm/src/event/EventManager.js +33 -4
- package/dist/esm/src/event/cancellation.d.ts +4 -0
- package/dist/esm/src/event/cancellation.js +4 -0
- package/dist/esm/src/event/type.d.ts +1 -0
- package/dist/esm/src/event/utils.d.ts +5 -1
- package/dist/esm/src/event/utils.js +56 -3
- package/dist/esm/src/evm/EvmEventTracker.d.ts +7 -0
- package/dist/esm/src/evm/EvmEventTracker.js +31 -5
- package/dist/esm/src/queue/EventQueue.d.ts +1 -0
- package/dist/esm/src/queue/EventQueue.js +11 -6
- 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/storage/StorageManager.d.ts +2 -0
- package/dist/esm/src/storage/StorageManager.js +6 -0
- package/dist/esm/src/storage/index.d.ts +1 -0
- package/dist/esm/src/storage/index.js +5 -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/index.umd.min.js +1 -1
- package/package.json +2 -2
|
@@ -72,13 +72,32 @@ export interface SolanaWalletConnectorMetadata {
|
|
|
72
72
|
readonly name: string;
|
|
73
73
|
readonly icon?: string;
|
|
74
74
|
}
|
|
75
|
+
/** Cluster health as exposed by framework-kit. */
|
|
76
|
+
export type SolanaClusterStatus = Readonly<{
|
|
77
|
+
status: "idle";
|
|
78
|
+
}> | Readonly<{
|
|
79
|
+
status: "connecting";
|
|
80
|
+
}> | Readonly<{
|
|
81
|
+
status: "ready";
|
|
82
|
+
latencyMs?: number;
|
|
83
|
+
}> | Readonly<{
|
|
84
|
+
status: "error";
|
|
85
|
+
error: unknown;
|
|
86
|
+
}>;
|
|
87
|
+
/** @deprecated framework-kit emits {@link SolanaClusterStatus} objects. */
|
|
88
|
+
export type LegacySolanaClusterStatus = SolanaClusterStatus["status"];
|
|
75
89
|
/**
|
|
76
90
|
* Cluster state from the store.
|
|
77
91
|
*/
|
|
78
92
|
export interface SolanaClusterState {
|
|
79
93
|
readonly endpoint: string;
|
|
80
94
|
readonly commitment?: string;
|
|
81
|
-
|
|
95
|
+
/**
|
|
96
|
+
* framework-kit's `ClusterStatus` is a discriminated union such as
|
|
97
|
+
* `{ status: 'ready', latencyMs?: number }`. The pre-1.39 string form is
|
|
98
|
+
* retained so custom stores and test doubles remain source-compatible.
|
|
99
|
+
*/
|
|
100
|
+
readonly status: SolanaClusterStatus | LegacySolanaClusterStatus;
|
|
82
101
|
}
|
|
83
102
|
/**
|
|
84
103
|
* The zustand vanilla store API that framework-kit exposes via `client.store`.
|
|
@@ -46,15 +46,32 @@ export interface SolanaPublicKey {
|
|
|
46
46
|
*/
|
|
47
47
|
export type UnsubscribeFn = () => void;
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* The rdns reported for a Solana wallet.
|
|
50
|
+
*
|
|
51
|
+
* The Wallet Standard has no reverse-domain identifier, so one is derived
|
|
52
|
+
* from the wallet's normalized name. Lowercasing and removing whitespace
|
|
53
|
+
* preserves the values historically reported by the framework-kit store;
|
|
54
|
+
* encoding keeps delimiters and other special characters safe for storage.
|
|
55
|
+
* Both Solana paths (Wallet Standard discovery and the framework-kit store)
|
|
56
|
+
* derive it the same way, so a wallet's `detect` and its `connect` share one
|
|
57
|
+
* rdns whichever path reported each.
|
|
58
|
+
*/
|
|
59
|
+
export declare function solanaWalletRdns(walletName: string): string;
|
|
60
|
+
/**
|
|
61
|
+
* Solana options for FormoAnalytics.
|
|
62
|
+
*
|
|
63
|
+
* Wallet discovery through the Wallet Standard is on by default and needs
|
|
64
|
+
* none of these. They add framework-kit's store, or name the cluster.
|
|
50
65
|
*/
|
|
51
66
|
export interface SolanaOptions {
|
|
52
67
|
/**
|
|
53
|
-
* The framework-kit client store (client.store)
|
|
54
|
-
* When provided,
|
|
55
|
-
*
|
|
68
|
+
* The framework-kit client store (client.store).
|
|
69
|
+
* When provided, transaction lifecycle events and cluster switches are
|
|
70
|
+
* tracked from the store, and connect/disconnect come from the store
|
|
71
|
+
* rather than from Wallet Standard discovery.
|
|
56
72
|
*
|
|
57
|
-
*
|
|
73
|
+
* Only for apps using framework-kit (`@solana/client`). Other integrations
|
|
74
|
+
* do not need a store when their wallets register through Wallet Standard.
|
|
58
75
|
*
|
|
59
76
|
* @example
|
|
60
77
|
* ```tsx
|
|
@@ -65,10 +82,16 @@ export interface SolanaOptions {
|
|
|
65
82
|
*/
|
|
66
83
|
store?: import("./storeTypes").SolanaClientStore;
|
|
67
84
|
/**
|
|
68
|
-
* The Solana cluster/network.
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
85
|
+
* The Solana cluster/network the app is on.
|
|
86
|
+
*
|
|
87
|
+
* With a store, usually auto-detected from its endpoint URL; only needed
|
|
88
|
+
* for custom RPC URLs that don't contain a recognizable cluster name.
|
|
89
|
+
* Without a store, the Wallet Standard cannot say which cluster the app
|
|
90
|
+
* uses, so a devnet or testnet app should set this (or call
|
|
91
|
+
* `formo.solana.setCluster()`); otherwise connections are reported on
|
|
92
|
+
* mainnet-beta.
|
|
93
|
+
* @default auto-detected from the store; otherwise mainnet-beta when the
|
|
94
|
+
* wallet supports it, or its first supported Solana cluster
|
|
72
95
|
*/
|
|
73
96
|
cluster?: SolanaCluster;
|
|
74
97
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.DEFAULT_SOLANA_CHAIN_ID = exports.SOLANA_CLUSTERS_BY_ID = exports.SOLANA_CHAIN_IDS = void 0;
|
|
12
12
|
exports.isSolanaChainId = isSolanaChainId;
|
|
13
|
+
exports.solanaWalletRdns = solanaWalletRdns;
|
|
13
14
|
/**
|
|
14
15
|
* Mapping of Solana clusters to numeric chain IDs for consistency with EVM events
|
|
15
16
|
* These IDs are non-standard but provide a way to identify Solana networks in our analytics
|
|
@@ -44,4 +45,18 @@ function isSolanaChainId(chainId) {
|
|
|
44
45
|
return false;
|
|
45
46
|
return Object.values(exports.SOLANA_CHAIN_IDS).includes(chainId);
|
|
46
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* The rdns reported for a Solana wallet.
|
|
50
|
+
*
|
|
51
|
+
* The Wallet Standard has no reverse-domain identifier, so one is derived
|
|
52
|
+
* from the wallet's normalized name. Lowercasing and removing whitespace
|
|
53
|
+
* preserves the values historically reported by the framework-kit store;
|
|
54
|
+
* encoding keeps delimiters and other special characters safe for storage.
|
|
55
|
+
* Both Solana paths (Wallet Standard discovery and the framework-kit store)
|
|
56
|
+
* derive it the same way, so a wallet's `detect` and its `connect` share one
|
|
57
|
+
* rdns whichever path reported each.
|
|
58
|
+
*/
|
|
59
|
+
function solanaWalletRdns(walletName) {
|
|
60
|
+
return "sol.wallet.".concat(encodeURIComponent(walletName.toLowerCase().replace(/\s+/g, "")));
|
|
61
|
+
}
|
|
47
62
|
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The subset of the Wallet Standard this SDK reads.
|
|
3
|
+
*
|
|
4
|
+
* Duck-typed on purpose: the SDK must not depend on `@wallet-standard/*`
|
|
5
|
+
* packages (see the dependency policy), and a wallet is discovered through
|
|
6
|
+
* window events, so nothing here is ever imported from a wallet library.
|
|
7
|
+
* Every field is what a conforming wallet exposes; the shapes are looser
|
|
8
|
+
* than the reference types so a slightly off wallet is skipped, not thrown
|
|
9
|
+
* on.
|
|
10
|
+
*
|
|
11
|
+
* @see https://github.com/wallet-standard/wallet-standard
|
|
12
|
+
*/
|
|
13
|
+
/** `namespace:reference`, e.g. `solana:mainnet` or `solana:devnet`. */
|
|
14
|
+
export type WalletStandardChain = string;
|
|
15
|
+
export interface WalletStandardAccount {
|
|
16
|
+
readonly address: string;
|
|
17
|
+
readonly publicKey?: unknown;
|
|
18
|
+
/** Chains this account can sign for. Absent on a non-conforming wallet. */
|
|
19
|
+
readonly chains?: readonly WalletStandardChain[];
|
|
20
|
+
readonly features?: readonly string[];
|
|
21
|
+
readonly label?: string;
|
|
22
|
+
readonly icon?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface WalletStandardWallet {
|
|
25
|
+
readonly version?: string;
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly icon?: string;
|
|
28
|
+
/** Every chain the wallet supports, NOT the one currently selected. */
|
|
29
|
+
readonly chains: readonly WalletStandardChain[];
|
|
30
|
+
readonly features: Readonly<Record<string, unknown>>;
|
|
31
|
+
/** Accounts the app is currently authorized for; empty until connected. */
|
|
32
|
+
readonly accounts: readonly WalletStandardAccount[];
|
|
33
|
+
}
|
|
34
|
+
/** What a `standard:events` `change` event carries: only what changed. */
|
|
35
|
+
export interface WalletStandardChangeProperties {
|
|
36
|
+
readonly chains?: readonly WalletStandardChain[];
|
|
37
|
+
readonly features?: Readonly<Record<string, unknown>>;
|
|
38
|
+
readonly accounts?: readonly WalletStandardAccount[];
|
|
39
|
+
}
|
|
40
|
+
/** The `standard:events` feature. */
|
|
41
|
+
export interface WalletStandardEventsFeature {
|
|
42
|
+
readonly version?: string;
|
|
43
|
+
on(event: "change", listener: (properties: WalletStandardChangeProperties) => void): () => void;
|
|
44
|
+
}
|
|
45
|
+
/** The API an app hands to wallets so they can announce themselves. */
|
|
46
|
+
export interface WalletStandardRegisterApi {
|
|
47
|
+
register(...wallets: WalletStandardWallet[]): () => void;
|
|
48
|
+
}
|
|
49
|
+
/** Dispatched by the app on `window`; `detail` is the register API. */
|
|
50
|
+
export declare const WALLET_STANDARD_APP_READY_EVENT = "wallet-standard:app-ready";
|
|
51
|
+
/** Dispatched by a wallet on `window`; `detail` is a callback taking the API. */
|
|
52
|
+
export declare const WALLET_STANDARD_REGISTER_WALLET_EVENT = "wallet-standard:register-wallet";
|
|
53
|
+
export declare const WALLET_STANDARD_EVENTS_FEATURE = "standard:events";
|
|
54
|
+
//# sourceMappingURL=walletStandardTypes.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The subset of the Wallet Standard this SDK reads.
|
|
4
|
+
*
|
|
5
|
+
* Duck-typed on purpose: the SDK must not depend on `@wallet-standard/*`
|
|
6
|
+
* packages (see the dependency policy), and a wallet is discovered through
|
|
7
|
+
* window events, so nothing here is ever imported from a wallet library.
|
|
8
|
+
* Every field is what a conforming wallet exposes; the shapes are looser
|
|
9
|
+
* than the reference types so a slightly off wallet is skipped, not thrown
|
|
10
|
+
* on.
|
|
11
|
+
*
|
|
12
|
+
* @see https://github.com/wallet-standard/wallet-standard
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.WALLET_STANDARD_EVENTS_FEATURE = exports.WALLET_STANDARD_REGISTER_WALLET_EVENT = exports.WALLET_STANDARD_APP_READY_EVENT = void 0;
|
|
16
|
+
/** Dispatched by the app on `window`; `detail` is the register API. */
|
|
17
|
+
exports.WALLET_STANDARD_APP_READY_EVENT = "wallet-standard:app-ready";
|
|
18
|
+
/** Dispatched by a wallet on `window`; `detail` is a callback taking the API. */
|
|
19
|
+
exports.WALLET_STANDARD_REGISTER_WALLET_EVENT = "wallet-standard:register-wallet";
|
|
20
|
+
exports.WALLET_STANDARD_EVENTS_FEATURE = "standard:events";
|
|
21
|
+
//# sourceMappingURL=walletStandardTypes.js.map
|
|
@@ -2,8 +2,10 @@ import { IStorage, StorageType } from "./type";
|
|
|
2
2
|
export declare class StorageManager {
|
|
3
3
|
private readonly writeKey;
|
|
4
4
|
private storages;
|
|
5
|
+
private resolvedTypes;
|
|
5
6
|
constructor(writeKey: string);
|
|
6
7
|
getStorage(type: StorageType): IStorage;
|
|
8
|
+
getResolvedType(type: StorageType): StorageType;
|
|
7
9
|
private createStorage;
|
|
8
10
|
private getWebStorage;
|
|
9
11
|
}
|
|
@@ -19,6 +19,7 @@ var StorageManager = /** @class */ (function () {
|
|
|
19
19
|
function StorageManager(writeKey) {
|
|
20
20
|
this.writeKey = writeKey;
|
|
21
21
|
this.storages = new Map();
|
|
22
|
+
this.resolvedTypes = new Map();
|
|
22
23
|
}
|
|
23
24
|
StorageManager.prototype.getStorage = function (type) {
|
|
24
25
|
if (!this.storages.has(type)) {
|
|
@@ -39,9 +40,14 @@ var StorageManager = /** @class */ (function () {
|
|
|
39
40
|
}
|
|
40
41
|
// Add to cache
|
|
41
42
|
this.storages.set(type, storage);
|
|
43
|
+
this.resolvedTypes.set(type, currentType);
|
|
42
44
|
}
|
|
43
45
|
return this.storages.get(type);
|
|
44
46
|
};
|
|
47
|
+
StorageManager.prototype.getResolvedType = function (type) {
|
|
48
|
+
this.getStorage(type);
|
|
49
|
+
return this.resolvedTypes.get(type);
|
|
50
|
+
};
|
|
45
51
|
StorageManager.prototype.createStorage = function (type) {
|
|
46
52
|
switch (type) {
|
|
47
53
|
case "cookieStorage":
|
|
@@ -5,4 +5,5 @@ export declare const cookie: () => IStorage;
|
|
|
5
5
|
export declare const local: () => IStorage;
|
|
6
6
|
export declare const session: () => IStorage;
|
|
7
7
|
export declare const memory: () => IStorage;
|
|
8
|
+
export declare const usesCookieStorage: () => boolean;
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.memory = exports.session = exports.local = exports.cookie = void 0;
|
|
17
|
+
exports.usesCookieStorage = exports.memory = exports.session = exports.local = exports.cookie = void 0;
|
|
18
18
|
exports.initStorageManager = initStorageManager;
|
|
19
19
|
var StorageManager_1 = require("./StorageManager");
|
|
20
20
|
__exportStar(require("./type"), exports);
|
|
@@ -38,4 +38,10 @@ var session = function () { return getStorageInstance("sessionStorage"); };
|
|
|
38
38
|
exports.session = session;
|
|
39
39
|
var memory = function () { return getStorageInstance("memoryStorage"); };
|
|
40
40
|
exports.memory = memory;
|
|
41
|
+
var usesCookieStorage = function () {
|
|
42
|
+
if (!globalManager)
|
|
43
|
+
return false;
|
|
44
|
+
return globalManager.getResolvedType("cookieStorage") === "cookieStorage";
|
|
45
|
+
};
|
|
46
|
+
exports.usesCookieStorage = usesCookieStorage;
|
|
41
47
|
//# sourceMappingURL=index.js.map
|
|
@@ -246,16 +246,26 @@ export interface Options {
|
|
|
246
246
|
*/
|
|
247
247
|
wagmi?: WagmiOptions;
|
|
248
248
|
/**
|
|
249
|
-
* Solana
|
|
250
|
-
*
|
|
251
|
-
*
|
|
249
|
+
* Solana wallet tracking.
|
|
250
|
+
*
|
|
251
|
+
* On by default: wallets are discovered through the Wallet Standard, the
|
|
252
|
+
* Solana analogue of EIP-6963, so connect and disconnect are autocaptured
|
|
253
|
+
* for compatible wallets registered with the page, including wallets used
|
|
254
|
+
* through Solana Kit, wallet-adapter, and framework-kit.
|
|
255
|
+
*
|
|
256
|
+
* - `false`: disable Solana wallet discovery and tracking entirely.
|
|
257
|
+
* - `SolanaOptions`: additionally pass `store: client.store` from
|
|
258
|
+
* framework-kit for transaction lifecycle events and cluster switches,
|
|
259
|
+
* or `cluster` to name the network a non-mainnet app is on.
|
|
252
260
|
*
|
|
253
261
|
* For signMessage/signTransaction, use formo.signature() directly
|
|
254
|
-
* (framework-kit
|
|
262
|
+
* (neither the Wallet Standard nor framework-kit's store reports these).
|
|
255
263
|
*
|
|
264
|
+
* @see https://github.com/wallet-standard/wallet-standard
|
|
256
265
|
* @see https://github.com/solana-foundation/framework-kit
|
|
266
|
+
* @default true
|
|
257
267
|
*/
|
|
258
|
-
solana?: SolanaOptions;
|
|
268
|
+
solana?: boolean | SolanaOptions;
|
|
259
269
|
/**
|
|
260
270
|
* Custom API host for sending events through your own domain to bypass ad blockers
|
|
261
271
|
* - If not provided, events are sent directly to events.formo.so
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.
|
|
1
|
+
export declare const version = "1.40.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cjs/src/version.js
CHANGED
|
@@ -3,5 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.version = void 0;
|
|
4
4
|
// This file is auto-generated by scripts/update-version.js during npm version
|
|
5
5
|
// Do not edit manually - it will be overwritten
|
|
6
|
-
exports.version = '1.
|
|
6
|
+
exports.version = '1.40.0';
|
|
7
7
|
//# sourceMappingURL=version.js.map
|
|
@@ -54,6 +54,7 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
54
54
|
private _onPopStateListener?;
|
|
55
55
|
private _onLocationChangeListener?;
|
|
56
56
|
private _pageHooksDisposed;
|
|
57
|
+
private _pageGeneration;
|
|
57
58
|
config: Config;
|
|
58
59
|
/**
|
|
59
60
|
* The wallet later events are attributed to, derived from whichever
|
|
@@ -87,7 +88,8 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
87
88
|
*/
|
|
88
89
|
page(category?: string, name?: string, properties?: IFormoEventProperties, context?: IFormoEventContext, callback?: (...args: unknown[]) => void): Promise<void>;
|
|
89
90
|
/**
|
|
90
|
-
* Reset the
|
|
91
|
+
* Reset user and wallet state while preserving the browser's anonymous id.
|
|
92
|
+
* Use `optOutTracking()` to clear the anonymous id and the attribution.
|
|
91
93
|
* @returns {void}
|
|
92
94
|
*/
|
|
93
95
|
reset(): void;
|
|
@@ -142,6 +144,7 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
142
144
|
chainId?: ChainID;
|
|
143
145
|
address?: Address;
|
|
144
146
|
}): void;
|
|
147
|
+
private retryWalletDetection;
|
|
145
148
|
/** @see WalletStateStore.clearProvider */
|
|
146
149
|
private clearActiveProvider;
|
|
147
150
|
/** @see WalletStateStore.backfill */
|
|
@@ -49,6 +49,7 @@ import { EVENTS_API_HOST, EventType, LOCAL_ANONYMOUS_ID_KEY, SESSION_USER_ID_KEY
|
|
|
49
49
|
import { cookie, session, initStorageManager } from "./storage";
|
|
50
50
|
import { getIdentityCookieDomain, getIdentityCookieSecurity, } from "./storage/cookiePolicy";
|
|
51
51
|
import { EventManager } from "./event";
|
|
52
|
+
import { clearAnonymousId } from "./event/utils";
|
|
52
53
|
import { EventQueue } from "./queue";
|
|
53
54
|
import { logger, Logger } from "./logger";
|
|
54
55
|
import { setConsentFlag, getConsentFlag, removeConsentFlag, } from "./consent";
|
|
@@ -90,6 +91,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
90
91
|
/** In-memory URL used to deduplicate SPA pageview events. */
|
|
91
92
|
this._currentUrl = "";
|
|
92
93
|
this._pageHooksDisposed = false;
|
|
94
|
+
this._pageGeneration = 0;
|
|
93
95
|
this.currentUserId = "";
|
|
94
96
|
/**
|
|
95
97
|
* Clean up resources and event listeners
|
|
@@ -187,6 +189,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
187
189
|
isAutocaptureEnabled: function (t) { return _this.isAutocaptureEnabled(t); },
|
|
188
190
|
isTrackingSuppressed: function () { return _this.isTrackingSuppressed(); },
|
|
189
191
|
willTrackEvent: function (chainId) { return _this.willTrackEvent(chainId); },
|
|
192
|
+
retryDetection: function () { return _this.retryWalletDetection(); },
|
|
190
193
|
isWagmiMode: function () { return _this.isWagmiMode; },
|
|
191
194
|
connect: function (params, properties) { return _this.connect(params, properties); },
|
|
192
195
|
disconnect: function (params) { return _this.disconnect(params); },
|
|
@@ -215,7 +218,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
215
218
|
// ever sent once the user has opted out, even via a timer or
|
|
216
219
|
// pagehide flush scheduled before opt-out.
|
|
217
220
|
canSend: function () { return !_this.hasOptedOutTracking(); },
|
|
218
|
-
}), options);
|
|
221
|
+
}), options, function () { return !_this.hasOptedOutTracking(); });
|
|
219
222
|
// Check consent status on initialization
|
|
220
223
|
if (this.hasOptedOutTracking()) {
|
|
221
224
|
logger.info("User has previously opted out of tracking");
|
|
@@ -242,9 +245,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
242
245
|
this.evmEvents.trackEIP1193Provider(provider);
|
|
243
246
|
}
|
|
244
247
|
}
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
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(this, typeof options.solana === "object" ? options.solana : undefined);
|
|
248
254
|
}
|
|
249
255
|
this._currentUrl = window.location.href;
|
|
250
256
|
// Seed currentAddress/currentChainId from the persisted snapshot before
|
|
@@ -314,7 +320,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
314
320
|
});
|
|
315
321
|
FormoAnalytics.init = function (writeKey, options) {
|
|
316
322
|
return __awaiter(this, void 0, void 0, function () {
|
|
317
|
-
var analytics, discovered;
|
|
323
|
+
var analytics, discovered, error_1;
|
|
318
324
|
return __generator(this, function (_a) {
|
|
319
325
|
switch (_a.label) {
|
|
320
326
|
case 0:
|
|
@@ -324,18 +330,21 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
324
330
|
logger.info("FormoAnalytics: Skipping provider detection (EVM disabled)");
|
|
325
331
|
return [3 /*break*/, 5];
|
|
326
332
|
case 1:
|
|
327
|
-
|
|
333
|
+
_a.trys.push([1, 4, , 5]);
|
|
328
334
|
return [4 /*yield*/, analytics.evmEvents.getProviders()];
|
|
329
335
|
case 2:
|
|
330
336
|
discovered = _a.sent();
|
|
331
337
|
return [4 /*yield*/, analytics.evmEvents.detectWallets(discovered)];
|
|
332
338
|
case 3:
|
|
333
339
|
_a.sent();
|
|
334
|
-
analytics.
|
|
340
|
+
if (!analytics.isWagmiMode) {
|
|
341
|
+
analytics.evmEvents.trackProviders(discovered);
|
|
342
|
+
}
|
|
335
343
|
return [3 /*break*/, 5];
|
|
336
344
|
case 4:
|
|
337
|
-
|
|
338
|
-
|
|
345
|
+
error_1 = _a.sent();
|
|
346
|
+
logger.warn("FormoAnalytics: Provider discovery failed", error_1);
|
|
347
|
+
return [3 /*break*/, 5];
|
|
339
348
|
case 5: return [2 /*return*/, analytics];
|
|
340
349
|
}
|
|
341
350
|
});
|
|
@@ -366,7 +375,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
366
375
|
});
|
|
367
376
|
};
|
|
368
377
|
/**
|
|
369
|
-
* Reset the
|
|
378
|
+
* Reset user and wallet state while preserving the browser's anonymous id.
|
|
379
|
+
* Use `optOutTracking()` to clear the anonymous id and the attribution.
|
|
370
380
|
* @returns {void}
|
|
371
381
|
*/
|
|
372
382
|
FormoAnalytics.prototype.reset = function () {
|
|
@@ -377,15 +387,11 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
377
387
|
// page lifetime, because they fall back to currentAddress. Keep the
|
|
378
388
|
// EVM provider reference so tracking can resume on the next connect.
|
|
379
389
|
this.wallet.reset();
|
|
380
|
-
cookie().remove(LOCAL_ANONYMOUS_ID_KEY);
|
|
381
390
|
cookie().remove(SESSION_USER_ID_KEY);
|
|
382
391
|
cookie().remove(SESSION_WALLET_DETECTED_KEY);
|
|
383
392
|
cookie().remove(SESSION_WALLET_IDENTIFIED_KEY);
|
|
384
393
|
cookie().remove(ACTIVE_WALLET_KEY);
|
|
385
|
-
//
|
|
386
|
-
// clear it too so reset()/optOutTracking() don't leave it to be
|
|
387
|
-
// re-attached to the next session's events.
|
|
388
|
-
session().remove(SESSION_TRAFFIC_SOURCE_KEY);
|
|
394
|
+
// Attribution belongs to the visit, so reset preserves it.
|
|
389
395
|
};
|
|
390
396
|
FormoAnalytics.prototype.cleanup = function () {
|
|
391
397
|
this.isCleanedUp = true;
|
|
@@ -569,6 +575,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
569
575
|
*/
|
|
570
576
|
FormoAnalytics.prototype.syncWalletState = function (params) {
|
|
571
577
|
this.wallet.syncWalletState(params);
|
|
578
|
+
this.retryWalletDetection();
|
|
579
|
+
};
|
|
580
|
+
FormoAnalytics.prototype.retryWalletDetection = function () {
|
|
581
|
+
if (this.isCleanedUp)
|
|
582
|
+
return;
|
|
583
|
+
void this.evmEvents.detectWallets(this.evmEvents.detectableProviders());
|
|
572
584
|
};
|
|
573
585
|
/** @see WalletStateStore.clearProvider */
|
|
574
586
|
FormoAnalytics.prototype.clearActiveProvider = function () {
|
|
@@ -768,6 +780,11 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
768
780
|
return [2 /*return*/];
|
|
769
781
|
}
|
|
770
782
|
if (!!params) return [3 /*break*/, 12];
|
|
783
|
+
// Wagmi owns wallet identification.
|
|
784
|
+
if (this.isWagmiMode) {
|
|
785
|
+
logger.info("identify() without params is a no-op in Wagmi mode");
|
|
786
|
+
return [2 /*return*/];
|
|
787
|
+
}
|
|
771
788
|
// If no params provided, auto-identify
|
|
772
789
|
logger.info("Auto-identifying with providers:", this.evm.all.map(function (p) { return p.info.name; }));
|
|
773
790
|
_i = 0, _a = this.evm.all;
|
|
@@ -947,10 +964,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
947
964
|
return __generator(this, function (_c) {
|
|
948
965
|
switch (_c.label) {
|
|
949
966
|
case 0:
|
|
950
|
-
//
|
|
951
|
-
|
|
952
|
-
// excluded environment (opt-out / timezone / host / path).
|
|
953
|
-
if (this.isTrackingSuppressed()) {
|
|
967
|
+
// Apply all policy checks before persisting the detection marker.
|
|
968
|
+
if (!this.shouldTrack()) {
|
|
954
969
|
logger.info("detect() skipped: tracking is suppressed for this visitor or environment");
|
|
955
970
|
return [2 /*return*/];
|
|
956
971
|
}
|
|
@@ -1012,6 +1027,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1012
1027
|
// Set opt-out flag in persistent storage using direct cookie access
|
|
1013
1028
|
// This must be done before switching storage to ensure persistence
|
|
1014
1029
|
setConsentFlag(this.writeKey, CONSENT_OPT_OUT_KEY, "true");
|
|
1030
|
+
this._pageGeneration++;
|
|
1015
1031
|
// Drop anything already buffered so a pending timer/pagehide flush
|
|
1016
1032
|
// cannot ship events after consent withdrawal.
|
|
1017
1033
|
this.eventManager.clear();
|
|
@@ -1019,6 +1035,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1019
1035
|
// on opt-in, and nothing else would retry an already-adopted one.
|
|
1020
1036
|
this.evmEvents.markRegisteredAdoptionsPending();
|
|
1021
1037
|
this.reset();
|
|
1038
|
+
// Consent withdrawal also clears the browser id and the attribution.
|
|
1039
|
+
clearAnonymousId(LOCAL_ANONYMOUS_ID_KEY);
|
|
1040
|
+
session().remove(SESSION_TRAFFIC_SOURCE_KEY);
|
|
1022
1041
|
logger.info("Successfully opted out of tracking");
|
|
1023
1042
|
};
|
|
1024
1043
|
/**
|
|
@@ -1045,11 +1064,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1045
1064
|
logger.info("Opting back into tracking");
|
|
1046
1065
|
// Remove opt-out flag
|
|
1047
1066
|
removeConsentFlag(this.writeKey, CONSENT_OPT_OUT_KEY);
|
|
1048
|
-
//
|
|
1049
|
-
// an unchanged wagmi connection produces no status or chain update to
|
|
1050
|
-
// retry on. Without this, opting back in leaves that wallet invisible for
|
|
1051
|
-
// the rest of the page load.
|
|
1067
|
+
// Retry wallet adoption skipped while opted out.
|
|
1052
1068
|
(_a = this.wagmiHandler) === null || _a === void 0 ? void 0 : _a.retryAdoption();
|
|
1069
|
+
this.retryWalletDetection();
|
|
1053
1070
|
logger.info("Successfully opted back into tracking");
|
|
1054
1071
|
};
|
|
1055
1072
|
/**
|
|
@@ -1130,29 +1147,30 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1130
1147
|
};
|
|
1131
1148
|
FormoAnalytics.prototype.trackPageHit = function (category, name, properties, context, callback) {
|
|
1132
1149
|
return __awaiter(this, void 0, void 0, function () {
|
|
1150
|
+
var canTrack, generation;
|
|
1133
1151
|
var _this = this;
|
|
1134
1152
|
return __generator(this, function (_a) {
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
// Idempotent and cheap when nothing is pending.
|
|
1138
|
-
if (!this.isCleanedUp) {
|
|
1153
|
+
canTrack = this.shouldTrack();
|
|
1154
|
+
if (!this.isCleanedUp && canTrack) {
|
|
1139
1155
|
try {
|
|
1140
1156
|
this.evmEvents.retryExternalAdoptions();
|
|
1157
|
+
this.retryWalletDetection();
|
|
1141
1158
|
}
|
|
1142
1159
|
catch (_b) {
|
|
1143
|
-
|
|
1160
|
+
// Detection retries must not break page tracking.
|
|
1144
1161
|
}
|
|
1145
1162
|
}
|
|
1146
|
-
if (!
|
|
1163
|
+
if (!canTrack) {
|
|
1147
1164
|
logger.info("Track page hit: Skipping event due to tracking configuration");
|
|
1148
1165
|
return [2 /*return*/];
|
|
1149
1166
|
}
|
|
1167
|
+
generation = this._pageGeneration;
|
|
1150
1168
|
setTimeout(function () {
|
|
1151
1169
|
// Drop in-flight page hits from an SDK instance that was torn down
|
|
1152
1170
|
// between scheduling and firing (e.g. provider remount in React Strict
|
|
1153
1171
|
// Mode / HMR). Otherwise the orphan instance would queue a page event
|
|
1154
1172
|
// here with its stale, never-populated `currentAddress`.
|
|
1155
|
-
if (_this._pageHooksDisposed)
|
|
1173
|
+
if (_this._pageHooksDisposed || generation !== _this._pageGeneration)
|
|
1156
1174
|
return;
|
|
1157
1175
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1158
1176
|
var e_2;
|
|
@@ -1182,7 +1200,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1182
1200
|
};
|
|
1183
1201
|
FormoAnalytics.prototype.trackEvent = function (type, payload, properties, context, callback) {
|
|
1184
1202
|
return __awaiter(this, void 0, void 0, function () {
|
|
1185
|
-
var
|
|
1203
|
+
var error_2;
|
|
1186
1204
|
return __generator(this, function (_a) {
|
|
1187
1205
|
switch (_a.label) {
|
|
1188
1206
|
case 0:
|
|
@@ -1201,8 +1219,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1201
1219
|
_a.sent();
|
|
1202
1220
|
return [3 /*break*/, 3];
|
|
1203
1221
|
case 2:
|
|
1204
|
-
|
|
1205
|
-
logger.error("Error tracking event:",
|
|
1222
|
+
error_2 = _a.sent();
|
|
1223
|
+
logger.error("Error tracking event:", error_2);
|
|
1206
1224
|
return [3 /*break*/, 3];
|
|
1207
1225
|
case 3: return [2 /*return*/];
|
|
1208
1226
|
}
|
|
@@ -1268,7 +1286,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1268
1286
|
*/
|
|
1269
1287
|
get: function () {
|
|
1270
1288
|
if (!this.solanaManager) {
|
|
1271
|
-
|
|
1289
|
+
// Only reachable after `solana: false` (or after cleanup). The host
|
|
1290
|
+
// opted out of discovery, so this manager serves the store path only.
|
|
1291
|
+
this.solanaManager = new SolanaManager(this, undefined, false);
|
|
1272
1292
|
}
|
|
1273
1293
|
return this.solanaManager;
|
|
1274
1294
|
},
|
|
@@ -69,6 +69,18 @@ var defaultContext = {
|
|
|
69
69
|
hasOptedOutTracking: function () { return false; },
|
|
70
70
|
};
|
|
71
71
|
export var FormoAnalyticsContext = createContext(defaultContext);
|
|
72
|
+
var optionObjectIds = new WeakMap();
|
|
73
|
+
var nextOptionObjectId = 1;
|
|
74
|
+
var optionObjectId = function (value) {
|
|
75
|
+
if (!value)
|
|
76
|
+
return undefined;
|
|
77
|
+
var id = optionObjectIds.get(value);
|
|
78
|
+
if (id === undefined) {
|
|
79
|
+
id = nextOptionObjectId++;
|
|
80
|
+
optionObjectIds.set(value, id);
|
|
81
|
+
}
|
|
82
|
+
return id;
|
|
83
|
+
};
|
|
72
84
|
/**
|
|
73
85
|
* A stable key over the serializable parts of Options. The provider effect
|
|
74
86
|
* re-initialises the SDK when this key changes; anything that alters SDK
|
|
@@ -92,6 +104,14 @@ export var computeOptionsKey = function (options) {
|
|
|
92
104
|
logger: options.logger,
|
|
93
105
|
referral: options.referral,
|
|
94
106
|
evm: options.evm,
|
|
107
|
+
// `solana` is a boolean or an options object. A store is a live event
|
|
108
|
+
// source, so replacing it must reinitialize the SDK even when both the
|
|
109
|
+
// old and new options contain a store.
|
|
110
|
+
solana: typeof options.solana === "object" ? undefined : options.solana,
|
|
111
|
+
solanaStoreId: typeof options.solana === "object"
|
|
112
|
+
? optionObjectId(options.solana.store)
|
|
113
|
+
: undefined,
|
|
114
|
+
solanaCluster: typeof options.solana === "object" ? options.solana.cluster : undefined,
|
|
95
115
|
// For complex objects, just track their presence, not their content
|
|
96
116
|
hasProvider: !!options.provider,
|
|
97
117
|
hasWagmi: !!options.wagmi,
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Address, APIEvent, ChainID, IFormoEvent, IFormoEventContext, IFormoEventProperties, Nullable, Options, SignatureStatus, TransactionStatus } from "../types";
|
|
2
2
|
import { IEventFactory } from "./type";
|
|
3
3
|
declare class EventFactory implements IEventFactory {
|
|
4
|
+
/** Consulted once per event, after the only await in creation. */
|
|
5
|
+
private readonly canCreate;
|
|
4
6
|
private options?;
|
|
5
7
|
private compiledPathPattern?;
|
|
6
8
|
private excludedQueryParams;
|
|
7
|
-
|
|
9
|
+
/** Bumped by invalidate(); an event created across a bump is dropped. */
|
|
10
|
+
private generation;
|
|
11
|
+
constructor(options?: Options,
|
|
12
|
+
/** Consulted once per event, after the only await in creation. */
|
|
13
|
+
canCreate?: () => boolean);
|
|
8
14
|
/**
|
|
9
15
|
* Validate an address for both EVM and Solana chains.
|
|
10
16
|
* Uses chainId for strict validation when available.
|
|
@@ -56,6 +62,8 @@ declare class EventFactory implements IEventFactory {
|
|
|
56
62
|
private redactStoredTrafficSources;
|
|
57
63
|
private getTrafficSources;
|
|
58
64
|
private getScreen;
|
|
65
|
+
/** Drop every event still being created. Called on clear() and close(). */
|
|
66
|
+
invalidate(): void;
|
|
59
67
|
private generateContext;
|
|
60
68
|
/**
|
|
61
69
|
* Add any missing default page properties using values from options and defaults
|