@dxos/observability 0.8.4-main.84f28bd → 0.8.4-main.8baae0fced

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 (330) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +14 -11
  3. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  4. package/dist/lib/browser/chunk-PSFTIG54.mjs +20 -0
  5. package/dist/lib/browser/chunk-PSFTIG54.mjs.map +7 -0
  6. package/dist/lib/browser/index.mjs +964 -34
  7. package/dist/lib/browser/index.mjs.map +4 -4
  8. package/dist/lib/browser/log-processor-HPHWNBOK.mjs +38 -0
  9. package/dist/lib/browser/log-processor-HPHWNBOK.mjs.map +7 -0
  10. package/dist/lib/browser/logs-UTNIFYHF.mjs +116 -0
  11. package/dist/lib/browser/logs-UTNIFYHF.mjs.map +7 -0
  12. package/dist/lib/browser/meta.json +1 -1
  13. package/dist/lib/browser/metrics-PRGSYAZJ.mjs +116 -0
  14. package/dist/lib/browser/metrics-PRGSYAZJ.mjs.map +7 -0
  15. package/dist/lib/browser/traces-browser-XRINKQUA.mjs +154 -0
  16. package/dist/lib/browser/traces-browser-XRINKQUA.mjs.map +7 -0
  17. package/dist/lib/node-esm/chunk-EDDZWPYV.mjs +22 -0
  18. package/dist/lib/node-esm/chunk-EDDZWPYV.mjs.map +7 -0
  19. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  20. package/dist/lib/node-esm/index.mjs +986 -34
  21. package/dist/lib/node-esm/index.mjs.map +4 -4
  22. package/dist/lib/node-esm/log-processor-ZODHERST.mjs +39 -0
  23. package/dist/lib/node-esm/log-processor-ZODHERST.mjs.map +7 -0
  24. package/dist/lib/node-esm/logs-ARJUVN3T.mjs +117 -0
  25. package/dist/lib/node-esm/logs-ARJUVN3T.mjs.map +7 -0
  26. package/dist/lib/node-esm/meta.json +1 -1
  27. package/dist/lib/node-esm/metrics-DREJOOAC.mjs +117 -0
  28. package/dist/lib/node-esm/metrics-DREJOOAC.mjs.map +7 -0
  29. package/dist/lib/node-esm/traces-74F7JUKF.mjs +125 -0
  30. package/dist/lib/node-esm/traces-74F7JUKF.mjs.map +7 -0
  31. package/dist/types/src/cli-observability-secrets.json +3 -4
  32. package/dist/types/src/extensions/index.d.ts +3 -0
  33. package/dist/types/src/extensions/index.d.ts.map +1 -0
  34. package/dist/types/src/extensions/index.js +6 -0
  35. package/dist/types/src/extensions/index.js.map +1 -0
  36. package/dist/types/src/extensions/otel/extension.d.ts +23 -0
  37. package/dist/types/src/extensions/otel/extension.d.ts.map +1 -0
  38. package/dist/types/src/extensions/otel/extension.js +220 -0
  39. package/dist/types/src/extensions/otel/extension.js.map +1 -0
  40. package/dist/types/src/extensions/otel/index.d.ts +2 -0
  41. package/dist/types/src/extensions/otel/index.d.ts.map +1 -0
  42. package/dist/types/src/extensions/otel/index.js +5 -0
  43. package/dist/types/src/extensions/otel/index.js.map +1 -0
  44. package/dist/types/src/{otel → extensions/otel}/logs.d.ts +4 -3
  45. package/dist/types/src/extensions/otel/logs.d.ts.map +1 -0
  46. package/dist/types/src/extensions/otel/logs.js +107 -0
  47. package/dist/types/src/extensions/otel/logs.js.map +1 -0
  48. package/dist/types/src/{otel → extensions/otel}/metrics.d.ts +0 -1
  49. package/dist/types/src/extensions/otel/metrics.d.ts.map +1 -0
  50. package/dist/types/src/{otel → extensions/otel}/metrics.js +8 -14
  51. package/dist/types/src/extensions/otel/metrics.js.map +1 -0
  52. package/dist/types/src/extensions/otel/otel.d.ts +19 -0
  53. package/dist/types/src/extensions/otel/otel.d.ts.map +1 -0
  54. package/dist/types/src/extensions/otel/otel.js +23 -0
  55. package/dist/types/src/extensions/otel/otel.js.map +1 -0
  56. package/dist/types/src/extensions/otel/span-processors.d.ts +25 -0
  57. package/dist/types/src/extensions/otel/span-processors.d.ts.map +1 -0
  58. package/dist/types/src/extensions/otel/span-processors.js +41 -0
  59. package/dist/types/src/extensions/otel/span-processors.js.map +1 -0
  60. package/dist/types/src/extensions/otel/traces-browser.d.ts +25 -0
  61. package/dist/types/src/extensions/otel/traces-browser.d.ts.map +1 -0
  62. package/dist/types/src/extensions/otel/traces-browser.js +105 -0
  63. package/dist/types/src/extensions/otel/traces-browser.js.map +1 -0
  64. package/dist/types/src/extensions/otel/traces.d.ts +25 -0
  65. package/dist/types/src/extensions/otel/traces.d.ts.map +1 -0
  66. package/dist/types/src/extensions/otel/traces.js +88 -0
  67. package/dist/types/src/extensions/otel/traces.js.map +1 -0
  68. package/dist/types/src/extensions/posthog/extension.d.ts +28 -0
  69. package/dist/types/src/extensions/posthog/extension.d.ts.map +1 -0
  70. package/dist/types/src/extensions/posthog/extension.js +156 -0
  71. package/dist/types/src/extensions/posthog/extension.js.map +1 -0
  72. package/dist/types/src/extensions/posthog/index.d.ts +2 -0
  73. package/dist/types/src/extensions/posthog/index.d.ts.map +1 -0
  74. package/dist/types/src/extensions/posthog/index.js +5 -0
  75. package/dist/types/src/extensions/posthog/index.js.map +1 -0
  76. package/dist/types/src/extensions/posthog/log-processor.d.ts +3 -0
  77. package/dist/types/src/extensions/posthog/log-processor.d.ts.map +1 -0
  78. package/dist/types/src/extensions/posthog/log-processor.js +36 -0
  79. package/dist/types/src/extensions/posthog/log-processor.js.map +1 -0
  80. package/dist/types/src/extensions/posthog/log-processor.test.d.ts +2 -0
  81. package/dist/types/src/extensions/posthog/log-processor.test.d.ts.map +1 -0
  82. package/dist/types/src/extensions/posthog/log-processor.test.js +146 -0
  83. package/dist/types/src/extensions/posthog/log-processor.test.js.map +1 -0
  84. package/dist/types/src/extensions/stub.d.ts +3 -0
  85. package/dist/types/src/extensions/stub.d.ts.map +1 -0
  86. package/dist/types/src/extensions/stub.js +16 -0
  87. package/dist/types/src/extensions/stub.js.map +1 -0
  88. package/dist/types/src/index.d.ts +3 -2
  89. package/dist/types/src/index.d.ts.map +1 -1
  90. package/dist/types/src/index.js +4 -3
  91. package/dist/types/src/index.js.map +1 -1
  92. package/dist/types/src/observability-extension.d.ts +74 -0
  93. package/dist/types/src/observability-extension.d.ts.map +1 -0
  94. package/dist/types/src/observability-extension.js +5 -0
  95. package/dist/types/src/observability-extension.js.map +1 -0
  96. package/dist/types/src/observability.d.ts +32 -110
  97. package/dist/types/src/observability.d.ts.map +1 -1
  98. package/dist/types/src/observability.js +178 -455
  99. package/dist/types/src/observability.js.map +1 -1
  100. package/dist/types/src/observability.test.d.ts +2 -0
  101. package/dist/types/src/observability.test.d.ts.map +1 -0
  102. package/dist/types/src/observability.test.js +312 -0
  103. package/dist/types/src/observability.test.js.map +1 -0
  104. package/dist/types/src/providers/client-observability.d.ts +11 -0
  105. package/dist/types/src/providers/client-observability.d.ts.map +1 -0
  106. package/dist/types/src/providers/client-observability.js +202 -0
  107. package/dist/types/src/providers/client-observability.js.map +1 -0
  108. package/dist/types/src/providers/index.d.ts +4 -0
  109. package/dist/types/src/providers/index.d.ts.map +1 -0
  110. package/dist/types/src/providers/index.js +7 -0
  111. package/dist/types/src/providers/index.js.map +1 -0
  112. package/dist/types/src/providers/ip-data.d.ts +5 -0
  113. package/dist/types/src/providers/ip-data.d.ts.map +1 -0
  114. package/dist/types/src/providers/ip-data.js +57 -0
  115. package/dist/types/src/providers/ip-data.js.map +1 -0
  116. package/dist/types/src/providers/storage.d.ts +3 -0
  117. package/dist/types/src/providers/storage.d.ts.map +1 -0
  118. package/dist/types/src/providers/storage.js +19 -0
  119. package/dist/types/src/providers/storage.js.map +1 -0
  120. package/dist/types/src/storage/browser.d.ts +19 -0
  121. package/dist/types/src/storage/browser.d.ts.map +1 -0
  122. package/dist/types/src/storage/browser.js +69 -0
  123. package/dist/types/src/storage/browser.js.map +1 -0
  124. package/dist/types/src/storage/index.d.ts +2 -0
  125. package/dist/types/src/storage/index.d.ts.map +1 -0
  126. package/{src/segment/index.ts → dist/types/src/storage/index.js} +1 -2
  127. package/dist/types/src/storage/index.js.map +1 -0
  128. package/dist/types/src/storage/node.d.ts +26 -0
  129. package/dist/types/src/storage/node.d.ts.map +1 -0
  130. package/dist/types/src/storage/node.js +92 -0
  131. package/dist/types/src/storage/node.js.map +1 -0
  132. package/dist/types/src/storage/node.test.d.ts +2 -0
  133. package/dist/types/src/storage/node.test.d.ts.map +1 -0
  134. package/dist/types/src/storage/node.test.js +103 -0
  135. package/dist/types/src/storage/node.test.js.map +1 -0
  136. package/dist/types/tsconfig.tsbuildinfo +1 -1
  137. package/package.json +48 -65
  138. package/src/cli-observability-secrets.json +3 -4
  139. package/src/extensions/index.ts +6 -0
  140. package/src/extensions/otel/extension.ts +279 -0
  141. package/src/extensions/otel/index.ts +5 -0
  142. package/src/extensions/otel/logs.ts +137 -0
  143. package/src/{otel → extensions/otel}/metrics.ts +6 -23
  144. package/src/extensions/otel/otel.ts +34 -0
  145. package/src/extensions/otel/span-processors.ts +45 -0
  146. package/src/extensions/otel/traces-browser.ts +139 -0
  147. package/src/extensions/otel/traces.ts +113 -0
  148. package/src/extensions/posthog/extension.ts +199 -0
  149. package/src/extensions/posthog/index.ts +5 -0
  150. package/src/extensions/posthog/log-processor.test.ts +186 -0
  151. package/src/extensions/posthog/log-processor.ts +43 -0
  152. package/src/extensions/stub.ts +19 -0
  153. package/src/index.ts +4 -3
  154. package/src/observability-extension.ts +94 -0
  155. package/src/observability.test.ts +531 -0
  156. package/src/observability.ts +238 -577
  157. package/src/providers/client-observability.ts +255 -0
  158. package/src/providers/index.ts +7 -0
  159. package/src/providers/ip-data.ts +91 -0
  160. package/src/providers/storage.ts +23 -0
  161. package/src/storage/browser.ts +71 -0
  162. package/src/{sentry → storage}/index.ts +0 -1
  163. package/src/storage/node.test.ts +129 -0
  164. package/src/{helpers/node-observability.ts → storage/node.ts} +41 -70
  165. package/src/vite-import-meta.d.ts +14 -0
  166. package/dist/lib/browser/chunk-33TCMAUB.mjs +0 -996
  167. package/dist/lib/browser/chunk-33TCMAUB.mjs.map +0 -7
  168. package/dist/lib/browser/chunk-5OQYI27L.mjs +0 -1
  169. package/dist/lib/browser/chunk-MWTIKIBZ.mjs +0 -147
  170. package/dist/lib/browser/chunk-MWTIKIBZ.mjs.map +0 -7
  171. package/dist/lib/browser/chunk-YEPQFAES.mjs +0 -164
  172. package/dist/lib/browser/chunk-YEPQFAES.mjs.map +0 -7
  173. package/dist/lib/browser/observability-EEM6BEY6.mjs +0 -10
  174. package/dist/lib/browser/otel-IRDZ7PES.mjs +0 -277
  175. package/dist/lib/browser/otel-IRDZ7PES.mjs.map +0 -7
  176. package/dist/lib/browser/segment/index.mjs +0 -11
  177. package/dist/lib/browser/segment/index.mjs.map +0 -7
  178. package/dist/lib/browser/sentry/index.mjs +0 -24
  179. package/dist/lib/browser/sentry/index.mjs.map +0 -7
  180. package/dist/lib/browser/sentry-log-processor-3F3SBJXM.mjs +0 -146
  181. package/dist/lib/browser/sentry-log-processor-3F3SBJXM.mjs.map +0 -7
  182. package/dist/lib/node-esm/chunk-552KLA6Z.mjs +0 -202
  183. package/dist/lib/node-esm/chunk-552KLA6Z.mjs.map +0 -7
  184. package/dist/lib/node-esm/chunk-EYW4X3O6.mjs +0 -997
  185. package/dist/lib/node-esm/chunk-EYW4X3O6.mjs.map +0 -7
  186. package/dist/lib/node-esm/chunk-MRAK2H7O.mjs +0 -2
  187. package/dist/lib/node-esm/chunk-MRAK2H7O.mjs.map +0 -7
  188. package/dist/lib/node-esm/chunk-TEH6VIKV.mjs +0 -135
  189. package/dist/lib/node-esm/chunk-TEH6VIKV.mjs.map +0 -7
  190. package/dist/lib/node-esm/observability-DAXZGOBS.mjs +0 -11
  191. package/dist/lib/node-esm/observability-DAXZGOBS.mjs.map +0 -7
  192. package/dist/lib/node-esm/otel-62HYJETM.mjs +0 -260
  193. package/dist/lib/node-esm/otel-62HYJETM.mjs.map +0 -7
  194. package/dist/lib/node-esm/segment/index.mjs +0 -12
  195. package/dist/lib/node-esm/segment/index.mjs.map +0 -7
  196. package/dist/lib/node-esm/sentry/index.mjs +0 -25
  197. package/dist/lib/node-esm/sentry/index.mjs.map +0 -7
  198. package/dist/lib/node-esm/sentry-log-processor-JAYRA23C.mjs +0 -147
  199. package/dist/lib/node-esm/sentry-log-processor-JAYRA23C.mjs.map +0 -7
  200. package/dist/types/src/helpers/browser-observability.d.ts +0 -17
  201. package/dist/types/src/helpers/browser-observability.d.ts.map +0 -1
  202. package/dist/types/src/helpers/browser-observability.js +0 -140
  203. package/dist/types/src/helpers/browser-observability.js.map +0 -1
  204. package/dist/types/src/helpers/common.d.ts +0 -12
  205. package/dist/types/src/helpers/common.d.ts.map +0 -1
  206. package/dist/types/src/helpers/common.js +0 -23
  207. package/dist/types/src/helpers/common.js.map +0 -1
  208. package/dist/types/src/helpers/index.d.ts +0 -6
  209. package/dist/types/src/helpers/index.d.ts.map +0 -1
  210. package/dist/types/src/helpers/index.js +0 -9
  211. package/dist/types/src/helpers/index.js.map +0 -1
  212. package/dist/types/src/helpers/map-spaces.d.ts +0 -18
  213. package/dist/types/src/helpers/map-spaces.d.ts.map +0 -1
  214. package/dist/types/src/helpers/map-spaces.js +0 -37
  215. package/dist/types/src/helpers/map-spaces.js.map +0 -1
  216. package/dist/types/src/helpers/node-observability.d.ts +0 -24
  217. package/dist/types/src/helpers/node-observability.d.ts.map +0 -1
  218. package/dist/types/src/helpers/node-observability.js +0 -101
  219. package/dist/types/src/helpers/node-observability.js.map +0 -1
  220. package/dist/types/src/helpers/setup-telemetry-listeners.d.ts +0 -4
  221. package/dist/types/src/helpers/setup-telemetry-listeners.d.ts.map +0 -1
  222. package/dist/types/src/helpers/setup-telemetry-listeners.js +0 -97
  223. package/dist/types/src/helpers/setup-telemetry-listeners.js.map +0 -1
  224. package/dist/types/src/otel/index.d.ts +0 -5
  225. package/dist/types/src/otel/index.d.ts.map +0 -1
  226. package/dist/types/src/otel/index.js +0 -8
  227. package/dist/types/src/otel/index.js.map +0 -1
  228. package/dist/types/src/otel/logs.d.ts.map +0 -1
  229. package/dist/types/src/otel/logs.js +0 -71
  230. package/dist/types/src/otel/logs.js.map +0 -1
  231. package/dist/types/src/otel/metrics.d.ts.map +0 -1
  232. package/dist/types/src/otel/metrics.js.map +0 -1
  233. package/dist/types/src/otel/otel.d.ts +0 -12
  234. package/dist/types/src/otel/otel.d.ts.map +0 -1
  235. package/dist/types/src/otel/otel.js +0 -11
  236. package/dist/types/src/otel/otel.js.map +0 -1
  237. package/dist/types/src/otel/traces-browser.d.ts +0 -8
  238. package/dist/types/src/otel/traces-browser.d.ts.map +0 -1
  239. package/dist/types/src/otel/traces-browser.js +0 -47
  240. package/dist/types/src/otel/traces-browser.js.map +0 -1
  241. package/dist/types/src/otel/traces.d.ts +0 -8
  242. package/dist/types/src/otel/traces.d.ts.map +0 -1
  243. package/dist/types/src/otel/traces.js +0 -40
  244. package/dist/types/src/otel/traces.js.map +0 -1
  245. package/dist/types/src/segment/base.d.ts +0 -15
  246. package/dist/types/src/segment/base.d.ts.map +0 -1
  247. package/dist/types/src/segment/base.js +0 -50
  248. package/dist/types/src/segment/base.js.map +0 -1
  249. package/dist/types/src/segment/browser.d.ts +0 -15
  250. package/dist/types/src/segment/browser.d.ts.map +0 -1
  251. package/dist/types/src/segment/browser.js +0 -67
  252. package/dist/types/src/segment/browser.js.map +0 -1
  253. package/dist/types/src/segment/index.d.ts +0 -3
  254. package/dist/types/src/segment/index.d.ts.map +0 -1
  255. package/dist/types/src/segment/index.js +0 -6
  256. package/dist/types/src/segment/index.js.map +0 -1
  257. package/dist/types/src/segment/node.d.ts +0 -16
  258. package/dist/types/src/segment/node.d.ts.map +0 -1
  259. package/dist/types/src/segment/node.js +0 -83
  260. package/dist/types/src/segment/node.js.map +0 -1
  261. package/dist/types/src/segment/types.d.ts +0 -52
  262. package/dist/types/src/segment/types.d.ts.map +0 -1
  263. package/dist/types/src/segment/types.js +0 -18
  264. package/dist/types/src/segment/types.js.map +0 -1
  265. package/dist/types/src/sentry/browser.d.ts +0 -32
  266. package/dist/types/src/sentry/browser.d.ts.map +0 -1
  267. package/dist/types/src/sentry/browser.js +0 -112
  268. package/dist/types/src/sentry/browser.js.map +0 -1
  269. package/dist/types/src/sentry/index.d.ts +0 -3
  270. package/dist/types/src/sentry/index.d.ts.map +0 -1
  271. package/dist/types/src/sentry/index.js +0 -6
  272. package/dist/types/src/sentry/index.js.map +0 -1
  273. package/dist/types/src/sentry/node.d.ts +0 -32
  274. package/dist/types/src/sentry/node.d.ts.map +0 -1
  275. package/dist/types/src/sentry/node.js +0 -111
  276. package/dist/types/src/sentry/node.js.map +0 -1
  277. package/dist/types/src/sentry/node.node.test.d.ts +0 -2
  278. package/dist/types/src/sentry/node.node.test.d.ts.map +0 -1
  279. package/dist/types/src/sentry/node.node.test.js +0 -34
  280. package/dist/types/src/sentry/node.node.test.js.map +0 -1
  281. package/dist/types/src/sentry/sentry-log-processor.d.ts +0 -9
  282. package/dist/types/src/sentry/sentry-log-processor.d.ts.map +0 -1
  283. package/dist/types/src/sentry/sentry-log-processor.js +0 -149
  284. package/dist/types/src/sentry/sentry-log-processor.js.map +0 -1
  285. package/dist/types/src/sentry/sentry.node.test.d.ts +0 -2
  286. package/dist/types/src/sentry/sentry.node.test.d.ts.map +0 -1
  287. package/dist/types/src/sentry/sentry.node.test.js +0 -28
  288. package/dist/types/src/sentry/sentry.node.test.js.map +0 -1
  289. package/dist/types/src/sentry/types.d.ts +0 -18
  290. package/dist/types/src/sentry/types.d.ts.map +0 -1
  291. package/dist/types/src/sentry/types.js +0 -4
  292. package/dist/types/src/sentry/types.js.map +0 -1
  293. package/dist/types/src/testing/index.d.ts +0 -2
  294. package/dist/types/src/testing/index.d.ts.map +0 -1
  295. package/dist/types/src/testing/index.js +0 -5
  296. package/dist/types/src/testing/index.js.map +0 -1
  297. package/dist/types/src/testing/testkit/browser.d.ts +0 -2
  298. package/dist/types/src/testing/testkit/browser.d.ts.map +0 -1
  299. package/dist/types/src/testing/testkit/browser.js +0 -7
  300. package/dist/types/src/testing/testkit/browser.js.map +0 -1
  301. package/dist/types/src/testing/testkit/index.d.ts +0 -2
  302. package/dist/types/src/testing/testkit/index.d.ts.map +0 -1
  303. package/dist/types/src/testing/testkit/index.js +0 -6
  304. package/dist/types/src/testing/testkit/index.js.map +0 -1
  305. package/src/helpers/browser-observability.ts +0 -177
  306. package/src/helpers/common.ts +0 -38
  307. package/src/helpers/index.ts +0 -9
  308. package/src/helpers/map-spaces.ts +0 -48
  309. package/src/helpers/setup-telemetry-listeners.ts +0 -108
  310. package/src/otel/index.ts +0 -8
  311. package/src/otel/logs.ts +0 -100
  312. package/src/otel/otel.ts +0 -21
  313. package/src/otel/traces-browser.ts +0 -59
  314. package/src/otel/traces.ts +0 -57
  315. package/src/segment/base.ts +0 -69
  316. package/src/segment/browser.ts +0 -68
  317. package/src/segment/node.ts +0 -94
  318. package/src/segment/types.ts +0 -57
  319. package/src/sentry/browser.ts +0 -133
  320. package/src/sentry/node.node.test.ts +0 -39
  321. package/src/sentry/node.ts +0 -126
  322. package/src/sentry/sentry-log-processor.ts +0 -166
  323. package/src/sentry/sentry.node.test.ts +0 -34
  324. package/src/sentry/types.ts +0 -22
  325. package/src/testing/index.ts +0 -5
  326. package/src/testing/testkit/browser.ts +0 -8
  327. package/src/testing/testkit/index.ts +0 -7
  328. package/src/testing/testkit/shims.d.ts +0 -5
  329. /package/dist/lib/browser/{chunk-5OQYI27L.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
  330. /package/dist/lib/{browser/observability-EEM6BEY6.mjs.map → node-esm/chunk-HSLMI22Q.mjs.map} +0 -0
@@ -0,0 +1,531 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { describe, it } from '@effect/vitest';
6
+ import * as Effect from 'effect/Effect';
7
+ import * as Exit from 'effect/Exit';
8
+ import * as Function from 'effect/Function';
9
+ import { expect, vi } from 'vitest';
10
+
11
+ import * as Observability from './observability';
12
+ import { type Extension, type ExtensionApi } from './observability-extension';
13
+
14
+ const createMockExtension = (overrides?: Partial<Extension> & { apis?: ExtensionApi[] }): Extension => ({
15
+ initialize: vi.fn(() => Effect.succeed(undefined)),
16
+ close: vi.fn(() => Effect.succeed(undefined)),
17
+ enable: vi.fn(() => Effect.succeed(undefined)),
18
+ disable: vi.fn(() => Effect.succeed(undefined)),
19
+ flush: vi.fn(() => Effect.succeed(undefined)),
20
+ identify: vi.fn(),
21
+ alias: vi.fn(),
22
+ setTags: vi.fn(),
23
+ enabled: true,
24
+ apis: [],
25
+ ...overrides,
26
+ });
27
+
28
+ describe('Observability', () => {
29
+ describe('lifecycle', () => {
30
+ it.effect('initializes all extensions in order', () =>
31
+ Effect.gen(function* () {
32
+ const callOrder: number[] = [];
33
+ const ext1 = createMockExtension({
34
+ initialize: vi.fn(() => {
35
+ callOrder.push(1);
36
+ return Effect.succeed(undefined);
37
+ }),
38
+ });
39
+ const ext2 = createMockExtension({
40
+ initialize: vi.fn(() => {
41
+ callOrder.push(2);
42
+ return Effect.succeed(undefined);
43
+ }),
44
+ });
45
+
46
+ yield* Function.pipe(
47
+ Observability.make(),
48
+ Observability.addExtension(Effect.succeed(ext1)),
49
+ Observability.addExtension(Effect.succeed(ext2)),
50
+ Observability.initialize,
51
+ );
52
+ expect(callOrder).toEqual([1, 2]);
53
+ }),
54
+ );
55
+
56
+ it.effect('calls close on all extensions', () =>
57
+ Effect.gen(function* () {
58
+ const ext1 = createMockExtension();
59
+ const ext2 = createMockExtension();
60
+
61
+ const obs = yield* Function.pipe(
62
+ Observability.make(),
63
+ Observability.addExtension(Effect.succeed(ext1)),
64
+ Observability.addExtension(Effect.succeed(ext2)),
65
+ Observability.initialize,
66
+ );
67
+ yield* obs.close();
68
+ expect(ext1.close).toHaveBeenCalled();
69
+ expect(ext2.close).toHaveBeenCalled();
70
+ }),
71
+ );
72
+
73
+ it.effect('initialize is idempotent (second call is no-op)', () =>
74
+ Effect.gen(function* () {
75
+ const ext = createMockExtension();
76
+ const obs = yield* Function.pipe(
77
+ Observability.make(),
78
+ Observability.addExtension(Effect.succeed(ext)),
79
+ Observability.initialize,
80
+ );
81
+ yield* obs.initialize();
82
+ expect(ext.initialize).toHaveBeenCalledTimes(1);
83
+ }),
84
+ );
85
+
86
+ it.effect('initialize resets on error (can retry)', () =>
87
+ Effect.gen(function* () {
88
+ let callCount = 0;
89
+ const ext = createMockExtension({
90
+ initialize: vi.fn(() =>
91
+ ++callCount === 1 ? Effect.fail(new Error('init failed')) : Effect.succeed(undefined),
92
+ ),
93
+ });
94
+
95
+ const obs = yield* Function.pipe(Observability.make(), Observability.addExtension(Effect.succeed(ext)));
96
+ // First init fails but is caught internally.
97
+ yield* obs.initialize();
98
+ // Can retry since _initialized was reset.
99
+ yield* obs.initialize();
100
+ expect(callCount).toBe(2);
101
+ }),
102
+ );
103
+
104
+ it.effect('close clears subscriptions', () =>
105
+ Effect.gen(function* () {
106
+ const cleanup = vi.fn();
107
+ const provider: Observability.DataProvider = () => Effect.succeed(cleanup);
108
+
109
+ const obs = yield* Function.pipe(
110
+ Observability.make(),
111
+ Observability.addDataProvider(provider),
112
+ Observability.initialize,
113
+ );
114
+ yield* obs.close();
115
+ expect(cleanup).toHaveBeenCalled();
116
+ }),
117
+ );
118
+ });
119
+
120
+ describe('enable/disable', () => {
121
+ it.effect('enable calls enable on all extensions', () =>
122
+ Effect.gen(function* () {
123
+ const ext1 = createMockExtension();
124
+ const ext2 = createMockExtension();
125
+ const obs = yield* Function.pipe(
126
+ Observability.make(),
127
+ Observability.addExtension(Effect.succeed(ext1)),
128
+ Observability.addExtension(Effect.succeed(ext2)),
129
+ Observability.initialize,
130
+ );
131
+ yield* obs.enable();
132
+ expect(ext1.enable).toHaveBeenCalled();
133
+ expect(ext2.enable).toHaveBeenCalled();
134
+ }),
135
+ );
136
+
137
+ it.effect('disable calls disable on all extensions', () =>
138
+ Effect.gen(function* () {
139
+ const ext1 = createMockExtension();
140
+ const ext2 = createMockExtension();
141
+ const obs = yield* Function.pipe(
142
+ Observability.make(),
143
+ Observability.addExtension(Effect.succeed(ext1)),
144
+ Observability.addExtension(Effect.succeed(ext2)),
145
+ Observability.initialize,
146
+ );
147
+ yield* obs.disable();
148
+ expect(ext1.disable).toHaveBeenCalled();
149
+ expect(ext2.disable).toHaveBeenCalled();
150
+ }),
151
+ );
152
+ });
153
+
154
+ describe('flush', () => {
155
+ it.effect('flush calls flush on all extensions', () =>
156
+ Effect.gen(function* () {
157
+ const ext1 = createMockExtension();
158
+ const ext2 = createMockExtension();
159
+ const obs = yield* Function.pipe(
160
+ Observability.make(),
161
+ Observability.addExtension(Effect.succeed(ext1)),
162
+ Observability.addExtension(Effect.succeed(ext2)),
163
+ Observability.initialize,
164
+ );
165
+ yield* obs.flush();
166
+ expect(ext1.flush).toHaveBeenCalled();
167
+ expect(ext2.flush).toHaveBeenCalled();
168
+ }),
169
+ );
170
+ });
171
+
172
+ describe('extensions', () => {
173
+ it.effect('cannot add extension after initialization', () =>
174
+ Effect.gen(function* () {
175
+ const obs = yield* Function.pipe(Observability.make(), Observability.initialize);
176
+ // addExtension calls the internal _addExtension which throws an invariant after init.
177
+ // The invariant throw becomes a defect inside Effect.gen.
178
+ const exit = yield* Function.pipe(
179
+ Effect.succeed(obs),
180
+ Observability.addExtension(Effect.succeed(createMockExtension())),
181
+ Effect.exit,
182
+ );
183
+ expect(Exit.isFailure(exit)).toBe(true);
184
+ }),
185
+ );
186
+
187
+ it.effect('enabled returns true when all extensions are enabled', () =>
188
+ Effect.gen(function* () {
189
+ const ext1 = createMockExtension({ enabled: true });
190
+ const ext2 = createMockExtension({ enabled: true });
191
+ const obs = yield* Function.pipe(
192
+ Observability.make(),
193
+ Observability.addExtension(Effect.succeed(ext1)),
194
+ Observability.addExtension(Effect.succeed(ext2)),
195
+ Observability.initialize,
196
+ );
197
+ expect(obs.enabled).toBe(true);
198
+ }),
199
+ );
200
+
201
+ it.effect('enabled returns false when any extension is disabled', () =>
202
+ Effect.gen(function* () {
203
+ const ext1 = createMockExtension({ enabled: true });
204
+ const ext2 = createMockExtension({ enabled: false });
205
+ const obs = yield* Function.pipe(
206
+ Observability.make(),
207
+ Observability.addExtension(Effect.succeed(ext1)),
208
+ Observability.addExtension(Effect.succeed(ext2)),
209
+ Observability.initialize,
210
+ );
211
+ expect(obs.enabled).toBe(false);
212
+ }),
213
+ );
214
+ });
215
+
216
+ describe('identify/alias', () => {
217
+ it.effect('identify forwards to all extensions', () =>
218
+ Effect.gen(function* () {
219
+ const ext1 = createMockExtension();
220
+ const ext2 = createMockExtension();
221
+ const obs = yield* Function.pipe(
222
+ Observability.make(),
223
+ Observability.addExtension(Effect.succeed(ext1)),
224
+ Observability.addExtension(Effect.succeed(ext2)),
225
+ Observability.initialize,
226
+ );
227
+ obs.identify('user-1', { name: 'Alice' }, { first_seen: 'today' });
228
+ expect(ext1.identify).toHaveBeenCalledWith('user-1', { name: 'Alice' }, { first_seen: 'today' });
229
+ expect(ext2.identify).toHaveBeenCalledWith('user-1', { name: 'Alice' }, { first_seen: 'today' });
230
+ }),
231
+ );
232
+
233
+ it.effect('alias forwards to all extensions', () =>
234
+ Effect.gen(function* () {
235
+ const ext1 = createMockExtension();
236
+ const ext2 = createMockExtension();
237
+ const obs = yield* Function.pipe(
238
+ Observability.make(),
239
+ Observability.addExtension(Effect.succeed(ext1)),
240
+ Observability.addExtension(Effect.succeed(ext2)),
241
+ Observability.initialize,
242
+ );
243
+ obs.alias('new-id', 'old-id');
244
+ expect(ext1.alias).toHaveBeenCalledWith('new-id', 'old-id');
245
+ expect(ext2.alias).toHaveBeenCalledWith('new-id', 'old-id');
246
+ }),
247
+ );
248
+ });
249
+
250
+ describe('setTags', () => {
251
+ it.effect('forwards processed tags to all extensions', () =>
252
+ Effect.gen(function* () {
253
+ const ext = createMockExtension();
254
+ const obs = yield* Function.pipe(
255
+ Observability.make(),
256
+ Observability.addExtension(Effect.succeed(ext)),
257
+ Observability.initialize,
258
+ );
259
+ obs.setTags({ key: 'value' });
260
+ expect(ext.setTags).toHaveBeenCalledWith({ key: 'value' });
261
+ }),
262
+ );
263
+
264
+ it.effect('filters out undefined values', () =>
265
+ Effect.gen(function* () {
266
+ const ext = createMockExtension();
267
+ const obs = yield* Function.pipe(
268
+ Observability.make(),
269
+ Observability.addExtension(Effect.succeed(ext)),
270
+ Observability.initialize,
271
+ );
272
+ obs.setTags({ key: 'value', empty: undefined });
273
+ expect(ext.setTags).toHaveBeenCalledWith({ key: 'value' });
274
+ }),
275
+ );
276
+
277
+ it.effect('converts values to strings', () =>
278
+ Effect.gen(function* () {
279
+ const ext = createMockExtension();
280
+ const obs = yield* Function.pipe(
281
+ Observability.make(),
282
+ Observability.addExtension(Effect.succeed(ext)),
283
+ Observability.initialize,
284
+ );
285
+ obs.setTags({ count: 42, flag: true });
286
+ expect(ext.setTags).toHaveBeenCalledWith({ count: '42', flag: 'true' });
287
+ }),
288
+ );
289
+
290
+ it.effect('filters by kind when specified', () =>
291
+ Effect.gen(function* () {
292
+ const errorsExt = createMockExtension({
293
+ apis: [{ kind: 'errors', isAvailable: () => Effect.succeed(true), captureException: vi.fn() }],
294
+ });
295
+ const eventsExt = createMockExtension({
296
+ apis: [{ kind: 'events', isAvailable: () => Effect.succeed(true), captureEvent: vi.fn() }],
297
+ });
298
+ const obs = yield* Function.pipe(
299
+ Observability.make(),
300
+ Observability.addExtension(Effect.succeed(errorsExt)),
301
+ Observability.addExtension(Effect.succeed(eventsExt)),
302
+ Observability.initialize,
303
+ );
304
+
305
+ obs.setTags({ key: 'value' }, 'errors');
306
+ expect(errorsExt.setTags).toHaveBeenCalledWith({ key: 'value' });
307
+ // The eventsExt is skipped because its api kind ('events') !== 'errors'.
308
+ expect(eventsExt.setTags).not.toHaveBeenCalled();
309
+ }),
310
+ );
311
+ });
312
+
313
+ describe('api delegation', () => {
314
+ it.effect('errors.captureException delegates to error-kind extensions only', () =>
315
+ Effect.gen(function* () {
316
+ const captureException = vi.fn();
317
+ const errorsExt = createMockExtension({
318
+ apis: [{ kind: 'errors', isAvailable: () => Effect.succeed(true), captureException }],
319
+ });
320
+ const eventsExt = createMockExtension({
321
+ apis: [{ kind: 'events', isAvailable: () => Effect.succeed(true), captureEvent: vi.fn() }],
322
+ });
323
+ const obs = yield* Function.pipe(
324
+ Observability.make(),
325
+ Observability.addExtension(Effect.succeed(errorsExt)),
326
+ Observability.addExtension(Effect.succeed(eventsExt)),
327
+ Observability.initialize,
328
+ );
329
+ const error = new Error('test');
330
+ obs.errors.captureException(error, { context: 'test' });
331
+ expect(captureException).toHaveBeenCalledWith(error, { context: 'test' });
332
+ }),
333
+ );
334
+
335
+ it.effect('events.captureEvent delegates to events-kind extensions only', () =>
336
+ Effect.gen(function* () {
337
+ const captureEvent = vi.fn();
338
+ const eventsExt = createMockExtension({
339
+ apis: [{ kind: 'events', isAvailable: () => Effect.succeed(true), captureEvent }],
340
+ });
341
+ const errorsExt = createMockExtension({
342
+ apis: [{ kind: 'errors', isAvailable: () => Effect.succeed(true), captureException: vi.fn() }],
343
+ });
344
+ const obs = yield* Function.pipe(
345
+ Observability.make(),
346
+ Observability.addExtension(Effect.succeed(eventsExt)),
347
+ Observability.addExtension(Effect.succeed(errorsExt)),
348
+ Observability.initialize,
349
+ );
350
+ obs.events.captureEvent('button_click', { page: 'home' });
351
+ expect(captureEvent).toHaveBeenCalledWith('button_click', { page: 'home' });
352
+ }),
353
+ );
354
+
355
+ it.effect('feedback.captureUserFeedback delegates to feedback-kind extensions only', () =>
356
+ Effect.gen(function* () {
357
+ const captureUserFeedback = vi.fn();
358
+ const feedbackExt = createMockExtension({
359
+ apis: [{ kind: 'feedback', isAvailable: () => Effect.succeed(true), captureUserFeedback }],
360
+ });
361
+ const obs = yield* Function.pipe(
362
+ Observability.make(),
363
+ Observability.addExtension(Effect.succeed(feedbackExt)),
364
+ Observability.initialize,
365
+ );
366
+ void obs.feedback.captureUserFeedback({ message: 'great app' });
367
+ expect(captureUserFeedback).toHaveBeenCalledWith({ message: 'great app' });
368
+ }),
369
+ );
370
+
371
+ it.effect('metrics delegates to metrics-kind extensions only', () =>
372
+ Effect.gen(function* () {
373
+ const gauge = vi.fn();
374
+ const increment = vi.fn();
375
+ const distribution = vi.fn();
376
+ const metricsExt = createMockExtension({
377
+ apis: [{ kind: 'metrics', isAvailable: () => Effect.succeed(true), gauge, increment, distribution }],
378
+ });
379
+ const obs = yield* Function.pipe(
380
+ Observability.make(),
381
+ Observability.addExtension(Effect.succeed(metricsExt)),
382
+ Observability.initialize,
383
+ );
384
+ obs.metrics.gauge('cpu', 0.5, { host: 'a' });
385
+ obs.metrics.increment('requests', 1, { route: '/api' });
386
+ obs.metrics.distribution('latency', 120, { endpoint: '/api' });
387
+ expect(gauge).toHaveBeenCalledWith('cpu', 0.5, { host: 'a' });
388
+ expect(increment).toHaveBeenCalledWith('requests', 1, { route: '/api' });
389
+ expect(distribution).toHaveBeenCalledWith('latency', 120, { endpoint: '/api' });
390
+ }),
391
+ );
392
+
393
+ it.effect('ignores extensions that do not provide the requested kind', () =>
394
+ Effect.gen(function* () {
395
+ const captureException = vi.fn();
396
+ const ext = createMockExtension({
397
+ apis: [{ kind: 'errors', isAvailable: () => Effect.succeed(true), captureException }],
398
+ });
399
+ const obs = yield* Function.pipe(
400
+ Observability.make(),
401
+ Observability.addExtension(Effect.succeed(ext)),
402
+ Observability.initialize,
403
+ );
404
+ // Call events — errors extension should not be invoked.
405
+ obs.events.captureEvent('test', {});
406
+ expect(captureException).not.toHaveBeenCalled();
407
+ }),
408
+ );
409
+ });
410
+
411
+ describe('data providers', () => {
412
+ it.effect('providers registered before init run during initialization', () =>
413
+ Effect.gen(function* () {
414
+ const providerFn = vi.fn();
415
+ const provider: Observability.DataProvider = (obs) => {
416
+ providerFn(obs);
417
+ return Effect.succeed(undefined);
418
+ };
419
+
420
+ yield* Function.pipe(Observability.make(), Observability.addDataProvider(provider), Observability.initialize);
421
+ expect(providerFn).toHaveBeenCalledTimes(1);
422
+ }),
423
+ );
424
+
425
+ it.effect('addDataProvider (post-init) immediately runs provider', () =>
426
+ Effect.gen(function* () {
427
+ const cleanup = vi.fn();
428
+ const provider: Observability.DataProvider = () => Effect.succeed(cleanup);
429
+
430
+ const obs = yield* Function.pipe(Observability.make(), Observability.initialize);
431
+ yield* obs.addDataProvider(provider);
432
+ // Provider runs immediately; cleanup registered.
433
+ yield* obs.close();
434
+ expect(cleanup).toHaveBeenCalled();
435
+ }),
436
+ );
437
+
438
+ it.effect('provider cleanup functions are called on close', () =>
439
+ Effect.gen(function* () {
440
+ const cleanup1 = vi.fn();
441
+ const cleanup2 = vi.fn();
442
+ const provider1: Observability.DataProvider = () => Effect.succeed(cleanup1);
443
+ const provider2: Observability.DataProvider = () => Effect.succeed(cleanup2);
444
+
445
+ const obs = yield* Function.pipe(
446
+ Observability.make(),
447
+ Observability.addDataProvider(provider1),
448
+ Observability.addDataProvider(provider2),
449
+ Observability.initialize,
450
+ );
451
+ yield* obs.close();
452
+ expect(cleanup1).toHaveBeenCalled();
453
+ expect(cleanup2).toHaveBeenCalled();
454
+ }),
455
+ );
456
+
457
+ it.effect('provider errors do not crash initialization', () =>
458
+ Effect.gen(function* () {
459
+ const failingProvider: Observability.DataProvider = () => Effect.fail(new Error('provider failed'));
460
+ const obs = yield* Function.pipe(Observability.make(), Observability.addDataProvider(failingProvider));
461
+ // Should not throw — error is caught internally.
462
+ yield* obs.initialize();
463
+ }),
464
+ );
465
+ });
466
+
467
+ describe('composition helpers', () => {
468
+ it.effect('make() creates a new Observability instance', () =>
469
+ Effect.gen(function* () {
470
+ const obs = yield* Observability.make();
471
+ expect(obs).toBeDefined();
472
+ expect(typeof obs.initialize).toBe('function');
473
+ expect(typeof obs.close).toBe('function');
474
+ expect(typeof obs.enable).toBe('function');
475
+ expect(typeof obs.disable).toBe('function');
476
+ }),
477
+ );
478
+
479
+ it.effect('addExtension pipes an extension into the instance', () =>
480
+ Effect.gen(function* () {
481
+ const ext = createMockExtension();
482
+ const obs = yield* Function.pipe(Observability.make(), Observability.addExtension(Effect.succeed(ext)));
483
+ yield* obs.initialize();
484
+ expect(ext.initialize).toHaveBeenCalled();
485
+ }),
486
+ );
487
+
488
+ it.effect('addDataProvider pipes a provider into the instance', () =>
489
+ Effect.gen(function* () {
490
+ const providerFn = vi.fn(() => Effect.succeed(undefined));
491
+ const provider: Observability.DataProvider = () => providerFn();
492
+
493
+ const obs = yield* Function.pipe(Observability.make(), Observability.addDataProvider(provider));
494
+ yield* obs.initialize();
495
+ expect(providerFn).toHaveBeenCalled();
496
+ }),
497
+ );
498
+
499
+ it.effect('initialize triggers initialization', () =>
500
+ Effect.gen(function* () {
501
+ const ext = createMockExtension();
502
+ const obs = yield* Function.pipe(
503
+ Observability.make(),
504
+ Observability.addExtension(Effect.succeed(ext)),
505
+ Observability.initialize,
506
+ );
507
+ expect(ext.initialize).toHaveBeenCalled();
508
+ expect(obs).toBeDefined();
509
+ }),
510
+ );
511
+
512
+ it.effect('full pipeline: make -> addExtension -> addDataProvider -> initialize', () =>
513
+ Effect.gen(function* () {
514
+ const ext = createMockExtension();
515
+ const providerFn = vi.fn(() => Effect.succeed(undefined));
516
+ const provider: Observability.DataProvider = () => providerFn();
517
+
518
+ const obs = yield* Function.pipe(
519
+ Observability.make(),
520
+ Observability.addExtension(Effect.succeed(ext)),
521
+ Observability.addDataProvider(provider),
522
+ Observability.initialize,
523
+ );
524
+
525
+ expect(ext.initialize).toHaveBeenCalled();
526
+ expect(providerFn).toHaveBeenCalled();
527
+ expect(obs.enabled).toBe(true);
528
+ }),
529
+ );
530
+ });
531
+ });