dishub-analytics.sdk 1.1.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/index.js ADDED
@@ -0,0 +1,542 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ class AnalyticsClient {
6
+ constructor(config) {
7
+ this.visitorId = null;
8
+ this.sessionId = null;
9
+ this.heartbeatInterval = null;
10
+ this.config = {
11
+ trackPageViews: true,
12
+ trackClicks: true,
13
+ trackHeartbeat: true,
14
+ heartbeatInterval: 15000,
15
+ ...config,
16
+ };
17
+ }
18
+ getVisitorId() {
19
+ return this.visitorId;
20
+ }
21
+ getSessionId() {
22
+ return this.sessionId;
23
+ }
24
+ async init() {
25
+ // Get or create visitor ID
26
+ if (typeof window !== 'undefined' && typeof localStorage !== 'undefined') {
27
+ let id = localStorage.getItem('ib_visitor_id');
28
+ if (!id) {
29
+ id = this.generateId();
30
+ localStorage.setItem('ib_visitor_id', id);
31
+ }
32
+ this.visitorId = id;
33
+ // Track session
34
+ await this.trackSession();
35
+ // Set up heartbeat
36
+ if (this.config.trackHeartbeat) {
37
+ this.startHeartbeat();
38
+ }
39
+ // Set up click tracking
40
+ if (this.config.trackClicks) {
41
+ this.setupClickTracking();
42
+ this.setupInteractionTracking();
43
+ }
44
+ // Set up disconnect listeners
45
+ this.setupDisconnectListeners();
46
+ }
47
+ }
48
+ async identify(userId, name) {
49
+ if (!userId)
50
+ return;
51
+ console.log(`[Analytics] Identifying user: ${userId}${name ? ` (${name})` : ''}`);
52
+ const changed = this.config.externalUserId !== userId || this.config.externalUserName !== name;
53
+ this.config.externalUserId = userId;
54
+ this.config.externalUserName = name;
55
+ if (changed && typeof window !== 'undefined') {
56
+ // Re-track session to update externalUserId on backend
57
+ await this.trackSession();
58
+ }
59
+ }
60
+ async request(path, payload, retries = 2) {
61
+ const url = `${this.config.endpoint}${path}`;
62
+ const body = JSON.stringify(payload);
63
+ const headers = {
64
+ 'Content-Type': 'application/json',
65
+ 'x-tenant-key': this.config.apiKey,
66
+ };
67
+ for (let i = 0; i <= retries; i++) {
68
+ try {
69
+ const response = await fetch(url, {
70
+ method: 'POST',
71
+ headers,
72
+ body,
73
+ });
74
+ if (!response.ok) {
75
+ throw new Error(`HTTP error! status: ${response.status}`);
76
+ }
77
+ return await response.json();
78
+ }
79
+ catch (error) {
80
+ if (i === retries) {
81
+ console.error(`[Analytics] Request failed after ${retries + 1} attempts:`, error);
82
+ throw error;
83
+ }
84
+ const delay = Math.pow(2, i) * 1000;
85
+ await new Promise(resolve => setTimeout(resolve, delay));
86
+ }
87
+ }
88
+ }
89
+ async trackSession() {
90
+ if (!this.visitorId)
91
+ return;
92
+ try {
93
+ const data = await this.request('/track', {
94
+ type: 'session',
95
+ payload: {
96
+ visitorId: this.visitorId,
97
+ userAgent: navigator.userAgent,
98
+ referrer: document.referrer,
99
+ deviceType: this.getDeviceType(),
100
+ browser: this.getBrowser(),
101
+ os: this.getOS(),
102
+ language: navigator.language,
103
+ screenWidth: window.screen.width,
104
+ screenHeight: window.screen.height,
105
+ segment: this.getSegment(),
106
+ externalUserId: this.config.externalUserId,
107
+ externalUserName: this.config.externalUserName,
108
+ utmSource: this.config.utmSource || this.getUtmParam('utm_source'),
109
+ utmMedium: this.config.utmMedium || this.getUtmParam('utm_medium'),
110
+ utmCampaign: this.config.utmCampaign || this.getUtmParam('utm_campaign'),
111
+ },
112
+ });
113
+ if (data?.id) {
114
+ this.sessionId = data.id;
115
+ if (typeof localStorage !== 'undefined') {
116
+ localStorage.setItem('ib_v2_session_id', data.id);
117
+ }
118
+ }
119
+ }
120
+ catch (error) {
121
+ console.error('[Analytics] trackSession error:', error);
122
+ }
123
+ }
124
+ async trackEvent(name, category, value, metadata) {
125
+ if (!this.sessionId && typeof window !== 'undefined') {
126
+ this.sessionId = localStorage.getItem('ib_v2_session_id');
127
+ }
128
+ if (!this.sessionId)
129
+ return;
130
+ try {
131
+ await this.request('/track', {
132
+ type: 'event',
133
+ payload: {
134
+ sessionId: this.sessionId,
135
+ name,
136
+ category,
137
+ value,
138
+ metadata
139
+ }
140
+ });
141
+ }
142
+ catch (error) {
143
+ // Silently fail
144
+ }
145
+ }
146
+ async trackPageView(path, title) {
147
+ if (!this.sessionId && typeof window !== 'undefined') {
148
+ this.sessionId = localStorage.getItem('ib_v2_session_id');
149
+ }
150
+ if (!this.sessionId)
151
+ return;
152
+ try {
153
+ await this.request('/track', {
154
+ type: 'pageview',
155
+ payload: {
156
+ sessionId: this.sessionId,
157
+ url: window.location.href,
158
+ path: path || window.location.pathname,
159
+ title: title || document.title,
160
+ referrer: document.referrer,
161
+ },
162
+ });
163
+ }
164
+ catch (error) {
165
+ // Silently fail after retries
166
+ }
167
+ }
168
+ startHeartbeat() {
169
+ const sendHeartbeat = async () => {
170
+ if (!this.sessionId && typeof window !== 'undefined') {
171
+ this.sessionId = localStorage.getItem('ib_v2_session_id');
172
+ }
173
+ if (!this.sessionId)
174
+ return;
175
+ try {
176
+ await fetch(`${this.config.endpoint}/track`, {
177
+ method: 'POST',
178
+ headers: {
179
+ 'Content-Type': 'application/json',
180
+ 'x-tenant-key': this.config.apiKey,
181
+ },
182
+ body: JSON.stringify({
183
+ type: 'heartbeat',
184
+ payload: { sessionId: this.sessionId },
185
+ }),
186
+ });
187
+ }
188
+ catch (error) {
189
+ // Heartbeat failures are fine to ignore
190
+ }
191
+ };
192
+ // Regular interval
193
+ this.heartbeatInterval = setInterval(sendHeartbeat, this.config.heartbeatInterval);
194
+ // Immediate heartbeat on tab focus to improve real-time pulse
195
+ if (typeof window !== 'undefined' && window.addEventListener) {
196
+ window.addEventListener('visibilitychange', () => {
197
+ if (document.visibilityState === 'visible') {
198
+ sendHeartbeat();
199
+ }
200
+ else if (document.visibilityState === 'hidden') {
201
+ // When tab is hidden, send one last heartbeat to ensure accuracy
202
+ sendHeartbeat();
203
+ }
204
+ });
205
+ }
206
+ }
207
+ setupDisconnectListeners() {
208
+ if (typeof window === 'undefined' || !window.addEventListener)
209
+ return;
210
+ // Use beforeunload to signal departure
211
+ window.addEventListener('beforeunload', () => {
212
+ this.disconnect();
213
+ });
214
+ // Some browsers prefer visibilitychange for tracking closure
215
+ window.addEventListener('visibilitychange', () => {
216
+ });
217
+ }
218
+ async disconnect() {
219
+ if (!this.sessionId && typeof window !== 'undefined') {
220
+ this.sessionId = localStorage.getItem('ib_v2_session_id');
221
+ }
222
+ if (!this.sessionId)
223
+ return;
224
+ console.log('[Analytics] Disconnecting session:', this.sessionId);
225
+ const url = `${this.config.endpoint}/track`;
226
+ const payload = {
227
+ type: 'disconnect',
228
+ payload: { sessionId: this.sessionId }
229
+ };
230
+ try {
231
+ // Use keepalive to ensure the request finishes even if page closes
232
+ await fetch(url, {
233
+ method: 'POST',
234
+ headers: {
235
+ 'Content-Type': 'application/json',
236
+ 'x-tenant-key': this.config.apiKey,
237
+ },
238
+ body: JSON.stringify(payload),
239
+ keepalive: true,
240
+ });
241
+ }
242
+ catch (error) {
243
+ // Ignore disconnect errors
244
+ }
245
+ }
246
+ setupClickTracking() {
247
+ if (typeof window === 'undefined')
248
+ return;
249
+ const handleClick = (e) => {
250
+ const target = e.target;
251
+ const interactive = target.closest('button, a, [role="button"]');
252
+ if (interactive) {
253
+ const tag = interactive.tagName.toLowerCase();
254
+ this.trackEvent(`click_${tag}`, 'interaction', undefined, {
255
+ text: interactive.innerText?.trim()?.slice(0, 50),
256
+ id: interactive.id,
257
+ path: window.location.pathname,
258
+ });
259
+ }
260
+ };
261
+ window.addEventListener('click', handleClick);
262
+ }
263
+ async trackInteraction(type, element, x, y, metadata) {
264
+ if (!this.sessionId && typeof window !== 'undefined') {
265
+ this.sessionId = localStorage.getItem('ib_v2_session_id');
266
+ }
267
+ if (!this.sessionId)
268
+ return;
269
+ try {
270
+ await this.request('/track', {
271
+ type: 'interaction',
272
+ payload: {
273
+ sessionId: this.sessionId,
274
+ type,
275
+ element,
276
+ x: x || 0,
277
+ y: y || 0,
278
+ width: typeof window !== 'undefined' ? window.innerWidth : 0,
279
+ path: typeof window !== 'undefined' ? window.location.pathname : '/',
280
+ ...metadata
281
+ },
282
+ });
283
+ }
284
+ catch (error) {
285
+ // Silently fail
286
+ }
287
+ }
288
+ setupInteractionTracking() {
289
+ if (typeof window === 'undefined')
290
+ return;
291
+ // Track clicks
292
+ const handleInteraction = (e) => {
293
+ if (!this.sessionId)
294
+ return;
295
+ const x = e.pageX;
296
+ const y = e.pageY;
297
+ const width = window.innerWidth;
298
+ const target = e.target;
299
+ const selector = this.getSelector(target);
300
+ this.request('/track', {
301
+ type: 'interaction',
302
+ payload: {
303
+ sessionId: this.sessionId,
304
+ x,
305
+ y,
306
+ width,
307
+ element: selector,
308
+ path: window.location.pathname,
309
+ type: 'click'
310
+ },
311
+ }).catch(() => { });
312
+ };
313
+ window.addEventListener('click', handleInteraction, { capture: true });
314
+ // Track scroll depth
315
+ let maxScrollDepth = 0;
316
+ let scrollTimeout;
317
+ const handleScroll = () => {
318
+ clearTimeout(scrollTimeout);
319
+ scrollTimeout = setTimeout(() => {
320
+ if (!this.sessionId)
321
+ return;
322
+ const scrollDepth = Math.round((window.scrollY + window.innerHeight) / document.documentElement.scrollHeight * 100);
323
+ if (scrollDepth > maxScrollDepth) {
324
+ maxScrollDepth = scrollDepth;
325
+ this.request('/track', {
326
+ type: 'interaction',
327
+ payload: {
328
+ sessionId: this.sessionId,
329
+ x: 0,
330
+ y: window.scrollY,
331
+ width: window.innerWidth,
332
+ element: `scroll-depth-${scrollDepth}`,
333
+ path: window.location.pathname,
334
+ type: 'scroll'
335
+ },
336
+ }).catch(() => { });
337
+ }
338
+ }, 500);
339
+ };
340
+ window.addEventListener('scroll', handleScroll, { passive: true });
341
+ }
342
+ getSelector(el) {
343
+ try {
344
+ if (el.id)
345
+ return `#${el.id}`;
346
+ const path = [];
347
+ let parent = el;
348
+ while (parent && parent.nodeType === Node.ELEMENT_NODE) {
349
+ let selector = parent.nodeName.toLowerCase();
350
+ if (parent.id) {
351
+ selector += `#${parent.id}`;
352
+ path.unshift(selector);
353
+ break;
354
+ }
355
+ else {
356
+ let sib = parent, nth = 1;
357
+ while (sib = sib.previousElementSibling) {
358
+ if (sib.nodeName.toLowerCase() == selector)
359
+ nth++;
360
+ }
361
+ if (nth != 1)
362
+ selector += `:nth-of-type(${nth})`;
363
+ }
364
+ path.unshift(selector);
365
+ parent = parent.parentElement;
366
+ }
367
+ return path.join(' > ');
368
+ }
369
+ catch (e) {
370
+ return 'unknown';
371
+ }
372
+ }
373
+ getDeviceType() {
374
+ if (typeof window === 'undefined')
375
+ return 'desktop';
376
+ const ua = navigator.userAgent.toLowerCase();
377
+ const isMobile = /mobile|iphone|ipod|android|blackberry|opera mini|iemobile|wpdesktop/i.test(ua);
378
+ // iPad Pro identifies as Macintosh but has touch points.
379
+ const isDisguisedIOS = navigator.userAgent.includes('Macintosh') &&
380
+ navigator.maxTouchPoints && navigator.maxTouchPoints > 1;
381
+ const isTablet = /tablet|ipad|playbook|silk|(android(?!.*mobi))/i.test(ua) ||
382
+ (isDisguisedIOS && Math.max(window.screen.width, window.screen.height) >= 768);
383
+ if (isTablet)
384
+ return 'tablet';
385
+ if (isMobile || (isDisguisedIOS && Math.max(window.screen.width, window.screen.height) < 768))
386
+ return 'mobile';
387
+ return 'desktop';
388
+ }
389
+ getBrowser() {
390
+ if (typeof window === 'undefined')
391
+ return 'Unknown';
392
+ const ua = navigator.userAgent;
393
+ if (ua.includes('Edg/') || ua.includes('Edg'))
394
+ return 'Edge';
395
+ if (ua.includes('OPR/') || ua.includes('Opera'))
396
+ return 'Opera';
397
+ if (ua.includes('Firefox') || ua.includes('FxiOS'))
398
+ return 'Firefox';
399
+ if (ua.includes('CriOS'))
400
+ return 'Chrome';
401
+ if (ua.includes('SamsungBrowser'))
402
+ return 'Samsung Browser';
403
+ if (ua.includes('Trident'))
404
+ return 'Internet Explorer';
405
+ if (ua.includes('Chrome'))
406
+ return 'Chrome';
407
+ if (ua.includes('Safari'))
408
+ return 'Safari';
409
+ return 'Unknown';
410
+ }
411
+ getOS() {
412
+ if (typeof window === 'undefined')
413
+ return 'Unknown';
414
+ const ua = navigator.userAgent;
415
+ if (ua.includes('iPhone') || ua.includes('iPad') || ua.includes('iPod'))
416
+ return 'iOS';
417
+ if (ua.includes('CrOS'))
418
+ return 'ChromeOS';
419
+ if (ua.includes('Android'))
420
+ return 'Android';
421
+ if (ua.includes('Mac OS') || ua.includes('Macintosh')) {
422
+ // Only treat as iOS if it's a touch device and NOT reporting itself as a Mac platform usually.
423
+ // On iPad, navigator.platform is 'MacIntel' but maxTouchPoints > 1.
424
+ if (navigator.maxTouchPoints && navigator.maxTouchPoints > 1)
425
+ return 'iOS';
426
+ return 'Mac OS';
427
+ }
428
+ if (ua.includes('Windows'))
429
+ return 'Windows';
430
+ if (ua.includes('Linux'))
431
+ return 'Linux';
432
+ return 'Unknown';
433
+ }
434
+ getSegment() {
435
+ if (this.config.segment)
436
+ return this.config.segment;
437
+ if (typeof window !== 'undefined') {
438
+ const path = window.location.pathname;
439
+ if (path.includes('admin'))
440
+ return 'admin';
441
+ if (path.includes('investor'))
442
+ return 'investor';
443
+ if (path.includes('project-owner'))
444
+ return 'project-owner';
445
+ }
446
+ return 'front';
447
+ }
448
+ getUtmParam(param) {
449
+ if (typeof window === 'undefined')
450
+ return undefined;
451
+ const urlParams = new URLSearchParams(window.location.search);
452
+ return urlParams.get(param) || undefined;
453
+ }
454
+ generateId() {
455
+ // Simple UUID v4 generator
456
+ return 'xxxxxxxx-xxxx-4xxx-yxxxxxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
457
+ const r = Math.random() * 16 | 0;
458
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
459
+ return v.toString(16);
460
+ });
461
+ }
462
+ destroy() {
463
+ if (this.heartbeatInterval) {
464
+ clearInterval(this.heartbeatInterval);
465
+ }
466
+ }
467
+ }
468
+
469
+ const Context = React.createContext(null);
470
+ function AnalyticsProvider({ children, apiKey, endpoint, config }) {
471
+ const [sessionId, setSessionId] = React.useState(null);
472
+ const [visitorId, setVisitorId] = React.useState(null);
473
+ const client = React.useMemo(() => {
474
+ return new AnalyticsClient({
475
+ apiKey,
476
+ endpoint,
477
+ ...config,
478
+ });
479
+ }, [apiKey, endpoint, JSON.stringify(config)]);
480
+ React.useEffect(() => {
481
+ const init = async () => {
482
+ await client.init();
483
+ setVisitorId(client.getVisitorId());
484
+ setSessionId(client.getSessionId());
485
+ };
486
+ init();
487
+ return () => {
488
+ client.destroy();
489
+ };
490
+ }, [client]);
491
+ // Track page views automatically if enabled
492
+ React.useEffect(() => {
493
+ if (typeof window === 'undefined')
494
+ return;
495
+ const handleRouteChange = () => {
496
+ client.trackPageView();
497
+ };
498
+ // Track initial page load
499
+ handleRouteChange();
500
+ // Listen for history changes (SPA navigation)
501
+ window.addEventListener('popstate', handleRouteChange);
502
+ // Standard SPA routing often uses pushState/replaceState
503
+ const originalPushState = window.history.pushState;
504
+ const originalReplaceState = window.history.replaceState;
505
+ window.history.pushState = function (...args) {
506
+ originalPushState.apply(this, args);
507
+ handleRouteChange();
508
+ };
509
+ window.history.replaceState = function (...args) {
510
+ originalReplaceState.apply(this, args);
511
+ handleRouteChange();
512
+ };
513
+ return () => {
514
+ window.removeEventListener('popstate', handleRouteChange);
515
+ window.history.pushState = originalPushState;
516
+ window.history.replaceState = originalReplaceState;
517
+ };
518
+ }, [client]);
519
+ const contextValue = React.useMemo(() => ({
520
+ trackEvent: client.trackEvent.bind(client),
521
+ trackInteraction: client.trackInteraction.bind(client),
522
+ identify: async (userId, name) => {
523
+ await client.identify(userId, name);
524
+ setSessionId(client.getSessionId());
525
+ },
526
+ sessionId,
527
+ visitorId
528
+ }), [client, sessionId, visitorId]);
529
+ return (React.createElement(Context.Provider, { value: contextValue }, children));
530
+ }
531
+ function useAnalytics() {
532
+ const context = React.useContext(Context);
533
+ if (!context) {
534
+ throw new Error('useAnalytics must be used within an AnalyticsProvider');
535
+ }
536
+ return context;
537
+ }
538
+
539
+ exports.AnalyticsClient = AnalyticsClient;
540
+ exports.AnalyticsProvider = AnalyticsProvider;
541
+ exports.useAnalytics = useAnalytics;
542
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/client.ts","../src/react.tsx"],"sourcesContent":["import { AnalyticsConfig } from './types';\n\nexport class AnalyticsClient {\n private config: AnalyticsConfig;\n private visitorId: string | null = null;\n private sessionId: string | null = null;\n private heartbeatInterval: NodeJS.Timeout | null = null;\n\n constructor(config: AnalyticsConfig) {\n this.config = {\n trackPageViews: true,\n trackClicks: true,\n trackHeartbeat: true,\n heartbeatInterval: 15000,\n ...config,\n };\n }\n\n public getVisitorId(): string | null {\n return this.visitorId;\n }\n\n public getSessionId(): string | null {\n return this.sessionId;\n }\n\n async init(): Promise<void> {\n // Get or create visitor ID\n if (typeof window !== 'undefined' && typeof localStorage !== 'undefined') {\n let id = localStorage.getItem('ib_visitor_id');\n if (!id) {\n id = this.generateId();\n localStorage.setItem('ib_visitor_id', id);\n }\n this.visitorId = id;\n\n // Track session\n await this.trackSession();\n\n // Set up heartbeat\n if (this.config.trackHeartbeat) {\n this.startHeartbeat();\n }\n\n // Set up click tracking\n if (this.config.trackClicks) {\n this.setupClickTracking();\n this.setupInteractionTracking();\n }\n\n // Set up disconnect listeners\n this.setupDisconnectListeners();\n }\n }\n\n async identify(userId: string, name?: string): Promise<void> {\n if (!userId) return;\n\n console.log(`[Analytics] Identifying user: ${userId}${name ? ` (${name})` : ''}`);\n const changed = this.config.externalUserId !== userId || this.config.externalUserName !== name;\n this.config.externalUserId = userId;\n this.config.externalUserName = name;\n\n if (changed && typeof window !== 'undefined') {\n // Re-track session to update externalUserId on backend\n await this.trackSession();\n }\n }\n\n private async request(path: string, payload: any, retries = 2): Promise<any> {\n const url = `${this.config.endpoint}${path}`;\n const body = JSON.stringify(payload);\n const headers = {\n 'Content-Type': 'application/json',\n 'x-tenant-key': this.config.apiKey,\n };\n\n for (let i = 0; i <= retries; i++) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n return await response.json();\n } catch (error) {\n if (i === retries) {\n console.error(`[Analytics] Request failed after ${retries + 1} attempts:`, error);\n throw error;\n }\n const delay = Math.pow(2, i) * 1000;\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n\n private async trackSession(): Promise<void> {\n if (!this.visitorId) return;\n\n try {\n const data = await this.request('/track', {\n type: 'session',\n payload: {\n visitorId: this.visitorId,\n userAgent: navigator.userAgent,\n referrer: document.referrer,\n deviceType: this.getDeviceType(),\n browser: this.getBrowser(),\n os: this.getOS(),\n language: navigator.language,\n screenWidth: window.screen.width,\n screenHeight: window.screen.height,\n segment: this.getSegment(),\n externalUserId: this.config.externalUserId,\n externalUserName: this.config.externalUserName,\n utmSource: this.config.utmSource || this.getUtmParam('utm_source'),\n utmMedium: this.config.utmMedium || this.getUtmParam('utm_medium'),\n utmCampaign: this.config.utmCampaign || this.getUtmParam('utm_campaign'),\n },\n });\n\n if (data?.id) {\n this.sessionId = data.id;\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('ib_v2_session_id', data.id);\n }\n }\n } catch (error) {\n console.error('[Analytics] trackSession error:', error);\n }\n }\n\n async trackEvent(name: string, category?: string, value?: string, metadata?: Record<string, any>): Promise<void> {\n if (!this.sessionId && typeof window !== 'undefined') {\n this.sessionId = localStorage.getItem('ib_v2_session_id');\n }\n\n if (!this.sessionId) return;\n\n try {\n await this.request('/track', {\n type: 'event',\n payload: {\n sessionId: this.sessionId,\n name,\n category,\n value,\n metadata\n }\n });\n } catch (error) {\n // Silently fail\n }\n }\n\n async trackPageView(path?: string, title?: string): Promise<void> {\n if (!this.sessionId && typeof window !== 'undefined') {\n this.sessionId = localStorage.getItem('ib_v2_session_id');\n }\n\n if (!this.sessionId) return;\n\n try {\n await this.request('/track', {\n type: 'pageview',\n payload: {\n sessionId: this.sessionId,\n url: window.location.href,\n path: path || window.location.pathname,\n title: title || document.title,\n referrer: document.referrer,\n },\n });\n } catch (error) {\n // Silently fail after retries\n }\n }\n\n private startHeartbeat(): void {\n const sendHeartbeat = async () => {\n if (!this.sessionId && typeof window !== 'undefined') {\n this.sessionId = localStorage.getItem('ib_v2_session_id');\n }\n if (!this.sessionId) return;\n\n try {\n await fetch(`${this.config.endpoint}/track`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-tenant-key': this.config.apiKey,\n },\n body: JSON.stringify({\n type: 'heartbeat',\n payload: { sessionId: this.sessionId },\n }),\n });\n } catch (error) {\n // Heartbeat failures are fine to ignore\n }\n };\n\n // Regular interval\n this.heartbeatInterval = setInterval(sendHeartbeat, this.config.heartbeatInterval);\n\n // Immediate heartbeat on tab focus to improve real-time pulse\n if (typeof window !== 'undefined' && window.addEventListener) {\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n sendHeartbeat();\n } else if (document.visibilityState === 'hidden') {\n // When tab is hidden, send one last heartbeat to ensure accuracy\n sendHeartbeat();\n }\n });\n }\n }\n\n private setupDisconnectListeners(): void {\n if (typeof window === 'undefined' || !window.addEventListener) return;\n\n // Use beforeunload to signal departure\n window.addEventListener('beforeunload', () => {\n this.disconnect();\n });\n\n // Some browsers prefer visibilitychange for tracking closure\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n // We don't disconnect on hidden (might be just tab switch), \n // but the backend timeout or beforeunload will handle the rest.\n // However, we could provide an option for strict real-time.\n }\n });\n }\n\n public async disconnect(): Promise<void> {\n if (!this.sessionId && typeof window !== 'undefined') {\n this.sessionId = localStorage.getItem('ib_v2_session_id');\n }\n if (!this.sessionId) return;\n\n console.log('[Analytics] Disconnecting session:', this.sessionId);\n\n const url = `${this.config.endpoint}/track`;\n const payload = {\n type: 'disconnect',\n payload: { sessionId: this.sessionId }\n };\n\n try {\n // Use keepalive to ensure the request finishes even if page closes\n await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-tenant-key': this.config.apiKey,\n },\n body: JSON.stringify(payload),\n keepalive: true,\n });\n } catch (error) {\n // Ignore disconnect errors\n }\n }\n\n private setupClickTracking(): void {\n if (typeof window === 'undefined') return;\n\n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n const interactive = target.closest('button, a, [role=\"button\"]');\n\n if (interactive) {\n const tag = interactive.tagName.toLowerCase();\n this.trackEvent(`click_${tag}`, 'interaction', undefined, {\n text: (interactive as any).innerText?.trim()?.slice(0, 50),\n id: interactive.id,\n path: window.location.pathname,\n });\n }\n };\n\n window.addEventListener('click', handleClick);\n }\n\n async trackInteraction(type: string, element: string, x?: number, y?: number, metadata?: Record<string, any>): Promise<void> {\n if (!this.sessionId && typeof window !== 'undefined') {\n this.sessionId = localStorage.getItem('ib_v2_session_id');\n }\n if (!this.sessionId) return;\n\n try {\n await this.request('/track', {\n type: 'interaction',\n payload: {\n sessionId: this.sessionId,\n type,\n element,\n x: x || 0,\n y: y || 0,\n width: typeof window !== 'undefined' ? window.innerWidth : 0,\n path: typeof window !== 'undefined' ? window.location.pathname : '/',\n ...metadata\n },\n });\n } catch (error) {\n // Silently fail\n }\n }\n\n private setupInteractionTracking(): void {\n if (typeof window === 'undefined') return;\n\n // Track clicks\n const handleInteraction = (e: MouseEvent) => {\n if (!this.sessionId) return;\n\n const x = e.pageX;\n const y = e.pageY;\n const width = window.innerWidth;\n const target = e.target as HTMLElement;\n const selector = this.getSelector(target);\n\n this.request('/track', {\n type: 'interaction',\n payload: {\n sessionId: this.sessionId,\n x,\n y,\n width,\n element: selector,\n path: window.location.pathname,\n type: 'click'\n },\n }).catch(() => { });\n };\n\n window.addEventListener('click', handleInteraction, { capture: true });\n\n // Track scroll depth\n let maxScrollDepth = 0;\n let scrollTimeout: NodeJS.Timeout;\n\n const handleScroll = () => {\n clearTimeout(scrollTimeout);\n scrollTimeout = setTimeout(() => {\n if (!this.sessionId) return;\n\n const scrollDepth = Math.round((window.scrollY + window.innerHeight) / document.documentElement.scrollHeight * 100);\n\n if (scrollDepth > maxScrollDepth) {\n maxScrollDepth = scrollDepth;\n\n this.request('/track', {\n type: 'interaction',\n payload: {\n sessionId: this.sessionId,\n x: 0,\n y: window.scrollY,\n width: window.innerWidth,\n element: `scroll-depth-${scrollDepth}`,\n path: window.location.pathname,\n type: 'scroll'\n },\n }).catch(() => { });\n }\n }, 500);\n };\n\n window.addEventListener('scroll', handleScroll, { passive: true });\n }\n\n private getSelector(el: HTMLElement): string {\n try {\n if (el.id) return `#${el.id}`;\n const path: string[] = [];\n let parent: HTMLElement | null = el;\n while (parent && parent.nodeType === Node.ELEMENT_NODE) {\n let selector = parent.nodeName.toLowerCase();\n if (parent.id) {\n selector += `#${parent.id}`;\n path.unshift(selector);\n break;\n } else {\n let sib = parent, nth = 1;\n while (sib = sib.previousElementSibling as HTMLElement) {\n if (sib.nodeName.toLowerCase() == selector) nth++;\n }\n if (nth != 1) selector += `:nth-of-type(${nth})`;\n }\n path.unshift(selector);\n parent = parent.parentElement;\n }\n return path.join(' > ');\n } catch (e) {\n return 'unknown';\n }\n }\n\n private getDeviceType(): string {\n if (typeof window === 'undefined') return 'desktop';\n const ua = navigator.userAgent.toLowerCase();\n\n const isMobile = /mobile|iphone|ipod|android|blackberry|opera mini|iemobile|wpdesktop/i.test(ua);\n // iPad Pro identifies as Macintosh but has touch points. \n const isDisguisedIOS = navigator.userAgent.includes('Macintosh') &&\n navigator.maxTouchPoints && navigator.maxTouchPoints > 1;\n\n const isTablet = /tablet|ipad|playbook|silk|(android(?!.*mobi))/i.test(ua) ||\n (isDisguisedIOS && Math.max(window.screen.width, window.screen.height) >= 768);\n\n if (isTablet) return 'tablet';\n if (isMobile || (isDisguisedIOS && Math.max(window.screen.width, window.screen.height) < 768)) return 'mobile';\n return 'desktop';\n }\n\n private getBrowser(): string {\n if (typeof window === 'undefined') return 'Unknown';\n const ua = navigator.userAgent;\n\n if (ua.includes('Edg/') || ua.includes('Edg')) return 'Edge';\n if (ua.includes('OPR/') || ua.includes('Opera')) return 'Opera';\n if (ua.includes('Firefox') || ua.includes('FxiOS')) return 'Firefox';\n if (ua.includes('CriOS')) return 'Chrome';\n if (ua.includes('SamsungBrowser')) return 'Samsung Browser';\n if (ua.includes('Trident')) return 'Internet Explorer';\n if (ua.includes('Chrome')) return 'Chrome';\n if (ua.includes('Safari')) return 'Safari';\n return 'Unknown';\n }\n\n private getOS(): string {\n if (typeof window === 'undefined') return 'Unknown';\n const ua = navigator.userAgent;\n\n if (ua.includes('iPhone') || ua.includes('iPad') || ua.includes('iPod')) return 'iOS';\n if (ua.includes('CrOS')) return 'ChromeOS';\n if (ua.includes('Android')) return 'Android';\n if (ua.includes('Mac OS') || ua.includes('Macintosh')) {\n // Only treat as iOS if it's a touch device and NOT reporting itself as a Mac platform usually.\n // On iPad, navigator.platform is 'MacIntel' but maxTouchPoints > 1.\n if (navigator.maxTouchPoints && navigator.maxTouchPoints > 1) return 'iOS';\n return 'Mac OS';\n }\n if (ua.includes('Windows')) return 'Windows';\n if (ua.includes('Linux')) return 'Linux';\n return 'Unknown';\n }\n\n private getSegment(): string {\n if (this.config.segment) return this.config.segment;\n\n if (typeof window !== 'undefined') {\n const path = window.location.pathname;\n if (path.includes('admin')) return 'admin';\n if (path.includes('investor')) return 'investor';\n if (path.includes('project-owner')) return 'project-owner';\n }\n\n return 'front';\n }\n\n private getUtmParam(param: string): string | undefined {\n if (typeof window === 'undefined') return undefined;\n const urlParams = new URLSearchParams(window.location.search);\n return urlParams.get(param) || undefined;\n }\n\n private generateId(): string {\n // Simple UUID v4 generator\n return 'xxxxxxxx-xxxx-4xxx-yxxxxxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n }\n\n destroy(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n }\n }\n}\n","import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';\nimport { AnalyticsClient } from './client';\nimport { AnalyticsConfig, AnalyticsContext } from './types';\n\nconst Context = createContext<AnalyticsContext | null>(null);\n\nexport interface AnalyticsProviderProps {\n children: React.ReactNode;\n apiKey: string;\n endpoint: string;\n config?: Partial<AnalyticsConfig>;\n}\n\nexport function AnalyticsProvider({ children, apiKey, endpoint, config }: AnalyticsProviderProps) {\n const [sessionId, setSessionId] = useState<string | null>(null);\n const [visitorId, setVisitorId] = useState<string | null>(null);\n\n const client = useMemo(() => {\n return new AnalyticsClient({\n apiKey,\n endpoint,\n ...config,\n });\n }, [apiKey, endpoint, JSON.stringify(config)]);\n\n useEffect(() => {\n const init = async () => {\n await client.init();\n setVisitorId(client.getVisitorId());\n setSessionId(client.getSessionId());\n };\n\n init();\n\n return () => {\n client.destroy();\n };\n }, [client]);\n\n // Track page views automatically if enabled\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const handleRouteChange = () => {\n client.trackPageView();\n };\n\n // Track initial page load\n handleRouteChange();\n\n // Listen for history changes (SPA navigation)\n window.addEventListener('popstate', handleRouteChange);\n\n // Standard SPA routing often uses pushState/replaceState\n const originalPushState = window.history.pushState;\n const originalReplaceState = window.history.replaceState;\n\n window.history.pushState = function (...args) {\n originalPushState.apply(this, args);\n handleRouteChange();\n };\n\n window.history.replaceState = function (...args) {\n originalReplaceState.apply(this, args);\n handleRouteChange();\n };\n\n return () => {\n window.removeEventListener('popstate', handleRouteChange);\n window.history.pushState = originalPushState;\n window.history.replaceState = originalReplaceState;\n };\n }, [client]);\n\n const contextValue = useMemo(() => ({\n trackEvent: client.trackEvent.bind(client),\n trackInteraction: client.trackInteraction.bind(client),\n identify: async (userId: string, name?: string) => {\n await client.identify(userId, name);\n setSessionId(client.getSessionId());\n },\n sessionId,\n visitorId\n }), [client, sessionId, visitorId]);\n\n return (\n <Context.Provider value={contextValue}>\n {children}\n </Context.Provider>\n );\n}\n\nexport function useAnalytics() {\n const context = useContext(Context);\n if (!context) {\n throw new Error('useAnalytics must be used within an AnalyticsProvider');\n }\n return context;\n}\n"],"names":["createContext","useState","useMemo","useEffect","useContext"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { AnalyticsConfig, AnalyticsContext } from './types';
3
+ export interface AnalyticsProviderProps {
4
+ children: React.ReactNode;
5
+ apiKey: string;
6
+ endpoint: string;
7
+ config?: Partial<AnalyticsConfig>;
8
+ }
9
+ export declare function AnalyticsProvider({ children, apiKey, endpoint, config }: AnalyticsProviderProps): React.JSX.Element;
10
+ export declare function useAnalytics(): AnalyticsContext;
@@ -0,0 +1,28 @@
1
+ export interface AnalyticsConfig {
2
+ apiKey: string;
3
+ endpoint: string;
4
+ trackPageViews?: boolean;
5
+ trackClicks?: boolean;
6
+ trackHeartbeat?: boolean;
7
+ heartbeatInterval?: number;
8
+ excludePaths?: string[];
9
+ segment?: string;
10
+ externalUserId?: string;
11
+ externalUserName?: string;
12
+ utmSource?: string;
13
+ utmMedium?: string;
14
+ utmCampaign?: string;
15
+ }
16
+ export interface TrackEventOptions {
17
+ name: string;
18
+ category?: string;
19
+ value?: string;
20
+ metadata?: Record<string, unknown>;
21
+ }
22
+ export interface AnalyticsContext {
23
+ trackEvent: (name: string, category?: string, value?: string, metadata?: Record<string, unknown>) => Promise<void>;
24
+ trackInteraction: (type: string, element: string, x?: number, y?: number, metadata?: Record<string, unknown>) => Promise<void>;
25
+ identify: (userId: string, name?: string) => Promise<void>;
26
+ sessionId: string | null;
27
+ visitorId: string | null;
28
+ }