@formo/analytics 1.11.5-alpha.4 → 1.11.6
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 +131 -39
- package/dist/cjs/src/FormoAnalytics.d.ts +72 -2
- package/dist/cjs/src/FormoAnalytics.d.ts.map +1 -1
- package/dist/cjs/src/FormoAnalytics.js +282 -5
- package/dist/cjs/src/FormoAnalytics.js.map +1 -1
- package/dist/cjs/src/constants/events.d.ts +8 -0
- package/dist/cjs/src/constants/events.d.ts.map +1 -0
- package/dist/cjs/src/constants/events.js +12 -0
- package/dist/cjs/src/constants/events.js.map +1 -0
- package/dist/cjs/src/constants/index.d.ts +1 -0
- package/dist/cjs/src/constants/index.d.ts.map +1 -1
- package/dist/cjs/src/constants/index.js +1 -0
- package/dist/cjs/src/constants/index.js.map +1 -1
- package/dist/cjs/src/types/base.d.ts +1 -0
- package/dist/cjs/src/types/base.d.ts.map +1 -1
- package/dist/cjs/src/types/index.d.ts +1 -0
- package/dist/cjs/src/types/index.d.ts.map +1 -1
- package/dist/cjs/src/types/index.js +1 -0
- package/dist/cjs/src/types/index.js.map +1 -1
- package/dist/cjs/src/types/wallet.d.ts +11 -0
- package/dist/cjs/src/types/wallet.d.ts.map +1 -0
- package/dist/cjs/src/types/wallet.js +3 -0
- package/dist/cjs/src/types/wallet.js.map +1 -0
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/src/FormoAnalytics.d.ts +72 -2
- package/dist/esm/src/FormoAnalytics.d.ts.map +1 -1
- package/dist/esm/src/FormoAnalytics.js +283 -6
- package/dist/esm/src/FormoAnalytics.js.map +1 -1
- package/dist/esm/src/constants/events.d.ts +8 -0
- package/dist/esm/src/constants/events.d.ts.map +1 -0
- package/dist/esm/src/constants/events.js +9 -0
- package/dist/esm/src/constants/events.js.map +1 -0
- package/dist/esm/src/constants/index.d.ts +1 -0
- package/dist/esm/src/constants/index.d.ts.map +1 -1
- package/dist/esm/src/constants/index.js +1 -0
- package/dist/esm/src/constants/index.js.map +1 -1
- package/dist/esm/src/types/base.d.ts +1 -0
- package/dist/esm/src/types/base.d.ts.map +1 -1
- package/dist/esm/src/types/index.d.ts +1 -0
- package/dist/esm/src/types/index.d.ts.map +1 -1
- package/dist/esm/src/types/index.js +1 -0
- package/dist/esm/src/types/index.js.map +1 -1
- package/dist/esm/src/types/wallet.d.ts +11 -0
- package/dist/esm/src/types/wallet.d.ts.map +1 -0
- package/dist/esm/src/types/wallet.js +2 -0
- package/dist/esm/src/types/wallet.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/index.umd.min.js +1 -1
- package/dist/index.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/FormoAnalytics.ts +322 -6
- package/src/constants/events.ts +7 -0
- package/src/constants/index.ts +1 -0
- package/src/global.d.ts +4 -0
- package/src/types/base.ts +2 -0
- package/src/types/index.ts +1 -0
- package/src/types/wallet.ts +12 -0
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Add the following to your
|
|
7
|
+
Add the following to your page:
|
|
8
8
|
|
|
9
9
|
```html
|
|
10
10
|
<script>
|
|
@@ -33,21 +33,96 @@ Add the following to your `index.html`:
|
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
-
###
|
|
36
|
+
### React Application
|
|
37
37
|
|
|
38
|
-
Install
|
|
38
|
+
**1. Install the SDK**
|
|
39
|
+
Install the Formo Analytics SDK using Yarn or NPM:
|
|
39
40
|
|
|
40
|
-
```
|
|
41
|
+
```jsx
|
|
41
42
|
yarn add @formo/analytics
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
or
|
|
45
46
|
|
|
47
|
+
```jsx
|
|
48
|
+
npm install @formo/analytics --save
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**2. Set up FormoAnalyticsProvider in Your Application**
|
|
52
|
+
|
|
53
|
+
Wrap your entire React application in the `FormoAnalyticsProvider` provided by the SDK.
|
|
54
|
+
|
|
55
|
+
```jsx
|
|
56
|
+
//App.tsx (or App.js)
|
|
57
|
+
import React from 'react';
|
|
58
|
+
import ReactDOM from 'react-dom/client';
|
|
59
|
+
import { FormoAnalyticsProvider } from '@formo/analytics';
|
|
60
|
+
import App from './App';
|
|
61
|
+
|
|
62
|
+
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
|
63
|
+
|
|
64
|
+
root.render(
|
|
65
|
+
<React.StrictMode>
|
|
66
|
+
<FormoAnalyticsProvider apiKey="YOUR_API_KEY" projectId="YOUR_PROJECT_ID">
|
|
67
|
+
<App />
|
|
68
|
+
</FormoAnalyticsProvider>
|
|
69
|
+
</React.StrictMode>
|
|
70
|
+
);
|
|
46
71
|
```
|
|
72
|
+
|
|
73
|
+
**3. Tracking Events and Page Views**
|
|
74
|
+
|
|
75
|
+
You can use the `useFormoAnalytics` hook from the SDK to track user interactions and page views.
|
|
76
|
+
|
|
77
|
+
Example: Tracking a Page View and Custom Event
|
|
78
|
+
|
|
79
|
+
```jsx
|
|
80
|
+
import React, { useEffect } from 'react';
|
|
81
|
+
import { useFormoAnalytics } from '@formo/analytics';
|
|
82
|
+
|
|
83
|
+
const HomePage = () => {
|
|
84
|
+
const analytics = useFormoAnalytics();
|
|
85
|
+
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
// Track a custom event
|
|
88
|
+
analytics?.track('custom_event', { key: 'value' });
|
|
89
|
+
}, [analytics]);
|
|
90
|
+
|
|
91
|
+
return <div>Welcome to the Home Page!</div>;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export default HomePage;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**4. Folder Structure Example**
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
/src
|
|
101
|
+
├── /components
|
|
102
|
+
│ └── HomePage.tsx
|
|
103
|
+
├── /App.tsx
|
|
104
|
+
└── /index.tsx (or index.js)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### Next.js Application
|
|
110
|
+
|
|
111
|
+
**1. Install the npm package:**
|
|
112
|
+
|
|
113
|
+
Install `@formo/analytics` via yarn or npm:
|
|
114
|
+
|
|
115
|
+
```jsx
|
|
116
|
+
yarn add @formo/analytics
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
or
|
|
120
|
+
|
|
121
|
+
```jsx
|
|
47
122
|
npm install @formo/analytics --save
|
|
48
123
|
```
|
|
49
124
|
|
|
50
|
-
|
|
125
|
+
**2. Set up the `FormoAnalyticsProvider` in your application:**
|
|
51
126
|
|
|
52
127
|
```jsx
|
|
53
128
|
// AnalyticsProvider.tsx
|
|
@@ -69,32 +144,6 @@ export const AnalyticsProvider: FC<FormoAnalyticsProviderProps> = ({
|
|
|
69
144
|
projectId,
|
|
70
145
|
children,
|
|
71
146
|
}) => {
|
|
72
|
-
// Initialize the FormoAnalytics SDK inside useEffect
|
|
73
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
74
|
-
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
const initialize = async () => {
|
|
77
|
-
try {
|
|
78
|
-
await FormoAnalytics.init(apiKey, projectId);
|
|
79
|
-
console.log('FormoAnalytics SDK initialized');
|
|
80
|
-
setIsInitialized(true);
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error('Failed to initialize FormoAnalytics SDK', error);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
initialize();
|
|
87
|
-
}, [apiKey, projectId]);
|
|
88
|
-
|
|
89
|
-
// To prevent app crashes, render a loading state during initialization
|
|
90
|
-
if (!isInitialized) {
|
|
91
|
-
return (
|
|
92
|
-
<FormoAnalyticsProvider apiKey={apiKey} projectId={projectId}>
|
|
93
|
-
Loading Content
|
|
94
|
-
</FormoAnalyticsProvider>
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
147
|
return (
|
|
99
148
|
<FormoAnalyticsProvider apiKey={apiKey} projectId={projectId}>
|
|
100
149
|
{children}
|
|
@@ -105,7 +154,7 @@ export const AnalyticsProvider: FC<FormoAnalyticsProviderProps> = ({
|
|
|
105
154
|
export default AnalyticsProvider;
|
|
106
155
|
```
|
|
107
156
|
|
|
108
|
-
|
|
157
|
+
**3. Integrating the Provider in Your Root Layout**
|
|
109
158
|
|
|
110
159
|
Wrap your application with the newly created `AnalyticsProvider` in your main layout file:
|
|
111
160
|
|
|
@@ -129,7 +178,7 @@ export default function RootLayout({
|
|
|
129
178
|
}
|
|
130
179
|
```
|
|
131
180
|
|
|
132
|
-
|
|
181
|
+
**4. Using the SDK**
|
|
133
182
|
|
|
134
183
|
Once the SDK is initialized, you can use its methods to track events and user interactions. Here’s how to do that:
|
|
135
184
|
|
|
@@ -144,7 +193,6 @@ const YourComponent = () => {
|
|
|
144
193
|
const track = async () => {
|
|
145
194
|
try {
|
|
146
195
|
console.log('Tracking page hit...');
|
|
147
|
-
analytics.page(); // Track the page view
|
|
148
196
|
analytics.track('custom_event', { key: 'value' }); // Track a custom event
|
|
149
197
|
} catch (error) {
|
|
150
198
|
console.error('Failed to track page hit', error);
|
|
@@ -158,10 +206,54 @@ const YourComponent = () => {
|
|
|
158
206
|
};
|
|
159
207
|
```
|
|
160
208
|
|
|
161
|
-
# Development
|
|
209
|
+
# Development Notes
|
|
210
|
+
|
|
211
|
+
If you want to contribute or run a local version of the Formo Analytics SDK, follow these steps:
|
|
212
|
+
|
|
213
|
+
1. Build the SDK Locally
|
|
214
|
+
|
|
215
|
+
Run the following command to build both CommonJS and ESM versions of the SDK:
|
|
216
|
+
|
|
217
|
+
```jsx
|
|
218
|
+
yarn build-cjs && yarn build-esm && yarn webpack --mode=production
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
or if you're using NPM:
|
|
222
|
+
|
|
223
|
+
```jsx
|
|
224
|
+
npm run build
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
2. Authenticate with NPM
|
|
228
|
+
|
|
229
|
+
To publish a new version of the package, log in to your NPM account:
|
|
230
|
+
|
|
231
|
+
```jsx
|
|
232
|
+
npm login
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
or:
|
|
236
|
+
|
|
237
|
+
```jsx
|
|
238
|
+
npm adduser
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
3. Publish the Package
|
|
242
|
+
|
|
243
|
+
Run the following command to publish the package to NPM:
|
|
244
|
+
|
|
245
|
+
```jsx
|
|
246
|
+
yarn publish
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
or:
|
|
250
|
+
|
|
251
|
+
```jsx
|
|
252
|
+
npm run publish
|
|
253
|
+
```
|
|
162
254
|
|
|
163
|
-
|
|
255
|
+
# Troubleshooting
|
|
164
256
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
257
|
+
**API Key Not Provided:** Ensure you pass a valid apiKey when initializing the SDK.
|
|
258
|
+
**SDK Not Initialized:** If you encounter issues with initialization, check the console logs for errors and ensure the project ID and API key are correct.
|
|
259
|
+
**Network Errors:** Verify that the analytics service URL is accessible from your network.
|
|
@@ -1,17 +1,57 @@
|
|
|
1
|
+
import { ChainID, EIP1193Provider } from './types';
|
|
1
2
|
interface IFormoAnalytics {
|
|
3
|
+
/**
|
|
4
|
+
* Initializes the FormoAnalytics instance with the provided API key and project ID.
|
|
5
|
+
*/
|
|
2
6
|
init(apiKey: string, projectId: string): Promise<FormoAnalytics>;
|
|
3
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Identifies the user with the provided user data.
|
|
9
|
+
*/
|
|
10
|
+
identify(userData: Record<string, any>): void;
|
|
11
|
+
/**
|
|
12
|
+
* Tracks page visit events.
|
|
13
|
+
*/
|
|
4
14
|
page(): void;
|
|
5
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Connects to a wallet with the specified chain ID and address.
|
|
17
|
+
*/
|
|
18
|
+
connect(params: {
|
|
19
|
+
account: string;
|
|
20
|
+
chainId: ChainID;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Disconnects the current wallet and clears the session information.
|
|
24
|
+
*/
|
|
25
|
+
disconnect(attributes?: {
|
|
26
|
+
account?: string;
|
|
27
|
+
chainId?: ChainID;
|
|
28
|
+
}): void;
|
|
29
|
+
/**
|
|
30
|
+
* Tracks a specific event with a name and associated data.
|
|
31
|
+
*/
|
|
32
|
+
track(eventName: string, eventData: Record<string, any>): void;
|
|
33
|
+
/**
|
|
34
|
+
* Switches the blockchain chain context and optionally logs additional attributes.
|
|
35
|
+
*/
|
|
36
|
+
chain(attributes: {
|
|
37
|
+
chainId: ChainID;
|
|
38
|
+
account?: string;
|
|
39
|
+
}): void;
|
|
6
40
|
}
|
|
7
41
|
export declare class FormoAnalytics implements IFormoAnalytics {
|
|
8
42
|
readonly apiKey: string;
|
|
9
43
|
projectId: string;
|
|
44
|
+
private _provider?;
|
|
45
|
+
private _registeredProviderListeners;
|
|
46
|
+
private sessionKey;
|
|
10
47
|
private config;
|
|
11
48
|
private sessionIdKey;
|
|
12
49
|
private timezoneToCountry;
|
|
50
|
+
currentChainId?: string | null;
|
|
51
|
+
currentConnectedAccount?: string;
|
|
13
52
|
private constructor();
|
|
14
53
|
static init(apiKey: string, projectId: string): Promise<FormoAnalytics>;
|
|
54
|
+
get provider(): EIP1193Provider | undefined;
|
|
15
55
|
private identifyUser;
|
|
16
56
|
private getSessionId;
|
|
17
57
|
private setSessionCookie;
|
|
@@ -20,7 +60,37 @@ export declare class FormoAnalytics implements IFormoAnalytics {
|
|
|
20
60
|
private trackEvent;
|
|
21
61
|
private maskSensitiveData;
|
|
22
62
|
private trackPageHit;
|
|
63
|
+
private trackProvider;
|
|
64
|
+
private registerChainChangedListener;
|
|
65
|
+
private handleAccountDisconnected;
|
|
66
|
+
private onChainChanged;
|
|
67
|
+
private onAccountsChanged;
|
|
68
|
+
private registerAccountsChangedListener;
|
|
69
|
+
private getCurrentChainId;
|
|
70
|
+
private handleAccountConnected;
|
|
71
|
+
private getCurrentWallet;
|
|
72
|
+
/**
|
|
73
|
+
* Stores the wallet address in session storage when connected.
|
|
74
|
+
* @param address - The wallet address to store.
|
|
75
|
+
*/
|
|
76
|
+
private storeWalletAddress;
|
|
77
|
+
/**
|
|
78
|
+
* Clears the wallet address from session storage when disconnected.
|
|
79
|
+
*/
|
|
80
|
+
private clearWalletAddress;
|
|
23
81
|
private buildApiUrl;
|
|
82
|
+
connect({ account, chainId }: {
|
|
83
|
+
account: string;
|
|
84
|
+
chainId: ChainID;
|
|
85
|
+
}): Promise<void>;
|
|
86
|
+
disconnect(attributes?: {
|
|
87
|
+
account?: string;
|
|
88
|
+
chainId?: ChainID;
|
|
89
|
+
}): Promise<void> | undefined;
|
|
90
|
+
chain({ chainId, account }: {
|
|
91
|
+
chainId: ChainID;
|
|
92
|
+
account?: string;
|
|
93
|
+
}): Promise<void>;
|
|
24
94
|
init(apiKey: string, projectId: string): Promise<FormoAnalytics>;
|
|
25
95
|
identify(userData: any): void;
|
|
26
96
|
page(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormoAnalytics.d.ts","sourceRoot":"","sources":["../../../src/FormoAnalytics.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FormoAnalytics.d.ts","sourceRoot":"","sources":["../../../src/FormoAnalytics.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAE,eAAe,EAAoB,MAAM,SAAS,CAAC;AAErE,UAAU,eAAe;IACvB;;OAEG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEjE;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAE9C;;OAEG;IACH,IAAI,IAAI,IAAI,CAAC;IAEb;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtE;;OAEG;IACH,UAAU,CAAC,UAAU,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAEvE;;OAEG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAE/D;;OAEG;IACH,KAAK,CAAC,UAAU,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AACD,qBAAa,cAAe,YAAW,eAAe;aAgBlC,MAAM,EAAE,MAAM;IACvB,SAAS,EAAE,MAAM;IAhB1B,OAAO,CAAC,SAAS,CAAC,CAAkB;IACpC,OAAO,CAAC,4BAA4B,CAG7B;IAEP,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,iBAAiB,CAAwC;IAEjE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC,OAAO;WAcM,IAAI,CACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAU1B,IAAI,QAAQ,IAAI,eAAe,GAAG,SAAS,CAE1C;IAED,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,cAAc;YAUR,UAAU;IA0DxB,OAAO,CAAC,iBAAiB;IAkEzB,OAAO,CAAC,YAAY;IAmCpB,OAAO,CAAC,aAAa;IA0BrB,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,yBAAyB;YAgBnB,cAAc;YA4Cd,iBAAiB;IAW/B,OAAO,CAAC,+BAA+B;YAYzB,iBAAiB;YAkBjB,sBAAsB;YActB,gBAAgB;IAyB9B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE;IAiBnE,UAAU,CAAC,UAAU,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE;IAoB/D,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAyBlE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAMhE,QAAQ,CAAC,QAAQ,EAAE,GAAG;IAItB,IAAI;IAIJ,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG;CAGxC"}
|
|
@@ -57,13 +57,20 @@ var utils_1 = require("./utils");
|
|
|
57
57
|
var highlight_run_1 = require("highlight.run");
|
|
58
58
|
var FormoAnalytics = /** @class */ (function () {
|
|
59
59
|
function FormoAnalytics(apiKey, projectId) {
|
|
60
|
+
var _a;
|
|
60
61
|
this.apiKey = apiKey;
|
|
61
62
|
this.projectId = projectId;
|
|
63
|
+
this._registeredProviderListeners = {};
|
|
64
|
+
this.sessionKey = 'walletAddress';
|
|
62
65
|
this.sessionIdKey = constants_1.SESSION_STORAGE_ID_KEY;
|
|
63
66
|
this.timezoneToCountry = constants_1.COUNTRY_LIST;
|
|
64
67
|
this.config = {
|
|
65
68
|
token: this.apiKey,
|
|
66
69
|
};
|
|
70
|
+
var provider = (window === null || window === void 0 ? void 0 : window.ethereum) || ((_a = window.web3) === null || _a === void 0 ? void 0 : _a.currentProvider);
|
|
71
|
+
if (provider) {
|
|
72
|
+
this.trackProvider(provider);
|
|
73
|
+
}
|
|
67
74
|
}
|
|
68
75
|
FormoAnalytics.init = function (apiKey, projectId) {
|
|
69
76
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -78,8 +85,15 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
78
85
|
});
|
|
79
86
|
});
|
|
80
87
|
};
|
|
88
|
+
Object.defineProperty(FormoAnalytics.prototype, "provider", {
|
|
89
|
+
get: function () {
|
|
90
|
+
return this._provider;
|
|
91
|
+
},
|
|
92
|
+
enumerable: false,
|
|
93
|
+
configurable: true
|
|
94
|
+
});
|
|
81
95
|
FormoAnalytics.prototype.identifyUser = function (userData) {
|
|
82
|
-
this.trackEvent(
|
|
96
|
+
this.trackEvent(constants_1.Event.IDENTIFY, userData);
|
|
83
97
|
};
|
|
84
98
|
FormoAnalytics.prototype.getSessionId = function () {
|
|
85
99
|
var existingSessionId = this.getCookieValue(this.sessionIdKey);
|
|
@@ -114,7 +128,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
114
128
|
// Function to send tracking data
|
|
115
129
|
FormoAnalytics.prototype.trackEvent = function (action, payload) {
|
|
116
130
|
return __awaiter(this, void 0, void 0, function () {
|
|
117
|
-
var maxRetries, attempt, apiUrl, requestData, sendRequest;
|
|
131
|
+
var maxRetries, attempt, apiUrl, address, requestData, sendRequest;
|
|
118
132
|
var _this = this;
|
|
119
133
|
return __generator(this, function (_a) {
|
|
120
134
|
switch (_a.label) {
|
|
@@ -123,9 +137,12 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
123
137
|
attempt = 0;
|
|
124
138
|
this.setSessionCookie(this.config.domain);
|
|
125
139
|
apiUrl = this.buildApiUrl();
|
|
140
|
+
return [4 /*yield*/, this.getCurrentWallet()];
|
|
141
|
+
case 1:
|
|
142
|
+
address = _a.sent();
|
|
126
143
|
requestData = {
|
|
127
144
|
project_id: this.projectId,
|
|
128
|
-
address:
|
|
145
|
+
address: address,
|
|
129
146
|
session_id: this.getSessionId(),
|
|
130
147
|
timestamp: new Date().toISOString(),
|
|
131
148
|
action: action,
|
|
@@ -170,7 +187,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
170
187
|
});
|
|
171
188
|
}); };
|
|
172
189
|
return [4 /*yield*/, sendRequest()];
|
|
173
|
-
case
|
|
190
|
+
case 2:
|
|
174
191
|
_a.sent();
|
|
175
192
|
return [2 /*return*/];
|
|
176
193
|
}
|
|
@@ -254,7 +271,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
254
271
|
setTimeout(function () {
|
|
255
272
|
var url = new URL(window.location.href);
|
|
256
273
|
var params = new URLSearchParams(url.search);
|
|
257
|
-
_this.trackEvent(
|
|
274
|
+
_this.trackEvent(constants_1.Event.PAGE, {
|
|
258
275
|
'user-agent': window.navigator.userAgent,
|
|
259
276
|
locale: language,
|
|
260
277
|
location: location,
|
|
@@ -268,6 +285,221 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
268
285
|
});
|
|
269
286
|
}, 300);
|
|
270
287
|
};
|
|
288
|
+
FormoAnalytics.prototype.trackProvider = function (provider) {
|
|
289
|
+
if (provider === this._provider) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
this.currentChainId = undefined;
|
|
293
|
+
this.currentConnectedAccount = undefined;
|
|
294
|
+
if (this._provider) {
|
|
295
|
+
var eventNames = Object.keys(this._registeredProviderListeners);
|
|
296
|
+
for (var _i = 0, eventNames_1 = eventNames; _i < eventNames_1.length; _i++) {
|
|
297
|
+
var eventName = eventNames_1[_i];
|
|
298
|
+
this._provider.removeListener(eventName, this._registeredProviderListeners[eventName]);
|
|
299
|
+
delete this._registeredProviderListeners[eventName];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
this._provider = provider;
|
|
303
|
+
this.getCurrentWallet();
|
|
304
|
+
this.registerAccountsChangedListener();
|
|
305
|
+
this.registerChainChangedListener();
|
|
306
|
+
};
|
|
307
|
+
FormoAnalytics.prototype.registerChainChangedListener = function () {
|
|
308
|
+
var _this = this;
|
|
309
|
+
var _a;
|
|
310
|
+
var listener = function () {
|
|
311
|
+
var args = [];
|
|
312
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
313
|
+
args[_i] = arguments[_i];
|
|
314
|
+
}
|
|
315
|
+
return _this.onChainChanged(args[0]);
|
|
316
|
+
};
|
|
317
|
+
(_a = this.provider) === null || _a === void 0 ? void 0 : _a.on('chainChanged', listener);
|
|
318
|
+
this._registeredProviderListeners['chainChanged'] = listener;
|
|
319
|
+
};
|
|
320
|
+
FormoAnalytics.prototype.handleAccountDisconnected = function () {
|
|
321
|
+
if (!this.currentConnectedAccount) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
var disconnectAttributes = {
|
|
325
|
+
address: this.currentConnectedAccount,
|
|
326
|
+
chainId: this.currentChainId,
|
|
327
|
+
};
|
|
328
|
+
this.currentChainId = undefined;
|
|
329
|
+
this.currentConnectedAccount = undefined;
|
|
330
|
+
this.clearWalletAddress();
|
|
331
|
+
return this.trackEvent(constants_1.Event.DISCONNECT, disconnectAttributes);
|
|
332
|
+
};
|
|
333
|
+
FormoAnalytics.prototype.onChainChanged = function (chainIdHex) {
|
|
334
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
335
|
+
var res, err_1;
|
|
336
|
+
return __generator(this, function (_a) {
|
|
337
|
+
switch (_a.label) {
|
|
338
|
+
case 0:
|
|
339
|
+
this.currentChainId = parseInt(chainIdHex).toString();
|
|
340
|
+
if (!!this.currentConnectedAccount) return [3 /*break*/, 4];
|
|
341
|
+
if (!this.provider) {
|
|
342
|
+
console.error('error', 'FormoAnalytics::onChainChanged: provider not found. CHAIN_CHANGED not reported');
|
|
343
|
+
return [2 /*return*/];
|
|
344
|
+
}
|
|
345
|
+
_a.label = 1;
|
|
346
|
+
case 1:
|
|
347
|
+
_a.trys.push([1, 3, , 4]);
|
|
348
|
+
return [4 /*yield*/, this.provider.request({
|
|
349
|
+
method: 'eth_accounts',
|
|
350
|
+
})];
|
|
351
|
+
case 2:
|
|
352
|
+
res = _a.sent();
|
|
353
|
+
if (!res || res.length === 0) {
|
|
354
|
+
console.error('error', 'FormoAnalytics::onChainChanged: unable to get account. eth_accounts returned empty');
|
|
355
|
+
return [2 /*return*/];
|
|
356
|
+
}
|
|
357
|
+
this.currentConnectedAccount = res[0];
|
|
358
|
+
return [3 /*break*/, 4];
|
|
359
|
+
case 3:
|
|
360
|
+
err_1 = _a.sent();
|
|
361
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
362
|
+
if (err_1.code !== 4001) {
|
|
363
|
+
// 4001: The request is rejected by the user , see https://docs.metamask.io/wallet/reference/provider-api/#errors
|
|
364
|
+
console.error('error', "FormoAnalytics::onChainChanged: unable to get account. eth_accounts threw an error", err_1);
|
|
365
|
+
return [2 /*return*/];
|
|
366
|
+
}
|
|
367
|
+
return [3 /*break*/, 4];
|
|
368
|
+
case 4: return [2 /*return*/, this.chain({
|
|
369
|
+
chainId: this.currentChainId,
|
|
370
|
+
account: this.currentConnectedAccount,
|
|
371
|
+
})];
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
};
|
|
376
|
+
FormoAnalytics.prototype.onAccountsChanged = function (accounts) {
|
|
377
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
378
|
+
var newAccount;
|
|
379
|
+
return __generator(this, function (_a) {
|
|
380
|
+
if (accounts.length > 0) {
|
|
381
|
+
newAccount = accounts[0];
|
|
382
|
+
if (newAccount !== this.currentConnectedAccount) {
|
|
383
|
+
this.handleAccountConnected(newAccount);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
this.handleAccountDisconnected();
|
|
388
|
+
}
|
|
389
|
+
return [2 /*return*/];
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
};
|
|
393
|
+
FormoAnalytics.prototype.registerAccountsChangedListener = function () {
|
|
394
|
+
var _this = this;
|
|
395
|
+
var _a, _b;
|
|
396
|
+
var listener = function () {
|
|
397
|
+
var args = [];
|
|
398
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
399
|
+
args[_i] = arguments[_i];
|
|
400
|
+
}
|
|
401
|
+
return _this.onAccountsChanged(args[0]);
|
|
402
|
+
};
|
|
403
|
+
(_a = this._provider) === null || _a === void 0 ? void 0 : _a.on('accountsChanged', listener);
|
|
404
|
+
this._registeredProviderListeners['accountsChanged'] = listener;
|
|
405
|
+
var handleAccountDisconnected = this.handleAccountDisconnected.bind(this);
|
|
406
|
+
(_b = this._provider) === null || _b === void 0 ? void 0 : _b.on('disconnect', handleAccountDisconnected);
|
|
407
|
+
this._registeredProviderListeners['disconnect'] = handleAccountDisconnected;
|
|
408
|
+
};
|
|
409
|
+
FormoAnalytics.prototype.getCurrentChainId = function () {
|
|
410
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
411
|
+
var chainIdHex;
|
|
412
|
+
var _a;
|
|
413
|
+
return __generator(this, function (_b) {
|
|
414
|
+
switch (_b.label) {
|
|
415
|
+
case 0:
|
|
416
|
+
if (!this.provider) {
|
|
417
|
+
console.error('FormoAnalytics::getCurrentChainId: provider not set');
|
|
418
|
+
}
|
|
419
|
+
return [4 /*yield*/, ((_a = this.provider) === null || _a === void 0 ? void 0 : _a.request({
|
|
420
|
+
method: 'eth_chainId',
|
|
421
|
+
}))];
|
|
422
|
+
case 1:
|
|
423
|
+
chainIdHex = _b.sent();
|
|
424
|
+
// Because we're connected, the chainId cannot be null
|
|
425
|
+
if (!chainIdHex) {
|
|
426
|
+
console.error("FormoAnalytics::getCurrentChainId: chainIdHex is: ".concat(chainIdHex));
|
|
427
|
+
}
|
|
428
|
+
return [2 /*return*/, parseInt(chainIdHex, 16).toString()];
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
};
|
|
433
|
+
FormoAnalytics.prototype.handleAccountConnected = function (account) {
|
|
434
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
435
|
+
var _a;
|
|
436
|
+
return __generator(this, function (_b) {
|
|
437
|
+
switch (_b.label) {
|
|
438
|
+
case 0:
|
|
439
|
+
if (account === this.currentConnectedAccount) {
|
|
440
|
+
// We have already reported this account
|
|
441
|
+
return [2 /*return*/];
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
this.currentConnectedAccount = account;
|
|
445
|
+
}
|
|
446
|
+
_a = this;
|
|
447
|
+
return [4 /*yield*/, this.getCurrentChainId()];
|
|
448
|
+
case 1:
|
|
449
|
+
_a.currentChainId = _b.sent();
|
|
450
|
+
this.connect({ account: account, chainId: this.currentChainId });
|
|
451
|
+
this.storeWalletAddress(account);
|
|
452
|
+
return [2 /*return*/];
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
FormoAnalytics.prototype.getCurrentWallet = function () {
|
|
458
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
459
|
+
var sessionData, parsedData, sessionExpiry, currentTime;
|
|
460
|
+
return __generator(this, function (_a) {
|
|
461
|
+
if (!this.provider) {
|
|
462
|
+
console.warn('FormoAnalytics::getCurrentWallet: the provider is not set');
|
|
463
|
+
return [2 /*return*/];
|
|
464
|
+
}
|
|
465
|
+
sessionData = sessionStorage.getItem(this.sessionKey);
|
|
466
|
+
if (!sessionData) {
|
|
467
|
+
return [2 /*return*/, null];
|
|
468
|
+
}
|
|
469
|
+
parsedData = JSON.parse(sessionData);
|
|
470
|
+
sessionExpiry = 30 * 60 * 1000;
|
|
471
|
+
currentTime = Date.now();
|
|
472
|
+
if (currentTime - parsedData.timestamp > sessionExpiry) {
|
|
473
|
+
console.warn('Session expired. Ignoring wallet address.');
|
|
474
|
+
sessionStorage.removeItem(this.sessionKey); // Clear expired session data
|
|
475
|
+
return [2 /*return*/, ''];
|
|
476
|
+
}
|
|
477
|
+
this.handleAccountConnected(parsedData.address);
|
|
478
|
+
return [2 /*return*/, parsedData.address || ''];
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
};
|
|
482
|
+
/**
|
|
483
|
+
* Stores the wallet address in session storage when connected.
|
|
484
|
+
* @param address - The wallet address to store.
|
|
485
|
+
*/
|
|
486
|
+
FormoAnalytics.prototype.storeWalletAddress = function (address) {
|
|
487
|
+
if (!address) {
|
|
488
|
+
console.error('No wallet address provided to store.');
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
var sessionData = {
|
|
492
|
+
address: address,
|
|
493
|
+
timestamp: Date.now(),
|
|
494
|
+
};
|
|
495
|
+
sessionStorage.setItem(this.sessionKey, JSON.stringify(sessionData));
|
|
496
|
+
};
|
|
497
|
+
/**
|
|
498
|
+
* Clears the wallet address from session storage when disconnected.
|
|
499
|
+
*/
|
|
500
|
+
FormoAnalytics.prototype.clearWalletAddress = function () {
|
|
501
|
+
sessionStorage.removeItem(this.sessionKey);
|
|
502
|
+
};
|
|
271
503
|
// Function to build the API URL
|
|
272
504
|
FormoAnalytics.prototype.buildApiUrl = function () {
|
|
273
505
|
var _a = this.config, host = _a.host, proxy = _a.proxy, token = _a.token, _b = _a.dataSource, dataSource = _b === void 0 ? 'analytics_events' : _b;
|
|
@@ -282,6 +514,51 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
282
514
|
}
|
|
283
515
|
return 'Error: No token provided';
|
|
284
516
|
};
|
|
517
|
+
FormoAnalytics.prototype.connect = function (_a) {
|
|
518
|
+
var account = _a.account, chainId = _a.chainId;
|
|
519
|
+
if (!chainId) {
|
|
520
|
+
throw new Error('FormoAnalytics::connect: chainId cannot be empty');
|
|
521
|
+
}
|
|
522
|
+
if (!account) {
|
|
523
|
+
throw new Error('FormoAnalytics::connect: account cannot be empty');
|
|
524
|
+
}
|
|
525
|
+
this.currentChainId = chainId.toString();
|
|
526
|
+
this.currentConnectedAccount = account;
|
|
527
|
+
return this.trackEvent(constants_1.Event.CONNECT, {
|
|
528
|
+
chainId: chainId,
|
|
529
|
+
address: account,
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
FormoAnalytics.prototype.disconnect = function (attributes) {
|
|
533
|
+
var account = (attributes === null || attributes === void 0 ? void 0 : attributes.account) || this.currentConnectedAccount;
|
|
534
|
+
if (!account) {
|
|
535
|
+
// We have most likely already reported this disconnection with the automatic
|
|
536
|
+
// `disconnect` detection
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
var chainId = (attributes === null || attributes === void 0 ? void 0 : attributes.chainId) || this.currentChainId;
|
|
540
|
+
var eventAttributes = __assign({ account: account }, (chainId && { chainId: chainId }));
|
|
541
|
+
this.currentChainId = undefined;
|
|
542
|
+
this.currentConnectedAccount = undefined;
|
|
543
|
+
return this.trackEvent(constants_1.Event.DISCONNECT, eventAttributes);
|
|
544
|
+
};
|
|
545
|
+
FormoAnalytics.prototype.chain = function (_a) {
|
|
546
|
+
var chainId = _a.chainId, account = _a.account;
|
|
547
|
+
if (!chainId || Number(chainId) === 0) {
|
|
548
|
+
throw new Error('FormoAnalytics::chain: chainId cannot be empty or 0');
|
|
549
|
+
}
|
|
550
|
+
if (!account && !this.currentConnectedAccount) {
|
|
551
|
+
throw new Error('FormoAnalytics::chain: account was empty and no previous account has been recorded. You can either pass an account or call connect() first');
|
|
552
|
+
}
|
|
553
|
+
if (isNaN(Number(chainId))) {
|
|
554
|
+
throw new Error('FormoAnalytics::chain: chainId must be a valid hex or decimal number');
|
|
555
|
+
}
|
|
556
|
+
this.currentChainId = chainId.toString();
|
|
557
|
+
return this.trackEvent(constants_1.Event.CHAIN_CHANGED, {
|
|
558
|
+
chainId: chainId,
|
|
559
|
+
account: account || this.currentConnectedAccount,
|
|
560
|
+
});
|
|
561
|
+
};
|
|
285
562
|
FormoAnalytics.prototype.init = function (apiKey, projectId) {
|
|
286
563
|
var instance = new FormoAnalytics(apiKey, projectId);
|
|
287
564
|
return Promise.resolve(instance);
|