logixia 1.13.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +81 -16
  2. package/dist/{async-context-CwBNMm2E.mjs → async-context-BzJrbfQs.mjs} +8 -4
  3. package/dist/async-context-BzJrbfQs.mjs.map +1 -0
  4. package/dist/{async-context-CSHWoHMB.js → async-context-DyQQYq3I.js} +8 -4
  5. package/dist/async-context-DyQQYq3I.js.map +1 -0
  6. package/dist/{azure-monitor.transport-CG7ClkYj.d.ts → azure-monitor.transport-Cn_3Usvu.d.ts} +2 -2
  7. package/dist/{azure-monitor.transport-CG7ClkYj.d.ts.map → azure-monitor.transport-Cn_3Usvu.d.ts.map} +1 -1
  8. package/dist/{azure-monitor.transport-Cm74kXZS.d.mts → azure-monitor.transport-D7Da4RAb.d.mts} +2 -2
  9. package/dist/{azure-monitor.transport-Cm74kXZS.d.mts.map → azure-monitor.transport-D7Da4RAb.d.mts.map} +1 -1
  10. package/dist/azure.d.mts +2 -2
  11. package/dist/azure.d.ts +2 -2
  12. package/dist/browser.d.mts +9 -0
  13. package/dist/browser.d.mts.map +1 -1
  14. package/dist/browser.d.ts +9 -0
  15. package/dist/browser.d.ts.map +1 -1
  16. package/dist/browser.js +43 -12
  17. package/dist/browser.js.map +1 -1
  18. package/dist/browser.mjs +43 -12
  19. package/dist/browser.mjs.map +1 -1
  20. package/dist/{logitron-logger.module-Bs3XYZgF.mjs → builder-0gEzRopq.mjs} +383 -1021
  21. package/dist/builder-0gEzRopq.mjs.map +1 -0
  22. package/dist/{logitron-logger.module-BsDZR5BH.js → builder-D44QktIo.js} +411 -1155
  23. package/dist/builder-D44QktIo.js.map +1 -0
  24. package/dist/cli/index.js +130 -65
  25. package/dist/cloudwatch.d.mts +2 -2
  26. package/dist/cloudwatch.d.ts +2 -2
  27. package/dist/cloudwatch.js +2 -1
  28. package/dist/cloudwatch.mjs +2 -1
  29. package/dist/{cloudwatch.transport-pNBNWJLt.js → cloudwatch.transport-BO1ahxw-.js} +26 -19
  30. package/dist/cloudwatch.transport-BO1ahxw-.js.map +1 -0
  31. package/dist/{cloudwatch.transport-yBwm4OeO.mjs → cloudwatch.transport-DZ6ies7g.mjs} +26 -19
  32. package/dist/cloudwatch.transport-DZ6ies7g.mjs.map +1 -0
  33. package/dist/{cloudwatch.transport-CGHY4buE.d.mts → cloudwatch.transport-DsEq633o.d.ts} +9 -2
  34. package/dist/cloudwatch.transport-DsEq633o.d.ts.map +1 -0
  35. package/dist/{cloudwatch.transport-DK_8cKd3.d.ts → cloudwatch.transport-UlyZFWMn.d.mts} +9 -2
  36. package/dist/cloudwatch.transport-UlyZFWMn.d.mts.map +1 -0
  37. package/dist/{coerce.utils-BN980Y9V.js → coerce.utils-B-LilukN.js} +1 -1
  38. package/dist/{coerce.utils-BN980Y9V.js.map → coerce.utils-B-LilukN.js.map} +1 -1
  39. package/dist/{coerce.utils-Dxv4_ikC.mjs → coerce.utils-Cu6IUTgX.mjs} +1 -1
  40. package/dist/{coerce.utils-Dxv4_ikC.mjs.map → coerce.utils-Cu6IUTgX.mjs.map} +1 -1
  41. package/dist/correlation.d.mts +24 -6
  42. package/dist/correlation.d.mts.map +1 -1
  43. package/dist/correlation.d.ts +24 -6
  44. package/dist/correlation.d.ts.map +1 -1
  45. package/dist/correlation.js +41 -16
  46. package/dist/correlation.js.map +1 -1
  47. package/dist/correlation.mjs +41 -16
  48. package/dist/correlation.mjs.map +1 -1
  49. package/dist/entry-fields-BJkuPnIg.mjs +30 -0
  50. package/dist/entry-fields-BJkuPnIg.mjs.map +1 -0
  51. package/dist/entry-fields-BvOLFlJ4.js +36 -0
  52. package/dist/entry-fields-BvOLFlJ4.js.map +1 -0
  53. package/dist/gcp.d.mts +2 -2
  54. package/dist/gcp.d.ts +2 -2
  55. package/dist/gcp.js +2 -1
  56. package/dist/gcp.mjs +2 -1
  57. package/dist/{gcp.transport-BOhkVKlI.d.ts → gcp.transport-B7oc97sG.d.ts} +2 -2
  58. package/dist/gcp.transport-B7oc97sG.d.ts.map +1 -0
  59. package/dist/{gcp.transport-SHdtc1n0.js → gcp.transport-CHV8MGgz.js} +5 -5
  60. package/dist/gcp.transport-CHV8MGgz.js.map +1 -0
  61. package/dist/{gcp.transport-BJuNRFe_.mjs → gcp.transport-DBX5TPIy.mjs} +5 -5
  62. package/dist/gcp.transport-DBX5TPIy.mjs.map +1 -0
  63. package/dist/{gcp.transport-Bi6CUqZR.d.mts → gcp.transport-GrJurKo8.d.mts} +2 -2
  64. package/dist/gcp.transport-GrJurKo8.d.mts.map +1 -0
  65. package/dist/{index-BPKwwERo.d.mts → index-3mw5gaCw.d.mts} +2 -2
  66. package/dist/{index-BPKwwERo.d.mts.map → index-3mw5gaCw.d.mts.map} +1 -1
  67. package/dist/{index-C1X-TE5I.d.ts → index-DhIoploR.d.ts} +2 -2
  68. package/dist/{index-C1X-TE5I.d.ts.map → index-DhIoploR.d.ts.map} +1 -1
  69. package/dist/index.d.mts +99 -137
  70. package/dist/index.d.mts.map +1 -1
  71. package/dist/index.d.ts +99 -137
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +146 -510
  74. package/dist/index.js.map +1 -1
  75. package/dist/index.mjs +99 -431
  76. package/dist/index.mjs.map +1 -1
  77. package/dist/logitron-logger-BFDSO8Io.d.mts +257 -0
  78. package/dist/logitron-logger-BFDSO8Io.d.mts.map +1 -0
  79. package/dist/logitron-logger-UVeN-mQm.d.ts +257 -0
  80. package/dist/logitron-logger-UVeN-mQm.d.ts.map +1 -0
  81. package/dist/middleware.d.mts +11 -4
  82. package/dist/middleware.d.mts.map +1 -1
  83. package/dist/middleware.d.ts +11 -4
  84. package/dist/middleware.d.ts.map +1 -1
  85. package/dist/middleware.js +148 -24
  86. package/dist/middleware.js.map +1 -1
  87. package/dist/middleware.mjs +148 -24
  88. package/dist/middleware.mjs.map +1 -1
  89. package/dist/nest.d.mts +481 -6
  90. package/dist/nest.d.mts.map +1 -1
  91. package/dist/nest.d.ts +481 -6
  92. package/dist/nest.d.ts.map +1 -1
  93. package/dist/nest.js +884 -13
  94. package/dist/nest.js.map +1 -0
  95. package/dist/nest.mjs +863 -6
  96. package/dist/nest.mjs.map +1 -0
  97. package/dist/{search-CFQRISUv.mjs → search-BFbu_oVn.mjs} +35 -12
  98. package/dist/search-BFbu_oVn.mjs.map +1 -0
  99. package/dist/{search-njTI2hdo.js → search-C4V0OMEn.js} +35 -12
  100. package/dist/search-C4V0OMEn.js.map +1 -0
  101. package/dist/{search-DujhR94O.d.ts → search-CNh9uVwR.d.ts} +2 -3
  102. package/dist/search-CNh9uVwR.d.ts.map +1 -0
  103. package/dist/{search-CQOo-Iq6.d.mts → search-DXANsQ2n.d.mts} +2 -3
  104. package/dist/search-DXANsQ2n.d.mts.map +1 -0
  105. package/dist/search.d.mts +3 -3
  106. package/dist/search.d.ts +3 -3
  107. package/dist/search.js +2 -2
  108. package/dist/search.mjs +2 -2
  109. package/dist/slack.transport-BZzoXDPn.d.mts +112 -0
  110. package/dist/slack.transport-BZzoXDPn.d.mts.map +1 -0
  111. package/dist/slack.transport-BfJRouB2.js +654 -0
  112. package/dist/slack.transport-BfJRouB2.js.map +1 -0
  113. package/dist/slack.transport-Bzw7sucI.mjs +643 -0
  114. package/dist/slack.transport-Bzw7sucI.mjs.map +1 -0
  115. package/dist/slack.transport-CXjQYOes.d.ts +112 -0
  116. package/dist/slack.transport-CXjQYOes.d.ts.map +1 -0
  117. package/dist/testing.d.mts +2 -2
  118. package/dist/testing.d.ts +2 -2
  119. package/dist/trace.utils-CvXgaiQT.mjs +278 -0
  120. package/dist/trace.utils-CvXgaiQT.mjs.map +1 -0
  121. package/dist/trace.utils-DpBOLDtq.js +358 -0
  122. package/dist/trace.utils-DpBOLDtq.js.map +1 -0
  123. package/dist/{transport.manager-D6KL3t9V.mjs → transport.manager-BiuCAJd2.mjs} +526 -160
  124. package/dist/transport.manager-BiuCAJd2.mjs.map +1 -0
  125. package/dist/{transport.manager-BivyUTtU.js → transport.manager-CXbKKdVE.js} +537 -159
  126. package/dist/transport.manager-CXbKKdVE.js.map +1 -0
  127. package/dist/{transport.types-B5vcyv2k.d.mts → transport.types-BMnurPcc.d.mts} +23 -3
  128. package/dist/transport.types-BMnurPcc.d.mts.map +1 -0
  129. package/dist/{transport.types-BuY84TwO.d.ts → transport.types-CGoHpWQR.d.ts} +23 -3
  130. package/dist/transport.types-CGoHpWQR.d.ts.map +1 -0
  131. package/dist/transports.d.mts +50 -20
  132. package/dist/transports.d.mts.map +1 -1
  133. package/dist/transports.d.ts +50 -20
  134. package/dist/transports.d.ts.map +1 -1
  135. package/dist/transports.js +9 -5
  136. package/dist/transports.mjs +8 -6
  137. package/dist/worker-entry.js +307 -55
  138. package/dist/worker.d.mts +2 -2
  139. package/dist/worker.d.ts +2 -2
  140. package/dist/worker.js +1 -1
  141. package/dist/worker.mjs +1 -1
  142. package/dist/{worker.transport-CfH6z37Z.js → worker.transport-BdPxu3PN.js} +1 -1
  143. package/dist/{worker.transport-CfH6z37Z.js.map → worker.transport-BdPxu3PN.js.map} +1 -1
  144. package/dist/{worker.transport-mKXgNK0L.d.ts → worker.transport-CdzSZJmw.d.ts} +2 -2
  145. package/dist/{worker.transport-mKXgNK0L.d.ts.map → worker.transport-CdzSZJmw.d.ts.map} +1 -1
  146. package/dist/{worker.transport-BP8Q28Z2.d.mts → worker.transport-JvGPog3C.d.mts} +2 -2
  147. package/dist/{worker.transport-BP8Q28Z2.d.mts.map → worker.transport-JvGPog3C.d.mts.map} +1 -1
  148. package/dist/{worker.transport-BhMyvqQ2.mjs → worker.transport-lPxO2MVL.mjs} +1 -1
  149. package/dist/{worker.transport-BhMyvqQ2.mjs.map → worker.transport-lPxO2MVL.mjs.map} +1 -1
  150. package/package.json +27 -14
  151. package/dist/.tsbuildinfo +0 -1
  152. package/dist/async-context-CSHWoHMB.js.map +0 -1
  153. package/dist/async-context-CwBNMm2E.mjs.map +0 -1
  154. package/dist/cloudwatch.transport-CGHY4buE.d.mts.map +0 -1
  155. package/dist/cloudwatch.transport-DK_8cKd3.d.ts.map +0 -1
  156. package/dist/cloudwatch.transport-pNBNWJLt.js.map +0 -1
  157. package/dist/cloudwatch.transport-yBwm4OeO.mjs.map +0 -1
  158. package/dist/gcp.transport-BJuNRFe_.mjs.map +0 -1
  159. package/dist/gcp.transport-BOhkVKlI.d.ts.map +0 -1
  160. package/dist/gcp.transport-Bi6CUqZR.d.mts.map +0 -1
  161. package/dist/gcp.transport-SHdtc1n0.js.map +0 -1
  162. package/dist/logitron-logger.module-BdG1Jnpk.d.mts +0 -618
  163. package/dist/logitron-logger.module-BdG1Jnpk.d.mts.map +0 -1
  164. package/dist/logitron-logger.module-Bs3XYZgF.mjs.map +0 -1
  165. package/dist/logitron-logger.module-BsDZR5BH.js.map +0 -1
  166. package/dist/logitron-logger.module-CbXy2gfW.d.ts +0 -618
  167. package/dist/logitron-logger.module-CbXy2gfW.d.ts.map +0 -1
  168. package/dist/search-CFQRISUv.mjs.map +0 -1
  169. package/dist/search-CQOo-Iq6.d.mts.map +0 -1
  170. package/dist/search-DujhR94O.d.ts.map +0 -1
  171. package/dist/search-njTI2hdo.js.map +0 -1
  172. package/dist/transport.manager-BivyUTtU.js.map +0 -1
  173. package/dist/transport.manager-D6KL3t9V.mjs.map +0 -1
  174. package/dist/transport.types-B5vcyv2k.d.mts.map +0 -1
  175. package/dist/transport.types-BuY84TwO.d.ts.map +0 -1
  176. package/scripts/postinstall.js +0 -61
@@ -1,16 +1,86 @@
1
1
  import { t as __require } from "./chunk-DLSkYcPk.mjs";
2
2
  import { n as internalLog, r as internalWarn, t as internalError } from "./internal-log-Cm8SOWSV.mjs";
3
3
  import { i as stringifyForLog } from "./safe-stringify-DJ66tW5I.mjs";
4
- import { t as LogixiaContext } from "./async-context-CwBNMm2E.mjs";
5
- import { t as safeToString } from "./coerce.utils-Dxv4_ikC.mjs";
6
- import { t as TransportManager } from "./transport.manager-D6KL3t9V.mjs";
4
+ import { i as TraceContext } from "./trace.utils-CvXgaiQT.mjs";
5
+ import { t as LogixiaContext } from "./async-context-BzJrbfQs.mjs";
6
+ import { t as safeToString } from "./coerce.utils-Cu6IUTgX.mjs";
7
+ import { d as stripControlChars, t as TransportManager } from "./transport.manager-BiuCAJd2.mjs";
7
8
  import { constants } from "node:os";
8
- import { AsyncLocalStorage } from "node:async_hooks";
9
9
  import buildFastStringify from "fast-json-stringify";
10
- import crypto from "crypto";
11
- import { Injectable, Module, Optional, RequestMethod, Scope } from "@nestjs/common";
12
- import { EMPTY, Observable } from "rxjs";
13
10
 
11
+ //#region src/types/index.ts
12
+ const LogLevel = {
13
+ ERROR: "error",
14
+ WARN: "warn",
15
+ INFO: "info",
16
+ DEBUG: "debug",
17
+ TRACE: "trace",
18
+ VERBOSE: "verbose"
19
+ };
20
+ const DEFAULT_LOG_LEVELS = {
21
+ error: 0,
22
+ warn: 1,
23
+ info: 2,
24
+ debug: 3,
25
+ trace: 4,
26
+ verbose: 5
27
+ };
28
+ const DEFAULT_LOG_COLORS = {
29
+ error: "red",
30
+ warn: "yellow",
31
+ info: "green",
32
+ debug: "blue",
33
+ trace: "magenta",
34
+ verbose: "cyan"
35
+ };
36
+
37
+ //#endregion
38
+ //#region src/core/default-config.ts
39
+ /**
40
+ * Default configuration for Logixia logger
41
+ */
42
+ const DEFAULT_CONFIG = {
43
+ appName: "App",
44
+ environment: "development",
45
+ traceId: true,
46
+ format: {
47
+ timestamp: true,
48
+ colorize: true,
49
+ json: false
50
+ },
51
+ silent: false,
52
+ levelOptions: {
53
+ level: LogLevel.INFO,
54
+ levels: {
55
+ [LogLevel.ERROR]: 0,
56
+ [LogLevel.WARN]: 1,
57
+ [LogLevel.INFO]: 2,
58
+ [LogLevel.DEBUG]: 3,
59
+ [LogLevel.TRACE]: 4,
60
+ [LogLevel.VERBOSE]: 5
61
+ },
62
+ colors: {
63
+ [LogLevel.ERROR]: "red",
64
+ [LogLevel.WARN]: "yellow",
65
+ [LogLevel.INFO]: "blue",
66
+ [LogLevel.DEBUG]: "green",
67
+ [LogLevel.TRACE]: "gray",
68
+ [LogLevel.VERBOSE]: "cyan"
69
+ }
70
+ },
71
+ fields: {
72
+ timestamp: true,
73
+ level: true,
74
+ appName: true,
75
+ traceId: true,
76
+ message: true,
77
+ payload: true,
78
+ timeTaken: true
79
+ },
80
+ outputs: ["console"]
81
+ };
82
+
83
+ //#endregion
14
84
  //#region src/plugin.ts
15
85
  /**
16
86
  * Holds an ordered list of `LogixiaPlugin` instances and dispatches lifecycle
@@ -117,33 +187,6 @@ function usePlugin(plugin) {
117
187
  globalPluginRegistry.register(plugin);
118
188
  }
119
189
 
120
- //#endregion
121
- //#region src/types/index.ts
122
- const LogLevel = {
123
- ERROR: "error",
124
- WARN: "warn",
125
- INFO: "info",
126
- DEBUG: "debug",
127
- TRACE: "trace",
128
- VERBOSE: "verbose"
129
- };
130
- const DEFAULT_LOG_LEVELS = {
131
- error: 0,
132
- warn: 1,
133
- info: 2,
134
- debug: 3,
135
- trace: 4,
136
- verbose: 5
137
- };
138
- const DEFAULT_LOG_COLORS = {
139
- error: "red",
140
- warn: "yellow",
141
- info: "green",
142
- debug: "blue",
143
- trace: "magenta",
144
- verbose: "cyan"
145
- };
146
-
147
190
  //#endregion
148
191
  //#region src/utils/error.utils.ts
149
192
  const EXTRA_FIELDS = [
@@ -386,16 +429,29 @@ function disableOtelBridge() {
386
429
  //#endregion
387
430
  //#region src/utils/redact.utils.ts
388
431
  const DEFAULT_CENSOR = "[REDACTED]";
432
+ /** Maximum nesting depth walked; deeper values are replaced with a marker. */
433
+ const MAX_DEPTH = 32;
434
+ /** Maximum number of objects/arrays visited per redaction pass. */
435
+ const MAX_NODES = 1e4;
436
+ /**
437
+ * Strings longer than this are truncated before pattern scanning. The tail is
438
+ * dropped rather than emitted unscanned, so oversized input can never carry an
439
+ * unredacted secret past the patterns.
440
+ */
441
+ const MAX_SCAN_LENGTH = 16384;
442
+ const MAX_DEPTH_MARKER = "[MaxDepth]";
443
+ const MAX_NODES_MARKER = "[MaxNodes]";
444
+ const REDACTION_FAILED = "[RedactionFailed]";
389
445
  /**
390
446
  * Conservative patterns: tokens and secrets that should NEVER appear in logs.
391
447
  * Applied when `autoDetect: true` or `autoDetect: 'conservative'`.
392
448
  */
393
449
  const PII_CONSERVATIVE_PATTERNS = [
394
- /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*/g,
450
+ /eyJ[A-Za-z0-9_-]{1,1024}\.[A-Za-z0-9_-]{1,16384}\.[A-Za-z0-9_-]{0,1024}/g,
395
451
  /Bearer\s+[A-Za-z0-9._~+/-]+=*/gi,
396
452
  /\b(?:sk|pk|api|key|secret|token)-[A-Za-z0-9_-]{16,}/gi,
397
453
  /\bAKIA[0-9A-Z]{16}\b/g,
398
- /\b[A-Za-z0-9/+]{40}\b(?=.*aws)/gi
454
+ /secret[_-]?(?:access[_-]?)?key["'\s:=]{1,6}[A-Za-z0-9/+]{40}(?![A-Za-z0-9/+])/gi
399
455
  ];
400
456
  /**
401
457
  * Conservative field-name paths auto-redacted by name regardless of value.
@@ -416,14 +472,24 @@ const PII_CONSERVATIVE_PATHS = [
416
472
  "**.privateKey",
417
473
  "**.private_key",
418
474
  "**.clientSecret",
419
- "**.client_secret"
475
+ "**.client_secret",
476
+ "**.cookie",
477
+ "**.set-cookie",
478
+ "**.x-api-key",
479
+ "**.session",
480
+ "**.proxy-authorization",
481
+ "**.x-auth-token",
482
+ "**.x-access-token",
483
+ "**.aws_secret_access_key",
484
+ "**.awsSecretAccessKey",
485
+ "**.secretAccessKey"
420
486
  ];
421
487
  /**
422
488
  * Aggressive patterns: also catch personal data that could identify a person.
423
489
  * Applied when `autoDetect: 'aggressive'`.
424
490
  */
425
491
  const PII_AGGRESSIVE_PATTERNS = [
426
- /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
492
+ /\b[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\.[A-Za-z]{2,24}\b/g,
427
493
  /\b\d{3}-?\d{2}-?\d{4}\b/g,
428
494
  /\b(?:\d[ -]?){13,19}\b/g,
429
495
  /\b(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g,
@@ -520,32 +586,54 @@ function matchesPath(fullPath, pattern) {
520
586
  }
521
587
  return re.test(fullPath);
522
588
  }
589
+ function isTokenChar(code) {
590
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 46 || code === 95 || code === 126 || code === 43 || code === 47 || code === 61 || code === 45;
591
+ }
523
592
  function applyPatterns(value, patterns, censor) {
524
593
  let redacted = value;
594
+ let suffix = "";
595
+ if (redacted.length > MAX_SCAN_LENGTH) {
596
+ let end = MAX_SCAN_LENGTH;
597
+ while (end > 0 && isTokenChar(redacted.charCodeAt(end - 1))) end--;
598
+ suffix = `…[truncated ${value.length - end} unscanned chars]`;
599
+ redacted = redacted.slice(0, end);
600
+ }
525
601
  for (const pattern of patterns) redacted = redacted.replace(pattern, censor);
526
- return redacted;
602
+ return redacted + suffix;
527
603
  }
528
604
  const CIRCULAR = "[Circular]";
529
605
  function joinPath(parent, key) {
530
606
  return parent ? `${parent}.${key}` : key;
531
607
  }
532
- function walkValue(value, state, fullPath, bare) {
608
+ function walkValue(value, state, fullPath, bare, depth) {
533
609
  const { paths = [], excludePaths = [], patterns = [], censor = DEFAULT_CENSOR } = state.config;
534
610
  if (paths.some((p) => matchesPath(fullPath, p) || matchesPath(bare, p))) return censor;
611
+ if (typeof value === "object" && value !== null) {
612
+ if (depth >= MAX_DEPTH) return MAX_DEPTH_MARKER;
613
+ if (++state.nodes > MAX_NODES) return MAX_NODES_MARKER;
614
+ }
535
615
  if (typeof value === "string") {
536
616
  if (patterns.length === 0) return value;
537
617
  if (excludePaths.some((p) => matchesPath(fullPath, p) || matchesPath(bare, p))) return value;
538
618
  return applyPatterns(value, patterns, censor);
539
619
  }
540
- if (Array.isArray(value)) return walkContainer(value, state, fullPath, bare, walkArray);
541
- if (isPlainObject(value)) return walkContainer(value, state, fullPath, bare, walkRecord);
620
+ if (Array.isArray(value)) return walkContainer(value, state, fullPath, bare, depth, walkArray);
621
+ if (value instanceof Error) return walkContainer(value, state, fullPath, bare, depth, walkError);
622
+ if (value instanceof URL) {
623
+ const url = new URL(value.href);
624
+ url.username = "";
625
+ url.password = "";
626
+ const redacted = walkValue(url.href, state, fullPath, bare, depth);
627
+ return redacted === value.href ? value : redacted;
628
+ }
629
+ if (isPlainObject(value)) return walkContainer(value, state, fullPath, bare, depth, typeof value.toJSON === "function" ? walkToJSON : walkRecord);
542
630
  return value;
543
631
  }
544
- function walkContainer(value, state, fullPath, bare, walk) {
632
+ function walkContainer(value, state, fullPath, bare, depth, walk) {
545
633
  if (state.ancestors.has(value)) return CIRCULAR;
546
634
  state.ancestors.add(value);
547
635
  try {
548
- return walk(value, state, fullPath, bare);
636
+ return walk(value, state, fullPath, bare, depth + 1);
549
637
  } finally {
550
638
  state.ancestors.delete(value);
551
639
  }
@@ -554,26 +642,51 @@ function walkContainer(value, state, fullPath, bare, walk) {
554
642
  * Array elements are matched by their indexed path (`users.0.password`) and by
555
643
  * the index-free path (`users.password`) that earlier versions used.
556
644
  */
557
- function walkArray(arr, state, fullPath, bare) {
645
+ function walkArray(arr, state, fullPath, bare, depth) {
558
646
  let result;
559
647
  for (const [i, item] of arr.entries()) {
560
- const next = walkValue(item, state, joinPath(fullPath, String(i)), bare);
648
+ const next = walkValue(item, state, joinPath(fullPath, String(i)), bare, depth);
561
649
  if (next !== item && !result) result = arr.slice(0, i);
562
650
  if (result) result.push(next);
563
651
  }
564
652
  return result ?? arr;
565
653
  }
566
- function walkRecord(obj, state, fullPath, bare) {
654
+ function walkRecord(obj, state, fullPath, bare, depth) {
567
655
  let result;
568
656
  const entries = Object.entries(obj);
569
657
  for (const [index, [key, value]] of entries.entries()) {
570
658
  const forbidden = key === "__proto__" || key === "constructor" || key === "prototype";
571
- const next = forbidden ? void 0 : walkValue(value, state, joinPath(fullPath, key), joinPath(bare, key));
659
+ const next = forbidden ? void 0 : walkValue(value, state, joinPath(fullPath, key), joinPath(bare, key), depth);
572
660
  if ((forbidden || next !== value) && !result) result = Object.fromEntries(entries.slice(0, index));
573
661
  if (result && !forbidden) result[key] = next;
574
662
  }
575
663
  return result ?? obj;
576
664
  }
665
+ /** Errors are serialized (own props + cause chain) and the result is walked. */
666
+ function walkError(err, state, fullPath, bare, depth) {
667
+ let serialized;
668
+ try {
669
+ serialized = serializeError(err);
670
+ } catch {
671
+ return {
672
+ name: err.name,
673
+ message: REDACTION_FAILED
674
+ };
675
+ }
676
+ const result = walkRecord(serialized, state, fullPath, bare, depth);
677
+ return result === serialized ? { ...serialized } : result;
678
+ }
679
+ /** Objects with `toJSON()` are redacted via the value they would serialize to. */
680
+ function walkToJSON(obj, state, fullPath, bare, depth) {
681
+ let json;
682
+ try {
683
+ json = obj.toJSON();
684
+ } catch {
685
+ return REDACTION_FAILED;
686
+ }
687
+ if (json === obj) return walkRecord(obj, state, fullPath, bare, depth);
688
+ return walkValue(json, state, fullPath, bare, depth);
689
+ }
577
690
  /**
578
691
  * Redact an object according to the given RedactConfig and return a new
579
692
  * top-level object. Subtrees with nothing to redact are shared with the input,
@@ -582,8 +695,9 @@ function walkRecord(obj, state, fullPath, bare) {
582
695
  function redactObject(obj, config, _currentPath = "") {
583
696
  const result = walkRecord(obj, {
584
697
  config,
585
- ancestors: new Set([obj])
586
- }, _currentPath, _currentPath);
698
+ ancestors: new Set([obj]),
699
+ nodes: 0
700
+ }, _currentPath, _currentPath, 0);
587
701
  return result === obj ? { ...obj } : result;
588
702
  }
589
703
  /**
@@ -594,12 +708,11 @@ function redactObject(obj, config, _currentPath = "") {
594
708
  * stays allocation-free for the common no-redact case.
595
709
  */
596
710
  function applyRedactionToString(value, config) {
597
- if (!config) return value;
711
+ const text = typeof value === "string" ? value : safeToString(value);
712
+ if (!config) return text;
598
713
  const resolved = resolveConfig(config);
599
- if (!resolved.patterns || resolved.patterns.length === 0) return value;
600
- let redacted = value;
601
- for (const pattern of resolved.patterns) redacted = redacted.replace(pattern, resolved.censor ?? DEFAULT_CENSOR);
602
- return redacted;
714
+ if (!resolved.patterns || resolved.patterns.length === 0) return text;
715
+ return applyPatterns(text, resolved.patterns, resolved.censor ?? DEFAULT_CENSOR);
603
716
  }
604
717
  /**
605
718
  * Apply redaction to a log payload (top-level call convenience wrapper).
@@ -639,11 +752,21 @@ const ALWAYS_EMIT_LEVELS = new Set([
639
752
  "warn",
640
753
  "fatal"
641
754
  ]);
755
+ const MAX_CACHED_TRACE_ID_LENGTH = 256;
756
+ function isCacheableTraceId(id) {
757
+ if (typeof id !== "string" || id.length === 0 || id.length > MAX_CACHED_TRACE_ID_LENGTH) return false;
758
+ for (let i = 0; i < id.length; i++) {
759
+ const c = id.charCodeAt(i);
760
+ if (c < 32 || c >= 127 && c <= 159) return false;
761
+ }
762
+ return true;
763
+ }
642
764
  var Sampler = class {
643
765
  constructor(config, onStats) {
644
766
  this.traceDecisions = /* @__PURE__ */ new Map();
645
767
  this.maxTrackedTraces = 1e5;
646
768
  this.traceTtlMs = 5 * 6e4;
769
+ this.traceMaxLifetimeMs = 60 * 6e4;
647
770
  this._tokenBucket = 0;
648
771
  this._lastRefillMs = Date.now();
649
772
  this._adaptiveWindow = [];
@@ -763,13 +886,15 @@ var Sampler = class {
763
886
  }
764
887
  /**
765
888
  * Return the cached decision for a trace, or make and cache a new one. Entries
766
- * idle past the TTL are re-decided; the least recently used entry is evicted
767
- * once the cap is reached.
889
+ * idle past the TTL, or older than the hard lifetime, are re-decided; the least
890
+ * recently used entry is evicted once the cap is reached. IDs that are empty,
891
+ * too long or contain control characters are sampled independently and never cached.
768
892
  */
769
893
  _decideForTrace(traceId, level) {
894
+ if (!isCacheableTraceId(traceId)) return this._sampleByRate(level);
770
895
  const now = Date.now();
771
896
  const known = this.traceDecisions.get(traceId);
772
- if (known && now - known.seenAt <= this.traceTtlMs) {
897
+ if (known && now - known.seenAt <= this.traceTtlMs && now - known.firstAt <= this.traceMaxLifetimeMs) {
773
898
  this.traceDecisions.delete(traceId);
774
899
  known.seenAt = now;
775
900
  this.traceDecisions.set(traceId, known);
@@ -779,6 +904,7 @@ var Sampler = class {
779
904
  this.traceDecisions.delete(traceId);
780
905
  this.traceDecisions.set(traceId, {
781
906
  emit,
907
+ firstAt: now,
782
908
  seenAt: now
783
909
  });
784
910
  if (this.traceDecisions.size > this.maxTrackedTraces) {
@@ -942,318 +1068,6 @@ function resetShutdownHandlers() {
942
1068
  shutdownInProgress = false;
943
1069
  }
944
1070
 
945
- //#endregion
946
- //#region node_modules/uuid/dist/esm-node/rng.js
947
- const rnds8Pool = new Uint8Array(256);
948
- let poolPtr = rnds8Pool.length;
949
- function rng() {
950
- if (poolPtr > rnds8Pool.length - 16) {
951
- crypto.randomFillSync(rnds8Pool);
952
- poolPtr = 0;
953
- }
954
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
955
- }
956
-
957
- //#endregion
958
- //#region node_modules/uuid/dist/esm-node/stringify.js
959
- /**
960
- * Convert array of 16 byte values to UUID string format of the form:
961
- * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
962
- */
963
- const byteToHex = [];
964
- for (let i = 0; i < 256; ++i) byteToHex.push((i + 256).toString(16).slice(1));
965
- function unsafeStringify(arr, offset = 0) {
966
- 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]];
967
- }
968
-
969
- //#endregion
970
- //#region node_modules/uuid/dist/esm-node/native.js
971
- var native_default = { randomUUID: crypto.randomUUID };
972
-
973
- //#endregion
974
- //#region node_modules/uuid/dist/esm-node/v4.js
975
- function v4(options, buf, offset) {
976
- if (native_default.randomUUID && !buf && !options) return native_default.randomUUID();
977
- options = options || {};
978
- const rnds = options.random || (options.rng || rng)();
979
- rnds[6] = rnds[6] & 15 | 64;
980
- rnds[8] = rnds[8] & 63 | 128;
981
- if (buf) {
982
- offset = offset || 0;
983
- for (let i = 0; i < 16; ++i) buf[offset + i] = rnds[i];
984
- return buf;
985
- }
986
- return unsafeStringify(rnds);
987
- }
988
- var v4_default = v4;
989
-
990
- //#endregion
991
- //#region src/utils/trace.utils.ts
992
- /** Default key used to store the trace ID in AsyncLocalStorage. */
993
- const TRACE_CONTEXT_KEY = "traceId";
994
- /**
995
- * Singleton that owns the AsyncLocalStorage and the active contextKey.
996
- *
997
- * Why a class instead of bare module-level variables?
998
- * - The contextKey is user-configurable; encapsulating it here means there is
999
- * exactly one place that reads and writes it.
1000
- * - All helpers (getCurrentTraceId, runWithTraceId, etc.) delegate to this
1001
- * instance, so the key is always in sync without hidden global state.
1002
- * - Easier to test: you can reset the singleton between test cases.
1003
- *
1004
- * Usage (advanced):
1005
- * import { TraceContext } from 'logixia';
1006
- * TraceContext.instance.contextKey // → 'traceId' (or custom)
1007
- * TraceContext.instance.getCurrentTraceId() // same as standalone fn
1008
- */
1009
- var TraceContext = class TraceContext {
1010
- static #_ = this._instance = null;
1011
- constructor() {
1012
- this.storage = new AsyncLocalStorage();
1013
- this._contextKey = TRACE_CONTEXT_KEY;
1014
- }
1015
- /** The process-wide singleton. */
1016
- static get instance() {
1017
- if (!TraceContext._instance) TraceContext._instance = new TraceContext();
1018
- return TraceContext._instance;
1019
- }
1020
- /** @internal Reset the singleton (useful in tests). */
1021
- static _reset() {
1022
- TraceContext._instance = null;
1023
- }
1024
- /** The AsyncLocalStorage key that holds the trace ID value. */
1025
- get contextKey() {
1026
- return this._contextKey;
1027
- }
1028
- /** @internal Called by TraceMiddleware when it boots to register the user's key. */
1029
- setContextKey(key) {
1030
- this._contextKey = key;
1031
- }
1032
- /** UUID v4 generator (default). */
1033
- generate() {
1034
- return v4_default();
1035
- }
1036
- /** Read the trace ID from the current async context. */
1037
- getCurrentTraceId() {
1038
- var _this$storage$getStor;
1039
- return (_this$storage$getStor = this.storage.getStore()) === null || _this$storage$getStor === void 0 ? void 0 : _this$storage$getStor[this._contextKey];
1040
- }
1041
- /**
1042
- * Mutate the CURRENT async context in-place.
1043
- *
1044
- * ⚠️ DEPRECATED — unsafe for concurrent requests.
1045
- *
1046
- * Uses `AsyncLocalStorage.enterWith()`, which mutates the current async
1047
- * execution context and every Promise chain spawned from it. In a server
1048
- * processing overlapping requests this can cause a trace ID set for one
1049
- * request to bleed into *other* in-flight requests that share the same
1050
- * async parent (e.g. a module-level setup function or a cached handler).
1051
- *
1052
- * Use {@link run} instead — it scopes the context to a callback so there
1053
- * is no risk of cross-request leakage.
1054
- *
1055
- * @deprecated Use `TraceContext.instance.run(traceId, fn)` — do not call
1056
- * `setTraceId` from request-handling code.
1057
- */
1058
- setTraceId(traceId, data) {
1059
- const current = this.storage.getStore() ?? {};
1060
- this.storage.enterWith({
1061
- ...current,
1062
- [this._contextKey]: traceId,
1063
- ...data
1064
- });
1065
- }
1066
- /** Run `fn` inside a new async context that carries `traceId`. */
1067
- run(traceId, fn, data) {
1068
- return this.storage.run({
1069
- [this._contextKey]: traceId,
1070
- ...data
1071
- }, fn);
1072
- }
1073
- };
1074
- /**
1075
- * The shared AsyncLocalStorage instance.
1076
- * @deprecated Prefer `TraceContext.instance.storage` for new code.
1077
- */
1078
- const traceStorage = TraceContext.instance.storage;
1079
- /** Returns the key currently used to store the trace ID in AsyncLocalStorage. */
1080
- function getTraceContextKey() {
1081
- return TraceContext.instance.contextKey;
1082
- }
1083
- /** @internal Called by TraceMiddleware / traceMiddleware() when they boot. */
1084
- function _setActiveContextKey(key) {
1085
- TraceContext.instance.setContextKey(key);
1086
- }
1087
- /** Generate a UUID v4 trace ID. */
1088
- function generateTraceId() {
1089
- return TraceContext.instance.generate();
1090
- }
1091
- /**
1092
- * Get the current trace ID from async context.
1093
- * Returns `undefined` when called outside a traced request.
1094
- */
1095
- function getCurrentTraceId() {
1096
- return TraceContext.instance.getCurrentTraceId();
1097
- }
1098
- /**
1099
- * Set trace ID in the CURRENT async context without starting a new one.
1100
- *
1101
- * ⚠️ DEPRECATED — unsafe for concurrent requests.
1102
- *
1103
- * Uses `AsyncLocalStorage.enterWith()`, which mutates the current async
1104
- * execution context and every Promise chain spawned from it. Under load this
1105
- * can cause a trace ID from one request to bleed into others sharing the same
1106
- * async parent.
1107
- *
1108
- * Use {@link runWithTraceId} instead. Migration patterns:
1109
- *
1110
- * **Express / Fastify middleware — before:**
1111
- * ```ts
1112
- * app.use((req, _res, next) => {
1113
- * setTraceId(req.headers['x-trace-id'] ?? generateTraceId());
1114
- * next();
1115
- * });
1116
- * ```
1117
- * **after:**
1118
- * ```ts
1119
- * app.use((req, _res, next) => {
1120
- * runWithTraceId(req.headers['x-trace-id'] ?? generateTraceId(), () => next());
1121
- * });
1122
- * ```
1123
- *
1124
- * **Kafka / queue consumer — before:**
1125
- * ```ts
1126
- * async function handle(msg) {
1127
- * setTraceId(msg.headers['x-trace-id']);
1128
- * await processMessage(msg);
1129
- * }
1130
- * ```
1131
- * **after:**
1132
- * ```ts
1133
- * async function handle(msg) {
1134
- * await runWithTraceId(msg.headers['x-trace-id'], () => processMessage(msg));
1135
- * }
1136
- * ```
1137
- *
1138
- * **Background job — before:**
1139
- * ```ts
1140
- * setTraceId(generateTraceId(), { jobId: job.id });
1141
- * await job.run();
1142
- * ```
1143
- * **after:**
1144
- * ```ts
1145
- * await runWithTraceId(generateTraceId(), () => job.run(), { jobId: job.id });
1146
- * ```
1147
- *
1148
- * @deprecated Use `runWithTraceId(traceId, fn)` — do not call `setTraceId`
1149
- * from request-handling code.
1150
- */
1151
- function setTraceId(traceId, data) {
1152
- TraceContext.instance.setTraceId(traceId, data);
1153
- }
1154
- /** Run `fn` inside a new async context carrying `traceId`. */
1155
- function runWithTraceId(traceId, fn, data) {
1156
- return TraceContext.instance.run(traceId, fn, data);
1157
- }
1158
- /**
1159
- * Coerce an arbitrary value to a non-empty trace ID string, or `undefined`.
1160
- * Rejects empty/whitespace-only strings, non-strings, and non-first array elements.
1161
- */
1162
- function toValidTraceId(value) {
1163
- const first = Array.isArray(value) ? value[0] : value;
1164
- if (typeof first !== "string") return void 0;
1165
- const trimmed = first.trim();
1166
- return trimmed.length > 0 ? trimmed : void 0;
1167
- }
1168
- /** W3C trace-context: `version-traceId(32hex)-spanId(16hex)-flags(2hex)`. */
1169
- const W3C_TRACEPARENT_RE = /^[\da-f]{2}-([\da-f]{32})-[\da-f]{16}-[\da-f]{2}$/i;
1170
- /**
1171
- * Extract the 32-hex trace-id segment from a W3C `traceparent` header value.
1172
- * Returns the parsed trace ID, or the original value unchanged when it is not a
1173
- * well-formed traceparent (so non-W3C propagation still works).
1174
- */
1175
- function parseTraceparent(value) {
1176
- const m = W3C_TRACEPARENT_RE.exec(value);
1177
- return m ? m[1] : value;
1178
- }
1179
- /** Extract trace ID from request using configuration (header → query → body → params). */
1180
- function extractTraceId(request, config) {
1181
- const req = request;
1182
- if (config.header) {
1183
- const headers = Array.isArray(config.header) ? config.header : [config.header];
1184
- for (const header of headers) {
1185
- var _req$headers;
1186
- const lower = header.toLowerCase();
1187
- const value = toValidTraceId((_req$headers = req.headers) === null || _req$headers === void 0 ? void 0 : _req$headers[lower]);
1188
- if (value) return lower === "traceparent" ? parseTraceparent(value) : value;
1189
- }
1190
- }
1191
- if (config.query) {
1192
- const queries = Array.isArray(config.query) ? config.query : [config.query];
1193
- for (const query of queries) {
1194
- var _req$query;
1195
- const value = toValidTraceId((_req$query = req.query) === null || _req$query === void 0 ? void 0 : _req$query[query]);
1196
- if (value) return value;
1197
- }
1198
- }
1199
- if (config.body) {
1200
- const bodyFields = Array.isArray(config.body) ? config.body : [config.body];
1201
- for (const field of bodyFields) {
1202
- var _req$body;
1203
- const value = toValidTraceId((_req$body = req.body) === null || _req$body === void 0 ? void 0 : _req$body[field]);
1204
- if (value) return value;
1205
- }
1206
- }
1207
- if (config.params) {
1208
- const paramFields = Array.isArray(config.params) ? config.params : [config.params];
1209
- for (const param of paramFields) {
1210
- var _req$params;
1211
- const value = toValidTraceId((_req$params = req.params) === null || _req$params === void 0 ? void 0 : _req$params[param]);
1212
- if (value) return value;
1213
- }
1214
- }
1215
- }
1216
- /**
1217
- * Default headers checked for incoming trace ID propagation, in priority order:
1218
- * traceparent (W3C/OTel) → x-trace-id → x-request-id → x-correlation-id → trace-id
1219
- */
1220
- const DEFAULT_TRACE_HEADERS = [
1221
- "traceparent",
1222
- "x-trace-id",
1223
- "x-request-id",
1224
- "x-correlation-id",
1225
- "trace-id"
1226
- ];
1227
- /**
1228
- * Create trace ID middleware for Express/NestJS
1229
- */
1230
- function createTraceMiddleware(config) {
1231
- const defaultExtractor = {
1232
- header: DEFAULT_TRACE_HEADERS,
1233
- query: ["traceId", "trace_id"]
1234
- };
1235
- const resolvedConfig = {
1236
- ...config,
1237
- extractor: (config === null || config === void 0 ? void 0 : config.extractor) ? {
1238
- ...defaultExtractor,
1239
- ...config.extractor
1240
- } : defaultExtractor
1241
- };
1242
- _setActiveContextKey(resolvedConfig.contextKey ?? TRACE_CONTEXT_KEY);
1243
- return (req, res, next) => {
1244
- let traceId;
1245
- if (resolvedConfig.extractor) traceId = extractTraceId(req, resolvedConfig.extractor);
1246
- if (!traceId) traceId = resolvedConfig.generator ? resolvedConfig.generator() : generateTraceId();
1247
- req.traceId = traceId;
1248
- const resObj = res;
1249
- if (!resObj.headersSent) try {
1250
- if (typeof resObj.setHeader === "function") resObj.setHeader("X-Trace-Id", traceId);
1251
- else if (typeof resObj.header === "function") resObj.header("X-Trace-Id", traceId);
1252
- } catch {}
1253
- runWithTraceId(traceId, () => next());
1254
- };
1255
- }
1256
-
1257
1071
  //#endregion
1258
1072
  //#region src/core/logitron-logger.ts
1259
1073
  const _fastStringifyEntry = buildFastStringify({
@@ -1816,9 +1630,21 @@ var LogixiaLogger = class LogixiaLogger {
1816
1630
  ...mergedData
1817
1631
  } : mergedData;
1818
1632
  let payload;
1819
- if (rawPayload !== void 0 && rawPayload !== null) payload = this._hasRedact ? applyRedaction(rawPayload, this.config.redact) ?? rawPayload : rawPayload;
1633
+ if (rawPayload !== void 0 && rawPayload !== null) if (this._hasRedact) try {
1634
+ payload = applyRedaction(rawPayload, this.config.redact) ?? rawPayload;
1635
+ } catch (error) {
1636
+ internalError("Redaction failed", error);
1637
+ payload = { redaction: REDACTION_FAILED };
1638
+ }
1639
+ else payload = rawPayload;
1820
1640
  const traceId = this.config.traceId ? TraceContext.instance.getCurrentTraceId() ?? this.fallbackTraceId : void 0;
1821
- const safeMessage = this._hasRedact ? applyRedactionToString(message, this.config.redact) : message;
1641
+ let safeMessage = message;
1642
+ if (this._hasRedact) try {
1643
+ safeMessage = applyRedactionToString(message, this.config.redact);
1644
+ } catch (error) {
1645
+ internalError("Redaction failed", error);
1646
+ safeMessage = REDACTION_FAILED;
1647
+ }
1822
1648
  const entry = {
1823
1649
  timestamp: nowIso(),
1824
1650
  level,
@@ -1889,9 +1715,9 @@ var LogixiaLogger = class LogixiaLogger {
1889
1715
  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} `;
1890
1716
  if (this._fieldCache.get("level") !== false) formatted += this._formattedLevels.get(entry.level) ?? `[${entry.level.toUpperCase()}] `;
1891
1717
  formatted += this._formattedAppName;
1892
- if (entry.traceId && this._fieldCache.get("traceId") !== false) formatted += `${cyan}[${entry.traceId}]${reset} `;
1893
- if (entry.context && this._fieldCache.get("context") !== false) formatted += `${yellow}[${entry.context}]${reset} `;
1894
- if (this._fieldCache.get("message") !== false) formatted += entry.message;
1718
+ if (entry.traceId && this._fieldCache.get("traceId") !== false) formatted += `${cyan}[${stripControlChars(String(entry.traceId))}]${reset} `;
1719
+ if (entry.context && this._fieldCache.get("context") !== false) formatted += `${yellow}[${stripControlChars(String(entry.context))}]${reset} `;
1720
+ if (this._fieldCache.get("message") !== false) formatted += stripControlChars(safeToString(entry.message));
1895
1721
  if (entry.payload !== void 0 && this._fieldCache.get("payload") !== false) formatted += ` ${stringifyForLog(entry.payload)}`;
1896
1722
  return formatted;
1897
1723
  }
@@ -1941,682 +1767,218 @@ function createLogger(config, context) {
1941
1767
  }
1942
1768
 
1943
1769
  //#endregion
1944
- //#region \0@oxc-project+runtime@0.95.0/helpers/decorateMetadata.js
1945
- function __decorateMetadata(k, v) {
1946
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1947
- }
1948
-
1949
- //#endregion
1950
- //#region \0@oxc-project+runtime@0.95.0/helpers/decorate.js
1951
- function __decorate(decorators, target, key, desc) {
1952
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1953
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1954
- 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;
1955
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1956
- }
1957
-
1958
- //#endregion
1959
- //#region src/core/logitron-nestjs.service.ts
1960
- var _LogixiaLoggerService;
1961
- let LogixiaLoggerService = _LogixiaLoggerService = class LogixiaLoggerService$1 {
1962
- constructor(config) {
1963
- this._mergedConfig = {
1964
- appName: "NestJS-App",
1965
- environment: "development",
1966
- traceId: true,
1967
- format: {
1968
- timestamp: true,
1969
- colorize: true,
1970
- json: false
1971
- },
1972
- silent: false,
1973
- levelOptions: {
1974
- level: LogLevel.INFO,
1975
- levels: {
1976
- error: 0,
1977
- warn: 1,
1978
- log: 2,
1979
- debug: 3,
1980
- verbose: 4
1981
- },
1982
- colors: {
1983
- error: "red",
1984
- warn: "yellow",
1985
- log: "green",
1986
- debug: "blue",
1987
- verbose: "cyan"
1988
- }
1989
- },
1990
- fields: {
1991
- timestamp: "[yyyy-mm-dd HH:MM:ss.MS]",
1992
- level: "[log_level]",
1993
- appName: "[app_name]",
1994
- traceId: "[trace_id]",
1995
- message: "[message]",
1996
- payload: "[payload]",
1997
- timeTaken: "[time_taken_MS]"
1998
- },
1999
- ...config
2000
- };
2001
- this.logger = new LogixiaLogger(this._mergedConfig);
2002
- this._createCustomLevelMethods();
2003
- }
2004
- _createCustomLevelMethods() {
2005
- var _this$_mergedConfig$l;
2006
- const levels = (_this$_mergedConfig$l = this._mergedConfig.levelOptions) === null || _this$_mergedConfig$l === void 0 ? void 0 : _this$_mergedConfig$l.levels;
2007
- if (!levels) return;
2008
- for (const levelName of Object.keys(levels)) {
2009
- const lower = levelName.toLowerCase();
2010
- if (typeof this[lower] !== "undefined") continue;
2011
- this[lower] = async (message, data) => {
2012
- return this.logger.logLevel(lower, message, data);
2013
- };
2014
- }
2015
- }
2016
- /**
2017
- * NestJS `LoggerService.log` — void, string context.
2018
- * Maps internally to `info`.
2019
- *
2020
- * @example `logger.log('User signed up', 'AuthService')`
2021
- */
2022
- log(message, context) {
2023
- this.setContextIfProvided(context);
2024
- this.logger.info(this.formatMessage(message)).catch((err) => internalError("LogixiaLoggerService.log failed", err));
2025
- }
2026
- /**
2027
- * Native async `info` — structured data, returns `Promise<void>`.
2028
- *
2029
- * @example `await logger.info('User signed up', { userId: 'u_abc' })`
2030
- */
2031
- async info(message, data) {
2032
- return this.logger.info(message, data);
2033
- }
2034
- error(message, dataOrTrace, context) {
2035
- if (typeof dataOrTrace === "object" && dataOrTrace !== null) return message instanceof Error ? this.logger.error(message, dataOrTrace) : this.logger.error(this.formatMessage(message), dataOrTrace);
2036
- this.setContextIfProvided(context);
2037
- const errorData = {};
2038
- if (typeof dataOrTrace === "string" && dataOrTrace) errorData.stack = dataOrTrace;
2039
- (message instanceof Error ? this.logger.error(message, errorData) : this.logger.error(this.formatMessage(message), errorData)).catch((err) => internalError("LogixiaLoggerService.error failed", err));
2040
- }
2041
- warn(message, dataOrContext) {
2042
- if (typeof dataOrContext === "object" && dataOrContext !== null) return this.logger.warn(this.formatMessage(message), dataOrContext);
2043
- this.setContextIfProvided(typeof dataOrContext === "string" ? dataOrContext : void 0);
2044
- this.logger.warn(this.formatMessage(message)).catch((err) => internalError("LogixiaLoggerService.warn failed", err));
2045
- }
2046
- debug(message, dataOrContext) {
2047
- if (typeof dataOrContext === "object" && dataOrContext !== null) return this.logger.debug(this.formatMessage(message), dataOrContext);
2048
- this.setContextIfProvided(typeof dataOrContext === "string" ? dataOrContext : void 0);
2049
- this.logger.debug(this.formatMessage(message)).catch((err) => internalError("LogixiaLoggerService.debug failed", err));
2050
- }
2051
- verbose(message, dataOrContext) {
2052
- if (typeof dataOrContext === "object" && dataOrContext !== null) return this.logger.trace(this.formatMessage(message), dataOrContext);
2053
- this.setContextIfProvided(typeof dataOrContext === "string" ? dataOrContext : void 0);
2054
- this.logger.trace(this.formatMessage(message)).catch((err) => internalError("LogixiaLoggerService.verbose failed", err));
2055
- }
2056
- /**
2057
- * Native async `trace` — lowest verbosity level, structured data.
2058
- */
2059
- async trace(message, data) {
2060
- return this.logger.trace(message, data);
2061
- }
2062
- /**
2063
- * Log at any named level with structured data.
2064
- */
2065
- logLevel(level, message, data) {
2066
- return this.logger.logLevel(level, message, data);
2067
- }
2068
- time(label) {
2069
- this.logger.time(label);
2070
- }
2071
- async timeEnd(label) {
2072
- return this.logger.timeEnd(label);
2073
- }
2074
- async timeAsync(label, fn) {
2075
- return this.logger.timeAsync(label, fn);
2076
- }
2077
- setContext(context) {
2078
- const coerced = typeof context === "string" ? context : safeToString(context);
2079
- this.context = coerced;
2080
- this.logger.setContext(coerced);
2081
- }
2082
- getContext() {
2083
- return this.context;
2084
- }
2085
- setLevel(level) {
2086
- this.logger.setLevel(level);
2087
- }
2088
- getLevel() {
2089
- return this.logger.getLevel();
2090
- }
2091
- child(context, data) {
2092
- const childService = new _LogixiaLoggerService(this._mergedConfig);
2093
- childService.logger = this.logger.child(context, data);
2094
- childService.context = context;
2095
- return childService;
2096
- }
2097
- getCurrentTraceId() {
2098
- return TraceContext.instance.getCurrentTraceId();
2099
- }
2100
- /** Returns the AsyncLocalStorage key currently used to store the trace ID. */
2101
- get traceContextKey() {
2102
- return getTraceContextKey();
2103
- }
2104
- async close() {
2105
- return this.logger.close();
2106
- }
2107
- static create(config) {
2108
- return new _LogixiaLoggerService(config);
2109
- }
2110
- getLogger() {
2111
- return this.logger;
2112
- }
2113
- setContextIfProvided(context) {
2114
- if (typeof context !== "string" || context.length === 0) return;
2115
- if (context !== this.context) this.setContext(context);
2116
- }
2117
- formatMessage(message) {
2118
- if (typeof message === "string") return message;
2119
- return safeToString(message);
2120
- }
2121
- };
2122
- LogixiaLoggerService = _LogixiaLoggerService = __decorate([Injectable({ scope: Scope.TRANSIENT }), __decorateMetadata("design:paramtypes", [Object])], LogixiaLoggerService);
2123
-
2124
- //#endregion
2125
- //#region src/core/kafka-trace.interceptor.ts
2126
- var _KafkaTraceInterceptor;
2127
- let KafkaTraceInterceptor = class KafkaTraceInterceptor$1 {
2128
- static {
2129
- _KafkaTraceInterceptor = this;
2130
- }
2131
- static #_ = this.metrics = {
2132
- accepted: 0,
2133
- acceptedWithoutTrace: 0,
2134
- dropped: 0
2135
- };
2136
- /** Reset counters (tests). */
2137
- static resetMetrics() {
2138
- _KafkaTraceInterceptor.metrics.accepted = 0;
2139
- _KafkaTraceInterceptor.metrics.acceptedWithoutTrace = 0;
2140
- _KafkaTraceInterceptor.metrics.dropped = 0;
2141
- }
2142
- /**
2143
- * @param config - TraceIdConfig options (extractor keys, contextKey, etc.)
2144
- * @param requireTraceId - When true, messages with no traceId are silently skipped
2145
- * (EMPTY Observable — message is ack'd, consumer stays alive).
2146
- * A WARN is logged AND `KafkaTraceInterceptor.metrics.dropped`
2147
- * increments so the missing traceId is observable end-to-end.
2148
- * Default: false (handler runs without trace context).
2149
- */
2150
- constructor(config, requireTraceId = false) {
2151
- this.config = config;
2152
- this.requireTraceId = requireTraceId;
2153
- this.ctx = TraceContext.instance;
2154
- this.config = {
2155
- enabled: true,
2156
- contextKey: "traceId",
2157
- extractor: {
2158
- body: [
2159
- "traceId",
2160
- "trace_id",
2161
- "x-trace-id"
2162
- ],
2163
- header: ["x-trace-id", "trace-id"]
2164
- },
2165
- ...config
2166
- };
2167
- }
2168
- intercept(context, next) {
2169
- var _this$config;
2170
- if (!((_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enabled)) return next.handle();
2171
- const rpcContext = context.switchToRpc();
2172
- const data = rpcContext.getData();
2173
- const rpcData = rpcContext.getContext();
2174
- let traceId;
2175
- if (this.config.extractor) traceId = extractTraceId({
2176
- body: data,
2177
- headers: (rpcData === null || rpcData === void 0 ? void 0 : rpcData.headers) ?? {},
2178
- query: {},
2179
- params: {}
2180
- }, this.config.extractor);
2181
- if (!traceId) traceId = this.ctx.getCurrentTraceId();
2182
- if (!traceId) {
2183
- if (this.requireTraceId) {
2184
- var _LogixiaLoggerModule$;
2185
- _KafkaTraceInterceptor.metrics.dropped++;
2186
- (_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.`);
2187
- return EMPTY;
2188
- }
2189
- _KafkaTraceInterceptor.metrics.acceptedWithoutTrace++;
2190
- return next.handle();
2191
- }
2192
- _KafkaTraceInterceptor.metrics.accepted++;
2193
- const kafkaContext = {
2194
- messageType: "kafka",
2195
- topic: rpcData === null || rpcData === void 0 ? void 0 : rpcData.topic,
2196
- partition: rpcData === null || rpcData === void 0 ? void 0 : rpcData.partition,
2197
- offset: rpcData === null || rpcData === void 0 ? void 0 : rpcData.offset,
2198
- key: rpcData === null || rpcData === void 0 ? void 0 : rpcData.key,
2199
- timestamp: rpcData === null || rpcData === void 0 ? void 0 : rpcData.timestamp
2200
- };
2201
- return new Observable((subscriber) => {
2202
- let inner;
2203
- this.ctx.run(traceId, () => {
2204
- inner = next.handle().subscribe({
2205
- next: (value) => subscriber.next(value),
2206
- error: (err) => subscriber.error(err),
2207
- complete: () => subscriber.complete()
2208
- });
2209
- }, kafkaContext);
2210
- return () => inner === null || inner === void 0 ? void 0 : inner.unsubscribe();
2211
- });
1770
+ //#region src/exceptions/exception.ts
1771
+ var LogixiaException = class extends Error {
1772
+ constructor(options) {
1773
+ super(options.message, { cause: options.cause });
1774
+ this.name = "LogixiaException";
1775
+ this.errorCode = options.code;
1776
+ this.errorType = options.type;
1777
+ this.httpStatus = options.httpStatus;
1778
+ this.param = options.param;
1779
+ this.details = options.details;
1780
+ this.docUrl = options.docUrl;
1781
+ this.metadata = options.metadata;
1782
+ Object.setPrototypeOf(this, new.target.prototype);
2212
1783
  }
2213
1784
  };
2214
- KafkaTraceInterceptor = _KafkaTraceInterceptor = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [Object, Boolean])], KafkaTraceInterceptor);
2215
-
2216
- //#endregion
2217
- //#region \0@oxc-project+runtime@0.95.0/helpers/decorateParam.js
2218
- function __decorateParam(paramIndex, decorator) {
2219
- return function(target, key) {
2220
- decorator(target, key, paramIndex);
2221
- };
1785
+ /**
1786
+ * Returns `true` when `value` is a `LogixiaException` instance.
1787
+ *
1788
+ * Useful in exception filters or middleware that need to distinguish a
1789
+ * `LogixiaException` from a plain `Error` or a framework `HttpException`.
1790
+ *
1791
+ * @example
1792
+ * ```ts
1793
+ * if (isLogixiaException(err)) {
1794
+ * console.log(err.errorCode, err.httpStatus);
1795
+ * }
1796
+ * ```
1797
+ */
1798
+ function isLogixiaException(value) {
1799
+ return value instanceof LogixiaException;
2222
1800
  }
2223
1801
 
2224
1802
  //#endregion
2225
- //#region src/core/trace.middleware.ts
2226
- /** Default response header used to echo the resolved traceId back to the caller. */
2227
- const DEFAULT_TRACE_RESPONSE_HEADER = "X-Trace-Id";
1803
+ //#region src/exceptions/builder.ts
2228
1804
  /**
2229
- * Resolve the response header name from config.
2230
- * - `undefined` → default `'X-Trace-Id'`
2231
- * - `string` → user's custom header
2232
- * - `false` → `null` (suppress entirely)
1805
+ * Generates a trace ID via the shared {@link TraceContext} generator.
1806
+ *
1807
+ * Delegates to `TraceContext.instance.generate()` so any custom generator
1808
+ * configured on `TraceIdConfig.generator` is respected — avoids the silent
1809
+ * "builder has its own UUID source" divergence this module had previously.
1810
+ *
1811
+ * @example `'550e8400-e29b-41d4-a716-446655440000'`
2233
1812
  */
2234
- function resolveResponseHeader(config) {
2235
- if ((config === null || config === void 0 ? void 0 : config.responseHeader) === false) return null;
2236
- return (config === null || config === void 0 ? void 0 : config.responseHeader) ?? DEFAULT_TRACE_RESPONSE_HEADER;
1813
+ function generateTraceId() {
1814
+ return TraceContext.instance.generate();
2237
1815
  }
1816
+ /** @deprecated Use `generateTraceId` instead. */
1817
+ const generateRequestId = generateTraceId;
2238
1818
  /**
2239
- * Echo the trace ID on the response, tolerating non-Express responses and
2240
- * already-sent headers. NestJS can run on Fastify (reply.header() instead of
2241
- * res.setHeader()), and on a closed/sent response setHeader throws — neither
2242
- * should crash the request. The trace ID is still propagated via async context.
1819
+ * Maps an HTTP status code to a human-friendly error type string.
1820
+ * Used as a fallback when the exception is a generic `HttpException`.
2243
1821
  */
2244
- function writeTraceHeader(res, header, traceId) {
2245
- const r = res;
2246
- if (r.headersSent) return;
2247
- try {
2248
- if (typeof r.setHeader === "function") r.setHeader(header, traceId);
2249
- else if (typeof r.header === "function") r.header(header, traceId);
2250
- } catch {}
1822
+ function httpStatusToType(status) {
1823
+ if (status === 400) return "api_error";
1824
+ if (status === 401) return "authentication_error";
1825
+ if (status === 402) return "payment_error";
1826
+ if (status === 403) return "authorization_error";
1827
+ if (status === 404) return "not_found_error";
1828
+ if (status === 408) return "timeout_error";
1829
+ if (status === 409) return "conflict_error";
1830
+ if (status === 422) return "validation_error";
1831
+ if (status === 429) return "rate_limit_error";
1832
+ if (status >= 500) return "server_error";
1833
+ if (status >= 400) return "api_error";
1834
+ return "server_error";
2251
1835
  }
2252
- let TraceMiddleware = class TraceMiddleware$1 {
2253
- constructor(config) {
2254
- this.config = config;
2255
- this.ctx = TraceContext.instance;
2256
- const defaultExtractor = {
2257
- header: DEFAULT_TRACE_HEADERS,
2258
- query: ["traceId", "trace_id"]
2259
- };
2260
- this.config = {
2261
- enabled: true,
2262
- generator: () => this.ctx.generate(),
2263
- contextKey: "traceId",
2264
- ...config,
2265
- extractor: (config === null || config === void 0 ? void 0 : config.extractor) ? {
2266
- ...defaultExtractor,
2267
- ...config.extractor
2268
- } : defaultExtractor
2269
- };
2270
- if (this.config.enabled) this.ctx.setContextKey(this.config.contextKey ?? "traceId");
2271
- }
2272
- use(req, res, next) {
2273
- var _this$config, _req$socket, _req$connection;
2274
- if (!((_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enabled)) return next();
2275
- let traceId;
2276
- if (this.config.extractor) traceId = extractTraceId(req, this.config.extractor);
2277
- if (!traceId && this.config.generator) {
2278
- const candidate = this.config.generator();
2279
- if (typeof candidate === "string" && candidate.trim().length > 0) traceId = candidate;
2280
- else internalWarn("TraceIdConfig.generator returned a non-string/empty value — using built-in generator.");
2281
- }
2282
- if (!traceId) traceId = this.ctx.generate();
2283
- req.traceId = traceId;
2284
- const header = resolveResponseHeader(this.config);
2285
- if (header) writeTraceHeader(res, header, traceId);
2286
- this.ctx.run(traceId, () => next(), {
2287
- method: req.method,
2288
- url: req.url,
2289
- userAgent: req.get("User-Agent"),
2290
- ip: req.ip || ((_req$socket = req.socket) === null || _req$socket === void 0 ? void 0 : _req$socket.remoteAddress) || ((_req$connection = req.connection) === null || _req$connection === void 0 ? void 0 : _req$connection.remoteAddress)
2291
- });
2292
- }
2293
- };
2294
- TraceMiddleware = __decorate([
2295
- Injectable(),
2296
- __decorateParam(0, Optional()),
2297
- __decorateMetadata("design:paramtypes", [Object])
2298
- ], TraceMiddleware);
2299
-
2300
- //#endregion
2301
- //#region src/core/websocket-trace.interceptor.ts
2302
- let WebSocketTraceInterceptor = class WebSocketTraceInterceptor$1 {
2303
- constructor(config) {
2304
- this.config = config;
2305
- this.ctx = TraceContext.instance;
2306
- this.config = {
2307
- enabled: true,
2308
- contextKey: "traceId",
2309
- extractor: {
2310
- body: [
2311
- "traceId",
2312
- "trace_id",
2313
- "x-trace-id"
2314
- ],
2315
- header: ["x-trace-id", "trace-id"],
2316
- query: ["traceId", "trace_id"]
2317
- },
2318
- ...config
2319
- };
2320
- }
2321
- intercept(context, next) {
2322
- var _this$config, _client$handshake3;
2323
- if (!((_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enabled)) return next.handle();
2324
- const wsContext = context.switchToWs();
2325
- const data = wsContext.getData();
2326
- const client = wsContext.getClient();
2327
- let traceId;
2328
- if (this.config.extractor) {
2329
- var _client$handshake, _client$handshake2;
2330
- traceId = extractTraceId({
2331
- body: data,
2332
- headers: (client === null || client === void 0 || (_client$handshake = client.handshake) === null || _client$handshake === void 0 ? void 0 : _client$handshake.headers) || {},
2333
- query: (client === null || client === void 0 || (_client$handshake2 = client.handshake) === null || _client$handshake2 === void 0 ? void 0 : _client$handshake2.query) || {},
2334
- params: {}
2335
- }, this.config.extractor);
2336
- }
2337
- if (!traceId) traceId = this.ctx.getCurrentTraceId();
2338
- if (!traceId) return next.handle();
2339
- const wsContextData = {
2340
- messageType: "websocket",
2341
- event: data === null || data === void 0 ? void 0 : data.event,
2342
- socketId: client === null || client === void 0 ? void 0 : client.id,
2343
- rooms: (client === null || client === void 0 ? void 0 : client.rooms) ? Array.from(client.rooms) : [],
2344
- clientAddress: client === null || client === void 0 || (_client$handshake3 = client.handshake) === null || _client$handshake3 === void 0 ? void 0 : _client$handshake3.address
2345
- };
2346
- return new Observable((observer) => {
2347
- let inner;
2348
- this.ctx.run(traceId, () => {
2349
- inner = next.handle().subscribe({
2350
- next: (value) => observer.next(value),
2351
- error: (err) => observer.error(err),
2352
- complete: () => observer.complete()
2353
- });
2354
- }, wsContextData);
2355
- return () => inner === null || inner === void 0 ? void 0 : inner.unsubscribe();
2356
- });
2357
- }
2358
- };
2359
- WebSocketTraceInterceptor = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [Object])], WebSocketTraceInterceptor);
2360
-
2361
- //#endregion
2362
- //#region src/core/logitron-logger.module.ts
2363
- var _LogixiaLoggerModule;
2364
- const DEFAULT_ROUTES = [{
2365
- path: "*",
2366
- method: RequestMethod.ALL
2367
- }];
2368
- const LOGIXIA_LOGGER_CONFIG = "LOGIXIA_LOGGER_CONFIG";
2369
- const LOGIXIA_TRACE_CONFIG = "TRACE_CONFIG";
2370
- const LOGIXIA_LOGGER_PREFIX = "LOGIXIA_LOGGER_";
2371
- let LogixiaLoggerModule = class LogixiaLoggerModule$1 {
2372
- static {
2373
- _LogixiaLoggerModule = this;
2374
- }
2375
- constructor() {
2376
- this.config = {};
2377
- }
2378
- static #_ = this.loggerConfig = {};
2379
- static #_2 = this._globalLogger = null;
1836
+ /**
1837
+ * Duck-type check for NestJS `HttpException`.
1838
+ * Avoids a hard import on `@nestjs/common` so the builder is usable outside NestJS.
1839
+ */
1840
+ function isHttpException(value) {
1841
+ return typeof value === "object" && value !== null && typeof value["getStatus"] === "function" && typeof value["getResponse"] === "function";
1842
+ }
1843
+ /**
1844
+ * Builds the optional `debug` block from an error.
1845
+ * Returns `undefined` when there is nothing useful to include.
1846
+ */
1847
+ function buildDebug(error, service, durationMs, expose) {
1848
+ if (expose.debug !== true) return void 0;
1849
+ const stack = error instanceof Error ? error.stack : void 0;
1850
+ const causeRaw = error instanceof Error ? error.cause : void 0;
1851
+ let cause;
1852
+ if (expose.cause !== true) cause = void 0;
1853
+ else if (causeRaw instanceof Error) cause = causeRaw.message;
1854
+ else if (causeRaw !== void 0 && causeRaw !== null) cause = String(causeRaw);
1855
+ if (!stack && !cause && !service && durationMs === void 0) return void 0;
1856
+ return {
1857
+ ...stack !== void 0 ? { stack } : {},
1858
+ ...cause !== void 0 ? { cause } : {},
1859
+ ...service !== void 0 ? { service } : {},
1860
+ ...durationMs !== void 0 ? { duration_ms: durationMs } : {}
1861
+ };
1862
+ }
1863
+ var ErrorResponseBuilder = class {
2380
1864
  /**
2381
- * @internal Set the global logger exactly once.
2382
- *
2383
- * Called from the module's forRoot / forRootAsync factory. If the module is
2384
- * initialised more than once in the same process (nested DI context, test
2385
- * harness creating multiple apps, hot reload, etc.) a warning is written to
2386
- * stderr and the first logger wins — silently overwriting would allow the
2387
- * newer instance's transport config to replace the live one while the old
2388
- * one is still being used by registered shutdown hooks, decorators, etc.
1865
+ * Build a `LogixiaErrorResponse` from any thrown value.
2389
1866
  *
2390
- * Use {@link _resetGlobalLogger} in tests to reset between runs.
2391
- */
2392
- static _setGlobalLogger(service) {
2393
- if (_LogixiaLoggerModule._globalLogger !== null) {
2394
- internalWarn("LogixiaLoggerModule.forRoot() was called more than once — ignoring the second init. If this is intentional (e.g. in tests), call LogixiaLoggerModule._resetGlobalLogger() first.");
2395
- return;
2396
- }
2397
- _LogixiaLoggerModule._globalLogger = service;
2398
- }
2399
- /** @internal Clear the global logger. Tests only. */
2400
- static _resetGlobalLogger() {
2401
- _LogixiaLoggerModule._globalLogger = null;
2402
- }
2403
- /**
2404
- * Returns the global LogixiaLoggerService instance that was created when the
2405
- * module booted. Useful for logging outside of NestJS DI — utility functions,
2406
- * plain scripts, decorators — without injecting the service everywhere.
1867
+ * @param params - See `BuildParams`.
1868
+ * @returns The unified error response and the HTTP status code to send.
2407
1869
  *
2408
- * Returns `null` if called before `LogixiaLoggerModule.forRoot[Async]()` has
2409
- * been initialised (i.e. before the NestJS app has started).
1870
+ * @remarks
1871
+ * `traceId` does not need to be supplied by the caller in most cases — the
1872
+ * builder reads `TraceContext.instance.getCurrentTraceId()` internally and
1873
+ * falls back to the explicit `traceId` argument only when AsyncLocalStorage
1874
+ * is empty. If neither source yields a value, `meta.trace_id` is omitted.
2410
1875
  *
2411
- * @example
1876
+ * @example In a NestJS exception filter
2412
1877
  * ```ts
2413
- * // some-util.ts
2414
- * import { LogixiaLoggerModule } from 'logixia/nest';
1878
+ * const { response, httpStatus } = ErrorResponseBuilder.build<AppCode, AppType>({
1879
+ * exception,
1880
+ * // Omit traceId — it will be picked up from ALS automatically.
1881
+ * path: request.url,
1882
+ * service: process.env.SERVICE_NAME,
1883
+ * startTime: request.startTime,
1884
+ * });
2415
1885
  *
2416
- * export function doSomething() {
2417
- * LogixiaLoggerModule.getGlobalLogger()?.info('doing something');
1886
+ * if (process.env.NODE_ENV === 'production') delete response.debug;
1887
+ * // Echo the resolved traceId back on whatever header your TraceIdConfig says —
1888
+ * // do NOT hardcode 'X-Trace-Id', use `resolveResponseHeader(config)` instead.
1889
+ * if (response.meta.trace_id) {
1890
+ * response.setHeader(resolveResponseHeader(config) ?? 'X-Trace-Id', response.meta.trace_id);
2418
1891
  * }
1892
+ * response.status(httpStatus).json(response);
2419
1893
  * ```
2420
1894
  */
2421
- static getGlobalLogger() {
2422
- return _LogixiaLoggerModule._globalLogger;
2423
- }
2424
- configure(consumer) {
2425
- const { forRoutes = DEFAULT_ROUTES, exclude } = this.config;
2426
- let resolvedTraceConfig;
2427
- if (typeof _LogixiaLoggerModule.loggerConfig.traceId === "object") resolvedTraceConfig = _LogixiaLoggerModule.loggerConfig.traceId;
2428
- else if (_LogixiaLoggerModule.loggerConfig.traceId === true) resolvedTraceConfig = {
2429
- enabled: true,
2430
- contextKey: "traceId",
2431
- generator: () => TraceContext.instance.generate()
1895
+ static build(params) {
1896
+ const { exception, path, service, startTime, traceId: rawTraceId, exposeDebug, exposeCause } = params;
1897
+ const expose = {
1898
+ debug: exposeDebug,
1899
+ cause: exposeCause
2432
1900
  };
2433
- const middleware = new TraceMiddleware(resolvedTraceConfig);
2434
- const middlewareConfig = (req, res, next) => middleware.use(req, res, next);
2435
- if (exclude) consumer.apply(middlewareConfig).exclude(...exclude).forRoutes(...forRoutes);
2436
- else consumer.apply(middlewareConfig).forRoutes(...forRoutes);
2437
- }
2438
- /**
2439
- * Configure the module with synchronous options
2440
- */
2441
- static forRoot(config) {
2442
- _LogixiaLoggerModule.loggerConfig = config || {};
2443
- 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) };
2444
- return {
2445
- module: _LogixiaLoggerModule,
2446
- providers: [
2447
- {
2448
- provide: LOGIXIA_LOGGER_CONFIG,
2449
- useValue: config || {}
2450
- },
2451
- {
2452
- provide: LOGIXIA_TRACE_CONFIG,
2453
- useValue: traceConfig
2454
- },
2455
- {
2456
- provide: LogixiaLoggerService,
2457
- useFactory: (loggerConfig) => {
2458
- const service = new LogixiaLoggerService({
2459
- level: "info",
2460
- service: "NestJSApp",
2461
- environment: "development",
2462
- fields: {},
2463
- formatters: ["text"],
2464
- outputs: ["console"],
2465
- levelOptions: {
2466
- level: "info",
2467
- levels: {
2468
- error: 0,
2469
- warn: 1,
2470
- info: 2,
2471
- debug: 3,
2472
- verbose: 4
2473
- },
2474
- colors: {
2475
- error: "red",
2476
- warn: "yellow",
2477
- info: "green",
2478
- debug: "blue",
2479
- verbose: "cyan"
2480
- }
2481
- },
2482
- ...loggerConfig
2483
- });
2484
- _LogixiaLoggerModule._setGlobalLogger(service);
2485
- return service;
1901
+ const traceId = TraceContext.instance.getCurrentTraceId() ?? rawTraceId;
1902
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1903
+ const durationMs = startTime !== void 0 ? Date.now() - startTime : void 0;
1904
+ if (isLogixiaException(exception)) {
1905
+ const debug$1 = buildDebug(exception, service, durationMs, expose);
1906
+ const errorBlock = {
1907
+ type: exception.errorType,
1908
+ code: exception.errorCode,
1909
+ message: exception.message
1910
+ };
1911
+ if (exception.param !== void 0) errorBlock.param = exception.param;
1912
+ if (exception.details !== void 0 && exception.details.length > 0) errorBlock.details = exception.details;
1913
+ if (exception.docUrl !== void 0) errorBlock.doc_url = exception.docUrl;
1914
+ return {
1915
+ response: {
1916
+ success: false,
1917
+ error: errorBlock,
1918
+ meta: {
1919
+ ...traceId !== void 0 ? { trace_id: traceId } : {},
1920
+ timestamp,
1921
+ path,
1922
+ status: exception.httpStatus
2486
1923
  },
2487
- inject: [LOGIXIA_LOGGER_CONFIG]
1924
+ ...debug$1 !== void 0 ? { debug: debug$1 } : {}
2488
1925
  },
2489
- {
2490
- provide: KafkaTraceInterceptor,
2491
- useFactory: (traceConfig$1) => new KafkaTraceInterceptor(traceConfig$1),
2492
- inject: [LOGIXIA_TRACE_CONFIG]
2493
- },
2494
- {
2495
- provide: WebSocketTraceInterceptor,
2496
- useFactory: (traceConfig$1) => new WebSocketTraceInterceptor(traceConfig$1),
2497
- inject: [LOGIXIA_TRACE_CONFIG]
2498
- }
2499
- ],
2500
- exports: [
2501
- LogixiaLoggerService,
2502
- LOGIXIA_LOGGER_CONFIG,
2503
- KafkaTraceInterceptor,
2504
- WebSocketTraceInterceptor
2505
- ],
2506
- global: true
2507
- };
2508
- }
2509
- /**
2510
- * Configure the module with asynchronous options
2511
- */
2512
- static forRootAsync(options) {
2513
- return {
2514
- module: _LogixiaLoggerModule,
2515
- imports: options.imports || [],
2516
- providers: [
2517
- ...this.createAsyncProviders(options),
2518
- {
2519
- provide: LOGIXIA_TRACE_CONFIG,
2520
- useFactory: (loggerConfig) => {
2521
- return typeof (loggerConfig === null || loggerConfig === void 0 ? void 0 : loggerConfig.traceId) === "object" ? loggerConfig.traceId : { enabled: !!(loggerConfig === null || loggerConfig === void 0 ? void 0 : loggerConfig.traceId) };
1926
+ httpStatus: exception.httpStatus
1927
+ };
1928
+ }
1929
+ if (isHttpException(exception)) {
1930
+ const status = exception.getStatus();
1931
+ const exResponse = exception.getResponse();
1932
+ let message;
1933
+ if (typeof exResponse === "string") message = exResponse;
1934
+ else if (typeof exResponse === "object" && exResponse !== null && "message" in exResponse) {
1935
+ const raw = exResponse.message;
1936
+ message = Array.isArray(raw) ? raw.join(", ") : String(raw);
1937
+ } else message = exception.message;
1938
+ const type = httpStatusToType(status);
1939
+ const code = `HTTP_${status}`;
1940
+ const debug$1 = buildDebug(exception, service, durationMs, expose);
1941
+ return {
1942
+ response: {
1943
+ success: false,
1944
+ error: {
1945
+ type,
1946
+ code,
1947
+ message
2522
1948
  },
2523
- inject: [LOGIXIA_LOGGER_CONFIG]
2524
- },
2525
- {
2526
- provide: LogixiaLoggerService,
2527
- useFactory: (loggerConfig) => {
2528
- const defaultConfig = {
2529
- level: "info",
2530
- service: "NestJSApp",
2531
- environment: "development",
2532
- fields: {},
2533
- formatters: ["text"],
2534
- outputs: ["console"],
2535
- levelOptions: {
2536
- level: "info",
2537
- levels: {
2538
- error: 0,
2539
- warn: 1,
2540
- info: 2,
2541
- debug: 3,
2542
- verbose: 4
2543
- },
2544
- colors: {
2545
- error: "red",
2546
- warn: "yellow",
2547
- info: "green",
2548
- debug: "blue",
2549
- verbose: "cyan"
2550
- }
2551
- },
2552
- ...loggerConfig
2553
- };
2554
- _LogixiaLoggerModule.loggerConfig = defaultConfig;
2555
- const service = new LogixiaLoggerService(defaultConfig);
2556
- _LogixiaLoggerModule._setGlobalLogger(service);
2557
- return service;
1949
+ meta: {
1950
+ ...traceId !== void 0 ? { trace_id: traceId } : {},
1951
+ timestamp,
1952
+ path,
1953
+ status
2558
1954
  },
2559
- inject: [LOGIXIA_LOGGER_CONFIG]
2560
- },
2561
- {
2562
- provide: KafkaTraceInterceptor,
2563
- useFactory: (traceConfig) => new KafkaTraceInterceptor(traceConfig),
2564
- inject: [LOGIXIA_TRACE_CONFIG]
1955
+ ...debug$1 !== void 0 ? { debug: debug$1 } : {}
2565
1956
  },
2566
- {
2567
- provide: WebSocketTraceInterceptor,
2568
- useFactory: (traceConfig) => new WebSocketTraceInterceptor(traceConfig),
2569
- inject: [LOGIXIA_TRACE_CONFIG]
2570
- }
2571
- ],
2572
- exports: [
2573
- LogixiaLoggerService,
2574
- LOGIXIA_LOGGER_CONFIG,
2575
- KafkaTraceInterceptor,
2576
- WebSocketTraceInterceptor
2577
- ],
2578
- global: true
2579
- };
2580
- }
2581
- /**
2582
- * Create feature-specific logger instances
2583
- */
2584
- static forFeature(context) {
2585
- const providerToken = `${LOGIXIA_LOGGER_PREFIX}${context.toUpperCase()}`;
1957
+ httpStatus: status
1958
+ };
1959
+ }
1960
+ const debug = buildDebug(exception instanceof Error ? exception : new Error(String(exception)), service, durationMs, expose);
2586
1961
  return {
2587
- module: _LogixiaLoggerModule,
2588
- providers: [{
2589
- provide: providerToken,
2590
- useFactory: (baseLogger) => {
2591
- return baseLogger.child(context);
1962
+ response: {
1963
+ success: false,
1964
+ error: {
1965
+ type: "server_error",
1966
+ code: "INTERNAL_SERVER_ERROR",
1967
+ message: "An unexpected error occurred."
2592
1968
  },
2593
- inject: [LogixiaLoggerService]
2594
- }],
2595
- exports: [providerToken]
2596
- };
2597
- }
2598
- static createAsyncProviders(options) {
2599
- if (options.useExisting || options.useFactory) return [this.createAsyncOptionsProvider(options)];
2600
- return [this.createAsyncOptionsProvider(options), {
2601
- provide: options.useClass,
2602
- useClass: options.useClass
2603
- }];
2604
- }
2605
- static createAsyncOptionsProvider(options) {
2606
- if (options.useFactory) return {
2607
- provide: LOGIXIA_LOGGER_CONFIG,
2608
- useFactory: options.useFactory,
2609
- inject: options.inject || []
2610
- };
2611
- return {
2612
- provide: LOGIXIA_LOGGER_CONFIG,
2613
- useFactory: async (optionsFactory) => await optionsFactory.createLogixiaOptions(),
2614
- inject: [options.useExisting || options.useClass]
1969
+ meta: {
1970
+ ...traceId !== void 0 ? { trace_id: traceId } : {},
1971
+ timestamp,
1972
+ path,
1973
+ status: 500
1974
+ },
1975
+ ...debug !== void 0 ? { debug } : {}
1976
+ },
1977
+ httpStatus: 500
2615
1978
  };
2616
1979
  }
2617
1980
  };
2618
- LogixiaLoggerModule = _LogixiaLoggerModule = __decorate([Module({})], LogixiaLoggerModule);
2619
1981
 
2620
1982
  //#endregion
2621
- export { resetShutdownHandlers as A, DEFAULT_LOG_COLORS as B, runWithTraceId as C, deregisterFromShutdown as D, _shutdownRegistrySize as E, getOtelMetaFields as F, usePlugin as G, LogLevel as H, initOtelBridge as I, isError as L, redactObject as M, disableOtelBridge as N, flushOnExit as O, getActiveOtelContext as P, normalizeError as R, getTraceContextKey as S, traceStorage as T, PluginRegistry as U, DEFAULT_LOG_LEVELS as V, globalPluginRegistry as W, TraceContext as _, WebSocketTraceInterceptor as a, extractTraceId as b, __decorateParam as c, __decorate as d, __decorateMetadata as f, TRACE_CONTEXT_KEY as g, DEFAULT_TRACE_HEADERS as h, LogixiaLoggerModule as i, applyRedaction as j, registerForShutdown as k, KafkaTraceInterceptor as l, createLogger as m, LOGIXIA_LOGGER_PREFIX as n, TraceMiddleware as o, LogixiaLogger as p, LOGIXIA_TRACE_CONFIG as r, resolveResponseHeader as s, LOGIXIA_LOGGER_CONFIG as t, LogixiaLoggerService as u, _setActiveContextKey as v, setTraceId as w, getCurrentTraceId as x, createTraceMiddleware as y, serializeError as z };
2622
- //# sourceMappingURL=logitron-logger.module-Bs3XYZgF.mjs.map
1983
+ export { globalPluginRegistry as C, DEFAULT_LOG_LEVELS as D, DEFAULT_LOG_COLORS as E, LogLevel as O, PluginRegistry as S, DEFAULT_CONFIG as T, getOtelMetaFields as _, isLogixiaException as a, normalizeError as b, _shutdownRegistrySize as c, registerForShutdown as d, resetShutdownHandlers as f, getActiveOtelContext as g, disableOtelBridge as h, LogixiaException as i, deregisterFromShutdown as l, redactObject as m, generateRequestId as n, LogixiaLogger as o, applyRedaction as p, generateTraceId as r, createLogger as s, ErrorResponseBuilder as t, flushOnExit as u, initOtelBridge as v, usePlugin as w, serializeError as x, isError as y };
1984
+ //# sourceMappingURL=builder-0gEzRopq.mjs.map