@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
|
@@ -45,6 +45,24 @@ export declare class EvmProviderRegistry {
|
|
|
45
45
|
private listeners;
|
|
46
46
|
/** The window-injected provider, once detected, so it is not re-wrapped. */
|
|
47
47
|
private injectedDetail?;
|
|
48
|
+
/**
|
|
49
|
+
* Attribution supplied by the integration layer for a provider that was
|
|
50
|
+
* never announced: the wagmi fallback wrap names a connector's provider
|
|
51
|
+
* after the CONNECTOR, so request-derived events carry the same wallet
|
|
52
|
+
* name as the hook-driven events from the same connection. Without it
|
|
53
|
+
* the name came from flag sniffing, and a custom or embedded connector
|
|
54
|
+
* whose provider exposes no recognised flag split one wallet's activity
|
|
55
|
+
* between "Injected Provider" and the connector's name.
|
|
56
|
+
*
|
|
57
|
+
* A RESOLVER, read at each `infoFor`, not a value: the name is live for
|
|
58
|
+
* the connector the integration layer bound it to (a WalletConnect
|
|
59
|
+
* session that resolves or changes its peer renames without a re-wrap),
|
|
60
|
+
* and the integration layer names events on its hook path with the same
|
|
61
|
+
* function, so the two paths cannot disagree. Which connector a
|
|
62
|
+
* provider is bound to is the integration layer's decision; it is not
|
|
63
|
+
* necessarily the connector that is current when the request runs.
|
|
64
|
+
*/
|
|
65
|
+
private attributions;
|
|
48
66
|
constructor(deps: EvmProviderRegistryDeps);
|
|
49
67
|
get all(): readonly EIP6963ProviderDetail[];
|
|
50
68
|
isTracked(provider: EIP1193Provider): boolean;
|
|
@@ -62,11 +80,25 @@ export declare class EvmProviderRegistry {
|
|
|
62
80
|
};
|
|
63
81
|
/** Add a discovered provider once. Returns false if already present. */
|
|
64
82
|
add(detail: EIP6963ProviderDetail): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Record (or, with `undefined`, forget) the integration layer's own
|
|
85
|
+
* attribution resolver for a provider. See `attributions`.
|
|
86
|
+
*/
|
|
87
|
+
rememberAttribution(provider: EIP1193Provider | undefined, resolve: (() => {
|
|
88
|
+
name: string;
|
|
89
|
+
rdns?: string;
|
|
90
|
+
} | undefined) | undefined): void;
|
|
91
|
+
/** The supplied attribution for a provider, if any resolves right now. */
|
|
92
|
+
private suppliedAttributionFor;
|
|
65
93
|
/**
|
|
66
94
|
* A provider's display name and rdns.
|
|
67
95
|
*
|
|
68
|
-
* EIP-6963 metadata is authoritative when we have it
|
|
69
|
-
*
|
|
96
|
+
* EIP-6963 metadata is authoritative when we have it. A supplied
|
|
97
|
+
* attribution (the connector a wagmi app connected through) comes next:
|
|
98
|
+
* it describes the SESSION, which is what the hook-driven events report.
|
|
99
|
+
* Otherwise fall back to sniffing the injected provider, which is all a
|
|
100
|
+
* pre-6963 wallet offers; a supplied name without an rdns keeps the
|
|
101
|
+
* sniffed rdns.
|
|
70
102
|
*/
|
|
71
103
|
infoFor(provider: EIP1193Provider): {
|
|
72
104
|
name: string;
|
|
@@ -74,6 +74,24 @@ var EvmProviderRegistry = /** @class */ (function () {
|
|
|
74
74
|
this.chainGenerations = new WeakMap();
|
|
75
75
|
/** Listeners this SDK attached, so teardown can remove exactly those. */
|
|
76
76
|
this.listeners = new Map();
|
|
77
|
+
/**
|
|
78
|
+
* Attribution supplied by the integration layer for a provider that was
|
|
79
|
+
* never announced: the wagmi fallback wrap names a connector's provider
|
|
80
|
+
* after the CONNECTOR, so request-derived events carry the same wallet
|
|
81
|
+
* name as the hook-driven events from the same connection. Without it
|
|
82
|
+
* the name came from flag sniffing, and a custom or embedded connector
|
|
83
|
+
* whose provider exposes no recognised flag split one wallet's activity
|
|
84
|
+
* between "Injected Provider" and the connector's name.
|
|
85
|
+
*
|
|
86
|
+
* A RESOLVER, read at each `infoFor`, not a value: the name is live for
|
|
87
|
+
* the connector the integration layer bound it to (a WalletConnect
|
|
88
|
+
* session that resolves or changes its peer renames without a re-wrap),
|
|
89
|
+
* and the integration layer names events on its hook path with the same
|
|
90
|
+
* function, so the two paths cannot disagree. Which connector a
|
|
91
|
+
* provider is bound to is the integration layer's decision; it is not
|
|
92
|
+
* necessarily the connector that is current when the request runs.
|
|
93
|
+
*/
|
|
94
|
+
this.attributions = new WeakMap();
|
|
77
95
|
}
|
|
78
96
|
Object.defineProperty(EvmProviderRegistry.prototype, "all", {
|
|
79
97
|
// ── the provider set ─────────────────────────────────────────────────────
|
|
@@ -132,19 +150,55 @@ var EvmProviderRegistry = /** @class */ (function () {
|
|
|
132
150
|
this.seen.add(provider);
|
|
133
151
|
return true;
|
|
134
152
|
};
|
|
153
|
+
/**
|
|
154
|
+
* Record (or, with `undefined`, forget) the integration layer's own
|
|
155
|
+
* attribution resolver for a provider. See `attributions`.
|
|
156
|
+
*/
|
|
157
|
+
EvmProviderRegistry.prototype.rememberAttribution = function (provider, resolve) {
|
|
158
|
+
if (!provider)
|
|
159
|
+
return;
|
|
160
|
+
if (!resolve) {
|
|
161
|
+
this.attributions.delete(provider);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
this.attributions.set(provider, resolve);
|
|
165
|
+
};
|
|
166
|
+
/** The supplied attribution for a provider, if any resolves right now. */
|
|
167
|
+
EvmProviderRegistry.prototype.suppliedAttributionFor = function (provider) {
|
|
168
|
+
var resolve = this.attributions.get(provider);
|
|
169
|
+
if (!resolve)
|
|
170
|
+
return undefined;
|
|
171
|
+
try {
|
|
172
|
+
var info = resolve();
|
|
173
|
+
return (info === null || info === void 0 ? void 0 : info.name) ? info : undefined;
|
|
174
|
+
}
|
|
175
|
+
catch (_a) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
135
179
|
/**
|
|
136
180
|
* A provider's display name and rdns.
|
|
137
181
|
*
|
|
138
|
-
* EIP-6963 metadata is authoritative when we have it
|
|
139
|
-
*
|
|
182
|
+
* EIP-6963 metadata is authoritative when we have it. A supplied
|
|
183
|
+
* attribution (the connector a wagmi app connected through) comes next:
|
|
184
|
+
* it describes the SESSION, which is what the hook-driven events report.
|
|
185
|
+
* Otherwise fall back to sniffing the injected provider, which is all a
|
|
186
|
+
* pre-6963 wallet offers; a supplied name without an rdns keeps the
|
|
187
|
+
* sniffed rdns.
|
|
140
188
|
*/
|
|
141
189
|
EvmProviderRegistry.prototype.infoFor = function (provider) {
|
|
142
190
|
var announced = this.details.find(function (p) { return p.provider === provider; });
|
|
191
|
+
var supplied = announced
|
|
192
|
+
? undefined
|
|
193
|
+
: this.suppliedAttributionFor(provider);
|
|
143
194
|
var info = announced
|
|
144
195
|
? { name: announced.info.name, rdns: announced.info.rdns }
|
|
145
196
|
: (function () {
|
|
197
|
+
var _a;
|
|
146
198
|
var injected = detectInjectedProviderInfo(provider);
|
|
147
|
-
return
|
|
199
|
+
return supplied
|
|
200
|
+
? { name: supplied.name, rdns: (_a = supplied.rdns) !== null && _a !== void 0 ? _a : injected.rdns }
|
|
201
|
+
: { name: injected.name, rdns: injected.rdns };
|
|
148
202
|
})();
|
|
149
203
|
// WalletConnect names the TRANSPORT; the session's peer names the
|
|
150
204
|
// wallet. Resolved live, per read: a session established after the
|
|
@@ -154,7 +208,10 @@ var EvmProviderRegistry = /** @class */ (function () {
|
|
|
154
208
|
// is included because a flagless WalletConnect-compatible provider
|
|
155
209
|
// registered BEFORE its session exists detects as nothing at all;
|
|
156
210
|
// the peer appearing later is itself the proof of what it was, so
|
|
157
|
-
// the rdns upgrades with it.
|
|
211
|
+
// the rdns upgrades with it. A supplied name gets the same treatment
|
|
212
|
+
// and no more: the integration layer resolves its own peer names
|
|
213
|
+
// where it wants them, and a branded connector must keep its name on
|
|
214
|
+
// both paths.
|
|
158
215
|
if (info.name === "WalletConnect" || info.name === "Injected Provider") {
|
|
159
216
|
var peer = readWalletConnectPeer(provider);
|
|
160
217
|
if (peer === null || peer === void 0 ? void 0 : peer.name) {
|
|
@@ -83,10 +83,15 @@ export declare class EvmRequestTracker {
|
|
|
83
83
|
/**
|
|
84
84
|
* Wallet attribution for request-derived events.
|
|
85
85
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* made
|
|
86
|
+
* Resolved through the registry at the START of each request and held
|
|
87
|
+
* for that request's whole lifecycle, receipt included. Reading it per
|
|
88
|
+
* status let a connector switch (two connectors sharing one provider) or
|
|
89
|
+
* a session change made while a prompt was open split one operation
|
|
90
|
+
* between two wallet names. Still live across requests: a WalletConnect
|
|
91
|
+
* session names its actual signer ("MetaMask Wallet", "Ledger Live") -
|
|
92
|
+
* the live-test rows had provider_name EMPTY on every signature and
|
|
93
|
+
* transaction, which made per-wallet activity unanswerable in the
|
|
94
|
+
* warehouse.
|
|
90
95
|
*/
|
|
91
96
|
private attributionFor;
|
|
92
97
|
private buildSignatureEventPayload;
|
|
@@ -296,7 +296,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
296
296
|
*/
|
|
297
297
|
EvmRequestTracker.prototype.dispatchWrappedRequest = function (_a, provider_1, request_1) {
|
|
298
298
|
return __awaiter(this, arguments, void 0, function (_b, provider, request) {
|
|
299
|
-
var generation_1, responsePromise, capturedChainId_1, response_1, error_1, rpcError, txPromise, txChainId_1, transactionHash_1, error_2, rpcError;
|
|
299
|
+
var generation_1, responsePromise, capturedChainId_1, attribution_1, response_1, error_1, rpcError, txPromise, txChainId_1, attribution_2, transactionHash_1, error_2, rpcError;
|
|
300
300
|
var _this = this;
|
|
301
301
|
var _c, _d, _e, _f;
|
|
302
302
|
var method = _b.method, params = _b.params;
|
|
@@ -339,6 +339,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
339
339
|
// below is never reported as unhandled. The real handling is there.
|
|
340
340
|
responsePromise.catch(function () { return undefined; });
|
|
341
341
|
capturedChainId_1 = this.registry.resolveChainId(provider);
|
|
342
|
+
attribution_1 = this.attributionFor(provider);
|
|
342
343
|
// Fire-and-forget tracking
|
|
343
344
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
344
345
|
var e_1;
|
|
@@ -346,7 +347,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
346
347
|
switch (_a.label) {
|
|
347
348
|
case 0:
|
|
348
349
|
_a.trys.push([0, 2, , 3]);
|
|
349
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)),
|
|
350
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)), attribution_1)];
|
|
350
351
|
case 1:
|
|
351
352
|
_a.sent();
|
|
352
353
|
return [3 /*break*/, 3];
|
|
@@ -372,7 +373,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
372
373
|
switch (_a.label) {
|
|
373
374
|
case 0:
|
|
374
375
|
_a.trys.push([0, 2, , 3]);
|
|
375
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.CONFIRMED }, this.buildSignatureEventPayload(method, params, response_1, capturedChainId_1, provider)),
|
|
376
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.CONFIRMED }, this.buildSignatureEventPayload(method, params, response_1, capturedChainId_1, provider)), attribution_1)];
|
|
376
377
|
case 1:
|
|
377
378
|
_a.sent();
|
|
378
379
|
return [3 /*break*/, 3];
|
|
@@ -397,7 +398,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
397
398
|
switch (_a.label) {
|
|
398
399
|
case 0:
|
|
399
400
|
_a.trys.push([0, 2, , 3]);
|
|
400
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)),
|
|
401
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)), attribution_1)];
|
|
401
402
|
case 1:
|
|
402
403
|
_a.sent();
|
|
403
404
|
return [3 /*break*/, 3];
|
|
@@ -436,6 +437,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
436
437
|
txPromise = request({ method: method, params: params });
|
|
437
438
|
txPromise.catch(function () { return undefined; });
|
|
438
439
|
txChainId_1 = this.registry.resolveChainId(provider);
|
|
440
|
+
attribution_2 = this.attributionFor(provider);
|
|
439
441
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
440
442
|
var payload, e_4;
|
|
441
443
|
return __generator(this, function (_a) {
|
|
@@ -445,7 +447,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
445
447
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
446
448
|
case 1:
|
|
447
449
|
payload = _a.sent();
|
|
448
|
-
return [4 /*yield*/, this.deps.transaction(__assign({ status: TransactionStatus.STARTED }, payload),
|
|
450
|
+
return [4 /*yield*/, this.deps.transaction(__assign({ status: TransactionStatus.STARTED }, payload), attribution_2)];
|
|
449
451
|
case 2:
|
|
450
452
|
_a.sent();
|
|
451
453
|
return [3 /*break*/, 4];
|
|
@@ -472,11 +474,11 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
472
474
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
473
475
|
case 1:
|
|
474
476
|
payload = _a.sent();
|
|
475
|
-
return [4 /*yield*/, this.deps.transaction(__assign(__assign({ status: TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }),
|
|
477
|
+
return [4 /*yield*/, this.deps.transaction(__assign(__assign({ status: TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }), attribution_2)];
|
|
476
478
|
case 2:
|
|
477
479
|
_a.sent();
|
|
478
480
|
// Start async polling for transaction receipt
|
|
479
|
-
this.pollTransactionReceipt(provider, transactionHash_1, payload);
|
|
481
|
+
this.pollTransactionReceipt(provider, transactionHash_1, payload, attribution_2);
|
|
480
482
|
return [3 /*break*/, 4];
|
|
481
483
|
case 3:
|
|
482
484
|
e_5 = _a.sent();
|
|
@@ -501,7 +503,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
501
503
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
502
504
|
case 1:
|
|
503
505
|
payload = _a.sent();
|
|
504
|
-
return [4 /*yield*/, this.deps.transaction(__assign({ status: TransactionStatus.REJECTED }, payload),
|
|
506
|
+
return [4 /*yield*/, this.deps.transaction(__assign({ status: TransactionStatus.REJECTED }, payload), attribution_2)];
|
|
505
507
|
case 2:
|
|
506
508
|
_a.sent();
|
|
507
509
|
return [3 /*break*/, 4];
|
|
@@ -523,10 +525,15 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
523
525
|
/**
|
|
524
526
|
* Wallet attribution for request-derived events.
|
|
525
527
|
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
* made
|
|
528
|
+
* Resolved through the registry at the START of each request and held
|
|
529
|
+
* for that request's whole lifecycle, receipt included. Reading it per
|
|
530
|
+
* status let a connector switch (two connectors sharing one provider) or
|
|
531
|
+
* a session change made while a prompt was open split one operation
|
|
532
|
+
* between two wallet names. Still live across requests: a WalletConnect
|
|
533
|
+
* session names its actual signer ("MetaMask Wallet", "Ledger Live") -
|
|
534
|
+
* the live-test rows had provider_name EMPTY on every signature and
|
|
535
|
+
* transaction, which made per-wallet activity unanswerable in the
|
|
536
|
+
* warehouse.
|
|
530
537
|
*/
|
|
531
538
|
EvmRequestTracker.prototype.attributionFor = function (provider) {
|
|
532
539
|
var info = this.registry.infoFor(provider);
|
|
@@ -596,8 +603,11 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
596
603
|
/**
|
|
597
604
|
* Polls for transaction receipt and emits tx.status = CONFIRMED or REVERTED.
|
|
598
605
|
*/
|
|
599
|
-
EvmRequestTracker.prototype.pollTransactionReceipt = function (provider_1, transactionHash_2, payload_1) {
|
|
600
|
-
return __awaiter(this, arguments, void 0, function (provider, transactionHash, payload,
|
|
606
|
+
EvmRequestTracker.prototype.pollTransactionReceipt = function (provider_1, transactionHash_2, payload_1, attribution_3) {
|
|
607
|
+
return __awaiter(this, arguments, void 0, function (provider, transactionHash, payload,
|
|
608
|
+
// Snapshot from the broadcast: a connector or session change during
|
|
609
|
+
// the poll window must not relabel the receipt.
|
|
610
|
+
attribution, maxAttempts, intervalMs) {
|
|
601
611
|
var attempts, poll;
|
|
602
612
|
var _this = this;
|
|
603
613
|
if (maxAttempts === void 0) { maxAttempts = 10; }
|
|
@@ -626,7 +636,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
626
636
|
// status: 1 = success, 0 = reverted
|
|
627
637
|
if (receipt.status === "0x1" || receipt.status === 1) {
|
|
628
638
|
this.deps
|
|
629
|
-
.transaction(__assign(__assign({ status: TransactionStatus.CONFIRMED }, payload), { transactionHash: transactionHash }),
|
|
639
|
+
.transaction(__assign(__assign({ status: TransactionStatus.CONFIRMED }, payload), { transactionHash: transactionHash }), attribution)
|
|
630
640
|
.catch(function (e) {
|
|
631
641
|
return logger.error("Formo: Failed to track transaction confirmation", e);
|
|
632
642
|
});
|
|
@@ -634,7 +644,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
634
644
|
}
|
|
635
645
|
else if (receipt.status === "0x0" || receipt.status === 0) {
|
|
636
646
|
this.deps
|
|
637
|
-
.transaction(__assign(__assign({ status: TransactionStatus.REVERTED }, payload), { transactionHash: transactionHash }),
|
|
647
|
+
.transaction(__assign(__assign({ status: TransactionStatus.REVERTED }, payload), { transactionHash: transactionHash }), attribution)
|
|
638
648
|
.catch(function (e) {
|
|
639
649
|
return logger.error("Formo: Failed to track transaction revert", e);
|
|
640
650
|
});
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SolanaManager
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
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.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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 =
|
|
50
|
-
|
|
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.
|
|
56
|
-
*
|
|
57
|
-
*
|
|
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.
|