logixia 1.8.2 → 1.8.4

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 (88) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/{index-CthBT3t8.d.mts → index-DknhKCCg.d.ts} +12 -1
  3. package/dist/index-DknhKCCg.d.ts.map +1 -0
  4. package/dist/{index-ClPZrfIU.d.ts → index-DnhKoNBG.d.mts} +12 -1
  5. package/dist/index-DnhKoNBG.d.mts.map +1 -0
  6. package/dist/index.d.mts +87 -16
  7. package/dist/index.d.mts.map +1 -1
  8. package/dist/index.d.ts +86 -15
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +78 -40
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +77 -37
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/{logitron-logger.module-Dx2mUz-g.d.ts → logitron-logger.module-BkPXi0He.d.ts} +97 -5
  15. package/dist/logitron-logger.module-BkPXi0He.d.ts.map +1 -0
  16. package/dist/logitron-logger.module-CMDM61Iz.js +2566 -0
  17. package/dist/logitron-logger.module-CMDM61Iz.js.map +1 -0
  18. package/dist/{logitron-logger.module-KU_L04y1.d.mts → logitron-logger.module-Cd5M_59H.d.mts} +97 -5
  19. package/dist/logitron-logger.module-Cd5M_59H.d.mts.map +1 -0
  20. package/dist/logitron-logger.module-uyg1-Khn.mjs +2285 -0
  21. package/dist/logitron-logger.module-uyg1-Khn.mjs.map +1 -0
  22. package/dist/middleware.d.mts +1 -1
  23. package/dist/middleware.d.mts.map +1 -1
  24. package/dist/middleware.d.ts +1 -1
  25. package/dist/middleware.d.ts.map +1 -1
  26. package/dist/middleware.js +4 -1
  27. package/dist/middleware.js.map +1 -1
  28. package/dist/middleware.mjs +4 -1
  29. package/dist/middleware.mjs.map +1 -1
  30. package/dist/nest.d.mts +4 -44
  31. package/dist/nest.d.mts.map +1 -1
  32. package/dist/nest.d.ts +4 -44
  33. package/dist/nest.d.ts.map +1 -1
  34. package/dist/nest.js +3 -93
  35. package/dist/nest.mjs +3 -92
  36. package/dist/search.d.mts +1 -1
  37. package/dist/search.js +1 -1
  38. package/dist/search.mjs +1 -1
  39. package/dist/testing.d.mts +1 -1
  40. package/dist/testing.d.ts +1 -1
  41. package/dist/{transport.manager-BCnLEmOy.mjs → transport.manager-D3U03fJg.mjs} +21 -11
  42. package/dist/transport.manager-D3U03fJg.mjs.map +1 -0
  43. package/dist/{transport.manager-DU1W0wV3.js → transport.manager-DPjB-dFH.js} +49 -15
  44. package/dist/transport.manager-DPjB-dFH.js.map +1 -0
  45. package/dist/transports.d.mts +3 -1
  46. package/dist/transports.d.mts.map +1 -1
  47. package/dist/transports.d.ts +3 -1
  48. package/dist/transports.d.ts.map +1 -1
  49. package/dist/transports.js +1 -1
  50. package/dist/transports.mjs +1 -1
  51. package/package.json +24 -23
  52. package/dist/build-DOx-YxF1.js +0 -536
  53. package/dist/build-DOx-YxF1.js.map +0 -1
  54. package/dist/build-DWmxA6A2.mjs +0 -536
  55. package/dist/build-DWmxA6A2.mjs.map +0 -1
  56. package/dist/chunk-BTgCAUrQ.js +0 -53
  57. package/dist/chunk-uEZWKkIX.mjs +0 -32
  58. package/dist/esm-1Ra90uql.mjs +0 -4256
  59. package/dist/esm-1Ra90uql.mjs.map +0 -1
  60. package/dist/esm-FNhqFIqG.js +0 -4267
  61. package/dist/esm-FNhqFIqG.js.map +0 -1
  62. package/dist/index-ClPZrfIU.d.ts.map +0 -1
  63. package/dist/index-CthBT3t8.d.mts.map +0 -1
  64. package/dist/lib-8XKCHDOH.mjs +0 -66301
  65. package/dist/lib-8XKCHDOH.mjs.map +0 -1
  66. package/dist/lib-BNEYXXTQ.js +0 -66304
  67. package/dist/lib-BNEYXXTQ.js.map +0 -1
  68. package/dist/logitron-logger.module-DucvDnxZ.mjs +0 -10986
  69. package/dist/logitron-logger.module-DucvDnxZ.mjs.map +0 -1
  70. package/dist/logitron-logger.module-Dx2mUz-g.d.ts.map +0 -1
  71. package/dist/logitron-logger.module-Fof9Er2E.js +0 -11260
  72. package/dist/logitron-logger.module-Fof9Er2E.js.map +0 -1
  73. package/dist/logitron-logger.module-KU_L04y1.d.mts.map +0 -1
  74. package/dist/nest.js.map +0 -1
  75. package/dist/nest.mjs.map +0 -1
  76. package/dist/promise-BI-3eI4n.js +0 -22743
  77. package/dist/promise-BI-3eI4n.js.map +0 -1
  78. package/dist/promise-BrZcjavs.mjs +0 -22740
  79. package/dist/promise-BrZcjavs.mjs.map +0 -1
  80. package/dist/sqlite3-CSkpjC90.js +0 -420
  81. package/dist/sqlite3-CSkpjC90.js.map +0 -1
  82. package/dist/sqlite3-DD2_nRRH.mjs +0 -417
  83. package/dist/sqlite3-DD2_nRRH.mjs.map +0 -1
  84. package/dist/transport.manager-BCnLEmOy.mjs.map +0 -1
  85. package/dist/transport.manager-DU1W0wV3.js.map +0 -1
  86. /package/dist/{search-DanSf_yc.d.mts → search-DN676Dnz.d.mts} +0 -0
  87. /package/dist/{search-1txemGPh.mjs → search-DOvSI-mb.mjs} +0 -0
  88. /package/dist/{search-DeZHhWxB.js → search-DoZF3RZj.js} +0 -0
@@ -0,0 +1,2566 @@
1
+ const require_transport_manager = require('./transport.manager-DPjB-dFH.js');
2
+ let fast_json_stringify = require("fast-json-stringify");
3
+ fast_json_stringify = require_transport_manager.__toESM(fast_json_stringify);
4
+ let node_async_hooks = require("node:async_hooks");
5
+ node_async_hooks = require_transport_manager.__toESM(node_async_hooks);
6
+ let node_crypto = require("node:crypto");
7
+ node_crypto = require_transport_manager.__toESM(node_crypto);
8
+ let crypto = require("crypto");
9
+ crypto = require_transport_manager.__toESM(crypto);
10
+ let __nestjs_common = require("@nestjs/common");
11
+ __nestjs_common = require_transport_manager.__toESM(__nestjs_common);
12
+ let rxjs = require("rxjs");
13
+ rxjs = require_transport_manager.__toESM(rxjs);
14
+
15
+ //#region src/context/async-context.ts
16
+ /** Generates an 8-character random ID using Node's crypto module. */
17
+ function randomShortId() {
18
+ return (0, node_crypto.randomUUID)().slice(0, 8);
19
+ }
20
+ const _storage = new node_async_hooks.AsyncLocalStorage();
21
+ const LogixiaContext = {
22
+ run(store, callback) {
23
+ const parent = _storage.getStore() ?? {};
24
+ return _storage.run({
25
+ ...parent,
26
+ ...store
27
+ }, callback);
28
+ },
29
+ get() {
30
+ return _storage.getStore();
31
+ },
32
+ set(fields) {
33
+ const store = _storage.getStore();
34
+ if (!store) return;
35
+ Object.assign(store, fields);
36
+ },
37
+ getStorage() {
38
+ return _storage;
39
+ }
40
+ };
41
+ /**
42
+ * Create an Express/Connect-compatible middleware that wraps each request in
43
+ * a `LogixiaContext.run()` scope populated with common request fields.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * import { createExpressContextMiddleware } from 'logixia';
48
+ * app.use(createExpressContextMiddleware());
49
+ * ```
50
+ */
51
+ function createExpressContextMiddleware(options = {}) {
52
+ const { enrich, traceIdHeader = "x-trace-id" } = options;
53
+ return function logixiaContextMiddleware(req, _res, next) {
54
+ const base = { traceId: (req["headers"] ?? {})[traceIdHeader] ?? randomShortId() };
55
+ LogixiaContext.run({
56
+ ...base,
57
+ ...enrich ? enrich(req) : {}
58
+ }, next);
59
+ };
60
+ }
61
+ /**
62
+ * Create a Fastify lifecycle hook that wraps each request in a context scope.
63
+ *
64
+ * Register with `fastify.addHook('onRequest', createFastifyContextHook())`.
65
+ */
66
+ function createFastifyContextHook(options = {}) {
67
+ const { enrich, traceIdHeader = "x-trace-id" } = options;
68
+ return function logixiaFastifyHook(request, _reply, done) {
69
+ const base = { traceId: (request["headers"] ?? {})[traceIdHeader] ?? request["id"] ?? randomShortId() };
70
+ LogixiaContext.run({
71
+ ...base,
72
+ ...enrich ? enrich(request) : {}
73
+ }, done);
74
+ };
75
+ }
76
+
77
+ //#endregion
78
+ //#region src/plugin.ts
79
+ /**
80
+ * Holds an ordered list of `LogixiaPlugin` instances and dispatches lifecycle
81
+ * events to them. One registry is created per logger instance; a global
82
+ * singleton is also exported for process-wide registration.
83
+ */
84
+ var PluginRegistry = class {
85
+ constructor() {
86
+ this._plugins = [];
87
+ }
88
+ /**
89
+ * Register a plugin. Silently skips if a plugin with the same `name` is
90
+ * already registered on this registry.
91
+ */
92
+ register(plugin) {
93
+ if (this._plugins.some((p) => p.name === plugin.name)) return;
94
+ this._plugins.push(plugin);
95
+ if (plugin.onInit) {
96
+ const result = plugin.onInit();
97
+ if (result instanceof Promise) result.catch(() => {});
98
+ }
99
+ }
100
+ /** Remove a previously registered plugin by name. No-op if not found. */
101
+ unregister(name) {
102
+ const idx = this._plugins.findIndex((p) => p.name === name);
103
+ if (idx !== -1) this._plugins.splice(idx, 1);
104
+ }
105
+ /** Returns `true` if a plugin with the given name is registered. */
106
+ has(name) {
107
+ return this._plugins.some((p) => p.name === name);
108
+ }
109
+ /** Number of currently registered plugins. */
110
+ get size() {
111
+ return this._plugins.length;
112
+ }
113
+ /**
114
+ * Run all `onLog` hooks in order.
115
+ * Returns `null` if any plugin cancels the entry; otherwise returns the
116
+ * (possibly transformed) entry.
117
+ */
118
+ async runOnLog(entry) {
119
+ let current = entry;
120
+ for (const plugin of this._plugins) {
121
+ if (!plugin.onLog) continue;
122
+ current = await plugin.onLog(current);
123
+ if (current === null) return null;
124
+ }
125
+ return current;
126
+ }
127
+ /**
128
+ * Notify all `onError` hooks.
129
+ * Errors thrown inside hooks are swallowed to prevent error cascades.
130
+ */
131
+ async runOnError(error, entry) {
132
+ for (const plugin of this._plugins) if (plugin.onError) {
133
+ const r = plugin.onError(error, entry);
134
+ if (r instanceof Promise) await r.catch(() => {});
135
+ }
136
+ }
137
+ /** Run all `onShutdown` hooks concurrently. Hook errors are swallowed. */
138
+ async runOnShutdown() {
139
+ await Promise.all(this._plugins.filter((p) => Boolean(p.onShutdown)).map((p) => {
140
+ const r = p.onShutdown();
141
+ return r instanceof Promise ? r.catch(() => {}) : Promise.resolve();
142
+ }));
143
+ }
144
+ };
145
+ /**
146
+ * Module-level singleton registry.
147
+ *
148
+ * Plugins registered here are automatically copied into every **new** logger
149
+ * instance created after the registration. Already-created loggers are not
150
+ * retroactively affected — use `logger.use(plugin)` for per-instance control.
151
+ */
152
+ const globalPluginRegistry = new PluginRegistry();
153
+ /**
154
+ * Register a plugin in the global registry so it applies to every future
155
+ * logger instance.
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * import { usePlugin } from 'logixia';
160
+ *
161
+ * usePlugin({
162
+ * name: 'audit-sink',
163
+ * onLog(entry) {
164
+ * if (entry.level === 'error') auditQueue.push(entry);
165
+ * return entry;
166
+ * },
167
+ * });
168
+ * ```
169
+ */
170
+ function usePlugin(plugin) {
171
+ globalPluginRegistry.register(plugin);
172
+ }
173
+
174
+ //#endregion
175
+ //#region src/types/index.ts
176
+ const LogLevel = {
177
+ ERROR: "error",
178
+ WARN: "warn",
179
+ INFO: "info",
180
+ DEBUG: "debug",
181
+ TRACE: "trace",
182
+ VERBOSE: "verbose"
183
+ };
184
+ const DEFAULT_LOG_LEVELS = {
185
+ error: 0,
186
+ warn: 1,
187
+ info: 2,
188
+ debug: 3,
189
+ trace: 4,
190
+ verbose: 5
191
+ };
192
+ const DEFAULT_LOG_COLORS = {
193
+ error: "red",
194
+ warn: "yellow",
195
+ info: "green",
196
+ debug: "blue",
197
+ trace: "magenta",
198
+ verbose: "cyan"
199
+ };
200
+
201
+ //#endregion
202
+ //#region src/utils/error.utils.ts
203
+ const EXTRA_FIELDS = [
204
+ "code",
205
+ "statusCode",
206
+ "status",
207
+ "errno",
208
+ "syscall",
209
+ "path",
210
+ "address",
211
+ "port",
212
+ "type"
213
+ ];
214
+ /**
215
+ * Serialize an Error into a plain JSON-safe object, including:
216
+ * - `name`, `message`, `stack`
217
+ * - `cause` (recursively serialized, full ES2022 chain)
218
+ * - `errors` (for AggregateError)
219
+ * - standard Node.js error fields (`code`, `statusCode`, `errno`, …)
220
+ * - any other enumerable own properties
221
+ */
222
+ function serializeError(error, options = {}) {
223
+ const { includeStack = true, maxDepth = 5, excludeFields = [] } = options;
224
+ return _serializeError(error, includeStack, maxDepth, excludeFields, 0, /* @__PURE__ */ new WeakSet());
225
+ }
226
+ function _serializeError(error, includeStack, maxDepth, excludeFields, depth, seen) {
227
+ if (depth >= maxDepth) return {
228
+ name: error.name,
229
+ message: error.message,
230
+ _truncated: true
231
+ };
232
+ if (seen.has(error)) return {
233
+ name: error.name,
234
+ message: error.message,
235
+ _circular: true
236
+ };
237
+ seen.add(error);
238
+ const serialized = {
239
+ name: error.name,
240
+ message: error.message
241
+ };
242
+ if (includeStack && error.stack) serialized.stack = error.stack;
243
+ const errorWithCause = error;
244
+ if (errorWithCause.cause !== void 0) if (errorWithCause.cause instanceof Error) serialized.cause = _serializeError(errorWithCause.cause, includeStack, maxDepth, excludeFields, depth + 1, seen);
245
+ else serialized.cause = serializeValue(errorWithCause.cause, maxDepth - depth - 1);
246
+ const aggregateError = error;
247
+ if (Array.isArray(aggregateError.errors)) serialized.errors = aggregateError.errors.map((e) => e instanceof Error ? _serializeError(e, includeStack, maxDepth, excludeFields, depth + 1, seen) : serializeValue(e, maxDepth - depth - 1));
248
+ const errorRecord = error;
249
+ for (const field of EXTRA_FIELDS) if (!excludeFields.includes(field) && field in error && errorRecord[field] !== void 0) serialized[field] = errorRecord[field];
250
+ const skip = new Set([
251
+ "name",
252
+ "message",
253
+ "stack",
254
+ "cause",
255
+ "errors",
256
+ ...EXTRA_FIELDS,
257
+ ...excludeFields
258
+ ]);
259
+ for (const key of Object.getOwnPropertyNames(error)) {
260
+ if (skip.has(key)) continue;
261
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
262
+ try {
263
+ serialized[key] = serializeValue(errorRecord[key], maxDepth - depth - 1);
264
+ } catch {
265
+ serialized[key] = "[Unserializable]";
266
+ }
267
+ }
268
+ return serialized;
269
+ }
270
+ /**
271
+ * Recursively serialize an arbitrary value to a JSON-safe representation.
272
+ */
273
+ function serializeValue(value, remainingDepth) {
274
+ if (remainingDepth <= 0) return "[Max Depth]";
275
+ if (value === null || value === void 0) return value;
276
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
277
+ if (value instanceof Date) return value.toISOString();
278
+ if (value instanceof Error) return _serializeError(value, true, remainingDepth, [], 0, /* @__PURE__ */ new WeakSet());
279
+ if (Array.isArray(value)) return value.map((item) => serializeValue(item, remainingDepth - 1));
280
+ if (typeof value === "object") {
281
+ const out = {};
282
+ for (const [k, v] of Object.entries(value)) {
283
+ if (k === "__proto__" || k === "constructor" || k === "prototype") continue;
284
+ try {
285
+ out[k] = serializeValue(v, remainingDepth - 1);
286
+ } catch {
287
+ out[k] = "[Unserializable]";
288
+ }
289
+ }
290
+ return out;
291
+ }
292
+ return String(value);
293
+ }
294
+ /**
295
+ * Type guard: returns true if the value looks like an Error object.
296
+ */
297
+ function isError(value) {
298
+ return value instanceof Error || Boolean(value) && typeof value === "object" && "name" in value && "message" in value;
299
+ }
300
+ /**
301
+ * Coerce any thrown value into a proper Error instance.
302
+ */
303
+ function normalizeError(error) {
304
+ if (isError(error)) return error;
305
+ if (typeof error === "string") return new Error(error);
306
+ if (typeof error === "object" && error !== null) {
307
+ const e = error;
308
+ const err = new Error(typeof e["message"] === "string" ? e["message"] : "Unknown error");
309
+ Object.assign(err, error);
310
+ return err;
311
+ }
312
+ return new Error(String(error));
313
+ }
314
+
315
+ //#endregion
316
+ //#region src/utils/otel.ts
317
+ let _otelApi;
318
+ function tryLoadOtelApi() {
319
+ if (_otelApi !== void 0) return _otelApi;
320
+ try {
321
+ _otelApi = require("@opentelemetry/api");
322
+ return _otelApi;
323
+ } catch {
324
+ _otelApi = null;
325
+ return null;
326
+ }
327
+ }
328
+ /**
329
+ * Read the currently active OTel span context (if any) and return its fields
330
+ * in a plain object suitable for spreading into a log entry.
331
+ *
332
+ * Returns `undefined` when:
333
+ * - `@opentelemetry/api` is not installed
334
+ * - No active span exists (root context)
335
+ * - The span context is invalid (all-zeros)
336
+ */
337
+ function getActiveOtelContext(opts = {}) {
338
+ const api = tryLoadOtelApi();
339
+ if (!api) return void 0;
340
+ const ctx = api.context.active();
341
+ const sc = api.trace.getSpanContext(ctx);
342
+ if (!sc || !api.trace.isSpanContextValid(sc)) return void 0;
343
+ const isSampled = (sc.traceFlags & api.trace.TraceFlags.SAMPLED) === api.trace.TraceFlags.SAMPLED;
344
+ if (opts.sampledOnly && !isSampled) return void 0;
345
+ return {
346
+ traceId: sc.traceId,
347
+ spanId: sc.spanId,
348
+ traceFlags: sc.traceFlags,
349
+ isSampled
350
+ };
351
+ }
352
+ /**
353
+ * Returns a metadata object with OTel context fields ready to merge into a log call,
354
+ * using the configured field names.
355
+ *
356
+ * Returns `{}` when no active span exists (safe to spread unconditionally).
357
+ *
358
+ * @example
359
+ * ```ts
360
+ * await logger.info('Payment processed', {
361
+ * ...getOtelMetaFields(),
362
+ * orderId: 'ord_123',
363
+ * });
364
+ * ```
365
+ */
366
+ function getOtelMetaFields(opts = {}) {
367
+ const { traceIdField = "traceId", spanIdField = "spanId", traceFlagsField = "traceFlags" } = opts;
368
+ const ctx = getActiveOtelContext(opts);
369
+ if (!ctx) return {};
370
+ return {
371
+ [traceIdField]: ctx.traceId,
372
+ [spanIdField]: ctx.spanId,
373
+ [traceFlagsField]: ctx.traceFlags
374
+ };
375
+ }
376
+ let _bridgeOptions = null;
377
+ /**
378
+ * Initialise the global OTel bridge.
379
+ *
380
+ * Once called, logixia's internal log pipeline checks for an active OTel span
381
+ * on **every** log call and automatically merges the span context into the
382
+ * entry's metadata — no per-call wiring needed.
383
+ *
384
+ * Call once at app startup, **after** the OTel SDK has been initialised:
385
+ * ```ts
386
+ * import { initOtelBridge } from 'logixia';
387
+ * initOtelBridge();
388
+ * ```
389
+ */
390
+ function initOtelBridge(opts = {}) {
391
+ _bridgeOptions = opts;
392
+ }
393
+ /**
394
+ * @internal
395
+ * Used by the core logger to inject OTel context when the bridge is active.
396
+ * Returns `{}` when the bridge is not initialised or no active span exists.
397
+ */
398
+ function _getOtelPayloadIfEnabled() {
399
+ if (!_bridgeOptions) return {};
400
+ return getOtelMetaFields(_bridgeOptions);
401
+ }
402
+ /**
403
+ * Disable the OTel bridge (useful for tests).
404
+ */
405
+ function disableOtelBridge() {
406
+ _bridgeOptions = null;
407
+ }
408
+
409
+ //#endregion
410
+ //#region src/utils/redact.utils.ts
411
+ const DEFAULT_CENSOR = "[REDACTED]";
412
+ /**
413
+ * Conservative patterns: tokens and secrets that should NEVER appear in logs.
414
+ * Applied when `autoDetect: true` or `autoDetect: 'conservative'`.
415
+ */
416
+ const PII_CONSERVATIVE_PATTERNS = [
417
+ /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*/g,
418
+ /Bearer\s+[A-Za-z0-9._~+/-]+=*/gi,
419
+ /\b(?:sk|pk|api|key|secret|token)-[A-Za-z0-9_-]{16,}/gi,
420
+ /\bAKIA[0-9A-Z]{16}\b/g,
421
+ /\b[A-Za-z0-9/+]{40}\b(?=.*aws)/gi
422
+ ];
423
+ /**
424
+ * Conservative field-name paths auto-redacted by name regardless of value.
425
+ */
426
+ const PII_CONSERVATIVE_PATHS = [
427
+ "**.password",
428
+ "**.passwd",
429
+ "**.secret",
430
+ "**.token",
431
+ "**.apiKey",
432
+ "**.api_key",
433
+ "**.accessToken",
434
+ "**.access_token",
435
+ "**.refreshToken",
436
+ "**.refresh_token",
437
+ "**.authorization",
438
+ "**.credentials",
439
+ "**.privateKey",
440
+ "**.private_key",
441
+ "**.clientSecret",
442
+ "**.client_secret"
443
+ ];
444
+ /**
445
+ * Aggressive patterns: also catch personal data that could identify a person.
446
+ * Applied when `autoDetect: 'aggressive'`.
447
+ */
448
+ const PII_AGGRESSIVE_PATTERNS = [
449
+ /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
450
+ /\b\d{3}-?\d{2}-?\d{4}\b/g,
451
+ /\b(?:\d[ -]?){13,19}\b/g,
452
+ /\b(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g,
453
+ /\b(?:\d{1,3}\.){3}\d{1,3}\b/g
454
+ ];
455
+ const PII_AGGRESSIVE_PATHS = [
456
+ ...PII_CONSERVATIVE_PATHS,
457
+ "**.email",
458
+ "**.emailAddress",
459
+ "**.email_address",
460
+ "**.phone",
461
+ "**.phoneNumber",
462
+ "**.phone_number",
463
+ "**.mobile",
464
+ "**.ssn",
465
+ "**.sin",
466
+ "**.dob",
467
+ "**.dateOfBirth",
468
+ "**.date_of_birth",
469
+ "**.creditCard",
470
+ "**.credit_card",
471
+ "**.cardNumber",
472
+ "**.card_number",
473
+ "**.cvv",
474
+ "**.cvc",
475
+ "**.ipAddress",
476
+ "**.ip_address"
477
+ ];
478
+ /**
479
+ * Build an effective config that merges `autoDetect` PII rules into the
480
+ * explicit `paths` and `patterns` the caller provided.
481
+ */
482
+ function resolveConfig(config) {
483
+ const { autoDetect } = config;
484
+ if (!autoDetect) return config;
485
+ const aggressive = autoDetect === "aggressive";
486
+ const extraPaths = aggressive ? PII_AGGRESSIVE_PATHS : PII_CONSERVATIVE_PATHS;
487
+ const extraPatterns = aggressive ? [...PII_CONSERVATIVE_PATTERNS, ...PII_AGGRESSIVE_PATTERNS] : PII_CONSERVATIVE_PATTERNS;
488
+ const { paths = [], patterns = [] } = config;
489
+ return {
490
+ ...config,
491
+ paths: [...paths, ...extraPaths],
492
+ patterns: [...patterns, ...extraPatterns]
493
+ };
494
+ }
495
+ /**
496
+ * Convert a dot-notation path pattern to a RegExp.
497
+ * Supports `*` (one segment) and `**` (zero or more segments).
498
+ *
499
+ * Examples:
500
+ * "password" → /^password$/
501
+ * "user.password" → /^user\.password$/
502
+ * "*.token" → /^[^.]+\.token$/
503
+ * "req.headers.*" → /^req\.headers\.[^.]+$/
504
+ * "**" → /^.*$/
505
+ */
506
+ function pathToRegExp(pattern) {
507
+ const regexStr = pattern.split(".").map((segment) => {
508
+ if (segment === "**") return ".*";
509
+ if (segment === "*") return "[^.]+";
510
+ return segment.replace(/[$()*+.?[\\\]^{|}]/g, "\\$&");
511
+ }).join("\\.");
512
+ return /* @__PURE__ */ new RegExp(`^${regexStr}$`);
513
+ }
514
+ /** Pre-compiled path matchers keyed by pattern string for perf */
515
+ const patternCache = /* @__PURE__ */ new Map();
516
+ function matchesPath(fullPath, pattern) {
517
+ let re = patternCache.get(pattern);
518
+ if (!re) {
519
+ re = pathToRegExp(pattern);
520
+ patternCache.set(pattern, re);
521
+ }
522
+ return re.test(fullPath);
523
+ }
524
+ /**
525
+ * Deep-clone and redact an object according to the given RedactConfig.
526
+ * Non-objects are returned as-is (with pattern replacement on strings).
527
+ *
528
+ * The function is intentionally non-mutating — it returns a new object.
529
+ */
530
+ function redactObject(obj, config, _currentPath = "") {
531
+ const { paths = [], patterns = [], censor = DEFAULT_CENSOR } = config;
532
+ const result = {};
533
+ for (const [key, value] of Object.entries(obj)) {
534
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
535
+ const fullPath = _currentPath ? `${_currentPath}.${key}` : key;
536
+ if (paths.length > 0 && paths.some((p) => matchesPath(fullPath, p))) {
537
+ result[key] = censor;
538
+ continue;
539
+ }
540
+ if (isPlainObject(value)) {
541
+ result[key] = redactObject(value, config, fullPath);
542
+ continue;
543
+ }
544
+ if (typeof value === "string" && patterns.length > 0) {
545
+ let redacted = value;
546
+ for (const pattern of patterns) redacted = redacted.replace(pattern, censor);
547
+ result[key] = redacted;
548
+ continue;
549
+ }
550
+ if (Array.isArray(value)) {
551
+ result[key] = value.map((item) => {
552
+ if (isPlainObject(item)) return redactObject(item, config, fullPath);
553
+ if (typeof item === "string" && patterns.length > 0) return patterns.reduce((s, p) => s.replace(p, censor), item);
554
+ return item;
555
+ });
556
+ continue;
557
+ }
558
+ result[key] = value;
559
+ }
560
+ return result;
561
+ }
562
+ /**
563
+ * Apply redaction to a log payload (top-level call convenience wrapper).
564
+ * Returns a new object — never mutates the input.
565
+ */
566
+ function applyRedaction(payload, config) {
567
+ if (!payload || !config) return payload;
568
+ const resolved = resolveConfig(config);
569
+ if ((!resolved.paths || resolved.paths.length === 0) && (!resolved.patterns || resolved.patterns.length === 0)) return payload;
570
+ return redactObject(payload, resolved);
571
+ }
572
+ function isPlainObject(value) {
573
+ return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof Error) && !(value instanceof RegExp);
574
+ }
575
+
576
+ //#endregion
577
+ //#region src/utils/sampling.utils.ts
578
+ const ALWAYS_EMIT_LEVELS = new Set(["error", "fatal"]);
579
+ var Sampler = class {
580
+ constructor(config, onStats) {
581
+ this.sampledTraces = /* @__PURE__ */ new Set();
582
+ this.droppedTraces = /* @__PURE__ */ new Set();
583
+ this._tokenBucket = 0;
584
+ this._lastRefillMs = Date.now();
585
+ this._stats = {
586
+ evaluated: 0,
587
+ emitted: 0,
588
+ dropped: 0,
589
+ byLevel: {},
590
+ windowStart: Date.now()
591
+ };
592
+ this.config = config;
593
+ if (config.maxLogsPerSecond && config.maxLogsPerSecond > 0) this._tokenBucket = config.maxLogsPerSecond;
594
+ const interval = config.statsIntervalMs ?? 6e4;
595
+ if (interval > 0 && onStats) {
596
+ this._statsTimer = setInterval(() => {
597
+ onStats(this.getStats());
598
+ this.resetStats();
599
+ }, interval);
600
+ if (this._statsTimer.unref) this._statsTimer.unref();
601
+ }
602
+ }
603
+ /**
604
+ * Decide whether a given log entry should be emitted.
605
+ *
606
+ * @param level Log level string (lowercase)
607
+ * @param traceId Active trace ID, if any
608
+ * @returns true → emit, false → drop
609
+ */
610
+ shouldEmit(level, traceId) {
611
+ var _this$config$perLevel;
612
+ const lvl = level.toLowerCase();
613
+ this._trackEvaluated(lvl);
614
+ if (ALWAYS_EMIT_LEVELS.has(lvl) && ((_this$config$perLevel = this.config.perLevel) === null || _this$config$perLevel === void 0 ? void 0 : _this$config$perLevel[lvl]) === void 0) {
615
+ this._trackEmitted(lvl);
616
+ return true;
617
+ }
618
+ if (this.config.traceConsistent && traceId) {
619
+ if (this.sampledTraces.has(traceId)) {
620
+ this._trackEmitted(lvl);
621
+ return true;
622
+ }
623
+ if (this.droppedTraces.has(traceId)) {
624
+ this._trackDropped(lvl);
625
+ return false;
626
+ }
627
+ const emit = this._sampleByRate(lvl);
628
+ if (emit) this.sampledTraces.add(traceId);
629
+ else this.droppedTraces.add(traceId);
630
+ if (emit) this._trackEmitted(lvl);
631
+ else this._trackDropped(lvl);
632
+ return emit;
633
+ }
634
+ if (!this._sampleByRate(lvl)) {
635
+ this._trackDropped(lvl);
636
+ return false;
637
+ }
638
+ if (this.config.maxLogsPerSecond && this.config.maxLogsPerSecond > 0) {
639
+ if (!this._consumeToken()) {
640
+ this._trackDropped(lvl);
641
+ return false;
642
+ }
643
+ }
644
+ this._trackEmitted(lvl);
645
+ return true;
646
+ }
647
+ getStats() {
648
+ return {
649
+ ...this._stats,
650
+ byLevel: { ...this._stats.byLevel }
651
+ };
652
+ }
653
+ resetStats() {
654
+ this._stats = {
655
+ evaluated: 0,
656
+ emitted: 0,
657
+ dropped: 0,
658
+ byLevel: {},
659
+ windowStart: Date.now()
660
+ };
661
+ this.sampledTraces.clear();
662
+ this.droppedTraces.clear();
663
+ }
664
+ destroy() {
665
+ if (this._statsTimer) clearInterval(this._statsTimer);
666
+ }
667
+ _sampleByRate(level) {
668
+ var _this$config$perLevel2, _this$config$perLevel3;
669
+ const rate = ((_this$config$perLevel2 = this.config.perLevel) === null || _this$config$perLevel2 === void 0 ? void 0 : _this$config$perLevel2[level]) ?? ((_this$config$perLevel3 = this.config.perLevel) === null || _this$config$perLevel3 === void 0 ? void 0 : _this$config$perLevel3["*"]) ?? this.config.rate ?? 1;
670
+ if (rate >= 1) return true;
671
+ if (rate <= 0) return false;
672
+ return Math.random() < rate;
673
+ }
674
+ _consumeToken() {
675
+ const now = Date.now();
676
+ const elapsed = (now - this._lastRefillMs) / 1e3;
677
+ const max = this.config.maxLogsPerSecond;
678
+ this._tokenBucket = Math.min(max, this._tokenBucket + elapsed * max);
679
+ this._lastRefillMs = now;
680
+ if (this._tokenBucket >= 1) {
681
+ this._tokenBucket -= 1;
682
+ return true;
683
+ }
684
+ return false;
685
+ }
686
+ _ensure(level) {
687
+ if (!this._stats.byLevel[level]) this._stats.byLevel[level] = {
688
+ evaluated: 0,
689
+ emitted: 0
690
+ };
691
+ }
692
+ _trackEvaluated(level) {
693
+ this._stats.evaluated++;
694
+ this._ensure(level);
695
+ this._stats.byLevel[level].evaluated++;
696
+ }
697
+ _trackEmitted(level) {
698
+ this._stats.emitted++;
699
+ this._ensure(level);
700
+ this._stats.byLevel[level].emitted++;
701
+ }
702
+ _trackDropped(_level) {
703
+ this._stats.dropped++;
704
+ }
705
+ };
706
+
707
+ //#endregion
708
+ //#region src/utils/shutdown.utils.ts
709
+ /** Module-level registry of all logger instances that have opted into graceful shutdown */
710
+ const registry = /* @__PURE__ */ new Set();
711
+ let shutdownHandlerRegistered = false;
712
+ /**
713
+ * Register a logger instance so it is included in the graceful shutdown flush.
714
+ * Called automatically when `gracefulShutdown: true` is set in logger config.
715
+ */
716
+ function registerForShutdown(logger) {
717
+ registry.add(logger);
718
+ }
719
+ /**
720
+ * Deregister a logger (e.g. after `logger.close()` is called manually).
721
+ */
722
+ function deregisterFromShutdown(logger) {
723
+ registry.delete(logger);
724
+ }
725
+ /**
726
+ * Register SIGTERM / SIGINT handlers that flush all registered loggers before
727
+ * the process exits. Idempotent — calling multiple times is safe.
728
+ *
729
+ * @example
730
+ * ```ts
731
+ * import { flushOnExit } from 'logixia';
732
+ * flushOnExit({ timeout: 5000 });
733
+ * ```
734
+ */
735
+ function flushOnExit(options = {}) {
736
+ if (shutdownHandlerRegistered) return;
737
+ shutdownHandlerRegistered = true;
738
+ const { timeout = 5e3, signals = ["SIGTERM", "SIGINT"], beforeFlush, afterFlush } = options;
739
+ const handler = async (signal) => {
740
+ const forceExitTimer = setTimeout(() => {
741
+ process.stderr.write(`[logixia] Graceful shutdown timed out after ${timeout}ms on ${signal}. Force-exiting.\n`);
742
+ process.exit(1);
743
+ }, timeout).unref();
744
+ try {
745
+ if (beforeFlush) await beforeFlush();
746
+ await Promise.allSettled([...registry].map((logger) => logger.close()));
747
+ if (afterFlush) await afterFlush();
748
+ } finally {
749
+ clearTimeout(forceExitTimer);
750
+ process.exit(0);
751
+ }
752
+ };
753
+ for (const signal of signals) if (process.listenerCount(signal) === 0) process.on(signal, handler);
754
+ }
755
+ /**
756
+ * Remove all graceful shutdown handlers and clear the registry.
757
+ * Primarily useful in tests.
758
+ */
759
+ function resetShutdownHandlers() {
760
+ registry.clear();
761
+ shutdownHandlerRegistered = false;
762
+ }
763
+
764
+ //#endregion
765
+ //#region node_modules/uuid/dist/esm-node/rng.js
766
+ const rnds8Pool = new Uint8Array(256);
767
+ let poolPtr = rnds8Pool.length;
768
+ function rng() {
769
+ if (poolPtr > rnds8Pool.length - 16) {
770
+ crypto.default.randomFillSync(rnds8Pool);
771
+ poolPtr = 0;
772
+ }
773
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
774
+ }
775
+
776
+ //#endregion
777
+ //#region node_modules/uuid/dist/esm-node/stringify.js
778
+ /**
779
+ * Convert array of 16 byte values to UUID string format of the form:
780
+ * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
781
+ */
782
+ const byteToHex = [];
783
+ for (let i = 0; i < 256; ++i) byteToHex.push((i + 256).toString(16).slice(1));
784
+ function unsafeStringify(arr, offset = 0) {
785
+ return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
786
+ }
787
+
788
+ //#endregion
789
+ //#region node_modules/uuid/dist/esm-node/native.js
790
+ var native_default = { randomUUID: crypto.default.randomUUID };
791
+
792
+ //#endregion
793
+ //#region node_modules/uuid/dist/esm-node/v4.js
794
+ function v4(options, buf, offset) {
795
+ if (native_default.randomUUID && !buf && !options) return native_default.randomUUID();
796
+ options = options || {};
797
+ const rnds = options.random || (options.rng || rng)();
798
+ rnds[6] = rnds[6] & 15 | 64;
799
+ rnds[8] = rnds[8] & 63 | 128;
800
+ if (buf) {
801
+ offset = offset || 0;
802
+ for (let i = 0; i < 16; ++i) buf[offset + i] = rnds[i];
803
+ return buf;
804
+ }
805
+ return unsafeStringify(rnds);
806
+ }
807
+ var v4_default = v4;
808
+
809
+ //#endregion
810
+ //#region src/utils/trace.utils.ts
811
+ /** Default key used to store the trace ID in AsyncLocalStorage. */
812
+ const TRACE_CONTEXT_KEY = "traceId";
813
+ /**
814
+ * Singleton that owns the AsyncLocalStorage and the active contextKey.
815
+ *
816
+ * Why a class instead of bare module-level variables?
817
+ * - The contextKey is user-configurable; encapsulating it here means there is
818
+ * exactly one place that reads and writes it.
819
+ * - All helpers (getCurrentTraceId, runWithTraceId, etc.) delegate to this
820
+ * instance, so the key is always in sync without hidden global state.
821
+ * - Easier to test: you can reset the singleton between test cases.
822
+ *
823
+ * Usage (advanced):
824
+ * import { TraceContext } from 'logixia';
825
+ * TraceContext.instance.contextKey // → 'traceId' (or custom)
826
+ * TraceContext.instance.getCurrentTraceId() // same as standalone fn
827
+ */
828
+ var TraceContext = class TraceContext {
829
+ static #_ = this._instance = null;
830
+ constructor() {
831
+ this.storage = new node_async_hooks.AsyncLocalStorage();
832
+ this._contextKey = TRACE_CONTEXT_KEY;
833
+ }
834
+ /** The process-wide singleton. */
835
+ static get instance() {
836
+ if (!TraceContext._instance) TraceContext._instance = new TraceContext();
837
+ return TraceContext._instance;
838
+ }
839
+ /** @internal Reset the singleton (useful in tests). */
840
+ static _reset() {
841
+ TraceContext._instance = null;
842
+ }
843
+ /** The AsyncLocalStorage key that holds the trace ID value. */
844
+ get contextKey() {
845
+ return this._contextKey;
846
+ }
847
+ /** @internal Called by TraceMiddleware when it boots to register the user's key. */
848
+ setContextKey(key) {
849
+ this._contextKey = key;
850
+ }
851
+ /** UUID v4 generator (default). */
852
+ generate() {
853
+ return v4_default();
854
+ }
855
+ /** Read the trace ID from the current async context. */
856
+ getCurrentTraceId() {
857
+ var _this$storage$getStor;
858
+ return (_this$storage$getStor = this.storage.getStore()) === null || _this$storage$getStor === void 0 ? void 0 : _this$storage$getStor[this._contextKey];
859
+ }
860
+ /**
861
+ * Mutate the CURRENT async context in-place.
862
+ *
863
+ * ⚠️ DEPRECATED — unsafe for concurrent requests.
864
+ *
865
+ * Uses `AsyncLocalStorage.enterWith()`, which mutates the current async
866
+ * execution context and every Promise chain spawned from it. In a server
867
+ * processing overlapping requests this can cause a trace ID set for one
868
+ * request to bleed into *other* in-flight requests that share the same
869
+ * async parent (e.g. a module-level setup function or a cached handler).
870
+ *
871
+ * Use {@link run} instead — it scopes the context to a callback so there
872
+ * is no risk of cross-request leakage.
873
+ *
874
+ * @deprecated Use `TraceContext.instance.run(traceId, fn)` — do not call
875
+ * `setTraceId` from request-handling code.
876
+ */
877
+ setTraceId(traceId, data) {
878
+ const current = this.storage.getStore() ?? {};
879
+ this.storage.enterWith({
880
+ ...current,
881
+ [this._contextKey]: traceId,
882
+ ...data
883
+ });
884
+ }
885
+ /** Run `fn` inside a new async context that carries `traceId`. */
886
+ run(traceId, fn, data) {
887
+ return this.storage.run({
888
+ [this._contextKey]: traceId,
889
+ ...data
890
+ }, fn);
891
+ }
892
+ };
893
+ /**
894
+ * The shared AsyncLocalStorage instance.
895
+ * @deprecated Prefer `TraceContext.instance.storage` for new code.
896
+ */
897
+ const traceStorage = TraceContext.instance.storage;
898
+ /** Returns the key currently used to store the trace ID in AsyncLocalStorage. */
899
+ function getTraceContextKey() {
900
+ return TraceContext.instance.contextKey;
901
+ }
902
+ /** @internal Called by TraceMiddleware / traceMiddleware() when they boot. */
903
+ function _setActiveContextKey(key) {
904
+ TraceContext.instance.setContextKey(key);
905
+ }
906
+ /** Generate a UUID v4 trace ID. */
907
+ function generateTraceId() {
908
+ return TraceContext.instance.generate();
909
+ }
910
+ /**
911
+ * Get the current trace ID from async context.
912
+ * Returns `undefined` when called outside a traced request.
913
+ */
914
+ function getCurrentTraceId() {
915
+ return TraceContext.instance.getCurrentTraceId();
916
+ }
917
+ /**
918
+ * Set trace ID in the CURRENT async context without starting a new one.
919
+ *
920
+ * ⚠️ DEPRECATED — unsafe for concurrent requests.
921
+ *
922
+ * Uses `AsyncLocalStorage.enterWith()`, which mutates the current async
923
+ * execution context and every Promise chain spawned from it. Under load this
924
+ * can cause a trace ID from one request to bleed into others sharing the same
925
+ * async parent.
926
+ *
927
+ * Use {@link runWithTraceId} instead. Migration patterns:
928
+ *
929
+ * **Express / Fastify middleware — before:**
930
+ * ```ts
931
+ * app.use((req, _res, next) => {
932
+ * setTraceId(req.headers['x-trace-id'] ?? generateTraceId());
933
+ * next();
934
+ * });
935
+ * ```
936
+ * **after:**
937
+ * ```ts
938
+ * app.use((req, _res, next) => {
939
+ * runWithTraceId(req.headers['x-trace-id'] ?? generateTraceId(), () => next());
940
+ * });
941
+ * ```
942
+ *
943
+ * **Kafka / queue consumer — before:**
944
+ * ```ts
945
+ * async function handle(msg) {
946
+ * setTraceId(msg.headers['x-trace-id']);
947
+ * await processMessage(msg);
948
+ * }
949
+ * ```
950
+ * **after:**
951
+ * ```ts
952
+ * async function handle(msg) {
953
+ * await runWithTraceId(msg.headers['x-trace-id'], () => processMessage(msg));
954
+ * }
955
+ * ```
956
+ *
957
+ * **Background job — before:**
958
+ * ```ts
959
+ * setTraceId(generateTraceId(), { jobId: job.id });
960
+ * await job.run();
961
+ * ```
962
+ * **after:**
963
+ * ```ts
964
+ * await runWithTraceId(generateTraceId(), () => job.run(), { jobId: job.id });
965
+ * ```
966
+ *
967
+ * @deprecated Use `runWithTraceId(traceId, fn)` — do not call `setTraceId`
968
+ * from request-handling code.
969
+ */
970
+ function setTraceId(traceId, data) {
971
+ TraceContext.instance.setTraceId(traceId, data);
972
+ }
973
+ /** Run `fn` inside a new async context carrying `traceId`. */
974
+ function runWithTraceId(traceId, fn, data) {
975
+ return TraceContext.instance.run(traceId, fn, data);
976
+ }
977
+ /**
978
+ * Coerce an arbitrary value to a non-empty trace ID string, or `undefined`.
979
+ * Rejects empty/whitespace-only strings, non-strings, and non-first array elements.
980
+ */
981
+ function toValidTraceId(value) {
982
+ const first = Array.isArray(value) ? value[0] : value;
983
+ if (typeof first !== "string") return void 0;
984
+ const trimmed = first.trim();
985
+ return trimmed.length > 0 ? trimmed : void 0;
986
+ }
987
+ /** Extract trace ID from request using configuration (header → query → body → params). */
988
+ function extractTraceId(request, config) {
989
+ const req = request;
990
+ if (config.header) {
991
+ const headers = Array.isArray(config.header) ? config.header : [config.header];
992
+ for (const header of headers) {
993
+ var _req$headers;
994
+ const value = toValidTraceId((_req$headers = req.headers) === null || _req$headers === void 0 ? void 0 : _req$headers[header.toLowerCase()]);
995
+ if (value) return value;
996
+ }
997
+ }
998
+ if (config.query) {
999
+ const queries = Array.isArray(config.query) ? config.query : [config.query];
1000
+ for (const query of queries) {
1001
+ var _req$query;
1002
+ const value = toValidTraceId((_req$query = req.query) === null || _req$query === void 0 ? void 0 : _req$query[query]);
1003
+ if (value) return value;
1004
+ }
1005
+ }
1006
+ if (config.body) {
1007
+ const bodyFields = Array.isArray(config.body) ? config.body : [config.body];
1008
+ for (const field of bodyFields) {
1009
+ var _req$body;
1010
+ const value = toValidTraceId((_req$body = req.body) === null || _req$body === void 0 ? void 0 : _req$body[field]);
1011
+ if (value) return value;
1012
+ }
1013
+ }
1014
+ if (config.params) {
1015
+ const paramFields = Array.isArray(config.params) ? config.params : [config.params];
1016
+ for (const param of paramFields) {
1017
+ var _req$params;
1018
+ const value = toValidTraceId((_req$params = req.params) === null || _req$params === void 0 ? void 0 : _req$params[param]);
1019
+ if (value) return value;
1020
+ }
1021
+ }
1022
+ }
1023
+ /**
1024
+ * Default headers checked for incoming trace ID propagation, in priority order:
1025
+ * traceparent (W3C/OTel) → x-trace-id → x-request-id → x-correlation-id → trace-id
1026
+ */
1027
+ const DEFAULT_TRACE_HEADERS = [
1028
+ "traceparent",
1029
+ "x-trace-id",
1030
+ "x-request-id",
1031
+ "x-correlation-id",
1032
+ "trace-id"
1033
+ ];
1034
+ /**
1035
+ * Create trace ID middleware for Express/NestJS
1036
+ */
1037
+ function createTraceMiddleware(config) {
1038
+ const defaultExtractor = {
1039
+ header: DEFAULT_TRACE_HEADERS,
1040
+ query: ["traceId", "trace_id"]
1041
+ };
1042
+ const resolvedConfig = {
1043
+ ...config,
1044
+ extractor: (config === null || config === void 0 ? void 0 : config.extractor) ? {
1045
+ ...defaultExtractor,
1046
+ ...config.extractor
1047
+ } : defaultExtractor
1048
+ };
1049
+ _setActiveContextKey(resolvedConfig.contextKey ?? TRACE_CONTEXT_KEY);
1050
+ return (req, res, next) => {
1051
+ let traceId;
1052
+ if (resolvedConfig.extractor) traceId = extractTraceId(req, resolvedConfig.extractor);
1053
+ if (!traceId) traceId = resolvedConfig.generator ? resolvedConfig.generator() : generateTraceId();
1054
+ req.traceId = traceId;
1055
+ res.setHeader("X-Trace-Id", traceId);
1056
+ runWithTraceId(traceId, () => next());
1057
+ };
1058
+ }
1059
+
1060
+ //#endregion
1061
+ //#region src/core/logitron-logger.ts
1062
+ const _fastStringifyEntry = (0, fast_json_stringify.default)({
1063
+ type: "object",
1064
+ properties: {
1065
+ timestamp: { type: "string" },
1066
+ level: { type: "string" },
1067
+ appName: { type: "string" },
1068
+ environment: { type: "string" },
1069
+ message: { type: "string" },
1070
+ context: { type: "string" },
1071
+ traceId: { type: "string" },
1072
+ payload: {
1073
+ type: "object",
1074
+ additionalProperties: true
1075
+ }
1076
+ },
1077
+ additionalProperties: true
1078
+ });
1079
+ function namespacePatternToRegex(pattern) {
1080
+ const escaped = pattern.split(".").map((s) => s === "*" ? "[^.]+" : s.replace(/[$()*+.?[\\\]^{|}]/g, "\\$&")).join("\\.");
1081
+ return /* @__PURE__ */ new RegExp(`^${escaped}$`);
1082
+ }
1083
+ /** Max compiled patterns to keep in memory. Oldest entry is evicted when full. */
1084
+ const _NS_CACHE_MAX = 1e3;
1085
+ const _nsPatternCache = /* @__PURE__ */ new Map();
1086
+ /**
1087
+ * One-shot warning so operators notice runaway pattern growth.
1088
+ * If the cache is being thrashed (>N evictions) the namespace level config is
1089
+ * almost certainly wrong — likely dynamic/unique patterns being registered.
1090
+ */
1091
+ let _nsCacheEvictionWarned = false;
1092
+ let _nsCacheEvictionCount = 0;
1093
+ function matchesNamespacePattern(ns, pattern) {
1094
+ let re = _nsPatternCache.get(pattern);
1095
+ if (!re) {
1096
+ re = namespacePatternToRegex(pattern);
1097
+ if (_nsPatternCache.size >= _NS_CACHE_MAX) {
1098
+ const firstKey = _nsPatternCache.keys().next().value;
1099
+ if (firstKey !== void 0) _nsPatternCache.delete(firstKey);
1100
+ _nsCacheEvictionCount++;
1101
+ if (!_nsCacheEvictionWarned) {
1102
+ _nsCacheEvictionWarned = true;
1103
+ process.stderr.write(`[logixia] namespace pattern cache hit ${_NS_CACHE_MAX} entries — evicting. This usually means dynamic/unique patterns are being registered at runtime; review your levelOptions.namespaces configuration.\n`);
1104
+ }
1105
+ }
1106
+ _nsPatternCache.set(pattern, re);
1107
+ }
1108
+ return re.test(ns);
1109
+ }
1110
+ function resolveInitialLevel(config) {
1111
+ var _config$levelOptions;
1112
+ const envLevel = process.env["LOGIXIA_LEVEL"];
1113
+ if (envLevel) return envLevel;
1114
+ if ((_config$levelOptions = config.levelOptions) === null || _config$levelOptions === void 0 ? void 0 : _config$levelOptions.level) return config.levelOptions.level;
1115
+ const nodeEnv = process.env["NODE_ENV"];
1116
+ if (nodeEnv === "development") return LogLevel.DEBUG;
1117
+ if (nodeEnv === "test") return LogLevel.WARN;
1118
+ if (nodeEnv === "production") return LogLevel.INFO;
1119
+ if (process.env["CI"]) return LogLevel.INFO;
1120
+ return LogLevel.INFO;
1121
+ }
1122
+ var LogixiaLogger = class LogixiaLogger {
1123
+ constructor(config, context) {
1124
+ this.timers = /* @__PURE__ */ new Map();
1125
+ this.contextData = {};
1126
+ this.fieldState = /* @__PURE__ */ new Map();
1127
+ this.fallbackTraceId = TraceContext.instance.generate();
1128
+ this._levelValues = /* @__PURE__ */ new Map();
1129
+ this._minLevelValue = 2;
1130
+ this._colorMap = /* @__PURE__ */ new Map();
1131
+ this._fieldCache = /* @__PURE__ */ new Map();
1132
+ this._hasContextData = false;
1133
+ this._formattedLevels = /* @__PURE__ */ new Map();
1134
+ this._formattedAppName = "";
1135
+ this._hasRedact = false;
1136
+ this._pluginRegistry = new PluginRegistry();
1137
+ this.config = {
1138
+ appName: "App",
1139
+ environment: "development",
1140
+ traceId: true,
1141
+ format: {
1142
+ timestamp: true,
1143
+ colorize: true,
1144
+ json: false
1145
+ },
1146
+ silent: false,
1147
+ levelOptions: {
1148
+ level: LogLevel.INFO,
1149
+ levels: {
1150
+ [LogLevel.ERROR]: 0,
1151
+ [LogLevel.WARN]: 1,
1152
+ [LogLevel.INFO]: 2,
1153
+ [LogLevel.DEBUG]: 3,
1154
+ [LogLevel.TRACE]: 4,
1155
+ [LogLevel.VERBOSE]: 5
1156
+ },
1157
+ colors: {
1158
+ [LogLevel.ERROR]: "red",
1159
+ [LogLevel.WARN]: "yellow",
1160
+ [LogLevel.INFO]: "blue",
1161
+ [LogLevel.DEBUG]: "green",
1162
+ [LogLevel.TRACE]: "gray",
1163
+ [LogLevel.VERBOSE]: "cyan"
1164
+ }
1165
+ },
1166
+ ...config
1167
+ };
1168
+ const resolvedLevel = resolveInitialLevel(this.config);
1169
+ this.config.levelOptions = {
1170
+ ...this.config.levelOptions,
1171
+ level: resolvedLevel
1172
+ };
1173
+ if (!this.config.fields) this.config.fields = {
1174
+ timestamp: "[yyyy-mm-dd HH:MM:ss.MS]",
1175
+ level: "[log_level]",
1176
+ appName: "[app_name]",
1177
+ traceId: "[trace_id]",
1178
+ message: "[message]",
1179
+ payload: "[payload]",
1180
+ timeTaken: "[time_taken_MS]"
1181
+ };
1182
+ this.context = context ?? "";
1183
+ if (this.config.transports) {
1184
+ var _this$config$levelOpt;
1185
+ const transportsWithColors = { ...this.config.transports };
1186
+ const userColors = (_this$config$levelOpt = this.config.levelOptions) === null || _this$config$levelOpt === void 0 ? void 0 : _this$config$levelOpt.colors;
1187
+ if (userColors && transportsWithColors.console) transportsWithColors.console = {
1188
+ ...typeof transportsWithColors.console === "object" ? transportsWithColors.console : {},
1189
+ levelColors: userColors
1190
+ };
1191
+ this.transportManager = new require_transport_manager.TransportManager(transportsWithColors);
1192
+ }
1193
+ if (this.config.sampling) this._sampler = new Sampler(this.config.sampling, (stats) => {
1194
+ process.stdout.write(JSON.stringify({
1195
+ level: "info",
1196
+ message: "[logixia/sampling] stats",
1197
+ ...stats
1198
+ }) + "\n");
1199
+ });
1200
+ this.setupGracefulShutdown();
1201
+ this.createCustomLevelMethods();
1202
+ for (const p of globalPluginRegistry._plugins) this._pluginRegistry.register(p);
1203
+ this._buildPerfCaches();
1204
+ }
1205
+ setupGracefulShutdown() {
1206
+ const shutdownCfg = this.config.gracefulShutdown;
1207
+ if (!shutdownCfg) return;
1208
+ const normalized = shutdownCfg === true ? { enabled: true } : shutdownCfg;
1209
+ if (!normalized.enabled) return;
1210
+ registerForShutdown(this);
1211
+ flushOnExit({
1212
+ timeout: normalized.timeout ?? 5e3,
1213
+ signals: normalized.signals ?? ["SIGTERM", "SIGINT"]
1214
+ });
1215
+ }
1216
+ createCustomLevelMethods() {
1217
+ var _this$config$levelOpt2;
1218
+ if ((_this$config$levelOpt2 = this.config.levelOptions) === null || _this$config$levelOpt2 === void 0 ? void 0 : _this$config$levelOpt2.levels) {
1219
+ for (const levelName of Object.keys(this.config.levelOptions.levels)) if (!this[levelName.toLowerCase()]) this[levelName.toLowerCase()] = async (message, data) => {
1220
+ await this.logLevel(levelName.toLowerCase(), message, data);
1221
+ };
1222
+ }
1223
+ }
1224
+ /**
1225
+ * Rebuild all hot-path caches after any config mutation or level change.
1226
+ * Keeps the actual log() call free of allocations in the common case.
1227
+ */
1228
+ _buildPerfCaches() {
1229
+ var _this$config$levelOpt3, _this$config$format, _this$config$redact$p, _this$config$redact$p2;
1230
+ const customLevelEntries = Object.entries(((_this$config$levelOpt3 = this.config.levelOptions) === null || _this$config$levelOpt3 === void 0 ? void 0 : _this$config$levelOpt3.levels) ?? {});
1231
+ this._levelValues = new Map([
1232
+ [LogLevel.ERROR, 0],
1233
+ [LogLevel.WARN, 1],
1234
+ [LogLevel.INFO, 2],
1235
+ [LogLevel.DEBUG, 3],
1236
+ [LogLevel.TRACE, 4],
1237
+ [LogLevel.VERBOSE, 5],
1238
+ ...customLevelEntries
1239
+ ]);
1240
+ const effectiveLevel = this.resolveEffectiveLevel();
1241
+ this._minLevelValue = this._levelValues.get(effectiveLevel) ?? 2;
1242
+ this._colorMap = new Map([
1243
+ ["black", "\x1B[30m"],
1244
+ ["red", "\x1B[31m"],
1245
+ ["green", "\x1B[32m"],
1246
+ ["yellow", "\x1B[33m"],
1247
+ ["blue", "\x1B[34m"],
1248
+ ["magenta", "\x1B[35m"],
1249
+ ["cyan", "\x1B[36m"],
1250
+ ["white", "\x1B[37m"],
1251
+ ["gray", "\x1B[90m"],
1252
+ ["grey", "\x1B[90m"],
1253
+ ["brightred", "\x1B[91m"],
1254
+ ["brightgreen", "\x1B[92m"],
1255
+ ["brightyellow", "\x1B[93m"],
1256
+ ["brightblue", "\x1B[94m"],
1257
+ ["brightmagenta", "\x1B[95m"],
1258
+ ["brightcyan", "\x1B[96m"],
1259
+ ["brightwhite", "\x1B[97m"],
1260
+ ["reset", "\x1B[0m"]
1261
+ ]);
1262
+ for (const f of [
1263
+ "timestamp",
1264
+ "level",
1265
+ "appName",
1266
+ "traceId",
1267
+ "context",
1268
+ "message",
1269
+ "payload"
1270
+ ]) {
1271
+ var _this$config$fields;
1272
+ if (this.fieldState.has(f)) this._fieldCache.set(f, this.fieldState.get(f));
1273
+ else if (((_this$config$fields = this.config.fields) === null || _this$config$fields === void 0 ? void 0 : _this$config$fields[f]) !== void 0) this._fieldCache.set(f, this.config.fields[f] !== false);
1274
+ else this._fieldCache.set(f, true);
1275
+ }
1276
+ const colorize = ((_this$config$format = this.config.format) === null || _this$config$format === void 0 ? void 0 : _this$config$format.colorize) ?? true;
1277
+ this._formattedLevels = /* @__PURE__ */ new Map();
1278
+ const _AUTO_PALETTE = [
1279
+ "magenta",
1280
+ "cyan",
1281
+ "yellow",
1282
+ "green",
1283
+ "blue"
1284
+ ];
1285
+ const _BUILTIN_LEVELS = new Set([
1286
+ "error",
1287
+ "warn",
1288
+ "info",
1289
+ "debug",
1290
+ "trace",
1291
+ "verbose"
1292
+ ]);
1293
+ let _paletteIdx = 0;
1294
+ for (const [lvl] of this._levelValues) {
1295
+ const upper = lvl.toUpperCase();
1296
+ if (colorize && this._fieldCache.get("level") !== false) {
1297
+ var _this$config$levelOpt4;
1298
+ let colorName = (_this$config$levelOpt4 = this.config.levelOptions) === null || _this$config$levelOpt4 === void 0 || (_this$config$levelOpt4 = _this$config$levelOpt4.colors) === null || _this$config$levelOpt4 === void 0 ? void 0 : _this$config$levelOpt4[lvl];
1299
+ if (!colorName) if (_BUILTIN_LEVELS.has(lvl)) colorName = "white";
1300
+ else {
1301
+ colorName = _AUTO_PALETTE[_paletteIdx % _AUTO_PALETTE.length];
1302
+ _paletteIdx++;
1303
+ }
1304
+ const code = this._colorMap.get(colorName.toLowerCase()) ?? this._colorMap.get("white");
1305
+ const reset = this._colorMap.get("reset");
1306
+ this._formattedLevels.set(lvl, `[${code}${upper}${reset}] `);
1307
+ } else this._formattedLevels.set(lvl, `[${upper}] `);
1308
+ }
1309
+ const appNameRaw = `[${this.config.appName ?? "App"}]`;
1310
+ if (this._fieldCache.get("appName") !== false) this._formattedAppName = colorize ? `${this._colorMap.get("gray")}${appNameRaw}${this._colorMap.get("reset")} ` : `${appNameRaw} `;
1311
+ else this._formattedAppName = "";
1312
+ this._hasRedact = !!(this.config.redact && ((((_this$config$redact$p = this.config.redact.paths) === null || _this$config$redact$p === void 0 ? void 0 : _this$config$redact$p.length) ?? 0) > 0 || (((_this$config$redact$p2 = this.config.redact.patterns) === null || _this$config$redact$p2 === void 0 ? void 0 : _this$config$redact$p2.length) ?? 0) > 0));
1313
+ }
1314
+ async error(messageOrError, data) {
1315
+ if (isError(messageOrError)) await this.log("error", messageOrError.message, {
1316
+ ...data,
1317
+ error: serializeError(messageOrError)
1318
+ });
1319
+ else await this.log("error", messageOrError, data);
1320
+ }
1321
+ async warn(message, data) {
1322
+ await this.log("warn", message, data);
1323
+ }
1324
+ async info(message, data) {
1325
+ await this.log("info", message, data);
1326
+ }
1327
+ async debug(message, data) {
1328
+ await this.log("debug", message, data);
1329
+ }
1330
+ async trace(message, data) {
1331
+ await this.log("trace", message, data);
1332
+ }
1333
+ async verbose(message, data) {
1334
+ await this.log("verbose", message, data);
1335
+ }
1336
+ async logLevel(level, message, data) {
1337
+ await this.log(level, message, data);
1338
+ }
1339
+ time(label) {
1340
+ this.timers.set(label, {
1341
+ label,
1342
+ startTime: Date.now()
1343
+ });
1344
+ }
1345
+ async timeEnd(label) {
1346
+ const timer = this.timers.get(label);
1347
+ if (!timer) {
1348
+ await this.warn(`Timer '${label}' does not exist`);
1349
+ return;
1350
+ }
1351
+ const endTime = Date.now();
1352
+ const duration = endTime - timer.startTime;
1353
+ timer.endTime = endTime;
1354
+ timer.duration = duration;
1355
+ await this.info(`Timer '${label}' finished`, {
1356
+ duration: `${duration}ms`,
1357
+ startTime: new Date(timer.startTime).toISOString(),
1358
+ endTime: new Date(endTime).toISOString()
1359
+ });
1360
+ this.timers.delete(label);
1361
+ return duration;
1362
+ }
1363
+ async timeAsync(label, fn) {
1364
+ this.time(label);
1365
+ try {
1366
+ const result = await fn();
1367
+ await this.timeEnd(label);
1368
+ return result;
1369
+ } catch (error) {
1370
+ await this.timeEnd(label);
1371
+ throw error;
1372
+ }
1373
+ }
1374
+ setLevel(level) {
1375
+ this.config.levelOptions = this.config.levelOptions ?? {};
1376
+ this.config.levelOptions.level = level;
1377
+ this._minLevelValue = this._levelValues.get(level) ?? this._minLevelValue;
1378
+ this._buildPerfCaches();
1379
+ }
1380
+ getLevel() {
1381
+ var _this$config$levelOpt5;
1382
+ return ((_this$config$levelOpt5 = this.config.levelOptions) === null || _this$config$levelOpt5 === void 0 ? void 0 : _this$config$levelOpt5.level) ?? LogLevel.INFO;
1383
+ }
1384
+ setContext(context) {
1385
+ this.context = context;
1386
+ }
1387
+ getContext() {
1388
+ return this.context;
1389
+ }
1390
+ enableField(fieldName) {
1391
+ this.fieldState.set(fieldName, true);
1392
+ this._fieldCache.set(fieldName, true);
1393
+ if (fieldName === "level" || fieldName === "appName") this._buildPerfCaches();
1394
+ require_transport_manager.internalLog(`Field '${fieldName}' enabled`);
1395
+ }
1396
+ disableField(fieldName) {
1397
+ this.fieldState.set(fieldName, false);
1398
+ this._fieldCache.set(fieldName, false);
1399
+ if (fieldName === "level" || fieldName === "appName") this._buildPerfCaches();
1400
+ require_transport_manager.internalLog(`Field '${fieldName}' disabled`);
1401
+ }
1402
+ isFieldEnabled(fieldName) {
1403
+ var _this$config$fields2;
1404
+ if (this.fieldState.has(fieldName)) return this.fieldState.get(fieldName);
1405
+ if (((_this$config$fields2 = this.config.fields) === null || _this$config$fields2 === void 0 ? void 0 : _this$config$fields2[fieldName]) !== void 0) return this.config.fields[fieldName] !== false;
1406
+ return true;
1407
+ }
1408
+ getFieldState() {
1409
+ return Object.fromEntries([
1410
+ "timestamp",
1411
+ "level",
1412
+ "appName",
1413
+ "service",
1414
+ "traceId",
1415
+ "message",
1416
+ "payload",
1417
+ "timeTaken",
1418
+ "context",
1419
+ "userId",
1420
+ "sessionId",
1421
+ "environment"
1422
+ ].map((f) => [f, this.isFieldEnabled(f)]));
1423
+ }
1424
+ resetFieldState() {
1425
+ this.fieldState.clear();
1426
+ require_transport_manager.internalLog("Field state reset to configuration defaults");
1427
+ }
1428
+ enableTransportLevelPrompting() {
1429
+ if (this.transportManager) this.transportManager.enableLevelPrompting();
1430
+ else require_transport_manager.internalWarn("Transport manager not initialized");
1431
+ }
1432
+ disableTransportLevelPrompting() {
1433
+ if (this.transportManager) this.transportManager.disableLevelPrompting();
1434
+ else require_transport_manager.internalWarn("Transport manager not initialized");
1435
+ }
1436
+ setTransportLevels(transportId, levels) {
1437
+ if (this.transportManager) this.transportManager.setTransportLevels(transportId, levels);
1438
+ else require_transport_manager.internalWarn("Transport manager not initialized");
1439
+ }
1440
+ getTransportLevels(transportId) {
1441
+ if (this.transportManager) return this.transportManager.getTransportLevels(transportId);
1442
+ require_transport_manager.internalWarn("Transport manager not initialized");
1443
+ }
1444
+ clearTransportLevelPreferences() {
1445
+ if (this.transportManager) this.transportManager.clearTransportLevelPreferences();
1446
+ else require_transport_manager.internalWarn("Transport manager not initialized");
1447
+ }
1448
+ getAvailableTransports() {
1449
+ var _this$transportManage;
1450
+ return ((_this$transportManage = this.transportManager) === null || _this$transportManage === void 0 ? void 0 : _this$transportManage.getTransports()) ?? [];
1451
+ }
1452
+ child(context, data) {
1453
+ const childLogger = new LogixiaLogger(this.config, context);
1454
+ if (data) childLogger.contextData = {
1455
+ ...this.contextData,
1456
+ ...data
1457
+ };
1458
+ return childLogger;
1459
+ }
1460
+ /**
1461
+ * Register a plugin on this logger instance.
1462
+ *
1463
+ * @example
1464
+ * ```ts
1465
+ * logger.use({
1466
+ * name: 'audit',
1467
+ * onLog(entry) { auditQueue.push(entry); return entry; },
1468
+ * });
1469
+ * ```
1470
+ */
1471
+ use(plugin) {
1472
+ this._pluginRegistry.register(plugin);
1473
+ return this;
1474
+ }
1475
+ /**
1476
+ * Remove a previously registered plugin by name.
1477
+ * No-op if the plugin is not registered on this instance.
1478
+ */
1479
+ unuse(pluginName) {
1480
+ this._pluginRegistry.unregister(pluginName);
1481
+ return this;
1482
+ }
1483
+ async flush() {
1484
+ if (this.transportManager) await this.transportManager.flush();
1485
+ }
1486
+ async healthCheck() {
1487
+ if (!this.transportManager) return {
1488
+ healthy: false,
1489
+ details: { error: "TransportManager not initialized" }
1490
+ };
1491
+ return this.transportManager.healthCheck();
1492
+ }
1493
+ async close() {
1494
+ var _this$_sampler;
1495
+ for (const [label, timer] of this.timers) await this.warn(`Timer '${label}' was not ended properly`, {
1496
+ startTime: new Date(timer.startTime).toISOString(),
1497
+ duration: `${Date.now() - timer.startTime}ms (incomplete)`
1498
+ });
1499
+ this.timers.clear();
1500
+ if (this.transportManager) {
1501
+ await this.transportManager.flush();
1502
+ await this.transportManager.close();
1503
+ }
1504
+ (_this$_sampler = this._sampler) === null || _this$_sampler === void 0 || _this$_sampler.destroy();
1505
+ await this._pluginRegistry.runOnShutdown();
1506
+ deregisterFromShutdown(this);
1507
+ }
1508
+ async log(level, message, data) {
1509
+ if (this.config.silent) return;
1510
+ if (!this.shouldLog(level)) return;
1511
+ if (this._sampler) {
1512
+ const traceId$1 = this.config.traceId ? TraceContext.instance.getCurrentTraceId() ?? this.fallbackTraceId : void 0;
1513
+ if (!this._sampler.shouldEmit(level, traceId$1)) return;
1514
+ }
1515
+ const alsContext = LogixiaContext.get();
1516
+ const otelFields = _getOtelPayloadIfEnabled();
1517
+ const hasOtel = Object.keys(otelFields).length > 0;
1518
+ let mergedData;
1519
+ if (alsContext && Object.keys(alsContext).length > 0) mergedData = {
1520
+ ...alsContext,
1521
+ ...hasOtel ? otelFields : {},
1522
+ ...data
1523
+ };
1524
+ else if (hasOtel) mergedData = {
1525
+ ...otelFields,
1526
+ ...data
1527
+ };
1528
+ else mergedData = data;
1529
+ const rawPayload = this._hasContextData ? {
1530
+ ...this.contextData,
1531
+ ...mergedData
1532
+ } : mergedData;
1533
+ let payload;
1534
+ if (rawPayload !== void 0 && rawPayload !== null) payload = this._hasRedact ? applyRedaction(rawPayload, this.config.redact) ?? rawPayload : rawPayload;
1535
+ const traceId = this.config.traceId ? TraceContext.instance.getCurrentTraceId() ?? this.fallbackTraceId : void 0;
1536
+ const entry = {
1537
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1538
+ level,
1539
+ appName: this.config.appName ?? "App",
1540
+ environment: this.config.environment ?? "development",
1541
+ message
1542
+ };
1543
+ if (this.context) entry.context = this.context;
1544
+ if (payload !== void 0) entry.payload = payload;
1545
+ if (traceId !== void 0) entry.traceId = traceId;
1546
+ let finalEntry = entry;
1547
+ if (this._pluginRegistry.size > 0) {
1548
+ finalEntry = await this._pluginRegistry.runOnLog(entry);
1549
+ if (finalEntry === null) return;
1550
+ }
1551
+ const formattedLog = this.formatLog(finalEntry);
1552
+ await this.output(formattedLog, level, finalEntry);
1553
+ }
1554
+ /**
1555
+ * Hot-path level check: a single Map lookup + integer compare.
1556
+ * The level map and threshold are pre-built in _buildPerfCaches().
1557
+ */
1558
+ shouldLog(level) {
1559
+ const v = this._levelValues.get(level);
1560
+ return v !== void 0 && v <= this._minLevelValue;
1561
+ }
1562
+ /**
1563
+ * Feature 3: Resolve the effective log level for this logger instance.
1564
+ *
1565
+ * Priority:
1566
+ * 1. ENV `LOGIXIA_LEVEL_<NS_UPPER>` (e.g. LOGIXIA_LEVEL_DB for ns "db" or "db.queries")
1567
+ * 2. Matching `namespaceLevels` config entry (longer pattern = more specific, wins)
1568
+ * 3. Global `LOGIXIA_LEVEL` ENV override
1569
+ * 4. `levelOptions.level` (resolved via Feature 5 in constructor)
1570
+ */
1571
+ resolveEffectiveLevel() {
1572
+ const ns = this.context;
1573
+ if (ns) {
1574
+ const nsKey = ns.split(".")[0].toUpperCase();
1575
+ const envNsLevel = process.env[`LOGIXIA_LEVEL_${nsKey}`];
1576
+ if (envNsLevel) return envNsLevel;
1577
+ const namespaceLevels = this.config.namespaceLevels;
1578
+ if (namespaceLevels) {
1579
+ const sortedPatterns = Object.keys(namespaceLevels).sort((a, b) => b.length - a.length);
1580
+ for (const pattern of sortedPatterns) if (matchesNamespacePattern(ns, pattern)) return namespaceLevels[pattern];
1581
+ }
1582
+ }
1583
+ const globalEnv = process.env["LOGIXIA_LEVEL"];
1584
+ if (globalEnv) return globalEnv;
1585
+ return this.getLevel();
1586
+ }
1587
+ formatLog(entry) {
1588
+ var _this$config$format2, _this$config$format3, _this$config$format4;
1589
+ if ((_this$config$format2 = this.config.format) === null || _this$config$format2 === void 0 ? void 0 : _this$config$format2.json) return _fastStringifyEntry(entry);
1590
+ let formatted = "";
1591
+ const doColorize = ((_this$config$format3 = this.config.format) === null || _this$config$format3 === void 0 ? void 0 : _this$config$format3.colorize) ?? true;
1592
+ const gray = doColorize ? this._colorMap.get("gray") : "";
1593
+ const cyan = doColorize ? this._colorMap.get("cyan") : "";
1594
+ const yellow = doColorize ? this._colorMap.get("yellow") : "";
1595
+ const reset = doColorize ? this._colorMap.get("reset") : "";
1596
+ if (((_this$config$format4 = this.config.format) === null || _this$config$format4 === void 0 ? void 0 : _this$config$format4.timestamp) !== false && this._fieldCache.get("timestamp") !== false) formatted += `${gray}[${entry.timestamp}]${reset} `;
1597
+ if (this._fieldCache.get("level") !== false) formatted += this._formattedLevels.get(entry.level) ?? `[${entry.level.toUpperCase()}] `;
1598
+ formatted += this._formattedAppName;
1599
+ if (entry.traceId && this._fieldCache.get("traceId") !== false) formatted += `${cyan}[${entry.traceId}]${reset} `;
1600
+ if (entry.context && this._fieldCache.get("context") !== false) formatted += `${yellow}[${entry.context}]${reset} `;
1601
+ if (this._fieldCache.get("message") !== false) formatted += entry.message;
1602
+ if (entry.payload !== void 0 && this._fieldCache.get("payload") !== false) formatted += ` ${JSON.stringify(entry.payload)}`;
1603
+ return formatted;
1604
+ }
1605
+ colorize(text, color) {
1606
+ var _this$config$format5;
1607
+ if (!((_this$config$format5 = this.config.format) === null || _this$config$format5 === void 0 ? void 0 : _this$config$format5.colorize)) return text;
1608
+ return `${this._colorMap.get(color.toLowerCase()) ?? this._colorMap.get("white")}${text}${this._colorMap.get("reset")}`;
1609
+ }
1610
+ async output(message, level, entry) {
1611
+ if (this.transportManager) try {
1612
+ await this.transportManager.write(entry);
1613
+ return;
1614
+ } catch (error) {
1615
+ require_transport_manager.internalError("Transport write failed", error);
1616
+ }
1617
+ (level === LogLevel.ERROR ? process.stderr : process.stdout).write(message + "\n");
1618
+ }
1619
+ };
1620
+ function createLogger(config, context) {
1621
+ var _config$levelOptions2;
1622
+ const logger = new LogixiaLogger(config, context);
1623
+ const mutableLogger = logger;
1624
+ if ((_config$levelOptions2 = config.levelOptions) === null || _config$levelOptions2 === void 0 ? void 0 : _config$levelOptions2.levels) {
1625
+ for (const levelName of Object.keys(config.levelOptions.levels)) if (!mutableLogger[levelName]) mutableLogger[levelName] = async (message, data) => {
1626
+ await logger.logLevel(levelName, message, data);
1627
+ };
1628
+ }
1629
+ return logger;
1630
+ }
1631
+
1632
+ //#endregion
1633
+ //#region \0@oxc-project+runtime@0.95.0/helpers/decorateMetadata.js
1634
+ function __decorateMetadata(k, v) {
1635
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1636
+ }
1637
+
1638
+ //#endregion
1639
+ //#region \0@oxc-project+runtime@0.95.0/helpers/decorate.js
1640
+ function __decorate(decorators, target, key, desc) {
1641
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1642
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1643
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1644
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1645
+ }
1646
+
1647
+ //#endregion
1648
+ //#region src/core/logitron-nestjs.service.ts
1649
+ var _LogixiaLoggerService;
1650
+ let LogixiaLoggerService = _LogixiaLoggerService = class LogixiaLoggerService$1 {
1651
+ constructor(config) {
1652
+ this._mergedConfig = {
1653
+ appName: "NestJS-App",
1654
+ environment: "development",
1655
+ traceId: true,
1656
+ format: {
1657
+ timestamp: true,
1658
+ colorize: true,
1659
+ json: false
1660
+ },
1661
+ silent: false,
1662
+ levelOptions: {
1663
+ level: LogLevel.INFO,
1664
+ levels: {
1665
+ error: 0,
1666
+ warn: 1,
1667
+ log: 2,
1668
+ debug: 3,
1669
+ verbose: 4
1670
+ },
1671
+ colors: {
1672
+ error: "red",
1673
+ warn: "yellow",
1674
+ log: "green",
1675
+ debug: "blue",
1676
+ verbose: "cyan"
1677
+ }
1678
+ },
1679
+ fields: {
1680
+ timestamp: "[yyyy-mm-dd HH:MM:ss.MS]",
1681
+ level: "[log_level]",
1682
+ appName: "[app_name]",
1683
+ traceId: "[trace_id]",
1684
+ message: "[message]",
1685
+ payload: "[payload]",
1686
+ timeTaken: "[time_taken_MS]"
1687
+ },
1688
+ ...config
1689
+ };
1690
+ this.logger = new LogixiaLogger(this._mergedConfig);
1691
+ this._createCustomLevelMethods();
1692
+ }
1693
+ _createCustomLevelMethods() {
1694
+ var _this$_mergedConfig$l;
1695
+ const levels = (_this$_mergedConfig$l = this._mergedConfig.levelOptions) === null || _this$_mergedConfig$l === void 0 ? void 0 : _this$_mergedConfig$l.levels;
1696
+ if (!levels) return;
1697
+ for (const levelName of Object.keys(levels)) {
1698
+ const lower = levelName.toLowerCase();
1699
+ if (typeof this[lower] !== "undefined") continue;
1700
+ this[lower] = async (message, data) => {
1701
+ return this.logger.logLevel(lower, message, data);
1702
+ };
1703
+ }
1704
+ }
1705
+ /**
1706
+ * NestJS `LoggerService.log` — void, string context.
1707
+ * Maps internally to `info`.
1708
+ *
1709
+ * @example `logger.log('User signed up', 'AuthService')`
1710
+ */
1711
+ log(message, context) {
1712
+ this.setContextIfProvided(context);
1713
+ this.logger.info(this.formatMessage(message)).catch((err) => require_transport_manager.internalError("LogixiaLoggerService.log failed", err));
1714
+ }
1715
+ /**
1716
+ * Native async `info` — structured data, returns `Promise<void>`.
1717
+ *
1718
+ * @example `await logger.info('User signed up', { userId: 'u_abc' })`
1719
+ */
1720
+ async info(message, data) {
1721
+ return this.logger.info(message, data);
1722
+ }
1723
+ error(message, dataOrTrace, context) {
1724
+ if (typeof dataOrTrace === "object" && dataOrTrace !== null) return message instanceof Error ? this.logger.error(message, dataOrTrace) : this.logger.error(this.formatMessage(message), dataOrTrace);
1725
+ this.setContextIfProvided(context);
1726
+ const errorData = {};
1727
+ if (typeof dataOrTrace === "string" && dataOrTrace) errorData.stack = dataOrTrace;
1728
+ (message instanceof Error ? this.logger.error(message, errorData) : this.logger.error(this.formatMessage(message), errorData)).catch((err) => require_transport_manager.internalError("LogixiaLoggerService.error failed", err));
1729
+ }
1730
+ warn(message, dataOrContext) {
1731
+ if (typeof dataOrContext === "object" && dataOrContext !== null) return this.logger.warn(this.formatMessage(message), dataOrContext);
1732
+ this.setContextIfProvided(typeof dataOrContext === "string" ? dataOrContext : void 0);
1733
+ this.logger.warn(this.formatMessage(message)).catch((err) => require_transport_manager.internalError("LogixiaLoggerService.warn failed", err));
1734
+ }
1735
+ debug(message, dataOrContext) {
1736
+ if (typeof dataOrContext === "object" && dataOrContext !== null) return this.logger.debug(this.formatMessage(message), dataOrContext);
1737
+ this.setContextIfProvided(typeof dataOrContext === "string" ? dataOrContext : void 0);
1738
+ this.logger.debug(this.formatMessage(message)).catch((err) => require_transport_manager.internalError("LogixiaLoggerService.debug failed", err));
1739
+ }
1740
+ verbose(message, dataOrContext) {
1741
+ if (typeof dataOrContext === "object" && dataOrContext !== null) return this.logger.trace(this.formatMessage(message), dataOrContext);
1742
+ this.setContextIfProvided(typeof dataOrContext === "string" ? dataOrContext : void 0);
1743
+ this.logger.trace(this.formatMessage(message)).catch((err) => require_transport_manager.internalError("LogixiaLoggerService.verbose failed", err));
1744
+ }
1745
+ /**
1746
+ * Native async `trace` — lowest verbosity level, structured data.
1747
+ */
1748
+ async trace(message, data) {
1749
+ return this.logger.trace(message, data);
1750
+ }
1751
+ /**
1752
+ * Log at any named level with structured data.
1753
+ */
1754
+ logLevel(level, message, data) {
1755
+ return this.logger.logLevel(level, message, data);
1756
+ }
1757
+ time(label) {
1758
+ this.logger.time(label);
1759
+ }
1760
+ async timeEnd(label) {
1761
+ return this.logger.timeEnd(label);
1762
+ }
1763
+ async timeAsync(label, fn) {
1764
+ return this.logger.timeAsync(label, fn);
1765
+ }
1766
+ setContext(context) {
1767
+ this.context = context;
1768
+ this.logger.setContext(context);
1769
+ }
1770
+ getContext() {
1771
+ return this.context;
1772
+ }
1773
+ setLevel(level) {
1774
+ this.logger.setLevel(level);
1775
+ }
1776
+ getLevel() {
1777
+ return this.logger.getLevel();
1778
+ }
1779
+ child(context, data) {
1780
+ const childService = new _LogixiaLoggerService(this._mergedConfig);
1781
+ childService.logger = this.logger.child(context, data);
1782
+ childService.context = context;
1783
+ return childService;
1784
+ }
1785
+ getCurrentTraceId() {
1786
+ return TraceContext.instance.getCurrentTraceId();
1787
+ }
1788
+ /** Returns the AsyncLocalStorage key currently used to store the trace ID. */
1789
+ get traceContextKey() {
1790
+ return getTraceContextKey();
1791
+ }
1792
+ async close() {
1793
+ return this.logger.close();
1794
+ }
1795
+ static create(config) {
1796
+ return new _LogixiaLoggerService(config);
1797
+ }
1798
+ getLogger() {
1799
+ return this.logger;
1800
+ }
1801
+ setContextIfProvided(context) {
1802
+ if (context && context !== this.context) this.setContext(context);
1803
+ }
1804
+ formatMessage(message) {
1805
+ if (typeof message === "string") return message;
1806
+ if (typeof message === "object") return JSON.stringify(message);
1807
+ return String(message);
1808
+ }
1809
+ };
1810
+ LogixiaLoggerService = _LogixiaLoggerService = __decorate([(0, __nestjs_common.Injectable)({ scope: __nestjs_common.Scope.TRANSIENT }), __decorateMetadata("design:paramtypes", [Object])], LogixiaLoggerService);
1811
+
1812
+ //#endregion
1813
+ //#region src/core/kafka-trace.interceptor.ts
1814
+ var _KafkaTraceInterceptor;
1815
+ let KafkaTraceInterceptor = class KafkaTraceInterceptor$1 {
1816
+ static {
1817
+ _KafkaTraceInterceptor = this;
1818
+ }
1819
+ static #_ = this.metrics = {
1820
+ accepted: 0,
1821
+ acceptedWithoutTrace: 0,
1822
+ dropped: 0
1823
+ };
1824
+ /** Reset counters (tests). */
1825
+ static resetMetrics() {
1826
+ _KafkaTraceInterceptor.metrics.accepted = 0;
1827
+ _KafkaTraceInterceptor.metrics.acceptedWithoutTrace = 0;
1828
+ _KafkaTraceInterceptor.metrics.dropped = 0;
1829
+ }
1830
+ /**
1831
+ * @param config - TraceIdConfig options (extractor keys, contextKey, etc.)
1832
+ * @param requireTraceId - When true, messages with no traceId are silently skipped
1833
+ * (EMPTY Observable — message is ack'd, consumer stays alive).
1834
+ * A WARN is logged AND `KafkaTraceInterceptor.metrics.dropped`
1835
+ * increments so the missing traceId is observable end-to-end.
1836
+ * Default: false (handler runs without trace context).
1837
+ */
1838
+ constructor(config, requireTraceId = false) {
1839
+ this.config = config;
1840
+ this.requireTraceId = requireTraceId;
1841
+ this.ctx = TraceContext.instance;
1842
+ this.config = {
1843
+ enabled: true,
1844
+ contextKey: "traceId",
1845
+ extractor: {
1846
+ body: [
1847
+ "traceId",
1848
+ "trace_id",
1849
+ "x-trace-id"
1850
+ ],
1851
+ header: ["x-trace-id", "trace-id"]
1852
+ },
1853
+ ...config
1854
+ };
1855
+ }
1856
+ intercept(context, next) {
1857
+ var _this$config;
1858
+ if (!((_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enabled)) return next.handle();
1859
+ const rpcContext = context.switchToRpc();
1860
+ const data = rpcContext.getData();
1861
+ const rpcData = rpcContext.getContext();
1862
+ let traceId;
1863
+ if (this.config.extractor) traceId = extractTraceId({
1864
+ body: data,
1865
+ headers: (rpcData === null || rpcData === void 0 ? void 0 : rpcData.headers) ?? {},
1866
+ query: {},
1867
+ params: {}
1868
+ }, this.config.extractor);
1869
+ if (!traceId) traceId = this.ctx.getCurrentTraceId();
1870
+ if (!traceId) {
1871
+ if (this.requireTraceId) {
1872
+ var _LogixiaLoggerModule$;
1873
+ _KafkaTraceInterceptor.metrics.dropped++;
1874
+ (_LogixiaLoggerModule$ = LogixiaLoggerModule.getGlobalLogger()) === null || _LogixiaLoggerModule$ === void 0 || _LogixiaLoggerModule$.warn(`[KafkaTraceInterceptor] Missing traceId on topic "${rpcData === null || rpcData === void 0 ? void 0 : rpcData.topic}" — message skipped.`);
1875
+ return rxjs.EMPTY;
1876
+ }
1877
+ _KafkaTraceInterceptor.metrics.acceptedWithoutTrace++;
1878
+ return next.handle();
1879
+ }
1880
+ _KafkaTraceInterceptor.metrics.accepted++;
1881
+ const kafkaContext = {
1882
+ messageType: "kafka",
1883
+ topic: rpcData === null || rpcData === void 0 ? void 0 : rpcData.topic,
1884
+ partition: rpcData === null || rpcData === void 0 ? void 0 : rpcData.partition,
1885
+ offset: rpcData === null || rpcData === void 0 ? void 0 : rpcData.offset,
1886
+ key: rpcData === null || rpcData === void 0 ? void 0 : rpcData.key,
1887
+ timestamp: rpcData === null || rpcData === void 0 ? void 0 : rpcData.timestamp
1888
+ };
1889
+ return new rxjs.Observable((subscriber) => {
1890
+ this.ctx.run(traceId, () => {
1891
+ next.handle().subscribe({
1892
+ next: (value) => subscriber.next(value),
1893
+ error: (err) => subscriber.error(err),
1894
+ complete: () => subscriber.complete()
1895
+ });
1896
+ }, kafkaContext);
1897
+ });
1898
+ }
1899
+ };
1900
+ KafkaTraceInterceptor = _KafkaTraceInterceptor = __decorate([(0, __nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [Object, Boolean])], KafkaTraceInterceptor);
1901
+
1902
+ //#endregion
1903
+ //#region \0@oxc-project+runtime@0.95.0/helpers/decorateParam.js
1904
+ function __decorateParam(paramIndex, decorator) {
1905
+ return function(target, key) {
1906
+ decorator(target, key, paramIndex);
1907
+ };
1908
+ }
1909
+
1910
+ //#endregion
1911
+ //#region src/core/trace.middleware.ts
1912
+ /** Default response header used to echo the resolved traceId back to the caller. */
1913
+ const DEFAULT_TRACE_RESPONSE_HEADER = "X-Trace-Id";
1914
+ /**
1915
+ * Resolve the response header name from config.
1916
+ * - `undefined` → default `'X-Trace-Id'`
1917
+ * - `string` → user's custom header
1918
+ * - `false` → `null` (suppress entirely)
1919
+ */
1920
+ function resolveResponseHeader(config) {
1921
+ if ((config === null || config === void 0 ? void 0 : config.responseHeader) === false) return null;
1922
+ return (config === null || config === void 0 ? void 0 : config.responseHeader) ?? DEFAULT_TRACE_RESPONSE_HEADER;
1923
+ }
1924
+ let TraceMiddleware = class TraceMiddleware$1 {
1925
+ constructor(config) {
1926
+ this.config = config;
1927
+ this.ctx = TraceContext.instance;
1928
+ const defaultExtractor = {
1929
+ header: DEFAULT_TRACE_HEADERS,
1930
+ query: ["traceId", "trace_id"]
1931
+ };
1932
+ this.config = {
1933
+ enabled: true,
1934
+ generator: () => this.ctx.generate(),
1935
+ contextKey: "traceId",
1936
+ ...config,
1937
+ extractor: (config === null || config === void 0 ? void 0 : config.extractor) ? {
1938
+ ...defaultExtractor,
1939
+ ...config.extractor
1940
+ } : defaultExtractor
1941
+ };
1942
+ if (this.config.enabled) this.ctx.setContextKey(this.config.contextKey ?? "traceId");
1943
+ }
1944
+ use(req, res, next) {
1945
+ var _this$config;
1946
+ if (!((_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enabled)) return next();
1947
+ let traceId;
1948
+ if (this.config.extractor) traceId = extractTraceId(req, this.config.extractor);
1949
+ if (!traceId && this.config.generator) {
1950
+ const candidate = this.config.generator();
1951
+ if (typeof candidate === "string" && candidate.trim().length > 0) traceId = candidate;
1952
+ else process.stderr.write("[logixia] TraceIdConfig.generator returned a non-string/empty value — using built-in generator.\n");
1953
+ }
1954
+ if (!traceId) traceId = this.ctx.generate();
1955
+ req.traceId = traceId;
1956
+ const header = resolveResponseHeader(this.config);
1957
+ if (header) res.setHeader(header, traceId);
1958
+ this.ctx.run(traceId, () => next(), {
1959
+ method: req.method,
1960
+ url: req.url,
1961
+ userAgent: req.get("User-Agent"),
1962
+ ip: req.ip || req.connection.remoteAddress
1963
+ });
1964
+ }
1965
+ };
1966
+ TraceMiddleware = __decorate([
1967
+ (0, __nestjs_common.Injectable)(),
1968
+ __decorateParam(0, (0, __nestjs_common.Optional)()),
1969
+ __decorateMetadata("design:paramtypes", [Object])
1970
+ ], TraceMiddleware);
1971
+
1972
+ //#endregion
1973
+ //#region src/core/websocket-trace.interceptor.ts
1974
+ let WebSocketTraceInterceptor = class WebSocketTraceInterceptor$1 {
1975
+ constructor(config) {
1976
+ this.config = config;
1977
+ this.ctx = TraceContext.instance;
1978
+ this.config = {
1979
+ enabled: true,
1980
+ contextKey: "traceId",
1981
+ extractor: {
1982
+ body: [
1983
+ "traceId",
1984
+ "trace_id",
1985
+ "x-trace-id"
1986
+ ],
1987
+ header: ["x-trace-id", "trace-id"],
1988
+ query: ["traceId", "trace_id"]
1989
+ },
1990
+ ...config
1991
+ };
1992
+ }
1993
+ intercept(context, next) {
1994
+ var _this$config, _client$handshake3;
1995
+ if (!((_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enabled)) return next.handle();
1996
+ const wsContext = context.switchToWs();
1997
+ const data = wsContext.getData();
1998
+ const client = wsContext.getClient();
1999
+ let traceId;
2000
+ if (this.config.extractor) {
2001
+ var _client$handshake, _client$handshake2;
2002
+ traceId = extractTraceId({
2003
+ body: data,
2004
+ headers: (client === null || client === void 0 || (_client$handshake = client.handshake) === null || _client$handshake === void 0 ? void 0 : _client$handshake.headers) || {},
2005
+ query: (client === null || client === void 0 || (_client$handshake2 = client.handshake) === null || _client$handshake2 === void 0 ? void 0 : _client$handshake2.query) || {},
2006
+ params: {}
2007
+ }, this.config.extractor);
2008
+ }
2009
+ if (!traceId) traceId = this.ctx.getCurrentTraceId();
2010
+ if (!traceId) return next.handle();
2011
+ const wsContextData = {
2012
+ messageType: "websocket",
2013
+ event: data === null || data === void 0 ? void 0 : data.event,
2014
+ socketId: client === null || client === void 0 ? void 0 : client.id,
2015
+ rooms: (client === null || client === void 0 ? void 0 : client.rooms) ? Array.from(client.rooms) : [],
2016
+ clientAddress: client === null || client === void 0 || (_client$handshake3 = client.handshake) === null || _client$handshake3 === void 0 ? void 0 : _client$handshake3.address
2017
+ };
2018
+ return new rxjs.Observable((observer) => {
2019
+ this.ctx.run(traceId, () => {
2020
+ next.handle().subscribe({
2021
+ next: (value) => observer.next(value),
2022
+ error: (err) => observer.error(err),
2023
+ complete: () => observer.complete()
2024
+ });
2025
+ }, wsContextData);
2026
+ });
2027
+ }
2028
+ };
2029
+ WebSocketTraceInterceptor = __decorate([(0, __nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [Object])], WebSocketTraceInterceptor);
2030
+
2031
+ //#endregion
2032
+ //#region src/core/logitron-logger.module.ts
2033
+ var _LogixiaLoggerModule;
2034
+ const DEFAULT_ROUTES = [{
2035
+ path: "*",
2036
+ method: __nestjs_common.RequestMethod.ALL
2037
+ }];
2038
+ const LOGIXIA_LOGGER_CONFIG = "LOGIXIA_LOGGER_CONFIG";
2039
+ const LOGIXIA_LOGGER_PREFIX = "LOGIXIA_LOGGER_";
2040
+ let LogixiaLoggerModule = class LogixiaLoggerModule$1 {
2041
+ static {
2042
+ _LogixiaLoggerModule = this;
2043
+ }
2044
+ constructor() {
2045
+ this.config = {};
2046
+ }
2047
+ static #_ = this.loggerConfig = {};
2048
+ static #_2 = this._globalLogger = null;
2049
+ /**
2050
+ * @internal Set the global logger exactly once.
2051
+ *
2052
+ * Called from the module's forRoot / forRootAsync factory. If the module is
2053
+ * initialised more than once in the same process (nested DI context, test
2054
+ * harness creating multiple apps, hot reload, etc.) a warning is written to
2055
+ * stderr and the first logger wins — silently overwriting would allow the
2056
+ * newer instance's transport config to replace the live one while the old
2057
+ * one is still being used by registered shutdown hooks, decorators, etc.
2058
+ *
2059
+ * Use {@link _resetGlobalLogger} in tests to reset between runs.
2060
+ */
2061
+ static _setGlobalLogger(service) {
2062
+ if (_LogixiaLoggerModule._globalLogger !== null) {
2063
+ process.stderr.write("[logixia] LogixiaLoggerModule.forRoot() was called more than once — ignoring the second init. If this is intentional (e.g. in tests), call LogixiaLoggerModule._resetGlobalLogger() first.\n");
2064
+ return;
2065
+ }
2066
+ _LogixiaLoggerModule._globalLogger = service;
2067
+ }
2068
+ /** @internal Clear the global logger. Tests only. */
2069
+ static _resetGlobalLogger() {
2070
+ _LogixiaLoggerModule._globalLogger = null;
2071
+ }
2072
+ /**
2073
+ * Returns the global LogixiaLoggerService instance that was created when the
2074
+ * module booted. Useful for logging outside of NestJS DI — utility functions,
2075
+ * plain scripts, decorators — without injecting the service everywhere.
2076
+ *
2077
+ * Returns `null` if called before `LogixiaLoggerModule.forRoot[Async]()` has
2078
+ * been initialised (i.e. before the NestJS app has started).
2079
+ *
2080
+ * @example
2081
+ * ```ts
2082
+ * // some-util.ts
2083
+ * import { LogixiaLoggerModule } from 'logixia/nest';
2084
+ *
2085
+ * export function doSomething() {
2086
+ * LogixiaLoggerModule.getGlobalLogger()?.info('doing something');
2087
+ * }
2088
+ * ```
2089
+ */
2090
+ static getGlobalLogger() {
2091
+ return _LogixiaLoggerModule._globalLogger;
2092
+ }
2093
+ configure(consumer) {
2094
+ const { forRoutes = DEFAULT_ROUTES, exclude } = this.config;
2095
+ let resolvedTraceConfig;
2096
+ if (typeof _LogixiaLoggerModule.loggerConfig.traceId === "object") resolvedTraceConfig = _LogixiaLoggerModule.loggerConfig.traceId;
2097
+ else if (_LogixiaLoggerModule.loggerConfig.traceId === true) resolvedTraceConfig = {
2098
+ enabled: true,
2099
+ contextKey: "traceId",
2100
+ generator: () => TraceContext.instance.generate()
2101
+ };
2102
+ const middleware = new TraceMiddleware(resolvedTraceConfig);
2103
+ const middlewareConfig = (req, res, next) => middleware.use(req, res, next);
2104
+ if (exclude) consumer.apply(middlewareConfig).exclude(...exclude).forRoutes(...forRoutes);
2105
+ else consumer.apply(middlewareConfig).forRoutes(...forRoutes);
2106
+ }
2107
+ /**
2108
+ * Configure the module with synchronous options
2109
+ */
2110
+ static forRoot(config) {
2111
+ _LogixiaLoggerModule.loggerConfig = config || {};
2112
+ const traceConfig = (config === null || config === void 0 ? void 0 : config.traceId) && typeof config.traceId === "object" ? config.traceId : { enabled: !!(config === null || config === void 0 ? void 0 : config.traceId) };
2113
+ return {
2114
+ module: _LogixiaLoggerModule,
2115
+ providers: [
2116
+ {
2117
+ provide: LOGIXIA_LOGGER_CONFIG,
2118
+ useValue: config || {}
2119
+ },
2120
+ {
2121
+ provide: "TRACE_CONFIG",
2122
+ useValue: traceConfig
2123
+ },
2124
+ {
2125
+ provide: LogixiaLoggerService,
2126
+ useFactory: (loggerConfig) => {
2127
+ const service = new LogixiaLoggerService({
2128
+ level: "info",
2129
+ service: "NestJSApp",
2130
+ environment: "development",
2131
+ fields: {},
2132
+ formatters: ["text"],
2133
+ outputs: ["console"],
2134
+ levelOptions: {
2135
+ level: "info",
2136
+ levels: {
2137
+ error: 0,
2138
+ warn: 1,
2139
+ info: 2,
2140
+ debug: 3,
2141
+ verbose: 4
2142
+ },
2143
+ colors: {
2144
+ error: "red",
2145
+ warn: "yellow",
2146
+ info: "green",
2147
+ debug: "blue",
2148
+ verbose: "cyan"
2149
+ }
2150
+ },
2151
+ ...loggerConfig
2152
+ });
2153
+ _LogixiaLoggerModule._setGlobalLogger(service);
2154
+ return service;
2155
+ },
2156
+ inject: [LOGIXIA_LOGGER_CONFIG]
2157
+ },
2158
+ {
2159
+ provide: KafkaTraceInterceptor,
2160
+ useFactory: (traceConfig$1) => new KafkaTraceInterceptor(traceConfig$1),
2161
+ inject: ["TRACE_CONFIG"]
2162
+ },
2163
+ {
2164
+ provide: WebSocketTraceInterceptor,
2165
+ useFactory: (traceConfig$1) => new WebSocketTraceInterceptor(traceConfig$1),
2166
+ inject: ["TRACE_CONFIG"]
2167
+ }
2168
+ ],
2169
+ exports: [
2170
+ LogixiaLoggerService,
2171
+ LOGIXIA_LOGGER_CONFIG,
2172
+ KafkaTraceInterceptor,
2173
+ WebSocketTraceInterceptor
2174
+ ],
2175
+ global: true
2176
+ };
2177
+ }
2178
+ /**
2179
+ * Configure the module with asynchronous options
2180
+ */
2181
+ static forRootAsync(options) {
2182
+ return {
2183
+ module: _LogixiaLoggerModule,
2184
+ imports: options.imports || [],
2185
+ providers: [
2186
+ ...this.createAsyncProviders(options),
2187
+ {
2188
+ provide: "TRACE_CONFIG",
2189
+ useFactory: (loggerConfig) => {
2190
+ return typeof (loggerConfig === null || loggerConfig === void 0 ? void 0 : loggerConfig.traceId) === "object" ? loggerConfig.traceId : { enabled: !!(loggerConfig === null || loggerConfig === void 0 ? void 0 : loggerConfig.traceId) };
2191
+ },
2192
+ inject: [LOGIXIA_LOGGER_CONFIG]
2193
+ },
2194
+ {
2195
+ provide: LogixiaLoggerService,
2196
+ useFactory: (loggerConfig) => {
2197
+ const defaultConfig = {
2198
+ level: "info",
2199
+ service: "NestJSApp",
2200
+ environment: "development",
2201
+ fields: {},
2202
+ formatters: ["text"],
2203
+ outputs: ["console"],
2204
+ levelOptions: {
2205
+ level: "info",
2206
+ levels: {
2207
+ error: 0,
2208
+ warn: 1,
2209
+ info: 2,
2210
+ debug: 3,
2211
+ verbose: 4
2212
+ },
2213
+ colors: {
2214
+ error: "red",
2215
+ warn: "yellow",
2216
+ info: "green",
2217
+ debug: "blue",
2218
+ verbose: "cyan"
2219
+ }
2220
+ },
2221
+ ...loggerConfig
2222
+ };
2223
+ _LogixiaLoggerModule.loggerConfig = defaultConfig;
2224
+ const service = new LogixiaLoggerService(defaultConfig);
2225
+ _LogixiaLoggerModule._setGlobalLogger(service);
2226
+ return service;
2227
+ },
2228
+ inject: [LOGIXIA_LOGGER_CONFIG]
2229
+ },
2230
+ {
2231
+ provide: KafkaTraceInterceptor,
2232
+ useFactory: (traceConfig) => new KafkaTraceInterceptor(traceConfig),
2233
+ inject: ["TRACE_CONFIG"]
2234
+ },
2235
+ {
2236
+ provide: WebSocketTraceInterceptor,
2237
+ useFactory: (traceConfig) => new WebSocketTraceInterceptor(traceConfig),
2238
+ inject: ["TRACE_CONFIG"]
2239
+ }
2240
+ ],
2241
+ exports: [
2242
+ LogixiaLoggerService,
2243
+ LOGIXIA_LOGGER_CONFIG,
2244
+ KafkaTraceInterceptor,
2245
+ WebSocketTraceInterceptor
2246
+ ],
2247
+ global: true
2248
+ };
2249
+ }
2250
+ /**
2251
+ * Create feature-specific logger instances
2252
+ */
2253
+ static forFeature(context) {
2254
+ const providerToken = `${LOGIXIA_LOGGER_PREFIX}${context.toUpperCase()}`;
2255
+ return {
2256
+ module: _LogixiaLoggerModule,
2257
+ providers: [{
2258
+ provide: providerToken,
2259
+ useFactory: (baseLogger) => {
2260
+ return baseLogger.child(context);
2261
+ },
2262
+ inject: [LogixiaLoggerService]
2263
+ }],
2264
+ exports: [providerToken]
2265
+ };
2266
+ }
2267
+ static createAsyncProviders(options) {
2268
+ if (options.useExisting || options.useFactory) return [this.createAsyncOptionsProvider(options)];
2269
+ return [this.createAsyncOptionsProvider(options), {
2270
+ provide: options.useClass,
2271
+ useClass: options.useClass
2272
+ }];
2273
+ }
2274
+ static createAsyncOptionsProvider(options) {
2275
+ if (options.useFactory) return {
2276
+ provide: LOGIXIA_LOGGER_CONFIG,
2277
+ useFactory: options.useFactory,
2278
+ inject: options.inject || []
2279
+ };
2280
+ return {
2281
+ provide: LOGIXIA_LOGGER_CONFIG,
2282
+ useFactory: async (optionsFactory) => await optionsFactory.createLogixiaOptions(),
2283
+ inject: [options.useExisting || options.useClass]
2284
+ };
2285
+ }
2286
+ };
2287
+ LogixiaLoggerModule = _LogixiaLoggerModule = __decorate([(0, __nestjs_common.Module)({})], LogixiaLoggerModule);
2288
+
2289
+ //#endregion
2290
+ Object.defineProperty(exports, 'DEFAULT_LOG_COLORS', {
2291
+ enumerable: true,
2292
+ get: function () {
2293
+ return DEFAULT_LOG_COLORS;
2294
+ }
2295
+ });
2296
+ Object.defineProperty(exports, 'DEFAULT_LOG_LEVELS', {
2297
+ enumerable: true,
2298
+ get: function () {
2299
+ return DEFAULT_LOG_LEVELS;
2300
+ }
2301
+ });
2302
+ Object.defineProperty(exports, 'DEFAULT_TRACE_HEADERS', {
2303
+ enumerable: true,
2304
+ get: function () {
2305
+ return DEFAULT_TRACE_HEADERS;
2306
+ }
2307
+ });
2308
+ Object.defineProperty(exports, 'KafkaTraceInterceptor', {
2309
+ enumerable: true,
2310
+ get: function () {
2311
+ return KafkaTraceInterceptor;
2312
+ }
2313
+ });
2314
+ Object.defineProperty(exports, 'LOGIXIA_LOGGER_CONFIG', {
2315
+ enumerable: true,
2316
+ get: function () {
2317
+ return LOGIXIA_LOGGER_CONFIG;
2318
+ }
2319
+ });
2320
+ Object.defineProperty(exports, 'LOGIXIA_LOGGER_PREFIX', {
2321
+ enumerable: true,
2322
+ get: function () {
2323
+ return LOGIXIA_LOGGER_PREFIX;
2324
+ }
2325
+ });
2326
+ Object.defineProperty(exports, 'LogLevel', {
2327
+ enumerable: true,
2328
+ get: function () {
2329
+ return LogLevel;
2330
+ }
2331
+ });
2332
+ Object.defineProperty(exports, 'LogixiaContext', {
2333
+ enumerable: true,
2334
+ get: function () {
2335
+ return LogixiaContext;
2336
+ }
2337
+ });
2338
+ Object.defineProperty(exports, 'LogixiaLogger', {
2339
+ enumerable: true,
2340
+ get: function () {
2341
+ return LogixiaLogger;
2342
+ }
2343
+ });
2344
+ Object.defineProperty(exports, 'LogixiaLoggerModule', {
2345
+ enumerable: true,
2346
+ get: function () {
2347
+ return LogixiaLoggerModule;
2348
+ }
2349
+ });
2350
+ Object.defineProperty(exports, 'LogixiaLoggerService', {
2351
+ enumerable: true,
2352
+ get: function () {
2353
+ return LogixiaLoggerService;
2354
+ }
2355
+ });
2356
+ Object.defineProperty(exports, 'PluginRegistry', {
2357
+ enumerable: true,
2358
+ get: function () {
2359
+ return PluginRegistry;
2360
+ }
2361
+ });
2362
+ Object.defineProperty(exports, 'TRACE_CONTEXT_KEY', {
2363
+ enumerable: true,
2364
+ get: function () {
2365
+ return TRACE_CONTEXT_KEY;
2366
+ }
2367
+ });
2368
+ Object.defineProperty(exports, 'TraceContext', {
2369
+ enumerable: true,
2370
+ get: function () {
2371
+ return TraceContext;
2372
+ }
2373
+ });
2374
+ Object.defineProperty(exports, 'TraceMiddleware', {
2375
+ enumerable: true,
2376
+ get: function () {
2377
+ return TraceMiddleware;
2378
+ }
2379
+ });
2380
+ Object.defineProperty(exports, 'WebSocketTraceInterceptor', {
2381
+ enumerable: true,
2382
+ get: function () {
2383
+ return WebSocketTraceInterceptor;
2384
+ }
2385
+ });
2386
+ Object.defineProperty(exports, '__decorate', {
2387
+ enumerable: true,
2388
+ get: function () {
2389
+ return __decorate;
2390
+ }
2391
+ });
2392
+ Object.defineProperty(exports, '__decorateMetadata', {
2393
+ enumerable: true,
2394
+ get: function () {
2395
+ return __decorateMetadata;
2396
+ }
2397
+ });
2398
+ Object.defineProperty(exports, '__decorateParam', {
2399
+ enumerable: true,
2400
+ get: function () {
2401
+ return __decorateParam;
2402
+ }
2403
+ });
2404
+ Object.defineProperty(exports, '_setActiveContextKey', {
2405
+ enumerable: true,
2406
+ get: function () {
2407
+ return _setActiveContextKey;
2408
+ }
2409
+ });
2410
+ Object.defineProperty(exports, 'applyRedaction', {
2411
+ enumerable: true,
2412
+ get: function () {
2413
+ return applyRedaction;
2414
+ }
2415
+ });
2416
+ Object.defineProperty(exports, 'createExpressContextMiddleware', {
2417
+ enumerable: true,
2418
+ get: function () {
2419
+ return createExpressContextMiddleware;
2420
+ }
2421
+ });
2422
+ Object.defineProperty(exports, 'createFastifyContextHook', {
2423
+ enumerable: true,
2424
+ get: function () {
2425
+ return createFastifyContextHook;
2426
+ }
2427
+ });
2428
+ Object.defineProperty(exports, 'createLogger', {
2429
+ enumerable: true,
2430
+ get: function () {
2431
+ return createLogger;
2432
+ }
2433
+ });
2434
+ Object.defineProperty(exports, 'createTraceMiddleware', {
2435
+ enumerable: true,
2436
+ get: function () {
2437
+ return createTraceMiddleware;
2438
+ }
2439
+ });
2440
+ Object.defineProperty(exports, 'deregisterFromShutdown', {
2441
+ enumerable: true,
2442
+ get: function () {
2443
+ return deregisterFromShutdown;
2444
+ }
2445
+ });
2446
+ Object.defineProperty(exports, 'disableOtelBridge', {
2447
+ enumerable: true,
2448
+ get: function () {
2449
+ return disableOtelBridge;
2450
+ }
2451
+ });
2452
+ Object.defineProperty(exports, 'extractTraceId', {
2453
+ enumerable: true,
2454
+ get: function () {
2455
+ return extractTraceId;
2456
+ }
2457
+ });
2458
+ Object.defineProperty(exports, 'flushOnExit', {
2459
+ enumerable: true,
2460
+ get: function () {
2461
+ return flushOnExit;
2462
+ }
2463
+ });
2464
+ Object.defineProperty(exports, 'getActiveOtelContext', {
2465
+ enumerable: true,
2466
+ get: function () {
2467
+ return getActiveOtelContext;
2468
+ }
2469
+ });
2470
+ Object.defineProperty(exports, 'getCurrentTraceId', {
2471
+ enumerable: true,
2472
+ get: function () {
2473
+ return getCurrentTraceId;
2474
+ }
2475
+ });
2476
+ Object.defineProperty(exports, 'getOtelMetaFields', {
2477
+ enumerable: true,
2478
+ get: function () {
2479
+ return getOtelMetaFields;
2480
+ }
2481
+ });
2482
+ Object.defineProperty(exports, 'getTraceContextKey', {
2483
+ enumerable: true,
2484
+ get: function () {
2485
+ return getTraceContextKey;
2486
+ }
2487
+ });
2488
+ Object.defineProperty(exports, 'globalPluginRegistry', {
2489
+ enumerable: true,
2490
+ get: function () {
2491
+ return globalPluginRegistry;
2492
+ }
2493
+ });
2494
+ Object.defineProperty(exports, 'initOtelBridge', {
2495
+ enumerable: true,
2496
+ get: function () {
2497
+ return initOtelBridge;
2498
+ }
2499
+ });
2500
+ Object.defineProperty(exports, 'isError', {
2501
+ enumerable: true,
2502
+ get: function () {
2503
+ return isError;
2504
+ }
2505
+ });
2506
+ Object.defineProperty(exports, 'normalizeError', {
2507
+ enumerable: true,
2508
+ get: function () {
2509
+ return normalizeError;
2510
+ }
2511
+ });
2512
+ Object.defineProperty(exports, 'redactObject', {
2513
+ enumerable: true,
2514
+ get: function () {
2515
+ return redactObject;
2516
+ }
2517
+ });
2518
+ Object.defineProperty(exports, 'registerForShutdown', {
2519
+ enumerable: true,
2520
+ get: function () {
2521
+ return registerForShutdown;
2522
+ }
2523
+ });
2524
+ Object.defineProperty(exports, 'resetShutdownHandlers', {
2525
+ enumerable: true,
2526
+ get: function () {
2527
+ return resetShutdownHandlers;
2528
+ }
2529
+ });
2530
+ Object.defineProperty(exports, 'resolveResponseHeader', {
2531
+ enumerable: true,
2532
+ get: function () {
2533
+ return resolveResponseHeader;
2534
+ }
2535
+ });
2536
+ Object.defineProperty(exports, 'runWithTraceId', {
2537
+ enumerable: true,
2538
+ get: function () {
2539
+ return runWithTraceId;
2540
+ }
2541
+ });
2542
+ Object.defineProperty(exports, 'serializeError', {
2543
+ enumerable: true,
2544
+ get: function () {
2545
+ return serializeError;
2546
+ }
2547
+ });
2548
+ Object.defineProperty(exports, 'setTraceId', {
2549
+ enumerable: true,
2550
+ get: function () {
2551
+ return setTraceId;
2552
+ }
2553
+ });
2554
+ Object.defineProperty(exports, 'traceStorage', {
2555
+ enumerable: true,
2556
+ get: function () {
2557
+ return traceStorage;
2558
+ }
2559
+ });
2560
+ Object.defineProperty(exports, 'usePlugin', {
2561
+ enumerable: true,
2562
+ get: function () {
2563
+ return usePlugin;
2564
+ }
2565
+ });
2566
+ //# sourceMappingURL=logitron-logger.module-CMDM61Iz.js.map