voltlog-io 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,707 @@
1
+ /**
2
+ * @module voltlog-io
3
+ * @description Type definitions for the OCPP-aware structured logger.
4
+ */
5
+ declare const LogLevel: {
6
+ readonly TRACE: 10;
7
+ readonly DEBUG: 20;
8
+ readonly INFO: 30;
9
+ readonly WARN: 40;
10
+ readonly ERROR: 50;
11
+ readonly FATAL: 60;
12
+ readonly SILENT: number;
13
+ };
14
+ type LogLevelName = keyof typeof LogLevel;
15
+ /** Numeric log level value */
16
+ type LogLevelValue = (typeof LogLevel)[LogLevelName];
17
+ /** Map from level name (lowercase) to numeric value */
18
+ declare const LogLevelNameMap: Record<string, number>;
19
+ /** Map from numeric value to level name */
20
+ declare const LogLevelValueMap: Record<number, LogLevelName>;
21
+ interface LogEntry<TMeta = Record<string, unknown>> {
22
+ /** Unique log ID (cuid2) */
23
+ id: string;
24
+ /** Numeric log level */
25
+ level: number;
26
+ /** Human-readable level name */
27
+ levelName: LogLevelName;
28
+ /** Log message */
29
+ message: string;
30
+ /** Unix epoch timestamp (ms) */
31
+ timestamp: number;
32
+ /** User-defined structured metadata (type-safe via generics) */
33
+ meta: TMeta;
34
+ /** Bound context from child logger (e.g. chargePointId, sessionId) */
35
+ context?: Record<string, unknown>;
36
+ /** Correlation ID for tracing across async operations */
37
+ correlationId?: string;
38
+ /** Error information */
39
+ error?: LogError;
40
+ }
41
+ interface LogError {
42
+ message: string;
43
+ stack?: string;
44
+ code?: string;
45
+ name?: string;
46
+ }
47
+ interface OcppExchangeMeta {
48
+ /** Charge point / station identity */
49
+ chargePointId?: string;
50
+ /** OCPP message type */
51
+ messageType?: "CALL" | "CALLRESULT" | "CALLERROR";
52
+ /** OCPP action name (e.g. BootNotification) */
53
+ action?: string;
54
+ /** Message direction */
55
+ direction?: "IN" | "OUT";
56
+ /** Correlation ID for request/response matching */
57
+ correlationId?: string;
58
+ /** Negotiated OCPP protocol version */
59
+ protocol?: string;
60
+ /** Serialized payload size in bytes */
61
+ payloadSize?: number;
62
+ /** Latency in milliseconds */
63
+ latencyMs?: number;
64
+ /** Response status (e.g. Accepted, Rejected) */
65
+ status?: string;
66
+ }
67
+ /**
68
+ * A Transformer receives formatted log entries and delivers them
69
+ * to a destination (console, file, webhook, database, etc.).
70
+ *
71
+ * Transformers are async-safe — `transform()` can return a Promise.
72
+ */
73
+ interface Transformer<TMeta = Record<string, unknown>> {
74
+ /** Unique name for this transformer */
75
+ name: string;
76
+ /** Optional per-transformer level filter */
77
+ level?: LogLevelName;
78
+ /** Process a log entry */
79
+ transform(entry: LogEntry<TMeta>): void | Promise<void>;
80
+ /** Flush any buffered entries */
81
+ flush?(): void | Promise<void>;
82
+ /** Graceful shutdown */
83
+ close?(): void | Promise<void>;
84
+ }
85
+ /**
86
+ * Middleware intercepts log entries before they reach transformers.
87
+ * Used for redaction, sampling, enrichment, alerting, etc.
88
+ *
89
+ * Call `next(entry)` to continue the pipeline.
90
+ * Omit `next()` to drop the entry (e.g. sampling).
91
+ */
92
+ type LogMiddleware<TMeta = Record<string, unknown>> = (entry: LogEntry<TMeta>, next: (entry: LogEntry<TMeta>) => void) => void;
93
+ /**
94
+ * Alert rules evaluate log entries and fire callbacks
95
+ * when configurable conditions are met.
96
+ */
97
+ interface AlertRule<TMeta = Record<string, unknown>> {
98
+ /** Alert name (for identification) */
99
+ name: string;
100
+ /** Condition — return true if this entry should count toward the alert */
101
+ when: (entry: LogEntry<TMeta>) => boolean;
102
+ /** Number of matching entries required to fire (default: 1) */
103
+ threshold?: number;
104
+ /** Time window in ms for threshold counting */
105
+ windowMs?: number;
106
+ /** Minimum cooldown in ms between alert firings (default: 0) */
107
+ cooldownMs?: number;
108
+ /** Callback fired when alert conditions are met */
109
+ onAlert: (entries: LogEntry<TMeta>[]) => void | Promise<void>;
110
+ }
111
+ interface LoggerOptions<TMeta = Record<string, unknown>> {
112
+ /** Minimum log level (default: INFO) */
113
+ level?: LogLevelName;
114
+ /** Transformers for log output */
115
+ transports?: Transformer<TMeta>[];
116
+ /** Middleware pipeline */
117
+ middleware?: LogMiddleware<TMeta>[];
118
+ /** Alert rules */
119
+ alerts?: AlertRule<TMeta>[];
120
+ /** Default bound context for all log entries */
121
+ context?: Record<string, unknown>;
122
+ /** Field paths to auto-redact (e.g. ['idToken', 'password']) */
123
+ redact?: string[];
124
+ /**
125
+ * When to include error stack traces:
126
+ * - `true` — always include
127
+ * - `false` — never include
128
+ * - `LogLevelName` — include at this level and above
129
+ * Default: 'ERROR'
130
+ */
131
+ includeStack?: boolean | LogLevelName;
132
+ /**
133
+ * Exchange log mode:
134
+ * - `true` — exchange logs alongside normal logs
135
+ * - `'only'` — only exchange-formatted logs
136
+ * - `false` — disabled (default)
137
+ */
138
+ exchangeLog?: boolean | "only";
139
+ /** Custom timestamp function (default: Date.now) */
140
+ timestamp?: () => number;
141
+ }
142
+ interface Logger<TMeta = Record<string, unknown>> {
143
+ trace(message: string, meta?: Partial<TMeta>): void;
144
+ debug(message: string, meta?: Partial<TMeta>): void;
145
+ info(message: string, meta?: Partial<TMeta>): void;
146
+ warn(message: string, meta?: Partial<TMeta>): void;
147
+ error(message: string, metaOrError?: Partial<TMeta> | Error, error?: Error): void;
148
+ fatal(message: string, metaOrError?: Partial<TMeta> | Error, error?: Error): void;
149
+ /** Create a child logger with additional bound context */
150
+ child(context: Record<string, unknown>): Logger<TMeta>;
151
+ /** Add a transformer at runtime */
152
+ addTransformer(transformer: Transformer<TMeta>): void;
153
+ /** Remove a transformer by name */
154
+ removeTransformer(name: string): void;
155
+ /** Add middleware at runtime */
156
+ addMiddleware(middleware: LogMiddleware<TMeta>): void;
157
+ /** Flush all transformers */
158
+ flush(): Promise<void>;
159
+ /** Close all transformers gracefully */
160
+ close(): Promise<void>;
161
+ }
162
+
163
+ /**
164
+ * @module voltlog-io
165
+ * @description Core Logger class — zero external dependencies (only cuid2), runtime-agnostic.
166
+ *
167
+ * @example Basic usage
168
+ * ```ts
169
+ * import { createLogger, consoleTransport } from 'voltlog-io';
170
+ *
171
+ * const logger = createLogger({
172
+ * level: 'INFO',
173
+ * transports: [consoleTransport()],
174
+ * });
175
+ *
176
+ * logger.info('Server started', { port: 9000 });
177
+ * ```
178
+ *
179
+ * @example Child logger with bound context
180
+ * ```ts
181
+ * const cpLogger = logger.child({ chargePointId: 'CP-101' });
182
+ * cpLogger.info('BootNotification received');
183
+ * // → auto-includes context: { chargePointId: 'CP-101' }
184
+ * ```
185
+ *
186
+ * @example Error with stack trace
187
+ * ```ts
188
+ * logger.error('Connection failed', new Error('ETIMEDOUT'));
189
+ * logger.error('Handler crashed', { action: 'BootNotification' }, new Error('null ref'));
190
+ * ```
191
+ *
192
+ * @example With ocpp-ws-io (if user has both packages)
193
+ * ```ts
194
+ * import { createLogger } from 'ocpp-ws-io/logger'; // re-export
195
+ * ```
196
+ */
197
+
198
+ /**
199
+ * Create a new logger instance.
200
+ *
201
+ * @example Minimal
202
+ * ```ts
203
+ * const logger = createLogger();
204
+ * logger.info('Hello');
205
+ * ```
206
+ *
207
+ * @example Full options
208
+ * ```ts
209
+ * import { createLogger, consoleTransport, prettyTransport } from 'voltlog-io';
210
+ *
211
+ * const logger = createLogger({
212
+ * level: 'DEBUG',
213
+ * transports: [prettyTransport()],
214
+ * redact: ['password', 'idToken'],
215
+ * includeStack: 'ERROR',
216
+ * });
217
+ * ```
218
+ *
219
+ * @example OCPP-aware with child loggers
220
+ * ```ts
221
+ * import { createLogger, prettyTransport } from 'voltlog-io';
222
+ * import type { OcppExchangeMeta } from 'voltlog-io';
223
+ *
224
+ * const logger = createLogger<OcppExchangeMeta>({
225
+ * level: 'INFO',
226
+ * transports: [prettyTransport()],
227
+ * });
228
+ *
229
+ * // Per-connection child logger
230
+ * const cpLog = logger.child({ chargePointId: 'CP-101' });
231
+ * cpLog.info('OCPP message', {
232
+ * messageType: 'CALL',
233
+ * action: 'BootNotification',
234
+ * direction: 'IN',
235
+ * });
236
+ * ```
237
+ */
238
+ declare function createLogger<TMeta = Record<string, unknown>>(options?: LoggerOptions<TMeta>): Logger<TMeta>;
239
+
240
+ /**
241
+ * @module voltlog-io
242
+ * @description Log level utilities — filtering, comparison, resolution.
243
+ */
244
+
245
+ /**
246
+ * Resolve a level name string to its numeric value.
247
+ * Case-insensitive. Returns INFO if unrecognized.
248
+ */
249
+ declare function resolveLevel(level: string | LogLevelName): number;
250
+ /**
251
+ * Check if a log entry at `entryLevel` passes the `filterLevel`.
252
+ */
253
+ declare function shouldLog(entryLevel: number, filterLevel: number): boolean;
254
+ /**
255
+ * Determine whether to include stack trace for a given entry level.
256
+ */
257
+ declare function shouldIncludeStack(entryLevel: number, includeStack: boolean | LogLevelName): boolean;
258
+
259
+ /**
260
+ * @module voltlog-io
261
+ * @description Redaction middleware — auto-redacts sensitive fields from log meta and context.
262
+ *
263
+ * @example
264
+ * ```ts
265
+ * import { createLogger, consoleTransport, redactionMiddleware } from 'voltlog-io';
266
+ *
267
+ * const logger = createLogger({
268
+ * transports: [consoleTransport()],
269
+ * middleware: [redactionMiddleware({ paths: ['password', 'idToken', 'authorization'] })],
270
+ * });
271
+ *
272
+ * logger.info('Auth attempt', { password: 's3cret', user: 'admin' });
273
+ * // → { password: '[REDACTED]', user: 'admin' }
274
+ * ```
275
+ */
276
+
277
+ interface RedactionOptions {
278
+ /** Field paths to redact (case-insensitive matching) */
279
+ paths: string[];
280
+ /** Replacement value (default: '[REDACTED]') */
281
+ replacement?: string;
282
+ /** Also redact matching keys in nested objects (default: true) */
283
+ deep?: boolean;
284
+ }
285
+ /**
286
+ * Create a redaction middleware that replaces sensitive field values.
287
+ */
288
+ declare function redactionMiddleware<TMeta = Record<string, unknown>>(options: RedactionOptions): LogMiddleware<TMeta>;
289
+
290
+ /**
291
+ * @module voltlog-io
292
+ * @description Sampling middleware — rate-limits logs per key to avoid flooding.
293
+ *
294
+ * @example
295
+ * ```ts
296
+ * import { createLogger, consoleTransport, samplingMiddleware } from 'voltlog-io';
297
+ *
298
+ * const logger = createLogger({
299
+ * transports: [consoleTransport()],
300
+ * middleware: [
301
+ * samplingMiddleware({
302
+ * keyFn: (entry) => `${entry.meta.action}:${entry.meta.chargePointId}`,
303
+ * maxPerWindow: 10,
304
+ * windowMs: 60_000, // 10 logs per minute per action+CP combo
305
+ * }),
306
+ * ],
307
+ * });
308
+ * ```
309
+ */
310
+
311
+ interface SamplingOptions<TMeta = Record<string, unknown>> {
312
+ /**
313
+ * Function to extract a sampling key from a log entry.
314
+ * Entries with the same key share a rate limit.
315
+ * Default: uses `entry.message`
316
+ */
317
+ keyFn?: (entry: LogEntry<TMeta>) => string;
318
+ /** Maximum entries allowed per key per window (default: 100) */
319
+ maxPerWindow?: number;
320
+ /** Time window in ms (default: 60000 = 1 minute) */
321
+ windowMs?: number;
322
+ /** Probability to keep a log (0 to 1). Default: 1 (keep all) */
323
+ sampleRate?: number;
324
+ /** Logs at this level or higher always pass. Default: 40 (WARN) */
325
+ priorityLevel?: number;
326
+ }
327
+ /**
328
+ * Create a sampling middleware that drops logs exceeding the rate limit.
329
+ */
330
+ declare function samplingMiddleware<TMeta = Record<string, unknown>>(options?: SamplingOptions<TMeta>): LogMiddleware<TMeta>;
331
+
332
+ /**
333
+ * @module voltlog-io
334
+ * @description OCPP enrichment middleware — auto-enriches log entries with OCPP metadata.
335
+ *
336
+ * @example
337
+ * ```ts
338
+ * import { createLogger, consoleTransport, ocppMiddleware } from 'voltlog-io';
339
+ * import type { OcppExchangeMeta } from 'voltlog-io';
340
+ *
341
+ * const logger = createLogger<OcppExchangeMeta>({
342
+ * transports: [consoleTransport()],
343
+ * middleware: [ocppMiddleware()],
344
+ * });
345
+ *
346
+ * // The middleware auto-computes payloadSize and adds correlationId to the entry
347
+ * logger.info('Message received', {
348
+ * action: 'BootNotification',
349
+ * messageType: 'CALL',
350
+ * direction: 'IN',
351
+ * });
352
+ * ```
353
+ */
354
+
355
+ interface OcppMiddlewareOptions {
356
+ /**
357
+ * Automatically compute payload size from meta if not set.
358
+ * Default: true
359
+ */
360
+ autoPayloadSize?: boolean;
361
+ /**
362
+ * Propagate correlationId from meta to entry.correlationId.
363
+ * Default: true
364
+ */
365
+ propagateCorrelationId?: boolean;
366
+ }
367
+ /**
368
+ * Create an OCPP enrichment middleware.
369
+ * Enriches log entries with computed OCPP metadata.
370
+ */
371
+ declare function ocppMiddleware(options?: OcppMiddlewareOptions): LogMiddleware<OcppExchangeMeta>;
372
+
373
+ /**
374
+ * @module voltlog-io
375
+ * @description Alert middleware — evaluates configurable rules and fires callbacks.
376
+ *
377
+ * @example
378
+ * ```ts
379
+ * import { createLogger, consoleTransport, alertMiddleware } from 'voltlog-io';
380
+ *
381
+ * const logger = createLogger({
382
+ * transports: [consoleTransport()],
383
+ * middleware: [
384
+ * alertMiddleware([
385
+ * {
386
+ * name: 'error-spike',
387
+ * when: (entry) => entry.level >= 50, // ERROR+
388
+ * threshold: 10,
389
+ * windowMs: 60_000,
390
+ * cooldownMs: 300_000,
391
+ * onAlert: async (entries) => {
392
+ * await sendEmail({ subject: `${entries.length} errors in 1 min` });
393
+ * },
394
+ * },
395
+ * {
396
+ * name: 'callerror-alert',
397
+ * when: (entry) => entry.meta.messageType === 'CALLERROR',
398
+ * threshold: 5,
399
+ * windowMs: 60_000,
400
+ * onAlert: (entries) => sendSlackNotification(entries),
401
+ * },
402
+ * ]),
403
+ * ],
404
+ * });
405
+ * ```
406
+ */
407
+
408
+ /**
409
+ * Create an alert middleware that evaluates rules against every log entry.
410
+ *
411
+ * Alerts are non-blocking — `onAlert` failures are silently caught
412
+ * to never interfere with the logging pipeline.
413
+ */
414
+ declare function alertMiddleware<TMeta = Record<string, unknown>>(rules: AlertRule<TMeta>[]): LogMiddleware<TMeta>;
415
+
416
+ /**
417
+ * Helper to create a type-safe middleware function.
418
+ *
419
+ * @example
420
+ * const myMiddleware = createMiddleware((entry, next) => {
421
+ * entry.meta.foo = 'bar';
422
+ * next(entry);
423
+ * });
424
+ */
425
+ declare function createMiddleware<TMeta = Record<string, unknown>>(fn: LogMiddleware<TMeta>): LogMiddleware<TMeta>;
426
+
427
+ /**
428
+ * @module voltlog-io
429
+ * @description Console transformer — outputs structured JSON logs to console.
430
+ * Works in Node.js, browsers, and all runtimes.
431
+ *
432
+ * @example
433
+ * ```ts
434
+ * import { createLogger, consoleTransport } from 'voltlog-io';
435
+ *
436
+ * const logger = createLogger({
437
+ * transports: [consoleTransport()],
438
+ * });
439
+ * ```
440
+ */
441
+
442
+ interface ConsoleTransportOptions {
443
+ /** Per-transport level filter */
444
+ level?: LogLevelName;
445
+ /**
446
+ * Use appropriate console method per level (console.warn, console.error, etc.).
447
+ * Default: true
448
+ */
449
+ useConsoleLevels?: boolean;
450
+ /**
451
+ * Format the entry before outputting. Return any value that console.log can handle.
452
+ * Default: serializes to JSON string.
453
+ */
454
+ formatter?: (entry: LogEntry) => unknown;
455
+ }
456
+ /**
457
+ * Create a console transformer. Outputs structured JSON to the console.
458
+ */
459
+ declare function consoleTransport(options?: ConsoleTransportOptions): Transformer;
460
+
461
+ /**
462
+ * @module voltlog-io
463
+ * @description Pretty transformer — human-readable colored output with OCPP exchange formatting.
464
+ *
465
+ * @example Dev mode
466
+ * ```ts
467
+ * import { createLogger, prettyTransport } from 'voltlog-io';
468
+ *
469
+ * const logger = createLogger({
470
+ * transports: [prettyTransport()],
471
+ * });
472
+ *
473
+ * logger.info('Server started', { port: 9000 });
474
+ * // → ℹ 2024-01-15T10:30:00.000Z INFO Server started { port: 9000 }
475
+ * ```
476
+ *
477
+ * @example OCPP exchange logs
478
+ * ```ts
479
+ * logger.info('OCPP exchange', {
480
+ * chargePointId: 'CP-101',
481
+ * action: 'BootNotification',
482
+ * messageType: 'CALL',
483
+ * direction: 'IN',
484
+ * latencyMs: 34,
485
+ * status: 'Accepted',
486
+ * });
487
+ * // → ⚡ CP-101 → BootNotification [IN] CALL
488
+ * // → ✔ Accepted (34ms)
489
+ * ```
490
+ */
491
+
492
+ interface PrettyTransportOptions {
493
+ /** Per-transport level filter */
494
+ level?: LogLevelName;
495
+ /** Show timestamps (default: true) */
496
+ timestamps?: boolean;
497
+ /** Use colors in output (default: true) */
498
+ colors?: boolean;
499
+ }
500
+ /**
501
+ * Create a pretty-print transformer for dev/debug use.
502
+ * Includes OCPP exchange log prettification.
503
+ */
504
+ declare function prettyTransport(options?: PrettyTransportOptions): Transformer;
505
+
506
+ /**
507
+ * @module voltlog-io
508
+ * @description JSON stream transformer — writes newline-delimited JSON to any writable stream.
509
+ * Useful for file logging, piping to external tools, etc.
510
+ *
511
+ * @example Write to file
512
+ * ```ts
513
+ * import { createWriteStream } from 'node:fs';
514
+ * import { createLogger, jsonStreamTransport } from 'voltlog-io';
515
+ *
516
+ * const logger = createLogger({
517
+ * transports: [
518
+ * jsonStreamTransport({ stream: createWriteStream('./app.log', { flags: 'a' }) }),
519
+ * ],
520
+ * });
521
+ * ```
522
+ *
523
+ * @example Write to stdout
524
+ * ```ts
525
+ * const logger = createLogger({
526
+ * transports: [jsonStreamTransport({ stream: process.stdout })],
527
+ * });
528
+ * ```
529
+ */
530
+
531
+ interface JsonStreamTransportOptions {
532
+ /** Writable stream to output to (e.g. fs.createWriteStream, process.stdout) */
533
+ stream: NodeJS.WritableStream;
534
+ /** Per-transport level filter */
535
+ level?: LogLevelName;
536
+ /**
537
+ * Custom serializer. Return the string to write.
538
+ * Default: JSON.stringify(entry) + '\n'
539
+ */
540
+ serializer?: (entry: LogEntry) => string;
541
+ }
542
+ /**
543
+ * Create a JSON stream transformer that writes newline-delimited JSON.
544
+ */
545
+ declare function jsonStreamTransport(options: JsonStreamTransportOptions): Transformer;
546
+
547
+ /**
548
+ * @module voltlog-io
549
+ * @description Webhook transformer — sends log entries to external HTTP endpoints.
550
+ * Supports batching for performance.
551
+ *
552
+ * @example
553
+ * ```ts
554
+ * import { createLogger, webhookTransport } from 'voltlog-io';
555
+ *
556
+ * const logger = createLogger({
557
+ * transports: [
558
+ * webhookTransport({
559
+ * url: 'https://my-api.com/logs',
560
+ * headers: { Authorization: 'Bearer token123' },
561
+ * batchSize: 50,
562
+ * flushIntervalMs: 5000,
563
+ * }),
564
+ * ],
565
+ * });
566
+ * ```
567
+ */
568
+
569
+ interface WebhookTransportOptions {
570
+ /** Target URL to POST log entries to */
571
+ url: string;
572
+ /** HTTP method (default: POST) */
573
+ method?: string;
574
+ /** Additional HTTP headers */
575
+ headers?: Record<string, string>;
576
+ /** Number of entries to batch before sending (default: 1 = no batching) */
577
+ batchSize?: number;
578
+ /** Max time in ms to wait before flushing a partial batch (default: 5000) */
579
+ flushIntervalMs?: number;
580
+ /** Per-transport level filter */
581
+ level?: LogLevelName;
582
+ /** Custom body serializer. Default: JSON.stringify({ entries: [...] }) */
583
+ serializer?: (entries: LogEntry[]) => string;
584
+ /** Retry failed requests (default: false) */
585
+ retry?: boolean;
586
+ /** Max retries (default: 3) */
587
+ maxRetries?: number;
588
+ }
589
+ /**
590
+ * Create a webhook transformer that POSTs log entries to an HTTP endpoint.
591
+ */
592
+ declare function webhookTransport(options: WebhookTransportOptions): Transformer;
593
+
594
+ /**
595
+ * @module voltlog-io
596
+ * @description Batch wrapper — wraps any transformer with buffering and periodic flushing.
597
+ *
598
+ * @example
599
+ * ```ts
600
+ * import { createLogger, batchTransport, consoleTransport } from 'voltlog-io';
601
+ *
602
+ * // Batch console output: flush every 100 entries or every 2 seconds
603
+ * const logger = createLogger({
604
+ * transports: [
605
+ * batchTransport(consoleTransport(), { batchSize: 100, flushIntervalMs: 2000 }),
606
+ * ],
607
+ * });
608
+ * ```
609
+ */
610
+
611
+ interface BatchTransportOptions {
612
+ /** Number of entries to buffer before flushing (default: 100) */
613
+ batchSize?: number;
614
+ /** Max time in ms to wait before flushing a partial batch (default: 5000) */
615
+ flushIntervalMs?: number;
616
+ }
617
+ /**
618
+ * Wrap any transformer with batching. Entries are buffered and flushed
619
+ * either when the batch is full or the timer fires.
620
+ */
621
+ declare function batchTransport(inner: Transformer, options?: BatchTransportOptions): Transformer;
622
+
623
+ /**
624
+ * @module voltlog-io
625
+ * @description Redis Streams transformer — publishes log entries to a Redis Stream.
626
+ * Users can then subscribe (XREAD/XREADGROUP) for real-time dashboards, monitoring, etc.
627
+ *
628
+ * Requires `ioredis` — user brings their own client instance (no hard dep).
629
+ *
630
+ * @example Basic
631
+ * ```ts
632
+ * import Redis from 'ioredis';
633
+ * import { createLogger, redisTransport } from 'voltlog-io';
634
+ *
635
+ * const redis = new Redis();
636
+ * const logger = createLogger({
637
+ * transports: [
638
+ * redisTransport({ client: redis, streamKey: 'logs:ocpp' }),
639
+ * ],
640
+ * });
641
+ *
642
+ * logger.info('CP connected', { chargePointId: 'CP-101' });
643
+ * // → XADD logs:ocpp * level INFO message "CP connected" ...
644
+ * ```
645
+ *
646
+ * @example With TTL and max stream length
647
+ * ```ts
648
+ * redisTransport({
649
+ * client: redis,
650
+ * streamKey: 'logs:ocpp',
651
+ * maxLen: 10_000, // keep last 10k entries (approximate trim)
652
+ * })
653
+ * ```
654
+ *
655
+ * @example Subscribing (consumer side)
656
+ * ```ts
657
+ * // In your dashboard / monitoring service:
658
+ * const redis = new Redis();
659
+ *
660
+ * // Read new entries from the stream
661
+ * const entries = await redis.xread('BLOCK', 0, 'STREAMS', 'logs:ocpp', '$');
662
+ *
663
+ * // Or use consumer groups for at-least-once delivery:
664
+ * await redis.xgroup('CREATE', 'logs:ocpp', 'dashboard', '$', 'MKSTREAM');
665
+ * const entries = await redis.xreadgroup(
666
+ * 'GROUP', 'dashboard', 'worker-1',
667
+ * 'BLOCK', 0, 'STREAMS', 'logs:ocpp', '>'
668
+ * );
669
+ * ```
670
+ */
671
+
672
+ /**
673
+ * Minimal interface for the Redis client methods we need.
674
+ * Compatible with `ioredis` — user provides their own instance.
675
+ */
676
+ interface RedisClient {
677
+ xadd(...args: (string | number)[]): Promise<string | null>;
678
+ quit?(): Promise<void>;
679
+ }
680
+ interface RedisTransportOptions {
681
+ /** Redis client instance (e.g. `new Redis()` from ioredis) */
682
+ client: RedisClient;
683
+ /** Redis Stream key to publish to (default: 'logs') */
684
+ streamKey?: string;
685
+ /**
686
+ * Max approximate stream length — older entries are trimmed.
687
+ * Uses MAXLEN ~ (approximate) to keep the stream bounded.
688
+ * Default: no limit.
689
+ */
690
+ maxLen?: number;
691
+ /** Per-transport level filter */
692
+ level?: LogLevelName;
693
+ /**
694
+ * Custom field mapper — convert LogEntry to flat key-value pairs for Redis.
695
+ * Default: serializes the entire entry as JSON under a single 'data' field.
696
+ */
697
+ fieldMapper?: (entry: LogEntry) => Record<string, string>;
698
+ }
699
+ /**
700
+ * Create a Redis Streams transformer.
701
+ *
702
+ * Publishes each log entry via XADD to a Redis Stream.
703
+ * Fire-and-forget — errors are silently swallowed to avoid blocking.
704
+ */
705
+ declare function redisTransport(options: RedisTransportOptions): Transformer;
706
+
707
+ export { type AlertRule, type BatchTransportOptions, type ConsoleTransportOptions, type JsonStreamTransportOptions, type LogEntry, type LogError, LogLevel, type LogLevelName, LogLevelNameMap, type LogLevelValue, LogLevelValueMap, type LogMiddleware, type Logger, type LoggerOptions, type OcppExchangeMeta, type OcppMiddlewareOptions, type PrettyTransportOptions, type RedactionOptions, type RedisClient, type RedisTransportOptions, type SamplingOptions, type Transformer, type WebhookTransportOptions, alertMiddleware, batchTransport, consoleTransport, createLogger, createMiddleware, jsonStreamTransport, ocppMiddleware, prettyTransport, redactionMiddleware, redisTransport, resolveLevel, samplingMiddleware, shouldIncludeStack, shouldLog, webhookTransport };