@arthurreira/analytics 0.9.0 → 0.11.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.js +19 -2
- package/dist/index.d.ts +7 -1
- package/dist/index.js +56 -0
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -135,9 +135,19 @@ function connectPresence(apiKey, sessionId, wsUrl = DEFAULT_WS_URL) {
|
|
|
135
135
|
let attempts = 0;
|
|
136
136
|
let intentionalClose = false;
|
|
137
137
|
let retryTimer = null;
|
|
138
|
+
let targetUrl;
|
|
139
|
+
try {
|
|
140
|
+
const u = new URL(wsUrl);
|
|
141
|
+
u.searchParams.set("api_key", apiKey);
|
|
142
|
+
u.searchParams.set("session_id", sessionId);
|
|
143
|
+
targetUrl = u.toString();
|
|
144
|
+
} catch {
|
|
145
|
+
return { disconnect: () => {
|
|
146
|
+
} };
|
|
147
|
+
}
|
|
138
148
|
function connect() {
|
|
139
149
|
try {
|
|
140
|
-
ws = new WebSocket(
|
|
150
|
+
ws = new WebSocket(targetUrl);
|
|
141
151
|
} catch {
|
|
142
152
|
return;
|
|
143
153
|
}
|
|
@@ -191,21 +201,28 @@ function useAnalytics(apiUrl, apiKey, options) {
|
|
|
191
201
|
const pendingEvents = useRef([]);
|
|
192
202
|
const pathname = useRef(typeof window !== "undefined" ? window?.location?.pathname ?? "" : "");
|
|
193
203
|
const presence = useRef(null);
|
|
204
|
+
const hasSentEnd = useRef(false);
|
|
194
205
|
useEffect(() => {
|
|
195
206
|
if (typeof window === "undefined") return;
|
|
196
207
|
const visitor_id = localStorage.getItem("af_analytics_visitor_id") || crypto.randomUUID();
|
|
197
208
|
localStorage.setItem("af_analytics_visitor_id", visitor_id);
|
|
209
|
+
let cancelled = false;
|
|
198
210
|
getOrCreateSession(apiUrl, apiKey, visitor_id).then((id) => {
|
|
211
|
+
if (cancelled) return;
|
|
199
212
|
sessionId.current = id;
|
|
200
213
|
presence.current = connectPresence(apiKey, id, options?.wsUrl);
|
|
201
214
|
pendingEvents.current.forEach((fn) => fn());
|
|
202
215
|
pendingEvents.current = [];
|
|
203
216
|
});
|
|
217
|
+
return () => {
|
|
218
|
+
cancelled = true;
|
|
219
|
+
};
|
|
204
220
|
}, []);
|
|
205
221
|
useEffect(() => {
|
|
206
222
|
if (typeof window === "undefined") return;
|
|
207
223
|
const sendEnd = () => {
|
|
208
|
-
if (!sessionId.current) return;
|
|
224
|
+
if (!sessionId.current || hasSentEnd.current) return;
|
|
225
|
+
hasSentEnd.current = true;
|
|
209
226
|
presence.current?.disconnect();
|
|
210
227
|
presence.current = null;
|
|
211
228
|
navigator.sendBeacon(`${apiUrl}/sessions/${sessionId.current}/end`);
|
package/dist/index.d.ts
CHANGED
|
@@ -7,4 +7,10 @@ declare function trackSearch(apiUrl: string, apiKey: string, sessionId: string,
|
|
|
7
7
|
declare function trackError(apiUrl: string, apiKey: string, sessionId: string, path: string, error: Error): Promise<void>;
|
|
8
8
|
declare function trackCTA(apiUrl: string, apiKey: string, sessionId: string, path: string, ctaId: string, ctaVariant?: string): Promise<void>;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
declare const DEFAULT_WS_URL = "wss://edge.arthurreira.dev/realtime";
|
|
11
|
+
interface PresenceConnection {
|
|
12
|
+
disconnect: () => void;
|
|
13
|
+
}
|
|
14
|
+
declare function connectPresence(apiKey: string, sessionId: string, wsUrl?: string): PresenceConnection;
|
|
15
|
+
|
|
16
|
+
export { DEFAULT_WS_URL, type PresenceConnection, connectPresence, createSession, trackCTA, trackClick, trackCopy, trackError, trackPageview, trackScroll, trackSearch };
|
package/dist/index.js
CHANGED
|
@@ -114,7 +114,63 @@ async function trackCTA(apiUrl, apiKey, sessionId, path, ctaId, ctaVariant) {
|
|
|
114
114
|
cta_variant: ctaVariant || null
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
// src/lib/presence.ts
|
|
119
|
+
var DEFAULT_WS_URL = "wss://edge.arthurreira.dev/realtime";
|
|
120
|
+
function connectPresence(apiKey, sessionId, wsUrl = DEFAULT_WS_URL) {
|
|
121
|
+
if (typeof WebSocket === "undefined") {
|
|
122
|
+
return { disconnect: () => {
|
|
123
|
+
} };
|
|
124
|
+
}
|
|
125
|
+
let ws = null;
|
|
126
|
+
let attempts = 0;
|
|
127
|
+
let intentionalClose = false;
|
|
128
|
+
let retryTimer = null;
|
|
129
|
+
let targetUrl;
|
|
130
|
+
try {
|
|
131
|
+
const u = new URL(wsUrl);
|
|
132
|
+
u.searchParams.set("api_key", apiKey);
|
|
133
|
+
u.searchParams.set("session_id", sessionId);
|
|
134
|
+
targetUrl = u.toString();
|
|
135
|
+
} catch {
|
|
136
|
+
return { disconnect: () => {
|
|
137
|
+
} };
|
|
138
|
+
}
|
|
139
|
+
function connect() {
|
|
140
|
+
try {
|
|
141
|
+
ws = new WebSocket(targetUrl);
|
|
142
|
+
} catch {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
ws.onopen = () => {
|
|
146
|
+
attempts = 0;
|
|
147
|
+
ws.send(JSON.stringify({ type: "join", api_key: apiKey, session_id: sessionId }));
|
|
148
|
+
};
|
|
149
|
+
ws.onclose = () => {
|
|
150
|
+
if (intentionalClose || attempts >= 3) return;
|
|
151
|
+
const delay = Math.pow(2, attempts) * 1e3;
|
|
152
|
+
attempts++;
|
|
153
|
+
retryTimer = setTimeout(connect, delay);
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
connect();
|
|
157
|
+
return {
|
|
158
|
+
disconnect: () => {
|
|
159
|
+
intentionalClose = true;
|
|
160
|
+
if (retryTimer !== null) {
|
|
161
|
+
clearTimeout(retryTimer);
|
|
162
|
+
retryTimer = null;
|
|
163
|
+
}
|
|
164
|
+
if (ws) {
|
|
165
|
+
ws.close();
|
|
166
|
+
ws = null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
117
171
|
export {
|
|
172
|
+
DEFAULT_WS_URL,
|
|
173
|
+
connectPresence,
|
|
118
174
|
createSession,
|
|
119
175
|
trackCTA,
|
|
120
176
|
trackClick,
|
package/package.json
CHANGED