@arthurreira/analytics 0.15.0 → 0.16.1

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.
@@ -136,12 +136,20 @@ var AfAnalytics = (() => {
136
136
  utm_term: params.get("utm_term"),
137
137
  utm_content: params.get("utm_content")
138
138
  };
139
+ console.log(`[AF Analytics] Creating session at ${apiUrl}/sessions with API key: ${apiKey.slice(0, 10)}...`);
139
140
  const res = await fetch(`${apiUrl}/sessions`, {
140
141
  method: "POST",
141
142
  headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
142
143
  body: JSON.stringify(body)
143
144
  });
145
+ console.log(`[AF Analytics] Session creation response: ${res.status} ${res.statusText}`);
146
+ if (!res.ok) {
147
+ const errText = await res.text();
148
+ console.error(`[AF Analytics] Session creation failed: ${errText}`);
149
+ return "";
150
+ }
144
151
  const data = await res.json();
152
+ console.log(`[AF Analytics] Session created: ${data.id}`);
145
153
  return data.id;
146
154
  }
147
155
  async function getOrCreateSession(apiUrl, apiKey) {
package/dist/client.d.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  interface AnalyticsProps {
2
2
  apiKey: string;
3
3
  apiUrl: string;
4
- wsUrl?: string;
5
4
  }
6
- declare function Analytics({ apiKey, apiUrl, wsUrl }: AnalyticsProps): null;
5
+ declare function Analytics({ apiKey, apiUrl }: AnalyticsProps): null;
7
6
 
8
7
  interface ExceptionFields {
9
8
  exception_type: string;
@@ -11,9 +10,7 @@ interface ExceptionFields {
11
10
  stack_trace: string | null;
12
11
  }
13
12
 
14
- declare function useAnalytics(apiUrl: string, apiKey: string, options?: {
15
- wsUrl?: string;
16
- }): {
13
+ declare function useAnalytics(apiUrl: string, apiKey: string): {
17
14
  trackPageview: (path: string) => void;
18
15
  trackClick: (e: MouseEvent, element: HTMLElement) => void;
19
16
  trackScroll: (depth: number) => void;
package/dist/client.js CHANGED
@@ -51,16 +51,29 @@ async function createSession(apiUrl, apiKey, visitorId) {
51
51
  sessionData.utm_term = params.get("utm_term");
52
52
  sessionData.utm_content = params.get("utm_content");
53
53
  }
54
- const response = await fetch(`${apiUrl}/sessions`, {
55
- method: "POST",
56
- headers: {
57
- "X-API-Key": apiKey,
58
- "Content-Type": "application/json"
59
- },
60
- body: JSON.stringify(sessionData)
61
- });
62
- const data = await response.json();
63
- return data.id;
54
+ console.log(`[AF Analytics SDK] Creating session at ${apiUrl}/sessions with API key: ${apiKey.slice(0, 10)}...`);
55
+ try {
56
+ const response = await fetch(`${apiUrl}/sessions`, {
57
+ method: "POST",
58
+ headers: {
59
+ "X-API-Key": apiKey,
60
+ "Content-Type": "application/json"
61
+ },
62
+ body: JSON.stringify(sessionData)
63
+ });
64
+ console.log(`[AF Analytics SDK] Session creation response: ${response.status} ${response.statusText}`);
65
+ if (!response.ok) {
66
+ const errText = await response.text();
67
+ console.error(`[AF Analytics SDK] Session creation failed: ${errText}`);
68
+ return null;
69
+ }
70
+ const data = await response.json();
71
+ console.log(`[AF Analytics SDK] Session created: ${data.id}`);
72
+ return data.id ?? null;
73
+ } catch (err) {
74
+ console.error(`[AF Analytics SDK] Session creation error: ${err}`);
75
+ return null;
76
+ }
64
77
  }
65
78
  async function sendEvent(apiUrl, apiKey, payload) {
66
79
  await fetch(`${apiUrl}/events`, {
@@ -130,60 +143,6 @@ async function trackCTA(apiUrl, apiKey, sessionId, path, ctaId, ctaVariant) {
130
143
  });
131
144
  }
132
145
 
133
- // src/lib/presence.ts
134
- var DEFAULT_WS_URL = "wss://edge.arthurreira.dev/realtime";
135
- function connectPresence(apiKey, sessionId, wsUrl = DEFAULT_WS_URL) {
136
- if (typeof WebSocket === "undefined") {
137
- return { disconnect: () => {
138
- } };
139
- }
140
- let ws = null;
141
- let attempts = 0;
142
- let intentionalClose = false;
143
- let retryTimer = null;
144
- let targetUrl;
145
- try {
146
- const u = new URL(wsUrl);
147
- u.searchParams.set("api_key", apiKey);
148
- u.searchParams.set("session_id", sessionId);
149
- targetUrl = u.toString();
150
- } catch {
151
- return { disconnect: () => {
152
- } };
153
- }
154
- function connect() {
155
- try {
156
- ws = new WebSocket(targetUrl);
157
- } catch {
158
- return;
159
- }
160
- ws.onopen = () => {
161
- attempts = 0;
162
- ws.send(JSON.stringify({ type: "join", api_key: apiKey, session_id: sessionId }));
163
- };
164
- ws.onclose = () => {
165
- if (intentionalClose || attempts >= 3) return;
166
- const delay = Math.pow(2, attempts) * 1e3;
167
- attempts++;
168
- retryTimer = setTimeout(connect, delay);
169
- };
170
- }
171
- connect();
172
- return {
173
- disconnect: () => {
174
- intentionalClose = true;
175
- if (retryTimer !== null) {
176
- clearTimeout(retryTimer);
177
- retryTimer = null;
178
- }
179
- if (ws) {
180
- ws.close();
181
- ws = null;
182
- }
183
- }
184
- };
185
- }
186
-
187
146
  // src/hooks/useAnalytics.ts
188
147
  var SESSION_EXPIRY_MINUTES = 30;
189
148
  var _sessionFlight = null;
@@ -197,11 +156,15 @@ async function getOrCreateSession(apiUrl, apiKey, visitorId) {
197
156
  localStorage.setItem("af_session_last_activity", String(now));
198
157
  return storedSessionId;
199
158
  }
159
+ localStorage.removeItem("af_session_id");
160
+ localStorage.removeItem("af_session_last_activity");
200
161
  }
201
162
  if (_sessionFlight) return _sessionFlight;
202
163
  _sessionFlight = createSession(apiUrl, apiKey, visitorId).then((id) => {
203
- localStorage.setItem("af_session_id", id);
204
- localStorage.setItem("af_session_last_activity", String(Date.now()));
164
+ if (id) {
165
+ localStorage.setItem("af_session_id", id);
166
+ localStorage.setItem("af_session_last_activity", String(Date.now()));
167
+ }
205
168
  _sessionFlight = null;
206
169
  return id;
207
170
  }).catch((err) => {
@@ -210,11 +173,10 @@ async function getOrCreateSession(apiUrl, apiKey, visitorId) {
210
173
  });
211
174
  return _sessionFlight;
212
175
  }
213
- function useAnalytics(apiUrl, apiKey, options) {
176
+ function useAnalytics(apiUrl, apiKey) {
214
177
  const sessionId = useRef(null);
215
178
  const pendingEvents = useRef([]);
216
179
  const pathname = useRef(typeof window !== "undefined" ? window?.location?.pathname ?? "" : "");
217
- const presence = useRef(null);
218
180
  const hasSentEnd = useRef(false);
219
181
  useEffect(() => {
220
182
  if (typeof window === "undefined") return;
@@ -222,9 +184,8 @@ function useAnalytics(apiUrl, apiKey, options) {
222
184
  localStorage.setItem("af_analytics_visitor_id", visitor_id);
223
185
  let cancelled = false;
224
186
  getOrCreateSession(apiUrl, apiKey, visitor_id).then((id) => {
225
- if (cancelled) return;
187
+ if (cancelled || !id) return;
226
188
  sessionId.current = id;
227
- presence.current = connectPresence(apiKey, id, options?.wsUrl);
228
189
  pendingEvents.current.forEach((fn) => fn());
229
190
  pendingEvents.current = [];
230
191
  });
@@ -237,8 +198,6 @@ function useAnalytics(apiUrl, apiKey, options) {
237
198
  const sendEnd = () => {
238
199
  if (!sessionId.current || hasSentEnd.current) return;
239
200
  hasSentEnd.current = true;
240
- presence.current?.disconnect();
241
- presence.current = null;
242
201
  navigator.sendBeacon(`${apiUrl}/sessions/${sessionId.current}/end`);
243
202
  localStorage.removeItem("af_session_id");
244
203
  localStorage.removeItem("af_session_last_activity");
@@ -291,8 +250,8 @@ function useAnalytics(apiUrl, apiKey, options) {
291
250
  }
292
251
 
293
252
  // src/components/Analytics.tsx
294
- function Analytics({ apiKey, apiUrl, wsUrl }) {
295
- const { trackPageview: trackPageview2, trackClick: trackClick2, trackScroll: trackScroll2, trackCopy: trackCopy2, trackException: trackException2 } = useAnalytics(apiUrl, apiKey, { wsUrl });
253
+ function Analytics({ apiKey, apiUrl }) {
254
+ const { trackPageview: trackPageview2, trackClick: trackClick2, trackScroll: trackScroll2, trackCopy: trackCopy2, trackException: trackException2 } = useAnalytics(apiUrl, apiKey);
296
255
  const lastTracked = useRef2(null);
297
256
  const lastScrollDepth = useRef2(0);
298
257
  const pathname = typeof window !== "undefined" ? window.location.pathname : "";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- declare function createSession(apiUrl: string, apiKey: string, visitorId?: string): Promise<any>;
1
+ declare function createSession(apiUrl: string, apiKey: string, visitorId?: string): Promise<string | null>;
2
2
  declare function trackPageview(apiUrl: string, apiKey: string, sessionId: string, path: string): Promise<void>;
3
3
  declare function trackClick(apiUrl: string, apiKey: string, sessionId: string, path: string, e: MouseEvent, element: HTMLElement): Promise<void>;
4
4
  declare function trackScroll(apiUrl: string, apiKey: string, sessionId: string, path: string, depth: number): Promise<void>;
package/dist/index.js CHANGED
@@ -42,16 +42,29 @@ async function createSession(apiUrl, apiKey, visitorId) {
42
42
  sessionData.utm_term = params.get("utm_term");
43
43
  sessionData.utm_content = params.get("utm_content");
44
44
  }
45
- const response = await fetch(`${apiUrl}/sessions`, {
46
- method: "POST",
47
- headers: {
48
- "X-API-Key": apiKey,
49
- "Content-Type": "application/json"
50
- },
51
- body: JSON.stringify(sessionData)
52
- });
53
- const data = await response.json();
54
- return data.id;
45
+ console.log(`[AF Analytics SDK] Creating session at ${apiUrl}/sessions with API key: ${apiKey.slice(0, 10)}...`);
46
+ try {
47
+ const response = await fetch(`${apiUrl}/sessions`, {
48
+ method: "POST",
49
+ headers: {
50
+ "X-API-Key": apiKey,
51
+ "Content-Type": "application/json"
52
+ },
53
+ body: JSON.stringify(sessionData)
54
+ });
55
+ console.log(`[AF Analytics SDK] Session creation response: ${response.status} ${response.statusText}`);
56
+ if (!response.ok) {
57
+ const errText = await response.text();
58
+ console.error(`[AF Analytics SDK] Session creation failed: ${errText}`);
59
+ return null;
60
+ }
61
+ const data = await response.json();
62
+ console.log(`[AF Analytics SDK] Session created: ${data.id}`);
63
+ return data.id ?? null;
64
+ } catch (err) {
65
+ console.error(`[AF Analytics SDK] Session creation error: ${err}`);
66
+ return null;
67
+ }
55
68
  }
56
69
  async function sendEvent(apiUrl, apiKey, payload) {
57
70
  await fetch(`${apiUrl}/events`, {
package/package.json CHANGED
@@ -1,35 +1,41 @@
1
- { "name": "@arthurreira/analytics",
2
- "version": "0.15.0",
3
- "type": "module",
4
- "scripts": {
5
- "build": "tsup",
6
- "prepare": "tsup",
7
- "dev": "tsup src/index.ts --format esm --dts --watch"
1
+ {
2
+ "name": "@arthurreira/analytics",
3
+ "version": "0.16.1",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsup",
7
+ "prepare": "tsup",
8
+ "dev": "tsup src/index.ts --format esm --dts --watch"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
8
14
  },
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js"
13
- },
14
- "./client": {
15
- "types": "./dist/client.d.ts",
16
- "import": "./dist/client.js"
17
- }
18
- },
19
- "sideEffects": false,
20
- "files": [
21
- "dist"
22
- ],
23
- "description": "Analytics SDK for af-analytics (browser client + helpers)",
24
- "license": "MIT",
25
- "dependencies": {},
26
- "devDependencies": {
27
- "tsup": "^8.5.1",
28
- "typescript": "^5.9.2",
29
- "@types/react": "^19.0.0"
30
- },
31
- "peerDependencies": {
32
- "next": "^14.0.0 || ^15.0.0 || ^16.0.0",
33
- "react": "^18.0.0 || ^19.0.0"
15
+ "./client": {
16
+ "types": "./dist/client.d.ts",
17
+ "import": "./dist/client.js"
34
18
  }
19
+ },
20
+ "sideEffects": false,
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "description": "Analytics SDK for af-analytics (browser client + helpers)",
25
+ "license": "MIT",
26
+ "devDependencies": {
27
+ "@testing-library/jest-dom": "^6.9.1",
28
+ "@testing-library/react": "^16.3.2",
29
+ "@types/react": "^19.0.0",
30
+ "jsdom": "^29.1.1",
31
+ "react": "^19.2.6",
32
+ "react-dom": "^19.2.6",
33
+ "tsup": "^8.5.1",
34
+ "typescript": "^5.9.2",
35
+ "vitest": "^4.1.7"
36
+ },
37
+ "peerDependencies": {
38
+ "next": "^14.0.0 || ^15.0.0 || ^16.0.0",
39
+ "react": "^18.0.0 || ^19.0.0"
40
+ }
35
41
  }