@agentuity/frontend 0.1.1 → 0.1.3
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/analytics/beacon-standalone.d.ts +106 -0
- package/dist/analytics/beacon-standalone.d.ts.map +1 -0
- package/dist/analytics/beacon-standalone.js +577 -0
- package/dist/analytics/beacon-standalone.js.map +1 -0
- package/dist/analytics/index.d.ts +15 -5
- package/dist/analytics/index.d.ts.map +1 -1
- package/dist/analytics/index.js +21 -5
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/types.d.ts +63 -35
- package/dist/analytics/types.d.ts.map +1 -1
- package/dist/beacon-script.d.ts +16 -0
- package/dist/beacon-script.d.ts.map +1 -0
- package/dist/beacon-script.js +3 -0
- package/dist/beacon-script.js.map +1 -0
- package/dist/beacon.js +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/analytics/beacon-standalone.ts +718 -0
- package/src/analytics/index.ts +29 -8
- package/src/analytics/types.ts +78 -49
- package/src/beacon-script.ts +24 -0
- package/src/index.ts +10 -7
- package/dist/analytics/beacon.d.ts +0 -15
- package/dist/analytics/beacon.d.ts.map +0 -1
- package/dist/analytics/beacon.js +0 -177
- package/dist/analytics/beacon.js.map +0 -1
- package/dist/analytics/collectors/clicks.d.ts +0 -10
- package/dist/analytics/collectors/clicks.d.ts.map +0 -1
- package/dist/analytics/collectors/clicks.js +0 -84
- package/dist/analytics/collectors/clicks.js.map +0 -1
- package/dist/analytics/collectors/errors.d.ts +0 -5
- package/dist/analytics/collectors/errors.d.ts.map +0 -1
- package/dist/analytics/collectors/errors.js +0 -43
- package/dist/analytics/collectors/errors.js.map +0 -1
- package/dist/analytics/collectors/forms.d.ts +0 -5
- package/dist/analytics/collectors/forms.d.ts.map +0 -1
- package/dist/analytics/collectors/forms.js +0 -55
- package/dist/analytics/collectors/forms.js.map +0 -1
- package/dist/analytics/collectors/pageview.d.ts +0 -15
- package/dist/analytics/collectors/pageview.d.ts.map +0 -1
- package/dist/analytics/collectors/pageview.js +0 -64
- package/dist/analytics/collectors/pageview.js.map +0 -1
- package/dist/analytics/collectors/scroll.d.ts +0 -17
- package/dist/analytics/collectors/scroll.d.ts.map +0 -1
- package/dist/analytics/collectors/scroll.js +0 -93
- package/dist/analytics/collectors/scroll.js.map +0 -1
- package/dist/analytics/collectors/spa.d.ts +0 -10
- package/dist/analytics/collectors/spa.d.ts.map +0 -1
- package/dist/analytics/collectors/spa.js +0 -53
- package/dist/analytics/collectors/spa.js.map +0 -1
- package/dist/analytics/collectors/visibility.d.ts +0 -18
- package/dist/analytics/collectors/visibility.d.ts.map +0 -1
- package/dist/analytics/collectors/visibility.js +0 -81
- package/dist/analytics/collectors/visibility.js.map +0 -1
- package/dist/analytics/collectors/webvitals.d.ts +0 -6
- package/dist/analytics/collectors/webvitals.d.ts.map +0 -1
- package/dist/analytics/collectors/webvitals.js +0 -111
- package/dist/analytics/collectors/webvitals.js.map +0 -1
- package/dist/analytics/events.d.ts +0 -18
- package/dist/analytics/events.d.ts.map +0 -1
- package/dist/analytics/events.js +0 -126
- package/dist/analytics/events.js.map +0 -1
- package/dist/analytics/offline.d.ts +0 -19
- package/dist/analytics/offline.d.ts.map +0 -1
- package/dist/analytics/offline.js +0 -145
- package/dist/analytics/offline.js.map +0 -1
- package/src/analytics/beacon.ts +0 -203
- package/src/analytics/collectors/clicks.ts +0 -100
- package/src/analytics/collectors/errors.ts +0 -49
- package/src/analytics/collectors/forms.ts +0 -64
- package/src/analytics/collectors/pageview.ts +0 -76
- package/src/analytics/collectors/scroll.ts +0 -112
- package/src/analytics/collectors/spa.ts +0 -60
- package/src/analytics/collectors/visibility.ts +0 -94
- package/src/analytics/collectors/webvitals.ts +0 -129
- package/src/analytics/events.ts +0 -146
- package/src/analytics/offline.ts +0 -163
package/dist/analytics/events.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { getVisitorId } from './utils/storage';
|
|
2
|
-
const BATCH_SIZE = 10;
|
|
3
|
-
const BATCH_TIMEOUT_MS = 5000;
|
|
4
|
-
const COLLECT_ENDPOINT = '/_agentuity/webanalytics/collect';
|
|
5
|
-
let eventQueue = [];
|
|
6
|
-
let batchTimeout = null;
|
|
7
|
-
let config = null;
|
|
8
|
-
/**
|
|
9
|
-
* Initialize the event queue with config
|
|
10
|
-
*/
|
|
11
|
-
export function initEventQueue(pageConfig) {
|
|
12
|
-
config = pageConfig;
|
|
13
|
-
// Flush on page unload
|
|
14
|
-
if (typeof window !== 'undefined') {
|
|
15
|
-
window.addEventListener('visibilitychange', () => {
|
|
16
|
-
if (document.visibilityState === 'hidden') {
|
|
17
|
-
flushEvents();
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
window.addEventListener('pagehide', () => {
|
|
21
|
-
flushEvents();
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Queue an event for sending
|
|
27
|
-
*/
|
|
28
|
-
export function queueEvent(event) {
|
|
29
|
-
if (!config) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
// Apply sample rate (default: 1 = 100%)
|
|
33
|
-
const sampleRate = config.sampleRate ?? 1;
|
|
34
|
-
if (sampleRate < 1 && Math.random() > sampleRate) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
// Check exclude patterns
|
|
38
|
-
const excludePatterns = config.excludePatterns ?? [];
|
|
39
|
-
if (excludePatterns.length > 0) {
|
|
40
|
-
const currentPath = window.location.pathname;
|
|
41
|
-
for (const pattern of excludePatterns) {
|
|
42
|
-
try {
|
|
43
|
-
if (new RegExp(pattern).test(currentPath)) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
// Invalid regex, skip
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
// Merge global properties with event data and serialize to JSON string for Catalyst
|
|
53
|
-
const mergedData = config.globalProperties && Object.keys(config.globalProperties).length > 0
|
|
54
|
-
? { ...config.globalProperties, ...event.event_data }
|
|
55
|
-
: event.event_data;
|
|
56
|
-
if (mergedData) {
|
|
57
|
-
event.event_data = JSON.stringify(mergedData);
|
|
58
|
-
}
|
|
59
|
-
eventQueue.push(event);
|
|
60
|
-
// Flush if batch size reached
|
|
61
|
-
if (eventQueue.length >= BATCH_SIZE) {
|
|
62
|
-
flushEvents();
|
|
63
|
-
}
|
|
64
|
-
else if (!batchTimeout) {
|
|
65
|
-
// Set timeout for batch flush
|
|
66
|
-
batchTimeout = setTimeout(() => {
|
|
67
|
-
flushEvents();
|
|
68
|
-
}, BATCH_TIMEOUT_MS);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Flush all queued events
|
|
73
|
-
*/
|
|
74
|
-
export function flushEvents() {
|
|
75
|
-
if (batchTimeout) {
|
|
76
|
-
clearTimeout(batchTimeout);
|
|
77
|
-
batchTimeout = null;
|
|
78
|
-
}
|
|
79
|
-
if (eventQueue.length === 0 || !config) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
const events = eventQueue;
|
|
83
|
-
eventQueue = [];
|
|
84
|
-
// In dev mode, log to console instead of sending
|
|
85
|
-
if (config.isDevmode) {
|
|
86
|
-
console.debug('[Agentuity Analytics] Events:', events);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const payload = {
|
|
90
|
-
org_id: config.orgId,
|
|
91
|
-
project_id: config.projectId,
|
|
92
|
-
session_id: config.sessionId,
|
|
93
|
-
thread_id: config.threadId,
|
|
94
|
-
visitor_id: getVisitorId(),
|
|
95
|
-
is_devmode: config.isDevmode,
|
|
96
|
-
events,
|
|
97
|
-
};
|
|
98
|
-
const body = JSON.stringify(payload);
|
|
99
|
-
// Use sendBeacon for reliable delivery
|
|
100
|
-
if (typeof navigator !== 'undefined' && navigator.sendBeacon) {
|
|
101
|
-
const sent = navigator.sendBeacon(COLLECT_ENDPOINT, body);
|
|
102
|
-
if (sent) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
// Fallback to fetch with keepalive
|
|
107
|
-
if (typeof fetch !== 'undefined') {
|
|
108
|
-
fetch(COLLECT_ENDPOINT, {
|
|
109
|
-
method: 'POST',
|
|
110
|
-
headers: {
|
|
111
|
-
'Content-Type': 'application/json',
|
|
112
|
-
},
|
|
113
|
-
body,
|
|
114
|
-
keepalive: true,
|
|
115
|
-
}).catch(() => {
|
|
116
|
-
// Silent failure - analytics is best effort
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Get current queue length (for testing)
|
|
122
|
-
*/
|
|
123
|
-
export function getQueueLength() {
|
|
124
|
-
return eventQueue.length;
|
|
125
|
-
}
|
|
126
|
-
//# sourceMappingURL=events.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/analytics/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { AnalyticsEvent } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Store event in IndexedDB for offline persistence
|
|
4
|
-
*/
|
|
5
|
-
export declare function storeOfflineEvent(event: AnalyticsEvent): Promise<void>;
|
|
6
|
-
/**
|
|
7
|
-
* Get all offline events and clear them
|
|
8
|
-
*/
|
|
9
|
-
export declare function getAndClearOfflineEvents(): Promise<AnalyticsEvent[]>;
|
|
10
|
-
/**
|
|
11
|
-
* Check if we're online
|
|
12
|
-
*/
|
|
13
|
-
export declare function isOnline(): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Initialize offline support
|
|
16
|
-
* Listens for online event to flush queued events
|
|
17
|
-
*/
|
|
18
|
-
export declare function initOfflineSupport(flushCallback: () => void): void;
|
|
19
|
-
//# sourceMappingURL=offline.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"offline.d.ts","sourceRoot":"","sources":["../../src/analytics/offline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA0D9C;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC5E;AAED;;GAEG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAgC1E;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAKlC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,IAAI,GAAG,IAAI,CASlE"}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
const DB_NAME = 'agentuity_analytics';
|
|
2
|
-
const STORE_NAME = 'events';
|
|
3
|
-
const DB_VERSION = 1;
|
|
4
|
-
const MAX_QUEUE_SIZE = 1000;
|
|
5
|
-
let db = null;
|
|
6
|
-
let dbInitPromise = null;
|
|
7
|
-
/**
|
|
8
|
-
* Initialize IndexedDB for offline event storage
|
|
9
|
-
*/
|
|
10
|
-
async function initDB() {
|
|
11
|
-
if (typeof indexedDB === 'undefined') {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
return new Promise((resolve) => {
|
|
15
|
-
try {
|
|
16
|
-
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
|
17
|
-
request.onerror = () => {
|
|
18
|
-
resolve(null);
|
|
19
|
-
};
|
|
20
|
-
request.onsuccess = () => {
|
|
21
|
-
resolve(request.result);
|
|
22
|
-
};
|
|
23
|
-
request.onupgradeneeded = (e) => {
|
|
24
|
-
const database = e.target.result;
|
|
25
|
-
if (!database.objectStoreNames.contains(STORE_NAME)) {
|
|
26
|
-
database.createObjectStore(STORE_NAME, { keyPath: 'id' });
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
resolve(null);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Get database instance
|
|
37
|
-
*/
|
|
38
|
-
async function getDB() {
|
|
39
|
-
if (db) {
|
|
40
|
-
return db;
|
|
41
|
-
}
|
|
42
|
-
if (!dbInitPromise) {
|
|
43
|
-
dbInitPromise = initDB();
|
|
44
|
-
}
|
|
45
|
-
db = await dbInitPromise;
|
|
46
|
-
return db;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Store event in IndexedDB for offline persistence
|
|
50
|
-
*/
|
|
51
|
-
export async function storeOfflineEvent(event) {
|
|
52
|
-
const database = await getDB();
|
|
53
|
-
if (!database) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
const transaction = database.transaction(STORE_NAME, 'readwrite');
|
|
58
|
-
const store = transaction.objectStore(STORE_NAME);
|
|
59
|
-
// Check current count and evict old events if needed before adding
|
|
60
|
-
const count = await new Promise((resolve) => {
|
|
61
|
-
const countRequest = store.count();
|
|
62
|
-
countRequest.onsuccess = () => resolve(countRequest.result);
|
|
63
|
-
countRequest.onerror = () => resolve(0);
|
|
64
|
-
});
|
|
65
|
-
if (count >= MAX_QUEUE_SIZE) {
|
|
66
|
-
// Evict oldest event (FIFO) before adding new one
|
|
67
|
-
await new Promise((resolve) => {
|
|
68
|
-
const cursorRequest = store.openCursor();
|
|
69
|
-
cursorRequest.onsuccess = () => {
|
|
70
|
-
const cursor = cursorRequest.result;
|
|
71
|
-
if (cursor) {
|
|
72
|
-
const deleteRequest = cursor.delete();
|
|
73
|
-
deleteRequest.onsuccess = () => resolve();
|
|
74
|
-
deleteRequest.onerror = () => resolve();
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
resolve();
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
cursorRequest.onerror = () => resolve();
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
store.add(event);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// Silent failure
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Get all offline events and clear them
|
|
91
|
-
*/
|
|
92
|
-
export async function getAndClearOfflineEvents() {
|
|
93
|
-
const database = await getDB();
|
|
94
|
-
if (!database) {
|
|
95
|
-
return [];
|
|
96
|
-
}
|
|
97
|
-
return new Promise((resolve) => {
|
|
98
|
-
try {
|
|
99
|
-
const transaction = database.transaction(STORE_NAME, 'readwrite');
|
|
100
|
-
const store = transaction.objectStore(STORE_NAME);
|
|
101
|
-
const events = [];
|
|
102
|
-
const request = store.openCursor();
|
|
103
|
-
request.onsuccess = () => {
|
|
104
|
-
const cursor = request.result;
|
|
105
|
-
if (cursor) {
|
|
106
|
-
events.push(cursor.value);
|
|
107
|
-
cursor.delete();
|
|
108
|
-
cursor.continue();
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
resolve(events);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
request.onerror = () => {
|
|
115
|
-
resolve([]);
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
resolve([]);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Check if we're online
|
|
125
|
-
*/
|
|
126
|
-
export function isOnline() {
|
|
127
|
-
if (typeof navigator === 'undefined') {
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
return navigator.onLine !== false;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Initialize offline support
|
|
134
|
-
* Listens for online event to flush queued events
|
|
135
|
-
*/
|
|
136
|
-
export function initOfflineSupport(flushCallback) {
|
|
137
|
-
if (typeof window === 'undefined') {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
window.addEventListener('online', () => {
|
|
141
|
-
// Flush offline events when coming back online
|
|
142
|
-
flushCallback();
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
//# sourceMappingURL=offline.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"offline.js","sourceRoot":"","sources":["../../src/analytics/offline.ts"],"names":[],"mappings":"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"}
|
package/src/analytics/beacon.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import type { AnalyticsPageConfig, AnalyticsClient } from './types';
|
|
2
|
-
import { initEventQueue, queueEvent, flushEvents } from './events';
|
|
3
|
-
import { initPageviewTracking, createBaseEvent, trackPageview } from './collectors/pageview';
|
|
4
|
-
import { initSPATracking } from './collectors/spa';
|
|
5
|
-
import { initClickTracking, initOutboundLinkTracking } from './collectors/clicks';
|
|
6
|
-
import { initScrollTracking } from './collectors/scroll';
|
|
7
|
-
import { initErrorTracking } from './collectors/errors';
|
|
8
|
-
import { initVisibilityTracking } from './collectors/visibility';
|
|
9
|
-
import { initFormTracking } from './collectors/forms';
|
|
10
|
-
import { initWebVitalsTracking } from './collectors/webvitals';
|
|
11
|
-
import { isOptedOut, setOptOut } from './utils/storage';
|
|
12
|
-
import { initOfflineSupport, getAndClearOfflineEvents } from './offline';
|
|
13
|
-
|
|
14
|
-
let initialized = false;
|
|
15
|
-
let trackingStarted = false;
|
|
16
|
-
let analyticsEnabled = true;
|
|
17
|
-
let consentRequired = false;
|
|
18
|
-
let consentGiven = false;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Check if analytics should run
|
|
22
|
-
*/
|
|
23
|
-
function shouldTrack(): boolean {
|
|
24
|
-
if (!analyticsEnabled) return false;
|
|
25
|
-
if (isOptedOut()) return false;
|
|
26
|
-
if (consentRequired && !consentGiven) return false;
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Initialize the analytics beacon
|
|
32
|
-
* Called automatically when the script loads
|
|
33
|
-
*/
|
|
34
|
-
export function initBeacon(): void {
|
|
35
|
-
if (initialized) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const config = window.__AGENTUITY_ANALYTICS__;
|
|
40
|
-
if (!config || !config.enabled) {
|
|
41
|
-
analyticsEnabled = false;
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
initialized = true;
|
|
46
|
-
consentRequired = config.requireConsent ?? false;
|
|
47
|
-
|
|
48
|
-
// If consent is required and not given, wait for optIn
|
|
49
|
-
if (consentRequired && !consentGiven) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
startTracking(config);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Start all tracking based on config
|
|
58
|
-
*/
|
|
59
|
-
function startTracking(config: AnalyticsPageConfig): void {
|
|
60
|
-
if (trackingStarted) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
trackingStarted = true;
|
|
64
|
-
|
|
65
|
-
// Initialize event queue
|
|
66
|
-
initEventQueue(config);
|
|
67
|
-
|
|
68
|
-
// Initialize offline support
|
|
69
|
-
initOfflineSupport(async () => {
|
|
70
|
-
// Flush offline events when coming back online
|
|
71
|
-
const offlineEvents = await getAndClearOfflineEvents();
|
|
72
|
-
for (const event of offlineEvents) {
|
|
73
|
-
queueEvent(event);
|
|
74
|
-
}
|
|
75
|
-
flushEvents();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Always track pageviews
|
|
79
|
-
initPageviewTracking();
|
|
80
|
-
|
|
81
|
-
// Initialize visibility tracking (for time on page)
|
|
82
|
-
initVisibilityTracking();
|
|
83
|
-
|
|
84
|
-
// Conditional tracking based on config (all default to true except requireConsent)
|
|
85
|
-
if (config.trackSPANavigation !== false) {
|
|
86
|
-
initSPATracking();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (config.trackClicks !== false) {
|
|
90
|
-
initClickTracking();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (config.trackOutboundLinks !== false) {
|
|
94
|
-
initOutboundLinkTracking();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (config.trackScroll !== false) {
|
|
98
|
-
initScrollTracking();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (config.trackErrors !== false) {
|
|
102
|
-
initErrorTracking();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (config.trackForms !== false) {
|
|
106
|
-
initFormTracking();
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (config.trackWebVitals !== false) {
|
|
110
|
-
initWebVitalsTracking();
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Create the analytics client API
|
|
116
|
-
*/
|
|
117
|
-
function createClient(): AnalyticsClient {
|
|
118
|
-
return {
|
|
119
|
-
track(eventName: string, properties?: Record<string, unknown>): void {
|
|
120
|
-
if (!shouldTrack()) return;
|
|
121
|
-
|
|
122
|
-
const event = createBaseEvent('custom');
|
|
123
|
-
event.event_name = eventName;
|
|
124
|
-
if (properties) {
|
|
125
|
-
event.event_data = properties;
|
|
126
|
-
}
|
|
127
|
-
queueEvent(event);
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
identify(userId: string, traits?: Record<string, unknown>): void {
|
|
131
|
-
if (!shouldTrack()) return;
|
|
132
|
-
|
|
133
|
-
const event = createBaseEvent('custom');
|
|
134
|
-
event.event_name = 'identify';
|
|
135
|
-
event.event_data = {
|
|
136
|
-
user_id: userId,
|
|
137
|
-
...traits,
|
|
138
|
-
};
|
|
139
|
-
queueEvent(event);
|
|
140
|
-
},
|
|
141
|
-
|
|
142
|
-
pageview(path?: string): void {
|
|
143
|
-
if (!shouldTrack()) return;
|
|
144
|
-
trackPageview(path);
|
|
145
|
-
},
|
|
146
|
-
|
|
147
|
-
async flush(): Promise<void> {
|
|
148
|
-
flushEvents();
|
|
149
|
-
},
|
|
150
|
-
|
|
151
|
-
optOut(): void {
|
|
152
|
-
setOptOut(true);
|
|
153
|
-
analyticsEnabled = false;
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
optIn(): void {
|
|
157
|
-
setOptOut(false);
|
|
158
|
-
analyticsEnabled = true;
|
|
159
|
-
consentGiven = true;
|
|
160
|
-
|
|
161
|
-
// If consent was required and now given, start tracking
|
|
162
|
-
if (consentRequired && !trackingStarted) {
|
|
163
|
-
const config = window.__AGENTUITY_ANALYTICS__;
|
|
164
|
-
if (config) {
|
|
165
|
-
startTracking(config);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
isEnabled(): boolean {
|
|
171
|
-
return shouldTrack();
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Singleton client instance
|
|
177
|
-
let clientInstance: AnalyticsClient | null = null;
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Get the analytics client instance
|
|
181
|
-
*/
|
|
182
|
-
export function getAnalytics(): AnalyticsClient {
|
|
183
|
-
if (!clientInstance) {
|
|
184
|
-
clientInstance = createClient();
|
|
185
|
-
}
|
|
186
|
-
return clientInstance;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Convenience function to track a custom event
|
|
191
|
-
*/
|
|
192
|
-
export function track(eventName: string, properties?: Record<string, unknown>): void {
|
|
193
|
-
getAnalytics().track(eventName, properties);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Auto-initialize when script loads
|
|
197
|
-
if (typeof window !== 'undefined') {
|
|
198
|
-
if (document.readyState === 'loading') {
|
|
199
|
-
document.addEventListener('DOMContentLoaded', initBeacon);
|
|
200
|
-
} else {
|
|
201
|
-
initBeacon();
|
|
202
|
-
}
|
|
203
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { createBaseEvent } from './pageview';
|
|
2
|
-
import { queueEvent } from '../events';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Initialize click tracking
|
|
6
|
-
* Tracks clicks on elements with data-analytics attribute
|
|
7
|
-
*/
|
|
8
|
-
export function initClickTracking(): void {
|
|
9
|
-
if (typeof document === 'undefined') {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
document.addEventListener(
|
|
14
|
-
'click',
|
|
15
|
-
(e) => {
|
|
16
|
-
const target = e.target as HTMLElement | null;
|
|
17
|
-
if (!target) return;
|
|
18
|
-
|
|
19
|
-
// Find closest element with data-analytics attribute
|
|
20
|
-
const analyticsElement = target.closest('[data-analytics]');
|
|
21
|
-
if (!analyticsElement) return;
|
|
22
|
-
|
|
23
|
-
const eventName = analyticsElement.getAttribute('data-analytics');
|
|
24
|
-
if (!eventName) return;
|
|
25
|
-
|
|
26
|
-
const event = createBaseEvent('click');
|
|
27
|
-
event.event_name = eventName;
|
|
28
|
-
|
|
29
|
-
// Collect additional data attributes
|
|
30
|
-
const eventData: Record<string, unknown> = {};
|
|
31
|
-
for (const attr of Array.from(analyticsElement.attributes)) {
|
|
32
|
-
if (attr.name.startsWith('data-analytics-')) {
|
|
33
|
-
const key = attr.name.replace('data-analytics-', '');
|
|
34
|
-
eventData[key] = attr.value;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Add element info
|
|
39
|
-
eventData.tag = analyticsElement.tagName.toLowerCase();
|
|
40
|
-
if (analyticsElement.id) {
|
|
41
|
-
eventData.id = analyticsElement.id;
|
|
42
|
-
}
|
|
43
|
-
const text = (analyticsElement as HTMLElement).innerText?.slice(0, 100);
|
|
44
|
-
if (text) {
|
|
45
|
-
eventData.text = text;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (Object.keys(eventData).length > 0) {
|
|
49
|
-
event.event_data = eventData;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
queueEvent(event);
|
|
53
|
-
},
|
|
54
|
-
{ capture: true, passive: true }
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Initialize outbound link tracking
|
|
60
|
-
*/
|
|
61
|
-
export function initOutboundLinkTracking(): void {
|
|
62
|
-
if (typeof document === 'undefined') {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
document.addEventListener(
|
|
67
|
-
'click',
|
|
68
|
-
(e) => {
|
|
69
|
-
const target = e.target as HTMLElement | null;
|
|
70
|
-
if (!target) return;
|
|
71
|
-
|
|
72
|
-
const link = target.closest('a');
|
|
73
|
-
if (!link) return;
|
|
74
|
-
|
|
75
|
-
const href = link.href;
|
|
76
|
-
if (!href) return;
|
|
77
|
-
|
|
78
|
-
// Check if it's an outbound link
|
|
79
|
-
try {
|
|
80
|
-
const url = new URL(href, window.location.origin);
|
|
81
|
-
if (url.hostname === window.location.hostname) {
|
|
82
|
-
return; // Same domain, not outbound
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const event = createBaseEvent('outbound_link');
|
|
86
|
-
event.event_name = 'outbound_link';
|
|
87
|
-
event.event_data = {
|
|
88
|
-
href,
|
|
89
|
-
hostname: url.hostname,
|
|
90
|
-
text: link.innerText?.slice(0, 100) || '',
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
queueEvent(event);
|
|
94
|
-
} catch {
|
|
95
|
-
// Invalid URL, ignore
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
{ capture: true, passive: true }
|
|
99
|
-
);
|
|
100
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { createBaseEvent } from './pageview';
|
|
2
|
-
import { queueEvent } from '../events';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Initialize JavaScript error tracking
|
|
6
|
-
*/
|
|
7
|
-
export function initErrorTracking(): void {
|
|
8
|
-
if (typeof window === 'undefined') {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Handle uncaught errors
|
|
13
|
-
window.addEventListener('error', (e) => {
|
|
14
|
-
const event = createBaseEvent('error');
|
|
15
|
-
event.event_name = 'js_error';
|
|
16
|
-
event.event_data = {
|
|
17
|
-
message: e.message || 'Unknown error',
|
|
18
|
-
filename: e.filename || '',
|
|
19
|
-
lineno: e.lineno || 0,
|
|
20
|
-
colno: e.colno || 0,
|
|
21
|
-
stack: e.error?.stack?.slice(0, 1000) || '',
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
queueEvent(event);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Handle unhandled promise rejections
|
|
28
|
-
window.addEventListener('unhandledrejection', (e) => {
|
|
29
|
-
const event = createBaseEvent('error');
|
|
30
|
-
event.event_name = 'unhandled_rejection';
|
|
31
|
-
|
|
32
|
-
let message = 'Unhandled Promise Rejection';
|
|
33
|
-
let stack = '';
|
|
34
|
-
|
|
35
|
-
if (e.reason instanceof Error) {
|
|
36
|
-
message = e.reason.message;
|
|
37
|
-
stack = e.reason.stack?.slice(0, 1000) || '';
|
|
38
|
-
} else if (typeof e.reason === 'string') {
|
|
39
|
-
message = e.reason;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
event.event_data = {
|
|
43
|
-
message,
|
|
44
|
-
stack,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
queueEvent(event);
|
|
48
|
-
});
|
|
49
|
-
}
|