@formo/analytics-react-native 0.1.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/README.md +302 -0
- package/lib/commonjs/FormoAnalytics.js +526 -0
- package/lib/commonjs/FormoAnalytics.js.map +1 -0
- package/lib/commonjs/FormoAnalyticsProvider.js +265 -0
- package/lib/commonjs/FormoAnalyticsProvider.js.map +1 -0
- package/lib/commonjs/constants/config.js +69 -0
- package/lib/commonjs/constants/config.js.map +1 -0
- package/lib/commonjs/constants/events.js +30 -0
- package/lib/commonjs/constants/events.js.map +1 -0
- package/lib/commonjs/constants/index.js +39 -0
- package/lib/commonjs/constants/index.js.map +1 -0
- package/lib/commonjs/constants/storage.js +23 -0
- package/lib/commonjs/constants/storage.js.map +1 -0
- package/lib/commonjs/index.js +65 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/lib/consent/index.js +56 -0
- package/lib/commonjs/lib/consent/index.js.map +1 -0
- package/lib/commonjs/lib/event/EventFactory.js +493 -0
- package/lib/commonjs/lib/event/EventFactory.js.map +1 -0
- package/lib/commonjs/lib/event/EventManager.js +46 -0
- package/lib/commonjs/lib/event/EventManager.js.map +1 -0
- package/lib/commonjs/lib/event/EventQueue.js +290 -0
- package/lib/commonjs/lib/event/EventQueue.js.map +1 -0
- package/lib/commonjs/lib/event/index.js +50 -0
- package/lib/commonjs/lib/event/index.js.map +1 -0
- package/lib/commonjs/lib/event/types.js +6 -0
- package/lib/commonjs/lib/event/types.js.map +1 -0
- package/lib/commonjs/lib/lifecycle/index.js +196 -0
- package/lib/commonjs/lib/lifecycle/index.js.map +1 -0
- package/lib/commonjs/lib/logger/index.js +48 -0
- package/lib/commonjs/lib/logger/index.js.map +1 -0
- package/lib/commonjs/lib/session/index.js +109 -0
- package/lib/commonjs/lib/session/index.js.map +1 -0
- package/lib/commonjs/lib/storage/AsyncStorageAdapter.js +164 -0
- package/lib/commonjs/lib/storage/AsyncStorageAdapter.js.map +1 -0
- package/lib/commonjs/lib/storage/MemoryStorage.js +41 -0
- package/lib/commonjs/lib/storage/MemoryStorage.js.map +1 -0
- package/lib/commonjs/lib/storage/StorageBlueprint.js +24 -0
- package/lib/commonjs/lib/storage/StorageBlueprint.js.map +1 -0
- package/lib/commonjs/lib/storage/StorageManager.js +126 -0
- package/lib/commonjs/lib/storage/StorageManager.js.map +1 -0
- package/lib/commonjs/lib/storage/index.js +49 -0
- package/lib/commonjs/lib/storage/index.js.map +1 -0
- package/lib/commonjs/lib/storage/types.js +2 -0
- package/lib/commonjs/lib/storage/types.js.map +1 -0
- package/lib/commonjs/lib/wagmi/WagmiEventHandler.js +445 -0
- package/lib/commonjs/lib/wagmi/WagmiEventHandler.js.map +1 -0
- package/lib/commonjs/lib/wagmi/index.js +28 -0
- package/lib/commonjs/lib/wagmi/index.js.map +1 -0
- package/lib/commonjs/lib/wagmi/types.js +2 -0
- package/lib/commonjs/lib/wagmi/types.js.map +1 -0
- package/lib/commonjs/types/base.js +6 -0
- package/lib/commonjs/types/base.js.map +1 -0
- package/lib/commonjs/types/events.js +22 -0
- package/lib/commonjs/types/events.js.map +1 -0
- package/lib/commonjs/types/index.js +28 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/commonjs/utils/address.js +82 -0
- package/lib/commonjs/utils/address.js.map +1 -0
- package/lib/commonjs/utils/hash.js +30 -0
- package/lib/commonjs/utils/hash.js.map +1 -0
- package/lib/commonjs/utils/helpers.js +116 -0
- package/lib/commonjs/utils/helpers.js.map +1 -0
- package/lib/commonjs/utils/index.js +61 -0
- package/lib/commonjs/utils/index.js.map +1 -0
- package/lib/commonjs/utils/timestamp.js +34 -0
- package/lib/commonjs/utils/timestamp.js.map +1 -0
- package/lib/commonjs/utils/trafficSource.js +147 -0
- package/lib/commonjs/utils/trafficSource.js.map +1 -0
- package/lib/commonjs/version.js +10 -0
- package/lib/commonjs/version.js.map +1 -0
- package/lib/module/FormoAnalytics.js +519 -0
- package/lib/module/FormoAnalytics.js.map +1 -0
- package/lib/module/FormoAnalyticsProvider.js +256 -0
- package/lib/module/FormoAnalyticsProvider.js.map +1 -0
- package/lib/module/constants/config.js +62 -0
- package/lib/module/constants/config.js.map +1 -0
- package/lib/module/constants/events.js +24 -0
- package/lib/module/constants/events.js.map +1 -0
- package/lib/module/constants/index.js +4 -0
- package/lib/module/constants/index.js.map +1 -0
- package/lib/module/constants/storage.js +17 -0
- package/lib/module/constants/storage.js.map +1 -0
- package/lib/module/index.js +51 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/lib/consent/index.js +49 -0
- package/lib/module/lib/consent/index.js.map +1 -0
- package/lib/module/lib/event/EventFactory.js +488 -0
- package/lib/module/lib/event/EventFactory.js.map +1 -0
- package/lib/module/lib/event/EventManager.js +41 -0
- package/lib/module/lib/event/EventManager.js.map +1 -0
- package/lib/module/lib/event/EventQueue.js +283 -0
- package/lib/module/lib/event/EventQueue.js.map +1 -0
- package/lib/module/lib/event/index.js +5 -0
- package/lib/module/lib/event/index.js.map +1 -0
- package/lib/module/lib/event/types.js +2 -0
- package/lib/module/lib/event/types.js.map +1 -0
- package/lib/module/lib/lifecycle/index.js +190 -0
- package/lib/module/lib/lifecycle/index.js.map +1 -0
- package/lib/module/lib/logger/index.js +42 -0
- package/lib/module/lib/logger/index.js.map +1 -0
- package/lib/module/lib/session/index.js +92 -0
- package/lib/module/lib/session/index.js.map +1 -0
- package/lib/module/lib/storage/AsyncStorageAdapter.js +158 -0
- package/lib/module/lib/storage/AsyncStorageAdapter.js.map +1 -0
- package/lib/module/lib/storage/MemoryStorage.js +35 -0
- package/lib/module/lib/storage/MemoryStorage.js.map +1 -0
- package/lib/module/lib/storage/StorageBlueprint.js +18 -0
- package/lib/module/lib/storage/StorageBlueprint.js.map +1 -0
- package/lib/module/lib/storage/StorageManager.js +115 -0
- package/lib/module/lib/storage/StorageManager.js.map +1 -0
- package/lib/module/lib/storage/index.js +5 -0
- package/lib/module/lib/storage/index.js.map +1 -0
- package/lib/module/lib/storage/types.js +2 -0
- package/lib/module/lib/storage/types.js.map +1 -0
- package/lib/module/lib/wagmi/WagmiEventHandler.js +439 -0
- package/lib/module/lib/wagmi/WagmiEventHandler.js.map +1 -0
- package/lib/module/lib/wagmi/index.js +3 -0
- package/lib/module/lib/wagmi/index.js.map +1 -0
- package/lib/module/lib/wagmi/types.js +2 -0
- package/lib/module/lib/wagmi/types.js.map +1 -0
- package/lib/module/types/base.js +2 -0
- package/lib/module/types/base.js.map +1 -0
- package/lib/module/types/events.js +17 -0
- package/lib/module/types/events.js.map +1 -0
- package/lib/module/types/index.js +3 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/utils/address.js +74 -0
- package/lib/module/utils/address.js.map +1 -0
- package/lib/module/utils/hash.js +24 -0
- package/lib/module/utils/hash.js.map +1 -0
- package/lib/module/utils/helpers.js +105 -0
- package/lib/module/utils/helpers.js.map +1 -0
- package/lib/module/utils/index.js +6 -0
- package/lib/module/utils/index.js.map +1 -0
- package/lib/module/utils/timestamp.js +26 -0
- package/lib/module/utils/timestamp.js.map +1 -0
- package/lib/module/utils/trafficSource.js +137 -0
- package/lib/module/utils/trafficSource.js.map +1 -0
- package/lib/module/version.js +4 -0
- package/lib/module/version.js.map +1 -0
- package/lib/typescript/FormoAnalytics.d.ts +163 -0
- package/lib/typescript/FormoAnalytics.d.ts.map +1 -0
- package/lib/typescript/FormoAnalyticsProvider.d.ts +29 -0
- package/lib/typescript/FormoAnalyticsProvider.d.ts.map +1 -0
- package/lib/typescript/constants/config.d.ts +8 -0
- package/lib/typescript/constants/config.d.ts.map +1 -0
- package/lib/typescript/constants/events.d.ts +23 -0
- package/lib/typescript/constants/events.d.ts.map +1 -0
- package/lib/typescript/constants/index.d.ts +4 -0
- package/lib/typescript/constants/index.d.ts.map +1 -0
- package/lib/typescript/constants/storage.d.ts +10 -0
- package/lib/typescript/constants/storage.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +44 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/lib/consent/index.d.ts +13 -0
- package/lib/typescript/lib/consent/index.d.ts.map +1 -0
- package/lib/typescript/lib/event/EventFactory.d.ts +61 -0
- package/lib/typescript/lib/event/EventFactory.d.ts.map +1 -0
- package/lib/typescript/lib/event/EventManager.d.ts +17 -0
- package/lib/typescript/lib/event/EventManager.d.ts.map +1 -0
- package/lib/typescript/lib/event/EventQueue.d.ts +74 -0
- package/lib/typescript/lib/event/EventQueue.d.ts.map +1 -0
- package/lib/typescript/lib/event/index.d.ts +5 -0
- package/lib/typescript/lib/event/index.d.ts.map +1 -0
- package/lib/typescript/lib/event/types.d.ts +23 -0
- package/lib/typescript/lib/event/types.d.ts.map +1 -0
- package/lib/typescript/lib/lifecycle/index.d.ts +46 -0
- package/lib/typescript/lib/lifecycle/index.d.ts.map +1 -0
- package/lib/typescript/lib/logger/index.d.ts +19 -0
- package/lib/typescript/lib/logger/index.d.ts.map +1 -0
- package/lib/typescript/lib/session/index.d.ts +41 -0
- package/lib/typescript/lib/session/index.d.ts.map +1 -0
- package/lib/typescript/lib/storage/AsyncStorageAdapter.d.ts +48 -0
- package/lib/typescript/lib/storage/AsyncStorageAdapter.d.ts.map +1 -0
- package/lib/typescript/lib/storage/MemoryStorage.d.ts +18 -0
- package/lib/typescript/lib/storage/MemoryStorage.d.ts.map +1 -0
- package/lib/typescript/lib/storage/StorageBlueprint.d.ts +21 -0
- package/lib/typescript/lib/storage/StorageBlueprint.d.ts.map +1 -0
- package/lib/typescript/lib/storage/StorageManager.d.ts +45 -0
- package/lib/typescript/lib/storage/StorageManager.d.ts.map +1 -0
- package/lib/typescript/lib/storage/index.d.ts +5 -0
- package/lib/typescript/lib/storage/index.d.ts.map +1 -0
- package/lib/typescript/lib/storage/types.d.ts +22 -0
- package/lib/typescript/lib/storage/types.d.ts.map +1 -0
- package/lib/typescript/lib/wagmi/WagmiEventHandler.d.ts +104 -0
- package/lib/typescript/lib/wagmi/WagmiEventHandler.d.ts.map +1 -0
- package/lib/typescript/lib/wagmi/index.d.ts +3 -0
- package/lib/typescript/lib/wagmi/index.d.ts.map +1 -0
- package/lib/typescript/lib/wagmi/types.d.ts +54 -0
- package/lib/typescript/lib/wagmi/types.d.ts.map +1 -0
- package/lib/typescript/types/base.d.ts +219 -0
- package/lib/typescript/types/base.d.ts.map +1 -0
- package/lib/typescript/types/events.d.ts +111 -0
- package/lib/typescript/types/events.d.ts.map +1 -0
- package/lib/typescript/types/index.d.ts +3 -0
- package/lib/typescript/types/index.d.ts.map +1 -0
- package/lib/typescript/utils/address.d.ts +25 -0
- package/lib/typescript/utils/address.d.ts.map +1 -0
- package/lib/typescript/utils/hash.d.ts +10 -0
- package/lib/typescript/utils/hash.d.ts.map +1 -0
- package/lib/typescript/utils/helpers.d.ts +26 -0
- package/lib/typescript/utils/helpers.d.ts.map +1 -0
- package/lib/typescript/utils/index.d.ts +6 -0
- package/lib/typescript/utils/index.d.ts.map +1 -0
- package/lib/typescript/utils/timestamp.d.ts +13 -0
- package/lib/typescript/utils/timestamp.d.ts.map +1 -0
- package/lib/typescript/utils/trafficSource.d.ts +30 -0
- package/lib/typescript/utils/trafficSource.d.ts.map +1 -0
- package/lib/typescript/version.d.ts +2 -0
- package/lib/typescript/version.d.ts.map +1 -0
- package/package.json +143 -0
- package/src/FormoAnalytics.ts +685 -0
- package/src/FormoAnalyticsProvider.tsx +296 -0
- package/src/constants/config.ts +62 -0
- package/src/constants/events.ts +26 -0
- package/src/constants/index.ts +3 -0
- package/src/constants/storage.ts +16 -0
- package/src/index.ts +55 -0
- package/src/lib/consent/index.ts +52 -0
- package/src/lib/event/EventFactory.ts +682 -0
- package/src/lib/event/EventManager.ts +50 -0
- package/src/lib/event/EventQueue.ts +371 -0
- package/src/lib/event/index.ts +4 -0
- package/src/lib/event/types.ts +107 -0
- package/src/lib/lifecycle/index.ts +215 -0
- package/src/lib/logger/index.ts +56 -0
- package/src/lib/session/index.ts +103 -0
- package/src/lib/storage/AsyncStorageAdapter.ts +173 -0
- package/src/lib/storage/MemoryStorage.ts +43 -0
- package/src/lib/storage/StorageBlueprint.ts +30 -0
- package/src/lib/storage/StorageManager.ts +121 -0
- package/src/lib/storage/index.ts +4 -0
- package/src/lib/storage/types.ts +23 -0
- package/src/lib/wagmi/WagmiEventHandler.ts +574 -0
- package/src/lib/wagmi/index.ts +2 -0
- package/src/lib/wagmi/types.ts +71 -0
- package/src/types/base.ts +287 -0
- package/src/types/events.ts +140 -0
- package/src/types/index.ts +2 -0
- package/src/utils/address.ts +84 -0
- package/src/utils/hash.ts +23 -0
- package/src/utils/helpers.ts +139 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/timestamp.ts +25 -0
- package/src/utils/trafficSource.ts +153 -0
- package/src/version.ts +3 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WagmiEventHandler for React Native
|
|
3
|
+
*
|
|
4
|
+
* Handles wallet event tracking by hooking into Wagmi v2's config.subscribe()
|
|
5
|
+
* and TanStack Query's MutationCache.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { SignatureStatus, TransactionStatus } from "../../types/events";
|
|
9
|
+
import { logger } from "../logger";
|
|
10
|
+
import {
|
|
11
|
+
WagmiConfig,
|
|
12
|
+
WagmiState,
|
|
13
|
+
QueryClient,
|
|
14
|
+
MutationCacheEvent,
|
|
15
|
+
UnsubscribeFn,
|
|
16
|
+
WagmiTrackingState,
|
|
17
|
+
WagmiMutationKey,
|
|
18
|
+
} from "./types";
|
|
19
|
+
|
|
20
|
+
// Interface for FormoAnalytics to avoid circular dependency
|
|
21
|
+
interface IFormoAnalyticsInstance {
|
|
22
|
+
connect(
|
|
23
|
+
params: { chainId: number; address: string },
|
|
24
|
+
properties?: Record<string, unknown>
|
|
25
|
+
): Promise<void>;
|
|
26
|
+
disconnect(params?: {
|
|
27
|
+
chainId?: number;
|
|
28
|
+
address?: string;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
chain(params: { chainId: number; address?: string }): Promise<void>;
|
|
31
|
+
signature(params: {
|
|
32
|
+
status: SignatureStatus;
|
|
33
|
+
chainId: number;
|
|
34
|
+
address: string;
|
|
35
|
+
message: string;
|
|
36
|
+
signatureHash?: string;
|
|
37
|
+
}): Promise<void>;
|
|
38
|
+
transaction(params: {
|
|
39
|
+
status: TransactionStatus;
|
|
40
|
+
chainId: number;
|
|
41
|
+
address: string;
|
|
42
|
+
data?: string;
|
|
43
|
+
to?: string;
|
|
44
|
+
value?: string;
|
|
45
|
+
transactionHash?: string;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
isAutocaptureEnabled(
|
|
48
|
+
eventType: "connect" | "disconnect" | "signature" | "transaction" | "chain"
|
|
49
|
+
): boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class WagmiEventHandler {
|
|
53
|
+
private formo: IFormoAnalyticsInstance;
|
|
54
|
+
private wagmiConfig: WagmiConfig;
|
|
55
|
+
private queryClient?: QueryClient;
|
|
56
|
+
private unsubscribers: UnsubscribeFn[] = [];
|
|
57
|
+
private trackingState: WagmiTrackingState = {
|
|
58
|
+
isProcessing: false,
|
|
59
|
+
};
|
|
60
|
+
private processedMutations = new Set<string>();
|
|
61
|
+
private pendingStatusChanges: Array<{
|
|
62
|
+
status: WagmiState["status"];
|
|
63
|
+
prevStatus: WagmiState["status"];
|
|
64
|
+
}> = [];
|
|
65
|
+
|
|
66
|
+
constructor(
|
|
67
|
+
formoAnalytics: IFormoAnalyticsInstance,
|
|
68
|
+
wagmiConfig: WagmiConfig,
|
|
69
|
+
queryClient?: QueryClient
|
|
70
|
+
) {
|
|
71
|
+
this.formo = formoAnalytics;
|
|
72
|
+
this.wagmiConfig = wagmiConfig;
|
|
73
|
+
this.queryClient = queryClient;
|
|
74
|
+
|
|
75
|
+
logger.info("WagmiEventHandler: Initializing Wagmi integration");
|
|
76
|
+
|
|
77
|
+
this.setupConnectionListeners();
|
|
78
|
+
|
|
79
|
+
if (this.queryClient) {
|
|
80
|
+
this.setupMutationTracking();
|
|
81
|
+
} else {
|
|
82
|
+
logger.warn(
|
|
83
|
+
"WagmiEventHandler: QueryClient not provided, signature and transaction events will not be tracked"
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Set up listeners for wallet connection, disconnection, and chain changes
|
|
90
|
+
*/
|
|
91
|
+
private setupConnectionListeners(): void {
|
|
92
|
+
logger.info("WagmiEventHandler: Setting up connection listeners");
|
|
93
|
+
|
|
94
|
+
// Subscribe to status changes
|
|
95
|
+
const statusUnsubscribe = this.wagmiConfig.subscribe(
|
|
96
|
+
(state: WagmiState) => state.status,
|
|
97
|
+
(status, prevStatus) => {
|
|
98
|
+
this.handleStatusChange(status, prevStatus);
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
this.unsubscribers.push(statusUnsubscribe);
|
|
102
|
+
|
|
103
|
+
// Subscribe to chain ID changes
|
|
104
|
+
const chainIdUnsubscribe = this.wagmiConfig.subscribe(
|
|
105
|
+
(state: WagmiState) => state.chainId,
|
|
106
|
+
(chainId, prevChainId) => {
|
|
107
|
+
this.handleChainChange(chainId, prevChainId);
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
this.unsubscribers.push(chainIdUnsubscribe);
|
|
111
|
+
|
|
112
|
+
logger.info("WagmiEventHandler: Connection listeners set up successfully");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Maximum pending status changes to prevent unbounded queue growth
|
|
116
|
+
private static readonly MAX_PENDING_STATUS_CHANGES = 10;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Handle status changes (connect/disconnect)
|
|
120
|
+
*/
|
|
121
|
+
private async handleStatusChange(
|
|
122
|
+
status: WagmiState["status"],
|
|
123
|
+
prevStatus: WagmiState["status"]
|
|
124
|
+
): Promise<void> {
|
|
125
|
+
if (this.trackingState.isProcessing) {
|
|
126
|
+
// Limit queue size to prevent unbounded growth during rapid status changes
|
|
127
|
+
if (this.pendingStatusChanges.length >= WagmiEventHandler.MAX_PENDING_STATUS_CHANGES) {
|
|
128
|
+
logger.warn("WagmiEventHandler: Pending status change queue full, dropping oldest");
|
|
129
|
+
this.pendingStatusChanges.shift();
|
|
130
|
+
}
|
|
131
|
+
// Queue status change to process after current one completes
|
|
132
|
+
this.pendingStatusChanges.push({ status, prevStatus });
|
|
133
|
+
logger.debug(
|
|
134
|
+
"WagmiEventHandler: Queuing status change for later processing"
|
|
135
|
+
);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this.trackingState.isProcessing = true;
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
// Process current status change
|
|
143
|
+
await this.processStatusChange(status, prevStatus);
|
|
144
|
+
|
|
145
|
+
// Process pending status changes iteratively (inline, no recursion)
|
|
146
|
+
while (this.pendingStatusChanges.length > 0) {
|
|
147
|
+
const pending = this.pendingStatusChanges.shift()!;
|
|
148
|
+
await this.processStatusChange(pending.status, pending.prevStatus);
|
|
149
|
+
}
|
|
150
|
+
} finally {
|
|
151
|
+
this.trackingState.isProcessing = false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Process a single status change (extracted for iterative processing)
|
|
157
|
+
*/
|
|
158
|
+
private async processStatusChange(
|
|
159
|
+
status: WagmiState["status"],
|
|
160
|
+
prevStatus: WagmiState["status"]
|
|
161
|
+
): Promise<void> {
|
|
162
|
+
try {
|
|
163
|
+
const state = this.getState();
|
|
164
|
+
const address = this.getConnectedAddress(state);
|
|
165
|
+
const chainId = state.chainId;
|
|
166
|
+
|
|
167
|
+
logger.info("WagmiEventHandler: Status changed", {
|
|
168
|
+
status,
|
|
169
|
+
prevStatus,
|
|
170
|
+
address,
|
|
171
|
+
chainId,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Handle disconnect
|
|
175
|
+
if (status === "disconnected" && prevStatus === "connected") {
|
|
176
|
+
if (this.formo.isAutocaptureEnabled("disconnect")) {
|
|
177
|
+
await this.formo.disconnect({
|
|
178
|
+
chainId: this.trackingState.lastChainId,
|
|
179
|
+
address: this.trackingState.lastAddress,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
this.trackingState.lastAddress = undefined;
|
|
183
|
+
this.trackingState.lastChainId = undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Handle connect
|
|
187
|
+
if (status === "connected" && prevStatus !== "connected") {
|
|
188
|
+
if (address && chainId !== undefined) {
|
|
189
|
+
this.trackingState.lastAddress = address;
|
|
190
|
+
this.trackingState.lastChainId = chainId;
|
|
191
|
+
|
|
192
|
+
if (this.formo.isAutocaptureEnabled("connect")) {
|
|
193
|
+
const connectorName = this.getConnectorName(state);
|
|
194
|
+
const connectorId = this.getConnectorId(state);
|
|
195
|
+
await this.formo.connect(
|
|
196
|
+
{ chainId, address },
|
|
197
|
+
{
|
|
198
|
+
...(connectorName && { providerName: connectorName }),
|
|
199
|
+
// Connector ID is typically the rdns for EIP-6963 wallets
|
|
200
|
+
...(connectorId && { rdns: connectorId }),
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.trackingState.lastStatus = status;
|
|
208
|
+
} catch (error) {
|
|
209
|
+
logger.error("WagmiEventHandler: Error handling status change:", error);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Handle chain ID changes
|
|
215
|
+
*/
|
|
216
|
+
private async handleChainChange(
|
|
217
|
+
chainId: number | undefined,
|
|
218
|
+
prevChainId: number | undefined
|
|
219
|
+
): Promise<void> {
|
|
220
|
+
// Skip if no change, chainId is undefined, or this is initial connection (prevChainId undefined)
|
|
221
|
+
if (chainId === prevChainId || chainId === undefined || prevChainId === undefined) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const state = this.getState();
|
|
226
|
+
if (state.status !== "connected") {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const address = this.getConnectedAddress(state);
|
|
231
|
+
if (!address) {
|
|
232
|
+
logger.warn("WagmiEventHandler: Chain changed but no address found");
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
logger.info("WagmiEventHandler: Chain changed", {
|
|
237
|
+
chainId,
|
|
238
|
+
prevChainId,
|
|
239
|
+
address,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
this.trackingState.lastChainId = chainId;
|
|
243
|
+
|
|
244
|
+
if (this.formo.isAutocaptureEnabled("chain")) {
|
|
245
|
+
try {
|
|
246
|
+
await this.formo.chain({ chainId, address });
|
|
247
|
+
} catch (error) {
|
|
248
|
+
logger.error("WagmiEventHandler: Error tracking chain change:", error);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Set up mutation tracking for signatures and transactions
|
|
255
|
+
*/
|
|
256
|
+
private setupMutationTracking(): void {
|
|
257
|
+
if (!this.queryClient) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
logger.info("WagmiEventHandler: Setting up mutation tracking");
|
|
262
|
+
|
|
263
|
+
const mutationCache = this.queryClient.getMutationCache();
|
|
264
|
+
const unsubscribe = mutationCache.subscribe((event: MutationCacheEvent) => {
|
|
265
|
+
this.handleMutationEvent(event);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
this.unsubscribers.push(unsubscribe);
|
|
269
|
+
logger.info("WagmiEventHandler: Mutation tracking set up successfully");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Handle mutation cache events
|
|
274
|
+
*/
|
|
275
|
+
private handleMutationEvent(event: MutationCacheEvent): void {
|
|
276
|
+
if (event.type !== "updated") {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const mutation = event.mutation;
|
|
281
|
+
const mutationKey = mutation.options.mutationKey;
|
|
282
|
+
|
|
283
|
+
if (!mutationKey || mutationKey.length === 0) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const mutationType = mutationKey[0] as string;
|
|
288
|
+
const state = mutation.state;
|
|
289
|
+
|
|
290
|
+
const mutationStateKey = `${mutation.mutationId}:${state.status}`;
|
|
291
|
+
|
|
292
|
+
if (this.processedMutations.has(mutationStateKey)) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
this.processedMutations.add(mutationStateKey);
|
|
297
|
+
|
|
298
|
+
logger.debug("WagmiEventHandler: Mutation event", {
|
|
299
|
+
mutationType,
|
|
300
|
+
mutationId: mutation.mutationId,
|
|
301
|
+
status: state.status,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (mutationType === "signMessage" || mutationType === "signTypedData") {
|
|
305
|
+
this.handleSignatureMutation(
|
|
306
|
+
mutationType as WagmiMutationKey,
|
|
307
|
+
mutation
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (
|
|
312
|
+
mutationType === "sendTransaction" ||
|
|
313
|
+
mutationType === "writeContract"
|
|
314
|
+
) {
|
|
315
|
+
this.handleTransactionMutation(
|
|
316
|
+
mutationType as WagmiMutationKey,
|
|
317
|
+
mutation
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Cleanup old mutations
|
|
322
|
+
if (this.processedMutations.size > 1000) {
|
|
323
|
+
const entries = Array.from(this.processedMutations);
|
|
324
|
+
for (let i = 0; i < 500; i++) {
|
|
325
|
+
const entry = entries[i];
|
|
326
|
+
if (entry) {
|
|
327
|
+
this.processedMutations.delete(entry);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Handle signature mutations
|
|
335
|
+
*/
|
|
336
|
+
private handleSignatureMutation(
|
|
337
|
+
mutationType: WagmiMutationKey,
|
|
338
|
+
mutation: MutationCacheEvent["mutation"]
|
|
339
|
+
): void {
|
|
340
|
+
if (!this.formo.isAutocaptureEnabled("signature")) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const state = mutation.state;
|
|
345
|
+
const variables = state.variables || {};
|
|
346
|
+
const chainId = this.trackingState.lastChainId;
|
|
347
|
+
const address = this.trackingState.lastAddress;
|
|
348
|
+
|
|
349
|
+
if (!address) {
|
|
350
|
+
logger.warn(
|
|
351
|
+
"WagmiEventHandler: Signature event but no address available"
|
|
352
|
+
);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (!chainId || chainId === 0) {
|
|
357
|
+
logger.warn(
|
|
358
|
+
"WagmiEventHandler: Signature event but no valid chainId available"
|
|
359
|
+
);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
let status: SignatureStatus;
|
|
365
|
+
let signatureHash: string | undefined;
|
|
366
|
+
|
|
367
|
+
if (state.status === "pending") {
|
|
368
|
+
status = SignatureStatus.REQUESTED;
|
|
369
|
+
} else if (state.status === "success") {
|
|
370
|
+
status = SignatureStatus.CONFIRMED;
|
|
371
|
+
signatureHash = state.data as string;
|
|
372
|
+
} else if (state.status === "error") {
|
|
373
|
+
status = SignatureStatus.REJECTED;
|
|
374
|
+
} else {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
let message: string;
|
|
379
|
+
if (mutationType === "signMessage") {
|
|
380
|
+
message = (variables.message as string) || "";
|
|
381
|
+
} else {
|
|
382
|
+
message = JSON.stringify(variables.message || variables.types || {});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
logger.info("WagmiEventHandler: Tracking signature event", {
|
|
386
|
+
status,
|
|
387
|
+
mutationType,
|
|
388
|
+
address,
|
|
389
|
+
chainId,
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
this.formo.signature({
|
|
393
|
+
status,
|
|
394
|
+
chainId,
|
|
395
|
+
address,
|
|
396
|
+
message,
|
|
397
|
+
...(signatureHash && { signatureHash }),
|
|
398
|
+
}).catch((error) => {
|
|
399
|
+
logger.error("WagmiEventHandler: Error tracking signature:", error);
|
|
400
|
+
});
|
|
401
|
+
} catch (error) {
|
|
402
|
+
logger.error(
|
|
403
|
+
"WagmiEventHandler: Error handling signature mutation:",
|
|
404
|
+
error
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Handle transaction mutations
|
|
411
|
+
*/
|
|
412
|
+
private handleTransactionMutation(
|
|
413
|
+
mutationType: WagmiMutationKey,
|
|
414
|
+
mutation: MutationCacheEvent["mutation"]
|
|
415
|
+
): void {
|
|
416
|
+
if (!this.formo.isAutocaptureEnabled("transaction")) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const state = mutation.state;
|
|
421
|
+
const variables = state.variables || {};
|
|
422
|
+
const chainId =
|
|
423
|
+
this.trackingState.lastChainId ||
|
|
424
|
+
(variables.chainId as number | undefined);
|
|
425
|
+
// Only use variables.account as fallback, not variables.address which is the contract address
|
|
426
|
+
const address =
|
|
427
|
+
this.trackingState.lastAddress ||
|
|
428
|
+
(variables.account as string | undefined);
|
|
429
|
+
|
|
430
|
+
if (!address) {
|
|
431
|
+
logger.warn(
|
|
432
|
+
"WagmiEventHandler: Transaction event but no address available"
|
|
433
|
+
);
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!chainId || chainId === 0) {
|
|
438
|
+
logger.warn(
|
|
439
|
+
"WagmiEventHandler: Transaction event but no valid chainId available"
|
|
440
|
+
);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
let status: TransactionStatus;
|
|
446
|
+
let transactionHash: string | undefined;
|
|
447
|
+
|
|
448
|
+
if (state.status === "pending") {
|
|
449
|
+
status = TransactionStatus.STARTED;
|
|
450
|
+
} else if (state.status === "success") {
|
|
451
|
+
status = TransactionStatus.BROADCASTED;
|
|
452
|
+
transactionHash = state.data as string;
|
|
453
|
+
} else if (state.status === "error") {
|
|
454
|
+
status = TransactionStatus.REJECTED;
|
|
455
|
+
} else {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const data = variables.data as string | undefined;
|
|
460
|
+
const to =
|
|
461
|
+
(variables.to as string | undefined) ||
|
|
462
|
+
(variables.address as string | undefined);
|
|
463
|
+
const value = variables.value?.toString();
|
|
464
|
+
|
|
465
|
+
logger.info("WagmiEventHandler: Tracking transaction event", {
|
|
466
|
+
status,
|
|
467
|
+
mutationType,
|
|
468
|
+
address,
|
|
469
|
+
chainId,
|
|
470
|
+
transactionHash,
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
this.formo.transaction({
|
|
474
|
+
status,
|
|
475
|
+
chainId,
|
|
476
|
+
address,
|
|
477
|
+
...(data && { data }),
|
|
478
|
+
...(to && { to }),
|
|
479
|
+
...(value && { value }),
|
|
480
|
+
...(transactionHash && { transactionHash }),
|
|
481
|
+
}).catch((error) => {
|
|
482
|
+
logger.error("WagmiEventHandler: Error tracking transaction:", error);
|
|
483
|
+
});
|
|
484
|
+
} catch (error) {
|
|
485
|
+
logger.error(
|
|
486
|
+
"WagmiEventHandler: Error handling transaction mutation:",
|
|
487
|
+
error
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Get current Wagmi state
|
|
494
|
+
*/
|
|
495
|
+
private getState(): WagmiState {
|
|
496
|
+
if (typeof this.wagmiConfig.getState === "function") {
|
|
497
|
+
return this.wagmiConfig.getState();
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (this.wagmiConfig.state) {
|
|
501
|
+
return this.wagmiConfig.state;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
logger.warn(
|
|
505
|
+
"WagmiEventHandler: Unable to get state from config, returning default state"
|
|
506
|
+
);
|
|
507
|
+
return {
|
|
508
|
+
status: "disconnected",
|
|
509
|
+
connections: new Map(),
|
|
510
|
+
current: undefined,
|
|
511
|
+
chainId: undefined,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Get connected address from state
|
|
517
|
+
*/
|
|
518
|
+
private getConnectedAddress(state: WagmiState): string | undefined {
|
|
519
|
+
if (!state.current) {
|
|
520
|
+
return undefined;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const connection = state.connections.get(state.current);
|
|
524
|
+
if (!connection || connection.accounts.length === 0) {
|
|
525
|
+
return undefined;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return connection.accounts[0];
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Get connector name from state
|
|
533
|
+
*/
|
|
534
|
+
private getConnectorName(state: WagmiState): string | undefined {
|
|
535
|
+
if (!state.current) {
|
|
536
|
+
return undefined;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const connection = state.connections.get(state.current);
|
|
540
|
+
return connection?.connector.name;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Get connector ID from state (typically the rdns for EIP-6963 wallets)
|
|
545
|
+
*/
|
|
546
|
+
private getConnectorId(state: WagmiState): string | undefined {
|
|
547
|
+
if (!state.current) {
|
|
548
|
+
return undefined;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const connection = state.connections.get(state.current);
|
|
552
|
+
return connection?.connector.id;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Clean up subscriptions
|
|
557
|
+
*/
|
|
558
|
+
public cleanup(): void {
|
|
559
|
+
logger.info("WagmiEventHandler: Cleaning up subscriptions");
|
|
560
|
+
|
|
561
|
+
for (const unsubscribe of this.unsubscribers) {
|
|
562
|
+
try {
|
|
563
|
+
unsubscribe();
|
|
564
|
+
} catch (error) {
|
|
565
|
+
logger.error("WagmiEventHandler: Error during cleanup:", error);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
this.unsubscribers = [];
|
|
570
|
+
this.processedMutations.clear();
|
|
571
|
+
this.pendingStatusChanges = [];
|
|
572
|
+
logger.info("WagmiEventHandler: Cleanup complete");
|
|
573
|
+
}
|
|
574
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wagmi types for React Native SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface WagmiState {
|
|
6
|
+
status: "connecting" | "connected" | "disconnected" | "reconnecting";
|
|
7
|
+
connections: Map<
|
|
8
|
+
string,
|
|
9
|
+
{
|
|
10
|
+
accounts: readonly string[];
|
|
11
|
+
chainId: number;
|
|
12
|
+
connector: {
|
|
13
|
+
name: string;
|
|
14
|
+
/** Connector ID - for EIP-6963 injected wallets, this is typically the rdns */
|
|
15
|
+
id: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
icon?: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
>;
|
|
21
|
+
current?: string;
|
|
22
|
+
chainId?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface WagmiConfig {
|
|
26
|
+
subscribe: <T>(
|
|
27
|
+
selector: (state: WagmiState) => T,
|
|
28
|
+
listener: (selectedState: T, prevSelectedState: T) => void
|
|
29
|
+
) => () => void;
|
|
30
|
+
getState?: () => WagmiState;
|
|
31
|
+
state?: WagmiState;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface QueryClient {
|
|
35
|
+
getMutationCache: () => MutationCache;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface MutationCache {
|
|
39
|
+
subscribe: (callback: (event: MutationCacheEvent) => void) => () => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface MutationCacheEvent {
|
|
43
|
+
type: "added" | "updated" | "removed";
|
|
44
|
+
mutation: {
|
|
45
|
+
mutationId: number;
|
|
46
|
+
options: {
|
|
47
|
+
mutationKey?: readonly string[];
|
|
48
|
+
};
|
|
49
|
+
state: {
|
|
50
|
+
status: "idle" | "pending" | "success" | "error";
|
|
51
|
+
data?: unknown;
|
|
52
|
+
error?: unknown;
|
|
53
|
+
variables?: Record<string, unknown>;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type UnsubscribeFn = () => void;
|
|
59
|
+
|
|
60
|
+
export interface WagmiTrackingState {
|
|
61
|
+
isProcessing: boolean;
|
|
62
|
+
lastAddress?: string;
|
|
63
|
+
lastChainId?: number;
|
|
64
|
+
lastStatus?: WagmiState["status"];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type WagmiMutationKey =
|
|
68
|
+
| "signMessage"
|
|
69
|
+
| "signTypedData"
|
|
70
|
+
| "sendTransaction"
|
|
71
|
+
| "writeContract";
|