UNPKG

lever-ui-logger

Version:

Zero-dependency logging library with optional EventBus integration. Built-in PII redaction, multiple transports, and comprehensive logging capabilities.

1,581 lines (1,565 loc) 54.2 kB
/** * Core Logger Types and Interface Definitions * * Foundational type definitions for the lever-ui-logger system, providing * comprehensive TypeScript interfaces for logger configuration, transport * systems, and event structures. Designed for seamless integration with * the EventBus architecture and maximum type safety. * * Key Types: * - Logger interface for structured logging with context and metadata * - Transport interface for pluggable log output destinations * - LoggerConfig for comprehensive logger configuration * - LogEventData for structured log event representation * - RedactionConfig for PII protection and data sanitization * - Sampling configuration for performance optimization * * @example * ```typescript * import type { Logger, LoggerConfig, Transport } from '@nuanced-labs/lever-ui-logger'; * * // Type-safe logger configuration * const config: LoggerConfig = { * level: 'info', * component: 'user-service', * defaultContext: { service: 'api', version: '1.0.0' }, * sampling: { debug: 0.1, info: 1.0 }, * redaction: { enabled: true, patterns: ['password', 'token'] }, * transports: [consoleTransport, beaconTransport] * }; * * // Custom transport implementation * const customTransport: Transport = { * name: 'custom-transport', * write: (event: LogEventData) => { * console.log(`${event.level}: ${event.message}`, event.context); * }, * flush: async () => { }, * close: async () => { } * }; * ``` */ /** * Log levels supported by the logger */ type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error'; /** * Transport interface for log output */ interface Transport { /** Transport name for identification */ name: string; /** Write a log event to this transport */ write(event: LogEventData): Promise<void> | void; /** Flush any pending logs */ flush(): Promise<void> | void; /** Close the transport and clean up resources */ close(): Promise<void> | void; /** Transport configuration */ config?: Record<string, unknown>; } /** * Log event data structure passed to transports */ interface LogEventData { /** Log level */ level: LogLevel; /** Log message */ message: string; /** Timestamp when log was created */ timestamp: number; /** Additional context data */ context: Record<string, unknown>; /** Additional arguments passed to log call */ args: readonly unknown[]; /** Component/logger name that created this log */ component: string; /** Logger instance name */ logger: string; } /** * Metric data structure for structured metrics logging */ interface MetricData { /** Metric name */ name: string; /** Metric fields/values */ fields: Record<string, number | string | boolean>; /** Timestamp when metric was recorded */ timestamp: number; /** Additional context */ context: Record<string, unknown>; /** Component that recorded the metric */ component: string; } /** * Error data structure for error logging */ interface ErrorData { /** Error name/type */ name: string; /** Error message */ message: string; /** Stack trace if available */ stack?: string; /** Whether error was handled by application */ handled: boolean; /** Timestamp when error occurred */ timestamp: number; /** Additional context */ context: Record<string, unknown>; /** Component where error occurred */ component: string; } /** * Transport interfaces and utilities for lever-ui-logger */ declare const Environment: { /** Check if running in browser environment */ readonly isBrowser: boolean; /** Check if running in Node.js environment */ readonly isNode: boolean; /** Check if running in production environment */ readonly isProduction: boolean; /** Check if console methods support styling */ readonly supportsConsoleStyles: boolean; }; /** * Console transport formatting modes */ type ConsoleFormatMode = 'json' | 'pretty' | 'compact'; /** * Console transport configuration */ interface ConsoleTransportConfig { /** Transport name (default: 'console') */ name?: string; /** Formatting mode for output */ format?: ConsoleFormatMode; /** Enable/disable colorized output */ colors?: boolean; /** Enable/disable timestamps */ timestamps?: boolean; /** Timestamp format string */ timestampFormat?: string; /** Enable/disable in production environments */ enableInProduction?: boolean; /** Maximum performance threshold in ms */ performanceThreshold?: number; /** Custom log level to console method mapping */ consoleMethods?: Partial<Record<LogLevel, string>>; } /** * Base transport class with common functionality */ declare abstract class BaseTransport implements Transport { readonly name: string; readonly config: Record<string, unknown>; constructor(name: string, config?: Record<string, unknown>); /** * Write a log event to this transport */ abstract write(_event: LogEventData): Promise<void> | void; /** * Flush any pending logs (default: no-op) */ flush(): Promise<void> | void; /** * Close the transport and clean up resources (default: no-op) */ close(): Promise<void> | void; /** * Check if transport should be active in current environment */ protected isEnabled(): boolean; /** * Measure performance of a function call */ protected measurePerformance<T>(fn: () => T, threshold?: number): T; } /** * Utility functions for formatting log data */ declare const Formatters: { /** * Format timestamp with configurable format */ readonly timestamp: (timestamp: number, format?: string) => string; /** * Pretty-print objects with indentation */ readonly prettyObject: (obj: unknown, indent?: number) => string; /** * Compact object representation */ readonly compactObject: (obj: unknown) => string; /** * Get log level priority for comparison */ readonly getLogLevelPriority: (level: LogLevel) => number; }; /** * ANSI color codes for terminal output */ declare const Colors: { readonly trace: "\u001B[36m"; readonly debug: "\u001B[34m"; readonly info: "\u001B[32m"; readonly warn: "\u001B[33m"; readonly error: "\u001B[31m"; readonly reset: "\u001B[0m"; readonly bold: "\u001B[1m"; readonly dim: "\u001B[2m"; readonly component: "\u001B[35m"; readonly timestamp: "\u001B[90m"; }; /** * Browser console styling */ declare const BrowserStyles: { readonly trace: "color: #00bcd4; font-weight: normal;"; readonly debug: "color: #2196f3; font-weight: normal;"; readonly info: "color: #4caf50; font-weight: normal;"; readonly warn: "color: #ff9800; font-weight: bold;"; readonly error: "color: #f44336; font-weight: bold;"; readonly component: "color: #9c27b0; font-weight: bold;"; readonly timestamp: "color: #666; font-weight: normal;"; }; /** * Console Transport with Advanced Formatting * * Cross-platform console transport that provides rich formatting, colorization, * and environment-specific optimizations. Supports both browser and Node.js * environments with appropriate styling and performance considerations. * * Features: * - Cross-platform support (browser/Node.js) * - Rich formatting with colors and styling * - Multiple format modes (pretty, compact, json) * - Performance monitoring and timing * - Level-specific console methods * - Grouping and indentation support * - Buffer management and flush control * * @example * ```typescript * import { ConsoleTransport } from '@nuanced-labs/lever-ui-logger'; * * // Basic console transport * const transport = new ConsoleTransport({ * level: 'info', * format: 'pretty', * colors: true, * timestamps: true * }); * * // Compact format for production * const compact = new ConsoleTransport({ * format: 'compact', * colors: false, * includeStack: false * }); * * // JSON format for log aggregation * const jsonTransport = new ConsoleTransport({ * format: 'json', * includeMetadata: true, * prettyPrint: false * }); * ``` */ /** * Console transport that outputs logs to the console with formatting and colors */ declare class ConsoleTransport extends BaseTransport { private readonly transportConfig; private readonly consoleMethods; constructor(config?: ConsoleTransportConfig); /** * Write a log event to the console */ write(event: LogEventData): void; /** * Check if transport should be active in current environment */ protected isEnabled(): boolean; /** * Initialize console method mapping */ private initializeConsoleMethods; /** * Format a log event according to the configured format */ private formatEvent; /** * Format data based on the configured format mode */ private formatData; /** * Write to console with browser CSS styles */ private writeWithBrowserStyles; /** * Write to console with ANSI colors */ private writeWithAnsiColors; /** * Write to console without colors */ private writeWithoutColors; } /** * Create a console transport with default configuration */ declare function createConsoleTransport(config?: ConsoleTransportConfig): ConsoleTransport; /** * Production-grade secure token handler for authentication tokens * * Provides comprehensive token security including: * - Memory protection against serialization attacks * - Token obfuscation using industry-standard techniques * - Comprehensive error message sanitization * - PII and token detection for debug outputs */ /** * Token provider function type */ type TokenProvider = () => string | Promise<string>; /** * Configuration for secure token handling */ interface SecureTokenConfig { /** Enable additional security measures (default: true) */ enableSecureMode?: boolean; /** Token expiration time in milliseconds (default: 1 hour) */ tokenTtl?: number; /** Enable token validation (default: true) */ validateToken?: boolean; /** Custom token validator function */ tokenValidator?: (_token: string) => boolean; } /** Secure token handler that prevents accidental token exposure */ declare class SecureTokenHandler { private readonly config; private readonly errorSanitizer; private tokenEntry; private tokenProvider; private disposed; private obfuscationKey; constructor(config?: SecureTokenConfig); /** * Set a static authentication token * * @param token - The authentication token to store securely * @throws Error if token is invalid or handler is disposed */ setToken(token: string | null): void; /** * Set a token provider function for dynamic token retrieval * * @param provider - Function that returns an authentication token * @throws Error if provider is invalid or handler is disposed */ setTokenProvider(provider: TokenProvider | null): void; /** * Retrieve the current authentication token * * @returns The current token or null if none available * @throws Error if token retrieval fails or handler is disposed */ getToken(): Promise<string | null>; /** * Check if a token is currently available and valid */ hasToken(): boolean; /** * Clear all token data and dispose resources * * This method should be called when the handler is no longer needed * to ensure tokens are properly cleared from memory. */ dispose(): void; /** * Create a secure JSON replacer function that sanitizes sensitive data */ createSecureReplacer(): (_key: string, _value: unknown) => unknown; /** * Sanitize HTTP headers to remove or mask authentication tokens * * @param headers - Headers object to sanitize * @returns New headers object with sensitive values masked */ sanitizeHeaders(headers: Record<string, string>): Record<string, string>; /** * Mask a token showing first and last few characters * * @param token - Token to mask * @returns Masked token */ maskToken(token: string): string; /** * Force sanitization of a value using masking strategy */ private forceSanitizeValue; /** * Default token validator */ private defaultTokenValidator; /** * Check if handler is disposed */ private checkDisposed; /** * Check if a token entry is valid and not expired */ private isTokenValid; /** * Multi-round obfuscation to protect tokens in memory using session key. * Uses a combination of XOR, character substitution, and encoding rounds * of transformation to protect tokens in memory against casual inspection * and memory dumps. Not meant for cryptographic security but provides * defense-in-depth against token extraction. */ private obfuscateToken; /** * Reverse the multi-round obfuscation process */ private deobfuscateToken; /** * XOR cipher implementation */ private xorCipher; /** * Character substitution using a custom mapping */ private substituteChars; /** * Reverse character substitution */ private reverseSubstituteChars; /** * Encode the obfuscated string using base64 or similar */ private encodeObfuscated; /** * Decode the obfuscated string */ private decodeObfuscated; /** * Sanitize error messages to prevent token leakage */ sanitizeErrorMessage(errorMessage: string): string; /** * Create character substitution map */ private createSubstitutionMap; /** * Create reverse substitution map */ private createReverseSubstitutionMap; /** * Simple encoding fallback for environments without btoa */ private simpleEncode; /** * Simple decoding fallback for environments without atob */ private simpleDecode; /** * Generate a random string for token clearing */ private generateRandomString; /** * Get or generate the session-specific obfuscation key */ private getObfuscationKey; /** * Make object non-serializable to prevent token leakage */ private makeNonSerializable; /** * Remove non-serializable protection (for disposal) */ private removeNonSerializable; } /** * Default secure token handler instance for immediate use */ declare const defaultSecureTokenHandler: SecureTokenHandler; /** * 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] * }); * ``` */ /** * 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. */ 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 * }; * ``` */ 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() * }); * ``` */ 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] * }); * ``` */ declare function createSendBeaconTransport(config: SendBeaconTransportConfig): SendBeaconTransport; /** * EventBus integration event classes following lever-ui-eventbus patterns * All events follow the class-based event pattern with public readonly properties */ /** * Base class for all logging events with sync coordination metadata. * * All logger events extend this class to provide consistent timestamp and client ID * tracking for cross-library coordination and lever-ui-sync integration. * * @example * ```typescript * // Events automatically get timestamp and clientId * const event = new LogEvent('info', 'message', {}, [], 'component', 'logger'); * console.log(event.timestamp); // 1640995200000 * console.log(event.clientId); // "550e8400-e29b-41d4-a716-446655440000" or "client-abc123-def456" * ``` */ declare class LoggerBaseEvent { readonly timestamp: number; readonly clientId: string; /** * Creates a new logger base event. * * @param timestamp - Unix timestamp when event was created (defaults to Date.now()) * @param clientId - Unique client identifier for this browser session (auto-generated) */ constructor(timestamp?: number, clientId?: string); } /** * Core logging event published to EventBus for all log calls. * * This event is posted to the EventBus whenever a log method is called (trace, debug, info, warn, error). * Other systems can subscribe to these events for analytics, monitoring, error tracking, etc. * * @example * ```typescript * // Subscribe to all log events * eventBus.subscribe(LogEvent, (event) => { * console.log(`[${event.level.toUpperCase()}] ${event.message}`, event.context); * * if (event.level === 'error') { * sendToErrorTracking(event); * } * }); * * // Logger automatically posts LogEvent to EventBus * logger.info('User logged in', { userId: '123', method: 'oauth' }); * ``` */ declare class LogEvent extends LoggerBaseEvent { readonly level: LogLevel; readonly message: string; readonly context: Record<string, unknown>; readonly args: readonly unknown[]; readonly component: string; readonly logger: string; /** * Creates a new log event. * * @param level - Log level (trace, debug, info, warn, error) * @param message - Primary log message * @param context - Structured context data object * @param args - Additional arguments passed to the log call * @param component - Component or module name that generated the log * @param logger - Logger instance name * @param timestamp - Optional custom timestamp (defaults to current time) * @param clientId - Optional custom client ID (defaults to generated ID) */ constructor(level: LogLevel, message: string, context: Record<string, unknown>, args: readonly unknown[], component: string, logger: string, timestamp?: number, clientId?: string); /** * Converts this event to the LogEventData format used by transports. * * @returns LogEventData object ready for transport processing * @example * ```typescript * const event = new LogEvent('info', 'test', {}, [], 'comp', 'logger'); * const transportData = event.toLogEventData(); * consoleTransport.write(transportData); * ``` */ toLogEventData(): LogEventData; } /** * Structured metrics event for performance monitoring and analytics. * * Use this event type for recording quantitative measurements like response times, * user interactions, performance metrics, and business analytics. * * @example * ```typescript * // Subscribe to metrics for analytics * eventBus.subscribe(MetricEvent, (event) => { * analytics.track(event.name, event.fields); * }); * * // Logger posts MetricEvent to EventBus * logger.metric('api_response_time', { * duration: 234, * endpoint: '/users', * status: 200 * }); * ``` */ declare class MetricEvent extends LoggerBaseEvent { readonly name: string; readonly fields: Record<string, number | string | boolean>; readonly context: Record<string, unknown>; readonly component: string; /** * Creates a new metric event. * * @param name - Metric name (e.g., 'page_load_time', 'button_click') * @param fields - Metric data and measurements * @param context - Additional context for the metric * @param component - Component that recorded the metric * @param timestamp - Optional custom timestamp * @param clientId - Optional custom client ID */ constructor(name: string, fields: Record<string, number | string | boolean>, context: Record<string, unknown>, component: string, timestamp?: number, clientId?: string); /** * Convert to metric data format */ toMetricData(): MetricData; } /** * Error event for unhandled errors, exceptions, and error boundary catches */ declare class ErrorEvent extends LoggerBaseEvent { readonly error: Error; readonly handled: boolean; readonly context: Record<string, unknown>; readonly component: string; constructor(error: Error, handled: boolean, context: Record<string, unknown>, component: string, timestamp?: number, clientId?: string); /** * Get error name (constructor name or custom name) */ get name(): string; /** * Get error message */ get message(): string; /** * Get stack trace if available */ get stack(): string | undefined; /** * Convert to error data format */ toErrorData(): ErrorData; } /** * EventBus transport for cross-library integration * * Publishes log events to the EventBus system to enable other parts of the * application to subscribe to and react to logging events. Provides filtering * to prevent infinite loops and error isolation to ensure transport failures * don't break the main logging system. * * @example * ```typescript * import { EventBusTransport } from 'lever-ui-logger/transports'; * * // Your EventBus implementation (must have 'post' method) * * const transport = new EventBusTransport(eventBus, { * enableSelfLogging: false, * filterComponents: ['eventbus-transport'] * }); * * // Use with logger * const logger = createLogger({ * transports: [transport] * }); * ``` */ /** * Configuration options for EventBus transport * * @example * ```typescript * const config: EventBusTransportConfig = { * name: 'custom-eventbus', * enableSelfLogging: false, * filterComponents: ['eventbus-transport', 'sensitive-component'], * silentErrors: false, * transformMetadata: { * transportId: 'main-eventbus', * version: '1.0.0' * } * }; * ``` */ interface EventBusTransportConfig { /** Transport name (default: 'eventbus') */ name?: string; /** Enable logging from the transport itself (default: false to prevent loops) */ enableSelfLogging?: boolean; /** Component names to filter out (prevents infinite loops) */ filterComponents?: string[]; /** Suppress error logging when EventBus operations fail (default: false) */ silentErrors?: boolean; /** Additional metadata to add to all published events */ transformMetadata?: Record<string, unknown>; /** Custom event transformer function */ eventTransformer?: (_event: LogEventData, _metadata: EventTransformMetadata) => LogEvent | MetricEvent | ErrorEvent | null; /** Enable publishing logger lifecycle events (default: true) */ enableLifecycleEvents?: boolean; } /** * EventBus interface for dependency injection * * Defines the minimal EventBus interface needed by the transport. * This allows for testing with mock EventBus instances. */ interface EventBusInterface { /** Post an event to all subscribers */ post<T>(_event: T): void | Promise<void>; /** Optional: Check if EventBus is healthy/connected */ isConnected?(): boolean; } /** * Metadata passed to event transformers */ interface EventTransformMetadata { /** Transport name */ transportName: string; /** Transformation timestamp */ transformTimestamp: number; /** Additional custom metadata */ metadata?: Record<string, unknown>; } /** * EventBus transport for cross-library integration * * Transforms log events into EventBus events and publishes them for * subscription by other systems. Includes comprehensive protection * against infinite loops and robust error handling. * * Features: * - Automatic event transformation (LogEvent, MetricEvent, ErrorEvent) * - Logger lifecycle event publishing (LoggerCreatedEvent, LoggerDestroyedEvent, LoggerConfigChangedEvent) * - Infinite loop prevention with component filtering * - Error isolation - transport failures don't break logging * - Configurable metadata enrichment * - Custom event transformation support * - Silent mode for production environments * * @example * ```typescript * const transport = new EventBusTransport(eventBus, { * filterComponents: ['eventbus-transport', 'analytics'], * transformMetadata: { source: 'main-app' }, * silentErrors: process.env.NODE_ENV === 'production' * }); * ``` */ declare class EventBusTransport extends BaseTransport { private readonly transportConfig; private readonly eventTransformer?; private readonly transformMetadata; private readonly eventBus; /** * Create a new EventBus transport instance * * @param eventBus - EventBus instance to publish events to * @param config - Transport configuration options * @param config.name - Transport name (default: 'eventbus') * @param config.enableSelfLogging - Allow transport to log about itself (default: false) * @param config.filterComponents - Component names to ignore (default: ['eventbus-transport']) * @param config.silentErrors - Suppress error logging (default: false) * @param config.transformMetadata - Additional metadata for events (default: {}) * @param config.eventTransformer - Custom event transformation function (optional) * * @example * ```typescript * const transport = new EventBusTransport(eventBus, { * enableSelfLogging: false, * filterComponents: ['eventbus-transport', 'debug-panel'], * transformMetadata: { * appVersion: '2.1.0', * environment: 'production' * } * }); * ``` */ constructor(eventBus: EventBusInterface, config?: EventBusTransportConfig); /** * Write a log event to the EventBus * * Transforms the log event data into appropriate EventBus event objects * and publishes them. Includes filtering to prevent infinite loops and * error handling to ensure transport failures don't break logging. * * @param event - The log event data to publish * * @example * ```typescript * // This will create and publish a LogEvent to EventBus * transport.write({ * level: 'info', * message: 'User action completed', * timestamp: Date.now(), * component: 'user-service', * context: { userId: '123', action: 'login' }, * args: [] * }); * ``` */ write(event: LogEventData): void; /** * Flush any pending events (no-op for EventBus transport) * * EventBus transport publishes events immediately, so flushing * is not necessary. This method is provided for transport interface * compatibility. * * @returns Resolved promise */ flush(): Promise<void>; /** * Close the transport (no-op for EventBus transport) * * EventBus transport doesn't maintain persistent connections, * so closing is not necessary. This method is provided for * transport interface compatibility. * * Note: Use publishLifecycleEvent('destroyed') explicitly if you * want to publish lifecycle events. * * @returns Resolved promise */ close(): Promise<void>; /** * Publish logger lifecycle events to EventBus * * Publishes lifecycle events (created, destroyed, config-changed) to the EventBus * to allow other systems to track logger state changes. * * @param eventType - Type of lifecycle event * @param config - Logger configuration (for created/config-changed events) * @param loggerName - Name of the logger (optional) * * @example * ```typescript * // Publish logger created event * transport.publishLifecycleEvent('created', { level: 'info' }, 'main-logger'); * * // Publish config changed event * transport.publishLifecycleEvent('config-changed', { level: 'debug' }); * * // Publish destroyed event * transport.publishLifecycleEvent('destroyed'); * ``` */ publishLifecycleEvent(eventType: 'created' | 'destroyed' | 'config-changed', config?: Record<string, unknown>, loggerName?: string): void; /** * Check if an event should be processed (infinite loop prevention) * * Filters out events from components that might cause infinite loops, * particularly events from the transport itself or other sensitive * components specified in the configuration. * * @param event - Log event to check * @returns True if event should be processed * * @internal */ private shouldProcessEvent; /** * Check if EventBus is ready to receive events * * Performs basic health checks on the EventBus instance to ensure * it's safe to publish events. Handles cases where EventBus might * be undefined or not connected. * * @returns True if EventBus is ready * * @internal */ private isEventBusReady; /** * Transform log event data into EventBus event objects * * Creates appropriate EventBus event instances (LogEvent, MetricEvent, ErrorEvent) * based on the log event data. Supports custom transformation functions * and adds transport metadata. * * @param event - Log event data to transform * @returns Transformed EventBus event or null if transformation fails * * @internal */ private transformEvent; /** * Create default EventBus events from log data * * Applies intelligent event type detection based on log content: * - Error events for error level logs or Error objects in context * - Metric events for logs with numeric data or specific patterns * - Log events for everything else * * @param event - Log event data * @param metadata - Transform metadata * @returns Appropriate EventBus event * * @internal */ private createDefaultEvent; /** * Detect if event should be treated as an error event * * @param event - Log event data * @returns True if this should be an ErrorEvent * * @internal */ private isErrorEvent; /** * Detect if event should be treated as a metric event * * @param event - Log event data * @returns True if this should be a MetricEvent * * @internal */ private isMetricEvent; /** * Create ErrorEvent from log data * * @param event - Log event data * @param metadata - Transform metadata * @returns ErrorEvent instance * * @internal */ private createErrorEvent; /** * Create MetricEvent from log data * * @param event - Log event data * @param metadata - Transform metadata * @returns MetricEvent instance * * @internal */ private createMetricEvent; /** * Create LogEvent from log data * * @param event - Log event data * @param metadata - Transform metadata * @returns LogEvent instance * * @internal */ private createLogEvent; /** * Publish event to EventBus * * Handles both synchronous and asynchronous EventBus post methods. * Includes error handling for publish failures. * * @param event - EventBus event to publish * * @internal */ private publishEvent; /** * Handle EventBus post errors * * Provides error logging and graceful degradation when EventBus * operations fail. Respects silent error configuration. * * @param error - Error that occurred * @param originalEvent - Original log event (if available) * * @internal */ private handlePublishError; } /** * Create an EventBus transport with default configuration * * Factory function that creates a new EventBus transport instance * with the provided EventBus and configuration. Provides a convenient * way to create transports without using the constructor directly. * * @param eventBus - EventBus instance to publish events to * @param config - Transport configuration options * @returns New EventBus transport instance * * @example * ```typescript * import { createEventBusTransport } from 'lever-ui-logger/transports'; * * // Your EventBus implementation * const eventBus = { post: (event) => console.log(event) }; * * const transport = createEventBusTransport(eventBus, { * filterComponents: ['eventbus-transport', 'analytics'], * transformMetadata: { * appVersion: '1.0.0', * environment: process.env.NODE_ENV * }, * silentErrors: process.env.NODE_ENV === 'production' * }); * * // Use with logger * const logger = createLogger({ * transports: [transport] * }); * ``` */ declare function createEventBusTransport(eventBus: EventBusInterface, config?: EventBusTransportConfig): EventBusTransport; /** * Error message sanitizer for preventing sensitive data leakage * * This module provides comprehensive sanitization of error messages and other strings * to prevent accidental exposure of tokens, API keys, passwords, and other sensitive data. * Based on security research and production patterns from major security tools. */ /** * Comprehensive regex patterns for detecting various types of sensitive tokens and PII * Based on research from security tools like TruffleHog and industry standards */ interface TokenPatterns { /** JWT tokens - Base64url encoded with 3 parts */ jwt: RegExp; /** Generic Bearer tokens */ bearer: RegExp; /** Generic API keys with common prefixes */ genericApiKey: RegExp; /** URLs with credentials */ urlWithCredentials: RegExp; /** Email addresses */ email: RegExp; /** Phone numbers */ phone: RegExp; /** Credit card numbers */ creditCard: RegExp; } /** * Configuration for the error sanitizer */ interface ErrorSanitizerConfig { /** Enable comprehensive token detection (default: true) */ enableTokenDetection?: boolean; /** Replacement strategy for detected sensitive data */ replacementStrategy?: 'mask' | 'redact' | 'hash'; /** Custom token patterns to detect */ customPatterns?: RegExp[]; /** Fields to always redact regardless of content */ sensitiveFields?: string[]; /** Maximum length of original value to show in mask (default: 8) */ maskRevealLength?: number; } /** * Production-grade error message sanitizer */ declare class ErrorMessageSanitizer { private readonly config; private readonly tokenPatterns; private readonly sensitiveFieldQuotedPattern; private readonly sensitiveFieldUnquotedPattern; constructor(config?: ErrorSanitizerConfig); /** * Sanitize an error message or any string containing potentially sensitive data * * @param input - The string to sanitize * @returns Sanitized string with sensitive data masked/redacted */ sanitize(input: string): string; /** * Sanitize sensitive key-value pairs in strings */ private sanitizeSensitiveFields; /** * Detect and sanitize various token patterns */ private sanitizeTokens; /** * Apply custom user-defined patterns */ private applyCustomPatterns; /** * Apply the configured sanitization strategy to a detected sensitive value */ private applySanitization; /** * Mask a value showing first and last few characters */ private maskValue; /** * Create a hash of the value for logging purposes */ private hashValue; /** * Create comprehensive token detection patterns */ private createTokenPatterns; /** * Check if a string contains any detectable sensitive data * * @param input - String to check * @returns True if sensitive data is detected */ hasSensitiveData(input: string): boolean; /** * Get statistics about what types of sensitive data were found * * @param input - String to analyze * @returns Object with counts of different sensitive data types found */ analyzeSensitiveData(input: string): Record<string, number>; } /** * Default error sanitizer instance for immediate use */ declare const defaultErrorSanitizer: ErrorMessageSanitizer; /** * @fileoverview Transport middleware system for log transformation and filtering * @module @nuanced-labs/lever-ui-logger/transports */ /** * Middleware context containing log data and metadata */ interface MiddlewareContext { /** The log event being processed */ event: LogEventData; /** Transport-specific metadata */ metadata: Record<string, unknown>; /** Skip this log (don't send to transport) */ skip?: boolean; /** Additional headers for the transport */ headers?: Record<string, string>; } /** * Middleware function that processes log events */ type MiddlewareFunction = (_context: MiddlewareContext, _next: () => void | Promise<void>) => void | Promise<void>; /** * Middleware configuration options */ interface MiddlewareOptions { /** Name for debugging and error messages */ name?: string; /** Only apply to specific log levels */ levels?: LogLevel[]; /** Skip middleware based on condition */ condition?: (_context: MiddlewareContext) => boolean; } /** * Transport middleware for processing log events */ declare class TransportMiddleware { private middlewares; /** * Add middleware to the pipeline */ use(fn: MiddlewareFunction, options?: MiddlewareOptions): this; /** * Execute middleware pipeline */ execute(event: LogEventData, metadata?: Record<string, unknown>): Promise<MiddlewareContext | null>; /** * Clear all middleware */ clear(): void; /** * Get middleware count */ get length(): number; } /** * Built-in middleware: Filter by log level * * @param {LogLevel} minLevel - Minimum log level to allow through * @returns {MiddlewareFunction} Middleware that filters logs below the specified level */ declare function filterByLevel(minLevel: LogLevel): MiddlewareFunction; /** * Built-in middleware: Add metadata to all events * * @param {Record<string, unknown>} metadata - Metadata to add to all events * @returns {MiddlewareFunction} Middleware that enriches events with additional metadata */ declare function addMetadata(metadata: Record<string, unknown>): MiddlewareFunction; /** * Built-in middleware: Transform event data * * @param {Function} transformer - Function to transform the event * @returns {MiddlewareFunction} Middleware that transforms events */ declare function transformEvent(transformer: (_event: LogEventData) => LogEventData | null): MiddlewareFunction; /** * Built-in middleware: Rate limiting * * @param {number} maxPerSecond - Maximum events allowed per second * @returns {MiddlewareFunction} Middleware that rate limits events */ declare function rateLimit(maxPerSecond: number): MiddlewareFunction; /** * Built-in middleware: Sampling * * @param {number} rate - Sample rate between 0 and 1 (e.g., 0.1 for 10%) * @returns {MiddlewareFunction} Middleware that samples events * @throws {Error} If rate is not between 0 and 1 */ declare function sample(rate: number): MiddlewareFunction; /** * Built-in middleware: Error enrichment * * @returns {MiddlewareFunction} Middleware that enriches error events with stack traces and details */ declare function enrichErrors(): MiddlewareFunction; /** * @fileoverview Compression support for transports using native browser APIs * @m