@arthurreira/analytics 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +5 -2
- package/dist/client.js +53 -5
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
interface AnalyticsProps {
|
|
2
2
|
apiKey: string;
|
|
3
3
|
apiUrl: string;
|
|
4
|
+
wsUrl?: string;
|
|
4
5
|
}
|
|
5
|
-
declare function Analytics({ apiKey, apiUrl }: AnalyticsProps): null;
|
|
6
|
+
declare function Analytics({ apiKey, apiUrl, wsUrl }: AnalyticsProps): null;
|
|
6
7
|
|
|
7
|
-
declare function useAnalytics(apiUrl: string, apiKey: string
|
|
8
|
+
declare function useAnalytics(apiUrl: string, apiKey: string, options?: {
|
|
9
|
+
wsUrl?: string;
|
|
10
|
+
}): {
|
|
8
11
|
trackPageview: (path: string) => void;
|
|
9
12
|
trackClick: (e: MouseEvent, element: HTMLElement) => void;
|
|
10
13
|
trackScroll: (depth: number) => void;
|
package/dist/client.js
CHANGED
|
@@ -54,7 +54,7 @@ async function createSession(apiUrl, apiKey, visitorId) {
|
|
|
54
54
|
const response = await fetch(`${apiUrl}/sessions`, {
|
|
55
55
|
method: "POST",
|
|
56
56
|
headers: {
|
|
57
|
-
"
|
|
57
|
+
"X-API-Key": apiKey,
|
|
58
58
|
"Content-Type": "application/json"
|
|
59
59
|
},
|
|
60
60
|
body: JSON.stringify(sessionData)
|
|
@@ -66,7 +66,7 @@ async function sendEvent(apiUrl, apiKey, payload) {
|
|
|
66
66
|
await fetch(`${apiUrl}/events`, {
|
|
67
67
|
method: "POST",
|
|
68
68
|
headers: {
|
|
69
|
-
"
|
|
69
|
+
"X-API-Key": apiKey,
|
|
70
70
|
"Content-Type": "application/json"
|
|
71
71
|
},
|
|
72
72
|
body: JSON.stringify(payload)
|
|
@@ -124,6 +124,50 @@ async function trackCTA(apiUrl, apiKey, sessionId, path, ctaId, ctaVariant) {
|
|
|
124
124
|
});
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// src/lib/presence.ts
|
|
128
|
+
var DEFAULT_WS_URL = "wss://edge.arthurreira.dev/realtime";
|
|
129
|
+
function connectPresence(apiKey, sessionId, wsUrl = DEFAULT_WS_URL) {
|
|
130
|
+
if (typeof WebSocket === "undefined") {
|
|
131
|
+
return { disconnect: () => {
|
|
132
|
+
} };
|
|
133
|
+
}
|
|
134
|
+
let ws = null;
|
|
135
|
+
let attempts = 0;
|
|
136
|
+
let intentionalClose = false;
|
|
137
|
+
let retryTimer = null;
|
|
138
|
+
function connect() {
|
|
139
|
+
try {
|
|
140
|
+
ws = new WebSocket(wsUrl);
|
|
141
|
+
} catch {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
ws.onopen = () => {
|
|
145
|
+
attempts = 0;
|
|
146
|
+
ws.send(JSON.stringify({ type: "join", api_key: apiKey, session_id: sessionId }));
|
|
147
|
+
};
|
|
148
|
+
ws.onclose = () => {
|
|
149
|
+
if (intentionalClose || attempts >= 3) return;
|
|
150
|
+
const delay = Math.pow(2, attempts) * 1e3;
|
|
151
|
+
attempts++;
|
|
152
|
+
retryTimer = setTimeout(connect, delay);
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
connect();
|
|
156
|
+
return {
|
|
157
|
+
disconnect: () => {
|
|
158
|
+
intentionalClose = true;
|
|
159
|
+
if (retryTimer !== null) {
|
|
160
|
+
clearTimeout(retryTimer);
|
|
161
|
+
retryTimer = null;
|
|
162
|
+
}
|
|
163
|
+
if (ws) {
|
|
164
|
+
ws.close();
|
|
165
|
+
ws = null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
127
171
|
// src/hooks/useAnalytics.ts
|
|
128
172
|
var SESSION_EXPIRY_MINUTES = 30;
|
|
129
173
|
async function getOrCreateSession(apiUrl, apiKey, visitorId) {
|
|
@@ -142,16 +186,18 @@ async function getOrCreateSession(apiUrl, apiKey, visitorId) {
|
|
|
142
186
|
localStorage.setItem("af_session_last_activity", String(now));
|
|
143
187
|
return newSessionId;
|
|
144
188
|
}
|
|
145
|
-
function useAnalytics(apiUrl, apiKey) {
|
|
189
|
+
function useAnalytics(apiUrl, apiKey, options) {
|
|
146
190
|
const sessionId = useRef(null);
|
|
147
191
|
const pendingEvents = useRef([]);
|
|
148
192
|
const pathname = useRef(typeof window !== "undefined" ? window?.location?.pathname ?? "" : "");
|
|
193
|
+
const presence = useRef(null);
|
|
149
194
|
useEffect(() => {
|
|
150
195
|
if (typeof window === "undefined") return;
|
|
151
196
|
const visitor_id = localStorage.getItem("af_analytics_visitor_id") || crypto.randomUUID();
|
|
152
197
|
localStorage.setItem("af_analytics_visitor_id", visitor_id);
|
|
153
198
|
getOrCreateSession(apiUrl, apiKey, visitor_id).then((id) => {
|
|
154
199
|
sessionId.current = id;
|
|
200
|
+
presence.current = connectPresence(apiKey, id, options?.wsUrl);
|
|
155
201
|
pendingEvents.current.forEach((fn) => fn());
|
|
156
202
|
pendingEvents.current = [];
|
|
157
203
|
});
|
|
@@ -160,6 +206,8 @@ function useAnalytics(apiUrl, apiKey) {
|
|
|
160
206
|
if (typeof window === "undefined") return;
|
|
161
207
|
const sendEnd = () => {
|
|
162
208
|
if (!sessionId.current) return;
|
|
209
|
+
presence.current?.disconnect();
|
|
210
|
+
presence.current = null;
|
|
163
211
|
navigator.sendBeacon(`${apiUrl}/sessions/${sessionId.current}/end`);
|
|
164
212
|
localStorage.removeItem("af_session_id");
|
|
165
213
|
localStorage.removeItem("af_session_last_activity");
|
|
@@ -209,8 +257,8 @@ function useAnalytics(apiUrl, apiKey) {
|
|
|
209
257
|
}
|
|
210
258
|
|
|
211
259
|
// src/components/Analytics.tsx
|
|
212
|
-
function Analytics({ apiKey, apiUrl }) {
|
|
213
|
-
const { trackPageview: trackPageview2, trackClick: trackClick2, trackScroll: trackScroll2, trackCopy: trackCopy2, trackError: trackError2 } = useAnalytics(apiUrl, apiKey);
|
|
260
|
+
function Analytics({ apiKey, apiUrl, wsUrl }) {
|
|
261
|
+
const { trackPageview: trackPageview2, trackClick: trackClick2, trackScroll: trackScroll2, trackCopy: trackCopy2, trackError: trackError2 } = useAnalytics(apiUrl, apiKey, { wsUrl });
|
|
214
262
|
const lastTracked = useRef2(null);
|
|
215
263
|
const lastScrollDepth = useRef2(0);
|
|
216
264
|
const pathname = typeof window !== "undefined" ? window.location.pathname : "";
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,7 @@ async function createSession(apiUrl, apiKey, visitorId) {
|
|
|
45
45
|
const response = await fetch(`${apiUrl}/sessions`, {
|
|
46
46
|
method: "POST",
|
|
47
47
|
headers: {
|
|
48
|
-
"
|
|
48
|
+
"X-API-Key": apiKey,
|
|
49
49
|
"Content-Type": "application/json"
|
|
50
50
|
},
|
|
51
51
|
body: JSON.stringify(sessionData)
|
|
@@ -57,7 +57,7 @@ async function sendEvent(apiUrl, apiKey, payload) {
|
|
|
57
57
|
await fetch(`${apiUrl}/events`, {
|
|
58
58
|
method: "POST",
|
|
59
59
|
headers: {
|
|
60
|
-
"
|
|
60
|
+
"X-API-Key": apiKey,
|
|
61
61
|
"Content-Type": "application/json"
|
|
62
62
|
},
|
|
63
63
|
body: JSON.stringify(payload)
|
package/package.json
CHANGED