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
TypeScript
/**
* 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