UNPKG

uni-analytics-sdk

Version:

A universal SDK for analytics and logging.

276 lines (230 loc) 8.42 kB
import { SDKEvent, Provider, UniversalSDKConfig, } from '@/interfaces'; // export class UniversalSDK { // private queue: SDKEvent[] = []; // private providers: Provider[] = []; // constructor() { // console.log("Universal SDK Initialized."); // } // public init() { // // Initialization logic will go here // } // public track(eventName: string, properties?: Record<string, any>) { // console.log(`Tracking event: ${eventName}`, properties); // // Queueing logic will go here // } // public identify(userId: string, traits?: Record<string, any>) { // console.log(`Identifying user: ${userId}`, traits); // // Queueing logic will go here // } // } /** * @fileoverview This file contains the core implementation of the Universal Analytics and Logging SDK. * It defines the main SDK class, provider interfaces, and the logic for event queueing, * batching, and dispatching. */ // ================================================================================================= // SECTION: Core SDK Implementation // ================================================================================================= /** * The main class for the Universal SDK. It orchestrates providers and manages the event lifecycle. */ /** * The core of the Universal SDK. It manages the event queue, provider lifecycle, * and orchestrates the sending of data. */ export class UniversalSDK { private queue: SDKEvent[] = []; private providers: Provider[] = []; private config: UniversalSDKConfig; private flushInterval: NodeJS.Timeout | null = null; private isInitialized = false; constructor(config: UniversalSDKConfig) { this.config = { queueSize: 20, flushInterval: 10000, // 10 seconds debug: false, ...config, }; } /** * Initializes the SDK and sets up all configured providers. * This must be called before any tracking or identification can occur. */ public async init(): Promise<void> { if (this.isInitialized) { if (this.config.debug) { console.warn('SDK already initialized.'); } return; } if (this.config.debug) { console.log('SDK Initializing with config:', this.config); } this.providers = this.config.providers; const setupPromises = this.providers.map(provider => { const providerConfig = this.config.providerConfigs?.[provider.name] || {}; return provider.setup(providerConfig).catch((error: any) => { console.error(`[SDK] Failed to setup provider: ${provider.name}`, error); }); }); await Promise.all(setupPromises); this.flushInterval = setInterval(() => this.flush(), this.config.flushInterval); this.isInitialized = true; if (this.config.debug) { console.log('SDK Initialized successfully.'); } } /** * Tracks a custom event. * @param eventName The name of the event. * @param properties An object of key-value pairs for additional data. */ public track(eventName: string, properties?: Record<string, any>): void { this.enqueue({ type: 'track', eventName, properties, timestamp: Date.now(), }); } /** * Identifies a user and associates traits with them. * @param userId A unique identifier for the user. * @param traits An object of user properties. */ public identify(userId: string, traits?: Record<string, any>): void { this.enqueue({ type: 'identify', userId, traits, timestamp: Date.now(), }); } /** * Captures a manually thrown error or exception. * @param error The error object. * @param context Additional context for the error. */ public captureException(error: Error, context?: Record<string, any>): void { this.enqueue({ type: 'captureException', error, context, timestamp: Date.now(), }); } /** * Captures a log message. * @param message The message to log. * @param level The severity level of the message. */ public captureMessage(message: string, level: 'info' | 'warning' | 'error' = 'info'): void { this.enqueue({ type: 'captureMessage', message, level, timestamp: Date.now(), }); } /** * Adds an event to the processing queue. * @param event The SDKEvent to enqueue. */ private enqueue(event: Omit<SDKEvent, 'timestamp'> & { timestamp?: number }): void { if (!this.isInitialized) { console.error('[SDK] SDK not initialized. Call .init() first.'); return; } const completeEvent: SDKEvent = { timestamp: Date.now(), ...event, }; this.queue.push(completeEvent); if (this.config.debug) { console.log('[SDK] Event enqueued:', completeEvent); console.log(`[SDK] Queue size: ${this.queue.length}`); } if (this.queue.length >= this.config.queueSize!) { this.flush(); } } /** * Sends all events in the queue to the configured providers. */ private async flush(): Promise<void> { if (this.queue.length === 0) { return; } const eventsToProcess = [...this.queue]; this.queue = []; if (this.config.debug) { console.log(`[SDK] Flushing ${eventsToProcess.length} events...`); } const processingPromises = this.providers.map(provider => { return provider.processEvents(eventsToProcess).catch((error: any) => { console.error(`[SDK] Error processing events for provider: ${provider.name}`, error); }); }); await Promise.all(processingPromises); } /** * Cleans up resources, like the flush interval. */ public shutdown(): void { if (this.flushInterval) { clearInterval(this.flushInterval); } this.flush(); // Final flush before shutting down } } // ================================================================================================= // SECTION: Example Usage (for demonstration) // ================================================================================================= // This part would be in a separate file in a real application. /* // 1. Define a mock provider for demonstration class ConsoleLogProvider implements Provider { name = 'ConsoleLogProvider'; async setup(config: Record<string, any>): Promise<void> { console.log(`[ConsoleLogProvider] Setup with config:`, config); } async processEvents(events: SDKEvent[]): Promise<void> { console.log(`[ConsoleLogProvider] Processing ${events.length} events:`); events.forEach(event => { console.log(JSON.stringify(event, null, 2)); }); } } // 2. Configure and initialize the SDK const sdk = new UniversalSDK({ providers: [new ConsoleLogProvider()], providerConfigs: { ConsoleLogProvider: { apiKey: 'test-key' } }, debug: true, maxQueueSize: 5, // Flush after 5 events for demo purposes }); sdk.init().then(() => { console.log("--- SDK Ready ---"); // 3. Use the SDK sdk.identify('user-123', { name: 'John Doe', plan: 'premium' }); sdk.track('Page Viewed', { page: '/home' }); sdk.track('Button Clicked', { button: 'signup' }); sdk.captureMessage('This is an informational message.', 'info'); sdk.track('Item Added', { item: 'sdk-core' }); // This should trigger a flush try { throw new Error("Something went wrong!"); } catch (e) { if (e instanceof Error) { sdk.captureException(e, { details: 'Caught in example usage' }); } } // The SDK will also flush automatically based on the flushInterval }); // Make sure to handle shutdown gracefully in a real app // window.addEventListener('beforeunload', () => sdk.shutdown()); */