@abdokouta/react-logger 1.0.0 â 1.0.1
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.
- package/LICENSE +21 -0
- package/README.md +38 -41
- package/config/logger.config.ts +19 -20
- package/dist/index.d.cts +35 -21
- package/dist/index.d.ts +35 -21
- package/dist/index.js +32 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +53 -30
package/dist/index.js
CHANGED
|
@@ -122,7 +122,7 @@ var LOGGER_CONFIG = /* @__PURE__ */ Symbol("LOGGER_CONFIG");
|
|
|
122
122
|
var LoggerService = class {
|
|
123
123
|
/**
|
|
124
124
|
* Create a new logger service
|
|
125
|
-
*
|
|
125
|
+
*
|
|
126
126
|
* @param config - Logger configuration
|
|
127
127
|
*/
|
|
128
128
|
constructor(config) {
|
|
@@ -136,20 +136,20 @@ var LoggerService = class {
|
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
138
|
* Get a logger channel instance
|
|
139
|
-
*
|
|
139
|
+
*
|
|
140
140
|
* Returns the specified channel, or the default channel if no name is provided.
|
|
141
141
|
* Channels are lazily initialized and cached.
|
|
142
|
-
*
|
|
142
|
+
*
|
|
143
143
|
* @param name - Channel name (uses default if not specified)
|
|
144
144
|
* @returns Logger instance
|
|
145
145
|
* @throws Error if channel is not configured
|
|
146
|
-
*
|
|
146
|
+
*
|
|
147
147
|
* @example
|
|
148
148
|
* ```typescript
|
|
149
149
|
* // Use default channel
|
|
150
150
|
* const logger = loggerService.channel();
|
|
151
151
|
* logger.info('Default message');
|
|
152
|
-
*
|
|
152
|
+
*
|
|
153
153
|
* // Use specific channel
|
|
154
154
|
* const errorLogger = loggerService.channel('errors');
|
|
155
155
|
* errorLogger.error('Critical error');
|
|
@@ -166,10 +166,10 @@ var LoggerService = class {
|
|
|
166
166
|
}
|
|
167
167
|
/**
|
|
168
168
|
* Log a message at the debug level (default channel)
|
|
169
|
-
*
|
|
169
|
+
*
|
|
170
170
|
* @param message - The log message
|
|
171
171
|
* @param context - Optional contextual data
|
|
172
|
-
*
|
|
172
|
+
*
|
|
173
173
|
* @example
|
|
174
174
|
* ```typescript
|
|
175
175
|
* loggerService.debug('Cache hit', { key: 'user:123' });
|
|
@@ -180,10 +180,10 @@ var LoggerService = class {
|
|
|
180
180
|
}
|
|
181
181
|
/**
|
|
182
182
|
* Log a message at the info level (default channel)
|
|
183
|
-
*
|
|
183
|
+
*
|
|
184
184
|
* @param message - The log message
|
|
185
185
|
* @param context - Optional contextual data
|
|
186
|
-
*
|
|
186
|
+
*
|
|
187
187
|
* @example
|
|
188
188
|
* ```typescript
|
|
189
189
|
* loggerService.info('User logged in', { userId: '123' });
|
|
@@ -194,10 +194,10 @@ var LoggerService = class {
|
|
|
194
194
|
}
|
|
195
195
|
/**
|
|
196
196
|
* Log a message at the warn level (default channel)
|
|
197
|
-
*
|
|
197
|
+
*
|
|
198
198
|
* @param message - The log message
|
|
199
199
|
* @param context - Optional contextual data
|
|
200
|
-
*
|
|
200
|
+
*
|
|
201
201
|
* @example
|
|
202
202
|
* ```typescript
|
|
203
203
|
* loggerService.warn('API rate limit approaching', { remaining: 10 });
|
|
@@ -208,10 +208,10 @@ var LoggerService = class {
|
|
|
208
208
|
}
|
|
209
209
|
/**
|
|
210
210
|
* Log a message at the error level (default channel)
|
|
211
|
-
*
|
|
211
|
+
*
|
|
212
212
|
* @param message - The log message
|
|
213
213
|
* @param context - Optional contextual data
|
|
214
|
-
*
|
|
214
|
+
*
|
|
215
215
|
* @example
|
|
216
216
|
* ```typescript
|
|
217
217
|
* loggerService.error('Database connection failed', { error });
|
|
@@ -222,10 +222,10 @@ var LoggerService = class {
|
|
|
222
222
|
}
|
|
223
223
|
/**
|
|
224
224
|
* Log a message at the fatal level (default channel)
|
|
225
|
-
*
|
|
225
|
+
*
|
|
226
226
|
* @param message - The log message
|
|
227
227
|
* @param context - Optional contextual data
|
|
228
|
-
*
|
|
228
|
+
*
|
|
229
229
|
* @example
|
|
230
230
|
* ```typescript
|
|
231
231
|
* loggerService.fatal('Application crashed', { error, stack });
|
|
@@ -236,10 +236,10 @@ var LoggerService = class {
|
|
|
236
236
|
}
|
|
237
237
|
/**
|
|
238
238
|
* Add persistent context to the default channel
|
|
239
|
-
*
|
|
239
|
+
*
|
|
240
240
|
* @param context - Key-value pairs to add to the shared context
|
|
241
241
|
* @returns The logger service instance for fluent chaining
|
|
242
|
-
*
|
|
242
|
+
*
|
|
243
243
|
* @example
|
|
244
244
|
* ```typescript
|
|
245
245
|
* loggerService
|
|
@@ -254,15 +254,15 @@ var LoggerService = class {
|
|
|
254
254
|
}
|
|
255
255
|
/**
|
|
256
256
|
* Remove keys from the default channel's shared context
|
|
257
|
-
*
|
|
257
|
+
*
|
|
258
258
|
* @param keys - Optional array of context keys to remove
|
|
259
259
|
* @returns The logger service instance for fluent chaining
|
|
260
|
-
*
|
|
260
|
+
*
|
|
261
261
|
* @example
|
|
262
262
|
* ```typescript
|
|
263
263
|
* // Remove specific keys
|
|
264
264
|
* loggerService.withoutContext(['userId', 'requestId']);
|
|
265
|
-
*
|
|
265
|
+
*
|
|
266
266
|
* // Clear all context
|
|
267
267
|
* loggerService.withoutContext();
|
|
268
268
|
* ```
|
|
@@ -273,7 +273,7 @@ var LoggerService = class {
|
|
|
273
273
|
}
|
|
274
274
|
/**
|
|
275
275
|
* Get all transporters from the default channel
|
|
276
|
-
*
|
|
276
|
+
*
|
|
277
277
|
* @returns Array of transporter instances
|
|
278
278
|
*/
|
|
279
279
|
getTransporters() {
|
|
@@ -281,7 +281,7 @@ var LoggerService = class {
|
|
|
281
281
|
}
|
|
282
282
|
/**
|
|
283
283
|
* Get the default channel name
|
|
284
|
-
*
|
|
284
|
+
*
|
|
285
285
|
* @returns Default channel name
|
|
286
286
|
*/
|
|
287
287
|
getDefaultChannelName() {
|
|
@@ -289,7 +289,7 @@ var LoggerService = class {
|
|
|
289
289
|
}
|
|
290
290
|
/**
|
|
291
291
|
* Get all configured channel names
|
|
292
|
-
*
|
|
292
|
+
*
|
|
293
293
|
* @returns Array of channel names
|
|
294
294
|
*/
|
|
295
295
|
getChannelNames() {
|
|
@@ -297,7 +297,7 @@ var LoggerService = class {
|
|
|
297
297
|
}
|
|
298
298
|
/**
|
|
299
299
|
* Check if a channel is configured
|
|
300
|
-
*
|
|
300
|
+
*
|
|
301
301
|
* @param name - Channel name
|
|
302
302
|
* @returns True if the channel is configured
|
|
303
303
|
*/
|
|
@@ -306,7 +306,7 @@ var LoggerService = class {
|
|
|
306
306
|
}
|
|
307
307
|
/**
|
|
308
308
|
* Check if a channel is currently active (cached)
|
|
309
|
-
*
|
|
309
|
+
*
|
|
310
310
|
* @param name - Channel name (uses default if not specified)
|
|
311
311
|
* @returns True if the channel is active
|
|
312
312
|
*/
|
|
@@ -316,7 +316,7 @@ var LoggerService = class {
|
|
|
316
316
|
}
|
|
317
317
|
/**
|
|
318
318
|
* Get the default channel instance
|
|
319
|
-
*
|
|
319
|
+
*
|
|
320
320
|
* @returns Logger instance
|
|
321
321
|
* @throws Error if default channel cannot be resolved
|
|
322
322
|
* @private
|
|
@@ -336,9 +336,9 @@ var LoggerService = class {
|
|
|
336
336
|
}
|
|
337
337
|
/**
|
|
338
338
|
* Resolve a channel by name
|
|
339
|
-
*
|
|
339
|
+
*
|
|
340
340
|
* Creates a new logger instance based on channel configuration.
|
|
341
|
-
*
|
|
341
|
+
*
|
|
342
342
|
* @param name - Channel name
|
|
343
343
|
* @returns Logger instance
|
|
344
344
|
* @throws Error if channel is not configured
|
|
@@ -686,10 +686,10 @@ var ConsoleTransporter = class {
|
|
|
686
686
|
var LoggerModule = class {
|
|
687
687
|
/**
|
|
688
688
|
* Configure the logger module
|
|
689
|
-
*
|
|
689
|
+
*
|
|
690
690
|
* @param config - Logger configuration (can be passed directly without defineConfig)
|
|
691
691
|
* @returns Dynamic module
|
|
692
|
-
*
|
|
692
|
+
*
|
|
693
693
|
* @example
|
|
694
694
|
* ```typescript
|
|
695
695
|
* LoggerModule.forRoot({
|
|
@@ -717,7 +717,7 @@ var LoggerModule = class {
|
|
|
717
717
|
}
|
|
718
718
|
/**
|
|
719
719
|
* Process configuration to add default transporters if needed
|
|
720
|
-
*
|
|
720
|
+
*
|
|
721
721
|
* @param config - Raw configuration
|
|
722
722
|
* @returns Processed configuration with defaults
|
|
723
723
|
* @private
|
|
@@ -755,7 +755,7 @@ LoggerModule = __decorateClass([
|
|
|
755
755
|
(0, import_react_di2.Module)({})
|
|
756
756
|
], LoggerModule);
|
|
757
757
|
|
|
758
|
-
// src/
|
|
758
|
+
// src/utils/define-config.util.ts
|
|
759
759
|
function defineConfig(config) {
|
|
760
760
|
return config;
|
|
761
761
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/enums/log-level.enum.ts","../src/services/logger.service.ts","../src/logger.ts","../src/constants/tokens.constant.ts","../src/logger.module.ts","../src/formatters/pretty.formatter.ts","../src/formatters/json.formatter.ts","../src/formatters/simple.formatter.ts","../src/transporters/silent.transporter.ts","../src/transporters/console.transporter.ts","../src/config/logger.config.ts","../src/transporters/storage.transporter.ts","../src/hooks/use-logger/use-logger.hook.ts","../src/hooks/use-logger-context/use-logger-context.hook.ts"],"sourcesContent":["/**\n * @abdokouta/logger\n *\n * A lightweight, client-side logging package inspired by Laravel's\n * logging architecture. Provides a clean interface for structured\n * logging with pluggable transporters, customizable formatters,\n * contextual logging, colors, and emoji support.\n *\n * @example\n * ```typescript\n * import { LoggerModule, defineConfig, LogLevel } from '@abdokouta/logger';\n * import { ConsoleTransporter, StorageTransporter } from '@abdokouta/logger';\n *\n * // Configure in your module\n * @Module({\n * imports: [\n * LoggerModule.forRoot(\n * defineConfig({\n * default: 'console',\n * channels: {\n * console: { transporters: [new ConsoleTransporter()] },\n * storage: { transporters: [new StorageTransporter()] },\n * },\n * })\n * ),\n * ],\n * })\n * export class AppModule {}\n *\n * // Use in services\n * @Injectable()\n * class UserService {\n * constructor(\n * @Inject(LoggerService) private logger: LoggerService\n * ) {}\n *\n * async createUser(data: UserData) {\n * this.logger.info('Creating user', { email: data.email });\n * }\n * }\n *\n * // Use in React components\n * function MyComponent() {\n * const logger = useLogger();\n * logger.info('Component rendered');\n * return <div>Hello</div>;\n * }\n * ```\n *\n * @module @abdokouta/logger\n */\n\n// ============================================================================\n// Enums\n// ============================================================================\nexport { LogLevel } from './enums';\n\n// ============================================================================\n// Core Interfaces\n// ============================================================================\nexport type { LogEntry } from './interfaces';\nexport type { FormatterInterface } from './interfaces';\nexport type { TransporterInterface } from './interfaces';\nexport type { LoggerInterface } from './interfaces';\nexport type { LoggerConfig } from './interfaces';\nexport type { LoggerServiceInterface } from './interfaces/logger-service.interface';\n\n// ============================================================================\n// Service (DI)\n// ============================================================================\nexport { LoggerService } from './services/logger.service';\nexport { LoggerService as Logger } from './services/logger.service';\n\n// ============================================================================\n// Module (DI Configuration)\n// ============================================================================\nexport { LoggerModule } from './logger.module';\nexport type { LoggerModuleOptions } from './config/logger.config';\nexport { defineConfig } from './config/logger.config';\n\n// ============================================================================\n// Formatters\n// ============================================================================\nexport { PrettyFormatter } from './formatters';\nexport { JsonFormatter } from './formatters';\nexport { SimpleFormatter } from './formatters';\n\n// ============================================================================\n// Transporters\n// ============================================================================\nexport { ConsoleTransporter } from './transporters';\nexport type { ConsoleTransporterOptions } from './transporters';\n\nexport { SilentTransporter } from './transporters';\n\nexport { StorageTransporter } from './transporters';\nexport type { StorageTransporterOptions } from './transporters';\n\n// ============================================================================\n// React Hooks\n// ============================================================================\nexport { useLogger } from './hooks/use-logger';\nexport { useLoggerContext } from './hooks/use-logger-context';\n","/**\n * Log Level Enum\n *\n * Defines the severity levels for log messages, ordered from\n * least severe (debug) to most severe (fatal). Inspired by\n * PSR-3 / Laravel logging levels, adapted for client-side use.\n *\n * Each level has a numeric value that enables level-based filtering.\n * A transporter configured with a minimum level will only process\n * messages at or above that severity.\n *\n * @module enums/log-level\n */\nexport enum LogLevel {\n /**\n * Detailed debug information.\n * Use for development-time diagnostics that should not appear in production.\n */\n Debug = 0,\n\n /**\n * Interesting events.\n * Example: User logs in, feature flag evaluated, route navigated.\n */\n Info = 1,\n\n /**\n * Exceptional occurrences that are not errors.\n * Example: Use of deprecated APIs, poor use of an API, recoverable issues.\n */\n Warn = 2,\n\n /**\n * Runtime errors that do not require immediate action but should\n * typically be logged and monitored.\n */\n Error = 3,\n\n /**\n * System is unusable or a critical failure has occurred.\n * Example: Unrecoverable state, data corruption detected.\n */\n Fatal = 4,\n}\n","/**\n * Logger Service\n * \n * Main logger service that handles channels internally (NO separate manager).\n * Provides high-level logging operations with support for multiple channels.\n * \n * **Architecture:**\n * - Manages channels internally (no separate LoggerManager)\n * - Provides unified logging API\n * - Supports multiple channels with different transporters\n * - Lazy channel initialization\n * \n * @module services/logger\n */\n\nimport { Injectable, Inject } from '@abdokouta/react-di';\nimport { Logger } from '../logger';\nimport type { LoggerInterface } from '../interfaces/logger.interface';\nimport type { LoggerServiceInterface } from '../interfaces/logger-service.interface';\nimport { LOGGER_CONFIG } from '../constants/tokens.constant';\nimport type { LoggerModuleOptions } from '../config/logger.config';\n\n/**\n * Logger service implementation\n * \n * Provides a unified logging API with support for multiple channels.\n * Handles channel management internally without a separate manager class.\n * \n * @example\n * ```typescript\n * @Injectable()\n * class UserService {\n * constructor(\n * @Inject(LoggerService) private logger: LoggerService\n * ) {}\n * \n * async createUser(data: UserData) {\n * // Use default channel\n * this.logger.info('Creating user', { email: data.email });\n * \n * try {\n * const user = await this.db.users.create(data);\n * this.logger.info('User created', { userId: user.id });\n * return user;\n * } catch (error) {\n * this.logger.error('Failed to create user', { error });\n * throw error;\n * }\n * }\n * \n * async auditAction(action: string) {\n * // Use specific channel\n * const auditLogger = this.logger.channel('audit');\n * auditLogger.info('User action', { action });\n * }\n * }\n * ```\n */\n@Injectable()\nexport class LoggerService implements LoggerServiceInterface {\n /** Logger configuration */\n private readonly config: LoggerModuleOptions;\n \n /** Cached channel instances */\n private channels: Map<string, LoggerInterface> = new Map();\n \n /** Default channel instance */\n private defaultChannel?: LoggerInterface;\n\n /**\n * Create a new logger service\n * \n * @param config - Logger configuration\n */\n constructor(\n @Inject(LOGGER_CONFIG)\n config: LoggerModuleOptions\n ) {\n this.config = config;\n }\n\n /**\n * Get a logger channel instance\n * \n * Returns the specified channel, or the default channel if no name is provided.\n * Channels are lazily initialized and cached.\n * \n * @param name - Channel name (uses default if not specified)\n * @returns Logger instance\n * @throws Error if channel is not configured\n * \n * @example\n * ```typescript\n * // Use default channel\n * const logger = loggerService.channel();\n * logger.info('Default message');\n * \n * // Use specific channel\n * const errorLogger = loggerService.channel('errors');\n * errorLogger.error('Critical error');\n * ```\n */\n channel(name?: string): LoggerInterface {\n const channelName = name ?? this.config.default;\n \n // Return cached channel if exists\n if (this.channels.has(channelName)) {\n return this.channels.get(channelName) as LoggerInterface;\n }\n \n // Resolve and cache new channel\n const channel = this.resolve(channelName);\n this.channels.set(channelName, channel);\n \n return channel;\n }\n\n /**\n * Log a message at the debug level (default channel)\n * \n * @param message - The log message\n * @param context - Optional contextual data\n * \n * @example\n * ```typescript\n * loggerService.debug('Cache hit', { key: 'user:123' });\n * ```\n */\n debug(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().debug(message, context);\n }\n\n /**\n * Log a message at the info level (default channel)\n * \n * @param message - The log message\n * @param context - Optional contextual data\n * \n * @example\n * ```typescript\n * loggerService.info('User logged in', { userId: '123' });\n * ```\n */\n info(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().info(message, context);\n }\n\n /**\n * Log a message at the warn level (default channel)\n * \n * @param message - The log message\n * @param context - Optional contextual data\n * \n * @example\n * ```typescript\n * loggerService.warn('API rate limit approaching', { remaining: 10 });\n * ```\n */\n warn(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().warn(message, context);\n }\n\n /**\n * Log a message at the error level (default channel)\n * \n * @param message - The log message\n * @param context - Optional contextual data\n * \n * @example\n * ```typescript\n * loggerService.error('Database connection failed', { error });\n * ```\n */\n error(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().error(message, context);\n }\n\n /**\n * Log a message at the fatal level (default channel)\n * \n * @param message - The log message\n * @param context - Optional contextual data\n * \n * @example\n * ```typescript\n * loggerService.fatal('Application crashed', { error, stack });\n * ```\n */\n fatal(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().fatal(message, context);\n }\n\n /**\n * Add persistent context to the default channel\n * \n * @param context - Key-value pairs to add to the shared context\n * @returns The logger service instance for fluent chaining\n * \n * @example\n * ```typescript\n * loggerService\n * .withContext({ requestId: 'abc-123' })\n * .withContext({ userId: 42 })\n * .info('Processing request');\n * ```\n */\n withContext(context: Record<string, unknown>): this {\n this.getDefaultChannel().withContext(context);\n return this;\n }\n\n /**\n * Remove keys from the default channel's shared context\n * \n * @param keys - Optional array of context keys to remove\n * @returns The logger service instance for fluent chaining\n * \n * @example\n * ```typescript\n * // Remove specific keys\n * loggerService.withoutContext(['userId', 'requestId']);\n * \n * // Clear all context\n * loggerService.withoutContext();\n * ```\n */\n withoutContext(keys?: string[]): this {\n this.getDefaultChannel().withoutContext(keys);\n return this;\n }\n\n /**\n * Get all transporters from the default channel\n * \n * @returns Array of transporter instances\n */\n getTransporters() {\n return this.getDefaultChannel().getTransporters();\n }\n\n /**\n * Get the default channel name\n * \n * @returns Default channel name\n */\n getDefaultChannelName(): string {\n return this.config.default;\n }\n\n /**\n * Get all configured channel names\n * \n * @returns Array of channel names\n */\n getChannelNames(): string[] {\n return Object.keys(this.config.channels);\n }\n\n /**\n * Check if a channel is configured\n * \n * @param name - Channel name\n * @returns True if the channel is configured\n */\n hasChannel(name: string): boolean {\n return name in this.config.channels;\n }\n\n /**\n * Check if a channel is currently active (cached)\n * \n * @param name - Channel name (uses default if not specified)\n * @returns True if the channel is active\n */\n isChannelActive(name?: string): boolean {\n const channelName = name ?? this.config.default;\n return this.channels.has(channelName);\n }\n\n /**\n * Get the default channel instance\n * \n * @returns Logger instance\n * @throws Error if default channel cannot be resolved\n * @private\n */\n private getDefaultChannel(): LoggerInterface {\n if (this.defaultChannel) {\n return this.defaultChannel;\n }\n \n // Lazy initialize default channel\n const channelName = this.config.default;\n \n if (this.channels.has(channelName)) {\n this.defaultChannel = this.channels.get(channelName) as LoggerInterface;\n return this.defaultChannel;\n }\n \n this.defaultChannel = this.resolve(channelName);\n this.channels.set(channelName, this.defaultChannel);\n \n return this.defaultChannel;\n }\n\n /**\n * Resolve a channel by name\n * \n * Creates a new logger instance based on channel configuration.\n * \n * @param name - Channel name\n * @returns Logger instance\n * @throws Error if channel is not configured\n * @private\n */\n private resolve(name: string): LoggerInterface {\n const channelConfig = this.config.channels[name];\n \n if (!channelConfig) {\n throw new Error(\n `Logger channel [${name}] is not configured. ` +\n `Available channels: ${Object.keys(this.config.channels).join(', ')}`\n );\n }\n \n // Create logger with channel configuration\n return new Logger(channelConfig);\n }\n}\n","/**\n * Logger Implementation\n * \n * Core logger class that implements the LoggerInterface.\n * Handles log entry creation, context management, and transporter dispatch.\n * \n * @module logger\n */\n\nimport type { LoggerInterface } from './interfaces/logger.interface';\nimport type { LoggerConfig } from './interfaces/logger-config.interface';\nimport type { TransporterInterface } from './interfaces/transporter.interface';\nimport type { LogEntry } from './interfaces/log-entry.interface';\nimport { LogLevel } from './enums/log-level.enum';\n\n/**\n * Logger class\n * \n * Implements the LoggerInterface with support for multiple transporters,\n * contextual logging, and log level filtering.\n */\nexport class Logger implements LoggerInterface {\n private readonly config: LoggerConfig;\n private sharedContext: Record<string, unknown> = {};\n\n constructor(config: LoggerConfig) {\n this.config = config;\n if (config.context) {\n this.sharedContext = { ...config.context };\n }\n }\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.DEBUG, message, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.INFO, message, context);\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.WARN, message, context);\n }\n\n error(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.ERROR, message, context);\n }\n\n fatal(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.FATAL, message, context);\n }\n\n withContext(context: Record<string, unknown>): this {\n this.sharedContext = { ...this.sharedContext, ...context };\n return this;\n }\n\n withoutContext(keys?: string[]): this {\n if (!keys) {\n this.sharedContext = {};\n } else {\n for (const key of keys) {\n delete this.sharedContext[key];\n }\n }\n return this;\n }\n\n getTransporters(): TransporterInterface[] {\n return this.config.transporters;\n }\n\n private log(level: LogLevel, message: string, context?: Record<string, unknown>): void {\n const entry: LogEntry = {\n level,\n message,\n context: { ...this.sharedContext, ...context },\n timestamp: new Date(),\n };\n\n for (const transporter of this.config.transporters) {\n transporter.log(entry);\n }\n }\n}\n","/**\n * Dependency Injection Tokens\n * \n * Defines DI tokens for the logger package.\n * Used with @abdokouta/react-di for dependency injection.\n * \n * @module constants/tokens\n */\n\n/**\n * Logger configuration token\n * \n * Used to inject the logger configuration into the LoggerService.\n * \n * @example\n * ```typescript\n * @Injectable()\n * class LoggerService {\n * constructor(\n * @Inject(LOGGER_CONFIG) private config: LoggerModuleOptions\n * ) {}\n * }\n * ```\n */\nexport const LOGGER_CONFIG = Symbol('LOGGER_CONFIG');\n\n/**\n * Logger service token\n * \n * Used to inject the logger service into other services.\n * \n * @example\n * ```typescript\n * @Injectable()\n * class UserService {\n * constructor(\n * @Inject(LOGGER_SERVICE) private logger: LoggerService\n * ) {}\n * }\n * ```\n */\nexport const LOGGER_SERVICE = Symbol('LOGGER_SERVICE');\n","/**\n * Logger Module\n * \n * Configures the logger system for dependency injection.\n * Provides LoggerService (NO manager) to the application.\n * \n * @module logger.module\n */\n\nimport { Module, forRoot, type DynamicModule } from '@abdokouta/react-di';\n\nimport { LoggerService } from './services/logger.service';\nimport { LOGGER_CONFIG } from './constants/tokens.constant';\nimport type { LoggerModuleOptions } from './config/logger.config';\nimport { SilentTransporter } from './transporters/silent.transporter';\nimport { ConsoleTransporter } from './transporters/console.transporter';\nimport type { LoggerConfig } from './interfaces/logger-config.interface';\n\n/**\n * Logger module\n * \n * Provides LoggerService to the application via dependency injection.\n * The service handles channels internally (NO separate manager).\n * \n * @example\n * ```typescript\n * import { Module } from '@abdokouta/react-di';\n * import { LoggerModule, defineConfig } from '@abdokouta/logger';\n * import { ConsoleTransporter, StorageTransporter } from '@abdokouta/logger';\n * import { LogLevel } from '@abdokouta/logger';\n * \n * @Module({\n * imports: [\n * LoggerModule.forRoot(\n * defineConfig({\n * default: 'console',\n * channels: {\n * console: {\n * transporters: [new ConsoleTransporter()],\n * context: { app: 'my-app' },\n * },\n * storage: {\n * transporters: [new StorageTransporter({ maxEntries: 500 })],\n * },\n * errors: {\n * transporters: [\n * new ConsoleTransporter({ level: LogLevel.Error }),\n * new StorageTransporter({ key: 'error-logs' }),\n * ],\n * },\n * },\n * })\n * ),\n * ],\n * })\n * export class AppModule {}\n * ```\n * \n * @example\n * ```typescript\n * // Using logger in a service\n * import { Injectable, Inject } from '@abdokouta/react-di';\n * import { LoggerService } from '@abdokouta/logger';\n * \n * @Injectable()\n * export class UserService {\n * constructor(\n * @Inject(LoggerService) private logger: LoggerService\n * ) {}\n * \n * async createUser(data: UserData) {\n * this.logger.info('Creating user', { email: data.email });\n * \n * try {\n * const user = await this.db.users.create(data);\n * this.logger.info('User created', { userId: user.id });\n * return user;\n * } catch (error) {\n * this.logger.error('Failed to create user', { error });\n * throw error;\n * }\n * }\n * \n * async auditAction(action: string) {\n * // Use specific channel\n * const auditLogger = this.logger.channel('audit');\n * auditLogger.info('User action', { action });\n * }\n * }\n * ```\n */\n@Module({})\n// biome-ignore lint/complexity/noStaticOnlyClass: Module pattern requires static methods\nexport class LoggerModule {\n /**\n * Configure the logger module\n * \n * @param config - Logger configuration (can be passed directly without defineConfig)\n * @returns Dynamic module\n * \n * @example\n * ```typescript\n * LoggerModule.forRoot({\n * default: 'console',\n * channels: {\n * console: {\n * transporters: [new ConsoleTransporter()],\n * },\n * },\n * })\n * ```\n */\n static forRoot(config: LoggerModuleOptions): DynamicModule {\n // Ensure default channel has transporters\n const processedConfig = LoggerModule.processConfig(config);\n\n return forRoot(LoggerModule, {\n providers: [\n {\n provide: LOGGER_CONFIG,\n useValue: processedConfig,\n },\n LoggerService,\n ],\n exports: [LoggerService, LOGGER_CONFIG],\n });\n }\n\n /**\n * Process configuration to add default transporters if needed\n * \n * @param config - Raw configuration\n * @returns Processed configuration with defaults\n * @private\n */\n private static processConfig(config: LoggerModuleOptions): LoggerModuleOptions {\n const processedChannels: Record<string, LoggerConfig> = {};\n\n // Use for...in loop for better compatibility\n for (const name in config.channels) {\n if (Object.prototype.hasOwnProperty.call(config.channels, name)) {\n const channelConfig = config.channels[name];\n \n // Skip if channelConfig is undefined\n if (!channelConfig) continue;\n \n // If no transporters specified, add default based on channel name\n if (!channelConfig.transporters || channelConfig.transporters.length === 0) {\n if (name === 'silent') {\n processedChannels[name] = {\n ...channelConfig,\n transporters: [new SilentTransporter()],\n };\n } else {\n processedChannels[name] = {\n ...channelConfig,\n transporters: [new ConsoleTransporter()],\n };\n }\n } else {\n processedChannels[name] = channelConfig;\n }\n }\n }\n\n return {\n ...config,\n channels: processedChannels,\n };\n }\n}\n","/**\n * Pretty Formatter\n *\n * A visually rich formatter that produces colorful, emoji-prefixed\n * log output designed for the browser console. Each log level is\n * assigned a distinct emoji and CSS color to make scanning logs\n * effortless during development.\n *\n * This is the default formatter used by the ConsoleTransporter.\n *\n * @module formatters/pretty\n *\n * @example\n * ```ts\n * const formatter = new PrettyFormatter();\n * const output = formatter.format(entry);\n * // => \"đ [DEBUG] [14:30:00.000] Hello world {userId: 42}\"\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport type { FormatterInterface, LogEntry } from '@/interfaces';\n\n/**\n * Mapping of log levels to their emoji prefix.\n * Provides instant visual identification of severity in console output.\n */\nconst LEVEL_EMOJI: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'đ',\n [LogLevel.Info]: 'âšī¸',\n [LogLevel.Warn]: 'â ī¸',\n [LogLevel.Error]: 'â',\n [LogLevel.Fatal]: 'đ',\n};\n\n/**\n * Mapping of log levels to their display label.\n * Used in the formatted output string between brackets.\n */\nconst LEVEL_LABEL: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'DEBUG',\n [LogLevel.Info]: 'INFO',\n [LogLevel.Warn]: 'WARN',\n [LogLevel.Error]: 'ERROR',\n [LogLevel.Fatal]: 'FATAL',\n};\n\n/**\n * Mapping of log levels to CSS color strings for browser console styling.\n * These colors are applied via `%c` formatting in `console.log`.\n */\nexport const LEVEL_COLORS: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'color: #8B8B8B',\n [LogLevel.Info]: 'color: #2196F3',\n [LogLevel.Warn]: 'color: #FF9800',\n [LogLevel.Error]: 'color: #F44336',\n [LogLevel.Fatal]:\n 'color: #FFFFFF; background: #F44336; font-weight: bold; padding: 1px 4px; border-radius: 2px',\n};\n\nexport class PrettyFormatter implements FormatterInterface {\n /**\n * Format a log entry into a pretty, human-readable string with\n * emoji prefix, level badge, timestamp, message, and context.\n *\n * The returned string includes `%c` placeholders for CSS styling\n * in the browser console. The ConsoleTransporter is responsible\n * for passing the corresponding style strings.\n *\n * @param entry - The log entry to format.\n * @returns The formatted string with CSS style placeholders.\n */\n format(entry: LogEntry): string {\n const emoji = LEVEL_EMOJI[entry.level];\n const label = LEVEL_LABEL[entry.level];\n const time = this.formatTimestamp(entry.timestamp);\n const contextStr = this.formatContext(entry.context);\n\n return `${emoji} %c[${label}]%c [${time}] ${entry.message}${contextStr}`;\n }\n\n /**\n * Extract a short time string (HH:mm:ss.SSS) from an ISO timestamp.\n *\n * @param timestamp - ISO 8601 timestamp string.\n * @returns A short time-only representation.\n */\n private formatTimestamp(timestamp: string): string {\n try {\n const date = new Date(timestamp);\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n const seconds = String(date.getSeconds()).padStart(2, '0');\n const ms = String(date.getMilliseconds()).padStart(3, '0');\n \n return `${hours}:${minutes}:${seconds}.${ms}`;\n } catch {\n return timestamp;\n }\n }\n\n /**\n * Serialize context data into a compact, readable string.\n * Returns an empty string when context is empty to keep output clean.\n *\n * @param context - The context record to serialize.\n * @returns A formatted context string or empty string.\n */\n private formatContext(context: Record<string, unknown>): string {\n const keys = Object.keys(context);\n\n if (keys.length === 0) {\n return '';\n }\n\n try {\n return ` ${JSON.stringify(context)}`;\n } catch {\n return ` [context serialization failed]`;\n }\n }\n}\n","/**\n * JSON Formatter\n *\n * Serializes log entries into compact JSON strings. Ideal for\n * structured logging scenarios where logs need to be parsed\n * programmatically â for example, when sending logs to a remote\n * endpoint or storing them in localStorage for later analysis.\n *\n * @module formatters/json\n *\n * @example\n * ```ts\n * const formatter = new JsonFormatter();\n * const output = formatter.format(entry);\n * // => '{\"level\":\"info\",\"message\":\"User logged in\",\"timestamp\":\"...\",\"context\":{\"userId\":42}}'\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport type { FormatterInterface, LogEntry } from '@/interfaces';\n\n/**\n * Mapping of log levels to their lowercase string representation\n * for JSON output.\n */\nconst LEVEL_STRING: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'debug',\n [LogLevel.Info]: 'info',\n [LogLevel.Warn]: 'warn',\n [LogLevel.Error]: 'error',\n [LogLevel.Fatal]: 'fatal',\n};\n\nexport class JsonFormatter implements FormatterInterface {\n /**\n * Format a log entry as a JSON string.\n *\n * Produces a flat JSON object with level (as string), message,\n * timestamp, and context fields. Context is omitted when empty\n * to keep output compact.\n *\n * @param entry - The log entry to format.\n * @returns A JSON-serialized string representation of the entry.\n */\n format(entry: LogEntry): string {\n const payload: Record<string, unknown> = {\n level: LEVEL_STRING[entry.level],\n message: entry.message,\n timestamp: entry.timestamp,\n };\n\n // Only include context when it has keys to keep JSON compact.\n if (Object.keys(entry.context).length > 0) {\n payload.context = entry.context;\n }\n\n try {\n return JSON.stringify(payload);\n } catch {\n return JSON.stringify({\n level: LEVEL_STRING[entry.level],\n message: entry.message,\n timestamp: entry.timestamp,\n error: 'context serialization failed',\n });\n }\n }\n}\n","/**\n * Simple Formatter\n *\n * A minimal, no-frills formatter that produces plain text log lines\n * without colors, emojis, or CSS styling. Suitable for environments\n * where styled output is not supported or when logs need to be\n * stored as plain text.\n *\n * @module formatters/simple\n *\n * @example\n * ```ts\n * const formatter = new SimpleFormatter();\n * const output = formatter.format(entry);\n * // => \"[DEBUG] [2026-03-28T14:30:00.000Z] Hello world {userId: 42}\"\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport type { FormatterInterface, LogEntry } from '@/interfaces';\n\n/**\n * Mapping of log levels to their uppercase string label.\n */\nconst LEVEL_LABEL: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'DEBUG',\n [LogLevel.Info]: 'INFO',\n [LogLevel.Warn]: 'WARN',\n [LogLevel.Error]: 'ERROR',\n [LogLevel.Fatal]: 'FATAL',\n};\n\nexport class SimpleFormatter implements FormatterInterface {\n /**\n * Format a log entry into a plain text line.\n *\n * Output pattern: `[LEVEL] [timestamp] message {context}`\n *\n * @param entry - The log entry to format.\n * @returns A plain text string with no styling.\n */\n format(entry: LogEntry): string {\n const label = LEVEL_LABEL[entry.level];\n const contextStr = this.formatContext(entry.context);\n\n return `[${label}] [${entry.timestamp}] ${entry.message}${contextStr}`;\n }\n\n /**\n * Serialize context data into a compact string.\n * Returns an empty string when context is empty.\n *\n * @param context - The context record to serialize.\n * @returns A formatted context string or empty string.\n */\n private formatContext(context: Record<string, unknown>): string {\n const keys = Object.keys(context);\n\n if (keys.length === 0) {\n return '';\n }\n\n try {\n return ` ${JSON.stringify(context)}`;\n } catch {\n return ' [context serialization failed]';\n }\n }\n}\n","/**\n * Silent Transporter\n *\n * A no-op transporter that silently discards all log entries.\n * Useful for production environments where logging should be\n * disabled, or for testing scenarios where log output would\n * pollute test results.\n *\n * Equivalent to Laravel's \"null\" log driver.\n *\n * @module transporters/silent\n *\n * @example\n * ```ts\n * const logger = new Logger({\n * transporters: [new SilentTransporter()],\n * });\n * logger.info('This will be silently discarded');\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport { SimpleFormatter } from '@/formatters';\nimport type { FormatterInterface, LogEntry, TransporterInterface } from '@/interfaces';\n\nexport class SilentTransporter implements TransporterInterface {\n /**\nThe formatter instance (maintained for interface compliance). */\n private _formatter: FormatterInterface;\n\n /**\nThe minimum log level (maintained for interface compliance). */\n private _level: LogLevel;\n\n /**\n * Create a new SilentTransporter instance.\n * All parameters are optional and exist only for interface compliance.\n */\n constructor() {\n this._formatter = new SimpleFormatter();\n this._level = LogLevel.Debug;\n }\n\n /**\n * No-op transport method. Silently discards the entry.\n *\n * @param _entry - The log entry (ignored).\n */\n transport(_entry: LogEntry): void {\n // Intentionally empty â this transporter discards all entries.\n }\n\n /**\n * Replace the current formatter.\n *\n * @param formatter - The new formatter instance.\n */\n setFormatter(formatter: FormatterInterface): void {\n this._formatter = formatter;\n }\n\n /**\n * Retrieve the currently assigned formatter.\n *\n * @returns The active formatter instance.\n */\n getFormatter(): FormatterInterface {\n return this._formatter;\n }\n\n /**\n * Get the minimum log level.\n *\n * @returns The current minimum LogLevel threshold.\n */\n getLevel(): LogLevel {\n return this._level;\n }\n\n /**\n * Set the minimum log level.\n *\n * @param level - The new minimum LogLevel threshold.\n */\n setLevel(level: LogLevel): void {\n this._level = level;\n }\n}\n","/**\n * Console Transporter\n *\n * Delivers log entries to the browser's developer console using the\n * appropriate `console.*` method for each severity level. When paired\n * with the PrettyFormatter (the default), output includes CSS-styled\n * level badges with colors and emoji prefixes.\n *\n * This is the primary transporter for development environments.\n *\n * @module transporters/console\n *\n * @example\n * ```ts\n * const transporter = new ConsoleTransporter();\n * transporter.transport(entry); // outputs to console with colors\n *\n * // With custom minimum level:\n * const warnOnly = new ConsoleTransporter({ level: LogLevel.Warn });\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport { LEVEL_COLORS, PrettyFormatter } from '@/formatters';\nimport type { FormatterInterface, LogEntry, TransporterInterface } from '@/interfaces';\n\n/**\n * Configuration options for the ConsoleTransporter.\n */\nexport interface ConsoleTransporterOptions {\n /**\n * The formatter to use for log entries.\n * Defaults to PrettyFormatter if not provided.\n */\n formatter?: FormatterInterface;\n\n /**\n * The minimum log level to transport.\n * Entries below this level are silently ignored.\n *\n * @default LogLevel.Debug\n */\n level?: LogLevel;\n}\n\nexport class ConsoleTransporter implements TransporterInterface {\n /**\nThe formatter used to convert log entries into output strings. */\n private _formatter: FormatterInterface;\n\n /**\nThe minimum log level threshold for this transporter. */\n private _level: LogLevel;\n\n /**\n * Create a new ConsoleTransporter instance.\n *\n * @param options - Optional configuration for formatter and minimum level.\n */\n constructor(options: ConsoleTransporterOptions = {}) {\n this._formatter = options.formatter ?? new PrettyFormatter();\n this._level = options.level ?? LogLevel.Debug;\n }\n\n /**\n * Deliver a log entry to the browser console.\n *\n * Routes the entry to the appropriate `console.*` method based on\n * the log level. When using the PrettyFormatter, CSS styles are\n * applied via `%c` placeholders for colored output.\n *\n * Entries below the configured minimum level are silently skipped.\n *\n * @param entry - The log entry to output.\n */\n transport(entry: LogEntry): void {\n // Skip entries below the minimum level threshold.\n if (entry.level < this._level) {\n return;\n }\n\n const formatted = this._formatter.format(entry);\n const method = this.resolveConsoleMethod(entry.level);\n\n // When using PrettyFormatter, apply CSS styles via %c placeholders.\n if (this._formatter instanceof PrettyFormatter) {\n const levelStyle = LEVEL_COLORS[entry.level];\n const resetStyle = 'color: inherit';\n\n method(formatted, levelStyle, resetStyle);\n } else {\n method(formatted);\n }\n }\n\n /**\n * Replace the current formatter.\n *\n * @param formatter - The new formatter instance to use.\n */\n setFormatter(formatter: FormatterInterface): void {\n this._formatter = formatter;\n }\n\n /**\n * Retrieve the currently assigned formatter.\n *\n * @returns The active formatter instance.\n */\n getFormatter(): FormatterInterface {\n return this._formatter;\n }\n\n /**\n * Get the minimum log level this transporter handles.\n *\n * @returns The current minimum LogLevel threshold.\n */\n getLevel(): LogLevel {\n return this._level;\n }\n\n /**\n * Set the minimum log level this transporter handles.\n *\n * @param level - The new minimum LogLevel threshold.\n */\n setLevel(level: LogLevel): void {\n this._level = level;\n }\n\n /**\n * Resolve the appropriate `console.*` method for a given log level.\n *\n * Maps logger severity levels to the closest browser console method\n * to ensure proper DevTools filtering and visual distinction.\n *\n * @param level - The log level to resolve.\n * @returns The bound console method function.\n */\n private resolveConsoleMethod(level: LogLevel): (...args: unknown[]) => void {\n switch (level) {\n case LogLevel.Debug:\n return console.debug.bind(console);\n case LogLevel.Info:\n return console.info.bind(console);\n case LogLevel.Warn:\n return console.warn.bind(console);\n case LogLevel.Error:\n return console.error.bind(console);\n case LogLevel.Fatal:\n return console.error.bind(console);\n default:\n return console.log.bind(console);\n }\n }\n}\n","/**\n * Logger Module Configuration\n * \n * Defines the configuration interface for the logger module.\n * Supports multiple channels with different transporters and settings.\n * \n * @module config/logger\n */\n\nimport type { LoggerConfig } from '../interfaces/logger-config.interface';\n\n/**\n * Logger module options\n * \n * Configuration for the logger module with support for multiple channels.\n * Each channel can have its own transporters, context, and settings.\n * \n * @example\n * ```typescript\n * const config: LoggerModuleOptions = {\n * default: 'console',\n * channels: {\n * console: {\n * transporters: [new ConsoleTransporter()],\n * context: { app: 'my-app' },\n * },\n * storage: {\n * transporters: [new StorageTransporter()],\n * },\n * errors: {\n * transporters: [\n * new ConsoleTransporter({ level: LogLevel.ERROR }),\n * new StorageTransporter({ key: 'error-logs' }),\n * ],\n * },\n * },\n * };\n * ```\n */\nexport interface LoggerModuleOptions {\n /**\n * Default channel name\n * \n * The channel to use when no specific channel is requested.\n * Must match one of the keys in the channels object.\n */\n default: string;\n\n /**\n * Channel configurations\n * \n * Map of channel names to their configurations.\n * Each channel can have its own transporters and settings.\n */\n channels: Record<string, LoggerConfig>;\n}\n\n/**\n * Helper function to define logger configuration with type safety\n * \n * @param config - Logger module options\n * @returns The same config with proper typing\n * \n * @example\n * ```typescript\n * import { defineConfig } from '@abdokouta/logger';\n * \n * const config = defineConfig({\n * default: 'console',\n * channels: {\n * console: {\n * transporters: [new ConsoleTransporter()],\n * },\n * },\n * });\n * ```\n */\nexport function defineConfig(config: LoggerModuleOptions): LoggerModuleOptions {\n return config;\n}\n","/**\n * Storage Transporter\n *\n * Persists log entries to the browser's localStorage as JSON strings.\n * Useful for capturing logs that survive page reloads, enabling\n * post-mortem debugging or user-submitted bug reports that include\n * recent log history.\n *\n * Entries are stored as a JSON array under a configurable storage key.\n * A maximum entry limit prevents unbounded storage growth.\n *\n * @module transporters/storage\n *\n * @example\n * ```ts\n * const transporter = new StorageTransporter({\n * key: 'app-logs',\n * maxEntries: 200,\n * });\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport { JsonFormatter } from '@/formatters';\nimport type { FormatterInterface, LogEntry, TransporterInterface } from '@/interfaces';\n\n/**\n * Configuration options for the StorageTransporter.\n */\nexport interface StorageTransporterOptions {\n /**\n * The localStorage key under which log entries are stored.\n *\n * @default \"logger:entries\"\n */\n key?: string;\n\n /**\n * Maximum number of entries to retain in storage.\n * When the limit is exceeded, the oldest entries are discarded (FIFO).\n *\n * @default 100\n */\n maxEntries?: number;\n\n /**\n * The formatter to use for serializing log entries.\n * Defaults to JsonFormatter if not provided.\n */\n formatter?: FormatterInterface;\n\n /**\n * The minimum log level to transport.\n * Entries below this level are silently ignored.\n *\n * @default LogLevel.Debug\n */\n level?: LogLevel;\n}\n\n/**\nDefault localStorage key for log storage. */\nconst DEFAULT_STORAGE_KEY = 'logger:entries';\n\n/**\nDefault maximum number of retained entries. */\nconst DEFAULT_MAX_ENTRIES = 100;\n\nexport class StorageTransporter implements TransporterInterface {\n /**\nThe formatter used to convert log entries into storable strings. */\n private _formatter: FormatterInterface;\n\n /**\nThe minimum log level threshold for this transporter. */\n private _level: LogLevel;\n\n /**\nThe localStorage key for persisting entries. */\n private readonly _key: string;\n\n /**\nMaximum number of entries to retain. */\n private readonly _maxEntries: number;\n\n /**\n * Create a new StorageTransporter instance.\n *\n * @param options - Optional configuration for storage key, limits, and formatter.\n */\n constructor(options: StorageTransporterOptions = {}) {\n this._formatter = options.formatter ?? new JsonFormatter();\n this._level = options.level ?? LogLevel.Debug;\n this._key = options.key ?? DEFAULT_STORAGE_KEY;\n this._maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;\n }\n\n /**\n * Persist a log entry to localStorage.\n *\n * The entry is formatted, appended to the existing entries array,\n * and trimmed to the maximum entry limit. If localStorage is\n * unavailable or full, the error is silently swallowed to avoid\n * crashing the application.\n *\n * @param entry - The log entry to persist.\n */\n transport(entry: LogEntry): void {\n // Skip entries below the minimum level threshold.\n if (entry.level < this._level) {\n return;\n }\n\n try {\n const formatted = this._formatter.format(entry);\n const entries = this.readEntries();\n\n entries.push(formatted);\n\n // Trim oldest entries when the limit is exceeded.\n while (entries.length > this._maxEntries) {\n entries.shift();\n }\n\n localStorage.setItem(this._key, JSON.stringify(entries));\n } catch {\n // Silently swallow storage errors (quota exceeded, unavailable, etc.)\n // to prevent logging from crashing the application.\n }\n }\n\n /**\n * Replace the current formatter.\n *\n * @param formatter - The new formatter instance.\n */\n setFormatter(formatter: FormatterInterface): void {\n this._formatter = formatter;\n }\n\n /**\n * Retrieve the currently assigned formatter.\n *\n * @returns The active formatter instance.\n */\n getFormatter(): FormatterInterface {\n return this._formatter;\n }\n\n /**\n * Get the minimum log level this transporter handles.\n *\n * @returns The current minimum LogLevel threshold.\n */\n getLevel(): LogLevel {\n return this._level;\n }\n\n /**\n * Set the minimum log level this transporter handles.\n *\n * @param level - The new minimum LogLevel threshold.\n */\n setLevel(level: LogLevel): void {\n this._level = level;\n }\n\n /**\n * Clear all stored log entries from localStorage.\n * Useful for manual cleanup or when resetting application state.\n */\n clear(): void {\n try {\n localStorage.removeItem(this._key);\n } catch {\n // Silently swallow if localStorage is unavailable.\n }\n }\n\n /**\n * Retrieve all stored log entries from localStorage.\n *\n * @returns An array of formatted log entry strings.\n */\n getEntries(): string[] {\n return this.readEntries();\n }\n\n /**\n * Read the current entries array from localStorage.\n * Returns an empty array if the key does not exist or parsing fails.\n *\n * @returns The parsed entries array.\n */\n private readEntries(): string[] {\n try {\n const raw = localStorage.getItem(this._key);\n\n if (!raw) {\n return [];\n }\n\n const parsed = JSON.parse(raw);\n\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n}\n","/**\n * useLogger Hook\n * \n * React hook for accessing the logger service in components.\n * Provides access to the default channel or a specific channel.\n * \n * @module hooks/use-logger\n */\n\nimport { useInject } from '@abdokouta/react-di';\nimport { LoggerService } from '@/services/logger.service';\nimport type { LoggerInterface } from '@/interfaces/logger.interface';\n\n/**\n * Access the logger service in React components\n * \n * Returns the logger service instance or a specific channel.\n * \n * @param channelName - Optional channel name (uses default if not specified)\n * @returns Logger instance\n * \n * @example\n * ```typescript\n * import { useLogger } from '@abdokouta/logger';\n * \n * function MyComponent() {\n * const logger = useLogger();\n * \n * const handleClick = () => {\n * logger.info('Button clicked', { timestamp: Date.now() });\n * };\n * \n * return <button onClick={handleClick}>Click me</button>;\n * }\n * ```\n * \n * @example\n * ```typescript\n * // Use specific channel\n * function ErrorBoundary({ error }: { error: Error }) {\n * const errorLogger = useLogger('errors');\n * \n * useEffect(() => {\n * errorLogger.error('Component error', {\n * message: error.message,\n * stack: error.stack,\n * });\n * }, [error]);\n * \n * return <div>Something went wrong</div>;\n * }\n * ```\n */\nexport function useLogger(channelName?: string): LoggerInterface {\n const loggerService = useInject(LoggerService);\n \n if (channelName) {\n return loggerService.channel(channelName);\n }\n \n // Return the service itself which implements LoggerInterface\n return loggerService as LoggerInterface;\n}\n","/**\n * useLoggerContext Hook\n * \n * React hook for managing logger context in components.\n * Automatically adds and removes context based on component lifecycle.\n * \n * @module hooks/use-logger-context\n */\n\nimport { useEffect } from 'react';\nimport { useLogger } from '../use-logger';\n\n/**\n * Manage logger context in React components\n * \n * Automatically adds context when the component mounts and removes it when unmounted.\n * Useful for adding component-specific context to all logs.\n * \n * @param context - Context to add to the logger\n * @param channelName - Optional channel name (uses default if not specified)\n * \n * @example\n * ```typescript\n * import { useLoggerContext } from '@abdokouta/logger';\n * \n * function UserProfile({ userId }: { userId: string }) {\n * // Add userId to all logs in this component\n * useLoggerContext({ userId, component: 'UserProfile' });\n * \n * const logger = useLogger();\n * \n * const handleUpdate = () => {\n * // This log will include { userId, component: 'UserProfile' }\n * logger.info('Updating profile');\n * };\n * \n * return <button onClick={handleUpdate}>Update</button>;\n * }\n * ```\n * \n * @example\n * ```typescript\n * // With specific channel\n * function PaymentForm({ orderId }: { orderId: string }) {\n * useLoggerContext({ orderId, form: 'payment' }, 'payment');\n * \n * const logger = useLogger('payment');\n * \n * const handleSubmit = () => {\n * logger.info('Payment submitted');\n * };\n * \n * return <form onSubmit={handleSubmit}>...</form>;\n * }\n * ```\n */\nexport function useLoggerContext(\n context: Record<string, unknown>,\n channelName?: string\n): void {\n const logger = useLogger(channelName);\n\n useEffect(() => {\n // Add context on mount\n logger.withContext(context);\n\n // Remove context on unmount\n return () => {\n logger.withoutContext(Object.keys(context));\n };\n }, [logger, context]);\n}\n"],"mappings":"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","names":["LogLevel","import_react_di","LEVEL_LABEL","import_react_di"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/enums/log-level.enum.ts","../src/services/logger.service.ts","../src/logger.ts","../src/constants/tokens.constant.ts","../src/logger.module.ts","../src/formatters/pretty.formatter.ts","../src/formatters/json.formatter.ts","../src/formatters/simple.formatter.ts","../src/transporters/silent.transporter.ts","../src/transporters/console.transporter.ts","../src/utils/define-config.util.ts","../src/transporters/storage.transporter.ts","../src/hooks/use-logger/use-logger.hook.ts","../src/hooks/use-logger-context/use-logger-context.hook.ts"],"sourcesContent":["/**\n * @abdokouta/logger\n *\n * A lightweight, client-side logging package inspired by Laravel's\n * logging architecture. Provides a clean interface for structured\n * logging with pluggable transporters, customizable formatters,\n * contextual logging, colors, and emoji support.\n *\n * @example\n * ```typescript\n * import { LoggerModule, defineConfig, LogLevel } from '@abdokouta/logger';\n * import { ConsoleTransporter, StorageTransporter } from '@abdokouta/logger';\n *\n * // Configure in your module\n * @Module({\n * imports: [\n * LoggerModule.forRoot(\n * defineConfig({\n * default: 'console',\n * channels: {\n * console: { transporters: [new ConsoleTransporter()] },\n * storage: { transporters: [new StorageTransporter()] },\n * },\n * })\n * ),\n * ],\n * })\n * export class AppModule {}\n *\n * // Use in services\n * @Injectable()\n * class UserService {\n * constructor(\n * @Inject(LoggerService) private logger: LoggerService\n * ) {}\n *\n * async createUser(data: UserData) {\n * this.logger.info('Creating user', { email: data.email });\n * }\n * }\n *\n * // Use in React components\n * function MyComponent() {\n * const logger = useLogger();\n * logger.info('Component rendered');\n * return <div>Hello</div>;\n * }\n * ```\n *\n * @module @abdokouta/logger\n */\n\n// ============================================================================\n// Enums\n// ============================================================================\nexport { LogLevel } from './enums';\n\n// ============================================================================\n// Core Interfaces\n// ============================================================================\nexport type { LogEntry } from './interfaces';\nexport type { FormatterInterface } from './interfaces';\nexport type { TransporterInterface } from './interfaces';\nexport type { LoggerInterface } from './interfaces';\nexport type { LoggerConfig } from './interfaces';\nexport type { LoggerServiceInterface } from './interfaces/logger-service.interface';\n\n// ============================================================================\n// Service (DI)\n// ============================================================================\nexport { LoggerService } from './services/logger.service';\nexport { LoggerService as Logger } from './services/logger.service';\n\n// ============================================================================\n// Module (DI Configuration)\n// ============================================================================\nexport { LoggerModule } from './logger.module';\nexport type { LoggerModuleOptions } from './config/logger.config';\n\n// ============================================================================\n// Utils\n// ============================================================================\nexport { defineConfig } from './utils';\n\n// ============================================================================\n// Formatters\n// ============================================================================\nexport { PrettyFormatter } from './formatters';\nexport { JsonFormatter } from './formatters';\nexport { SimpleFormatter } from './formatters';\n\n// ============================================================================\n// Transporters\n// ============================================================================\nexport { ConsoleTransporter } from './transporters';\nexport type { ConsoleTransporterOptions } from './transporters';\n\nexport { SilentTransporter } from './transporters';\n\nexport { StorageTransporter } from './transporters';\nexport type { StorageTransporterOptions } from './transporters';\n\n// ============================================================================\n// React Hooks\n// ============================================================================\nexport { useLogger } from './hooks/use-logger';\nexport { useLoggerContext } from './hooks/use-logger-context';\n","/**\n * Log Level Enum\n *\n * Defines the severity levels for log messages, ordered from\n * least severe (debug) to most severe (fatal). Inspired by\n * PSR-3 / Laravel logging levels, adapted for client-side use.\n *\n * Each level has a numeric value that enables level-based filtering.\n * A transporter configured with a minimum level will only process\n * messages at or above that severity.\n *\n * @module enums/log-level\n */\nexport enum LogLevel {\n /**\n * Detailed debug information.\n * Use for development-time diagnostics that should not appear in production.\n */\n Debug = 0,\n\n /**\n * Interesting events.\n * Example: User logs in, feature flag evaluated, route navigated.\n */\n Info = 1,\n\n /**\n * Exceptional occurrences that are not errors.\n * Example: Use of deprecated APIs, poor use of an API, recoverable issues.\n */\n Warn = 2,\n\n /**\n * Runtime errors that do not require immediate action but should\n * typically be logged and monitored.\n */\n Error = 3,\n\n /**\n * System is unusable or a critical failure has occurred.\n * Example: Unrecoverable state, data corruption detected.\n */\n Fatal = 4,\n}\n","/**\n * Logger Service\n *\n * Main logger service that handles channels internally (NO separate manager).\n * Provides high-level logging operations with support for multiple channels.\n *\n * **Architecture:**\n * - Manages channels internally (no separate LoggerManager)\n * - Provides unified logging API\n * - Supports multiple channels with different transporters\n * - Lazy channel initialization\n *\n * @module services/logger\n */\n\nimport { Injectable, Inject } from '@abdokouta/react-di';\nimport { Logger } from '../logger';\nimport type { LoggerInterface } from '../interfaces/logger.interface';\nimport type { LoggerServiceInterface } from '../interfaces/logger-service.interface';\nimport { LOGGER_CONFIG } from '../constants/tokens.constant';\nimport type { LoggerModuleOptions } from '../config/logger.config';\n\n/**\n * Logger service implementation\n *\n * Provides a unified logging API with support for multiple channels.\n * Handles channel management internally without a separate manager class.\n *\n * @example\n * ```typescript\n * @Injectable()\n * class UserService {\n * constructor(\n * @Inject(LoggerService) private logger: LoggerService\n * ) {}\n *\n * async createUser(data: UserData) {\n * // Use default channel\n * this.logger.info('Creating user', { email: data.email });\n *\n * try {\n * const user = await this.db.users.create(data);\n * this.logger.info('User created', { userId: user.id });\n * return user;\n * } catch (error) {\n * this.logger.error('Failed to create user', { error });\n * throw error;\n * }\n * }\n *\n * async auditAction(action: string) {\n * // Use specific channel\n * const auditLogger = this.logger.channel('audit');\n * auditLogger.info('User action', { action });\n * }\n * }\n * ```\n */\n@Injectable()\nexport class LoggerService implements LoggerServiceInterface {\n /** Logger configuration */\n private readonly config: LoggerModuleOptions;\n\n /** Cached channel instances */\n private channels: Map<string, LoggerInterface> = new Map();\n\n /** Default channel instance */\n private defaultChannel?: LoggerInterface;\n\n /**\n * Create a new logger service\n *\n * @param config - Logger configuration\n */\n constructor(\n @Inject(LOGGER_CONFIG)\n config: LoggerModuleOptions\n ) {\n this.config = config;\n }\n\n /**\n * Get a logger channel instance\n *\n * Returns the specified channel, or the default channel if no name is provided.\n * Channels are lazily initialized and cached.\n *\n * @param name - Channel name (uses default if not specified)\n * @returns Logger instance\n * @throws Error if channel is not configured\n *\n * @example\n * ```typescript\n * // Use default channel\n * const logger = loggerService.channel();\n * logger.info('Default message');\n *\n * // Use specific channel\n * const errorLogger = loggerService.channel('errors');\n * errorLogger.error('Critical error');\n * ```\n */\n channel(name?: string): LoggerInterface {\n const channelName = name ?? this.config.default;\n\n // Return cached channel if exists\n if (this.channels.has(channelName)) {\n return this.channels.get(channelName) as LoggerInterface;\n }\n\n // Resolve and cache new channel\n const channel = this.resolve(channelName);\n this.channels.set(channelName, channel);\n\n return channel;\n }\n\n /**\n * Log a message at the debug level (default channel)\n *\n * @param message - The log message\n * @param context - Optional contextual data\n *\n * @example\n * ```typescript\n * loggerService.debug('Cache hit', { key: 'user:123' });\n * ```\n */\n debug(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().debug(message, context);\n }\n\n /**\n * Log a message at the info level (default channel)\n *\n * @param message - The log message\n * @param context - Optional contextual data\n *\n * @example\n * ```typescript\n * loggerService.info('User logged in', { userId: '123' });\n * ```\n */\n info(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().info(message, context);\n }\n\n /**\n * Log a message at the warn level (default channel)\n *\n * @param message - The log message\n * @param context - Optional contextual data\n *\n * @example\n * ```typescript\n * loggerService.warn('API rate limit approaching', { remaining: 10 });\n * ```\n */\n warn(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().warn(message, context);\n }\n\n /**\n * Log a message at the error level (default channel)\n *\n * @param message - The log message\n * @param context - Optional contextual data\n *\n * @example\n * ```typescript\n * loggerService.error('Database connection failed', { error });\n * ```\n */\n error(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().error(message, context);\n }\n\n /**\n * Log a message at the fatal level (default channel)\n *\n * @param message - The log message\n * @param context - Optional contextual data\n *\n * @example\n * ```typescript\n * loggerService.fatal('Application crashed', { error, stack });\n * ```\n */\n fatal(message: string, context: Record<string, unknown> = {}): void {\n this.getDefaultChannel().fatal(message, context);\n }\n\n /**\n * Add persistent context to the default channel\n *\n * @param context - Key-value pairs to add to the shared context\n * @returns The logger service instance for fluent chaining\n *\n * @example\n * ```typescript\n * loggerService\n * .withContext({ requestId: 'abc-123' })\n * .withContext({ userId: 42 })\n * .info('Processing request');\n * ```\n */\n withContext(context: Record<string, unknown>): this {\n this.getDefaultChannel().withContext(context);\n return this;\n }\n\n /**\n * Remove keys from the default channel's shared context\n *\n * @param keys - Optional array of context keys to remove\n * @returns The logger service instance for fluent chaining\n *\n * @example\n * ```typescript\n * // Remove specific keys\n * loggerService.withoutContext(['userId', 'requestId']);\n *\n * // Clear all context\n * loggerService.withoutContext();\n * ```\n */\n withoutContext(keys?: string[]): this {\n this.getDefaultChannel().withoutContext(keys);\n return this;\n }\n\n /**\n * Get all transporters from the default channel\n *\n * @returns Array of transporter instances\n */\n getTransporters() {\n return this.getDefaultChannel().getTransporters();\n }\n\n /**\n * Get the default channel name\n *\n * @returns Default channel name\n */\n getDefaultChannelName(): string {\n return this.config.default;\n }\n\n /**\n * Get all configured channel names\n *\n * @returns Array of channel names\n */\n getChannelNames(): string[] {\n return Object.keys(this.config.channels);\n }\n\n /**\n * Check if a channel is configured\n *\n * @param name - Channel name\n * @returns True if the channel is configured\n */\n hasChannel(name: string): boolean {\n return name in this.config.channels;\n }\n\n /**\n * Check if a channel is currently active (cached)\n *\n * @param name - Channel name (uses default if not specified)\n * @returns True if the channel is active\n */\n isChannelActive(name?: string): boolean {\n const channelName = name ?? this.config.default;\n return this.channels.has(channelName);\n }\n\n /**\n * Get the default channel instance\n *\n * @returns Logger instance\n * @throws Error if default channel cannot be resolved\n * @private\n */\n private getDefaultChannel(): LoggerInterface {\n if (this.defaultChannel) {\n return this.defaultChannel;\n }\n\n // Lazy initialize default channel\n const channelName = this.config.default;\n\n if (this.channels.has(channelName)) {\n this.defaultChannel = this.channels.get(channelName) as LoggerInterface;\n return this.defaultChannel;\n }\n\n this.defaultChannel = this.resolve(channelName);\n this.channels.set(channelName, this.defaultChannel);\n\n return this.defaultChannel;\n }\n\n /**\n * Resolve a channel by name\n *\n * Creates a new logger instance based on channel configuration.\n *\n * @param name - Channel name\n * @returns Logger instance\n * @throws Error if channel is not configured\n * @private\n */\n private resolve(name: string): LoggerInterface {\n const channelConfig = this.config.channels[name];\n\n if (!channelConfig) {\n throw new Error(\n `Logger channel [${name}] is not configured. ` +\n `Available channels: ${Object.keys(this.config.channels).join(', ')}`\n );\n }\n\n // Create logger with channel configuration\n return new Logger(channelConfig);\n }\n}\n","/**\n * Logger Implementation\n *\n * Core logger class that implements the LoggerInterface.\n * Handles log entry creation, context management, and transporter dispatch.\n *\n * @module logger\n */\n\nimport type { LoggerInterface } from './interfaces/logger.interface';\nimport type { LoggerConfig } from './interfaces/logger-config.interface';\nimport type { TransporterInterface } from './interfaces/transporter.interface';\nimport type { LogEntry } from './interfaces/log-entry.interface';\nimport { LogLevel } from './enums/log-level.enum';\n\n/**\n * Logger class\n *\n * Implements the LoggerInterface with support for multiple transporters,\n * contextual logging, and log level filtering.\n */\nexport class Logger implements LoggerInterface {\n private readonly config: LoggerConfig;\n private sharedContext: Record<string, unknown> = {};\n\n constructor(config: LoggerConfig) {\n this.config = config;\n if (config.context) {\n this.sharedContext = { ...config.context };\n }\n }\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.DEBUG, message, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.INFO, message, context);\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.WARN, message, context);\n }\n\n error(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.ERROR, message, context);\n }\n\n fatal(message: string, context?: Record<string, unknown>): void {\n this.log(LogLevel.FATAL, message, context);\n }\n\n withContext(context: Record<string, unknown>): this {\n this.sharedContext = { ...this.sharedContext, ...context };\n return this;\n }\n\n withoutContext(keys?: string[]): this {\n if (!keys) {\n this.sharedContext = {};\n } else {\n for (const key of keys) {\n delete this.sharedContext[key];\n }\n }\n return this;\n }\n\n getTransporters(): TransporterInterface[] {\n return this.config.transporters;\n }\n\n private log(level: LogLevel, message: string, context?: Record<string, unknown>): void {\n const entry: LogEntry = {\n level,\n message,\n context: { ...this.sharedContext, ...context },\n timestamp: new Date(),\n };\n\n for (const transporter of this.config.transporters) {\n transporter.log(entry);\n }\n }\n}\n","/**\n * Dependency Injection Tokens\n *\n * Defines DI tokens for the logger package.\n * Used with @abdokouta/react-di for dependency injection.\n *\n * @module constants/tokens\n */\n\n/**\n * Logger configuration token\n *\n * Used to inject the logger configuration into the LoggerService.\n *\n * @example\n * ```typescript\n * @Injectable()\n * class LoggerService {\n * constructor(\n * @Inject(LOGGER_CONFIG) private config: LoggerModuleOptions\n * ) {}\n * }\n * ```\n */\nexport const LOGGER_CONFIG = Symbol('LOGGER_CONFIG');\n\n/**\n * Logger service token\n *\n * Used to inject the logger service into other services.\n *\n * @example\n * ```typescript\n * @Injectable()\n * class UserService {\n * constructor(\n * @Inject(LOGGER_SERVICE) private logger: LoggerService\n * ) {}\n * }\n * ```\n */\nexport const LOGGER_SERVICE = Symbol('LOGGER_SERVICE');\n","/**\n * Logger Module\n *\n * Configures the logger system for dependency injection.\n * Provides LoggerService (NO manager) to the application.\n *\n * @module logger.module\n */\n\nimport { Module, forRoot, type DynamicModule } from '@abdokouta/react-di';\n\nimport { LoggerService } from './services/logger.service';\nimport { LOGGER_CONFIG } from './constants/tokens.constant';\nimport type { LoggerModuleOptions } from './config/logger.config';\nimport { SilentTransporter } from './transporters/silent.transporter';\nimport { ConsoleTransporter } from './transporters/console.transporter';\nimport type { LoggerConfig } from './interfaces/logger-config.interface';\n\n/**\n * Logger module\n *\n * Provides LoggerService to the application via dependency injection.\n * The service handles channels internally (NO separate manager).\n *\n * @example\n * ```typescript\n * import { Module } from '@abdokouta/react-di';\n * import { LoggerModule, defineConfig } from '@abdokouta/logger';\n * import { ConsoleTransporter, StorageTransporter } from '@abdokouta/logger';\n * import { LogLevel } from '@abdokouta/logger';\n *\n * @Module({\n * imports: [\n * LoggerModule.forRoot(\n * defineConfig({\n * default: 'console',\n * channels: {\n * console: {\n * transporters: [new ConsoleTransporter()],\n * context: { app: 'my-app' },\n * },\n * storage: {\n * transporters: [new StorageTransporter({ maxEntries: 500 })],\n * },\n * errors: {\n * transporters: [\n * new ConsoleTransporter({ level: LogLevel.Error }),\n * new StorageTransporter({ key: 'error-logs' }),\n * ],\n * },\n * },\n * })\n * ),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * @example\n * ```typescript\n * // Using logger in a service\n * import { Injectable, Inject } from '@abdokouta/react-di';\n * import { LoggerService } from '@abdokouta/logger';\n *\n * @Injectable()\n * export class UserService {\n * constructor(\n * @Inject(LoggerService) private logger: LoggerService\n * ) {}\n *\n * async createUser(data: UserData) {\n * this.logger.info('Creating user', { email: data.email });\n *\n * try {\n * const user = await this.db.users.create(data);\n * this.logger.info('User created', { userId: user.id });\n * return user;\n * } catch (error) {\n * this.logger.error('Failed to create user', { error });\n * throw error;\n * }\n * }\n *\n * async auditAction(action: string) {\n * // Use specific channel\n * const auditLogger = this.logger.channel('audit');\n * auditLogger.info('User action', { action });\n * }\n * }\n * ```\n */\n@Module({})\n// biome-ignore lint/complexity/noStaticOnlyClass: Module pattern requires static methods\nexport class LoggerModule {\n /**\n * Configure the logger module\n *\n * @param config - Logger configuration (can be passed directly without defineConfig)\n * @returns Dynamic module\n *\n * @example\n * ```typescript\n * LoggerModule.forRoot({\n * default: 'console',\n * channels: {\n * console: {\n * transporters: [new ConsoleTransporter()],\n * },\n * },\n * })\n * ```\n */\n static forRoot(config: LoggerModuleOptions): DynamicModule {\n // Ensure default channel has transporters\n const processedConfig = LoggerModule.processConfig(config);\n\n return forRoot(LoggerModule, {\n providers: [\n {\n provide: LOGGER_CONFIG,\n useValue: processedConfig,\n },\n LoggerService,\n ],\n exports: [LoggerService, LOGGER_CONFIG],\n });\n }\n\n /**\n * Process configuration to add default transporters if needed\n *\n * @param config - Raw configuration\n * @returns Processed configuration with defaults\n * @private\n */\n private static processConfig(config: LoggerModuleOptions): LoggerModuleOptions {\n const processedChannels: Record<string, LoggerConfig> = {};\n\n // Use for...in loop for better compatibility\n for (const name in config.channels) {\n if (Object.prototype.hasOwnProperty.call(config.channels, name)) {\n const channelConfig = config.channels[name];\n\n // Skip if channelConfig is undefined\n if (!channelConfig) continue;\n\n // If no transporters specified, add default based on channel name\n if (!channelConfig.transporters || channelConfig.transporters.length === 0) {\n if (name === 'silent') {\n processedChannels[name] = {\n ...channelConfig,\n transporters: [new SilentTransporter()],\n };\n } else {\n processedChannels[name] = {\n ...channelConfig,\n transporters: [new ConsoleTransporter()],\n };\n }\n } else {\n processedChannels[name] = channelConfig;\n }\n }\n }\n\n return {\n ...config,\n channels: processedChannels,\n };\n }\n}\n","/**\n * Pretty Formatter\n *\n * A visually rich formatter that produces colorful, emoji-prefixed\n * log output designed for the browser console. Each log level is\n * assigned a distinct emoji and CSS color to make scanning logs\n * effortless during development.\n *\n * This is the default formatter used by the ConsoleTransporter.\n *\n * @module formatters/pretty\n *\n * @example\n * ```ts\n * const formatter = new PrettyFormatter();\n * const output = formatter.format(entry);\n * // => \"đ [DEBUG] [14:30:00.000] Hello world {userId: 42}\"\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport type { FormatterInterface, LogEntry } from '@/interfaces';\n\n/**\n * Mapping of log levels to their emoji prefix.\n * Provides instant visual identification of severity in console output.\n */\nconst LEVEL_EMOJI: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'đ',\n [LogLevel.Info]: 'âšī¸',\n [LogLevel.Warn]: 'â ī¸',\n [LogLevel.Error]: 'â',\n [LogLevel.Fatal]: 'đ',\n};\n\n/**\n * Mapping of log levels to their display label.\n * Used in the formatted output string between brackets.\n */\nconst LEVEL_LABEL: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'DEBUG',\n [LogLevel.Info]: 'INFO',\n [LogLevel.Warn]: 'WARN',\n [LogLevel.Error]: 'ERROR',\n [LogLevel.Fatal]: 'FATAL',\n};\n\n/**\n * Mapping of log levels to CSS color strings for browser console styling.\n * These colors are applied via `%c` formatting in `console.log`.\n */\nexport const LEVEL_COLORS: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'color: #8B8B8B',\n [LogLevel.Info]: 'color: #2196F3',\n [LogLevel.Warn]: 'color: #FF9800',\n [LogLevel.Error]: 'color: #F44336',\n [LogLevel.Fatal]:\n 'color: #FFFFFF; background: #F44336; font-weight: bold; padding: 1px 4px; border-radius: 2px',\n};\n\nexport class PrettyFormatter implements FormatterInterface {\n /**\n * Format a log entry into a pretty, human-readable string with\n * emoji prefix, level badge, timestamp, message, and context.\n *\n * The returned string includes `%c` placeholders for CSS styling\n * in the browser console. The ConsoleTransporter is responsible\n * for passing the corresponding style strings.\n *\n * @param entry - The log entry to format.\n * @returns The formatted string with CSS style placeholders.\n */\n format(entry: LogEntry): string {\n const emoji = LEVEL_EMOJI[entry.level];\n const label = LEVEL_LABEL[entry.level];\n const time = this.formatTimestamp(entry.timestamp);\n const contextStr = this.formatContext(entry.context);\n\n return `${emoji} %c[${label}]%c [${time}] ${entry.message}${contextStr}`;\n }\n\n /**\n * Extract a short time string (HH:mm:ss.SSS) from an ISO timestamp.\n *\n * @param timestamp - ISO 8601 timestamp string.\n * @returns A short time-only representation.\n */\n private formatTimestamp(timestamp: string): string {\n try {\n const date = new Date(timestamp);\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n const seconds = String(date.getSeconds()).padStart(2, '0');\n const ms = String(date.getMilliseconds()).padStart(3, '0');\n\n return `${hours}:${minutes}:${seconds}.${ms}`;\n } catch {\n return timestamp;\n }\n }\n\n /**\n * Serialize context data into a compact, readable string.\n * Returns an empty string when context is empty to keep output clean.\n *\n * @param context - The context record to serialize.\n * @returns A formatted context string or empty string.\n */\n private formatContext(context: Record<string, unknown>): string {\n const keys = Object.keys(context);\n\n if (keys.length === 0) {\n return '';\n }\n\n try {\n return ` ${JSON.stringify(context)}`;\n } catch {\n return ` [context serialization failed]`;\n }\n }\n}\n","/**\n * JSON Formatter\n *\n * Serializes log entries into compact JSON strings. Ideal for\n * structured logging scenarios where logs need to be parsed\n * programmatically â for example, when sending logs to a remote\n * endpoint or storing them in localStorage for later analysis.\n *\n * @module formatters/json\n *\n * @example\n * ```ts\n * const formatter = new JsonFormatter();\n * const output = formatter.format(entry);\n * // => '{\"level\":\"info\",\"message\":\"User logged in\",\"timestamp\":\"...\",\"context\":{\"userId\":42}}'\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport type { FormatterInterface, LogEntry } from '@/interfaces';\n\n/**\n * Mapping of log levels to their lowercase string representation\n * for JSON output.\n */\nconst LEVEL_STRING: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'debug',\n [LogLevel.Info]: 'info',\n [LogLevel.Warn]: 'warn',\n [LogLevel.Error]: 'error',\n [LogLevel.Fatal]: 'fatal',\n};\n\nexport class JsonFormatter implements FormatterInterface {\n /**\n * Format a log entry as a JSON string.\n *\n * Produces a flat JSON object with level (as string), message,\n * timestamp, and context fields. Context is omitted when empty\n * to keep output compact.\n *\n * @param entry - The log entry to format.\n * @returns A JSON-serialized string representation of the entry.\n */\n format(entry: LogEntry): string {\n const payload: Record<string, unknown> = {\n level: LEVEL_STRING[entry.level],\n message: entry.message,\n timestamp: entry.timestamp,\n };\n\n // Only include context when it has keys to keep JSON compact.\n if (Object.keys(entry.context).length > 0) {\n payload.context = entry.context;\n }\n\n try {\n return JSON.stringify(payload);\n } catch {\n return JSON.stringify({\n level: LEVEL_STRING[entry.level],\n message: entry.message,\n timestamp: entry.timestamp,\n error: 'context serialization failed',\n });\n }\n }\n}\n","/**\n * Simple Formatter\n *\n * A minimal, no-frills formatter that produces plain text log lines\n * without colors, emojis, or CSS styling. Suitable for environments\n * where styled output is not supported or when logs need to be\n * stored as plain text.\n *\n * @module formatters/simple\n *\n * @example\n * ```ts\n * const formatter = new SimpleFormatter();\n * const output = formatter.format(entry);\n * // => \"[DEBUG] [2026-03-28T14:30:00.000Z] Hello world {userId: 42}\"\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport type { FormatterInterface, LogEntry } from '@/interfaces';\n\n/**\n * Mapping of log levels to their uppercase string label.\n */\nconst LEVEL_LABEL: Record<LogLevel, string> = {\n [LogLevel.Debug]: 'DEBUG',\n [LogLevel.Info]: 'INFO',\n [LogLevel.Warn]: 'WARN',\n [LogLevel.Error]: 'ERROR',\n [LogLevel.Fatal]: 'FATAL',\n};\n\nexport class SimpleFormatter implements FormatterInterface {\n /**\n * Format a log entry into a plain text line.\n *\n * Output pattern: `[LEVEL] [timestamp] message {context}`\n *\n * @param entry - The log entry to format.\n * @returns A plain text string with no styling.\n */\n format(entry: LogEntry): string {\n const label = LEVEL_LABEL[entry.level];\n const contextStr = this.formatContext(entry.context);\n\n return `[${label}] [${entry.timestamp}] ${entry.message}${contextStr}`;\n }\n\n /**\n * Serialize context data into a compact string.\n * Returns an empty string when context is empty.\n *\n * @param context - The context record to serialize.\n * @returns A formatted context string or empty string.\n */\n private formatContext(context: Record<string, unknown>): string {\n const keys = Object.keys(context);\n\n if (keys.length === 0) {\n return '';\n }\n\n try {\n return ` ${JSON.stringify(context)}`;\n } catch {\n return ' [context serialization failed]';\n }\n }\n}\n","/**\n * Silent Transporter\n *\n * A no-op transporter that silently discards all log entries.\n * Useful for production environments where logging should be\n * disabled, or for testing scenarios where log output would\n * pollute test results.\n *\n * Equivalent to Laravel's \"null\" log driver.\n *\n * @module transporters/silent\n *\n * @example\n * ```ts\n * const logger = new Logger({\n * transporters: [new SilentTransporter()],\n * });\n * logger.info('This will be silently discarded');\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport { SimpleFormatter } from '@/formatters';\nimport type { FormatterInterface, LogEntry, TransporterInterface } from '@/interfaces';\n\nexport class SilentTransporter implements TransporterInterface {\n /**\nThe formatter instance (maintained for interface compliance). */\n private _formatter: FormatterInterface;\n\n /**\nThe minimum log level (maintained for interface compliance). */\n private _level: LogLevel;\n\n /**\n * Create a new SilentTransporter instance.\n * All parameters are optional and exist only for interface compliance.\n */\n constructor() {\n this._formatter = new SimpleFormatter();\n this._level = LogLevel.Debug;\n }\n\n /**\n * No-op transport method. Silently discards the entry.\n *\n * @param _entry - The log entry (ignored).\n */\n transport(_entry: LogEntry): void {\n // Intentionally empty â this transporter discards all entries.\n }\n\n /**\n * Replace the current formatter.\n *\n * @param formatter - The new formatter instance.\n */\n setFormatter(formatter: FormatterInterface): void {\n this._formatter = formatter;\n }\n\n /**\n * Retrieve the currently assigned formatter.\n *\n * @returns The active formatter instance.\n */\n getFormatter(): FormatterInterface {\n return this._formatter;\n }\n\n /**\n * Get the minimum log level.\n *\n * @returns The current minimum LogLevel threshold.\n */\n getLevel(): LogLevel {\n return this._level;\n }\n\n /**\n * Set the minimum log level.\n *\n * @param level - The new minimum LogLevel threshold.\n */\n setLevel(level: LogLevel): void {\n this._level = level;\n }\n}\n","/**\n * Console Transporter\n *\n * Delivers log entries to the browser's developer console using the\n * appropriate `console.*` method for each severity level. When paired\n * with the PrettyFormatter (the default), output includes CSS-styled\n * level badges with colors and emoji prefixes.\n *\n * This is the primary transporter for development environments.\n *\n * @module transporters/console\n *\n * @example\n * ```ts\n * const transporter = new ConsoleTransporter();\n * transporter.transport(entry); // outputs to console with colors\n *\n * // With custom minimum level:\n * const warnOnly = new ConsoleTransporter({ level: LogLevel.Warn });\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport { LEVEL_COLORS, PrettyFormatter } from '@/formatters';\nimport type { FormatterInterface, LogEntry, TransporterInterface } from '@/interfaces';\n\n/**\n * Configuration options for the ConsoleTransporter.\n */\nexport interface ConsoleTransporterOptions {\n /**\n * The formatter to use for log entries.\n * Defaults to PrettyFormatter if not provided.\n */\n formatter?: FormatterInterface;\n\n /**\n * The minimum log level to transport.\n * Entries below this level are silently ignored.\n *\n * @default LogLevel.Debug\n */\n level?: LogLevel;\n}\n\nexport class ConsoleTransporter implements TransporterInterface {\n /**\nThe formatter used to convert log entries into output strings. */\n private _formatter: FormatterInterface;\n\n /**\nThe minimum log level threshold for this transporter. */\n private _level: LogLevel;\n\n /**\n * Create a new ConsoleTransporter instance.\n *\n * @param options - Optional configuration for formatter and minimum level.\n */\n constructor(options: ConsoleTransporterOptions = {}) {\n this._formatter = options.formatter ?? new PrettyFormatter();\n this._level = options.level ?? LogLevel.Debug;\n }\n\n /**\n * Deliver a log entry to the browser console.\n *\n * Routes the entry to the appropriate `console.*` method based on\n * the log level. When using the PrettyFormatter, CSS styles are\n * applied via `%c` placeholders for colored output.\n *\n * Entries below the configured minimum level are silently skipped.\n *\n * @param entry - The log entry to output.\n */\n transport(entry: LogEntry): void {\n // Skip entries below the minimum level threshold.\n if (entry.level < this._level) {\n return;\n }\n\n const formatted = this._formatter.format(entry);\n const method = this.resolveConsoleMethod(entry.level);\n\n // When using PrettyFormatter, apply CSS styles via %c placeholders.\n if (this._formatter instanceof PrettyFormatter) {\n const levelStyle = LEVEL_COLORS[entry.level];\n const resetStyle = 'color: inherit';\n\n method(formatted, levelStyle, resetStyle);\n } else {\n method(formatted);\n }\n }\n\n /**\n * Replace the current formatter.\n *\n * @param formatter - The new formatter instance to use.\n */\n setFormatter(formatter: FormatterInterface): void {\n this._formatter = formatter;\n }\n\n /**\n * Retrieve the currently assigned formatter.\n *\n * @returns The active formatter instance.\n */\n getFormatter(): FormatterInterface {\n return this._formatter;\n }\n\n /**\n * Get the minimum log level this transporter handles.\n *\n * @returns The current minimum LogLevel threshold.\n */\n getLevel(): LogLevel {\n return this._level;\n }\n\n /**\n * Set the minimum log level this transporter handles.\n *\n * @param level - The new minimum LogLevel threshold.\n */\n setLevel(level: LogLevel): void {\n this._level = level;\n }\n\n /**\n * Resolve the appropriate `console.*` method for a given log level.\n *\n * Maps logger severity levels to the closest browser console method\n * to ensure proper DevTools filtering and visual distinction.\n *\n * @param level - The log level to resolve.\n * @returns The bound console method function.\n */\n private resolveConsoleMethod(level: LogLevel): (...args: unknown[]) => void {\n switch (level) {\n case LogLevel.Debug:\n return console.debug.bind(console);\n case LogLevel.Info:\n return console.info.bind(console);\n case LogLevel.Warn:\n return console.warn.bind(console);\n case LogLevel.Error:\n return console.error.bind(console);\n case LogLevel.Fatal:\n return console.error.bind(console);\n default:\n return console.log.bind(console);\n }\n }\n}\n","/**\n * Define Config Utility\n *\n * Helper function to define logger configuration with type safety.\n *\n * @module @abdokouta/logger\n */\n\nimport type { LoggerModuleOptions } from '../config/logger.config';\n\n/**\n * Helper function to define logger configuration with type safety\n *\n * Provides IDE autocomplete and type checking for configuration objects.\n * This pattern is consistent with modern tooling (Vite, Vitest, etc.).\n *\n * @param config - The logger configuration object\n * @returns The same configuration object with proper typing\n *\n * @example\n * ```typescript\n * // logger.config.ts\n * import { defineConfig, ConsoleTransporter, LogLevel } from '@abdokouta/logger';\n *\n * export default defineConfig({\n * default: 'console',\n * channels: {\n * console: {\n * transporters: [new ConsoleTransporter({ level: LogLevel.Debug })],\n * context: { app: 'my-app' },\n * },\n * },\n * });\n * ```\n */\nexport function defineConfig(config: LoggerModuleOptions): LoggerModuleOptions {\n return config;\n}\n","/**\n * Storage Transporter\n *\n * Persists log entries to the browser's localStorage as JSON strings.\n * Useful for capturing logs that survive page reloads, enabling\n * post-mortem debugging or user-submitted bug reports that include\n * recent log history.\n *\n * Entries are stored as a JSON array under a configurable storage key.\n * A maximum entry limit prevents unbounded storage growth.\n *\n * @module transporters/storage\n *\n * @example\n * ```ts\n * const transporter = new StorageTransporter({\n * key: 'app-logs',\n * maxEntries: 200,\n * });\n * ```\n */\nimport { LogLevel } from '@/enums';\nimport { JsonFormatter } from '@/formatters';\nimport type { FormatterInterface, LogEntry, TransporterInterface } from '@/interfaces';\n\n/**\n * Configuration options for the StorageTransporter.\n */\nexport interface StorageTransporterOptions {\n /**\n * The localStorage key under which log entries are stored.\n *\n * @default \"logger:entries\"\n */\n key?: string;\n\n /**\n * Maximum number of entries to retain in storage.\n * When the limit is exceeded, the oldest entries are discarded (FIFO).\n *\n * @default 100\n */\n maxEntries?: number;\n\n /**\n * The formatter to use for serializing log entries.\n * Defaults to JsonFormatter if not provided.\n */\n formatter?: FormatterInterface;\n\n /**\n * The minimum log level to transport.\n * Entries below this level are silently ignored.\n *\n * @default LogLevel.Debug\n */\n level?: LogLevel;\n}\n\n/**\nDefault localStorage key for log storage. */\nconst DEFAULT_STORAGE_KEY = 'logger:entries';\n\n/**\nDefault maximum number of retained entries. */\nconst DEFAULT_MAX_ENTRIES = 100;\n\nexport class StorageTransporter implements TransporterInterface {\n /**\nThe formatter used to convert log entries into storable strings. */\n private _formatter: FormatterInterface;\n\n /**\nThe minimum log level threshold for this transporter. */\n private _level: LogLevel;\n\n /**\nThe localStorage key for persisting entries. */\n private readonly _key: string;\n\n /**\nMaximum number of entries to retain. */\n private readonly _maxEntries: number;\n\n /**\n * Create a new StorageTransporter instance.\n *\n * @param options - Optional configuration for storage key, limits, and formatter.\n */\n constructor(options: StorageTransporterOptions = {}) {\n this._formatter = options.formatter ?? new JsonFormatter();\n this._level = options.level ?? LogLevel.Debug;\n this._key = options.key ?? DEFAULT_STORAGE_KEY;\n this._maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;\n }\n\n /**\n * Persist a log entry to localStorage.\n *\n * The entry is formatted, appended to the existing entries array,\n * and trimmed to the maximum entry limit. If localStorage is\n * unavailable or full, the error is silently swallowed to avoid\n * crashing the application.\n *\n * @param entry - The log entry to persist.\n */\n transport(entry: LogEntry): void {\n // Skip entries below the minimum level threshold.\n if (entry.level < this._level) {\n return;\n }\n\n try {\n const formatted = this._formatter.format(entry);\n const entries = this.readEntries();\n\n entries.push(formatted);\n\n // Trim oldest entries when the limit is exceeded.\n while (entries.length > this._maxEntries) {\n entries.shift();\n }\n\n localStorage.setItem(this._key, JSON.stringify(entries));\n } catch {\n // Silently swallow storage errors (quota exceeded, unavailable, etc.)\n // to prevent logging from crashing the application.\n }\n }\n\n /**\n * Replace the current formatter.\n *\n * @param formatter - The new formatter instance.\n */\n setFormatter(formatter: FormatterInterface): void {\n this._formatter = formatter;\n }\n\n /**\n * Retrieve the currently assigned formatter.\n *\n * @returns The active formatter instance.\n */\n getFormatter(): FormatterInterface {\n return this._formatter;\n }\n\n /**\n * Get the minimum log level this transporter handles.\n *\n * @returns The current minimum LogLevel threshold.\n */\n getLevel(): LogLevel {\n return this._level;\n }\n\n /**\n * Set the minimum log level this transporter handles.\n *\n * @param level - The new minimum LogLevel threshold.\n */\n setLevel(level: LogLevel): void {\n this._level = level;\n }\n\n /**\n * Clear all stored log entries from localStorage.\n * Useful for manual cleanup or when resetting application state.\n */\n clear(): void {\n try {\n localStorage.removeItem(this._key);\n } catch {\n // Silently swallow if localStorage is unavailable.\n }\n }\n\n /**\n * Retrieve all stored log entries from localStorage.\n *\n * @returns An array of formatted log entry strings.\n */\n getEntries(): string[] {\n return this.readEntries();\n }\n\n /**\n * Read the current entries array from localStorage.\n * Returns an empty array if the key does not exist or parsing fails.\n *\n * @returns The parsed entries array.\n */\n private readEntries(): string[] {\n try {\n const raw = localStorage.getItem(this._key);\n\n if (!raw) {\n return [];\n }\n\n const parsed = JSON.parse(raw);\n\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n}\n","/**\n * useLogger Hook\n *\n * React hook for accessing the logger service in components.\n * Provides access to the default channel or a specific channel.\n *\n * @module hooks/use-logger\n */\n\nimport { useInject } from '@abdokouta/react-di';\nimport { LoggerService } from '@/services/logger.service';\nimport type { LoggerInterface } from '@/interfaces/logger.interface';\n\n/**\n * Access the logger service in React components\n *\n * Returns the logger service instance or a specific channel.\n *\n * @param channelName - Optional channel name (uses default if not specified)\n * @returns Logger instance\n *\n * @example\n * ```typescript\n * import { useLogger } from '@abdokouta/logger';\n *\n * function MyComponent() {\n * const logger = useLogger();\n *\n * const handleClick = () => {\n * logger.info('Button clicked', { timestamp: Date.now() });\n * };\n *\n * return <button onClick={handleClick}>Click me</button>;\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Use specific channel\n * function ErrorBoundary({ error }: { error: Error }) {\n * const errorLogger = useLogger('errors');\n *\n * useEffect(() => {\n * errorLogger.error('Component error', {\n * message: error.message,\n * stack: error.stack,\n * });\n * }, [error]);\n *\n * return <div>Something went wrong</div>;\n * }\n * ```\n */\nexport function useLogger(channelName?: string): LoggerInterface {\n const loggerService = useInject(LoggerService);\n\n if (channelName) {\n return loggerService.channel(channelName);\n }\n\n // Return the service itself which implements LoggerInterface\n return loggerService as LoggerInterface;\n}\n","/**\n * useLoggerContext Hook\n *\n * React hook for managing logger context in components.\n * Automatically adds and removes context based on component lifecycle.\n *\n * @module hooks/use-logger-context\n */\n\nimport { useEffect } from 'react';\nimport { useLogger } from '../use-logger';\n\n/**\n * Manage logger context in React components\n *\n * Automatically adds context when the component mounts and removes it when unmounted.\n * Useful for adding component-specific context to all logs.\n *\n * @param context - Context to add to the logger\n * @param channelName - Optional channel name (uses default if not specified)\n *\n * @example\n * ```typescript\n * import { useLoggerContext } from '@abdokouta/logger';\n *\n * function UserProfile({ userId }: { userId: string }) {\n * // Add userId to all logs in this component\n * useLoggerContext({ userId, component: 'UserProfile' });\n *\n * const logger = useLogger();\n *\n * const handleUpdate = () => {\n * // This log will include { userId, component: 'UserProfile' }\n * logger.info('Updating profile');\n * };\n *\n * return <button onClick={handleUpdate}>Update</button>;\n * }\n * ```\n *\n * @example\n * ```typescript\n * // With specific channel\n * function PaymentForm({ orderId }: { orderId: string }) {\n * useLoggerContext({ orderId, form: 'payment' }, 'payment');\n *\n * const logger = useLogger('payment');\n *\n * const handleSubmit = () => {\n * logger.info('Payment submitted');\n * };\n *\n * return <form onSubmit={handleSubmit}>...</form>;\n * }\n * ```\n */\nexport function useLoggerContext(context: Record<string, unknown>, channelName?: string): void {\n const logger = useLogger(channelName);\n\n useEffect(() => {\n // Add context on mount\n logger.withContext(context);\n\n // Remove context on unmount\n return () => {\n logger.withoutContext(Object.keys(context));\n };\n }, [logger, context]);\n}\n"],"mappings":"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","names":["LogLevel","import_react_di","LEVEL_LABEL","import_react_di"]}
|