UNPKG

overcentric

Version:

Overcentric watches your website, product, and users - and tells you what matters and what to do about it.

115 lines (114 loc) 4.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventQueue = void 0; class EventQueue { constructor(config) { this.eventQueue = []; this.flushTimeoutId = null; this.MAX_BATCH_SIZE = 10; this.FLUSH_INTERVAL = 2000; // 2 seconds this.MAX_RETRIES = 3; this.DEFAULT_ENDPOINT = 'http://localhost:4000/api/events'; this.config = config; this.setupEventListeners(); } static getInstance(config) { if (!EventQueue.instance) { EventQueue.instance = new EventQueue(config); } return EventQueue.instance; } logDebug(message) { var _a, _b; (_b = (_a = this.config).onDebugLog) === null || _b === void 0 ? void 0 : _b.call(_a, message); } setupEventListeners() { window.addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') { this.flushEvents(); } }); window.addEventListener('beforeunload', () => { this.flushEvents(); }); } addEvent(eventName, properties) { this.eventQueue.push({ eventName, properties, timestamp: Date.now() }); this.logDebug(`overcentric: Tracking event: ${eventName}`); this.logDebug(`overcentric: Event properties: ${JSON.stringify(properties)}`); if (this.eventQueue.length >= this.MAX_BATCH_SIZE) { this.flushEvents(); } else { this.scheduleFlush(); } } scheduleFlush() { if (this.flushTimeoutId) return; this.flushTimeoutId = setTimeout(() => { this.flushTimeoutId = null; this.flushEvents(); }, this.FLUSH_INTERVAL); } async flushEvents() { if (this.eventQueue.length === 0) return; const events = [...this.eventQueue]; this.eventQueue = []; const payload = { projectId: this.config.projectId, events, clientTimestamp: Date.now() }; const endpoint = this.config.endpoint || this.DEFAULT_ENDPOINT; try { // Try sendBeacon first (most efficient, works even on page unload) if (navigator.sendBeacon) { const blob = new Blob([JSON.stringify(payload)], { type: 'application/json' }); const success = navigator.sendBeacon(endpoint, blob); if (success) { this.logDebug(`overcentric: Sent ${events.length} events via beacon`); return; } } // Fall back to fetch if sendBeacon fails or isn't available let retries = 0; while (retries < this.MAX_RETRIES) { try { const response = await fetch(endpoint, { method: 'POST', body: JSON.stringify(payload), headers: { 'Content-Type': 'application/json' }, keepalive: true }); if (response.ok) { this.logDebug(`overcentric: Sent ${events.length} events via fetch`); return; } } catch (error) { this.logDebug(`overcentric: Error sending events (attempt ${retries + 1}): ${error}`); retries++; if (retries < this.MAX_RETRIES) { await new Promise(resolve => setTimeout(resolve, 1000 * retries)); } } } // If all retries failed, queue the events again this.eventQueue.push(...events); this.logDebug(`overcentric: Failed to send events after ${this.MAX_RETRIES} retries. Requeued ${events.length} events.`); } catch (error) { this.logDebug(`overcentric: Error in flushEvents: ${error}`); this.eventQueue.push(...events); } } } exports.EventQueue = EventQueue;