@arthurreira/analytics 0.18.0 → 0.20.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.
@@ -38,20 +38,47 @@ var AfAnalytics = (() => {
38
38
  // src/vanilla.ts
39
39
  var vanilla_exports = {};
40
40
  __export(vanilla_exports, {
41
- init: () => init
41
+ consent: () => consent,
42
+ init: () => init,
43
+ isOptedOut: () => isOptedOut,
44
+ optIn: () => optIn,
45
+ optOut: () => optOut
42
46
  });
47
+
48
+ // src/lib/consent.ts
49
+ var CONSENT_KEY = "af_analytics_opted_out";
50
+ function optOut() {
51
+ if (typeof localStorage === "undefined") return;
52
+ localStorage.setItem(CONSENT_KEY, "1");
53
+ }
54
+ function optIn() {
55
+ if (typeof localStorage === "undefined") return;
56
+ localStorage.removeItem(CONSENT_KEY);
57
+ }
58
+ function isOptedOut() {
59
+ if (typeof localStorage !== "undefined" && localStorage.getItem(CONSENT_KEY) === "1") return true;
60
+ if (typeof navigator !== "undefined" && navigator.doNotTrack === "1") return true;
61
+ return false;
62
+ }
63
+ function consent(enabled) {
64
+ if (enabled) optIn();
65
+ else optOut();
66
+ }
67
+
68
+ // src/vanilla.ts
43
69
  var _currentScript = document.currentScript;
44
70
  var SESSION_EXPIRY_MS = 30 * 60 * 1e3;
45
71
  var IDLE_TOUCH_INTERVAL_MS = 5 * 60 * 1e3;
46
72
  var BC_CHANNEL = "af_analytics_session";
47
73
  var BC_ADOPT_TIMEOUT_MS = 50;
48
74
  function readConfig() {
49
- var _a, _b, _c, _d;
75
+ var _a, _b, _c, _d, _e, _f;
50
76
  const script = _currentScript != null ? _currentScript : document.querySelector("script[data-api-key]");
51
77
  const apiKey = (_b = (_a = script == null ? void 0 : script.dataset.apiKey) == null ? void 0 : _a.trim()) != null ? _b : "";
52
78
  const apiUrl = ((_d = (_c = script == null ? void 0 : script.dataset.url) == null ? void 0 : _c.trim()) != null ? _d : "").replace(/\/$/, "");
53
79
  if (!apiKey || !apiUrl) return null;
54
- return { apiKey, apiUrl };
80
+ const wsUrl = (_f = (_e = script == null ? void 0 : script.dataset.wsUrl) == null ? void 0 : _e.trim()) != null ? _f : apiUrl.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://") + "/realtime";
81
+ return { apiKey, apiUrl, wsUrl };
55
82
  }
56
83
  function generateId() {
57
84
  if (typeof crypto !== "undefined" && crypto.randomUUID) {
@@ -97,6 +124,7 @@ var AfAnalytics = (() => {
97
124
  }
98
125
  }
99
126
  function send(apiUrl, apiKey, payload) {
127
+ if (isOptedOut()) return;
100
128
  fetch(`${apiUrl}/events`, {
101
129
  method: "POST",
102
130
  headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
@@ -157,7 +185,7 @@ var AfAnalytics = (() => {
157
185
  return () => channel.close();
158
186
  }
159
187
  async function createRemoteSession(apiUrl, apiKey, visitorId) {
160
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
188
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
161
189
  const nav = navigator;
162
190
  const conn = (_c = (_b = (_a = nav["connection"]) != null ? _a : nav["mozConnection"]) != null ? _b : nav["webkitConnection"]) != null ? _c : null;
163
191
  const params = new URLSearchParams(window.location.search);
@@ -182,14 +210,22 @@ var AfAnalytics = (() => {
182
210
  utm_term: params.get("utm_term"),
183
211
  utm_content: params.get("utm_content")
184
212
  };
185
- const res = await fetch(`${apiUrl}/sessions`, {
186
- method: "POST",
187
- headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
188
- body: JSON.stringify(body)
189
- });
190
- if (!res.ok) return "";
191
- const data = await res.json();
192
- return data.id;
213
+ for (let attempt = 0; attempt < 3; attempt++) {
214
+ try {
215
+ const res = await fetch(`${apiUrl}/sessions`, {
216
+ method: "POST",
217
+ headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
218
+ body: JSON.stringify(body)
219
+ });
220
+ if (res.ok) {
221
+ const data = await res.json();
222
+ return (_o = (_n = data.session_id) != null ? _n : data.id) != null ? _o : "";
223
+ }
224
+ } catch (e) {
225
+ }
226
+ if (attempt < 2) await new Promise((r) => setTimeout(r, 500 * 2 ** attempt));
227
+ }
228
+ return "";
193
229
  }
194
230
  async function getOrCreateSession(apiUrl, apiKey) {
195
231
  const stored = getStoredSession();
@@ -235,6 +271,7 @@ var AfAnalytics = (() => {
235
271
  send(apiUrl, apiKey, __spreadValues(__spreadValues({}, baseFields(sessionId, "js_exception")), fields));
236
272
  }
237
273
  function init() {
274
+ if (isOptedOut()) return;
238
275
  const config = readConfig();
239
276
  if (!config) return;
240
277
  const { apiKey, apiUrl } = config;
package/dist/client.js CHANGED
@@ -8,6 +8,14 @@ import { usePathname } from "next/navigation";
8
8
  // src/hooks/useAnalytics.ts
9
9
  import { useEffect, useRef } from "react";
10
10
 
11
+ // src/lib/consent.ts
12
+ var CONSENT_KEY = "af_analytics_opted_out";
13
+ function isOptedOut() {
14
+ if (typeof localStorage !== "undefined" && localStorage.getItem(CONSENT_KEY) === "1") return true;
15
+ if (typeof navigator !== "undefined" && navigator.doNotTrack === "1") return true;
16
+ return false;
17
+ }
18
+
11
19
  // src/lib/api.ts
12
20
  var BASE_FIELDS = (sessionId, eventType, path) => ({
13
21
  session_id: sessionId,
@@ -28,6 +36,7 @@ function getGpu() {
28
36
  }
29
37
  }
30
38
  async function createSession(apiUrl, apiKey, visitorId) {
39
+ if (isOptedOut()) return null;
31
40
  const sessionData = { visitor_id: visitorId };
32
41
  if (typeof window !== "undefined") {
33
42
  const nav = navigator;
@@ -77,6 +86,7 @@ async function createSession(apiUrl, apiKey, visitorId) {
77
86
  }
78
87
  }
79
88
  async function sendEvent(apiUrl, apiKey, payload) {
89
+ if (isOptedOut()) return;
80
90
  await fetch(`${apiUrl}/events`, {
81
91
  method: "POST",
82
92
  headers: {
@@ -144,8 +154,7 @@ async function trackCTA(apiUrl, apiKey, sessionId, path, ctaId, ctaVariant) {
144
154
  }
145
155
 
146
156
  // src/lib/presence.ts
147
- var DEFAULT_WS_URL = "wss://edge.arthurreira.dev/realtime";
148
- function connectPresence(apiKey, sessionId, wsUrl = DEFAULT_WS_URL) {
157
+ function connectPresence(apiKey, sessionId, wsUrl) {
149
158
  if (typeof WebSocket === "undefined") {
150
159
  return { disconnect: () => {
151
160
  } };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ declare function optOut(): void;
2
+ declare function optIn(): void;
3
+ /**
4
+ * Returns true when the user has opted out via localStorage flag OR
5
+ * the browser-level DNT header is set to "1".
6
+ */
7
+ declare function isOptedOut(): boolean;
8
+ declare function consent(enabled: boolean): void;
9
+
1
10
  declare function createSession(apiUrl: string, apiKey: string, visitorId?: string): Promise<string | null>;
2
11
  declare function trackPageview(apiUrl: string, apiKey: string, sessionId: string, path: string): Promise<void>;
3
12
  declare function trackClick(apiUrl: string, apiKey: string, sessionId: string, path: string, e: MouseEvent, element: HTMLElement): Promise<void>;
@@ -13,10 +22,9 @@ declare function trackException(apiUrl: string, apiKey: string, sessionId: strin
13
22
  declare function trackError(apiUrl: string, apiKey: string, sessionId: string, path: string, error: Error): Promise<void>;
14
23
  declare function trackCTA(apiUrl: string, apiKey: string, sessionId: string, path: string, ctaId: string, ctaVariant?: string): Promise<void>;
15
24
 
16
- declare const DEFAULT_WS_URL = "wss://edge.arthurreira.dev/realtime";
17
25
  interface PresenceConnection {
18
26
  disconnect: () => void;
19
27
  }
20
- declare function connectPresence(apiKey: string, sessionId: string, wsUrl?: string): PresenceConnection;
28
+ declare function connectPresence(apiKey: string, sessionId: string, wsUrl: string): PresenceConnection;
21
29
 
22
- export { DEFAULT_WS_URL, type ExceptionFields, type PresenceConnection, connectPresence, createSession, trackCTA, trackClick, trackCopy, trackError, trackException, trackPageview, trackScroll, trackSearch };
30
+ export { type ExceptionFields, type PresenceConnection, connectPresence, consent, createSession, isOptedOut, optIn, optOut, trackCTA, trackClick, trackCopy, trackError, trackException, trackPageview, trackScroll, trackSearch };
package/dist/index.js CHANGED
@@ -1,3 +1,23 @@
1
+ // src/lib/consent.ts
2
+ var CONSENT_KEY = "af_analytics_opted_out";
3
+ function optOut() {
4
+ if (typeof localStorage === "undefined") return;
5
+ localStorage.setItem(CONSENT_KEY, "1");
6
+ }
7
+ function optIn() {
8
+ if (typeof localStorage === "undefined") return;
9
+ localStorage.removeItem(CONSENT_KEY);
10
+ }
11
+ function isOptedOut() {
12
+ if (typeof localStorage !== "undefined" && localStorage.getItem(CONSENT_KEY) === "1") return true;
13
+ if (typeof navigator !== "undefined" && navigator.doNotTrack === "1") return true;
14
+ return false;
15
+ }
16
+ function consent(enabled) {
17
+ if (enabled) optIn();
18
+ else optOut();
19
+ }
20
+
1
21
  // src/lib/api.ts
2
22
  var BASE_FIELDS = (sessionId, eventType, path) => ({
3
23
  session_id: sessionId,
@@ -18,6 +38,7 @@ function getGpu() {
18
38
  }
19
39
  }
20
40
  async function createSession(apiUrl, apiKey, visitorId) {
41
+ if (isOptedOut()) return null;
21
42
  const sessionData = { visitor_id: visitorId };
22
43
  if (typeof window !== "undefined") {
23
44
  const nav = navigator;
@@ -67,6 +88,7 @@ async function createSession(apiUrl, apiKey, visitorId) {
67
88
  }
68
89
  }
69
90
  async function sendEvent(apiUrl, apiKey, payload) {
91
+ if (isOptedOut()) return;
70
92
  await fetch(`${apiUrl}/events`, {
71
93
  method: "POST",
72
94
  headers: {
@@ -134,8 +156,7 @@ async function trackCTA(apiUrl, apiKey, sessionId, path, ctaId, ctaVariant) {
134
156
  }
135
157
 
136
158
  // src/lib/presence.ts
137
- var DEFAULT_WS_URL = "wss://edge.arthurreira.dev/realtime";
138
- function connectPresence(apiKey, sessionId, wsUrl = DEFAULT_WS_URL) {
159
+ function connectPresence(apiKey, sessionId, wsUrl) {
139
160
  if (typeof WebSocket === "undefined") {
140
161
  return { disconnect: () => {
141
162
  } };
@@ -204,9 +225,12 @@ function connectPresence(apiKey, sessionId, wsUrl = DEFAULT_WS_URL) {
204
225
  };
205
226
  }
206
227
  export {
207
- DEFAULT_WS_URL,
208
228
  connectPresence,
229
+ consent,
209
230
  createSession,
231
+ isOptedOut,
232
+ optIn,
233
+ optOut,
210
234
  trackCTA,
211
235
  trackClick,
212
236
  trackCopy,
package/package.json CHANGED
@@ -1,12 +1,7 @@
1
1
  {
2
2
  "name": "@arthurreira/analytics",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "type": "module",
5
- "scripts": {
6
- "build": "tsup",
7
- "prepare": "tsup",
8
- "dev": "tsup src/index.ts --format esm --dts --watch"
9
- },
10
5
  "exports": {
11
6
  ".": {
12
7
  "types": "./dist/index.d.ts",
@@ -37,5 +32,9 @@
37
32
  "peerDependencies": {
38
33
  "next": "^14.0.0 || ^15.0.0 || ^16.0.0",
39
34
  "react": "^18.0.0 || ^19.0.0"
35
+ },
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "dev": "tsup src/index.ts --format esm --dts --watch"
40
39
  }
41
40
  }