autotel 4.3.0 → 5.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 (381) hide show
  1. package/README.md +125 -103
  2. package/dist/analysis.cjs +87 -0
  3. package/dist/analysis.cjs.map +1 -0
  4. package/dist/analysis.d.cts +87 -0
  5. package/dist/analysis.d.cts.map +1 -0
  6. package/dist/analysis.d.ts +87 -0
  7. package/dist/analysis.d.ts.map +1 -0
  8. package/dist/analysis.js +85 -0
  9. package/dist/analysis.js.map +1 -0
  10. package/dist/{attribute-redacting-processor-DtTS9xxh.d.ts → attribute-redacting-processor-Pk7lAzWd.d.cts} +13 -8
  11. package/dist/attribute-redacting-processor-Pk7lAzWd.d.cts.map +1 -0
  12. package/dist/{attribute-redacting-processor-DtTS9xxh.d.cts → attribute-redacting-processor-Pk7lAzWd.d.ts} +13 -8
  13. package/dist/attribute-redacting-processor-Pk7lAzWd.d.ts.map +1 -0
  14. package/dist/attribute-redacting-processor.cjs +4 -4
  15. package/dist/attribute-redacting-processor.cjs.map +1 -1
  16. package/dist/attribute-redacting-processor.d.cts +1 -1
  17. package/dist/attribute-redacting-processor.d.ts +1 -1
  18. package/dist/attribute-redacting-processor.js +4 -4
  19. package/dist/attribute-redacting-processor.js.map +1 -1
  20. package/dist/attributes.d.cts +1 -1
  21. package/dist/attributes.d.ts +1 -1
  22. package/dist/auto.cjs +1 -1
  23. package/dist/auto.cjs.map +1 -1
  24. package/dist/auto.d.cts +1 -1
  25. package/dist/auto.d.ts +1 -1
  26. package/dist/auto.js +1 -1
  27. package/dist/auto.js.map +1 -1
  28. package/dist/business-baggage.d.cts +2 -3
  29. package/dist/business-baggage.d.cts.map +1 -1
  30. package/dist/business-baggage.d.ts +2 -3
  31. package/dist/business-baggage.d.ts.map +1 -1
  32. package/dist/{canonical-log-line-processor-xvjMgtpF.d.cts → canonical-log-line-processor-B4WgG-VS.d.cts} +2 -3
  33. package/dist/canonical-log-line-processor-B4WgG-VS.d.cts.map +1 -0
  34. package/dist/{canonical-log-line-processor-BcRuAdRk.d.ts → canonical-log-line-processor-CL_J7gb5.d.ts} +2 -3
  35. package/dist/canonical-log-line-processor-CL_J7gb5.d.ts.map +1 -0
  36. package/dist/{canonical-log-line-processor-CcrDi6TO.cjs → canonical-log-line-processor-DOjb6Kxy.cjs} +5 -5
  37. package/dist/canonical-log-line-processor-DOjb6Kxy.cjs.map +1 -0
  38. package/dist/{canonical-log-line-processor-FLezvFCB.js → canonical-log-line-processor-mKABvGP0.js} +5 -5
  39. package/dist/canonical-log-line-processor-mKABvGP0.js.map +1 -0
  40. package/dist/config.d.cts +12 -7
  41. package/dist/config.d.cts.map +1 -1
  42. package/dist/config.d.ts +12 -7
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/correlation-id.cjs +1 -1
  45. package/dist/correlation-id.d.cts +0 -1
  46. package/dist/correlation-id.d.cts.map +1 -1
  47. package/dist/correlation-id.d.ts +0 -1
  48. package/dist/correlation-id.d.ts.map +1 -1
  49. package/dist/correlation-id.js +1 -1
  50. package/dist/db.d.cts.map +1 -1
  51. package/dist/db.d.ts.map +1 -1
  52. package/dist/decorators.cjs +1 -1
  53. package/dist/decorators.cjs.map +1 -1
  54. package/dist/decorators.d.cts +1 -2
  55. package/dist/decorators.d.cts.map +1 -1
  56. package/dist/decorators.d.ts +1 -2
  57. package/dist/decorators.d.ts.map +1 -1
  58. package/dist/decorators.js +1 -1
  59. package/dist/decorators.js.map +1 -1
  60. package/dist/{define-event-CreknLm3.d.ts → define-event-B2z1SBe7.d.ts} +2 -3
  61. package/dist/define-event-B2z1SBe7.d.ts.map +1 -0
  62. package/dist/{define-event-HZRizPwz.d.cts → define-event-CGG048HE.d.cts} +2 -3
  63. package/dist/define-event-CGG048HE.d.cts.map +1 -0
  64. package/dist/diagnostics.cjs +10 -1
  65. package/dist/diagnostics.cjs.map +1 -1
  66. package/dist/diagnostics.d.cts +0 -1
  67. package/dist/diagnostics.d.cts.map +1 -1
  68. package/dist/diagnostics.d.ts +0 -1
  69. package/dist/diagnostics.d.ts.map +1 -1
  70. package/dist/diagnostics.js +10 -1
  71. package/dist/diagnostics.js.map +1 -1
  72. package/dist/drain-pipeline.d.cts +12 -5
  73. package/dist/drain-pipeline.d.cts.map +1 -1
  74. package/dist/drain-pipeline.d.ts +12 -5
  75. package/dist/drain-pipeline.d.ts.map +1 -1
  76. package/dist/enrichers.d.cts.map +1 -1
  77. package/dist/enrichers.d.ts.map +1 -1
  78. package/dist/{event-rzA1X5h3.cjs → event-CwIpFdoY.cjs} +3 -3
  79. package/dist/event-CwIpFdoY.cjs.map +1 -0
  80. package/dist/{event-BEm5IJ8U.js → event-pLMF5b3d.js} +4 -4
  81. package/dist/event-pLMF5b3d.js.map +1 -0
  82. package/dist/{event-subscriber-D1XLkPzi.d.ts → event-subscriber-CWh8sTGh.d.cts} +2 -2
  83. package/dist/event-subscriber-CWh8sTGh.d.cts.map +1 -0
  84. package/dist/{event-subscriber-D1XLkPzi.d.cts → event-subscriber-CWh8sTGh.d.ts} +2 -2
  85. package/dist/event-subscriber-CWh8sTGh.d.ts.map +1 -0
  86. package/dist/event-subscriber.d.cts +1 -1
  87. package/dist/event-subscriber.d.ts +1 -1
  88. package/dist/{event-testing-CfFs3to2.d.ts → event-testing-CA2mIx1E.d.ts} +2 -3
  89. package/dist/event-testing-CA2mIx1E.d.ts.map +1 -0
  90. package/dist/{event-testing-BqRnI0z4.d.cts → event-testing-D0qWfqAy.d.cts} +2 -3
  91. package/dist/event-testing-D0qWfqAy.d.cts.map +1 -0
  92. package/dist/event-testing.d.cts +1 -1
  93. package/dist/event-testing.d.ts +1 -1
  94. package/dist/event.cjs +1 -1
  95. package/dist/event.d.cts +3 -4
  96. package/dist/event.d.cts.map +1 -1
  97. package/dist/event.d.ts +3 -4
  98. package/dist/event.d.ts.map +1 -1
  99. package/dist/event.js +1 -1
  100. package/dist/exporters.d.cts +0 -4
  101. package/dist/exporters.d.cts.map +1 -1
  102. package/dist/exporters.d.ts +0 -4
  103. package/dist/exporters.d.ts.map +1 -1
  104. package/dist/{filtering-span-processor-B8R8B7Uk.d.ts → filtering-span-processor-BpDagWNa.d.cts} +1 -2
  105. package/dist/filtering-span-processor-BpDagWNa.d.cts.map +1 -0
  106. package/dist/{filtering-span-processor-B8R8B7Uk.d.cts → filtering-span-processor-BpDagWNa.d.ts} +1 -2
  107. package/dist/filtering-span-processor-BpDagWNa.d.ts.map +1 -0
  108. package/dist/filtering-span-processor.d.cts +1 -1
  109. package/dist/filtering-span-processor.d.ts +1 -1
  110. package/dist/functional-Bit6noRu.js +840 -0
  111. package/dist/functional-Bit6noRu.js.map +1 -0
  112. package/dist/functional-Cj7PSItS.cjs +890 -0
  113. package/dist/functional-Cj7PSItS.cjs.map +1 -0
  114. package/dist/functional.cjs +2 -2
  115. package/dist/functional.d.cts +79 -130
  116. package/dist/functional.d.cts.map +1 -1
  117. package/dist/functional.d.ts +79 -130
  118. package/dist/functional.d.ts.map +1 -1
  119. package/dist/functional.js +2 -2
  120. package/dist/http.cjs +5 -5
  121. package/dist/http.cjs.map +1 -1
  122. package/dist/http.d.cts +4 -5
  123. package/dist/http.d.cts.map +1 -1
  124. package/dist/http.d.ts +4 -5
  125. package/dist/http.d.ts.map +1 -1
  126. package/dist/http.js +5 -5
  127. package/dist/http.js.map +1 -1
  128. package/dist/{index-eKuioqT1.d.cts → index-BPcxVucm.d.cts} +2 -3
  129. package/dist/index-BPcxVucm.d.cts.map +1 -0
  130. package/dist/{index-Ck06vlW2.d.ts → index-DolOVX6F.d.ts} +2 -3
  131. package/dist/index-DolOVX6F.d.ts.map +1 -0
  132. package/dist/index.cjs +7 -8
  133. package/dist/index.cjs.map +1 -1
  134. package/dist/index.d.cts +14 -14
  135. package/dist/index.d.cts.map +1 -1
  136. package/dist/index.d.ts +14 -14
  137. package/dist/index.d.ts.map +1 -1
  138. package/dist/index.js +7 -8
  139. package/dist/index.js.map +1 -1
  140. package/dist/{init-BxJEJ9Tn.cjs → init-B2uvZReD.cjs} +19 -10
  141. package/dist/init-B2uvZReD.cjs.map +1 -0
  142. package/dist/{init-B7u-DjxM.d.ts → init-CTyqG9qR.d.ts} +24 -17
  143. package/dist/init-CTyqG9qR.d.ts.map +1 -0
  144. package/dist/{init-BvBB45-T.js → init-CdEWjhvl.js} +20 -11
  145. package/dist/init-CdEWjhvl.js.map +1 -0
  146. package/dist/{init-DSrRmVnz.d.cts → init-a4yPDYqC.d.cts} +24 -17
  147. package/dist/init-a4yPDYqC.d.cts.map +1 -0
  148. package/dist/instrumentation.cjs +7 -13
  149. package/dist/instrumentation.cjs.map +1 -1
  150. package/dist/instrumentation.d.cts +0 -1
  151. package/dist/instrumentation.d.cts.map +1 -1
  152. package/dist/instrumentation.d.ts +0 -1
  153. package/dist/instrumentation.d.ts.map +1 -1
  154. package/dist/instrumentation.js +8 -14
  155. package/dist/instrumentation.js.map +1 -1
  156. package/dist/{logger-BauSUhUv.d.ts → logger-CN4xpzMd.d.cts} +1 -2
  157. package/dist/logger-CN4xpzMd.d.cts.map +1 -0
  158. package/dist/{logger-BauSUhUv.d.cts → logger-CN4xpzMd.d.ts} +1 -2
  159. package/dist/logger-CN4xpzMd.d.ts.map +1 -0
  160. package/dist/logger-D3Ej3DII.js.map +1 -1
  161. package/dist/logger-thMPLpOG.cjs.map +1 -1
  162. package/dist/logger.d.cts +1 -1
  163. package/dist/logger.d.ts +1 -1
  164. package/dist/messaging-adapters.cjs.map +1 -1
  165. package/dist/messaging-adapters.d.cts +0 -1
  166. package/dist/messaging-adapters.d.cts.map +1 -1
  167. package/dist/messaging-adapters.d.ts +0 -1
  168. package/dist/messaging-adapters.d.ts.map +1 -1
  169. package/dist/messaging-adapters.js.map +1 -1
  170. package/dist/messaging-testing.d.cts +0 -1
  171. package/dist/messaging-testing.d.cts.map +1 -1
  172. package/dist/messaging-testing.d.ts +0 -1
  173. package/dist/messaging-testing.d.ts.map +1 -1
  174. package/dist/messaging.cjs +27 -10
  175. package/dist/messaging.cjs.map +1 -1
  176. package/dist/messaging.d.cts +6 -7
  177. package/dist/messaging.d.cts.map +1 -1
  178. package/dist/messaging.d.ts +6 -7
  179. package/dist/messaging.d.ts.map +1 -1
  180. package/dist/messaging.js +27 -10
  181. package/dist/messaging.js.map +1 -1
  182. package/dist/metric-helpers.d.cts +0 -1
  183. package/dist/metric-helpers.d.cts.map +1 -1
  184. package/dist/metric-helpers.d.ts +0 -1
  185. package/dist/metric-helpers.d.ts.map +1 -1
  186. package/dist/{metric-testing-DXdK3-Q3.d.ts → metric-testing-CWm6UhaR.d.ts} +2 -3
  187. package/dist/metric-testing-CWm6UhaR.d.ts.map +1 -0
  188. package/dist/{metric-testing-MxvzChDp.d.cts → metric-testing-CpvP3ZIa.d.cts} +2 -3
  189. package/dist/metric-testing-CpvP3ZIa.d.cts.map +1 -0
  190. package/dist/metric-testing.d.cts +1 -1
  191. package/dist/metric-testing.d.ts +1 -1
  192. package/dist/metric.d.cts +3 -4
  193. package/dist/metric.d.cts.map +1 -1
  194. package/dist/metric.d.ts +3 -4
  195. package/dist/metric.d.ts.map +1 -1
  196. package/dist/parse-error.d.cts.map +1 -1
  197. package/dist/parse-error.d.ts.map +1 -1
  198. package/dist/processors.cjs +1 -1
  199. package/dist/processors.d.cts +1 -1
  200. package/dist/processors.d.ts +1 -1
  201. package/dist/processors.js +1 -1
  202. package/dist/register.d.cts +1 -1
  203. package/dist/register.d.ts +1 -1
  204. package/dist/{sampling-DfYhDJij.d.cts → sampling-BR9fkSwx.d.cts} +127 -10
  205. package/dist/sampling-BR9fkSwx.d.cts.map +1 -0
  206. package/dist/{sampling-CR0Va1VB.d.ts → sampling-CP3e7-Yr.d.ts} +127 -10
  207. package/dist/sampling-CP3e7-Yr.d.ts.map +1 -0
  208. package/dist/sampling.cjs +160 -12
  209. package/dist/sampling.cjs.map +1 -1
  210. package/dist/sampling.d.cts +2 -2
  211. package/dist/sampling.d.ts +2 -2
  212. package/dist/sampling.js +157 -13
  213. package/dist/sampling.js.map +1 -1
  214. package/dist/security-schema.d.cts +9 -4
  215. package/dist/security-schema.d.cts.map +1 -1
  216. package/dist/security-schema.d.ts +9 -4
  217. package/dist/security-schema.d.ts.map +1 -1
  218. package/dist/semantic-conventions-FhSxv-bK.d.cts.map +1 -1
  219. package/dist/semantic-conventions-FhSxv-bK.d.ts.map +1 -1
  220. package/dist/semantic-conventions.cjs.map +1 -1
  221. package/dist/semantic-conventions.js.map +1 -1
  222. package/dist/semantic-helpers.cjs +85 -304
  223. package/dist/semantic-helpers.cjs.map +1 -1
  224. package/dist/semantic-helpers.d.cts +21 -12
  225. package/dist/semantic-helpers.d.cts.map +1 -1
  226. package/dist/semantic-helpers.d.ts +21 -12
  227. package/dist/semantic-helpers.d.ts.map +1 -1
  228. package/dist/semantic-helpers.js +85 -304
  229. package/dist/semantic-helpers.js.map +1 -1
  230. package/dist/slo.cjs +225 -0
  231. package/dist/slo.cjs.map +1 -0
  232. package/dist/slo.d.cts +97 -0
  233. package/dist/slo.d.cts.map +1 -0
  234. package/dist/slo.d.ts +97 -0
  235. package/dist/slo.d.ts.map +1 -0
  236. package/dist/slo.js +223 -0
  237. package/dist/slo.js.map +1 -0
  238. package/dist/{span-name-normalizer-8ZOGJuwv.d.ts → span-name-normalizer-CN1-8C76.d.cts} +1 -2
  239. package/dist/span-name-normalizer-CN1-8C76.d.cts.map +1 -0
  240. package/dist/{span-name-normalizer-8ZOGJuwv.d.cts → span-name-normalizer-CN1-8C76.d.ts} +1 -2
  241. package/dist/span-name-normalizer-CN1-8C76.d.ts.map +1 -0
  242. package/dist/span-name-normalizer.cjs.map +1 -1
  243. package/dist/span-name-normalizer.d.cts +1 -1
  244. package/dist/span-name-normalizer.d.ts +1 -1
  245. package/dist/span-name-normalizer.js.map +1 -1
  246. package/dist/tail-sampling-processor.d.cts +0 -1
  247. package/dist/tail-sampling-processor.d.cts.map +1 -1
  248. package/dist/tail-sampling-processor.d.ts +0 -1
  249. package/dist/tail-sampling-processor.d.ts.map +1 -1
  250. package/dist/test-span-collector.cjs.map +1 -1
  251. package/dist/test-span-collector.d.cts +0 -1
  252. package/dist/test-span-collector.d.cts.map +1 -1
  253. package/dist/test-span-collector.d.ts +0 -1
  254. package/dist/test-span-collector.d.ts.map +1 -1
  255. package/dist/test-span-collector.js.map +1 -1
  256. package/dist/testing.cjs +76 -11
  257. package/dist/testing.cjs.map +1 -1
  258. package/dist/testing.d.cts +30 -5
  259. package/dist/testing.d.cts.map +1 -1
  260. package/dist/testing.d.ts +30 -5
  261. package/dist/testing.d.ts.map +1 -1
  262. package/dist/testing.js +73 -12
  263. package/dist/testing.js.map +1 -1
  264. package/dist/{trace-context-Cijqoi6e.d.ts → trace-context-IuyoPyNq.d.cts} +9 -9
  265. package/dist/trace-context-IuyoPyNq.d.cts.map +1 -0
  266. package/dist/{trace-context-Cijqoi6e.d.cts → trace-context-IuyoPyNq.d.ts} +9 -9
  267. package/dist/trace-context-IuyoPyNq.d.ts.map +1 -0
  268. package/dist/trace-factory-validation-BjVAinz6.js +13 -0
  269. package/dist/trace-factory-validation-BjVAinz6.js.map +1 -0
  270. package/dist/trace-factory-validation-Dc8epn87.cjs +19 -0
  271. package/dist/trace-factory-validation-Dc8epn87.cjs.map +1 -0
  272. package/dist/trace-helpers.cjs +7 -7
  273. package/dist/trace-helpers.cjs.map +1 -1
  274. package/dist/trace-helpers.d.cts +6 -7
  275. package/dist/trace-helpers.d.cts.map +1 -1
  276. package/dist/trace-helpers.d.ts +6 -7
  277. package/dist/trace-helpers.d.ts.map +1 -1
  278. package/dist/trace-helpers.js +7 -7
  279. package/dist/trace-helpers.js.map +1 -1
  280. package/dist/tracer-provider.d.cts +0 -1
  281. package/dist/tracer-provider.d.cts.map +1 -1
  282. package/dist/tracer-provider.d.ts +0 -1
  283. package/dist/tracer-provider.d.ts.map +1 -1
  284. package/dist/{track-D7O7oIZa.js → track-BBcxEJEC.js} +7 -12
  285. package/dist/track-BBcxEJEC.js.map +1 -0
  286. package/dist/{track-eovhCJ-I.cjs → track-BI6dmZ2X.cjs} +6 -17
  287. package/dist/track-BI6dmZ2X.cjs.map +1 -0
  288. package/dist/validate.cjs.map +1 -1
  289. package/dist/validate.d.cts +1 -2
  290. package/dist/validate.d.cts.map +1 -1
  291. package/dist/validate.d.ts +1 -2
  292. package/dist/validate.d.ts.map +1 -1
  293. package/dist/validate.js.map +1 -1
  294. package/dist/validation-attributes.d.cts +17 -8
  295. package/dist/validation-attributes.d.cts.map +1 -1
  296. package/dist/validation-attributes.d.ts +17 -8
  297. package/dist/validation-attributes.d.ts.map +1 -1
  298. package/dist/webhook.cjs +5 -4
  299. package/dist/webhook.cjs.map +1 -1
  300. package/dist/webhook.d.cts +4 -4
  301. package/dist/webhook.d.cts.map +1 -1
  302. package/dist/webhook.d.ts +4 -4
  303. package/dist/webhook.d.ts.map +1 -1
  304. package/dist/webhook.js +5 -4
  305. package/dist/webhook.js.map +1 -1
  306. package/dist/workflow-distributed.cjs +5 -5
  307. package/dist/workflow-distributed.cjs.map +1 -1
  308. package/dist/workflow-distributed.d.cts +25 -15
  309. package/dist/workflow-distributed.d.cts.map +1 -1
  310. package/dist/workflow-distributed.d.ts +25 -15
  311. package/dist/workflow-distributed.d.ts.map +1 -1
  312. package/dist/workflow-distributed.js +5 -5
  313. package/dist/workflow-distributed.js.map +1 -1
  314. package/dist/workflow.cjs +24 -30
  315. package/dist/workflow.cjs.map +1 -1
  316. package/dist/workflow.d.cts +11 -6
  317. package/dist/workflow.d.cts.map +1 -1
  318. package/dist/workflow.d.ts +11 -6
  319. package/dist/workflow.d.ts.map +1 -1
  320. package/dist/workflow.js +24 -30
  321. package/dist/workflow.js.map +1 -1
  322. package/dist/yaml-config.d.cts +2 -3
  323. package/dist/yaml-config.d.cts.map +1 -1
  324. package/dist/yaml-config.d.ts +2 -3
  325. package/dist/yaml-config.d.ts.map +1 -1
  326. package/package.json +23 -14
  327. package/skills/analyze-traces/SKILL.md +42 -13
  328. package/skills/autotel-core/SKILL.md +24 -17
  329. package/skills/autotel-events/SKILL.md +1 -1
  330. package/skills/autotel-frameworks/SKILL.md +41 -6
  331. package/skills/autotel-instrumentation/SKILL.md +14 -9
  332. package/skills/autotel-request-logging/SKILL.md +19 -14
  333. package/skills/autotel-structured-errors/SKILL.md +2 -2
  334. package/skills/build-audit-trails/SKILL.md +11 -11
  335. package/skills/build-audit-trails/references/audit-queries.md +3 -3
  336. package/skills/debug-missing-spans/SKILL.md +12 -12
  337. package/skills/migrate-to-autotel/SKILL.md +20 -20
  338. package/skills/review-otel-patterns/SKILL.md +44 -42
  339. package/skills/review-otel-patterns/references/code-review.md +4 -4
  340. package/skills/review-otel-patterns/references/processor-pipeline.md +3 -3
  341. package/skills/review-otel-patterns/references/structured-errors.md +1 -1
  342. package/skills/review-otel-patterns/references/wide-spans.md +2 -2
  343. package/skills/tune-sampling/SKILL.md +91 -16
  344. package/dist/attribute-redacting-processor-DtTS9xxh.d.cts.map +0 -1
  345. package/dist/attribute-redacting-processor-DtTS9xxh.d.ts.map +0 -1
  346. package/dist/canonical-log-line-processor-BcRuAdRk.d.ts.map +0 -1
  347. package/dist/canonical-log-line-processor-CcrDi6TO.cjs.map +0 -1
  348. package/dist/canonical-log-line-processor-FLezvFCB.js.map +0 -1
  349. package/dist/canonical-log-line-processor-xvjMgtpF.d.cts.map +0 -1
  350. package/dist/define-event-CreknLm3.d.ts.map +0 -1
  351. package/dist/define-event-HZRizPwz.d.cts.map +0 -1
  352. package/dist/event-BEm5IJ8U.js.map +0 -1
  353. package/dist/event-rzA1X5h3.cjs.map +0 -1
  354. package/dist/event-subscriber-D1XLkPzi.d.cts.map +0 -1
  355. package/dist/event-subscriber-D1XLkPzi.d.ts.map +0 -1
  356. package/dist/event-testing-BqRnI0z4.d.cts.map +0 -1
  357. package/dist/event-testing-CfFs3to2.d.ts.map +0 -1
  358. package/dist/filtering-span-processor-B8R8B7Uk.d.cts.map +0 -1
  359. package/dist/filtering-span-processor-B8R8B7Uk.d.ts.map +0 -1
  360. package/dist/functional-CwsPyc4l.cjs +0 -1298
  361. package/dist/functional-CwsPyc4l.cjs.map +0 -1
  362. package/dist/functional-dAYhXQPA.js +0 -1248
  363. package/dist/functional-dAYhXQPA.js.map +0 -1
  364. package/dist/index-Ck06vlW2.d.ts.map +0 -1
  365. package/dist/index-eKuioqT1.d.cts.map +0 -1
  366. package/dist/init-B7u-DjxM.d.ts.map +0 -1
  367. package/dist/init-BvBB45-T.js.map +0 -1
  368. package/dist/init-BxJEJ9Tn.cjs.map +0 -1
  369. package/dist/init-DSrRmVnz.d.cts.map +0 -1
  370. package/dist/logger-BauSUhUv.d.cts.map +0 -1
  371. package/dist/logger-BauSUhUv.d.ts.map +0 -1
  372. package/dist/metric-testing-DXdK3-Q3.d.ts.map +0 -1
  373. package/dist/metric-testing-MxvzChDp.d.cts.map +0 -1
  374. package/dist/sampling-CR0Va1VB.d.ts.map +0 -1
  375. package/dist/sampling-DfYhDJij.d.cts.map +0 -1
  376. package/dist/span-name-normalizer-8ZOGJuwv.d.cts.map +0 -1
  377. package/dist/span-name-normalizer-8ZOGJuwv.d.ts.map +0 -1
  378. package/dist/trace-context-Cijqoi6e.d.cts.map +0 -1
  379. package/dist/trace-context-Cijqoi6e.d.ts.map +0 -1
  380. package/dist/track-D7O7oIZa.js.map +0 -1
  381. package/dist/track-eovhCJ-I.cjs.map +0 -1
@@ -0,0 +1,87 @@
1
+ //#region src/analysis.d.ts
2
+ /**
3
+ * Core Analysis Loop
4
+ *
5
+ * Debugging from first principles: take the events you care about, take a
6
+ * comparable normal population, and ask which recorded field separates them.
7
+ * The loop is mechanical, so run it in code instead of clicking through a
8
+ * dashboard.
9
+ *
10
+ * `compareCohorts()` scores every field/value pair by how much more often it
11
+ * appears in the outlier group than in the baseline. The top result names the
12
+ * cohort behind a regression, which is the hypothesis you then verify against
13
+ * individual traces.
14
+ *
15
+ * The input is any array of flat records: wide events from
16
+ * `getRequestLogger()`, `TestSpan.attributes` from `autotel/testing`, or rows
17
+ * returned by a backend query.
18
+ *
19
+ * @example Find the cohort behind a latency regression
20
+ * ```typescript
21
+ * import { compareCohorts } from 'autotel/analysis'
22
+ *
23
+ * const slow = events.filter((event) => event['duration_ms'] >= 800)
24
+ * const normal = events.filter((event) => event['duration_ms'] < 800)
25
+ *
26
+ * const [top] = compareCohorts({ outlier: slow, baseline: normal })
27
+ * // { field: 'payment.provider', value: 'bank-beta', difference: 0.94, ... }
28
+ * ```
29
+ */
30
+ /** A flat telemetry record. Span attributes and wide events both satisfy it. */
31
+ type AnalysisEvent = Record<string, unknown>;
32
+ /** How strongly one field/value pair separates the outlier group from the baseline. */
33
+ interface CohortDifference {
34
+ /** Attribute name, such as `payment.provider`. */
35
+ field: string;
36
+ /** The value, rendered as a string for display and grouping. */
37
+ value: string;
38
+ /** Share of outlier events carrying this value, 0-1. */
39
+ outlierFraction: number;
40
+ /** Share of baseline events carrying this value, 0-1. */
41
+ baselineFraction: number;
42
+ /** `outlierFraction - baselineFraction`. Positive means over-represented in the outliers. */
43
+ difference: number;
44
+ outlierCount: number;
45
+ baselineCount: number;
46
+ }
47
+ interface CompareCohortsOptions {
48
+ /** The events you are investigating: the errors, the slow requests, the failed checkouts. */
49
+ outlier: readonly AnalysisEvent[];
50
+ /** A comparable normal population from the same time range. */
51
+ baseline: readonly AnalysisEvent[];
52
+ /** Restrict the scan to these fields. Defaults to every field seen in either group. */
53
+ fields?: readonly string[];
54
+ /** Fields to skip, such as identifiers you already know are unique. */
55
+ ignoreFields?: readonly string[];
56
+ /**
57
+ * Skip a field once it holds more distinct values than this across both
58
+ * groups. Default 50.
59
+ */
60
+ maxValuesPerField?: number;
61
+ /**
62
+ * Skip a field whose distinct values outnumber this share of the combined
63
+ * events. A request id or a raw duration takes a near-unique value per
64
+ * event, so its values never repeat and it cannot describe a cohort. The
65
+ * ratio catches those fields in small populations, where an absolute cap
66
+ * does not. Bucket numeric fields at instrumentation time if you want them
67
+ * ranked. Default 0.5.
68
+ */
69
+ maxUniqueRatio?: number;
70
+ /** Drop pairs whose absolute difference falls below this. Default 0.1. */
71
+ minDifference?: number;
72
+ /** Maximum results to return, strongest first. Default 20. */
73
+ limit?: number;
74
+ }
75
+ /**
76
+ * Rank the field/value pairs that separate an outlier group from a baseline.
77
+ *
78
+ * Returns an empty array when either group is empty, because a fraction over
79
+ * zero events carries no information.
80
+ *
81
+ * @param options - The two populations and the scan limits
82
+ * @returns Differences sorted by absolute strength, strongest first
83
+ */
84
+ declare function compareCohorts(options: CompareCohortsOptions): CohortDifference[];
85
+ //#endregion
86
+ export { AnalysisEvent, CohortDifference, CompareCohortsOptions, compareCohorts };
87
+ //# sourceMappingURL=analysis.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.d.cts","names":[],"sources":["../src/analysis.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8BY,gBAAgB;;UAGX;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;EACA;EACA;;UAGe;;EAEf,kBAAkB;;EAElB,mBAAmB;;EAEnB;;EAEA;;;;;EAKA;;;;;;;;;EASA;;EAEA;;EAEA;;;;;;;;;;;iBAiFc,eACd,SAAS,wBACR"}
@@ -0,0 +1,87 @@
1
+ //#region src/analysis.d.ts
2
+ /**
3
+ * Core Analysis Loop
4
+ *
5
+ * Debugging from first principles: take the events you care about, take a
6
+ * comparable normal population, and ask which recorded field separates them.
7
+ * The loop is mechanical, so run it in code instead of clicking through a
8
+ * dashboard.
9
+ *
10
+ * `compareCohorts()` scores every field/value pair by how much more often it
11
+ * appears in the outlier group than in the baseline. The top result names the
12
+ * cohort behind a regression, which is the hypothesis you then verify against
13
+ * individual traces.
14
+ *
15
+ * The input is any array of flat records: wide events from
16
+ * `getRequestLogger()`, `TestSpan.attributes` from `autotel/testing`, or rows
17
+ * returned by a backend query.
18
+ *
19
+ * @example Find the cohort behind a latency regression
20
+ * ```typescript
21
+ * import { compareCohorts } from 'autotel/analysis'
22
+ *
23
+ * const slow = events.filter((event) => event['duration_ms'] >= 800)
24
+ * const normal = events.filter((event) => event['duration_ms'] < 800)
25
+ *
26
+ * const [top] = compareCohorts({ outlier: slow, baseline: normal })
27
+ * // { field: 'payment.provider', value: 'bank-beta', difference: 0.94, ... }
28
+ * ```
29
+ */
30
+ /** A flat telemetry record. Span attributes and wide events both satisfy it. */
31
+ type AnalysisEvent = Record<string, unknown>;
32
+ /** How strongly one field/value pair separates the outlier group from the baseline. */
33
+ interface CohortDifference {
34
+ /** Attribute name, such as `payment.provider`. */
35
+ field: string;
36
+ /** The value, rendered as a string for display and grouping. */
37
+ value: string;
38
+ /** Share of outlier events carrying this value, 0-1. */
39
+ outlierFraction: number;
40
+ /** Share of baseline events carrying this value, 0-1. */
41
+ baselineFraction: number;
42
+ /** `outlierFraction - baselineFraction`. Positive means over-represented in the outliers. */
43
+ difference: number;
44
+ outlierCount: number;
45
+ baselineCount: number;
46
+ }
47
+ interface CompareCohortsOptions {
48
+ /** The events you are investigating: the errors, the slow requests, the failed checkouts. */
49
+ outlier: readonly AnalysisEvent[];
50
+ /** A comparable normal population from the same time range. */
51
+ baseline: readonly AnalysisEvent[];
52
+ /** Restrict the scan to these fields. Defaults to every field seen in either group. */
53
+ fields?: readonly string[];
54
+ /** Fields to skip, such as identifiers you already know are unique. */
55
+ ignoreFields?: readonly string[];
56
+ /**
57
+ * Skip a field once it holds more distinct values than this across both
58
+ * groups. Default 50.
59
+ */
60
+ maxValuesPerField?: number;
61
+ /**
62
+ * Skip a field whose distinct values outnumber this share of the combined
63
+ * events. A request id or a raw duration takes a near-unique value per
64
+ * event, so its values never repeat and it cannot describe a cohort. The
65
+ * ratio catches those fields in small populations, where an absolute cap
66
+ * does not. Bucket numeric fields at instrumentation time if you want them
67
+ * ranked. Default 0.5.
68
+ */
69
+ maxUniqueRatio?: number;
70
+ /** Drop pairs whose absolute difference falls below this. Default 0.1. */
71
+ minDifference?: number;
72
+ /** Maximum results to return, strongest first. Default 20. */
73
+ limit?: number;
74
+ }
75
+ /**
76
+ * Rank the field/value pairs that separate an outlier group from a baseline.
77
+ *
78
+ * Returns an empty array when either group is empty, because a fraction over
79
+ * zero events carries no information.
80
+ *
81
+ * @param options - The two populations and the scan limits
82
+ * @returns Differences sorted by absolute strength, strongest first
83
+ */
84
+ declare function compareCohorts(options: CompareCohortsOptions): CohortDifference[];
85
+ //#endregion
86
+ export { AnalysisEvent, CohortDifference, CompareCohortsOptions, compareCohorts };
87
+ //# sourceMappingURL=analysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.d.ts","names":[],"sources":["../src/analysis.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8BY,gBAAgB;;UAGX;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;EACA;EACA;;UAGe;;EAEf,kBAAkB;;EAElB,mBAAmB;;EAEnB;;EAEA;;;;;EAKA;;;;;;;;;EASA;;EAEA;;EAEA;;;;;;;;;;;iBAiFc,eACd,SAAS,wBACR"}
@@ -0,0 +1,85 @@
1
+ //#region src/analysis.ts
2
+ const DEFAULT_MAX_VALUES_PER_FIELD = 50;
3
+ const DEFAULT_MAX_UNIQUE_RATIO = .5;
4
+ const DEFAULT_MIN_DIFFERENCE = .1;
5
+ const DEFAULT_LIMIT = 20;
6
+ /**
7
+ * Render a value as a grouping key.
8
+ *
9
+ * Objects and arrays return undefined: a nested structure does not name a
10
+ * cohort, and stringifying it produces noise rather than a testable split.
11
+ */
12
+ function valueKey(value) {
13
+ if (value === null || value === void 0) return;
14
+ const kind = typeof value;
15
+ if (kind === "string" || kind === "number" || kind === "boolean" || kind === "bigint") return String(value);
16
+ }
17
+ /**
18
+ * Fold one group's events into the shared tally.
19
+ *
20
+ * Both groups accumulate into the same structure, so the caller never builds a
21
+ * combined array or revisits an event once per candidate field.
22
+ */
23
+ function accumulate(tally, events, group, includes) {
24
+ for (const event of events) for (const [field, raw] of Object.entries(event)) {
25
+ if (!includes(field)) continue;
26
+ const value = valueKey(raw);
27
+ if (value === void 0) continue;
28
+ let values = tally.get(field);
29
+ if (values === void 0) {
30
+ values = /* @__PURE__ */ new Map();
31
+ tally.set(field, values);
32
+ }
33
+ const counts = values.get(value) ?? {
34
+ outlier: 0,
35
+ baseline: 0
36
+ };
37
+ counts[group]++;
38
+ values.set(value, counts);
39
+ }
40
+ }
41
+ /**
42
+ * Rank the field/value pairs that separate an outlier group from a baseline.
43
+ *
44
+ * Returns an empty array when either group is empty, because a fraction over
45
+ * zero events carries no information.
46
+ *
47
+ * @param options - The two populations and the scan limits
48
+ * @returns Differences sorted by absolute strength, strongest first
49
+ */
50
+ function compareCohorts(options) {
51
+ const { outlier, baseline, fields, ignoreFields, maxValuesPerField = DEFAULT_MAX_VALUES_PER_FIELD, maxUniqueRatio = DEFAULT_MAX_UNIQUE_RATIO, minDifference = DEFAULT_MIN_DIFFERENCE, limit = DEFAULT_LIMIT } = options;
52
+ if (outlier.length === 0 || baseline.length === 0) return [];
53
+ const ignored = new Set(ignoreFields);
54
+ const selected = fields === void 0 ? void 0 : new Set(fields);
55
+ const includes = (field) => !ignored.has(field) && (selected === void 0 || selected.has(field));
56
+ const tally = /* @__PURE__ */ new Map();
57
+ accumulate(tally, outlier, "outlier", includes);
58
+ accumulate(tally, baseline, "baseline", includes);
59
+ const results = [];
60
+ const total = outlier.length + baseline.length;
61
+ for (const [field, values] of tally) {
62
+ if (values.size > maxValuesPerField || values.size > total * maxUniqueRatio) continue;
63
+ for (const [value, counts] of values) {
64
+ const outlierFraction = counts.outlier / outlier.length;
65
+ const baselineFraction = counts.baseline / baseline.length;
66
+ const difference = outlierFraction - baselineFraction;
67
+ if (Math.abs(difference) < minDifference) continue;
68
+ results.push({
69
+ field,
70
+ value,
71
+ outlierFraction,
72
+ baselineFraction,
73
+ difference,
74
+ outlierCount: counts.outlier,
75
+ baselineCount: counts.baseline
76
+ });
77
+ }
78
+ }
79
+ results.sort((a, b) => Math.abs(b.difference) - Math.abs(a.difference) || b.difference - a.difference || a.field.localeCompare(b.field) || a.value.localeCompare(b.value));
80
+ return results.slice(0, limit);
81
+ }
82
+
83
+ //#endregion
84
+ export { compareCohorts };
85
+ //# sourceMappingURL=analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.js","names":[],"sources":["../src/analysis.ts"],"sourcesContent":["/**\n * Core Analysis Loop\n *\n * Debugging from first principles: take the events you care about, take a\n * comparable normal population, and ask which recorded field separates them.\n * The loop is mechanical, so run it in code instead of clicking through a\n * dashboard.\n *\n * `compareCohorts()` scores every field/value pair by how much more often it\n * appears in the outlier group than in the baseline. The top result names the\n * cohort behind a regression, which is the hypothesis you then verify against\n * individual traces.\n *\n * The input is any array of flat records: wide events from\n * `getRequestLogger()`, `TestSpan.attributes` from `autotel/testing`, or rows\n * returned by a backend query.\n *\n * @example Find the cohort behind a latency regression\n * ```typescript\n * import { compareCohorts } from 'autotel/analysis'\n *\n * const slow = events.filter((event) => event['duration_ms'] >= 800)\n * const normal = events.filter((event) => event['duration_ms'] < 800)\n *\n * const [top] = compareCohorts({ outlier: slow, baseline: normal })\n * // { field: 'payment.provider', value: 'bank-beta', difference: 0.94, ... }\n * ```\n */\n\n/** A flat telemetry record. Span attributes and wide events both satisfy it. */\nexport type AnalysisEvent = Record<string, unknown>;\n\n/** How strongly one field/value pair separates the outlier group from the baseline. */\nexport interface CohortDifference {\n /** Attribute name, such as `payment.provider`. */\n field: string;\n /** The value, rendered as a string for display and grouping. */\n value: string;\n /** Share of outlier events carrying this value, 0-1. */\n outlierFraction: number;\n /** Share of baseline events carrying this value, 0-1. */\n baselineFraction: number;\n /** `outlierFraction - baselineFraction`. Positive means over-represented in the outliers. */\n difference: number;\n outlierCount: number;\n baselineCount: number;\n}\n\nexport interface CompareCohortsOptions {\n /** The events you are investigating: the errors, the slow requests, the failed checkouts. */\n outlier: readonly AnalysisEvent[];\n /** A comparable normal population from the same time range. */\n baseline: readonly AnalysisEvent[];\n /** Restrict the scan to these fields. Defaults to every field seen in either group. */\n fields?: readonly string[];\n /** Fields to skip, such as identifiers you already know are unique. */\n ignoreFields?: readonly string[];\n /**\n * Skip a field once it holds more distinct values than this across both\n * groups. Default 50.\n */\n maxValuesPerField?: number;\n /**\n * Skip a field whose distinct values outnumber this share of the combined\n * events. A request id or a raw duration takes a near-unique value per\n * event, so its values never repeat and it cannot describe a cohort. The\n * ratio catches those fields in small populations, where an absolute cap\n * does not. Bucket numeric fields at instrumentation time if you want them\n * ranked. Default 0.5.\n */\n maxUniqueRatio?: number;\n /** Drop pairs whose absolute difference falls below this. Default 0.1. */\n minDifference?: number;\n /** Maximum results to return, strongest first. Default 20. */\n limit?: number;\n}\n\nconst DEFAULT_MAX_VALUES_PER_FIELD = 50;\nconst DEFAULT_MAX_UNIQUE_RATIO = 0.5;\nconst DEFAULT_MIN_DIFFERENCE = 0.1;\nconst DEFAULT_LIMIT = 20;\n\n/**\n * Render a value as a grouping key.\n *\n * Objects and arrays return undefined: a nested structure does not name a\n * cohort, and stringifying it produces noise rather than a testable split.\n */\nfunction valueKey(value: unknown): string | undefined {\n if (value === null || value === undefined) {\n return undefined;\n }\n const kind = typeof value;\n if (\n kind === 'string' ||\n kind === 'number' ||\n kind === 'boolean' ||\n kind === 'bigint'\n ) {\n return String(value);\n }\n return undefined;\n}\n\n/** Occurrences of one value, split by the group it appeared in. */\ninterface ValueCounts {\n outlier: number;\n baseline: number;\n}\n\n/** field -> value -> counts */\ntype FieldTally = Map<string, Map<string, ValueCounts>>;\n\n/**\n * Fold one group's events into the shared tally.\n *\n * Both groups accumulate into the same structure, so the caller never builds a\n * combined array or revisits an event once per candidate field.\n */\nfunction accumulate(\n tally: FieldTally,\n events: readonly AnalysisEvent[],\n group: keyof ValueCounts,\n includes: (field: string) => boolean,\n): void {\n for (const event of events) {\n for (const [field, raw] of Object.entries(event)) {\n if (!includes(field)) {\n continue;\n }\n const value = valueKey(raw);\n if (value === undefined) {\n continue;\n }\n let values = tally.get(field);\n if (values === undefined) {\n values = new Map<string, ValueCounts>();\n tally.set(field, values);\n }\n const counts = values.get(value) ?? { outlier: 0, baseline: 0 };\n counts[group]++;\n values.set(value, counts);\n }\n }\n}\n\n/**\n * Rank the field/value pairs that separate an outlier group from a baseline.\n *\n * Returns an empty array when either group is empty, because a fraction over\n * zero events carries no information.\n *\n * @param options - The two populations and the scan limits\n * @returns Differences sorted by absolute strength, strongest first\n */\nexport function compareCohorts(\n options: CompareCohortsOptions,\n): CohortDifference[] {\n const {\n outlier,\n baseline,\n fields,\n ignoreFields,\n maxValuesPerField = DEFAULT_MAX_VALUES_PER_FIELD,\n maxUniqueRatio = DEFAULT_MAX_UNIQUE_RATIO,\n minDifference = DEFAULT_MIN_DIFFERENCE,\n limit = DEFAULT_LIMIT,\n } = options;\n\n if (outlier.length === 0 || baseline.length === 0) {\n return [];\n }\n\n const ignored = new Set(ignoreFields);\n const selected = fields === undefined ? undefined : new Set(fields);\n const includes = (field: string) =>\n !ignored.has(field) && (selected === undefined || selected.has(field));\n\n const tally: FieldTally = new Map();\n accumulate(tally, outlier, 'outlier', includes);\n accumulate(tally, baseline, 'baseline', includes);\n\n const results: CohortDifference[] = [];\n const total = outlier.length + baseline.length;\n\n for (const [field, values] of tally) {\n if (\n values.size > maxValuesPerField ||\n values.size > total * maxUniqueRatio\n ) {\n continue;\n }\n\n for (const [value, counts] of values) {\n const outlierFraction = counts.outlier / outlier.length;\n const baselineFraction = counts.baseline / baseline.length;\n const difference = outlierFraction - baselineFraction;\n\n if (Math.abs(difference) < minDifference) {\n continue;\n }\n\n results.push({\n field,\n value,\n outlierFraction,\n baselineFraction,\n difference,\n outlierCount: counts.outlier,\n baselineCount: counts.baseline,\n });\n }\n }\n\n // Strongest first. On a tie prefer the over-represented value, because a\n // cohort you can open traces from beats one defined by its absence. Fall\n // back to field and value so repeated runs return the same order.\n results.sort(\n (a, b) =>\n Math.abs(b.difference) - Math.abs(a.difference) ||\n b.difference - a.difference ||\n a.field.localeCompare(b.field) ||\n a.value.localeCompare(b.value),\n );\n\n return results.slice(0, limit);\n}\n"],"mappings":";AA6EA,MAAM,+BAA+B;AACrC,MAAM,2BAA2B;AACjC,MAAM,yBAAyB;AAC/B,MAAM,gBAAgB;;;;;;;AAQtB,SAAS,SAAS,OAAoC;CACpD,IAAI,UAAU,QAAQ,UAAU,QAC9B;CAEF,MAAM,OAAO,OAAO;CACpB,IACE,SAAS,YACT,SAAS,YACT,SAAS,aACT,SAAS,UAET,OAAO,OAAO,KAAK;AAGvB;;;;;;;AAiBA,SAAS,WACP,OACA,QACA,OACA,UACM;CACN,KAAK,MAAM,SAAS,QAClB,KAAK,MAAM,CAAC,OAAO,QAAQ,OAAO,QAAQ,KAAK,GAAG;EAChD,IAAI,CAAC,SAAS,KAAK,GACjB;EAEF,MAAM,QAAQ,SAAS,GAAG;EAC1B,IAAI,UAAU,QACZ;EAEF,IAAI,SAAS,MAAM,IAAI,KAAK;EAC5B,IAAI,WAAW,QAAW;GACxB,yBAAS,IAAI,IAAyB;GACtC,MAAM,IAAI,OAAO,MAAM;EACzB;EACA,MAAM,SAAS,OAAO,IAAI,KAAK,KAAK;GAAE,SAAS;GAAG,UAAU;EAAE;EAC9D,OAAO,MAAM;EACb,OAAO,IAAI,OAAO,MAAM;CAC1B;AAEJ;;;;;;;;;;AAWA,SAAgB,eACd,SACoB;CACpB,MAAM,EACJ,SACA,UACA,QACA,cACA,oBAAoB,8BACpB,iBAAiB,0BACjB,gBAAgB,wBAChB,QAAQ,kBACN;CAEJ,IAAI,QAAQ,WAAW,KAAK,SAAS,WAAW,GAC9C,OAAO,CAAC;CAGV,MAAM,UAAU,IAAI,IAAI,YAAY;CACpC,MAAM,WAAW,WAAW,SAAY,SAAY,IAAI,IAAI,MAAM;CAClE,MAAM,YAAY,UAChB,CAAC,QAAQ,IAAI,KAAK,MAAM,aAAa,UAAa,SAAS,IAAI,KAAK;CAEtE,MAAM,wBAAoB,IAAI,IAAI;CAClC,WAAW,OAAO,SAAS,WAAW,QAAQ;CAC9C,WAAW,OAAO,UAAU,YAAY,QAAQ;CAEhD,MAAM,UAA8B,CAAC;CACrC,MAAM,QAAQ,QAAQ,SAAS,SAAS;CAExC,KAAK,MAAM,CAAC,OAAO,WAAW,OAAO;EACnC,IACE,OAAO,OAAO,qBACd,OAAO,OAAO,QAAQ,gBAEtB;EAGF,KAAK,MAAM,CAAC,OAAO,WAAW,QAAQ;GACpC,MAAM,kBAAkB,OAAO,UAAU,QAAQ;GACjD,MAAM,mBAAmB,OAAO,WAAW,SAAS;GACpD,MAAM,aAAa,kBAAkB;GAErC,IAAI,KAAK,IAAI,UAAU,IAAI,eACzB;GAGF,QAAQ,KAAK;IACX;IACA;IACA;IACA;IACA;IACA,cAAc,OAAO;IACrB,eAAe,OAAO;GACxB,CAAC;EACH;CACF;CAKA,QAAQ,MACL,GAAG,MACF,KAAK,IAAI,EAAE,UAAU,IAAI,KAAK,IAAI,EAAE,UAAU,KAC9C,EAAE,aAAa,EAAE,cACjB,EAAE,MAAM,cAAc,EAAE,KAAK,KAC7B,EAAE,MAAM,cAAc,EAAE,KAAK,CACjC;CAEA,OAAO,QAAQ,MAAM,GAAG,KAAK;AAC/B"}
@@ -1,6 +1,5 @@
1
1
  import { ReadableSpan, Span, SpanProcessor } from "@opentelemetry/sdk-trace-base";
2
2
  import { AttributeValue, Context } from "@opentelemetry/api";
3
-
4
3
  //#region src/attribute-redacting-processor.d.ts
5
4
  /**
6
5
  * Custom redactor function type
@@ -74,14 +73,17 @@ declare const REDACTOR_PATTERNS: {
74
73
  * Each builtin preserves just enough signal for debugging while scrubbing PII.
75
74
  */
76
75
  declare const builtinPatterns: {
77
- /** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */readonly creditCard: {
76
+ /** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */
77
+ readonly creditCard: {
78
78
  readonly pattern: RegExp;
79
79
  readonly mask: (m: string) => string;
80
- }; /** Email addresses → a***@***.com */
80
+ };
81
+ /** Email addresses → a***@***.com */
81
82
  readonly email: {
82
83
  readonly pattern: RegExp;
83
84
  readonly mask: (m: string) => string;
84
- }; /** IPv4 addresses → ***.***.***.100 (last octet only) */
85
+ };
86
+ /** IPv4 addresses → ***.***.***.100 (last octet only) */
85
87
  readonly ipv4: {
86
88
  readonly pattern: RegExp;
87
89
  readonly mask: (m: string) => string;
@@ -99,15 +101,18 @@ declare const builtinPatterns: {
99
101
  readonly phone: {
100
102
  readonly pattern: RegExp;
101
103
  readonly mask: (m: string) => string;
102
- }; /** JWT tokens → eyJ***.*** */
104
+ };
105
+ /** JWT tokens → eyJ***.*** */
103
106
  readonly jwt: {
104
107
  readonly pattern: RegExp;
105
108
  readonly mask: () => string;
106
- }; /** Bearer tokens → Bearer *** */
109
+ };
110
+ /** Bearer tokens → Bearer *** */
107
111
  readonly bearer: {
108
112
  readonly pattern: RegExp;
109
113
  readonly mask: () => string;
110
- }; /** IBAN → FR76****189 (country + check digits + last 3) */
114
+ };
115
+ /** IBAN → FR76****189 (country + check digits + last 3) */
111
116
  readonly iban: {
112
117
  readonly pattern: RegExp;
113
118
  readonly mask: (m: string) => string;
@@ -172,4 +177,4 @@ declare class AttributeRedactingProcessor implements SpanProcessor {
172
177
  }
173
178
  //#endregion
174
179
  export { AttributeRedactorPreset as a, REDACTOR_PATTERNS as c, builtinPatterns as d, createAttributeRedactor as f, AttributeRedactorFn as i, REDACTOR_PRESETS as l, normalizeAttributeRedactorConfig as m, AttributeRedactingProcessorOptions as n, BuiltinPatternName as o, createRedactedSpan as p, AttributeRedactorConfig as r, MaskFn as s, AttributeRedactingProcessor as t, ValuePatternConfig as u };
175
- //# sourceMappingURL=attribute-redacting-processor-DtTS9xxh.d.ts.map
180
+ //# sourceMappingURL=attribute-redacting-processor-Pk7lAzWd.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-redacting-processor-Pk7lAzWd.d.cts","names":[],"sources":["../src/attribute-redacting-processor.ts"],"mappings":";;;;;;KAsCY,uBACV,aACA,OAAO,mBACJ;;;;KAKO;;;;KAKA,UAAU;;;;UAKL;;EAEf;;EAEA,SAAS;;EAET;;EAEA,OAAO;;;;;KAMG,kCAAkC;;;;UAK7B;;EAEf,cAAc;;EAGd,gBAAgB;;EAGhB;;EAGA,qBAAqB;;EAGrB,WAAW;;EAGX;;EAGA,WAAW;;;;;UAMI;EACf,UAAU,0BAA0B;;;;;cAMzB;;;;;;;;;;;;;;cAmBA;;;;aAIC,OAAA;;;;;aAKA,OAAA;;;;;aAWA,OAAA;;;;;;;;;;;;;;aAeA,OAAA;;;;;;;;;;;;;;;aA4BA,OAAA;;;;;;cAqDD,kBAAkB,OAC7B,yBACA;;;;;iBA+Cc,iCACd,KAAK,0BAA0B,oCAC9B,0BAA0B;;;;;;;iBA4NpB,mBACP,MAAM,cACN,UAAU,sBACT;;;;;;;;;;;;;;iBAuCa,wBACd,QAAQ,0BAA0B,0BACjC;;;;;;;;;;;;;cAgBU,uCAAuC;mBACjC;mBACA;EAGf,YAAA,kBAAkB,eAClB,SAAS;;;;EAUX,QAAQ,MAAM,MAAM,eAAe;;;;EAOnC,MAAM,MAAM;EAWZ,cAAc;EAId,YAAY"}
@@ -1,6 +1,5 @@
1
1
  import { ReadableSpan, Span, SpanProcessor } from "@opentelemetry/sdk-trace-base";
2
2
  import { AttributeValue, Context } from "@opentelemetry/api";
3
-
4
3
  //#region src/attribute-redacting-processor.d.ts
5
4
  /**
6
5
  * Custom redactor function type
@@ -74,14 +73,17 @@ declare const REDACTOR_PATTERNS: {
74
73
  * Each builtin preserves just enough signal for debugging while scrubbing PII.
75
74
  */
76
75
  declare const builtinPatterns: {
77
- /** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */readonly creditCard: {
76
+ /** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */
77
+ readonly creditCard: {
78
78
  readonly pattern: RegExp;
79
79
  readonly mask: (m: string) => string;
80
- }; /** Email addresses → a***@***.com */
80
+ };
81
+ /** Email addresses → a***@***.com */
81
82
  readonly email: {
82
83
  readonly pattern: RegExp;
83
84
  readonly mask: (m: string) => string;
84
- }; /** IPv4 addresses → ***.***.***.100 (last octet only) */
85
+ };
86
+ /** IPv4 addresses → ***.***.***.100 (last octet only) */
85
87
  readonly ipv4: {
86
88
  readonly pattern: RegExp;
87
89
  readonly mask: (m: string) => string;
@@ -99,15 +101,18 @@ declare const builtinPatterns: {
99
101
  readonly phone: {
100
102
  readonly pattern: RegExp;
101
103
  readonly mask: (m: string) => string;
102
- }; /** JWT tokens → eyJ***.*** */
104
+ };
105
+ /** JWT tokens → eyJ***.*** */
103
106
  readonly jwt: {
104
107
  readonly pattern: RegExp;
105
108
  readonly mask: () => string;
106
- }; /** Bearer tokens → Bearer *** */
109
+ };
110
+ /** Bearer tokens → Bearer *** */
107
111
  readonly bearer: {
108
112
  readonly pattern: RegExp;
109
113
  readonly mask: () => string;
110
- }; /** IBAN → FR76****189 (country + check digits + last 3) */
114
+ };
115
+ /** IBAN → FR76****189 (country + check digits + last 3) */
111
116
  readonly iban: {
112
117
  readonly pattern: RegExp;
113
118
  readonly mask: (m: string) => string;
@@ -172,4 +177,4 @@ declare class AttributeRedactingProcessor implements SpanProcessor {
172
177
  }
173
178
  //#endregion
174
179
  export { AttributeRedactorPreset as a, REDACTOR_PATTERNS as c, builtinPatterns as d, createAttributeRedactor as f, AttributeRedactorFn as i, REDACTOR_PRESETS as l, normalizeAttributeRedactorConfig as m, AttributeRedactingProcessorOptions as n, BuiltinPatternName as o, createRedactedSpan as p, AttributeRedactorConfig as r, MaskFn as s, AttributeRedactingProcessor as t, ValuePatternConfig as u };
175
- //# sourceMappingURL=attribute-redacting-processor-DtTS9xxh.d.cts.map
180
+ //# sourceMappingURL=attribute-redacting-processor-Pk7lAzWd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-redacting-processor-Pk7lAzWd.d.ts","names":[],"sources":["../src/attribute-redacting-processor.ts"],"mappings":";;;;;;KAsCY,uBACV,aACA,OAAO,mBACJ;;;;KAKO;;;;KAKA,UAAU;;;;UAKL;;EAEf;;EAEA,SAAS;;EAET;;EAEA,OAAO;;;;;KAMG,kCAAkC;;;;UAK7B;;EAEf,cAAc;;EAGd,gBAAgB;;EAGhB;;EAGA,qBAAqB;;EAGrB,WAAW;;EAGX;;EAGA,WAAW;;;;;UAMI;EACf,UAAU,0BAA0B;;;;;cAMzB;;;;;;;;;;;;;;cAmBA;;;;aAIC,OAAA;;;;;aAKA,OAAA;;;;;aAWA,OAAA;;;;;;;;;;;;;;aAeA,OAAA;;;;;;;;;;;;;;;aA4BA,OAAA;;;;;;cAqDD,kBAAkB,OAC7B,yBACA;;;;;iBA+Cc,iCACd,KAAK,0BAA0B,oCAC9B,0BAA0B;;;;;;;iBA4NpB,mBACP,MAAM,cACN,UAAU,sBACT;;;;;;;;;;;;;;iBAuCa,wBACd,QAAQ,0BAA0B,0BACjC;;;;;;;;;;;;;cAgBU,uCAAuC;mBACjC;mBACA;EAGf,YAAA,kBAAkB,eAClB,SAAS;;;;EAUX,QAAQ,MAAM,MAAM,eAAe;;;;EAOnC,MAAM,MAAM;EAWZ,cAAc;EAId,YAAY"}
@@ -22,7 +22,7 @@ const builtinPatterns = {
22
22
  /** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */
23
23
  creditCard: {
24
24
  pattern: /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,
25
- mask: (m) => `****${m.replace(/[\s-]/g, "").slice(-4)}`
25
+ mask: (m) => `****${m.replaceAll(/[\s-]/g, "").slice(-4)}`
26
26
  },
27
27
  /** Email addresses → a***@***.com */
28
28
  email: {
@@ -51,7 +51,7 @@ const builtinPatterns = {
51
51
  phone: {
52
52
  pattern: /(?:\+\d{1,3}[\s.-]?\(?\d{1,4}\)?(?:[\s.-]?\d{2,4}){2,4}|\(\d{1,4}\)(?:[\s.-]?\d{2,4}){2,4}|\b\d{3}[-.]?\d{3}[-.]?\d{4}\b)/g,
53
53
  mask: (m) => {
54
- const digits = m.replace(/[^\d]/g, "");
54
+ const digits = m.replaceAll(/[^\d]/g, "");
55
55
  if (m.startsWith("+") && digits.length > 4) {
56
56
  const ccMatch = m.match(/^\+\d{1,3}/);
57
57
  return `${ccMatch ? ccMatch[0] : "+"}******${digits.slice(-2)}`;
@@ -74,7 +74,7 @@ const builtinPatterns = {
74
74
  iban: {
75
75
  pattern: /\b[A-Z]{2}\d{2}[\s-]?[\dA-Z]{4}[\s-]?[\dA-Z]{4}[\s-]?[\dA-Z]{4}[\s-]?[\dA-Z]{0,4}[\s-]?[\dA-Z]{0,4}[\s-]?[\dA-Z]{0,4}\b/g,
76
76
  mask: (m) => {
77
- const clean = m.replace(/[\s-]/g, "");
77
+ const clean = m.replaceAll(/[\s-]/g, "");
78
78
  return `${clean.slice(0, 4)}****${clean.slice(-3)}`;
79
79
  }
80
80
  }
@@ -232,7 +232,7 @@ function resolveConfig(config) {
232
232
  patterns: normalized.patterns ? [...normalized.patterns] : void 0
233
233
  };
234
234
  if (resolvedConfig.builtins !== false) {
235
- const builtinValuePatterns = (Array.isArray(resolvedConfig.builtins) ? resolvedConfig.builtins : Object.keys(builtinPatterns)).filter((name) => name in builtinPatterns).map(builtinToValuePattern);
235
+ const builtinValuePatterns = (Array.isArray(resolvedConfig.builtins) ? resolvedConfig.builtins : Object.keys(builtinPatterns)).filter((name) => name in builtinPatterns).map((name) => builtinToValuePattern(name));
236
236
  resolvedConfig.valuePatterns = [...resolvedConfig.valuePatterns ?? [], ...builtinValuePatterns];
237
237
  }
238
238
  return resolvedConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"attribute-redacting-processor.cjs","names":[],"sources":["../src/attribute-redacting-processor.ts"],"sourcesContent":["/**\n * Attribute Redacting Processor\n *\n * Automatically redacts PII and sensitive data from span attributes before export.\n * This is critical for compliance (GDPR, PCI-DSS, HIPAA) and data security.\n *\n * @example Basic usage with preset\n * ```typescript\n * init({\n * service: 'my-app',\n * attributeRedactor: 'default'\n * })\n * ```\n *\n * @example Custom patterns\n * ```typescript\n * init({\n * service: 'my-app',\n * attributeRedactor: {\n * keyPatterns: [/password/i, /secret/i],\n * valuePatterns: [\n * { name: 'customerId', pattern: /CUST-\\d{8}/g, replacement: 'CUST-***' }\n * ]\n * }\n * })\n * ```\n */\n\nimport type {\n SpanProcessor,\n ReadableSpan,\n} from '@opentelemetry/sdk-trace-base';\nimport type { Context, AttributeValue, Attributes } from '@opentelemetry/api';\nimport type { Span } from '@opentelemetry/sdk-trace-base';\n\n/**\n * Custom redactor function type\n */\nexport type AttributeRedactorFn = (\n key: string,\n value: AttributeValue,\n) => AttributeValue;\n\n/**\n * Built-in redactor preset names\n */\nexport type AttributeRedactorPreset = 'default' | 'strict' | 'pci-dss';\n\n/**\n * Masker function type - receives the matched string and returns a masked version\n */\nexport type MaskFn = (match: string) => string;\n\n/**\n * Value pattern configuration\n */\nexport interface ValuePatternConfig {\n /** Name for debugging/logging */\n name: string;\n /** Regex pattern to match in values */\n pattern: RegExp;\n /** Custom replacement (default: uses global replacement) */\n replacement?: string;\n /** Mask function for smart partial masking (overrides replacement) */\n mask?: MaskFn;\n}\n\n/**\n * Built-in PII pattern names\n */\nexport type BuiltinPatternName = keyof typeof builtinPatterns;\n\n/**\n * Attribute redactor configuration\n */\nexport interface AttributeRedactorConfig {\n /** Patterns to match against attribute keys (redacts entire value if key matches) */\n keyPatterns?: RegExp[];\n\n /** Patterns to match against attribute values (redacts matched portion) */\n valuePatterns?: ValuePatternConfig[];\n\n /** Dot-notation paths to redact (e.g. 'user.password', 'payment.card') */\n paths?: string[];\n\n /** Built-in PII patterns to enable. `true` enables all, `false` disables all, array selects specific ones. */\n builtins?: boolean | BuiltinPatternName[];\n\n /** Custom RegExp patterns for string-level redaction */\n patterns?: RegExp[];\n\n /** Default replacement string (default: '[REDACTED]') */\n replacement?: string;\n\n /** Custom redactor function for full control */\n redactor?: AttributeRedactorFn;\n}\n\n/**\n * Processor options\n */\nexport interface AttributeRedactingProcessorOptions {\n redactor: AttributeRedactorConfig | AttributeRedactorPreset;\n}\n\n/**\n * Built-in patterns for detecting sensitive data\n */\nexport const REDACTOR_PATTERNS = {\n // Value patterns (match content in attribute values)\n email: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/gi,\n phone: /\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b/g,\n ssn: /\\b\\d{3}[-]?\\d{2}[-]?\\d{4}\\b/g,\n creditCard: /\\b\\d{4}[- ]?\\d{4}[- ]?\\d{4}[- ]?\\d{4}\\b/g,\n bearerToken: /Bearer\\s+[A-Za-z0-9._~+/=-]+/gi,\n apiKeyInValue: /(?:api[_-]?key|apikey|api_secret)[=:][\\s\"']*[A-Za-z0-9_-]+/gi,\n jwt: /eyJ[A-Za-z0-9_-]*\\.eyJ[A-Za-z0-9_-]*\\.[A-Za-z0-9_-]*/g,\n\n // Key patterns (match attribute names - redacts entire value)\n sensitiveKey:\n /^(password|passwd|pwd|secret|token|api[_-]?key|auth|credential|private[_-]?key|authorization)$/i,\n} as const;\n\n/**\n * Built-in PII detection patterns with smart masking.\n * Each builtin preserves just enough signal for debugging while scrubbing PII.\n */\nexport const builtinPatterns = {\n /** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */\n creditCard: {\n pattern: /\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b/g,\n mask: (m: string) => `****${m.replace(/[\\s-]/g, '').slice(-4)}`,\n },\n /** Email addresses → a***@***.com */\n email: {\n pattern: /[\\w.+-]+@[\\w-]+\\.[\\w.]+/g,\n mask: (m: string) => {\n const at = m.indexOf('@');\n if (at < 1) return '***@***';\n const tld = m.slice(m.lastIndexOf('.'));\n return `${m[0]}***@***${tld}`;\n },\n },\n /** IPv4 addresses → ***.***.***.100 (last octet only) */\n ipv4: {\n pattern:\n /\\b(?!0\\.0\\.0\\.0\\b)(?!127\\.0\\.0\\.1\\b)\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/g,\n mask: (m: string) => `***.***.***.${m.split('.').pop()}`,\n },\n /**\n * International / formatted phone numbers.\n *\n * Matches:\n * - `+33 1 23 45 67 89` -> `+33******89`\n * - `(415) 555-1234` -> `********34`\n * - `555-123-4567` / `555.123.4567` / `5551234567` -> `********67`\n *\n * Bare short digit runs like `12345678` are intentionally not matched.\n */\n phone: {\n pattern:\n /(?:\\+\\d{1,3}[\\s.-]?\\(?\\d{1,4}\\)?(?:[\\s.-]?\\d{2,4}){2,4}|\\(\\d{1,4}\\)(?:[\\s.-]?\\d{2,4}){2,4}|\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b)/g,\n mask: (m: string) => {\n const digits = m.replace(/[^\\d]/g, '');\n const hasPlus = m.startsWith('+');\n if (hasPlus && digits.length > 4) {\n const ccMatch = m.match(/^\\+\\d{1,3}/);\n const cc = ccMatch ? ccMatch[0] : '+';\n return `${cc}******${digits.slice(-2)}`;\n }\n if (digits.length > 2) {\n return `${'*'.repeat(digits.length - 2)}${digits.slice(-2)}`;\n }\n return '***';\n },\n },\n /** JWT tokens → eyJ***.*** */\n jwt: {\n pattern: /\\beyJ[\\w-]*\\.[\\w-]*\\.[\\w-]*\\b/g,\n mask: () => 'eyJ***.***',\n },\n /** Bearer tokens → Bearer *** */\n bearer: {\n pattern: /\\bBearer\\s+[\\w\\-.~+/]{8,}=*/gi,\n mask: () => 'Bearer ***',\n },\n /** IBAN → FR76****189 (country + check digits + last 3) */\n iban: {\n pattern:\n /\\b[A-Z]{2}\\d{2}[\\s-]?[\\dA-Z]{4}[\\s-]?[\\dA-Z]{4}[\\s-]?[\\dA-Z]{4}[\\s-]?[\\dA-Z]{0,4}[\\s-]?[\\dA-Z]{0,4}[\\s-]?[\\dA-Z]{0,4}\\b/g,\n mask: (m: string) => {\n const clean = m.replace(/[\\s-]/g, '');\n return `${clean.slice(0, 4)}****${clean.slice(-3)}`;\n },\n },\n} as const;\n\nfunction cloneRegex(re: RegExp): RegExp {\n return new RegExp(re.source, re.flags);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction toRegExp(value: unknown): RegExp | undefined {\n if (value instanceof RegExp) return value;\n if (typeof value === 'string') return new RegExp(value, 'g');\n if (isPlainObject(value) && typeof value.source === 'string') {\n const flags = typeof value.flags === 'string' ? value.flags : 'g';\n return new RegExp(value.source, flags);\n }\n return undefined;\n}\n\nfunction toRegExpArray(value: unknown): RegExp[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const out: RegExp[] = [];\n for (const item of value) {\n const re = toRegExp(item);\n if (re) out.push(re);\n }\n return out.length > 0 ? out : [];\n}\n\nfunction builtinToValuePattern(name: BuiltinPatternName): ValuePatternConfig {\n const b = builtinPatterns[name];\n return { name, pattern: cloneRegex(b.pattern), mask: b.mask };\n}\n\n/**\n * Default value patterns for the 'default' preset\n */\nconst DEFAULT_VALUE_PATTERNS: ValuePatternConfig[] = [\n builtinToValuePattern('email'),\n builtinToValuePattern('phone'),\n { name: 'ssn', pattern: REDACTOR_PATTERNS.ssn },\n builtinToValuePattern('creditCard'),\n];\n\n/**\n * Built-in redactor presets\n */\nexport const REDACTOR_PRESETS: Record<\n AttributeRedactorPreset,\n AttributeRedactorConfig\n> = {\n /**\n * Default preset - covers common PII patterns with smart masking\n * Detects: emails (a***@***.com), phone numbers, SSNs, credit cards (****1111)\n * Redacts keys: password, secret, token, apiKey, auth, credential\n */\n default: {\n keyPatterns: [REDACTOR_PATTERNS.sensitiveKey],\n valuePatterns: DEFAULT_VALUE_PATTERNS,\n builtins: true,\n replacement: '[REDACTED]',\n },\n\n /**\n * Strict preset - more aggressive redaction for high-security environments\n * Includes everything in default plus: Bearer tokens, JWTs, IBAN, API keys in values\n */\n strict: {\n keyPatterns: [REDACTOR_PATTERNS.sensitiveKey, /bearer/i, /jwt/i],\n valuePatterns: [\n ...DEFAULT_VALUE_PATTERNS,\n builtinToValuePattern('jwt'),\n builtinToValuePattern('bearer'),\n builtinToValuePattern('iban'),\n { name: 'apiKeyInValue', pattern: REDACTOR_PATTERNS.apiKeyInValue },\n ],\n builtins: true,\n replacement: '[REDACTED]',\n },\n\n /**\n * PCI-DSS preset - focused on payment card industry compliance\n * Redacts: credit card numbers (****1111), CVV-like patterns, card-related keys\n */\n 'pci-dss': {\n keyPatterns: [/card/i, /cvv/i, /cvc/i, /pan/i, /expir/i, /ccn/i],\n valuePatterns: [builtinToValuePattern('creditCard')],\n builtins: ['creditCard'],\n replacement: '[REDACTED]',\n },\n};\n\n/**\n * Normalize redactor config that may have been deserialized from JSON/YAML.\n * Converts regex-like values back to RegExp instances.\n */\nexport function normalizeAttributeRedactorConfig(\n raw: AttributeRedactorConfig | AttributeRedactorPreset | unknown,\n): AttributeRedactorConfig | AttributeRedactorPreset | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (typeof raw === 'string') return raw as AttributeRedactorPreset;\n if (!isPlainObject(raw)) return undefined;\n\n const config: AttributeRedactorConfig = {};\n\n if (Array.isArray(raw.paths)) {\n config.paths = raw.paths.filter(\n (value): value is string => typeof value === 'string',\n );\n }\n\n if (typeof raw.replacement === 'string') {\n config.replacement = raw.replacement;\n }\n\n if (typeof raw.builtins === 'boolean') {\n config.builtins = raw.builtins;\n } else if (Array.isArray(raw.builtins)) {\n config.builtins = raw.builtins.filter(\n (name): name is BuiltinPatternName => typeof name === 'string',\n );\n }\n\n if (typeof raw.redactor === 'function') {\n config.redactor = raw.redactor as AttributeRedactorFn;\n }\n\n const keyPatterns = toRegExpArray(raw.keyPatterns);\n if (keyPatterns) config.keyPatterns = keyPatterns;\n\n const patterns = toRegExpArray(raw.patterns);\n if (patterns) config.patterns = patterns;\n\n if (Array.isArray(raw.valuePatterns)) {\n const valuePatterns: ValuePatternConfig[] = [];\n for (const item of raw.valuePatterns) {\n if (!isPlainObject(item) || typeof item.name !== 'string') continue;\n const pattern = toRegExp(item.pattern);\n if (!pattern) continue;\n valuePatterns.push({\n name: item.name,\n pattern,\n replacement:\n typeof item.replacement === 'string' ? item.replacement : undefined,\n mask:\n typeof item.mask === 'function' ? (item.mask as MaskFn) : undefined,\n });\n }\n config.valuePatterns = valuePatterns;\n }\n\n return config;\n}\n\n/**\n * Resolve config to a normalized form\n */\nfunction resolveConfig(\n config: AttributeRedactorConfig | AttributeRedactorPreset,\n): AttributeRedactorConfig {\n const normalized = normalizeAttributeRedactorConfig(config);\n if (!normalized) {\n throw new Error('Invalid attribute redactor config');\n }\n\n if (typeof normalized === 'string') {\n const preset = REDACTOR_PRESETS[normalized];\n if (!preset) {\n throw new Error(\n `Unknown attribute redactor preset: \"${normalized}\". ` +\n `Available presets: ${Object.keys(REDACTOR_PRESETS).join(', ')}`,\n );\n }\n return preset;\n }\n\n const resolvedConfig: AttributeRedactorConfig = {\n ...normalized,\n keyPatterns: normalized.keyPatterns\n ? [...normalized.keyPatterns]\n : undefined,\n valuePatterns: normalized.valuePatterns\n ? [...normalized.valuePatterns]\n : undefined,\n paths: normalized.paths ? [...normalized.paths] : undefined,\n patterns: normalized.patterns ? [...normalized.patterns] : undefined,\n };\n\n // Merge built-in patterns if enabled\n if (resolvedConfig.builtins !== false) {\n const builtinNames = Array.isArray(resolvedConfig.builtins)\n ? resolvedConfig.builtins\n : (Object.keys(builtinPatterns) as BuiltinPatternName[]);\n const builtinValuePatterns = builtinNames\n .filter((name) => name in builtinPatterns)\n .map(builtinToValuePattern);\n\n resolvedConfig.valuePatterns = [\n ...(resolvedConfig.valuePatterns ?? []),\n ...builtinValuePatterns,\n ];\n }\n\n return resolvedConfig;\n}\n\n/**\n * Create a redactor function from config\n */\nfunction createRedactorFromConfig(\n config: AttributeRedactorConfig,\n): AttributeRedactorFn {\n // If custom redactor provided, use it directly\n if (config.redactor) {\n return config.redactor;\n }\n\n const keyPatterns = config.keyPatterns ?? [];\n const valuePatterns = config.valuePatterns ?? [];\n const paths = config.paths ?? [];\n const pathSet = new Set(paths);\n const customPatterns = config.patterns ?? [];\n const defaultReplacement = config.replacement ?? '[REDACTED]';\n\n // Build masker list from valuePatterns that have mask functions\n const maskers: [RegExp, MaskFn][] = valuePatterns\n .filter((vp) => vp.mask)\n .map((vp) => [cloneRegex(vp.pattern), vp.mask!]);\n\n return (key: string, value: AttributeValue): AttributeValue => {\n // Key-pattern and path-based redaction only applies to string values.\n // Numbers, booleans and other non-string attributes are not credentials;\n // replacing them with the string '[REDACTED]' silently changes their\n // type and corrupts downstream consumers (LLM token counters etc.).\n if (typeof value === 'string') {\n for (const pattern of keyPatterns) {\n pattern.lastIndex = 0;\n if (pattern.test(key)) {\n return defaultReplacement;\n }\n }\n if (pathSet.has(key)) {\n return defaultReplacement;\n }\n }\n\n // For non-string values, return as-is\n if (typeof value !== 'string') {\n if (Array.isArray(value)) {\n return value.map((item) => {\n if (typeof item === 'string') {\n return redactStringValue(\n item,\n valuePatterns,\n maskers,\n customPatterns,\n defaultReplacement,\n ) as string;\n }\n return item;\n }) as AttributeValue;\n }\n return value;\n }\n\n // Three-tier strategy: path-based → masker-based → pattern-based\n return redactStringValue(\n value,\n valuePatterns,\n maskers,\n customPatterns,\n defaultReplacement,\n );\n };\n}\n\n/**\n * Apply three-tier redaction strategy to a string\n * 1. Masker-based: built-in patterns with smart partial masking\n * 2. Pattern-based: custom RegExp patterns replaced with replacement\n */\nfunction redactStringValue(\n value: string,\n patterns: ValuePatternConfig[],\n maskers: [RegExp, MaskFn][],\n customPatterns: RegExp[],\n defaultReplacement: string,\n): string {\n let result = value;\n\n // Tier 1: Apply maskers (smart partial masking)\n for (const [pattern, mask] of maskers) {\n pattern.lastIndex = 0;\n result = result.replace(pattern, mask);\n }\n\n // Tier 2: Apply value patterns without mask (full replacement)\n for (const { pattern, replacement, mask } of patterns) {\n if (mask) continue; // Already handled by maskers\n pattern.lastIndex = 0;\n result = result.replaceAll(pattern, replacement ?? defaultReplacement);\n }\n\n // Tier 3: Apply custom patterns\n for (const pattern of customPatterns) {\n pattern.lastIndex = 0;\n result = result.replaceAll(pattern, defaultReplacement);\n }\n\n return result;\n}\n\n/**\n * Create a proxy wrapper around ReadableSpan with redacted attributes\n *\n * Since ReadableSpan.attributes is readonly, we use a Proxy to intercept\n * attribute access and return the redacted version.\n */\nfunction createRedactedSpan(\n span: ReadableSpan,\n redactor: AttributeRedactorFn,\n): ReadableSpan {\n // Pre-compute redacted attributes (cached for efficiency)\n const redactedAttributes: Attributes = {};\n for (const [key, value] of Object.entries(span.attributes)) {\n if (value !== undefined) {\n redactedAttributes[key] = redactor(key, value);\n }\n }\n\n // Return a proxy that intercepts attribute access\n return new Proxy(span, {\n get(target, prop) {\n if (prop === 'attributes') {\n return redactedAttributes;\n }\n // For all other properties, delegate to the original span\n const value = Reflect.get(target, prop);\n // Bind methods to the original target\n if (typeof value === 'function') {\n return value.bind(target);\n }\n return value;\n },\n });\n}\n\n/**\n * Create an attribute redactor function from a config or preset.\n *\n * This is useful when you need to apply the same redaction logic\n * outside of the span processor pipeline (e.g., for canonical log lines).\n *\n * @example\n * ```typescript\n * const redactor = createAttributeRedactor('default');\n * const redactedValue = redactor('user.password', 'secret123');\n * // redactedValue === '[REDACTED]'\n * ```\n */\nexport function createAttributeRedactor(\n config: AttributeRedactorConfig | AttributeRedactorPreset,\n): AttributeRedactorFn {\n return createRedactorFromConfig(resolveConfig(config));\n}\n\n/**\n * Span processor that redacts sensitive data from span attributes.\n *\n * Redaction happens in onEnd() when all attributes are finalized.\n * Uses a Proxy wrapper to intercept attribute access since ReadableSpan\n * attributes are readonly.\n *\n * Common use cases:\n * - PII compliance (GDPR, CCPA)\n * - PCI-DSS compliance for payment data\n * - Preventing secrets from leaking to observability backends\n */\nexport class AttributeRedactingProcessor implements SpanProcessor {\n private readonly wrappedProcessor: SpanProcessor;\n private readonly redactor: AttributeRedactorFn;\n\n constructor(\n wrappedProcessor: SpanProcessor,\n options: AttributeRedactingProcessorOptions,\n ) {\n this.wrappedProcessor = wrappedProcessor;\n const config = resolveConfig(options.redactor);\n this.redactor = createRedactorFromConfig(config);\n }\n\n /**\n * Pass through onStart unchanged - attributes aren't finalized yet\n */\n onStart(span: Span, parentContext: Context): void {\n this.wrappedProcessor.onStart(span, parentContext);\n }\n\n /**\n * Redact attributes and forward to wrapped processor\n */\n onEnd(span: ReadableSpan): void {\n try {\n const redactedSpan = createRedactedSpan(span, this.redactor);\n this.wrappedProcessor.onEnd(redactedSpan);\n } catch {\n // Fail-open: if redaction fails, forward original span\n // This ensures we don't lose telemetry due to redaction errors\n this.wrappedProcessor.onEnd(span);\n }\n }\n\n forceFlush(): Promise<void> {\n return this.wrappedProcessor.forceFlush();\n }\n\n shutdown(): Promise<void> {\n return this.wrappedProcessor.shutdown();\n }\n}\n\n/**\n * Export createRedactedSpan for advanced users who want to use it directly\n */\nexport { createRedactedSpan };\n"],"mappings":"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"}
1
+ {"version":3,"file":"attribute-redacting-processor.cjs","names":[],"sources":["../src/attribute-redacting-processor.ts"],"sourcesContent":["/**\n * Attribute Redacting Processor\n *\n * Automatically redacts PII and sensitive data from span attributes before export.\n * This is critical for compliance (GDPR, PCI-DSS, HIPAA) and data security.\n *\n * @example Basic usage with preset\n * ```typescript\n * init({\n * service: 'my-app',\n * attributeRedactor: 'default'\n * })\n * ```\n *\n * @example Custom patterns\n * ```typescript\n * init({\n * service: 'my-app',\n * attributeRedactor: {\n * keyPatterns: [/password/i, /secret/i],\n * valuePatterns: [\n * { name: 'customerId', pattern: /CUST-\\d{8}/g, replacement: 'CUST-***' }\n * ]\n * }\n * })\n * ```\n */\n\nimport type {\n SpanProcessor,\n ReadableSpan,\n} from '@opentelemetry/sdk-trace-base';\nimport type { Context, AttributeValue, Attributes } from '@opentelemetry/api';\nimport type { Span } from '@opentelemetry/sdk-trace-base';\n\n/**\n * Custom redactor function type\n */\nexport type AttributeRedactorFn = (\n key: string,\n value: AttributeValue,\n) => AttributeValue;\n\n/**\n * Built-in redactor preset names\n */\nexport type AttributeRedactorPreset = 'default' | 'strict' | 'pci-dss';\n\n/**\n * Masker function type - receives the matched string and returns a masked version\n */\nexport type MaskFn = (match: string) => string;\n\n/**\n * Value pattern configuration\n */\nexport interface ValuePatternConfig {\n /** Name for debugging/logging */\n name: string;\n /** Regex pattern to match in values */\n pattern: RegExp;\n /** Custom replacement (default: uses global replacement) */\n replacement?: string;\n /** Mask function for smart partial masking (overrides replacement) */\n mask?: MaskFn;\n}\n\n/**\n * Built-in PII pattern names\n */\nexport type BuiltinPatternName = keyof typeof builtinPatterns;\n\n/**\n * Attribute redactor configuration\n */\nexport interface AttributeRedactorConfig {\n /** Patterns to match against attribute keys (redacts entire value if key matches) */\n keyPatterns?: RegExp[];\n\n /** Patterns to match against attribute values (redacts matched portion) */\n valuePatterns?: ValuePatternConfig[];\n\n /** Dot-notation paths to redact (e.g. 'user.password', 'payment.card') */\n paths?: string[];\n\n /** Built-in PII patterns to enable. `true` enables all, `false` disables all, array selects specific ones. */\n builtins?: boolean | BuiltinPatternName[];\n\n /** Custom RegExp patterns for string-level redaction */\n patterns?: RegExp[];\n\n /** Default replacement string (default: '[REDACTED]') */\n replacement?: string;\n\n /** Custom redactor function for full control */\n redactor?: AttributeRedactorFn;\n}\n\n/**\n * Processor options\n */\nexport interface AttributeRedactingProcessorOptions {\n redactor: AttributeRedactorConfig | AttributeRedactorPreset;\n}\n\n/**\n * Built-in patterns for detecting sensitive data\n */\nexport const REDACTOR_PATTERNS = {\n // Value patterns (match content in attribute values)\n email: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/gi,\n phone: /\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b/g,\n ssn: /\\b\\d{3}[-]?\\d{2}[-]?\\d{4}\\b/g,\n creditCard: /\\b\\d{4}[- ]?\\d{4}[- ]?\\d{4}[- ]?\\d{4}\\b/g,\n bearerToken: /Bearer\\s+[A-Za-z0-9._~+/=-]+/gi,\n apiKeyInValue: /(?:api[_-]?key|apikey|api_secret)[=:][\\s\"']*[A-Za-z0-9_-]+/gi,\n jwt: /eyJ[A-Za-z0-9_-]*\\.eyJ[A-Za-z0-9_-]*\\.[A-Za-z0-9_-]*/g,\n\n // Key patterns (match attribute names - redacts entire value)\n sensitiveKey:\n /^(password|passwd|pwd|secret|token|api[_-]?key|auth|credential|private[_-]?key|authorization)$/i,\n} as const;\n\n/**\n * Built-in PII detection patterns with smart masking.\n * Each builtin preserves just enough signal for debugging while scrubbing PII.\n */\nexport const builtinPatterns = {\n /** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */\n creditCard: {\n pattern: /\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b/g,\n mask: (m: string) => `****${m.replaceAll(/[\\s-]/g, '').slice(-4)}`,\n },\n /** Email addresses → a***@***.com */\n email: {\n pattern: /[\\w.+-]+@[\\w-]+\\.[\\w.]+/g,\n mask: (m: string) => {\n const at = m.indexOf('@');\n if (at < 1) return '***@***';\n const tld = m.slice(m.lastIndexOf('.'));\n return `${m[0]}***@***${tld}`;\n },\n },\n /** IPv4 addresses → ***.***.***.100 (last octet only) */\n ipv4: {\n pattern:\n /\\b(?!0\\.0\\.0\\.0\\b)(?!127\\.0\\.0\\.1\\b)\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/g,\n mask: (m: string) => `***.***.***.${m.split('.').pop()}`,\n },\n /**\n * International / formatted phone numbers.\n *\n * Matches:\n * - `+33 1 23 45 67 89` -> `+33******89`\n * - `(415) 555-1234` -> `********34`\n * - `555-123-4567` / `555.123.4567` / `5551234567` -> `********67`\n *\n * Bare short digit runs like `12345678` are intentionally not matched.\n */\n phone: {\n pattern:\n /(?:\\+\\d{1,3}[\\s.-]?\\(?\\d{1,4}\\)?(?:[\\s.-]?\\d{2,4}){2,4}|\\(\\d{1,4}\\)(?:[\\s.-]?\\d{2,4}){2,4}|\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b)/g,\n mask: (m: string) => {\n const digits = m.replaceAll(/[^\\d]/g, '');\n const hasPlus = m.startsWith('+');\n if (hasPlus && digits.length > 4) {\n const ccMatch = m.match(/^\\+\\d{1,3}/);\n const cc = ccMatch ? ccMatch[0] : '+';\n return `${cc}******${digits.slice(-2)}`;\n }\n if (digits.length > 2) {\n return `${'*'.repeat(digits.length - 2)}${digits.slice(-2)}`;\n }\n return '***';\n },\n },\n /** JWT tokens → eyJ***.*** */\n jwt: {\n pattern: /\\beyJ[\\w-]*\\.[\\w-]*\\.[\\w-]*\\b/g,\n mask: () => 'eyJ***.***',\n },\n /** Bearer tokens → Bearer *** */\n bearer: {\n pattern: /\\bBearer\\s+[\\w\\-.~+/]{8,}=*/gi,\n mask: () => 'Bearer ***',\n },\n /** IBAN → FR76****189 (country + check digits + last 3) */\n iban: {\n pattern:\n /\\b[A-Z]{2}\\d{2}[\\s-]?[\\dA-Z]{4}[\\s-]?[\\dA-Z]{4}[\\s-]?[\\dA-Z]{4}[\\s-]?[\\dA-Z]{0,4}[\\s-]?[\\dA-Z]{0,4}[\\s-]?[\\dA-Z]{0,4}\\b/g,\n mask: (m: string) => {\n const clean = m.replaceAll(/[\\s-]/g, '');\n return `${clean.slice(0, 4)}****${clean.slice(-3)}`;\n },\n },\n} as const;\n\nfunction cloneRegex(re: RegExp): RegExp {\n return new RegExp(re.source, re.flags);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction toRegExp(value: unknown): RegExp | undefined {\n if (value instanceof RegExp) return value;\n if (typeof value === 'string') return new RegExp(value, 'g');\n if (isPlainObject(value) && typeof value.source === 'string') {\n const flags = typeof value.flags === 'string' ? value.flags : 'g';\n return new RegExp(value.source, flags);\n }\n return undefined;\n}\n\nfunction toRegExpArray(value: unknown): RegExp[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const out: RegExp[] = [];\n for (const item of value) {\n const re = toRegExp(item);\n if (re) out.push(re);\n }\n return out.length > 0 ? out : [];\n}\n\nfunction builtinToValuePattern(name: BuiltinPatternName): ValuePatternConfig {\n const b = builtinPatterns[name];\n return { name, pattern: cloneRegex(b.pattern), mask: b.mask };\n}\n\n/**\n * Default value patterns for the 'default' preset\n */\nconst DEFAULT_VALUE_PATTERNS: ValuePatternConfig[] = [\n builtinToValuePattern('email'),\n builtinToValuePattern('phone'),\n { name: 'ssn', pattern: REDACTOR_PATTERNS.ssn },\n builtinToValuePattern('creditCard'),\n];\n\n/**\n * Built-in redactor presets\n */\nexport const REDACTOR_PRESETS: Record<\n AttributeRedactorPreset,\n AttributeRedactorConfig\n> = {\n /**\n * Default preset - covers common PII patterns with smart masking\n * Detects: emails (a***@***.com), phone numbers, SSNs, credit cards (****1111)\n * Redacts keys: password, secret, token, apiKey, auth, credential\n */\n default: {\n keyPatterns: [REDACTOR_PATTERNS.sensitiveKey],\n valuePatterns: DEFAULT_VALUE_PATTERNS,\n builtins: true,\n replacement: '[REDACTED]',\n },\n\n /**\n * Strict preset - more aggressive redaction for high-security environments\n * Includes everything in default plus: Bearer tokens, JWTs, IBAN, API keys in values\n */\n strict: {\n keyPatterns: [REDACTOR_PATTERNS.sensitiveKey, /bearer/i, /jwt/i],\n valuePatterns: [\n ...DEFAULT_VALUE_PATTERNS,\n builtinToValuePattern('jwt'),\n builtinToValuePattern('bearer'),\n builtinToValuePattern('iban'),\n { name: 'apiKeyInValue', pattern: REDACTOR_PATTERNS.apiKeyInValue },\n ],\n builtins: true,\n replacement: '[REDACTED]',\n },\n\n /**\n * PCI-DSS preset - focused on payment card industry compliance\n * Redacts: credit card numbers (****1111), CVV-like patterns, card-related keys\n */\n 'pci-dss': {\n keyPatterns: [/card/i, /cvv/i, /cvc/i, /pan/i, /expir/i, /ccn/i],\n valuePatterns: [builtinToValuePattern('creditCard')],\n builtins: ['creditCard'],\n replacement: '[REDACTED]',\n },\n};\n\n/**\n * Normalize redactor config that may have been deserialized from JSON/YAML.\n * Converts regex-like values back to RegExp instances.\n */\nexport function normalizeAttributeRedactorConfig(\n raw: AttributeRedactorConfig | AttributeRedactorPreset | unknown,\n): AttributeRedactorConfig | AttributeRedactorPreset | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (typeof raw === 'string') return raw as AttributeRedactorPreset;\n if (!isPlainObject(raw)) return undefined;\n\n const config: AttributeRedactorConfig = {};\n\n if (Array.isArray(raw.paths)) {\n config.paths = raw.paths.filter(\n (value): value is string => typeof value === 'string',\n );\n }\n\n if (typeof raw.replacement === 'string') {\n config.replacement = raw.replacement;\n }\n\n if (typeof raw.builtins === 'boolean') {\n config.builtins = raw.builtins;\n } else if (Array.isArray(raw.builtins)) {\n config.builtins = raw.builtins.filter(\n (name): name is BuiltinPatternName => typeof name === 'string',\n );\n }\n\n if (typeof raw.redactor === 'function') {\n config.redactor = raw.redactor as AttributeRedactorFn;\n }\n\n const keyPatterns = toRegExpArray(raw.keyPatterns);\n if (keyPatterns) config.keyPatterns = keyPatterns;\n\n const patterns = toRegExpArray(raw.patterns);\n if (patterns) config.patterns = patterns;\n\n if (Array.isArray(raw.valuePatterns)) {\n const valuePatterns: ValuePatternConfig[] = [];\n for (const item of raw.valuePatterns) {\n if (!isPlainObject(item) || typeof item.name !== 'string') continue;\n const pattern = toRegExp(item.pattern);\n if (!pattern) continue;\n valuePatterns.push({\n name: item.name,\n pattern,\n replacement:\n typeof item.replacement === 'string' ? item.replacement : undefined,\n mask:\n typeof item.mask === 'function' ? (item.mask as MaskFn) : undefined,\n });\n }\n config.valuePatterns = valuePatterns;\n }\n\n return config;\n}\n\n/**\n * Resolve config to a normalized form\n */\nfunction resolveConfig(\n config: AttributeRedactorConfig | AttributeRedactorPreset,\n): AttributeRedactorConfig {\n const normalized = normalizeAttributeRedactorConfig(config);\n if (!normalized) {\n throw new Error('Invalid attribute redactor config');\n }\n\n if (typeof normalized === 'string') {\n const preset = REDACTOR_PRESETS[normalized];\n if (!preset) {\n throw new Error(\n `Unknown attribute redactor preset: \"${normalized}\". ` +\n `Available presets: ${Object.keys(REDACTOR_PRESETS).join(', ')}`,\n );\n }\n return preset;\n }\n\n const resolvedConfig: AttributeRedactorConfig = {\n ...normalized,\n keyPatterns: normalized.keyPatterns\n ? [...normalized.keyPatterns]\n : undefined,\n valuePatterns: normalized.valuePatterns\n ? [...normalized.valuePatterns]\n : undefined,\n paths: normalized.paths ? [...normalized.paths] : undefined,\n patterns: normalized.patterns ? [...normalized.patterns] : undefined,\n };\n\n // Merge built-in patterns if enabled\n if (resolvedConfig.builtins !== false) {\n const builtinNames = Array.isArray(resolvedConfig.builtins)\n ? resolvedConfig.builtins\n : (Object.keys(builtinPatterns) as BuiltinPatternName[]);\n const builtinValuePatterns = builtinNames\n .filter((name) => name in builtinPatterns)\n .map((name) => builtinToValuePattern(name));\n\n resolvedConfig.valuePatterns = [\n ...(resolvedConfig.valuePatterns ?? []),\n ...builtinValuePatterns,\n ];\n }\n\n return resolvedConfig;\n}\n\n/**\n * Create a redactor function from config\n */\nfunction createRedactorFromConfig(\n config: AttributeRedactorConfig,\n): AttributeRedactorFn {\n // If custom redactor provided, use it directly\n if (config.redactor) {\n return config.redactor;\n }\n\n const keyPatterns = config.keyPatterns ?? [];\n const valuePatterns = config.valuePatterns ?? [];\n const paths = config.paths ?? [];\n const pathSet = new Set(paths);\n const customPatterns = config.patterns ?? [];\n const defaultReplacement = config.replacement ?? '[REDACTED]';\n\n // Build masker list from valuePatterns that have mask functions\n const maskers: [RegExp, MaskFn][] = valuePatterns\n .filter((vp) => vp.mask)\n .map((vp) => [cloneRegex(vp.pattern), vp.mask!]);\n\n return (key: string, value: AttributeValue): AttributeValue => {\n // Key-pattern and path-based redaction only applies to string values.\n // Numbers, booleans and other non-string attributes are not credentials;\n // replacing them with the string '[REDACTED]' silently changes their\n // type and corrupts downstream consumers (LLM token counters etc.).\n if (typeof value === 'string') {\n for (const pattern of keyPatterns) {\n pattern.lastIndex = 0;\n if (pattern.test(key)) {\n return defaultReplacement;\n }\n }\n if (pathSet.has(key)) {\n return defaultReplacement;\n }\n }\n\n // For non-string values, return as-is\n if (typeof value !== 'string') {\n if (Array.isArray(value)) {\n return value.map((item) => {\n if (typeof item === 'string') {\n return redactStringValue(\n item,\n valuePatterns,\n maskers,\n customPatterns,\n defaultReplacement,\n ) as string;\n }\n return item;\n }) as AttributeValue;\n }\n return value;\n }\n\n // Three-tier strategy: path-based → masker-based → pattern-based\n return redactStringValue(\n value,\n valuePatterns,\n maskers,\n customPatterns,\n defaultReplacement,\n );\n };\n}\n\n/**\n * Apply three-tier redaction strategy to a string\n * 1. Masker-based: built-in patterns with smart partial masking\n * 2. Pattern-based: custom RegExp patterns replaced with replacement\n */\nfunction redactStringValue(\n value: string,\n patterns: ValuePatternConfig[],\n maskers: [RegExp, MaskFn][],\n customPatterns: RegExp[],\n defaultReplacement: string,\n): string {\n let result = value;\n\n // Tier 1: Apply maskers (smart partial masking)\n for (const [pattern, mask] of maskers) {\n pattern.lastIndex = 0;\n result = result.replace(pattern, mask);\n }\n\n // Tier 2: Apply value patterns without mask (full replacement)\n for (const { pattern, replacement, mask } of patterns) {\n if (mask) continue; // Already handled by maskers\n pattern.lastIndex = 0;\n result = result.replaceAll(pattern, replacement ?? defaultReplacement);\n }\n\n // Tier 3: Apply custom patterns\n for (const pattern of customPatterns) {\n pattern.lastIndex = 0;\n result = result.replaceAll(pattern, defaultReplacement);\n }\n\n return result;\n}\n\n/**\n * Create a proxy wrapper around ReadableSpan with redacted attributes\n *\n * Since ReadableSpan.attributes is readonly, we use a Proxy to intercept\n * attribute access and return the redacted version.\n */\nfunction createRedactedSpan(\n span: ReadableSpan,\n redactor: AttributeRedactorFn,\n): ReadableSpan {\n // Pre-compute redacted attributes (cached for efficiency)\n const redactedAttributes: Attributes = {};\n for (const [key, value] of Object.entries(span.attributes)) {\n if (value !== undefined) {\n redactedAttributes[key] = redactor(key, value);\n }\n }\n\n // Return a proxy that intercepts attribute access\n return new Proxy(span, {\n get(target, prop) {\n if (prop === 'attributes') {\n return redactedAttributes;\n }\n // For all other properties, delegate to the original span\n const value = Reflect.get(target, prop);\n // Bind methods to the original target\n if (typeof value === 'function') {\n return value.bind(target);\n }\n return value;\n },\n });\n}\n\n/**\n * Create an attribute redactor function from a config or preset.\n *\n * This is useful when you need to apply the same redaction logic\n * outside of the span processor pipeline (e.g., for canonical log lines).\n *\n * @example\n * ```typescript\n * const redactor = createAttributeRedactor('default');\n * const redactedValue = redactor('user.password', 'secret123');\n * // redactedValue === '[REDACTED]'\n * ```\n */\nexport function createAttributeRedactor(\n config: AttributeRedactorConfig | AttributeRedactorPreset,\n): AttributeRedactorFn {\n return createRedactorFromConfig(resolveConfig(config));\n}\n\n/**\n * Span processor that redacts sensitive data from span attributes.\n *\n * Redaction happens in onEnd() when all attributes are finalized.\n * Uses a Proxy wrapper to intercept attribute access since ReadableSpan\n * attributes are readonly.\n *\n * Common use cases:\n * - PII compliance (GDPR, CCPA)\n * - PCI-DSS compliance for payment data\n * - Preventing secrets from leaking to observability backends\n */\nexport class AttributeRedactingProcessor implements SpanProcessor {\n private readonly wrappedProcessor: SpanProcessor;\n private readonly redactor: AttributeRedactorFn;\n\n constructor(\n wrappedProcessor: SpanProcessor,\n options: AttributeRedactingProcessorOptions,\n ) {\n this.wrappedProcessor = wrappedProcessor;\n const config = resolveConfig(options.redactor);\n this.redactor = createRedactorFromConfig(config);\n }\n\n /**\n * Pass through onStart unchanged - attributes aren't finalized yet\n */\n onStart(span: Span, parentContext: Context): void {\n this.wrappedProcessor.onStart(span, parentContext);\n }\n\n /**\n * Redact attributes and forward to wrapped processor\n */\n onEnd(span: ReadableSpan): void {\n try {\n const redactedSpan = createRedactedSpan(span, this.redactor);\n this.wrappedProcessor.onEnd(redactedSpan);\n } catch {\n // Fail-open: if redaction fails, forward original span\n // This ensures we don't lose telemetry due to redaction errors\n this.wrappedProcessor.onEnd(span);\n }\n }\n\n forceFlush(): Promise<void> {\n return this.wrappedProcessor.forceFlush();\n }\n\n shutdown(): Promise<void> {\n return this.wrappedProcessor.shutdown();\n }\n}\n\n/**\n * Export createRedactedSpan for advanced users who want to use it directly\n */\nexport { createRedactedSpan };\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { a as AttributeRedactorPreset, c as REDACTOR_PATTERNS, d as builtinPatterns, f as createAttributeRedactor, i as AttributeRedactorFn, l as REDACTOR_PRESETS, m as normalizeAttributeRedactorConfig, n as AttributeRedactingProcessorOptions, o as BuiltinPatternName, p as createRedactedSpan, r as AttributeRedactorConfig, s as MaskFn, t as AttributeRedactingProcessor, u as ValuePatternConfig } from "./attribute-redacting-processor-DtTS9xxh.cjs";
1
+ import { a as AttributeRedactorPreset, c as REDACTOR_PATTERNS, d as builtinPatterns, f as createAttributeRedactor, i as AttributeRedactorFn, l as REDACTOR_PRESETS, m as normalizeAttributeRedactorConfig, n as AttributeRedactingProcessorOptions, o as BuiltinPatternName, p as createRedactedSpan, r as AttributeRedactorConfig, s as MaskFn, t as AttributeRedactingProcessor, u as ValuePatternConfig } from "./attribute-redacting-processor-Pk7lAzWd.cjs";
2
2
  export { AttributeRedactingProcessor, AttributeRedactingProcessorOptions, AttributeRedactorConfig, AttributeRedactorFn, AttributeRedactorPreset, BuiltinPatternName, MaskFn, REDACTOR_PATTERNS, REDACTOR_PRESETS, ValuePatternConfig, builtinPatterns, createAttributeRedactor, createRedactedSpan, normalizeAttributeRedactorConfig };
@@ -1,2 +1,2 @@
1
- import { a as AttributeRedactorPreset, c as REDACTOR_PATTERNS, d as builtinPatterns, f as createAttributeRedactor, i as AttributeRedactorFn, l as REDACTOR_PRESETS, m as normalizeAttributeRedactorConfig, n as AttributeRedactingProcessorOptions, o as BuiltinPatternName, p as createRedactedSpan, r as AttributeRedactorConfig, s as MaskFn, t as AttributeRedactingProcessor, u as ValuePatternConfig } from "./attribute-redacting-processor-DtTS9xxh.js";
1
+ import { a as AttributeRedactorPreset, c as REDACTOR_PATTERNS, d as builtinPatterns, f as createAttributeRedactor, i as AttributeRedactorFn, l as REDACTOR_PRESETS, m as normalizeAttributeRedactorConfig, n as AttributeRedactingProcessorOptions, o as BuiltinPatternName, p as createRedactedSpan, r as AttributeRedactorConfig, s as MaskFn, t as AttributeRedactingProcessor, u as ValuePatternConfig } from "./attribute-redacting-processor-Pk7lAzWd.js";
2
2
  export { AttributeRedactingProcessor, AttributeRedactingProcessorOptions, AttributeRedactorConfig, AttributeRedactorFn, AttributeRedactorPreset, BuiltinPatternName, MaskFn, REDACTOR_PATTERNS, REDACTOR_PRESETS, ValuePatternConfig, builtinPatterns, createAttributeRedactor, createRedactedSpan, normalizeAttributeRedactorConfig };
@@ -20,7 +20,7 @@ const builtinPatterns = {
20
20
  /** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */
21
21
  creditCard: {
22
22
  pattern: /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,
23
- mask: (m) => `****${m.replace(/[\s-]/g, "").slice(-4)}`
23
+ mask: (m) => `****${m.replaceAll(/[\s-]/g, "").slice(-4)}`
24
24
  },
25
25
  /** Email addresses → a***@***.com */
26
26
  email: {
@@ -49,7 +49,7 @@ const builtinPatterns = {
49
49
  phone: {
50
50
  pattern: /(?:\+\d{1,3}[\s.-]?\(?\d{1,4}\)?(?:[\s.-]?\d{2,4}){2,4}|\(\d{1,4}\)(?:[\s.-]?\d{2,4}){2,4}|\b\d{3}[-.]?\d{3}[-.]?\d{4}\b)/g,
51
51
  mask: (m) => {
52
- const digits = m.replace(/[^\d]/g, "");
52
+ const digits = m.replaceAll(/[^\d]/g, "");
53
53
  if (m.startsWith("+") && digits.length > 4) {
54
54
  const ccMatch = m.match(/^\+\d{1,3}/);
55
55
  return `${ccMatch ? ccMatch[0] : "+"}******${digits.slice(-2)}`;
@@ -72,7 +72,7 @@ const builtinPatterns = {
72
72
  iban: {
73
73
  pattern: /\b[A-Z]{2}\d{2}[\s-]?[\dA-Z]{4}[\s-]?[\dA-Z]{4}[\s-]?[\dA-Z]{4}[\s-]?[\dA-Z]{0,4}[\s-]?[\dA-Z]{0,4}[\s-]?[\dA-Z]{0,4}\b/g,
74
74
  mask: (m) => {
75
- const clean = m.replace(/[\s-]/g, "");
75
+ const clean = m.replaceAll(/[\s-]/g, "");
76
76
  return `${clean.slice(0, 4)}****${clean.slice(-3)}`;
77
77
  }
78
78
  }
@@ -230,7 +230,7 @@ function resolveConfig(config) {
230
230
  patterns: normalized.patterns ? [...normalized.patterns] : void 0
231
231
  };
232
232
  if (resolvedConfig.builtins !== false) {
233
- const builtinValuePatterns = (Array.isArray(resolvedConfig.builtins) ? resolvedConfig.builtins : Object.keys(builtinPatterns)).filter((name) => name in builtinPatterns).map(builtinToValuePattern);
233
+ const builtinValuePatterns = (Array.isArray(resolvedConfig.builtins) ? resolvedConfig.builtins : Object.keys(builtinPatterns)).filter((name) => name in builtinPatterns).map((name) => builtinToValuePattern(name));
234
234
  resolvedConfig.valuePatterns = [...resolvedConfig.valuePatterns ?? [], ...builtinValuePatterns];
235
235
  }
236
236
  return resolvedConfig;