autotel 4.3.0 → 6.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 (384) 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 +9 -9
  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 +2 -2
  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-subscriber-D1XLkPzi.d.ts → event-subscriber-CWh8sTGh.d.cts} +2 -2
  79. package/dist/event-subscriber-CWh8sTGh.d.cts.map +1 -0
  80. package/dist/{event-subscriber-D1XLkPzi.d.cts → event-subscriber-CWh8sTGh.d.ts} +2 -2
  81. package/dist/event-subscriber-CWh8sTGh.d.ts.map +1 -0
  82. package/dist/event-subscriber.d.cts +1 -1
  83. package/dist/event-subscriber.d.ts +1 -1
  84. package/dist/{event-testing-CfFs3to2.d.ts → event-testing-CA2mIx1E.d.ts} +2 -3
  85. package/dist/event-testing-CA2mIx1E.d.ts.map +1 -0
  86. package/dist/{event-testing-BqRnI0z4.d.cts → event-testing-D0qWfqAy.d.cts} +2 -3
  87. package/dist/event-testing-D0qWfqAy.d.cts.map +1 -0
  88. package/dist/event-testing.d.cts +1 -1
  89. package/dist/event-testing.d.ts +1 -1
  90. package/dist/event.cjs +4 -4
  91. package/dist/event.d.cts +3 -4
  92. package/dist/event.d.cts.map +1 -1
  93. package/dist/event.d.ts +3 -4
  94. package/dist/event.d.ts.map +1 -1
  95. package/dist/event.js +1 -1
  96. package/dist/exporters.d.cts +0 -4
  97. package/dist/exporters.d.cts.map +1 -1
  98. package/dist/exporters.d.ts +0 -4
  99. package/dist/exporters.d.ts.map +1 -1
  100. package/dist/{filtering-span-processor-B8R8B7Uk.d.ts → filtering-span-processor-BpDagWNa.d.cts} +1 -2
  101. package/dist/filtering-span-processor-BpDagWNa.d.cts.map +1 -0
  102. package/dist/{filtering-span-processor-B8R8B7Uk.d.cts → filtering-span-processor-BpDagWNa.d.ts} +1 -2
  103. package/dist/filtering-span-processor-BpDagWNa.d.ts.map +1 -0
  104. package/dist/filtering-span-processor.d.cts +1 -1
  105. package/dist/filtering-span-processor.d.ts +1 -1
  106. package/dist/functional-BnDUxnSl.js +838 -0
  107. package/dist/functional-BnDUxnSl.js.map +1 -0
  108. package/dist/functional-DcLBuCPz.cjs +888 -0
  109. package/dist/functional-DcLBuCPz.cjs.map +1 -0
  110. package/dist/functional.cjs +2 -2
  111. package/dist/functional.d.cts +79 -130
  112. package/dist/functional.d.cts.map +1 -1
  113. package/dist/functional.d.ts +79 -130
  114. package/dist/functional.d.ts.map +1 -1
  115. package/dist/functional.js +2 -2
  116. package/dist/http.cjs +6 -6
  117. package/dist/http.cjs.map +1 -1
  118. package/dist/http.d.cts +4 -5
  119. package/dist/http.d.cts.map +1 -1
  120. package/dist/http.d.ts +4 -5
  121. package/dist/http.d.ts.map +1 -1
  122. package/dist/http.js +5 -5
  123. package/dist/http.js.map +1 -1
  124. package/dist/{index-eKuioqT1.d.cts → index-BPcxVucm.d.cts} +2 -3
  125. package/dist/index-BPcxVucm.d.cts.map +1 -0
  126. package/dist/{index-Ck06vlW2.d.ts → index-DolOVX6F.d.ts} +2 -3
  127. package/dist/index-DolOVX6F.d.ts.map +1 -0
  128. package/dist/index.cjs +25 -167
  129. package/dist/index.cjs.map +1 -1
  130. package/dist/index.d.cts +14 -14
  131. package/dist/index.d.cts.map +1 -1
  132. package/dist/index.d.ts +14 -14
  133. package/dist/index.d.ts.map +1 -1
  134. package/dist/index.js +6 -148
  135. package/dist/index.js.map +1 -1
  136. package/dist/init-C3RApHKJ.cjs +3371 -0
  137. package/dist/init-C3RApHKJ.cjs.map +1 -0
  138. package/dist/{init-DSrRmVnz.d.cts → init-D6n2diBy.d.ts} +46 -20
  139. package/dist/init-D6n2diBy.d.ts.map +1 -0
  140. package/dist/init-R-gSEXkJ.js +3190 -0
  141. package/dist/init-R-gSEXkJ.js.map +1 -0
  142. package/dist/{init-B7u-DjxM.d.ts → init-XzXzrarP.d.cts} +46 -20
  143. package/dist/init-XzXzrarP.d.cts.map +1 -0
  144. package/dist/instrumentation.cjs +7 -13
  145. package/dist/instrumentation.cjs.map +1 -1
  146. package/dist/instrumentation.d.cts +0 -1
  147. package/dist/instrumentation.d.cts.map +1 -1
  148. package/dist/instrumentation.d.ts +0 -1
  149. package/dist/instrumentation.d.ts.map +1 -1
  150. package/dist/instrumentation.js +8 -14
  151. package/dist/instrumentation.js.map +1 -1
  152. package/dist/{logger-BauSUhUv.d.ts → logger-CN4xpzMd.d.cts} +1 -2
  153. package/dist/logger-CN4xpzMd.d.cts.map +1 -0
  154. package/dist/{logger-BauSUhUv.d.cts → logger-CN4xpzMd.d.ts} +1 -2
  155. package/dist/logger-CN4xpzMd.d.ts.map +1 -0
  156. package/dist/logger-D3Ej3DII.js.map +1 -1
  157. package/dist/logger-thMPLpOG.cjs.map +1 -1
  158. package/dist/logger.d.cts +1 -1
  159. package/dist/logger.d.ts +1 -1
  160. package/dist/messaging-adapters.cjs.map +1 -1
  161. package/dist/messaging-adapters.d.cts +0 -1
  162. package/dist/messaging-adapters.d.cts.map +1 -1
  163. package/dist/messaging-adapters.d.ts +0 -1
  164. package/dist/messaging-adapters.d.ts.map +1 -1
  165. package/dist/messaging-adapters.js.map +1 -1
  166. package/dist/messaging-testing.d.cts +0 -1
  167. package/dist/messaging-testing.d.cts.map +1 -1
  168. package/dist/messaging-testing.d.ts +0 -1
  169. package/dist/messaging-testing.d.ts.map +1 -1
  170. package/dist/messaging.cjs +27 -10
  171. package/dist/messaging.cjs.map +1 -1
  172. package/dist/messaging.d.cts +6 -7
  173. package/dist/messaging.d.cts.map +1 -1
  174. package/dist/messaging.d.ts +6 -7
  175. package/dist/messaging.d.ts.map +1 -1
  176. package/dist/messaging.js +27 -10
  177. package/dist/messaging.js.map +1 -1
  178. package/dist/metric-helpers.d.cts +0 -1
  179. package/dist/metric-helpers.d.cts.map +1 -1
  180. package/dist/metric-helpers.d.ts +0 -1
  181. package/dist/metric-helpers.d.ts.map +1 -1
  182. package/dist/{metric-testing-DXdK3-Q3.d.ts → metric-testing-CWm6UhaR.d.ts} +2 -3
  183. package/dist/metric-testing-CWm6UhaR.d.ts.map +1 -0
  184. package/dist/{metric-testing-MxvzChDp.d.cts → metric-testing-CpvP3ZIa.d.cts} +2 -3
  185. package/dist/metric-testing-CpvP3ZIa.d.cts.map +1 -0
  186. package/dist/metric-testing.d.cts +1 -1
  187. package/dist/metric-testing.d.ts +1 -1
  188. package/dist/metric.d.cts +3 -4
  189. package/dist/metric.d.cts.map +1 -1
  190. package/dist/metric.d.ts +3 -4
  191. package/dist/metric.d.ts.map +1 -1
  192. package/dist/parse-error.d.cts.map +1 -1
  193. package/dist/parse-error.d.ts.map +1 -1
  194. package/dist/processors.cjs +1 -1
  195. package/dist/processors.d.cts +1 -1
  196. package/dist/processors.d.ts +1 -1
  197. package/dist/processors.js +1 -1
  198. package/dist/register.d.cts +1 -1
  199. package/dist/register.d.ts +1 -1
  200. package/dist/{sampling-DfYhDJij.d.cts → sampling-BR9fkSwx.d.cts} +127 -10
  201. package/dist/sampling-BR9fkSwx.d.cts.map +1 -0
  202. package/dist/{sampling-CR0Va1VB.d.ts → sampling-CP3e7-Yr.d.ts} +127 -10
  203. package/dist/sampling-CP3e7-Yr.d.ts.map +1 -0
  204. package/dist/sampling.cjs +160 -12
  205. package/dist/sampling.cjs.map +1 -1
  206. package/dist/sampling.d.cts +2 -2
  207. package/dist/sampling.d.ts +2 -2
  208. package/dist/sampling.js +157 -13
  209. package/dist/sampling.js.map +1 -1
  210. package/dist/security-schema.d.cts +9 -4
  211. package/dist/security-schema.d.cts.map +1 -1
  212. package/dist/security-schema.d.ts +9 -4
  213. package/dist/security-schema.d.ts.map +1 -1
  214. package/dist/semantic-conventions-FhSxv-bK.d.cts.map +1 -1
  215. package/dist/semantic-conventions-FhSxv-bK.d.ts.map +1 -1
  216. package/dist/semantic-conventions.cjs.map +1 -1
  217. package/dist/semantic-conventions.js.map +1 -1
  218. package/dist/semantic-helpers.cjs +85 -304
  219. package/dist/semantic-helpers.cjs.map +1 -1
  220. package/dist/semantic-helpers.d.cts +21 -12
  221. package/dist/semantic-helpers.d.cts.map +1 -1
  222. package/dist/semantic-helpers.d.ts +21 -12
  223. package/dist/semantic-helpers.d.ts.map +1 -1
  224. package/dist/semantic-helpers.js +85 -304
  225. package/dist/semantic-helpers.js.map +1 -1
  226. package/dist/slo.cjs +225 -0
  227. package/dist/slo.cjs.map +1 -0
  228. package/dist/slo.d.cts +97 -0
  229. package/dist/slo.d.cts.map +1 -0
  230. package/dist/slo.d.ts +97 -0
  231. package/dist/slo.d.ts.map +1 -0
  232. package/dist/slo.js +223 -0
  233. package/dist/slo.js.map +1 -0
  234. package/dist/{span-name-normalizer-8ZOGJuwv.d.ts → span-name-normalizer-CN1-8C76.d.cts} +1 -2
  235. package/dist/span-name-normalizer-CN1-8C76.d.cts.map +1 -0
  236. package/dist/{span-name-normalizer-8ZOGJuwv.d.cts → span-name-normalizer-CN1-8C76.d.ts} +1 -2
  237. package/dist/span-name-normalizer-CN1-8C76.d.ts.map +1 -0
  238. package/dist/span-name-normalizer.cjs.map +1 -1
  239. package/dist/span-name-normalizer.d.cts +1 -1
  240. package/dist/span-name-normalizer.d.ts +1 -1
  241. package/dist/span-name-normalizer.js.map +1 -1
  242. package/dist/tail-sampling-processor.d.cts +0 -1
  243. package/dist/tail-sampling-processor.d.cts.map +1 -1
  244. package/dist/tail-sampling-processor.d.ts +0 -1
  245. package/dist/tail-sampling-processor.d.ts.map +1 -1
  246. package/dist/test-span-collector.cjs.map +1 -1
  247. package/dist/test-span-collector.d.cts +0 -1
  248. package/dist/test-span-collector.d.cts.map +1 -1
  249. package/dist/test-span-collector.d.ts +0 -1
  250. package/dist/test-span-collector.d.ts.map +1 -1
  251. package/dist/test-span-collector.js.map +1 -1
  252. package/dist/testing.cjs +76 -11
  253. package/dist/testing.cjs.map +1 -1
  254. package/dist/testing.d.cts +30 -5
  255. package/dist/testing.d.cts.map +1 -1
  256. package/dist/testing.d.ts +30 -5
  257. package/dist/testing.d.ts.map +1 -1
  258. package/dist/testing.js +73 -12
  259. package/dist/testing.js.map +1 -1
  260. package/dist/{trace-context-Cijqoi6e.d.ts → trace-context-IuyoPyNq.d.cts} +9 -9
  261. package/dist/trace-context-IuyoPyNq.d.cts.map +1 -0
  262. package/dist/{trace-context-Cijqoi6e.d.cts → trace-context-IuyoPyNq.d.ts} +9 -9
  263. package/dist/trace-context-IuyoPyNq.d.ts.map +1 -0
  264. package/dist/trace-factory-validation-BjVAinz6.js +13 -0
  265. package/dist/trace-factory-validation-BjVAinz6.js.map +1 -0
  266. package/dist/trace-factory-validation-Dc8epn87.cjs +19 -0
  267. package/dist/trace-factory-validation-Dc8epn87.cjs.map +1 -0
  268. package/dist/trace-helpers.cjs +7 -7
  269. package/dist/trace-helpers.cjs.map +1 -1
  270. package/dist/trace-helpers.d.cts +6 -7
  271. package/dist/trace-helpers.d.cts.map +1 -1
  272. package/dist/trace-helpers.d.ts +6 -7
  273. package/dist/trace-helpers.d.ts.map +1 -1
  274. package/dist/trace-helpers.js +7 -7
  275. package/dist/trace-helpers.js.map +1 -1
  276. package/dist/tracer-provider.d.cts +0 -1
  277. package/dist/tracer-provider.d.cts.map +1 -1
  278. package/dist/tracer-provider.d.ts +0 -1
  279. package/dist/tracer-provider.d.ts.map +1 -1
  280. package/dist/validate.cjs.map +1 -1
  281. package/dist/validate.d.cts +1 -2
  282. package/dist/validate.d.cts.map +1 -1
  283. package/dist/validate.d.ts +1 -2
  284. package/dist/validate.d.ts.map +1 -1
  285. package/dist/validate.js.map +1 -1
  286. package/dist/validation-attributes.d.cts +17 -8
  287. package/dist/validation-attributes.d.cts.map +1 -1
  288. package/dist/validation-attributes.d.ts +17 -8
  289. package/dist/validation-attributes.d.ts.map +1 -1
  290. package/dist/webhook.cjs +5 -4
  291. package/dist/webhook.cjs.map +1 -1
  292. package/dist/webhook.d.cts +4 -4
  293. package/dist/webhook.d.cts.map +1 -1
  294. package/dist/webhook.d.ts +4 -4
  295. package/dist/webhook.d.ts.map +1 -1
  296. package/dist/webhook.js +5 -4
  297. package/dist/webhook.js.map +1 -1
  298. package/dist/workflow-distributed.cjs +5 -5
  299. package/dist/workflow-distributed.cjs.map +1 -1
  300. package/dist/workflow-distributed.d.cts +25 -15
  301. package/dist/workflow-distributed.d.cts.map +1 -1
  302. package/dist/workflow-distributed.d.ts +25 -15
  303. package/dist/workflow-distributed.d.ts.map +1 -1
  304. package/dist/workflow-distributed.js +5 -5
  305. package/dist/workflow-distributed.js.map +1 -1
  306. package/dist/workflow.cjs +24 -30
  307. package/dist/workflow.cjs.map +1 -1
  308. package/dist/workflow.d.cts +11 -6
  309. package/dist/workflow.d.cts.map +1 -1
  310. package/dist/workflow.d.ts +11 -6
  311. package/dist/workflow.d.ts.map +1 -1
  312. package/dist/workflow.js +24 -30
  313. package/dist/workflow.js.map +1 -1
  314. package/dist/yaml-config.d.cts +2 -3
  315. package/dist/yaml-config.d.cts.map +1 -1
  316. package/dist/yaml-config.d.ts +2 -3
  317. package/dist/yaml-config.d.ts.map +1 -1
  318. package/package.json +24 -16
  319. package/dist/attribute-redacting-processor-DtTS9xxh.d.cts.map +0 -1
  320. package/dist/attribute-redacting-processor-DtTS9xxh.d.ts.map +0 -1
  321. package/dist/canonical-log-line-processor-BcRuAdRk.d.ts.map +0 -1
  322. package/dist/canonical-log-line-processor-CcrDi6TO.cjs.map +0 -1
  323. package/dist/canonical-log-line-processor-FLezvFCB.js.map +0 -1
  324. package/dist/canonical-log-line-processor-xvjMgtpF.d.cts.map +0 -1
  325. package/dist/define-event-CreknLm3.d.ts.map +0 -1
  326. package/dist/define-event-HZRizPwz.d.cts.map +0 -1
  327. package/dist/event-BEm5IJ8U.js +0 -761
  328. package/dist/event-BEm5IJ8U.js.map +0 -1
  329. package/dist/event-rzA1X5h3.cjs +0 -778
  330. package/dist/event-rzA1X5h3.cjs.map +0 -1
  331. package/dist/event-subscriber-D1XLkPzi.d.cts.map +0 -1
  332. package/dist/event-subscriber-D1XLkPzi.d.ts.map +0 -1
  333. package/dist/event-testing-BqRnI0z4.d.cts.map +0 -1
  334. package/dist/event-testing-CfFs3to2.d.ts.map +0 -1
  335. package/dist/filtering-span-processor-B8R8B7Uk.d.cts.map +0 -1
  336. package/dist/filtering-span-processor-B8R8B7Uk.d.ts.map +0 -1
  337. package/dist/functional-CwsPyc4l.cjs +0 -1298
  338. package/dist/functional-CwsPyc4l.cjs.map +0 -1
  339. package/dist/functional-dAYhXQPA.js +0 -1248
  340. package/dist/functional-dAYhXQPA.js.map +0 -1
  341. package/dist/index-Ck06vlW2.d.ts.map +0 -1
  342. package/dist/index-eKuioqT1.d.cts.map +0 -1
  343. package/dist/init-B7u-DjxM.d.ts.map +0 -1
  344. package/dist/init-BvBB45-T.js +0 -1034
  345. package/dist/init-BvBB45-T.js.map +0 -1
  346. package/dist/init-BxJEJ9Tn.cjs +0 -1111
  347. package/dist/init-BxJEJ9Tn.cjs.map +0 -1
  348. package/dist/init-DSrRmVnz.d.cts.map +0 -1
  349. package/dist/logger-BauSUhUv.d.cts.map +0 -1
  350. package/dist/logger-BauSUhUv.d.ts.map +0 -1
  351. package/dist/metric-testing-DXdK3-Q3.d.ts.map +0 -1
  352. package/dist/metric-testing-MxvzChDp.d.cts.map +0 -1
  353. package/dist/operation-context-CKBoA4Qy.js +0 -59
  354. package/dist/operation-context-CKBoA4Qy.js.map +0 -1
  355. package/dist/operation-context-hzKbTKnt.cjs +0 -72
  356. package/dist/operation-context-hzKbTKnt.cjs.map +0 -1
  357. package/dist/sampling-CR0Va1VB.d.ts.map +0 -1
  358. package/dist/sampling-DfYhDJij.d.cts.map +0 -1
  359. package/dist/span-name-normalizer-8ZOGJuwv.d.cts.map +0 -1
  360. package/dist/span-name-normalizer-8ZOGJuwv.d.ts.map +0 -1
  361. package/dist/trace-context-Cijqoi6e.d.cts.map +0 -1
  362. package/dist/trace-context-Cijqoi6e.d.ts.map +0 -1
  363. package/dist/track-D7O7oIZa.js +0 -1115
  364. package/dist/track-D7O7oIZa.js.map +0 -1
  365. package/dist/track-eovhCJ-I.cjs +0 -1218
  366. package/dist/track-eovhCJ-I.cjs.map +0 -1
  367. package/skills/analyze-traces/SKILL.md +0 -180
  368. package/skills/autotel-core/SKILL.md +0 -159
  369. package/skills/autotel-events/SKILL.md +0 -84
  370. package/skills/autotel-frameworks/SKILL.md +0 -90
  371. package/skills/autotel-instrumentation/SKILL.md +0 -145
  372. package/skills/autotel-request-logging/SKILL.md +0 -94
  373. package/skills/autotel-structured-errors/SKILL.md +0 -125
  374. package/skills/build-audit-trails/SKILL.md +0 -460
  375. package/skills/build-audit-trails/references/audit-queries.md +0 -73
  376. package/skills/build-audit-trails/references/framework-wiring.md +0 -196
  377. package/skills/debug-missing-spans/SKILL.md +0 -250
  378. package/skills/migrate-to-autotel/SKILL.md +0 -269
  379. package/skills/review-otel-patterns/SKILL.md +0 -538
  380. package/skills/review-otel-patterns/references/code-review.md +0 -76
  381. package/skills/review-otel-patterns/references/processor-pipeline.md +0 -205
  382. package/skills/review-otel-patterns/references/structured-errors.md +0 -102
  383. package/skills/review-otel-patterns/references/wide-spans.md +0 -85
  384. package/skills/tune-sampling/SKILL.md +0 -215
@@ -0,0 +1,3371 @@
1
+ const require_rolldown_runtime = require('./rolldown-runtime-C_NdSu1c.cjs');
2
+ const require_tracer_provider = require('./tracer-provider.cjs');
3
+ const require_config = require('./config.cjs');
4
+ const require_sampling = require('./sampling.cjs');
5
+ const require_node_require = require('./node-require-PFqDihze.cjs');
6
+ const require_tail_sampling_processor = require('./tail-sampling-processor.cjs');
7
+ const require_filtering_span_processor = require('./filtering-span-processor.cjs');
8
+ const require_span_name_normalizer = require('./span-name-normalizer.cjs');
9
+ const require_attribute_redacting_processor = require('./attribute-redacting-processor.cjs');
10
+ const require_pretty_console_exporter = require('./pretty-console-exporter-CMzlrRNg.cjs');
11
+ const require_yaml_config = require('./yaml-config.cjs');
12
+ const require_canonical_log_line_processor = require('./canonical-log-line-processor-DOjb6Kxy.cjs');
13
+ const require_structured_error = require('./structured-error-CHg7DoIQ.cjs');
14
+ const require_metric = require('./metric.cjs');
15
+ let _opentelemetry_sdk_node = require("@opentelemetry/sdk-node");
16
+ let _opentelemetry_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
17
+ let _opentelemetry_resources = require("@opentelemetry/resources");
18
+ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
19
+ let _opentelemetry_api = require("@opentelemetry/api");
20
+ let _opentelemetry_sdk_metrics = require("@opentelemetry/sdk-metrics");
21
+ let _opentelemetry_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
22
+ let _opentelemetry_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
23
+ let _opentelemetry_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
24
+ let _opentelemetry_sdk_logs = require("@opentelemetry/sdk-logs");
25
+ let node_os = require("node:os");
26
+ let node_async_hooks = require("node:async_hooks");
27
+ node_async_hooks = require_rolldown_runtime.__toESM(node_async_hooks, 1);
28
+
29
+ //#region src/posthog-logs.ts
30
+ var RedactingLogRecordProcessor = class {
31
+ wrapped;
32
+ redact;
33
+ constructor(wrapped, redact) {
34
+ this.wrapped = wrapped;
35
+ this.redact = redact;
36
+ }
37
+ onEmit(logRecord, context) {
38
+ if (logRecord.body && typeof logRecord.body === "string") logRecord.body = this.redact(logRecord.body);
39
+ if (logRecord.attributes) {
40
+ for (const [key, value] of Object.entries(logRecord.attributes)) if (typeof value === "string") logRecord.attributes[key] = this.redact(value);
41
+ else if (Array.isArray(value)) logRecord.attributes[key] = value.map((item) => typeof item === "string" ? this.redact(item) : item);
42
+ }
43
+ this.wrapped.onEmit(logRecord, context);
44
+ }
45
+ shutdown() {
46
+ return this.wrapped.shutdown();
47
+ }
48
+ forceFlush() {
49
+ return this.wrapped.forceFlush();
50
+ }
51
+ };
52
+ /**
53
+ * Build log record processors for PostHog OTLP logs integration.
54
+ *
55
+ * Resolution order:
56
+ * 1. config.url if provided
57
+ * 2. POSTHOG_LOGS_URL env var
58
+ * 3. Empty array (disabled)
59
+ */
60
+ function buildPostHogLogProcessors(config, stringRedactor) {
61
+ const url = config?.url || process.env.POSTHOG_LOGS_URL;
62
+ if (!url) return [];
63
+ const sdkLogs = require_node_require.safeRequire("@opentelemetry/sdk-logs");
64
+ const exporterModule = require_node_require.safeRequire("@opentelemetry/exporter-logs-otlp-http");
65
+ if (!sdkLogs || !exporterModule) return [];
66
+ const exporter = new exporterModule.OTLPLogExporter({ url });
67
+ let processor = new sdkLogs.BatchLogRecordProcessor({ exporter });
68
+ if (stringRedactor) processor = new RedactingLogRecordProcessor(processor, stringRedactor);
69
+ return [processor];
70
+ }
71
+
72
+ //#endregion
73
+ //#region src/baggage-span-processor.ts
74
+ /**
75
+ * Span processor that automatically copies baggage entries to span attributes
76
+ *
77
+ * This makes baggage visible in trace UIs (Jaeger, Grafana, DataDog, etc.)
78
+ * without manually calling ctx.setAttribute() for each baggage entry.
79
+ *
80
+ * @example Enable in init()
81
+ * ```typescript
82
+ * init({
83
+ * service: 'my-app',
84
+ * baggage: true // Uses default 'baggage.' prefix
85
+ * });
86
+ *
87
+ * // Now baggage automatically appears as span attributes
88
+ * await withBaggage({
89
+ * baggage: { 'tenant.id': 't1', 'user.id': 'u1' },
90
+ * fn: async () => {
91
+ * // Span has baggage.tenant.id and baggage.user.id attributes!
92
+ * }
93
+ * });
94
+ * ```
95
+ *
96
+ * @example Custom prefix
97
+ * ```typescript
98
+ * init({
99
+ * service: 'my-app',
100
+ * baggage: 'ctx' // Uses 'ctx.' prefix
101
+ * });
102
+ * // Creates attributes: ctx.tenant.id, ctx.user.id
103
+ * ```
104
+ */
105
+ var BaggageSpanProcessor = class {
106
+ prefix;
107
+ constructor(options = {}) {
108
+ this.prefix = options.prefix ?? "baggage.";
109
+ }
110
+ onStart(span, parentContext) {
111
+ let baggage = _opentelemetry_api.propagation.getBaggage(parentContext);
112
+ if (!baggage) baggage = _opentelemetry_api.propagation.getBaggage(_opentelemetry_api.context.active());
113
+ if (!baggage) try {
114
+ const { getActiveContextWithBaggage } = require_node_require.requireModule("./trace-context");
115
+ const storedContext = getActiveContextWithBaggage();
116
+ baggage = _opentelemetry_api.propagation.getBaggage(storedContext);
117
+ } catch {}
118
+ if (!baggage) return;
119
+ for (const [key, entry] of baggage.getAllEntries()) span.setAttribute(`${this.prefix}${key}`, entry.value);
120
+ }
121
+ onEnd(_span) {}
122
+ async shutdown() {}
123
+ async forceFlush() {}
124
+ };
125
+
126
+ //#endregion
127
+ //#region src/redact-values.ts
128
+ /** Standalone string redaction for use outside the span processor pipeline. */
129
+ function createStringRedactor(config) {
130
+ const resolved = typeof config === "string" ? require_attribute_redacting_processor.REDACTOR_PRESETS[config] : config;
131
+ const valuePatterns = resolved.valuePatterns ?? [];
132
+ const defaultReplacement = resolved.replacement ?? "[REDACTED]";
133
+ return (value) => {
134
+ let result = value;
135
+ for (const { pattern, replacement, mask } of valuePatterns) {
136
+ pattern.lastIndex = 0;
137
+ result = mask ? result.replaceAll(pattern, (match) => mask(match)) : result.replaceAll(pattern, replacement ?? defaultReplacement);
138
+ }
139
+ return result;
140
+ };
141
+ }
142
+
143
+ //#endregion
144
+ //#region src/env-config.ts
145
+ /**
146
+ * Validate URL format
147
+ */
148
+ function isValidUrl(urlString) {
149
+ try {
150
+ const url = new URL(urlString);
151
+ return url.protocol === "http:" || url.protocol === "https:";
152
+ } catch {
153
+ return false;
154
+ }
155
+ }
156
+ /**
157
+ * Resolve OpenTelemetry environment variables from process.env
158
+ */
159
+ function resolveOtelEnv() {
160
+ const env = {};
161
+ if (process.env.OTEL_SERVICE_NAME) {
162
+ const value = process.env.OTEL_SERVICE_NAME.trim();
163
+ if (value) env.OTEL_SERVICE_NAME = value;
164
+ }
165
+ if (process.env.OTEL_EXPORTER_OTLP_ENDPOINT) {
166
+ const value = process.env.OTEL_EXPORTER_OTLP_ENDPOINT.trim();
167
+ if (value && isValidUrl(value)) env.OTEL_EXPORTER_OTLP_ENDPOINT = value;
168
+ }
169
+ if (process.env.OTEL_EXPORTER_OTLP_HEADERS) {
170
+ const value = process.env.OTEL_EXPORTER_OTLP_HEADERS.trim();
171
+ if (value) env.OTEL_EXPORTER_OTLP_HEADERS = value;
172
+ }
173
+ if (process.env.OTEL_RESOURCE_ATTRIBUTES) {
174
+ const value = process.env.OTEL_RESOURCE_ATTRIBUTES.trim();
175
+ if (value) env.OTEL_RESOURCE_ATTRIBUTES = value;
176
+ }
177
+ if (process.env.OTEL_EXPORTER_OTLP_PROTOCOL) {
178
+ const value = process.env.OTEL_EXPORTER_OTLP_PROTOCOL.trim().toLowerCase();
179
+ if (value === "http" || value === "grpc") env.OTEL_EXPORTER_OTLP_PROTOCOL = value;
180
+ }
181
+ if (process.env.OTEL_TRACES_SAMPLER) {
182
+ const value = process.env.OTEL_TRACES_SAMPLER.trim();
183
+ if (value) env.OTEL_TRACES_SAMPLER = value;
184
+ }
185
+ if (process.env.OTEL_TRACES_SAMPLER_ARG) {
186
+ const value = process.env.OTEL_TRACES_SAMPLER_ARG.trim();
187
+ if (value) env.OTEL_TRACES_SAMPLER_ARG = value;
188
+ }
189
+ return env;
190
+ }
191
+ function parseRatioSamplerArg(samplerName, samplerArg) {
192
+ if (samplerArg === void 0) return 1;
193
+ const ratio = Number(samplerArg);
194
+ if (!Number.isFinite(ratio) || ratio < 0 || ratio > 1) {
195
+ console.error(`[autotel] Invalid OTEL_TRACES_SAMPLER_ARG="${samplerArg}" for ${samplerName}. Expected a number in [0..1]. Falling back to 1.0.`);
196
+ return 1;
197
+ }
198
+ return ratio;
199
+ }
200
+ function warnOnUnusedSamplerArg(samplerName, samplerArg) {
201
+ if (samplerArg !== void 0) console.error(`[autotel] OTEL_TRACES_SAMPLER_ARG is not used by OTEL_TRACES_SAMPLER="${samplerName}". Ignoring value "${samplerArg}".`);
202
+ }
203
+ function createSamplerFromEnv(env) {
204
+ const samplerName = env.OTEL_TRACES_SAMPLER;
205
+ if (!samplerName) return;
206
+ switch (samplerName) {
207
+ case "always_on":
208
+ warnOnUnusedSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG);
209
+ return new _opentelemetry_sdk_trace_base.AlwaysOnSampler();
210
+ case "always_off":
211
+ warnOnUnusedSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG);
212
+ return new _opentelemetry_sdk_trace_base.AlwaysOffSampler();
213
+ case "traceidratio": return new _opentelemetry_sdk_trace_base.TraceIdRatioBasedSampler(parseRatioSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG));
214
+ case "parentbased_always_on":
215
+ warnOnUnusedSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG);
216
+ return new _opentelemetry_sdk_trace_base.ParentBasedSampler({ root: new _opentelemetry_sdk_trace_base.AlwaysOnSampler() });
217
+ case "parentbased_always_off":
218
+ warnOnUnusedSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG);
219
+ return new _opentelemetry_sdk_trace_base.ParentBasedSampler({ root: new _opentelemetry_sdk_trace_base.AlwaysOffSampler() });
220
+ case "parentbased_traceidratio": return new _opentelemetry_sdk_trace_base.ParentBasedSampler({ root: new _opentelemetry_sdk_trace_base.TraceIdRatioBasedSampler(parseRatioSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG)) });
221
+ case "jaeger_remote":
222
+ case "parentbased_jaeger_remote":
223
+ case "xray":
224
+ console.error(`[autotel] OTEL_TRACES_SAMPLER="${samplerName}" is not supported yet by autotel. Falling back to the next sampler source.`);
225
+ return;
226
+ default:
227
+ console.error(`[autotel] Unknown OTEL_TRACES_SAMPLER="${samplerName}". Falling back to the next sampler source.`);
228
+ return;
229
+ }
230
+ }
231
+ /**
232
+ * Parse OTEL_RESOURCE_ATTRIBUTES from comma-separated key=value pairs
233
+ * Example: "service.version=1.0.0,deployment.environment=production"
234
+ */
235
+ function parseResourceAttributes(input) {
236
+ if (!input || input.trim() === "") return {};
237
+ const attributes = {};
238
+ const pairs = input.split(",");
239
+ for (const pair of pairs) {
240
+ const trimmedPair = pair.trim();
241
+ if (!trimmedPair) continue;
242
+ const equalIndex = trimmedPair.indexOf("=");
243
+ if (equalIndex === -1) continue;
244
+ const key = trimmedPair.slice(0, equalIndex).trim();
245
+ const value = trimmedPair.slice(equalIndex + 1).trim();
246
+ if (key && value) attributes[key] = value;
247
+ }
248
+ return attributes;
249
+ }
250
+ /**
251
+ * Parse OTEL_EXPORTER_OTLP_HEADERS from comma-separated key=value pairs
252
+ * Example: "api-key=secret123,x-custom-header=value"
253
+ */
254
+ function parseOtlpHeaders(input) {
255
+ if (!input || input.trim() === "") return {};
256
+ const headers = {};
257
+ const pairs = input.split(",");
258
+ for (const pair of pairs) {
259
+ const trimmedPair = pair.trim();
260
+ if (!trimmedPair) continue;
261
+ const equalIndex = trimmedPair.indexOf("=");
262
+ if (equalIndex === -1) continue;
263
+ const key = trimmedPair.slice(0, equalIndex).trim();
264
+ const value = trimmedPair.slice(equalIndex + 1).trim();
265
+ if (key && value) headers[key] = value;
266
+ }
267
+ return headers;
268
+ }
269
+ /**
270
+ * Convert resolved environment variables to config
271
+ */
272
+ function envToConfig(env) {
273
+ const config = {};
274
+ if (env.OTEL_SERVICE_NAME) config.service = env.OTEL_SERVICE_NAME;
275
+ if (env.OTEL_EXPORTER_OTLP_ENDPOINT) config.endpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT;
276
+ if (env.OTEL_EXPORTER_OTLP_PROTOCOL) config.protocol = env.OTEL_EXPORTER_OTLP_PROTOCOL;
277
+ if (env.OTEL_EXPORTER_OTLP_HEADERS) config.headers = parseOtlpHeaders(env.OTEL_EXPORTER_OTLP_HEADERS);
278
+ const resourceAttrs = parseResourceAttributes(env.OTEL_RESOURCE_ATTRIBUTES);
279
+ if (Object.keys(resourceAttrs).length > 0) config.resourceAttributes = resourceAttrs;
280
+ const sampler = createSamplerFromEnv(env);
281
+ if (sampler) config.otelSampler = sampler;
282
+ return config;
283
+ }
284
+ /**
285
+ * Main function to resolve config from environment variables
286
+ */
287
+ function resolveConfigFromEnv() {
288
+ return envToConfig(resolveOtelEnv());
289
+ }
290
+
291
+ //#endregion
292
+ //#region src/devtools.ts
293
+ const defaultHost = "127.0.0.1";
294
+ const defaultPort = 4318;
295
+ function resolveDevtoolsConfig(config) {
296
+ if (!config) return {
297
+ enabled: false,
298
+ endpoint: void 0,
299
+ embedded: false,
300
+ host: defaultHost,
301
+ port: defaultPort,
302
+ verbose: false
303
+ };
304
+ if (config === true) return {
305
+ enabled: true,
306
+ endpoint: `http://${defaultHost}:${defaultPort}`,
307
+ embedded: false,
308
+ host: defaultHost,
309
+ port: defaultPort,
310
+ verbose: false
311
+ };
312
+ const enabled = config.enabled ?? true;
313
+ const host = config.host ?? defaultHost;
314
+ const port = config.port ?? defaultPort;
315
+ const endpoint = config.endpoint ?? `http://${host}:${port}`;
316
+ return {
317
+ enabled,
318
+ endpoint: enabled ? endpoint : void 0,
319
+ embedded: enabled && (config.embedded ?? false),
320
+ host,
321
+ port,
322
+ verbose: config.verbose ?? false
323
+ };
324
+ }
325
+
326
+ //#endregion
327
+ //#region src/process-handlers.ts
328
+ let removeOwnedHandlers = [];
329
+ const DEFAULT_SIGNALS = ["SIGTERM", "SIGINT"];
330
+ function signalExitCode(signal) {
331
+ return 128 + node_os.constants.signals[signal];
332
+ }
333
+ /**
334
+ * Surface a fatal error before shutting down.
335
+ *
336
+ * Registering an `uncaughtException` / `unhandledRejection` listener overrides
337
+ * Node's default of printing the stack to stderr, so without this a crash under
338
+ * `fatalErrors` would exit silently. Autotel's own logger is silent by default,
339
+ * so we print to stderr directly to guarantee the crash stays visible.
340
+ */
341
+ function reportFatalError(error, event) {
342
+ const err = error instanceof Error ? error : new Error(String(error));
343
+ console.error(`[autotel] ${event}, flushing telemetry then exiting`, err);
344
+ }
345
+ function installProcessHandlers(config, shutdown) {
346
+ uninstallProcessHandlers();
347
+ let shutdownInFlight;
348
+ const runShutdownOnce = () => {
349
+ if (shutdownInFlight) return shutdownInFlight;
350
+ const timeoutMs = config.shutdownTimeoutMs ?? 2e3;
351
+ let timeoutHandle;
352
+ const shutdownAttempt = Promise.resolve().then(shutdown).catch(() => void 0);
353
+ const timeout = new Promise((resolve) => {
354
+ timeoutHandle = setTimeout(resolve, timeoutMs);
355
+ timeoutHandle.unref();
356
+ });
357
+ shutdownInFlight = Promise.race([shutdownAttempt, timeout]).then(() => {
358
+ if (timeoutHandle) clearTimeout(timeoutHandle);
359
+ });
360
+ return shutdownInFlight;
361
+ };
362
+ let exitScheduled = false;
363
+ let resolvedExitCode = 0;
364
+ let fatalLatched = false;
365
+ const shutdownAndExit = (exitCode, fatal) => {
366
+ if (fatal) {
367
+ if (!fatalLatched) {
368
+ resolvedExitCode = exitCode;
369
+ fatalLatched = true;
370
+ }
371
+ } else if (!exitScheduled && !fatalLatched) resolvedExitCode = exitCode;
372
+ if (exitScheduled) return;
373
+ exitScheduled = true;
374
+ runShutdownOnce().then(() => {
375
+ process.exit(resolvedExitCode);
376
+ });
377
+ };
378
+ for (const signal of config.signals ?? DEFAULT_SIGNALS) {
379
+ const listener = () => {
380
+ shutdownAndExit(signalExitCode(signal), false);
381
+ };
382
+ process.on(signal, listener);
383
+ removeOwnedHandlers.push(() => {
384
+ process.removeListener(signal, listener);
385
+ });
386
+ }
387
+ if (config.fatalErrors ?? true) {
388
+ const uncaughtExceptionListener = (error) => {
389
+ reportFatalError(error, "uncaughtException");
390
+ shutdownAndExit(1, true);
391
+ };
392
+ const unhandledRejectionListener = (reason) => {
393
+ reportFatalError(reason, "unhandledRejection");
394
+ shutdownAndExit(1, true);
395
+ };
396
+ process.on("uncaughtException", uncaughtExceptionListener);
397
+ process.on("unhandledRejection", unhandledRejectionListener);
398
+ removeOwnedHandlers.push(() => {
399
+ process.removeListener("uncaughtException", uncaughtExceptionListener);
400
+ }, () => {
401
+ process.removeListener("unhandledRejection", unhandledRejectionListener);
402
+ });
403
+ }
404
+ }
405
+ function uninstallProcessHandlers() {
406
+ for (const removeHandler of removeOwnedHandlers) removeHandler();
407
+ removeOwnedHandlers = [];
408
+ }
409
+
410
+ //#endregion
411
+ //#region src/rate-limiter.ts
412
+ /**
413
+ * Token bucket rate limiter
414
+ *
415
+ * Allows bursts up to burstCapacity, then smooths to maxEventsPerSecond.
416
+ * Thread-safe for async operations.
417
+ */
418
+ var TokenBucketRateLimiter = class {
419
+ tokens;
420
+ maxTokens;
421
+ refillRate;
422
+ lastRefill;
423
+ constructor(config) {
424
+ this.maxTokens = config.burstCapacity || config.maxEventsPerSecond * 2;
425
+ this.tokens = this.maxTokens;
426
+ this.refillRate = config.maxEventsPerSecond / 1e3;
427
+ this.lastRefill = Date.now();
428
+ }
429
+ /**
430
+ * Try to consume a token (allow an event)
431
+ * Returns true if allowed, false if rate limit exceeded
432
+ */
433
+ tryConsume(count = 1) {
434
+ this.refill();
435
+ if (this.tokens >= count) {
436
+ this.tokens -= count;
437
+ return true;
438
+ }
439
+ return false;
440
+ }
441
+ /**
442
+ * Wait until a token is available (async rate limiting)
443
+ * Returns a promise that resolves when the event can be processed
444
+ */
445
+ async waitForToken(count = 1) {
446
+ this.refill();
447
+ if (this.tokens >= count) {
448
+ this.tokens -= count;
449
+ return;
450
+ }
451
+ const tokensNeeded = count - this.tokens;
452
+ const waitMs = Math.ceil(tokensNeeded / this.refillRate);
453
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
454
+ return this.waitForToken(count);
455
+ }
456
+ /**
457
+ * Refill tokens based on elapsed time
458
+ */
459
+ refill() {
460
+ const now = Date.now();
461
+ const tokensToAdd = (now - this.lastRefill) * this.refillRate;
462
+ this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
463
+ this.lastRefill = now;
464
+ }
465
+ /**
466
+ * Get current available tokens (for testing/debugging)
467
+ */
468
+ getAvailableTokens() {
469
+ this.refill();
470
+ return Math.floor(this.tokens);
471
+ }
472
+ /**
473
+ * Reset the rate limiter (for testing)
474
+ */
475
+ reset() {
476
+ this.tokens = this.maxTokens;
477
+ this.lastRefill = Date.now();
478
+ }
479
+ };
480
+
481
+ //#endregion
482
+ //#region src/trace-context.ts
483
+ /**
484
+ * AsyncLocalStorage for storing the active context with baggage
485
+ * This allows setters to update the context and have it persist
486
+ */
487
+ const contextStorage = new node_async_hooks.AsyncLocalStorage();
488
+ /**
489
+ * Get the context storage instance (for initialization in functional.ts)
490
+ */
491
+ function getContextStorage() {
492
+ return contextStorage;
493
+ }
494
+ /**
495
+ * Get the active context, checking our stored context first
496
+ * This ensures baggage setters work with OpenTelemetry's propagation
497
+ */
498
+ function getActiveContextWithBaggage() {
499
+ return contextStorage.getStore()?.value ?? _opentelemetry_api.context.active();
500
+ }
501
+ /**
502
+ * Set a value in AsyncLocalStorage, preferring enterWith() when available
503
+ * (Node.js) and falling back to run() for environments that only support
504
+ * run() (e.g. Cloudflare Workers).
505
+ *
506
+ * On runtimes without enterWith() we mutate the existing run() scope when one
507
+ * exists. This is what allows baggage/correlation updates to remain visible
508
+ * for the rest of the traced callback in Workers.
509
+ */
510
+ function enterOrRun(storage, value) {
511
+ const existingStore = storage.getStore();
512
+ if (existingStore) {
513
+ existingStore.value = value;
514
+ return;
515
+ }
516
+ const boxedValue = { value };
517
+ try {
518
+ storage.enterWith(boxedValue);
519
+ } catch {
520
+ storage.run(boxedValue, () => {});
521
+ }
522
+ }
523
+ function updateActiveContext(newContext) {
524
+ enterOrRun(contextStorage, newContext);
525
+ const manager = _opentelemetry_api.context._getContextManager?.();
526
+ if (!manager) return;
527
+ const asyncLocal = manager._asyncLocalStorage ?? void 0;
528
+ if (asyncLocal?.enterWith) {
529
+ asyncLocal.enterWith(newContext);
530
+ return;
531
+ }
532
+ if (typeof manager.with === "function") manager.with(newContext, () => {});
533
+ }
534
+ /**
535
+ * Create a TraceContext from an OpenTelemetry Span
536
+ *
537
+ * This utility extracts trace context information from a span
538
+ * and provides span manipulation methods and baggage operations in a consistent format.
539
+ *
540
+ * Note: Baggage methods always operate on the currently active context,
541
+ * which may differ from the context when createTraceContext was called.
542
+ */
543
+ function createTraceContext(span) {
544
+ const spanContext = span.spanContext();
545
+ if (!contextStorage.getStore()?.value) {
546
+ const activeContext = _opentelemetry_api.context.active();
547
+ enterOrRun(contextStorage, activeContext);
548
+ }
549
+ const traceCtx = {
550
+ traceId: spanContext.traceId,
551
+ spanId: spanContext.spanId,
552
+ correlationId: spanContext.traceId.slice(0, 16),
553
+ setAttribute: span.setAttribute.bind(span),
554
+ setAttributes: span.setAttributes.bind(span),
555
+ setStatus: span.setStatus.bind(span),
556
+ recordException: span.recordException.bind(span),
557
+ addEvent: span.addEvent.bind(span),
558
+ addLink: span.addLink.bind(span),
559
+ addLinks: span.addLinks.bind(span),
560
+ updateName: span.updateName.bind(span),
561
+ isRecording: span.isRecording.bind(span),
562
+ recordError: (error) => {
563
+ const err = error instanceof Error ? error : new Error(String(error));
564
+ require_structured_error.recordStructuredError(traceCtx, err);
565
+ },
566
+ track: (event, data) => {
567
+ track(event, data);
568
+ },
569
+ getBaggage(key) {
570
+ const activeCtx = _opentelemetry_api.context.active();
571
+ let baggage = _opentelemetry_api.propagation.getBaggage(activeCtx);
572
+ if (!baggage) {
573
+ const storedContext = contextStorage.getStore()?.value;
574
+ if (storedContext) baggage = _opentelemetry_api.propagation.getBaggage(storedContext);
575
+ }
576
+ return baggage?.getEntry(key)?.value;
577
+ },
578
+ setBaggage(key, value) {
579
+ const activeCtx = _opentelemetry_api.context.active();
580
+ const currentContext = contextStorage.getStore()?.value ?? activeCtx;
581
+ const updated = (_opentelemetry_api.propagation.getBaggage(currentContext) ?? _opentelemetry_api.propagation.createBaggage()).setEntry(key, { value });
582
+ updateActiveContext(_opentelemetry_api.propagation.setBaggage(currentContext, updated));
583
+ return value;
584
+ },
585
+ deleteBaggage(key) {
586
+ const activeCtx = _opentelemetry_api.context.active();
587
+ const currentContext = contextStorage.getStore()?.value ?? activeCtx;
588
+ const baggage = _opentelemetry_api.propagation.getBaggage(currentContext);
589
+ if (baggage) {
590
+ const updated = baggage.removeEntry(key);
591
+ updateActiveContext(_opentelemetry_api.propagation.setBaggage(currentContext, updated));
592
+ }
593
+ },
594
+ getAllBaggage() {
595
+ const activeCtx = _opentelemetry_api.context.active();
596
+ let baggage = _opentelemetry_api.propagation.getBaggage(activeCtx);
597
+ if (!baggage) {
598
+ const storedContext = contextStorage.getStore()?.value;
599
+ if (storedContext) baggage = _opentelemetry_api.propagation.getBaggage(storedContext);
600
+ }
601
+ if (!baggage) return /* @__PURE__ */ new Map();
602
+ const entries = /* @__PURE__ */ new Map();
603
+ for (const [key, entry] of baggage.getAllEntries()) entries.set(key, entry);
604
+ return entries;
605
+ },
606
+ getTypedBaggage: ((namespace) => {
607
+ const activeCtx = _opentelemetry_api.context.active();
608
+ let baggage = _opentelemetry_api.propagation.getBaggage(activeCtx);
609
+ if (!baggage) {
610
+ const storedContext = contextStorage.getStore()?.value;
611
+ if (storedContext) baggage = _opentelemetry_api.propagation.getBaggage(storedContext);
612
+ }
613
+ if (!baggage) return;
614
+ const prefix = namespace ? `${namespace}.` : "";
615
+ const result = {};
616
+ for (const [key, entry] of baggage.getAllEntries()) if (namespace && key.startsWith(prefix)) {
617
+ const fieldName = key.slice(prefix.length);
618
+ result[fieldName] = entry.value;
619
+ } else if (!namespace) result[key] = entry.value;
620
+ return Object.keys(result).length > 0 ? result : void 0;
621
+ }),
622
+ setTypedBaggage: ((namespace, value) => {
623
+ const activeCtx = _opentelemetry_api.context.active();
624
+ const currentContext = contextStorage.getStore()?.value ?? activeCtx;
625
+ let baggage = _opentelemetry_api.propagation.getBaggage(currentContext) ?? _opentelemetry_api.propagation.createBaggage();
626
+ const prefix = namespace ? `${namespace}.` : "";
627
+ for (const [key, val] of Object.entries(value)) if (val !== void 0) {
628
+ const baggageKey = `${prefix}${key}`;
629
+ baggage = baggage.setEntry(baggageKey, { value: String(val) });
630
+ }
631
+ updateActiveContext(_opentelemetry_api.propagation.setBaggage(currentContext, baggage));
632
+ })
633
+ };
634
+ return traceCtx;
635
+ }
636
+ /**
637
+ * Define a typed baggage schema for type-safe baggage operations
638
+ *
639
+ * This helper provides a type-safe API for working with baggage entries.
640
+ * The namespace parameter is optional and prefixes all keys to avoid collisions.
641
+ *
642
+ * @template T - The baggage schema type (all fields are treated as optional)
643
+ * @param namespace - Optional namespace to prefix baggage keys
644
+ *
645
+ * @example Basic usage
646
+ * ```typescript
647
+ * type TenantBaggage = { tenantId: string; region?: string };
648
+ * const tenantBaggage = defineBaggageSchema<TenantBaggage>('tenant');
649
+ *
650
+ * export const handler = trace<TenantBaggage>((ctx) => async () => {
651
+ * // Get typed baggage
652
+ * const tenant = tenantBaggage.get(ctx);
653
+ * if (tenant?.tenantId) {
654
+ * console.log('Tenant:', tenant.tenantId);
655
+ * }
656
+ *
657
+ * // Set typed baggage
658
+ * tenantBaggage.set(ctx, { tenantId: 't1', region: 'us-east-1' });
659
+ * });
660
+ * ```
661
+ *
662
+ * @example With withBaggage helper
663
+ * ```typescript
664
+ * const tenantBaggage = defineBaggageSchema<TenantBaggage>('tenant');
665
+ *
666
+ * export const handler = trace<TenantBaggage>((ctx) => async () => {
667
+ * return await tenantBaggage.with(ctx, { tenantId: 't1' }, async () => {
668
+ * // Baggage is available here and in child spans
669
+ * const tenant = tenantBaggage.get(ctx);
670
+ * });
671
+ * });
672
+ * ```
673
+ */
674
+ function defineBaggageSchema(namespace) {
675
+ return {
676
+ /**
677
+ * Get typed baggage from context
678
+ * @param ctx - Trace context
679
+ * @returns Partial baggage object or undefined if no baggage is set
680
+ */
681
+ get: (ctx) => {
682
+ if (!ctx.getTypedBaggage) return void 0;
683
+ return ctx.getTypedBaggage(namespace);
684
+ },
685
+ /**
686
+ * Set typed baggage in context
687
+ *
688
+ * Note: For proper scoping across async boundaries, use the `with` method instead
689
+ *
690
+ * @param ctx - Trace context
691
+ * @param value - Partial baggage object to set
692
+ */
693
+ set: (ctx, value) => {
694
+ if (!ctx.setTypedBaggage) return;
695
+ ctx.setTypedBaggage(namespace, value);
696
+ },
697
+ /**
698
+ * Run a function with typed baggage properly scoped
699
+ *
700
+ * This is the recommended way to set baggage as it ensures proper
701
+ * scoping across async boundaries.
702
+ *
703
+ * @param ctx - Trace context (can be omitted, will use active context)
704
+ * @param value - Partial baggage object to set
705
+ * @param fn - Function to execute with the baggage
706
+ */
707
+ with: (ctxOrValue, valueOrFn, maybeFn) => {
708
+ const value = maybeFn ? valueOrFn : ctxOrValue;
709
+ const fn = maybeFn || valueOrFn;
710
+ const prefix = namespace ? `${namespace}.` : "";
711
+ const flatBaggage = {};
712
+ for (const [key, val] of Object.entries(value)) if (val !== void 0) flatBaggage[`${prefix}${key}`] = String(val);
713
+ const currentContext = _opentelemetry_api.context.active();
714
+ let baggage = _opentelemetry_api.propagation.getBaggage(currentContext) ?? _opentelemetry_api.propagation.createBaggage();
715
+ for (const [key, val] of Object.entries(flatBaggage)) baggage = baggage.setEntry(key, { value: val });
716
+ const newContext = _opentelemetry_api.propagation.setBaggage(currentContext, baggage);
717
+ return _opentelemetry_api.context.with(newContext, fn);
718
+ }
719
+ };
720
+ }
721
+
722
+ //#endregion
723
+ //#region src/correlation-id.ts
724
+ /**
725
+ * Correlation ID utilities for event-driven observability
726
+ *
727
+ * Provides a stable join key across events, logs, and spans even when traces fragment.
728
+ * Format: 16 hex chars (64 bits), crypto-random, URL-safe.
729
+ *
730
+ * Lifecycle:
731
+ * 1. Generated at boundary root (HTTP server span, message process span, cron job span)
732
+ * 2. Reused within context (nested work shares it via AsyncLocalStorage)
733
+ * 3. Propagated via baggage (optional, default OFF to avoid header bloat)
734
+ *
735
+ * @example Basic usage
736
+ * ```typescript
737
+ * import { generateCorrelationId, getCorrelationId } from 'autotel/correlation-id';
738
+ *
739
+ * // Generate a new correlation ID
740
+ * const id = generateCorrelationId();
741
+ * // Returns: 'a1b2c3d4e5f67890'
742
+ *
743
+ * // Get current correlation ID from context
744
+ * const currentId = getCorrelationId();
745
+ * ```
746
+ */
747
+ /**
748
+ * AsyncLocalStorage for storing correlation ID
749
+ * This allows correlation IDs to persist across async boundaries
750
+ */
751
+ const correlationStorage = new node_async_hooks.AsyncLocalStorage();
752
+ /**
753
+ * Baggage key for correlation ID propagation
754
+ */
755
+ const CORRELATION_ID_BAGGAGE_KEY = "autotel.correlation_id";
756
+ /**
757
+ * Generate a new correlation ID
758
+ *
759
+ * Format: 16 hex chars (64 bits), crypto-random, URL-safe
760
+ *
761
+ * @returns A new correlation ID
762
+ *
763
+ * @example
764
+ * ```typescript
765
+ * const id = generateCorrelationId();
766
+ * // Returns: 'a1b2c3d4e5f67890'
767
+ * ```
768
+ */
769
+ function generateCorrelationId() {
770
+ const bytes = /* @__PURE__ */ new Uint8Array(8);
771
+ crypto.getRandomValues(bytes);
772
+ return [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
773
+ }
774
+ /**
775
+ * Get the current correlation ID from context
776
+ *
777
+ * Resolution order:
778
+ * 1. AsyncLocalStorage (from explicit setCorrelationId or runWithCorrelationId)
779
+ * 2. Baggage (if propagated from upstream)
780
+ * 3. Active span's trace ID (first 16 chars as fallback)
781
+ * 4. undefined (if not in any context)
782
+ *
783
+ * @returns Current correlation ID or undefined
784
+ *
785
+ * @example
786
+ * ```typescript
787
+ * const id = getCorrelationId();
788
+ * if (id) {
789
+ * console.log('Correlation ID:', id);
790
+ * }
791
+ * ```
792
+ */
793
+ function getCorrelationId() {
794
+ const storedId = correlationStorage.getStore()?.value;
795
+ if (storedId) return storedId;
796
+ const activeContext = _opentelemetry_api.context.active();
797
+ const baggageEntry = _opentelemetry_api.propagation.getBaggage(activeContext)?.getEntry(CORRELATION_ID_BAGGAGE_KEY);
798
+ if (baggageEntry?.value) return baggageEntry.value;
799
+ const span = _opentelemetry_api.trace.getActiveSpan();
800
+ if (span) return span.spanContext().traceId.slice(0, 16);
801
+ }
802
+ /**
803
+ * Get or create a correlation ID
804
+ *
805
+ * If a correlation ID exists in the current context, returns it.
806
+ * Otherwise, generates a new one.
807
+ *
808
+ * @returns Existing or new correlation ID
809
+ *
810
+ * @example
811
+ * ```typescript
812
+ * const id = getOrCreateCorrelationId();
813
+ * // Always returns a valid correlation ID
814
+ * ```
815
+ */
816
+ function getOrCreateCorrelationId() {
817
+ return getCorrelationId() ?? generateCorrelationId();
818
+ }
819
+ /**
820
+ * Run a function with a specific correlation ID in context
821
+ *
822
+ * The correlation ID will be available via getCorrelationId() throughout
823
+ * the execution of the function and any async operations it spawns.
824
+ *
825
+ * @param correlationId - Correlation ID to use
826
+ * @param fn - Function to execute
827
+ * @returns The return value of the function
828
+ *
829
+ * @example
830
+ * ```typescript
831
+ * await runWithCorrelationId('abc123', async () => {
832
+ * // getCorrelationId() returns 'abc123' here
833
+ * await processRequest();
834
+ * });
835
+ * ```
836
+ */
837
+ function runWithCorrelationId(correlationId, fn) {
838
+ return correlationStorage.run({ value: correlationId }, fn);
839
+ }
840
+ /**
841
+ * Set correlation ID in the current context (mutates context)
842
+ *
843
+ * Note: This updates the AsyncLocalStorage context. For proper scoping
844
+ * across async boundaries, prefer runWithCorrelationId() instead.
845
+ *
846
+ * @param correlationId - Correlation ID to set
847
+ *
848
+ * @example
849
+ * ```typescript
850
+ * setCorrelationId('abc123');
851
+ * // Now getCorrelationId() returns 'abc123'
852
+ * ```
853
+ */
854
+ function setCorrelationId(correlationId) {
855
+ enterOrRun(correlationStorage, correlationId);
856
+ }
857
+ /**
858
+ * Set correlation ID in baggage for propagation
859
+ *
860
+ * This adds the correlation ID to the W3C baggage header, allowing it
861
+ * to be propagated to downstream services.
862
+ *
863
+ * Note: Only use this when you explicitly want cross-service propagation.
864
+ * Default is OFF to avoid header bloat.
865
+ *
866
+ * @param correlationId - Correlation ID to propagate
867
+ * @returns New context with baggage set
868
+ *
869
+ * @example
870
+ * ```typescript
871
+ * const newContext = setCorrelationIdInBaggage('abc123');
872
+ * context.with(newContext, () => {
873
+ * // Baggage will be propagated in outgoing requests
874
+ * });
875
+ * ```
876
+ */
877
+ function setCorrelationIdInBaggage(correlationId) {
878
+ const activeContext = _opentelemetry_api.context.active();
879
+ let baggage = _opentelemetry_api.propagation.getBaggage(activeContext) ?? _opentelemetry_api.propagation.createBaggage();
880
+ baggage = baggage.setEntry(CORRELATION_ID_BAGGAGE_KEY, { value: correlationId });
881
+ return _opentelemetry_api.propagation.setBaggage(activeContext, baggage);
882
+ }
883
+ /**
884
+ * Get the correlation storage instance (for internal use in init/shutdown)
885
+ */
886
+ function getCorrelationStorage() {
887
+ return correlationStorage;
888
+ }
889
+
890
+ //#endregion
891
+ //#region src/event-queue.ts
892
+ const DEFAULT_CONFIG$2 = {
893
+ maxSize: 5e4,
894
+ batchSize: 100,
895
+ flushInterval: 1e4,
896
+ maxRetries: 3,
897
+ rateLimit: {
898
+ maxEventsPerSecond: 100,
899
+ burstCapacity: 200
900
+ }
901
+ };
902
+ /**
903
+ * Get subscriber name for metrics (stable, low-cardinality)
904
+ *
905
+ * Priority:
906
+ * 1. Explicit config: subscriber.name
907
+ * 2. Class static property (if available)
908
+ * 3. Fallback: lowercase class name without "Subscriber" suffix
909
+ */
910
+ function getSubscriberName(subscriber) {
911
+ if (subscriber.name) return subscriber.name.toLowerCase();
912
+ return (subscriber.constructor?.name || "unknown").replace(/Subscriber$/i, "").toLowerCase();
913
+ }
914
+ /**
915
+ * Events queue with batching and backpressure
916
+ *
917
+ * Features:
918
+ * - Batches events for efficient sending
919
+ * - Bounded queue with drop-oldest policy (prod) or blocking (dev)
920
+ * - Exponential backoff retry
921
+ * - Rate limiting to prevent overwhelming subscribers
922
+ * - Graceful flush on shutdown
923
+ */
924
+ var EventQueue = class {
925
+ queue = [];
926
+ flushTimer = null;
927
+ config;
928
+ subscribers;
929
+ rateLimiter;
930
+ flushPromise = null;
931
+ isShuttingDown = false;
932
+ metrics = null;
933
+ observableCleanups = [];
934
+ subscriberHealthy = /* @__PURE__ */ new Map();
935
+ constructor(subscribers, config) {
936
+ this.subscribers = subscribers;
937
+ this.config = {
938
+ ...DEFAULT_CONFIG$2,
939
+ ...config
940
+ };
941
+ this.rateLimiter = this.config.rateLimit ? new TokenBucketRateLimiter(this.config.rateLimit) : null;
942
+ for (const subscriber of subscribers) {
943
+ const name = getSubscriberName(subscriber);
944
+ this.subscriberHealthy.set(name, true);
945
+ }
946
+ this.initMetrics();
947
+ }
948
+ /**
949
+ * Initialize OTel metrics for queue observability
950
+ */
951
+ initMetrics() {
952
+ const meter = require_config.getConfig().meter;
953
+ const queueSize = meter.createObservableGauge("autotel.event_delivery.queue.size", {
954
+ description: "Current number of events in the delivery queue",
955
+ unit: "count"
956
+ });
957
+ const queueSizeCallback = (observableResult) => {
958
+ observableResult.observe(this.queue.length);
959
+ };
960
+ queueSize.addCallback(queueSizeCallback);
961
+ this.observableCleanups.push(() => queueSize.removeCallback(queueSizeCallback));
962
+ const oldestAge = meter.createObservableGauge("autotel.event_delivery.queue.oldest_age_ms", {
963
+ description: "Age of the oldest event in the queue in milliseconds",
964
+ unit: "ms"
965
+ });
966
+ const oldestAgeCallback = (observableResult) => {
967
+ if (this.queue.length > 0) {
968
+ const oldest = this.queue[0];
969
+ const ageMs = Date.now() - oldest.timestamp;
970
+ observableResult.observe(ageMs);
971
+ } else observableResult.observe(0);
972
+ };
973
+ oldestAge.addCallback(oldestAgeCallback);
974
+ this.observableCleanups.push(() => oldestAge.removeCallback(oldestAgeCallback));
975
+ const delivered = meter.createCounter("autotel.event_delivery.queue.delivered", {
976
+ description: "Number of events successfully delivered to subscribers",
977
+ unit: "count"
978
+ });
979
+ const failed = meter.createCounter("autotel.event_delivery.queue.failed", {
980
+ description: "Number of events that failed delivery after all retry attempts",
981
+ unit: "count"
982
+ });
983
+ const dropped = meter.createCounter("autotel.event_delivery.queue.dropped", {
984
+ description: "Number of events dropped from the queue",
985
+ unit: "count"
986
+ });
987
+ const latency = meter.createHistogram("autotel.event_delivery.queue.latency_ms", {
988
+ description: "Event delivery latency from enqueue to successful send",
989
+ unit: "ms"
990
+ });
991
+ const subscriberHealth = meter.createObservableGauge("autotel.event_delivery.subscriber.health", {
992
+ description: "Subscriber health status (1=healthy, 0=unhealthy)",
993
+ unit: "1"
994
+ });
995
+ const subscriberHealthCallback = (observableResult) => {
996
+ for (const [subscriberName, isHealthy] of this.subscriberHealthy) observableResult.observe(isHealthy ? 1 : 0, { subscriber: subscriberName });
997
+ };
998
+ subscriberHealth.addCallback(subscriberHealthCallback);
999
+ this.observableCleanups.push(() => subscriberHealth.removeCallback(subscriberHealthCallback));
1000
+ this.metrics = {
1001
+ queueSize,
1002
+ oldestAge,
1003
+ delivered,
1004
+ failed,
1005
+ dropped,
1006
+ latency,
1007
+ subscriberHealth
1008
+ };
1009
+ }
1010
+ /**
1011
+ * Record a dropped event with reason and emit debug breadcrumb
1012
+ */
1013
+ recordDropped(reason, event, subscriberName) {
1014
+ const attrs = { reason };
1015
+ if (subscriberName) attrs.subscriber = subscriberName;
1016
+ this.metrics?.dropped.add(1, attrs);
1017
+ const logLevel = reason === "payload_invalid" ? "error" : "warn";
1018
+ const logger = getLogger();
1019
+ if (logLevel === "error") logger.error({
1020
+ eventName: event?.name,
1021
+ subscriber: subscriberName,
1022
+ reason,
1023
+ correlationId: event?._correlationId,
1024
+ traceId: event?._traceId
1025
+ }, `[autotel] Event dropped: ${reason}`);
1026
+ else logger.warn({
1027
+ eventName: event?.name,
1028
+ subscriber: subscriberName,
1029
+ reason,
1030
+ correlationId: event?._correlationId,
1031
+ traceId: event?._traceId
1032
+ }, `[autotel] Event dropped: ${reason}`);
1033
+ }
1034
+ /**
1035
+ * Record permanent delivery failure (after all retries exhausted)
1036
+ * Increments failed counter and logs error
1037
+ */
1038
+ recordFailed(event, subscriberName, error) {
1039
+ this.metrics?.failed.add(1, { subscriber: subscriberName });
1040
+ this.subscriberHealthy.set(subscriberName, false);
1041
+ getLogger().error({
1042
+ eventName: event.name,
1043
+ subscriber: subscriberName,
1044
+ correlationId: event._correlationId,
1045
+ traceId: event._traceId,
1046
+ err: error
1047
+ }, `[autotel] Event delivery failed after all retries`);
1048
+ }
1049
+ /**
1050
+ * Mark subscriber as unhealthy on transient failure (without incrementing failed counter)
1051
+ * Used during retry attempts - only recordFailed should increment the counter
1052
+ */
1053
+ markSubscriberUnhealthy(subscriberName) {
1054
+ this.subscriberHealthy.set(subscriberName, false);
1055
+ }
1056
+ /**
1057
+ * Record successful delivery
1058
+ */
1059
+ recordDelivered(event, subscriberName, startTime) {
1060
+ const latencyMs = Date.now() - startTime;
1061
+ this.metrics?.delivered.add(1, { subscriber: subscriberName });
1062
+ this.metrics?.latency.record(latencyMs, { subscriber: subscriberName });
1063
+ this.subscriberHealthy.set(subscriberName, true);
1064
+ }
1065
+ /**
1066
+ * Enqueue an event for sending
1067
+ *
1068
+ * Backpressure policy:
1069
+ * - Drops oldest event and logs warning if queue is full (same behavior in all environments)
1070
+ */
1071
+ enqueue(event) {
1072
+ if (this.isShuttingDown) {
1073
+ this.recordDropped("shutdown", event);
1074
+ return;
1075
+ }
1076
+ if (this.queue.length >= this.config.maxSize) {
1077
+ const droppedEvent = this.queue.shift();
1078
+ this.recordDropped("rate_limit", droppedEvent);
1079
+ getLogger().warn({ droppedEvent: droppedEvent?.name }, `[autotel] Events queue full (${this.config.maxSize} events). Dropping oldest event. Events are being produced faster than they can be sent. Check your subscribers or reduce tracking frequency.`);
1080
+ }
1081
+ const enrichedEvent = {
1082
+ ...event,
1083
+ _correlationId: event._correlationId || getOrCreateCorrelationId()
1084
+ };
1085
+ this.queue.push(enrichedEvent);
1086
+ this.scheduleBatchFlush();
1087
+ }
1088
+ /**
1089
+ * Schedule a batch flush if not already scheduled
1090
+ */
1091
+ scheduleBatchFlush() {
1092
+ if (this.flushTimer || this.flushPromise) return;
1093
+ this.flushTimer = setTimeout(() => {
1094
+ this.flushTimer = null;
1095
+ this.flushBatch();
1096
+ }, this.config.flushInterval);
1097
+ }
1098
+ /**
1099
+ * Flush a batch of events
1100
+ * Uses promise-based concurrency control to prevent race conditions
1101
+ */
1102
+ async flushBatch() {
1103
+ if (this.queue.length === 0) return;
1104
+ if (this.flushPromise) {
1105
+ await this.flushPromise;
1106
+ return;
1107
+ }
1108
+ this.flushPromise = this.doFlushBatch();
1109
+ try {
1110
+ await this.flushPromise;
1111
+ } finally {
1112
+ this.flushPromise = null;
1113
+ if (this.queue.length > 0) this.scheduleBatchFlush();
1114
+ }
1115
+ }
1116
+ /**
1117
+ * Internal flush implementation
1118
+ */
1119
+ async doFlushBatch() {
1120
+ const batch = this.queue.splice(0, this.config.batchSize);
1121
+ await this.sendWithRetry(batch, this.config.maxRetries);
1122
+ }
1123
+ /**
1124
+ * Send events with exponential backoff retry
1125
+ * Tracks per-event, per-subscriber failures so failed counter reflects actual failed deliveries.
1126
+ * On retry, only failed (event, subscriber) pairs are re-sent to avoid double-counting delivered.
1127
+ */
1128
+ async sendWithRetry(events, retriesLeft, subscribersByEventIndex) {
1129
+ const failedDeliveries = await this.sendToSubscribers(events, subscribersByEventIndex);
1130
+ if (failedDeliveries.length > 0) if (retriesLeft > 0) {
1131
+ const failedEventIndicesOrdered = [...new Set(failedDeliveries.map((f) => f.eventIndex))].toSorted((a, b) => a - b);
1132
+ const eventsToRetry = failedEventIndicesOrdered.map((i) => events[i]);
1133
+ const failedSubscribersByRetryIndex = /* @__PURE__ */ new Map();
1134
+ for (const [j, origIndex] of failedEventIndicesOrdered.entries()) {
1135
+ const set = /* @__PURE__ */ new Set();
1136
+ for (const { eventIndex, subscriberName } of failedDeliveries) if (eventIndex === origIndex) set.add(subscriberName);
1137
+ failedSubscribersByRetryIndex.set(j, set);
1138
+ }
1139
+ const delay = Math.pow(2, this.config.maxRetries - retriesLeft) * 1e3;
1140
+ await new Promise((resolve) => setTimeout(resolve, delay));
1141
+ return this.sendWithRetry(eventsToRetry, retriesLeft - 1, failedSubscribersByRetryIndex);
1142
+ } else {
1143
+ for (const { eventIndex, subscriberName, error } of failedDeliveries) {
1144
+ const event = events[eventIndex];
1145
+ if (event) this.recordFailed(event, subscriberName, error);
1146
+ }
1147
+ const failedSubscriberNames = [...new Set(failedDeliveries.map((f) => f.subscriberName))];
1148
+ getLogger().error({
1149
+ failedSubscribers: failedSubscriberNames,
1150
+ retriesAttempted: this.config.maxRetries
1151
+ }, "[autotel] Failed to send events after retries");
1152
+ }
1153
+ }
1154
+ /**
1155
+ * Send events to configured subscribers with rate limiting and metrics.
1156
+ * When subscribersByEventIndex is provided (retry path), only those subscribers are tried per event.
1157
+ * Returns per-event, per-subscriber failures (empty if all succeeded).
1158
+ */
1159
+ async sendToSubscribers(events, subscribersByEventIndex) {
1160
+ const failedDeliveries = [];
1161
+ const sendOne = async (event, eventIndex) => {
1162
+ const subscriberNames = subscribersByEventIndex?.get(eventIndex);
1163
+ const failures = await this.sendEventToSubscribers(event, subscriberNames ?? void 0);
1164
+ for (const failure of failures) failedDeliveries.push({
1165
+ eventIndex,
1166
+ subscriberName: failure.subscriberName,
1167
+ error: failure.error
1168
+ });
1169
+ };
1170
+ if (!this.rateLimiter) {
1171
+ for (const [i, event] of events.entries()) if (event) await sendOne(event, i);
1172
+ return failedDeliveries;
1173
+ }
1174
+ for (const [i, event] of events.entries()) {
1175
+ await this.rateLimiter.waitForToken();
1176
+ if (event) await sendOne(event, i);
1177
+ }
1178
+ return failedDeliveries;
1179
+ }
1180
+ /**
1181
+ * Send a single event to subscribers.
1182
+ * - When subscriberNames is undefined (initial attempt): send to all subscribers.
1183
+ * - When subscriberNames is provided (retry): send only to those subscribers (never re-send to healthy ones).
1184
+ * Returns list of subscribers that failed (empty if all succeeded).
1185
+ */
1186
+ async sendEventToSubscribers(event, subscriberNames) {
1187
+ const startTime = event.timestamp;
1188
+ const failures = [];
1189
+ const subscribersToTry = subscriberNames === void 0 ? this.subscribers : this.subscribers.filter((s) => subscriberNames.has(getSubscriberName(s)));
1190
+ const results = await Promise.allSettled(subscribersToTry.map(async (subscriber) => {
1191
+ const subscriberName = getSubscriberName(subscriber);
1192
+ try {
1193
+ await subscriber.trackEvent(event.name, event.attributes, {
1194
+ autotel: event.autotel,
1195
+ schema: event.schema
1196
+ });
1197
+ this.recordDelivered(event, subscriberName, startTime);
1198
+ return {
1199
+ subscriberName,
1200
+ success: true
1201
+ };
1202
+ } catch (error) {
1203
+ this.markSubscriberUnhealthy(subscriberName);
1204
+ return {
1205
+ subscriberName,
1206
+ success: false,
1207
+ error: error instanceof Error ? error : void 0
1208
+ };
1209
+ }
1210
+ }));
1211
+ for (const result of results) if (result.status === "fulfilled" && !result.value.success) failures.push({
1212
+ subscriberName: result.value.subscriberName,
1213
+ error: result.value.error
1214
+ });
1215
+ return failures;
1216
+ }
1217
+ /**
1218
+ * Flush all remaining events. Queue remains usable after flush (e.g. for
1219
+ * auto-flush at root span end). Use shutdown() when tearing down the queue.
1220
+ */
1221
+ async flush() {
1222
+ if (this.flushTimer) {
1223
+ clearTimeout(this.flushTimer);
1224
+ this.flushTimer = null;
1225
+ }
1226
+ if (this.flushPromise) await this.flushPromise;
1227
+ while (this.queue.length > 0) await this.doFlushBatch();
1228
+ }
1229
+ /**
1230
+ * Flush remaining events and permanently disable the queue (reject new events).
1231
+ * Use for process/SDK shutdown; use flush() for periodic or span-end drain.
1232
+ */
1233
+ async shutdown() {
1234
+ this.isShuttingDown = true;
1235
+ await this.flush();
1236
+ }
1237
+ /**
1238
+ * Cleanup observable metric callbacks to prevent memory leaks
1239
+ * Call this when destroying the EventQueue instance
1240
+ */
1241
+ cleanup() {
1242
+ for (const cleanupFn of this.observableCleanups) try {
1243
+ cleanupFn();
1244
+ } catch {}
1245
+ this.observableCleanups = [];
1246
+ }
1247
+ /**
1248
+ * Get queue size (for testing/debugging)
1249
+ */
1250
+ size() {
1251
+ return this.queue.length;
1252
+ }
1253
+ /**
1254
+ * Get subscriber health status (for testing/debugging)
1255
+ */
1256
+ getSubscriberHealth() {
1257
+ return new Map(this.subscriberHealthy);
1258
+ }
1259
+ /**
1260
+ * Check if a specific subscriber is healthy
1261
+ */
1262
+ isSubscriberHealthy(subscriberName) {
1263
+ return this.subscriberHealthy.get(subscriberName.toLowerCase()) ?? true;
1264
+ }
1265
+ /**
1266
+ * Manually mark a subscriber as healthy or unhealthy
1267
+ * (used for circuit breaker integration)
1268
+ */
1269
+ setSubscriberHealth(subscriberName, healthy) {
1270
+ this.subscriberHealthy.set(subscriberName.toLowerCase(), healthy);
1271
+ }
1272
+ };
1273
+
1274
+ //#endregion
1275
+ //#region src/validation.ts
1276
+ const DEFAULT_CONFIG$1 = {
1277
+ maxEventNameLength: 100,
1278
+ maxAttributeKeyLength: 100,
1279
+ maxAttributeValueLength: 1e3,
1280
+ maxAttributeCount: 50,
1281
+ maxNestingDepth: 3,
1282
+ sensitivePatterns: [
1283
+ /password/i,
1284
+ /secret/i,
1285
+ /token/i,
1286
+ /api[_-]?key/i,
1287
+ /access[_-]?key/i,
1288
+ /private[_-]?key/i,
1289
+ /auth/i,
1290
+ /credential/i,
1291
+ /ssn/i,
1292
+ /credit[_-]?card/i
1293
+ ]
1294
+ };
1295
+ var ValidationError = class extends Error {
1296
+ constructor(message) {
1297
+ super(message);
1298
+ this.name = "ValidationError";
1299
+ }
1300
+ };
1301
+ /**
1302
+ * Validate and sanitize event name
1303
+ * Throws ValidationError if invalid
1304
+ */
1305
+ function validateEventName(eventName, config = DEFAULT_CONFIG$1) {
1306
+ if (typeof eventName !== "string") throw new ValidationError(`Event name must be a string, got ${typeof eventName}`);
1307
+ const trimmed = eventName.trim();
1308
+ if (trimmed.length === 0) throw new ValidationError("Event name cannot be empty");
1309
+ if (trimmed.length > config.maxEventNameLength) throw new ValidationError(`Event name too long (${trimmed.length} chars). Max: ${config.maxEventNameLength}`);
1310
+ if (!/^[a-zA-Z0-9._-]+$/.test(trimmed)) throw new ValidationError(`Event name contains invalid characters: "${trimmed}". Use only letters, numbers, dots, underscores, and hyphens.`);
1311
+ return trimmed;
1312
+ }
1313
+ /**
1314
+ * Validate and sanitize attributes
1315
+ * Returns sanitized attributes (sensitive data redacted)
1316
+ */
1317
+ function validateAttributes(attributes, config = DEFAULT_CONFIG$1) {
1318
+ if (attributes === void 0 || attributes === null) return;
1319
+ if (typeof attributes !== "object" || Array.isArray(attributes)) throw new ValidationError("Attributes must be an object");
1320
+ const keys = Object.keys(attributes);
1321
+ if (keys.length > config.maxAttributeCount) throw new ValidationError(`Too many attributes (${keys.length}). Max: ${config.maxAttributeCount}`);
1322
+ const sanitized = {};
1323
+ for (const key of keys) {
1324
+ if (key.length > config.maxAttributeKeyLength) throw new ValidationError(`Attribute key too long: "${key.slice(0, 20)}..." (${key.length} chars). Max: ${config.maxAttributeKeyLength}`);
1325
+ const value = attributes[key];
1326
+ if (typeof value === "string" && config.sensitivePatterns.some((pattern) => pattern.test(key))) {
1327
+ sanitized[key] = "[REDACTED]";
1328
+ continue;
1329
+ }
1330
+ sanitized[key] = sanitizeValue(value, config, 1);
1331
+ }
1332
+ return sanitized;
1333
+ }
1334
+ /**
1335
+ * Sanitize attribute value (recursive)
1336
+ */
1337
+ function sanitizeValue(value, config, depth) {
1338
+ if (depth > config.maxNestingDepth) return "[MAX_DEPTH_EXCEEDED]";
1339
+ if (value === null || value === void 0) return value;
1340
+ if (typeof value === "string") {
1341
+ if (value.length > config.maxAttributeValueLength) return value.slice(0, config.maxAttributeValueLength) + "...";
1342
+ return value;
1343
+ }
1344
+ if (typeof value === "number" || typeof value === "boolean") return value;
1345
+ if (Array.isArray(value)) return value.map((item) => sanitizeValue(item, config, depth + 1));
1346
+ if (typeof value === "object") try {
1347
+ JSON.stringify(value);
1348
+ const sanitized = {};
1349
+ for (const key in value) if (Object.prototype.hasOwnProperty.call(value, key)) {
1350
+ const nested = value[key];
1351
+ sanitized[key] = typeof nested === "string" && config.sensitivePatterns.some((pattern) => pattern.test(key)) ? "[REDACTED]" : sanitizeValue(nested, config, depth + 1);
1352
+ }
1353
+ return sanitized;
1354
+ } catch {
1355
+ return "[CIRCULAR]";
1356
+ }
1357
+ return `[${typeof value}]`;
1358
+ }
1359
+ /**
1360
+ * Validate and sanitize an events event
1361
+ * Returns { eventName, attributes } with sanitized values
1362
+ */
1363
+ function validateEvent(eventName, attributes, config) {
1364
+ const fullConfig = {
1365
+ ...DEFAULT_CONFIG$1,
1366
+ ...config
1367
+ };
1368
+ return {
1369
+ eventName: validateEventName(eventName, fullConfig),
1370
+ attributes: validateAttributes(attributes, fullConfig)
1371
+ };
1372
+ }
1373
+
1374
+ //#endregion
1375
+ //#region src/track.ts
1376
+ /**
1377
+ * Global track() function for business events
1378
+ *
1379
+ * Simple, no instantiation needed, auto-attaches trace context
1380
+ */
1381
+ let eventsQueue = null;
1382
+ /**
1383
+ * Build autotel event context for trace correlation
1384
+ *
1385
+ * Works in multiple contexts:
1386
+ * 1. Inside a span → use current span's trace_id + span_id
1387
+ * 2. Outside span → use correlation_id only
1388
+ * 3. With trace URL config → include clickable trace URL
1389
+ */
1390
+ function buildAutotelContext(span) {
1391
+ const eventsConfig = getEventsConfig();
1392
+ const config = getConfig();
1393
+ const correlationId = getOrCreateCorrelationId();
1394
+ if (!eventsConfig?.includeTraceContext) return { correlation_id: correlationId };
1395
+ const autotelContext = { correlation_id: correlationId };
1396
+ const spanContext = span?.spanContext();
1397
+ if (spanContext) {
1398
+ autotelContext.trace_id = spanContext.traceId;
1399
+ autotelContext.span_id = spanContext.spanId;
1400
+ autotelContext.trace_flags = spanContext.traceFlags.toString(16).padStart(2, "0");
1401
+ const traceState = spanContext.traceState;
1402
+ if (traceState) try {
1403
+ if (typeof traceState.serialize === "function") {
1404
+ const traceStateStr = traceState.serialize();
1405
+ if (traceStateStr) autotelContext.trace_state = traceStateStr;
1406
+ }
1407
+ } catch {}
1408
+ if (eventsConfig.traceUrl && config) {
1409
+ const traceUrl = eventsConfig.traceUrl({
1410
+ traceId: spanContext.traceId,
1411
+ spanId: spanContext.spanId,
1412
+ correlationId,
1413
+ serviceName: config.service,
1414
+ environment: config.environment
1415
+ });
1416
+ if (traceUrl) autotelContext.trace_url = traceUrl;
1417
+ }
1418
+ } else if (eventsConfig.traceUrl && config) {
1419
+ const traceUrl = eventsConfig.traceUrl({
1420
+ correlationId,
1421
+ serviceName: config.service,
1422
+ environment: config.environment
1423
+ });
1424
+ if (traceUrl) autotelContext.trace_url = traceUrl;
1425
+ }
1426
+ return autotelContext;
1427
+ }
1428
+ /**
1429
+ * Initialize events queue lazily
1430
+ */
1431
+ function getOrCreateQueue() {
1432
+ if (!isInitialized()) {
1433
+ warnIfNotInitialized("track()");
1434
+ return null;
1435
+ }
1436
+ if (!eventsQueue) {
1437
+ const config = getConfig();
1438
+ if (!config?.subscribers || config.subscribers.length === 0) return null;
1439
+ eventsQueue = new EventQueue(config.subscribers);
1440
+ }
1441
+ return eventsQueue;
1442
+ }
1443
+ /**
1444
+ * Track a business events event
1445
+ *
1446
+ * Features:
1447
+ * - Auto-attaches traceId and spanId if in active span
1448
+ * - Batched sending with retry
1449
+ * - Type-safe with optional generic
1450
+ * - No-op if init() not called or no subscribers configured
1451
+ *
1452
+ * @example Basic usage
1453
+ * ```typescript
1454
+ * track('user.signup', { userId: '123', plan: 'pro' })
1455
+ * ```
1456
+ *
1457
+ * @example With type safety
1458
+ * ```typescript
1459
+ * interface EventDatas {
1460
+ * 'user.signup': { userId: string; plan: string }
1461
+ * 'plan.upgraded': { userId: string; revenue: number }
1462
+ * }
1463
+ *
1464
+ * track<EventDatas>('user.signup', { userId: '123', plan: 'pro' })
1465
+ * ```
1466
+ *
1467
+ * @example Trace correlation (automatic)
1468
+ * ```typescript
1469
+ * @Instrumented()
1470
+ * class UserService {
1471
+ * async createUser(data: CreateUserData) {
1472
+ * // This track call automatically includes traceId + spanId
1473
+ * track('user.signup', { userId: data.id })
1474
+ * }
1475
+ * }
1476
+ * ```
1477
+ */
1478
+ function track(event, data, options) {
1479
+ const queue = getOrCreateQueue();
1480
+ if (!queue) return;
1481
+ const validated = validateEvent(event, data, getValidationConfig() || void 0);
1482
+ const span = _opentelemetry_api.trace.getActiveSpan();
1483
+ const enrichedData = span ? {
1484
+ ...validated.attributes,
1485
+ traceId: span.spanContext().traceId,
1486
+ spanId: span.spanContext().spanId
1487
+ } : validated.attributes;
1488
+ const autotelContext = buildAutotelContext(span);
1489
+ queue.enqueue({
1490
+ name: validated.eventName,
1491
+ attributes: enrichedData,
1492
+ timestamp: Date.now(),
1493
+ autotel: autotelContext,
1494
+ schema: options?.schema
1495
+ });
1496
+ }
1497
+ /**
1498
+ * Get events queue (for flush/shutdown)
1499
+ * @internal
1500
+ */
1501
+ function getEventQueue() {
1502
+ return eventsQueue;
1503
+ }
1504
+ /**
1505
+ * Reset events queue (for shutdown/cleanup)
1506
+ * @internal
1507
+ */
1508
+ function resetEventQueue() {
1509
+ eventsQueue = null;
1510
+ }
1511
+
1512
+ //#endregion
1513
+ //#region src/circuit-breaker.ts
1514
+ const DEFAULT_CONFIG = {
1515
+ failureThreshold: 5,
1516
+ resetTimeout: 3e4,
1517
+ windowSize: 6e4
1518
+ };
1519
+ const CircuitState = {
1520
+ CLOSED: "CLOSED",
1521
+ OPEN: "OPEN",
1522
+ HALF_OPEN: "HALF_OPEN"
1523
+ };
1524
+ /**
1525
+ * Circuit breaker implementation
1526
+ *
1527
+ * Tracks failures and automatically opens the circuit to prevent
1528
+ * overwhelming failing subscribers.
1529
+ */
1530
+ var CircuitBreaker = class {
1531
+ state = CircuitState.CLOSED;
1532
+ failures = [];
1533
+ lastFailureTime = 0;
1534
+ config;
1535
+ name;
1536
+ constructor(name, config) {
1537
+ this.name = name;
1538
+ this.config = {
1539
+ ...DEFAULT_CONFIG,
1540
+ ...config
1541
+ };
1542
+ }
1543
+ /**
1544
+ * Execute a function with circuit breaker protection
1545
+ * Throws CircuitOpenError if circuit is open
1546
+ */
1547
+ async execute(fn) {
1548
+ if (this.state === CircuitState.OPEN) {
1549
+ const now = Date.now();
1550
+ if (now - this.lastFailureTime >= this.config.resetTimeout) this.state = CircuitState.HALF_OPEN;
1551
+ else throw new CircuitOpenError(`Circuit breaker is OPEN for ${this.name}. Will retry in ${Math.ceil((this.config.resetTimeout - (now - this.lastFailureTime)) / 1e3)}s`);
1552
+ }
1553
+ try {
1554
+ const result = await fn();
1555
+ if (this.state === CircuitState.HALF_OPEN) this.reset();
1556
+ return result;
1557
+ } catch (error) {
1558
+ this.recordFailure(error);
1559
+ throw error;
1560
+ }
1561
+ }
1562
+ /**
1563
+ * Record a failure and potentially open the circuit
1564
+ */
1565
+ recordFailure(error) {
1566
+ const now = Date.now();
1567
+ this.failures = this.failures.filter((f) => now - f.timestamp < this.config.windowSize);
1568
+ this.failures.push({
1569
+ timestamp: now,
1570
+ error: error instanceof Error ? error.message : String(error)
1571
+ });
1572
+ this.lastFailureTime = now;
1573
+ if (this.failures.length >= this.config.failureThreshold) {
1574
+ if (this.state === CircuitState.HALF_OPEN) this.state = CircuitState.OPEN;
1575
+ else if (this.state === CircuitState.CLOSED) this.state = CircuitState.OPEN;
1576
+ }
1577
+ }
1578
+ /**
1579
+ * Reset the circuit breaker (on success)
1580
+ */
1581
+ reset() {
1582
+ this.state = CircuitState.CLOSED;
1583
+ this.failures = [];
1584
+ this.lastFailureTime = 0;
1585
+ }
1586
+ /**
1587
+ * Get current state (for monitoring)
1588
+ */
1589
+ getState() {
1590
+ return this.state;
1591
+ }
1592
+ /**
1593
+ * Get failure count in current window
1594
+ */
1595
+ getFailureCount() {
1596
+ const now = Date.now();
1597
+ this.failures = this.failures.filter((f) => now - f.timestamp < this.config.windowSize);
1598
+ return this.failures.length;
1599
+ }
1600
+ /**
1601
+ * Get recent failures (for debugging)
1602
+ */
1603
+ getRecentFailures() {
1604
+ const now = Date.now();
1605
+ return this.failures.filter((f) => now - f.timestamp < this.config.windowSize);
1606
+ }
1607
+ /**
1608
+ * Manually reset the circuit breaker (for testing or manual intervention)
1609
+ */
1610
+ forceReset() {
1611
+ this.reset();
1612
+ }
1613
+ /**
1614
+ * Manually open the circuit (for testing or manual intervention)
1615
+ */
1616
+ forceOpen() {
1617
+ this.state = CircuitState.OPEN;
1618
+ this.lastFailureTime = Date.now();
1619
+ }
1620
+ };
1621
+ /**
1622
+ * Error thrown when circuit is open
1623
+ */
1624
+ var CircuitOpenError = class extends Error {
1625
+ constructor(message) {
1626
+ super(message);
1627
+ this.name = "CircuitOpenError";
1628
+ }
1629
+ };
1630
+
1631
+ //#endregion
1632
+ //#region src/operation-context.ts
1633
+ /**
1634
+ * Operation context tracking using AsyncLocalStorage
1635
+ *
1636
+ * This module provides a way to track operation names across async boundaries
1637
+ * so they can be automatically captured in events events.
1638
+ *
1639
+ * We cannot read span attributes from OpenTelemetry's API (it's write-only),
1640
+ * so we maintain our own async context storage.
1641
+ */
1642
+ /**
1643
+ * AsyncLocalStorage instance for tracking operation context
1644
+ */
1645
+ const operationStorage = new node_async_hooks.AsyncLocalStorage();
1646
+ /**
1647
+ * Get the current operation context (if any)
1648
+ *
1649
+ * @returns The current operation context, or undefined if not in an operation
1650
+ *
1651
+ * @example
1652
+ * ```typescript
1653
+ * const ctx = getOperationContext();
1654
+ * if (ctx) {
1655
+ * console.log('Current operation:', ctx.name);
1656
+ * }
1657
+ * ```
1658
+ */
1659
+ function getOperationContext() {
1660
+ return operationStorage.getStore();
1661
+ }
1662
+ /**
1663
+ * Run a function within an operation context
1664
+ *
1665
+ * This sets the operation name for the duration of the function execution,
1666
+ * including all async operations spawned from it.
1667
+ *
1668
+ * @param name - The operation name to set
1669
+ * @param fn - The function to execute within the context
1670
+ * @returns The result of the function
1671
+ *
1672
+ * @example
1673
+ * ```typescript
1674
+ * const result = await runInOperationContext('user.create', async () => {
1675
+ * // Any events.trackEvent() calls here will automatically capture
1676
+ * // 'operation.name': 'user.create'
1677
+ * await createUser();
1678
+ * return 'success';
1679
+ * });
1680
+ * ```
1681
+ */
1682
+ function runInOperationContext(name, fn) {
1683
+ return operationStorage.run({ name }, fn);
1684
+ }
1685
+
1686
+ //#endregion
1687
+ //#region src/events-config.ts
1688
+ /**
1689
+ * Hash a string value for PII protection
1690
+ *
1691
+ * Uses a simple, fast hash function suitable for correlation.
1692
+ * NOT cryptographically secure - use for PII masking, not security.
1693
+ */
1694
+ function hashValue(value) {
1695
+ let hash = 0;
1696
+ for (let i = 0; i < value.length; i++) {
1697
+ const char = value.charCodeAt(i);
1698
+ hash = (hash << 5) - hash + char;
1699
+ hash = hash & hash;
1700
+ }
1701
+ return (hash >>> 0).toString(16).padStart(8, "0");
1702
+ }
1703
+
1704
+ //#endregion
1705
+ //#region src/event.ts
1706
+ /**
1707
+ * Events API for product events platforms
1708
+ *
1709
+ * Track user behavior, business events, and critical actions.
1710
+ * Sends to product events platforms (PostHog, Mixpanel, Amplitude) via subscribers.
1711
+ * For business people who think in events/funnels.
1712
+ *
1713
+ * For OpenTelemetry metrics (Prometheus/Grafana), use the Metrics class instead.
1714
+ *
1715
+ * @example Recommended: Configure subscribers in init(), use track() function
1716
+ * ```typescript
1717
+ * import { init, track } from 'autotel';
1718
+ * import { PostHogSubscriber } from 'autotel-subscribers/posthog';
1719
+ *
1720
+ * init({
1721
+ * service: 'my-app',
1722
+ * subscribers: [new PostHogSubscriber({ apiKey: 'phc_...' })]
1723
+ * });
1724
+ *
1725
+ * // Track events - uses subscribers from init()
1726
+ * track('application.submitted', { jobId: '123', userId: '456' });
1727
+ * ```
1728
+ *
1729
+ * @example Create Event instance (inherits subscribers from init)
1730
+ * ```typescript
1731
+ * import { Event } from 'autotel/event';
1732
+ *
1733
+ * // Uses subscribers configured in init()
1734
+ * const event = new Event('job-application');
1735
+ * event.trackEvent('application.submitted', { jobId: '123' });
1736
+ * ```
1737
+ *
1738
+ * @example Override subscribers for specific Event instance
1739
+ * ```typescript
1740
+ * import { Event } from 'autotel/event';
1741
+ * import { PostHogSubscriber } from 'autotel-subscribers/posthog';
1742
+ *
1743
+ * // Override: use different subscribers for this instance
1744
+ * const event = new Event('job-application', {
1745
+ * subscribers: [new PostHogSubscriber({ apiKey: 'phc_different_project' })]
1746
+ * });
1747
+ *
1748
+ * event.trackEvent('application.submitted', { jobId: '123' });
1749
+ * ```
1750
+ */
1751
+ var Event = class {
1752
+ serviceName;
1753
+ logger;
1754
+ collector;
1755
+ subscribers;
1756
+ hasSubscribers;
1757
+ circuitBreakers;
1758
+ /**
1759
+ * Create a new Event instance
1760
+ *
1761
+ * **Note**: Most users should use `init()` + `track()` instead of creating Event instances directly.
1762
+ *
1763
+ * **Subscriber Resolution**:
1764
+ * - If `subscribers` provided in options → uses those (instance override)
1765
+ * - If `subscribers` not provided → falls back to subscribers from `init()` (global config)
1766
+ * - If neither → no subscribers (events logged only)
1767
+ *
1768
+ * @param serviceName - Service name for identifying events
1769
+ * @param options - Optional configuration (logger, collector, subscribers)
1770
+ *
1771
+ * @example Recommended: Use track() with init()
1772
+ * ```typescript
1773
+ * import { init, track } from 'autotel';
1774
+ * import { PostHogSubscriber } from 'autotel-subscribers/posthog';
1775
+ *
1776
+ * init({
1777
+ * service: 'checkout',
1778
+ * subscribers: [new PostHogSubscriber({ apiKey: 'phc_...' })]
1779
+ * });
1780
+ *
1781
+ * track('purchase.completed', { amount: 99.99 });
1782
+ * ```
1783
+ *
1784
+ * @example Inherit subscribers from init()
1785
+ * ```typescript
1786
+ * // Uses subscribers configured in init()
1787
+ * const event = new Event('checkout');
1788
+ * event.trackEvent('purchase.completed', { amount: 99.99 });
1789
+ * ```
1790
+ *
1791
+ * @example Override subscribers for this instance
1792
+ * ```typescript
1793
+ * import { Event } from 'autotel/event';
1794
+ * import { PostHogSubscriber } from 'autotel-subscribers/posthog';
1795
+ *
1796
+ * // Override: use different subscribers for this instance only
1797
+ * const event = new Event('checkout', {
1798
+ * subscribers: [new PostHogSubscriber({ apiKey: 'phc_different_project' })]
1799
+ * });
1800
+ * ```
1801
+ */
1802
+ constructor(serviceName, options = {}) {
1803
+ this.serviceName = serviceName;
1804
+ this.logger = options.logger;
1805
+ this.collector = options.collector;
1806
+ this.subscribers = options.subscribers === void 0 ? getConfig()?.subscribers || [] : options.subscribers;
1807
+ this.hasSubscribers = this.subscribers.length > 0;
1808
+ this.circuitBreakers = /* @__PURE__ */ new Map();
1809
+ for (const subscriber of this.subscribers) {
1810
+ const subscriberName = subscriber.name || "Unknown";
1811
+ this.circuitBreakers.set(subscriber, new CircuitBreaker(subscriberName, {
1812
+ failureThreshold: 5,
1813
+ resetTimeout: 3e4,
1814
+ windowSize: 6e4
1815
+ }));
1816
+ }
1817
+ }
1818
+ /**
1819
+ * Automatically enrich attributes with all available telemetry context
1820
+ *
1821
+ * Auto-captures:
1822
+ * - Resource attributes: service.version, deployment.environment
1823
+ * - Trace context: traceId, spanId, correlationId
1824
+ * - Operation context: operation.name
1825
+ */
1826
+ enrichWithTelemetryContext(attributes = {}) {
1827
+ const enriched = {
1828
+ service: this.serviceName,
1829
+ ...attributes
1830
+ };
1831
+ const config = getConfig();
1832
+ if (config) {
1833
+ if (config.version) enriched["service.version"] = config.version;
1834
+ if (config.environment) enriched["deployment.environment"] = config.environment;
1835
+ }
1836
+ const spanContext = _opentelemetry_api.trace.getActiveSpan()?.spanContext();
1837
+ if (spanContext) {
1838
+ enriched.traceId = spanContext.traceId;
1839
+ enriched.spanId = spanContext.spanId;
1840
+ enriched.correlationId = spanContext.traceId.slice(0, 16);
1841
+ }
1842
+ const operationContext = getOperationContext();
1843
+ if (operationContext) enriched["operation.name"] = operationContext.name;
1844
+ return enriched;
1845
+ }
1846
+ /**
1847
+ * Build autotel event context for trace correlation
1848
+ *
1849
+ * Works in 4 contexts:
1850
+ * 1. Inside a span → use current span's trace_id + span_id
1851
+ * 2. Outside span but in AsyncLocalStorage context → use trace_id + correlation_id
1852
+ * 3. Totally standalone → use correlation_id + service/env/version
1853
+ * 4. Batch/fan-in (multiple linked parents) → use count + hash or full array
1854
+ *
1855
+ * @returns AutotelEventContext or undefined if trace context is disabled
1856
+ */
1857
+ buildAutotelContext() {
1858
+ const eventsConfig = getEventsConfig();
1859
+ if (!eventsConfig?.includeTraceContext) return { correlation_id: getOrCreateCorrelationId() };
1860
+ const config = getConfig();
1861
+ const spanContext = _opentelemetry_api.trace.getActiveSpan()?.spanContext();
1862
+ const correlationId = getOrCreateCorrelationId();
1863
+ const autotelContext = { correlation_id: correlationId };
1864
+ if (spanContext) {
1865
+ autotelContext.trace_id = spanContext.traceId;
1866
+ autotelContext.span_id = spanContext.spanId;
1867
+ autotelContext.trace_flags = spanContext.traceFlags.toString(16).padStart(2, "0");
1868
+ const traceState = spanContext.traceState;
1869
+ if (traceState) {
1870
+ let traceStateStr = "";
1871
+ try {
1872
+ if (typeof traceState.serialize === "function") traceStateStr = traceState.serialize();
1873
+ } catch {}
1874
+ if (traceStateStr) autotelContext.trace_state = traceStateStr;
1875
+ }
1876
+ if (eventsConfig.traceUrl) {
1877
+ const traceUrl = eventsConfig.traceUrl({
1878
+ traceId: spanContext.traceId,
1879
+ spanId: spanContext.spanId,
1880
+ correlationId,
1881
+ serviceName: config?.service || this.serviceName,
1882
+ environment: config?.environment
1883
+ });
1884
+ if (traceUrl) autotelContext.trace_url = traceUrl;
1885
+ }
1886
+ } else if (eventsConfig.traceUrl && config) {
1887
+ const traceUrl = eventsConfig.traceUrl({
1888
+ correlationId,
1889
+ serviceName: config.service,
1890
+ environment: config.environment
1891
+ });
1892
+ if (traceUrl) autotelContext.trace_url = traceUrl;
1893
+ }
1894
+ return autotelContext;
1895
+ }
1896
+ /**
1897
+ * Enrich event attributes from baggage with guardrails
1898
+ *
1899
+ * @param attributes - Current event attributes
1900
+ * @returns Enriched attributes with baggage values
1901
+ */
1902
+ enrichFromBaggage(attributes) {
1903
+ const enrichConfig = getEventsConfig()?.enrichFromBaggage;
1904
+ if (!enrichConfig) return attributes;
1905
+ const enriched = { ...attributes };
1906
+ const activeContext = _opentelemetry_api.context.active();
1907
+ const baggage = _opentelemetry_api.propagation.getBaggage(activeContext);
1908
+ if (!baggage) return enriched;
1909
+ let keyCount = 0;
1910
+ let byteCount = 0;
1911
+ const maxKeys = enrichConfig.maxKeys ?? 10;
1912
+ const maxBytes = enrichConfig.maxBytes ?? 1024;
1913
+ const prefix = enrichConfig.prefix ?? "";
1914
+ for (const [key, entry] of baggage.getAllEntries()) {
1915
+ if (!this.isBaggageKeyAllowed(key, enrichConfig)) continue;
1916
+ if (keyCount >= maxKeys) break;
1917
+ const value = entry.value;
1918
+ const transform = enrichConfig.transform?.[key];
1919
+ let transformedValue;
1920
+ if (transform === "hash") transformedValue = hashValue(value);
1921
+ else if (transform === "plain" || !transform) transformedValue = value;
1922
+ else if (typeof transform === "function") transformedValue = transform(value);
1923
+ else transformedValue = value;
1924
+ const valueBytes = new TextEncoder().encode(transformedValue).length;
1925
+ if (byteCount + valueBytes > maxBytes) continue;
1926
+ const enrichedKey = `${prefix}${key}`;
1927
+ enriched[enrichedKey] = transformedValue;
1928
+ keyCount++;
1929
+ byteCount += valueBytes;
1930
+ }
1931
+ return enriched;
1932
+ }
1933
+ /**
1934
+ * Check if a baggage key is allowed based on config
1935
+ */
1936
+ isBaggageKeyAllowed(key, config) {
1937
+ if (config.deny) {
1938
+ for (const pattern of config.deny) if (this.matchesBaggagePattern(key, pattern)) return false;
1939
+ }
1940
+ for (const pattern of config.allow) if (this.matchesBaggagePattern(key, pattern)) return true;
1941
+ return false;
1942
+ }
1943
+ /**
1944
+ * Check if a key matches a baggage pattern
1945
+ * Supports exact matches and wildcard patterns (e.g., 'tenant.*')
1946
+ */
1947
+ matchesBaggagePattern(key, pattern) {
1948
+ if (pattern.endsWith(".*")) {
1949
+ const prefix = pattern.slice(0, -2);
1950
+ return key.startsWith(prefix + ".");
1951
+ }
1952
+ return key === pattern;
1953
+ }
1954
+ /**
1955
+ * Track a business event
1956
+ *
1957
+ * Use this for tracking user actions, business events, product usage:
1958
+ * - "user.signup"
1959
+ * - "order.completed"
1960
+ * - "feature.used"
1961
+ *
1962
+ * Events are sent to configured subscribers (PostHog, Mixpanel, etc.).
1963
+ *
1964
+ * @example
1965
+ * ```typescript
1966
+ * // Track user signup
1967
+ * events.trackEvent('user.signup', {
1968
+ * userId: '123',
1969
+ * plan: 'pro'
1970
+ * })
1971
+ *
1972
+ * // Track order
1973
+ * events.trackEvent('order.completed', {
1974
+ * orderId: 'ord_123',
1975
+ * amount: 99.99
1976
+ * })
1977
+ * ```
1978
+ */
1979
+ trackEvent(eventName, attributes) {
1980
+ const validated = validateEvent(eventName, attributes, getValidationConfig() || void 0);
1981
+ const enrichedAttributes = this.enrichWithTelemetryContext(validated.attributes);
1982
+ this.logger?.info({
1983
+ event: validated.eventName,
1984
+ attributes: enrichedAttributes
1985
+ }, "Event tracked");
1986
+ this.collector?.recordEvent({
1987
+ event: validated.eventName,
1988
+ attributes: enrichedAttributes,
1989
+ service: this.serviceName,
1990
+ timestamp: Date.now()
1991
+ });
1992
+ if (this.hasSubscribers) {
1993
+ const autotelContext = this.buildAutotelContext();
1994
+ const finalAttributes = this.enrichFromBaggage(enrichedAttributes);
1995
+ this.notifySubscribers((subscriber) => subscriber.trackEvent(validated.eventName, finalAttributes, { autotel: autotelContext }));
1996
+ }
1997
+ }
1998
+ /**
1999
+ * Notify all subscribers concurrently without blocking
2000
+ * Uses circuit breakers to protect against failing subscribers
2001
+ * Uses Promise.allSettled to prevent subscriber errors from affecting other subscribers
2002
+ */
2003
+ async notifySubscribers(fn) {
2004
+ const promises = this.subscribers.map(async (subscriber) => {
2005
+ const circuitBreaker = this.circuitBreakers.get(subscriber);
2006
+ if (!circuitBreaker) return;
2007
+ try {
2008
+ await circuitBreaker.execute(() => fn(subscriber));
2009
+ } catch (error) {
2010
+ if (error instanceof CircuitOpenError) {
2011
+ getLogger().warn({ subscriberName: subscriber.name || "Unknown" }, `[Events] ${error.message}`);
2012
+ return;
2013
+ }
2014
+ getLogger().error({
2015
+ err: error instanceof Error ? error : void 0,
2016
+ subscriberName: subscriber.name || "Unknown"
2017
+ }, `[Events] Subscriber ${subscriber.name || "Unknown"} failed`);
2018
+ }
2019
+ });
2020
+ await Promise.allSettled(promises);
2021
+ }
2022
+ /**
2023
+ * Track conversion funnel steps
2024
+ *
2025
+ * Monitor where users drop off in multi-step processes.
2026
+ *
2027
+ * @example
2028
+ * ```typescript
2029
+ * // Track signup funnel
2030
+ * events.trackFunnelStep('signup', 'started', { userId: '123' })
2031
+ * events.trackFunnelStep('signup', 'email_verified', { userId: '123' })
2032
+ * events.trackFunnelStep('signup', 'completed', { userId: '123' })
2033
+ *
2034
+ * // Track checkout flow
2035
+ * events.trackFunnelStep('checkout', 'started', { cartValue: 99.99 })
2036
+ * events.trackFunnelStep('checkout', 'payment_info', { cartValue: 99.99 })
2037
+ * events.trackFunnelStep('checkout', 'completed', { cartValue: 99.99 })
2038
+ * ```
2039
+ */
2040
+ trackFunnelStep(funnelName, status, attributes) {
2041
+ const enrichedAttributes = this.enrichWithTelemetryContext(attributes);
2042
+ this.logger?.info({
2043
+ funnel: funnelName,
2044
+ status,
2045
+ attributes: enrichedAttributes
2046
+ }, "Funnel step tracked");
2047
+ this.collector?.recordFunnelStep({
2048
+ funnel: funnelName,
2049
+ status,
2050
+ attributes: enrichedAttributes,
2051
+ service: this.serviceName,
2052
+ timestamp: Date.now()
2053
+ });
2054
+ if (this.hasSubscribers) {
2055
+ const autotelContext = this.buildAutotelContext();
2056
+ const finalAttributes = this.enrichFromBaggage(enrichedAttributes);
2057
+ this.notifySubscribers((subscriber) => subscriber.trackFunnelStep(funnelName, status, finalAttributes, { autotel: autotelContext }));
2058
+ }
2059
+ }
2060
+ /**
2061
+ * Track outcomes (success/failure/partial)
2062
+ *
2063
+ * Monitor success rates of critical operations.
2064
+ *
2065
+ * @example
2066
+ * ```typescript
2067
+ * // Track email delivery
2068
+ * events.trackOutcome('email.delivery', 'success', {
2069
+ * recipientType: 'user',
2070
+ * emailType: 'welcome'
2071
+ * })
2072
+ *
2073
+ * events.trackOutcome('email.delivery', 'failure', {
2074
+ * recipientType: 'user',
2075
+ * errorCode: 'invalid_email'
2076
+ * })
2077
+ *
2078
+ * // Track payment processing
2079
+ * events.trackOutcome('payment.process', 'success', { amount: 99.99 })
2080
+ * events.trackOutcome('payment.process', 'failure', { error: 'insufficient_funds' })
2081
+ * ```
2082
+ */
2083
+ trackOutcome(operationName, status, attributes) {
2084
+ const enrichedAttributes = this.enrichWithTelemetryContext(attributes);
2085
+ this.logger?.info({
2086
+ operation: operationName,
2087
+ status,
2088
+ attributes: enrichedAttributes
2089
+ }, "Outcome tracked");
2090
+ this.collector?.recordOutcome({
2091
+ operation: operationName,
2092
+ status,
2093
+ attributes: enrichedAttributes,
2094
+ service: this.serviceName,
2095
+ timestamp: Date.now()
2096
+ });
2097
+ if (this.hasSubscribers) {
2098
+ const autotelContext = this.buildAutotelContext();
2099
+ const finalAttributes = this.enrichFromBaggage(enrichedAttributes);
2100
+ this.notifySubscribers((subscriber) => subscriber.trackOutcome(operationName, status, finalAttributes, { autotel: autotelContext }));
2101
+ }
2102
+ }
2103
+ /**
2104
+ * Track value metrics
2105
+ *
2106
+ * Record numerical values like revenue, transaction amounts,
2107
+ * item counts, processing times, engagement scores, etc.
2108
+ *
2109
+ * @example
2110
+ * ```typescript
2111
+ * // Track revenue
2112
+ * events.trackValue('order.revenue', 149.99, {
2113
+ * currency: 'USD',
2114
+ * productCategory: 'electronics'
2115
+ * })
2116
+ *
2117
+ * // Track items per cart
2118
+ * events.trackValue('cart.item_count', 5, {
2119
+ * userId: '123'
2120
+ * })
2121
+ *
2122
+ * // Track processing time
2123
+ * events.trackValue('api.response_time', 250, {
2124
+ * unit: 'ms',
2125
+ * endpoint: '/api/checkout'
2126
+ * })
2127
+ * ```
2128
+ */
2129
+ trackValue(metricName, value, attributes) {
2130
+ const enrichedAttributes = this.enrichWithTelemetryContext({
2131
+ metric: metricName,
2132
+ ...attributes
2133
+ });
2134
+ this.logger?.debug({
2135
+ metric: metricName,
2136
+ value,
2137
+ attributes: enrichedAttributes
2138
+ }, "Value tracked");
2139
+ this.collector?.recordValue({
2140
+ metric: metricName,
2141
+ value,
2142
+ attributes: enrichedAttributes,
2143
+ service: this.serviceName,
2144
+ timestamp: Date.now()
2145
+ });
2146
+ if (this.hasSubscribers) {
2147
+ const autotelContext = this.buildAutotelContext();
2148
+ const finalAttributes = this.enrichFromBaggage(enrichedAttributes);
2149
+ this.notifySubscribers((subscriber) => subscriber.trackValue(metricName, value, finalAttributes, { autotel: autotelContext }));
2150
+ }
2151
+ }
2152
+ /**
2153
+ * Flush all subscribers and wait for pending events
2154
+ *
2155
+ * Call this before shutdown to ensure all events are delivered.
2156
+ *
2157
+ * @example
2158
+ * ```typescript
2159
+ * const event =new Event('app', { subscribers: [...] });
2160
+ *
2161
+ * // Before shutdown
2162
+ * await events.flush();
2163
+ * ```
2164
+ */
2165
+ async flush() {
2166
+ if (!this.hasSubscribers) return;
2167
+ const shutdownPromises = this.subscribers.map(async (subscriber) => {
2168
+ if (subscriber.shutdown) try {
2169
+ await subscriber.shutdown();
2170
+ } catch (error) {
2171
+ getLogger().error({
2172
+ err: error instanceof Error ? error : void 0,
2173
+ subscriberName: subscriber.name || "Unknown"
2174
+ }, `[Events] Failed to shutdown subscriber ${subscriber.name || "Unknown"}`);
2175
+ }
2176
+ });
2177
+ await Promise.allSettled(shutdownPromises);
2178
+ }
2179
+ /**
2180
+ * Shutdown the Event instance and all subscribers
2181
+ *
2182
+ * Unlike `flush()`, this method:
2183
+ * - Shuts down all subscribers
2184
+ * - Prevents further event tracking (hasSubscribers becomes false)
2185
+ * - Should only be called once at application shutdown
2186
+ *
2187
+ * @example
2188
+ * ```typescript
2189
+ * // In Next.js API route with after()
2190
+ * import { after } from 'next/server';
2191
+ *
2192
+ * export async function POST(req: Request) {
2193
+ * const event = new Event('checkout', { subscribers: [...] });
2194
+ * event.trackEvent('order.completed', { orderId: '123' });
2195
+ *
2196
+ * after(async () => {
2197
+ * await event.shutdown();
2198
+ * });
2199
+ *
2200
+ * return Response.json({ success: true });
2201
+ * }
2202
+ * ```
2203
+ */
2204
+ async shutdown() {
2205
+ if (!this.hasSubscribers) return;
2206
+ await Promise.allSettled(this.subscribers.map(async (subscriber) => {
2207
+ if (subscriber.shutdown) try {
2208
+ await subscriber.shutdown();
2209
+ } catch (error) {
2210
+ getLogger().error({
2211
+ err: error instanceof Error ? error : void 0,
2212
+ subscriberName: subscriber.name || "Unknown"
2213
+ }, `[Events] Failed to shutdown subscriber ${subscriber.name || "Unknown"}`);
2214
+ }
2215
+ }));
2216
+ this.hasSubscribers = false;
2217
+ }
2218
+ /**
2219
+ * Track funnel progression with custom step names
2220
+ *
2221
+ * Unlike trackFunnelStep which uses FunnelStatus enum values,
2222
+ * this method allows any string as the step name for flexible funnel tracking.
2223
+ *
2224
+ * @param funnelName - Name of the funnel (e.g., "checkout", "onboarding")
2225
+ * @param stepName - Custom step name (e.g., "cart_viewed", "payment_entered")
2226
+ * @param stepNumber - Optional numeric position in the funnel
2227
+ * @param attributes - Optional event attributes
2228
+ *
2229
+ * @example
2230
+ * ```typescript
2231
+ * // Track custom checkout steps
2232
+ * event.trackFunnelProgression('checkout', 'cart_viewed', 1);
2233
+ * event.trackFunnelProgression('checkout', 'shipping_selected', 2);
2234
+ * event.trackFunnelProgression('checkout', 'payment_entered', 3);
2235
+ * event.trackFunnelProgression('checkout', 'order_confirmed', 4);
2236
+ * ```
2237
+ */
2238
+ trackFunnelProgression(funnelName, stepName, stepNumber, attributes) {
2239
+ const enrichedAttributes = this.enrichWithTelemetryContext(attributes);
2240
+ this.logger?.info({
2241
+ funnel: funnelName,
2242
+ stepName,
2243
+ stepNumber,
2244
+ attributes: enrichedAttributes
2245
+ }, "Funnel progression tracked");
2246
+ this.collector?.recordFunnelStep({
2247
+ funnel: funnelName,
2248
+ status: stepName,
2249
+ attributes: {
2250
+ ...enrichedAttributes,
2251
+ step_name: stepName,
2252
+ ...stepNumber === void 0 ? {} : { step_number: stepNumber }
2253
+ },
2254
+ service: this.serviceName,
2255
+ timestamp: Date.now()
2256
+ });
2257
+ if (this.hasSubscribers) {
2258
+ const autotelContext = this.buildAutotelContext();
2259
+ const finalAttributes = this.enrichFromBaggage(enrichedAttributes);
2260
+ this.notifySubscribers(async (subscriber) => {
2261
+ await (subscriber.trackFunnelProgression ? subscriber.trackFunnelProgression(funnelName, stepName, stepNumber, finalAttributes, { autotel: autotelContext }) : subscriber.trackFunnelStep(funnelName, stepName, {
2262
+ ...finalAttributes,
2263
+ step_name: stepName,
2264
+ ...stepNumber === void 0 ? {} : { step_number: stepNumber }
2265
+ }, { autotel: autotelContext }));
2266
+ });
2267
+ }
2268
+ }
2269
+ /**
2270
+ * Track multiple events in a batch
2271
+ *
2272
+ * Useful for bulk event tracking with consistent timestamps.
2273
+ * Events are sent to subscribers individually but processed together.
2274
+ *
2275
+ * @param events - Array of events to track
2276
+ *
2277
+ * @example
2278
+ * ```typescript
2279
+ * event.trackBatch([
2280
+ * { name: 'item.viewed', attributes: { itemId: '1' } },
2281
+ * { name: 'item.viewed', attributes: { itemId: '2' } },
2282
+ * { name: 'cart.updated', attributes: { itemCount: 2 } },
2283
+ * ]);
2284
+ * ```
2285
+ */
2286
+ trackBatch(events) {
2287
+ for (const event of events) {
2288
+ const filteredAttributes = event.attributes ? Object.fromEntries(Object.entries(event.attributes).filter(([, v]) => v !== void 0 && v !== null)) : void 0;
2289
+ this.trackEvent(event.name, filteredAttributes);
2290
+ }
2291
+ }
2292
+ };
2293
+ /**
2294
+ * Global events instances (singleton pattern)
2295
+ */
2296
+ const eventsInstances = /* @__PURE__ */ new Map();
2297
+ /**
2298
+ * Get or create an Events instance for a service
2299
+ *
2300
+ * @param serviceName - Service name for identifying events
2301
+ * @param logger - Optional logger
2302
+ * @returns Events instance
2303
+ *
2304
+ * @example
2305
+ * ```typescript
2306
+ * const event =getEvents('job-application')
2307
+ * events.trackEvent('application.submitted', { jobId: '123' })
2308
+ * ```
2309
+ */
2310
+ function getEvents(serviceName, logger) {
2311
+ if (!eventsInstances.has(serviceName)) eventsInstances.set(serviceName, new Event(serviceName, { logger }));
2312
+ return eventsInstances.get(serviceName);
2313
+ }
2314
+ /**
2315
+ * Reset all events instances (mainly for testing)
2316
+ */
2317
+ function resetEvents() {
2318
+ eventsInstances.clear();
2319
+ }
2320
+
2321
+ //#endregion
2322
+ //#region src/shutdown.ts
2323
+ /**
2324
+ * Graceful shutdown with flush and cleanup
2325
+ */
2326
+ /**
2327
+ * Error codes that mean "the OTLP endpoint wasn't reachable" — expected and
2328
+ * harmless when no collector is configured. Deliberately limited to
2329
+ * connection-establishment failures (refused / DNS), not post-connection
2330
+ * errors like ECONNRESET or ETIMEDOUT, which can indicate a real problem
2331
+ * talking to a configured backend and should surface.
2332
+ */
2333
+ const UNREACHABLE_ENDPOINT_CODES = /* @__PURE__ */ new Set([
2334
+ "ECONNREFUSED",
2335
+ "ENOTFOUND",
2336
+ "EAI_AGAIN"
2337
+ ]);
2338
+ function errorCode(error) {
2339
+ if (typeof error === "object" && error !== null && "code" in error) {
2340
+ const code = error.code;
2341
+ if (typeof code === "string") return code;
2342
+ }
2343
+ }
2344
+ /**
2345
+ * True when the error (or every error it wraps) is an unreachable-endpoint
2346
+ * failure. Traverses `AggregateError.errors` and the `cause` chain, since the
2347
+ * SDK often wraps the underlying network error.
2348
+ */
2349
+ function isUnreachableEndpointError(error, depth = 0) {
2350
+ if (depth > 5 || error === null || typeof error !== "object") return false;
2351
+ if (error instanceof AggregateError) return error.errors.length > 0 && error.errors.every((e) => isUnreachableEndpointError(e, depth + 1));
2352
+ const code = errorCode(error);
2353
+ if (code && UNREACHABLE_ENDPOINT_CODES.has(code)) return true;
2354
+ const cause = error.cause;
2355
+ return cause !== void 0 && cause !== error ? isUnreachableEndpointError(cause, depth + 1) : false;
2356
+ }
2357
+ /**
2358
+ * Flush all pending telemetry
2359
+ *
2360
+ * Flushes both events events and OpenTelemetry spans to their destinations.
2361
+ * Includes timeout protection to prevent hanging in serverless environments.
2362
+ *
2363
+ * Safe to call multiple times.
2364
+ *
2365
+ * @param options - Optional configuration
2366
+ * @param options.timeout - Timeout in milliseconds (default: 2000ms)
2367
+ * @param options.forShutdown - If true, permanently disables the events queue after flush (used internally by shutdown())
2368
+ *
2369
+ * @example Manual flush in serverless
2370
+ * ```typescript
2371
+ * import { flush } from 'autotel';
2372
+ *
2373
+ * export const handler = async (event) => {
2374
+ * // ... process event
2375
+ * await flush(); // Flush before function returns
2376
+ * return result;
2377
+ * };
2378
+ * ```
2379
+ *
2380
+ * @example With custom timeout
2381
+ * ```typescript
2382
+ * await flush({ timeout: 5000 }); // 5 second timeout
2383
+ * ```
2384
+ */
2385
+ async function flush(options) {
2386
+ const timeout = options?.timeout ?? 2e3;
2387
+ const forShutdown = options?.forShutdown ?? false;
2388
+ const doFlush = async () => {
2389
+ const eventsQueue = getEventQueue();
2390
+ if (eventsQueue) await (forShutdown ? eventsQueue.shutdown() : eventsQueue.flush());
2391
+ try {
2392
+ const tracerProvider = require_tracer_provider.getForceFlushableProvider(getSdk());
2393
+ if (tracerProvider) await tracerProvider.forceFlush();
2394
+ } catch {}
2395
+ };
2396
+ let timeoutHandle;
2397
+ try {
2398
+ await Promise.race([doFlush().finally(() => {
2399
+ if (timeoutHandle) clearTimeout(timeoutHandle);
2400
+ }), new Promise((_, reject) => {
2401
+ timeoutHandle = setTimeout(() => reject(/* @__PURE__ */ new Error("Flush timeout")), timeout);
2402
+ timeoutHandle.unref();
2403
+ })]);
2404
+ } catch (error) {
2405
+ if (timeoutHandle) clearTimeout(timeoutHandle);
2406
+ getLogger().error({ err: error instanceof Error ? error : new Error(String(error)) }, "[autotel] Flush error");
2407
+ throw error;
2408
+ }
2409
+ }
2410
+ /**
2411
+ * Shutdown telemetry and cleanup resources
2412
+ *
2413
+ * - Flushes all pending data
2414
+ * - Shuts down OpenTelemetry SDK
2415
+ * - Cleans up resources
2416
+ *
2417
+ * Call this before process exit.
2418
+ *
2419
+ * Always performs cleanup even if flush fails, preventing resource leaks
2420
+ * in serverless handlers or tests.
2421
+ *
2422
+ * @example Express server
2423
+ * ```typescript
2424
+ * const server = app.listen(3000)
2425
+ *
2426
+ * process.on('SIGTERM', async () => {
2427
+ * await server.close()
2428
+ * await shutdown()
2429
+ * process.exit(0)
2430
+ * })
2431
+ * ```
2432
+ */
2433
+ async function shutdown() {
2434
+ const logger = getLogger();
2435
+ let shutdownError = null;
2436
+ try {
2437
+ await flush({ forShutdown: true });
2438
+ } catch (error) {
2439
+ const err = error instanceof Error ? error : new Error(String(error));
2440
+ shutdownError = err;
2441
+ logger.error({ err }, "[autotel] Flush failed during shutdown, continuing cleanup");
2442
+ }
2443
+ try {
2444
+ const sdk = getSdk();
2445
+ if (sdk) await sdk.shutdown();
2446
+ } catch (error) {
2447
+ const err = error instanceof Error ? error : new Error(String(error));
2448
+ if (!isUnreachableEndpointError(error)) {
2449
+ if (!shutdownError) shutdownError = err;
2450
+ logger.error({ err }, "[autotel] SDK shutdown failed");
2451
+ }
2452
+ } finally {
2453
+ uninstallProcessHandlers();
2454
+ await _closeEmbeddedDevtools();
2455
+ const eventsQueue = getEventQueue();
2456
+ if (eventsQueue && typeof eventsQueue.cleanup === "function") eventsQueue.cleanup();
2457
+ resetEvents();
2458
+ require_metric.resetMetrics();
2459
+ resetEventQueue();
2460
+ }
2461
+ if (shutdownError) throw shutdownError;
2462
+ }
2463
+
2464
+ //#endregion
2465
+ //#region src/init.ts
2466
+ /**
2467
+ * Simplified initialization for autotel
2468
+ *
2469
+ * Single init() function with sensible defaults.
2470
+ * Replaces initInstrumentation() and separate events config.
2471
+ */
2472
+ /**
2473
+ * Silent logger (no-op) - used as default when user doesn't provide one.
2474
+ * Internal autotel logs are silent by default to avoid spam.
2475
+ * Users can import { autotelLogger } from 'autotel/logger' to create their own.
2476
+ */
2477
+ const silentLogger = {
2478
+ info: () => {},
2479
+ warn: () => {},
2480
+ error: () => {},
2481
+ debug: () => {}
2482
+ };
2483
+ /**
2484
+ * Adapts an Autotel Sampler to the OTel SDK Sampler interface.
2485
+ */
2486
+ function toOtelSampler(sampler) {
2487
+ return {
2488
+ shouldSample(_context, _traceId, spanName, _spanKind, _attributes, links) {
2489
+ const samplingContext = {
2490
+ operationName: spanName,
2491
+ args: [],
2492
+ links
2493
+ };
2494
+ const shouldTrace = sampler.shouldSample(samplingContext);
2495
+ const rate = sampler.sampleRate?.(samplingContext);
2496
+ return {
2497
+ decision: shouldTrace ? _opentelemetry_sdk_trace_base.SamplingDecision.RECORD_AND_SAMPLED : _opentelemetry_sdk_trace_base.SamplingDecision.NOT_RECORD,
2498
+ ...shouldTrace && rate !== void 0 && rate > 1 ? { attributes: { [require_sampling.AUTOTEL_SAMPLING_RATE]: rate } } : {}
2499
+ };
2500
+ },
2501
+ toString() {
2502
+ return `AutotelSamplerAdapter`;
2503
+ }
2504
+ };
2505
+ }
2506
+ let OTLPTraceExporterGRPC;
2507
+ let OTLPMetricExporterGRPC;
2508
+ let OTLPLogExporterGRPC;
2509
+ /**
2510
+ * Helper: Lazy-load gRPC trace exporter
2511
+ */
2512
+ function loadGRPCTraceExporter() {
2513
+ if (OTLPTraceExporterGRPC) return OTLPTraceExporterGRPC;
2514
+ try {
2515
+ OTLPTraceExporterGRPC = require_node_require.requireModule("@opentelemetry/exporter-trace-otlp-grpc").OTLPTraceExporter;
2516
+ return OTLPTraceExporterGRPC;
2517
+ } catch {
2518
+ throw new Error("gRPC trace exporter not found. Install @opentelemetry/exporter-trace-otlp-grpc");
2519
+ }
2520
+ }
2521
+ /**
2522
+ * Helper: Lazy-load gRPC metric exporter
2523
+ */
2524
+ function loadGRPCMetricExporter() {
2525
+ if (OTLPMetricExporterGRPC) return OTLPMetricExporterGRPC;
2526
+ try {
2527
+ OTLPMetricExporterGRPC = require_node_require.requireModule("@opentelemetry/exporter-metrics-otlp-grpc").OTLPMetricExporter;
2528
+ return OTLPMetricExporterGRPC;
2529
+ } catch {
2530
+ throw new Error("gRPC metric exporter not found. Install @opentelemetry/exporter-metrics-otlp-grpc");
2531
+ }
2532
+ }
2533
+ /**
2534
+ * Helper: Create trace exporter based on protocol
2535
+ */
2536
+ function createTraceExporter(protocol, config) {
2537
+ if (protocol === "grpc") return new (loadGRPCTraceExporter())(config);
2538
+ return new _opentelemetry_exporter_trace_otlp_http.OTLPTraceExporter(config);
2539
+ }
2540
+ /**
2541
+ * Helper: Create metric exporter based on protocol
2542
+ */
2543
+ function createMetricExporter(protocol, config) {
2544
+ if (protocol === "grpc") return new (loadGRPCMetricExporter())(config);
2545
+ return new _opentelemetry_exporter_metrics_otlp_http.OTLPMetricExporter(config);
2546
+ }
2547
+ /**
2548
+ * Helper: Lazy-load gRPC log exporter
2549
+ */
2550
+ function loadGRPCLogExporter() {
2551
+ if (OTLPLogExporterGRPC) return OTLPLogExporterGRPC;
2552
+ try {
2553
+ OTLPLogExporterGRPC = require_node_require.requireModule("@opentelemetry/exporter-logs-otlp-grpc").OTLPLogExporter;
2554
+ return OTLPLogExporterGRPC;
2555
+ } catch {
2556
+ throw new Error("gRPC log exporter not found. Install @opentelemetry/exporter-logs-otlp-grpc");
2557
+ }
2558
+ }
2559
+ /**
2560
+ * Helper: Create log exporter based on protocol
2561
+ */
2562
+ function createLogExporter(protocol, config) {
2563
+ if (protocol === "grpc") return new (loadGRPCLogExporter())(config);
2564
+ return new _opentelemetry_exporter_logs_otlp_http.OTLPLogExporter(config);
2565
+ }
2566
+ /**
2567
+ * Helper: Resolve protocol from config and environment
2568
+ */
2569
+ function resolveProtocol(configProtocol) {
2570
+ if (configProtocol === "grpc" || configProtocol === "http") return configProtocol;
2571
+ const envProtocol = process.env.OTEL_EXPORTER_OTLP_PROTOCOL;
2572
+ if (envProtocol === "grpc") return "grpc";
2573
+ if (envProtocol === "http/protobuf" || envProtocol === "http") return "http";
2574
+ return "http";
2575
+ }
2576
+ /**
2577
+ * Helper: Adjust endpoint URL for protocol
2578
+ * gRPC exporters don't need the /v1/traces or /v1/metrics path
2579
+ * HTTP exporters need the full path
2580
+ */
2581
+ function formatEndpointUrl(endpoint, signal, protocol) {
2582
+ if (protocol === "grpc") return endpoint.replace(/\/(v1\/)?(traces|metrics|logs)$/, "");
2583
+ if (!endpoint.endsWith(`/v1/${signal}`)) return `${endpoint}/v1/${signal}`;
2584
+ return endpoint;
2585
+ }
2586
+ let initialized = false;
2587
+ let locked = false;
2588
+ let config = null;
2589
+ let sdk = null;
2590
+ let warnedOnce = false;
2591
+ let logger = silentLogger;
2592
+ let validationConfig = null;
2593
+ let eventsConfig = null;
2594
+ let _stringRedactor = null;
2595
+ function acceptsStringRedactor(subscriber) {
2596
+ return typeof subscriber === "object" && subscriber !== null && "setStringRedactor" in subscriber && typeof subscriber.setStringRedactor === "function";
2597
+ }
2598
+ let _optionalRequire = require_node_require.safeRequire;
2599
+ let _devtoolsClose = null;
2600
+ const LOG_LEVELS = {
2601
+ debug: 0,
2602
+ info: 1,
2603
+ warn: 2,
2604
+ error: 3
2605
+ };
2606
+ /**
2607
+ * Lock the logger to prevent further `init()` calls.
2608
+ * Use this when framework plugins set up instrumentation and you want
2609
+ * to prevent accidental re-initialization from user code.
2610
+ */
2611
+ function lockLogger() {
2612
+ locked = true;
2613
+ }
2614
+ /**
2615
+ * Check if the logger has been locked.
2616
+ */
2617
+ function isLoggerLocked() {
2618
+ return locked;
2619
+ }
2620
+ function createSilentLogger() {
2621
+ return {
2622
+ info: () => {},
2623
+ warn: () => {},
2624
+ error: () => {},
2625
+ debug: () => {}
2626
+ };
2627
+ }
2628
+ function wrapLogger(base, silent, minLevel) {
2629
+ if (silent) return createSilentLogger();
2630
+ const threshold = LOG_LEVELS[minLevel];
2631
+ const wrap = (fn, level) => {
2632
+ if (LOG_LEVELS[level] < threshold) return (() => {});
2633
+ return ((...args) => fn(...args));
2634
+ };
2635
+ return {
2636
+ debug: wrap(base.debug, "debug"),
2637
+ info: wrap(base.info, "info"),
2638
+ warn: wrap(base.warn, "warn"),
2639
+ error: wrap(base.error, "error")
2640
+ };
2641
+ }
2642
+ /**
2643
+ * Resolve the effective attribute redactor. Explicit config wins (`false`
2644
+ * disables). Otherwise the `AUTOTEL_REDACT_PII` env var controls it, and as a
2645
+ * final default PII redaction is auto-enabled in production.
2646
+ */
2647
+ function resolveAttributeRedactor(explicit, environment) {
2648
+ if (explicit === false) return void 0;
2649
+ if (explicit !== void 0) return explicit;
2650
+ const flag = process.env.AUTOTEL_REDACT_PII?.trim().toLowerCase();
2651
+ if (flag) {
2652
+ if ([
2653
+ "off",
2654
+ "false",
2655
+ "0",
2656
+ "none",
2657
+ "disabled"
2658
+ ].includes(flag)) return;
2659
+ if (flag === "default" || flag === "strict" || flag === "pci-dss") return flag;
2660
+ if ([
2661
+ "on",
2662
+ "true",
2663
+ "1",
2664
+ "enabled"
2665
+ ].includes(flag)) return "default";
2666
+ }
2667
+ return environment === "production" ? "default" : void 0;
2668
+ }
2669
+ function detectEnvironmentAttributes() {
2670
+ const attrs = {};
2671
+ const commitSha = process.env.COMMIT_SHA || process.env.GITHUB_SHA || process.env.VERCEL_GIT_COMMIT_SHA || process.env.CF_PAGES_COMMIT_SHA || process.env.AWS_CODEPIPELINE_EXECUTION_ID;
2672
+ if (commitSha) attrs["service.commit.sha"] = commitSha;
2673
+ const region = process.env.VERCEL_REGION || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || process.env.FLY_REGION || process.env.CF_REGION || process.env.GOOGLE_CLOUD_REGION;
2674
+ if (region) attrs["service.region"] = region;
2675
+ const version = process.env.APP_VERSION || process.env.HEROKU_RELEASE_VERSION || process.env.VERCEL_GIT_COMMIT_REF;
2676
+ if (version) attrs["service.deploy.version"] = version;
2677
+ return attrs;
2678
+ }
2679
+ /**
2680
+ * Resolve metrics flag with env var override support
2681
+ */
2682
+ function resolveMetricsFlag(configFlag = "auto") {
2683
+ const envFlag = process.env.AUTOTEL_METRICS;
2684
+ if (envFlag === "on" || envFlag === "true") return true;
2685
+ if (envFlag === "off" || envFlag === "false") return false;
2686
+ if (configFlag === true) return true;
2687
+ if (configFlag === false) return false;
2688
+ return true;
2689
+ }
2690
+ /**
2691
+ * Resolve logs flag with env var override support.
2692
+ * Defaults to disabled (opt-in only) to avoid unexpected log export
2693
+ * and to preserve the upstream SDK's OTEL_LOGS_EXPORTER handling.
2694
+ */
2695
+ function resolveLogsFlag(configFlag = "auto") {
2696
+ const envFlag = process.env.AUTOTEL_LOGS;
2697
+ if (envFlag === "on" || envFlag === "true") return true;
2698
+ if (envFlag === "off" || envFlag === "false") return false;
2699
+ if (configFlag === true) return true;
2700
+ if (configFlag === false) return false;
2701
+ return false;
2702
+ }
2703
+ /**
2704
+ * Resolve debug flag with env var override support
2705
+ *
2706
+ * Supports:
2707
+ * - `'pretty'`: Colorized, hierarchical output (PrettyConsoleExporter)
2708
+ * - `true` / `'true'` / `'1'`: Raw JSON output (ConsoleSpanExporter)
2709
+ * - `false` / `'false'` / `'0'`: Disabled
2710
+ */
2711
+ function resolveDebugFlag(configFlag) {
2712
+ const envFlag = process.env.AUTOTEL_DEBUG;
2713
+ if (envFlag === "pretty") return "pretty";
2714
+ if (envFlag === "true" || envFlag === "1") return true;
2715
+ if (envFlag === "false" || envFlag === "0") return false;
2716
+ return configFlag ?? false;
2717
+ }
2718
+ function normalizeOtlpHeaders(headers) {
2719
+ if (!headers) return void 0;
2720
+ if (typeof headers !== "string") return headers;
2721
+ const parsed = {};
2722
+ for (const pair of headers.split(",")) {
2723
+ const [key, ...valueParts] = pair.split("=");
2724
+ if (!key || valueParts.length === 0) continue;
2725
+ parsed[key.trim()] = valueParts.join("=").trim();
2726
+ }
2727
+ return parsed;
2728
+ }
2729
+ function resolveOtlpDestinations(config, fallbackEndpoint) {
2730
+ return (config.destinations === void 0 ? fallbackEndpoint ? [{
2731
+ endpoint: fallbackEndpoint,
2732
+ headers: config.headers,
2733
+ protocol: config.protocol
2734
+ }] : [] : config.destinations).map((destination) => ({
2735
+ endpoint: destination.endpoint,
2736
+ protocol: resolveProtocol(destination.protocol ?? config.protocol),
2737
+ headers: normalizeOtlpHeaders(destination.headers ?? config.headers),
2738
+ signals: destination.signals ? new Set(destination.signals) : void 0
2739
+ }));
2740
+ }
2741
+ function destinationSupportsSignal(destination, signal) {
2742
+ return destination.signals ? destination.signals.has(signal) : true;
2743
+ }
2744
+ /**
2745
+ * Initialize autotel - Write Once, Observe Everywhere
2746
+ *
2747
+ * Follows OpenTelemetry standards: opinionated defaults with full flexibility
2748
+ * Idempotent: multiple calls are safe, last one wins
2749
+ *
2750
+ * @example Minimal setup (OTLP default)
2751
+ * ```typescript
2752
+ * init({ service: 'my-app' })
2753
+ * ```
2754
+ *
2755
+ * @example With events (observe in PostHog, Mixpanel, etc.)
2756
+ * ```typescript
2757
+ * import { PostHogSubscriber } from 'autotel-subscribers/posthog';
2758
+ *
2759
+ * init({
2760
+ * service: 'my-app',
2761
+ * subscribers: [new PostHogSubscriber({ apiKey: '...' })]
2762
+ * })
2763
+ * ```
2764
+ *
2765
+ * @example Observe in Jaeger
2766
+ * ```typescript
2767
+ * import { JaegerExporter } from '@opentelemetry/exporter-jaeger'
2768
+ *
2769
+ * init({
2770
+ * service: 'my-app',
2771
+ * spanExporter: new JaegerExporter({ endpoint: 'http://localhost:14268/api/traces' })
2772
+ * })
2773
+ * ```
2774
+ *
2775
+ * @example Observe in Zipkin
2776
+ * ```typescript
2777
+ * import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'
2778
+ *
2779
+ * init({
2780
+ * service: 'my-app',
2781
+ * spanExporter: new ZipkinExporter({ url: 'http://localhost:9411/api/v2/spans' })
2782
+ * })
2783
+ * ```
2784
+ *
2785
+ * @example Observe in Datadog
2786
+ * ```typescript
2787
+ * import { DatadogSpanProcessor } from '@opentelemetry/exporter-datadog'
2788
+ *
2789
+ * init({
2790
+ * service: 'my-app',
2791
+ * spanProcessor: new DatadogSpanProcessor({ ... })
2792
+ * })
2793
+ * ```
2794
+ *
2795
+ * @example Console output (dev)
2796
+ * ```typescript
2797
+ * import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
2798
+ *
2799
+ * init({
2800
+ * service: 'my-app',
2801
+ * spanProcessor: new SimpleSpanProcessor(new ConsoleSpanExporter())
2802
+ * })
2803
+ * ```
2804
+ */
2805
+ function init(cfg) {
2806
+ if (locked) return;
2807
+ const envConfig = resolveConfigFromEnv();
2808
+ const yamlConfig = require_yaml_config.loadYamlConfig() ?? {};
2809
+ const mergedConfig = {
2810
+ ...envConfig,
2811
+ ...yamlConfig,
2812
+ ...cfg,
2813
+ resourceAttributes: {
2814
+ ...envConfig.resourceAttributes,
2815
+ ...yamlConfig.resourceAttributes,
2816
+ ...detectEnvironmentAttributes(),
2817
+ ...cfg.resourceAttributes
2818
+ },
2819
+ headers: cfg.headers ?? yamlConfig.headers ?? envConfig.headers
2820
+ };
2821
+ const resolvedRedactor = resolveAttributeRedactor(mergedConfig.attributeRedactor, mergedConfig.environment || process.env.NODE_ENV || "development");
2822
+ if (resolvedRedactor === void 0) mergedConfig.attributeRedactor = void 0;
2823
+ else {
2824
+ const normalizedRedactor = require_attribute_redacting_processor.normalizeAttributeRedactorConfig(resolvedRedactor);
2825
+ if (!normalizedRedactor) throw new Error("Invalid attributeRedactor config");
2826
+ mergedConfig.attributeRedactor = normalizedRedactor;
2827
+ }
2828
+ const devtoolsConfig = resolveDevtoolsConfig(mergedConfig.devtools);
2829
+ if (devtoolsConfig.enabled && mergedConfig.logs === void 0) mergedConfig.logs = true;
2830
+ const silent = mergedConfig.silent ?? false;
2831
+ const minLevel = mergedConfig.minLevel ?? "info";
2832
+ logger = wrapLogger(mergedConfig.logger || silentLogger, silent, minLevel);
2833
+ if (initialized) logger.warn({}, "[autotel] init() called again - last config wins. This may cause unexpected behavior.");
2834
+ config = mergedConfig;
2835
+ validationConfig = mergedConfig.validation || null;
2836
+ eventsConfig = mergedConfig.events || null;
2837
+ let endpoint = mergedConfig.endpoint ?? devtoolsConfig.endpoint;
2838
+ const version = mergedConfig.version || detectVersion();
2839
+ const environment = mergedConfig.environment || process.env.NODE_ENV || "development";
2840
+ const metricsEnabled = resolveMetricsFlag(mergedConfig.metrics);
2841
+ const logsEnabled = resolveLogsFlag(mergedConfig.logs);
2842
+ if (devtoolsConfig.enabled && devtoolsConfig.embedded) {
2843
+ const devtoolsModule = _optionalRequire("autotel-devtools");
2844
+ if (devtoolsModule?.createDevtools) {
2845
+ const devtoolsInstance = devtoolsModule.createDevtools({
2846
+ port: devtoolsConfig.port,
2847
+ host: devtoolsConfig.host,
2848
+ verbose: devtoolsConfig.verbose
2849
+ });
2850
+ _devtoolsClose = devtoolsInstance.close;
2851
+ endpoint = `http://${devtoolsConfig.host}:${devtoolsInstance.port}`;
2852
+ logger.info({}, `[autotel] autotel-devtools embedded server started at ${endpoint}`);
2853
+ } else logger.warn({}, "[autotel] devtools.embedded requested but autotel-devtools is not installed. Falling back to endpoint-only mode.");
2854
+ }
2855
+ const hostname = detectHostname();
2856
+ let resource = (0, _opentelemetry_resources.resourceFromAttributes)({
2857
+ [_opentelemetry_semantic_conventions.ATTR_SERVICE_NAME]: mergedConfig.service,
2858
+ [_opentelemetry_semantic_conventions.ATTR_SERVICE_VERSION]: version,
2859
+ "deployment.environment": environment,
2860
+ "deployment.environment.name": environment
2861
+ });
2862
+ if (hostname) resource = resource.merge((0, _opentelemetry_resources.resourceFromAttributes)({
2863
+ "host.name": hostname,
2864
+ "datadog.host.name": hostname
2865
+ }));
2866
+ if (mergedConfig.resource) resource = resource.merge(mergedConfig.resource);
2867
+ if (mergedConfig.resourceAttributes) resource = resource.merge((0, _opentelemetry_resources.resourceFromAttributes)(mergedConfig.resourceAttributes));
2868
+ const otlpDestinations = resolveOtlpDestinations(mergedConfig, endpoint);
2869
+ const configuredSpanProcessors = mergedConfig.spanProcessors && mergedConfig.spanProcessors.length > 0 ? mergedConfig.spanProcessors : mergedConfig.spanProcessor ? [mergedConfig.spanProcessor] : void 0;
2870
+ const configuredSpanExporters = mergedConfig.spanExporters && mergedConfig.spanExporters.length > 0 ? mergedConfig.spanExporters : mergedConfig.spanExporter ? [mergedConfig.spanExporter] : void 0;
2871
+ const configuredMetricReaders = mergedConfig.metricReaders && mergedConfig.metricReaders.length > 0 ? mergedConfig.metricReaders : mergedConfig.metricReader ? [mergedConfig.metricReader] : void 0;
2872
+ const configuredLogRecordProcessors = mergedConfig.logRecordProcessors && mergedConfig.logRecordProcessors.length > 0 ? mergedConfig.logRecordProcessors : mergedConfig.logRecordProcessor ? [mergedConfig.logRecordProcessor] : void 0;
2873
+ let spanProcessors = [];
2874
+ if (configuredSpanProcessors && configuredSpanProcessors.length > 0) spanProcessors.push(...configuredSpanProcessors);
2875
+ else if (configuredSpanExporters && configuredSpanExporters.length > 0) for (const exporter of configuredSpanExporters) spanProcessors.push(new require_tail_sampling_processor.TailSamplingSpanProcessor(new _opentelemetry_sdk_trace_base.BatchSpanProcessor(exporter)));
2876
+ else for (const destination of otlpDestinations) {
2877
+ if (!destinationSupportsSignal(destination, "traces")) continue;
2878
+ const traceExporter = createTraceExporter(destination.protocol, {
2879
+ url: formatEndpointUrl(destination.endpoint, "traces", destination.protocol),
2880
+ headers: destination.headers
2881
+ });
2882
+ spanProcessors.push(new require_tail_sampling_processor.TailSamplingSpanProcessor(new _opentelemetry_sdk_trace_base.BatchSpanProcessor(traceExporter)));
2883
+ }
2884
+ if (mergedConfig.baggage) {
2885
+ const prefix = typeof mergedConfig.baggage === "string" ? mergedConfig.baggage ? `${mergedConfig.baggage}.` : "" : "baggage.";
2886
+ spanProcessors.push(new BaggageSpanProcessor({ prefix }));
2887
+ }
2888
+ const debugMode = resolveDebugFlag(mergedConfig.debug);
2889
+ if (debugMode === "pretty") spanProcessors.push(new _opentelemetry_sdk_trace_base.SimpleSpanProcessor(new require_pretty_console_exporter.PrettyConsoleExporter()));
2890
+ else if (debugMode === true) spanProcessors.push(new _opentelemetry_sdk_trace_base.SimpleSpanProcessor(new _opentelemetry_sdk_trace_base.ConsoleSpanExporter()));
2891
+ if (mergedConfig.canonicalLogLines?.enabled) {
2892
+ const canonicalOptions = {
2893
+ logger: mergedConfig.canonicalLogLines.logger || mergedConfig.logger,
2894
+ rootSpansOnly: mergedConfig.canonicalLogLines.rootSpansOnly,
2895
+ minLevel: mergedConfig.canonicalLogLines.minLevel,
2896
+ messageFormat: mergedConfig.canonicalLogLines.messageFormat,
2897
+ includeResourceAttributes: mergedConfig.canonicalLogLines.includeResourceAttributes,
2898
+ shouldEmit: mergedConfig.canonicalLogLines.shouldEmit,
2899
+ keep: mergedConfig.canonicalLogLines.keep,
2900
+ drain: mergedConfig.canonicalLogLines.drain,
2901
+ onDrainError: mergedConfig.canonicalLogLines.onDrainError,
2902
+ pretty: mergedConfig.canonicalLogLines.pretty
2903
+ };
2904
+ spanProcessors.push(new require_canonical_log_line_processor.CanonicalLogLineProcessor(canonicalOptions));
2905
+ }
2906
+ if (mergedConfig.attributeRedactor && spanProcessors.length > 0) {
2907
+ const redactor = mergedConfig.attributeRedactor;
2908
+ spanProcessors = spanProcessors.map((processor) => new require_attribute_redacting_processor.AttributeRedactingProcessor(processor, { redactor }));
2909
+ }
2910
+ if (mergedConfig.attributeRedactor) _stringRedactor = createStringRedactor(mergedConfig.attributeRedactor);
2911
+ if (_stringRedactor && mergedConfig.subscribers) {
2912
+ for (const subscriber of mergedConfig.subscribers) if (acceptsStringRedactor(subscriber)) subscriber.setStringRedactor(_stringRedactor);
2913
+ }
2914
+ if (mergedConfig.spanNameNormalizer && spanProcessors.length > 0) spanProcessors = spanProcessors.map((processor) => new require_span_name_normalizer.SpanNameNormalizingProcessor(processor, { normalizer: mergedConfig.spanNameNormalizer }));
2915
+ if (mergedConfig.spanFilter && spanProcessors.length > 0) spanProcessors = spanProcessors.map((processor) => new require_filtering_span_processor.FilteringSpanProcessor(processor, { filter: mergedConfig.spanFilter }));
2916
+ const metricReaders = [];
2917
+ if (configuredMetricReaders && configuredMetricReaders.length > 0) metricReaders.push(...configuredMetricReaders);
2918
+ else if (metricsEnabled) for (const destination of otlpDestinations) {
2919
+ if (!destinationSupportsSignal(destination, "metrics")) continue;
2920
+ const metricExporter = createMetricExporter(destination.protocol, {
2921
+ url: formatEndpointUrl(destination.endpoint, "metrics", destination.protocol),
2922
+ headers: destination.headers
2923
+ });
2924
+ metricReaders.push(new _opentelemetry_sdk_metrics.PeriodicExportingMetricReader({ exporter: metricExporter }));
2925
+ }
2926
+ let logRecordProcessors;
2927
+ if (configuredLogRecordProcessors && configuredLogRecordProcessors.length > 0) logRecordProcessors = [...configuredLogRecordProcessors];
2928
+ if (logsEnabled) {
2929
+ for (const destination of otlpDestinations) {
2930
+ if (!destinationSupportsSignal(destination, "logs")) continue;
2931
+ let processor = new _opentelemetry_sdk_logs.BatchLogRecordProcessor({ exporter: createLogExporter(destination.protocol, {
2932
+ url: formatEndpointUrl(destination.endpoint, "logs", destination.protocol),
2933
+ headers: destination.headers
2934
+ }) });
2935
+ if (_stringRedactor) processor = new RedactingLogRecordProcessor(processor, _stringRedactor);
2936
+ if (!logRecordProcessors) logRecordProcessors = [];
2937
+ logRecordProcessors.push(processor);
2938
+ }
2939
+ if (otlpDestinations.some((destination) => destinationSupportsSignal(destination, "logs"))) logger.info({}, "[autotel] OTLP log exporter configured");
2940
+ }
2941
+ const posthogProcessors = buildPostHogLogProcessors(mergedConfig.posthog, _stringRedactor);
2942
+ if (posthogProcessors.length > 0) {
2943
+ if (!logRecordProcessors) logRecordProcessors = [];
2944
+ logRecordProcessors.push(...posthogProcessors);
2945
+ logger.info({}, "[autotel] PostHog OTLP logs configured");
2946
+ }
2947
+ let finalInstrumentations = mergedConfig.instrumentations ? [...mergedConfig.instrumentations] : [];
2948
+ if (mergedConfig.autoInstrumentations !== void 0 && mergedConfig.autoInstrumentations !== false) {
2949
+ if (isESMMode()) logger.info({}, "[autotel] ESM mode detected. For auto-instrumentation to work:\n 1. Install @opentelemetry/auto-instrumentations-node as a direct dependency\n 2. Import autotel/register FIRST in your instrumentation file\n 3. Use getNodeAutoInstrumentations() directly instead of autoInstrumentations\n See: https://github.com/jagreehal/autotel#esm-setup");
2950
+ try {
2951
+ const manualInstrumentationNames = getInstrumentationNames(mergedConfig.instrumentations ?? []);
2952
+ if (manualInstrumentationNames.size > 0) {
2953
+ const manualNames = [...manualInstrumentationNames].join(", ");
2954
+ logger.info({}, `[autotel] Detected manual instrumentations (${manualNames}). These will take precedence over auto-instrumentations. Tip: Set autoInstrumentations:false if you want full manual control, or remove manual configs to use auto-instrumentations.`);
2955
+ }
2956
+ const autoInstrumentations = getAutoInstrumentations(mergedConfig.autoInstrumentations, manualInstrumentationNames);
2957
+ if (autoInstrumentations && autoInstrumentations.length > 0) finalInstrumentations = [...finalInstrumentations, ...autoInstrumentations];
2958
+ } catch (error) {
2959
+ logger.warn({}, `[autotel] Failed to configure auto-instrumentations: ${error instanceof Error ? error.message : String(error)}`);
2960
+ }
2961
+ }
2962
+ const autotelSampler = mergedConfig.sampler ?? (mergedConfig.sampling ? require_sampling.resolveSamplingPreset(mergedConfig.sampling) : void 0);
2963
+ if (autotelSampler) mergedConfig.sampler = autotelSampler;
2964
+ const sampler = autotelSampler ? toOtelSampler(autotelSampler) : envConfig.otelSampler ?? toOtelSampler(require_sampling.samplingPresets.production());
2965
+ const sdkOptions = {
2966
+ resource,
2967
+ serviceName: mergedConfig.service,
2968
+ sampler,
2969
+ instrumentations: finalInstrumentations
2970
+ };
2971
+ if (spanProcessors.length > 0) sdkOptions.spanProcessors = spanProcessors;
2972
+ if (metricReaders.length > 0) sdkOptions.metricReaders = metricReaders;
2973
+ if (logRecordProcessors && logRecordProcessors.length > 0) sdkOptions.logRecordProcessors = logRecordProcessors;
2974
+ sdk = mergedConfig.sdkFactory ? mergedConfig.sdkFactory(sdkOptions) : new _opentelemetry_sdk_node.NodeSDK(sdkOptions);
2975
+ if (!sdk) throw new Error("[autotel] sdkFactory must return a NodeSDK instance");
2976
+ sdk.start();
2977
+ if (mergedConfig.openllmetry?.enabled) {
2978
+ const traceloop = _optionalRequire("@traceloop/node-server-sdk");
2979
+ if (traceloop) {
2980
+ const initOptions = { ...mergedConfig.openllmetry.options };
2981
+ try {
2982
+ initOptions.tracerProvider = sdk.getTracerProvider();
2983
+ } catch {}
2984
+ if (configuredSpanExporters?.[0]) initOptions.exporter = configuredSpanExporters[0];
2985
+ if (typeof traceloop.initialize === "function") {
2986
+ traceloop.initialize(initOptions);
2987
+ logger.info({}, "[autotel] OpenLLMetry initialized successfully");
2988
+ } else logger.warn({}, "[autotel] OpenLLMetry initialize function not found. Check @traceloop/node-server-sdk version.");
2989
+ } else logger.warn({}, "[autotel] OpenLLMetry enabled but @traceloop/node-server-sdk is not installed. Install it as a peer dependency to use OpenLLMetry integration.");
2990
+ }
2991
+ initialized = true;
2992
+ const processHandlers = mergedConfig.processHandlers;
2993
+ if (processHandlers) installProcessHandlers(processHandlers === true ? {} : processHandlers, shutdown);
2994
+ else uninstallProcessHandlers();
2995
+ }
2996
+ /**
2997
+ * Extract instrumentation class names from instrumentation instances
2998
+ * Used to detect duplicates between manual and auto instrumentations
2999
+ */
3000
+ function getInstrumentationNames(instrumentations) {
3001
+ const names = /* @__PURE__ */ new Set();
3002
+ if (!instrumentations) return names;
3003
+ for (const instrumentation of instrumentations) if (instrumentation && typeof instrumentation === "object") names.add(instrumentation.constructor.name);
3004
+ return names;
3005
+ }
3006
+ /**
3007
+ * Map common instrumentation class names to their package names
3008
+ * Used to disable auto-instrumentations when user provides manual configs
3009
+ */
3010
+ const INSTRUMENTATION_CLASS_TO_PACKAGE = {
3011
+ HttpInstrumentation: "@opentelemetry/instrumentation-http",
3012
+ HttpsInstrumentation: "@opentelemetry/instrumentation-http",
3013
+ ExpressInstrumentation: "@opentelemetry/instrumentation-express",
3014
+ FastifyInstrumentation: "@opentelemetry/instrumentation-fastify",
3015
+ MongoDBInstrumentation: "@opentelemetry/instrumentation-mongodb",
3016
+ MongooseInstrumentation: "@opentelemetry/instrumentation-mongoose",
3017
+ PrismaInstrumentation: "@opentelemetry/instrumentation-prisma",
3018
+ PinoInstrumentation: "@opentelemetry/instrumentation-pino",
3019
+ WinstonInstrumentation: "@opentelemetry/instrumentation-winston",
3020
+ RedisInstrumentation: "@opentelemetry/instrumentation-redis",
3021
+ GraphQLInstrumentation: "@opentelemetry/instrumentation-graphql",
3022
+ GrpcInstrumentation: "@opentelemetry/instrumentation-grpc",
3023
+ IORedisInstrumentation: "@opentelemetry/instrumentation-ioredis",
3024
+ KnexInstrumentation: "@opentelemetry/instrumentation-knex",
3025
+ NestJsInstrumentation: "@opentelemetry/instrumentation-nestjs-core",
3026
+ PgInstrumentation: "@opentelemetry/instrumentation-pg",
3027
+ MySQLInstrumentation: "@opentelemetry/instrumentation-mysql",
3028
+ MySQL2Instrumentation: "@opentelemetry/instrumentation-mysql2"
3029
+ };
3030
+ /**
3031
+ * Detect if we're running in ESM mode
3032
+ */
3033
+ function isESMMode() {
3034
+ try {
3035
+ const fs = require_node_require.requireModule("node:fs");
3036
+ try {
3037
+ return JSON.parse(fs.readFileSync(`${process.cwd()}/package.json`, "utf8")).type === "module";
3038
+ } catch {
3039
+ return false;
3040
+ }
3041
+ } catch {
3042
+ return false;
3043
+ }
3044
+ }
3045
+ /**
3046
+ * Lazy-load auto-instrumentations (optional peer dependency)
3047
+ * Only loads when integrations config is truthy, avoiding ~40+ package imports at startup.
3048
+ */
3049
+ function loadNodeAutoInstrumentations() {
3050
+ try {
3051
+ return require_node_require.requireModule("@opentelemetry/auto-instrumentations-node").getNodeAutoInstrumentations;
3052
+ } catch {
3053
+ const isESM = isESMMode();
3054
+ const baseMessage = "@opentelemetry/auto-instrumentations-node not found.";
3055
+ if (isESM) throw new Error(`${baseMessage}\n\nESM Setup Required:
3056
+ 1. Install as a direct dependency: pnpm add @opentelemetry/auto-instrumentations-node
3057
+ 2. Create instrumentation.mjs with:
3058
+ import 'autotel/register'; // MUST be first!
3059
+ import { init } from 'autotel';
3060
+ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
3061
+ init({ service: "my-app", instrumentations: getNodeAutoInstrumentations() });
3062
+ 3. Run with: tsx --import ./instrumentation.mjs src/index.ts
3063
+
3064
+ See: https://github.com/jagreehal/autotel#esm-setup`);
3065
+ throw new Error(`${baseMessage} Install it: pnpm add @opentelemetry/auto-instrumentations-node`);
3066
+ }
3067
+ }
3068
+ /**
3069
+ * Injectable loader for testing. Set to override the default loader.
3070
+ * @internal
3071
+ */
3072
+ let _autoInstrumentationsLoader = null;
3073
+ /**
3074
+ * Get auto-instrumentations based on simple integration names
3075
+ * Excludes instrumentations that are manually provided to avoid conflicts
3076
+ */
3077
+ function getAutoInstrumentations(integrations, manualInstrumentationNames = /* @__PURE__ */ new Set()) {
3078
+ if (integrations === false) return [];
3079
+ const getNodeAutoInstrumentations = _autoInstrumentationsLoader ? _autoInstrumentationsLoader() : loadNodeAutoInstrumentations();
3080
+ const exclusionConfig = {};
3081
+ for (const className of manualInstrumentationNames) {
3082
+ const packageName = INSTRUMENTATION_CLASS_TO_PACKAGE[className];
3083
+ if (packageName) exclusionConfig[packageName] = { enabled: false };
3084
+ }
3085
+ if (integrations === true) {
3086
+ if (Object.keys(exclusionConfig).length > 0) return getNodeAutoInstrumentations(exclusionConfig);
3087
+ return getNodeAutoInstrumentations();
3088
+ }
3089
+ if (Array.isArray(integrations)) {
3090
+ const config = { ...exclusionConfig };
3091
+ for (const name of integrations) {
3092
+ const packageName = `@opentelemetry/instrumentation-${name}`;
3093
+ if (!exclusionConfig[packageName]) config[packageName] = { enabled: true };
3094
+ }
3095
+ return getNodeAutoInstrumentations(config);
3096
+ }
3097
+ const config = {
3098
+ ...exclusionConfig,
3099
+ ...integrations
3100
+ };
3101
+ for (const packageName of Object.keys(exclusionConfig)) if (Object.keys(integrations).find((key) => packageName.includes(key))) config[packageName] = { enabled: false };
3102
+ return getNodeAutoInstrumentations(config);
3103
+ }
3104
+ /**
3105
+ * Check if autotel has been initialized
3106
+ */
3107
+ function isInitialized() {
3108
+ return initialized;
3109
+ }
3110
+ /**
3111
+ * Get current config (internal use)
3112
+ */
3113
+ function getConfig() {
3114
+ return config;
3115
+ }
3116
+ /**
3117
+ * Get current logger (internal use)
3118
+ */
3119
+ function getLogger() {
3120
+ return logger;
3121
+ }
3122
+ /**
3123
+ * Get validation config (internal use)
3124
+ */
3125
+ function getValidationConfig() {
3126
+ return validationConfig;
3127
+ }
3128
+ /**
3129
+ * Get events config (internal use)
3130
+ */
3131
+ function getEventsConfig() {
3132
+ return eventsConfig;
3133
+ }
3134
+ /**
3135
+ * Warn once if not initialized (same behavior in all environments)
3136
+ */
3137
+ function warnIfNotInitialized(context) {
3138
+ if (!initialized && !warnedOnce) {
3139
+ logger.warn({}, `[autotel] ${context} used before init() called. Call init({ service: "..." }) first. See: https://docs.autotel.dev/quickstart`);
3140
+ warnedOnce = true;
3141
+ }
3142
+ }
3143
+ /**
3144
+ * Auto-detect version from package.json
3145
+ */
3146
+ function detectVersion() {
3147
+ try {
3148
+ const fs = require_node_require.requireModule("node:fs");
3149
+ return JSON.parse(fs.readFileSync(`${process.cwd()}/package.json`, "utf8")).version || "1.0.0";
3150
+ } catch {
3151
+ return "1.0.0";
3152
+ }
3153
+ }
3154
+ /**
3155
+ * Detect hostname for resource attributes.
3156
+ * Supports Datadog conventions (DD_HOSTNAME) and falls back to system hostname.
3157
+ *
3158
+ * Priority order:
3159
+ * 1. DD_HOSTNAME environment variable (Datadog convention)
3160
+ * 2. HOSTNAME environment variable (common Unix convention)
3161
+ * 3. os.hostname() (system hostname)
3162
+ *
3163
+ * @returns hostname string or undefined if detection fails
3164
+ */
3165
+ function detectHostname() {
3166
+ if (process.env.DD_HOSTNAME) return process.env.DD_HOSTNAME;
3167
+ if (process.env.HOSTNAME) return process.env.HOSTNAME;
3168
+ try {
3169
+ return require_node_require.requireModule("node:os").hostname();
3170
+ } catch {
3171
+ return;
3172
+ }
3173
+ }
3174
+ /**
3175
+ * @internal Close embedded devtools if running.
3176
+ */
3177
+ async function _closeEmbeddedDevtools() {
3178
+ if (_devtoolsClose) {
3179
+ await _devtoolsClose();
3180
+ _devtoolsClose = null;
3181
+ }
3182
+ }
3183
+ /**
3184
+ * Get SDK instance (for shutdown)
3185
+ */
3186
+ function getSdk() {
3187
+ return sdk;
3188
+ }
3189
+
3190
+ //#endregion
3191
+ Object.defineProperty(exports, 'BaggageSpanProcessor', {
3192
+ enumerable: true,
3193
+ get: function () {
3194
+ return BaggageSpanProcessor;
3195
+ }
3196
+ });
3197
+ Object.defineProperty(exports, 'CORRELATION_ID_BAGGAGE_KEY', {
3198
+ enumerable: true,
3199
+ get: function () {
3200
+ return CORRELATION_ID_BAGGAGE_KEY;
3201
+ }
3202
+ });
3203
+ Object.defineProperty(exports, 'Event', {
3204
+ enumerable: true,
3205
+ get: function () {
3206
+ return Event;
3207
+ }
3208
+ });
3209
+ Object.defineProperty(exports, 'createStringRedactor', {
3210
+ enumerable: true,
3211
+ get: function () {
3212
+ return createStringRedactor;
3213
+ }
3214
+ });
3215
+ Object.defineProperty(exports, 'createTraceContext', {
3216
+ enumerable: true,
3217
+ get: function () {
3218
+ return createTraceContext;
3219
+ }
3220
+ });
3221
+ Object.defineProperty(exports, 'defineBaggageSchema', {
3222
+ enumerable: true,
3223
+ get: function () {
3224
+ return defineBaggageSchema;
3225
+ }
3226
+ });
3227
+ Object.defineProperty(exports, 'flush', {
3228
+ enumerable: true,
3229
+ get: function () {
3230
+ return flush;
3231
+ }
3232
+ });
3233
+ Object.defineProperty(exports, 'generateCorrelationId', {
3234
+ enumerable: true,
3235
+ get: function () {
3236
+ return generateCorrelationId;
3237
+ }
3238
+ });
3239
+ Object.defineProperty(exports, 'getActiveContextWithBaggage', {
3240
+ enumerable: true,
3241
+ get: function () {
3242
+ return getActiveContextWithBaggage;
3243
+ }
3244
+ });
3245
+ Object.defineProperty(exports, 'getConfig', {
3246
+ enumerable: true,
3247
+ get: function () {
3248
+ return getConfig;
3249
+ }
3250
+ });
3251
+ Object.defineProperty(exports, 'getContextStorage', {
3252
+ enumerable: true,
3253
+ get: function () {
3254
+ return getContextStorage;
3255
+ }
3256
+ });
3257
+ Object.defineProperty(exports, 'getCorrelationId', {
3258
+ enumerable: true,
3259
+ get: function () {
3260
+ return getCorrelationId;
3261
+ }
3262
+ });
3263
+ Object.defineProperty(exports, 'getCorrelationStorage', {
3264
+ enumerable: true,
3265
+ get: function () {
3266
+ return getCorrelationStorage;
3267
+ }
3268
+ });
3269
+ Object.defineProperty(exports, 'getEventQueue', {
3270
+ enumerable: true,
3271
+ get: function () {
3272
+ return getEventQueue;
3273
+ }
3274
+ });
3275
+ Object.defineProperty(exports, 'getEvents', {
3276
+ enumerable: true,
3277
+ get: function () {
3278
+ return getEvents;
3279
+ }
3280
+ });
3281
+ Object.defineProperty(exports, 'getLogger', {
3282
+ enumerable: true,
3283
+ get: function () {
3284
+ return getLogger;
3285
+ }
3286
+ });
3287
+ Object.defineProperty(exports, 'getOperationContext', {
3288
+ enumerable: true,
3289
+ get: function () {
3290
+ return getOperationContext;
3291
+ }
3292
+ });
3293
+ Object.defineProperty(exports, 'getOrCreateCorrelationId', {
3294
+ enumerable: true,
3295
+ get: function () {
3296
+ return getOrCreateCorrelationId;
3297
+ }
3298
+ });
3299
+ Object.defineProperty(exports, 'getSdk', {
3300
+ enumerable: true,
3301
+ get: function () {
3302
+ return getSdk;
3303
+ }
3304
+ });
3305
+ Object.defineProperty(exports, 'init', {
3306
+ enumerable: true,
3307
+ get: function () {
3308
+ return init;
3309
+ }
3310
+ });
3311
+ Object.defineProperty(exports, 'isInitialized', {
3312
+ enumerable: true,
3313
+ get: function () {
3314
+ return isInitialized;
3315
+ }
3316
+ });
3317
+ Object.defineProperty(exports, 'isLoggerLocked', {
3318
+ enumerable: true,
3319
+ get: function () {
3320
+ return isLoggerLocked;
3321
+ }
3322
+ });
3323
+ Object.defineProperty(exports, 'lockLogger', {
3324
+ enumerable: true,
3325
+ get: function () {
3326
+ return lockLogger;
3327
+ }
3328
+ });
3329
+ Object.defineProperty(exports, 'resetEvents', {
3330
+ enumerable: true,
3331
+ get: function () {
3332
+ return resetEvents;
3333
+ }
3334
+ });
3335
+ Object.defineProperty(exports, 'runInOperationContext', {
3336
+ enumerable: true,
3337
+ get: function () {
3338
+ return runInOperationContext;
3339
+ }
3340
+ });
3341
+ Object.defineProperty(exports, 'runWithCorrelationId', {
3342
+ enumerable: true,
3343
+ get: function () {
3344
+ return runWithCorrelationId;
3345
+ }
3346
+ });
3347
+ Object.defineProperty(exports, 'setCorrelationId', {
3348
+ enumerable: true,
3349
+ get: function () {
3350
+ return setCorrelationId;
3351
+ }
3352
+ });
3353
+ Object.defineProperty(exports, 'setCorrelationIdInBaggage', {
3354
+ enumerable: true,
3355
+ get: function () {
3356
+ return setCorrelationIdInBaggage;
3357
+ }
3358
+ });
3359
+ Object.defineProperty(exports, 'shutdown', {
3360
+ enumerable: true,
3361
+ get: function () {
3362
+ return shutdown;
3363
+ }
3364
+ });
3365
+ Object.defineProperty(exports, 'track', {
3366
+ enumerable: true,
3367
+ get: function () {
3368
+ return track;
3369
+ }
3370
+ });
3371
+ //# sourceMappingURL=init-C3RApHKJ.cjs.map