@formo/analytics 1.38.1 → 1.38.2

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.
@@ -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; otherwise fall back to
69
- * sniffing the injected provider, which is all a pre-6963 wallet offers.
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; otherwise fall back to
142
- * sniffing the injected provider, which is all a pre-6963 wallet offers.
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 { name: injected.name, rdns: injected.rdns };
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
- * Live per read through the registry, so a WalletConnect session names
87
- * its actual signer ("MetaMask Wallet", "Ledger Live") - the live-test
88
- * rows had provider_name EMPTY on every signature and transaction, which
89
- * made per-wallet activity unanswerable in the warehouse.
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)), this.attributionFor(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)), this.attributionFor(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)), this.attributionFor(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), this.attributionFor(provider))];
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 }), this.attributionFor(provider))];
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), this.attributionFor(provider))];
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
- * Live per read through the registry, so a WalletConnect session names
530
- * its actual signer ("MetaMask Wallet", "Ledger Live") - the live-test
531
- * rows had provider_name EMPTY on every signature and transaction, which
532
- * made per-wallet activity unanswerable in the warehouse.
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, maxAttempts, intervalMs) {
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 }), this.attributionFor(provider))
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 }), this.attributionFor(provider))
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,2 +1,2 @@
1
- export declare const version = "1.38.1";
1
+ export declare const version = "1.38.2";
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.1';
6
+ exports.version = '1.38.2';
7
7
  //# sourceMappingURL=version.js.map
@@ -6,7 +6,7 @@
6
6
  * wrapping approach when Wagmi mode is enabled.
7
7
  */
8
8
  import { FormoAnalytics } from "../FormoAnalytics";
9
- import { WagmiConfig, QueryClient } from "./types";
9
+ import { QueryClient, WagmiConfig } from "./types";
10
10
  /**
11
11
  * How long the markers stay trustworthy after the last handler goes away.
12
12
  *
@@ -337,6 +337,35 @@ export declare class WagmiEventHandler {
337
337
  * (still connected through its own connector).
338
338
  */
339
339
  private isAddressConnected;
340
+ /**
341
+ * A specific connector's name and rdns, for the fallback-wrapped
342
+ * provider's request-derived events.
343
+ *
344
+ * The NAME is exactly what the hook path emits for that connector
345
+ * (`getConnectorName`: the live WalletConnect peer for a WalletConnect
346
+ * connector, the connector's own name otherwise), so a branded connector
347
+ * keeps its name on both paths and a session that changes wallets
348
+ * renames on both. The rdns is the connector's when wagmi knows it as
349
+ * ONE value (EIP-6963 discovered connectors carry theirs, some as a
350
+ * one-element list); a connector that matches several rdns values does
351
+ * not say which one this provider is, so nothing is passed and the
352
+ * registry keeps the sniffed one.
353
+ */
354
+ private attributionForConnector;
355
+ /**
356
+ * Resolver handed to the registry at wrap time, read at each request
357
+ * start. BOUND to the connector whose `getProvider` resolved to the
358
+ * wrapped provider, not to whichever connector is current: an app can
359
+ * keep a wallet client over a previous connector's provider and issue a
360
+ * request through it after switching, and that request belongs to the
361
+ * wallet that handles it. The peer name is still read live. A provider
362
+ * SHARED by two connectors is re-bound when the new connector's
363
+ * resolution lands (one microtask for an injected connector); a request
364
+ * issued inside that gap keeps the previous label.
365
+ */
366
+ private boundConnectorAttribution;
367
+ /** `getConnectorName` for a SPECIFIC connector, current or not. */
368
+ private nameForConnector;
340
369
  /**
341
370
  * Get the connector name from Wagmi state
342
371
  */
@@ -75,6 +75,16 @@ var RESERVED_FIELDS = new Set([
75
75
  "transactionHash",
76
76
  "function_name",
77
77
  "function_args",
78
+ // Wallet attribution. Function args are spread AFTER the attribution
79
+ // properties, so an ABI input named `providerName` would silently
80
+ // relabel the wallet on every broadcast and receipt event. `rdns` is
81
+ // reserved with it even though THIS path (wagmi mutation attribution)
82
+ // emits only the name: elsewhere in the SDK - the EIP-1193 request path
83
+ // and connect events - `rdns` is the wallet-identity key, so an ABI
84
+ // input by that name would land in the same warehouse column as real
85
+ // wallet identities.
86
+ "providerName",
87
+ "rdns",
78
88
  ]);
79
89
  /**
80
90
  * Connections already announced to a destination during this page load.
@@ -2337,6 +2347,75 @@ var WagmiEventHandler = /** @class */ (function () {
2337
2347
  });
2338
2348
  return found;
2339
2349
  };
2350
+ /**
2351
+ * A specific connector's name and rdns, for the fallback-wrapped
2352
+ * provider's request-derived events.
2353
+ *
2354
+ * The NAME is exactly what the hook path emits for that connector
2355
+ * (`getConnectorName`: the live WalletConnect peer for a WalletConnect
2356
+ * connector, the connector's own name otherwise), so a branded connector
2357
+ * keeps its name on both paths and a session that changes wallets
2358
+ * renames on both. The rdns is the connector's when wagmi knows it as
2359
+ * ONE value (EIP-6963 discovered connectors carry theirs, some as a
2360
+ * one-element list); a connector that matches several rdns values does
2361
+ * not say which one this provider is, so nothing is passed and the
2362
+ * registry keeps the sniffed one.
2363
+ */
2364
+ WagmiEventHandler.prototype.attributionForConnector = function (connector, state) {
2365
+ var name = this.nameForConnector(connector, state);
2366
+ if (!name) {
2367
+ return undefined;
2368
+ }
2369
+ var raw = connector.rdns;
2370
+ var rdns = typeof raw === "string" && raw.length > 0
2371
+ ? raw
2372
+ : Array.isArray(raw) && raw.length === 1 && typeof raw[0] === "string" && raw[0].length > 0
2373
+ ? raw[0]
2374
+ : undefined;
2375
+ return __assign({ name: name }, (rdns && { rdns: rdns }));
2376
+ };
2377
+ /**
2378
+ * Resolver handed to the registry at wrap time, read at each request
2379
+ * start. BOUND to the connector whose `getProvider` resolved to the
2380
+ * wrapped provider, not to whichever connector is current: an app can
2381
+ * keep a wallet client over a previous connector's provider and issue a
2382
+ * request through it after switching, and that request belongs to the
2383
+ * wallet that handles it. The peer name is still read live. A provider
2384
+ * SHARED by two connectors is re-bound when the new connector's
2385
+ * resolution lands (one microtask for an injected connector); a request
2386
+ * issued inside that gap keeps the previous label.
2387
+ */
2388
+ WagmiEventHandler.prototype.boundConnectorAttribution = function (connector) {
2389
+ var _this = this;
2390
+ return function () {
2391
+ if (_this.disposed)
2392
+ return undefined;
2393
+ try {
2394
+ return _this.attributionForConnector(connector, _this.getState());
2395
+ }
2396
+ catch (_a) {
2397
+ return undefined;
2398
+ }
2399
+ };
2400
+ };
2401
+ /** `getConnectorName` for a SPECIFIC connector, current or not. */
2402
+ WagmiEventHandler.prototype.nameForConnector = function (connector, state) {
2403
+ var _a;
2404
+ var cached = walletConnectPeerNames.get(connector);
2405
+ if (cached) {
2406
+ return cached;
2407
+ }
2408
+ var current = state.current
2409
+ ? (_a = state.connections.get(state.current)) === null || _a === void 0 ? void 0 : _a.connector
2410
+ : undefined;
2411
+ if (current === connector) {
2412
+ // Backstop kick, as in getConnectorName; only the current connection
2413
+ // has a session to look up.
2414
+ this.kickWalletConnectPeerLookup(state);
2415
+ }
2416
+ var name = connector.name;
2417
+ return typeof name === "string" && name.length > 0 ? name : undefined;
2418
+ };
2340
2419
  /**
2341
2420
  * Get the connector name from Wagmi state
2342
2421
  */
@@ -2474,7 +2553,7 @@ var WagmiEventHandler = /** @class */ (function () {
2474
2553
  return;
2475
2554
  }
2476
2555
  var chainId = (_b = _this.getActiveConnectionChainId(live)) !== null && _b !== void 0 ? _b : live.chainId;
2477
- var wrapped = (_d = (_c = _this.formo)._wrapWagmiProvider) === null || _d === void 0 ? void 0 : _d.call(_c, provider, typeof chainId === "number" ? chainId : undefined);
2556
+ var wrapped = (_d = (_c = _this.formo)._wrapWagmiProvider) === null || _d === void 0 ? void 0 : _d.call(_c, provider, typeof chainId === "number" ? chainId : undefined, _this.boundConnectorAttribution(connector));
2478
2557
  if (wrapped !== true) {
2479
2558
  // The provider was refused (invalid shape, frozen provider,
2480
2559
  // torn-down SDK).
@@ -31,6 +31,12 @@ export interface WagmiConnector {
31
31
  name: string;
32
32
  type: string;
33
33
  uid: string;
34
+ /**
35
+ * Any connector implementation may expose an rdns; EIP-6963 discovered
36
+ * connectors are one source. A connector matching several rdns values
37
+ * lists them all.
38
+ */
39
+ rdns?: string | readonly string[];
34
40
  }
35
41
  /**
36
42
  * Wagmi config interface
@@ -192,7 +192,15 @@ function buildSafeFunctionArgs(functionArgs, reservedFields) {
192
192
  var result = {};
193
193
  for (var _i = 0, _a = Object.entries(functionArgs); _i < _a.length; _i++) {
194
194
  var _b = _a[_i], key = _b[0], val = _b[1];
195
- var safeKey = reservedFields.has(key) ? "arg_".concat(key) : key;
195
+ // A prefixed key must not land on another argument's own name: an ABI
196
+ // with both `to` and `arg_to` would otherwise keep only one of them,
197
+ // whichever came later. Keep prefixing until the name is free.
198
+ var safeKey = key;
199
+ if (reservedFields.has(key)) {
200
+ do {
201
+ safeKey = "arg_".concat(safeKey);
202
+ } while (safeKey in functionArgs);
203
+ }
196
204
  result[safeKey] = val;
197
205
  // If the value is a nested object (struct), flatten it
198
206
  // Skip flattened keys that would overwrite existing top-level args
@@ -428,8 +428,17 @@ export declare class FormoAnalytics implements IFormoAnalytics {
428
428
  * gap. Lifecycle (connect/chain/disconnect) stays store-driven: only the
429
429
  * request wrapper installs here. Double counting is prevented in the
430
430
  * wrapper via `shouldSkipRequestCapture`.
431
+ *
432
+ * `attribution` resolves, live, the name and rdns of the connector this
433
+ * provider was wrapped for. Request-derived events are named from the
434
+ * registry, which for an unannounced provider falls back to flag
435
+ * sniffing; recording the connector's resolver here keeps them in
436
+ * agreement with the hook-driven events for that connector.
431
437
  */
432
- _wrapWagmiProvider(provider: EIP1193Provider, chainId?: number): boolean;
438
+ _wrapWagmiProvider(provider: EIP1193Provider, chainId?: number, attribution?: () => {
439
+ name: string;
440
+ rdns?: string;
441
+ } | undefined): boolean;
433
442
  /** INTERNAL. Chain updates for the fallback-wrapped provider. */
434
443
  _rememberWagmiProviderChain(provider: EIP1193Provider, chainId: number | undefined): void;
435
444
  registerProvider(provider: EIP1193Provider, info?: {
@@ -1015,6 +1015,9 @@ var FormoAnalytics = /** @class */ (function () {
1015
1015
  // Drop anything already buffered so a pending timer/pagehide flush
1016
1016
  // cannot ship events after consent withdrawal.
1017
1017
  this.eventManager.clear();
1018
+ // Identity is purged below; registered sessions must be re-learned
1019
+ // on opt-in, and nothing else would retry an already-adopted one.
1020
+ this.evmEvents.markRegisteredAdoptionsPending();
1018
1021
  this.reset();
1019
1022
  logger.info("Successfully opted out of tracking");
1020
1023
  };
@@ -1360,8 +1363,14 @@ var FormoAnalytics = /** @class */ (function () {
1360
1363
  * gap. Lifecycle (connect/chain/disconnect) stays store-driven: only the
1361
1364
  * request wrapper installs here. Double counting is prevented in the
1362
1365
  * wrapper via `shouldSkipRequestCapture`.
1366
+ *
1367
+ * `attribution` resolves, live, the name and rdns of the connector this
1368
+ * provider was wrapped for. Request-derived events are named from the
1369
+ * registry, which for an unannounced provider falls back to flag
1370
+ * sniffing; recording the connector's resolver here keeps them in
1371
+ * agreement with the hook-driven events for that connector.
1363
1372
  */
1364
- FormoAnalytics.prototype._wrapWagmiProvider = function (provider, chainId) {
1373
+ FormoAnalytics.prototype._wrapWagmiProvider = function (provider, chainId, attribution) {
1365
1374
  if (this.isCleanedUp || !isValidProvider(provider))
1366
1375
  return false;
1367
1376
  try {
@@ -1371,6 +1380,7 @@ var FormoAnalytics = /** @class */ (function () {
1371
1380
  if (!this.evmRequests.registerRequestListeners(provider)) {
1372
1381
  return false;
1373
1382
  }
1383
+ this.evm.rememberAttribution(provider, attribution);
1374
1384
  if (chainId !== undefined) {
1375
1385
  this.evm.rememberChain(provider, chainId);
1376
1386
  }