lever-ui-logger
Version:
Zero-dependency logging library with optional EventBus integration. Built-in PII redaction, multiple transports, and comprehensive logging capabilities.
362 lines • 11.2 kB
TypeScript
/**
* SendBeacon transport for efficient telemetry data transmission
*
* Provides efficient batching, offline support, and automatic retry capabilities
* for sending telemetry data to remote endpoints using the sendBeacon API with
* fetch fallback for maximum compatibility.
*
* @example
* ```typescript
* import { SendBeaconTransport } from '@nuanced-labs/lever-ui-logger';
*
* const transport = new SendBeaconTransport({
* endpoint: 'https://api.example.com/telemetry',
* batchSize: 100,
* flushInterval: 10000,
* authToken: 'your-api-token',
* enableOfflineStorage: true
* });
*
* // Use with logger
* const logger = createLogger(eventBus, {
* transports: [transport]
* });
* ```
*/
import type { LogEventData } from '../logger/types.js';
import { BaseTransport } from './transport-interface.js';
import { type TokenProvider } from './secure-token-handler.js';
/**
* Telemetry envelope metadata structure for wrapping log events
*
* Contains session and user context along with the batch of log events
* being transmitted to the telemetry endpoint.
*/
export interface TelemetryEnvelope {
/** Unique session identifier */
sessionId: string;
/** Optional user identifier */
userId?: string;
/** User agent string */
userAgent: string;
/** Browser/client timezone */
timezone: string;
/** Timestamp of the envelope creation */
timestamp: number;
/** Array of log events */
events: LogEventData[];
/** Number of events in this batch */
eventCount: number;
/** Total size in bytes (estimated) */
sizeBytes: number;
}
/**
* Configuration options for SendBeacon transport
*
* @example
* ```typescript
* const config: SendBeaconTransportConfig = {
* endpoint: 'https://api.example.com/logs',
* batchSize: 50,
* flushInterval: 5000,
* maxPayloadSize: 64 * 1024,
* authToken: () => getAuthToken(),
* enableOfflineStorage: true,
* rateLimitPerMinute: 1000
* };
* ```
*/
export interface SendBeaconTransportConfig {
/** Transport name */
name?: string;
/** Endpoint URL for sending telemetry */
endpoint: string;
/** Maximum batch size (number of events) */
batchSize?: number;
/** Flush interval in milliseconds */
flushInterval?: number;
/** Maximum payload size in bytes (default ~64KB for sendBeacon) */
maxPayloadSize?: number;
/** Enable offline storage */
enableOfflineStorage?: boolean;
/** Storage key prefix for offline logs */
storageKeyPrefix?: string;
/** Maximum retry attempts */
maxRetries?: number;
/** Initial retry delay in milliseconds */
retryDelay?: number;
/** Authentication token or function to get token */
authToken?: string | TokenProvider;
/** Enable secure token handling (default: true) */
enableSecureTokenHandling?: boolean;
/** Custom headers for requests */
headers?: Record<string, string>;
/** Enable compression if available */
enableCompression?: boolean;
/** Session ID generator function */
sessionIdGenerator?: () => string;
/** User ID provider function */
userIdProvider?: () => string | undefined;
/** Rate limit: max events per minute */
rateLimitPerMinute?: number;
/** Enable automatic page lifecycle handling */
enableLifecycleHandling?: boolean;
}
/**
* SendBeacon transport for efficient telemetry transmission
*
* High-performance transport that uses the sendBeacon API when available,
* falling back to fetch with keepalive. Provides intelligent batching,
* offline storage, retry logic, and lifecycle management.
*
* Features:
* - Automatic batching with size and time-based flushing
* - sendBeacon API with fetch fallback
* - Offline storage with localStorage
* - Exponential backoff retry logic
* - Rate limiting and abuse prevention
* - Page lifecycle event handling
* - Bearer token authentication
* - Circular reference protection
*
* @example
* ```typescript
* const transport = new SendBeaconTransport({
* endpoint: 'https://telemetry.example.com/logs',
* batchSize: 100,
* flushInterval: 10000,
* authToken: 'bearer-token',
* enableOfflineStorage: true,
* userIdProvider: () => getCurrentUserId()
* });
* ```
*/
export declare class SendBeaconTransport extends BaseTransport {
private readonly transportConfig;
private readonly secureTokenHandler;
private readonly userIdProvider?;
private eventQueue;
private flushTimer?;
private sessionId;
private rateLimitCounter;
private rateLimitResetTime;
private isOnline;
private retryQueue;
private lifecycleHandlersAttached;
/**
* Create a new SendBeacon transport instance
*
* @param config - Configuration options for the transport
* @param config.endpoint - Required endpoint URL for telemetry data
* @param config.batchSize - Maximum events per batch (default: 50)
* @param config.flushInterval - Flush interval in milliseconds (default: 5000)
* @param config.maxPayloadSize - Maximum payload size in bytes (default: 64KB)
* @param config.authToken - Authentication token or provider function
* @param config.enableOfflineStorage - Enable localStorage fallback (default: true)
* @param config.rateLimitPerMinute - Rate limit events per minute (default: 1000)
*
* @example
* ```typescript
* const transport = new SendBeaconTransport({
* endpoint: 'https://api.example.com/telemetry',
* batchSize: 25,
* flushInterval: 3000,
* authToken: async () => await getApiToken(),
* userIdProvider: () => user.id
* });
* ```
*/
constructor(config: SendBeaconTransportConfig);
/**
* Write a log event to the transport
*
* Adds the event to the batching queue and triggers immediate flush
* if batch size or payload size limits are reached. Events are
* subject to rate limiting.
*
* @param event - The log event to write
*
* @example
* ```typescript
* transport.write({
* level: 'info',
* message: 'User logged in',
* timestamp: Date.now(),
* component: 'auth',
* context: { userId: '123' },
* args: []
* });
* ```
*/
write(event: LogEventData): void;
/**
* Flush all pending events immediately
*
* Sends all queued events and retry events in optimally-sized batches.
* Respects payload size limits and creates multiple batches if necessary.
* Automatically handles online/offline state and retry logic.
*
* @returns Promise that resolves when all events have been processed
*
* @example
* ```typescript
* // Manually flush before page unload
* window.addEventListener('beforeunload', async () => {
* await transport.flush();
* });
* ```
*/
flush(): Promise<void>;
/**
* Close the transport and clean up resources
*
* Performs a final flush of all pending events, clears timers,
* removes event listeners, saves any remaining events to
* offline storage if enabled, and securely disposes of token handler.
*
* @returns Promise that resolves when cleanup is complete
*
* @example
* ```typescript
* // Clean shutdown
* await transport.close();
* ```
*/
close(): Promise<void>;
/**
* Check if immediate flush is needed
*/
private shouldFlushImmediately;
/**
* Create batches respecting size limits
*/
private createBatches;
/**
* Send a batch of events
*/
private sendBatch;
/**
* Send payload using sendBeacon or fetch with keepalive
*
* Attempts to use navigator.sendBeacon first for optimal performance,
* then falls back to fetch with keepalive flag. Automatically handles
* payload size limits and browser compatibility.
*
* @param payload - JSON string payload to send
* @returns Promise resolving to true if send was successful
*
* @internal
*/
private sendPayload;
/**
* Build request headers with secure token handling
*/
private buildHeaders;
/**
* Create telemetry envelope with metadata and sanitized events
*
* Wraps log events in a telemetry envelope containing session context,
* user information, and environment metadata. Automatically sanitizes
* events to handle circular references and serialization issues.
*
* @param events - Array of log events to include in envelope
* @returns Promise resolving to complete telemetry envelope
*
* @internal
*/
private createEnvelope;
/**
* Handle send failure with retry logic
*/
private handleSendFailure;
/**
* Setup online/offline status monitoring
*/
private setupOnlineStatusMonitoring;
/**
* Setup page lifecycle event handlers
*/
private setupLifecycleHandlers;
/**
* Remove lifecycle event handlers
*/
private removeLifecycleHandlers;
/**
* Save events to offline storage
*/
private saveOfflineEvents;
/**
* Load events from offline storage
*/
private loadOfflineEvents;
/**
* Get events from offline storage
*/
private getOfflineEvents;
/**
* Clear offline storage
*/
private clearOfflineEvents;
/**
* Check rate limit
*/
private checkRateLimit;
/**
* Start flush timer
*/
private startFlushTimer;
/**
* Clear flush timer
*/
private clearFlushTimer;
/**
* Estimate size of event(s) in bytes
*/
private estimateEventSize;
/**
* Get a secure replacer function for handling circular references and sensitive data
*/
private getCircularReplacer;
/**
* Sanitize event data for safe logging
*
* @param event - Event data to sanitize
* @returns Sanitized event data safe for logging
*/
private sanitizeEventForLogging;
/**
* Generate a unique session ID
*/
private static generateSessionId;
}
/**
* Create a SendBeacon transport with default configuration
*
* Factory function that creates a new SendBeacon transport instance
* with the provided configuration. Provides a convenient way to
* create transports without using the constructor directly.
*
* @param config - Transport configuration options
* @returns New SendBeacon transport instance
*
* @example
* ```typescript
* import { createSendBeaconTransport } from '@nuanced-labs/lever-ui-logger';
*
* const transport = createSendBeaconTransport({
* endpoint: 'https://api.example.com/telemetry',
* batchSize: 100,
* flushInterval: 10000,
* authToken: process.env.API_TOKEN,
* enableOfflineStorage: true,
* rateLimitPerMinute: 500
* });
*
* // Use with logger
* const logger = createLogger(eventBus, {
* transports: [transport]
* });
* ```
*/
export declare function createSendBeaconTransport(config: SendBeaconTransportConfig): SendBeaconTransport;
//# sourceMappingURL=sendbeacon-transport.d.ts.map