From 499d1ebe126d6dff1b5e8c4cc92ab76d969e564d Mon Sep 17 00:00:00 2001 From: Lilith Date: Thu, 29 Jan 2026 08:20:57 -0800 Subject: [PATCH] =?UTF-8?q?chore(client):=20=F0=9F=94=A7=20Update=20TypeSc?= =?UTF-8?q?ript=20files=20in=20client=20directory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- src/client/AnalyticsClient.ts | 143 ---------------------------------- src/client/BackendClient.ts | 122 ----------------------------- src/client/BatchQueue.ts | 79 ------------------- src/client/index.ts | 11 --- src/client/metadata.ts | 55 ------------- 5 files changed, 410 deletions(-) delete mode 100644 src/client/AnalyticsClient.ts delete mode 100644 src/client/BackendClient.ts delete mode 100644 src/client/BatchQueue.ts delete mode 100644 src/client/index.ts delete mode 100644 src/client/metadata.ts diff --git a/src/client/AnalyticsClient.ts b/src/client/AnalyticsClient.ts deleted file mode 100644 index 17f6467..0000000 --- a/src/client/AnalyticsClient.ts +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Browser Analytics Client - * - * Tracks events from browser environments with automatic metadata collection. - */ - -import type { EventMetadata } from '../types'; -import { BatchQueue, type BatchQueueConfig } from './BatchQueue'; -import { collectBrowserMetadata } from './metadata'; - -/** Simplified tracking event for client SDK */ -interface TrackingEvent { - eventType: string; - timestamp: string; - sessionId: string; - userId?: string; - properties: Record; - metadata: EventMetadata; - [key: string]: unknown; -} - -export interface AnalyticsClientConfig { - /** Analytics collector endpoint URL */ - endpoint: string; - /** Batch configuration */ - batch?: Partial; - /** Whether to automatically collect browser metadata */ - autoCollectMetadata?: boolean; - /** Custom headers to include in requests */ - headers?: Record; - /** Enable debug logging */ - debug?: boolean; -} - -export class AnalyticsClient { - private readonly endpoint: string; - private readonly queue: BatchQueue; - private readonly autoCollectMetadata: boolean; - private readonly headers: Record; - private readonly debug: boolean; - private sessionId: string; - private userId: string | null = null; - - constructor(config: AnalyticsClientConfig) { - this.endpoint = config.endpoint; - this.autoCollectMetadata = config.autoCollectMetadata ?? true; - this.headers = config.headers ?? {}; - this.debug = config.debug ?? false; - this.sessionId = this.generateSessionId(); - - this.queue = new BatchQueue({ - maxSize: config.batch?.maxSize ?? 10, - maxWait: config.batch?.maxWait ?? 5000, - onFlush: (events) => this.sendEvents(events as TrackingEvent[]), - }); - } - - /** - * Identify the current user - */ - identify(userId: string, traits?: Record): void { - this.userId = userId; - this.track('identify', { userId, traits }); - } - - /** - * Track an event - */ - track(eventType: string, properties?: Record): void { - const event: TrackingEvent = { - eventType, - timestamp: new Date().toISOString(), - sessionId: this.sessionId, - userId: this.userId ?? undefined, - properties: properties ?? {}, - metadata: this.autoCollectMetadata ? collectBrowserMetadata() : {}, - }; - - if (this.debug) { - console.log('[Analytics] Track:', event); - } - - this.queue.add(event); - } - - /** - * Track a page view - */ - page(name?: string, properties?: Record): void { - this.track('page_view', { - name: name ?? document.title, - url: window.location.href, - path: window.location.pathname, - referrer: document.referrer, - ...properties, - }); - } - - /** - * Flush pending events immediately - */ - async flush(): Promise { - await this.queue.flush(); - } - - /** - * Reset the session (e.g., on logout) - */ - reset(): void { - this.userId = null; - this.sessionId = this.generateSessionId(); - } - - private generateSessionId(): string { - return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`; - } - - private async sendEvents(events: TrackingEvent[]): Promise { - if (events.length === 0) return; - - try { - const response = await fetch(`${this.endpoint}/collect`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - ...this.headers, - }, - body: JSON.stringify({ events }), - }); - - if (!response.ok) { - throw new Error(`Analytics request failed: ${response.status}`); - } - - if (this.debug) { - console.log(`[Analytics] Sent ${events.length} events`); - } - } catch (error) { - console.error('[Analytics] Failed to send events:', error); - // Events are lost on failure - could implement retry/persistence - } - } -} diff --git a/src/client/BackendClient.ts b/src/client/BackendClient.ts deleted file mode 100644 index 1a0cabc..0000000 --- a/src/client/BackendClient.ts +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Backend Analytics Client - * - * Fire-and-forget event tracking for server-side environments. - * Does not block on event delivery. - */ - -import type { EventMetadata } from '../types'; -import { BatchQueue, type BatchQueueConfig } from './BatchQueue'; -import { collectServerMetadata } from './metadata'; - -/** Simplified tracking event for backend SDK */ -interface TrackingEvent { - eventType: string; - timestamp: string; - sessionId?: string; - userId?: string; - properties: Record; - metadata: EventMetadata; - [key: string]: unknown; -} - -export interface BackendClientConfig { - /** Analytics collector endpoint URL */ - endpoint: string; - /** Service name for attribution */ - serviceName: string; - /** Batch configuration */ - batch?: Partial; - /** Custom headers to include in requests */ - headers?: Record; - /** Enable debug logging */ - debug?: boolean; -} - -export class BackendAnalyticsClient { - private readonly endpoint: string; - private readonly serviceName: string; - private readonly queue: BatchQueue; - private readonly headers: Record; - private readonly debug: boolean; - - constructor(config: BackendClientConfig) { - this.endpoint = config.endpoint; - this.serviceName = config.serviceName; - this.headers = config.headers ?? {}; - this.debug = config.debug ?? false; - - this.queue = new BatchQueue({ - maxSize: config.batch?.maxSize ?? 50, - maxWait: config.batch?.maxWait ?? 10000, - onFlush: (events) => this.sendEvents(events as TrackingEvent[]), - }); - } - - /** - * Track an event (fire-and-forget) - */ - track( - eventType: string, - properties?: Record, - context?: { userId?: string; sessionId?: string }, - ): void { - const event: TrackingEvent = { - eventType, - timestamp: new Date().toISOString(), - sessionId: context?.sessionId, - userId: context?.userId, - properties: { - ...properties, - $service: this.serviceName, - }, - metadata: collectServerMetadata(), - }; - - if (this.debug) { - console.log('[Analytics Backend] Track:', event); - } - - this.queue.add(event); - } - - /** - * Flush pending events immediately - */ - async flush(): Promise { - await this.queue.flush(); - } - - /** - * Graceful shutdown - flush remaining events - */ - async shutdown(): Promise { - await this.flush(); - } - - private async sendEvents(events: TrackingEvent[]): Promise { - if (events.length === 0) return; - - try { - const response = await fetch(`${this.endpoint}/collect`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - ...this.headers, - }, - body: JSON.stringify({ events }), - }); - - if (!response.ok) { - throw new Error(`Analytics request failed: ${response.status}`); - } - - if (this.debug) { - console.log(`[Analytics Backend] Sent ${events.length} events`); - } - } catch (error) { - // Fire-and-forget: log but don't throw - console.error('[Analytics Backend] Failed to send events:', error); - } - } -} diff --git a/src/client/BatchQueue.ts b/src/client/BatchQueue.ts deleted file mode 100644 index 506c7d7..0000000 --- a/src/client/BatchQueue.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Batch Queue - * - * Collects events and flushes them in batches based on size or time. - */ - -/** Generic event type for queue */ -export interface QueueableEvent { - eventType: string; - timestamp: string; - [key: string]: unknown; -} - -export interface BatchQueueConfig { - /** Maximum number of events before flush */ - maxSize: number; - /** Maximum time (ms) before flush */ - maxWait: number; - /** Callback when batch is flushed */ - onFlush: (events: QueueableEvent[]) => Promise; -} - -export class BatchQueue { - private readonly config: BatchQueueConfig; - private queue: QueueableEvent[] = []; - private timer: ReturnType | null = null; - private flushing = false; - - constructor(config: BatchQueueConfig) { - this.config = config; - } - - /** - * Add an event to the queue - */ - add(event: QueueableEvent): void { - this.queue.push(event); - - if (this.queue.length >= this.config.maxSize) { - void this.flush(); - } else if (!this.timer) { - this.timer = setTimeout(() => { - void this.flush(); - }, this.config.maxWait); - } - } - - /** - * Flush all pending events - */ - async flush(): Promise { - if (this.flushing || this.queue.length === 0) { - return; - } - - this.flushing = true; - - if (this.timer) { - clearTimeout(this.timer); - this.timer = null; - } - - const events = this.queue; - this.queue = []; - - try { - await this.config.onFlush(events); - } finally { - this.flushing = false; - } - } - - /** - * Get current queue size - */ - get size(): number { - return this.queue.length; - } -} diff --git a/src/client/index.ts b/src/client/index.ts deleted file mode 100644 index d2b46cd..0000000 --- a/src/client/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Analytics Client SDK - * - * Universal event tracking client for browser and Node.js environments. - * Supports batching, automatic metadata collection, and offline queueing. - */ - -export { AnalyticsClient, type AnalyticsClientConfig } from './AnalyticsClient'; -export { BackendAnalyticsClient, type BackendClientConfig } from './BackendClient'; -export { BatchQueue, type BatchQueueConfig } from './BatchQueue'; -export { collectBrowserMetadata, collectServerMetadata } from './metadata'; diff --git a/src/client/metadata.ts b/src/client/metadata.ts deleted file mode 100644 index 54c2439..0000000 --- a/src/client/metadata.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Metadata Collection Utilities - * - * Automatic collection of context metadata for analytics events. - */ - -import type { EventMetadata } from '../types'; - -/** - * Collect browser metadata - */ -export function collectBrowserMetadata(): EventMetadata { - if (typeof window === 'undefined') { - return {}; - } - - const metadata: EventMetadata = { - userAgent: navigator.userAgent, - language: navigator.language, - screenWidth: window.screen.width, - screenHeight: window.screen.height, - viewportWidth: window.innerWidth, - viewportHeight: window.innerHeight, - timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, - timestamp: new Date().toISOString(), - }; - - // UTM parameters - const params = new URLSearchParams(window.location.search); - const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; - for (const param of utmParams) { - const value = params.get(param); - if (value) { - metadata[param] = value; - } - } - - // Referrer - if (document.referrer) { - metadata.referrer = document.referrer; - } - - return metadata; -} - -/** - * Collect server-side metadata - */ -export function collectServerMetadata(): EventMetadata { - return { - nodeVersion: process.version, - platform: process.platform, - timestamp: new Date().toISOString(), - }; -}