@wgtechlabs/log-engine 2.0.0 → 2.1.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.
Files changed (36) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +869 -608
  3. package/dist/formatter/data-formatter.d.ts +2 -1
  4. package/dist/formatter/data-formatter.d.ts.map +1 -1
  5. package/dist/formatter/data-formatter.js +1 -1
  6. package/dist/formatter/message-formatter.d.ts +23 -23
  7. package/dist/formatter/message-formatter.d.ts.map +1 -1
  8. package/dist/formatter/message-formatter.js +23 -23
  9. package/dist/formatter/timestamp.d.ts.map +1 -1
  10. package/dist/index.d.ts +130 -136
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +108 -108
  13. package/dist/logger/advanced-outputs.d.ts +159 -0
  14. package/dist/logger/advanced-outputs.d.ts.map +1 -0
  15. package/dist/logger/advanced-outputs.js +586 -0
  16. package/dist/logger/config.d.ts +18 -18
  17. package/dist/logger/config.d.ts.map +1 -1
  18. package/dist/logger/config.js +32 -29
  19. package/dist/logger/core.d.ts +128 -84
  20. package/dist/logger/core.d.ts.map +1 -1
  21. package/dist/logger/core.js +259 -74
  22. package/dist/logger/environment.d.ts +15 -15
  23. package/dist/logger/environment.d.ts.map +1 -1
  24. package/dist/logger/environment.js +15 -15
  25. package/dist/logger/filtering.d.ts +16 -16
  26. package/dist/logger/filtering.d.ts.map +1 -1
  27. package/dist/logger/filtering.js +37 -22
  28. package/dist/redaction/config.d.ts +8 -8
  29. package/dist/redaction/config.d.ts.map +1 -1
  30. package/dist/redaction/config.js +8 -8
  31. package/dist/redaction/redactor.d.ts +60 -60
  32. package/dist/redaction/redactor.d.ts.map +1 -1
  33. package/dist/redaction/redactor.js +101 -96
  34. package/dist/types/index.d.ts +98 -16
  35. package/dist/types/index.d.ts.map +1 -1
  36. package/package.json +80 -68
@@ -0,0 +1,586 @@
1
+ "use strict";
2
+ /**
3
+ * Advanced output handlers for log-engine
4
+ * Provides file, HTTP, and other production-ready output handlers
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.SAFE_BASE_DIRS = exports.HttpOutputHandler = exports.FileOutputHandler = void 0;
41
+ exports.createBuiltInHandler = createBuiltInHandler;
42
+ exports.secureExistsSync = secureExistsSync;
43
+ exports.secureMkdirSync = secureMkdirSync;
44
+ exports.secureStatSync = secureStatSync;
45
+ exports.secureWriteFileSync = secureWriteFileSync;
46
+ exports.secureUnlinkSync = secureUnlinkSync;
47
+ exports.secureRenameSync = secureRenameSync;
48
+ exports.validatePath = validatePath;
49
+ const fs = __importStar(require("fs"));
50
+ const path = __importStar(require("path"));
51
+ const os = __importStar(require("os"));
52
+ /**
53
+ * Secure filesystem operations for logging operations
54
+ *
55
+ * SECURITY NOTE: These functions implement comprehensive path validation and access controls
56
+ * to prevent path traversal attacks, directory injection, and unauthorized file access.
57
+ * ESLint security rules are disabled for specific fs operations because:
58
+ *
59
+ * 1. All paths are validated through validatePath() which:
60
+ * - Prevents directory traversal (../)
61
+ * - Restricts access to predefined safe directories
62
+ * - Blocks access to system directories
63
+ * - Normalizes and resolves paths securely
64
+ *
65
+ * 2. The logging library requires dynamic file paths by design (user-configurable log files)
66
+ * 3. All operations are wrapped in try-catch with comprehensive error handling
67
+ * 4. File operations are restricted to log and temp directories only
68
+ */
69
+ /**
70
+ * Predefined safe base directories for different operation types
71
+ * Restricted to specific subdirectories to prevent unauthorized access
72
+ */
73
+ const SAFE_BASE_DIRS = {
74
+ LOG_FILES: [path.resolve('./logs'), path.resolve('./var/log'), path.resolve('./data/logs')],
75
+ TEMP_FILES: [path.resolve('./temp'), path.resolve('./logs'), path.resolve('./tmp'), os.tmpdir()],
76
+ CONFIG_FILES: [path.resolve('./config'), path.resolve('./etc'), path.resolve('./logs')]
77
+ };
78
+ exports.SAFE_BASE_DIRS = SAFE_BASE_DIRS;
79
+ /**
80
+ * Validates file path with comprehensive security checks
81
+ * Prevents path traversal, restricts to safe directories, blocks system paths
82
+ */
83
+ function validatePath(filePath) {
84
+ if (!filePath || typeof filePath !== 'string') {
85
+ throw new Error('File path must be a non-empty string');
86
+ }
87
+ // Resolve and normalize the path to handle relative paths and traversal attempts
88
+ const resolvedPath = path.resolve(filePath);
89
+ const normalizedPath = path.normalize(resolvedPath);
90
+ // Check for path traversal attempts in original path - reject ANY use of '..'
91
+ if (filePath.includes('..')) {
92
+ throw new Error(`Path traversal detected: ${filePath}`);
93
+ }
94
+ // Ensure path is within safe directories (logs, current directory, or temp)
95
+ const safeBaseDirs = [
96
+ ...SAFE_BASE_DIRS.LOG_FILES,
97
+ ...SAFE_BASE_DIRS.TEMP_FILES,
98
+ ...SAFE_BASE_DIRS.CONFIG_FILES
99
+ ];
100
+ const isInSafeDir = safeBaseDirs.some(safeDir => normalizedPath.startsWith(safeDir));
101
+ if (!isInSafeDir) {
102
+ throw new Error(`File path outside allowed directories: ${filePath}`);
103
+ }
104
+ // Block access to dangerous system directories
105
+ const dangerousPaths = [
106
+ '/etc', '/sys', '/proc', '/dev', '/root', '/bin', '/sbin',
107
+ 'C:\\Windows', 'C:\\System32', 'C:\\Program Files', 'C:\\Users\\All Users'
108
+ ];
109
+ if (dangerousPaths.some(dangerous => normalizedPath.startsWith(dangerous))) {
110
+ throw new Error(`Access denied to system directory: ${filePath}`);
111
+ }
112
+ return normalizedPath;
113
+ }
114
+ /**
115
+ * Secure file existence check
116
+ * Uses fs.accessSync instead of fs.existsSync for better security practices
117
+ */
118
+ function secureExistsSync(filePath) {
119
+ try {
120
+ const safePath = validatePath(filePath);
121
+ // SECURITY: Path has been validated and restricted to safe directories
122
+ fs.accessSync(safePath, fs.constants.F_OK);
123
+ return true;
124
+ }
125
+ catch {
126
+ return false;
127
+ }
128
+ }
129
+ /**
130
+ * Secure directory creation with recursive option support
131
+ * Restricted to log and temp directories only
132
+ */
133
+ function secureMkdirSync(dirPath, options) {
134
+ const safePath = validatePath(dirPath);
135
+ try {
136
+ const mkdirOptions = { recursive: Boolean(options?.recursive) };
137
+ // SECURITY: Path has been validated and restricted to safe directories
138
+ fs.mkdirSync(safePath, mkdirOptions);
139
+ }
140
+ catch (error) {
141
+ const errorMessage = error instanceof Error ? error.message : String(error);
142
+ throw new Error(`Failed to create directory ${dirPath}: ${errorMessage}`);
143
+ }
144
+ }
145
+ /**
146
+ * Secure file stat operation
147
+ * Returns file system statistics for validated paths only
148
+ */
149
+ function secureStatSync(filePath) {
150
+ const safePath = validatePath(filePath);
151
+ try {
152
+ // SECURITY: Path has been validated and restricted to safe directories
153
+ return fs.statSync(safePath);
154
+ }
155
+ catch (error) {
156
+ const errorMessage = error instanceof Error ? error.message : String(error);
157
+ throw new Error(`Failed to stat file ${filePath}: ${errorMessage}`);
158
+ }
159
+ }
160
+ /**
161
+ * Secure file write operation
162
+ * Validates path and data before writing to prevent injection attacks
163
+ */
164
+ function secureWriteFileSync(filePath, data, options) {
165
+ const safePath = validatePath(filePath);
166
+ // Validate data parameter
167
+ if (typeof data !== 'string') {
168
+ throw new Error('Data must be a string for security');
169
+ }
170
+ try {
171
+ const writeOptions = options || {};
172
+ // SECURITY: Path has been validated and restricted to safe directories
173
+ fs.writeFileSync(safePath, data, writeOptions);
174
+ }
175
+ catch (error) {
176
+ const errorMessage = error instanceof Error ? error.message : String(error);
177
+ throw new Error(`Failed to write file ${filePath}: ${errorMessage}`);
178
+ }
179
+ }
180
+ /**
181
+ * Secure file deletion
182
+ * Restricted to log and temp files only for safety
183
+ */
184
+ function secureUnlinkSync(filePath) {
185
+ const safePath = validatePath(filePath);
186
+ // Additional safety check: only allow deletion of log and temp files
187
+ const logDirs = [...SAFE_BASE_DIRS.LOG_FILES, ...SAFE_BASE_DIRS.TEMP_FILES];
188
+ const isInLogDir = logDirs.some(logDir => safePath.startsWith(logDir));
189
+ if (!isInLogDir) {
190
+ throw new Error(`File deletion not allowed outside log/temp directories: ${filePath}`);
191
+ }
192
+ try {
193
+ // SECURITY: Path has been validated and restricted to log/temp directories
194
+ fs.unlinkSync(safePath);
195
+ }
196
+ catch (error) {
197
+ const errorMessage = error instanceof Error ? error.message : String(error);
198
+ throw new Error(`Failed to delete file ${filePath}: ${errorMessage}`);
199
+ }
200
+ }
201
+ /**
202
+ * Secure file rename/move operation
203
+ * Both source and destination must be in safe directories
204
+ */
205
+ function secureRenameSync(oldPath, newPath) {
206
+ const safeOldPath = validatePath(oldPath);
207
+ const safeNewPath = validatePath(newPath);
208
+ // Ensure both paths are in allowed directories (log/temp only for safety)
209
+ const allowedDirs = [...SAFE_BASE_DIRS.LOG_FILES, ...SAFE_BASE_DIRS.TEMP_FILES];
210
+ const oldInAllowed = allowedDirs.some(dir => safeOldPath.startsWith(dir));
211
+ const newInAllowed = allowedDirs.some(dir => safeNewPath.startsWith(dir));
212
+ if (!oldInAllowed || !newInAllowed) {
213
+ throw new Error(`File rename not allowed outside safe directories: ${oldPath} -> ${newPath}`);
214
+ }
215
+ try {
216
+ // SECURITY: Both paths have been validated and restricted to safe directories
217
+ fs.renameSync(safeOldPath, safeNewPath);
218
+ }
219
+ catch (error) {
220
+ const errorMessage = error instanceof Error ? error.message : String(error);
221
+ throw new Error(`Failed to rename file ${oldPath} to ${newPath}: ${errorMessage}`);
222
+ }
223
+ }
224
+ /**
225
+ * File output handler with rotation support and concurrency protection
226
+ * Implements atomic file operations and write queuing to prevent corruption
227
+ */
228
+ class FileOutputHandler {
229
+ constructor(config) {
230
+ this.currentFileSize = 0;
231
+ this.rotationInProgress = false;
232
+ this.writeQueue = [];
233
+ /**
234
+ * Default formatter for file output
235
+ */
236
+ this.defaultFormatter = (level, message, data) => {
237
+ const timestamp = new Date().toISOString();
238
+ const dataStr = data ? ` ${JSON.stringify(data)}` : '';
239
+ return `${timestamp} [${level.toUpperCase()}] ${message}${dataStr}\n`;
240
+ };
241
+ /**
242
+ * Write log to file with rotation support and concurrency protection
243
+ * Queues writes during rotation to prevent file corruption
244
+ */
245
+ this.write = (level, message, data) => {
246
+ // If rotation is in progress, queue the write
247
+ if (this.rotationInProgress) {
248
+ this.writeQueue.push({ level, message, data });
249
+ return;
250
+ }
251
+ try {
252
+ this.writeToFile(level, message, data);
253
+ }
254
+ catch (error) {
255
+ // Fallback to console if file writing fails
256
+ console.error('File output handler failed:', error);
257
+ console.log(`[${level.toUpperCase()}] ${message}`, data);
258
+ }
259
+ };
260
+ // Set defaults
261
+ this.config = {
262
+ filePath: config.filePath,
263
+ append: config.append ?? true,
264
+ maxFileSize: config.maxFileSize ?? 0, // 0 means no rotation
265
+ maxBackupFiles: config.maxBackupFiles ?? 3,
266
+ formatter: config.formatter ?? this.defaultFormatter
267
+ };
268
+ // Ensure directory exists and validate paths
269
+ try {
270
+ const dir = path.dirname(this.config.filePath);
271
+ if (!secureExistsSync(dir)) {
272
+ secureMkdirSync(dir, { recursive: true });
273
+ }
274
+ // Get current file size if it exists
275
+ if (secureExistsSync(this.config.filePath)) {
276
+ this.currentFileSize = secureStatSync(this.config.filePath).size;
277
+ }
278
+ }
279
+ catch (error) {
280
+ // Re-throw with context for better error handling
281
+ const errorMessage = error instanceof Error ? error.message : String(error);
282
+ throw new Error(`Failed to initialize file output handler: ${errorMessage}`);
283
+ }
284
+ }
285
+ /**
286
+ * Write to file with concurrency protection and rotation check
287
+ * If rotation is in progress, messages are queued to prevent corruption
288
+ */
289
+ writeToFile(level, message, data) {
290
+ const formattedMessage = this.config.formatter(level, message, data);
291
+ // Check if rotation is needed
292
+ if (this.config.maxFileSize > 0 &&
293
+ this.currentFileSize + Buffer.byteLength(formattedMessage) > this.config.maxFileSize) {
294
+ this.rotateFile();
295
+ }
296
+ // Write to file using secure filesystem wrapper
297
+ const writeOptions = this.config.append ? { flag: 'a' } : { flag: 'w' };
298
+ secureWriteFileSync(this.config.filePath, formattedMessage, writeOptions);
299
+ this.currentFileSize += Buffer.byteLength(formattedMessage);
300
+ }
301
+ /**
302
+ * Process queued writes after rotation completes
303
+ */
304
+ processWriteQueue() {
305
+ while (this.writeQueue.length > 0) {
306
+ const queuedWrite = this.writeQueue.shift();
307
+ if (queuedWrite) {
308
+ try {
309
+ this.writeToFile(queuedWrite.level, queuedWrite.message, queuedWrite.data);
310
+ }
311
+ catch (error) {
312
+ console.error('Failed to process queued write:', error);
313
+ console.log(`[${queuedWrite.level.toUpperCase()}] ${queuedWrite.message}`, queuedWrite.data);
314
+ }
315
+ }
316
+ }
317
+ }
318
+ /**
319
+ * Rotate log files when size limit is reached
320
+ * Implements concurrency protection to prevent corruption during rotation
321
+ */
322
+ rotateFile() {
323
+ // Prevent concurrent rotations
324
+ if (this.rotationInProgress) {
325
+ return;
326
+ }
327
+ this.rotationInProgress = true;
328
+ try {
329
+ // Move backup files
330
+ for (let i = this.config.maxBackupFiles - 1; i >= 1; i--) {
331
+ const oldFile = `${this.config.filePath}.${i}`;
332
+ const newFile = `${this.config.filePath}.${i + 1}`;
333
+ if (secureExistsSync(oldFile)) {
334
+ if (i === this.config.maxBackupFiles - 1) {
335
+ // Delete the oldest file
336
+ secureUnlinkSync(oldFile);
337
+ }
338
+ else {
339
+ secureRenameSync(oldFile, newFile);
340
+ }
341
+ }
342
+ }
343
+ // Move current file to .1
344
+ if (secureExistsSync(this.config.filePath)) {
345
+ const backupFile = `${this.config.filePath}.1`;
346
+ secureRenameSync(this.config.filePath, backupFile);
347
+ }
348
+ this.currentFileSize = 0;
349
+ }
350
+ catch (error) {
351
+ console.error('File rotation failed:', error);
352
+ }
353
+ finally {
354
+ // Always reset rotation flag and process queued writes
355
+ this.rotationInProgress = false;
356
+ this.processWriteQueue();
357
+ }
358
+ }
359
+ /**
360
+ * Clean up resources and process any remaining queued writes
361
+ */
362
+ destroy() {
363
+ // Process any remaining queued writes
364
+ if (this.writeQueue.length > 0) {
365
+ this.processWriteQueue();
366
+ }
367
+ // Clear the write queue
368
+ this.writeQueue = [];
369
+ this.rotationInProgress = false;
370
+ }
371
+ }
372
+ exports.FileOutputHandler = FileOutputHandler;
373
+ /**
374
+ * HTTP output handler for sending logs to remote endpoints
375
+ */
376
+ class HttpOutputHandler {
377
+ constructor(config) {
378
+ this.logBuffer = [];
379
+ this.flushTimeout = null;
380
+ /**
381
+ * Default formatter for HTTP output
382
+ */
383
+ this.defaultFormatter = (logs) => {
384
+ return {
385
+ logs: logs.map(log => ({
386
+ timestamp: log.timestamp,
387
+ level: log.level,
388
+ message: log.message,
389
+ data: log.data
390
+ }))
391
+ };
392
+ };
393
+ /**
394
+ * Write log to HTTP endpoint with batching support
395
+ */
396
+ this.write = (level, message, data) => {
397
+ try {
398
+ // Add to buffer
399
+ this.logBuffer.push({
400
+ level,
401
+ message,
402
+ data,
403
+ timestamp: new Date().toISOString()
404
+ });
405
+ // Flush if batch size reached
406
+ if (this.logBuffer.length >= this.config.batchSize) {
407
+ this.flush();
408
+ }
409
+ else {
410
+ // Schedule a flush if not already scheduled
411
+ if (!this.flushTimeout) {
412
+ this.flushTimeout = setTimeout(() => {
413
+ this.flush();
414
+ }, 1000); // Flush after 1 second if batch isn't full
415
+ }
416
+ }
417
+ }
418
+ catch (error) {
419
+ // Fallback to console if HTTP fails
420
+ console.error('HTTP output handler failed:', error);
421
+ console.log(`[${level.toUpperCase()}] ${message}`, data);
422
+ }
423
+ };
424
+ // Set defaults
425
+ this.config = {
426
+ url: config.url,
427
+ method: config.method ?? 'POST',
428
+ headers: config.headers ?? { 'Content-Type': 'application/json' },
429
+ batchSize: config.batchSize ?? 1,
430
+ timeout: config.timeout ?? 5000,
431
+ formatter: config.formatter ?? this.defaultFormatter
432
+ };
433
+ }
434
+ /**
435
+ * Flush buffered logs to HTTP endpoint
436
+ */
437
+ flush() {
438
+ if (this.logBuffer.length === 0) {
439
+ return;
440
+ }
441
+ try {
442
+ const payload = this.config.formatter([...this.logBuffer]);
443
+ this.logBuffer = []; // Clear buffer
444
+ if (this.flushTimeout) {
445
+ clearTimeout(this.flushTimeout);
446
+ this.flushTimeout = null;
447
+ }
448
+ // Send HTTP request (using fetch if available, otherwise fall back)
449
+ this.sendHttpRequest(payload);
450
+ }
451
+ catch (error) {
452
+ console.error('HTTP flush failed:', error);
453
+ }
454
+ }
455
+ /**
456
+ * Send HTTP request with appropriate method based on environment
457
+ */
458
+ sendHttpRequest(payload) {
459
+ // Try to use fetch (Node.js 18+ or browser)
460
+ if (typeof fetch !== 'undefined') {
461
+ fetch(this.config.url, {
462
+ method: this.config.method,
463
+ headers: this.config.headers,
464
+ body: JSON.stringify(payload),
465
+ signal: AbortSignal.timeout(this.config.timeout)
466
+ }).catch(error => {
467
+ console.error('HTTP request failed:', error);
468
+ });
469
+ }
470
+ else {
471
+ // Fallback for older Node.js versions
472
+ this.sendHttpRequestNodeJS(payload);
473
+ }
474
+ }
475
+ /**
476
+ * Fallback HTTP implementation for Node.js environments without fetch
477
+ */
478
+ sendHttpRequestNodeJS(payload) {
479
+ try {
480
+ const https = require('https');
481
+ const parsedUrl = new URL(this.config.url);
482
+ const isHttps = parsedUrl.protocol === 'https:';
483
+ // Security: Block HTTP (cleartext) connections by default
484
+ if (!isHttps) {
485
+ throw new Error('SECURITY ERROR: HTTP (cleartext) connections are not allowed for log transmission. Use HTTPS URLs only.');
486
+ }
487
+ const postData = JSON.stringify(payload);
488
+ const options = {
489
+ hostname: parsedUrl.hostname,
490
+ port: parsedUrl.port ? parseInt(parsedUrl.port, 10) : 443,
491
+ path: parsedUrl.pathname + parsedUrl.search,
492
+ method: this.config.method,
493
+ headers: {
494
+ ...this.config.headers,
495
+ 'Content-Length': Buffer.byteLength(postData)
496
+ },
497
+ timeout: this.config.timeout
498
+ };
499
+ const req = https.request(options, (res) => {
500
+ // Handle response (optional: log success/failure)
501
+ res.on('data', () => { }); // Consume response
502
+ res.on('end', () => { });
503
+ });
504
+ req.on('error', (error) => {
505
+ console.error('HTTP request failed:', error);
506
+ });
507
+ req.on('timeout', () => {
508
+ req.destroy();
509
+ console.error('HTTP request timed out');
510
+ });
511
+ req.write(postData);
512
+ req.end();
513
+ }
514
+ catch (error) {
515
+ console.error('HTTP request setup failed:', error);
516
+ }
517
+ }
518
+ /**
519
+ * Cleanup method to prevent memory leaks
520
+ */
521
+ destroy() {
522
+ if (this.flushTimeout) {
523
+ clearTimeout(this.flushTimeout);
524
+ this.flushTimeout = null;
525
+ }
526
+ // Flush any remaining logs
527
+ this.flush();
528
+ }
529
+ }
530
+ exports.HttpOutputHandler = HttpOutputHandler;
531
+ /**
532
+ * Returns a logging handler function based on the specified type and configuration.
533
+ *
534
+ * Supported types are:
535
+ * - `'console'`: Logs to the console using the appropriate method for the log level.
536
+ * - `'silent'`: Returns a no-op handler that discards all logs.
537
+ * - `'file'`: Writes logs to a file with optional rotation; requires `filePath` in config.
538
+ * - `'http'`: Sends logs to a remote HTTP endpoint; requires `url` in config.
539
+ *
540
+ * If required configuration is missing or initialization fails, logs an error and returns either a fallback handler or `null`.
541
+ *
542
+ * @param type - The type of output handler to create (`'console'`, `'silent'`, `'file'`, or `'http'`)
543
+ * @returns A log handler function or `null` if the handler cannot be created
544
+ */
545
+ function createBuiltInHandler(type, config) {
546
+ switch (type) {
547
+ case 'console':
548
+ return (level, message, data) => {
549
+ const method = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';
550
+ // Use safe method call to prevent object injection
551
+ if (Object.prototype.hasOwnProperty.call(console, method) && typeof console[method] === 'function') {
552
+ console[method](message, data);
553
+ }
554
+ else {
555
+ console.log(message, data);
556
+ }
557
+ };
558
+ case 'silent':
559
+ return () => { }; // No-op handler
560
+ case 'file':
561
+ if (config && typeof config.filePath === 'string') {
562
+ try {
563
+ const handler = new FileOutputHandler(config);
564
+ return handler.write;
565
+ }
566
+ catch (error) {
567
+ // Return a handler that logs the expected error message and falls back to console
568
+ return (level, message, data) => {
569
+ console.error('File output handler failed:', error);
570
+ console.log(`[${level.toUpperCase()}] ${message}`, data);
571
+ };
572
+ }
573
+ }
574
+ console.error('File output handler requires filePath in config');
575
+ return null;
576
+ case 'http':
577
+ if (config && typeof config.url === 'string') {
578
+ const handler = new HttpOutputHandler(config);
579
+ return handler.write;
580
+ }
581
+ console.error('HTTP output handler requires url in config');
582
+ return null;
583
+ default:
584
+ return null;
585
+ }
586
+ }
@@ -11,32 +11,32 @@ export declare class LoggerConfigManager {
11
11
  private config;
12
12
  constructor();
13
13
  /**
14
- * Get current configuration
15
- * @returns Current logger configuration
16
- */
14
+ * Get current configuration
15
+ * @returns Current logger configuration
16
+ */
17
17
  getConfig(): LoggerConfig;
18
18
  /**
19
- * Updates logger configuration with new settings
20
- * Merges provided config with existing settings (partial update)
21
- * Supports backwards compatibility by mapping level to mode with deprecation warnings
22
- * @param config - Partial configuration object to apply
23
- */
19
+ * Updates logger configuration with new settings
20
+ * Merges provided config with existing settings (partial update)
21
+ * Supports backwards compatibility by mapping level to mode with deprecation warnings
22
+ * @param config - Partial configuration object to apply
23
+ */
24
24
  updateConfig(config: Partial<LoggerConfig>): void;
25
25
  /**
26
- * Handle legacy level-based configuration with deprecation warnings
27
- * @param config - Configuration containing legacy level property
28
- */
26
+ * Handle legacy level-based configuration with deprecation warnings
27
+ * @param config - Configuration containing legacy level property
28
+ */
29
29
  private handleLegacyLevelConfig;
30
30
  /**
31
- * Map legacy LogLevel values to LogMode values
32
- * @param levelValue - Legacy level value
33
- * @returns Corresponding LogMode or undefined if invalid
34
- */
31
+ * Map legacy LogLevel values to LogMode values
32
+ * @param levelValue - Legacy level value
33
+ * @returns Corresponding LogMode or undefined if invalid
34
+ */
35
35
  private mapLevelToMode;
36
36
  /**
37
- * Create deprecation warning message using LogFormatter
38
- * Outputs formatted deprecation warning messages to console
39
- */
37
+ * Create deprecation warning message using LogFormatter
38
+ * Outputs formatted deprecation warning messages to console
39
+ */
40
40
  private createDeprecationWarning;
41
41
  }
42
42
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/logger/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAqB,MAAM,UAAU,CAAC;AAG3D;;;GAGG;AACH,qBAAa,mBAAmB;IAC5B,OAAO,CAAC,MAAM,CAAe;;IAS7B;;;OAGG;IACH,SAAS,IAAI,YAAY;IAIzB;;;;;OAKG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAgBjD;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAqB/B;;;;OAIG;IACH,OAAO,CAAC,cAAc;IActB;;;OAGG;IACH,OAAO,CAAC,wBAAwB;CAQnC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/logger/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAqB,MAAM,UAAU,CAAC;AAG3D;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAe;;IAS7B;;;SAGK;IACL,SAAS,IAAI,YAAY;IAIzB;;;;;SAKK;IACL,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAiBjD;;;SAGK;IACL,OAAO,CAAC,uBAAuB;IAsB/B;;;;SAIK;IACL,OAAO,CAAC,cAAc;IActB;;;SAGK;IACL,OAAO,CAAC,wBAAwB;CAQjC"}