@ncoderz/log-m8 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/LogLevel.ts","../src/PluginKind.ts","../src/appenders/ConsoleAppender.ts","../src/appenders/FileAppender.ts","../src/LogM8Utils.ts","../src/filters/MatchFilter.ts","../src/formatters/DefaultFormatter.ts","../src/formatters/JsonFormatter.ts","../src/PluginManager.ts","../src/LogM8.ts"],"sourcesContent":["import { LogM8 as Logging } from './LogM8.ts';\n\n// Type exports for public API\nexport { type Appender } from './Appender.ts';\nexport { type AppenderConfig } from './AppenderConfig.ts';\nexport { type ConsoleAppenderConfig } from './appenders/ConsoleAppender.ts';\n/* NODEJS:START */\nexport { type FileAppenderConfig } from './appenders/FileAppender.ts';\n/* NODEJS:END */\nexport { type Filter } from './Filter.ts';\nexport { type FilterConfig } from './FilterConfig.ts';\nexport { type MatchFilterConfig } from './filters/MatchFilter.ts';\nexport { type Formatter } from './Formatter.ts';\nexport { type FormatterConfig } from './FormatterConfig.ts';\nexport { type DefaultFormatterConfig } from './formatters/DefaultFormatter.ts';\nexport { type Log } from './Log.ts';\nexport { type LogContext } from './LogContext.ts';\nexport { type LoggingConfig } from './LoggingConfig.ts';\nexport { LogLevel, type LogLevelType } from './LogLevel.ts';\nexport { LogM8Utils } from './LogM8Utils.ts';\nexport { type Plugin } from './Plugin.ts';\nexport { type PluginConfig } from './PluginConfig.ts';\nexport { type PluginFactory } from './PluginFactory.ts';\nexport { PluginKind, type PluginKindType } from './PluginKind.ts';\n\n/**\n * Default singleton instance of the LogM8 logging manager.\n *\n * Pre-configured with built-in appenders and formatters for immediate use.\n * Most applications should use this export rather than creating new LogM8 instances.\n *\n * @example\n * ```typescript\n * import { LogM8 } from 'log-m8';\n *\n * // Initialize with default console output\n * LogM8.init();\n *\n * // Get a logger and start logging\n * const logger = LogM8.getLogger('app');\n * logger.info('Application started');\n * ```\n */\nconst LogM8 = new Logging();\nexport { LogM8 };\n","/**\n * Enumeration of supported log severity levels in ascending order of verbosity.\n *\n * The logging system uses this hierarchy to determine which events to emit:\n * - 'off': Disables all logging\n * - 'fatal': Critical system failures requiring immediate intervention\n * - 'error': Failures preventing normal operation\n * - 'warn': Potentially problematic situations\n * - 'info': General informational messages about normal operation\n * - 'debug': Detailed diagnostic information for development\n * - 'track': Analytics and user behavior tracking events\n * - 'trace': Most detailed execution information for fine-grained debugging\n *\n * Events are emitted when their level index is <= logger's level index.\n * The 'track' level is positioned between 'debug' and 'trace' to allow\n * analytics collection without the verbosity of full trace logging.\n *\n * @example\n * ```typescript\n * // Logger set to 'info' will emit: fatal, error, warn, info\n * logger.setLevel('info');\n * logger.debug('Not emitted'); // debug > info in hierarchy\n * logger.info('Emitted'); // info <= info in hierarchy\n * ```\n */\nconst LogLevel = {\n off: 'off', // No logging\n\n fatal: 'fatal',\n error: 'error',\n warn: 'warn',\n info: 'info',\n debug: 'debug',\n track: 'track', // Special log level for analytics\n trace: 'trace',\n} as const;\n\n/**\n * Type representing a LogLevel enum value.\n */\nexport type LogLevelType = (typeof LogLevel)[keyof typeof LogLevel];\n\nexport { LogLevel };\n","/**\n * Enumeration of plugin types supported by the LogM8 plugin system.\n *\n * The logging system uses a plugin architecture where functionality is\n * provided by three categories of plugins:\n *\n * - **appender**: Output destinations that write formatted log events\n * - **filter**: Event processors that determine which events to log\n * - **formatter**: Event transformers that convert LogEvent objects to output format\n *\n * Each plugin factory must declare its kind to enable proper registration\n * and instantiation during system initialization.\n *\n * @example\n * ```typescript\n * class CustomAppender implements Appender {\n * kind = PluginKind.appender;\n * // ... implementation\n * }\n *\n * class CustomFilter implements Filter {\n * kind = PluginKind.filter;\n * // ... implementation\n * }\n * ```\n */\nconst PluginKind = {\n appender: 'appender', // Log output destinations (console, file, network, etc.)\n filter: 'filter', // Event filtering logic (level, content, rate limiting, etc.)\n formatter: 'formatter', // Event formatting (text, JSON, custom templates, etc.)\n} as const;\n\n/**\n * Type representing a PluginKind enum value.\n */\nexport type PluginKindType = (typeof PluginKind)[keyof typeof PluginKind];\n\nexport { PluginKind };\n","import type { Appender } from '../Appender.ts';\nimport type { AppenderConfig } from '../AppenderConfig.ts';\nimport type { Filter } from '../Filter.ts';\nimport type { Formatter } from '../Formatter.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogLevel, type LogLevelType } from '../LogLevel.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\nconst NAME = 'console';\nconst VERSION = '1.0.0';\nconst KIND = PluginKind.appender;\n\nconst SUPPORTED_LEVELS = new Set<LogLevelType>([\n LogLevel.fatal,\n LogLevel.error,\n LogLevel.warn,\n LogLevel.info,\n LogLevel.debug,\n LogLevel.track,\n LogLevel.trace,\n]);\n\n/**\n * Configuration interface for console appender.\n * Currently extends base AppenderConfig without additional options.\n */\nexport interface ConsoleAppenderConfig extends AppenderConfig {\n //\n}\n\n/**\n * Built-in appender that outputs log events to the global console object.\n *\n * Maps log levels to appropriate console methods (error, warn, info, debug, etc.)\n * with fallback to console.log when specific methods are unavailable.\n * Automatically detects console availability and gracefully handles environments\n * where console is not available.\n *\n * Features:\n * - Zero-configuration operation\n * - Automatic console method mapping by log level\n * - Graceful degradation when console methods are missing\n * - No-op flush operation (console output is immediate)\n * - Environment detection for console availability\n *\n * @example\n * ```typescript\n * // Automatic registration - no manual setup needed\n * Logging.init({\n * appenders: [{ name: 'console', formatter: 'default-formatter' }]\n * });\n * ```\n */\nclass ConsoleAppender implements Appender {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public readonly supportedLevels = SUPPORTED_LEVELS;\n public enabled = true;\n public priority?: number;\n\n private _config?: AppenderConfig;\n private _formatter?: Formatter;\n private _filters: Filter[] = [];\n private _available = true;\n\n // Console method mapping with fallbacks for missing methods\n private off = () => {};\n private fatal = console.error ? console.error.bind(console) : console.log.bind(console);\n private error = console.error ? console.error.bind(console) : console.log.bind(console);\n private warn = console.warn ? console.warn.bind(console) : console.log.bind(console);\n private info = console.info ? console.info.bind(console) : console.log.bind(console);\n private debug = console.debug ? console.debug.bind(console) : console.log.bind(console);\n // Avoid console.trace as it captures stack traces and is significantly slower; prefer debug/log\n private trace = console.debug ? console.debug.bind(console) : console.log.bind(console);\n private track = console.log.bind(console);\n\n public init(config: AppenderConfig, formatter?: Formatter, filters?: Filter[]): void {\n this._config = config;\n this._formatter = formatter;\n this._filters = filters || [];\n this._available = typeof console !== 'undefined' && !!console.log;\n\n this.enabled = this._config?.enabled !== false; // Default to true if not specified\n this.priority = this._config?.priority;\n }\n\n public dispose(): void {\n // No resources to dispose for console appender\n }\n\n public write(event: LogEvent): void {\n if (!this._available) return;\n\n // Apply filters in sequence - any filter denial skips the event\n for (const filter of this._filters) {\n if (filter.enabled && !filter.filter(event)) {\n return; // Skip if any filter denies logging\n }\n }\n\n // Format the event or produce a minimal, fast default payload\n // When no formatter is provided, avoid passing the whole event object to the console,\n // as object inspection/serialization is comparatively slow and increases variance.\n const data = this._formatter ? this._formatter.format(event) : [event];\n\n // Output using level-appropriate console method\n this[event.level](...data);\n }\n\n public flush(): void {\n // No-op for console appender\n }\n\n public enableFilter(name: string): void {\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = true;\n }\n\n public disableFilter(name: string): void {\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = false;\n }\n\n private _getFilter(name: string): Filter | undefined {\n return this._filters.find((f) => f.name === name);\n }\n}\n\n/**\n * Factory for creating ConsoleAppender instances.\n *\n * Automatically registered with the LogM8 system and creates console appenders\n * when referenced by name in logging configuration.\n */\nclass ConsoleAppenderFactory implements PluginFactory<ConsoleAppenderConfig, ConsoleAppender> {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public create(config: AppenderConfig): ConsoleAppender {\n const appender = new ConsoleAppender();\n appender.init(config);\n return appender;\n }\n}\n\nexport { ConsoleAppender, ConsoleAppenderFactory };\n","import type { WriteStream } from 'fs';\nimport { createWriteStream } from 'fs';\n\nimport type { Appender } from '../Appender.ts';\nimport type { AppenderConfig } from '../AppenderConfig.ts';\nimport type { Filter } from '../Filter.ts';\nimport type { Formatter } from '../Formatter.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogLevel, type LogLevelType } from '../LogLevel.ts';\nimport { LogM8Utils } from '../LogM8Utils.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\nconst NAME = 'file';\nconst VERSION = '1.0.0';\nconst KIND = PluginKind.appender;\n\nconst DEFAULT_FILENAME = 'app.log';\n\nconst SUPPORTED_LEVELS = new Set<LogLevelType>([\n LogLevel.fatal,\n LogLevel.error,\n LogLevel.warn,\n LogLevel.info,\n LogLevel.debug,\n LogLevel.track,\n LogLevel.trace,\n]);\n\n/**\n * Configuration options for the file appender.\n *\n * - filename: Destination file path. The file is opened on init.\n * - append: When true, appends to the existing file; otherwise it is truncated.\n */\nexport interface FileAppenderConfig extends AppenderConfig {\n /** Destination file path to write logs into. */\n filename: string;\n /** Append to existing file (true) or overwrite on startup (false). Default: false */\n append?: boolean;\n}\n\n/**\n * Appender that writes each formatted log event to a file (one line per event).\n *\n * Behavior\n * - Initializes a WriteStream on init() using the provided filename.\n * - Joins formatted tokens with a single space and appends a trailing newline.\n * - If no formatter is configured, writes the raw LogEvent via String() coercion of tokens.\n * - Respects per-appender filters before writing.\n * - flush() is a no-op; data is flushed by the stream implementation. dispose() ends the stream.\n */\nclass FileAppender implements Appender {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public readonly supportedLevels = SUPPORTED_LEVELS;\n public enabled = true;\n public priority?: number;\n\n private _config?: FileAppenderConfig;\n private _formatter?: Formatter;\n private _filters: Filter[] = [];\n private _stream?: WriteStream;\n\n public init(config: AppenderConfig, formatter?: Formatter, filters?: Filter[]): void {\n this._config = config as FileAppenderConfig;\n this._formatter = formatter;\n this._filters = filters || [];\n const flags = this._config.append ? 'a' : 'w';\n this._stream = createWriteStream(this._config.filename ?? DEFAULT_FILENAME, { flags });\n\n this.enabled = this._config?.enabled !== false; // Default to true if not specified\n this.priority = this._config?.priority;\n }\n\n public dispose(): void {\n this._stream?.end();\n }\n\n public write(event: LogEvent): void {\n if (!this._stream) return;\n\n // Filter\n for (const filter of this._filters) {\n if (filter.enabled && !filter.filter(event)) {\n return; // Skip if any filter denies logging\n }\n }\n\n // Format\n const data = this._formatter ? this._formatter.format(event) : [event];\n\n // Log\n const message = data\n .map((d) => {\n if (LogM8Utils.isString(d)) return d;\n return String(d);\n })\n .join(' ');\n this._stream.write(message + '\\n');\n }\n\n public flush(): void {\n // No-op for file appender; data is flushed on stream end.\n }\n\n public enableFilter(name: string): void {\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = true;\n }\n\n public disableFilter(name: string): void {\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = false;\n }\n\n private _getFilter(name: string): Filter | undefined {\n return this._filters.find((f) => f.name === name);\n }\n}\n\nclass FileAppenderFactory implements PluginFactory<FileAppenderConfig, FileAppender> {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public create(config: AppenderConfig): FileAppender {\n const appender = new FileAppender();\n appender.init(config);\n return appender;\n }\n}\n\nexport { FileAppender, FileAppenderFactory };\n","/**\n * Regex pattern for matching timestamp format tokens.\n *\n * Matches tokens in descending length order to prevent partial replacement\n * (e.g., 'SSS' before 'SS' before 'S'). Used by formatTimestamp to identify\n * and replace format placeholders.\n */\nconst TIMESTAMP_TOKEN_REGEX = /(yyyy|SSS|hh|mm|ss|SS|zz|z|yy|MM|dd|A|a|h|S)/g;\n\nconst REGEX_MATCHER = /^\\/(.+)\\/([dgimsuvy]*)$/;\n\n// Constants for error serialization\nconst EXCLUDED_ERROR_KEYS = new Set(['name', 'message', 'stack', 'cause']);\nconst COMMON_NON_ENUMERABLE_PROPS = ['code', 'errno', 'syscall', 'path'] as const;\n\nexport interface StringifyLogOptions {\n /** Max object/array nesting depth to descend into (default 3). */\n maxDepth?: number;\n /** Truncate long string values to this length (default 200). */\n maxStringLength?: number;\n /** Truncate long arrays to this length (default: 100) */\n maxArrayLength?: number;\n}\n\nexport interface SerializedError {\n name: string;\n message: string;\n stack?: string;\n cause?: SerializedError | null;\n [key: string]: unknown; // For additional properties\n}\n\n/**\n * Utility functions for timestamp formatting and object property access.\n *\n * Provides environment detection, nested property traversal, and flexible\n * timestamp formatting with support for custom tokens, ISO formats, and\n * locale-specific output.\n */\nclass LogM8Utils {\n /**\n * Detects browser environment for feature compatibility.\n *\n * @returns True when both window and document global objects are available\n */\n public static isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof window.document !== 'undefined';\n }\n\n /**\n * Check if an object is a string.\n *\n * @param obj - The object to check.\n * @returns true if the object is a string, otherwise false.\n */\n public static isString(obj: unknown): boolean {\n return typeof obj === 'string' || obj instanceof String;\n }\n\n /**\n * Traverses nested object properties using dot-separated path notation.\n *\n * Supports both object property access and array indexing with numeric keys.\n * Also supports bracket notation for array indices which is normalized internally\n * (e.g., `data[0].items[2]` becomes `data.0.items.2`).\n * Safe navigation that returns undefined for invalid paths rather than throwing.\n *\n * @param obj - Source object to traverse\n * @param path - Dot-separated property path (e.g., 'user.profile.name', 'items.0.id')\n * or a path with bracket indices (e.g., 'items[0].id')\n * @returns Property value at the specified path, or undefined if not found\n *\n * @example\n * ```typescript\n * const data = { user: { profile: { name: 'John' } }, items: [{ id: 1 }, { id: 2 }] };\n * getPropertyByPath(data, 'user.profile.name'); // 'John'\n * getPropertyByPath(data, 'items.0.id'); // 1\n * getPropertyByPath(data, 'items[1].id'); // 2 (bracket notation)\n * getPropertyByPath(data, 'missing.path'); // undefined\n * ```\n */\n public static getPropertyByPath(obj: unknown, path: string): unknown {\n let value = obj;\n // Support bracket index notation by converting to dot-separated tokens, e.g., data[0].items[2] -> data.0.items.2\n const normalized = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const segments = normalized.split('.');\n for (const key of segments) {\n if (typeof value === 'object' && value !== null) {\n if (Array.isArray(value)) {\n // Handle array indexing with numeric keys\n const idx = Number(key);\n if (Number.isInteger(idx) && idx >= 0) {\n value = value[idx];\n continue;\n }\n }\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined;\n }\n }\n return value;\n }\n\n /**\n * Formats Date objects using preset formats or custom token patterns.\n *\n * Supports common presets ('iso', 'locale') and flexible token-based formatting\n * for complete control over timestamp appearance. Tokens are replaced with\n * corresponding date/time components, while non-token text is preserved literally.\n *\n * Supported format tokens:\n * - yyyy: 4-digit year (2025)\n * - yy: 2-digit year (25)\n * - MM: month with leading zero (01-12)\n * - dd: day with leading zero (01-31)\n * - hh: 24-hour format hour with leading zero (00-23)\n * - h: 12-hour format hour (1-12)\n * - mm: minutes with leading zero (00-59)\n * - ss: seconds with leading zero (00-59)\n * - SSS: milliseconds with leading zeros (000-999)\n * - SS: centiseconds with leading zero (00-99)\n * - S: deciseconds (0-9)\n * - A: uppercase AM/PM\n * - a: lowercase am/pm\n * - z: timezone offset with colon (±HH:MM)\n * - zz: timezone offset without colon (±HHMM)\n *\n * @param date - Date instance to format\n * @param fmt - Format preset ('iso'|'locale') or custom token pattern\n * @returns Formatted timestamp string\n *\n * @example\n * ```typescript\n * const date = new Date('2025-08-04T14:23:45.123Z');\n *\n * // Presets\n * formatTimestamp(date, 'iso'); // '2025-08-04T14:23:45.123Z'\n * formatTimestamp(date, 'locale'); // '8/4/2025, 2:23:45 PM' (locale-dependent)\n *\n * // Custom patterns\n * formatTimestamp(date, 'yyyy-MM-dd hh:mm:ss'); // '2025-08-04 14:23:45'\n * formatTimestamp(date, 'MM/dd/yyyy h:mm A'); // '08/04/2025 2:23 PM'\n * formatTimestamp(date, 'hh:mm:ss.SSS'); // '14:23:45.123'\n * formatTimestamp(date, 'yyyy-MM-dd hh:mm:ss z'); // '2025-08-04 14:23:45 +00:00'\n * ```\n */\n public static formatTimestamp(date: Date, fmt?: string): string {\n const fmtLower = fmt?.toLowerCase();\n if (!fmt || fmtLower === 'iso' || fmtLower === 'toisostring') {\n return date.toISOString();\n }\n if (fmtLower === 'locale' || fmtLower === 'tolocalestring') {\n return date.toLocaleString();\n }\n\n // Custom token-based formatting\n const pad = (n: number, z = 2) => String(n).padStart(z, '0');\n const hours24 = date.getHours();\n const hours12 = hours24 % 12 === 0 ? 12 : hours24 % 12;\n\n // Process tokens in descending length order to avoid partial matches\n return fmt.replace(TIMESTAMP_TOKEN_REGEX, (m) => {\n switch (m) {\n case 'yyyy':\n return pad(date.getFullYear(), 4);\n case 'yy':\n return pad(date.getFullYear() % 100);\n case 'MM':\n return pad(date.getMonth() + 1);\n case 'dd':\n return pad(date.getDate());\n case 'hh':\n return pad(hours24);\n case 'h':\n return pad(hours12);\n case 'mm':\n return pad(date.getMinutes());\n case 'ss':\n return pad(date.getSeconds());\n case 'SSS':\n return pad(date.getMilliseconds(), 3);\n case 'SS':\n return pad(Math.floor(date.getMilliseconds() / 10), 2);\n case 'S':\n return pad(Math.floor(date.getMilliseconds() / 100), 1);\n case 'A':\n return hours24 < 12 ? 'AM' : 'PM';\n case 'a':\n return hours24 < 12 ? 'am' : 'pm';\n case 'z':\n case 'zz': {\n // Calculate timezone offset: positive values are ahead of UTC\n const tzOffset = -date.getTimezoneOffset();\n const tzSign = tzOffset >= 0 ? '+' : '-';\n const tzHours = Math.floor(Math.abs(tzOffset) / 60);\n const tzMinutes = Math.abs(tzOffset) % 60;\n if (m === 'z') {\n // Format as ±HH:MM with colon separator\n return `${tzSign}${pad(tzHours)}:${pad(tzMinutes)}`;\n }\n // Format as ±HHMM without separator\n return `${tzSign}${pad(tzHours)}${pad(tzMinutes)}`;\n }\n\n default:\n return m;\n }\n });\n }\n\n /**\n * Converts arbitrary values into JSON strings optimized for logging systems.\n *\n * This utility ensures that any JavaScript value can be safely logged without causing\n * serialization errors or producing excessively large output. It's designed specifically\n * for logging contexts where reliability and readability are more important than\n * perfect fidelity.\n *\n * ## Key Features\n *\n * **Depth Protection**: Prevents stack overflows and excessive output by limiting\n * object traversal depth. Objects/arrays beyond the limit are replaced with\n * \"[Object]\" or \"[Array]\" placeholders.\n *\n * **Array Length Limiting**: Automatically truncates arrays that exceed the maximum\n * length threshold. Truncated arrays include a message indicating how many additional\n * items were omitted.\n *\n * **String Truncation**: Automatically truncates long strings to prevent log flooding.\n * Truncated strings end with an ellipsis (…) character.\n *\n * **Type Safety**: Handles problematic JavaScript types that would normally cause\n * JSON.stringify to throw:\n * - BigInt values are converted to strings\n * - Date objects are normalized to ISO 8601 format\n * - Error instances are serialized to structured objects via {@link LogM8Utils.serializeError}\n *\n * ## Implementation Details\n *\n * - Uses a WeakMap to track traversal depth per object, preventing revisits to the\n * same instance at different depths\n * - Respects existing `toJSON()` methods on objects\n * - Not designed for full cycle detection - cyclic references are handled by the\n * depth limit rather than explicit cycle breaking\n * - The replacer function executes in the context of the parent object, enabling\n * depth tracking through the traversal\n *\n * @param value - Any JavaScript value to stringify for logging (events, contexts, errors, etc.)\n * @param options - Configuration for controlling output size and complexity\n * @param options.maxDepth - Maximum nesting depth for objects/arrays (default: 3).\n * Level 0 = primitive values only,\n * Level 1 = top-level properties,\n * Level 2 = nested properties, etc.\n * @param options.maxArrayLength - Maximum number of array elements to include before truncation (default: 100).\n * Arrays exceeding this limit will be truncated with a message\n * indicating the number of omitted items.\n * @param options.maxStringLength - Maximum character length for strings before truncation (default: 200)\n * @param space - Indentation for pretty-printing. Can be a number (spaces) or string (e.g., '\\t').\n * Pass undefined for compact output (recommended for production logs).\n *\n * @returns A JSON string that is guaranteed to be safe for logging systems\n *\n * @example\n * // Basic usage with default options\n * const json = LogM8Utils.stringifyLog({ message: 'User logged in', userId: 12345 });\n * // => '{\"message\":\"User logged in\",\"userId\":12345}'\n *\n * @example\n * // Handling problematic types\n * const data = {\n * bigNumber: 123456789012345678901234567890n,\n * timestamp: new Date('2024-01-15T10:30:00Z'),\n * error: new Error('Connection failed'),\n * longText: 'x'.repeat(500)\n * };\n * const json = LogM8Utils.stringifyLog(data);\n * // => '{\"bigNumber\":\"123456789012345678901234567890\",\"timestamp\":\"2024-01-15T10:30:00.000Z\",\"error\":{...},\"longText\":\"xxx...xxx…\"}'\n *\n * @example\n * // Array length limiting for large arrays\n * const largeData = {\n * items: new Array(1000).fill({ id: 1, name: 'item' }),\n * values: Array.from({ length: 500 }, (_, i) => i)\n * };\n * const json = LogM8Utils.stringifyLog(largeData, { maxArrayLength: 50 });\n * // => '{\"items\":[{...},{...},...,\"... 950 more items\"],\"values\":[0,1,2,...,\"... 450 more items\"]}'\n *\n * @example\n * // Depth limiting for deeply nested objects\n * const deepObj = {\n * level1: {\n * level2: {\n * level3: {\n * level4: {\n * level5: 'too deep'\n * }\n * }\n * }\n * }\n * };\n * const json = LogM8Utils.stringifyLog(deepObj, { maxDepth: 3 });\n * // => '{\"level1\":{\"level2\":{\"level3\":{\"level4\":\"[Object]\"}}}}'\n *\n * @example\n * // Custom options for verbose debugging\n * const debugJson = LogM8Utils.stringifyLog(\n * complexObject,\n * { maxDepth: 5, maxArrayLength: 500, maxStringLength: 1000 },\n * 2 // Pretty print with 2 spaces\n * );\n *\n * @example\n * // Production logging with minimal output\n * const prodJson = LogM8Utils.stringifyLog(\n * userEvent,\n * { maxDepth: 2, maxArrayLength: 20, maxStringLength: 100 } // Aggressive truncation for high-volume logs\n * );\n *\n * @example\n * // Handling arrays with mixed content\n * const mixedArray = {\n * results: [\n * { id: 1, data: 'first' },\n * { id: 2, data: 'second' },\n * ...Array(200).fill({ id: 999, data: 'bulk' })\n * ]\n * };\n * const json = LogM8Utils.stringifyLog(mixedArray, { maxArrayLength: 10 });\n * // First 10 items preserved, then truncation message\n *\n * @see {@link LogM8Utils.serializeError} - For Error serialization details\n */\n public static stringifyLog(\n value: unknown,\n { maxDepth = 3, maxStringLength = 200, maxArrayLength = 100 }: StringifyLogOptions = {},\n space?: number | string,\n ): string {\n const levels = new WeakMap<object, number>();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n function replacer(this: any, key: string, v: any): any {\n // Depth gate first: if we've reached the cap, stop descending\n if (v && typeof v === 'object') {\n const parentLevel = levels.get(this as object) ?? 0;\n if (parentLevel >= maxDepth) {\n return Array.isArray(v) ? '[Array]' : '[Object]';\n }\n levels.set(v as object, parentLevel + 1);\n\n // Array length limiting\n if (Array.isArray(v) && v.length > maxArrayLength) {\n const truncated = v.slice(0, maxArrayLength);\n truncated.push(`... ${v.length - maxArrayLength} more items`);\n return truncated;\n }\n }\n\n // Practical logging tweaks\n if (LogM8Utils.isString(v) && v.length > maxStringLength) {\n return v.slice(0, maxStringLength) + '…';\n }\n if (typeof v === 'bigint') {\n return v.toString();\n }\n if (v instanceof Date) {\n return v.toISOString();\n }\n if (v instanceof Error) {\n return LogM8Utils.serializeError(v);\n }\n\n return v;\n }\n\n return JSON.stringify(value, replacer, space);\n }\n\n /**\n * Serializes an Error (or Error-like) into a plain, JSON-safe object.\n *\n * Behavior:\n * - Returns null for falsy inputs.\n * - If the object provides a custom toJSON(), that result is used verbatim to\n * honor caller-defined serialization.\n * - Otherwise includes standard fields: name, message, stack.\n * - Recursively serializes the optional error.cause chain using the same rules.\n * - Handles circular references in the cause chain safely.\n * - Copies other own enumerable properties (excluding name, message, stack, cause),\n * skipping properties that throw on access or are not JSON-serializable.\n * - Optionally includes common non-enumerable properties like 'code' if present.\n *\n * Important:\n * - This function does not attempt to preserve all non-enumerable properties.\n * - Circular references in the cause chain are detected and handled gracefully.\n *\n * @param error - Unknown error input (Error instance or compatible object).\n * @returns Structured error data suitable for logging, or null when input is falsy.\n *\n * @example\n * try {\n * throw new Error('Boom');\n * } catch (e) {\n * const payload = LogM8Utils.serializeError(e);\n * // { name: 'Error', message: 'Boom', stack: '...', ... }\n * }\n */\n public static serializeError(error: unknown): SerializedError | null {\n // Internal recursive function with circular reference tracking\n const serializeErrorInternal = (\n error: unknown,\n seen: WeakSet<object>,\n ): SerializedError | null => {\n // Handle non-error values\n if (!error) return null;\n\n // Type guard to check if it's an Error-like object\n const errorObj = error as Error;\n\n // Prevent circular references\n if (typeof errorObj === 'object' && errorObj !== null) {\n if (seen.has(errorObj)) {\n return {\n name: 'CircularReference',\n message: 'Circular reference detected in error cause chain',\n };\n }\n seen.add(errorObj);\n }\n\n // If the error has a toJSON method, use it\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (typeof (errorObj as any).toJSON === 'function') {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = (errorObj as any).toJSON();\n // Ensure the result is JSON-serializable\n JSON.stringify(result);\n return result;\n } catch (_e) {\n // If toJSON fails or returns non-serializable data, continue with standard serialization\n }\n }\n\n // Create base error object\n const serialized: SerializedError = {\n name: errorObj.name || 'Error',\n message: errorObj.message || '',\n stack: errorObj.stack,\n };\n\n // Handle the 'cause' property recursively\n if ('cause' in errorObj && errorObj.cause !== undefined) {\n serialized.cause = serializeErrorInternal(errorObj.cause, seen);\n }\n\n // Set of standard properties to exclude\n\n // Include other enumerable properties\n // This catches custom properties added to the error\n for (const key in errorObj) {\n if (Object.prototype.hasOwnProperty.call(errorObj, key) && !EXCLUDED_ERROR_KEYS.has(key)) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const value = (errorObj as any)[key];\n // Ensure the value is JSON-serializable\n JSON.stringify(value);\n serialized[key] = value;\n } catch (_e) {\n // Skip properties that can't be accessed or aren't JSON-serializable\n }\n }\n }\n\n // Optionally include specific non-enumerable properties that are commonly used\n for (const prop of COMMON_NON_ENUMERABLE_PROPS) {\n try {\n const descriptor = Object.getOwnPropertyDescriptor(errorObj, prop);\n if (descriptor && descriptor.value !== undefined) {\n // Ensure the value is JSON-serializable\n JSON.stringify(descriptor.value);\n serialized[prop] = descriptor.value;\n }\n } catch (_e) {\n // Skip if property access fails or value is not serializable\n }\n }\n\n return serialized;\n };\n\n // Start the serialization with a fresh WeakSet for tracking\n return serializeErrorInternal(error, new WeakSet());\n }\n\n /**\n * Take a regex in the format /regex/flags and parse it into a RegExp object\n *\n * @param regex regex in the format /regex/flags\n * @param extraFlags additional flags to apply to the regex\n * @returns RegExp object or undefined if the regex is invalid\n */\n public static parseRegexFromString(regex: string, extraFlags?: string[]): RegExp | undefined {\n try {\n const match = regex.match(REGEX_MATCHER);\n if (match == null) return undefined;\n const [, pattern, flags] = match;\n\n let finalFlags = flags;\n if (Array.isArray(extraFlags)) {\n for (const flag of extraFlags) {\n if (!flags.includes(flag)) {\n finalFlags += flag;\n }\n }\n }\n\n return new RegExp(pattern, finalFlags);\n } catch (_e) {\n return undefined;\n }\n }\n}\n\nexport { LogM8Utils };\n","import type { Filter } from '../Filter.ts';\nimport type { FilterConfig } from '../FilterConfig.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogM8Utils } from '../LogM8Utils.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\n/**\n * Configuration for MatchFilter.\n *\n * Provides simple allow/deny rule maps where each key is a dot-path into the LogEvent\n * (supports array bracket notation like `data[0].items[2]`) and each value is the value\n * that must match for the rule to apply.\n *\n * Behavior:\n * - allow: If provided and non-empty, an event must satisfy ALL allow rules to pass.\n * - deny: If provided, an event that satisfies ANY deny rule will be blocked.\n * - Precedence: deny rules take precedence over allow; i.e., an event that passes allow\n * but matches a deny rule will be denied.\n *\n * Examples:\n * ```ts\n * // Only allow events from a specific logger AND with a specific data value\n * { name: 'match-filter', allow: { 'logger': 'app.service', 'data[0].type': 'audit' } }\n *\n * // Deny events for a user id regardless of other matches\n * { name: 'match-filter', deny: { 'context.userId': '1234' } }\n *\n * // Combined example\n * {\n * name: 'match-filter',\n * allow: { 'logger': 'allow.this.logger', 'data[0].custom[3].path': 4 },\n * deny: { 'logger': 'block.this.logger', 'context.userId': '1234' }\n * }\n * ```\n */\nexport interface MatchFilterConfig extends FilterConfig {\n /** All rules in this map must match for the event to be allowed (AND). */\n allow?: Record<string, unknown>;\n /** If any rule in this map matches, the event will be denied (OR). */\n deny?: Record<string, unknown>;\n}\n\n/**\n * Built-in filter providing straightforward allow/deny path-based matching.\n *\n * Use this when you want quick, declarative filtering without writing code. Rules are\n * evaluated against the LogEvent using robust dot-path resolution (with support for\n * `array[index]` notation). Comparisons use deep equality for objects/arrays and strict\n * equality for primitives.\n */\nclass MatchFilter implements Filter {\n public name = 'match-filter';\n public version = '1.0.0';\n public kind = PluginKind.filter;\n\n public enabled = true;\n\n private _allow?: Record<string, unknown>;\n private _deny?: Record<string, unknown>;\n /**\n * Initializes allow/deny rule maps. Values are compared using deep equality for\n * arrays/objects and strict equality for primitives. Missing maps are treated as empty.\n * @param config - Filter configuration with optional allow/deny maps\n */\n public init(config: FilterConfig): void {\n const cfg = (config ?? {}) as MatchFilterConfig;\n // Pre-compile any regex-like strings (e.g., '/pattern/flags') in rule maps for efficiency\n this._allow = this._prepareRules(cfg.allow);\n this._deny = this._prepareRules(cfg.deny);\n this.enabled = cfg.enabled !== false; // Default to true if not specified\n }\n\n public dispose(): void {\n // no resources to release\n }\n\n /**\n * Evaluates the given event against configured rules.\n * - allow: if provided and non-empty, ALL rules must match (AND)\n * - deny: if provided, ANY match denies (OR); deny takes precedence over allow\n * Returns false on unexpected errors to fail-safe.\n * @param logEvent - Event to evaluate\n * @returns true when the event should be logged; false to drop\n */\n public filter(logEvent: LogEvent): boolean {\n try {\n // Allow rules: if provided, ALL must match\n if (this._allow && Object.keys(this._allow).length > 0) {\n for (const [path, expected] of Object.entries(this._allow)) {\n const actual = LogM8Utils.getPropertyByPath(logEvent, path);\n if (!this._matches(actual, expected)) return false;\n }\n }\n\n // Deny rules: if ANY matches, deny\n if (this._deny && Object.keys(this._deny).length > 0) {\n for (const [path, expected] of Object.entries(this._deny)) {\n const actual = LogM8Utils.getPropertyByPath(logEvent, path);\n if (this._matches(actual, expected)) return false;\n }\n }\n\n return true;\n } catch (_err) {\n // Be conservative on unexpected errors\n return false;\n }\n }\n\n // Matches actual against expected, supporting RegExp; otherwise deep equality.\n private _matches(actual: unknown, expected: unknown): boolean {\n // Pre-compiled regex\n if (expected instanceof RegExp) {\n if (actual === undefined || actual === null) return false;\n const asString = typeof actual === 'string' ? actual : String(actual);\n return expected.test(asString);\n }\n\n return this._isEqual(actual, expected);\n }\n\n // Simple deep equality for primitives, arrays, plain objects, dates\n private _isEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n\n // Handle NaN\n if (typeof a === 'number' && typeof b === 'number') {\n return Number.isNaN(a) && Number.isNaN(b);\n }\n\n // Dates\n if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();\n\n // Arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!this._isEqual(a[i], b[i])) return false;\n }\n return true;\n }\n\n // Plain objects\n if (this._isPlainObject(a) && this._isPlainObject(b)) {\n const aKeys = Object.keys(a as Record<string, unknown>);\n const bKeys = Object.keys(b as Record<string, unknown>);\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(b as object, key)) return false;\n if (\n !this._isEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])\n )\n return false;\n }\n return true;\n }\n\n return false;\n }\n\n private _isPlainObject(val: unknown): val is Record<string, unknown> {\n return (\n typeof val === 'object' &&\n val !== null &&\n !Array.isArray(val) &&\n Object.getPrototypeOf(val) === Object.prototype\n );\n }\n\n // Convert rule map values: regex-like strings -> RegExp; leave others as-is.\n private _prepareRules(map?: Record<string, unknown>): Record<string, unknown> | undefined {\n if (!map || Object.keys(map).length === 0) return undefined;\n const prepared: Record<string, unknown> = {};\n for (const [path, val] of Object.entries(map)) {\n if (typeof val === 'string') {\n const rx = LogM8Utils.parseRegexFromString(val);\n prepared[path] = rx ?? val;\n } else {\n prepared[path] = val;\n }\n }\n return prepared;\n }\n}\n\nclass MatchFilterFactory implements PluginFactory<MatchFilterConfig, MatchFilter> {\n public name = 'match-filter';\n public version = '1.0.0';\n public kind = PluginKind.filter;\n\n public create(config: MatchFilterConfig): MatchFilter {\n const filter = new MatchFilter();\n filter.init(config);\n return filter;\n }\n}\n\nexport { MatchFilterFactory };\n","import type { Formatter } from '../Formatter.ts';\nimport type { FormatterConfig } from '../FormatterConfig.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogLevel } from '../LogLevel.ts';\nimport { LogM8Utils } from '../LogM8Utils.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\nconst NAME = 'default-formatter';\nconst VERSION = '1.0.0';\nconst KIND = PluginKind.formatter;\n\nconst DEFAULT_FORMAT = ['{timestamp} {LEVEL} [{logger}]', '{message}', '{data}'];\nconst DEFAULT_TIMESTAMP_FORMAT = 'hh:mm:ss.SSS';\n\n/**\n * Configuration for the default text formatter.\n *\n * Extends the base FormatterConfig with options for template customization,\n * timestamp formatting, and optional colorization.\n */\nexport interface DefaultFormatterConfig extends FormatterConfig {\n /**\n * Custom format template(s) using token syntax.\n * Provide a single template string or an array of template strings for multi-line output.\n * Defaults to a readable text format: ['{timestamp} {LEVEL} [{logger}]', '{message}', '{data}'].\n */\n format?: string | string[];\n\n /**\n * Timestamp format pattern or preset.\n * Supports 'iso', 'locale', or custom token patterns (yyyy-MM-dd hh:mm:ss).\n */\n timestampFormat?: string;\n\n /**\n * Enable colorized output for level tokens.\n *\n * - Node.js: Applies ANSI escape codes.\n * - Browser: Returns a tuple ['%cLEVEL', css] suitable for console.log('%c..', ..)\n * when {LEVEL} is resolved; appenders may pass tokens straight to console APIs.\n *\n * Set to true to enable; environment detection is used only to decide ANSI vs CSS.\n */\n color?: boolean;\n}\n\n/**\n * Built-in text formatter with token-based templates and optional colorized levels.\n *\n * Features\n * - Customizable templates using curly-brace tokens mixed with literal text.\n * - Timestamp formatting via presets or custom patterns.\n * - Optional colorization of the {LEVEL} token (ANSI in Node.js, CSS tuple in browsers).\n *\n * Notes\n * - This formatter outputs text (not JSON). It returns an array of strings/values that\n * appenders can pass to console/file outputs.\n * - The {data} token resolves to the `logEvent.data` array. If present as its own\n * line entry, items are expanded in-place; if the array is empty, the token is removed.\n * - {message} is passed through as-is when it’s not a string (e.g., objects or errors).\n * - Any other token (including nested paths like {context.userId}) is resolved using\n * dot-path access on the LogEvent.\n *\n * Supported tokens\n * - {timestamp}: Formatted with `timestampFormat`.\n * - {LEVEL}: Uppercase level label (with optional colorization/padding).\n * - {level}: Lowercase level name.\n * - {logger}: Logger name.\n * - {message}: Primary log message (string or non-string value).\n * - {data}: Additional data arguments array (expanded inline when present alone in a line).\n * - {context.*}: Nested context properties.\n *\n * @example\n * // Text with colors\n * formatter.init({\n * format: '{timestamp} {LEVEL} [{logger}] {message}',\n * timestampFormat: 'hh:mm:ss.SSS',\n * color: true,\n * });\n *\n * // Multi-line text output with expanded data\n * formatter.init({\n * format: [\n * '{timestamp} {LEVEL} [{logger}] {message}',\n * 'Context: {context}',\n * 'Data: {data}',\n * ],\n * });\n */\nclass DefaultFormatter implements Formatter {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n private _config!: DefaultFormatterConfig;\n private _format!: string[][];\n private _timestampFormat: string = DEFAULT_TIMESTAMP_FORMAT;\n private _levelMap!: Record<string, string | [string, string]>;\n private _colorEnabled: boolean = false;\n\n // ANSI color codes for Node.js terminal output\n private _levelColorMap: Record<string, string> = {\n trace: '\\x1b[37m', // White\n track: '\\x1b[38;5;208m', // Orange\n debug: '\\x1b[90m', // Grey\n info: '\\x1b[34m', // Blue\n warn: '\\x1b[33m', // Yellow\n error: '\\x1b[31m', // Red\n fatal: '\\x1b[41m', // Red background\n };\n\n // CSS color styles for browser console output\n private _levelCssColorMap: Record<string, string> = {\n trace: 'color: #bbb;', // Light gray\n track: 'color: orange;',\n debug: 'color: grey;',\n info: 'color: blue;',\n warn: 'color: gold;',\n error: 'color: red;',\n fatal: 'background: red; color: white;',\n };\n\n public init(config: DefaultFormatterConfig): void {\n const isBrowser = LogM8Utils.isBrowser();\n\n this._config = Object.assign({}, config);\n this._colorEnabled = !!this._config.color;\n\n // Parse format templates into token/literal segments\n this._format = [];\n let formatConfig = (this._config.format ?? DEFAULT_FORMAT) as string[];\n if (typeof this._config.format === 'string') formatConfig = [this._config.format];\n\n if (formatConfig) {\n for (const f of formatConfig) {\n // Split format string preserving both tokens ({...}) and literal text\n const regex = /(\\{[^}]+\\})|([^{}]+)/g;\n const parts = [];\n let match;\n while ((match = regex.exec(f)) !== null) {\n if (match[1]) {\n parts.push(match[1]); // token\n } else if (match[2] !== undefined) {\n parts.push(match[2]); // literal (preserve all, including whitespace)\n }\n }\n this._format.push(parts);\n }\n }\n\n this._timestampFormat = this._config.timestampFormat ?? DEFAULT_TIMESTAMP_FORMAT;\n\n // Build level display map with padding and optional colorization\n const levelValues = Object.values(LogLevel);\n const maxLevelLength = Math.max(...levelValues.map((l) => l.length));\n\n this._levelMap = levelValues.reduce(\n (acc, level) => {\n let levelStr = level.toUpperCase().padEnd(maxLevelLength, ' ');\n if (this._colorEnabled) {\n if (isBrowser) {\n // Browser: return [text, cssStyle] array for console.log('%c...', style)\n const css = this._levelCssColorMap[level] || '';\n acc[level] = [`%c${levelStr}`, css];\n return acc;\n } else {\n // Node.js: wrap with ANSI escape codes\n const color = this._levelColorMap[level] || '';\n const reset = '\\x1b[0m';\n levelStr = color + levelStr + reset;\n }\n }\n acc[level] = levelStr;\n return acc;\n },\n {} as Record<string, string | [string, string]>,\n );\n }\n\n public dispose(): void {}\n\n public format(logEvent: LogEvent): unknown[] {\n let output: unknown[] | undefined;\n\n const formatArr = this._format;\n if (formatArr.length > 0) {\n output = formatArr.map((item) => {\n if (item.length === 1) {\n return this.resolveToken(item[0], logEvent);\n }\n return item.reduce((str, part) => {\n const val = this.resolveToken(part, logEvent);\n return str + String(val);\n }, '');\n });\n // Locate data token and expand or remove it based on content\n const dataIndex = output.findIndex((v) => Array.isArray(v));\n if (dataIndex >= 0) {\n const data = output[dataIndex] as unknown[];\n if (data.length > 0) output.splice(dataIndex, 1, ...data);\n else output.splice(dataIndex, 1);\n }\n } else {\n output = [\n LogM8Utils.formatTimestamp(logEvent.timestamp, this._timestampFormat),\n logEvent.level,\n logEvent.logger,\n logEvent.message,\n ...logEvent.data,\n logEvent.context,\n ];\n }\n\n return output;\n }\n\n private resolveToken(part: string, logEvent: LogEvent): unknown {\n // Process tokens using curly brace syntax: {property.path}\n if (part.startsWith('{') && part.endsWith('}')) {\n const key = part.slice(1, -1);\n if (key === 'message' && typeof logEvent.message !== 'string') {\n return logEvent.message;\n } else if (key === 'LEVEL') {\n return this._levelMap[logEvent.level] ?? logEvent.level;\n } else if (key === 'timestamp') {\n const raw = LogM8Utils.getPropertyByPath(logEvent, key);\n return LogM8Utils.formatTimestamp(raw as Date, this._timestampFormat);\n }\n // Resolve data properties and context via dot-path notation\n return LogM8Utils.getPropertyByPath(logEvent, key);\n }\n // Return literal text unchanged\n return part;\n }\n}\n\nclass DefaultFormatterFactory implements PluginFactory<DefaultFormatterConfig, DefaultFormatter> {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public create(config: DefaultFormatterConfig): DefaultFormatter {\n const appender = new DefaultFormatter();\n appender.init(config);\n return appender;\n }\n}\n\nexport { DefaultFormatterFactory };\n","import type { Formatter } from '../Formatter.ts';\nimport type { FormatterConfig } from '../FormatterConfig.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogM8Utils } from '../LogM8Utils.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\nconst NAME = 'json-formatter';\nconst VERSION = '1.0.0';\nconst KIND = PluginKind.formatter;\n\nconst DEFAULT_FORMAT = ['timestamp', 'level', 'logger', 'message', 'data'];\nconst DEFAULT_TIMESTAMP_FORMAT = 'iso';\nconst DEFAULT_PRETTY = 2;\nconst DEFAULT_MAX_DEPTH = 3;\nconst DEFAULT_MAX_STRING_LEN = 1000;\nconst DEFAULT_MAX_ARRAY_LEN = 100;\n\n/**\n * Configuration for the JSON formatter.\n *\n * Extends the base FormatterConfig with options for selecting which fields to\n * include, pretty printing, timestamp formatting, and output size limits.\n */\nexport interface JsonFormatterConfig extends FormatterConfig {\n /**\n * Fields to include in the output object.\n * Accepts a single field or an array of fields. Defaults to\n * ['timestamp', 'level', 'logger', 'message', 'data'].\n *\n * Each entry is used as the object key and resolved via dot-path on the LogEvent.\n * Special handling:\n * - 'LEVEL' returns the raw level string (e.g., 'info').\n * - 'timestamp' is formatted with `timestampFormat`.\n *\n * If the list is empty, the entire LogEvent object is used.\n */\n format?: string | string[];\n\n /**\n * Pretty-print JSON output.\n * - true: default indentation of 2 spaces.\n * - number: use the provided number of spaces.\n * - false/undefined: minified JSON with no extra whitespace.\n */\n pretty?: boolean | number;\n\n /**\n * Timestamp format pattern or preset.\n * Supports 'iso', 'locale', or custom token patterns (yyyy-MM-dd hh:mm:ss).\n */\n timestampFormat?: string;\n\n /**\n * Maximum depth for nested objects in JSON output.\n * Defaults to 3.\n */\n maxDepth?: number;\n\n /**\n * Maximum length for string values in JSON output.\n * Strings longer than this may be truncated by `stringifyLog`. Defaults to 1000.\n */\n maxStringLen?: number;\n\n /**\n * Maximum length for array values in JSON output.\n * Arrays longer than this may be truncated by `stringifyLog`. Defaults to 100.\n */\n maxArrayLen?: number;\n}\n\n/**\n * JSON formatter that emits a single JSON string per log event.\n *\n * Features\n * - Select fields via `format` (e.g., ['timestamp','level','logger','message','data']).\n * - Formats timestamps using `timestampFormat` ('iso', 'locale', or custom pattern).\n * - Pretty printing with fixed (2 spaces) or custom indentation.\n * - Output size controls via `maxDepth`, `maxStringLen`, and `maxArrayLen` (passed to `LogM8Utils.stringifyLog`).\n *\n * Behavior\n * - Returns an array with a single element: the JSON string representation of the selected fields.\n * - Field resolution uses dot-path access on the LogEvent (e.g., 'context.userId').\n * - Special tokens:\n * - 'timestamp': formatted per `timestampFormat`.\n * - 'LEVEL': raw level string (lowercase; no color or padding).\n * - If `format` is empty, the entire LogEvent object is serialized.\n *\n * Examples\n *\n * // Default fields, minified JSON\n * formatter.init({});\n * // => [\"{\\\"timestamp\\\":\\\"...\\\",\\\"level\\\":\\\"info\\\",\\\"logger\\\":\\\"app\\\",\\\"message\\\":\\\"...\\\",\\\"data\\\":[]}\"]\n *\n * // Pretty printed output (2 spaces)\n * formatter.init({ pretty: true });\n *\n * // Custom fields with a nested context property\n * formatter.init({\n * format: ['timestamp', 'LEVEL', 'logger', 'context.userId', 'message'],\n * timestampFormat: 'hh:mm:ss.SSS',\n * pretty: 2,\n * });\n */\nclass JsonFormatter implements Formatter {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n private _config!: JsonFormatterConfig;\n private _format!: string[];\n private _pretty: number | undefined;\n private _maxDepth: number = DEFAULT_MAX_DEPTH;\n private _maxStringLen: number = DEFAULT_MAX_STRING_LEN;\n private _maxArrayLen: number = DEFAULT_MAX_ARRAY_LEN;\n private _timestampFormat: string = DEFAULT_TIMESTAMP_FORMAT;\n\n public init(config: JsonFormatterConfig): void {\n this._config = Object.assign({}, config);\n\n this._pretty =\n this._config.pretty === true\n ? DEFAULT_PRETTY\n : this._config.pretty\n ? this._config.pretty\n : undefined;\n this._maxDepth = this._config.maxDepth ?? DEFAULT_MAX_DEPTH;\n this._maxStringLen = this._config.maxStringLen ?? DEFAULT_MAX_STRING_LEN;\n this._maxArrayLen = this._config.maxArrayLen ?? DEFAULT_MAX_ARRAY_LEN;\n\n let formatConfig = (this._config.format ?? DEFAULT_FORMAT) as string[];\n if (typeof this._config.format === 'string') formatConfig = [this._config.format];\n this._format = formatConfig;\n\n this._timestampFormat = this._config.timestampFormat ?? DEFAULT_TIMESTAMP_FORMAT;\n }\n\n public dispose(): void {}\n\n public format(logEvent: LogEvent): unknown[] {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let outputObj: any = {};\n\n const formatArr = this._format;\n if (formatArr.length > 0) {\n formatArr.forEach((item) => {\n const t = this.resolveToken(item, logEvent);\n if (t != undefined) {\n outputObj[t.key] = t.value;\n }\n });\n } else {\n // When no fields are specified, fall back to including the entire LogEvent object.\n outputObj = logEvent;\n }\n\n return [\n LogM8Utils.stringifyLog(\n outputObj,\n {\n maxDepth: this._maxDepth,\n maxStringLength: this._maxStringLen,\n maxArrayLength: this._maxArrayLen,\n },\n this._pretty,\n ),\n ];\n }\n\n private resolveToken(\n part: string,\n logEvent: LogEvent,\n ): { key: string; value: unknown } | undefined {\n // Process tokens for JSON object construction\n const key = part;\n if (key === 'LEVEL') {\n return { key, value: logEvent.level };\n } else if (key === 'timestamp') {\n const raw = LogM8Utils.getPropertyByPath(logEvent, key);\n return { key, value: LogM8Utils.formatTimestamp(raw as Date, this._timestampFormat) };\n }\n // Resolve properties via dot-path notation\n return { key, value: LogM8Utils.getPropertyByPath(logEvent, key) };\n }\n}\n\nclass JsonFormatterFactory implements PluginFactory<JsonFormatterConfig, JsonFormatter> {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public create(config: JsonFormatterConfig): JsonFormatter {\n const appender = new JsonFormatter();\n appender.init(config);\n return appender;\n }\n}\n\nexport { JsonFormatterFactory };\n","import type { Plugin } from './Plugin.ts';\nimport type { PluginConfig } from './PluginConfig.ts';\nimport type { PluginFactory } from './PluginFactory.ts';\nimport type { PluginKindType } from './PluginKind.ts';\n\n/**\n * Manages registration and lifecycle of plugin factories and created plugin instances.\n * Allows registering factories, creating plugins by kind, and disposing resources.\n */\nclass PluginManager {\n private _pluginFactories: Map<string, PluginFactory> = new Map();\n private _plugins: Plugin[] = [];\n\n /**\n * Registers a plugin factory.\n * @param pluginFactory - Factory to register for creating plugins.\n * @throws Error if a factory with the same name is already registered.\n */\n registerPluginFactory(pluginFactory: PluginFactory): void {\n if (this._pluginFactories.has(pluginFactory.name)) {\n throw new Error(`LogM8: Plugin with name ${pluginFactory.name} is already registered.`);\n }\n this._pluginFactories.set(pluginFactory.name, pluginFactory);\n }\n\n /**\n * Creates and registers a plugin instance using the matching factory.\n * @param kind - The kind of plugin to create (appender, filter, formatter).\n * @param nameOrConfig - Plugin name string or configuration object with plugin name.\n * @returns The created plugin instance.\n * @throws Error if no matching factory is found.\n */\n createPlugin(kind: PluginKindType, nameOrConfig: string | PluginConfig): Plugin {\n const name = typeof nameOrConfig === 'string' ? nameOrConfig : nameOrConfig.name;\n const config = typeof nameOrConfig === 'string' ? { name } : nameOrConfig;\n const pluginFactory = this.getPluginFactory(name, kind);\n if (!pluginFactory) {\n throw new Error(`LogM8: Plugin factory kind '${kind}' with name '${name}' not found.`);\n }\n const plugin = pluginFactory.create(config);\n this._plugins.push(plugin);\n return plugin;\n }\n\n /**\n * Retrieves a registered plugin factory by name and kind.\n * @param name - The factory name.\n * @param kind - The expected plugin kind.\n * @returns The factory if found and matching kind, otherwise undefined.\n */\n getPluginFactory(name: string, kind: PluginKindType): PluginFactory | undefined {\n const pluginFactory = this._pluginFactories.get(name);\n if (!pluginFactory || kind !== pluginFactory.kind) return;\n return pluginFactory;\n }\n\n /**\n * Disposes all created plugin instances by invoking their dispose methods.\n * Clears the internal plugin list.\n */\n disposePlugins(): void {\n this._plugins.forEach((plugin) => {\n plugin.dispose();\n });\n this._plugins = [];\n }\n\n /**\n * Clears all registered plugin factories without disposing instances.\n */\n clearFactories(): void {\n this._pluginFactories.clear();\n }\n}\n\nexport { PluginManager };\n","import type { Appender } from './Appender.ts';\nimport type { AppenderConfig } from './AppenderConfig.ts';\nimport { ConsoleAppenderFactory } from './appenders/ConsoleAppender.ts';\n/* NODEJS:START */\nimport { FileAppenderFactory } from './appenders/FileAppender.ts';\n/* NODEJS:END */\nimport type { Filter } from './Filter.ts';\nimport { MatchFilterFactory } from './filters/MatchFilter.ts';\nimport type { Formatter } from './Formatter.ts';\nimport { DefaultFormatterFactory } from './formatters/DefaultFormatter.ts';\nimport { JsonFormatterFactory } from './formatters/JsonFormatter.ts';\nimport type { Log } from './Log.ts';\nimport type { LogContext } from './LogContext.ts';\nimport type { LogEvent } from './LogEvent.ts';\nimport type { LoggingConfig } from './LoggingConfig.ts';\nimport type { LogImpl } from './LogImpl.ts';\nimport { LogLevel, type LogLevelType } from './LogLevel.ts';\nimport { LogM8Utils } from './LogM8Utils.ts';\nimport type { PluginFactory } from './PluginFactory.ts';\nimport { PluginKind } from './PluginKind.ts';\nimport { PluginManager } from './PluginManager.ts';\n\nconst MAX_LOG_BUFFER_SIZE = 100; // Maximum size of the log buffer before dropping events\nconst DEFAULT_FORMATTER = 'default-formatter';\nconst DEFAULT_APPENDERS = [\n {\n name: 'console',\n formatter: DEFAULT_FORMATTER,\n },\n];\n\n/**\n * Central logging manager providing hierarchical loggers and configurable output.\n *\n * LogM8 manages the complete logging lifecycle including:\n * - Logger creation and configuration with hierarchical naming\n * - Plugin-based appender, formatter, and filter system\n * - Pre-initialization event buffering (up to 100 events)\n * - Runtime appender and filter control (enable/disable/flush)\n * - Built-in console and file appenders with customizable formatting\n *\n * The manager operates as a singleton export but can also be instantiated directly.\n * Events logged before init() are buffered and flushed on first post-init log.\n *\n * @example\n * ```typescript\n * import { Logging } from 'log-m8';\n *\n * // Configure logging system\n * Logging.init({\n * level: 'info',\n * loggers: { 'app.database': 'debug' },\n * appenders: [\n * { name: 'console', formatter: 'default-formatter' },\n * { name: 'file', filename: 'app.log' }\n * ]\n * });\n *\n * // Use hierarchical loggers\n * const logger = Logging.getLogger('app.service');\n * logger.info('Service started');\n *\n * // Runtime control\n * Logging.disableAppender('console');\n * Logging.disableFilter('sensitive-data');\n * Logging.flushAppenders();\n * ```\n */\nclass LogM8 {\n private _initialized: boolean;\n private _pluginManager: PluginManager;\n private _loggers: Map<string, Log>;\n private _appenders: Appender[];\n private _filters: Filter[] = [];\n\n private _globalLogLevel: LogLevelType;\n private _globalLogLevelNumber: number;\n private _logLevelValues: LogLevelType[];\n private _logLevelSet: Set<LogLevelType>;\n\n // Buffer for log events before the system is initialized\n private _logBuffer: LogEvent[];\n\n constructor() {\n this._initialized = false;\n this._pluginManager = new PluginManager();\n this._loggers = new Map();\n this._appenders = [];\n this._filters = [];\n\n this._logLevelValues = Object.values(LogLevel);\n this._logLevelSet = new Set<LogLevelType>(this._logLevelValues);\n this._globalLogLevel = LogLevel.info;\n this._globalLogLevelNumber = this._logLevelValues.indexOf(LogLevel.info);\n\n this._logBuffer = [];\n\n // Register built-in plugin factories for console/file appenders and default formatter\n this._pluginManager.registerPluginFactory(new ConsoleAppenderFactory());\n /* NODEJS:START */\n this._pluginManager.registerPluginFactory(new FileAppenderFactory());\n /* NODEJS:END */\n this._pluginManager.registerPluginFactory(new DefaultFormatterFactory());\n this._pluginManager.registerPluginFactory(new JsonFormatterFactory());\n this._pluginManager.registerPluginFactory(new MatchFilterFactory());\n }\n\n /**\n * Initializes the logging system with configuration and flushes any buffered events.\n *\n * Sets up default and per-logger levels, creates configured appenders with their\n * formatters and filters, and processes any events buffered before initialization.\n * Appenders are sorted by priority (descending) for deterministic execution order.\n *\n * @param config - Logging configuration object\n * @param config.level - Default log level for all loggers ('info' if not specified)\n * @param config.loggers - Per-logger level overrides by name\n * @param config.appenders - Appender configurations (defaults to console if not specified)\n *\n * @throws {Error} When referenced plugin factories are not registered\n *\n * @example\n * ```typescript\n * Logging.init({\n * level: 'warn',\n * loggers: { 'app.database': 'debug' },\n * appenders: [{\n * name: 'console',\n * formatter: 'default-formatter',\n * filters: ['sensitive-data']\n * }]\n * });\n * ```\n */\n public init(config?: LoggingConfig): void {\n config = Object.assign({}, config);\n\n this._reset();\n\n // Set the default logging level\n const levelStr = (config.level ?? '').trim().toLowerCase();\n this._globalLogLevel = this._logLevelSet.has(levelStr as LogLevelType)\n ? (levelStr as LogLevelType)\n : LogLevel.info;\n\n // Set up loggers\n for (const [name, l] of Object.entries(config.loggers ?? {})) {\n const levelStr = (l ?? '').trim().toLowerCase();\n const logger = this.getLogger(name);\n const level = this._logLevelSet.has(levelStr as LogLevelType)\n ? (levelStr as LogLevelType)\n : this._globalLogLevel;\n logger.setLevel(level);\n }\n\n // Set up appenders\n const appenderConfigs = config.appenders ?? DEFAULT_APPENDERS;\n for (const appenderConfigOrName of appenderConfigs) {\n const appender = this._pluginManager.createPlugin(\n PluginKind.appender,\n appenderConfigOrName,\n ) as Appender;\n\n const appenderConfig: AppenderConfig = LogM8Utils.isString(appenderConfigOrName)\n ? {\n name: appender.name,\n }\n : (appenderConfigOrName as AppenderConfig);\n\n const formatter = appenderConfig?.formatter\n ? (this._pluginManager.createPlugin(\n PluginKind.formatter,\n appenderConfig.formatter,\n ) as Formatter)\n : undefined;\n\n const filters: Filter[] = [];\n const ac = appenderConfig as AppenderConfig;\n for (const filterConfig of ac.filters ?? []) {\n const filter = this._pluginManager.createPlugin(PluginKind.filter, filterConfig);\n if (filter) {\n filters.push(filter as Filter);\n } else {\n if (console && console.log) {\n console.log(\n `LogM8: Filter '${filterConfig}' not found for appender ${appenderConfig.name}.`,\n );\n }\n }\n }\n\n appender.init(appenderConfig, formatter, filters);\n this._appenders.push(appender);\n }\n\n // Sort the appenders by their priority\n this._sortAppenders();\n\n // Set up global filters\n for (const filterConfig of config.filters ?? []) {\n const filter = this._pluginManager.createPlugin(PluginKind.filter, filterConfig);\n if (filter) {\n this._filters.push(filter as Filter);\n } else {\n if (console && console.log) {\n console.log(`LogM8: Filter '${filterConfig}' not found (global).`);\n }\n }\n }\n\n this._initialized = true;\n }\n\n /**\n * Shuts down the logging system and releases all resources.\n *\n * Flushes all appenders, disposes plugin instances, clears logger registry,\n * discards buffered events, and deregisters plugin factories. The system\n * can be reinitialized after disposal.\n *\n * @example\n * ```typescript\n * // Graceful shutdown\n * await new Promise(resolve => {\n * Logging.flushAppenders();\n * setTimeout(() => {\n * Logging.dispose();\n * resolve();\n * }, 100);\n * });\n * ```\n */\n public dispose(): void {\n // Reset to initial state (flushes appenders, disposes all plugins)\n this._reset();\n\n // Clear the log buffer\n this._logBuffer = [];\n\n // Deregister all plugin factories\n this._pluginManager.clearFactories();\n\n this._initialized = false;\n }\n\n /**\n * Checks if the logging system has been initialized.\n *\n * @returns True if the system is initialized, false otherwise.\n */\n public isInitialized(): boolean {\n return this._initialized;\n }\n\n /**\n * Retrieves or creates a logger instance with hierarchical naming.\n *\n * Logger instances are cached and reused for the same name. Names can be\n * provided as strings with dot-separation or as array segments that get\n * joined. Each logger maintains independent level and context settings.\n *\n * @param name - Logger name as string ('app.service') or segments (['app', 'service'])\n * @returns Logger instance for the specified name\n *\n * @example\n * ```typescript\n * const logger1 = Logging.getLogger('app.database');\n * const logger2 = Logging.getLogger(['app', 'database']);\n * // logger1 === logger2 (same instance)\n *\n * logger1.setLevel('debug');\n * logger1.setContext({ service: 'postgres' });\n * ```\n */\n public getLogger(name: string | string[]): Log {\n let nameStr: string = name as string;\n if (Array.isArray(name)) {\n nameStr = name.join('.');\n }\n\n const existingLogger = this._loggers.get(nameStr);\n if (existingLogger) return existingLogger;\n\n const logger: LogImpl = {\n name: nameStr,\n level: this._globalLogLevel,\n context: {},\n } as LogImpl;\n\n logger.fatal = this._log.bind(this, logger, LogLevel.fatal);\n logger.error = this._log.bind(this, logger, LogLevel.error);\n logger.warn = this._log.bind(this, logger, LogLevel.warn);\n logger.info = this._log.bind(this, logger, LogLevel.info);\n logger.debug = this._log.bind(this, logger, LogLevel.debug);\n logger.trace = this._log.bind(this, logger, LogLevel.trace);\n logger.track = this._log.bind(this, logger, LogLevel.track);\n\n logger.setLevel = this._setLevel.bind(this, logger);\n logger.setContext = this._setContext.bind(this, logger);\n logger.getLogger = (name) => this.getLogger([logger.name, name]);\n\n // Set initial level and context\n this._setLevel(logger, this._globalLogLevel);\n\n this._loggers.set(logger.name, logger);\n\n return logger;\n }\n\n /**\n * Sets the global logging level or a specific logger's level.\n *\n * @param level - New logging level name (e.g., 'info', 'debug', 'off')\n * @param logger - Optional logger name to set level for a specific logger\n */\n public setLevel(level: LogLevelType, logger?: string): void {\n if (logger) {\n this.getLogger(logger).setLevel(level);\n } else {\n // Set global log level\n this._globalLogLevel = this._logLevelSet.has(level) ? level : this._globalLogLevel;\n this._globalLogLevelNumber = this._logLevelValues.indexOf(this._globalLogLevel);\n }\n }\n\n /**\n * Enables an appender to resume processing log events.\n *\n * @param name - Name of the appender to enable\n */\n public enableAppender(name: string): void {\n const appender = this._getAppender(name);\n if (!appender) return;\n appender.enabled = true;\n }\n\n /**\n * Disables an appender to stop processing log events.\n *\n * @param name - Name of the appender to disable\n */\n public disableAppender(name: string): void {\n const appender = this._getAppender(name);\n if (!appender) return;\n appender.enabled = false;\n }\n\n /**\n * Forces an appender to flush any buffered output.\n *\n * Catches and logs flush errors to console without interrupting operation.\n * Useful for ensuring data persistence before shutdown or at intervals.\n *\n * @param name - Name of the appender to flush\n */\n public flushAppender(name: string): void {\n const appender = this._getAppender(name);\n if (!appender) return;\n try {\n appender.flush();\n } catch (err) {\n if (console && console.error) {\n console.error(`LogM8: Failed to flush appender: ${appender.name}:`, err);\n }\n }\n }\n\n /**\n * Flushes all configured appenders.\n *\n * Iterates through all appenders calling flush on each, with individual\n * error handling per appender.\n */\n public flushAppenders(): void {\n for (const appender of this._appenders) {\n this.flushAppender(appender.name);\n }\n }\n\n /**\n * Enables a filter to resume processing log events.\n *\n * When an appender name is provided, enables the filter only for that specific\n * appender. When no appender is specified, enables the filter globally.\n * Silently ignores requests for non-existent filters or appenders.\n *\n * @param name - Name of the filter to enable\n * @param appenderName - Optional appender name to enable filter for specific appender only\n *\n * @example\n * ```typescript\n * // Enable filter globally\n * Logging.enableFilter('sensitive-data');\n *\n * // Enable filter only for console appender\n * Logging.enableFilter('debug-filter', 'console');\n * ```\n */\n public enableFilter(name: string, appenderName?: string): void {\n if (appenderName) {\n this._getAppender(appenderName)?.enableFilter(name);\n return;\n }\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = true;\n }\n\n /**\n * Disables a filter to stop processing log events.\n *\n * When an appender name is provided, disables the filter only for that specific\n * appender. When no appender is specified, disables the filter globally.\n * Silently ignores requests for non-existent filters or appenders.\n *\n * @param name - Name of the filter to disable\n * @param appenderName - Optional appender name to disable filter for specific appender only\n *\n * @example\n * ```typescript\n * // Disable filter globally\n * Logging.disableFilter('sensitive-data');\n *\n * // Disable filter only for file appender\n * Logging.disableFilter('debug-filter', 'file');\n * ```\n */\n public disableFilter(name: string, appenderName?: string): void {\n if (appenderName) {\n this._getAppender(appenderName)?.disableFilter(name);\n return;\n }\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = false;\n }\n\n /**\n * Registers a custom plugin factory for appenders, formatters, or filters.\n *\n * Allows extending the logging system with custom implementations.\n * Must be called before init() to be available during configuration.\n *\n * @param pluginFactory - Factory instance implementing the PluginFactory interface\n *\n * @example\n * ```typescript\n * class SlackAppenderFactory implements PluginFactory {\n * name = 'slack';\n * kind = PluginKind.appender;\n * create(config) { return new SlackAppender(config); }\n * }\n *\n * Logging.registerPluginFactory(new SlackAppenderFactory());\n * ```\n */\n public registerPluginFactory(pluginFactory: PluginFactory): void {\n this._pluginManager.registerPluginFactory(pluginFactory);\n }\n\n private _log(\n logger: LogImpl,\n level: LogLevelType,\n message: string | unknown,\n ...data: unknown[]\n ): void {\n // Early return if level not enabled - O(1) performance for disabled logs\n const levelNumber = this._logLevelValues.indexOf(level);\n if (levelNumber > logger._levelNumber || levelNumber > this._globalLogLevelNumber) return;\n\n // Create a log event for the log\n const logEvent: LogEvent = {\n logger: logger.name,\n level,\n message,\n data,\n context: logger.context,\n timestamp: new Date(),\n };\n\n if (this._initialized) {\n // Process buffered log events first (FIFO order)\n if (this._logBuffer.length > 0) {\n for (const bufferedEvent of this._logBuffer) {\n this._processLogEvent(bufferedEvent);\n }\n this._logBuffer = []; // Clear the buffer after processing\n }\n\n // Process the log event immediately\n this._processLogEvent(logEvent);\n } else {\n // Buffer the log events until initialization is complete\n if (this._logBuffer.length >= MAX_LOG_BUFFER_SIZE) {\n this._logBuffer.shift(); // Drop the oldest event if buffer is full\n }\n this._logBuffer.push(logEvent);\n }\n }\n\n private _setLevel(logger: LogImpl, level: LogLevelType): void {\n logger.level = this._logLevelSet.has(level) ? level : logger.level;\n\n logger._levelNumber = this._logLevelValues.indexOf(level);\n\n logger.isEnabled = logger.level !== LogLevel.off;\n // Boolean flags indicate enablement for that severity level and above\n const levelNumber = logger._levelNumber;\n logger.isFatal = this._logLevelValues.indexOf(LogLevel.fatal) <= levelNumber;\n logger.isError = this._logLevelValues.indexOf(LogLevel.error) <= levelNumber;\n logger.isWarn = this._logLevelValues.indexOf(LogLevel.warn) <= levelNumber;\n logger.isInfo = this._logLevelValues.indexOf(LogLevel.info) <= levelNumber;\n logger.isDebug = this._logLevelValues.indexOf(LogLevel.debug) <= levelNumber;\n logger.isTrack = this._logLevelValues.indexOf(LogLevel.track) <= levelNumber;\n logger.isTrace = this._logLevelValues.indexOf(LogLevel.trace) <= levelNumber;\n }\n\n private _setContext(logger: LogImpl, context: LogContext): void {\n logger.context = context ?? {};\n }\n\n private _processLogEvent(event: LogEvent): void {\n // Filter\n for (const filter of this._filters) {\n if (filter.enabled && !filter.filter(event)) {\n return; // Skip if any filter denies logging\n }\n }\n\n // Process each appender (they should be in their priority order)\n for (const appender of this._appenders) {\n try {\n if (!appender.enabled) continue;\n if (!appender.supportedLevels.has(event.level)) continue;\n appender.write(event);\n } catch (err) {\n if (console && console.log) {\n console.log(`LogM8: Failed to append log with '${appender.name}':`, err);\n }\n }\n }\n }\n\n private _getAppender(name: string): Appender | undefined {\n return this._appenders.find((a) => a.name === name);\n }\n\n private _sortAppenders(): void {\n // Sort by descending priority - higher numbers execute first\n this._appenders.sort((a, b) => {\n const aPriority = a?.priority ?? 0;\n const bPriority = b?.priority ?? 0;\n return bPriority - aPriority; // Higher priority first\n });\n }\n\n private _getFilter(name: string): Filter | undefined {\n return this._filters.find((f) => f.name === name);\n }\n\n private _reset(): void {\n // FLush all appenders before disposing\n this.flushAppenders();\n\n this._appenders = [];\n this._loggers.clear();\n this._globalLogLevel = LogLevel.info;\n\n // Dispose all plugins\n this._pluginManager.disposePlugins();\n }\n}\n\nexport { LogM8 };\n"],"mappings":"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","names":["LogM8","error","NAME","VERSION","KIND","SUPPORTED_LEVELS","NAME","VERSION","KIND","NAME","VERSION","KIND","DEFAULT_FORMAT","DEFAULT_TIMESTAMP_FORMAT","levelStr","name","LogM8"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/LogLevel.ts","../src/PluginKind.ts","../src/appenders/ConsoleAppender.ts","../src/appenders/FileAppender.ts","../src/LogM8Utils.ts","../src/filters/MatchFilter.ts","../src/formatters/DefaultFormatter.ts","../src/formatters/JsonFormatter.ts","../src/PluginManager.ts","../src/LogM8.ts","../src/NullLogger.ts"],"sourcesContent":["import { LogM8 as Logging } from './LogM8.ts';\n\n// Type exports for public API\nexport { type Appender } from './Appender.ts';\nexport { type AppenderConfig } from './AppenderConfig.ts';\nexport { type ConsoleAppenderConfig } from './appenders/ConsoleAppender.ts';\n/* NODEJS:START */\nexport { type FileAppenderConfig } from './appenders/FileAppender.ts';\n/* NODEJS:END */\nexport { type Filter } from './Filter.ts';\nexport { type FilterConfig } from './FilterConfig.ts';\nexport { type MatchFilterConfig } from './filters/MatchFilter.ts';\nexport { type Formatter } from './Formatter.ts';\nexport { type FormatterConfig } from './FormatterConfig.ts';\nexport { type DefaultFormatterConfig } from './formatters/DefaultFormatter.ts';\nexport { type Log } from './Log.ts';\nexport { type LogContext } from './LogContext.ts';\nexport { type LoggingConfig } from './LoggingConfig.ts';\nexport { LogLevel, type LogLevelType } from './LogLevel.ts';\nexport { LogM8Utils } from './LogM8Utils.ts';\nexport { NullLogger } from './NullLogger.ts';\nexport { type Plugin } from './Plugin.ts';\nexport { type PluginConfig } from './PluginConfig.ts';\nexport { type PluginFactory } from './PluginFactory.ts';\nexport { PluginKind, type PluginKindType } from './PluginKind.ts';\n\n/**\n * Default singleton instance of the LogM8 logging manager.\n *\n * Pre-configured with built-in appenders and formatters for immediate use.\n * Most applications should use this export rather than creating new LogM8 instances.\n *\n * @example\n * ```typescript\n * import { LogM8 } from 'log-m8';\n *\n * // Initialize with default console output\n * LogM8.init();\n *\n * // Get a logger and start logging\n * const logger = LogM8.getLogger('app');\n * logger.info('Application started');\n * ```\n */\nconst LogM8 = new Logging();\nexport { LogM8 };\n","/**\n * Enumeration of supported log severity levels in ascending order of verbosity.\n *\n * The logging system uses this hierarchy to determine which events to emit:\n * - 'off': Disables all logging\n * - 'fatal': Critical system failures requiring immediate intervention\n * - 'error': Failures preventing normal operation\n * - 'warn': Potentially problematic situations\n * - 'info': General informational messages about normal operation\n * - 'debug': Detailed diagnostic information for development\n * - 'track': Analytics and user behavior tracking events\n * - 'trace': Most detailed execution information for fine-grained debugging\n *\n * Events are emitted when their level index is <= logger's level index.\n * The 'track' level is positioned between 'debug' and 'trace' to allow\n * analytics collection without the verbosity of full trace logging.\n *\n * @example\n * ```typescript\n * // Logger set to 'info' will emit: fatal, error, warn, info\n * logger.setLevel('info');\n * logger.debug('Not emitted'); // debug > info in hierarchy\n * logger.info('Emitted'); // info <= info in hierarchy\n * ```\n */\nconst LogLevel = {\n off: 'off', // No logging\n\n fatal: 'fatal',\n error: 'error',\n warn: 'warn',\n info: 'info',\n debug: 'debug',\n track: 'track', // Special log level for analytics\n trace: 'trace',\n} as const;\n\n/**\n * Type representing a LogLevel enum value.\n */\nexport type LogLevelType = (typeof LogLevel)[keyof typeof LogLevel];\n\nexport { LogLevel };\n","/**\n * Enumeration of plugin types supported by the LogM8 plugin system.\n *\n * The logging system uses a plugin architecture where functionality is\n * provided by three categories of plugins:\n *\n * - **appender**: Output destinations that write formatted log events\n * - **filter**: Event processors that determine which events to log\n * - **formatter**: Event transformers that convert LogEvent objects to output format\n *\n * Each plugin factory must declare its kind to enable proper registration\n * and instantiation during system initialization.\n *\n * @example\n * ```typescript\n * class CustomAppender implements Appender {\n * kind = PluginKind.appender;\n * // ... implementation\n * }\n *\n * class CustomFilter implements Filter {\n * kind = PluginKind.filter;\n * // ... implementation\n * }\n * ```\n */\nconst PluginKind = {\n appender: 'appender', // Log output destinations (console, file, network, etc.)\n filter: 'filter', // Event filtering logic (level, content, rate limiting, etc.)\n formatter: 'formatter', // Event formatting (text, JSON, custom templates, etc.)\n} as const;\n\n/**\n * Type representing a PluginKind enum value.\n */\nexport type PluginKindType = (typeof PluginKind)[keyof typeof PluginKind];\n\nexport { PluginKind };\n","import type { Appender } from '../Appender.ts';\nimport type { AppenderConfig } from '../AppenderConfig.ts';\nimport type { Filter } from '../Filter.ts';\nimport type { Formatter } from '../Formatter.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogLevel, type LogLevelType } from '../LogLevel.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\nconst NAME = 'console';\nconst VERSION = '1.0.0';\nconst KIND = PluginKind.appender;\n\nconst SUPPORTED_LEVELS = new Set<LogLevelType>([\n LogLevel.fatal,\n LogLevel.error,\n LogLevel.warn,\n LogLevel.info,\n LogLevel.debug,\n LogLevel.track,\n LogLevel.trace,\n]);\n\n/**\n * Configuration interface for console appender.\n * Currently extends base AppenderConfig without additional options.\n */\nexport interface ConsoleAppenderConfig extends AppenderConfig {\n //\n}\n\n/**\n * Built-in appender that outputs log events to the global console object.\n *\n * Maps log levels to appropriate console methods (error, warn, info, debug, etc.)\n * with fallback to console.log when specific methods are unavailable.\n * Automatically detects console availability and gracefully handles environments\n * where console is not available.\n *\n * Features:\n * - Zero-configuration operation\n * - Automatic console method mapping by log level\n * - Graceful degradation when console methods are missing\n * - No-op flush operation (console output is immediate)\n * - Environment detection for console availability\n *\n * @example\n * ```typescript\n * // Automatic registration - no manual setup needed\n * Logging.init({\n * appenders: [{ name: 'console', formatter: 'default-formatter' }]\n * });\n * ```\n */\nclass ConsoleAppender implements Appender {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public readonly supportedLevels = SUPPORTED_LEVELS;\n public enabled = true;\n public priority?: number;\n\n private _config?: AppenderConfig;\n private _formatter?: Formatter;\n private _filters: Filter[] = [];\n private _available = true;\n\n // Console method mapping with fallbacks for missing methods\n private off = () => {};\n private fatal = console.error ? console.error.bind(console) : console.log.bind(console);\n private error = console.error ? console.error.bind(console) : console.log.bind(console);\n private warn = console.warn ? console.warn.bind(console) : console.log.bind(console);\n private info = console.info ? console.info.bind(console) : console.log.bind(console);\n private debug = console.debug ? console.debug.bind(console) : console.log.bind(console);\n // Avoid console.trace as it captures stack traces and is significantly slower; prefer debug/log\n private trace = console.debug ? console.debug.bind(console) : console.log.bind(console);\n private track = console.log.bind(console);\n\n public init(config: AppenderConfig, formatter?: Formatter, filters?: Filter[]): void {\n this._config = config;\n this._formatter = formatter;\n this._filters = filters || [];\n this._available = typeof console !== 'undefined' && !!console.log;\n\n this.enabled = this._config?.enabled !== false; // Default to true if not specified\n this.priority = this._config?.priority;\n }\n\n public dispose(): void {\n // No resources to dispose for console appender\n }\n\n public write(event: LogEvent): void {\n if (!this._available) return;\n\n // Apply filters in sequence - any filter denial skips the event\n for (const filter of this._filters) {\n if (filter.enabled && !filter.filter(event)) {\n return; // Skip if any filter denies logging\n }\n }\n\n // Format the event or produce a minimal, fast default payload\n // When no formatter is provided, avoid passing the whole event object to the console,\n // as object inspection/serialization is comparatively slow and increases variance.\n const data = this._formatter ? this._formatter.format(event) : [event];\n\n // Output using level-appropriate console method\n this[event.level](...data);\n }\n\n public flush(): void {\n // No-op for console appender\n }\n\n public enableFilter(name: string): void {\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = true;\n }\n\n public disableFilter(name: string): void {\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = false;\n }\n\n private _getFilter(name: string): Filter | undefined {\n return this._filters.find((f) => f.name === name);\n }\n}\n\n/**\n * Factory for creating ConsoleAppender instances.\n *\n * Automatically registered with the LogM8 system and creates console appenders\n * when referenced by name in logging configuration.\n */\nclass ConsoleAppenderFactory implements PluginFactory<ConsoleAppenderConfig, ConsoleAppender> {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public create(config: AppenderConfig): ConsoleAppender {\n const appender = new ConsoleAppender();\n appender.init(config);\n return appender;\n }\n}\n\nexport { ConsoleAppender, ConsoleAppenderFactory };\n","import type { WriteStream } from 'fs';\nimport { createWriteStream } from 'fs';\n\nimport type { Appender } from '../Appender.ts';\nimport type { AppenderConfig } from '../AppenderConfig.ts';\nimport type { Filter } from '../Filter.ts';\nimport type { Formatter } from '../Formatter.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogLevel, type LogLevelType } from '../LogLevel.ts';\nimport { LogM8Utils } from '../LogM8Utils.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\nconst NAME = 'file';\nconst VERSION = '1.0.0';\nconst KIND = PluginKind.appender;\n\nconst DEFAULT_FILENAME = 'app.log';\n\nconst SUPPORTED_LEVELS = new Set<LogLevelType>([\n LogLevel.fatal,\n LogLevel.error,\n LogLevel.warn,\n LogLevel.info,\n LogLevel.debug,\n LogLevel.track,\n LogLevel.trace,\n]);\n\n/**\n * Configuration options for the file appender.\n *\n * - filename: Destination file path. The file is opened on init.\n * - append: When true, appends to the existing file; otherwise it is truncated.\n */\nexport interface FileAppenderConfig extends AppenderConfig {\n /** Destination file path to write logs into. */\n filename: string;\n /** Append to existing file (true) or overwrite on startup (false). Default: false */\n append?: boolean;\n}\n\n/**\n * Appender that writes each formatted log event to a file (one line per event).\n *\n * Behavior\n * - Initializes a WriteStream on init() using the provided filename.\n * - Joins formatted tokens with a single space and appends a trailing newline.\n * - If no formatter is configured, writes the raw LogEvent via String() coercion of tokens.\n * - Respects per-appender filters before writing.\n * - flush() is a no-op; data is flushed by the stream implementation. dispose() ends the stream.\n */\nclass FileAppender implements Appender {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public readonly supportedLevels = SUPPORTED_LEVELS;\n public enabled = true;\n public priority?: number;\n\n private _config?: FileAppenderConfig;\n private _formatter?: Formatter;\n private _filters: Filter[] = [];\n private _stream?: WriteStream;\n private _streamCreationFailed = false;\n\n public init(config: AppenderConfig, formatter?: Formatter, filters?: Filter[]): void {\n this._config = config as FileAppenderConfig;\n this._formatter = formatter;\n this._filters = filters || [];\n\n this.enabled = this._config?.enabled !== false; // Default to true if not specified\n this.priority = this._config?.priority;\n\n if (this.enabled) {\n // Create the write stream\n this._createStream();\n }\n }\n\n public dispose(): void {\n this._stream?.end();\n this._stream = undefined;\n }\n\n public write(event: LogEvent): void {\n if (this._streamCreationFailed) return; // If stream creation failed, cannot write\n\n if (!this._stream) {\n try {\n this._createStream();\n } catch (err) {\n if (console && console.error) {\n console.error(`LogM8 [FileAppender]: Failed to create file stream: ${err}`);\n }\n this._streamCreationFailed = true;\n }\n }\n if (!this._stream) return; // If still undefined, initialization failed\n\n // Filter\n for (const filter of this._filters) {\n if (filter.enabled && !filter.filter(event)) {\n return; // Skip if any filter denies logging\n }\n }\n\n // Format\n const data = this._formatter ? this._formatter.format(event) : [event];\n\n // Log\n const message = data\n .map((d) => {\n if (LogM8Utils.isString(d)) return d;\n return String(d);\n })\n .join(' ');\n this._stream.write(message + '\\n');\n }\n\n public flush(): void {\n // No-op for file appender; data is flushed on stream end.\n }\n\n public enableFilter(name: string): void {\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = true;\n }\n\n public disableFilter(name: string): void {\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = false;\n }\n\n private _getFilter(name: string): Filter | undefined {\n return this._filters.find((f) => f.name === name);\n }\n\n private _createStream(): void {\n const flags = this._config?.append ? 'a' : 'w';\n this._stream = createWriteStream(this._config?.filename ?? DEFAULT_FILENAME, { flags });\n }\n}\n\nclass FileAppenderFactory implements PluginFactory<FileAppenderConfig, FileAppender> {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public create(config: AppenderConfig): FileAppender {\n const appender = new FileAppender();\n appender.init(config);\n return appender;\n }\n}\n\nexport { FileAppender, FileAppenderFactory };\n","/**\n * Regex pattern for matching timestamp format tokens.\n *\n * Matches tokens in descending length order to prevent partial replacement\n * (e.g., 'SSS' before 'SS' before 'S'). Used by formatTimestamp to identify\n * and replace format placeholders.\n */\nconst TIMESTAMP_TOKEN_REGEX = /(yyyy|SSS|hh|mm|ss|SS|zz|z|yy|MM|dd|A|a|h|S)/g;\n\nconst REGEX_MATCHER = /^\\/(.+)\\/([dgimsuvy]*)$/;\n\n// Constants for error serialization\nconst EXCLUDED_ERROR_KEYS = new Set(['name', 'message', 'stack', 'cause']);\nconst COMMON_NON_ENUMERABLE_PROPS = ['code', 'errno', 'syscall', 'path'] as const;\n\nexport interface StringifyLogOptions {\n /** Max object/array nesting depth to descend into (default 3). */\n maxDepth?: number;\n /** Truncate long string values to this length (default 200). */\n maxStringLength?: number;\n /** Truncate long arrays to this length (default: 100) */\n maxArrayLength?: number;\n}\n\nexport interface SerializedError {\n name: string;\n message: string;\n stack?: string;\n cause?: SerializedError | null;\n [key: string]: unknown; // For additional properties\n}\n\n/**\n * Utility functions for timestamp formatting and object property access.\n *\n * Provides environment detection, nested property traversal, and flexible\n * timestamp formatting with support for custom tokens, ISO formats, and\n * locale-specific output.\n */\nclass LogM8Utils {\n /**\n * Detects browser environment for feature compatibility.\n *\n * @returns True when both window and document global objects are available\n */\n public static isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof window.document !== 'undefined';\n }\n\n /**\n * Check if an object is a string.\n *\n * @param obj - The object to check.\n * @returns true if the object is a string, otherwise false.\n */\n public static isString(obj: unknown): boolean {\n return typeof obj === 'string' || obj instanceof String;\n }\n\n /**\n * Traverses nested object properties using dot-separated path notation.\n *\n * Supports both object property access and array indexing with numeric keys.\n * Also supports bracket notation for array indices which is normalized internally\n * (e.g., `data[0].items[2]` becomes `data.0.items.2`).\n * Safe navigation that returns undefined for invalid paths rather than throwing.\n *\n * @param obj - Source object to traverse\n * @param path - Dot-separated property path (e.g., 'user.profile.name', 'items.0.id')\n * or a path with bracket indices (e.g., 'items[0].id')\n * @returns Property value at the specified path, or undefined if not found\n *\n * @example\n * ```typescript\n * const data = { user: { profile: { name: 'John' } }, items: [{ id: 1 }, { id: 2 }] };\n * getPropertyByPath(data, 'user.profile.name'); // 'John'\n * getPropertyByPath(data, 'items.0.id'); // 1\n * getPropertyByPath(data, 'items[1].id'); // 2 (bracket notation)\n * getPropertyByPath(data, 'missing.path'); // undefined\n * ```\n */\n public static getPropertyByPath(obj: unknown, path: string): unknown {\n let value = obj;\n // Support bracket index notation by converting to dot-separated tokens, e.g., data[0].items[2] -> data.0.items.2\n const normalized = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const segments = normalized.split('.');\n for (const key of segments) {\n if (typeof value === 'object' && value !== null) {\n if (Array.isArray(value)) {\n // Handle array indexing with numeric keys\n const idx = Number(key);\n if (Number.isInteger(idx) && idx >= 0) {\n value = value[idx];\n continue;\n }\n }\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined;\n }\n }\n return value;\n }\n\n /**\n * Formats Date objects using preset formats or custom token patterns.\n *\n * Supports common presets ('iso', 'locale') and flexible token-based formatting\n * for complete control over timestamp appearance. Tokens are replaced with\n * corresponding date/time components, while non-token text is preserved literally.\n *\n * Supported format tokens:\n * - yyyy: 4-digit year (2025)\n * - yy: 2-digit year (25)\n * - MM: month with leading zero (01-12)\n * - dd: day with leading zero (01-31)\n * - hh: 24-hour format hour with leading zero (00-23)\n * - h: 12-hour format hour (1-12)\n * - mm: minutes with leading zero (00-59)\n * - ss: seconds with leading zero (00-59)\n * - SSS: milliseconds with leading zeros (000-999)\n * - SS: centiseconds with leading zero (00-99)\n * - S: deciseconds (0-9)\n * - A: uppercase AM/PM\n * - a: lowercase am/pm\n * - z: timezone offset with colon (±HH:MM)\n * - zz: timezone offset without colon (±HHMM)\n *\n * @param date - Date instance to format\n * @param fmt - Format preset ('iso'|'locale') or custom token pattern\n * @returns Formatted timestamp string\n *\n * @example\n * ```typescript\n * const date = new Date('2025-08-04T14:23:45.123Z');\n *\n * // Presets\n * formatTimestamp(date, 'iso'); // '2025-08-04T14:23:45.123Z'\n * formatTimestamp(date, 'locale'); // '8/4/2025, 2:23:45 PM' (locale-dependent)\n *\n * // Custom patterns\n * formatTimestamp(date, 'yyyy-MM-dd hh:mm:ss'); // '2025-08-04 14:23:45'\n * formatTimestamp(date, 'MM/dd/yyyy h:mm A'); // '08/04/2025 2:23 PM'\n * formatTimestamp(date, 'hh:mm:ss.SSS'); // '14:23:45.123'\n * formatTimestamp(date, 'yyyy-MM-dd hh:mm:ss z'); // '2025-08-04 14:23:45 +00:00'\n * ```\n */\n public static formatTimestamp(date: Date, fmt?: string): string {\n const fmtLower = fmt?.toLowerCase();\n if (!fmt || fmtLower === 'iso' || fmtLower === 'toisostring') {\n return date.toISOString();\n }\n if (fmtLower === 'locale' || fmtLower === 'tolocalestring') {\n return date.toLocaleString();\n }\n\n // Custom token-based formatting\n const pad = (n: number, z = 2) => String(n).padStart(z, '0');\n const hours24 = date.getHours();\n const hours12 = hours24 % 12 === 0 ? 12 : hours24 % 12;\n\n // Process tokens in descending length order to avoid partial matches\n return fmt.replace(TIMESTAMP_TOKEN_REGEX, (m) => {\n switch (m) {\n case 'yyyy':\n return pad(date.getFullYear(), 4);\n case 'yy':\n return pad(date.getFullYear() % 100);\n case 'MM':\n return pad(date.getMonth() + 1);\n case 'dd':\n return pad(date.getDate());\n case 'hh':\n return pad(hours24);\n case 'h':\n return pad(hours12);\n case 'mm':\n return pad(date.getMinutes());\n case 'ss':\n return pad(date.getSeconds());\n case 'SSS':\n return pad(date.getMilliseconds(), 3);\n case 'SS':\n return pad(Math.floor(date.getMilliseconds() / 10), 2);\n case 'S':\n return pad(Math.floor(date.getMilliseconds() / 100), 1);\n case 'A':\n return hours24 < 12 ? 'AM' : 'PM';\n case 'a':\n return hours24 < 12 ? 'am' : 'pm';\n case 'z':\n case 'zz': {\n // Calculate timezone offset: positive values are ahead of UTC\n const tzOffset = -date.getTimezoneOffset();\n const tzSign = tzOffset >= 0 ? '+' : '-';\n const tzHours = Math.floor(Math.abs(tzOffset) / 60);\n const tzMinutes = Math.abs(tzOffset) % 60;\n if (m === 'z') {\n // Format as ±HH:MM with colon separator\n return `${tzSign}${pad(tzHours)}:${pad(tzMinutes)}`;\n }\n // Format as ±HHMM without separator\n return `${tzSign}${pad(tzHours)}${pad(tzMinutes)}`;\n }\n\n default:\n return m;\n }\n });\n }\n\n /**\n * Converts arbitrary values into JSON strings optimized for logging systems.\n *\n * This utility ensures that any JavaScript value can be safely logged without causing\n * serialization errors or producing excessively large output. It's designed specifically\n * for logging contexts where reliability and readability are more important than\n * perfect fidelity.\n *\n * ## Key Features\n *\n * **Depth Protection**: Prevents stack overflows and excessive output by limiting\n * object traversal depth. Objects/arrays beyond the limit are replaced with\n * \"[Object]\" or \"[Array]\" placeholders.\n *\n * **Array Length Limiting**: Automatically truncates arrays that exceed the maximum\n * length threshold. Truncated arrays include a message indicating how many additional\n * items were omitted.\n *\n * **String Truncation**: Automatically truncates long strings to prevent log flooding.\n * Truncated strings end with an ellipsis (…) character.\n *\n * **Type Safety**: Handles problematic JavaScript types that would normally cause\n * JSON.stringify to throw:\n * - BigInt values are converted to strings\n * - Date objects are normalized to ISO 8601 format\n * - Error instances are serialized to structured objects via {@link LogM8Utils.serializeError}\n *\n * ## Implementation Details\n *\n * - Uses a WeakMap to track traversal depth per object, preventing revisits to the\n * same instance at different depths\n * - Respects existing `toJSON()` methods on objects\n * - Not designed for full cycle detection - cyclic references are handled by the\n * depth limit rather than explicit cycle breaking\n * - The replacer function executes in the context of the parent object, enabling\n * depth tracking through the traversal\n *\n * @param value - Any JavaScript value to stringify for logging (events, contexts, errors, etc.)\n * @param options - Configuration for controlling output size and complexity\n * @param options.maxDepth - Maximum nesting depth for objects/arrays (default: 3).\n * Level 0 = primitive values only,\n * Level 1 = top-level properties,\n * Level 2 = nested properties, etc.\n * @param options.maxArrayLength - Maximum number of array elements to include before truncation (default: 100).\n * Arrays exceeding this limit will be truncated with a message\n * indicating the number of omitted items.\n * @param options.maxStringLength - Maximum character length for strings before truncation (default: 200)\n * @param space - Indentation for pretty-printing. Can be a number (spaces) or string (e.g., '\\t').\n * Pass undefined for compact output (recommended for production logs).\n *\n * @returns A JSON string that is guaranteed to be safe for logging systems\n *\n * @example\n * // Basic usage with default options\n * const json = LogM8Utils.stringifyLog({ message: 'User logged in', userId: 12345 });\n * // => '{\"message\":\"User logged in\",\"userId\":12345}'\n *\n * @example\n * // Handling problematic types\n * const data = {\n * bigNumber: 123456789012345678901234567890n,\n * timestamp: new Date('2024-01-15T10:30:00Z'),\n * error: new Error('Connection failed'),\n * longText: 'x'.repeat(500)\n * };\n * const json = LogM8Utils.stringifyLog(data);\n * // => '{\"bigNumber\":\"123456789012345678901234567890\",\"timestamp\":\"2024-01-15T10:30:00.000Z\",\"error\":{...},\"longText\":\"xxx...xxx…\"}'\n *\n * @example\n * // Array length limiting for large arrays\n * const largeData = {\n * items: new Array(1000).fill({ id: 1, name: 'item' }),\n * values: Array.from({ length: 500 }, (_, i) => i)\n * };\n * const json = LogM8Utils.stringifyLog(largeData, { maxArrayLength: 50 });\n * // => '{\"items\":[{...},{...},...,\"... 950 more items\"],\"values\":[0,1,2,...,\"... 450 more items\"]}'\n *\n * @example\n * // Depth limiting for deeply nested objects\n * const deepObj = {\n * level1: {\n * level2: {\n * level3: {\n * level4: {\n * level5: 'too deep'\n * }\n * }\n * }\n * }\n * };\n * const json = LogM8Utils.stringifyLog(deepObj, { maxDepth: 3 });\n * // => '{\"level1\":{\"level2\":{\"level3\":{\"level4\":\"[Object]\"}}}}'\n *\n * @example\n * // Custom options for verbose debugging\n * const debugJson = LogM8Utils.stringifyLog(\n * complexObject,\n * { maxDepth: 5, maxArrayLength: 500, maxStringLength: 1000 },\n * 2 // Pretty print with 2 spaces\n * );\n *\n * @example\n * // Production logging with minimal output\n * const prodJson = LogM8Utils.stringifyLog(\n * userEvent,\n * { maxDepth: 2, maxArrayLength: 20, maxStringLength: 100 } // Aggressive truncation for high-volume logs\n * );\n *\n * @example\n * // Handling arrays with mixed content\n * const mixedArray = {\n * results: [\n * { id: 1, data: 'first' },\n * { id: 2, data: 'second' },\n * ...Array(200).fill({ id: 999, data: 'bulk' })\n * ]\n * };\n * const json = LogM8Utils.stringifyLog(mixedArray, { maxArrayLength: 10 });\n * // First 10 items preserved, then truncation message\n *\n * @see {@link LogM8Utils.serializeError} - For Error serialization details\n */\n public static stringifyLog(\n value: unknown,\n { maxDepth = 3, maxStringLength = 200, maxArrayLength = 100 }: StringifyLogOptions = {},\n space?: number | string,\n ): string {\n const levels = new WeakMap<object, number>();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n function replacer(this: any, key: string, v: any): any {\n // Depth gate first: if we've reached the cap, stop descending\n if (v && typeof v === 'object') {\n const parentLevel = levels.get(this as object) ?? 0;\n if (parentLevel >= maxDepth) {\n return Array.isArray(v) ? '[Array]' : '[Object]';\n }\n levels.set(v as object, parentLevel + 1);\n\n // Array length limiting\n if (Array.isArray(v) && v.length > maxArrayLength) {\n const truncated = v.slice(0, maxArrayLength);\n truncated.push(`... ${v.length - maxArrayLength} more items`);\n return truncated;\n }\n }\n\n // Practical logging tweaks\n if (LogM8Utils.isString(v) && v.length > maxStringLength) {\n return v.slice(0, maxStringLength) + '…';\n }\n if (typeof v === 'bigint') {\n return v.toString();\n }\n if (v instanceof Date) {\n return v.toISOString();\n }\n if (v instanceof Error) {\n return LogM8Utils.serializeError(v);\n }\n\n return v;\n }\n\n return JSON.stringify(value, replacer, space);\n }\n\n /**\n * Serializes an Error (or Error-like) into a plain, JSON-safe object.\n *\n * Behavior:\n * - Returns null for falsy inputs.\n * - If the object provides a custom toJSON(), that result is used verbatim to\n * honor caller-defined serialization.\n * - Otherwise includes standard fields: name, message, stack.\n * - Recursively serializes the optional error.cause chain using the same rules.\n * - Handles circular references in the cause chain safely.\n * - Copies other own enumerable properties (excluding name, message, stack, cause),\n * skipping properties that throw on access or are not JSON-serializable.\n * - Optionally includes common non-enumerable properties like 'code' if present.\n *\n * Important:\n * - This function does not attempt to preserve all non-enumerable properties.\n * - Circular references in the cause chain are detected and handled gracefully.\n *\n * @param error - Unknown error input (Error instance or compatible object).\n * @returns Structured error data suitable for logging, or null when input is falsy.\n *\n * @example\n * try {\n * throw new Error('Boom');\n * } catch (e) {\n * const payload = LogM8Utils.serializeError(e);\n * // { name: 'Error', message: 'Boom', stack: '...', ... }\n * }\n */\n public static serializeError(error: unknown): SerializedError | null {\n // Internal recursive function with circular reference tracking\n const serializeErrorInternal = (\n error: unknown,\n seen: WeakSet<object>,\n ): SerializedError | null => {\n // Handle non-error values\n if (!error) return null;\n\n // Type guard to check if it's an Error-like object\n const errorObj = error as Error;\n\n // Prevent circular references\n if (typeof errorObj === 'object' && errorObj !== null) {\n if (seen.has(errorObj)) {\n return {\n name: 'CircularReference',\n message: 'Circular reference detected in error cause chain',\n };\n }\n seen.add(errorObj);\n }\n\n // If the error has a toJSON method, use it\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (typeof (errorObj as any).toJSON === 'function') {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = (errorObj as any).toJSON();\n // Ensure the result is JSON-serializable\n JSON.stringify(result);\n return result;\n } catch (_e) {\n // If toJSON fails or returns non-serializable data, continue with standard serialization\n }\n }\n\n // Create base error object\n const serialized: SerializedError = {\n name: errorObj.name || 'Error',\n message: errorObj.message || '',\n stack: errorObj.stack,\n };\n\n // Handle the 'cause' property recursively\n if ('cause' in errorObj && errorObj.cause !== undefined) {\n serialized.cause = serializeErrorInternal(errorObj.cause, seen);\n }\n\n // Set of standard properties to exclude\n\n // Include other enumerable properties\n // This catches custom properties added to the error\n for (const key in errorObj) {\n if (Object.prototype.hasOwnProperty.call(errorObj, key) && !EXCLUDED_ERROR_KEYS.has(key)) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const value = (errorObj as any)[key];\n // Ensure the value is JSON-serializable\n JSON.stringify(value);\n serialized[key] = value;\n } catch (_e) {\n // Skip properties that can't be accessed or aren't JSON-serializable\n }\n }\n }\n\n // Optionally include specific non-enumerable properties that are commonly used\n for (const prop of COMMON_NON_ENUMERABLE_PROPS) {\n try {\n const descriptor = Object.getOwnPropertyDescriptor(errorObj, prop);\n if (descriptor && descriptor.value !== undefined) {\n // Ensure the value is JSON-serializable\n JSON.stringify(descriptor.value);\n serialized[prop] = descriptor.value;\n }\n } catch (_e) {\n // Skip if property access fails or value is not serializable\n }\n }\n\n return serialized;\n };\n\n // Start the serialization with a fresh WeakSet for tracking\n return serializeErrorInternal(error, new WeakSet());\n }\n\n /**\n * Take a regex in the format /regex/flags and parse it into a RegExp object\n *\n * @param regex regex in the format /regex/flags\n * @param extraFlags additional flags to apply to the regex\n * @returns RegExp object or undefined if the regex is invalid\n */\n public static parseRegexFromString(regex: string, extraFlags?: string[]): RegExp | undefined {\n try {\n const match = regex.match(REGEX_MATCHER);\n if (match == null) return undefined;\n const [, pattern, flags] = match;\n\n let finalFlags = flags;\n if (Array.isArray(extraFlags)) {\n for (const flag of extraFlags) {\n if (!flags.includes(flag)) {\n finalFlags += flag;\n }\n }\n }\n\n return new RegExp(pattern, finalFlags);\n } catch (_e) {\n return undefined;\n }\n }\n}\n\nexport { LogM8Utils };\n","import type { Filter } from '../Filter.ts';\nimport type { FilterConfig } from '../FilterConfig.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogM8Utils } from '../LogM8Utils.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\n/**\n * Configuration for MatchFilter.\n *\n * Provides simple allow/deny rule maps where each key is a dot-path into the LogEvent\n * (supports array bracket notation like `data[0].items[2]`) and each value is the value\n * that must match for the rule to apply.\n *\n * Behavior:\n * - allow: If provided and non-empty, an event must satisfy ALL allow rules to pass.\n * - deny: If provided, an event that satisfies ANY deny rule will be blocked.\n * - Precedence: deny rules take precedence over allow; i.e., an event that passes allow\n * but matches a deny rule will be denied.\n *\n * Examples:\n * ```ts\n * // Only allow events from a specific logger AND with a specific data value\n * { name: 'match-filter', allow: { 'logger': 'app.service', 'data[0].type': 'audit' } }\n *\n * // Deny events for a user id regardless of other matches\n * { name: 'match-filter', deny: { 'context.userId': '1234' } }\n *\n * // Combined example\n * {\n * name: 'match-filter',\n * allow: { 'logger': 'allow.this.logger', 'data[0].custom[3].path': 4 },\n * deny: { 'logger': 'block.this.logger', 'context.userId': '1234' }\n * }\n * ```\n */\nexport interface MatchFilterConfig extends FilterConfig {\n /** All rules in this map must match for the event to be allowed (AND). */\n allow?: Record<string, unknown>;\n /** If any rule in this map matches, the event will be denied (OR). */\n deny?: Record<string, unknown>;\n}\n\n/**\n * Built-in filter providing straightforward allow/deny path-based matching.\n *\n * Use this when you want quick, declarative filtering without writing code. Rules are\n * evaluated against the LogEvent using robust dot-path resolution (with support for\n * `array[index]` notation). Comparisons use deep equality for objects/arrays and strict\n * equality for primitives.\n */\nclass MatchFilter implements Filter {\n public name = 'match-filter';\n public version = '1.0.0';\n public kind = PluginKind.filter;\n\n public enabled = true;\n\n private _allow?: Record<string, unknown>;\n private _deny?: Record<string, unknown>;\n /**\n * Initializes allow/deny rule maps. Values are compared using deep equality for\n * arrays/objects and strict equality for primitives. Missing maps are treated as empty.\n * @param config - Filter configuration with optional allow/deny maps\n */\n public init(config: FilterConfig): void {\n const cfg = (config ?? {}) as MatchFilterConfig;\n // Pre-compile any regex-like strings (e.g., '/pattern/flags') in rule maps for efficiency\n this._allow = this._prepareRules(cfg.allow);\n this._deny = this._prepareRules(cfg.deny);\n this.enabled = cfg.enabled !== false; // Default to true if not specified\n }\n\n public dispose(): void {\n // no resources to release\n }\n\n /**\n * Evaluates the given event against configured rules.\n * - allow: if provided and non-empty, ALL rules must match (AND)\n * - deny: if provided, ANY match denies (OR); deny takes precedence over allow\n * Returns false on unexpected errors to fail-safe.\n * @param logEvent - Event to evaluate\n * @returns true when the event should be logged; false to drop\n */\n public filter(logEvent: LogEvent): boolean {\n try {\n // Allow rules: if provided, ALL must match\n if (this._allow && Object.keys(this._allow).length > 0) {\n for (const [path, expected] of Object.entries(this._allow)) {\n const actual = LogM8Utils.getPropertyByPath(logEvent, path);\n if (!this._matches(actual, expected)) return false;\n }\n }\n\n // Deny rules: if ANY matches, deny\n if (this._deny && Object.keys(this._deny).length > 0) {\n for (const [path, expected] of Object.entries(this._deny)) {\n const actual = LogM8Utils.getPropertyByPath(logEvent, path);\n if (this._matches(actual, expected)) return false;\n }\n }\n\n return true;\n } catch (_err) {\n // Be conservative on unexpected errors\n return false;\n }\n }\n\n // Matches actual against expected, supporting RegExp; otherwise deep equality.\n private _matches(actual: unknown, expected: unknown): boolean {\n // Pre-compiled regex\n if (expected instanceof RegExp) {\n if (actual === undefined || actual === null) return false;\n const asString = typeof actual === 'string' ? actual : String(actual);\n return expected.test(asString);\n }\n\n return this._isEqual(actual, expected);\n }\n\n // Simple deep equality for primitives, arrays, plain objects, dates\n private _isEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n\n // Handle NaN\n if (typeof a === 'number' && typeof b === 'number') {\n return Number.isNaN(a) && Number.isNaN(b);\n }\n\n // Dates\n if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();\n\n // Arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!this._isEqual(a[i], b[i])) return false;\n }\n return true;\n }\n\n // Plain objects\n if (this._isPlainObject(a) && this._isPlainObject(b)) {\n const aKeys = Object.keys(a as Record<string, unknown>);\n const bKeys = Object.keys(b as Record<string, unknown>);\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(b as object, key)) return false;\n if (\n !this._isEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])\n )\n return false;\n }\n return true;\n }\n\n return false;\n }\n\n private _isPlainObject(val: unknown): val is Record<string, unknown> {\n return (\n typeof val === 'object' &&\n val !== null &&\n !Array.isArray(val) &&\n Object.getPrototypeOf(val) === Object.prototype\n );\n }\n\n // Convert rule map values: regex-like strings -> RegExp; leave others as-is.\n private _prepareRules(map?: Record<string, unknown>): Record<string, unknown> | undefined {\n if (!map || Object.keys(map).length === 0) return undefined;\n const prepared: Record<string, unknown> = {};\n for (const [path, val] of Object.entries(map)) {\n if (typeof val === 'string') {\n const rx = LogM8Utils.parseRegexFromString(val);\n prepared[path] = rx ?? val;\n } else {\n prepared[path] = val;\n }\n }\n return prepared;\n }\n}\n\nclass MatchFilterFactory implements PluginFactory<MatchFilterConfig, MatchFilter> {\n public name = 'match-filter';\n public version = '1.0.0';\n public kind = PluginKind.filter;\n\n public create(config: MatchFilterConfig): MatchFilter {\n const filter = new MatchFilter();\n filter.init(config);\n return filter;\n }\n}\n\nexport { MatchFilterFactory };\n","import type { Formatter } from '../Formatter.ts';\nimport type { FormatterConfig } from '../FormatterConfig.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogLevel } from '../LogLevel.ts';\nimport { LogM8Utils } from '../LogM8Utils.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\nconst NAME = 'default-formatter';\nconst VERSION = '1.0.0';\nconst KIND = PluginKind.formatter;\n\nconst DEFAULT_FORMAT = ['{timestamp} {LEVEL} [{logger}]', '{message}', '{data}'];\nconst DEFAULT_TIMESTAMP_FORMAT = 'hh:mm:ss.SSS';\n\n/**\n * Configuration for the default text formatter.\n *\n * Extends the base FormatterConfig with options for template customization,\n * timestamp formatting, and optional colorization.\n */\nexport interface DefaultFormatterConfig extends FormatterConfig {\n /**\n * Custom format template(s) using token syntax.\n * Provide a single template string or an array of template strings for multi-line output.\n * Defaults to a readable text format: ['{timestamp} {LEVEL} [{logger}]', '{message}', '{data}'].\n */\n format?: string | string[];\n\n /**\n * Timestamp format pattern or preset.\n * Supports 'iso', 'locale', or custom token patterns (yyyy-MM-dd hh:mm:ss).\n */\n timestampFormat?: string;\n\n /**\n * Enable colorized output for level tokens.\n *\n * - Node.js: Applies ANSI escape codes.\n * - Browser: Returns a tuple ['%cLEVEL', css] suitable for console.log('%c..', ..)\n * when {LEVEL} is resolved; appenders may pass tokens straight to console APIs.\n *\n * Set to true to enable; environment detection is used only to decide ANSI vs CSS.\n */\n color?: boolean;\n}\n\n/**\n * Built-in text formatter with token-based templates and optional colorized levels.\n *\n * Features\n * - Customizable templates using curly-brace tokens mixed with literal text.\n * - Timestamp formatting via presets or custom patterns.\n * - Optional colorization of the {LEVEL} token (ANSI in Node.js, CSS tuple in browsers).\n *\n * Notes\n * - This formatter outputs text (not JSON). It returns an array of strings/values that\n * appenders can pass to console/file outputs.\n * - The {data} token resolves to the `logEvent.data` array. If present as its own\n * line entry, items are expanded in-place; if the array is empty, the token is removed.\n * - {message} is passed through as-is when it’s not a string (e.g., objects or errors).\n * - Any other token (including nested paths like {context.userId}) is resolved using\n * dot-path access on the LogEvent.\n *\n * Supported tokens\n * - {timestamp}: Formatted with `timestampFormat`.\n * - {LEVEL}: Uppercase level label (with optional colorization/padding).\n * - {level}: Lowercase level name.\n * - {logger}: Logger name.\n * - {message}: Primary log message (string or non-string value).\n * - {data}: Additional data arguments array (expanded inline when present alone in a line).\n * - {context.*}: Nested context properties.\n *\n * @example\n * // Text with colors\n * formatter.init({\n * format: '{timestamp} {LEVEL} [{logger}] {message}',\n * timestampFormat: 'hh:mm:ss.SSS',\n * color: true,\n * });\n *\n * // Multi-line text output with expanded data\n * formatter.init({\n * format: [\n * '{timestamp} {LEVEL} [{logger}] {message}',\n * 'Context: {context}',\n * 'Data: {data}',\n * ],\n * });\n */\nclass DefaultFormatter implements Formatter {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n private _config!: DefaultFormatterConfig;\n private _format!: string[][];\n private _timestampFormat: string = DEFAULT_TIMESTAMP_FORMAT;\n private _levelMap!: Record<string, string | [string, string]>;\n private _colorEnabled: boolean = false;\n\n // ANSI color codes for Node.js terminal output\n private _levelColorMap: Record<string, string> = {\n trace: '\\x1b[37m', // White\n track: '\\x1b[38;5;208m', // Orange\n debug: '\\x1b[90m', // Grey\n info: '\\x1b[34m', // Blue\n warn: '\\x1b[33m', // Yellow\n error: '\\x1b[31m', // Red\n fatal: '\\x1b[41m', // Red background\n };\n\n // CSS color styles for browser console output\n private _levelCssColorMap: Record<string, string> = {\n trace: 'color: #bbb;', // Light gray\n track: 'color: orange;',\n debug: 'color: grey;',\n info: 'color: blue;',\n warn: 'color: gold;',\n error: 'color: red;',\n fatal: 'background: red; color: white;',\n };\n\n public init(config: DefaultFormatterConfig): void {\n const isBrowser = LogM8Utils.isBrowser();\n\n this._config = Object.assign({}, config);\n this._colorEnabled = !!this._config.color;\n\n // Parse format templates into token/literal segments\n this._format = [];\n let formatConfig = (this._config.format ?? DEFAULT_FORMAT) as string[];\n if (typeof this._config.format === 'string') formatConfig = [this._config.format];\n\n if (formatConfig) {\n for (const f of formatConfig) {\n // Split format string preserving both tokens ({...}) and literal text\n const regex = /(\\{[^}]+\\})|([^{}]+)/g;\n const parts = [];\n let match;\n while ((match = regex.exec(f)) !== null) {\n if (match[1]) {\n parts.push(match[1]); // token\n } else if (match[2] !== undefined) {\n parts.push(match[2]); // literal (preserve all, including whitespace)\n }\n }\n this._format.push(parts);\n }\n }\n\n this._timestampFormat = this._config.timestampFormat ?? DEFAULT_TIMESTAMP_FORMAT;\n\n // Build level display map with padding and optional colorization\n const levelValues = Object.values(LogLevel);\n const maxLevelLength = Math.max(...levelValues.map((l) => l.length));\n\n this._levelMap = levelValues.reduce(\n (acc, level) => {\n let levelStr = level.toUpperCase().padEnd(maxLevelLength, ' ');\n if (this._colorEnabled) {\n if (isBrowser) {\n // Browser: return [text, cssStyle] array for console.log('%c...', style)\n const css = this._levelCssColorMap[level] || '';\n acc[level] = [`%c${levelStr}`, css];\n return acc;\n } else {\n // Node.js: wrap with ANSI escape codes\n const color = this._levelColorMap[level] || '';\n const reset = '\\x1b[0m';\n levelStr = color + levelStr + reset;\n }\n }\n acc[level] = levelStr;\n return acc;\n },\n {} as Record<string, string | [string, string]>,\n );\n }\n\n public dispose(): void {}\n\n public format(logEvent: LogEvent): unknown[] {\n let output: unknown[] | undefined;\n\n const formatArr = this._format;\n if (formatArr.length > 0) {\n output = formatArr.map((item) => {\n if (item.length === 1) {\n return this.resolveToken(item[0], logEvent);\n }\n return item.reduce((str, part) => {\n const val = this.resolveToken(part, logEvent);\n return str + String(val);\n }, '');\n });\n // Locate data token and expand or remove it based on content\n const dataIndex = output.findIndex((v) => Array.isArray(v));\n if (dataIndex >= 0) {\n const data = output[dataIndex] as unknown[];\n if (data.length > 0) output.splice(dataIndex, 1, ...data);\n else output.splice(dataIndex, 1);\n }\n } else {\n output = [\n LogM8Utils.formatTimestamp(logEvent.timestamp, this._timestampFormat),\n logEvent.level,\n logEvent.logger,\n logEvent.message,\n ...logEvent.data,\n logEvent.context,\n ];\n }\n\n return output;\n }\n\n private resolveToken(part: string, logEvent: LogEvent): unknown {\n // Process tokens using curly brace syntax: {property.path}\n if (part.startsWith('{') && part.endsWith('}')) {\n const key = part.slice(1, -1);\n if (key === 'message' && typeof logEvent.message !== 'string') {\n return logEvent.message;\n } else if (key === 'LEVEL') {\n return this._levelMap[logEvent.level] ?? logEvent.level;\n } else if (key === 'timestamp') {\n const raw = LogM8Utils.getPropertyByPath(logEvent, key);\n return LogM8Utils.formatTimestamp(raw as Date, this._timestampFormat);\n }\n // Resolve data properties and context via dot-path notation\n return LogM8Utils.getPropertyByPath(logEvent, key);\n }\n // Return literal text unchanged\n return part;\n }\n}\n\nclass DefaultFormatterFactory implements PluginFactory<DefaultFormatterConfig, DefaultFormatter> {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public create(config: DefaultFormatterConfig): DefaultFormatter {\n const appender = new DefaultFormatter();\n appender.init(config);\n return appender;\n }\n}\n\nexport { DefaultFormatterFactory };\n","import type { Formatter } from '../Formatter.ts';\nimport type { FormatterConfig } from '../FormatterConfig.ts';\nimport type { LogEvent } from '../LogEvent.ts';\nimport { LogM8Utils } from '../LogM8Utils.ts';\nimport type { PluginFactory } from '../PluginFactory.ts';\nimport { PluginKind } from '../PluginKind.ts';\n\nconst NAME = 'json-formatter';\nconst VERSION = '1.0.0';\nconst KIND = PluginKind.formatter;\n\nconst DEFAULT_FORMAT = ['timestamp', 'level', 'logger', 'message', 'data'];\nconst DEFAULT_TIMESTAMP_FORMAT = 'iso';\nconst DEFAULT_PRETTY = 2;\nconst DEFAULT_MAX_DEPTH = 3;\nconst DEFAULT_MAX_STRING_LEN = 1000;\nconst DEFAULT_MAX_ARRAY_LEN = 100;\n\n/**\n * Configuration for the JSON formatter.\n *\n * Extends the base FormatterConfig with options for selecting which fields to\n * include, pretty printing, timestamp formatting, and output size limits.\n */\nexport interface JsonFormatterConfig extends FormatterConfig {\n /**\n * Fields to include in the output object.\n * Accepts a single field or an array of fields. Defaults to\n * ['timestamp', 'level', 'logger', 'message', 'data'].\n *\n * Each entry is used as the object key and resolved via dot-path on the LogEvent.\n * Special handling:\n * - 'LEVEL' returns the raw level string (e.g., 'info').\n * - 'timestamp' is formatted with `timestampFormat`.\n *\n * If the list is empty, the entire LogEvent object is used.\n */\n format?: string | string[];\n\n /**\n * Pretty-print JSON output.\n * - true: default indentation of 2 spaces.\n * - number: use the provided number of spaces.\n * - false/undefined: minified JSON with no extra whitespace.\n */\n pretty?: boolean | number;\n\n /**\n * Timestamp format pattern or preset.\n * Supports 'iso', 'locale', or custom token patterns (yyyy-MM-dd hh:mm:ss).\n */\n timestampFormat?: string;\n\n /**\n * Maximum depth for nested objects in JSON output.\n * Defaults to 3.\n */\n maxDepth?: number;\n\n /**\n * Maximum length for string values in JSON output.\n * Strings longer than this may be truncated by `stringifyLog`. Defaults to 1000.\n */\n maxStringLen?: number;\n\n /**\n * Maximum length for array values in JSON output.\n * Arrays longer than this may be truncated by `stringifyLog`. Defaults to 100.\n */\n maxArrayLen?: number;\n}\n\n/**\n * JSON formatter that emits a single JSON string per log event.\n *\n * Features\n * - Select fields via `format` (e.g., ['timestamp','level','logger','message','data']).\n * - Formats timestamps using `timestampFormat` ('iso', 'locale', or custom pattern).\n * - Pretty printing with fixed (2 spaces) or custom indentation.\n * - Output size controls via `maxDepth`, `maxStringLen`, and `maxArrayLen` (passed to `LogM8Utils.stringifyLog`).\n *\n * Behavior\n * - Returns an array with a single element: the JSON string representation of the selected fields.\n * - Field resolution uses dot-path access on the LogEvent (e.g., 'context.userId').\n * - Special tokens:\n * - 'timestamp': formatted per `timestampFormat`.\n * - 'LEVEL': raw level string (lowercase; no color or padding).\n * - If `format` is empty, the entire LogEvent object is serialized.\n *\n * Examples\n *\n * // Default fields, minified JSON\n * formatter.init({});\n * // => [\"{\\\"timestamp\\\":\\\"...\\\",\\\"level\\\":\\\"info\\\",\\\"logger\\\":\\\"app\\\",\\\"message\\\":\\\"...\\\",\\\"data\\\":[]}\"]\n *\n * // Pretty printed output (2 spaces)\n * formatter.init({ pretty: true });\n *\n * // Custom fields with a nested context property\n * formatter.init({\n * format: ['timestamp', 'LEVEL', 'logger', 'context.userId', 'message'],\n * timestampFormat: 'hh:mm:ss.SSS',\n * pretty: 2,\n * });\n */\nclass JsonFormatter implements Formatter {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n private _config!: JsonFormatterConfig;\n private _format!: string[];\n private _pretty: number | undefined;\n private _maxDepth: number = DEFAULT_MAX_DEPTH;\n private _maxStringLen: number = DEFAULT_MAX_STRING_LEN;\n private _maxArrayLen: number = DEFAULT_MAX_ARRAY_LEN;\n private _timestampFormat: string = DEFAULT_TIMESTAMP_FORMAT;\n\n public init(config: JsonFormatterConfig): void {\n this._config = Object.assign({}, config);\n\n this._pretty =\n this._config.pretty === true\n ? DEFAULT_PRETTY\n : this._config.pretty\n ? this._config.pretty\n : undefined;\n this._maxDepth = this._config.maxDepth ?? DEFAULT_MAX_DEPTH;\n this._maxStringLen = this._config.maxStringLen ?? DEFAULT_MAX_STRING_LEN;\n this._maxArrayLen = this._config.maxArrayLen ?? DEFAULT_MAX_ARRAY_LEN;\n\n let formatConfig = (this._config.format ?? DEFAULT_FORMAT) as string[];\n if (typeof this._config.format === 'string') formatConfig = [this._config.format];\n this._format = formatConfig;\n\n this._timestampFormat = this._config.timestampFormat ?? DEFAULT_TIMESTAMP_FORMAT;\n }\n\n public dispose(): void {}\n\n public format(logEvent: LogEvent): unknown[] {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let outputObj: any = {};\n\n const formatArr = this._format;\n if (formatArr.length > 0) {\n formatArr.forEach((item) => {\n const t = this.resolveToken(item, logEvent);\n if (t != undefined) {\n outputObj[t.key] = t.value;\n }\n });\n } else {\n // When no fields are specified, fall back to including the entire LogEvent object.\n outputObj = logEvent;\n }\n\n return [\n LogM8Utils.stringifyLog(\n outputObj,\n {\n maxDepth: this._maxDepth,\n maxStringLength: this._maxStringLen,\n maxArrayLength: this._maxArrayLen,\n },\n this._pretty,\n ),\n ];\n }\n\n private resolveToken(\n part: string,\n logEvent: LogEvent,\n ): { key: string; value: unknown } | undefined {\n // Process tokens for JSON object construction\n const key = part;\n if (key === 'LEVEL') {\n return { key, value: logEvent.level };\n } else if (key === 'timestamp') {\n const raw = LogM8Utils.getPropertyByPath(logEvent, key);\n return { key, value: LogM8Utils.formatTimestamp(raw as Date, this._timestampFormat) };\n }\n // Resolve properties via dot-path notation\n return { key, value: LogM8Utils.getPropertyByPath(logEvent, key) };\n }\n}\n\nclass JsonFormatterFactory implements PluginFactory<JsonFormatterConfig, JsonFormatter> {\n public name = NAME;\n public version = VERSION;\n public kind = KIND;\n\n public create(config: JsonFormatterConfig): JsonFormatter {\n const appender = new JsonFormatter();\n appender.init(config);\n return appender;\n }\n}\n\nexport { JsonFormatterFactory };\n","import type { Plugin } from './Plugin.ts';\nimport type { PluginConfig } from './PluginConfig.ts';\nimport type { PluginFactory } from './PluginFactory.ts';\nimport type { PluginKindType } from './PluginKind.ts';\n\n/**\n * Manages registration and lifecycle of plugin factories and created plugin instances.\n * Allows registering factories, creating plugins by kind, and disposing resources.\n */\nclass PluginManager {\n private _pluginFactories: Map<string, PluginFactory> = new Map();\n private _plugins: Plugin[] = [];\n\n /**\n * Registers a plugin factory.\n * @param pluginFactory - Factory to register for creating plugins.\n * @throws Error if a factory with the same name is already registered.\n */\n registerPluginFactory(pluginFactory: PluginFactory): void {\n if (this._pluginFactories.has(pluginFactory.name)) {\n throw new Error(`LogM8: Plugin with name ${pluginFactory.name} is already registered.`);\n }\n this._pluginFactories.set(pluginFactory.name, pluginFactory);\n }\n\n /**\n * Creates and registers a plugin instance using the matching factory.\n * @param kind - The kind of plugin to create (appender, filter, formatter).\n * @param nameOrConfig - Plugin name string or configuration object with plugin name.\n * @returns The created plugin instance.\n * @throws Error if no matching factory is found.\n */\n createPlugin(kind: PluginKindType, nameOrConfig: string | PluginConfig): Plugin {\n const name = typeof nameOrConfig === 'string' ? nameOrConfig : nameOrConfig.name;\n const config = typeof nameOrConfig === 'string' ? { name } : nameOrConfig;\n const pluginFactory = this.getPluginFactory(name, kind);\n if (!pluginFactory) {\n throw new Error(`LogM8: Plugin factory kind '${kind}' with name '${name}' not found.`);\n }\n const plugin = pluginFactory.create(config);\n this._plugins.push(plugin);\n return plugin;\n }\n\n /**\n * Retrieves a registered plugin factory by name and kind.\n * @param name - The factory name.\n * @param kind - The expected plugin kind.\n * @returns The factory if found and matching kind, otherwise undefined.\n */\n getPluginFactory(name: string, kind: PluginKindType): PluginFactory | undefined {\n const pluginFactory = this._pluginFactories.get(name);\n if (!pluginFactory || kind !== pluginFactory.kind) return;\n return pluginFactory;\n }\n\n /**\n * Disposes all created plugin instances by invoking their dispose methods.\n * Clears the internal plugin list.\n */\n disposePlugins(): void {\n this._plugins.forEach((plugin) => {\n plugin.dispose();\n });\n this._plugins = [];\n }\n\n /**\n * Clears all registered plugin factories without disposing instances.\n */\n clearFactories(): void {\n this._pluginFactories.clear();\n }\n}\n\nexport { PluginManager };\n","/**\n * LogM8 - Central logging manager for TypeScript/JavaScript\n *\n */\n\nimport type { Appender } from './Appender.ts';\nimport type { AppenderConfig } from './AppenderConfig.ts';\nimport { ConsoleAppenderFactory } from './appenders/ConsoleAppender.ts';\n/* NODEJS:START */\nimport { FileAppenderFactory } from './appenders/FileAppender.ts';\n/* NODEJS:END */\nimport type { Filter } from './Filter.ts';\nimport { MatchFilterFactory } from './filters/MatchFilter.ts';\nimport type { Formatter } from './Formatter.ts';\nimport { DefaultFormatterFactory } from './formatters/DefaultFormatter.ts';\nimport { JsonFormatterFactory } from './formatters/JsonFormatter.ts';\nimport type { Log } from './Log.ts';\nimport type { LogContext } from './LogContext.ts';\nimport type { LogEvent } from './LogEvent.ts';\nimport type { LoggingConfig } from './LoggingConfig.ts';\nimport type { LogImpl } from './LogImpl.ts';\nimport { LogLevel, type LogLevelType } from './LogLevel.ts';\nimport { LogM8Utils } from './LogM8Utils.ts';\nimport type { PluginFactory } from './PluginFactory.ts';\nimport { PluginKind } from './PluginKind.ts';\nimport { PluginManager } from './PluginManager.ts';\n\nconst MAX_LOG_BUFFER_SIZE = 100; // Maximum size of the log buffer before dropping events\nconst DEFAULT_FORMATTER = 'default-formatter';\nconst DEFAULT_APPENDERS = [\n {\n name: 'console',\n formatter: DEFAULT_FORMATTER,\n },\n];\n\n/**\n * Central logging manager providing hierarchical loggers and configurable output.\n *\n * LogM8 manages the complete logging lifecycle including:\n * - Logger creation and configuration with hierarchical naming\n * - Plugin-based appender, formatter, and filter system\n * - Pre-initialization event buffering (up to 100 events)\n * - Runtime appender and filter control (enable/disable/flush)\n * - Built-in console and file appenders with customizable formatting\n *\n * The manager operates as a singleton export but can also be instantiated directly.\n * Events logged before init() are buffered and flushed on first post-init log.\n *\n * @example\n * ```typescript\n * import { Logging } from 'log-m8';\n *\n * // Configure logging system\n * Logging.init({\n * level: 'info',\n * loggers: { 'app.database': 'debug' },\n * appenders: [\n * { name: 'console', formatter: 'default-formatter' },\n * { name: 'file', filename: 'app.log' }\n * ]\n * });\n *\n * // Use hierarchical loggers\n * const logger = Logging.getLogger('app.service');\n * logger.info('Service started');\n *\n * // Runtime control\n * Logging.disableAppender('console');\n * Logging.disableFilter('sensitive-data');\n * Logging.flushAppenders();\n * ```\n */\nclass LogM8 {\n private _initialized: boolean;\n private _pluginManager: PluginManager;\n private _loggers: Map<string, Log>;\n private _appenders: Appender[];\n private _filters: Filter[] = [];\n\n private _globalLogLevel: LogLevelType;\n private _globalLogLevelNumber: number;\n private _logLevelValues: LogLevelType[];\n private _logLevelSet: Set<LogLevelType>;\n\n // Buffer for log events before the system is initialized\n private _logBuffer: LogEvent[];\n\n constructor() {\n this._initialized = false;\n this._pluginManager = new PluginManager();\n this._loggers = new Map();\n this._appenders = [];\n this._filters = [];\n\n this._logLevelValues = Object.values(LogLevel);\n this._logLevelSet = new Set<LogLevelType>(this._logLevelValues);\n this._globalLogLevel = LogLevel.info;\n this._globalLogLevelNumber = this._logLevelValues.indexOf(LogLevel.info);\n\n this._logBuffer = [];\n\n // Register built-in plugin factories for console/file appenders and default formatter\n this._pluginManager.registerPluginFactory(new ConsoleAppenderFactory());\n /* NODEJS:START */\n this._pluginManager.registerPluginFactory(new FileAppenderFactory());\n /* NODEJS:END */\n this._pluginManager.registerPluginFactory(new DefaultFormatterFactory());\n this._pluginManager.registerPluginFactory(new JsonFormatterFactory());\n this._pluginManager.registerPluginFactory(new MatchFilterFactory());\n }\n\n /**\n * Initializes the logging system with configuration and flushes any buffered events.\n *\n * Sets up default and per-logger levels, creates configured appenders with their\n * formatters and filters, and processes any events buffered before initialization.\n * Appenders are sorted by priority (descending) for deterministic execution order.\n *\n * @param config - Logging configuration object\n * @param config.level - Default log level for all loggers ('info' if not specified)\n * @param config.loggers - Per-logger level overrides by name\n * @param config.appenders - Appender configurations (defaults to console if not specified)\n *\n * @throws {Error} When referenced plugin factories are not registered\n *\n * @example\n * ```typescript\n * Logging.init({\n * level: 'warn',\n * loggers: { 'app.database': 'debug' },\n * appenders: [{\n * name: 'console',\n * formatter: 'default-formatter',\n * filters: ['sensitive-data']\n * }]\n * });\n * ```\n */\n public init(config?: LoggingConfig): void {\n config = Object.assign({}, config);\n\n this._reset();\n\n // Set the global logging level\n this.setLevel(config.level ?? LogLevel.info);\n\n // Set up loggers\n for (const [name, l] of Object.entries(config.loggers ?? {})) {\n const levelStr = (l ?? '').trim().toLowerCase();\n const logger = this.getLogger(name);\n const level = this._logLevelSet.has(levelStr as LogLevelType)\n ? (levelStr as LogLevelType)\n : this._globalLogLevel;\n logger.setLevel(level);\n }\n\n // Set up appenders\n const appenderConfigs = config.appenders ?? DEFAULT_APPENDERS;\n for (const appenderConfigOrName of appenderConfigs) {\n const appender = this._pluginManager.createPlugin(\n PluginKind.appender,\n appenderConfigOrName,\n ) as Appender;\n\n const appenderConfig: AppenderConfig = LogM8Utils.isString(appenderConfigOrName)\n ? {\n name: appender.name,\n }\n : (appenderConfigOrName as AppenderConfig);\n\n const formatter = appenderConfig?.formatter\n ? (this._pluginManager.createPlugin(\n PluginKind.formatter,\n appenderConfig.formatter,\n ) as Formatter)\n : undefined;\n\n const filters: Filter[] = [];\n const ac = appenderConfig as AppenderConfig;\n for (const filterConfig of ac.filters ?? []) {\n const filter = this._pluginManager.createPlugin(PluginKind.filter, filterConfig);\n if (filter) {\n filters.push(filter as Filter);\n } else {\n if (console && console.log) {\n console.log(\n `LogM8: Filter '${filterConfig}' not found for appender ${appenderConfig.name}.`,\n );\n }\n }\n }\n\n appender.init(appenderConfig, formatter, filters);\n this._appenders.push(appender);\n }\n\n // Sort the appenders by their priority\n this._sortAppenders();\n\n // Set up global filters\n for (const filterConfig of config.filters ?? []) {\n const filter = this._pluginManager.createPlugin(PluginKind.filter, filterConfig);\n if (filter) {\n this._filters.push(filter as Filter);\n } else {\n if (console && console.log) {\n console.log(`LogM8: Filter '${filterConfig}' not found (global).`);\n }\n }\n }\n\n this._initialized = true;\n }\n\n /**\n * Shuts down the logging system and releases all resources.\n *\n * Flushes all appenders, disposes plugin instances, clears logger registry,\n * discards buffered events, and deregisters plugin factories. The system\n * can be reinitialized after disposal.\n *\n * @example\n * ```typescript\n * // Graceful shutdown\n * await new Promise(resolve => {\n * Logging.flushAppenders();\n * setTimeout(() => {\n * Logging.dispose();\n * resolve();\n * }, 100);\n * });\n * ```\n */\n public dispose(): void {\n // Reset to initial state (flushes appenders, disposes all plugins)\n this._reset();\n\n // Clear the log buffer\n this._logBuffer = [];\n\n // Deregister all plugin factories\n this._pluginManager.clearFactories();\n\n this._initialized = false;\n }\n\n /**\n * Checks if the logging system has been initialized.\n *\n * @returns True if the system is initialized, false otherwise.\n */\n public isInitialized(): boolean {\n return this._initialized;\n }\n\n /**\n * Retrieves or creates a logger instance with hierarchical naming.\n *\n * Logger instances are cached and reused for the same name. Names can be\n * provided as strings with dot-separation or as array segments that get\n * joined. Each logger maintains independent level and context settings.\n *\n * @param name - Logger name as string ('app.service') or segments (['app', 'service'])\n * @returns Logger instance for the specified name\n *\n * @example\n * ```typescript\n * const logger1 = Logging.getLogger('app.database');\n * const logger2 = Logging.getLogger(['app', 'database']);\n * // logger1 === logger2 (same instance)\n *\n * logger1.setLevel('debug');\n * logger1.setContext({ service: 'postgres' });\n * ```\n */\n public getLogger(name: string | string[]): Log {\n let nameStr: string = name as string;\n if (Array.isArray(name)) {\n nameStr = name.join('.');\n }\n\n const existingLogger = this._loggers.get(nameStr);\n if (existingLogger) return existingLogger;\n\n const logger: LogImpl = {\n name: nameStr,\n level: this._globalLogLevel,\n context: {},\n } as LogImpl;\n\n logger.fatal = this._log.bind(this, logger, LogLevel.fatal);\n logger.error = this._log.bind(this, logger, LogLevel.error);\n logger.warn = this._log.bind(this, logger, LogLevel.warn);\n logger.info = this._log.bind(this, logger, LogLevel.info);\n logger.debug = this._log.bind(this, logger, LogLevel.debug);\n logger.trace = this._log.bind(this, logger, LogLevel.trace);\n logger.track = this._log.bind(this, logger, LogLevel.track);\n\n logger.setLevel = this._setLevel.bind(this, logger);\n logger.setContext = this._setContext.bind(this, logger);\n logger.getLogger = (name) => this.getLogger([logger.name, name]);\n\n // Set initial level and context\n this._setLevel(logger, this._globalLogLevel);\n\n this._loggers.set(logger.name, logger);\n\n return logger;\n }\n\n /**\n * Sets the global logging level or a specific logger's level.\n *\n * @param level - New logging level name (e.g., 'info', 'debug', 'off')\n * @param logger - Optional logger name to set level for a specific logger\n */\n public setLevel(level: string | LogLevelType, logger?: string): void {\n const levelStr = (level ?? '').trim().toLowerCase() as LogLevelType;\n\n if (logger) {\n this.getLogger(logger).setLevel(levelStr);\n } else {\n // Set global log level\n this._globalLogLevel = this._logLevelSet.has(levelStr) ? levelStr : this._globalLogLevel;\n this._globalLogLevelNumber = this._logLevelValues.indexOf(this._globalLogLevel);\n }\n }\n\n /**\n * Enables an appender to resume processing log events.\n *\n * @param name - Name of the appender to enable\n */\n public enableAppender(name: string): void {\n const appender = this._getAppender(name);\n if (!appender) return;\n appender.enabled = true;\n }\n\n /**\n * Disables an appender to stop processing log events.\n *\n * @param name - Name of the appender to disable\n */\n public disableAppender(name: string): void {\n const appender = this._getAppender(name);\n if (!appender) return;\n appender.enabled = false;\n }\n\n /**\n * Forces an appender to flush any buffered output.\n *\n * Catches and logs flush errors to console without interrupting operation.\n * Useful for ensuring data persistence before shutdown or at intervals.\n *\n * @param name - Name of the appender to flush\n */\n public flushAppender(name: string): void {\n const appender = this._getAppender(name);\n if (!appender) return;\n try {\n appender.flush();\n } catch (err) {\n if (console && console.error) {\n console.error(`LogM8: Failed to flush appender: ${appender.name}:`, err);\n }\n }\n }\n\n /**\n * Flushes all configured appenders.\n *\n * Iterates through all appenders calling flush on each, with individual\n * error handling per appender.\n */\n public flushAppenders(): void {\n for (const appender of this._appenders) {\n this.flushAppender(appender.name);\n }\n }\n\n /**\n * Enables a filter to resume processing log events.\n *\n * When an appender name is provided, enables the filter only for that specific\n * appender. When no appender is specified, enables the filter globally.\n * Silently ignores requests for non-existent filters or appenders.\n *\n * @param name - Name of the filter to enable\n * @param appenderName - Optional appender name to enable filter for specific appender only\n *\n * @example\n * ```typescript\n * // Enable filter globally\n * Logging.enableFilter('sensitive-data');\n *\n * // Enable filter only for console appender\n * Logging.enableFilter('debug-filter', 'console');\n * ```\n */\n public enableFilter(name: string, appenderName?: string): void {\n if (appenderName) {\n this._getAppender(appenderName)?.enableFilter(name);\n return;\n }\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = true;\n }\n\n /**\n * Disables a filter to stop processing log events.\n *\n * When an appender name is provided, disables the filter only for that specific\n * appender. When no appender is specified, disables the filter globally.\n * Silently ignores requests for non-existent filters or appenders.\n *\n * @param name - Name of the filter to disable\n * @param appenderName - Optional appender name to disable filter for specific appender only\n *\n * @example\n * ```typescript\n * // Disable filter globally\n * Logging.disableFilter('sensitive-data');\n *\n * // Disable filter only for file appender\n * Logging.disableFilter('debug-filter', 'file');\n * ```\n */\n public disableFilter(name: string, appenderName?: string): void {\n if (appenderName) {\n this._getAppender(appenderName)?.disableFilter(name);\n return;\n }\n const filter = this._getFilter(name);\n if (!filter) return;\n filter.enabled = false;\n }\n\n /**\n * Registers a custom plugin factory for appenders, formatters, or filters.\n *\n * Allows extending the logging system with custom implementations.\n * Must be called before init() to be available during configuration.\n *\n * @param pluginFactory - Factory instance implementing the PluginFactory interface\n *\n * @example\n * ```typescript\n * class SlackAppenderFactory implements PluginFactory {\n * name = 'slack';\n * kind = PluginKind.appender;\n * create(config) { return new SlackAppender(config); }\n * }\n *\n * Logging.registerPluginFactory(new SlackAppenderFactory());\n * ```\n */\n public registerPluginFactory(pluginFactory: PluginFactory): void {\n this._pluginManager.registerPluginFactory(pluginFactory);\n }\n\n private _log(\n logger: LogImpl,\n level: LogLevelType,\n message: string | unknown,\n ...data: unknown[]\n ): void {\n // Early return if level not enabled - O(1) performance for disabled logs\n const levelNumber = this._logLevelValues.indexOf(level);\n if (levelNumber > logger._levelNumber || levelNumber > this._globalLogLevelNumber) return;\n\n // Create a log event for the log\n const logEvent: LogEvent = {\n logger: logger.name,\n level,\n message,\n data,\n context: logger.context,\n timestamp: new Date(),\n };\n\n if (this._initialized) {\n // Process buffered log events first (FIFO order)\n if (this._logBuffer.length > 0) {\n for (const bufferedEvent of this._logBuffer) {\n this._processLogEvent(bufferedEvent);\n }\n this._logBuffer = []; // Clear the buffer after processing\n }\n\n // Process the log event immediately\n this._processLogEvent(logEvent);\n } else {\n // Buffer the log events until initialization is complete\n if (this._logBuffer.length >= MAX_LOG_BUFFER_SIZE) {\n this._logBuffer.shift(); // Drop the oldest event if buffer is full\n }\n this._logBuffer.push(logEvent);\n }\n }\n\n private _setLevel(logger: LogImpl, level: string | LogLevelType): void {\n const levelStr = (level ?? '').trim().toLowerCase() as LogLevelType;\n\n logger.level = this._logLevelSet.has(levelStr) ? levelStr : logger.level;\n logger._levelNumber = this._logLevelValues.indexOf(logger.level);\n\n logger.isEnabled = logger.level !== LogLevel.off;\n // Boolean flags indicate enablement for that severity level and above\n const levelNumber = logger._levelNumber;\n logger.isFatal = this._logLevelValues.indexOf(LogLevel.fatal) <= levelNumber;\n logger.isError = this._logLevelValues.indexOf(LogLevel.error) <= levelNumber;\n logger.isWarn = this._logLevelValues.indexOf(LogLevel.warn) <= levelNumber;\n logger.isInfo = this._logLevelValues.indexOf(LogLevel.info) <= levelNumber;\n logger.isDebug = this._logLevelValues.indexOf(LogLevel.debug) <= levelNumber;\n logger.isTrack = this._logLevelValues.indexOf(LogLevel.track) <= levelNumber;\n logger.isTrace = this._logLevelValues.indexOf(LogLevel.trace) <= levelNumber;\n }\n\n private _setContext(logger: LogImpl, context: LogContext): void {\n logger.context = context ?? {};\n }\n\n private _processLogEvent(event: LogEvent): void {\n // Filter\n for (const filter of this._filters) {\n if (filter.enabled && !filter.filter(event)) {\n return; // Skip if any filter denies logging\n }\n }\n\n // Process each appender (they should be in their priority order)\n for (const appender of this._appenders) {\n try {\n if (!appender.enabled) continue;\n if (!appender.supportedLevels.has(event.level)) continue;\n appender.write(event);\n } catch (err) {\n if (console && console.log) {\n console.log(`LogM8: Failed to append log with '${appender.name}':`, err);\n }\n }\n }\n }\n\n private _getAppender(name: string): Appender | undefined {\n return this._appenders.find((a) => a.name === name);\n }\n\n private _sortAppenders(): void {\n // Sort by descending priority - higher numbers execute first\n this._appenders.sort((a, b) => {\n const aPriority = a?.priority ?? 0;\n const bPriority = b?.priority ?? 0;\n return bPriority - aPriority; // Higher priority first\n });\n }\n\n private _getFilter(name: string): Filter | undefined {\n return this._filters.find((f) => f.name === name);\n }\n\n private _reset(): void {\n // FLush all appenders before disposing\n this.flushAppenders();\n\n this._appenders = [];\n this._loggers.clear();\n this._globalLogLevel = LogLevel.info;\n\n // Dispose all plugins\n this._pluginManager.disposePlugins();\n }\n}\n\nexport { LogM8 };\n","import { type Log } from './Log.ts';\nimport type { LogContext } from './LogContext.ts';\nimport type { LogLevelType } from './LogLevel.ts';\n\nclass NullLogger implements Log {\n fatal(_message: string, ..._args: unknown[]): void {\n // No operation\n }\n\n error(_message: string, ..._args: unknown[]): void {\n // No operation\n }\n\n warn(_message: string, ..._args: unknown[]): void {\n // No operation\n }\n\n info(_message: string, ..._args: unknown[]): void {\n // No operation\n }\n\n debug(_message: string, ..._args: unknown[]): void {\n // No operation\n }\n\n track(_message: string, ..._args: unknown[]): void {\n // No operation\n }\n\n trace(_message: string, ..._args: unknown[]): void {\n // No operation\n }\n\n readonly isFatal = false;\n readonly isError = false;\n readonly isWarn = false;\n readonly isInfo = false;\n readonly isDebug = false;\n readonly isTrack = false;\n readonly isTrace = false;\n\n readonly isEnabled = false;\n readonly name = 'nullLogger';\n readonly level = 'off';\n readonly context: LogContext = {};\n\n setLevel(_level: LogLevelType): void {\n // No operation\n }\n\n setContext(context: LogContext): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this.context as any) = context;\n }\n\n getLogger(_name: string): Log {\n return this as unknown as Log; // Return self for any sub-logger\n }\n}\n\nexport { NullLogger };\n"],"mappings":"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","names":["LogM8","error","NAME","VERSION","KIND","SUPPORTED_LEVELS","NAME","VERSION","KIND","NAME","VERSION","KIND","DEFAULT_FORMAT","DEFAULT_TIMESTAMP_FORMAT","name","LogM8"]}
package/dist/index.d.cts CHANGED
@@ -239,7 +239,7 @@ interface Log {
239
239
  *
240
240
  * @param level - New logging level name (e.g., 'info', 'debug', 'off')
241
241
  */
242
- setLevel(level: LogLevelType): void;
242
+ setLevel(level: string | LogLevelType): void;
243
243
  /**
244
244
  * Replaces the logger's contextual data.
245
245
  *
@@ -484,6 +484,11 @@ interface PluginFactory<C extends PluginConfig = PluginConfig, P extends Plugin
484
484
  create(config: C): P;
485
485
  }
486
486
 
487
+ /**
488
+ * LogM8 - Central logging manager for TypeScript/JavaScript
489
+ *
490
+ */
491
+
487
492
  /**
488
493
  * Central logging manager providing hierarchical loggers and configurable output.
489
494
  *
@@ -614,7 +619,7 @@ declare class LogM8$1 {
614
619
  * @param level - New logging level name (e.g., 'info', 'debug', 'off')
615
620
  * @param logger - Optional logger name to set level for a specific logger
616
621
  */
617
- setLevel(level: LogLevelType, logger?: string): void;
622
+ setLevel(level: string | LogLevelType, logger?: string): void;
618
623
  /**
619
624
  * Enables an appender to resume processing log events.
620
625
  *
@@ -1275,6 +1280,30 @@ declare class LogM8Utils {
1275
1280
  static parseRegexFromString(regex: string, extraFlags?: string[]): RegExp | undefined;
1276
1281
  }
1277
1282
 
1283
+ declare class NullLogger implements Log {
1284
+ fatal(_message: string, ..._args: unknown[]): void;
1285
+ error(_message: string, ..._args: unknown[]): void;
1286
+ warn(_message: string, ..._args: unknown[]): void;
1287
+ info(_message: string, ..._args: unknown[]): void;
1288
+ debug(_message: string, ..._args: unknown[]): void;
1289
+ track(_message: string, ..._args: unknown[]): void;
1290
+ trace(_message: string, ..._args: unknown[]): void;
1291
+ readonly isFatal = false;
1292
+ readonly isError = false;
1293
+ readonly isWarn = false;
1294
+ readonly isInfo = false;
1295
+ readonly isDebug = false;
1296
+ readonly isTrack = false;
1297
+ readonly isTrace = false;
1298
+ readonly isEnabled = false;
1299
+ readonly name = "nullLogger";
1300
+ readonly level = "off";
1301
+ readonly context: LogContext;
1302
+ setLevel(_level: LogLevelType): void;
1303
+ setContext(context: LogContext): void;
1304
+ getLogger(_name: string): Log;
1305
+ }
1306
+
1278
1307
  /**
1279
1308
  * Default singleton instance of the LogM8 logging manager.
1280
1309
  *
@@ -1295,4 +1324,4 @@ declare class LogM8Utils {
1295
1324
  */
1296
1325
  declare const LogM8: LogM8$1;
1297
1326
 
1298
- export { type Appender, type AppenderConfig, type ConsoleAppenderConfig, type DefaultFormatterConfig, type FileAppenderConfig, type Filter, type FilterConfig, type Formatter, type FormatterConfig, type Log, type LogContext, LogLevel, type LogLevelType, LogM8, LogM8Utils, type LoggingConfig, type MatchFilterConfig, type Plugin, type PluginConfig, type PluginFactory, PluginKind, type PluginKindType };
1327
+ export { type Appender, type AppenderConfig, type ConsoleAppenderConfig, type DefaultFormatterConfig, type FileAppenderConfig, type Filter, type FilterConfig, type Formatter, type FormatterConfig, type Log, type LogContext, LogLevel, type LogLevelType, LogM8, LogM8Utils, type LoggingConfig, type MatchFilterConfig, NullLogger, type Plugin, type PluginConfig, type PluginFactory, PluginKind, type PluginKindType };