logixia 1.3.1 → 1.5.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 (59) hide show
  1. package/README.md +848 -7
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/{index-iDTW2-eY.d.mts → index-Ium497V3.d.mts} +180 -2
  4. package/dist/index-Ium497V3.d.mts.map +1 -0
  5. package/dist/{index-CHIsdA9n.d.ts → index-t-ActikQ.d.ts} +180 -2
  6. package/dist/index-t-ActikQ.d.ts.map +1 -0
  7. package/dist/index.d.mts +734 -3
  8. package/dist/index.d.mts.map +1 -1
  9. package/dist/index.d.ts +734 -3
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +643 -2
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +618 -3
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/{logitron-logger.module-BqNKp0Fs.js → logitron-logger.module-B7CsnCYA.js} +418 -52
  16. package/dist/logitron-logger.module-B7CsnCYA.js.map +1 -0
  17. package/dist/{logitron-logger.module-Bq3_KckP.d.ts → logitron-logger.module-CMRBDGwm.d.ts} +181 -34
  18. package/dist/logitron-logger.module-CMRBDGwm.d.ts.map +1 -0
  19. package/dist/{logitron-logger.module-2AzkadqZ.mjs → logitron-logger.module-DdVy45xE.mjs} +366 -54
  20. package/dist/logitron-logger.module-DdVy45xE.mjs.map +1 -0
  21. package/dist/{logitron-logger.module-DW_mmXbj.d.mts → logitron-logger.module-Eaw6bH9M.d.mts} +181 -34
  22. package/dist/logitron-logger.module-Eaw6bH9M.d.mts.map +1 -0
  23. package/dist/middleware.d.mts +1 -1
  24. package/dist/middleware.d.ts +1 -1
  25. package/dist/nest.d.mts +2 -2
  26. package/dist/nest.d.ts +2 -2
  27. package/dist/nest.js +2 -2
  28. package/dist/nest.mjs +2 -2
  29. package/dist/{promise-DaiZ2BaH.js → promise-BI-3eI4n.js} +285 -128
  30. package/dist/promise-BI-3eI4n.js.map +1 -0
  31. package/dist/{promise-C4pQPcK4.mjs → promise-BrZcjavs.mjs} +285 -128
  32. package/dist/promise-BrZcjavs.mjs.map +1 -0
  33. package/dist/testing.d.mts +1 -1
  34. package/dist/testing.d.ts +1 -1
  35. package/dist/testing.js +7 -1
  36. package/dist/testing.js.map +1 -1
  37. package/dist/testing.mjs +7 -1
  38. package/dist/testing.mjs.map +1 -1
  39. package/dist/{transport.manager-5VVdqS3o.mjs → transport.manager-DR7TLXQT.mjs} +82 -4
  40. package/dist/transport.manager-DR7TLXQT.mjs.map +1 -0
  41. package/dist/{transport.manager-DCOm4uIQ.js → transport.manager-DVTM978M.js} +82 -4
  42. package/dist/transport.manager-DVTM978M.js.map +1 -0
  43. package/dist/transports.d.mts +61 -168
  44. package/dist/transports.d.mts.map +1 -1
  45. package/dist/transports.d.ts +61 -168
  46. package/dist/transports.d.ts.map +1 -1
  47. package/dist/transports.js +1 -1
  48. package/dist/transports.mjs +1 -1
  49. package/package.json +62 -1
  50. package/dist/index-CHIsdA9n.d.ts.map +0 -1
  51. package/dist/index-iDTW2-eY.d.mts.map +0 -1
  52. package/dist/logitron-logger.module-2AzkadqZ.mjs.map +0 -1
  53. package/dist/logitron-logger.module-Bq3_KckP.d.ts.map +0 -1
  54. package/dist/logitron-logger.module-BqNKp0Fs.js.map +0 -1
  55. package/dist/logitron-logger.module-DW_mmXbj.d.mts.map +0 -1
  56. package/dist/promise-C4pQPcK4.mjs.map +0 -1
  57. package/dist/promise-DaiZ2BaH.js.map +0 -1
  58. package/dist/transport.manager-5VVdqS3o.mjs.map +0 -1
  59. package/dist/transport.manager-DCOm4uIQ.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,8 +1,95 @@
1
- import { A as RequestMetrics, C as SamplingConfig, D as HttpError, E as TraceIdExtractorConfig, O as HttpRequest, S as RequestContext, T as TraceIdConfig, _ as LogLevelString, a as Environment, b as NamespaceLevels, c as GracefulShutdownConfig, d as ILogger, f as ILoggerDefault, g as LogLevel, h as LogFieldKey, i as DEFAULT_LOG_LEVELS, j as RequestTiming, k as HttpResponse, l as IBaseLogger, m as LogEntry, n as CustomLevelMethods, o as ErrorSerializationOptions, p as LogColor, r as DEFAULT_LOG_COLORS, s as ExtractLevels, t as ContextData, u as ILogFormatter, v as LoggerConfig, w as TimingEntry, x as RedactConfig, y as LoggerWithLevels } from "./index-CHIsdA9n.js";
2
- import { a as LogixiaOptionsFactory, c as LogixiaLoggerService, i as LogixiaLoggerModule, l as LogixiaLogger, n as LOGIXIA_LOGGER_PREFIX, o as WebSocketTraceInterceptor, r as LogixiaAsyncOptions, s as KafkaTraceInterceptor, t as LOGIXIA_LOGGER_CONFIG, u as createLogger$1 } from "./logitron-logger.module-Bq3_KckP.js";
1
+ import { C as SamplingConfig, E as TraceIdExtractorConfig, G as RequestTiming, H as HttpRequest, S as RequestContext, T as TraceIdConfig, U as HttpResponse, V as HttpError, W as RequestMetrics, _ as LogLevelString, a as Environment, b as NamespaceLevels, c as GracefulShutdownConfig, d as ILogger, f as ILoggerDefault, g as LogLevel, h as LogFieldKey, i as DEFAULT_LOG_LEVELS, l as IBaseLogger, m as LogEntry, n as CustomLevelMethods, o as ErrorSerializationOptions, p as LogColor, r as DEFAULT_LOG_COLORS, s as ExtractLevels, t as ContextData, u as ILogFormatter, v as LoggerConfig, w as TimingEntry, x as RedactConfig, y as LoggerWithLevels } from "./index-t-ActikQ.js";
2
+ import { a as LogixiaOptionsFactory, c as LogixiaLoggerService, d as LogixiaPlugin, f as PluginRegistry, i as LogixiaLoggerModule, l as LogixiaLogger, m as usePlugin, n as LOGIXIA_LOGGER_PREFIX, o as WebSocketTraceInterceptor, p as globalPluginRegistry, r as LogixiaAsyncOptions, s as KafkaTraceInterceptor, t as LOGIXIA_LOGGER_CONFIG, u as createLogger$1 } from "./logitron-logger.module-CMRBDGwm.js";
3
3
  import "./search-Cg_OasF-.js";
4
+ import { ArgumentsHost, ExceptionFilter } from "@nestjs/common";
4
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
+ import { IncomingMessage, ServerResponse } from "node:http";
5
7
 
8
+ //#region src/core/nestjs-extras.d.ts
9
+
10
+ /**
11
+ * Inject the Logixia logger registered in the current NestJS DI container.
12
+ *
13
+ * Equivalent to `@Inject(LOGIXIA_LOGGER_TOKEN)` but without needing to import
14
+ * the internal token constant yourself.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * constructor(@InjectLogger() private readonly logger: LogixiaLoggerService) {}
19
+ * ```
20
+ */
21
+ declare const InjectLogger: () => ParameterDecorator;
22
+ interface LogMethodOptions {
23
+ /**
24
+ * Log level to use for entry / exit messages.
25
+ * @default 'debug'
26
+ */
27
+ level?: 'debug' | 'info' | 'verbose';
28
+ /**
29
+ * Whether to log the arguments passed to the method.
30
+ * Disable for high-throughput hot paths.
31
+ * @default true
32
+ */
33
+ logArgs?: boolean;
34
+ /**
35
+ * Whether to log the return value of the method.
36
+ * @default false
37
+ */
38
+ logResult?: boolean;
39
+ /**
40
+ * Whether to log error stack traces for thrown errors.
41
+ * @default true
42
+ */
43
+ logErrors?: boolean;
44
+ /**
45
+ * Custom label used in log messages instead of the auto-detected class.method name.
46
+ */
47
+ label?: string;
48
+ }
49
+ /**
50
+ * Method decorator that auto-logs entry, exit, duration, and errors.
51
+ *
52
+ * Works on both async and sync methods. Attaches to the logger found on the
53
+ * class instance via a `logger` property (the conventional NestJS name).
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * @LogMethod({ level: 'info', logArgs: true })
58
+ * async processPayment(orderId: string): Promise<void> { … }
59
+ * ```
60
+ */
61
+ declare function LogMethod(options?: LogMethodOptions): MethodDecorator;
62
+ /**
63
+ * Global NestJS exception filter that converts any exception into the standard
64
+ * `LogixiaErrorResponse` wire format and logs it with full request context.
65
+ *
66
+ * Handles three exception types in priority order:
67
+ * 1. `LogixiaException` — typed fields used directly
68
+ * 2. NestJS `HttpException` — status + message extracted
69
+ * 3. Unknown / plain Error — falls back to 500 `server_error`
70
+ *
71
+ * **Debug stripping in production:**
72
+ * The `debug` block is automatically stripped when `NODE_ENV === 'production'`.
73
+ *
74
+ * **Trace ID headers:**
75
+ * `X-Trace-ID` and `X-Request-ID` are echoed back on every error response so
76
+ * clients can correlate with server logs.
77
+ *
78
+ * **Retry-After header:**
79
+ * Automatically added for `429` responses (`Retry-After: 60`).
80
+ *
81
+ * Register in `main.ts`:
82
+ * ```ts
83
+ * const logger = app.get(LogixiaLoggerService);
84
+ * app.useGlobalFilters(new LogixiaExceptionFilter(logger));
85
+ * ```
86
+ */
87
+ declare class LogixiaExceptionFilter implements ExceptionFilter {
88
+ private readonly logger?;
89
+ constructor(logger?: LogixiaLoggerService | undefined);
90
+ catch(exception: unknown, host: ArgumentsHost): void;
91
+ }
92
+ //#endregion
6
93
  //#region src/formatters/json.formatter.d.ts
7
94
  declare class JsonFormatter implements ILogFormatter {
8
95
  private includeTimestamp;
@@ -71,6 +158,118 @@ declare function isError(value: unknown): value is Error;
71
158
  */
72
159
  declare function normalizeError(error: unknown): Error;
73
160
  //#endregion
161
+ //#region src/utils/otel.d.ts
162
+ /**
163
+ * logixia — OpenTelemetry auto trace-log correlation
164
+ *
165
+ * Zero-config: if `@opentelemetry/api` is installed, logixia automatically
166
+ * reads the active span context and injects `traceId`, `spanId`, and
167
+ * `traceFlags` into every log entry. No manual wiring needed.
168
+ *
169
+ * The integration is completely optional — if `@opentelemetry/api` is absent
170
+ * (or the OTel SDK is not initialised), all helpers return `undefined` silently.
171
+ *
172
+ * Additionally exposes a `createOtelLogExporter()` factory that routes every
173
+ * logixia log entry through the active OTel LoggerProvider (OTLP export).
174
+ *
175
+ * @example Auto bridge (zero config)
176
+ * ```ts
177
+ * import { createLogger } from 'logixia';
178
+ * import { initOtelBridge } from 'logixia';
179
+ *
180
+ * // Call once at app startup, after your OTel SDK is initialised
181
+ * initOtelBridge();
182
+ *
183
+ * const logger = createLogger({ appName: 'api' });
184
+ * // Every logger.info / warn / error call now auto-injects traceId + spanId
185
+ * // from the currently active OTel span — no per-call code needed.
186
+ * ```
187
+ *
188
+ * @example Manual span context injection
189
+ * ```ts
190
+ * import { getActiveOtelContext } from 'logixia';
191
+ *
192
+ * const ctx = getActiveOtelContext();
193
+ * await logger.info('Payment processed', { ...ctx, orderId: 'ord_123' });
194
+ * // → { traceId: 'abc...', spanId: 'def...', traceFlags: 1, orderId: 'ord_123' }
195
+ * ```
196
+ */
197
+ interface OtelSpanContext {
198
+ /** W3C 32-hex-char trace ID */
199
+ traceId: string;
200
+ /** W3C 16-hex-char span ID */
201
+ spanId: string;
202
+ /** W3C trace-flags integer (1 = sampled) */
203
+ traceFlags: number;
204
+ /** Whether this context is from a valid, sampled span */
205
+ isSampled: boolean;
206
+ }
207
+ interface OtelBridgeOptions {
208
+ /**
209
+ * Field name written to log entries for the trace ID.
210
+ * @default 'traceId'
211
+ */
212
+ traceIdField?: string;
213
+ /**
214
+ * Field name written to log entries for the span ID.
215
+ * @default 'spanId'
216
+ */
217
+ spanIdField?: string;
218
+ /**
219
+ * Field name written to log entries for trace flags.
220
+ * @default 'traceFlags'
221
+ */
222
+ traceFlagsField?: string;
223
+ /**
224
+ * Only inject context when the span is sampled (traceFlags bit 1 set).
225
+ * @default false
226
+ */
227
+ sampledOnly?: boolean;
228
+ }
229
+ /**
230
+ * Read the currently active OTel span context (if any) and return its fields
231
+ * in a plain object suitable for spreading into a log entry.
232
+ *
233
+ * Returns `undefined` when:
234
+ * - `@opentelemetry/api` is not installed
235
+ * - No active span exists (root context)
236
+ * - The span context is invalid (all-zeros)
237
+ */
238
+ declare function getActiveOtelContext(opts?: OtelBridgeOptions): OtelSpanContext | undefined;
239
+ /**
240
+ * Returns a metadata object with OTel context fields ready to merge into a log call,
241
+ * using the configured field names.
242
+ *
243
+ * Returns `{}` when no active span exists (safe to spread unconditionally).
244
+ *
245
+ * @example
246
+ * ```ts
247
+ * await logger.info('Payment processed', {
248
+ * ...getOtelMetaFields(),
249
+ * orderId: 'ord_123',
250
+ * });
251
+ * ```
252
+ */
253
+ declare function getOtelMetaFields(opts?: OtelBridgeOptions): Record<string, unknown>;
254
+ /**
255
+ * Initialise the global OTel bridge.
256
+ *
257
+ * Once called, logixia's internal log pipeline checks for an active OTel span
258
+ * on **every** log call and automatically merges the span context into the
259
+ * entry's metadata — no per-call wiring needed.
260
+ *
261
+ * Call once at app startup, **after** the OTel SDK has been initialised:
262
+ * ```ts
263
+ * import { initOtelBridge } from 'logixia';
264
+ * initOtelBridge();
265
+ * ```
266
+ */
267
+ declare function initOtelBridge(opts?: OtelBridgeOptions): void;
268
+ /**
269
+ * Disable the OTel bridge (useful for tests).
270
+ */
271
+ declare function disableOtelBridge(): void;
272
+ //#endregion
74
273
  //#region src/utils/redact.utils.d.ts
75
274
  /**
76
275
  * Deep-clone and redact an object according to the given RedactConfig.
@@ -173,6 +372,106 @@ declare const DEFAULT_TRACE_HEADERS: string[];
173
372
  */
174
373
  declare function createTraceMiddleware(config: TraceIdConfig): (req: unknown, res: unknown, next: () => void) => void;
175
374
  //#endregion
375
+ //#region src/utils/typed-logger.d.ts
376
+ /**
377
+ * logixia — TypeScript typed log fields
378
+ *
379
+ * Solves the type-safety gap: standard `Record<string, unknown>` metadata gives
380
+ * zero IDE autocomplete and lets typos slip silently into production logs.
381
+ *
382
+ * Two complementary utilities:
383
+ *
384
+ * 1. `createTypedLogger<TFields>()` — wraps any IBaseLogger so that the second
385
+ * argument of every log method is constrained to `TFields` (a typed object).
386
+ * Compile-time safety, zero runtime overhead.
387
+ *
388
+ * 2. `defineLogSchema<TFields>(schema)` — declares expected fields with optional
389
+ * validators. In development (NODE_ENV !== 'production') every log call is
390
+ * validated against the schema and a warning is emitted for missing required
391
+ * fields or type mismatches.
392
+ *
393
+ * @example
394
+ * ```ts
395
+ * import { createTypedLogger, defineLogSchema } from 'logixia';
396
+ *
397
+ * interface OrderFields {
398
+ * orderId: string;
399
+ * userId: string;
400
+ * amount?: number;
401
+ * currency?: string;
402
+ * }
403
+ *
404
+ * const schema = defineLogSchema<OrderFields>({
405
+ * orderId: { type: 'string', required: true },
406
+ * userId: { type: 'string', required: true },
407
+ * amount: { type: 'number' },
408
+ * currency: { type: 'string' },
409
+ * });
410
+ *
411
+ * const orderLogger = createTypedLogger<OrderFields>(baseLogger, schema);
412
+ * await orderLogger.info('Order created', { orderId: 'ord_123', userId: 'usr_456', amount: 99.99 });
413
+ * // ^^^^ fully typed autocomplete ^^^^
414
+ * ```
415
+ */
416
+ type LogFieldType = 'string' | 'number' | 'boolean' | 'object' | 'array';
417
+ interface LogFieldDef {
418
+ type: LogFieldType;
419
+ /** Emit a warning when this field is missing from the log call. Default: false */
420
+ required?: boolean;
421
+ /** Custom validator — return a string to emit it as a warning message. */
422
+ validate?: (value: unknown) => string | undefined;
423
+ }
424
+ type LogSchema<TFields extends Record<string, unknown>> = { [K in keyof TFields]: LogFieldDef };
425
+ interface CompiledSchema<TFields extends Record<string, unknown>> {
426
+ readonly fields: LogSchema<TFields>;
427
+ /**
428
+ * Validate a payload against the schema.
429
+ * Returns an array of warning strings (empty = pass).
430
+ * Only runs in non-production environments.
431
+ */
432
+ validate(payload: Partial<TFields>): string[];
433
+ }
434
+ /**
435
+ * Define a typed schema for a category of log entries.
436
+ *
437
+ * Call this once at module initialisation and pass it to `createTypedLogger`.
438
+ * In development, every log call is validated against the schema.
439
+ */
440
+ declare function defineLogSchema<TFields extends Record<string, unknown>>(fields: LogSchema<TFields>): CompiledSchema<TFields>;
441
+ /** IBaseLogger-compatible subset used by TypedLogger */
442
+ interface LoggerLike {
443
+ error(message: string | Error, data?: Record<string, unknown>): Promise<void>;
444
+ warn(message: string, data?: Record<string, unknown>): Promise<void>;
445
+ info(message: string, data?: Record<string, unknown>): Promise<void>;
446
+ debug(message: string, data?: Record<string, unknown>): Promise<void>;
447
+ verbose?(message: string, data?: Record<string, unknown>): Promise<void>;
448
+ trace?(message: string, data?: Record<string, unknown>): Promise<void>;
449
+ }
450
+ /**
451
+ * A logger whose metadata is typed to `TFields`.
452
+ *
453
+ * The `error` overload still accepts a plain `Error` object as the first arg
454
+ * (with optional `TFields` data) so the typed logger remains a drop-in replacement.
455
+ */
456
+ interface TypedLogger<TFields extends Record<string, unknown>> {
457
+ error(error: Error, data?: Partial<TFields>): Promise<void>;
458
+ error(message: string, data?: Partial<TFields>): Promise<void>;
459
+ warn(message: string, data?: Partial<TFields>): Promise<void>;
460
+ info(message: string, data?: Partial<TFields>): Promise<void>;
461
+ debug(message: string, data?: Partial<TFields>): Promise<void>;
462
+ verbose(message: string, data?: Partial<TFields>): Promise<void>;
463
+ trace(message: string, data?: Partial<TFields>): Promise<void>;
464
+ /** Access the underlying untyped logger if needed. */
465
+ readonly raw: LoggerLike;
466
+ }
467
+ /**
468
+ * Wrap any logixia logger with a type-safe field interface.
469
+ *
470
+ * @param logger Any object that implements `IBaseLogger` (e.g. the result of `createLogger()`)
471
+ * @param schema Optional schema for dev-time validation. Created with `defineLogSchema()`.
472
+ */
473
+ declare function createTypedLogger<TFields extends Record<string, unknown>>(logger: LoggerLike, schema?: CompiledSchema<TFields>): TypedLogger<TFields>;
474
+ //#endregion
176
475
  //#region src/context/async-context.d.ts
177
476
  interface LogContext {
178
477
  requestId?: string;
@@ -259,6 +558,438 @@ interface SamplingStats {
259
558
  windowStart: number;
260
559
  }
261
560
  //#endregion
561
+ //#region src/exceptions/types.d.ts
562
+ /**
563
+ * Unified error response shape for logixia.
564
+ *
565
+ * Design-inspired by Stripe (`type` + `code` + `param`), GitHub (`details[]`),
566
+ * Twilio (`doc_url`), and Cloudflare (`success: false` envelope).
567
+ *
568
+ * The shape is intentionally framework-agnostic — it works for HTTP, WebSocket,
569
+ * Queue/RPC, and any other transport. Your exception filter is responsible for
570
+ * serialising it onto the wire.
571
+ *
572
+ * @template TCode - Union of valid error code strings you define (e.g. `'PE-AUTH-001' | 'PE-USR-001'`).
573
+ * Defaults to `string` for untyped usage.
574
+ * @template TType - Union of valid error type strings you define (e.g. `'authentication_error' | 'validation_error'`).
575
+ * Defaults to `string` for untyped usage.
576
+ *
577
+ * @example Fully typed usage
578
+ * ```ts
579
+ * type AppCode = 'PE-AUTH-001' | 'PE-VAL-001';
580
+ * type AppType = 'authentication_error' | 'validation_error';
581
+ *
582
+ * const response: LogixiaErrorResponse<AppCode, AppType> = { ... };
583
+ * ```
584
+ */
585
+ interface LogixiaErrorResponse<TCode extends string = string, TType extends string = string> {
586
+ /** Always `false` — allows `if (response.success)` branching on the client. */
587
+ success: false;
588
+ error: {
589
+ /**
590
+ * Broad category that tells the client **how** to handle this error.
591
+ * e.g. `'validation_error'` → show field errors; `'authentication_error'` → redirect to login.
592
+ */
593
+ type: TType;
594
+ /**
595
+ * Machine-readable, stable error identifier.
596
+ * e.g. `'PE-AUTH-001'` — never changes; safe to switch/match on.
597
+ */
598
+ code: TCode;
599
+ /**
600
+ * Human-readable message shown to the end-user.
601
+ * May change between releases — do not rely on it programmatically.
602
+ */
603
+ message: string;
604
+ /**
605
+ * The specific request field that caused this error (Stripe pattern).
606
+ * e.g. `'email'` | `'metadata.name'`
607
+ */
608
+ param?: string;
609
+ /**
610
+ * Array of field-level errors for batch validation failures (GitHub pattern).
611
+ * Only present when more than one field is invalid.
612
+ */
613
+ details?: ErrorDetail[];
614
+ /**
615
+ * Documentation URL for this specific error (Twilio pattern).
616
+ * e.g. `'https://docs.example.com/errors/PE-AUTH-001'`
617
+ */
618
+ doc_url?: string;
619
+ };
620
+ meta: {
621
+ /** ULID / UUID-based request identifier for log correlation. */
622
+ request_id: string;
623
+ /** ISO 8601 timestamp of when the error was produced. */
624
+ timestamp: string;
625
+ /** Request path that caused the error. e.g. `'/api/v1/auth/login'` */
626
+ path: string;
627
+ /** HTTP status code mirrored in the body for clients that can't read headers. */
628
+ status: number;
629
+ };
630
+ /**
631
+ * Developer / diagnostic context.
632
+ *
633
+ * ⚠️ **Strip this in production.** The `ErrorResponseBuilder` always populates it
634
+ * (when possible); your exception filter should call `delete response.debug` before
635
+ * sending the response when `NODE_ENV === 'production'`.
636
+ */
637
+ debug?: {
638
+ /** Full stack trace of the underlying error. */
639
+ stack?: string;
640
+ /** Serialised `error.cause` (ES 2022 chained errors). */
641
+ cause?: string;
642
+ /** Originating micro-service name. e.g. `'gatekeeper'` | `'worker'` */
643
+ service?: string;
644
+ /** Wall-clock time in ms from `request.startTime` to error handling. */
645
+ duration_ms?: number;
646
+ };
647
+ }
648
+ /**
649
+ * A single field-level validation error (GitHub pattern).
650
+ *
651
+ * @example
652
+ * ```ts
653
+ * { field: 'email', message: 'must be a valid email address', code: 'invalid_format' }
654
+ * { field: 'password', message: 'required', code: 'required' }
655
+ * ```
656
+ */
657
+ interface ErrorDetail {
658
+ /** Dot-notation field path. e.g. `'email'` | `'user.address.zip'` */
659
+ field: string;
660
+ /** Human-readable reason this field failed. */
661
+ message: string;
662
+ /**
663
+ * Machine-readable failure code for this field.
664
+ * Suggested values: `'required'` | `'invalid_format'` | `'too_long'` | `'too_short'` |
665
+ * `'out_of_range'` | `'invalid_enum_value'` | `'duplicate'`
666
+ */
667
+ code: string;
668
+ }
669
+ //#endregion
670
+ //#region src/exceptions/builder.d.ts
671
+ /** Input parameters for `ErrorResponseBuilder.build`. */
672
+ interface BuildParams {
673
+ /** The caught exception — any type. */
674
+ exception: unknown;
675
+ /**
676
+ * Request / correlation ID to embed in `meta.request_id`.
677
+ * If omitted a UUID-based ID is auto-generated: `req_<uuid without dashes>`.
678
+ */
679
+ requestId?: string | undefined;
680
+ /** Request path. e.g. `'/api/v1/auth/login'` */
681
+ path: string;
682
+ /**
683
+ * Originating service name for `debug.service`.
684
+ * e.g. `process.env.SERVICE_NAME` → `'gatekeeper'`
685
+ */
686
+ service?: string | undefined;
687
+ /**
688
+ * `Date.now()` captured at the start of the request.
689
+ * When present, `debug.duration_ms` is computed automatically.
690
+ */
691
+ startTime?: number | undefined;
692
+ }
693
+ /**
694
+ * Generates a `req_` prefixed request ID using Node's built-in `crypto.randomUUID`.
695
+ * No extra dependencies required.
696
+ *
697
+ * @example `'req_550e8400e29b41d4a716446655440000'`
698
+ */
699
+ declare function generateRequestId(): string;
700
+ declare class ErrorResponseBuilder {
701
+ /**
702
+ * Build a `LogixiaErrorResponse` from any thrown value.
703
+ *
704
+ * @param params - See `BuildParams`.
705
+ * @returns The unified error response and the HTTP status code to send.
706
+ *
707
+ * @example In a NestJS exception filter
708
+ * ```ts
709
+ * const { response, httpStatus } = ErrorResponseBuilder.build<AppCode, AppType>({
710
+ * exception,
711
+ * requestId: request.headers['x-trace-id'] as string | undefined,
712
+ * path: request.url,
713
+ * service: process.env.SERVICE_NAME,
714
+ * startTime: request.startTime,
715
+ * });
716
+ *
717
+ * if (process.env.NODE_ENV === 'production') delete response.debug;
718
+ * response.setHeader('X-Trace-ID', response.meta.request_id);
719
+ * response.status(httpStatus).json(response);
720
+ * ```
721
+ */
722
+ static build<TCode extends string = string, TType extends string = string>(params: BuildParams): {
723
+ response: LogixiaErrorResponse<TCode, TType>;
724
+ httpStatus: number;
725
+ };
726
+ }
727
+ //#endregion
728
+ //#region src/exceptions/exception.d.ts
729
+ /**
730
+ * Constructor options for `LogixiaException`.
731
+ *
732
+ * All user-supplied fields — logixia only owns the wire format.
733
+ */
734
+ interface LogixiaExceptionOptions<TCode extends string = string, TType extends string = string> {
735
+ /**
736
+ * Machine-readable, stable error code.
737
+ * e.g. `'PE-AUTH-001'`
738
+ */
739
+ code: TCode;
740
+ /**
741
+ * Broad error type category.
742
+ * e.g. `'authentication_error'` | `'validation_error'` | `'rate_limit_error'`
743
+ */
744
+ type: TType;
745
+ /**
746
+ * HTTP status code to send on the wire.
747
+ * e.g. `401` | `400` | `429` | `500`
748
+ */
749
+ httpStatus: number;
750
+ /**
751
+ * Human-readable message for the end-user.
752
+ * This IS sent in the response body — keep it safe (no internal paths, etc.).
753
+ */
754
+ message: string;
755
+ /**
756
+ * The specific request field that caused this error (Stripe pattern).
757
+ * e.g. `'email'` | `'metadata.name'`
758
+ */
759
+ param?: string;
760
+ /**
761
+ * Array of per-field validation errors (GitHub pattern).
762
+ * Typically used for `400` / `422` validation failures.
763
+ */
764
+ details?: ErrorDetail[];
765
+ /**
766
+ * Documentation URL for this error (Twilio pattern).
767
+ * e.g. `'https://docs.example.com/errors/PE-AUTH-001'`
768
+ */
769
+ docUrl?: string;
770
+ /**
771
+ * Original error for ES 2022 cause chaining.
772
+ * Serialised into `debug.cause` by the `ErrorResponseBuilder`.
773
+ * Never sent to the client in production.
774
+ */
775
+ cause?: Error;
776
+ /**
777
+ * Arbitrary metadata for logging purposes only.
778
+ * This is **never** included in the HTTP response — it is passed to your
779
+ * logger / monitoring integrations through the exception object.
780
+ *
781
+ * @example
782
+ * ```ts
783
+ * metadata: { userId: 'u_abc', attemptCount: 3 }
784
+ * ```
785
+ */
786
+ metadata?: Record<string, unknown>;
787
+ }
788
+ declare class LogixiaException<TCode extends string = string, TType extends string = string> extends Error {
789
+ /** @readonly The machine-readable error code supplied by the caller. */
790
+ readonly errorCode: TCode;
791
+ /** @readonly The error type category supplied by the caller. */
792
+ readonly errorType: TType;
793
+ /** @readonly HTTP status code to respond with. */
794
+ readonly httpStatus: number;
795
+ /** @readonly Field pointer that caused this error (Stripe pattern). */
796
+ readonly param: string | undefined;
797
+ /** @readonly Field-level validation errors (GitHub pattern). */
798
+ readonly details: ErrorDetail[] | undefined;
799
+ /** @readonly Documentation URL for this error (Twilio pattern). */
800
+ readonly docUrl: string | undefined;
801
+ /**
802
+ * @readonly Extra context for your logger — never serialised into the HTTP response.
803
+ */
804
+ readonly metadata: Record<string, unknown> | undefined;
805
+ constructor(options: LogixiaExceptionOptions<TCode, TType>);
806
+ }
807
+ /**
808
+ * Returns `true` when `value` is a `LogixiaException` instance.
809
+ *
810
+ * Useful in exception filters or middleware that need to distinguish a
811
+ * `LogixiaException` from a plain `Error` or a framework `HttpException`.
812
+ *
813
+ * @example
814
+ * ```ts
815
+ * if (isLogixiaException(err)) {
816
+ * console.log(err.errorCode, err.httpStatus);
817
+ * }
818
+ * ```
819
+ */
820
+ declare function isLogixiaException<TCode extends string = string, TType extends string = string>(value?: unknown): value is LogixiaException<TCode, TType>;
821
+ //#endregion
822
+ //#region src/metrics.d.ts
823
+ /**
824
+ * Increment a counter on each matching log entry.
825
+ *
826
+ * @example Count every error entry, labelled by context:
827
+ * ```ts
828
+ * error_count: { type: 'counter', levelFilter: 'error', labels: ['context'] }
829
+ * ```
830
+ *
831
+ * @example Count entries where payload.event === 'checkout':
832
+ * ```ts
833
+ * checkout_events: { type: 'counter', field: 'event', value: 'checkout' }
834
+ * ```
835
+ */
836
+ interface CounterConfig {
837
+ type: 'counter';
838
+ /** Only increment when `entry.level` equals this value. Omit to count all entries. */
839
+ levelFilter?: string;
840
+ /**
841
+ * Only increment when `entry.payload[field] === value`.
842
+ * If omitted, every entry (matching `levelFilter`) is counted.
843
+ */
844
+ field?: string;
845
+ value?: unknown;
846
+ /** `entry.payload` fields used as Prometheus label dimensions. `'level'` is also valid. */
847
+ labels?: string[];
848
+ help?: string;
849
+ }
850
+ /**
851
+ * Observe a numeric payload field and bucket it into a Prometheus histogram.
852
+ *
853
+ * @example Duration histogram labelled by HTTP method and status code:
854
+ * ```ts
855
+ * http_request_duration: {
856
+ * type: 'histogram',
857
+ * field: 'duration',
858
+ * labels: ['method', 'statusCode'],
859
+ * buckets: [10, 25, 50, 100, 250, 500, 1000],
860
+ * }
861
+ * ```
862
+ */
863
+ interface HistogramConfig {
864
+ type: 'histogram';
865
+ /** The `entry.payload` field containing the numeric value to observe. */
866
+ field: string;
867
+ /** `entry.payload` fields used as Prometheus label dimensions. */
868
+ labels?: string[];
869
+ help?: string;
870
+ /**
871
+ * Bucket upper bounds (inclusive). Sorted automatically.
872
+ * Default: [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000]
873
+ */
874
+ buckets?: number[];
875
+ }
876
+ /**
877
+ * Track the most recent numeric value of a payload field as a gauge.
878
+ *
879
+ * @example Track live connection count:
880
+ * ```ts
881
+ * active_connections: { type: 'gauge', field: 'connections' }
882
+ * ```
883
+ */
884
+ interface GaugeConfig {
885
+ type: 'gauge';
886
+ /** The `entry.payload` field containing the numeric value. */
887
+ field: string;
888
+ /** `entry.payload` fields used as Prometheus label dimensions. */
889
+ labels?: string[];
890
+ help?: string;
891
+ }
892
+ type MetricConfig = CounterConfig | HistogramConfig | GaugeConfig;
893
+ type MetricsMap = Record<string, MetricConfig>;
894
+ /**
895
+ * A logixia plugin that extracts Prometheus-compatible metrics from log entries.
896
+ *
897
+ * Implements `LogixiaPlugin` — pass directly to `logger.use()`:
898
+ * ```ts
899
+ * const metrics = new MetricsPlugin({ ... });
900
+ * logger.use(metrics);
901
+ * ```
902
+ *
903
+ * Or use the `createMetricsPlugin()` factory (preferred):
904
+ * ```ts
905
+ * const metrics = createMetricsPlugin({ ... });
906
+ * logger.use(metrics);
907
+ * ```
908
+ */
909
+ declare class MetricsPlugin implements LogixiaPlugin {
910
+ readonly name = "logixia-metrics";
911
+ private readonly map;
912
+ private readonly metricState;
913
+ constructor(map: MetricsMap);
914
+ onInit(): void;
915
+ onLog(entry: LogEntry): LogEntry;
916
+ /**
917
+ * Render all registered metrics in the Prometheus text exposition format
918
+ * (version 0.0.4).
919
+ *
920
+ * All metric names are prefixed with `logixia_`.
921
+ *
922
+ * @example
923
+ * ```
924
+ * # HELP logixia_error_count Total error log entries
925
+ * # TYPE logixia_error_count counter
926
+ * logixia_error_count{context="OrderService"} 7
927
+ * ```
928
+ */
929
+ render(): string;
930
+ /**
931
+ * Reset all metric counters and observations back to zero.
932
+ * Useful between test runs or on a scheduled reset interval.
933
+ */
934
+ reset(): void;
935
+ /**
936
+ * Express route handler — call `app.get('/metrics', metrics.expressHandler())`.
937
+ *
938
+ * @example
939
+ * ```ts
940
+ * import express from 'express';
941
+ * const app = express();
942
+ * app.get('/metrics', metrics.expressHandler());
943
+ * ```
944
+ */
945
+ expressHandler(): (req: unknown, res: {
946
+ set(k: string, v: string): unknown;
947
+ end(body: string): void;
948
+ }) => void;
949
+ /**
950
+ * Raw Node.js `http` server handler.
951
+ * Responds to `GET /metrics` with the Prometheus text payload.
952
+ *
953
+ * @example Start a dedicated metrics server on the standard port:
954
+ * ```ts
955
+ * import http from 'node:http';
956
+ * const server = http.createServer(metrics.httpHandler());
957
+ * server.listen(9464); // Prometheus default port for custom exporters
958
+ * ```
959
+ */
960
+ httpHandler(): (req: IncomingMessage, res: ServerResponse) => void;
961
+ private initAllState;
962
+ private initSingleState;
963
+ }
964
+ /**
965
+ * Create a `MetricsPlugin` from a metrics map and return it ready for
966
+ * `logger.use()`.
967
+ *
968
+ * @example
969
+ * ```ts
970
+ * import { createMetricsPlugin } from 'logixia';
971
+ *
972
+ * const metrics = createMetricsPlugin({
973
+ * http_request_duration: {
974
+ * type: 'histogram',
975
+ * field: 'duration',
976
+ * labels: ['method', 'statusCode'],
977
+ * help: 'HTTP request duration in milliseconds',
978
+ * },
979
+ * error_count: {
980
+ * type: 'counter',
981
+ * levelFilter: 'error',
982
+ * labels: ['context'],
983
+ * help: 'Total error log entries',
984
+ * },
985
+ * });
986
+ *
987
+ * logger.use(metrics);
988
+ * app.get('/metrics', metrics.expressHandler());
989
+ * ```
990
+ */
991
+ declare function createMetricsPlugin(map: MetricsMap): MetricsPlugin;
992
+ //#endregion
262
993
  //#region src/index.d.ts
263
994
  /**
264
995
  * Default configuration for Logixia logger
@@ -345,5 +1076,5 @@ declare const logger: LogixiaLogger<{
345
1076
  outputs: string[];
346
1077
  }>;
347
1078
  //#endregion
348
- export { ContextData, CustomLevelMethods, DEFAULT_CONFIG, DEFAULT_LOG_COLORS, DEFAULT_LOG_LEVELS, DEFAULT_TRACE_HEADERS, Environment, ErrorSerializationOptions, ExtractLevels, FlushOnExitOptions, GracefulShutdownConfig, HttpError, HttpRequest, HttpResponse, IBaseLogger, ILogFormatter, ILogger, ILoggerDefault, JsonFormatter, KafkaTraceInterceptor, LOGIXIA_LOGGER_CONFIG, LOGIXIA_LOGGER_PREFIX, LogColor, type LogContext, LogEntry, LogFieldKey, LogLevel, LogLevelString, LoggerConfig, LoggerConfig as LoggerConfigInterface, LoggerWithLevels, LogixiaAsyncOptions, LogixiaContext, LogixiaLogger, LogixiaLoggerModule, LogixiaLoggerService, LogixiaOptionsFactory, NamespaceLevels, type RedactConfig, RequestContext, RequestMetrics, RequestTiming, SamplingConfig, type SamplingStats, TextFormatter, TimingEntry, TraceIdConfig, TraceIdExtractorConfig, WebSocketTraceInterceptor, applyRedaction, createExpressContextMiddleware, createFastifyContextHook, createLogger, createLoggerService, createTraceMiddleware, deregisterFromShutdown, extractTraceId, flushOnExit, generateTraceId, getCurrentTraceId, isError, logger, normalizeError, redactObject, registerForShutdown, resetShutdownHandlers, runWithTraceId, serializeError, setTraceId, traceStorage };
1079
+ export { type BuildParams, type CompiledSchema, ContextData, type CounterConfig, CustomLevelMethods, DEFAULT_CONFIG, DEFAULT_LOG_COLORS, DEFAULT_LOG_LEVELS, DEFAULT_TRACE_HEADERS, Environment, type ErrorDetail, ErrorResponseBuilder, ErrorSerializationOptions, ExtractLevels, FlushOnExitOptions, type GaugeConfig, GracefulShutdownConfig, type HistogramConfig, HttpError, HttpRequest, HttpResponse, IBaseLogger, ILogFormatter, ILogger, ILoggerDefault, InjectLogger, JsonFormatter, KafkaTraceInterceptor, LOGIXIA_LOGGER_CONFIG, LOGIXIA_LOGGER_PREFIX, LogColor, type LogContext, LogEntry, type LogFieldDef, LogFieldKey, type LogFieldType, LogLevel, LogLevelString, LogMethod, type LogMethodOptions, type LogSchema, LoggerConfig, LoggerConfig as LoggerConfigInterface, type LoggerLike, LoggerWithLevels, LogixiaAsyncOptions, LogixiaContext, type LogixiaErrorResponse, LogixiaException, LogixiaExceptionFilter, type LogixiaExceptionOptions, LogixiaLogger, LogixiaLoggerModule, LogixiaLoggerService, LogixiaOptionsFactory, type LogixiaPlugin, type MetricConfig, type MetricsMap, MetricsPlugin, NamespaceLevels, type OtelBridgeOptions, type OtelSpanContext, PluginRegistry, type RedactConfig, RequestContext, RequestMetrics, RequestTiming, SamplingConfig, type SamplingStats, TextFormatter, TimingEntry, TraceIdConfig, TraceIdExtractorConfig, type TypedLogger, WebSocketTraceInterceptor, applyRedaction, createExpressContextMiddleware, createFastifyContextHook, createLogger, createLoggerService, createMetricsPlugin, createTraceMiddleware, createTypedLogger, defineLogSchema, deregisterFromShutdown, disableOtelBridge, extractTraceId, flushOnExit, generateRequestId, generateTraceId, getActiveOtelContext, getCurrentTraceId, getOtelMetaFields, globalPluginRegistry, initOtelBridge, isError, isLogixiaException, logger, normalizeError, redactObject, registerForShutdown, resetShutdownHandlers, runWithTraceId, serializeError, setTraceId, traceStorage, usePlugin };
349
1080
  //# sourceMappingURL=index.d.ts.map