@abdokouta/react-logger 1.0.0

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.
@@ -0,0 +1,1231 @@
1
+ import { DynamicModule } from '@abdokouta/react-di';
2
+
3
+ /**
4
+ * Log Level Enum
5
+ *
6
+ * Defines the severity levels for log messages, ordered from
7
+ * least severe (debug) to most severe (fatal). Inspired by
8
+ * PSR-3 / Laravel logging levels, adapted for client-side use.
9
+ *
10
+ * Each level has a numeric value that enables level-based filtering.
11
+ * A transporter configured with a minimum level will only process
12
+ * messages at or above that severity.
13
+ *
14
+ * @module enums/log-level
15
+ */
16
+ declare enum LogLevel {
17
+ /**
18
+ * Detailed debug information.
19
+ * Use for development-time diagnostics that should not appear in production.
20
+ */
21
+ Debug = 0,
22
+ /**
23
+ * Interesting events.
24
+ * Example: User logs in, feature flag evaluated, route navigated.
25
+ */
26
+ Info = 1,
27
+ /**
28
+ * Exceptional occurrences that are not errors.
29
+ * Example: Use of deprecated APIs, poor use of an API, recoverable issues.
30
+ */
31
+ Warn = 2,
32
+ /**
33
+ * Runtime errors that do not require immediate action but should
34
+ * typically be logged and monitored.
35
+ */
36
+ Error = 3,
37
+ /**
38
+ * System is unusable or a critical failure has occurred.
39
+ * Example: Unrecoverable state, data corruption detected.
40
+ */
41
+ Fatal = 4
42
+ }
43
+
44
+ /**
45
+ * Log Entry Interface
46
+ *
47
+ * Represents a single log message with all associated metadata.
48
+ * This is the core data structure that flows through formatters
49
+ * and transporters. Every log call produces one LogEntry.
50
+ *
51
+ * @module interfaces/log-entry
52
+ */
53
+
54
+ interface LogEntry {
55
+ /**
56
+ * The severity level of this log entry.
57
+ * Determines how the message is displayed and whether it passes
58
+ * the transporter's minimum level filter.
59
+ */
60
+ level: LogLevel;
61
+ /**
62
+ * The human-readable log message.
63
+ * May contain interpolation placeholders depending on the formatter.
64
+ */
65
+ message: string;
66
+ /**
67
+ * ISO 8601 timestamp of when the log entry was created.
68
+ * Automatically set by the Logger at the time of the log call.
69
+ *
70
+ * @example "2026-03-28T14:30:00.000Z"
71
+ */
72
+ timestamp: string;
73
+ /**
74
+ * Contextual data attached to this log entry.
75
+ * Merged from the logger's shared context and any per-call context.
76
+ * Useful for structured logging (e.g., user ID, request ID, component name).
77
+ */
78
+ context: Record<string, unknown>;
79
+ }
80
+
81
+ /**
82
+ * Formatter Interface
83
+ *
84
+ * Defines the contract for log message formatters. A formatter is
85
+ * responsible for converting a LogEntry into a presentable string
86
+ * (or structured output) before it is handed to a transporter.
87
+ *
88
+ * Inspired by Monolog's FormatterInterface / Laravel's log formatting,
89
+ * adapted for lightweight client-side usage.
90
+ *
91
+ * @module interfaces/formatter
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * class MyFormatter implements FormatterInterface {
96
+ * format(entry: LogEntry): string {
97
+ * return `[${entry.level}] ${entry.message}`;
98
+ * }
99
+ * }
100
+ * ```
101
+ */
102
+
103
+ interface FormatterInterface {
104
+ /**
105
+ * Format a log entry into a string representation.
106
+ *
107
+ * @param entry - The log entry to format.
108
+ * @returns The formatted string ready for output.
109
+ */
110
+ format(entry: LogEntry): string;
111
+ }
112
+
113
+ /**
114
+ * Transporter Interface
115
+ *
116
+ * Defines the contract for log transporters (also known as handlers
117
+ * or channels in other frameworks). A transporter receives formatted
118
+ * log entries and delivers them to a specific destination — such as
119
+ * the browser console, localStorage, or a remote endpoint.
120
+ *
121
+ * Inspired by Laravel's channel/handler pattern and Monolog's
122
+ * HandlerInterface, simplified for client-side environments.
123
+ *
124
+ * @module interfaces/transporter
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * class MyTransporter implements TransporterInterface {
129
+ * private formatter: FormatterInterface = new SimpleFormatter();
130
+ *
131
+ * transport(entry: LogEntry): void {
132
+ * const output = this.formatter.format(entry);
133
+ * // deliver output to destination
134
+ * }
135
+ *
136
+ * setFormatter(formatter: FormatterInterface): void {
137
+ * this.formatter = formatter;
138
+ * }
139
+ *
140
+ * getFormatter(): FormatterInterface {
141
+ * return this.formatter;
142
+ * }
143
+ * }
144
+ * ```
145
+ */
146
+
147
+ interface TransporterInterface {
148
+ /**
149
+ * Deliver a log entry to the transport destination.
150
+ * The transporter should use its assigned formatter to convert the
151
+ * entry into the appropriate output format before delivery.
152
+ *
153
+ * @param entry - The log entry to transport.
154
+ */
155
+ transport(entry: LogEntry): void;
156
+ /**
157
+ * Replace the current formatter with a new one.
158
+ *
159
+ * @param formatter - The formatter instance to use for future entries.
160
+ */
161
+ setFormatter(formatter: FormatterInterface): void;
162
+ /**
163
+ * Retrieve the currently assigned formatter.
164
+ *
165
+ * @returns The active formatter instance.
166
+ */
167
+ getFormatter(): FormatterInterface;
168
+ /**
169
+ * Get the minimum log level this transporter will handle.
170
+ * Entries below this level should be silently ignored.
171
+ *
172
+ * @returns The minimum LogLevel threshold.
173
+ */
174
+ getLevel(): LogLevel;
175
+ /**
176
+ * Set the minimum log level this transporter will handle.
177
+ *
178
+ * @param level - The minimum LogLevel threshold.
179
+ */
180
+ setLevel(level: LogLevel): void;
181
+ }
182
+
183
+ /**
184
+ * Logger Interface
185
+ *
186
+ * Defines the public contract for the Logger. Consumers should
187
+ * depend on this interface rather than the concrete Logger class
188
+ * to enable easy testing and substitution.
189
+ *
190
+ * Follows PSR-3 / Laravel conventions with log level methods,
191
+ * contextual logging (withContext / withoutContext), and
192
+ * transporter management.
193
+ *
194
+ * @module interfaces/logger
195
+ */
196
+
197
+ interface LoggerInterface {
198
+ /**
199
+ * Log a message at the debug level.
200
+ *
201
+ * @param message - The log message.
202
+ * @param context - Optional contextual data for this single entry.
203
+ */
204
+ debug(message: string, context?: Record<string, unknown>): void;
205
+ /**
206
+ * Log a message at the info level.
207
+ *
208
+ * @param message - The log message.
209
+ * @param context - Optional contextual data for this single entry.
210
+ */
211
+ info(message: string, context?: Record<string, unknown>): void;
212
+ /**
213
+ * Log a message at the warn level.
214
+ *
215
+ * @param message - The log message.
216
+ * @param context - Optional contextual data for this single entry.
217
+ */
218
+ warn(message: string, context?: Record<string, unknown>): void;
219
+ /**
220
+ * Log a message at the error level.
221
+ *
222
+ * @param message - The log message.
223
+ * @param context - Optional contextual data for this single entry.
224
+ */
225
+ error(message: string, context?: Record<string, unknown>): void;
226
+ /**
227
+ * Log a message at the fatal level.
228
+ *
229
+ * @param message - The log message.
230
+ * @param context - Optional contextual data for this single entry.
231
+ */
232
+ fatal(message: string, context?: Record<string, unknown>): void;
233
+ /**
234
+ * Add persistent context that will be merged into every future log entry.
235
+ * Calling this multiple times merges new keys into the existing context.
236
+ *
237
+ * Inspired by Laravel's `Logger::withContext()`.
238
+ *
239
+ * @param context - Key-value pairs to add to the shared context.
240
+ * @returns The logger instance for fluent chaining.
241
+ */
242
+ withContext(context: Record<string, unknown>): this;
243
+ /**
244
+ * Remove keys from the shared context, or clear it entirely.
245
+ *
246
+ * When called with an array of keys, only those keys are removed.
247
+ * When called without arguments, the entire shared context is flushed.
248
+ *
249
+ * Inspired by Laravel's `Logger::withoutContext()`.
250
+ *
251
+ * @param keys - Optional array of context keys to remove.
252
+ * @returns The logger instance for fluent chaining.
253
+ */
254
+ withoutContext(keys?: string[]): this;
255
+ /**
256
+ * Retrieve all currently registered transporters.
257
+ *
258
+ * @returns An array of active transporter instances.
259
+ */
260
+ getTransporters(): TransporterInterface[];
261
+ }
262
+
263
+ /**
264
+ * Logger Configuration Interface
265
+ *
266
+ * Defines the shape of configuration options accepted by the Logger
267
+ * constructor and the LoggerManager. Provides sensible defaults so
268
+ * consumers can create a logger with zero configuration.
269
+ *
270
+ * @module interfaces/logger-config
271
+ *
272
+ * @example
273
+ * ```ts
274
+ * const config: LoggerConfig = {
275
+ * transporters: [new ConsoleTransporter()],
276
+ * context: { app: 'my-app' },
277
+ * };
278
+ * const logger = new Logger(config);
279
+ * ```
280
+ */
281
+
282
+ interface LoggerConfig {
283
+ /**
284
+ * The list of transporters that will receive log entries.
285
+ * If omitted, the logger will default to a single ConsoleTransporter.
286
+ */
287
+ transporters?: TransporterInterface[];
288
+ /**
289
+ * Initial shared context that will be merged into every log entry.
290
+ * Useful for setting application-wide metadata such as app name,
291
+ * environment, or version.
292
+ *
293
+ * @default {}
294
+ */
295
+ context?: Record<string, unknown>;
296
+ }
297
+
298
+ /**
299
+ * Logger Service Interface
300
+ *
301
+ * Defines the contract for logger service implementations.
302
+ * Manages multiple logging channels.
303
+ */
304
+ interface LoggerServiceInterface {
305
+ /**
306
+ * Get a logger channel by name
307
+ *
308
+ * @param channelName - Channel name (uses default if not specified)
309
+ * @returns Logger instance
310
+ */
311
+ channel(channelName?: string): LoggerInterface;
312
+ /**
313
+ * Get the default channel name
314
+ *
315
+ * @returns Default channel name
316
+ */
317
+ getDefaultChannelName(): string;
318
+ /**
319
+ * Get all configured channel names
320
+ *
321
+ * @returns Array of channel names
322
+ */
323
+ getChannelNames(): string[];
324
+ /**
325
+ * Check if a channel exists
326
+ *
327
+ * @param channelName - Channel name
328
+ * @returns True if channel exists
329
+ */
330
+ hasChannel(channelName: string): boolean;
331
+ /**
332
+ * Log a debug message to default channel
333
+ */
334
+ debug(message: string, context?: Record<string, unknown>): void;
335
+ /**
336
+ * Log an info message to default channel
337
+ */
338
+ info(message: string, context?: Record<string, unknown>): void;
339
+ /**
340
+ * Log a warning message to default channel
341
+ */
342
+ warn(message: string, context?: Record<string, unknown>): void;
343
+ /**
344
+ * Log an error message to default channel
345
+ */
346
+ error(message: string, context?: Record<string, unknown>): void;
347
+ }
348
+
349
+ /**
350
+ * Logger Module Configuration
351
+ *
352
+ * Defines the configuration interface for the logger module.
353
+ * Supports multiple channels with different transporters and settings.
354
+ *
355
+ * @module config/logger
356
+ */
357
+
358
+ /**
359
+ * Logger module options
360
+ *
361
+ * Configuration for the logger module with support for multiple channels.
362
+ * Each channel can have its own transporters, context, and settings.
363
+ *
364
+ * @example
365
+ * ```typescript
366
+ * const config: LoggerModuleOptions = {
367
+ * default: 'console',
368
+ * channels: {
369
+ * console: {
370
+ * transporters: [new ConsoleTransporter()],
371
+ * context: { app: 'my-app' },
372
+ * },
373
+ * storage: {
374
+ * transporters: [new StorageTransporter()],
375
+ * },
376
+ * errors: {
377
+ * transporters: [
378
+ * new ConsoleTransporter({ level: LogLevel.ERROR }),
379
+ * new StorageTransporter({ key: 'error-logs' }),
380
+ * ],
381
+ * },
382
+ * },
383
+ * };
384
+ * ```
385
+ */
386
+ interface LoggerModuleOptions {
387
+ /**
388
+ * Default channel name
389
+ *
390
+ * The channel to use when no specific channel is requested.
391
+ * Must match one of the keys in the channels object.
392
+ */
393
+ default: string;
394
+ /**
395
+ * Channel configurations
396
+ *
397
+ * Map of channel names to their configurations.
398
+ * Each channel can have its own transporters and settings.
399
+ */
400
+ channels: Record<string, LoggerConfig>;
401
+ }
402
+ /**
403
+ * Helper function to define logger configuration with type safety
404
+ *
405
+ * @param config - Logger module options
406
+ * @returns The same config with proper typing
407
+ *
408
+ * @example
409
+ * ```typescript
410
+ * import { defineConfig } from '@abdokouta/logger';
411
+ *
412
+ * const config = defineConfig({
413
+ * default: 'console',
414
+ * channels: {
415
+ * console: {
416
+ * transporters: [new ConsoleTransporter()],
417
+ * },
418
+ * },
419
+ * });
420
+ * ```
421
+ */
422
+ declare function defineConfig(config: LoggerModuleOptions): LoggerModuleOptions;
423
+
424
+ /**
425
+ * Logger service implementation
426
+ *
427
+ * Provides a unified logging API with support for multiple channels.
428
+ * Handles channel management internally without a separate manager class.
429
+ *
430
+ * @example
431
+ * ```typescript
432
+ * @Injectable()
433
+ * class UserService {
434
+ * constructor(
435
+ * @Inject(LoggerService) private logger: LoggerService
436
+ * ) {}
437
+ *
438
+ * async createUser(data: UserData) {
439
+ * // Use default channel
440
+ * this.logger.info('Creating user', { email: data.email });
441
+ *
442
+ * try {
443
+ * const user = await this.db.users.create(data);
444
+ * this.logger.info('User created', { userId: user.id });
445
+ * return user;
446
+ * } catch (error) {
447
+ * this.logger.error('Failed to create user', { error });
448
+ * throw error;
449
+ * }
450
+ * }
451
+ *
452
+ * async auditAction(action: string) {
453
+ * // Use specific channel
454
+ * const auditLogger = this.logger.channel('audit');
455
+ * auditLogger.info('User action', { action });
456
+ * }
457
+ * }
458
+ * ```
459
+ */
460
+ declare class LoggerService implements LoggerServiceInterface {
461
+ /** Logger configuration */
462
+ private readonly config;
463
+ /** Cached channel instances */
464
+ private channels;
465
+ /** Default channel instance */
466
+ private defaultChannel?;
467
+ /**
468
+ * Create a new logger service
469
+ *
470
+ * @param config - Logger configuration
471
+ */
472
+ constructor(config: LoggerModuleOptions);
473
+ /**
474
+ * Get a logger channel instance
475
+ *
476
+ * Returns the specified channel, or the default channel if no name is provided.
477
+ * Channels are lazily initialized and cached.
478
+ *
479
+ * @param name - Channel name (uses default if not specified)
480
+ * @returns Logger instance
481
+ * @throws Error if channel is not configured
482
+ *
483
+ * @example
484
+ * ```typescript
485
+ * // Use default channel
486
+ * const logger = loggerService.channel();
487
+ * logger.info('Default message');
488
+ *
489
+ * // Use specific channel
490
+ * const errorLogger = loggerService.channel('errors');
491
+ * errorLogger.error('Critical error');
492
+ * ```
493
+ */
494
+ channel(name?: string): LoggerInterface;
495
+ /**
496
+ * Log a message at the debug level (default channel)
497
+ *
498
+ * @param message - The log message
499
+ * @param context - Optional contextual data
500
+ *
501
+ * @example
502
+ * ```typescript
503
+ * loggerService.debug('Cache hit', { key: 'user:123' });
504
+ * ```
505
+ */
506
+ debug(message: string, context?: Record<string, unknown>): void;
507
+ /**
508
+ * Log a message at the info level (default channel)
509
+ *
510
+ * @param message - The log message
511
+ * @param context - Optional contextual data
512
+ *
513
+ * @example
514
+ * ```typescript
515
+ * loggerService.info('User logged in', { userId: '123' });
516
+ * ```
517
+ */
518
+ info(message: string, context?: Record<string, unknown>): void;
519
+ /**
520
+ * Log a message at the warn level (default channel)
521
+ *
522
+ * @param message - The log message
523
+ * @param context - Optional contextual data
524
+ *
525
+ * @example
526
+ * ```typescript
527
+ * loggerService.warn('API rate limit approaching', { remaining: 10 });
528
+ * ```
529
+ */
530
+ warn(message: string, context?: Record<string, unknown>): void;
531
+ /**
532
+ * Log a message at the error level (default channel)
533
+ *
534
+ * @param message - The log message
535
+ * @param context - Optional contextual data
536
+ *
537
+ * @example
538
+ * ```typescript
539
+ * loggerService.error('Database connection failed', { error });
540
+ * ```
541
+ */
542
+ error(message: string, context?: Record<string, unknown>): void;
543
+ /**
544
+ * Log a message at the fatal level (default channel)
545
+ *
546
+ * @param message - The log message
547
+ * @param context - Optional contextual data
548
+ *
549
+ * @example
550
+ * ```typescript
551
+ * loggerService.fatal('Application crashed', { error, stack });
552
+ * ```
553
+ */
554
+ fatal(message: string, context?: Record<string, unknown>): void;
555
+ /**
556
+ * Add persistent context to the default channel
557
+ *
558
+ * @param context - Key-value pairs to add to the shared context
559
+ * @returns The logger service instance for fluent chaining
560
+ *
561
+ * @example
562
+ * ```typescript
563
+ * loggerService
564
+ * .withContext({ requestId: 'abc-123' })
565
+ * .withContext({ userId: 42 })
566
+ * .info('Processing request');
567
+ * ```
568
+ */
569
+ withContext(context: Record<string, unknown>): this;
570
+ /**
571
+ * Remove keys from the default channel's shared context
572
+ *
573
+ * @param keys - Optional array of context keys to remove
574
+ * @returns The logger service instance for fluent chaining
575
+ *
576
+ * @example
577
+ * ```typescript
578
+ * // Remove specific keys
579
+ * loggerService.withoutContext(['userId', 'requestId']);
580
+ *
581
+ * // Clear all context
582
+ * loggerService.withoutContext();
583
+ * ```
584
+ */
585
+ withoutContext(keys?: string[]): this;
586
+ /**
587
+ * Get all transporters from the default channel
588
+ *
589
+ * @returns Array of transporter instances
590
+ */
591
+ getTransporters(): TransporterInterface[];
592
+ /**
593
+ * Get the default channel name
594
+ *
595
+ * @returns Default channel name
596
+ */
597
+ getDefaultChannelName(): string;
598
+ /**
599
+ * Get all configured channel names
600
+ *
601
+ * @returns Array of channel names
602
+ */
603
+ getChannelNames(): string[];
604
+ /**
605
+ * Check if a channel is configured
606
+ *
607
+ * @param name - Channel name
608
+ * @returns True if the channel is configured
609
+ */
610
+ hasChannel(name: string): boolean;
611
+ /**
612
+ * Check if a channel is currently active (cached)
613
+ *
614
+ * @param name - Channel name (uses default if not specified)
615
+ * @returns True if the channel is active
616
+ */
617
+ isChannelActive(name?: string): boolean;
618
+ /**
619
+ * Get the default channel instance
620
+ *
621
+ * @returns Logger instance
622
+ * @throws Error if default channel cannot be resolved
623
+ * @private
624
+ */
625
+ private getDefaultChannel;
626
+ /**
627
+ * Resolve a channel by name
628
+ *
629
+ * Creates a new logger instance based on channel configuration.
630
+ *
631
+ * @param name - Channel name
632
+ * @returns Logger instance
633
+ * @throws Error if channel is not configured
634
+ * @private
635
+ */
636
+ private resolve;
637
+ }
638
+
639
+ /**
640
+ * Logger Module
641
+ *
642
+ * Configures the logger system for dependency injection.
643
+ * Provides LoggerService (NO manager) to the application.
644
+ *
645
+ * @module logger.module
646
+ */
647
+
648
+ /**
649
+ * Logger module
650
+ *
651
+ * Provides LoggerService to the application via dependency injection.
652
+ * The service handles channels internally (NO separate manager).
653
+ *
654
+ * @example
655
+ * ```typescript
656
+ * import { Module } from '@abdokouta/react-di';
657
+ * import { LoggerModule, defineConfig } from '@abdokouta/logger';
658
+ * import { ConsoleTransporter, StorageTransporter } from '@abdokouta/logger';
659
+ * import { LogLevel } from '@abdokouta/logger';
660
+ *
661
+ * @Module({
662
+ * imports: [
663
+ * LoggerModule.forRoot(
664
+ * defineConfig({
665
+ * default: 'console',
666
+ * channels: {
667
+ * console: {
668
+ * transporters: [new ConsoleTransporter()],
669
+ * context: { app: 'my-app' },
670
+ * },
671
+ * storage: {
672
+ * transporters: [new StorageTransporter({ maxEntries: 500 })],
673
+ * },
674
+ * errors: {
675
+ * transporters: [
676
+ * new ConsoleTransporter({ level: LogLevel.Error }),
677
+ * new StorageTransporter({ key: 'error-logs' }),
678
+ * ],
679
+ * },
680
+ * },
681
+ * })
682
+ * ),
683
+ * ],
684
+ * })
685
+ * export class AppModule {}
686
+ * ```
687
+ *
688
+ * @example
689
+ * ```typescript
690
+ * // Using logger in a service
691
+ * import { Injectable, Inject } from '@abdokouta/react-di';
692
+ * import { LoggerService } from '@abdokouta/logger';
693
+ *
694
+ * @Injectable()
695
+ * export class UserService {
696
+ * constructor(
697
+ * @Inject(LoggerService) private logger: LoggerService
698
+ * ) {}
699
+ *
700
+ * async createUser(data: UserData) {
701
+ * this.logger.info('Creating user', { email: data.email });
702
+ *
703
+ * try {
704
+ * const user = await this.db.users.create(data);
705
+ * this.logger.info('User created', { userId: user.id });
706
+ * return user;
707
+ * } catch (error) {
708
+ * this.logger.error('Failed to create user', { error });
709
+ * throw error;
710
+ * }
711
+ * }
712
+ *
713
+ * async auditAction(action: string) {
714
+ * // Use specific channel
715
+ * const auditLogger = this.logger.channel('audit');
716
+ * auditLogger.info('User action', { action });
717
+ * }
718
+ * }
719
+ * ```
720
+ */
721
+ declare class LoggerModule {
722
+ /**
723
+ * Configure the logger module
724
+ *
725
+ * @param config - Logger configuration (can be passed directly without defineConfig)
726
+ * @returns Dynamic module
727
+ *
728
+ * @example
729
+ * ```typescript
730
+ * LoggerModule.forRoot({
731
+ * default: 'console',
732
+ * channels: {
733
+ * console: {
734
+ * transporters: [new ConsoleTransporter()],
735
+ * },
736
+ * },
737
+ * })
738
+ * ```
739
+ */
740
+ static forRoot(config: LoggerModuleOptions): DynamicModule;
741
+ /**
742
+ * Process configuration to add default transporters if needed
743
+ *
744
+ * @param config - Raw configuration
745
+ * @returns Processed configuration with defaults
746
+ * @private
747
+ */
748
+ private static processConfig;
749
+ }
750
+
751
+ /**
752
+ * Pretty Formatter
753
+ *
754
+ * A visually rich formatter that produces colorful, emoji-prefixed
755
+ * log output designed for the browser console. Each log level is
756
+ * assigned a distinct emoji and CSS color to make scanning logs
757
+ * effortless during development.
758
+ *
759
+ * This is the default formatter used by the ConsoleTransporter.
760
+ *
761
+ * @module formatters/pretty
762
+ *
763
+ * @example
764
+ * ```ts
765
+ * const formatter = new PrettyFormatter();
766
+ * const output = formatter.format(entry);
767
+ * // => "🐛 [DEBUG] [14:30:00.000] Hello world {userId: 42}"
768
+ * ```
769
+ */
770
+
771
+ declare class PrettyFormatter implements FormatterInterface {
772
+ /**
773
+ * Format a log entry into a pretty, human-readable string with
774
+ * emoji prefix, level badge, timestamp, message, and context.
775
+ *
776
+ * The returned string includes `%c` placeholders for CSS styling
777
+ * in the browser console. The ConsoleTransporter is responsible
778
+ * for passing the corresponding style strings.
779
+ *
780
+ * @param entry - The log entry to format.
781
+ * @returns The formatted string with CSS style placeholders.
782
+ */
783
+ format(entry: LogEntry): string;
784
+ /**
785
+ * Extract a short time string (HH:mm:ss.SSS) from an ISO timestamp.
786
+ *
787
+ * @param timestamp - ISO 8601 timestamp string.
788
+ * @returns A short time-only representation.
789
+ */
790
+ private formatTimestamp;
791
+ /**
792
+ * Serialize context data into a compact, readable string.
793
+ * Returns an empty string when context is empty to keep output clean.
794
+ *
795
+ * @param context - The context record to serialize.
796
+ * @returns A formatted context string or empty string.
797
+ */
798
+ private formatContext;
799
+ }
800
+
801
+ declare class JsonFormatter implements FormatterInterface {
802
+ /**
803
+ * Format a log entry as a JSON string.
804
+ *
805
+ * Produces a flat JSON object with level (as string), message,
806
+ * timestamp, and context fields. Context is omitted when empty
807
+ * to keep output compact.
808
+ *
809
+ * @param entry - The log entry to format.
810
+ * @returns A JSON-serialized string representation of the entry.
811
+ */
812
+ format(entry: LogEntry): string;
813
+ }
814
+
815
+ declare class SimpleFormatter implements FormatterInterface {
816
+ /**
817
+ * Format a log entry into a plain text line.
818
+ *
819
+ * Output pattern: `[LEVEL] [timestamp] message {context}`
820
+ *
821
+ * @param entry - The log entry to format.
822
+ * @returns A plain text string with no styling.
823
+ */
824
+ format(entry: LogEntry): string;
825
+ /**
826
+ * Serialize context data into a compact string.
827
+ * Returns an empty string when context is empty.
828
+ *
829
+ * @param context - The context record to serialize.
830
+ * @returns A formatted context string or empty string.
831
+ */
832
+ private formatContext;
833
+ }
834
+
835
+ /**
836
+ * Console Transporter
837
+ *
838
+ * Delivers log entries to the browser's developer console using the
839
+ * appropriate `console.*` method for each severity level. When paired
840
+ * with the PrettyFormatter (the default), output includes CSS-styled
841
+ * level badges with colors and emoji prefixes.
842
+ *
843
+ * This is the primary transporter for development environments.
844
+ *
845
+ * @module transporters/console
846
+ *
847
+ * @example
848
+ * ```ts
849
+ * const transporter = new ConsoleTransporter();
850
+ * transporter.transport(entry); // outputs to console with colors
851
+ *
852
+ * // With custom minimum level:
853
+ * const warnOnly = new ConsoleTransporter({ level: LogLevel.Warn });
854
+ * ```
855
+ */
856
+
857
+ /**
858
+ * Configuration options for the ConsoleTransporter.
859
+ */
860
+ interface ConsoleTransporterOptions {
861
+ /**
862
+ * The formatter to use for log entries.
863
+ * Defaults to PrettyFormatter if not provided.
864
+ */
865
+ formatter?: FormatterInterface;
866
+ /**
867
+ * The minimum log level to transport.
868
+ * Entries below this level are silently ignored.
869
+ *
870
+ * @default LogLevel.Debug
871
+ */
872
+ level?: LogLevel;
873
+ }
874
+ declare class ConsoleTransporter implements TransporterInterface {
875
+ /**
876
+ The formatter used to convert log entries into output strings. */
877
+ private _formatter;
878
+ /**
879
+ The minimum log level threshold for this transporter. */
880
+ private _level;
881
+ /**
882
+ * Create a new ConsoleTransporter instance.
883
+ *
884
+ * @param options - Optional configuration for formatter and minimum level.
885
+ */
886
+ constructor(options?: ConsoleTransporterOptions);
887
+ /**
888
+ * Deliver a log entry to the browser console.
889
+ *
890
+ * Routes the entry to the appropriate `console.*` method based on
891
+ * the log level. When using the PrettyFormatter, CSS styles are
892
+ * applied via `%c` placeholders for colored output.
893
+ *
894
+ * Entries below the configured minimum level are silently skipped.
895
+ *
896
+ * @param entry - The log entry to output.
897
+ */
898
+ transport(entry: LogEntry): void;
899
+ /**
900
+ * Replace the current formatter.
901
+ *
902
+ * @param formatter - The new formatter instance to use.
903
+ */
904
+ setFormatter(formatter: FormatterInterface): void;
905
+ /**
906
+ * Retrieve the currently assigned formatter.
907
+ *
908
+ * @returns The active formatter instance.
909
+ */
910
+ getFormatter(): FormatterInterface;
911
+ /**
912
+ * Get the minimum log level this transporter handles.
913
+ *
914
+ * @returns The current minimum LogLevel threshold.
915
+ */
916
+ getLevel(): LogLevel;
917
+ /**
918
+ * Set the minimum log level this transporter handles.
919
+ *
920
+ * @param level - The new minimum LogLevel threshold.
921
+ */
922
+ setLevel(level: LogLevel): void;
923
+ /**
924
+ * Resolve the appropriate `console.*` method for a given log level.
925
+ *
926
+ * Maps logger severity levels to the closest browser console method
927
+ * to ensure proper DevTools filtering and visual distinction.
928
+ *
929
+ * @param level - The log level to resolve.
930
+ * @returns The bound console method function.
931
+ */
932
+ private resolveConsoleMethod;
933
+ }
934
+
935
+ /**
936
+ * Silent Transporter
937
+ *
938
+ * A no-op transporter that silently discards all log entries.
939
+ * Useful for production environments where logging should be
940
+ * disabled, or for testing scenarios where log output would
941
+ * pollute test results.
942
+ *
943
+ * Equivalent to Laravel's "null" log driver.
944
+ *
945
+ * @module transporters/silent
946
+ *
947
+ * @example
948
+ * ```ts
949
+ * const logger = new Logger({
950
+ * transporters: [new SilentTransporter()],
951
+ * });
952
+ * logger.info('This will be silently discarded');
953
+ * ```
954
+ */
955
+
956
+ declare class SilentTransporter implements TransporterInterface {
957
+ /**
958
+ The formatter instance (maintained for interface compliance). */
959
+ private _formatter;
960
+ /**
961
+ The minimum log level (maintained for interface compliance). */
962
+ private _level;
963
+ /**
964
+ * Create a new SilentTransporter instance.
965
+ * All parameters are optional and exist only for interface compliance.
966
+ */
967
+ constructor();
968
+ /**
969
+ * No-op transport method. Silently discards the entry.
970
+ *
971
+ * @param _entry - The log entry (ignored).
972
+ */
973
+ transport(_entry: LogEntry): void;
974
+ /**
975
+ * Replace the current formatter.
976
+ *
977
+ * @param formatter - The new formatter instance.
978
+ */
979
+ setFormatter(formatter: FormatterInterface): void;
980
+ /**
981
+ * Retrieve the currently assigned formatter.
982
+ *
983
+ * @returns The active formatter instance.
984
+ */
985
+ getFormatter(): FormatterInterface;
986
+ /**
987
+ * Get the minimum log level.
988
+ *
989
+ * @returns The current minimum LogLevel threshold.
990
+ */
991
+ getLevel(): LogLevel;
992
+ /**
993
+ * Set the minimum log level.
994
+ *
995
+ * @param level - The new minimum LogLevel threshold.
996
+ */
997
+ setLevel(level: LogLevel): void;
998
+ }
999
+
1000
+ /**
1001
+ * Storage Transporter
1002
+ *
1003
+ * Persists log entries to the browser's localStorage as JSON strings.
1004
+ * Useful for capturing logs that survive page reloads, enabling
1005
+ * post-mortem debugging or user-submitted bug reports that include
1006
+ * recent log history.
1007
+ *
1008
+ * Entries are stored as a JSON array under a configurable storage key.
1009
+ * A maximum entry limit prevents unbounded storage growth.
1010
+ *
1011
+ * @module transporters/storage
1012
+ *
1013
+ * @example
1014
+ * ```ts
1015
+ * const transporter = new StorageTransporter({
1016
+ * key: 'app-logs',
1017
+ * maxEntries: 200,
1018
+ * });
1019
+ * ```
1020
+ */
1021
+
1022
+ /**
1023
+ * Configuration options for the StorageTransporter.
1024
+ */
1025
+ interface StorageTransporterOptions {
1026
+ /**
1027
+ * The localStorage key under which log entries are stored.
1028
+ *
1029
+ * @default "logger:entries"
1030
+ */
1031
+ key?: string;
1032
+ /**
1033
+ * Maximum number of entries to retain in storage.
1034
+ * When the limit is exceeded, the oldest entries are discarded (FIFO).
1035
+ *
1036
+ * @default 100
1037
+ */
1038
+ maxEntries?: number;
1039
+ /**
1040
+ * The formatter to use for serializing log entries.
1041
+ * Defaults to JsonFormatter if not provided.
1042
+ */
1043
+ formatter?: FormatterInterface;
1044
+ /**
1045
+ * The minimum log level to transport.
1046
+ * Entries below this level are silently ignored.
1047
+ *
1048
+ * @default LogLevel.Debug
1049
+ */
1050
+ level?: LogLevel;
1051
+ }
1052
+ declare class StorageTransporter implements TransporterInterface {
1053
+ /**
1054
+ The formatter used to convert log entries into storable strings. */
1055
+ private _formatter;
1056
+ /**
1057
+ The minimum log level threshold for this transporter. */
1058
+ private _level;
1059
+ /**
1060
+ The localStorage key for persisting entries. */
1061
+ private readonly _key;
1062
+ /**
1063
+ Maximum number of entries to retain. */
1064
+ private readonly _maxEntries;
1065
+ /**
1066
+ * Create a new StorageTransporter instance.
1067
+ *
1068
+ * @param options - Optional configuration for storage key, limits, and formatter.
1069
+ */
1070
+ constructor(options?: StorageTransporterOptions);
1071
+ /**
1072
+ * Persist a log entry to localStorage.
1073
+ *
1074
+ * The entry is formatted, appended to the existing entries array,
1075
+ * and trimmed to the maximum entry limit. If localStorage is
1076
+ * unavailable or full, the error is silently swallowed to avoid
1077
+ * crashing the application.
1078
+ *
1079
+ * @param entry - The log entry to persist.
1080
+ */
1081
+ transport(entry: LogEntry): void;
1082
+ /**
1083
+ * Replace the current formatter.
1084
+ *
1085
+ * @param formatter - The new formatter instance.
1086
+ */
1087
+ setFormatter(formatter: FormatterInterface): void;
1088
+ /**
1089
+ * Retrieve the currently assigned formatter.
1090
+ *
1091
+ * @returns The active formatter instance.
1092
+ */
1093
+ getFormatter(): FormatterInterface;
1094
+ /**
1095
+ * Get the minimum log level this transporter handles.
1096
+ *
1097
+ * @returns The current minimum LogLevel threshold.
1098
+ */
1099
+ getLevel(): LogLevel;
1100
+ /**
1101
+ * Set the minimum log level this transporter handles.
1102
+ *
1103
+ * @param level - The new minimum LogLevel threshold.
1104
+ */
1105
+ setLevel(level: LogLevel): void;
1106
+ /**
1107
+ * Clear all stored log entries from localStorage.
1108
+ * Useful for manual cleanup or when resetting application state.
1109
+ */
1110
+ clear(): void;
1111
+ /**
1112
+ * Retrieve all stored log entries from localStorage.
1113
+ *
1114
+ * @returns An array of formatted log entry strings.
1115
+ */
1116
+ getEntries(): string[];
1117
+ /**
1118
+ * Read the current entries array from localStorage.
1119
+ * Returns an empty array if the key does not exist or parsing fails.
1120
+ *
1121
+ * @returns The parsed entries array.
1122
+ */
1123
+ private readEntries;
1124
+ }
1125
+
1126
+ /**
1127
+ * useLogger Hook
1128
+ *
1129
+ * React hook for accessing the logger service in components.
1130
+ * Provides access to the default channel or a specific channel.
1131
+ *
1132
+ * @module hooks/use-logger
1133
+ */
1134
+
1135
+ /**
1136
+ * Access the logger service in React components
1137
+ *
1138
+ * Returns the logger service instance or a specific channel.
1139
+ *
1140
+ * @param channelName - Optional channel name (uses default if not specified)
1141
+ * @returns Logger instance
1142
+ *
1143
+ * @example
1144
+ * ```typescript
1145
+ * import { useLogger } from '@abdokouta/logger';
1146
+ *
1147
+ * function MyComponent() {
1148
+ * const logger = useLogger();
1149
+ *
1150
+ * const handleClick = () => {
1151
+ * logger.info('Button clicked', { timestamp: Date.now() });
1152
+ * };
1153
+ *
1154
+ * return <button onClick={handleClick}>Click me</button>;
1155
+ * }
1156
+ * ```
1157
+ *
1158
+ * @example
1159
+ * ```typescript
1160
+ * // Use specific channel
1161
+ * function ErrorBoundary({ error }: { error: Error }) {
1162
+ * const errorLogger = useLogger('errors');
1163
+ *
1164
+ * useEffect(() => {
1165
+ * errorLogger.error('Component error', {
1166
+ * message: error.message,
1167
+ * stack: error.stack,
1168
+ * });
1169
+ * }, [error]);
1170
+ *
1171
+ * return <div>Something went wrong</div>;
1172
+ * }
1173
+ * ```
1174
+ */
1175
+ declare function useLogger(channelName?: string): LoggerInterface;
1176
+
1177
+ /**
1178
+ * useLoggerContext Hook
1179
+ *
1180
+ * React hook for managing logger context in components.
1181
+ * Automatically adds and removes context based on component lifecycle.
1182
+ *
1183
+ * @module hooks/use-logger-context
1184
+ */
1185
+ /**
1186
+ * Manage logger context in React components
1187
+ *
1188
+ * Automatically adds context when the component mounts and removes it when unmounted.
1189
+ * Useful for adding component-specific context to all logs.
1190
+ *
1191
+ * @param context - Context to add to the logger
1192
+ * @param channelName - Optional channel name (uses default if not specified)
1193
+ *
1194
+ * @example
1195
+ * ```typescript
1196
+ * import { useLoggerContext } from '@abdokouta/logger';
1197
+ *
1198
+ * function UserProfile({ userId }: { userId: string }) {
1199
+ * // Add userId to all logs in this component
1200
+ * useLoggerContext({ userId, component: 'UserProfile' });
1201
+ *
1202
+ * const logger = useLogger();
1203
+ *
1204
+ * const handleUpdate = () => {
1205
+ * // This log will include { userId, component: 'UserProfile' }
1206
+ * logger.info('Updating profile');
1207
+ * };
1208
+ *
1209
+ * return <button onClick={handleUpdate}>Update</button>;
1210
+ * }
1211
+ * ```
1212
+ *
1213
+ * @example
1214
+ * ```typescript
1215
+ * // With specific channel
1216
+ * function PaymentForm({ orderId }: { orderId: string }) {
1217
+ * useLoggerContext({ orderId, form: 'payment' }, 'payment');
1218
+ *
1219
+ * const logger = useLogger('payment');
1220
+ *
1221
+ * const handleSubmit = () => {
1222
+ * logger.info('Payment submitted');
1223
+ * };
1224
+ *
1225
+ * return <form onSubmit={handleSubmit}>...</form>;
1226
+ * }
1227
+ * ```
1228
+ */
1229
+ declare function useLoggerContext(context: Record<string, unknown>, channelName?: string): void;
1230
+
1231
+ export { ConsoleTransporter, type ConsoleTransporterOptions, type FormatterInterface, JsonFormatter, type LogEntry, LogLevel, LoggerService as Logger, type LoggerConfig, type LoggerInterface, LoggerModule, type LoggerModuleOptions, LoggerService, type LoggerServiceInterface, PrettyFormatter, SilentTransporter, SimpleFormatter, StorageTransporter, type StorageTransporterOptions, type TransporterInterface, defineConfig, useLogger, useLoggerContext };