@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;
|
|
@@ -77,6 +77,24 @@ var EvmProviderRegistry = /** @class */ (function () {
|
|
|
77
77
|
this.chainGenerations = new WeakMap();
|
|
78
78
|
/** Listeners this SDK attached, so teardown can remove exactly those. */
|
|
79
79
|
this.listeners = new Map();
|
|
80
|
+
/**
|
|
81
|
+
* Attribution supplied by the integration layer for a provider that was
|
|
82
|
+
* never announced: the wagmi fallback wrap names a connector's provider
|
|
83
|
+
* after the CONNECTOR, so request-derived events carry the same wallet
|
|
84
|
+
* name as the hook-driven events from the same connection. Without it
|
|
85
|
+
* the name came from flag sniffing, and a custom or embedded connector
|
|
86
|
+
* whose provider exposes no recognised flag split one wallet's activity
|
|
87
|
+
* between "Injected Provider" and the connector's name.
|
|
88
|
+
*
|
|
89
|
+
* A RESOLVER, read at each `infoFor`, not a value: the name is live for
|
|
90
|
+
* the connector the integration layer bound it to (a WalletConnect
|
|
91
|
+
* session that resolves or changes its peer renames without a re-wrap),
|
|
92
|
+
* and the integration layer names events on its hook path with the same
|
|
93
|
+
* function, so the two paths cannot disagree. Which connector a
|
|
94
|
+
* provider is bound to is the integration layer's decision; it is not
|
|
95
|
+
* necessarily the connector that is current when the request runs.
|
|
96
|
+
*/
|
|
97
|
+
this.attributions = new WeakMap();
|
|
80
98
|
}
|
|
81
99
|
Object.defineProperty(EvmProviderRegistry.prototype, "all", {
|
|
82
100
|
// ── the provider set ─────────────────────────────────────────────────────
|
|
@@ -135,19 +153,55 @@ var EvmProviderRegistry = /** @class */ (function () {
|
|
|
135
153
|
this.seen.add(provider);
|
|
136
154
|
return true;
|
|
137
155
|
};
|
|
156
|
+
/**
|
|
157
|
+
* Record (or, with `undefined`, forget) the integration layer's own
|
|
158
|
+
* attribution resolver for a provider. See `attributions`.
|
|
159
|
+
*/
|
|
160
|
+
EvmProviderRegistry.prototype.rememberAttribution = function (provider, resolve) {
|
|
161
|
+
if (!provider)
|
|
162
|
+
return;
|
|
163
|
+
if (!resolve) {
|
|
164
|
+
this.attributions.delete(provider);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
this.attributions.set(provider, resolve);
|
|
168
|
+
};
|
|
169
|
+
/** The supplied attribution for a provider, if any resolves right now. */
|
|
170
|
+
EvmProviderRegistry.prototype.suppliedAttributionFor = function (provider) {
|
|
171
|
+
var resolve = this.attributions.get(provider);
|
|
172
|
+
if (!resolve)
|
|
173
|
+
return undefined;
|
|
174
|
+
try {
|
|
175
|
+
var info = resolve();
|
|
176
|
+
return (info === null || info === void 0 ? void 0 : info.name) ? info : undefined;
|
|
177
|
+
}
|
|
178
|
+
catch (_a) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
138
182
|
/**
|
|
139
183
|
* A provider's display name and rdns.
|
|
140
184
|
*
|
|
141
|
-
* EIP-6963 metadata is authoritative when we have it
|
|
142
|
-
*
|
|
185
|
+
* EIP-6963 metadata is authoritative when we have it. A supplied
|
|
186
|
+
* attribution (the connector a wagmi app connected through) comes next:
|
|
187
|
+
* it describes the SESSION, which is what the hook-driven events report.
|
|
188
|
+
* Otherwise fall back to sniffing the injected provider, which is all a
|
|
189
|
+
* pre-6963 wallet offers; a supplied name without an rdns keeps the
|
|
190
|
+
* sniffed rdns.
|
|
143
191
|
*/
|
|
144
192
|
EvmProviderRegistry.prototype.infoFor = function (provider) {
|
|
145
193
|
var announced = this.details.find(function (p) { return p.provider === provider; });
|
|
194
|
+
var supplied = announced
|
|
195
|
+
? undefined
|
|
196
|
+
: this.suppliedAttributionFor(provider);
|
|
146
197
|
var info = announced
|
|
147
198
|
? { name: announced.info.name, rdns: announced.info.rdns }
|
|
148
199
|
: (function () {
|
|
200
|
+
var _a;
|
|
149
201
|
var injected = (0, provider_1.detectInjectedProviderInfo)(provider);
|
|
150
|
-
return
|
|
202
|
+
return supplied
|
|
203
|
+
? { name: supplied.name, rdns: (_a = supplied.rdns) !== null && _a !== void 0 ? _a : injected.rdns }
|
|
204
|
+
: { name: injected.name, rdns: injected.rdns };
|
|
151
205
|
})();
|
|
152
206
|
// WalletConnect names the TRANSPORT; the session's peer names the
|
|
153
207
|
// wallet. Resolved live, per read: a session established after the
|
|
@@ -157,7 +211,10 @@ var EvmProviderRegistry = /** @class */ (function () {
|
|
|
157
211
|
// is included because a flagless WalletConnect-compatible provider
|
|
158
212
|
// registered BEFORE its session exists detects as nothing at all;
|
|
159
213
|
// the peer appearing later is itself the proof of what it was, so
|
|
160
|
-
// the rdns upgrades with it.
|
|
214
|
+
// the rdns upgrades with it. A supplied name gets the same treatment
|
|
215
|
+
// and no more: the integration layer resolves its own peer names
|
|
216
|
+
// where it wants them, and a branded connector must keep its name on
|
|
217
|
+
// both paths.
|
|
161
218
|
if (info.name === "WalletConnect" || info.name === "Injected Provider") {
|
|
162
219
|
var peer = (0, provider_1.readWalletConnectPeer)(provider);
|
|
163
220
|
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;
|
|
@@ -299,7 +299,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
299
299
|
*/
|
|
300
300
|
EvmRequestTracker.prototype.dispatchWrappedRequest = function (_a, provider_2, request_1) {
|
|
301
301
|
return __awaiter(this, arguments, void 0, function (_b, provider, request) {
|
|
302
|
-
var generation_1, responsePromise, capturedChainId_1, response_1, error_1, rpcError, txPromise, txChainId_1, transactionHash_1, error_2, rpcError;
|
|
302
|
+
var generation_1, responsePromise, capturedChainId_1, attribution_1, response_1, error_1, rpcError, txPromise, txChainId_1, attribution_2, transactionHash_1, error_2, rpcError;
|
|
303
303
|
var _this = this;
|
|
304
304
|
var _c, _d, _e, _f;
|
|
305
305
|
var method = _b.method, params = _b.params;
|
|
@@ -342,6 +342,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
342
342
|
// below is never reported as unhandled. The real handling is there.
|
|
343
343
|
responsePromise.catch(function () { return undefined; });
|
|
344
344
|
capturedChainId_1 = this.registry.resolveChainId(provider);
|
|
345
|
+
attribution_1 = this.attributionFor(provider);
|
|
345
346
|
// Fire-and-forget tracking
|
|
346
347
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
347
348
|
var e_1;
|
|
@@ -349,7 +350,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
349
350
|
switch (_a.label) {
|
|
350
351
|
case 0:
|
|
351
352
|
_a.trys.push([0, 2, , 3]);
|
|
352
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: types_1.SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)),
|
|
353
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: types_1.SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)), attribution_1)];
|
|
353
354
|
case 1:
|
|
354
355
|
_a.sent();
|
|
355
356
|
return [3 /*break*/, 3];
|
|
@@ -375,7 +376,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
375
376
|
switch (_a.label) {
|
|
376
377
|
case 0:
|
|
377
378
|
_a.trys.push([0, 2, , 3]);
|
|
378
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: types_1.SignatureStatus.CONFIRMED }, this.buildSignatureEventPayload(method, params, response_1, capturedChainId_1, provider)),
|
|
379
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: types_1.SignatureStatus.CONFIRMED }, this.buildSignatureEventPayload(method, params, response_1, capturedChainId_1, provider)), attribution_1)];
|
|
379
380
|
case 1:
|
|
380
381
|
_a.sent();
|
|
381
382
|
return [3 /*break*/, 3];
|
|
@@ -400,7 +401,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
400
401
|
switch (_a.label) {
|
|
401
402
|
case 0:
|
|
402
403
|
_a.trys.push([0, 2, , 3]);
|
|
403
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: types_1.SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)),
|
|
404
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: types_1.SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)), attribution_1)];
|
|
404
405
|
case 1:
|
|
405
406
|
_a.sent();
|
|
406
407
|
return [3 /*break*/, 3];
|
|
@@ -439,6 +440,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
439
440
|
txPromise = request({ method: method, params: params });
|
|
440
441
|
txPromise.catch(function () { return undefined; });
|
|
441
442
|
txChainId_1 = this.registry.resolveChainId(provider);
|
|
443
|
+
attribution_2 = this.attributionFor(provider);
|
|
442
444
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
443
445
|
var payload, e_4;
|
|
444
446
|
return __generator(this, function (_a) {
|
|
@@ -448,7 +450,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
448
450
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
449
451
|
case 1:
|
|
450
452
|
payload = _a.sent();
|
|
451
|
-
return [4 /*yield*/, this.deps.transaction(__assign({ status: types_1.TransactionStatus.STARTED }, payload),
|
|
453
|
+
return [4 /*yield*/, this.deps.transaction(__assign({ status: types_1.TransactionStatus.STARTED }, payload), attribution_2)];
|
|
452
454
|
case 2:
|
|
453
455
|
_a.sent();
|
|
454
456
|
return [3 /*break*/, 4];
|
|
@@ -475,11 +477,11 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
475
477
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
476
478
|
case 1:
|
|
477
479
|
payload = _a.sent();
|
|
478
|
-
return [4 /*yield*/, this.deps.transaction(__assign(__assign({ status: types_1.TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }),
|
|
480
|
+
return [4 /*yield*/, this.deps.transaction(__assign(__assign({ status: types_1.TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }), attribution_2)];
|
|
479
481
|
case 2:
|
|
480
482
|
_a.sent();
|
|
481
483
|
// Start async polling for transaction receipt
|
|
482
|
-
this.pollTransactionReceipt(provider, transactionHash_1, payload);
|
|
484
|
+
this.pollTransactionReceipt(provider, transactionHash_1, payload, attribution_2);
|
|
483
485
|
return [3 /*break*/, 4];
|
|
484
486
|
case 3:
|
|
485
487
|
e_5 = _a.sent();
|
|
@@ -504,7 +506,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
504
506
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
505
507
|
case 1:
|
|
506
508
|
payload = _a.sent();
|
|
507
|
-
return [4 /*yield*/, this.deps.transaction(__assign({ status: types_1.TransactionStatus.REJECTED }, payload),
|
|
509
|
+
return [4 /*yield*/, this.deps.transaction(__assign({ status: types_1.TransactionStatus.REJECTED }, payload), attribution_2)];
|
|
508
510
|
case 2:
|
|
509
511
|
_a.sent();
|
|
510
512
|
return [3 /*break*/, 4];
|
|
@@ -526,10 +528,15 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
526
528
|
/**
|
|
527
529
|
* Wallet attribution for request-derived events.
|
|
528
530
|
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
* made
|
|
531
|
+
* Resolved through the registry at the START of each request and held
|
|
532
|
+
* for that request's whole lifecycle, receipt included. Reading it per
|
|
533
|
+
* status let a connector switch (two connectors sharing one provider) or
|
|
534
|
+
* a session change made while a prompt was open split one operation
|
|
535
|
+
* between two wallet names. Still live across requests: a WalletConnect
|
|
536
|
+
* session names its actual signer ("MetaMask Wallet", "Ledger Live") -
|
|
537
|
+
* the live-test rows had provider_name EMPTY on every signature and
|
|
538
|
+
* transaction, which made per-wallet activity unanswerable in the
|
|
539
|
+
* warehouse.
|
|
533
540
|
*/
|
|
534
541
|
EvmRequestTracker.prototype.attributionFor = function (provider) {
|
|
535
542
|
var info = this.registry.infoFor(provider);
|
|
@@ -599,8 +606,11 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
599
606
|
/**
|
|
600
607
|
* Polls for transaction receipt and emits tx.status = CONFIRMED or REVERTED.
|
|
601
608
|
*/
|
|
602
|
-
EvmRequestTracker.prototype.pollTransactionReceipt = function (provider_2, transactionHash_2, payload_1) {
|
|
603
|
-
return __awaiter(this, arguments, void 0, function (provider, transactionHash, payload,
|
|
609
|
+
EvmRequestTracker.prototype.pollTransactionReceipt = function (provider_2, transactionHash_2, payload_1, attribution_3) {
|
|
610
|
+
return __awaiter(this, arguments, void 0, function (provider, transactionHash, payload,
|
|
611
|
+
// Snapshot from the broadcast: a connector or session change during
|
|
612
|
+
// the poll window must not relabel the receipt.
|
|
613
|
+
attribution, maxAttempts, intervalMs) {
|
|
604
614
|
var attempts, poll;
|
|
605
615
|
var _this = this;
|
|
606
616
|
if (maxAttempts === void 0) { maxAttempts = 10; }
|
|
@@ -629,7 +639,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
629
639
|
// status: 1 = success, 0 = reverted
|
|
630
640
|
if (receipt.status === "0x1" || receipt.status === 1) {
|
|
631
641
|
this.deps
|
|
632
|
-
.transaction(__assign(__assign({ status: types_1.TransactionStatus.CONFIRMED }, payload), { transactionHash: transactionHash }),
|
|
642
|
+
.transaction(__assign(__assign({ status: types_1.TransactionStatus.CONFIRMED }, payload), { transactionHash: transactionHash }), attribution)
|
|
633
643
|
.catch(function (e) {
|
|
634
644
|
return logger_1.logger.error("Formo: Failed to track transaction confirmation", e);
|
|
635
645
|
});
|
|
@@ -637,7 +647,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
637
647
|
}
|
|
638
648
|
else if (receipt.status === "0x0" || receipt.status === 0) {
|
|
639
649
|
this.deps
|
|
640
|
-
.transaction(__assign(__assign({ status: types_1.TransactionStatus.REVERTED }, payload), { transactionHash: transactionHash }),
|
|
650
|
+
.transaction(__assign(__assign({ status: types_1.TransactionStatus.REVERTED }, payload), { transactionHash: transactionHash }), attribution)
|
|
641
651
|
.catch(function (e) {
|
|
642
652
|
return logger_1.logger.error("Formo: Failed to track transaction revert", e);
|
|
643
653
|
});
|
|
@@ -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
|
|
@@ -2,34 +2,126 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* SolanaManager
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* Subscribes to framework-kit's zustand store for automatic event capture
|
|
7
|
-
* of wallet connect/disconnect and transaction lifecycle events.
|
|
5
|
+
* Owns the two ways the SDK learns about Solana wallets:
|
|
8
6
|
*
|
|
9
|
-
*
|
|
7
|
+
* 1. `SolanaWalletStandardRegistry`: discovers wallets through the Wallet
|
|
8
|
+
* Standard and reports detect / connect / disconnect. On by default, so
|
|
9
|
+
* compatible wallets registered by Solana Kit, wallet-adapter,
|
|
10
|
+
* framework-kit, or another host are covered with no configuration,
|
|
11
|
+
* exactly like EVM wallets through EIP-6963. `solana: false` turns it off.
|
|
12
|
+
* 2. `SolanaStoreHandler`: subscribes to framework-kit's zustand store for
|
|
13
|
+
* connect / disconnect / cluster changes AND the transaction lifecycle.
|
|
14
|
+
* Opt-in through `solana: { store }` or `formo.solana.setStore()`.
|
|
15
|
+
*
|
|
16
|
+
* Both observe the same Wallet Standard connection when a framework-kit app
|
|
17
|
+
* connects. A store supplied at initialization owns wallet events; a store
|
|
18
|
+
* attached later takes ownership when it observes its first connection and
|
|
19
|
+
* adopts any connect the registry already reported. One connect per
|
|
20
|
+
* connection, whichever path an app is on.
|
|
21
|
+
*
|
|
22
|
+
* For signMessage/signTransaction tracking (not captured by either path),
|
|
10
23
|
* use formo.signature() directly with the address and chainId.
|
|
11
24
|
*
|
|
12
|
-
* For manual event tracking
|
|
25
|
+
* For manual event tracking, use the core API directly:
|
|
13
26
|
* formo.transaction(), formo.signature(), formo.connect(), formo.disconnect().
|
|
14
27
|
*/
|
|
15
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
29
|
exports.SolanaManager = void 0;
|
|
17
30
|
var logger_1 = require("../logger");
|
|
18
31
|
var SolanaStoreHandler_1 = require("./SolanaStoreHandler");
|
|
32
|
+
var SolanaWalletStandardRegistry_1 = require("./SolanaWalletStandardRegistry");
|
|
33
|
+
var types_1 = require("./types");
|
|
19
34
|
var SolanaManager = /** @class */ (function () {
|
|
20
|
-
|
|
35
|
+
/**
|
|
36
|
+
* @param formo - The SDK instance events are reported to.
|
|
37
|
+
* @param options - `options.solana` as passed to the SDK, if an object.
|
|
38
|
+
* @param enabled - Whether Solana tracking is enabled. False only when the
|
|
39
|
+
* host app passed `solana: false`; both discovery and stores then stay off.
|
|
40
|
+
*/
|
|
41
|
+
function SolanaManager(formo, options, enabled) {
|
|
42
|
+
if (enabled === void 0) { enabled = true; }
|
|
43
|
+
var _this = this;
|
|
21
44
|
this.formo = formo;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
else if (options === null || options === void 0 ? void 0 : options.cluster) {
|
|
45
|
+
this.enabled = enabled;
|
|
46
|
+
this.storeOwnsWalletEvents = false;
|
|
47
|
+
if (!enabled)
|
|
48
|
+
return;
|
|
49
|
+
if (options === null || options === void 0 ? void 0 : options.cluster) {
|
|
29
50
|
// Store pending cluster for when setStore is called later
|
|
30
51
|
this.pendingCluster = options.cluster;
|
|
31
52
|
}
|
|
53
|
+
// A store supplied at initialization owns wallet events from the outset:
|
|
54
|
+
// unlike a store attached later, it has not missed any prior registry
|
|
55
|
+
// state and it knows the cluster more precisely.
|
|
56
|
+
this.storeOwnsWalletEvents = !!(options === null || options === void 0 ? void 0 : options.store);
|
|
57
|
+
this.registry = new SolanaWalletStandardRegistry_1.SolanaWalletStandardRegistry({
|
|
58
|
+
isAutocaptureEnabled: function (t) { return _this.formo.isAutocaptureEnabled(t); },
|
|
59
|
+
willTrackEvent: function (chainId) { return _this.formo.willTrackEvent(chainId); },
|
|
60
|
+
detect: function (params) { return _this.formo.detect(params); },
|
|
61
|
+
connect: function (params, properties) {
|
|
62
|
+
return _this.formo.connect(params, properties);
|
|
63
|
+
},
|
|
64
|
+
disconnect: function (params) { return _this.formo.disconnect(params); },
|
|
65
|
+
chain: function (params) { return _this.formo.chain(params); },
|
|
66
|
+
syncWalletState: function (params) { return _this.formo.syncWalletState(params); },
|
|
67
|
+
currentAddress: function () { return _this.formo.currentAddress; },
|
|
68
|
+
ownsWalletEvents: function () { return !_this.storeOwnsWalletEvents; },
|
|
69
|
+
}, { cluster: options === null || options === void 0 ? void 0 : options.cluster });
|
|
70
|
+
if (options === null || options === void 0 ? void 0 : options.store) {
|
|
71
|
+
logger_1.logger.info("SolanaManager: Initializing store-based Solana tracking");
|
|
72
|
+
this.attachStore(options.store, options.cluster);
|
|
73
|
+
}
|
|
32
74
|
}
|
|
75
|
+
SolanaManager.prototype.attachStore = function (store, cluster) {
|
|
76
|
+
var _this = this;
|
|
77
|
+
var _a;
|
|
78
|
+
this.storeHandler = new SolanaStoreHandler_1.SolanaStoreHandler(this.formo, store, {
|
|
79
|
+
cluster: cluster,
|
|
80
|
+
beforeWalletConnect: function (connection) {
|
|
81
|
+
var _a, _b;
|
|
82
|
+
// The store's cluster is authoritative even when chain autocapture is
|
|
83
|
+
// disabled. Keep central attribution correct without manufacturing a
|
|
84
|
+
// chain event in that mode.
|
|
85
|
+
_this.formo.syncWalletState({
|
|
86
|
+
address: connection.address,
|
|
87
|
+
chainId: connection.chainId,
|
|
88
|
+
});
|
|
89
|
+
if (_this.storeOwnsWalletEvents)
|
|
90
|
+
return true;
|
|
91
|
+
var reported = (_a = _this.registry) === null || _a === void 0 ? void 0 : _a.takeReportedConnection(connection.address, connection.rdns);
|
|
92
|
+
_this.storeOwnsWalletEvents = true;
|
|
93
|
+
// If Wallet Standard got there first, the store adopts that live
|
|
94
|
+
// connection instead of emitting it again. Correct its cluster if
|
|
95
|
+
// the store has more precise information.
|
|
96
|
+
if (!reported) {
|
|
97
|
+
// Nothing to adopt. Either the registry never reported this
|
|
98
|
+
// connection, or it reported it under another identity, in which
|
|
99
|
+
// case the store is about to emit a second connect for the same
|
|
100
|
+
// live connection. Both paths derive the rdns from the wallet's
|
|
101
|
+
// own name, so a mismatch means the store's connector is labelled
|
|
102
|
+
// differently from the registered wallet.
|
|
103
|
+
var held = (_b = _this.registry) === null || _b === void 0 ? void 0 : _b.reportedConnectionRdns(connection.address);
|
|
104
|
+
if (held) {
|
|
105
|
+
logger_1.logger.warn("SolanaManager: Store connector does not match the discovered wallet; the connection is reported twice", { storeRdns: connection.rdns, walletRdns: held });
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (reported.chainId !== connection.chainId &&
|
|
110
|
+
_this.formo.isAutocaptureEnabled("chain")) {
|
|
111
|
+
_this.formo.chain(connection).catch(function (error) {
|
|
112
|
+
logger_1.logger.error("SolanaManager: Error correcting cluster during store handoff", error);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
// Keep the registry's snapshot on the store's detected cluster. This is
|
|
119
|
+
// silent once the store owns events; during a late handoff it corrects a
|
|
120
|
+
// registry-reported connection before the store adopts it.
|
|
121
|
+
var detectedCluster = types_1.SOLANA_CLUSTERS_BY_ID[this.storeHandler.getChainId()];
|
|
122
|
+
if (detectedCluster)
|
|
123
|
+
(_a = this.registry) === null || _a === void 0 ? void 0 : _a.setCluster(detectedCluster);
|
|
124
|
+
};
|
|
33
125
|
/**
|
|
34
126
|
* Set the framework-kit zustand store for automatic event tracking.
|
|
35
127
|
* This enables autocapture mode — connect/disconnect and transaction events
|
|
@@ -48,29 +140,52 @@ var SolanaManager = /** @class */ (function () {
|
|
|
48
140
|
*/
|
|
49
141
|
SolanaManager.prototype.setStore = function (store, options) {
|
|
50
142
|
var _a;
|
|
143
|
+
if (!this.enabled) {
|
|
144
|
+
logger_1.logger.warn("SolanaManager: Ignoring setStore. Solana tracking is off for this instance (solana: false, or the SDK was cleaned up)");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
51
147
|
(_a = this.storeHandler) === null || _a === void 0 ? void 0 : _a.cleanup();
|
|
52
|
-
this.storeHandler =
|
|
53
|
-
|
|
54
|
-
|
|
148
|
+
this.storeHandler = undefined;
|
|
149
|
+
this.storeOwnsWalletEvents = false;
|
|
150
|
+
this.attachStore(store, (options === null || options === void 0 ? void 0 : options.cluster) || this.pendingCluster);
|
|
55
151
|
this.pendingCluster = undefined;
|
|
56
152
|
};
|
|
57
153
|
/**
|
|
58
|
-
* Update the cluster/network.
|
|
59
|
-
*
|
|
60
|
-
*
|
|
154
|
+
* Update the cluster/network.
|
|
155
|
+
*
|
|
156
|
+
* With a framework-kit store, only needed if the store endpoint doesn't
|
|
157
|
+
* contain a recognizable cluster name (e.g. custom RPC URLs). Without one,
|
|
158
|
+
* this is how a non-mainnet app tells the SDK which cluster its Wallet
|
|
159
|
+
* Standard connections are on, since the standard itself cannot say.
|
|
61
160
|
*/
|
|
62
161
|
SolanaManager.prototype.setCluster = function (cluster) {
|
|
162
|
+
var _a;
|
|
163
|
+
if (!this.enabled)
|
|
164
|
+
return;
|
|
63
165
|
if (this.storeHandler) {
|
|
64
166
|
this.storeHandler.setCluster(cluster);
|
|
65
167
|
}
|
|
66
168
|
else {
|
|
67
169
|
this.pendingCluster = cluster;
|
|
68
170
|
}
|
|
171
|
+
(_a = this.registry) === null || _a === void 0 ? void 0 : _a.setCluster(cluster);
|
|
69
172
|
};
|
|
173
|
+
Object.defineProperty(SolanaManager.prototype, "discoveredWallets", {
|
|
174
|
+
/** Names of the Wallet Standard wallets discovered so far. */
|
|
175
|
+
get: function () {
|
|
176
|
+
var _a, _b;
|
|
177
|
+
return (_b = (_a = this.registry) === null || _a === void 0 ? void 0 : _a.walletNames) !== null && _b !== void 0 ? _b : [];
|
|
178
|
+
},
|
|
179
|
+
enumerable: false,
|
|
180
|
+
configurable: true
|
|
181
|
+
});
|
|
70
182
|
SolanaManager.prototype.cleanup = function () {
|
|
71
|
-
var _a;
|
|
183
|
+
var _a, _b;
|
|
72
184
|
(_a = this.storeHandler) === null || _a === void 0 ? void 0 : _a.cleanup();
|
|
73
185
|
this.storeHandler = undefined;
|
|
186
|
+
this.storeOwnsWalletEvents = false;
|
|
187
|
+
(_b = this.registry) === null || _b === void 0 ? void 0 : _b.cleanup();
|
|
188
|
+
this.registry = undefined;
|
|
74
189
|
};
|
|
75
190
|
return SolanaManager;
|
|
76
191
|
}());
|
|
@@ -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.
|