@cloff/sdk 1.0.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 +244 -0
- package/dist/index.d.ts +205 -0
- package/dist/index.js +1049 -0
- package/dist/widget.d.ts +18 -0
- package/dist/widget.js +623 -0
- package/package.json +30 -0
- package/src/index.ts +1194 -0
- package/src/widget.ts +664 -0
- package/tsconfig.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Clof SDK (Client Analytics & Session Replay)
|
|
2
|
+
|
|
3
|
+
A lightweight, performance-optimized, and privacy-preserving Web Analytics, Session Replay, and Canister APM observability library, complete with an offline-first buffering engine and embeddable analytics UI widget.
|
|
4
|
+
|
|
5
|
+
Designed for decentralized apps (dApps) to easily record active user metrics, sessions, custom events, campaign UTM parameters, Core Web Vitals, exceptions (with timeline breadcrumbs), and securely embed verified analytics charts for public display.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- ⚡ **Lightweight**: Minimal dependencies, keeping your bundle sizes ultra-small.
|
|
12
|
+
- 📶 **Offline-First Buffering**: Telemetry data (page views, events, exceptions) is safely queued in `localStorage` if the user is offline or a request fails, preventing data loss.
|
|
13
|
+
- 🔄 **Auto-Flush Sync**: Automatically listens to browser connectivity transitions (`online` event) to seamlessly flush buffered logs to the registry database.
|
|
14
|
+
- 🐞 **Error & Exception Tracker**: Capture uncaught runtime exceptions and promise rejections with auto-collected chronological breadcrumbs.
|
|
15
|
+
- 🕒 **Session Lifecycle Manager**: Automatically maintains sessions in `sessionStorage` with a 30-minute idle inactivity timeout.
|
|
16
|
+
- 🏷️ **UTM & Referrer Tracking**: Automatically parses and reports campaign sources (`utm_source`, `utm_medium`, `utm_campaign`) and traffic referrers.
|
|
17
|
+
- ⚙️ **Automatic Page View Tracking**: Listeners to automatically track route changes in single-page apps (SPA) using `window.history` monkeypatching.
|
|
18
|
+
- 📈 **Core Web Vitals Observer**: Natively tracks performance metrics (Page Load Time, Largest Contentful Paint, Cumulative Layout Shift, and Interaction to Next Paint).
|
|
19
|
+
- 🧬 **ICP Canister Observability (APM)**: Track and monitor duration, latency, and status (success/reject/error) of actors and canister calls.
|
|
20
|
+
- 📊 **Embeddable Chart Widget**: A responsive, framework-agnostic Custom Element Web Component `<clof-widget>` to show verified public analytics.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
Install the package via your preferred package manager:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @cloff/sdk
|
|
30
|
+
# or
|
|
31
|
+
yarn add @cloff/sdk
|
|
32
|
+
# or
|
|
33
|
+
pnpm add @cloff/sdk
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 🚀 Usage
|
|
39
|
+
|
|
40
|
+
### 1. Initialization Config
|
|
41
|
+
Configure the tracker by passing your API Key and optional configuration attributes:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { Clof } from '@cloff/sdk';
|
|
45
|
+
|
|
46
|
+
const tracker = new Clof('YOUR_API_KEY', {
|
|
47
|
+
debug: false, // Enable console logs for debugging
|
|
48
|
+
autoTrackPageViews: true, // Automatically listen to SPA route changes
|
|
49
|
+
userId: () => getCurrentUid(), // Dynamic getter to retrieve the current user's ID
|
|
50
|
+
enableErrors: true, // Automatically capture uncaught errors & unhandled rejections
|
|
51
|
+
enableAPM: true, // Track network request durations and Page Vitals
|
|
52
|
+
enableCanisterAPM: true, // Track ICP canister calls automatically
|
|
53
|
+
captureConsole: false // Capture console.error statements as breadcrumbs
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### Configuration Options
|
|
58
|
+
* `debug`: `boolean` (default `false`) — Logs SDK actions to the developer console.
|
|
59
|
+
* `autoTrackPageViews`: `boolean` (default `false`) — Automatically hooks into browser navigation/history to log page views.
|
|
60
|
+
* `userId`: `string | (() => string | null | undefined)` — Required if `autoTrackPageViews` is enabled. A string or function returning the active user ID.
|
|
61
|
+
* `enableErrors`: `boolean` (default `true`) — Automatically catches unhandled browser errors, promise rejections, and enables manual error reporting.
|
|
62
|
+
* `enableAPM`: `boolean` (default `true`) — Captures web performance metrics and Core Web Vitals (LCP, CLS, INP).
|
|
63
|
+
* `enableCanisterAPM`: `boolean` (default `true`) — Captures duration, canister ID, method name, call types, and responses for smart contract interactions.
|
|
64
|
+
* `captureConsole`: `boolean` (default `false`) — Monopoles `console.error` calls and appends them as diagnostic breadcrumbs.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### 2. Manual Tracking APIs
|
|
69
|
+
|
|
70
|
+
#### A. Track Page Views (with Performance Vitals)
|
|
71
|
+
Manually track page views. The SDK automatically appends page load speeds and Web Vitals if observed:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
tracker.trackPageView('user_wallet_address', {
|
|
75
|
+
path: '/marketplace', // Defaults to window.location.pathname
|
|
76
|
+
title: 'NFT Marketplace', // Defaults to document.title
|
|
77
|
+
referrer: 'https://google.com' // Defaults to document.referrer
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### B. Track Custom Events
|
|
82
|
+
Log custom interaction metrics, user goals, or conversion triggers:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
tracker.trackEvent('user_wallet_address', 'swap_completed', {
|
|
86
|
+
pair: 'ICP-USDT',
|
|
87
|
+
amount: 250.0,
|
|
88
|
+
slippage: 0.005
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### C. Deduplicated Active User Ping
|
|
93
|
+
Pings the server once per day per user (automatically cached and deduplicated in `localStorage` to save network bandwidth):
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
tracker.track('user_wallet_address');
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### 3. Canister APM Tracking
|
|
102
|
+
|
|
103
|
+
Track calls to smart contract canisters on the Internet Computer. The SDK collects latencies, success rates, and errors.
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
tracker.trackCanisterCall(
|
|
107
|
+
'ryjl3-tyaaa-aaaaa-aaaba-cai', // Canister ID
|
|
108
|
+
'submitPost', // Method Name
|
|
109
|
+
'success', // 'success' | 'error'
|
|
110
|
+
140, // duration in milliseconds
|
|
111
|
+
{ gasLimit: 300000 } // Optional metadata payload
|
|
112
|
+
);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### 4. Error & Exception Handling APIs
|
|
118
|
+
|
|
119
|
+
You can capture exceptions manually in try/catch blocks or hook them into framework-level error boundaries.
|
|
120
|
+
|
|
121
|
+
#### A. Capture Exception
|
|
122
|
+
Send a standard `Error` object or string description with optional contextual metadata. Uncaught exceptions will also package a chronological text timeline of the last 50 user journey actions (breadcrumbs) to enable **Session Replay**:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
try {
|
|
126
|
+
executeContractCall();
|
|
127
|
+
} catch (error) {
|
|
128
|
+
tracker.captureException(error, {
|
|
129
|
+
gasLimit: 3000000,
|
|
130
|
+
canisterId: 'ryjl3-tyaaa-aaaaa-aaaba-cai'
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### B. Capture Message
|
|
136
|
+
Log arbitrary log events, warning states, or telemetry markers:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
tracker.captureMessage('Transaction took longer than expected', 'warning', {
|
|
140
|
+
durationMs: 8200
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### 5. Offline-First Queuing Engine
|
|
147
|
+
|
|
148
|
+
If a user's device loses internet connection, the SDK ensures no analytics or crash data is lost:
|
|
149
|
+
1. All events (`trackPageView`, `trackEvent`, `captureException`) are serialized and buffered in `localStorage` under the key `clof_telemetry_queue_[apiKey]`.
|
|
150
|
+
2. A queue buffer holds up to `500` events using First-In-First-Out eviction.
|
|
151
|
+
3. The SDK hooks into the browser `online` window event. When the internet connection returns, it automatically flushes all buffered events sequentially in the background.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 📊 Public Analytics Widget Embed
|
|
156
|
+
|
|
157
|
+
Embed the responsive `<clof-widget>` (or legacy `<socio-dau-widget>`) Custom Element to display active metrics charts and demographics publicly.
|
|
158
|
+
|
|
159
|
+
### Widget Properties
|
|
160
|
+
- `api-key`: (Required) Your registered app's API key.
|
|
161
|
+
- `days`: Number of days of history to display on the SVG chart (default `30`).
|
|
162
|
+
- `theme`: `dark` or `light` (default auto-detects browser/system theme).
|
|
163
|
+
- `accent-color`: Hex color overriding the primary purple style (e.g. `#10b981` for emerald).
|
|
164
|
+
|
|
165
|
+
### 1. React SPA (Vite / CRA)
|
|
166
|
+
```tsx
|
|
167
|
+
import { useEffect } from 'react';
|
|
168
|
+
|
|
169
|
+
export default function VerifiedAnalytics() {
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
// Loads custom element client-side
|
|
172
|
+
import('@cloff/sdk/widget');
|
|
173
|
+
}, []);
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<div style={{ width: '100%', maxWidth: '600px' }}>
|
|
177
|
+
{/* @ts-ignore */}
|
|
178
|
+
<clof-widget api-key="YOUR_API_KEY" days="30" theme="dark" />
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 2. Next.js (SSR with Dynamic Import)
|
|
185
|
+
To prevent server-side custom element rendering warnings and hydration mismatches, wrap the widget in a client component and load it dynamically with `ssr: false`:
|
|
186
|
+
|
|
187
|
+
**Step 1: Create a client component wrapper (e.g. `WidgetWrapper.tsx`)**
|
|
188
|
+
```tsx
|
|
189
|
+
'use client';
|
|
190
|
+
|
|
191
|
+
import { useEffect } from 'react';
|
|
192
|
+
|
|
193
|
+
export default function WidgetWrapper() {
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
import('@cloff/sdk/widget');
|
|
196
|
+
}, []);
|
|
197
|
+
|
|
198
|
+
return <clof-widget api-key="YOUR_API_KEY" days="30" theme="dark" />;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Step 2: Load with dynamic import in your page**
|
|
203
|
+
```tsx
|
|
204
|
+
import dynamic from 'next/dynamic';
|
|
205
|
+
|
|
206
|
+
const PublicWidget = dynamic(() => import('./WidgetWrapper'), {
|
|
207
|
+
ssr: false,
|
|
208
|
+
loading: () => <p>Loading Analytics Widget...</p>,
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 3. HTML / CDN Embed
|
|
213
|
+
```html
|
|
214
|
+
<!-- Load the widget Custom Element script -->
|
|
215
|
+
<script type="module" src="https://esm.sh/@cloff/sdk@1.0.0/dist/widget.js"></script>
|
|
216
|
+
|
|
217
|
+
<!-- Embed the custom element -->
|
|
218
|
+
<clof-widget api-key="YOUR_API_KEY" days="30" theme="dark"></clof-widget>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### TypeScript JSX Declarations
|
|
222
|
+
Add this interface to your `global.d.ts` or type declaration file to prevent JSX compilation element errors:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
declare namespace JSX {
|
|
226
|
+
interface IntrinsicElements {
|
|
227
|
+
'clof-widget': React.DetailedHTMLProps<
|
|
228
|
+
React.HTMLAttributes<HTMLElement> & {
|
|
229
|
+
'api-key': string;
|
|
230
|
+
days?: string | number;
|
|
231
|
+
theme?: 'dark' | 'light';
|
|
232
|
+
'accent-color'?: string;
|
|
233
|
+
},
|
|
234
|
+
HTMLElement
|
|
235
|
+
>;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
MIT License.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
export interface TrackerConfig {
|
|
2
|
+
supabaseUrl?: string;
|
|
3
|
+
supabaseAnonKey?: string;
|
|
4
|
+
debug?: boolean;
|
|
5
|
+
autoTrackPageViews?: boolean;
|
|
6
|
+
userId?: string | (() => string | null | undefined);
|
|
7
|
+
enableErrors?: boolean;
|
|
8
|
+
enableAPM?: boolean;
|
|
9
|
+
enableCanisterAPM?: boolean;
|
|
10
|
+
captureConsole?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class Clof {
|
|
13
|
+
private apiKey;
|
|
14
|
+
private supabase;
|
|
15
|
+
private debug;
|
|
16
|
+
private sessionId;
|
|
17
|
+
private configUserId;
|
|
18
|
+
private enableErrors;
|
|
19
|
+
private enableAPM;
|
|
20
|
+
private enableCanisterAPM;
|
|
21
|
+
private captureConsole;
|
|
22
|
+
private breadcrumbs;
|
|
23
|
+
private maxBreadcrumbs;
|
|
24
|
+
private vitals;
|
|
25
|
+
constructor(apiKey: string, config?: TrackerConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Helper to identify device form-factor from Navigator UA string
|
|
28
|
+
*/
|
|
29
|
+
private getDeviceType;
|
|
30
|
+
/**
|
|
31
|
+
* Helper to extract browser name from UA string
|
|
32
|
+
*/
|
|
33
|
+
private getBrowser;
|
|
34
|
+
/**
|
|
35
|
+
* Helper to extract OS name from UA string
|
|
36
|
+
*/
|
|
37
|
+
private getOS;
|
|
38
|
+
/**
|
|
39
|
+
* Helper to retrieve timezone identifier as location
|
|
40
|
+
*/
|
|
41
|
+
private getLocation;
|
|
42
|
+
/**
|
|
43
|
+
* Helper to parse UTM parameters from search URL
|
|
44
|
+
*/
|
|
45
|
+
private getUTMParams;
|
|
46
|
+
/**
|
|
47
|
+
* Generate UUID v4
|
|
48
|
+
*/
|
|
49
|
+
private generateUUID;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve and ping the current user session
|
|
52
|
+
*/
|
|
53
|
+
private getSessionId;
|
|
54
|
+
private registerSession;
|
|
55
|
+
private pingSession;
|
|
56
|
+
/**
|
|
57
|
+
* Observes page loading performance and layout stability
|
|
58
|
+
*/
|
|
59
|
+
private setupVitalsObserver;
|
|
60
|
+
/**
|
|
61
|
+
* Setup a click listener to log interaction breadcrumbs
|
|
62
|
+
*/
|
|
63
|
+
private setupClickObserver;
|
|
64
|
+
/**
|
|
65
|
+
* Intercept console warnings & errors to record breadcrumbs
|
|
66
|
+
*/
|
|
67
|
+
private setupConsoleObserver;
|
|
68
|
+
/**
|
|
69
|
+
* Listen to global unhandled exceptions and promise rejections
|
|
70
|
+
*/
|
|
71
|
+
private setupErrorObservers;
|
|
72
|
+
/**
|
|
73
|
+
* Hook global fetch to auto-trace API durations and catch status >= 400 silent errors
|
|
74
|
+
*/
|
|
75
|
+
private setupFetchInterception;
|
|
76
|
+
/**
|
|
77
|
+
* Estimate cycles consumed by a canister call using client-side heuristics.
|
|
78
|
+
* Query calls are free on ICP. Update calls incur:
|
|
79
|
+
* base_fee (5M) + est_instructions × 1 cycle/instruction + ingress_bytes × 2000 cycles/byte
|
|
80
|
+
*/
|
|
81
|
+
static estimateCanisterCycles(callType: 'query' | 'update', durationMs: number, requestSize?: number): number;
|
|
82
|
+
/**
|
|
83
|
+
* Log a canister call action manually
|
|
84
|
+
*/
|
|
85
|
+
trackCanisterCall(canisterId: string, method: string, status: 'success' | 'error', durationMs?: number, metadata?: any): void;
|
|
86
|
+
/**
|
|
87
|
+
* Add manual trace breadcrumbs
|
|
88
|
+
*/
|
|
89
|
+
addBreadcrumb(message: string, category?: string, metadata?: any): void;
|
|
90
|
+
/**
|
|
91
|
+
* Track user activity (Legacy DAU Ping).
|
|
92
|
+
* Uses localStorage to deduplicate pings on the same day for a given user.
|
|
93
|
+
*/
|
|
94
|
+
track(userId: string | number, force?: boolean): Promise<{
|
|
95
|
+
success: boolean;
|
|
96
|
+
error?: string;
|
|
97
|
+
}>;
|
|
98
|
+
/**
|
|
99
|
+
* Track specific Page Views.
|
|
100
|
+
* Logs page navigation events, referrer, and captures performance Web Vitals.
|
|
101
|
+
*/
|
|
102
|
+
trackPageView(userId: string | number, options?: {
|
|
103
|
+
path?: string;
|
|
104
|
+
title?: string;
|
|
105
|
+
referrer?: string;
|
|
106
|
+
}): Promise<{
|
|
107
|
+
success: boolean;
|
|
108
|
+
error?: string;
|
|
109
|
+
}>;
|
|
110
|
+
/**
|
|
111
|
+
* Track Custom Events (actions, goals, conversions)
|
|
112
|
+
*/
|
|
113
|
+
trackEvent(userId: string | number, eventName: string, properties?: Record<string, any>): Promise<{
|
|
114
|
+
success: boolean;
|
|
115
|
+
error?: string;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* Log an exception manually to the database
|
|
119
|
+
*/
|
|
120
|
+
captureException(error: any, extraContext?: any): Promise<{
|
|
121
|
+
success: boolean;
|
|
122
|
+
error?: string;
|
|
123
|
+
}>;
|
|
124
|
+
/**
|
|
125
|
+
* Log a custom severity warning or info message to the database
|
|
126
|
+
*/
|
|
127
|
+
captureMessage(message: string, severity?: 'error' | 'warning' | 'info', extraContext?: any): Promise<{
|
|
128
|
+
success: boolean;
|
|
129
|
+
error?: string;
|
|
130
|
+
}>;
|
|
131
|
+
/**
|
|
132
|
+
* Helper function to execute error logging RPC
|
|
133
|
+
*/
|
|
134
|
+
private logErrorToDatabase;
|
|
135
|
+
/**
|
|
136
|
+
* Log latency of a duration in milliseconds manually
|
|
137
|
+
*/
|
|
138
|
+
trackPerformanceSpan(name: string, durationMs: number, entryType?: string, metadata?: any): Promise<{
|
|
139
|
+
success: boolean;
|
|
140
|
+
error?: string;
|
|
141
|
+
}>;
|
|
142
|
+
/**
|
|
143
|
+
* Log latency of an ICP canister call with method-level granularity
|
|
144
|
+
*/
|
|
145
|
+
trackCanisterSpan(canisterId: string, methodName: string, callType: 'query' | 'update', durationMs: number, status?: 'success' | 'reject' | 'error', errorMsg?: string, requestSize?: number, responseSize?: number): Promise<{
|
|
146
|
+
success: boolean;
|
|
147
|
+
error?: string;
|
|
148
|
+
}>;
|
|
149
|
+
/**
|
|
150
|
+
* Wrap an @dfinity/agent HttpAgent to intercept canister calls for APM.
|
|
151
|
+
* Returns the same agent proxied — no @dfinity/agent dependency needed.
|
|
152
|
+
*
|
|
153
|
+
* Usage:
|
|
154
|
+
* import { HttpAgent } from '@dfinity/agent';
|
|
155
|
+
* const agent = new HttpAgent();
|
|
156
|
+
* const wrapped = tracker.wrapHttpAgent(agent);
|
|
157
|
+
* // use wrapped everywhere instead of agent
|
|
158
|
+
*/
|
|
159
|
+
wrapHttpAgent<T>(agent: T): T;
|
|
160
|
+
/**
|
|
161
|
+
* Start a performance span timer
|
|
162
|
+
*/
|
|
163
|
+
startSpan(name: string, entryType?: string): {
|
|
164
|
+
end: (metadata?: any) => Promise<void>;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Measure latency of a function and resolve its result
|
|
168
|
+
*/
|
|
169
|
+
measure<T>(name: string, fn: () => Promise<T> | T, entryType?: string, metadata?: any): Promise<T>;
|
|
170
|
+
/**
|
|
171
|
+
* Define a user funnel for conversion analysis.
|
|
172
|
+
* Stores the ordered event sequence to the database so the
|
|
173
|
+
* dashboard can visualize drop-off at each step.
|
|
174
|
+
*
|
|
175
|
+
* Example:
|
|
176
|
+
* tracker.defineFunnel('Swap Flow', [
|
|
177
|
+
* 'connect_wallet',
|
|
178
|
+
* 'click_swap_token',
|
|
179
|
+
* 'sign_transaction',
|
|
180
|
+
* 'swap_success'
|
|
181
|
+
* ])
|
|
182
|
+
*/
|
|
183
|
+
defineFunnel(name: string, steps: string[]): Promise<{
|
|
184
|
+
success: boolean;
|
|
185
|
+
error?: string;
|
|
186
|
+
}>;
|
|
187
|
+
private resolveUserId;
|
|
188
|
+
/**
|
|
189
|
+
* Listen to Single-Page App (SPA) route changes and track page views automatically
|
|
190
|
+
*/
|
|
191
|
+
private setupAutoTracking;
|
|
192
|
+
private setupOnlineListener;
|
|
193
|
+
private isOnline;
|
|
194
|
+
private isNetworkError;
|
|
195
|
+
private getQueueKey;
|
|
196
|
+
private getOfflineQueue;
|
|
197
|
+
private saveOfflineQueue;
|
|
198
|
+
private enqueueOfflineAction;
|
|
199
|
+
private isFlushing;
|
|
200
|
+
private flushOfflineQueue;
|
|
201
|
+
private executeRpc;
|
|
202
|
+
private logDebug;
|
|
203
|
+
private logError;
|
|
204
|
+
}
|
|
205
|
+
export { Clof as SocioDauTracker, Clof as ClofTracker };
|