@formo/analytics 1.38.2 → 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.
Files changed (38) hide show
  1. package/dist/cjs/src/FormoAnalytics.js +9 -4
  2. package/dist/cjs/src/FormoAnalyticsProvider.js +20 -0
  3. package/dist/cjs/src/solana/SolanaManager.d.ts +37 -9
  4. package/dist/cjs/src/solana/SolanaManager.js +135 -20
  5. package/dist/cjs/src/solana/SolanaStoreHandler.d.ts +6 -0
  6. package/dist/cjs/src/solana/SolanaStoreHandler.js +17 -8
  7. package/dist/cjs/src/solana/SolanaWalletStandardRegistry.d.ts +163 -0
  8. package/dist/cjs/src/solana/SolanaWalletStandardRegistry.js +447 -0
  9. package/dist/cjs/src/solana/index.d.ts +10 -5
  10. package/dist/cjs/src/solana/index.js +12 -6
  11. package/dist/cjs/src/solana/storeTypes.d.ts +20 -1
  12. package/dist/cjs/src/solana/types.d.ts +32 -9
  13. package/dist/cjs/src/solana/types.js +15 -0
  14. package/dist/cjs/src/solana/walletStandardTypes.d.ts +54 -0
  15. package/dist/cjs/src/solana/walletStandardTypes.js +21 -0
  16. package/dist/cjs/src/types/base.d.ts +15 -5
  17. package/dist/cjs/src/version.d.ts +1 -1
  18. package/dist/cjs/src/version.js +1 -1
  19. package/dist/esm/src/FormoAnalytics.js +9 -4
  20. package/dist/esm/src/FormoAnalyticsProvider.js +20 -0
  21. package/dist/esm/src/solana/SolanaManager.d.ts +37 -9
  22. package/dist/esm/src/solana/SolanaManager.js +135 -20
  23. package/dist/esm/src/solana/SolanaStoreHandler.d.ts +6 -0
  24. package/dist/esm/src/solana/SolanaStoreHandler.js +18 -9
  25. package/dist/esm/src/solana/SolanaWalletStandardRegistry.d.ts +163 -0
  26. package/dist/esm/src/solana/SolanaWalletStandardRegistry.js +444 -0
  27. package/dist/esm/src/solana/index.d.ts +10 -5
  28. package/dist/esm/src/solana/index.js +10 -5
  29. package/dist/esm/src/solana/storeTypes.d.ts +20 -1
  30. package/dist/esm/src/solana/types.d.ts +32 -9
  31. package/dist/esm/src/solana/types.js +14 -0
  32. package/dist/esm/src/solana/walletStandardTypes.d.ts +54 -0
  33. package/dist/esm/src/solana/walletStandardTypes.js +18 -0
  34. package/dist/esm/src/types/base.d.ts +15 -5
  35. package/dist/esm/src/version.d.ts +1 -1
  36. package/dist/esm/src/version.js +1 -1
  37. package/dist/index.umd.min.js +1 -1
  38. package/package.json +2 -2
@@ -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
@@ -246,16 +246,26 @@ export interface Options {
246
246
  */
247
247
  wagmi?: WagmiOptions;
248
248
  /**
249
- * Solana integration configuration.
250
- * Pass `store: client.store` from framework-kit for automatic tracking of
251
- * wallet connect/disconnect and transaction events.
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 doesn't track these in the store).
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.38.2";
1
+ export declare const version = "1.39.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -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.38.2';
6
+ exports.version = '1.39.0';
7
7
  //# sourceMappingURL=version.js.map
@@ -242,9 +242,12 @@ var FormoAnalytics = /** @class */ (function () {
242
242
  this.evmEvents.trackEIP1193Provider(provider);
243
243
  }
244
244
  }
245
- // Initialize Solana manager if Solana options are provided
246
- if (options.solana) {
247
- this.solanaManager = new SolanaManager(this, options.solana);
245
+ // Solana wallets are discovered through the Wallet Standard
246
+ // unconditionally, the way EVM wallets are through EIP-6963: an app
247
+ // that never configures Solana still gets its connects. `solana: false`
248
+ // is the opt-out; an object adds framework-kit's store or a cluster.
249
+ if (options.solana !== false) {
250
+ this.solanaManager = new SolanaManager(this, typeof options.solana === "object" ? options.solana : undefined);
248
251
  }
249
252
  this._currentUrl = window.location.href;
250
253
  // Seed currentAddress/currentChainId from the persisted snapshot before
@@ -1268,7 +1271,9 @@ var FormoAnalytics = /** @class */ (function () {
1268
1271
  */
1269
1272
  get: function () {
1270
1273
  if (!this.solanaManager) {
1271
- this.solanaManager = new SolanaManager(this);
1274
+ // Only reachable after `solana: false` (or after cleanup). The host
1275
+ // opted out of discovery, so this manager serves the store path only.
1276
+ this.solanaManager = new SolanaManager(this, undefined, false);
1272
1277
  }
1273
1278
  return this.solanaManager;
1274
1279
  },
@@ -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,14 +1,27 @@
1
1
  /**
2
2
  * SolanaManager
3
3
  *
4
- * Manages the lifecycle of the Solana store integration.
5
- * Subscribes to framework-kit's zustand store for automatic event capture
6
- * of wallet connect/disconnect and transaction lifecycle events.
4
+ * Owns the two ways the SDK learns about Solana wallets:
7
5
  *
8
- * For signMessage/signTransaction tracking (not captured by the store),
6
+ * 1. `SolanaWalletStandardRegistry`: discovers wallets through the Wallet
7
+ * Standard and reports detect / connect / disconnect. On by default, so
8
+ * compatible wallets registered by Solana Kit, wallet-adapter,
9
+ * framework-kit, or another host are covered with no configuration,
10
+ * exactly like EVM wallets through EIP-6963. `solana: false` turns it off.
11
+ * 2. `SolanaStoreHandler`: subscribes to framework-kit's zustand store for
12
+ * connect / disconnect / cluster changes AND the transaction lifecycle.
13
+ * Opt-in through `solana: { store }` or `formo.solana.setStore()`.
14
+ *
15
+ * Both observe the same Wallet Standard connection when a framework-kit app
16
+ * connects. A store supplied at initialization owns wallet events; a store
17
+ * attached later takes ownership when it observes its first connection and
18
+ * adopts any connect the registry already reported. One connect per
19
+ * connection, whichever path an app is on.
20
+ *
21
+ * For signMessage/signTransaction tracking (not captured by either path),
9
22
  * use formo.signature() directly with the address and chainId.
10
23
  *
11
- * For manual event tracking without the store, use the core API directly:
24
+ * For manual event tracking, use the core API directly:
12
25
  * formo.transaction(), formo.signature(), formo.connect(), formo.disconnect().
13
26
  */
14
27
  import { FormoAnalytics } from "../FormoAnalytics";
@@ -16,9 +29,19 @@ import { SolanaCluster, SolanaOptions } from "./types";
16
29
  import { SolanaClientStore } from "./storeTypes";
17
30
  export declare class SolanaManager {
18
31
  private formo;
32
+ private readonly enabled;
19
33
  private storeHandler?;
34
+ private registry?;
20
35
  private pendingCluster?;
21
- constructor(formo: FormoAnalytics, options?: SolanaOptions);
36
+ private storeOwnsWalletEvents;
37
+ /**
38
+ * @param formo - The SDK instance events are reported to.
39
+ * @param options - `options.solana` as passed to the SDK, if an object.
40
+ * @param enabled - Whether Solana tracking is enabled. False only when the
41
+ * host app passed `solana: false`; both discovery and stores then stay off.
42
+ */
43
+ constructor(formo: FormoAnalytics, options?: SolanaOptions, enabled?: boolean);
44
+ private attachStore;
22
45
  /**
23
46
  * Set the framework-kit zustand store for automatic event tracking.
24
47
  * This enables autocapture mode — connect/disconnect and transaction events
@@ -39,11 +62,16 @@ export declare class SolanaManager {
39
62
  cluster?: SolanaCluster;
40
63
  }): void;
41
64
  /**
42
- * Update the cluster/network. Only needed if the store endpoint doesn't
43
- * contain a recognizable cluster name (e.g. custom RPC URLs).
44
- * In most cases, the cluster is auto-detected from the store's endpoint.
65
+ * Update the cluster/network.
66
+ *
67
+ * With a framework-kit store, only needed if the store endpoint doesn't
68
+ * contain a recognizable cluster name (e.g. custom RPC URLs). Without one,
69
+ * this is how a non-mainnet app tells the SDK which cluster its Wallet
70
+ * Standard connections are on, since the standard itself cannot say.
45
71
  */
46
72
  setCluster(cluster: SolanaCluster): void;
73
+ /** Names of the Wallet Standard wallets discovered so far. */
74
+ get discoveredWallets(): string[];
47
75
  cleanup(): void;
48
76
  }
49
77
  //# sourceMappingURL=SolanaManager.d.ts.map
@@ -1,32 +1,124 @@
1
1
  /**
2
2
  * SolanaManager
3
3
  *
4
- * Manages the lifecycle of the Solana store integration.
5
- * Subscribes to framework-kit's zustand store for automatic event capture
6
- * of wallet connect/disconnect and transaction lifecycle events.
4
+ * Owns the two ways the SDK learns about Solana wallets:
7
5
  *
8
- * For signMessage/signTransaction tracking (not captured by the store),
6
+ * 1. `SolanaWalletStandardRegistry`: discovers wallets through the Wallet
7
+ * Standard and reports detect / connect / disconnect. On by default, so
8
+ * compatible wallets registered by Solana Kit, wallet-adapter,
9
+ * framework-kit, or another host are covered with no configuration,
10
+ * exactly like EVM wallets through EIP-6963. `solana: false` turns it off.
11
+ * 2. `SolanaStoreHandler`: subscribes to framework-kit's zustand store for
12
+ * connect / disconnect / cluster changes AND the transaction lifecycle.
13
+ * Opt-in through `solana: { store }` or `formo.solana.setStore()`.
14
+ *
15
+ * Both observe the same Wallet Standard connection when a framework-kit app
16
+ * connects. A store supplied at initialization owns wallet events; a store
17
+ * attached later takes ownership when it observes its first connection and
18
+ * adopts any connect the registry already reported. One connect per
19
+ * connection, whichever path an app is on.
20
+ *
21
+ * For signMessage/signTransaction tracking (not captured by either path),
9
22
  * use formo.signature() directly with the address and chainId.
10
23
  *
11
- * For manual event tracking without the store, use the core API directly:
24
+ * For manual event tracking, use the core API directly:
12
25
  * formo.transaction(), formo.signature(), formo.connect(), formo.disconnect().
13
26
  */
14
27
  import { logger } from "../logger";
15
28
  import { SolanaStoreHandler } from "./SolanaStoreHandler";
29
+ import { SolanaWalletStandardRegistry } from "./SolanaWalletStandardRegistry";
30
+ import { SOLANA_CLUSTERS_BY_ID, } from "./types";
16
31
  var SolanaManager = /** @class */ (function () {
17
- function SolanaManager(formo, options) {
32
+ /**
33
+ * @param formo - The SDK instance events are reported to.
34
+ * @param options - `options.solana` as passed to the SDK, if an object.
35
+ * @param enabled - Whether Solana tracking is enabled. False only when the
36
+ * host app passed `solana: false`; both discovery and stores then stay off.
37
+ */
38
+ function SolanaManager(formo, options, enabled) {
39
+ if (enabled === void 0) { enabled = true; }
40
+ var _this = this;
18
41
  this.formo = formo;
19
- if (options === null || options === void 0 ? void 0 : options.store) {
20
- logger.info("SolanaManager: Initializing store-based Solana tracking");
21
- this.storeHandler = new SolanaStoreHandler(formo, options.store, {
22
- cluster: options.cluster,
23
- });
24
- }
25
- else if (options === null || options === void 0 ? void 0 : options.cluster) {
42
+ this.enabled = enabled;
43
+ this.storeOwnsWalletEvents = false;
44
+ if (!enabled)
45
+ return;
46
+ if (options === null || options === void 0 ? void 0 : options.cluster) {
26
47
  // Store pending cluster for when setStore is called later
27
48
  this.pendingCluster = options.cluster;
28
49
  }
50
+ // A store supplied at initialization owns wallet events from the outset:
51
+ // unlike a store attached later, it has not missed any prior registry
52
+ // state and it knows the cluster more precisely.
53
+ this.storeOwnsWalletEvents = !!(options === null || options === void 0 ? void 0 : options.store);
54
+ this.registry = new SolanaWalletStandardRegistry({
55
+ isAutocaptureEnabled: function (t) { return _this.formo.isAutocaptureEnabled(t); },
56
+ willTrackEvent: function (chainId) { return _this.formo.willTrackEvent(chainId); },
57
+ detect: function (params) { return _this.formo.detect(params); },
58
+ connect: function (params, properties) {
59
+ return _this.formo.connect(params, properties);
60
+ },
61
+ disconnect: function (params) { return _this.formo.disconnect(params); },
62
+ chain: function (params) { return _this.formo.chain(params); },
63
+ syncWalletState: function (params) { return _this.formo.syncWalletState(params); },
64
+ currentAddress: function () { return _this.formo.currentAddress; },
65
+ ownsWalletEvents: function () { return !_this.storeOwnsWalletEvents; },
66
+ }, { cluster: options === null || options === void 0 ? void 0 : options.cluster });
67
+ if (options === null || options === void 0 ? void 0 : options.store) {
68
+ logger.info("SolanaManager: Initializing store-based Solana tracking");
69
+ this.attachStore(options.store, options.cluster);
70
+ }
29
71
  }
72
+ SolanaManager.prototype.attachStore = function (store, cluster) {
73
+ var _this = this;
74
+ var _a;
75
+ this.storeHandler = new SolanaStoreHandler(this.formo, store, {
76
+ cluster: cluster,
77
+ beforeWalletConnect: function (connection) {
78
+ var _a, _b;
79
+ // The store's cluster is authoritative even when chain autocapture is
80
+ // disabled. Keep central attribution correct without manufacturing a
81
+ // chain event in that mode.
82
+ _this.formo.syncWalletState({
83
+ address: connection.address,
84
+ chainId: connection.chainId,
85
+ });
86
+ if (_this.storeOwnsWalletEvents)
87
+ return true;
88
+ var reported = (_a = _this.registry) === null || _a === void 0 ? void 0 : _a.takeReportedConnection(connection.address, connection.rdns);
89
+ _this.storeOwnsWalletEvents = true;
90
+ // If Wallet Standard got there first, the store adopts that live
91
+ // connection instead of emitting it again. Correct its cluster if
92
+ // the store has more precise information.
93
+ if (!reported) {
94
+ // Nothing to adopt. Either the registry never reported this
95
+ // connection, or it reported it under another identity, in which
96
+ // case the store is about to emit a second connect for the same
97
+ // live connection. Both paths derive the rdns from the wallet's
98
+ // own name, so a mismatch means the store's connector is labelled
99
+ // differently from the registered wallet.
100
+ var held = (_b = _this.registry) === null || _b === void 0 ? void 0 : _b.reportedConnectionRdns(connection.address);
101
+ if (held) {
102
+ logger.warn("SolanaManager: Store connector does not match the discovered wallet; the connection is reported twice", { storeRdns: connection.rdns, walletRdns: held });
103
+ }
104
+ return true;
105
+ }
106
+ if (reported.chainId !== connection.chainId &&
107
+ _this.formo.isAutocaptureEnabled("chain")) {
108
+ _this.formo.chain(connection).catch(function (error) {
109
+ logger.error("SolanaManager: Error correcting cluster during store handoff", error);
110
+ });
111
+ }
112
+ return false;
113
+ },
114
+ });
115
+ // Keep the registry's snapshot on the store's detected cluster. This is
116
+ // silent once the store owns events; during a late handoff it corrects a
117
+ // registry-reported connection before the store adopts it.
118
+ var detectedCluster = SOLANA_CLUSTERS_BY_ID[this.storeHandler.getChainId()];
119
+ if (detectedCluster)
120
+ (_a = this.registry) === null || _a === void 0 ? void 0 : _a.setCluster(detectedCluster);
121
+ };
30
122
  /**
31
123
  * Set the framework-kit zustand store for automatic event tracking.
32
124
  * This enables autocapture mode — connect/disconnect and transaction events
@@ -45,29 +137,52 @@ var SolanaManager = /** @class */ (function () {
45
137
  */
46
138
  SolanaManager.prototype.setStore = function (store, options) {
47
139
  var _a;
140
+ if (!this.enabled) {
141
+ logger.warn("SolanaManager: Ignoring setStore. Solana tracking is off for this instance (solana: false, or the SDK was cleaned up)");
142
+ return;
143
+ }
48
144
  (_a = this.storeHandler) === null || _a === void 0 ? void 0 : _a.cleanup();
49
- this.storeHandler = new SolanaStoreHandler(this.formo, store, {
50
- cluster: (options === null || options === void 0 ? void 0 : options.cluster) || this.pendingCluster,
51
- });
145
+ this.storeHandler = undefined;
146
+ this.storeOwnsWalletEvents = false;
147
+ this.attachStore(store, (options === null || options === void 0 ? void 0 : options.cluster) || this.pendingCluster);
52
148
  this.pendingCluster = undefined;
53
149
  };
54
150
  /**
55
- * Update the cluster/network. Only needed if the store endpoint doesn't
56
- * contain a recognizable cluster name (e.g. custom RPC URLs).
57
- * In most cases, the cluster is auto-detected from the store's endpoint.
151
+ * Update the cluster/network.
152
+ *
153
+ * With a framework-kit store, only needed if the store endpoint doesn't
154
+ * contain a recognizable cluster name (e.g. custom RPC URLs). Without one,
155
+ * this is how a non-mainnet app tells the SDK which cluster its Wallet
156
+ * Standard connections are on, since the standard itself cannot say.
58
157
  */
59
158
  SolanaManager.prototype.setCluster = function (cluster) {
159
+ var _a;
160
+ if (!this.enabled)
161
+ return;
60
162
  if (this.storeHandler) {
61
163
  this.storeHandler.setCluster(cluster);
62
164
  }
63
165
  else {
64
166
  this.pendingCluster = cluster;
65
167
  }
168
+ (_a = this.registry) === null || _a === void 0 ? void 0 : _a.setCluster(cluster);
66
169
  };
170
+ Object.defineProperty(SolanaManager.prototype, "discoveredWallets", {
171
+ /** Names of the Wallet Standard wallets discovered so far. */
172
+ get: function () {
173
+ var _a, _b;
174
+ return (_b = (_a = this.registry) === null || _a === void 0 ? void 0 : _a.walletNames) !== null && _b !== void 0 ? _b : [];
175
+ },
176
+ enumerable: false,
177
+ configurable: true
178
+ });
67
179
  SolanaManager.prototype.cleanup = function () {
68
- var _a;
180
+ var _a, _b;
69
181
  (_a = this.storeHandler) === null || _a === void 0 ? void 0 : _a.cleanup();
70
182
  this.storeHandler = undefined;
183
+ this.storeOwnsWalletEvents = false;
184
+ (_b = this.registry) === null || _b === void 0 ? void 0 : _b.cleanup();
185
+ this.registry = undefined;
71
186
  };
72
187
  return SolanaManager;
73
188
  }());
@@ -48,8 +48,14 @@ export declare class SolanaStoreHandler {
48
48
  * When true, auto-detection from the store endpoint is disabled.
49
49
  */
50
50
  private explicitCluster;
51
+ private beforeWalletConnect?;
51
52
  constructor(formoAnalytics: FormoAnalytics, store: SolanaClientStore, options?: {
52
53
  cluster?: SolanaCluster;
54
+ beforeWalletConnect?: (connection: {
55
+ address: string;
56
+ chainId: number;
57
+ rdns: string;
58
+ }) => boolean;
53
59
  });
54
60
  /**
55
61
  * Update the cluster/network.
@@ -25,7 +25,7 @@ var __assign = (this && this.__assign) || function () {
25
25
  };
26
26
  import { TransactionStatus } from "../types/events";
27
27
  import { logger } from "../logger";
28
- import { SOLANA_CHAIN_IDS } from "./types";
28
+ import { SOLANA_CHAIN_IDS, solanaWalletRdns, } from "./types";
29
29
  import { isBlockedSolanaAddress } from "./address";
30
30
  /**
31
31
  * Clean up old entries from a Set to prevent memory leaks.
@@ -66,6 +66,7 @@ var SolanaStoreHandler = /** @class */ (function () {
66
66
  this.formo = formoAnalytics;
67
67
  this.store = store;
68
68
  this.explicitCluster = !!(options === null || options === void 0 ? void 0 : options.cluster);
69
+ this.beforeWalletConnect = options === null || options === void 0 ? void 0 : options.beforeWalletConnect;
69
70
  this.cluster = (options === null || options === void 0 ? void 0 : options.cluster) || this.detectClusterFromStore(store) || "mainnet-beta";
70
71
  this.chainId = SOLANA_CHAIN_IDS[this.cluster];
71
72
  logger.info("SolanaStoreHandler: Initializing framework-kit store integration", {
@@ -138,7 +139,7 @@ var SolanaStoreHandler = /** @class */ (function () {
138
139
  logger.info("SolanaStoreHandler: Wallet subscription set up");
139
140
  };
140
141
  SolanaStoreHandler.prototype.checkInitialWalletState = function () {
141
- var _a;
142
+ var _a, _b, _c;
142
143
  var state = this.store.getState();
143
144
  var wallet = state.wallet;
144
145
  if (wallet.status === "connected") {
@@ -151,11 +152,17 @@ var SolanaStoreHandler = /** @class */ (function () {
151
152
  address: address,
152
153
  chainId: this.chainId,
153
154
  });
154
- if (this.formo.isAutocaptureEnabled("connect")) {
155
- var connectorName = ((_a = wallet.session.connector) === null || _a === void 0 ? void 0 : _a.name) || wallet.connectorId;
155
+ var connectorName = ((_a = wallet.session.connector) === null || _a === void 0 ? void 0 : _a.name) || wallet.connectorId;
156
+ var rdns = solanaWalletRdns(connectorName);
157
+ var shouldEmit = (_c = (_b = this.beforeWalletConnect) === null || _b === void 0 ? void 0 : _b.call(this, {
158
+ address: address,
159
+ chainId: this.chainId,
160
+ rdns: rdns,
161
+ })) !== null && _c !== void 0 ? _c : true;
162
+ if (shouldEmit && this.formo.isAutocaptureEnabled("connect")) {
156
163
  this.formo.connect({ chainId: this.chainId, address: address }, {
157
164
  providerName: connectorName,
158
- rdns: "sol.wallet.".concat(connectorName.toLowerCase().replace(/\s+/g, "")),
165
+ rdns: rdns,
159
166
  }).catch(function (error) {
160
167
  logger.error("SolanaStoreHandler: Error emitting initial connect", error);
161
168
  });
@@ -187,7 +194,7 @@ var SolanaStoreHandler = /** @class */ (function () {
187
194
  this.lastWalletStatus = wallet.status;
188
195
  };
189
196
  SolanaStoreHandler.prototype.handleConnect = function (wallet) {
190
- var _a;
197
+ var _a, _b, _c;
191
198
  var address = wallet.session.account.address;
192
199
  if (!address || isBlockedSolanaAddress(address)) {
193
200
  return;
@@ -203,11 +210,13 @@ var SolanaStoreHandler = /** @class */ (function () {
203
210
  chainId: chainId,
204
211
  connector: wallet.connectorId,
205
212
  });
206
- if (this.formo.isAutocaptureEnabled("connect")) {
207
- var connectorName = ((_a = wallet.session.connector) === null || _a === void 0 ? void 0 : _a.name) || wallet.connectorId;
213
+ var connectorName = ((_a = wallet.session.connector) === null || _a === void 0 ? void 0 : _a.name) || wallet.connectorId;
214
+ var rdns = solanaWalletRdns(connectorName);
215
+ var shouldEmit = (_c = (_b = this.beforeWalletConnect) === null || _b === void 0 ? void 0 : _b.call(this, { address: address, chainId: chainId, rdns: rdns })) !== null && _c !== void 0 ? _c : true;
216
+ if (shouldEmit && this.formo.isAutocaptureEnabled("connect")) {
208
217
  this.formo.connect({ chainId: chainId, address: address }, {
209
218
  providerName: connectorName,
210
- rdns: "sol.wallet.".concat(connectorName.toLowerCase().replace(/\s+/g, "")),
219
+ rdns: rdns,
211
220
  }).catch(function (error) {
212
221
  logger.error("SolanaStoreHandler: Error emitting connect", error);
213
222
  });