UNPKG

@getpassage/react-native

Version:

Passage React Native SDK for mobile authentication

166 lines (165 loc) 5.98 kB
import { logger } from "./logger"; import { extractSessionId } from "./jwt-utils"; // Analytics event types - all events start with SDK_ export const ANALYTICS_EVENTS = { SDK_MODAL_OPENED: "SDK_MODAL_OPENED", SDK_MODAL_CLOSED: "SDK_MODAL_CLOSED", SDK_CONFIGURE_START: "SDK_CONFIGURE_START", SDK_CONFIGURE_SUCCESS: "SDK_CONFIGURE_SUCCESS", SDK_CONFIGURE_ERROR: "SDK_CONFIGURE_ERROR", SDK_CONFIGURATION_REQUEST: "SDK_CONFIGURATION_REQUEST", SDK_CONFIGURATION_SUCCESS: "SDK_CONFIGURATION_SUCCESS", SDK_CONFIGURATION_ERROR: "SDK_CONFIGURATION_ERROR", SDK_OPEN_REQUEST: "SDK_OPEN_REQUEST", SDK_OPEN_SUCCESS: "SDK_OPEN_SUCCESS", SDK_OPEN_ERROR: "SDK_OPEN_ERROR", SDK_ON_SUCCESS: "SDK_ON_SUCCESS", SDK_ON_ERROR: "SDK_ON_ERROR", SDK_REMOTE_CONTROL_CONNECT_START: "SDK_REMOTE_CONTROL_CONNECT_START", SDK_REMOTE_CONTROL_CONNECT_SUCCESS: "SDK_REMOTE_CONTROL_CONNECT_SUCCESS", SDK_REMOTE_CONTROL_CONNECT_ERROR: "SDK_REMOTE_CONTROL_CONNECT_ERROR", SDK_REMOTE_CONTROL_DISCONNECT: "SDK_REMOTE_CONTROL_DISCONNECT", SDK_WEBVIEW_SWITCH: "SDK_WEBVIEW_SWITCH", SDK_NAVIGATION_START: "SDK_NAVIGATION_START", SDK_NAVIGATION_SUCCESS: "SDK_NAVIGATION_SUCCESS", SDK_NAVIGATION_ERROR: "SDK_NAVIGATION_ERROR", SDK_COMMAND_RECEIVED: "SDK_COMMAND_RECEIVED", SDK_COMMAND_SUCCESS: "SDK_COMMAND_SUCCESS", SDK_COMMAND_ERROR: "SDK_COMMAND_ERROR", }; class AnalyticsManager { constructor() { this.enabled = false; this.analyticsUrl = "https://api.getpassage.ai/analytics"; this.sdkName = "react-native"; this.sessionId = null; // Only set if extracted from intent token this.eventQueue = []; this.BATCH_SIZE = 10; this.FLUSH_INTERVAL = 5000; // 5 seconds // Don't generate sessionId by default - only set when extracted from intent token try { // Get SDK version from package.json if available const packageJson = require("../package.json"); this.sdkVersion = packageJson.version; } catch (error) { // Fallback if package.json is not available this.sdkVersion = undefined; } } /** * Update intent token and extract session ID */ updateIntentToken(token) { if (!token) { this.intentToken = undefined; this.sessionId = null; return; } this.intentToken = token; this.sessionId = extractSessionId(token); // Use JWT utility logger.debug("[ANALYTICS] Intent token updated", { sessionId: this.sessionId, hasToken: !!token, }); } configure(config) { var _a; this.enabled = (_a = config.enabled) !== null && _a !== void 0 ? _a : true; // Default to enabled logger.debug("[ANALYTICS] Configured analytics", { enabled: this.enabled, analyticsUrl: this.analyticsUrl, sdkVersion: this.sdkVersion, sdkName: this.sdkName, sessionId: this.sessionId, }); if (this.enabled) { this.startBatchFlushTimer(); } } track(event, metadata) { if (!this.enabled) { return; } const analyticsEvent = { event, source: "sdk", sdkName: this.sdkName, sdkVersion: this.sdkVersion, platform: "react-native", timestamp: new Date().toISOString(), metadata: metadata || {}, }; // Only include sessionId if it was successfully extracted from intent token if (this.sessionId) { analyticsEvent.sessionId = this.sessionId; } this.eventQueue.push(analyticsEvent); logger.debug("[ANALYTICS] Event queued", { event, sessionId: this.sessionId, queueSize: this.eventQueue.length, }); // Flush immediately if queue is full if (this.eventQueue.length >= this.BATCH_SIZE) { this.flush(); } } async flush() { if (!this.enabled || this.eventQueue.length === 0) { return; } const eventsToSend = [...this.eventQueue]; this.eventQueue = []; try { logger.debug("[ANALYTICS] Flushing events", { count: eventsToSend.length, }); const response = await fetch(this.analyticsUrl, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ events: eventsToSend, }), }); if (response.ok) { logger.debug("[ANALYTICS] Events sent successfully", { count: eventsToSend.length, status: response.status, }); } else { logger.error("[ANALYTICS] Failed to send events", { status: response.status, response: await response.text(), }); // Re-queue events on failure this.eventQueue.unshift(...eventsToSend); } } catch (error) { logger.error("[ANALYTICS] Error sending events", error); // Re-queue events on error this.eventQueue.unshift(...eventsToSend); } } startBatchFlushTimer() { if (this.flushTimer) { clearInterval(this.flushTimer); } this.flushTimer = setInterval(() => { this.flush(); }, this.FLUSH_INTERVAL); } destroy() { if (this.flushTimer) { clearInterval(this.flushTimer); this.flushTimer = undefined; } // Flush any remaining events this.flush(); } } export const analytics = new AnalyticsManager();