flowgrid-sdk 1.2.0 → 1.3.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 (314) hide show
  1. package/README.md +224 -250
  2. package/dist/237.flowgrid.min.js +2 -0
  3. package/dist/237.flowgrid.min.js.map +1 -0
  4. package/dist/546.flowgrid.min.js +3 -0
  5. package/dist/546.flowgrid.min.js.LICENSE.txt +14 -0
  6. package/dist/546.flowgrid.min.js.map +1 -0
  7. package/dist/EXAMPLE.d.ts +1 -0
  8. package/dist/EXAMPLE.js +55 -0
  9. package/dist/EXAMPLE.js.map +1 -0
  10. package/dist/browser.d.ts +46 -103
  11. package/dist/browser.js +102 -0
  12. package/dist/browser.js.map +1 -0
  13. package/dist/flowgrid.min.js +1 -1
  14. package/dist/flowgrid.min.js.map +1 -1
  15. package/dist/index.d.ts +7 -8
  16. package/dist/index.js +64 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/lib/client/transport.d.ts +14 -4
  19. package/dist/lib/client/transport.js +432 -0
  20. package/dist/lib/client/transport.js.map +1 -0
  21. package/dist/lib/consent/index.d.ts +0 -5
  22. package/dist/lib/consent/index.js +32 -0
  23. package/dist/lib/consent/index.js.map +1 -0
  24. package/dist/lib/consent/manager.js +336 -0
  25. package/dist/lib/consent/manager.js.map +1 -0
  26. package/dist/lib/consent/types.d.ts +3 -20
  27. package/dist/lib/consent/types.js +10 -0
  28. package/dist/lib/consent/types.js.map +1 -0
  29. package/dist/lib/features/analytics/attribution.d.ts +6 -47
  30. package/dist/lib/features/analytics/attribution.js +181 -0
  31. package/dist/lib/features/analytics/attribution.js.map +1 -0
  32. package/dist/lib/features/analytics/events.d.ts +1 -28
  33. package/dist/lib/features/analytics/events.js +256 -0
  34. package/dist/lib/features/analytics/events.js.map +1 -0
  35. package/dist/lib/features/analytics/funnels.js +260 -0
  36. package/dist/lib/features/analytics/funnels.js.map +1 -0
  37. package/dist/lib/features/analytics/heatmaps.d.ts +12 -19
  38. package/dist/lib/features/analytics/heatmaps.js +258 -0
  39. package/dist/lib/features/analytics/heatmaps.js.map +1 -0
  40. package/dist/lib/features/analytics/identify.d.ts +1 -21
  41. package/dist/lib/features/analytics/identify.js +213 -0
  42. package/dist/lib/features/analytics/identify.js.map +1 -0
  43. package/dist/lib/features/analytics/index.d.ts +2 -0
  44. package/dist/lib/features/analytics/index.js +15 -0
  45. package/dist/lib/features/analytics/index.js.map +1 -0
  46. package/dist/lib/features/analytics/page-views.d.ts +13 -30
  47. package/dist/lib/features/analytics/page-views.js +268 -0
  48. package/dist/lib/features/analytics/page-views.js.map +1 -0
  49. package/dist/lib/features/analytics/performance.d.ts +18 -24
  50. package/dist/lib/features/analytics/performance.js +232 -0
  51. package/dist/lib/features/analytics/performance.js.map +1 -0
  52. package/dist/lib/features/analytics/replay.d.ts +170 -0
  53. package/dist/lib/features/analytics/replay.js +381 -0
  54. package/dist/lib/features/analytics/replay.js.map +1 -0
  55. package/dist/lib/features/analytics/retention.d.ts +1 -76
  56. package/dist/lib/features/analytics/retention.js +135 -0
  57. package/dist/lib/features/analytics/retention.js.map +1 -0
  58. package/dist/lib/features/analytics/sessions.d.ts +12 -37
  59. package/dist/lib/features/analytics/sessions.js +213 -0
  60. package/dist/lib/features/analytics/sessions.js.map +1 -0
  61. package/dist/lib/features/core/activation.d.ts +1 -24
  62. package/dist/lib/features/core/activation.js +175 -0
  63. package/dist/lib/features/core/activation.js.map +1 -0
  64. package/dist/lib/features/core/experiment.d.ts +53 -21
  65. package/dist/lib/features/core/experiment.js +554 -0
  66. package/dist/lib/features/core/experiment.js.map +1 -0
  67. package/dist/lib/features/core/index.js +9 -0
  68. package/dist/lib/features/core/index.js.map +1 -0
  69. package/dist/lib/features/core/track-feature.d.ts +1 -8
  70. package/dist/lib/features/core/track-feature.js +119 -0
  71. package/dist/lib/features/core/track-feature.js.map +1 -0
  72. package/dist/lib/features/core/track-prompt.d.ts +5 -8
  73. package/dist/lib/features/core/track-prompt.js +181 -0
  74. package/dist/lib/features/core/track-prompt.js.map +1 -0
  75. package/dist/lib/features/ecommerce/cart.d.ts +1 -24
  76. package/dist/lib/features/ecommerce/cart.js +244 -0
  77. package/dist/lib/features/ecommerce/cart.js.map +1 -0
  78. package/dist/lib/features/ecommerce/checkout.d.ts +1 -28
  79. package/dist/lib/features/ecommerce/checkout.js +254 -0
  80. package/dist/lib/features/ecommerce/checkout.js.map +1 -0
  81. package/dist/lib/features/ecommerce/index.d.ts +0 -2
  82. package/dist/lib/features/ecommerce/index.js +15 -0
  83. package/dist/lib/features/ecommerce/index.js.map +1 -0
  84. package/dist/lib/features/ecommerce/ltv.d.ts +1 -69
  85. package/dist/lib/features/ecommerce/ltv.js +114 -0
  86. package/dist/lib/features/ecommerce/ltv.js.map +1 -0
  87. package/dist/lib/features/ecommerce/products.d.ts +1 -33
  88. package/dist/lib/features/ecommerce/products.js +223 -0
  89. package/dist/lib/features/ecommerce/products.js.map +1 -0
  90. package/dist/lib/features/ecommerce/promotions.d.ts +1 -30
  91. package/dist/lib/features/ecommerce/promotions.js +197 -0
  92. package/dist/lib/features/ecommerce/promotions.js.map +1 -0
  93. package/dist/lib/features/ecommerce/purchases.d.ts +1 -48
  94. package/dist/lib/features/ecommerce/purchases.js +193 -0
  95. package/dist/lib/features/ecommerce/purchases.js.map +1 -0
  96. package/dist/lib/features/ecommerce/refunds.d.ts +1 -27
  97. package/dist/lib/features/ecommerce/refunds.js +195 -0
  98. package/dist/lib/features/ecommerce/refunds.js.map +1 -0
  99. package/dist/lib/features/ecommerce/search.d.ts +1 -24
  100. package/dist/lib/features/ecommerce/search.js +156 -0
  101. package/dist/lib/features/ecommerce/search.js.map +1 -0
  102. package/dist/lib/features/ecommerce/subscriptions.d.ts +1 -28
  103. package/dist/lib/features/ecommerce/subscriptions.js +207 -0
  104. package/dist/lib/features/ecommerce/subscriptions.js.map +1 -0
  105. package/dist/lib/features/ecommerce/wishlist.d.ts +1 -28
  106. package/dist/lib/features/ecommerce/wishlist.js +186 -0
  107. package/dist/lib/features/ecommerce/wishlist.js.map +1 -0
  108. package/dist/lib/features/enterprise/acquisition.d.ts +2 -57
  109. package/dist/lib/features/enterprise/acquisition.js +166 -0
  110. package/dist/lib/features/enterprise/acquisition.js.map +1 -0
  111. package/dist/lib/features/enterprise/alerts.d.ts +1 -37
  112. package/dist/lib/features/enterprise/alerts.js +246 -0
  113. package/dist/lib/features/enterprise/alerts.js.map +1 -0
  114. package/dist/lib/features/enterprise/churn.d.ts +1 -42
  115. package/dist/lib/features/enterprise/churn.js +175 -0
  116. package/dist/lib/features/enterprise/churn.js.map +1 -0
  117. package/dist/lib/features/enterprise/cohorts.d.ts +1 -37
  118. package/dist/lib/features/enterprise/cohorts.js +201 -0
  119. package/dist/lib/features/enterprise/cohorts.js.map +1 -0
  120. package/dist/lib/features/enterprise/engagement.d.ts +40 -46
  121. package/dist/lib/features/enterprise/engagement.js +335 -0
  122. package/dist/lib/features/enterprise/engagement.js.map +1 -0
  123. package/dist/lib/features/enterprise/forecasting.d.ts +0 -50
  124. package/dist/lib/features/enterprise/forecasting.js +232 -0
  125. package/dist/lib/features/enterprise/forecasting.js.map +1 -0
  126. package/dist/lib/features/enterprise/index.d.ts +1 -1
  127. package/dist/lib/features/enterprise/index.js +76 -0
  128. package/dist/lib/features/enterprise/index.js.map +1 -0
  129. package/dist/lib/features/enterprise/monetization.d.ts +1 -60
  130. package/dist/lib/features/enterprise/monetization.js +146 -0
  131. package/dist/lib/features/enterprise/monetization.js.map +1 -0
  132. package/dist/lib/features/enterprise/multi-path-funnels.d.ts +1 -17
  133. package/dist/lib/features/enterprise/multi-path-funnels.js +205 -0
  134. package/dist/lib/features/enterprise/multi-path-funnels.js.map +1 -0
  135. package/dist/lib/features/enterprise/paths.d.ts +1 -56
  136. package/dist/lib/features/enterprise/paths.js +149 -0
  137. package/dist/lib/features/enterprise/paths.js.map +1 -0
  138. package/dist/lib/features/enterprise/security.d.ts +8 -57
  139. package/dist/lib/features/enterprise/security.js +202 -0
  140. package/dist/lib/features/enterprise/security.js.map +1 -0
  141. package/dist/lib/features/enterprise/support.d.ts +3 -42
  142. package/dist/lib/features/enterprise/support.js +162 -0
  143. package/dist/lib/features/enterprise/support.js.map +1 -0
  144. package/dist/lib/flowgrid.d.ts +278 -0
  145. package/dist/lib/flowgrid.js +323 -0
  146. package/dist/lib/flowgrid.js.map +1 -0
  147. package/dist/lib/frameworks/index.d.ts +13 -6
  148. package/dist/lib/frameworks/index.js +18 -0
  149. package/dist/lib/frameworks/index.js.map +1 -0
  150. package/dist/lib/frameworks/nextjs/client.js +355 -0
  151. package/dist/lib/frameworks/nextjs/client.js.map +1 -0
  152. package/dist/lib/frameworks/nextjs/index.js +31 -0
  153. package/dist/lib/frameworks/nextjs/index.js.map +1 -0
  154. package/dist/lib/frameworks/nextjs/server.js +259 -0
  155. package/dist/lib/frameworks/nextjs/server.js.map +1 -0
  156. package/dist/lib/frameworks/node/index.js +391 -0
  157. package/dist/lib/frameworks/node/index.js.map +1 -0
  158. package/dist/lib/frameworks/nuxt/index.js +288 -0
  159. package/dist/lib/frameworks/nuxt/index.js.map +1 -0
  160. package/dist/lib/frameworks/react/CookieBanner.js +166 -0
  161. package/dist/lib/frameworks/react/CookieBanner.js.map +1 -0
  162. package/dist/lib/frameworks/react/index.d.ts +2 -2
  163. package/dist/lib/frameworks/react/index.js +271 -0
  164. package/dist/lib/frameworks/react/index.js.map +1 -0
  165. package/dist/lib/frameworks/vue/CookieBanner.js +165 -0
  166. package/dist/lib/frameworks/vue/CookieBanner.js.map +1 -0
  167. package/dist/lib/frameworks/vue/index.d.ts +2 -2
  168. package/dist/lib/frameworks/vue/index.js +390 -0
  169. package/dist/lib/frameworks/vue/index.js.map +1 -0
  170. package/dist/lib/tracking/analytics/attribution.d.ts +14 -0
  171. package/dist/lib/tracking/analytics/attribution.js +18 -0
  172. package/dist/lib/tracking/analytics/attribution.js.map +1 -0
  173. package/dist/lib/tracking/analytics/events.d.ts +26 -0
  174. package/dist/lib/tracking/analytics/events.js +30 -0
  175. package/dist/lib/tracking/analytics/events.js.map +1 -0
  176. package/dist/lib/tracking/analytics/funnels.d.ts +16 -0
  177. package/dist/lib/tracking/analytics/funnels.js +22 -0
  178. package/dist/lib/tracking/analytics/funnels.js.map +1 -0
  179. package/dist/lib/tracking/analytics/heatmaps.d.ts +27 -0
  180. package/dist/lib/tracking/analytics/heatmaps.js +22 -0
  181. package/dist/lib/tracking/analytics/heatmaps.js.map +1 -0
  182. package/dist/lib/tracking/analytics/identify.d.ts +16 -0
  183. package/dist/lib/tracking/analytics/identify.js +22 -0
  184. package/dist/lib/tracking/analytics/identify.js.map +1 -0
  185. package/dist/lib/tracking/analytics/index.d.ts +10 -0
  186. package/dist/lib/tracking/analytics/index.js +11 -0
  187. package/dist/lib/tracking/analytics/index.js.map +1 -0
  188. package/dist/lib/tracking/analytics/page-views.d.ts +29 -0
  189. package/dist/lib/tracking/analytics/page-views.js +50 -0
  190. package/dist/lib/tracking/analytics/page-views.js.map +1 -0
  191. package/dist/lib/tracking/analytics/performance.d.ts +22 -0
  192. package/dist/lib/tracking/analytics/performance.js +22 -0
  193. package/dist/lib/tracking/analytics/performance.js.map +1 -0
  194. package/dist/lib/tracking/analytics/replay.d.ts +34 -0
  195. package/dist/lib/tracking/analytics/replay.js +46 -0
  196. package/dist/lib/tracking/analytics/replay.js.map +1 -0
  197. package/dist/lib/tracking/analytics/retention.d.ts +10 -0
  198. package/dist/lib/tracking/analytics/retention.js +10 -0
  199. package/dist/lib/tracking/analytics/retention.js.map +1 -0
  200. package/dist/lib/tracking/analytics/sessions.d.ts +20 -0
  201. package/dist/lib/tracking/analytics/sessions.js +26 -0
  202. package/dist/lib/tracking/analytics/sessions.js.map +1 -0
  203. package/dist/lib/tracking/core/activation.d.ts +23 -0
  204. package/dist/lib/tracking/core/activation.js +33 -0
  205. package/dist/lib/tracking/core/activation.js.map +1 -0
  206. package/dist/lib/tracking/core/experiment.d.ts +122 -0
  207. package/dist/lib/tracking/core/experiment.js +150 -0
  208. package/dist/lib/tracking/core/experiment.js.map +1 -0
  209. package/dist/lib/tracking/core/feature.d.ts +13 -0
  210. package/dist/lib/tracking/core/feature.js +14 -0
  211. package/dist/lib/tracking/core/feature.js.map +1 -0
  212. package/dist/lib/tracking/core/index.d.ts +4 -0
  213. package/dist/lib/tracking/core/index.js +5 -0
  214. package/dist/lib/tracking/core/index.js.map +1 -0
  215. package/dist/lib/tracking/core/prompt.d.ts +18 -0
  216. package/dist/lib/tracking/core/prompt.js +26 -0
  217. package/dist/lib/tracking/core/prompt.js.map +1 -0
  218. package/dist/lib/tracking/ecommerce/cart.d.ts +17 -0
  219. package/dist/lib/tracking/ecommerce/cart.js +22 -0
  220. package/dist/lib/tracking/ecommerce/cart.js.map +1 -0
  221. package/dist/lib/tracking/ecommerce/checkout.d.ts +17 -0
  222. package/dist/lib/tracking/ecommerce/checkout.js +22 -0
  223. package/dist/lib/tracking/ecommerce/checkout.js.map +1 -0
  224. package/dist/lib/tracking/ecommerce/index.d.ts +10 -0
  225. package/dist/lib/tracking/ecommerce/index.js +11 -0
  226. package/dist/lib/tracking/ecommerce/index.js.map +1 -0
  227. package/dist/lib/tracking/ecommerce/ltv.d.ts +15 -0
  228. package/dist/lib/tracking/ecommerce/ltv.js +14 -0
  229. package/dist/lib/tracking/ecommerce/ltv.js.map +1 -0
  230. package/dist/lib/tracking/ecommerce/products.d.ts +15 -0
  231. package/dist/lib/tracking/ecommerce/products.js +18 -0
  232. package/dist/lib/tracking/ecommerce/products.js.map +1 -0
  233. package/dist/lib/tracking/ecommerce/promotions.d.ts +14 -0
  234. package/dist/lib/tracking/ecommerce/promotions.js +25 -0
  235. package/dist/lib/tracking/ecommerce/promotions.js.map +1 -0
  236. package/dist/lib/tracking/ecommerce/purchases.d.ts +11 -0
  237. package/dist/lib/tracking/ecommerce/purchases.js +10 -0
  238. package/dist/lib/tracking/ecommerce/purchases.js.map +1 -0
  239. package/dist/lib/tracking/ecommerce/refunds.d.ts +17 -0
  240. package/dist/lib/tracking/ecommerce/refunds.js +22 -0
  241. package/dist/lib/tracking/ecommerce/refunds.js.map +1 -0
  242. package/dist/lib/tracking/ecommerce/search.d.ts +24 -0
  243. package/dist/lib/tracking/ecommerce/search.js +22 -0
  244. package/dist/lib/tracking/ecommerce/search.js.map +1 -0
  245. package/dist/lib/tracking/ecommerce/subscriptions.d.ts +21 -0
  246. package/dist/lib/tracking/ecommerce/subscriptions.js +38 -0
  247. package/dist/lib/tracking/ecommerce/subscriptions.js.map +1 -0
  248. package/dist/lib/tracking/ecommerce/wishlist.d.ts +19 -0
  249. package/dist/lib/tracking/ecommerce/wishlist.js +26 -0
  250. package/dist/lib/tracking/ecommerce/wishlist.js.map +1 -0
  251. package/dist/lib/tracking/enterprise/acquisition.d.ts +25 -0
  252. package/dist/lib/tracking/enterprise/acquisition.js +22 -0
  253. package/dist/lib/tracking/enterprise/acquisition.js.map +1 -0
  254. package/dist/lib/tracking/enterprise/alerts.d.ts +32 -0
  255. package/dist/lib/tracking/enterprise/alerts.js +30 -0
  256. package/dist/lib/tracking/enterprise/alerts.js.map +1 -0
  257. package/dist/lib/tracking/enterprise/churn.d.ts +23 -0
  258. package/dist/lib/tracking/enterprise/churn.js +22 -0
  259. package/dist/lib/tracking/enterprise/churn.js.map +1 -0
  260. package/dist/lib/tracking/enterprise/cohorts.d.ts +18 -0
  261. package/dist/lib/tracking/enterprise/cohorts.js +18 -0
  262. package/dist/lib/tracking/enterprise/cohorts.js.map +1 -0
  263. package/dist/lib/tracking/enterprise/engagement.d.ts +31 -0
  264. package/dist/lib/tracking/enterprise/engagement.js +44 -0
  265. package/dist/lib/tracking/enterprise/engagement.js.map +1 -0
  266. package/dist/lib/tracking/enterprise/forecasting.d.ts +18 -0
  267. package/dist/lib/tracking/enterprise/forecasting.js +22 -0
  268. package/dist/lib/tracking/enterprise/forecasting.js.map +1 -0
  269. package/dist/lib/tracking/enterprise/index.d.ts +11 -0
  270. package/dist/lib/tracking/enterprise/index.js +12 -0
  271. package/dist/lib/tracking/enterprise/index.js.map +1 -0
  272. package/dist/lib/tracking/enterprise/monetization.d.ts +14 -0
  273. package/dist/lib/tracking/enterprise/monetization.js +10 -0
  274. package/dist/lib/tracking/enterprise/monetization.js.map +1 -0
  275. package/dist/lib/tracking/enterprise/multi-path-funnels.d.ts +20 -0
  276. package/dist/lib/tracking/enterprise/multi-path-funnels.js +18 -0
  277. package/dist/lib/tracking/enterprise/multi-path-funnels.js.map +1 -0
  278. package/dist/lib/tracking/enterprise/paths.d.ts +20 -0
  279. package/dist/lib/tracking/enterprise/paths.js +18 -0
  280. package/dist/lib/tracking/enterprise/paths.js.map +1 -0
  281. package/dist/lib/tracking/enterprise/security.d.ts +28 -0
  282. package/dist/lib/tracking/enterprise/security.js +26 -0
  283. package/dist/lib/tracking/enterprise/security.js.map +1 -0
  284. package/dist/lib/tracking/enterprise/support.d.ts +25 -0
  285. package/dist/lib/tracking/enterprise/support.js +22 -0
  286. package/dist/lib/tracking/enterprise/support.js.map +1 -0
  287. package/dist/lib/tracking/index.d.ts +4 -0
  288. package/dist/lib/tracking/index.js +5 -0
  289. package/dist/lib/tracking/index.js.map +1 -0
  290. package/dist/lib/types/analytics.d.ts +10 -2
  291. package/dist/lib/types/analytics.js +6 -0
  292. package/dist/lib/types/analytics.js.map +1 -0
  293. package/dist/lib/types/common.js +6 -0
  294. package/dist/lib/types/common.js.map +1 -0
  295. package/dist/lib/types/ecommerce.js +6 -0
  296. package/dist/lib/types/ecommerce.js.map +1 -0
  297. package/dist/lib/types/index.js +8 -0
  298. package/dist/lib/types/index.js.map +1 -0
  299. package/dist/lib/utils/browser.d.ts +16 -0
  300. package/dist/lib/utils/browser.js +32 -0
  301. package/dist/lib/utils/browser.js.map +1 -0
  302. package/dist/lib/utils/identity.js +346 -0
  303. package/dist/lib/utils/identity.js.map +1 -0
  304. package/dist/lib/utils/storage.js +105 -0
  305. package/dist/lib/utils/storage.js.map +1 -0
  306. package/dist/umd/237.index.js +2 -0
  307. package/dist/umd/237.index.js.map +1 -0
  308. package/dist/umd/546.index.js +3 -0
  309. package/dist/umd/546.index.js.LICENSE.txt +14 -0
  310. package/dist/umd/546.index.js.map +1 -0
  311. package/dist/umd/index.js +2 -0
  312. package/dist/umd/index.js.map +1 -0
  313. package/package.json +27 -80
  314. package/dist/lib/features/ecommerce/inventory.d.ts +0 -219
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","mappings":"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","sources":["webpack://FlowGridSDK/webpack/universalModuleDefinition","webpack://FlowGridSDK/webpack/runtime/load script","webpack://FlowGridSDK/webpack/bootstrap","webpack://FlowGridSDK/webpack/runtime/define property getters","webpack://FlowGridSDK/webpack/runtime/ensure chunk","webpack://FlowGridSDK/webpack/runtime/get javascript chunk filename","webpack://FlowGridSDK/webpack/runtime/global","webpack://FlowGridSDK/webpack/runtime/hasOwnProperty shorthand","webpack://FlowGridSDK/webpack/runtime/make namespace object","webpack://FlowGridSDK/webpack/runtime/publicPath","webpack://FlowGridSDK/webpack/runtime/jsonp chunk loading","webpack://FlowGridSDK/./src/lib/client/transport.ts","webpack://FlowGridSDK/./src/lib/utils/storage.ts","webpack://FlowGridSDK/./src/lib/utils/identity.ts","webpack://FlowGridSDK/./src/lib/features/core/activation.ts","webpack://FlowGridSDK/./src/lib/features/core/track-feature.ts","webpack://FlowGridSDK/./src/lib/features/core/track-prompt.ts","webpack://FlowGridSDK/./src/lib/features/core/experiment.ts","webpack://FlowGridSDK/./src/lib/utils/browser.ts","webpack://FlowGridSDK/./src/lib/features/analytics/page-views.ts","webpack://FlowGridSDK/./src/lib/features/analytics/sessions.ts","webpack://FlowGridSDK/./src/lib/features/analytics/events.ts","webpack://FlowGridSDK/./src/lib/features/analytics/identify.ts","webpack://FlowGridSDK/./src/lib/features/analytics/funnels.ts","webpack://FlowGridSDK/./src/lib/features/analytics/retention.ts","webpack://FlowGridSDK/./src/lib/features/analytics/attribution.ts","webpack://FlowGridSDK/./src/lib/features/analytics/heatmaps.ts","webpack://FlowGridSDK/./src/lib/features/analytics/performance.ts","webpack://FlowGridSDK/./src/lib/features/analytics/replay.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/products.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/cart.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/checkout.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/purchases.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/refunds.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/promotions.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/wishlist.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/ltv.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/search.ts","webpack://FlowGridSDK/./src/lib/features/ecommerce/subscriptions.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/engagement.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/cohorts.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/churn.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/monetization.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/multi-path-funnels.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/support.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/acquisition.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/paths.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/alerts.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/security.ts","webpack://FlowGridSDK/./src/lib/features/enterprise/forecasting.ts","webpack://FlowGridSDK/./src/lib/tracking/core/activation.ts","webpack://FlowGridSDK/./src/lib/tracking/core/feature.ts","webpack://FlowGridSDK/./src/lib/tracking/core/prompt.ts","webpack://FlowGridSDK/./src/lib/tracking/core/experiment.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/page-views.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/sessions.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/events.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/identify.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/funnels.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/retention.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/attribution.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/heatmaps.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/performance.ts","webpack://FlowGridSDK/./src/lib/tracking/analytics/replay.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/products.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/cart.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/checkout.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/purchases.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/refunds.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/promotions.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/wishlist.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/ltv.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/search.ts","webpack://FlowGridSDK/./src/lib/tracking/ecommerce/subscriptions.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/engagement.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/cohorts.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/churn.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/monetization.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/multi-path-funnels.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/support.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/acquisition.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/paths.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/alerts.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/security.ts","webpack://FlowGridSDK/./src/lib/tracking/enterprise/forecasting.ts","webpack://FlowGridSDK/./src/lib/flowgrid.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"FlowGridSDK\"] = factory();\n\telse\n\t\troot[\"FlowGridSDK\"] = factory();\n})(this, () => {\nreturn ","var inProgress = {};\nvar dataWebpackPrefix = \"FlowGridSDK:\";\n// loadScript function to load a script via script tag\n__webpack_require__.l = (url, done, key, chunkId) => {\n\tif(inProgress[url]) { inProgress[url].push(done); return; }\n\tvar script, needAttach;\n\tif(key !== undefined) {\n\t\tvar scripts = document.getElementsByTagName(\"script\");\n\t\tfor(var i = 0; i < scripts.length; i++) {\n\t\t\tvar s = scripts[i];\n\t\t\tif(s.getAttribute(\"src\") == url || s.getAttribute(\"data-webpack\") == dataWebpackPrefix + key) { script = s; break; }\n\t\t}\n\t}\n\tif(!script) {\n\t\tneedAttach = true;\n\t\tscript = document.createElement('script');\n\n\t\tscript.charset = 'utf-8';\n\t\tif (__webpack_require__.nc) {\n\t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n\t\t}\n\t\tscript.setAttribute(\"data-webpack\", dataWebpackPrefix + key);\n\n\t\tscript.src = url;\n\t}\n\tinProgress[url] = [done];\n\tvar onScriptComplete = (prev, event) => {\n\t\t// avoid mem leaks in IE.\n\t\tscript.onerror = script.onload = null;\n\t\tclearTimeout(timeout);\n\t\tvar doneFns = inProgress[url];\n\t\tdelete inProgress[url];\n\t\tscript.parentNode && script.parentNode.removeChild(script);\n\t\tdoneFns && doneFns.forEach((fn) => (fn(event)));\n\t\tif(prev) return prev(event);\n\t}\n\tvar timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);\n\tscript.onerror = onScriptComplete.bind(null, script.onerror);\n\tscript.onload = onScriptComplete.bind(null, script.onload);\n\tneedAttach && document.head.appendChild(script);\n};","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.f = {};\n// This file contains only the entry chunk.\n// The chunk loading function for additional chunks\n__webpack_require__.e = (chunkId) => {\n\treturn Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {\n\t\t__webpack_require__.f[key](chunkId, promises);\n\t\treturn promises;\n\t}, []));\n};","// This function allow to reference async chunks\n__webpack_require__.u = (chunkId) => {\n\t// return url for filenames based on template\n\treturn \"\" + chunkId + \".index.js\";\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","var scriptUrl;\nif (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \"\";\nvar document = __webpack_require__.g.document;\nif (!scriptUrl && document) {\n\tif (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT')\n\t\tscriptUrl = document.currentScript.src;\n\tif (!scriptUrl) {\n\t\tvar scripts = document.getElementsByTagName(\"script\");\n\t\tif(scripts.length) {\n\t\t\tvar i = scripts.length - 1;\n\t\t\twhile (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src;\n\t\t}\n\t}\n}\n// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration\n// or pass an empty string (\"\") and set the __webpack_public_path__ variable from your code to use your own logic.\nif (!scriptUrl) throw new Error(\"Automatic publicPath is not supported in this browser\");\nscriptUrl = scriptUrl.replace(/^blob:/, \"\").replace(/#.*$/, \"\").replace(/\\?.*$/, \"\").replace(/\\/[^\\/]+$/, \"/\");\n__webpack_require__.p = scriptUrl;","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t792: 0\n};\n\n__webpack_require__.f.j = (chunkId, promises) => {\n\t\t// JSONP chunk loading for javascript\n\t\tvar installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;\n\t\tif(installedChunkData !== 0) { // 0 means \"already installed\".\n\n\t\t\t// a Promise means \"currently loading\".\n\t\t\tif(installedChunkData) {\n\t\t\t\tpromises.push(installedChunkData[2]);\n\t\t\t} else {\n\t\t\t\tif(true) { // all chunks have JS\n\t\t\t\t\t// setup Promise in chunk cache\n\t\t\t\t\tvar promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));\n\t\t\t\t\tpromises.push(installedChunkData[2] = promise);\n\n\t\t\t\t\t// start chunk loading\n\t\t\t\t\tvar url = __webpack_require__.p + __webpack_require__.u(chunkId);\n\t\t\t\t\t// create error before stack unwound to get useful stacktrace later\n\t\t\t\t\tvar error = new Error();\n\t\t\t\t\tvar loadingEnded = (event) => {\n\t\t\t\t\t\tif(__webpack_require__.o(installedChunks, chunkId)) {\n\t\t\t\t\t\t\tinstalledChunkData = installedChunks[chunkId];\n\t\t\t\t\t\t\tif(installedChunkData !== 0) installedChunks[chunkId] = undefined;\n\t\t\t\t\t\t\tif(installedChunkData) {\n\t\t\t\t\t\t\t\tvar errorType = event && (event.type === 'load' ? 'missing' : event.type);\n\t\t\t\t\t\t\t\tvar realSrc = event && event.target && event.target.src;\n\t\t\t\t\t\t\t\terror.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';\n\t\t\t\t\t\t\t\terror.name = 'ChunkLoadError';\n\t\t\t\t\t\t\t\terror.type = errorType;\n\t\t\t\t\t\t\t\terror.request = realSrc;\n\t\t\t\t\t\t\t\tinstalledChunkData[1](error);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\t__webpack_require__.l(url, loadingEnded, \"chunk-\" + chunkId, chunkId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n};\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n// no on chunks loaded\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = (parentChunkLoadingFunction, data) => {\n\tvar [chunkIds, moreModules, runtime] = data;\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some((id) => (installedChunks[id] !== 0))) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\n}\n\nvar chunkLoadingGlobal = this[\"webpackChunkFlowGridSDK\"] = this[\"webpackChunkFlowGridSDK\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","import { IdentityManager } from '../utils/identity';\n\n// ============================================================================\n// CONSENT\n// ============================================================================\n\nexport type ConsentCategory = 'analytics' | 'marketing';\nexport type BotDetectionMode = 'block' | 'tag' | 'disabled';\n\nexport interface FlowGridTransportConfig {\n /** Bot detection mode: 'block' skips events, 'tag' adds _bot flag, 'disabled' sends all */\n botDetection?: BotDetectionMode;\n /** Respect navigator.doNotTrack / globalPrivacyControl (default true) */\n respectDNT?: boolean;\n /** Global sampling rate 0.0–1.0 (default 1.0 = send everything) */\n sampleRate?: number;\n}\n\n/**\n * SDK Feature Types\n */\nexport type FeatureType = \n | \"engagement\"\n | \"cohorts\"\n | \"churn\"\n | \"monetization\"\n | \"multi_path_funnels\"\n | \"support\"\n | \"acquisition\"\n | \"paths\"\n | \"alerts\"\n | \"security\"\n | \"forecasting\";\n\n/**\n * FlowGridTransport — Unified transport layer for Flowgrid SDK.\n *\n * @description\n * Provides a secure, validated RPC-style transport layer used by all SDK modules.\n * Handles:\n * - Input validation\n * - Payload size enforcement\n * - Timeout handling\n * - Retry logic (network failures only)\n * - Authorization headers\n * - Feature-scoped endpoint routing\n *\n * This class is designed to be extended by higher-level modules\n * (e.g., Analytics, Experiments, Engagement, Cohorts).\n *\n * @example\n * ```ts\n * const client = new FlowGridTransport(\"web_123\", \"https://core.flow-grid.xyz\", \"sk_live_xxx\");\n * ```\n */\nexport class FlowGridTransport {\n\n /**\n * Unique Web ID identifying the site or application.\n * Used by the backend to associate incoming events.\n */\n protected webId: string;\n\n /**\n * Base API endpoint.\n * Example values:\n * - \"core.flow-grid.xyz\"\n * - \"https://core.flow-grid.xyz\"\n *\n * Protocol is normalized automatically.\n */\n protected endpoint: string;\n\n /**\n * Private API key used for authenticating requests.\n * Sent as a Bearer token in the Authorization header.\n */\n protected apiKey: string;\n\n /**\n * Visitor ID for cross-session visitor tracking.\n * Persisted per-visitor (cookie/localStorage) and sent with every event.\n */\n protected visitorId: string;\n\n /**\n * Optional identity manager that owns the visitor/session lifecycle.\n * When provided, visitor_id is resolved at call time (not construction time).\n */\n protected identityManager?: IdentityManager;\n\n /**\n * Maximum allowed payload size (in bytes).\n * Prevents oversized event submissions.\n */\n private static readonly MAX_PAYLOAD_SIZE = 10_000; // 10KB\n\n /**\n * Maximum time (ms) before request is aborted.\n */\n private static readonly TIMEOUT_MS = 10_000;\n\n /**\n * Maximum retry attempts for network-level failures and 5xx server errors.\n */\n private static readonly MAX_RETRIES = 3;\n\n /** Max events to persist in localStorage buffer */\n private static readonly MAX_BUFFER_EVENTS = 100;\n\n /** Max buffer size in bytes */\n private static readonly MAX_BUFFER_SIZE = 50_000; // 50KB\n\n /** localStorage key for failed event buffer */\n private static readonly EVENT_BUFFER_KEY = 'fg_event_buffer';\n\n /** Consent state */\n private static consent: Record<ConsentCategory, boolean> = { analytics: true, marketing: true };\n\n /** Transport config */\n protected transportConfig: FlowGridTransportConfig;\n\n /**\n * Creates a new FlowGridTransport instance.\n *\n * @param webId - Unique identifier for the web property.\n * @param endpoint - API base endpoint.\n * @param apiKey - Private API key for authentication.\n * @param visitorId - Optional visitor ID for cross-session tracking.\n *\n * @throws {Error} If required parameters are missing.\n */\n constructor(webId: string, endpoint: string, apiKey: string, visitorId?: string, identityManager?: IdentityManager, config?: FlowGridTransportConfig) {\n if (!webId?.trim() || !endpoint?.trim()) {\n throw new Error(\"SDK init failed: webId and endpoint are required.\");\n }\n\n this.webId = webId.trim();\n this.endpoint = this.normalizeEndpoint(endpoint);\n this.apiKey = apiKey;\n this.identityManager = identityManager;\n this.visitorId = visitorId ?? '';\n this.transportConfig = {\n botDetection: config?.botDetection ?? 'block',\n respectDNT: config?.respectDNT ?? true,\n sampleRate: config?.sampleRate ?? 1.0,\n };\n\n // Drain buffered events from previous failed attempts\n this.drainEventBuffer();\n }\n\n // ---------------------------------------------------------------------------\n // CONSENT API\n // ---------------------------------------------------------------------------\n\n static setConsent(consent: Partial<Record<ConsentCategory, boolean>>): void {\n Object.assign(FlowGridTransport.consent, consent);\n }\n\n static hasConsent(category: ConsentCategory): boolean {\n return FlowGridTransport.consent[category] ?? false;\n }\n\n // ---------------------------------------------------------------------------\n // BOT DETECTION\n // ---------------------------------------------------------------------------\n\n private static isLikelyBot(): boolean {\n if (typeof navigator === 'undefined') return false;\n if ((navigator as any).webdriver) return true;\n if (/bot|crawl|spider|headless|phantom|puppeteer/i.test(navigator.userAgent)) return true;\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // DNT / GPC CHECK\n // ---------------------------------------------------------------------------\n\n private isDNTEnabled(): boolean {\n if (typeof navigator === 'undefined') return false;\n if ((navigator as any).globalPrivacyControl) return true;\n if (navigator.doNotTrack === '1') return true;\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // DEVICE ENRICHMENT\n // ---------------------------------------------------------------------------\n\n private static getDeviceContext(): Record<string, unknown> {\n if (typeof window === 'undefined' || typeof navigator === 'undefined') return {};\n return {\n _screen_width: window.screen?.width,\n _screen_height: window.screen?.height,\n _device_type: /Mobi|Android/i.test(navigator.userAgent) ? 'mobile' : 'desktop',\n _language: navigator.language,\n };\n }\n\n // ---------------------------------------------------------------------------\n // SENDBACON FALLBACK\n // ---------------------------------------------------------------------------\n\n /**\n * Fire-and-forget event via sendBeacon. Used for page unload events.\n */\n sendViaBeacon(eventName: string, properties: Record<string, any> = {}): boolean {\n if (typeof navigator === 'undefined' || typeof navigator.sendBeacon !== 'function') return false;\n\n const resolvedVisitorId = this.identityManager\n ? this.identityManager.getVisitorId()\n : (this.visitorId ?? '');\n\n const callType = properties.type || 'event';\n const url = `${this.endpoint}/api/v1/sdk/functions?call=${encodeURIComponent(callType)}`;\n const payload = JSON.stringify({\n web_id: this.webId,\n visitor_id: resolvedVisitorId,\n event_name: eventName,\n properties: { ...properties, ...FlowGridTransport.getDeviceContext() },\n });\n\n return navigator.sendBeacon(url, new Blob([payload], { type: 'application/json' }));\n }\n\n // ---------------------------------------------------------------------------\n // RAW LARGE-PAYLOAD POST (session replay chunks, etc.)\n // ---------------------------------------------------------------------------\n\n /**\n * POST a large opaque payload to a dedicated SDK endpoint, bypassing the\n * 10KB validator. Used by session replay (`call=replay_chunk`) where each\n * batch of rrweb events can be hundreds of kilobytes.\n *\n * Falls back to `navigator.sendBeacon` on `pagehide` / final flush.\n */\n protected async postRaw(\n callType: string,\n body: Record<string, unknown>,\n options: { useBeacon?: boolean } = {},\n ): Promise<void> {\n if (FlowGridTransport.consent.analytics === false) return;\n if (this.transportConfig.respectDNT !== false && this.isDNTEnabled()) return;\n\n const url = `${this.endpoint}/api/v1/sdk/functions?call=${encodeURIComponent(callType)}`;\n const resolvedVisitorId = this.identityManager\n ? this.identityManager.getVisitorId()\n : (this.visitorId ?? '');\n\n const payload = JSON.stringify({\n web_id: this.webId,\n visitor_id: resolvedVisitorId,\n ...body,\n });\n\n if (options.useBeacon && typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {\n navigator.sendBeacon(url, new Blob([payload], { type: 'application/json' }));\n return;\n }\n\n try {\n await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: payload,\n keepalive: true,\n });\n } catch {\n // swallow — replay is best-effort\n }\n }\n\n // ---------------------------------------------------------------------------\n // EVENT BUFFER (localStorage persistence)\n // ---------------------------------------------------------------------------\n\n private bufferEvent(url: string, method: string, body?: string): void {\n if (typeof localStorage === 'undefined') return;\n try {\n const raw = localStorage.getItem(FlowGridTransport.EVENT_BUFFER_KEY);\n const buffer: Array<{ url: string; method: string; body?: string }> = raw ? JSON.parse(raw) : [];\n\n if (buffer.length >= FlowGridTransport.MAX_BUFFER_EVENTS) return;\n\n const serialized = JSON.stringify([...buffer, { url, method, body }]);\n if (new TextEncoder().encode(serialized).length > FlowGridTransport.MAX_BUFFER_SIZE) return;\n\n buffer.push({ url, method, body });\n localStorage.setItem(FlowGridTransport.EVENT_BUFFER_KEY, JSON.stringify(buffer));\n } catch { /* storage unavailable */ }\n }\n\n private drainEventBuffer(): void {\n if (typeof localStorage === 'undefined') return;\n try {\n const raw = localStorage.getItem(FlowGridTransport.EVENT_BUFFER_KEY);\n if (!raw) return;\n const buffer: Array<{ url: string; method: string; body?: string }> = JSON.parse(raw);\n localStorage.removeItem(FlowGridTransport.EVENT_BUFFER_KEY);\n\n for (const evt of buffer) {\n // Best-effort replay; don't await\n fetch(evt.url, {\n method: evt.method,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: evt.body,\n }).catch(() => {});\n }\n } catch { /* storage unavailable */ }\n }\n\n /**\n * Core RPC transport method for standard SDK calls.\n *\n * @template T Expected JSON response type.\n *\n * @param eventName - Logical event or function name.\n * @param properties - Arbitrary event payload properties.\n * @param method - HTTP method (\"GET\", \"POST\", \"PATCH\").\n *\n * @returns Promise resolving to typed response.\n */\n protected async init<T>(\n eventName: string,\n properties: Record<string, any> = {},\n method: \"GET\" | \"POST\" | \"PATCH\" = \"POST\"\n ): Promise<T> {\n\n // Consent gate\n if (!FlowGridTransport.hasConsent('analytics')) {\n return {} as T;\n }\n\n // DNT / GPC gate\n if (this.transportConfig.respectDNT && this.isDNTEnabled()) {\n return {} as T;\n }\n\n // Bot detection\n if (this.transportConfig.botDetection === 'block' && FlowGridTransport.isLikelyBot()) {\n return {} as T;\n }\n\n this.validateInput(eventName, properties);\n\n // Bot tagging\n if (this.transportConfig.botDetection === 'tag' && FlowGridTransport.isLikelyBot()) {\n properties = { ...properties, _bot: true };\n }\n\n // Auto device enrichment\n const enriched = { ...FlowGridTransport.getDeviceContext(), ...properties };\n\n const callType = enriched.type || \"event\";\n const url = `${this.endpoint}/api/v1/sdk/functions?call=${encodeURIComponent(callType)}`;\n\n const resolvedVisitorId = this.identityManager\n ? this.identityManager.getVisitorId()\n : (this.visitorId ?? '');\n\n const body = JSON.stringify({\n web_id: this.webId,\n visitor_id: resolvedVisitorId,\n event_name: eventName,\n properties: enriched,\n });\n\n return this.executeRequest<T>(url, method, method === \"GET\" ? undefined : body);\n }\n\n /**\n * Feature-scoped RPC transport method.\n * Routes to the SDK API endpoint with a feature type qualifier.\n *\n * @param eventName - Name of the event to track.\n * @param properties - Additional properties to send (must include type).\n */\n protected async initFeature<T>(eventName: string, properties: Record<string, any> & { type: FeatureType }): Promise<T> {\n\n this.validateInput(eventName, properties);\n\n if (!properties.type) {\n throw new Error('Feature events must include a type property');\n }\n\n const url = `${this.endpoint}/api/v1/sdk/functions?call=${encodeURIComponent(properties.type)}`;\n\n const resolvedVisitorId = this.identityManager\n ? this.identityManager.getVisitorId()\n : (this.visitorId ?? '');\n\n const body = JSON.stringify({\n web_id: this.webId,\n visitor_id: resolvedVisitorId,\n event_name: eventName,\n properties,\n });\n\n return this.executeRequest(url, \"POST\", body);\n }\n\n /**\n * Executes HTTP request with timeout and retry handling.\n *\n * @template T Expected response type.\n *\n * @param url - Fully constructed request URL.\n * @param method - HTTP method.\n * @param body - Optional JSON body (POST/PATCH only).\n * @param extraHeaders - Additional headers to include.\n *\n * @throws {Error} On timeout, network failure, or non-OK HTTP status.\n */\n private async executeRequest<T>(\n url: string,\n method: \"GET\" | \"POST\" | \"PATCH\",\n body?: string,\n extraHeaders?: Record<string, string>\n ): Promise<T> {\n\n let attempt = 0;\n\n while (true) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FlowGridTransport.TIMEOUT_MS);\n\n try {\n const res = await fetch(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`,\n ...extraHeaders,\n },\n body,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Retry on 5xx (server transient errors)\n if (res.status >= 500 && attempt < FlowGridTransport.MAX_RETRIES) {\n attempt++;\n await this.backoff(attempt);\n continue;\n }\n\n if (!res.ok) {\n const text = await this.safeRead(res);\n throw new Error(\n `SDK request failed (${res.status} ${res.statusText}) ${text}`\n );\n }\n\n return await res.json();\n\n } catch (error) {\n clearTimeout(timeoutId);\n\n const isNetworkError =\n error instanceof Error &&\n (error.name === \"AbortError\" || error.message.includes(\"fetch\"));\n\n if (isNetworkError && attempt < FlowGridTransport.MAX_RETRIES) {\n attempt++;\n await this.backoff(attempt);\n continue;\n }\n\n // Final failure — try sendBeacon, then buffer to localStorage\n if (attempt >= FlowGridTransport.MAX_RETRIES) {\n const beaconSent = body && typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function'\n ? navigator.sendBeacon(url, new Blob([body], { type: 'application/json' }))\n : false;\n\n if (!beaconSent) {\n this.bufferEvent(url, method, body);\n }\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(\"SDK request timed out\");\n }\n\n throw error;\n }\n }\n }\n\n /**\n * Exponential backoff: 1s, 2s, 4s ...\n */\n private backoff(attempt: number): Promise<void> {\n const ms = Math.pow(2, attempt - 1) * 1000;\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n /**\n * Validates event name and payload.\n *\n * @param eventName - Event identifier.\n * @param properties - Associated event properties.\n *\n * @throws {Error} If validation fails.\n */\n private validateInput(eventName: string, properties: Record<string, any>) {\n\n if (!eventName || typeof eventName !== \"string\" || !eventName.trim()) {\n throw new Error(\"Event name must be a non-empty string\");\n }\n\n if (eventName.length > 100) {\n throw new Error(\"Event name must be less than 100 characters\");\n }\n\n let serialized: string;\n\n try {\n serialized = JSON.stringify({\n web_id: this.webId,\n visitor_id: this.visitorId ?? '',\n event_name: eventName,\n properties,\n });\n } catch {\n throw new Error(\"Properties must be JSON serializable\");\n }\n\n if (new TextEncoder().encode(serialized).length > FlowGridTransport.MAX_PAYLOAD_SIZE) {\n throw new Error(\"Event payload too large (max 10KB)\");\n }\n\n const sensitiveKeys = [\"password\", \"token\", \"secret\", \"apikey\", \"authorization\"];\n const lower = serialized.toLowerCase();\n\n for (const key of sensitiveKeys) {\n if (lower.includes(key)) {\n console.warn(\n `SDK Warning: Properties may contain sensitive data (${key}).`\n );\n }\n }\n }\n\n /**\n * Normalizes endpoint input.\n * Ensures protocol is present and removes trailing slashes.\n *\n * @param endpoint - Raw endpoint string.\n * @returns Normalized endpoint URL.\n */\n private normalizeEndpoint(endpoint: string): string {\n let clean = endpoint.trim();\n\n if (!clean.startsWith(\"http://\") && !clean.startsWith(\"https://\")) {\n clean = `https://${clean}`;\n }\n\n return clean.replace(/\\/+$/, \"\");\n }\n\n /**\n * Safely reads response text without throwing.\n *\n * @param res - Fetch Response object.\n * @returns Response text or empty string.\n */\n private async safeRead(res: Response): Promise<string> {\n try {\n return await res.text();\n } catch {\n return \"\";\n }\n }\n}\n","/**\n * @fileoverview FlowGrid storage utilities.\n * @module utils/storage\n *\n * @description\n * Reads visitor identity and UTM attribution data from the same\n * cookie / localStorage / sessionStorage keys used by the FlowGrid\n * tracking scripts (track.js & flowgrid_oss_client_sdk.js).\n *\n * These functions are **read-only** — the tracking scripts remain the\n * single writer. The SDK only consumes these values.\n */\n\n// ============================================================================\n// COOKIE HELPERS\n// ============================================================================\n\n/**\n * Read a cookie value by name.\n * Returns `null` when the cookie is absent or document.cookie is unavailable.\n */\nexport function getCookie(name: string): string | null {\n if (typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));\n return match ? match[2] : null;\n}\n\n// ============================================================================\n// VISITOR IDENTITY\n// ============================================================================\n\n/**\n * Resolve the visitor ID written by track.js / flowgrid_oss_client_sdk.js.\n *\n * Storage locations (checked in order):\n * 1. cookie `visitor_id`\n * 2. localStorage `visitor_id`\n *\n * Returns `null` when neither source contains a value (e.g. tracking\n * script hasn't run yet, or running server-side).\n */\nexport function getVisitorId(): string | null {\n try {\n return getCookie('visitor_id') || localStorage.getItem('visitor_id');\n } catch {\n // localStorage unavailable (SSR, privacy mode, etc.)\n return getCookie('visitor_id');\n }\n}\n\n/**\n * Resolve the session ID written by track.js.\n *\n * Storage: `sessionStorage(\"session_id\")`\n */\nexport function getSessionId(): string | null {\n try {\n return sessionStorage.getItem('session_id');\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve the web_id written by track.js.\n *\n * Storage: `localStorage(\"web_id\")`\n */\nexport function getWebId(): string | null {\n try {\n return localStorage.getItem('web_id');\n } catch {\n return null;\n }\n}\n\n// ============================================================================\n// UTM / ATTRIBUTION\n// ============================================================================\n\nexport interface FlowGridUTM {\n utmSource?: string;\n utmMedium?: string;\n utmCampaign?: string;\n utmTerm?: string;\n utmContent?: string;\n ref?: string;\n source?: string;\n via?: string;\n}\n\n/**\n * Read UTM & attribution parameters persisted by\n * flowgrid_oss_client_sdk.js as `__flowgrid_*` cookies.\n */\nexport function getUTM(): FlowGridUTM {\n return {\n utmSource: getCookie('__flowgrid_utm_source') || undefined,\n utmMedium: getCookie('__flowgrid_utm_medium') || undefined,\n utmCampaign: getCookie('__flowgrid_utm_campaign') || undefined,\n utmTerm: getCookie('__flowgrid_utm_term') || undefined,\n utmContent: getCookie('__flowgrid_utm_content') || undefined,\n ref: getCookie('__flowgrid_ref') || undefined,\n source: getCookie('__flowgrid_source') || undefined,\n via: getCookie('__flowgrid_via') || undefined,\n };\n}\n\nexport interface FlowGridUTMHistoryEntry {\n timestamp: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_content?: string;\n utm_term?: string;\n}\n\n/**\n * Read the full UTM history array persisted by flowgrid_oss_client_sdk.js.\n *\n * Checks localStorage first, then the `utm_history` cookie.\n */\nexport function getUTMHistory(): FlowGridUTMHistoryEntry[] {\n try {\n const raw =\n localStorage.getItem('utm_history') ||\n getCookie('utm_history');\n return raw ? JSON.parse(raw) : [];\n } catch {\n return [];\n }\n}\n","/**\n * @fileoverview FlowGrid Identity Manager.\n * @module utils/identity\n *\n * @description\n * Owns the visitor/session identity lifecycle.\n * Writes its own cookies/storage so the SDK can self-bootstrap\n * without depending on an external tracking script (track.js).\n *\n * Backward-compatible: checks for existing track.js `visitor_id`\n * before falling back to its own `fg_visitor_id` key.\n */\n\nimport { getCookie, getVisitorId as getTrackJsVisitorId } from './storage';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport interface IdentityConfig {\n /** Explicit visitor ID (overrides auto-resolution) */\n visitorId?: string;\n /** Cookie domain (defaults to current hostname) */\n cookieDomain?: string;\n /** Visitor cookie max-age in days (default: 365) */\n visitorMaxAgeDays?: number;\n /** Session timeout in minutes (default: 30) */\n sessionTimeoutMinutes?: number;\n /** Storage strategy */\n storage?: 'cookie' | 'localStorage' | 'memory';\n /** Server-side cookie reader (e.g. Next.js `cookies()`) */\n serverCookies?: ServerCookieReader;\n /** Write to `visitor_id` (track.js compat) instead of `fg_visitor_id` (default true) */\n compat?: boolean;\n}\n\n/**\n * Minimal interface for reading cookies server-side.\n * Compatible with Next.js `cookies()` and Nuxt `useCookie()`.\n */\nexport interface ServerCookieReader {\n get(name: string): { value: string } | string | undefined | null;\n}\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst LEGACY_VISITOR_COOKIE = 'fg_visitor_id';\nconst COMPAT_VISITOR_COOKIE = 'visitor_id';\nconst SESSION_KEY = 'fg_session_id';\nconst SESSION_TOUCH_KEY = 'fg_session_touch';\n\n// ============================================================================\n// IDENTITY MANAGER\n// ============================================================================\n\nexport class IdentityManager {\n private visitorId: string = '';\n private sessionId: string = '';\n private config: Required<Omit<IdentityConfig, 'serverCookies'>> & { serverCookies?: ServerCookieReader; compat: boolean };\n\n /** In-memory store for SSR / Node environments */\n private memoryStore: Record<string, string> = {};\n\n constructor(config?: IdentityConfig) {\n this.config = {\n visitorId: config?.visitorId ?? '',\n cookieDomain: config?.cookieDomain ?? '',\n visitorMaxAgeDays: config?.visitorMaxAgeDays ?? 365,\n sessionTimeoutMinutes: config?.sessionTimeoutMinutes ?? 30,\n storage: config?.storage ?? (this.detectBrowser() ? 'cookie' : 'memory'),\n serverCookies: config?.serverCookies,\n compat: config?.compat ?? true,\n };\n\n this.visitorId = this.resolveVisitorId();\n this.sessionId = '';\n }\n\n // ---------------------------------------------------------------------------\n // PUBLIC API\n // ---------------------------------------------------------------------------\n\n /**\n * Get or create a persistent visitor ID.\n *\n * Resolution order:\n * 1. Explicit config.visitorId\n * 2. track.js `visitor_id` cookie/localStorage (backward compat)\n * 3. `fg_visitor_id` cookie\n * 4. `fg_visitor_id` localStorage\n * 5. Server cookie reader (if provided)\n * 6. Generate new UUID v4, persist to cookie + localStorage\n */\n getVisitorId(): string {\n if (this.visitorId) return this.visitorId;\n this.visitorId = this.resolveVisitorId();\n return this.visitorId;\n }\n\n /**\n * Get or create a session ID.\n *\n * - Reads from sessionStorage `fg_session_id`\n * - If absent or expired (>sessionTimeoutMinutes since last activity), creates new\n * - Persists to sessionStorage\n * - Touches timestamp on every call\n */\n getSessionId(): string {\n if (this.config.storage === 'memory') {\n return this.getMemorySessionId();\n }\n\n if (!this.detectBrowser()) {\n return this.getMemorySessionId();\n }\n\n try {\n const existing = sessionStorage.getItem(SESSION_KEY);\n const lastTouch = sessionStorage.getItem(SESSION_TOUCH_KEY);\n\n if (existing && lastTouch) {\n const elapsed = Date.now() - parseInt(lastTouch, 10);\n const timeoutMs = this.config.sessionTimeoutMinutes * 60 * 1000;\n if (elapsed < timeoutMs) {\n sessionStorage.setItem(SESSION_TOUCH_KEY, String(Date.now()));\n this.sessionId = existing;\n return existing;\n }\n }\n\n // Create new session\n const newSession = this.generateSessionId();\n sessionStorage.setItem(SESSION_KEY, newSession);\n sessionStorage.setItem(SESSION_TOUCH_KEY, String(Date.now()));\n this.sessionId = newSession;\n return newSession;\n } catch {\n return this.getMemorySessionId();\n }\n }\n\n /**\n * Update the visitor ID (e.g. after identify() links anonymous → known user).\n * Persists to cookie + localStorage.\n */\n setVisitorId(id: string): void {\n this.visitorId = id;\n this.persistVisitorId(id);\n }\n\n /** Clear session (e.g. on logout). */\n clearSession(): void {\n this.sessionId = '';\n delete this.memoryStore[SESSION_KEY];\n delete this.memoryStore[SESSION_TOUCH_KEY];\n\n if (this.detectBrowser()) {\n try {\n sessionStorage.removeItem(SESSION_KEY);\n sessionStorage.removeItem(SESSION_TOUCH_KEY);\n } catch { /* SSR / privacy mode */ }\n }\n }\n\n /** Clear all identity (GDPR). Removes visitor + session + experiment assignments. */\n clearAll(): void {\n this.visitorId = '';\n this.sessionId = '';\n this.memoryStore = {};\n\n if (!this.detectBrowser()) return;\n\n try {\n // Cookies\n this.deleteCookie(this.visitorCookieName);\n this.deleteCookie(LEGACY_VISITOR_COOKIE);\n\n // localStorage\n localStorage.removeItem(this.visitorCookieName);\n localStorage.removeItem(LEGACY_VISITOR_COOKIE);\n localStorage.removeItem('fg_exp_assignments');\n\n // sessionStorage\n sessionStorage.removeItem(SESSION_KEY);\n sessionStorage.removeItem(SESSION_TOUCH_KEY);\n } catch { /* SSR / privacy mode */ }\n }\n\n /** Check if running in a browser environment. */\n isBrowser(): boolean {\n return this.detectBrowser();\n }\n\n // ---------------------------------------------------------------------------\n // PRIVATE — VISITOR RESOLUTION\n // ---------------------------------------------------------------------------\n\n /** Returns the primary cookie name based on compat mode */\n private get visitorCookieName(): string {\n return this.config.compat ? COMPAT_VISITOR_COOKIE : LEGACY_VISITOR_COOKIE;\n }\n\n private resolveVisitorId(): string {\n // 1. Explicit config\n if (this.config.visitorId) return this.config.visitorId;\n\n // 2. track.js backward compat (cookie/localStorage `visitor_id`)\n if (this.detectBrowser()) {\n const trackJsId = getTrackJsVisitorId();\n if (trackJsId) {\n // Migration: if fg_visitor_id exists with a different value, prefer visitor_id (track.js was first)\n const legacyId = this.readCookie(LEGACY_VISITOR_COOKIE) || this.readLocalStorage(LEGACY_VISITOR_COOKIE);\n if (legacyId && legacyId !== trackJsId) {\n // Merge identities by keeping track.js id as canonical\n this.removeLegacyCookie();\n }\n this.persistVisitorId(trackJsId);\n return trackJsId;\n }\n }\n\n // 3. Migration: fg_visitor_id → visitor_id\n if (this.config.compat) {\n const legacyId = this.readCookie(LEGACY_VISITOR_COOKIE) || this.readLocalStorage(LEGACY_VISITOR_COOKIE);\n if (legacyId) {\n this.persistVisitorId(legacyId);\n this.removeLegacyCookie();\n return legacyId;\n }\n }\n\n // 4. Own cookie\n const cookieId = this.readCookie(this.visitorCookieName);\n if (cookieId) return cookieId;\n\n // 5. localStorage\n if (this.detectBrowser()) {\n try {\n const lsId = localStorage.getItem(this.visitorCookieName);\n if (lsId) return lsId;\n } catch { /* unavailable */ }\n }\n\n // 6. Server cookie reader\n if (this.config.serverCookies) {\n const serverVal = this.readServerCookie(this.visitorCookieName);\n if (serverVal) return serverVal;\n }\n\n // 7. Memory store\n if (this.memoryStore[this.visitorCookieName]) {\n return this.memoryStore[this.visitorCookieName];\n }\n\n // 8. Generate new ID\n const newId = this.generateVisitorId();\n this.persistVisitorId(newId);\n return newId;\n }\n\n private readLocalStorage(key: string): string | null {\n if (!this.detectBrowser()) return null;\n try { return localStorage.getItem(key); } catch { return null; }\n }\n\n private removeLegacyCookie(): void {\n this.deleteCookie(LEGACY_VISITOR_COOKIE);\n if (this.detectBrowser()) {\n try { localStorage.removeItem(LEGACY_VISITOR_COOKIE); } catch { /* */ }\n }\n }\n\n private persistVisitorId(id: string): void {\n const cookieName = this.visitorCookieName;\n\n if (this.config.storage === 'memory') {\n this.memoryStore[cookieName] = id;\n return;\n }\n\n if (!this.detectBrowser()) {\n this.memoryStore[cookieName] = id;\n return;\n }\n\n // Cookie\n this.writeCookie(cookieName, id, this.config.visitorMaxAgeDays);\n\n // localStorage as fallback\n try {\n localStorage.setItem(cookieName, id);\n } catch { /* unavailable */ }\n }\n\n // ---------------------------------------------------------------------------\n // PRIVATE — SESSION HELPERS\n // ---------------------------------------------------------------------------\n\n private getMemorySessionId(): string {\n const existing = this.memoryStore[SESSION_KEY];\n const lastTouch = this.memoryStore[SESSION_TOUCH_KEY];\n\n if (existing && lastTouch) {\n const elapsed = Date.now() - parseInt(lastTouch, 10);\n const timeoutMs = this.config.sessionTimeoutMinutes * 60 * 1000;\n if (elapsed < timeoutMs) {\n this.memoryStore[SESSION_TOUCH_KEY] = String(Date.now());\n this.sessionId = existing;\n return existing;\n }\n }\n\n const newSession = this.generateSessionId();\n this.memoryStore[SESSION_KEY] = newSession;\n this.memoryStore[SESSION_TOUCH_KEY] = String(Date.now());\n this.sessionId = newSession;\n return newSession;\n }\n\n // ---------------------------------------------------------------------------\n // PRIVATE — COOKIE OPERATIONS\n // ---------------------------------------------------------------------------\n\n private readCookie(name: string): string | null {\n // Server-side reader first\n if (this.config.serverCookies) {\n return this.readServerCookie(name);\n }\n\n // Browser cookie\n if (this.detectBrowser()) {\n return getCookie(name);\n }\n\n return null;\n }\n\n private readServerCookie(name: string): string | null {\n if (!this.config.serverCookies) return null;\n const result = this.config.serverCookies.get(name);\n if (!result) return null;\n // Next.js cookies().get() returns { value: string }\n if (typeof result === 'object' && 'value' in result) return result.value || null;\n // Nuxt useCookie() returns string directly\n if (typeof result === 'string') return result || null;\n return null;\n }\n\n private writeCookie(name: string, value: string, maxAgeDays: number): void {\n if (!this.detectBrowser()) return;\n\n const maxAge = maxAgeDays * 24 * 60 * 60;\n const domain = this.config.cookieDomain ? `; Domain=${this.config.cookieDomain}` : '';\n const secure = location.protocol === 'https:' ? '; Secure' : '';\n\n document.cookie = `${name}=${encodeURIComponent(value)}; Path=/; Max-Age=${maxAge}; SameSite=Lax${secure}${domain}`;\n }\n\n private deleteCookie(name: string): void {\n if (!this.detectBrowser()) return;\n const domain = this.config.cookieDomain ? `; Domain=${this.config.cookieDomain}` : '';\n document.cookie = `${name}=; Path=/; Max-Age=0${domain}`;\n }\n\n // ---------------------------------------------------------------------------\n // PRIVATE — ID GENERATION\n // ---------------------------------------------------------------------------\n\n private generateVisitorId(): string {\n return `fg_${this.uuidV4()}`;\n }\n\n private generateSessionId(): string {\n return `fgs_${Date.now()}_${this.randomHex(8)}`;\n }\n\n private uuidV4(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for environments without crypto.randomUUID\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n private randomHex(length: number): string {\n const bytes = new Uint8Array(length);\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\n crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < length; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n }\n\n // ---------------------------------------------------------------------------\n // PRIVATE — ENVIRONMENT DETECTION\n // ---------------------------------------------------------------------------\n\n private detectBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n }\n}\n","/**\n * @fileoverview Core - User Activation Tracking\n * @module features/core/activation\n * \n * @description\n * Track user activation events including onboarding steps,\n * signup completions, and first-time actions.\n * \n * @useCases\n * - Track onboarding step completions\n * - Monitor signup funnel\n * - Measure time to first value\n * - Identify activation bottlenecks\n * - A/B test onboarding flows\n * \n * @metrics\n * - Activation rate\n * - Onboarding completion rate\n * - Time to activate\n * - Drop-off by step\n * - Activation by source\n * \n * @chartData\n * - Funnel chart: Onboarding steps\n * - Line chart: Activation rate over time\n * - Bar chart: Activation by cohort/source\n * - KPI: Time to first value\n * \n * @example\n * ```typescript\n * const activation = new Activation(webId, endpoint, apiKey);\n * \n * // Track activation event\n * await activation.create({\n * eventName: 'onboarding_completed',\n * properties: { userId: 'user_123', step: 'profile_setup' }\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { TimeSeriesData } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Base configuration for activation events.\n */\nexport interface ActivationConfig {\n /** Event name */\n eventName: string;\n /** Event properties */\n properties: Record<string, unknown>;\n}\n\n/**\n * Onboarding step configuration.\n */\nexport interface OnboardingStepConfig {\n /** User ID */\n userId: string;\n /** Step identifier */\n stepId: string;\n /** Step name */\n stepName: string;\n /** Step order/number */\n stepOrder: number;\n /** Total steps in flow */\n totalSteps: number;\n /** Time spent on step (ms) */\n timeSpent?: number;\n /** Whether step was skipped */\n skipped?: boolean;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * First action configuration.\n */\nexport interface FirstActionConfig {\n /** User ID */\n userId: string;\n /** Action name */\n actionName: string;\n /** Time since signup (ms) */\n timeSinceSignup: number;\n /** Source/referrer */\n source?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Activation response from API.\n */\nexport interface ActivationResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n tracked: boolean;\n activationId?: string;\n isFirstActivation?: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Activation analytics data.\n */\nexport interface ActivationAnalyticsData {\n /** Summary metrics */\n summary: {\n totalSignups: number;\n activatedUsers: number;\n activationRate: number;\n avgTimeToActivate: number;\n onboardingCompletionRate: number;\n };\n /** Activation by step */\n byStep: Array<{\n stepId: string;\n stepName: string;\n started: number;\n completed: number;\n dropOff: number;\n avgTimeSpent: number;\n }>;\n /** Activation by source */\n bySource: Array<{\n source: string;\n signups: number;\n activated: number;\n activationRate: number;\n }>;\n /** Activation trends */\n trends: TimeSeriesData;\n /** Cohort activation */\n byCohort: Array<{\n cohort: string;\n users: number;\n activated: number;\n activationRate: number;\n avgTimeToActivate: number;\n }>;\n}\n\n// ============================================================================\n// ACTIVATION CLASS\n// ============================================================================\n\n/**\n * Activation - Track user activation events.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides activation tracking including:\n * - Generic activation events\n * - Onboarding step tracking\n * - First action tracking\n * - Signup completion\n * - Activation analytics\n * \n * @example\n * ```typescript\n * const activation = new Activation(webId, endpoint, apiKey);\n * \n * // Track onboarding step\n * await activation.trackOnboardingStep({\n * userId: 'user_123',\n * stepId: 'profile_setup',\n * stepName: 'Set Up Profile',\n * stepOrder: 2,\n * totalSteps: 5\n * });\n * \n * // Track first value action\n * await activation.trackFirstAction({\n * userId: 'user_123',\n * actionName: 'created_first_project',\n * timeSinceSignup: 3600000 // 1 hour\n * });\n * ```\n */\nexport class Activation extends FlowGridTransport {\n /**\n * Creates and tracks an activation event.\n * \n * @param config - Activation configuration\n * @returns Promise resolving to activation response\n */\n async create(config: ActivationConfig): Promise<ActivationResponse> {\n return await this.init(config.eventName, {\n ...config.properties,\n type: \"activation\",\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks an onboarding step completion.\n * \n * @param config - Onboarding step configuration\n * @returns Promise resolving to activation response\n */\n async trackOnboardingStep(config: OnboardingStepConfig): Promise<ActivationResponse> {\n return await this.init(\"onboarding_step\", {\n type: \"activation\",\n subtype: \"onboarding_step\",\n userId: config.userId,\n stepId: config.stepId,\n stepName: config.stepName,\n stepOrder: config.stepOrder,\n totalSteps: config.totalSteps,\n progress: Math.round((config.stepOrder / config.totalSteps) * 100),\n timeSpent: config.timeSpent,\n skipped: config.skipped || false,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks onboarding completion.\n * \n * @param userId - User ID\n * @param totalTimeSpent - Total time in onboarding (ms)\n * @param stepsCompleted - Number of steps completed\n * @param stepsSkipped - Number of steps skipped\n * @returns Promise resolving to activation response\n */\n async completeOnboarding(\n userId: string,\n totalTimeSpent: number,\n stepsCompleted: number,\n stepsSkipped: number\n ): Promise<ActivationResponse> {\n return await this.init(\"onboarding_completed\", {\n type: \"activation\",\n subtype: \"onboarding_complete\",\n userId,\n totalTimeSpent,\n stepsCompleted,\n stepsSkipped,\n completionRate: Math.round((stepsCompleted / (stepsCompleted + stepsSkipped)) * 100),\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks user's first meaningful action (activation moment).\n * \n * @param config - First action configuration\n * @returns Promise resolving to activation response\n */\n async trackFirstAction(config: FirstActionConfig): Promise<ActivationResponse> {\n return await this.init(\"first_action\", {\n type: \"activation\",\n subtype: \"first_action\",\n userId: config.userId,\n actionName: config.actionName,\n timeSinceSignup: config.timeSinceSignup,\n source: config.source,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks signup completion.\n * \n * @param userId - User ID\n * @param method - Signup method (email, google, etc.)\n * @param source - Traffic source\n * @param properties - Additional properties\n * @returns Promise resolving to activation response\n */\n async trackSignup(\n userId: string,\n method: 'email' | 'google' | 'github' | 'apple' | 'sso' | string,\n source?: string,\n properties?: Record<string, unknown>\n ): Promise<ActivationResponse> {\n return await this.init(\"signup_completed\", {\n type: \"activation\",\n subtype: \"signup\",\n userId,\n method,\n source,\n ...properties,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Activation;\n","/**\n * @fileoverview Core - Feature Usage Tracking\n * @module features/core/track-feature\n * \n * @description\n * Track feature usage events to understand how users\n * interact with different parts of your product.\n * \n * @useCases\n * - Track feature adoption rates\n * - Measure feature engagement\n * - Identify power users\n * - Prioritize feature development\n * - Detect underused features\n * \n * @metrics\n * - Feature adoption rate\n * - Feature usage frequency\n * - Users per feature\n * - Feature stickiness\n * - Time spent per feature\n * \n * @chartData\n * - Bar chart: Most used features\n * - Heatmap: Feature usage by user segment\n * - Line chart: Feature adoption over time\n * - Table: Feature engagement metrics\n * \n * @example\n * ```typescript\n * const trackFeature = new TrackFeature(webId, endpoint, apiKey);\n * \n * await trackFeature.create({\n * userId: 'user_123',\n * action: 'export_report',\n * properties: { featureName: 'export_report', featureId: 'export_report_001' }\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { TimeSeriesData } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n\ntype FeatureConfigProperties = {\n featureId?: string;\n featureName: string;\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Base configuration for feature tracking.\n */\nexport interface FeatureConfig {\n /** Feature tracking properties */\n action: string;\n\n /** Feature category */\n category?: string;\n\n userId: string;\n\n /** Event properties */\n properties: FeatureConfigProperties;\n\n}\n\n/**\n * Detailed feature usage configuration.\n */\nexport interface FeatureUsageConfig {\n /** Feature identifier */\n featureId: string;\n /** Feature name */\n featureName: string;\n /** User ID */\n userId?: string;\n /** Usage action */\n action: 'viewed' | 'used' | 'completed' | 'abandoned';\n /** Time spent (ms) */\n duration?: number;\n /** Success/failure */\n success?: boolean;\n /** Feature category */\n category?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Feature discovery configuration.\n */\nexport interface FeatureDiscoveryConfig {\n /** Feature identifier */\n featureId: string;\n /** User ID */\n userId: string;\n /** How feature was discovered */\n discoveryMethod: 'organic' | 'tooltip' | 'announcement' | 'search' | 'onboarding' | 'recommendation' | string;\n /** Whether user engaged with feature */\n engaged: boolean;\n}\n\n/**\n * Feature tracking response.\n */\nexport interface FeatureResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n tracked: boolean;\n featureId?: string;\n isFirstUse?: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Feature analytics data.\n */\nexport interface FeatureAnalyticsData {\n /** Summary metrics */\n summary: {\n totalFeatures: number;\n totalUsage: number;\n uniqueUsers: number;\n avgUsagePerUser: number;\n mostUsedFeature: string;\n leastUsedFeature: string;\n };\n /** Usage by feature */\n byFeature: Array<{\n featureId: string;\n featureName: string;\n category: string;\n usageCount: number;\n uniqueUsers: number;\n adoptionRate: number;\n avgDuration: number;\n successRate: number;\n }>;\n /** Usage by user segment */\n bySegment: Array<{\n segment: string;\n topFeatures: string[];\n avgFeaturesUsed: number;\n }>;\n /** Feature trends */\n trends: TimeSeriesData;\n /** Feature correlations */\n correlations: Array<{\n featureA: string;\n featureB: string;\n correlation: number;\n }>;\n}\n\n// ============================================================================\n// TRACK FEATURE CLASS\n// ============================================================================\n\n/**\n * TrackFeature - Track feature usage events.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides feature tracking including:\n * - Generic feature events\n * - Detailed usage tracking\n * - Feature discovery tracking\n * \n * @example\n * ```typescript\n * const trackFeature = new TrackFeature(webId, endpoint, apiKey);\n * \n * // Simple feature tracking\n * await trackFeature.create({\n * userId: 'user_123',\n * action: 'dark_mode_enabled',\n * properties: { featureName: 'dark_mode' }\n * });\n * \n * // Detailed feature usage\n * await trackFeature.trackUsage({\n * featureId: 'export',\n * featureName: 'Data Export',\n * userId: 'user_123',\n * action: 'completed',\n * duration: 5000,\n * success: true,\n * properties: { format: 'csv' }\n * });\n * ```\n */\n\nexport class TrackFeature extends FlowGridTransport {\n /**\n * Records a feature usage event.\n * \n * @param config - Feature configuration\n * @returns Promise resolving to feature response\n */\n async create(config: FeatureConfig): Promise<FeatureResponse> {\n return await this.init(\"create_tracking\", {\n type: \"feature_usage\",\n subtype: \"create_custom\",\n userId: config.userId,\n category: config.category,\n action: config.action,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks detailed feature usage.\n * \n * @param config - Feature usage configuration\n * @returns Promise resolving to feature response\n */\n async trackUsage(config: FeatureUsageConfig): Promise<FeatureResponse> {\n return await this.init(\"feature_usage\", {\n type: \"feature_usage\",\n subtype: config.action,\n featureId: config.featureId,\n featureName: config.featureName,\n userId: config.userId,\n action: config.action,\n duration: config.duration,\n success: config.success,\n category: config.category,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n}\n\nexport default TrackFeature;\n","/**\n * @fileoverview Core - Prompt & AI Interaction Tracking\n * @module features/core/track-prompt\n * \n * @description\n * Track AI prompt interactions, completions, and user feedback\n * for AI-powered features.\n * \n * @useCases\n * - Track AI prompt submissions\n * - Monitor response quality\n * - Measure user satisfaction\n * - Analyze prompt patterns\n * - Optimize AI features\n * \n * @metrics\n * - Prompts per user\n * - Response acceptance rate\n * - Average response time\n * - User satisfaction score\n * - Token usage\n * \n * @chartData\n * - Line chart: Prompts over time\n * - Bar chart: Prompts by category\n * - Histogram: Response time distribution\n * - Gauge: Satisfaction score\n * \n * @example\n * ```typescript\n * const trackPrompt = new TrackPrompt(webId, endpoint, apiKey);\n * \n * await trackPrompt.create({\n * eventName: 'ai_completion',\n * properties: { \n * promptType: 'code_suggestion',\n * accepted: true \n * }\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { TimeSeriesData } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Base configuration for prompt events.\n */\nexport interface PromptConfig {\n /** Event name */\n eventName: string;\n /** Event properties */\n properties: Record<string, unknown>;\n}\n\n/**\n * AI prompt submission configuration.\n */\nexport interface PromptSubmissionConfig {\n /** Prompt ID */\n promptId: string;\n /** User ID */\n userId?: string;\n /** Prompt text (may be truncated/hashed for privacy) */\n promptText?: string;\n /** Prompt category/type */\n promptType: string;\n /** Model used */\n model?: string;\n /** Input token count */\n inputTokens?: number;\n /** Session/conversation ID */\n conversationId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * AI response configuration.\n */\nexport interface PromptResponseConfig {\n /** Prompt ID */\n promptId: string;\n /** Response time (ms) */\n responseTime: number;\n /** Output token count */\n outputTokens?: number;\n /** Whether response completed */\n completed: boolean;\n /** Error if any */\n error?: string;\n /** Response quality (if auto-detected) */\n qualityScore?: number;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * User feedback on AI response.\n */\nexport interface PromptFeedbackConfig {\n /** Prompt ID */\n promptId: string;\n /** User ID */\n userId?: string;\n /** Feedback type */\n feedbackType: 'accepted' | 'rejected' | 'edited' | 'thumbs_up' | 'thumbs_down';\n /** Rating (1-5) */\n rating?: number;\n /** User comment */\n comment?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Prompt tracking response.\n */\nexport interface PromptResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n tracked: boolean;\n promptId?: string;\n };\n timestamp: string;\n}\n\n/**\n * Prompt analytics data.\n */\nexport interface PromptAnalyticsData {\n /** Summary metrics */\n summary: {\n totalPrompts: number;\n uniqueUsers: number;\n avgResponseTime: number;\n acceptanceRate: number;\n avgSatisfactionScore: number;\n totalTokensUsed: number;\n errorRate: number;\n };\n /** Usage by prompt type */\n byType: Array<{\n promptType: string;\n count: number;\n acceptanceRate: number;\n avgResponseTime: number;\n avgTokens: number;\n }>;\n /** Usage by model */\n byModel: Array<{\n model: string;\n count: number;\n avgResponseTime: number;\n errorRate: number;\n }>;\n /** Feedback breakdown */\n feedback: {\n accepted: number;\n rejected: number;\n edited: number;\n thumbsUp: number;\n thumbsDown: number;\n };\n /** Trends */\n trends: TimeSeriesData;\n}\n\n// ============================================================================\n// TRACK PROMPT CLASS\n// ============================================================================\n\n/**\n * TrackPrompt - Track AI prompt interactions.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides prompt tracking including:\n * - Prompt submissions\n * - Response tracking\n * - User feedback\n * - Quality metrics\n * - Usage analytics\n * \n * @example\n * ```typescript\n * const trackPrompt = new TrackPrompt(webId, endpoint, apiKey);\n * \n * // Track prompt submission\n * await trackPrompt.trackSubmission({\n * promptId: 'prompt_123',\n * userId: 'user_456',\n * promptType: 'code_completion',\n * model: 'gpt-4',\n * inputTokens: 150\n * });\n * \n * // Track response\n * await trackPrompt.trackResponse({\n * promptId: 'prompt_123',\n * responseTime: 1200,\n * outputTokens: 300,\n * completed: true\n * });\n * \n * // Track user feedback\n * await trackPrompt.trackFeedback({\n * promptId: 'prompt_123',\n * feedbackType: 'accepted',\n * rating: 5\n * });\n * ```\n */\nexport class TrackPrompt extends FlowGridTransport {\n /**\n * Creates and tracks a prompt event.\n * \n * @param config - Prompt configuration\n * @returns Promise resolving to prompt response\n */\n async create(config: PromptConfig): Promise<PromptResponse> {\n return await this.init(config.eventName, {\n ...config.properties,\n type: \"prompt\",\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a prompt submission.\n * \n * @param config - Prompt submission configuration\n * @returns Promise resolving to prompt response\n */\n async trackSubmission(config: PromptSubmissionConfig): Promise<PromptResponse> {\n return await this.init(\"prompt_submitted\", {\n type: \"prompt\",\n subtype: \"submission\",\n promptId: config.promptId,\n userId: config.userId,\n promptType: config.promptType,\n model: config.model,\n inputTokens: config.inputTokens,\n conversationId: config.conversationId,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a prompt response.\n * \n * @param config - Prompt response configuration\n * @returns Promise resolving to prompt response\n */\n async trackResponse(config: PromptResponseConfig): Promise<PromptResponse> {\n return await this.init(\"prompt_response\", {\n type: \"prompt\",\n subtype: \"response\",\n promptId: config.promptId,\n responseTime: config.responseTime,\n outputTokens: config.outputTokens,\n completed: config.completed,\n error: config.error,\n qualityScore: config.qualityScore,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks user feedback on a prompt response.\n * \n * @param config - Prompt feedback configuration\n * @returns Promise resolving to prompt response\n */\n async trackFeedback(config: PromptFeedbackConfig): Promise<PromptResponse> {\n return await this.init(\"prompt_feedback\", {\n type: \"prompt\",\n subtype: \"feedback\",\n promptId: config.promptId,\n userId: config.userId,\n feedbackType: config.feedbackType,\n rating: config.rating,\n comment: config.comment,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a conversation/multi-turn prompt session.\n * \n * @param conversationId - Conversation ID\n * @param userId - User ID\n * @param turnCount - Number of turns\n * @param totalDuration - Total conversation duration (ms)\n * @returns Promise resolving to prompt response\n */\n async trackConversation(\n conversationId: string,\n userId: string,\n turnCount: number,\n totalDuration: number\n ): Promise<PromptResponse> {\n return await this.init(\"prompt_conversation\", {\n type: \"prompt\",\n subtype: \"conversation\",\n conversationId,\n userId,\n turnCount,\n totalDuration,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default TrackPrompt;\n","/**\n * @fileoverview Core - A/B Testing & Experiments\n * @module features/core/experiment\n * \n * @description\n * Track A/B tests, experiments, and variant assignments\n * to measure impact and optimize product decisions.\n * \n * @useCases\n * - Run A/B tests on features\n * - Track variant assignments\n * - Measure experiment impact\n * - Statistical significance analysis\n * - Multi-variant testing\n * \n * @metrics\n * - Conversion by variant\n * - Statistical significance\n * - Sample size per variant\n * - Experiment duration\n * - Impact on key metrics\n * \n * @chartData\n * - Bar chart: Conversion by variant\n * - Line chart: Metric trends by variant\n * - Table: Experiment results summary\n * - Confidence interval visualization\n * \n * @example\n * ```typescript\n * const experiment = new Experiment(webId, endpoint, apiKey);\n * \n * await experiment.track({\n * eventName: 'checkout_flow_test',\n * variant: 'simplified_v2',\n * properties: { userId: 'user_123' }\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { TimeSeriesData } from \"../../types\";\nimport { ServerCookieReader } from \"../../utils/identity\";\nimport { getCookie } from \"../../utils/storage\";\n\n// ============================================================================\n// HASHING UTILITY (FNV-1a)\n// ============================================================================\n\n/**\n * FNV-1a 32-bit hash — lightweight deterministic hash for variant assignment.\n * Ensures the same user always gets the same variant regardless of device.\n */\nfunction fnv1a(input: string): number {\n let hash = 0x811c9dc5; // FNV offset basis\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = (hash * 0x01000193) >>> 0; // FNV prime, unsigned 32-bit\n }\n return hash;\n}\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking an experiment-related event.\n *\n * Used when sending a generic experiment event with a specific variant\n * and associated properties.\n */\nexport interface ExperimentConfig {\n /** Logical experiment event name */\n eventName: string;\n\n /** Variant identifier associated with this event */\n variant: string;\n\n /** Additional contextual event data */\n properties: Record<string, unknown>;\n}\n\n/**\n * Defines the structure and metadata of an experiment.\n *\n * Used when creating or updating an experiment configuration.\n */\nexport interface ExperimentDefinition {\n /** Unique identifier for the experiment */\n experimentId: string;\n\n /** Human-readable experiment name */\n name: string;\n\n /** Optional description of experiment purpose */\n description?: string;\n\n /**\n * Variants participating in the experiment.\n *\n * Shape matches the verify endpoint and the client-side engine:\n * `{ id, weight }` (with optional human-readable `name`).\n */\n variants: Array<{\n /** Unique identifier for the variant */\n id: string;\n\n /** Traffic allocation weight (relative distribution) */\n weight: number;\n\n /** Optional human-readable variant name */\n name?: string;\n }>;\n\n /**\n * Optional audience configuration.\n * Allows limiting exposure by percentage and/or filter conditions.\n */\n audience?: {\n /** Percentage of total traffic eligible (0–100) */\n percentage: number;\n\n /** Attribute-based targeting filters */\n filters?: Record<string, unknown>;\n };\n\n /** Primary metric used to evaluate experiment success */\n primaryMetric: string;\n\n /** Optional secondary metrics */\n secondaryMetrics?: string[];\n\n /** Optional ISO start date */\n startDate?: string;\n\n /** Optional ISO end date */\n endDate?: string;\n}\n\n/**\n * Configuration for assigning a user to a specific experiment variant.\n *\n * Represents an explicit assignment event.\n */\nexport interface ExperimentAssignmentConfig {\n /** Experiment identifier */\n experimentId: string;\n\n /** Unique user identifier */\n userId: string;\n\n /** Assigned variant identifier */\n variantId: string;\n\n /**\n * Assignment origin:\n * - random: weighted allocation\n * - targeted: rule-based assignment\n * - override: manual or forced assignment\n */\n source?: 'random' | 'targeted' | 'override';\n}\n\n/**\n * Configuration for recording a conversion event within an experiment.\n *\n * Used to attribute metric changes to a specific variant.\n */\nexport interface ExperimentConversionConfig {\n /** Experiment identifier */\n experimentId: string;\n\n /** Unique user identifier */\n userId: string;\n\n /** Variant associated with the user */\n variantId: string;\n\n /** Metric name being recorded */\n metricName: string;\n\n /** Numeric metric value */\n value: number;\n}\n\n/**\n * Standardized response returned from experiment tracking operations.\n *\n * Ensures consistent structure across assignment, exposure,\n * definition, and conversion events.\n */\nexport interface ExperimentResponse {\n /** Event name associated with the request */\n eventName: string;\n\n /** Properties sent with the event */\n properties: Record<string, unknown>;\n\n /** Server acknowledgment metadata */\n response: {\n /** Indicates whether the event was successfully recorded */\n tracked: boolean;\n\n /** Optional experiment identifier */\n experimentId?: string;\n\n /** Optional variant identifier */\n variantId?: string;\n };\n\n /** ISO timestamp of the recorded event */\n timestamp: string;\n}\n\n/**\n * Aggregated results for a single experiment.\n *\n * Represents computed performance metrics per variant.\n */\nexport interface ExperimentResultsData {\n /** Experiment metadata */\n experiment: {\n experimentId: string;\n name: string;\n status: 'running' | 'paused' | 'completed';\n startDate: string;\n /** Duration in days */\n duration: number;\n };\n\n /** Variant-level performance metrics */\n variants: Array<{\n variantId: string;\n name: string;\n\n /** Total participants assigned */\n participants: number;\n\n /** Total recorded conversions */\n conversions: number;\n\n /** conversions / participants */\n conversionRate: number;\n\n /** Relative improvement compared to baseline */\n improvement: number;\n\n /** Statistical confidence level (0–1 or percentage depending on backend) */\n confidence: number;\n\n /** Indicates highest performing variant */\n isWinner: boolean;\n\n /** Indicates whether statistical threshold is met */\n isStatisticallySignificant: boolean;\n }>;\n\n /** Time-series metric trends per metric name */\n trends: Record<string, TimeSeriesData>;\n\n /** System-generated recommendation */\n recommendation: {\n action: 'ship_winner' | 'continue' | 'stop' | 'needs_more_data';\n winningVariant?: string;\n confidence: number;\n reason: string;\n };\n}\n\n/**\n * Aggregated analytics across all experiments.\n *\n * Provides high-level performance and activity overview.\n */\nexport interface ExperimentAnalyticsData {\n /** Platform-wide experiment summary */\n summary: {\n totalExperiments: number;\n activeExperiments: number;\n completedExperiments: number;\n avgExperimentDuration: number;\n winRate: number;\n };\n\n /** Currently active experiments */\n active: Array<{\n experimentId: string;\n name: string;\n participants: number;\n daysSinceStart: number;\n leadingVariant: string;\n confidence: number;\n }>;\n\n /** Recently completed experiments */\n recentResults: Array<{\n experimentId: string;\n name: string;\n winner: string;\n improvement: number;\n completedDate: string;\n }>;\n}\n\nexport interface VariantResponse {\n experimentId: string;\n userId?: string;\n variantId: string;\n assignedAt: string;\n}\n\n/**\n * Local experiment variant definition used by the client-side\n * assignment engine (ported from sdk.js).\n */\nexport interface ExperimentVariant {\n /** Variant identifier */\n id: string;\n /** Traffic allocation weight */\n weight: number;\n}\n\n/**\n * Lightweight experiment config passed to `initExperiments()`.\n */\nexport interface ExperimentInitConfig {\n /** Unique experiment identifier */\n id: string;\n /** Weighted variant list */\n variants: ExperimentVariant[];\n /** Optional properties forwarded to the verify endpoint */\n properties?: Record<string, unknown>;\n}\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst ASSIGNMENT_STORAGE_KEY = 'fg_exp_assignments';\nconst ASSIGNMENT_COOKIE_KEY = 'fg_exp_assignments';\nconst ASSIGNMENT_COOKIE_MAX_AGE_DAYS = 365;\n\n// ============================================================================\n// EXPERIMENT CLASS\n// ============================================================================\n\n/**\n * Experiment - A/B Testing & Experimentation SDK\n *\n * @extends FlowGridTransport\n *\n * @description\n * Provides structured experiment lifecycle management including:\n * - Experiment definition\n * - Deterministic or server-based variant assignment\n * - Exposure tracking\n * - Conversion tracking\n * - Statistical results & analysis\n *\n * This class enforces correct HTTP semantics:\n *\n * Exposure and conversion events are strictly POST to preserve:\n * - Statistical validity\n * - Unique participant counting\n * - Accurate conversion attribution\n * - Idempotent replay safety\n *\n * @lifecycle\n * 1. Define experiment\n * 2. Assign user to variant\n * 3. Track exposure (when user actually sees variant)\n * 4. Track conversions (primary/secondary metrics)\n * 5. Query results & statistical analysis\n *\n * @statistical_model\n * - Variant-level sample sizes tracked independently\n * - Conversion rates calculated per variant\n * - Confidence intervals computed server-side\n * - Statistical significance evaluated against control\n *\n * @guarantees\n * - Assignment is explicitly recorded\n * - Exposure tracking is immutable\n * - Conversion events are attributable to assigned variant\n * - Results queries never mutate experiment state\n *\n * @example\n * ```typescript\n * const experiment = new Experiment(webId, endpoint, apiKey);\n *\n * // 1. Define experiment\n * await experiment.define({\n * experimentId: 'checkout_v2',\n * name: 'Simplified Checkout',\n * variants: [\n * { variantId: 'control', name: 'Current', weight: 50 },\n * { variantId: 'treatment', name: 'Simplified', weight: 50 }\n * ],\n * primaryMetric: 'checkout_completed'\n * });\n *\n * // 2. Assign user\n * await experiment.assign({\n * experimentId: 'checkout_v2',\n * userId: 'user_123',\n * variantId: 'treatment'\n * });\n *\n * // 3. Track exposure\n * await experiment.trackExposure('checkout_v2', 'user_123', 'treatment');\n *\n * // 4. Track conversion\n * await experiment.trackConversion({\n * experimentId: 'checkout_v2',\n * userId: 'user_123',\n * variantId: 'treatment',\n * metricName: 'checkout_completed',\n * value: 1\n * });\n *\n * // 5. Fetch results\n * const results = await experiment.getResults('checkout_v2');\n * ```\n */\nexport class Experiment extends FlowGridTransport {\n\n // ---------------------------------------------------------------------------\n // CLIENT-SIDE EXPERIMENT ENGINE STATE\n // ---------------------------------------------------------------------------\n\n /** Verified experiment configs: { [experiment_id]: { variants, properties, verified } } */\n private experiments: Record<string, {\n variants: ExperimentVariant[];\n properties: Record<string, unknown>;\n verified: boolean;\n }> = {};\n\n /** Local variant assignments: { [experiment_id]: variant_id } */\n private assignments: Record<string, string> = {};\n\n // ---------------------------------------------------------------------------\n // CLIENT-SIDE ENGINE — SSR-safe persistence (localStorage + cookie mirror)\n // ---------------------------------------------------------------------------\n\n /**\n * Decode the cookie’s URL-encoded JSON payload into an assignment map.\n * Returns `{}` on any parse failure so a stale cookie never throws.\n */\n private parseAssignmentCookie(raw: string | null): Record<string, string> {\n if (!raw) return {};\n try {\n const decoded = decodeURIComponent(raw);\n const parsed = JSON.parse(decoded);\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n }\n\n private readAssignmentCookie(): Record<string, string> {\n return this.parseAssignmentCookie(getCookie(ASSIGNMENT_COOKIE_KEY));\n }\n\n /**\n * Persist `this.assignments` to a first-party cookie so SSR requests on\n * subsequent navigations see the same variant. Best-effort — no-op in\n * non-browser contexts or when document.cookie is unavailable.\n */\n private writeAssignmentCookie(): void {\n try {\n if (typeof document === 'undefined') return;\n const value = encodeURIComponent(JSON.stringify(this.assignments));\n const maxAge = ASSIGNMENT_COOKIE_MAX_AGE_DAYS * 24 * 60 * 60;\n const sameSite = 'Lax';\n const secure = typeof location !== 'undefined' && location.protocol === 'https:'\n ? '; Secure'\n : '';\n document.cookie = `${ASSIGNMENT_COOKIE_KEY}=${value}; Path=/; Max-Age=${maxAge}; SameSite=${sameSite}${secure}`;\n } catch { /* SSR or restricted env */ }\n }\n\n private loadAssignments(): Record<string, string> {\n // 1. localStorage — authoritative on the client\n try {\n if (typeof localStorage !== 'undefined') {\n const stored = localStorage.getItem(ASSIGNMENT_STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (parsed && typeof parsed === 'object') return parsed;\n }\n }\n } catch { /* SSR or privacy mode */ }\n\n // 2. Cookie fallback — lets SSR + first-paint resolve a variant\n const cookieAssignments = this.readAssignmentCookie();\n if (Object.keys(cookieAssignments).length > 0) return cookieAssignments;\n\n return {};\n }\n\n private saveAssignments(): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(ASSIGNMENT_STORAGE_KEY, JSON.stringify(this.assignments));\n }\n } catch { /* SSR or privacy mode */ }\n // Mirror to cookie so the next SSR request can hydrate without flashing.\n this.writeAssignmentCookie();\n }\n\n /**\n * Inject assignments from server context (SSR/Node).\n * Use this when assignments were resolved server-side and need to be\n * available before localStorage is accessible.\n */\n injectAssignments(assignments: Record<string, string>): void {\n this.assignments = { ...this.assignments, ...assignments };\n }\n\n /**\n * Returns all current assignments (for SSR hydration).\n */\n getAssignments(): Record<string, string> {\n return { ...this.assignments };\n }\n\n /**\n * Hydrate assignments from a server-side cookie reader\n * (Next.js `cookies()`, Nuxt `useCookie()`, Hono ctx, etc.).\n *\n * @example\n * ```ts\n * import { cookies } from \"next/headers\";\n * fg.experiments.client.hydrateFromCookies(cookies());\n * const variant = fg.experiments.variant(\"checkout_v2\");\n * ```\n */\n hydrateFromCookies(reader: ServerCookieReader): void {\n const raw = reader.get(ASSIGNMENT_COOKIE_KEY);\n const value = typeof raw === 'string' ? raw : raw?.value ?? null;\n const parsed = this.parseAssignmentCookie(value ?? null);\n if (Object.keys(parsed).length > 0) this.injectAssignments(parsed);\n }\n\n /**\n * Hydrate assignments from a raw `Cookie` request header string.\n * Useful for runtimes without a structured cookie reader (Workers, Bun, etc.).\n */\n hydrateFromCookieHeader(cookieHeader: string | null | undefined): void {\n if (!cookieHeader) return;\n const parts = cookieHeader.split(/;\\s*/);\n const prefix = `${ASSIGNMENT_COOKIE_KEY}=`;\n const match = parts.find(p => p.startsWith(prefix));\n if (!match) return;\n const parsed = this.parseAssignmentCookie(match.slice(prefix.length));\n if (Object.keys(parsed).length > 0) this.injectAssignments(parsed);\n }\n\n /**\n * Serialise current assignments as a `Set-Cookie` header value.\n * Use server-side after a server-only assignment so the response can\n * seed the visitor’s browser with the same variant.\n */\n serializeAssignmentCookie(): string {\n const value = encodeURIComponent(JSON.stringify(this.assignments));\n const maxAge = ASSIGNMENT_COOKIE_MAX_AGE_DAYS * 24 * 60 * 60;\n return `${ASSIGNMENT_COOKIE_KEY}=${value}; Path=/; Max-Age=${maxAge}; SameSite=Lax`;\n }\n\n /**\n * Clear all locally cached assignments (cookie + localStorage + memory).\n * Useful for logout flows or test resets.\n */\n clearAssignments(): void {\n this.assignments = {};\n try {\n if (typeof localStorage !== 'undefined') localStorage.removeItem(ASSIGNMENT_STORAGE_KEY);\n } catch { /* noop */ }\n try {\n if (typeof document !== 'undefined') {\n document.cookie = `${ASSIGNMENT_COOKIE_KEY}=; Path=/; Max-Age=0; SameSite=Lax`;\n }\n } catch { /* noop */ }\n }\n\n // ---------------------------------------------------------------------------\n // CLIENT-SIDE ENGINE — stable anonymous ID\n // ---------------------------------------------------------------------------\n\n private static readonly ANON_ID_KEY = 'fg_anon_id';\n\n /**\n * Returns a stable anonymous ID. Generates a UUID on first call and\n * persists it in localStorage so the same anonymous visitor always\n * receives a consistent variant assignment.\n */\n private getOrCreateAnonId(): string {\n try {\n if (typeof localStorage !== 'undefined') {\n const existing = localStorage.getItem(Experiment.ANON_ID_KEY);\n if (existing) return existing;\n\n const id = typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n const r = (Math.random() * 16) | 0;\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);\n });\n\n localStorage.setItem(Experiment.ANON_ID_KEY, id);\n return id;\n }\n } catch { /* SSR or privacy mode */ }\n // Non-browser fallback — still deterministic within process lifetime\n return 'anon_' + fnv1a(String(Math.random())).toString(36);\n }\n\n // ---------------------------------------------------------------------------\n // CLIENT-SIDE ENGINE — deterministic hash-based assignment\n // ---------------------------------------------------------------------------\n\n /**\n * Deterministic variant assignment using FNV-1a hash.\n * Same userId + experimentId always produces the same variant.\n */\n private deterministicAssign(userId: string, experimentId: string, variants: ExperimentVariant[]): string {\n const hashValue = fnv1a(userId + experimentId);\n let totalWeight = 0;\n for (const v of variants) totalWeight += v.weight;\n\n const bucket = (hashValue % 10000) / 10000 * totalWeight;\n let cumulative = 0;\n for (const v of variants) {\n cumulative += v.weight;\n if (bucket < cumulative) return v.id;\n }\n return variants[variants.length - 1].id;\n }\n\n private assignVariant(experimentId: string, variants: ExperimentVariant[]): void {\n // Reload from localStorage to handle cross-tab race conditions\n this.assignments = this.loadAssignments();\n\n const existing = this.assignments[experimentId];\n if (existing && variants.some(v => v.id === existing)) {\n // Existing assignment still valid — keep it\n return;\n }\n\n // Resolve a userId for the hash: prefer identityManager's visitorId, then fall back\n const userId = this.identityManager?.getVisitorId?.()\n || this.visitorId\n || this.getOrCreateAnonId();\n\n // Deterministic assignment via hash\n const assignedVariantId = this.deterministicAssign(userId, experimentId, variants);\n this.assignments[experimentId] = assignedVariantId;\n this.saveAssignments();\n\n // Fire-and-forget assignment event.\n // The backend AssignmentHandlerNode requires `userId` in properties.\n this.init('experiment_assignment', {\n type: 'experiment',\n subtype: 'assignment',\n experimentId,\n userId,\n variantId: assignedVariantId,\n source: 'random',\n assignmentSource: 'sdk_init',\n timestamp: new Date().toISOString(),\n }).catch(() => {});\n }\n\n // ---------------------------------------------------------------------------\n // CLIENT-SIDE ENGINE — server verification\n // ---------------------------------------------------------------------------\n\n private async verifyExperiments(configs: ExperimentInitConfig[]): Promise<void> {\n const payload = {\n web_id: this.webId,\n experiments: configs.map(exp => ({\n experiment_id: exp.id,\n variants: exp.variants,\n properties: exp.properties || {},\n })),\n };\n\n try {\n const res = await fetch(`${this.endpoint}/api/v1/experiments/verify`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n const response = await res.json();\n\n if (response.ok && Array.isArray(response.data)) {\n for (const item of response.data) {\n if (item.action !== 'error') {\n this.experiments[item.experiment_id] = {\n variants: item.variants,\n properties: item.properties ?? {},\n verified: true,\n };\n this.assignVariant(item.experiment_id, item.variants);\n }\n }\n }\n } catch {\n // Network failure — fall back to local config\n for (const exp of configs) {\n this.experiments[exp.id] = {\n variants: exp.variants,\n properties: exp.properties || {},\n verified: false,\n };\n this.assignVariant(exp.id, exp.variants);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // CLIENT-SIDE ENGINE — public init\n // ---------------------------------------------------------------------------\n\n /**\n * Initialise the client-side experiment engine.\n *\n * Verifies experiment configs against the API, assigns variants using\n * weighted random allocation, and persists assignments in localStorage\n * under `fg_exp_assignments`.\n *\n * @param experiments - Array of experiment configs to register\n */\n async initExperiments(experiments: ExperimentInitConfig[]): Promise<void> {\n this.assignments = this.loadAssignments();\n\n if (experiments.length > 0) {\n await this.verifyExperiments(experiments);\n }\n }\n\n /**\n * Returns the locally assigned variant for an experiment.\n *\n * Reads from the in-memory assignment map (backed by localStorage).\n * Returns `null` if no assignment exists.\n */\n getLocalVariant(experimentId: string): string | null {\n // Re-read from storage to stay in sync with other tabs\n this.assignments = this.loadAssignments();\n return this.assignments[experimentId] ?? null;\n }\n\n /**\n * Track a conversion against the locally assigned variant.\n *\n * No-op if the visitor has no assignment for this experiment.\n */\n async trackLocalConversion(\n experimentId: string,\n metricName: string = 'conversion',\n metricValue: number = 1\n ): Promise<void> {\n const variantId = this.getLocalVariant(experimentId);\n if (!variantId) return;\n\n // Backend ConversionHandlerNode requires `userId` — resolve from\n // identity manager or the persisted anonymous ID.\n const userId = this.identityManager?.getVisitorId?.()\n || this.visitorId\n || this.getOrCreateAnonId();\n\n await this.init('experiment_conversion', {\n type: 'experiment',\n subtype: 'conversion',\n experimentId,\n userId,\n variantId,\n metricName,\n value: metricValue,\n timestamp: new Date().toISOString(),\n });\n }\n\n // ---------------------------------------------------------------------------\n // SERVER-SIDE EXPERIMENT METHODS\n //\n // Backend supports write events only: definition, assignment, conversion,\n // exposure, plus the deprecated generic custom shim below. Read endpoints\n // (results / analytics / variant lookup) are not exposed via the SDK\n // functions router.\n // ---------------------------------------------------------------------------\n\n /**\n * @deprecated Prefer `assign()`, `trackExposure()`, or `trackConversion()`.\n * Retained as a write-only compatibility shim for generic experiment events.\n */\n async track(config: ExperimentConfig): Promise<ExperimentResponse> {\n return await this.init(config.eventName, {\n ...config.properties,\n type: \"experiment\",\n subtype: \"custom\",\n variant: config.variant,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Defines a new experiment.\n */\n async define(definition: ExperimentDefinition): Promise<ExperimentResponse> {\n return await this.init(\"experiment_definition\", {\n type: \"experiment\",\n subtype: \"definition\",\n ...definition,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Assigns a user to a variant.\n */\n async assign(config: ExperimentAssignmentConfig): Promise<ExperimentResponse> {\n return await this.init(\"experiment_assignment\", {\n type: \"experiment\",\n subtype: \"assignment\",\n experimentId: config.experimentId,\n userId: config.userId,\n variantId: config.variantId,\n source: config.source || \"random\",\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Records a conversion event for an experiment.\n */\n async trackConversion(config: ExperimentConversionConfig): Promise<ExperimentResponse> {\n return await this.init(\"experiment_conversion\", {\n type: \"experiment\",\n subtype: \"conversion\",\n experimentId: config.experimentId,\n userId: config.userId,\n variantId: config.variantId,\n metricName: config.metricName,\n value: config.value,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Records that a user was exposed to a variant.\n */\n async trackExposure(\n experimentId: string,\n userId: string,\n variantId: string\n ): Promise<ExperimentResponse> {\n return await this.init(\"experiment_exposure\", {\n type: \"experiment\",\n subtype: \"exposure\",\n experimentId,\n userId,\n variantId,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Experiment;\n","/**\n * @fileoverview Browser environment helpers.\n *\n * Tiny utilities to check for browser globals safely so feature classes can\n * expose `autoTrack()` methods that no-op gracefully on the server.\n */\n\n/** Safe `window` accessor; returns `undefined` outside the browser. */\nexport function getWindow(): (Window & typeof globalThis) | undefined {\n return typeof window !== \"undefined\" ? window : undefined;\n}\n\n/** Safe `document` accessor; returns `undefined` outside the browser. */\nexport function getDocument(): Document | undefined {\n return typeof document !== \"undefined\" ? document : undefined;\n}\n\n/** Returns true when running in a real browser-like environment. */\nexport function isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/** A teardown function returned by every `autoTrack()` API. */\nexport type Teardown = () => void;\n\n/** Compose multiple teardown functions into one. */\nexport function combineTeardowns(...fns: Array<Teardown | undefined | null | false>): Teardown {\n return () => {\n for (const fn of fns) {\n if (typeof fn === \"function\") {\n try { fn(); } catch { /* swallow */ }\n }\n }\n };\n}\n","/**\n * @fileoverview Product Analytics - Page View Tracking\n * @module features/analytics/page-views\n * \n * @description\n * Track page views with rich context including scroll depth, time on page,\n * referrer information, and user engagement signals.\n * \n * @useCases\n * - Track which pages users visit most frequently\n * - Measure time spent on content pages\n * - Identify high bounce rate pages\n * - Analyze user navigation patterns\n * - Monitor landing page performance\n * \n * @metrics\n * - Total page views\n * - Unique page views \n * - Average time on page\n * - Bounce rate by page\n * - Scroll depth distribution\n * - Entry/exit page analysis\n * \n * @chartData\n * - Line chart: Page views over time\n * - Bar chart: Top pages by views\n * - Heatmap: Scroll depth by page\n * - Funnel: Page flow analysis\n * \n * @example\n * ```typescript\n * const pageViews = new PageViews(webId, endpoint, apiKey);\n * \n * // Track a page view\n * await pageViews.track({\n * url: window.location.href,\n * path: window.location.pathname,\n * title: document.title,\n * referrer: document.referrer\n * });\n * \n * // Track with scroll depth\n * await pageViews.trackScrollDepth({\n * path: '/blog/article-1',\n * scrollDepth: 75\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { getWindow, getDocument, isBrowser, combineTeardowns, Teardown } from \"../../utils/browser\";\nimport { \n PageView, \n TrafficMetrics, \n TimeSeriesData, \n ChartDataPoint,\n DateRangeFilter,\n PaginationParams \n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking a page view.\n */\nexport interface PageViewConfig {\n /** Full page URL */\n url: string;\n /** Page path (without domain) */\n path: string;\n /** Page title */\n title?: string;\n /** Referrer URL */\n referrer?: string;\n /** User ID (if authenticated) */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Configuration for tracking scroll depth.\n */\nexport interface ScrollDepthConfig {\n /** Page path */\n path: string;\n /** Scroll depth percentage (0-100) */\n scrollDepth: number;\n /** Time at this depth (seconds) */\n timeAtDepth?: number;\n}\n\n/**\n * Configuration for tracking time on page.\n */\nexport interface TimeOnPageConfig {\n /** Page path */\n path: string;\n /** Time spent in seconds */\n duration: number;\n /** Whether user engaged (scrolled, clicked, etc.) */\n engaged?: boolean;\n}\n\n/**\n * Page view response from API.\n */\nexport interface PageViewResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n pageViewId: string;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Page analytics data for charts.\n */\nexport interface PageAnalyticsData {\n /** Top pages */\n topPages: Array<{\n path: string;\n title: string;\n views: number;\n uniqueViews: number;\n avgTimeOnPage: number;\n bounceRate: number;\n }>;\n /** Page views time series */\n timeSeries: TimeSeriesData;\n /** Summary metrics */\n summary: {\n totalPageViews: number;\n uniquePageViews: number;\n avgTimeOnPage: number;\n avgScrollDepth: number;\n bounceRate: number;\n };\n}\n\n// ============================================================================\n// PAGE VIEWS CLASS\n// ============================================================================\n\n/**\n * PageViews - Track and analyze page view events.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides comprehensive page view tracking with support for:\n * - Basic page view events\n * - Scroll depth tracking\n * - Time on page measurement\n * - Exit intent detection\n * - Page engagement scoring\n * \n * @example\n * ```typescript\n * const pageViews = new PageViews(webId, endpoint, apiKey);\n * \n * // Basic page view\n * await pageViews.track({\n * url: 'https://example.com/products',\n * path: '/products',\n * title: 'Our Products'\n * });\n * ```\n */\nexport class PageViews extends FlowGridTransport {\n /**\n * Tracks a page view event.\n * \n * @param config - Page view configuration\n * @returns Promise resolving to the API response\n * \n * @example\n * ```typescript\n * await pageViews.track({\n * url: window.location.href,\n * path: window.location.pathname,\n * title: document.title\n * });\n * ```\n */\n async track(config: PageViewConfig): Promise<PageViewResponse> {\n return await this.init(\"page_view\", {\n type: \"page_view\",\n url: config.url,\n path: config.path,\n title: config.title || \"\",\n referrer: config.referrer || \"\",\n userId: config.userId,\n sessionId: config.sessionId,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks scroll depth on a page.\n * \n * @param config - Scroll depth configuration\n * @returns Promise resolving to the API response\n * \n * @example\n * ```typescript\n * // Track when user scrolls to 50%\n * await pageViews.trackScrollDepth({\n * path: '/article/how-to-guide',\n * scrollDepth: 50\n * });\n * ```\n */\n async trackScrollDepth(config: ScrollDepthConfig): Promise<PageViewResponse> {\n return await this.init(\"scroll_depth\", {\n type: \"scroll_depth\",\n path: config.path,\n scrollDepth: Math.min(100, Math.max(0, config.scrollDepth)),\n timeAtDepth: config.timeAtDepth,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks time spent on a page.\n * \n * @param config - Time on page configuration\n * @returns Promise resolving to the API response\n * \n * @example\n * ```typescript\n * // Track on page unload\n * window.addEventListener('beforeunload', () => {\n * pageViews.trackTimeOnPage({\n * path: '/pricing',\n * duration: 45,\n * engaged: true\n * });\n * });\n * ```\n */\n async trackTimeOnPage(config: TimeOnPageConfig): Promise<PageViewResponse> {\n return await this.init(\"time_on_page\", {\n type: \"time_on_page\",\n path: config.path,\n duration: config.duration,\n engaged: config.engaged ?? false,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a page exit event.\n * \n * @param path - Page path being exited\n * @param duration - Time spent on page\n * @param scrollDepth - Final scroll depth\n * @returns Promise resolving to the API response\n */\n async trackExit(\n path: string, \n duration: number, \n scrollDepth: number\n ): Promise<PageViewResponse> {\n return await this.init(\"page_exit\", {\n type: \"page_exit\",\n path,\n duration,\n scrollDepth,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Auto-track page views for both classic full-page navigations and SPA\n * route changes (history.pushState / replaceState / popstate). Also wires\n * scroll-depth thresholds (25/50/75/100%) and a final time-on-page event\n * when the page is hidden or unloaded.\n *\n * @returns A teardown function that detaches every listener.\n *\n * @example\n * ```ts\n * const stop = fg.pageViews.client.autoTrack({ userId: \"u_1\" });\n * ```\n */\n autoTrack(options: { userId?: string; sessionId?: string } = {}): Teardown {\n if (!isBrowser()) return () => { /* no-op on the server */ };\n const win = getWindow()!;\n const doc = getDocument()!;\n\n let currentPath = win.location.pathname;\n let pageStart = Date.now();\n let maxDepth = 0;\n const sentDepths = new Set<number>();\n\n const fireView = () => {\n void this.track({\n url: win.location.href,\n path: win.location.pathname,\n title: doc.title,\n referrer: doc.referrer,\n userId: options.userId,\n sessionId: options.sessionId,\n });\n };\n\n const flushTimeOnPage = () => {\n const duration = Math.round((Date.now() - pageStart) / 1000);\n if (duration <= 0) return;\n void this.trackTimeOnPage({ path: currentPath, duration, engaged: maxDepth > 10 });\n };\n\n const onRouteChange = () => {\n if (win.location.pathname === currentPath) return;\n flushTimeOnPage();\n currentPath = win.location.pathname;\n pageStart = Date.now();\n maxDepth = 0;\n sentDepths.clear();\n fireView();\n };\n\n // Patch history methods so we can detect SPA route changes.\n const origPush = win.history.pushState;\n const origReplace = win.history.replaceState;\n win.history.pushState = function (...args) {\n const r = origPush.apply(this, args);\n win.dispatchEvent(new Event(\"flowgrid:locationchange\"));\n return r;\n };\n win.history.replaceState = function (...args) {\n const r = origReplace.apply(this, args);\n win.dispatchEvent(new Event(\"flowgrid:locationchange\"));\n return r;\n };\n const popHandler = () => onRouteChange();\n const locHandler = () => onRouteChange();\n win.addEventListener(\"popstate\", popHandler);\n win.addEventListener(\"flowgrid:locationchange\", locHandler);\n\n // Scroll-depth thresholds.\n const onScroll = () => {\n const docEl = doc.documentElement;\n const scrollTop = win.scrollY || docEl.scrollTop;\n const height = Math.max(1, docEl.scrollHeight - win.innerHeight);\n const depth = Math.min(100, Math.round((scrollTop / height) * 100));\n if (depth > maxDepth) maxDepth = depth;\n for (const t of [25, 50, 75, 100]) {\n if (depth >= t && !sentDepths.has(t)) {\n sentDepths.add(t);\n void this.trackScrollDepth({ path: currentPath, scrollDepth: t });\n }\n }\n };\n win.addEventListener(\"scroll\", onScroll, { passive: true });\n\n // Flush on unload / visibility change.\n const onHide = () => { if (doc.visibilityState === \"hidden\") flushTimeOnPage(); };\n doc.addEventListener(\"visibilitychange\", onHide);\n win.addEventListener(\"pagehide\", flushTimeOnPage);\n\n // Initial view.\n fireView();\n\n return combineTeardowns(\n () => win.removeEventListener(\"popstate\", popHandler),\n () => win.removeEventListener(\"flowgrid:locationchange\", locHandler),\n () => win.removeEventListener(\"scroll\", onScroll),\n () => doc.removeEventListener(\"visibilitychange\", onHide),\n () => win.removeEventListener(\"pagehide\", flushTimeOnPage),\n () => { win.history.pushState = origPush; win.history.replaceState = origReplace; },\n );\n }\n}\n\nexport default PageViews;\n","/**\n * @fileoverview Product Analytics - Session Tracking\n * @module features/analytics/sessions\n * \n * @description\n * Track user sessions with comprehensive context including device info,\n * geographic location, traffic source, and engagement metrics.\n * \n * @useCases\n * - Monitor active user sessions in real-time\n * - Analyze session duration and depth\n * - Track user journey across pages\n * - Identify traffic sources and campaigns\n * - Segment users by device and location\n * \n * @metrics\n * - Total sessions\n * - Unique visitors\n * - Average session duration\n * - Pages per session\n * - Bounce rate\n * - New vs returning visitors\n * \n * @chartData\n * - Line chart: Sessions over time\n * - Pie chart: Traffic source breakdown\n * - Bar chart: Sessions by device type\n * - Geo map: Sessions by country\n * \n * @example\n * ```typescript\n * const sessions = new Sessions(webId, endpoint, apiKey);\n * \n * // Start a new session\n * const session = await sessions.start({\n * userId: 'user_123',\n * device: { type: 'desktop', browser: 'Chrome' },\n * source: 'google',\n * medium: 'organic'\n * });\n * \n * // End session\n * await sessions.end(session.sessionId);\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { getWindow, getDocument, isBrowser, combineTeardowns, Teardown } from \"../../utils/browser\";\nimport { \n Session,\n DeviceInfo, \n GeoLocation, \n UTMParams,\n TrafficMetrics,\n TimeSeriesData,\n DateRangeFilter,\n PaginationParams,\n UserIdentity\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for starting a new session.\n */\nexport interface SessionStartConfig {\n /** User identity */\n user?: UserIdentity;\n /** Device information */\n device?: DeviceInfo;\n /** Geographic location */\n location?: GeoLocation;\n /** Traffic source */\n source?: string;\n /** Traffic medium */\n medium?: string;\n /** Campaign name */\n campaign?: string;\n /** UTM parameters */\n utm?: UTMParams;\n /** Landing page URL */\n landingPage?: string;\n /** Referrer URL */\n referrer?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Session response from API.\n */\nexport interface SessionResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n sessionId: string;\n started: boolean;\n isNewVisitor: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Session end response.\n */\nexport interface SessionEndResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n sessionId: string;\n duration: number;\n pageViews: number;\n eventCount: number;\n };\n timestamp: string;\n}\n\n/**\n * Session analytics data for charts.\n */\nexport interface SessionAnalyticsData {\n /** Summary metrics */\n summary: {\n totalSessions: number;\n uniqueVisitors: number;\n newVisitors: number;\n returningVisitors: number;\n avgSessionDuration: number;\n avgPagesPerSession: number;\n bounceRate: number;\n };\n /** Sessions time series */\n timeSeries: TimeSeriesData;\n /** Sessions by source */\n bySource: Array<{\n source: string;\n sessions: number;\n percentage: number;\n }>;\n /** Sessions by device */\n byDevice: Array<{\n device: string;\n sessions: number;\n percentage: number;\n }>;\n /** Sessions by country */\n byCountry: Array<{\n country: string;\n countryCode: string;\n sessions: number;\n }>;\n}\n\n/**\n * Real-time session data.\n */\nexport interface RealTimeSessionData {\n /** Currently active sessions */\n activeSessions: number;\n /** Active users in last 5 minutes */\n activeUsers5min: number;\n /** Active users in last 30 minutes */\n activeUsers30min: number;\n /** Sessions by page (real-time) */\n sessionsByPage: Array<{ path: string; count: number }>;\n /** Sessions by country (real-time) */\n sessionsByCountry: Array<{ country: string; count: number }>;\n}\n\n// ============================================================================\n// SESSIONS CLASS\n// ============================================================================\n\n/**\n * Sessions - Track and analyze user sessions.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides comprehensive session tracking including:\n * - Session lifecycle (start, update, end)\n * - Device and location tracking\n * - Traffic source attribution\n * - Real-time session monitoring\n * - Session replay triggers\n * \n * @example\n * ```typescript\n * const sessions = new Sessions(webId, endpoint, apiKey);\n * \n * // Start session on page load\n * const session = await sessions.start({\n * user: { userId: 'user_123' },\n * device: { type: 'mobile', os: 'iOS' },\n * source: 'email',\n * campaign: 'summer_sale'\n * });\n * \n * // Get real-time data\n * const realTime = await sessions.getRealTime();\n * console.log(`${realTime.activeSessions} users online`);\n * ```\n */\nexport class Sessions extends FlowGridTransport {\n /**\n * Starts a new user session.\n * \n * @param config - Session configuration\n * @returns Promise resolving to session response with sessionId\n * \n * @example\n * ```typescript\n * const session = await sessions.start({\n * user: { userId: 'user_123' },\n * source: 'google',\n * medium: 'cpc',\n * campaign: 'brand_terms'\n * });\n * localStorage.setItem('sessionId', session.response.sessionId);\n * ```\n */\n async start(config: SessionStartConfig = {}): Promise<SessionResponse> {\n return await this.init(\"session_start\", {\n type: \"session_start\",\n user: config.user,\n device: config.device,\n location: config.location,\n source: config.source || config.utm?.utmSource,\n medium: config.medium || config.utm?.utmMedium,\n campaign: config.campaign || config.utm?.utmCampaign,\n utm: config.utm,\n landingPage: config.landingPage || (typeof window !== 'undefined' ? window.location.href : ''),\n referrer: config.referrer || (typeof document !== 'undefined' ? document.referrer : ''),\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Updates an existing session with new data.\n * \n * @param sessionId - Session identifier\n * @param properties - Properties to update\n * @returns Promise resolving to update response\n */\n async update(\n sessionId: string, \n properties: Record<string, unknown>\n ): Promise<SessionResponse> {\n return await this.init(\"session_update\", {\n type: \"session_update\",\n sessionId,\n ...properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Ends a user session.\n * \n * @param sessionId - Session identifier to end\n * @returns Promise resolving to session end response with metrics\n * \n * @example\n * ```typescript\n * window.addEventListener('beforeunload', async () => {\n * const sessionId = localStorage.getItem('sessionId');\n * if (sessionId) {\n * await sessions.end(sessionId);\n * }\n * });\n * ```\n */\n async end(sessionId: string): Promise<SessionEndResponse> {\n return await this.init(\"session_end\", {\n type: \"session_end\",\n sessionId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a heartbeat to keep session alive.\n * \n * @param sessionId - Session identifier\n * @returns Promise resolving to heartbeat response\n */\n async heartbeat(sessionId: string): Promise<SessionResponse> {\n return await this.init(\"session_heartbeat\", {\n type: \"session_heartbeat\",\n sessionId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Auto-manage a browser session: starts on call, sends a heartbeat on a\n * fixed interval, and ends the session on `pagehide`. The resolved\n * `sessionId` is stored on `sessionStorage` so reloads within the same tab\n * resume the same session.\n *\n * @param config Optional initial config forwarded to {@link Sessions.start}.\n * @param options.heartbeatMs Interval between heartbeats. Default 30s.\n * @returns A teardown function that ends the session and detaches listeners.\n */\n autoTrack(config: SessionStartConfig = {}, options: { heartbeatMs?: number } = {}): Teardown {\n if (!isBrowser()) return () => { /* no-op on the server */ };\n const win = getWindow()!;\n const doc = getDocument()!;\n const heartbeatMs = options.heartbeatMs ?? 30_000;\n\n const STORE_KEY = \"flowgrid:sessionId\";\n let sessionId: string | undefined;\n try { sessionId = win.sessionStorage.getItem(STORE_KEY) || undefined; } catch { /* private mode */ }\n\n const startPromise = sessionId\n ? Promise.resolve(sessionId)\n : this.start(config).then((r) => {\n sessionId = r.response.sessionId;\n try { win.sessionStorage.setItem(STORE_KEY, sessionId); } catch { /* ignore */ }\n return sessionId;\n }).catch(() => undefined);\n\n const beat = win.setInterval(() => {\n if (sessionId && doc.visibilityState === \"visible\") void this.heartbeat(sessionId);\n }, heartbeatMs);\n\n const onHide = () => { if (sessionId) void this.end(sessionId); };\n win.addEventListener(\"pagehide\", onHide);\n\n return combineTeardowns(\n () => win.clearInterval(beat),\n () => win.removeEventListener(\"pagehide\", onHide),\n () => { void startPromise.then(() => { if (sessionId) void this.end(sessionId); }); },\n () => { try { win.sessionStorage.removeItem(STORE_KEY); } catch { /* ignore */ } },\n );\n }\n}\n\nexport default Sessions;\n","/**\n * @fileoverview Product Analytics - Custom Event Tracking\n * @module features/analytics/events\n * \n * @description\n * Track custom events with flexible properties for any user action\n * or system event. Supports categorization, value tracking, and batching.\n * \n * @useCases\n * - Track button clicks and CTA interactions\n * - Monitor feature usage and engagement\n * - Capture form submissions and errors\n * - Log search queries and results\n * - Record video/audio playback events\n * \n * @metrics\n * - Event counts by type\n * - Event trends over time\n * - Unique users per event\n * - Event value aggregations\n * - Event-to-conversion correlation\n * \n * @chartData\n * - Bar chart: Top events by count\n * - Line chart: Event trends over time\n * - Heatmap: Events by hour/day\n * - Sankey: Event flow paths\n * \n * @example\n * ```typescript\n * const events = new Events(webId, endpoint, apiKey);\n * \n * // Track a button click\n * await events.track({\n * eventName: 'cta_clicked',\n * category: 'engagement',\n * action: 'click',\n * label: 'signup_hero'\n * });\n * \n * // Track with value\n * await events.track({\n * eventName: 'video_watched',\n * value: 120, // seconds\n * properties: { videoId: 'intro-video' }\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n CustomEvent,\n ClickEvent,\n FormEvent,\n SearchEvent,\n ErrorEvent,\n TimeSeriesData,\n DateRangeFilter,\n PaginationParams,\n ChartDataPoint\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking a custom event.\n */\nexport interface EventTrackConfig {\n /** Event name (required) */\n eventName: string;\n /** Event category for grouping */\n category?: string;\n /** Event action */\n action?: string;\n /** Event label for sub-categorization */\n label?: string;\n /** Numeric value associated with event */\n value?: number;\n /** Non-interactive event (won't affect bounce rate) */\n nonInteraction?: boolean;\n /** User ID */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Batch event tracking configuration.\n */\nexport interface BatchEventConfig {\n /** Array of events to track */\n events: EventTrackConfig[];\n}\n\n/**\n * Event response from API.\n */\nexport interface EventResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n eventId: string;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Batch event response.\n */\nexport interface BatchEventResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n tracked: number;\n failed: number;\n eventIds: string[];\n };\n timestamp: string;\n}\n\n/**\n * Event analytics data for charts.\n */\nexport interface EventAnalyticsData {\n /** Top events by count */\n topEvents: Array<{\n eventName: string;\n category: string;\n count: number;\n uniqueUsers: number;\n totalValue: number;\n }>;\n /** Events time series */\n timeSeries: TimeSeriesData;\n /** Events by category */\n byCategory: Array<{\n category: string;\n count: number;\n percentage: number;\n }>;\n /** Summary metrics */\n summary: {\n totalEvents: number;\n uniqueEventTypes: number;\n eventsPerUser: number;\n totalValue: number;\n };\n}\n\n// ============================================================================\n// EVENTS CLASS\n// ============================================================================\n\n/**\n * Events - Track and analyze custom events.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides flexible custom event tracking including:\n * - Standard event tracking with categories\n * - Click and interaction tracking\n * - Form submission tracking\n * - Search event tracking\n * - Error and exception logging\n * - Batch event submission\n * \n * @example\n * ```typescript\n * const events = new Events(webId, endpoint, apiKey);\n * \n * // Track feature usage\n * await events.track({\n * eventName: 'feature_used',\n * category: 'features',\n * action: 'use',\n * label: 'export_pdf',\n * properties: { format: 'A4', pages: 5 }\n * });\n * ```\n */\nexport class Events extends FlowGridTransport {\n /**\n * Tracks a custom event.\n * \n * @param config - Event configuration\n * @returns Promise resolving to event response\n * \n * @example\n * ```typescript\n * await events.track({\n * eventName: 'upgrade_clicked',\n * category: 'monetization',\n * action: 'click',\n * label: 'pricing_page',\n * value: 99.99\n * });\n * ```\n */\n async track(config: EventTrackConfig): Promise<EventResponse> {\n return await this.init(\"custom_event\", {\n type: \"custom_event\",\n eventName: config.eventName,\n category: config.category || \"general\",\n action: config.action,\n label: config.label,\n value: config.value,\n nonInteraction: config.nonInteraction || false,\n userId: config.userId,\n sessionId: config.sessionId,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks multiple events in a single request.\n * \n * @param config - Batch configuration with events array\n * @returns Promise resolving to batch response\n * \n * @example\n * ```typescript\n * await events.trackBatch({\n * events: [\n * { eventName: 'step_1_complete', category: 'onboarding' },\n * { eventName: 'step_2_complete', category: 'onboarding' },\n * { eventName: 'step_3_complete', category: 'onboarding' }\n * ]\n * });\n * ```\n */\n async trackBatch(config: BatchEventConfig): Promise<BatchEventResponse> {\n const events = config.events.map(e => ({\n ...e,\n timestamp: new Date().toISOString()\n }));\n\n return await this.init(\"batch_events\", {\n type: \"batch_events\",\n events,\n count: events.length,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a click/interaction event.\n * \n * @param config - Click event configuration\n * @returns Promise resolving to event response\n * \n * @example\n * ```typescript\n * document.addEventListener('click', (e) => {\n * if (e.target.dataset.track) {\n * events.trackClick({\n * elementId: e.target.id,\n * elementText: e.target.textContent,\n * targetUrl: e.target.href\n * });\n * }\n * });\n * ```\n */\n async trackClick(config: ClickEvent): Promise<EventResponse> {\n return await this.init(\"click_event\", {\n type: \"click_event\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a form submission event.\n * \n * @param config - Form event configuration\n * @returns Promise resolving to event response\n * \n * @example\n * ```typescript\n * form.addEventListener('submit', async (e) => {\n * await events.trackForm({\n * formId: 'contact-form',\n * formName: 'Contact Us',\n * success: true,\n * fields: ['name', 'email', 'message'],\n * completionTime: 45\n * });\n * });\n * ```\n */\n async trackForm(config: FormEvent): Promise<EventResponse> {\n return await this.init(\"form_event\", {\n type: \"form_event\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a search event.\n * \n * @param config - Search event configuration\n * @returns Promise resolving to event response\n * \n * @example\n * ```typescript\n * await events.trackSearch({\n * query: 'wireless headphones',\n * category: 'products',\n * resultsCount: 42,\n * filters: { brand: 'Sony', priceRange: '100-200' }\n * });\n * ```\n */\n async trackSearch(config: SearchEvent): Promise<EventResponse> {\n return await this.init(\"search_event\", {\n type: \"search_event\",\n query: config.query,\n category: config.category,\n resultsCount: config.resultsCount,\n resultClicked: config.resultClicked,\n clickedPosition: config.clickedPosition,\n filters: config.filters,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks an error or exception.\n * \n * @param config - Error event configuration\n * @returns Promise resolving to event response\n * \n * @example\n * ```typescript\n * window.onerror = (message, source, line, col, error) => {\n * events.trackError({\n * message: message.toString(),\n * stack: error?.stack,\n * type: error?.name,\n * fatal: false,\n * context: source\n * });\n * };\n * ```\n */\n async trackError(config: ErrorEvent): Promise<EventResponse> {\n return await this.init(\"error_event\", {\n type: \"error_event\",\n message: config.message,\n stack: config.stack,\n errorType: config.type,\n fatal: config.fatal || false,\n context: config.context,\n userAction: config.userAction,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Events;\n","/**\n * @fileoverview Product Analytics - User Identification & Traits\n * @module features/analytics/identify\n * \n * @description\n * Identify users and track their traits for personalization,\n * segmentation, and cohort analysis.\n * \n * @useCases\n * - Link anonymous sessions to authenticated users\n * - Store user profile data for segmentation\n * - Track user lifecycle changes (signup, upgrade, churn)\n * - Enable personalized experiences\n * - Build user cohorts for analysis\n * \n * @metrics\n * - Total identified users\n * - Anonymous to identified conversion rate\n * - Users by plan/segment\n * - User lifetime value distribution\n * - Trait distribution\n * \n * @chartData\n * - Pie chart: Users by plan\n * - Bar chart: Users by trait value\n * - Line chart: New identifications over time\n * - Table: User segments\n * \n * @example\n * ```typescript\n * const identify = new Identify(webId, endpoint, apiKey);\n * \n * // Identify user on login\n * await identify.user({\n * userId: 'user_123',\n * traits: {\n * email: 'user@example.com',\n * name: 'John Doe',\n * plan: 'premium',\n * createdAt: '2025-01-15'\n * }\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n UserIdentity,\n UserTraits,\n MoneyValue,\n DateRangeFilter,\n PaginationParams,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for identifying a user.\n */\nexport interface IdentifyConfig {\n /** Unique user identifier */\n userId: string;\n /** Anonymous ID to link (optional) */\n anonymousId?: string;\n /** User traits/properties */\n traits?: UserTraits;\n}\n\n/**\n * Configuration for aliasing user IDs.\n */\nexport interface AliasConfig {\n /** Previous user ID */\n previousId: string;\n /** New user ID */\n userId: string;\n}\n\n/**\n * Configuration for grouping users.\n */\nexport interface GroupConfig {\n /** User ID */\n userId: string;\n /** Group/company ID */\n groupId: string;\n /** Group traits */\n traits?: {\n name?: string;\n industry?: string;\n employees?: number;\n plan?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Identify response from API.\n */\nexport interface IdentifyResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n userId: string;\n identified: boolean;\n isNewUser: boolean;\n linkedAnonymousId?: string;\n };\n timestamp: string;\n}\n\n/**\n * User analytics data for charts.\n */\nexport interface UserAnalyticsData {\n /** Summary metrics */\n summary: {\n totalUsers: number;\n identifiedUsers: number;\n anonymousUsers: number;\n newUsersThisPeriod: number;\n identificationRate: number;\n };\n /** Users by plan/segment */\n byPlan: Array<{\n plan: string;\n count: number;\n percentage: number;\n mrr?: MoneyValue;\n }>;\n /** New users time series */\n newUsersTimeSeries: TimeSeriesData;\n /** User lifecycle distribution */\n byLifecycleStage: Array<{\n stage: string;\n count: number;\n percentage: number;\n }>;\n}\n\n// ============================================================================\n// IDENTIFY CLASS\n// ============================================================================\n\n/**\n * Identify - User identification and trait management.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides user identification capabilities including:\n * - User identification on login/signup\n * - Anonymous to identified user linking\n * - User trait/property storage\n * - User aliasing for ID changes\n * - Group/company association\n * \n * @example\n * ```typescript\n * const identify = new Identify(webId, endpoint, apiKey);\n * \n * // On user signup\n * await identify.user({\n * userId: 'user_123',\n * anonymousId: getAnonymousId(),\n * traits: {\n * email: 'user@example.com',\n * name: 'Jane Smith',\n * plan: 'starter',\n * createdAt: new Date().toISOString()\n * }\n * });\n * \n * // Associate user with company\n * await identify.group({\n * userId: 'user_123',\n * groupId: 'company_456',\n * traits: { name: 'Acme Inc', employees: 50 }\n * });\n * ```\n */\nexport class Identify extends FlowGridTransport {\n /**\n * Identifies a user with traits.\n * \n * @param config - Identification configuration\n * @returns Promise resolving to identify response\n * \n * @example\n * ```typescript\n * // Basic identification\n * await identify.user({\n * userId: 'user_123',\n * traits: { email: 'user@example.com' }\n * });\n * \n * // With anonymous ID linking\n * await identify.user({\n * userId: 'user_123',\n * anonymousId: localStorage.getItem('anonId'),\n * traits: {\n * name: 'John Doe',\n * plan: 'premium',\n * ltv: { amount: 29900, currency: 'USD' }\n * }\n * });\n * ```\n */\n async user(config: IdentifyConfig): Promise<IdentifyResponse> {\n return await this.init(\"identify_user\", {\n type: \"identify\",\n userId: config.userId,\n anonymousId: config.anonymousId,\n traits: config.traits || {},\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Updates traits for an existing user.\n * \n * @param userId - User identifier\n * @param traits - Traits to update/add\n * @returns Promise resolving to identify response\n * \n * @example\n * ```typescript\n * // Update user plan after upgrade\n * await identify.updateTraits('user_123', {\n * plan: 'enterprise',\n * ltv: { amount: 99900, currency: 'USD' }\n * });\n * ```\n */\n async updateTraits(userId: string, traits: UserTraits): Promise<IdentifyResponse> {\n return await this.init(\"update_traits\", {\n type: \"update_traits\",\n userId,\n traits,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Creates an alias between two user IDs.\n * \n * @param config - Alias configuration\n * @returns Promise resolving to alias response\n * \n * @example\n * ```typescript\n * // When user ID changes (e.g., after migration)\n * await identify.alias({\n * previousId: 'old_user_id',\n * userId: 'new_user_id'\n * });\n * ```\n */\n async alias(config: AliasConfig): Promise<IdentifyResponse> {\n return await this.init(\"alias_user\", {\n type: \"alias\",\n previousId: config.previousId,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Associates a user with a group/company.\n * \n * @param config - Group configuration\n * @returns Promise resolving to group response\n * \n * @example\n * ```typescript\n * await identify.group({\n * userId: 'user_123',\n * groupId: 'company_456',\n * traits: {\n * name: 'Acme Corporation',\n * industry: 'Technology',\n * employees: 500,\n * plan: 'enterprise'\n * }\n * });\n * ```\n */\n async group(config: GroupConfig): Promise<IdentifyResponse> {\n return await this.init(\"group_user\", {\n type: \"group\",\n userId: config.userId,\n groupId: config.groupId,\n traits: config.traits || {},\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Resets user identity (logout).\n * \n * @param userId - User ID to reset\n * @returns Promise resolving to reset response\n */\n async reset(userId: string): Promise<IdentifyResponse> {\n return await this.init(\"reset_identity\", {\n type: \"reset\",\n userId,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Identify;\n","/**\n * @fileoverview Product Analytics - Funnel Analysis\n * @module features/analytics/funnels\n * \n * @description\n * Define and analyze conversion funnels to understand user journeys,\n * identify drop-off points, and optimize conversion rates.\n * \n * @useCases\n * - Track signup/onboarding completion rates\n * - Analyze checkout funnel performance\n * - Identify where users drop off in key flows\n * - Compare funnel performance across segments\n * - A/B test different funnel variations\n * \n * @metrics\n * - Step-by-step conversion rates\n * - Drop-off rates at each step\n * - Time to complete each step\n * - Overall funnel conversion rate\n * - Funnel completion time\n * \n * @chartData\n * - Funnel chart: Step-by-step visualization\n * - Bar chart: Conversion by step\n * - Line chart: Funnel performance over time\n * - Comparison: Funnel variants side-by-side\n * \n * @example\n * ```typescript\n * const funnels = new Funnels(webId, endpoint, apiKey);\n * \n * // Track funnel step\n * await funnels.trackStep({\n * funnelId: 'checkout_funnel',\n * step: 'add_payment',\n * stepNumber: 3,\n * userId: 'user_123'\n * });\n * \n * // Get funnel analysis\n * const analysis = await funnels.analyze('checkout_funnel');\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n FunnelStep,\n FunnelAnalysis,\n DateRangeFilter,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Funnel definition configuration.\n */\nexport interface FunnelDefinition {\n /** Unique funnel identifier */\n funnelId: string;\n /** Funnel name for display */\n name: string;\n /** Funnel description */\n description?: string;\n /** Ordered list of step definitions */\n steps: Array<{\n /** Step name */\n name: string;\n /** Event(s) that trigger this step */\n events: string[];\n /** Step description */\n description?: string;\n /** Whether step is optional */\n optional?: boolean;\n }>;\n}\n\n/**\n * Configuration for tracking a funnel step.\n */\nexport interface FunnelStepConfig {\n /** Funnel identifier */\n funnelId: string;\n /** Step name or event */\n step: string;\n /** Step number (1-indexed) */\n stepNumber: number;\n /** User ID */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Funnel step response from API.\n */\nexport interface FunnelStepResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n funnelId: string;\n step: string;\n tracked: boolean;\n previousStep?: string;\n timeFromPrevious?: number;\n };\n timestamp: string;\n}\n\n/**\n * Funnel analytics data for charts.\n */\nexport interface FunnelAnalyticsData {\n /** Funnel definition */\n funnel: FunnelDefinition;\n /** Analysis results */\n analysis: FunnelAnalysis;\n /** Step-by-step data for visualization */\n visualization: Array<{\n step: string;\n entered: number;\n completed: number;\n conversionRate: number;\n dropOffRate: number;\n avgTime: number;\n }>;\n /** Performance over time */\n trendData: TimeSeriesData;\n}\n\n/**\n * Funnel comparison data.\n */\nexport interface FunnelComparisonData {\n /** Base funnel data */\n baseline: FunnelAnalyticsData;\n /** Comparison funnel data */\n comparison: FunnelAnalyticsData;\n /** Step-by-step comparison */\n stepComparison: Array<{\n step: string;\n baselineRate: number;\n comparisonRate: number;\n difference: number;\n significant: boolean;\n }>;\n}\n\n// ============================================================================\n// FUNNELS CLASS\n// ============================================================================\n\n/**\n * Funnels - Define and analyze conversion funnels.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides funnel analysis capabilities including:\n * - Funnel definition and management\n * - Step-by-step event tracking\n * - Conversion and drop-off analysis\n * - Time-to-completion tracking\n * - Segment-based funnel comparison\n * \n * @example\n * ```typescript\n * const funnels = new Funnels(webId, endpoint, apiKey);\n * \n * // Define a signup funnel\n * await funnels.define({\n * funnelId: 'signup_funnel',\n * name: 'User Signup',\n * steps: [\n * { name: 'Visit Landing', events: ['page_view_landing'] },\n * { name: 'Click Signup', events: ['signup_clicked'] },\n * { name: 'Submit Form', events: ['signup_submitted'] },\n * { name: 'Verify Email', events: ['email_verified'] }\n * ]\n * });\n * \n * // Analyze funnel performance\n * const analysis = await funnels.analyze('signup_funnel', {\n * range: 'last30days'\n * });\n * ```\n */\nexport class Funnels extends FlowGridTransport {\n /**\n * Defines a new funnel or updates existing.\n * \n * @param config - Funnel definition\n * @returns Promise resolving to definition response\n * \n * @example\n * ```typescript\n * await funnels.define({\n * funnelId: 'checkout_funnel',\n * name: 'Checkout Flow',\n * steps: [\n * { name: 'View Cart', events: ['view_cart'] },\n * { name: 'Begin Checkout', events: ['begin_checkout'] },\n * { name: 'Add Shipping', events: ['add_shipping_info'] },\n * { name: 'Add Payment', events: ['add_payment_info'] },\n * { name: 'Purchase', events: ['purchase'] }\n * ]\n * });\n * ```\n */\n async define(config: FunnelDefinition): Promise<FunnelStepResponse> {\n return await this.init(\"define_funnel\", {\n type: \"define_funnel\",\n funnelId: config.funnelId,\n name: config.name,\n description: config.description,\n steps: config.steps,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a funnel step completion.\n * \n * @param config - Funnel step configuration\n * @returns Promise resolving to step response\n * \n * @example\n * ```typescript\n * // Track user progressing through checkout\n * await funnels.trackStep({\n * funnelId: 'checkout_funnel',\n * step: 'add_shipping_info',\n * stepNumber: 3,\n * userId: 'user_123',\n * properties: { shippingMethod: 'express' }\n * });\n * ```\n */\n async trackStep(config: FunnelStepConfig): Promise<FunnelStepResponse> {\n return await this.init(\"funnel_step\", {\n type: \"funnel_step\",\n funnelId: config.funnelId,\n step: config.step,\n stepNumber: config.stepNumber,\n userId: config.userId,\n sessionId: config.sessionId,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks funnel completion.\n * \n * @param funnelId - Funnel identifier\n * @param userId - User who completed\n * @param properties - Completion properties\n * @returns Promise resolving to completion response\n */\n async trackComplete(\n funnelId: string,\n userId?: string,\n properties?: Record<string, unknown>\n ): Promise<FunnelStepResponse> {\n return await this.init(\"funnel_complete\", {\n type: \"funnel_complete\",\n funnelId,\n userId,\n ...properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks funnel abandonment.\n * \n * @param funnelId - Funnel identifier\n * @param lastStep - Last completed step\n * @param userId - User who abandoned\n * @param reason - Optional abandonment reason\n * @returns Promise resolving to abandonment response\n */\n async trackAbandon(\n funnelId: string,\n lastStep: string,\n userId?: string,\n reason?: string\n ): Promise<FunnelStepResponse> {\n return await this.init(\"funnel_abandon\", {\n type: \"funnel_abandon\",\n funnelId,\n lastStep,\n userId,\n reason,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Analyzes funnel performance.\n * \n * @param funnelId - Funnel identifier\n * @param filter - Date range filter\n * @returns Promise resolving to funnel analytics\n * \n * @example\n * ```typescript\n * const analysis = await funnels.analyze('checkout_funnel', {\n * range: 'last7days'\n * });\n * \n * // Funnel visualization data\n * const funnelData = analysis.visualization.map(step => ({\n * name: step.step,\n * value: step.entered,\n * conversion: step.conversionRate\n * }));\n * \n * // Overall conversion rate\n * console.log(`Conversion: ${analysis.analysis.overallConversionRate}%`);\n * ```\n */\n async analyze(\n funnelId: string,\n filter?: DateRangeFilter\n ): Promise<FunnelAnalyticsData> {\n return await this.init(\"analyze_funnel\", {\n type: \"query\",\n funnelId,\n filter: filter || { range: \"last30days\" },\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Compares two funnel periods or segments.\n * \n * @param funnelId - Funnel identifier\n * @param baselineFilter - Baseline period filter\n * @param comparisonFilter - Comparison period filter\n * @returns Promise resolving to comparison data\n * \n * @example\n * ```typescript\n * const comparison = await funnels.compare(\n * 'checkout_funnel',\n * { range: 'last30days' },\n * { range: 'last60days' }\n * );\n * \n * // Side-by-side comparison chart\n * const comparisonData = comparison.stepComparison.map(s => ({\n * step: s.step,\n * baseline: s.baselineRate,\n * comparison: s.comparisonRate\n * }));\n * ```\n */\n async compare(\n funnelId: string,\n baselineFilter: DateRangeFilter,\n comparisonFilter: DateRangeFilter\n ): Promise<FunnelComparisonData> {\n return await this.init(\"compare_funnel\", {\n type: \"query\",\n funnelId,\n baselineFilter,\n comparisonFilter,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Lists all defined funnels.\n * \n * @returns Promise resolving to funnel list\n */\n async list(): Promise<FunnelDefinition[]> {\n return await this.init(\"list_funnels\", {\n type: \"query\",\n timestamp: new Date().toISOString()\n });\n }\n}\n\nexport default Funnels;\n","/**\n * @fileoverview Product Analytics - Retention Analysis\n * @module features/analytics/retention\n * \n * @description\n * Track and analyze user retention using cohort analysis,\n * identify churn patterns, and measure user stickiness.\n * \n * @useCases\n * - Measure week-over-week retention rates\n * - Compare retention across user cohorts\n * - Identify churn risk factors\n * - Track feature adoption impact on retention\n * - Calculate DAU/MAU ratios (stickiness)\n * \n * @metrics\n * - Day 1, 7, 30 retention rates\n * - Cohort retention curves\n * - Churn rate by segment\n * - User resurrection rate\n * - DAU/WAU/MAU ratios\n * \n * @chartData\n * - Retention curve: Line chart over time\n * - Cohort matrix: Heatmap by cohort/period\n * - Bar chart: Retention by segment\n * - Trend line: Stickiness over time\n * \n * @example\n * ```typescript\n * const retention = new Retention(webId, endpoint, apiKey);\n * \n * // Track user activity\n * await retention.trackActivity({\n * userId: 'user_123',\n * action: 'feature_used'\n * });\n * \n * // Get cohort analysis\n * const cohorts = await retention.getCohortAnalysis({\n * range: 'last90days',\n * granularity: 'week'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n RetentionCohort,\n UserLifecycleStage,\n LifecycleMetrics,\n DateRangeFilter,\n TimeGranularity,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking user activity.\n */\nexport interface ActivityConfig {\n /** User identifier */\n userId: string;\n /** Activity type/action */\n action?: string;\n /** Session ID */\n sessionId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Configuration for cohort analysis.\n */\nexport interface CohortAnalysisConfig {\n /** Date range for analysis */\n filter?: DateRangeFilter;\n /** Cohort granularity */\n granularity?: TimeGranularity;\n /** Segment by trait */\n segmentBy?: string;\n /** Number of periods to show */\n periods?: number;\n}\n\n/**\n * Activity tracking response.\n */\nexport interface ActivityResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n userId: string;\n tracked: boolean;\n daysSinceFirstSeen: number;\n isReturning: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Cohort analysis data for charts.\n */\nexport interface CohortAnalysisData {\n /** Cohort data */\n cohorts: RetentionCohort[];\n /** Retention matrix for heatmap */\n matrix: Array<{\n cohort: string;\n periods: Array<{\n period: number;\n retained: number;\n retentionRate: number;\n }>;\n }>;\n /** Summary metrics */\n summary: {\n avgDay1Retention: number;\n avgDay7Retention: number;\n avgDay30Retention: number;\n overallRetentionTrend: 'improving' | 'declining' | 'stable';\n };\n}\n\n/**\n * User stickiness data.\n */\nexport interface StickinessData {\n /** DAU - Daily Active Users */\n dau: number;\n /** WAU - Weekly Active Users */\n wau: number;\n /** MAU - Monthly Active Users */\n mau: number;\n /** DAU/MAU ratio (stickiness) */\n dauMauRatio: number;\n /** DAU/WAU ratio */\n dauWauRatio: number;\n /** Stickiness trend over time */\n trendData: TimeSeriesData;\n}\n\n/**\n * Churn analysis data.\n */\nexport interface ChurnAnalysisData {\n /** Current churn rate */\n churnRate: number;\n /** Users at risk of churning */\n atRiskUsers: number;\n /** Users who churned this period */\n churnedUsers: number;\n /** Churn by segment */\n bySegment: Array<{\n segment: string;\n churnRate: number;\n count: number;\n }>;\n /** Common churn factors */\n churnFactors: Array<{\n factor: string;\n correlation: number;\n }>;\n /** Churn trend */\n trendData: TimeSeriesData;\n}\n\n// ============================================================================\n// RETENTION CLASS\n// ============================================================================\n\n/**\n * Retention - Track and analyze user retention.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides retention analysis capabilities including:\n * - User activity tracking\n * - Cohort-based retention analysis\n * - Stickiness metrics (DAU/MAU)\n * - Churn prediction and analysis\n * - Lifecycle stage tracking\n * \n * @example\n * ```typescript\n * const retention = new Retention(webId, endpoint, apiKey);\n * \n * // Track daily user activity\n * await retention.trackActivity({\n * userId: 'user_123',\n * action: 'daily_login'\n * });\n * \n * // Analyze cohort retention\n * const analysis = await retention.getCohortAnalysis({\n * granularity: 'week',\n * periods: 12\n * });\n * \n * // Cohort heatmap data\n * const heatmapData = analysis.matrix;\n * ```\n */\nexport class Retention extends FlowGridTransport {\n /**\n * Tracks user activity for retention calculation.\n * \n * @param config - Activity configuration\n * @returns Promise resolving to activity response\n * \n * @example\n * ```typescript\n * // Track on app open\n * await retention.trackActivity({\n * userId: 'user_123',\n * action: 'app_opened'\n * });\n * \n * // Track specific feature usage\n * await retention.trackActivity({\n * userId: 'user_123',\n * action: 'used_export',\n * properties: { format: 'pdf' }\n * });\n * ```\n */\n async trackActivity(config: ActivityConfig): Promise<ActivityResponse> {\n return await this.init(\"user_activity\", {\n type: \"user_activity\",\n userId: config.userId,\n action: config.action || \"active\",\n sessionId: config.sessionId,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks user lifecycle stage change.\n * \n * @param userId - User identifier\n * @param stage - New lifecycle stage\n * @param previousStage - Previous stage (optional)\n * @returns Promise resolving to stage change response\n */\n async trackLifecycleChange(\n userId: string,\n stage: UserLifecycleStage,\n previousStage?: UserLifecycleStage\n ): Promise<ActivityResponse> {\n return await this.init(\"lifecycle_change\", {\n type: \"lifecycle_change\",\n userId,\n stage,\n previousStage,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Retention;\n","/**\n * @fileoverview Product Analytics - Revenue Attribution\n * @module features/analytics/attribution\n * \n * @description\n * Multi-touch attribution modeling to understand which marketing\n * channels and touchpoints drive conversions and revenue.\n * \n * @useCases\n * - Track marketing touchpoints across customer journey\n * - Calculate attribution for conversions\n * - Compare attribution models (first-touch, last-touch, linear)\n * - Optimize marketing spend allocation\n * - Understand channel effectiveness\n * \n * @metrics\n * - Attributed revenue by channel\n * - Conversion paths\n * - Assisted conversions\n * - Time to conversion\n * - Channel influence score\n * \n * @chartData\n * - Sankey diagram: Customer journey paths\n * - Bar chart: Revenue by channel\n * - Table: Attribution comparison by model\n * - Pie chart: Channel contribution\n * \n * @example\n * ```typescript\n * const attribution = new Attribution(webId, endpoint, apiKey);\n * \n * // Track touchpoint\n * await attribution.trackTouchpoint({\n * userId: 'user_123',\n * channel: 'google_ads',\n * campaign: 'brand_terms',\n * medium: 'cpc'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n UTMParams,\n MoneyValue,\n DateRangeFilter,\n TimeSeriesData\n} from \"../../types\";\nimport { getWindow, getDocument, isBrowser } from \"../../utils/browser\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Attribution model types.\n */\nexport type AttributionModel = \n | 'first_touch'\n | 'last_touch'\n | 'linear'\n | 'time_decay'\n | 'position_based'\n | 'data_driven';\n\n/**\n * Marketing touchpoint configuration.\n */\nexport interface TouchpointConfig {\n /** User ID */\n userId: string;\n /** Marketing channel */\n channel: string;\n /** Campaign name */\n campaign?: string;\n /** Traffic medium */\n medium?: string;\n /** Traffic source */\n source?: string;\n /** Content/creative */\n content?: string;\n /** Search term */\n term?: string;\n /** Referrer URL */\n referrer?: string;\n /** Landing page */\n landingPage?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Conversion event for attribution.\n */\nexport interface ConversionEvent {\n /** User ID */\n userId: string;\n /** Conversion type */\n conversionType: 'purchase' | 'signup' | 'lead' | 'custom';\n /** Conversion value */\n value?: MoneyValue;\n /** Conversion identifier (e.g., order ID) */\n conversionId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Touchpoint response from API.\n */\nexport interface TouchpointResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n touchpointId: string;\n userId: string;\n position: number;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Attribution report data.\n */\nexport interface AttributionReportData {\n /** Selected attribution model */\n model: AttributionModel;\n /** Attribution by channel */\n byChannel: Array<{\n channel: string;\n conversions: number;\n attributedRevenue: MoneyValue;\n assistedConversions: number;\n avgTouchpoints: number;\n firstTouchConversions: number;\n lastTouchConversions: number;\n }>;\n /** Top conversion paths */\n topPaths: Array<{\n path: string[];\n conversions: number;\n revenue: MoneyValue;\n avgTimeToConvert: number;\n }>;\n /** Summary metrics */\n summary: {\n totalConversions: number;\n totalRevenue: MoneyValue;\n avgTouchpointsPerConversion: number;\n avgTimeToConversion: number;\n topChannel: string;\n topCampaign: string;\n };\n /** Model comparison */\n modelComparison: Array<{\n model: AttributionModel;\n channelAttribution: Record<string, number>;\n }>;\n}\n\n// ============================================================================\n// ATTRIBUTION CLASS\n// ============================================================================\n\n/**\n * Attribution - Multi-touch attribution tracking.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides attribution capabilities including:\n * - Touchpoint tracking\n * - Conversion attribution\n * - Multiple attribution models\n * - Path analysis\n * - Channel effectiveness\n * \n * @example\n * ```typescript\n * const attribution = new Attribution(webId, endpoint, apiKey);\n * \n * // Track touchpoints throughout customer journey\n * await attribution.trackTouchpoint({\n * userId: 'user_123',\n * channel: 'email',\n * campaign: 'welcome_series',\n * medium: 'email'\n * });\n * \n * // Record conversion\n * await attribution.recordConversion({\n * userId: 'user_123',\n * conversionType: 'purchase',\n * value: { amount: 9999, currency: 'USD' },\n * conversionId: 'ORD-12345'\n * });\n * ```\n */\nexport class Attribution extends FlowGridTransport {\n /**\n * Tracks a marketing touchpoint.\n * \n * @param config - Touchpoint configuration\n * @returns Promise resolving to touchpoint response\n * \n * @example\n * ```typescript\n * await attribution.trackTouchpoint({\n * userId: 'user_123',\n * channel: 'facebook_ads',\n * campaign: 'retargeting_cart',\n * medium: 'paid_social',\n * landingPage: '/products/special-offer'\n * });\n * ```\n */\n async trackTouchpoint(config: TouchpointConfig): Promise<TouchpointResponse> {\n return await this.init(\"attribution_touchpoint\", {\n type: \"attribution_touchpoint\",\n userId: config.userId,\n channel: config.channel,\n campaign: config.campaign,\n medium: config.medium,\n source: config.source,\n content: config.content,\n term: config.term,\n referrer: config.referrer,\n landingPage: config.landingPage,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Records a conversion for attribution.\n * \n * @param event - Conversion event\n * @returns Promise resolving to conversion response\n * \n * @example\n * ```typescript\n * await attribution.recordConversion({\n * userId: 'user_123',\n * conversionType: 'purchase',\n * value: { amount: 14999, currency: 'USD' },\n * conversionId: 'ORD-98765'\n * });\n * ```\n */\n async recordConversion(event: ConversionEvent): Promise<TouchpointResponse> {\n return await this.init(\"attribution_conversion\", {\n type: \"attribution_conversion\",\n userId: event.userId,\n conversionType: event.conversionType,\n value: event.value,\n conversionId: event.conversionId,\n ...event.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Auto-capture a touchpoint from `utm_*` query params and `document.referrer`.\n * Browser-only; returns null on the server or when no UTM/referrer data is present.\n */\n captureFromUrl(userId: string): TouchpointConfig | null {\n if (!isBrowser()) return null;\n const win = getWindow();\n const doc = getDocument();\n if (!win || !doc) return null;\n\n const params = new URLSearchParams(win.location.search);\n const utm: UTMParams = {\n utmSource: params.get(\"utm_source\") ?? undefined,\n utmMedium: params.get(\"utm_medium\") ?? undefined,\n utmCampaign: params.get(\"utm_campaign\") ?? undefined,\n utmTerm: params.get(\"utm_term\") ?? undefined,\n utmContent: params.get(\"utm_content\") ?? undefined,\n };\n const referrer = doc.referrer || undefined;\n\n if (!utm.utmSource && !utm.utmMedium && !utm.utmCampaign && !referrer) {\n return null;\n }\n\n const config: TouchpointConfig = {\n userId,\n channel: utm.utmSource || (referrer ? \"referral\" : \"direct\"),\n campaign: utm.utmCampaign,\n medium: utm.utmMedium,\n source: utm.utmSource,\n content: utm.utmContent,\n term: utm.utmTerm,\n referrer,\n landingPage: win.location.pathname,\n };\n void this.trackTouchpoint(config);\n return config;\n }\n}\n\nexport default Attribution;\n","/**\n * @fileoverview Product Analytics - Heatmaps & Click Tracking\n * @module features/analytics/heatmaps\n * \n * @description\n * Track user interactions for heatmap visualization including\n * clicks, mouse movements, and scroll behavior.\n * \n * @useCases\n * - Visualize click patterns on pages\n * - Identify dead zones and ignored elements\n * - Analyze scroll depth and attention\n * - Optimize CTA placement\n * - Improve page layout based on behavior\n * \n * @metrics\n * - Click coordinates and density\n * - Scroll depth distribution\n * - Attention time by viewport\n * - Element interaction rates\n * - Rage clicks detection\n * \n * @chartData\n * - Heatmap: Click density overlay\n * - Scroll map: Attention by page section\n * - Element report: Interaction by element\n * - Rage click detection\n * \n * @example\n * ```typescript\n * const heatmaps = new Heatmaps(webId, endpoint, apiKey);\n * \n * // Track click\n * await heatmaps.trackClick({\n * pageUrl: '/pricing',\n * x: 450,\n * y: 320,\n * viewportWidth: 1920,\n * viewportHeight: 1080\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter } from \"../../types\";\nimport { getWindow, getDocument, isBrowser, combineTeardowns, Teardown } from \"../../utils/browser\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Click interaction data.\n */\nexport interface ClickData {\n /** Page URL */\n pageUrl: string;\n /** X coordinate (from left) */\n x: number;\n /** Y coordinate (from top) */\n y: number;\n /** Viewport width */\n viewportWidth: number;\n /** Viewport height */\n viewportHeight: number;\n /** Element selector clicked */\n elementSelector?: string;\n /** Element text (truncated) */\n elementText?: string;\n /** User ID */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n}\n\n/**\n * Movement/hover data.\n */\nexport interface MovementData {\n /** Page URL */\n pageUrl: string;\n /** Movement path (array of x,y coordinates) */\n path: Array<{ x: number; y: number; t: number }>;\n /** Viewport dimensions */\n viewport: { width: number; height: number };\n /** Session ID */\n sessionId?: string;\n}\n\n/**\n * Scroll data.\n */\nexport interface ScrollData {\n /** Page URL */\n pageUrl: string;\n /** Maximum scroll depth reached (percentage) */\n maxScrollDepth: number;\n /** Page height */\n pageHeight: number;\n /** Viewport height */\n viewportHeight: number;\n /** Time at various scroll depths */\n timeAtDepths?: Record<number, number>;\n /** Session ID */\n sessionId?: string;\n}\n\n/**\n * Heatmap response from API.\n */\nexport interface HeatmapResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n recorded: boolean;\n interactionId: string;\n };\n timestamp: string;\n}\n\n/**\n * Heatmap data for visualization.\n */\nexport interface HeatmapData {\n /** Page URL */\n pageUrl: string;\n /** Click points for heatmap */\n clicks: Array<{\n x: number;\n y: number;\n count: number;\n normalizedX: number;\n normalizedY: number;\n }>;\n /** Scroll depth data */\n scrollDepth: Array<{\n depth: number;\n usersReached: number;\n percentageReached: number;\n avgTimeAtDepth: number;\n }>;\n /** Element interaction data */\n elements: Array<{\n selector: string;\n clicks: number;\n hovers: number;\n avgTimeHovered: number;\n }>;\n /** Rage click zones */\n rageClicks: Array<{\n x: number;\n y: number;\n count: number;\n element: string;\n }>;\n /** Summary */\n summary: {\n totalClicks: number;\n uniqueSessions: number;\n avgScrollDepth: number;\n rageClickRate: number;\n };\n}\n\n// ============================================================================\n// HEATMAPS CLASS\n// ============================================================================\n\n/**\n * Heatmaps - Track user interactions for heatmap visualization.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides heatmap data collection including:\n * - Click tracking with coordinates\n * - Mouse movement tracking\n * - Scroll depth tracking\n * - Element interaction tracking\n * - Rage click detection\n * \n * @example\n * ```typescript\n * const heatmaps = new Heatmaps(webId, endpoint, apiKey);\n * \n * // Track clicks\n * document.addEventListener('click', (e) => {\n * heatmaps.trackClick({\n * pageUrl: window.location.pathname,\n * x: e.clientX,\n * y: e.clientY + window.scrollY,\n * viewportWidth: window.innerWidth,\n * viewportHeight: window.innerHeight,\n * elementSelector: getSelector(e.target)\n * });\n * });\n * \n * // Get heatmap data for visualization\n * const data = await heatmaps.getData('/pricing', { range: 'last7days' });\n * ```\n */\nexport class Heatmaps extends FlowGridTransport {\n\n /** Throttle timestamps */\n private lastMovementTime = 0;\n private lastScrollTime = 0;\n\n /** Throttle intervals (ms) */\n private static readonly MOVEMENT_THROTTLE_MS = 100;\n private static readonly SCROLL_THROTTLE_MS = 500;\n\n /**\n * Tracks a click interaction.\n * \n * @param data - Click data\n * @returns Promise resolving to heatmap response\n */\n async trackClick(data: ClickData): Promise<HeatmapResponse> {\n return await this.init(\"heatmap_click\", {\n type: \"heatmap_click\",\n pageUrl: data.pageUrl,\n x: data.x,\n y: data.y,\n normalizedX: data.x / data.viewportWidth,\n normalizedY: data.y / data.viewportHeight,\n viewportWidth: data.viewportWidth,\n viewportHeight: data.viewportHeight,\n elementSelector: data.elementSelector,\n elementText: data.elementText?.substring(0, 50),\n userId: data.userId,\n sessionId: data.sessionId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks mouse movement path.\n * \n * @param data - Movement data\n * @returns Promise resolving to heatmap response\n */\n async trackMovement(data: MovementData): Promise<HeatmapResponse> {\n const now = Date.now();\n if (now - this.lastMovementTime < Heatmaps.MOVEMENT_THROTTLE_MS) {\n return { eventName: 'heatmap_movement', properties: {}, response: { recorded: false, interactionId: '' }, timestamp: new Date().toISOString() };\n }\n this.lastMovementTime = now;\n\n return await this.init(\"heatmap_movement\", {\n type: \"heatmap_movement\",\n pageUrl: data.pageUrl,\n path: data.path,\n viewport: data.viewport,\n sessionId: data.sessionId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks scroll behavior.\n * \n * @param data - Scroll data\n * @returns Promise resolving to heatmap response\n */\n async trackScroll(data: ScrollData): Promise<HeatmapResponse> {\n const now = Date.now();\n if (now - this.lastScrollTime < Heatmaps.SCROLL_THROTTLE_MS) {\n return { eventName: 'heatmap_scroll', properties: {}, response: { recorded: false, interactionId: '' }, timestamp: new Date().toISOString() };\n }\n this.lastScrollTime = now;\n\n return await this.init(\"heatmap_scroll\", {\n type: \"heatmap_scroll\",\n pageUrl: data.pageUrl,\n maxScrollDepth: data.maxScrollDepth,\n pageHeight: data.pageHeight,\n viewportHeight: data.viewportHeight,\n timeAtDepths: data.timeAtDepths,\n sessionId: data.sessionId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks rage clicks (repeated clicks in frustration).\n * \n * @param pageUrl - Page URL\n * @param x - X coordinate\n * @param y - Y coordinate\n * @param clickCount - Number of rapid clicks\n * @returns Promise resolving to heatmap response\n */\n async trackRageClick(\n pageUrl: string,\n x: number,\n y: number,\n clickCount: number\n ): Promise<HeatmapResponse> {\n return await this.init(\"heatmap_rage_click\", {\n type: \"heatmap_rage_click\",\n pageUrl,\n x,\n y,\n clickCount,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Auto-collect heatmap interactions: clicks (with element selector + text)\n * and scroll depth on the current page. Mouse-move tracking is opt-in\n * because the volume can be very high.\n *\n * @param options.movement Subscribe to throttled mousemove sampling.\n * @param options.userId Attached to every event.\n * @returns Teardown function detaching all listeners.\n */\n autoTrack(options: { movement?: boolean; userId?: string; sessionId?: string } = {}): Teardown {\n if (!isBrowser()) return () => { /* no-op on the server */ };\n const win = getWindow()!;\n const doc = getDocument()!;\n\n const selectorOf = (el: Element | null): string => {\n if (!el) return \"\";\n if (el.id) return `#${el.id}`;\n const tag = el.tagName.toLowerCase();\n const cls = (el.className && typeof el.className === \"string\")\n ? \".\" + el.className.trim().split(/\\s+/).slice(0, 2).join(\".\")\n : \"\";\n return `${tag}${cls}`;\n };\n\n const onClick = (e: MouseEvent) => {\n const target = e.target as Element | null;\n void this.trackClick({\n pageUrl: win.location.pathname,\n x: e.clientX,\n y: e.clientY + win.scrollY,\n viewportWidth: win.innerWidth,\n viewportHeight: win.innerHeight,\n elementSelector: selectorOf(target),\n elementText: (target?.textContent || \"\").trim().slice(0, 50),\n userId: options.userId,\n sessionId: options.sessionId,\n });\n };\n doc.addEventListener(\"click\", onClick, { capture: true, passive: true });\n\n let maxDepth = 0;\n const onScroll = () => {\n const docEl = doc.documentElement;\n const top = win.scrollY || docEl.scrollTop;\n const height = Math.max(1, docEl.scrollHeight - win.innerHeight);\n const depth = Math.min(100, Math.round((top / height) * 100));\n if (depth > maxDepth) maxDepth = depth;\n void this.trackScroll({\n pageUrl: win.location.pathname,\n maxScrollDepth: maxDepth,\n pageHeight: docEl.scrollHeight,\n viewportHeight: win.innerHeight,\n sessionId: options.sessionId,\n });\n };\n win.addEventListener(\"scroll\", onScroll, { passive: true });\n\n let moveTeardown: (() => void) | undefined;\n if (options.movement) {\n let buffer: Array<{ x: number; y: number; t: number }> = [];\n const start = Date.now();\n const onMove = (e: MouseEvent) => {\n buffer.push({ x: e.clientX, y: e.clientY, t: Date.now() - start });\n if (buffer.length >= 50) {\n const path = buffer; buffer = [];\n void this.trackMovement({\n pageUrl: win.location.pathname,\n path,\n viewport: { width: win.innerWidth, height: win.innerHeight },\n sessionId: options.sessionId,\n });\n }\n };\n doc.addEventListener(\"mousemove\", onMove, { passive: true });\n moveTeardown = () => doc.removeEventListener(\"mousemove\", onMove);\n }\n\n return combineTeardowns(\n () => doc.removeEventListener(\"click\", onClick, { capture: true } as EventListenerOptions),\n () => win.removeEventListener(\"scroll\", onScroll),\n moveTeardown,\n );\n }\n}\n\nexport default Heatmaps;\n","/**\n * @fileoverview Product Analytics - Performance Monitoring\n * @module features/analytics/performance\n * \n * @description\n * Track web performance metrics including Core Web Vitals,\n * page load times, and resource performance.\n * \n * @useCases\n * - Monitor Core Web Vitals (LCP, FID, CLS)\n * - Track page load performance\n * - Identify slow pages and resources\n * - Correlate performance with conversions\n * - Monitor API response times\n * \n * @metrics\n * - Largest Contentful Paint (LCP)\n * - First Input Delay (FID)\n * - Cumulative Layout Shift (CLS)\n * - Time to First Byte (TTFB)\n * - First Contentful Paint (FCP)\n * \n * @chartData\n * - Line chart: Core Web Vitals over time\n * - Bar chart: Slowest pages\n * - Histogram: Load time distribution\n * - Gauge: Performance score\n * \n * @example\n * ```typescript\n * const performance = new Performance(webId, endpoint, apiKey);\n * \n * // Track Core Web Vitals\n * await performance.trackWebVitals({\n * lcp: 2500,\n * fid: 100,\n * cls: 0.1,\n * pageUrl: '/products'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData } from \"../../types\";\nimport { getWindow, isBrowser, combineTeardowns, Teardown } from \"../../utils/browser\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Core Web Vitals data.\n */\nexport interface WebVitalsData {\n /** Largest Contentful Paint (ms) */\n lcp?: number;\n /** First Input Delay (ms) */\n fid?: number;\n /** Cumulative Layout Shift (score) */\n cls?: number;\n /** First Contentful Paint (ms) */\n fcp?: number;\n /** Time to First Byte (ms) */\n ttfb?: number;\n /** Interaction to Next Paint (ms) */\n inp?: number;\n /** Page URL */\n pageUrl: string;\n /** User ID */\n userId?: string;\n /** Connection type */\n connectionType?: 'slow-2g' | '2g' | '3g' | '4g' | 'wifi' | 'unknown';\n /** Device type */\n deviceType?: 'mobile' | 'tablet' | 'desktop';\n}\n\n/**\n * Page load timing data.\n */\nexport interface PageLoadData {\n /** Page URL */\n pageUrl: string;\n /** DNS lookup time (ms) */\n dnsTime?: number;\n /** TCP connection time (ms) */\n tcpTime?: number;\n /** Time to first byte (ms) */\n ttfb?: number;\n /** DOM content loaded time (ms) */\n domContentLoaded?: number;\n /** Full page load time (ms) */\n loadTime?: number;\n /** DOM interactive time (ms) */\n domInteractive?: number;\n /** Number of resources */\n resourceCount?: number;\n /** Total transfer size (bytes) */\n transferSize?: number;\n}\n\n/**\n * Resource timing data.\n */\nexport interface ResourceData {\n /** Resource URL */\n resourceUrl: string;\n /** Resource type */\n resourceType: 'script' | 'stylesheet' | 'image' | 'font' | 'fetch' | 'xhr' | 'other';\n /** Duration (ms) */\n duration: number;\n /** Transfer size (bytes) */\n transferSize?: number;\n /** Page URL where resource was loaded */\n pageUrl: string;\n}\n\n/**\n * Performance response from API.\n */\nexport interface PerformanceResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n recorded: boolean;\n performanceScore?: number;\n };\n timestamp: string;\n}\n\n/**\n * Performance analytics data.\n */\nexport interface PerformanceAnalyticsData {\n /** Core Web Vitals summary */\n webVitals: {\n lcp: { p50: number; p75: number; p95: number; good: number; needsImprovement: number; poor: number };\n fid: { p50: number; p75: number; p95: number; good: number; needsImprovement: number; poor: number };\n cls: { p50: number; p75: number; p95: number; good: number; needsImprovement: number; poor: number };\n inp: { p50: number; p75: number; p95: number; good: number; needsImprovement: number; poor: number };\n };\n /** Performance by page */\n byPage: Array<{\n pageUrl: string;\n avgLoadTime: number;\n avgLCP: number;\n avgFID: number;\n avgCLS: number;\n sampleSize: number;\n }>;\n /** Performance by device */\n byDevice: Array<{\n device: string;\n avgLoadTime: number;\n avgLCP: number;\n sampleSize: number;\n }>;\n /** Slowest resources */\n slowResources: Array<{\n resourceUrl: string;\n resourceType: string;\n avgDuration: number;\n occurrences: number;\n }>;\n /** Performance trends */\n trends: {\n lcp: TimeSeriesData;\n fid: TimeSeriesData;\n cls: TimeSeriesData;\n };\n /** Overall score (0-100) */\n performanceScore: number;\n}\n\n// ============================================================================\n// PERFORMANCE CLASS\n// ============================================================================\n\n/**\n * Performance - Track web performance metrics.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides performance monitoring including:\n * - Core Web Vitals tracking\n * - Page load timing\n * - Resource performance\n * - API response times\n * - Performance scoring\n * \n * @example\n * ```typescript\n * const performance = new Performance(webId, endpoint, apiKey);\n * \n * // Track Web Vitals (use web-vitals library)\n * import { onLCP, onFID, onCLS } from 'web-vitals';\n * \n * onLCP((metric) => {\n * performance.trackWebVitals({\n * lcp: metric.value,\n * pageUrl: window.location.pathname\n * });\n * });\n * ```\n */\nexport class PerformanceTracking extends FlowGridTransport {\n /**\n * Tracks Core Web Vitals.\n * \n * @param data - Web Vitals data\n * @returns Promise resolving to performance response\n */\n async trackWebVitals(data: WebVitalsData): Promise<PerformanceResponse> {\n return await this.init(\"web_vitals\", {\n type: \"web_vitals\",\n ...data,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks page load timing.\n * \n * @param data - Page load data\n * @returns Promise resolving to performance response\n */\n async trackPageLoad(data: PageLoadData): Promise<PerformanceResponse> {\n return await this.init(\"page_load\", {\n type: \"page_load\",\n ...data,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks resource performance.\n * \n * @param data - Resource data\n * @returns Promise resolving to performance response\n */\n async trackResource(data: ResourceData): Promise<PerformanceResponse> {\n return await this.init(\"resource_timing\", {\n type: \"resource_timing\",\n ...data,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks API call performance.\n * \n * @param endpoint - API endpoint\n * @param duration - Response time (ms)\n * @param success - Whether call succeeded\n * @param statusCode - HTTP status code\n * @returns Promise resolving to performance response\n */\n async trackApiCall(\n endpoint: string,\n duration: number,\n success: boolean,\n statusCode?: number\n ): Promise<PerformanceResponse> {\n return await this.init(\"api_timing\", {\n type: \"api_timing\",\n endpoint,\n duration,\n success,\n statusCode,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Auto-collect Core Web Vitals, navigation timing, and resource timing\n * directly from the browser. Safe no-op outside the browser.\n *\n * @param options.userId Optional user identifier attached to every metric.\n * @param options.resources When true, also subscribes to PerformanceObserver\n * for `resource` entries. Default: false (noisy).\n * @param options.minDuration Only forward resources slower than this (ms). Default 200.\n * @returns A teardown function that detaches all observers/listeners.\n *\n * @example\n * ```ts\n * const stop = fg.performance.client.autoTrack({ userId: \"u_1\" });\n * // ...later\n * stop();\n * ```\n */\n autoTrack(options: {\n userId?: string;\n resources?: boolean;\n minDuration?: number;\n } = {}): Teardown {\n if (!isBrowser()) return () => { /* no-op on the server */ };\n\n const win = getWindow()!;\n const pageUrl = win.location.pathname;\n const teardowns: Array<() => void> = [];\n\n // --- Web Vitals via the `web-vitals` library (dynamic import keeps it\n // out of server bundles even if tree-shaking misses it).\n let cancelled = false;\n void import(\"web-vitals\").then((wv) => {\n if (cancelled) return;\n const send = (metric: { name: string; value: number }) => {\n const key = metric.name.toLowerCase() as keyof Pick<WebVitalsData, \"lcp\" | \"fid\" | \"cls\" | \"fcp\" | \"ttfb\" | \"inp\">;\n const payload: WebVitalsData = { pageUrl, userId: options.userId };\n (payload[key] as number | undefined) = metric.value;\n void this.trackWebVitals(payload);\n };\n wv.onLCP?.(send);\n wv.onCLS?.(send);\n wv.onINP?.(send);\n wv.onFCP?.(send);\n wv.onTTFB?.(send);\n // FID was removed in web-vitals v4+, but we still surface it if present\n (wv as { onFID?: (cb: (m: { name: string; value: number }) => void) => void }).onFID?.(send);\n }).catch(() => { /* library missing — silently skip */ });\n teardowns.push(() => { cancelled = true; });\n\n // --- PerformanceNavigationTiming → trackPageLoad\n const reportNavigation = () => {\n const nav = win.performance?.getEntriesByType?.(\"navigation\")?.[0] as\n PerformanceNavigationTiming | undefined;\n if (!nav) return;\n void this.trackPageLoad({\n pageUrl,\n dnsTime: Math.max(0, nav.domainLookupEnd - nav.domainLookupStart),\n tcpTime: Math.max(0, nav.connectEnd - nav.connectStart),\n ttfb: Math.max(0, nav.responseStart - nav.requestStart),\n domContentLoaded: nav.domContentLoadedEventEnd,\n loadTime: nav.loadEventEnd,\n domInteractive: nav.domInteractive,\n transferSize: nav.transferSize,\n });\n };\n if (win.document.readyState === \"complete\") {\n reportNavigation();\n } else {\n const onLoad = () => reportNavigation();\n win.addEventListener(\"load\", onLoad, { once: true });\n teardowns.push(() => win.removeEventListener(\"load\", onLoad));\n }\n\n // --- Resource timing (opt-in)\n if (options.resources && typeof win.PerformanceObserver === \"function\") {\n const min = options.minDuration ?? 200;\n const obs = new win.PerformanceObserver((list) => {\n for (const entry of list.getEntries() as PerformanceResourceTiming[]) {\n if (entry.duration < min) continue;\n const initiator = entry.initiatorType as ResourceData[\"resourceType\"];\n void this.trackResource({\n resourceUrl: entry.name,\n resourceType: ([\n \"script\", \"stylesheet\", \"image\", \"font\", \"fetch\", \"xhr\",\n ].includes(initiator) ? initiator : \"other\"),\n duration: Math.round(entry.duration),\n transferSize: entry.transferSize,\n pageUrl,\n });\n }\n });\n try {\n obs.observe({ type: \"resource\", buffered: true });\n teardowns.push(() => obs.disconnect());\n } catch { /* unsupported */ }\n }\n\n return combineTeardowns(...teardowns);\n }\n}\n\nexport { PerformanceTracking as Performance };\nexport default PerformanceTracking;\n","/**\n * @fileoverview Session Replay (rrweb) capture.\n * @module features/analytics/replay\n *\n * @description\n * Browser-only DOM session replay powered by [rrweb](https://github.com/rrweb-io/rrweb).\n * Records DOM mutations, mouse, scroll, input, and viewport events, batches them\n * into chunks, and ships them to the FlowGrid backend at `call=replay_chunk`.\n *\n * Loaded dynamically so it is only pulled into the bundle when `start()` is\n * called in a browser environment.\n *\n * @example\n * ```ts\n * const stop = await fg.replay.start({\n * sampleRate: 1.0,\n * maskAllInputs: true,\n * });\n * // ...later\n * stop();\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { isBrowser, getDocument, type Teardown } from \"../../utils/browser\";\n\n// ============================================================================\n// CONFIG\n// ============================================================================\n\nexport interface SessionReplayOptions {\n\n /** Explicit enable switch. Pass `false` to keep the recorder disabled. */\n enabled?: boolean;\n\n /** Sampling rate 0.0-1.0. Default 1.0 (record every session). */\n sampleRate?: number;\n\n /** Existing session ID to attach the recording to. Auto-generated otherwise. */\n sessionId?: string;\n\n /** User ID for the recording, if known. */\n userId?: string;\n\n /** Mask all `<input>`, `<textarea>` and `[contenteditable]` values. Default true. */\n maskAllInputs?: boolean;\n\n /** Mask text content under elements matching this CSS class. Default `\"fg-mask\"`. */\n maskTextClass?: string | RegExp;\n\n /** Skip recording elements matching this CSS class entirely. Default `\"fg-block\"`. */\n blockClass?: string | RegExp;\n\n /** Ignore events on elements matching this CSS class. Default `\"fg-ignore\"`. */\n ignoreClass?: string;\n\n /** Flush buffered events at most every N ms. Default 5000. */\n flushIntervalMs?: number;\n\n /** Force flush when buffer reaches N bytes (approximate). Default 512KB. */\n flushBytes?: number;\n\n /** Maximum recording length per session in ms. Default 30 minutes. */\n maxDurationMs?: number;\n\n /** Hard cap on total bytes captured per session. Default 10MB. */\n maxBytes?: number;\n\n /** Invoked when recorder state changes or lifecycle metadata is updated. */\n onStatus?: (status: SessionReplayStatus) => void;\n\n /** Invoked after a chunk is accepted for transport. */\n onFlush?: (metadata: SessionReplayFlushMetadata) => void;\n\n /** Invoked when events are dropped due to limits or serialization issues. */\n onDrop?: (metadata: SessionReplayDropMetadata) => void;\n\n /** Invoked when recorder setup or teardown fails. */\n onError?: (error: Error, context: SessionReplayErrorContext) => void;\n\n}\n\nexport type SessionReplayState =\n | \"idle\"\n | \"starting\"\n | \"recording\"\n | \"stopped\"\n | \"disabled\"\n | \"sampled_out\"\n | \"error\";\n\nexport type SessionReplayFlushReason =\n | \"interval\"\n | \"size\"\n | \"visibility_hidden\"\n | \"pagehide\"\n | \"manual\"\n | \"stop\"\n | \"max_duration\"\n | \"max_bytes\";\n\nexport interface SessionReplayStatus {\n state: SessionReplayState;\n sessionId?: string;\n userId?: string;\n startedAt?: string;\n sequence: number;\n bufferedEvents: number;\n bufferedBytes: number;\n totalBytes: number;\n droppedEvents: number;\n recorderVersion: string;\n lastFlushReason?: SessionReplayFlushReason;\n lastError?: string;\n}\n\nexport interface SessionReplayFlushMetadata {\n sessionId: string;\n userId?: string;\n sequence: number;\n eventsCount: number;\n byteSize: number;\n reason: SessionReplayFlushReason;\n isFinal: boolean;\n droppedEvents: number;\n capturedAt: string;\n idempotencyKey: string;\n}\n\nexport interface SessionReplayDropMetadata {\n sessionId?: string;\n reason: \"serialization_error\" | \"max_bytes\";\n droppedEvents: number;\n byteSize?: number;\n maxBytes?: number;\n}\n\nexport interface SessionReplayErrorContext {\n phase: \"import\" | \"record\" | \"flush\" | \"stop\";\n sessionId?: string;\n}\n\nexport interface SessionReplaySendChunkOptions {\n userId?: string;\n sequence?: number;\n useBeacon?: boolean;\n startedAt?: string;\n capturedAt?: string;\n pageUrl?: string;\n isFinal?: boolean;\n reason?: SessionReplayFlushReason;\n privacy?: ReplayPrivacyMetadata;\n droppedEvents?: number;\n recorderVersion?: string;\n}\n\nexport interface ReplayPrivacyMetadata {\n masking_mode: \"all_inputs\" | \"selective\" | \"custom\";\n blocked_selectors: string[];\n redacted_fields: string[];\n consent_state: \"granted\" | \"denied\" | \"unknown\";\n sampling_state: \"sampled_in\" | \"sampled_out\";\n}\n\ninterface ActiveRecording {\n sessionId: string;\n userId?: string;\n startedAtMs: number;\n startedAt: string;\n sequence: number;\n buffer: unknown[];\n bufferBytes: number;\n totalBytes: number;\n droppedEvents: number;\n stopped: boolean;\n flushTimer: ReturnType<typeof setInterval>;\n durationGuard: ReturnType<typeof setTimeout>;\n stopRecording?: Teardown;\n onVisibility: () => void;\n onPageHide: () => void;\n options: Required<Pick<SessionReplayOptions, \"flushIntervalMs\" | \"flushBytes\" | \"maxDurationMs\" | \"maxBytes\" | \"maskAllInputs\">> & SessionReplayOptions;\n}\n\nconst DEFAULT_FLUSH_MS = 5_000;\nconst DEFAULT_FLUSH_BYTES = 512 * 1024;\nconst DEFAULT_MAX_DURATION_MS = 30 * 60 * 1000;\nconst DEFAULT_MAX_BYTES = 10 * 1024 * 1024;\nconst STORAGE_KEY = \"flowgrid:replaySessionId\";\nconst RECORDER_VERSION = \"rrweb@2\";\n\n// ============================================================================\n// SESSION REPLAY CLASS\n// ============================================================================\n\nexport class SessionReplay extends FlowGridTransport {\n private disabled = false;\n private active: ActiveRecording | null = null;\n private state: SessionReplayState = \"idle\";\n private boundUserId?: string;\n private lastError?: string;\n\n /**\n * Begin capturing the current page as a replay session. Returns a teardown\n * function that flushes the final buffer (via `sendBeacon` when possible)\n * and detaches the recorder.\n *\n * No-op on the server or when the browser fails sampling.\n */\n async start(options: SessionReplayOptions = {}): Promise<Teardown> {\n\n if (options.enabled === false || this.disabled) {\n this.setState(\"disabled\", options);\n return () => {};\n }\n\n if (this.active && !this.active.stopped) {\n this.emitStatus(this.active.options);\n return () => this.stop(\"manual\");\n }\n\n if (!isBrowser()) return () => {};\n\n this.setState(\"starting\", options);\n\n const sampleRate = options.sampleRate ?? 1.0;\n if (sampleRate < 1 && Math.random() > sampleRate) {\n this.setState(\"sampled_out\", options);\n return () => {};\n }\n\n let rrweb: typeof import(\"rrweb\");\n try {\n rrweb = await import(\"rrweb\");\n } catch (error) {\n this.handleError(this.toError(error), { phase: \"import\" }, options);\n return () => {};\n }\n\n const doc = getDocument();\n if (!doc) return () => {};\n\n const sessionId = options.sessionId ?? this.resolveSessionId();\n const normalizedOptions = this.normalizeOptions(options);\n const startedAtMs = Date.now();\n \n const active: ActiveRecording = {\n sessionId,\n userId: options.userId ?? this.boundUserId,\n startedAtMs,\n startedAt: new Date(startedAtMs).toISOString(),\n sequence: 0,\n buffer: [],\n bufferBytes: 0,\n totalBytes: 0,\n droppedEvents: 0,\n stopped: false,\n flushTimer: setInterval(() => { void this.flush(\"interval\"); }, normalizedOptions.flushIntervalMs),\n durationGuard: setTimeout(() => this.stop(\"max_duration\"), normalizedOptions.maxDurationMs),\n onVisibility: () => {\n if (doc.visibilityState === \"hidden\") void this.flush(\"visibility_hidden\", { useBeacon: true });\n },\n onPageHide: () => { void this.flush(\"pagehide\", { useBeacon: true }); },\n options: normalizedOptions,\n };\n\n this.active = active;\n\n try {\n\n active.stopRecording = rrweb.record({\n emit: (event: unknown) => this.captureEvent(event),\n maskAllInputs: normalizedOptions.maskAllInputs,\n maskTextClass: normalizedOptions.maskTextClass ?? \"fg-mask\",\n blockClass: normalizedOptions.blockClass ?? \"fg-block\",\n ignoreClass: normalizedOptions.ignoreClass ?? \"fg-ignore\",\n });\n\n } catch (error) {\n\n this.handleError(this.toError(error), { \n phase: \"record\", sessionId \n }, normalizedOptions);\n\n active.stopped = true;\n\n this.cleanupActive(\"stop\");\n\n this.active = null;\n\n return () => {};\n\n }\n\n doc.addEventListener(\"visibilitychange\", active.onVisibility);\n window.addEventListener(\"pagehide\", active.onPageHide);\n\n this.setState(\"recording\", normalizedOptions);\n\n return () => this.stop(\"manual\");\n }\n\n /** Enable replay capture and start recording immediately. */\n enable(options: SessionReplayOptions = {}): Promise<Teardown> {\n this.disabled = false;\n return this.start({ ...options, enabled: true });\n }\n\n /** Disable replay capture and stop any active recording. */\n disable(): void {\n this.disabled = true;\n this.stop(\"manual\");\n this.setState(\"disabled\", this.active?.options);\n }\n\n /** Stop recording and flush the final chunk with lifecycle metadata. */\n stop(reason: SessionReplayFlushReason = \"stop\"): void {\n const active = this.active;\n if (!active || active.stopped) return;\n active.stopped = true;\n this.cleanupActive(reason);\n void this.flush(reason, { useBeacon: true, isFinal: true });\n this.setState(\"stopped\", active.options, reason);\n this.active = null;\n }\n\n /** Flush buffered rrweb events without stopping the recorder. */\n async flush(\n reason: SessionReplayFlushReason = \"manual\",\n options: { useBeacon?: boolean; isFinal?: boolean } = {},\n ): Promise<void> {\n\n const active = this.active;\n if (!active || active.buffer.length === 0) return;\n\n const events = active.buffer;\n const eventsCount = events.length;\n const byteSize = active.bufferBytes;\n const sequence = active.sequence++;\n active.buffer = [];\n active.bufferBytes = 0;\n\n const capturedAt = new Date().toISOString();\n const idempotencyKey = this.createIdempotencyKey(active.sessionId, sequence, byteSize);\n const metadata: SessionReplayFlushMetadata = {\n sessionId: active.sessionId,\n userId: active.userId,\n sequence,\n eventsCount,\n byteSize,\n reason,\n isFinal: options.isFinal === true,\n droppedEvents: active.droppedEvents,\n capturedAt,\n idempotencyKey,\n };\n\n try {\n await this.postReplayChunk(active.sessionId, events, {\n userId: active.userId,\n sequence,\n useBeacon: options.useBeacon,\n startedAt: active.startedAt,\n capturedAt,\n pageUrl: this.getPageUrl(),\n isFinal: metadata.isFinal,\n reason,\n privacy: this.createPrivacyMetadata(active.options, \"sampled_in\"),\n droppedEvents: active.droppedEvents,\n recorderVersion: RECORDER_VERSION,\n }, idempotencyKey);\n active.options.onFlush?.(metadata);\n this.emitStatus(active.options, reason);\n } catch (error) {\n this.handleError(this.toError(error), { phase: \"flush\", sessionId: active.sessionId }, active.options);\n }\n }\n\n /** Bind a known user to subsequent chunks in the active recording. */\n identify(userId: string): void {\n this.boundUserId = userId;\n if (this.active) {\n this.active.userId = userId;\n this.emitStatus(this.active.options);\n }\n }\n\n /** Current recorder health/lifecycle state. */\n getStatus(): SessionReplayStatus {\n return this.createStatus(this.active?.options);\n }\n\n /**\n * Manually persist a single rrweb event chunk. Most callers should use\n * `start()` instead; this is exposed for tests and advanced integrations\n * that drive `rrweb.record()` themselves.\n */\n async sendChunk(\n sessionId: string,\n events: unknown[],\n options: SessionReplaySendChunkOptions = {},\n ): Promise<void> {\n if (events.length === 0) return;\n await this.postReplayChunk(sessionId, events, options);\n }\n\n private async postReplayChunk(\n sessionId: string,\n events: unknown[],\n options: SessionReplaySendChunkOptions,\n idempotencyKey = this.createIdempotencyKey(sessionId, options.sequence ?? 0, this.measureEvents(events)),\n ): Promise<void> {\n await this.postRaw(\n \"replay_chunk\",\n {\n type: \"replay_chunk\",\n session_id: sessionId,\n user_id: options.userId,\n sequence: options.sequence ?? 0,\n started_at: options.startedAt,\n captured_at: options.capturedAt ?? new Date().toISOString(),\n events,\n page_url: options.pageUrl ?? this.getPageUrl(),\n idempotency_key: idempotencyKey,\n compression: \"none\",\n is_final: options.isFinal === true,\n chunk_kind: options.isFinal ? \"final\" : \"partial\",\n flush_reason: options.reason ?? \"manual\",\n dropped_events: options.droppedEvents ?? 0,\n recorder_version: options.recorderVersion ?? RECORDER_VERSION,\n privacy: options.privacy ?? this.createPrivacyMetadata(undefined, \"sampled_in\"),\n },\n { useBeacon: options.useBeacon },\n );\n }\n\n private captureEvent(event: unknown): void {\n const active = this.active;\n if (!active || active.stopped) return;\n\n let size = 0;\n try {\n size = JSON.stringify(event).length;\n } catch {\n active.droppedEvents++;\n active.options.onDrop?.({\n sessionId: active.sessionId,\n reason: \"serialization_error\",\n droppedEvents: active.droppedEvents,\n });\n return;\n }\n\n if (active.totalBytes + size > active.options.maxBytes) {\n active.droppedEvents++;\n active.options.onDrop?.({\n sessionId: active.sessionId,\n reason: \"max_bytes\",\n droppedEvents: active.droppedEvents,\n byteSize: active.totalBytes + size,\n maxBytes: active.options.maxBytes,\n });\n this.stop(\"max_bytes\");\n return;\n }\n\n active.totalBytes += size;\n active.buffer.push(event);\n active.bufferBytes += size;\n\n if (active.bufferBytes >= active.options.flushBytes) {\n void this.flush(\"size\");\n }\n }\n\n private cleanupActive(reason: SessionReplayFlushReason): void {\n const active = this.active;\n if (!active) return;\n const doc = getDocument();\n clearInterval(active.flushTimer);\n clearTimeout(active.durationGuard);\n doc?.removeEventListener(\"visibilitychange\", active.onVisibility);\n window.removeEventListener(\"pagehide\", active.onPageHide);\n try {\n active.stopRecording?.();\n } catch (error) {\n this.handleError(this.toError(error), { phase: \"stop\", sessionId: active.sessionId }, active.options);\n }\n this.emitStatus(active.options, reason);\n }\n\n private normalizeOptions(options: SessionReplayOptions): ActiveRecording[\"options\"] {\n return {\n ...options,\n flushIntervalMs: options.flushIntervalMs ?? DEFAULT_FLUSH_MS,\n flushBytes: options.flushBytes ?? DEFAULT_FLUSH_BYTES,\n maxDurationMs: options.maxDurationMs ?? DEFAULT_MAX_DURATION_MS,\n maxBytes: options.maxBytes ?? DEFAULT_MAX_BYTES,\n maskAllInputs: options.maskAllInputs ?? true,\n };\n }\n\n private createStatus(options?: SessionReplayOptions, reason?: SessionReplayFlushReason): SessionReplayStatus {\n const active = this.active;\n return {\n state: this.state,\n sessionId: active?.sessionId,\n userId: active?.userId ?? this.boundUserId,\n startedAt: active?.startedAt,\n sequence: active?.sequence ?? 0,\n bufferedEvents: active?.buffer.length ?? 0,\n bufferedBytes: active?.bufferBytes ?? 0,\n totalBytes: active?.totalBytes ?? 0,\n droppedEvents: active?.droppedEvents ?? 0,\n recorderVersion: RECORDER_VERSION,\n lastFlushReason: reason,\n lastError: this.lastError,\n };\n }\n\n private setState(state: SessionReplayState, options?: SessionReplayOptions, reason?: SessionReplayFlushReason): void {\n this.state = state;\n this.emitStatus(options, reason);\n }\n\n private emitStatus(options?: SessionReplayOptions, reason?: SessionReplayFlushReason): void {\n options?.onStatus?.(this.createStatus(options, reason));\n }\n\n private handleError(error: Error, context: SessionReplayErrorContext, options?: SessionReplayOptions): void {\n this.lastError = error.message;\n this.state = \"error\";\n options?.onError?.(error, context);\n this.emitStatus(options);\n }\n\n private createPrivacyMetadata(\n options?: SessionReplayOptions,\n samplingState: ReplayPrivacyMetadata[\"sampling_state\"] = \"sampled_in\",\n ): ReplayPrivacyMetadata {\n return {\n masking_mode: options?.maskAllInputs === false ? \"selective\" : \"all_inputs\",\n blocked_selectors: this.selectorList(options?.blockClass ?? \"fg-block\"),\n redacted_fields: this.selectorList(options?.maskTextClass ?? \"fg-mask\"),\n consent_state: FlowGridTransport.hasConsent(\"analytics\") ? \"granted\" : \"denied\",\n sampling_state: samplingState,\n };\n }\n\n private selectorList(selector: string | RegExp): string[] {\n return typeof selector === \"string\" ? [selector] : [selector.source];\n }\n\n private getPageUrl(): string {\n try {\n return typeof location !== \"undefined\" ? location.href : \"\";\n } catch {\n return \"\";\n }\n }\n\n private createIdempotencyKey(sessionId: string, sequence: number, byteSize: number): string {\n return `${this.webId}:${sessionId}:${sequence}:${byteSize}`;\n }\n\n private measureEvents(events: unknown[]): number {\n try {\n return JSON.stringify(events).length;\n } catch {\n return 0;\n }\n }\n\n private toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n }\n\n private resolveSessionId(): string {\n try {\n const existing = sessionStorage.getItem(STORAGE_KEY);\n if (existing) return existing;\n const fresh = this.generateId();\n sessionStorage.setItem(STORAGE_KEY, fresh);\n return fresh;\n } catch {\n return this.generateId();\n }\n }\n\n private generateId(): string {\n const cryptoObj = (typeof crypto !== \"undefined\" ? crypto : undefined) as Crypto | undefined;\n if (cryptoObj?.randomUUID) return cryptoObj.randomUUID();\n return `rep_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n }\n}\n\nexport default SessionReplay;\n","/**\n * @fileoverview Ecommerce - Product Tracking\n * @module features/ecommerce/products\n * \n * @description\n * Track product interactions including views, impressions, clicks,\n * and product list interactions.\n * \n * @useCases\n * - Track product page views\n * - Measure product list/search impressions\n * - Analyze product click-through rates\n * - Monitor product detail engagement\n * - Compare product performance\n * \n * @metrics\n * - Product views\n * - Product impressions\n * - Click-through rate\n * - View-to-cart rate\n * - Revenue per product\n * \n * @chartData\n * - Bar chart: Top products by views\n * - Line chart: Product views over time\n * - Table: Product performance comparison\n * - Scatter: Price vs conversion rate\n * \n * @example\n * ```typescript\n * const products = new Products(webId, endpoint, apiKey);\n * \n * // Track product view\n * await products.view({\n * productId: 'SKU-123',\n * name: 'Premium Headphones',\n * price: 299.99,\n * currency: 'USD',\n * category: 'Electronics/Audio'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n Product,\n ProductList,\n ProductPerformance,\n TimeSeriesData,\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking a product view.\n */\nexport interface ProductViewConfig extends Product {\n /** User ID (if authenticated) */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n /** How user arrived at product (search, category, recommendation) */\n source?: 'search' | 'category' | 'recommendation' | 'direct' | 'ad';\n /** Search query if from search */\n searchQuery?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Configuration for tracking product impressions.\n */\nexport interface ProductImpressionConfig {\n /** List information */\n list: ProductList;\n /** User ID */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n}\n\n/**\n * Configuration for tracking product clicks.\n */\nexport interface ProductClickConfig {\n /** Product clicked */\n product: Product;\n /** List where product was clicked */\n listId?: string;\n /** Position in list */\n position?: number;\n /** User ID */\n userId?: string;\n}\n\n/**\n * Product event response from API.\n */\nexport interface ProductResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n productId: string;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Product analytics data for charts.\n */\nexport interface ProductAnalyticsData {\n /** Top products by various metrics */\n topProducts: {\n byViews: ProductPerformance[];\n byRevenue: ProductPerformance[];\n byConversion: ProductPerformance[];\n };\n /** Product views time series */\n viewsTimeSeries: TimeSeriesData;\n /** Summary metrics */\n summary: {\n totalProductViews: number;\n uniqueProductsViewed: number;\n avgViewsPerProduct: number;\n topCategory: string;\n topBrand: string;\n };\n /** Performance by category */\n byCategory: Array<{\n category: string;\n views: number;\n revenue: number;\n conversionRate: number;\n }>;\n}\n\n// ============================================================================\n// PRODUCTS CLASS\n// ============================================================================\n\n/**\n * Products - Track product interactions.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides product tracking capabilities including:\n * - Product page views\n * - Product list impressions\n * - Product clicks from lists\n * - Product detail interactions\n * - Quick view tracking\n * \n * @example\n * ```typescript\n * const products = new Products(webId, endpoint, apiKey);\n * \n * // Track product page view\n * await products.view({\n * productId: 'PROD-001',\n * name: 'Wireless Earbuds',\n * price: 79.99,\n * currency: 'USD',\n * category: 'Electronics/Audio',\n * brand: 'AudioTech'\n * });\n * \n * // Track list impressions\n * await products.impression({\n * list: {\n * listId: 'search-results',\n * listName: 'Search Results',\n * products: searchResults\n * }\n * });\n * ```\n */\nexport class Products extends FlowGridTransport {\n /**\n * Tracks a product page view.\n * \n * @param config - Product view configuration\n * @returns Promise resolving to product response\n * \n * @example\n * ```typescript\n * await products.view({\n * productId: 'SKU-12345',\n * name: 'Premium Widget',\n * price: 49.99,\n * currency: 'USD',\n * category: 'Widgets/Premium',\n * brand: 'WidgetCo',\n * source: 'search',\n * searchQuery: 'premium widget'\n * });\n * ```\n */\n async view(config: ProductViewConfig): Promise<ProductResponse> {\n return await this.init(\"product_view\", {\n type: \"ecommerce\",\n subtype: \"product_view\",\n product: {\n productId: config.productId,\n name: config.name,\n brand: config.brand,\n category: config.category,\n variant: config.variant,\n price: config.price,\n currency: config.currency,\n url: config.url,\n imageUrl: config.imageUrl,\n rating: config.rating,\n reviewCount: config.reviewCount,\n stockStatus: config.stockStatus,\n attributes: config.attributes\n },\n source: config.source,\n searchQuery: config.searchQuery,\n userId: config.userId,\n sessionId: config.sessionId,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks product list impressions.\n * \n * @param config - Impression configuration\n * @returns Promise resolving to impression response\n * \n * @example\n * ```typescript\n * // Track products shown in search results\n * await products.impression({\n * list: {\n * listId: 'search-results',\n * listName: 'Search Results',\n * products: products.map((p, i) => ({ ...p, position: i + 1 }))\n * }\n * });\n * ```\n */\n async impression(config: ProductImpressionConfig): Promise<ProductResponse> {\n return await this.init(\"product_impression\", {\n type: \"ecommerce\",\n subtype: \"product_impression\",\n list: config.list,\n productCount: config.list.products.length,\n userId: config.userId,\n sessionId: config.sessionId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a product click from a list.\n * \n * @param config - Click configuration\n * @returns Promise resolving to click response\n * \n * @example\n * ```typescript\n * await products.click({\n * product: selectedProduct,\n * listId: 'homepage-featured',\n * position: 3\n * });\n * ```\n */\n async click(config: ProductClickConfig): Promise<ProductResponse> {\n return await this.init(\"product_click\", {\n type: \"ecommerce\",\n subtype: \"product_click\",\n product: config.product,\n listId: config.listId,\n position: config.position,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a quick view interaction (modal product view).\n * \n * @param product - Product being quick-viewed\n * @param listId - List where quick view was triggered\n * @returns Promise resolving to quick view response\n */\n async quickView(product: Product, listId?: string): Promise<ProductResponse> {\n return await this.init(\"product_quick_view\", {\n type: \"ecommerce\",\n subtype: \"product_quick_view\",\n product,\n listId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks product detail interaction (zoom, read reviews, etc.).\n * \n * @param productId - Product identifier\n * @param action - Interaction type\n * @param properties - Additional properties\n * @returns Promise resolving to interaction response\n */\n async interaction(\n productId: string,\n action: 'zoom' | 'read_reviews' | 'size_guide' | 'compare' | 'share' | 'notify_stock',\n properties?: Record<string, unknown>\n ): Promise<ProductResponse> {\n return await this.init(\"product_interaction\", {\n type: \"ecommerce\",\n subtype: \"product_interaction\",\n productId,\n action,\n ...properties,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Products;\n","/**\n * @fileoverview Ecommerce - Cart Tracking\n * @module features/ecommerce/cart\n * \n * @description\n * Track shopping cart interactions including add/remove items,\n * cart views, and cart abandonment.\n * \n * @useCases\n * - Track add to cart events\n * - Monitor cart modifications\n * - Detect cart abandonment\n * - Analyze popular cart items\n * - Measure cart value trends\n * \n * @metrics\n * - Add to cart rate\n * - Average cart value\n * - Cart abandonment rate\n * - Items per cart\n * - Cart-to-checkout rate\n * \n * @chartData\n * - Line chart: Cart value over time\n * - Bar chart: Top added products\n * - Pie chart: Abandonment reasons\n * - Funnel: Cart to checkout flow\n * \n * @example\n * ```typescript\n * const cart = new CartTracking(webId, endpoint, apiKey);\n * \n * // Track add to cart\n * await cart.addItem({\n * product: { productId: 'SKU-123', name: 'Widget', price: 29.99, currency: 'USD' },\n * quantity: 2,\n * cartId: 'cart_abc'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n Product,\n Cart,\n CartItem,\n CartAnalytics,\n CurrencyCode,\n DateRangeFilter,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for adding item to cart.\n */\nexport interface AddToCartConfig {\n /** Product being added */\n product: Product;\n /** Quantity to add */\n quantity: number;\n /** Cart identifier */\n cartId?: string;\n /** User ID */\n userId?: string;\n /** Source of add (product page, quick add, etc.) */\n source?: 'product_page' | 'quick_add' | 'wishlist' | 'recommendation' | 'reorder';\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Configuration for removing item from cart.\n */\nexport interface RemoveFromCartConfig {\n /** Product being removed */\n product: Product;\n /** Quantity to remove */\n quantity: number;\n /** Cart identifier */\n cartId?: string;\n /** User ID */\n userId?: string;\n /** Reason for removal */\n reason?: 'user_action' | 'out_of_stock' | 'price_change' | 'auto_expired';\n}\n\n/**\n * Configuration for updating cart item.\n */\nexport interface UpdateCartItemConfig {\n /** Product being updated */\n product: Product;\n /** Previous quantity */\n previousQuantity: number;\n /** New quantity */\n newQuantity: number;\n /** Cart identifier */\n cartId?: string;\n}\n\n/**\n * Configuration for cart view.\n */\nexport interface ViewCartConfig {\n /** Current cart state */\n cart: Cart;\n /** User ID */\n userId?: string;\n}\n\n/**\n * Cart event response from API.\n */\nexport interface CartResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n cartId: string;\n tracked: boolean;\n cartValue: number;\n itemCount: number;\n };\n timestamp: string;\n}\n\n/**\n * Cart analytics data for charts.\n */\nexport interface CartAnalyticsData {\n /** Cart metrics summary */\n summary: {\n totalAddToCarts: number;\n totalRemoveFromCarts: number;\n averageCartValue: number;\n averageItemsPerCart: number;\n abandonmentRate: number;\n cartToCheckoutRate: number;\n };\n /** Add to cart trends */\n addToCartTimeSeries: TimeSeriesData;\n /** Top products added to cart */\n topAddedProducts: Array<{\n product: Pick<Product, 'productId' | 'name' | 'category'>;\n addCount: number;\n removeCount: number;\n netAdds: number;\n }>;\n /** Abandonment analysis */\n abandonment: {\n rate: number;\n avgAbandonedValue: number;\n topAbandonedProducts: Array<{\n product: Pick<Product, 'productId' | 'name'>;\n abandonCount: number;\n }>;\n };\n}\n\n// ============================================================================\n// CART TRACKING CLASS\n// ============================================================================\n\n/**\n * CartTracking - Track shopping cart interactions.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides cart tracking capabilities including:\n * - Add to cart events\n * - Remove from cart events\n * - Cart quantity updates\n * - Cart view tracking\n * - Cart abandonment detection\n * \n * @example\n * ```typescript\n * const cart = new CartTracking(webId, endpoint, apiKey);\n * \n * // Track add to cart\n * await cart.addItem({\n * product: {\n * productId: 'PROD-001',\n * name: 'Widget Pro',\n * price: 99.99,\n * currency: 'USD'\n * },\n * quantity: 1,\n * source: 'product_page'\n * });\n * \n * // Track cart view\n * await cart.view({\n * cart: currentCart\n * });\n * ```\n */\nexport class CartTracking extends FlowGridTransport {\n /**\n * Tracks adding an item to cart.\n * \n * @param config - Add to cart configuration\n * @returns Promise resolving to cart response\n * \n * @example\n * ```typescript\n * await cart.addItem({\n * product: {\n * productId: 'SKU-123',\n * name: 'Premium Widget',\n * price: 49.99,\n * currency: 'USD',\n * category: 'Widgets'\n * },\n * quantity: 2,\n * source: 'product_page'\n * });\n * ```\n */\n async addItem(config: AddToCartConfig): Promise<CartResponse> {\n const lineTotal = config.product.price * config.quantity - (config.product.discount || 0);\n \n return await this.init(\"add_to_cart\", {\n type: \"ecommerce\",\n subtype: \"add_to_cart\",\n product: config.product,\n quantity: config.quantity,\n lineTotal,\n cartId: config.cartId,\n userId: config.userId,\n source: config.source,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks removing an item from cart.\n * \n * @param config - Remove from cart configuration\n * @returns Promise resolving to cart response\n * \n * @example\n * ```typescript\n * await cart.removeItem({\n * product: productToRemove,\n * quantity: 1,\n * cartId: 'cart_123',\n * reason: 'user_action'\n * });\n * ```\n */\n async removeItem(config: RemoveFromCartConfig): Promise<CartResponse> {\n return await this.init(\"remove_from_cart\", {\n type: \"ecommerce\",\n subtype: \"remove_from_cart\",\n product: config.product,\n quantity: config.quantity,\n cartId: config.cartId,\n userId: config.userId,\n reason: config.reason || \"user_action\",\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks cart item quantity update.\n * \n * @param config - Update configuration\n * @returns Promise resolving to cart response\n * \n * @example\n * ```typescript\n * await cart.updateItem({\n * product: item.product,\n * previousQuantity: 1,\n * newQuantity: 3,\n * cartId: 'cart_123'\n * });\n * ```\n */\n async updateItem(config: UpdateCartItemConfig): Promise<CartResponse> {\n return await this.init(\"update_cart_item\", {\n type: \"ecommerce\",\n subtype: \"update_cart_item\",\n product: config.product,\n previousQuantity: config.previousQuantity,\n newQuantity: config.newQuantity,\n quantityChange: config.newQuantity - config.previousQuantity,\n cartId: config.cartId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a cart view event.\n * \n * @param config - View cart configuration\n * @returns Promise resolving to cart response\n * \n * @example\n * ```typescript\n * await cart.view({\n * cart: {\n * cartId: 'cart_123',\n * items: cartItems,\n * subtotal: 149.97,\n * total: 164.97,\n * currency: 'USD',\n * itemCount: 3\n * }\n * });\n * ```\n */\n async view(config: ViewCartConfig): Promise<CartResponse> {\n return await this.init(\"view_cart\", {\n type: \"ecommerce\",\n subtype: \"view_cart\",\n cart: config.cart,\n cartValue: config.cart.total,\n itemCount: config.cart.itemCount,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks cart abandonment.\n * \n * @param cart - Abandoned cart state\n * @param reason - Abandonment reason (if known)\n * @returns Promise resolving to cart response\n */\n async abandon(\n cart: Cart,\n reason?: 'exit' | 'timeout' | 'price_too_high' | 'shipping_cost' | 'other'\n ): Promise<CartResponse> {\n return await this.init(\"cart_abandoned\", {\n type: \"ecommerce\",\n subtype: \"cart_abandoned\",\n cart,\n cartValue: cart.total,\n itemCount: cart.itemCount,\n reason,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Applies a coupon to the cart.\n * \n * @param cartId - Cart identifier\n * @param couponCode - Coupon code applied\n * @param success - Whether coupon was valid\n * @param discount - Discount amount (if successful)\n * @returns Promise resolving to cart response\n */\n async applyCoupon(\n cartId: string,\n couponCode: string,\n success: boolean,\n discount?: number\n ): Promise<CartResponse> {\n return await this.init(\"apply_coupon\", {\n type: \"ecommerce\",\n subtype: \"apply_coupon\",\n cartId,\n couponCode,\n success,\n discount,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default CartTracking;\n","/**\n * @fileoverview Ecommerce - Checkout Tracking\n * @module features/ecommerce/checkout\n * \n * @description\n * Track checkout flow progress, payment attempts, and checkout\n * optimization opportunities.\n * \n * @useCases\n * - Track checkout step progression\n * - Identify checkout drop-off points\n * - Monitor payment success rates\n * - Analyze shipping method preferences\n * - Optimize checkout UX\n * \n * @metrics\n * - Checkout initiation rate\n * - Step completion rates\n * - Payment success rate\n * - Checkout abandonment rate\n * - Average time to complete\n * \n * @chartData\n * - Funnel chart: Checkout steps\n * - Bar chart: Abandonment by step\n * - Pie chart: Payment methods\n * - Line chart: Checkout completions over time\n * \n * @example\n * ```typescript\n * const checkout = new Checkout(webId, endpoint, apiKey);\n * \n * // Begin checkout\n * await checkout.begin({\n * cart: shoppingCart,\n * userId: 'user_123'\n * });\n * \n * // Track step progress\n * await checkout.step({\n * step: 'add_payment_info',\n * stepNumber: 3,\n * cart: shoppingCart\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n Cart,\n CheckoutStep,\n ShippingInfo,\n PaymentInfo,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for beginning checkout.\n */\nexport interface BeginCheckoutConfig {\n /** Cart being checked out */\n cart: Cart;\n /** User ID */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Configuration for tracking checkout step.\n */\nexport interface CheckoutStepConfig {\n /** Checkout step */\n step: CheckoutStep;\n /** Step number */\n stepNumber: number;\n /** Cart state at this step */\n cart: Cart;\n /** Option selected at this step (e.g., shipping method) */\n option?: string;\n /** User ID */\n userId?: string;\n}\n\n/**\n * Configuration for adding shipping info.\n */\nexport interface AddShippingConfig {\n /** Cart being checked out */\n cart: Cart;\n /** Shipping information */\n shipping: ShippingInfo;\n /** User ID */\n userId?: string;\n}\n\n/**\n * Configuration for adding payment info.\n */\nexport interface AddPaymentConfig {\n /** Cart being checked out */\n cart: Cart;\n /** Payment information (non-sensitive) */\n payment: PaymentInfo;\n /** User ID */\n userId?: string;\n}\n\n/**\n * Checkout event response from API.\n */\nexport interface CheckoutResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n checkoutId: string;\n step: string;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Checkout analytics data for charts.\n */\nexport interface CheckoutAnalyticsData {\n /** Checkout funnel data */\n funnel: Array<{\n step: CheckoutStep;\n stepNumber: number;\n started: number;\n completed: number;\n conversionRate: number;\n dropOffRate: number;\n avgTimeToComplete: number;\n }>;\n /** Summary metrics */\n summary: {\n checkoutsStarted: number;\n checkoutsCompleted: number;\n overallConversionRate: number;\n avgCheckoutTime: number;\n avgOrderValue: number;\n abandonmentRate: number;\n };\n /** Checkouts over time */\n timeSeries: TimeSeriesData;\n /** Shipping methods used */\n shippingMethods: Array<{\n method: string;\n count: number;\n percentage: number;\n avgShippingCost: number;\n }>;\n /** Payment methods used */\n paymentMethods: Array<{\n method: string;\n count: number;\n percentage: number;\n successRate: number;\n }>;\n /** Abandonment analysis */\n abandonmentByStep: Array<{\n step: CheckoutStep;\n abandonments: number;\n percentage: number;\n avgCartValue: number;\n }>;\n}\n\n// ============================================================================\n// CHECKOUT CLASS\n// ============================================================================\n\n/**\n * Checkout - Track checkout flow and payments.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides checkout tracking capabilities including:\n * - Checkout initiation\n * - Step-by-step progress\n * - Shipping info capture\n * - Payment info capture\n * - Checkout abandonment\n * \n * @example\n * ```typescript\n * const checkout = new Checkout(webId, endpoint, apiKey);\n * \n * // Start checkout\n * await checkout.begin({ cart: shoppingCart });\n * \n * // Track shipping step\n * await checkout.addShipping({\n * cart: shoppingCart,\n * shipping: {\n * method: 'express',\n * carrier: 'FedEx',\n * cost: 9.99\n * }\n * });\n * \n * // Track payment step\n * await checkout.addPayment({\n * cart: shoppingCart,\n * payment: {\n * method: 'credit_card',\n * cardBrand: 'Visa'\n * }\n * });\n * ```\n */\nexport class Checkout extends FlowGridTransport {\n /**\n * Tracks checkout initiation.\n * \n * @param config - Begin checkout configuration\n * @returns Promise resolving to checkout response\n * \n * @example\n * ```typescript\n * await checkout.begin({\n * cart: {\n * cartId: 'cart_123',\n * items: cartItems,\n * total: 199.99,\n * currency: 'USD',\n * itemCount: 3\n * }\n * });\n * ```\n */\n async begin(config: BeginCheckoutConfig): Promise<CheckoutResponse> {\n return await this.init(\"begin_checkout\", {\n type: \"ecommerce\",\n subtype: \"begin_checkout\",\n cart: config.cart,\n cartValue: config.cart.total,\n itemCount: config.cart.itemCount,\n userId: config.userId,\n sessionId: config.sessionId,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks checkout step progress.\n * \n * @param config - Checkout step configuration\n * @returns Promise resolving to checkout response\n * \n * @example\n * ```typescript\n * await checkout.step({\n * step: 'add_shipping_info',\n * stepNumber: 2,\n * cart: shoppingCart,\n * option: 'express_shipping'\n * });\n * ```\n */\n async step(config: CheckoutStepConfig): Promise<CheckoutResponse> {\n return await this.init(\"checkout_step\", {\n type: \"ecommerce\",\n subtype: \"checkout_step\",\n step: config.step,\n stepNumber: config.stepNumber,\n cart: config.cart,\n option: config.option,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks adding shipping information.\n * \n * @param config - Shipping info configuration\n * @returns Promise resolving to checkout response\n * \n * @example\n * ```typescript\n * await checkout.addShipping({\n * cart: shoppingCart,\n * shipping: {\n * method: 'standard',\n * carrier: 'USPS',\n * cost: 5.99,\n * estimatedDelivery: '2026-02-07'\n * }\n * });\n * ```\n */\n async addShipping(config: AddShippingConfig): Promise<CheckoutResponse> {\n return await this.init(\"add_shipping_info\", {\n type: \"ecommerce\",\n subtype: \"shipping_info\",\n cart: config.cart,\n shipping: config.shipping,\n shippingMethod: config.shipping.method,\n shippingCost: config.shipping.cost,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks adding payment information.\n * \n * @param config - Payment info configuration\n * @returns Promise resolving to checkout response\n * \n * @example\n * ```typescript\n * await checkout.addPayment({\n * cart: shoppingCart,\n * payment: {\n * method: 'credit_card',\n * provider: 'stripe',\n * cardBrand: 'Mastercard',\n * cardLast4: '4242'\n * }\n * });\n * ```\n */\n async addPayment(config: AddPaymentConfig): Promise<CheckoutResponse> {\n return await this.init(\"add_payment_info\", {\n type: \"ecommerce\",\n subtype: \"payment_info\",\n cart: config.cart,\n payment: config.payment,\n paymentMethod: config.payment.method,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks checkout abandonment.\n * \n * @param cart - Cart at abandonment\n * @param step - Last completed step\n * @param reason - Abandonment reason (if known)\n * @returns Promise resolving to checkout response\n */\n async abandon(\n cart: Cart,\n step: CheckoutStep,\n reason?: string\n ): Promise<CheckoutResponse> {\n return await this.init(\"checkout_abandoned\", {\n type: \"ecommerce\",\n subtype: \"checkout_abandoned\",\n cart,\n step,\n cartValue: cart.total,\n reason,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks payment attempt (success or failure).\n * \n * @param success - Whether payment succeeded\n * @param cart - Cart being paid for\n * @param payment - Payment information\n * @param errorCode - Error code (if failed)\n * @returns Promise resolving to checkout response\n */\n async paymentAttempt(\n success: boolean,\n cart: Cart,\n payment: PaymentInfo,\n errorCode?: string\n ): Promise<CheckoutResponse> {\n return await this.init(\"payment_attempt\", {\n type: \"ecommerce\",\n subtype: \"payment_attempt\",\n success,\n cart,\n payment,\n errorCode,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Checkout;\n","/**\n * @fileoverview Ecommerce - Purchase/Transaction Tracking\n * @module features/ecommerce/purchases\n * \n * @description\n * Track completed purchases, transactions, and revenue with\n * full order details and customer information.\n * \n * @useCases\n * - Track completed purchases\n * - Calculate revenue metrics\n * - Monitor order values\n * - Analyze purchase patterns\n * - Track customer lifetime value\n * \n * @metrics\n * - Total revenue\n * - Number of orders\n * - Average order value\n * - Revenue per customer\n * - Items per order\n * \n * @chartData\n * - Line chart: Revenue over time\n * - Bar chart: Revenue by product/category\n * - KPI cards: Revenue, AOV, Orders\n * - Table: Recent transactions\n * \n * @example\n * ```typescript\n * const purchases = new Purchases(webId, endpoint, apiKey);\n * \n * // Track a purchase\n * await purchases.track({\n * order: {\n * orderId: 'ORD-12345',\n * items: orderItems,\n * total: 299.99,\n * currency: 'USD'\n * }\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n Order,\n CartItem,\n ShippingInfo,\n PaymentInfo,\n RevenueMetrics,\n MoneyValue,\n CurrencyCode,\n DateRangeFilter,\n TimeSeriesData,\n PaginationParams\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking a purchase.\n */\nexport interface PurchaseConfig {\n /** Order details */\n order: Order;\n /** User ID */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n /** Attribution data */\n attribution?: {\n source?: string;\n medium?: string;\n campaign?: string;\n affiliate?: string;\n };\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Purchase event response from API.\n */\nexport interface PurchaseResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n orderId: string;\n tracked: boolean;\n revenue: number;\n isFirstPurchase: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Revenue analytics data for charts.\n */\nexport interface RevenueAnalyticsData {\n /** Revenue summary */\n summary: {\n totalRevenue: MoneyValue;\n netRevenue: MoneyValue;\n totalOrders: number;\n averageOrderValue: MoneyValue;\n itemsSold: number;\n uniqueCustomers: number;\n repeatPurchaseRate: number;\n };\n /** Revenue time series */\n revenueTimeSeries: TimeSeriesData;\n /** Orders time series */\n ordersTimeSeries: TimeSeriesData;\n /** Revenue by category */\n byCategory: Array<{\n category: string;\n revenue: number;\n orders: number;\n percentage: number;\n }>;\n /** Revenue by product */\n byProduct: Array<{\n productId: string;\n productName: string;\n revenue: number;\n unitsSold: number;\n }>;\n /** Revenue by geography */\n byCountry: Array<{\n country: string;\n revenue: number;\n orders: number;\n }>;\n /** Customer segments */\n customerSegments: Array<{\n segment: 'new' | 'returning' | 'vip';\n customers: number;\n revenue: number;\n avgOrderValue: number;\n }>;\n}\n\n/**\n * Recent orders data.\n */\nexport interface RecentOrdersData {\n orders: Array<{\n orderId: string;\n total: MoneyValue;\n itemCount: number;\n status: string;\n createdAt: string;\n customer?: {\n userId: string;\n isNew: boolean;\n };\n }>;\n pagination: {\n page: number;\n limit: number;\n total: number;\n hasMore: boolean;\n };\n}\n\n// ============================================================================\n// PURCHASES CLASS\n// ============================================================================\n\n/**\n * Purchases - Track completed purchases and revenue.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides purchase tracking capabilities including:\n * - Purchase completion events\n * - Revenue tracking\n * - Order details capture\n * - Customer LTV tracking\n * - Attribution tracking\n * \n * @example\n * ```typescript\n * const purchases = new Purchases(webId, endpoint, apiKey);\n * \n * // Track completed purchase\n * await purchases.track({\n * order: {\n * orderId: 'ORD-12345',\n * items: cartItems,\n * subtotal: 279.99,\n * discountTotal: 30.00,\n * shippingTotal: 9.99,\n * taxTotal: 26.00,\n * total: 285.98,\n * currency: 'USD',\n * shipping: { method: 'express', cost: 9.99 },\n * payment: { method: 'credit_card' }\n * },\n * userId: 'user_123'\n * });\n * ```\n */\nexport class Purchases extends FlowGridTransport {\n /**\n * Tracks a completed purchase.\n * \n * @param config - Purchase configuration\n * @returns Promise resolving to purchase response\n * \n * @example\n * ```typescript\n * await purchases.track({\n * order: {\n * orderId: 'ORD-98765',\n * items: [\n * { productId: 'PROD-1', name: 'Widget', price: 29.99, quantity: 2, lineTotal: 59.98 }\n * ],\n * subtotal: 59.98,\n * discountTotal: 0,\n * shippingTotal: 5.99,\n * taxTotal: 5.40,\n * total: 71.37,\n * currency: 'USD'\n * },\n * attribution: {\n * source: 'google',\n * medium: 'cpc',\n * campaign: 'spring_sale'\n * }\n * });\n * ```\n */\n async track(config: PurchaseConfig): Promise<PurchaseResponse> {\n const order = config.order;\n \n return await this.init(\"purchase\", {\n type: \"ecommerce\",\n subtype: \"purchase\",\n order: {\n orderId: order.orderId,\n items: order.items,\n subtotal: order.subtotal,\n discountTotal: order.discountTotal,\n shippingTotal: order.shippingTotal,\n taxTotal: order.taxTotal,\n total: order.total,\n currency: order.currency,\n shipping: order.shipping,\n payment: order.payment,\n coupons: order.coupons,\n affiliation: order.affiliation\n },\n revenue: order.total,\n itemCount: order.items.reduce((sum, i) => sum + i.quantity, 0),\n userId: config.userId,\n sessionId: config.sessionId,\n attribution: config.attribution,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks order status change.\n * \n * @param orderId - Order identifier\n * @param newStatus - New order status\n * @param previousStatus - Previous status (optional)\n * @returns Promise resolving to status change response\n */\n async statusChange(\n orderId: string,\n newStatus: Order['status'],\n previousStatus?: Order['status']\n ): Promise<PurchaseResponse> {\n return await this.init(\"order_status_change\", {\n type: \"ecommerce\",\n subtype: \"order_status_change\",\n orderId,\n newStatus,\n previousStatus,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks order shipped event.\n * \n * @param orderId - Order identifier\n * @param shipping - Shipping details with tracking\n * @returns Promise resolving to shipped response\n */\n async shipped(orderId: string, shipping: ShippingInfo): Promise<PurchaseResponse> {\n return await this.init(\"order_shipped\", {\n type: \"ecommerce\",\n subtype: \"order_shipped\",\n orderId,\n shipping,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks order delivered event.\n * \n * @param orderId - Order identifier\n * @param deliveredAt - Delivery timestamp\n * @returns Promise resolving to delivered response\n */\n async delivered(orderId: string, deliveredAt?: string): Promise<PurchaseResponse> {\n return await this.init(\"order_delivered\", {\n type: \"ecommerce\",\n subtype: \"order_delivered\",\n orderId,\n deliveredAt: deliveredAt || new Date().toISOString(),\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Purchases;\n","/**\n * @fileoverview Ecommerce - Refund Tracking\n * @module features/ecommerce/refunds\n * \n * @description\n * Track refunds, returns, and order cancellations with\n * reason analysis and revenue impact.\n * \n * @useCases\n * - Track full and partial refunds\n * - Analyze refund reasons\n * - Monitor return rates by product\n * - Calculate net revenue after refunds\n * - Identify problematic products\n * \n * @metrics\n * - Total refunds\n * - Refund rate\n * - Average refund value\n * - Refunds by reason\n * - Net revenue impact\n * \n * @chartData\n * - Bar chart: Refunds by reason\n * - Line chart: Refund trends\n * - Table: Products with highest return rates\n * - KPI: Refund rate vs benchmark\n * \n * @example\n * ```typescript\n * const refunds = new Refunds(webId, endpoint, apiKey);\n * \n * // Track a refund\n * await refunds.track({\n * orderId: 'ORD-12345',\n * refundId: 'REF-001',\n * amount: 49.99,\n * currency: 'USD',\n * reason: 'defective',\n * isFullRefund: false\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n Refund,\n CartItem,\n MoneyValue,\n CurrencyCode,\n DateRangeFilter,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking a refund.\n */\nexport interface RefundConfig extends Refund {\n /** User ID */\n userId?: string;\n /** Initiated by (customer or admin) */\n initiatedBy?: 'customer' | 'admin' | 'system';\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Refund event response from API.\n */\nexport interface RefundResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n refundId: string;\n orderId: string;\n tracked: boolean;\n refundedAmount: number;\n };\n timestamp: string;\n}\n\n/**\n * Refund analytics data for charts.\n */\nexport interface RefundAnalyticsData {\n /** Summary metrics */\n summary: {\n totalRefunds: number;\n totalRefundValue: MoneyValue;\n refundRate: number;\n averageRefundValue: MoneyValue;\n fullRefundCount: number;\n partialRefundCount: number;\n };\n /** Refunds time series */\n timeSeries: TimeSeriesData;\n /** Refunds by reason */\n byReason: Array<{\n reason: string;\n count: number;\n totalValue: number;\n percentage: number;\n }>;\n /** Products with highest refund rates */\n topRefundedProducts: Array<{\n productId: string;\n productName: string;\n refundCount: number;\n refundValue: number;\n refundRate: number;\n }>;\n /** Revenue impact */\n revenueImpact: {\n grossRevenue: MoneyValue;\n refundedAmount: MoneyValue;\n netRevenue: MoneyValue;\n refundImpactPercent: number;\n };\n}\n\n// ============================================================================\n// REFUNDS CLASS\n// ============================================================================\n\n/**\n * Refunds - Track refunds and returns.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides refund tracking capabilities including:\n * - Full refund tracking\n * - Partial refund tracking\n * - Refund reason analysis\n * - Return rate monitoring\n * - Revenue impact calculation\n * \n * @example\n * ```typescript\n * const refunds = new Refunds(webId, endpoint, apiKey);\n * \n * // Track full refund\n * await refunds.track({\n * orderId: 'ORD-12345',\n * refundId: 'REF-001',\n * amount: 149.99,\n * currency: 'USD',\n * reason: 'customer_request',\n * isFullRefund: true\n * });\n * \n * // Track partial refund with items\n * await refunds.track({\n * orderId: 'ORD-12345',\n * refundId: 'REF-002',\n * items: [refundedItem],\n * amount: 49.99,\n * currency: 'USD',\n * reason: 'defective',\n * isFullRefund: false\n * });\n * ```\n */\nexport class Refunds extends FlowGridTransport {\n /**\n * Tracks a refund event.\n * \n * @param config - Refund configuration\n * @returns Promise resolving to refund response\n * \n * @example\n * ```typescript\n * await refunds.track({\n * orderId: 'ORD-98765',\n * refundId: 'REF-123',\n * items: [\n * { productId: 'PROD-1', name: 'Widget', price: 29.99, quantity: 1, lineTotal: 29.99 }\n * ],\n * amount: 29.99,\n * currency: 'USD',\n * reason: 'wrong_item',\n * isFullRefund: false,\n * initiatedBy: 'customer'\n * });\n * ```\n */\n async track(config: RefundConfig): Promise<RefundResponse> {\n return await this.init(\"refund\", {\n type: \"ecommerce\",\n subtype: \"refund\",\n orderId: config.orderId,\n refundId: config.refundId,\n items: config.items,\n amount: config.amount,\n currency: config.currency,\n reason: config.reason,\n isFullRefund: config.isFullRefund,\n userId: config.userId,\n initiatedBy: config.initiatedBy,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a refund request (before processing).\n * \n * @param orderId - Original order ID\n * @param items - Items requested for refund\n * @param reason - Refund reason\n * @returns Promise resolving to request response\n */\n async request(\n orderId: string,\n items?: CartItem[],\n reason?: string\n ): Promise<RefundResponse> {\n return await this.init(\"refund_requested\", {\n type: \"ecommerce\",\n subtype: \"refund_requested\",\n orderId,\n items,\n reason,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks refund approval.\n * \n * @param refundId - Refund identifier\n * @param approvedAmount - Approved refund amount\n * @returns Promise resolving to approval response\n */\n async approve(refundId: string, approvedAmount: number): Promise<RefundResponse> {\n return await this.init(\"refund_approved\", {\n type: \"ecommerce\",\n subtype: \"refund_approved\",\n refundId,\n approvedAmount,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks refund denial.\n * \n * @param refundId - Refund identifier\n * @param denialReason - Reason for denial\n * @returns Promise resolving to denial response\n */\n async deny(refundId: string, denialReason: string): Promise<RefundResponse> {\n return await this.init(\"refund_denied\", {\n type: \"ecommerce\",\n subtype: \"refund_denied\",\n refundId,\n denialReason,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks refund completion (money returned).\n * \n * @param refundId - Refund identifier\n * @param processedAmount - Amount actually refunded\n * @returns Promise resolving to completion response\n */\n async complete(refundId: string, processedAmount: number): Promise<RefundResponse> {\n return await this.init(\"refund_completed\", {\n type: \"ecommerce\",\n subtype: \"refund_completed\",\n refundId,\n processedAmount,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Refunds;\n","/**\n * @fileoverview Ecommerce - Promotion Tracking\n * @module features/ecommerce/promotions\n * \n * @description\n * Track promotional content, coupon usage, and discount\n * effectiveness across your ecommerce store.\n * \n * @useCases\n * - Track promotional banner views\n * - Measure promotion click-through rates\n * - Analyze coupon usage and effectiveness\n * - Monitor discount impact on revenue\n * - Compare promotion performance\n * \n * @metrics\n * - Promotion impressions\n * - Promotion CTR\n * - Coupon redemption rate\n * - Revenue attributed to promotions\n * - Discount impact on margins\n * \n * @chartData\n * - Bar chart: Top promotions by revenue\n * - Line chart: Coupon usage over time\n * - Table: Promotion performance comparison\n * - Pie chart: Revenue by promotion type\n * \n * @example\n * ```typescript\n * const promotions = new Promotions(webId, endpoint, apiKey);\n * \n * // Track promotion view\n * await promotions.view({\n * promotionId: 'PROMO-SUMMER',\n * name: 'Summer Sale 20% Off',\n * creative: 'homepage-banner'\n * });\n * \n * // Track coupon usage\n * await promotions.couponUsed({\n * code: 'SAVE20',\n * discountValue: 20,\n * orderId: 'ORD-123'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n Promotion,\n MoneyValue,\n DateRangeFilter,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking promotion view.\n */\nexport interface PromotionViewConfig extends Promotion {\n /** User ID */\n userId?: string;\n /** Page where promotion was shown */\n page?: string;\n}\n\n/**\n * Configuration for tracking promotion click.\n */\nexport interface PromotionClickConfig extends Promotion {\n /** User ID */\n userId?: string;\n /** Destination URL */\n destinationUrl?: string;\n}\n\n/**\n * Configuration for tracking coupon usage.\n */\nexport interface CouponUsageConfig {\n /** Coupon code */\n code: string;\n /** Order ID where coupon was applied */\n orderId: string;\n /** Discount amount */\n discountValue: number;\n /** Discount type */\n discountType: 'percentage' | 'fixed';\n /** Order value before discount */\n orderValueBefore: number;\n /** Order value after discount */\n orderValueAfter: number;\n /** User ID */\n userId?: string;\n}\n\n/**\n * Promotion event response from API.\n */\nexport interface PromotionResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n promotionId: string;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Promotion analytics data for charts.\n */\nexport interface PromotionAnalyticsData {\n /** Summary metrics */\n summary: {\n totalPromotionViews: number;\n totalPromotionClicks: number;\n overallCTR: number;\n totalCouponsUsed: number;\n totalDiscountGiven: MoneyValue;\n revenueFromPromotions: MoneyValue;\n };\n /** Top performing promotions */\n topPromotions: Array<{\n promotionId: string;\n name: string;\n views: number;\n clicks: number;\n ctr: number;\n conversions: number;\n revenue: number;\n }>;\n /** Coupon performance */\n coupons: Array<{\n code: string;\n usageCount: number;\n totalDiscount: number;\n avgOrderValue: number;\n conversionLift: number;\n }>;\n /** Promotions over time */\n timeSeries: TimeSeriesData;\n /** Revenue impact */\n revenueImpact: {\n promotedRevenue: MoneyValue;\n nonPromotedRevenue: MoneyValue;\n promotionRevenueShare: number;\n avgDiscountPercent: number;\n };\n}\n\n// ============================================================================\n// PROMOTIONS CLASS\n// ============================================================================\n\n/**\n * Promotions - Track promotions and coupons.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides promotion tracking capabilities including:\n * - Promotion/banner impressions\n * - Promotion clicks\n * - Coupon applications\n * - Coupon success/failure\n * - Revenue attribution\n * \n * @example\n * ```typescript\n * const promotions = new Promotions(webId, endpoint, apiKey);\n * \n * // Track banner impression\n * await promotions.view({\n * promotionId: 'FLASH-SALE',\n * name: 'Flash Sale - 30% Off',\n * creative: 'hero-banner',\n * position: 'homepage-top'\n * });\n * \n * // Track banner click\n * await promotions.click({\n * promotionId: 'FLASH-SALE',\n * name: 'Flash Sale - 30% Off',\n * destinationUrl: '/sale'\n * });\n * ```\n */\nexport class Promotions extends FlowGridTransport {\n /**\n * Tracks promotion view/impression.\n * \n * @param config - Promotion view configuration\n * @returns Promise resolving to promotion response\n * \n * @example\n * ```typescript\n * await promotions.view({\n * promotionId: 'SUMMER-2026',\n * name: 'Summer Collection Launch',\n * creative: 'collection-banner',\n * position: 'homepage-hero',\n * page: '/home'\n * });\n * ```\n */\n async view(config: PromotionViewConfig): Promise<PromotionResponse> {\n return await this.init(\"promotion_view\", {\n type: \"ecommerce\",\n subtype: \"promotion_view\",\n promotionId: config.promotionId,\n name: config.name,\n creative: config.creative,\n position: config.position,\n page: config.page,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks promotion click.\n * \n * @param config - Promotion click configuration\n * @returns Promise resolving to promotion response\n * \n * @example\n * ```typescript\n * await promotions.click({\n * promotionId: 'SUMMER-2026',\n * name: 'Summer Collection Launch',\n * destinationUrl: '/collections/summer-2026'\n * });\n * ```\n */\n async click(config: PromotionClickConfig): Promise<PromotionResponse> {\n return await this.init(\"promotion_click\", {\n type: \"ecommerce\",\n subtype: \"promotion_click\",\n promotionId: config.promotionId,\n name: config.name,\n creative: config.creative,\n position: config.position,\n destinationUrl: config.destinationUrl,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks successful coupon usage.\n * \n * @param config - Coupon usage configuration\n * @returns Promise resolving to coupon response\n * \n * @example\n * ```typescript\n * await promotions.couponUsed({\n * code: 'SAVE20',\n * orderId: 'ORD-12345',\n * discountValue: 20,\n * discountType: 'percentage',\n * orderValueBefore: 100,\n * orderValueAfter: 80\n * });\n * ```\n */\n async couponUsed(config: CouponUsageConfig): Promise<PromotionResponse> {\n return await this.init(\"coupon_used\", {\n type: \"ecommerce\",\n subtype: \"coupon_used\",\n code: config.code,\n orderId: config.orderId,\n discountValue: config.discountValue,\n discountType: config.discountType,\n orderValueBefore: config.orderValueBefore,\n orderValueAfter: config.orderValueAfter,\n savings: config.orderValueBefore - config.orderValueAfter,\n userId: config.userId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks coupon application attempt (including failures).\n * \n * @param code - Coupon code attempted\n * @param success - Whether coupon was valid\n * @param failureReason - Reason for failure (if failed)\n * @returns Promise resolving to attempt response\n */\n async couponAttempt(\n code: string,\n success: boolean,\n failureReason?: 'expired' | 'invalid' | 'minimum_not_met' | 'already_used' | 'not_applicable'\n ): Promise<PromotionResponse> {\n return await this.init(\"coupon_attempt\", {\n type: \"ecommerce\",\n subtype: \"coupon_attempt\",\n code,\n success,\n failureReason,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Promotions;\n","/**\n * @fileoverview Ecommerce - Wishlist Tracking\n * @module features/ecommerce/wishlist\n * \n * @description\n * Track wishlist interactions to understand purchase intent\n * and drive conversions from saved items.\n * \n * @useCases\n * - Track wishlist additions\n * - Monitor wishlist to cart conversions\n * - Identify popular wishlist items\n * - Trigger price drop notifications\n * - Analyze wishlist behavior patterns\n * \n * @metrics\n * - Wishlist additions\n * - Wishlist to cart rate\n * - Wishlist to purchase rate\n * - Average items per wishlist\n * - Top wishlisted products\n * \n * @chartData\n * - Bar chart: Top wishlisted products\n * - Line chart: Wishlist activity over time\n * - Funnel: Wishlist to purchase conversion\n * - Table: Wishlist conversion rates by product\n * \n * @example\n * ```typescript\n * const wishlist = new WishlistTracking(webId, endpoint, apiKey);\n * \n * // Add to wishlist\n * await wishlist.add({\n * product: { productId: 'PROD-123', name: 'Widget', price: 49.99, currency: 'USD' },\n * wishlistId: 'wl_user123'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n Product,\n Wishlist,\n WishlistItem,\n DateRangeFilter,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for adding to wishlist.\n */\nexport interface AddToWishlistConfig {\n /** Product being added */\n product: Product;\n /** Wishlist ID */\n wishlistId?: string;\n /** User ID */\n userId?: string;\n /** Source of add */\n source?: 'product_page' | 'quick_add' | 'list_view' | 'search';\n}\n\n/**\n * Configuration for removing from wishlist.\n */\nexport interface RemoveFromWishlistConfig {\n /** Product being removed */\n product: Product;\n /** Wishlist ID */\n wishlistId?: string;\n /** User ID */\n userId?: string;\n /** Reason for removal */\n reason?: 'user_action' | 'purchased' | 'moved_to_cart' | 'out_of_stock';\n}\n\n/**\n * Wishlist event response from API.\n */\nexport interface WishlistResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n wishlistId: string;\n productId: string;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Wishlist analytics data for charts.\n */\nexport interface WishlistAnalyticsData {\n /** Summary metrics */\n summary: {\n totalWishlistAdds: number;\n totalWishlistRemoves: number;\n activeWishlists: number;\n avgItemsPerWishlist: number;\n wishlistToCartRate: number;\n wishlistToPurchaseRate: number;\n };\n /** Top wishlisted products */\n topProducts: Array<{\n product: Pick<Product, 'productId' | 'name' | 'category' | 'price'>;\n wishlistCount: number;\n conversionToCart: number;\n conversionToPurchase: number;\n }>;\n /** Wishlist activity time series */\n timeSeries: TimeSeriesData;\n /** Conversion funnel */\n conversionFunnel: {\n wishlisted: number;\n addedToCart: number;\n purchased: number;\n wishlistToCartRate: number;\n cartToPurchaseRate: number;\n };\n}\n\n// ============================================================================\n// WISHLIST TRACKING CLASS\n// ============================================================================\n\n/**\n * WishlistTracking - Track wishlist interactions.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides wishlist tracking capabilities including:\n * - Add to wishlist events\n * - Remove from wishlist events\n * - Wishlist views\n * - Move to cart tracking\n * - Wishlist sharing\n * \n * @example\n * ```typescript\n * const wishlist = new WishlistTracking(webId, endpoint, apiKey);\n * \n * // Add product to wishlist\n * await wishlist.add({\n * product: {\n * productId: 'PROD-001',\n * name: 'Designer Bag',\n * price: 299.99,\n * currency: 'USD'\n * },\n * source: 'product_page'\n * });\n * \n * // Track wishlist view\n * await wishlist.view({\n * wishlistId: 'wl_user123',\n * items: wishlistItems\n * });\n * ```\n */\nexport class WishlistTracking extends FlowGridTransport {\n /**\n * Tracks adding product to wishlist.\n * \n * @param config - Add to wishlist configuration\n * @returns Promise resolving to wishlist response\n * \n * @example\n * ```typescript\n * await wishlist.add({\n * product: {\n * productId: 'SKU-789',\n * name: 'Premium Sneakers',\n * price: 159.99,\n * currency: 'USD',\n * category: 'Footwear'\n * },\n * source: 'product_page'\n * });\n * ```\n */\n async add(config: AddToWishlistConfig): Promise<WishlistResponse> {\n return await this.init(\"add_to_wishlist\", {\n type: \"ecommerce\",\n subtype: \"add_to_wishlist\",\n product: config.product,\n wishlistId: config.wishlistId,\n userId: config.userId,\n source: config.source,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks removing product from wishlist.\n * \n * @param config - Remove from wishlist configuration\n * @returns Promise resolving to wishlist response\n * \n * @example\n * ```typescript\n * await wishlist.remove({\n * product: productToRemove,\n * wishlistId: 'wl_user123',\n * reason: 'moved_to_cart'\n * });\n * ```\n */\n async remove(config: RemoveFromWishlistConfig): Promise<WishlistResponse> {\n return await this.init(\"remove_from_wishlist\", {\n type: \"ecommerce\",\n subtype: \"remove_from_wishlist\",\n product: config.product,\n wishlistId: config.wishlistId,\n userId: config.userId,\n reason: config.reason || \"user_action\",\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks wishlist view.\n * \n * @param wishlist - Wishlist being viewed\n * @returns Promise resolving to wishlist response\n */\n async view(wishlist: Wishlist): Promise<WishlistResponse> {\n return await this.init(\"view_wishlist\", {\n type: \"ecommerce\",\n subtype: \"view_wishlist\",\n wishlistId: wishlist.wishlistId,\n itemCount: wishlist.items.length,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks moving item from wishlist to cart.\n * \n * @param product - Product being moved\n * @param wishlistId - Source wishlist\n * @returns Promise resolving to wishlist response\n */\n async moveToCart(product: Product, wishlistId?: string): Promise<WishlistResponse> {\n return await this.init(\"wishlist_to_cart\", {\n type: \"ecommerce\",\n subtype: \"wishlist_to_cart\",\n product,\n wishlistId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks wishlist sharing.\n * \n * @param wishlistId - Wishlist being shared\n * @param method - Share method\n * @returns Promise resolving to wishlist response\n */\n async share(\n wishlistId: string,\n method: 'email' | 'link' | 'social'\n ): Promise<WishlistResponse> {\n return await this.init(\"share_wishlist\", {\n type: \"ecommerce\",\n subtype: \"share_wishlist\",\n wishlistId,\n method,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default WishlistTracking;\n","/**\n * @fileoverview Ecommerce - Customer Lifetime Value (LTV)\n * @module features/ecommerce/ltv\n * \n * @description\n * Calculate and track customer lifetime value to understand\n * customer worth and optimize acquisition costs.\n * \n * @useCases\n * - Calculate customer LTV\n * - Segment customers by value\n * - Track LTV trends over time\n * - Identify high-value customers\n * - Optimize acquisition spend (LTV:CAC)\n * \n * @metrics\n * - Average LTV\n * - LTV by cohort\n * - LTV by segment\n * - LTV:CAC ratio\n * - Customer value distribution\n * \n * @chartData\n * - Line chart: LTV by cohort over time\n * - Bar chart: LTV by segment\n * - Histogram: Customer value distribution\n * - KPI: Average LTV, LTV:CAC\n * \n * @example\n * ```typescript\n * const ltv = new CustomerLTV(webId, endpoint, apiKey);\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { \n MoneyValue,\n CurrencyCode,\n DateRangeFilter,\n TimeSeriesData\n} from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Customer value data.\n */\nexport interface CustomerValueData {\n /** Customer/user ID */\n userId: string;\n /** Total revenue from customer */\n totalRevenue: MoneyValue;\n /** Number of orders */\n orderCount: number;\n /** Average order value */\n averageOrderValue: MoneyValue;\n /** Predicted future value */\n predictedLTV: MoneyValue;\n /** Customer segment */\n segment: 'low' | 'medium' | 'high' | 'vip';\n /** Days since first purchase */\n customerAge: number;\n /** Days since last purchase */\n daysSinceLastPurchase: number;\n /** Purchase frequency (orders per month) */\n purchaseFrequency: number;\n}\n\n/**\n * Configuration for recording acquisition cost.\n */\nexport interface AcquisitionCostConfig {\n /** Customer/user ID */\n userId: string;\n /** Acquisition cost */\n cost: MoneyValue;\n /** Acquisition channel */\n channel: string;\n /** Campaign (if applicable) */\n campaign?: string;\n}\n\n/**\n * LTV event response from API.\n */\nexport interface LTVResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n userId: string;\n ltv: number;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * LTV analytics data for charts.\n */\nexport interface LTVAnalyticsData {\n /** Summary metrics */\n summary: {\n averageLTV: MoneyValue;\n medianLTV: MoneyValue;\n totalCustomerValue: MoneyValue;\n averageCAC: MoneyValue;\n ltvCacRatio: number;\n averageOrderValue: MoneyValue;\n averageOrdersPerCustomer: number;\n };\n /** LTV by customer segment */\n bySegment: Array<{\n segment: string;\n customerCount: number;\n averageLTV: MoneyValue;\n totalRevenue: MoneyValue;\n percentageOfCustomers: number;\n percentageOfRevenue: number;\n }>;\n /** LTV by cohort */\n byCohort: Array<{\n cohort: string;\n customerCount: number;\n averageLTV: MoneyValue;\n ltvProgression: number[];\n }>;\n /** LTV by acquisition channel */\n byChannel: Array<{\n channel: string;\n customers: number;\n averageLTV: MoneyValue;\n averageCAC: MoneyValue;\n ltvCacRatio: number;\n roi: number;\n }>;\n /** LTV distribution */\n distribution: Array<{\n range: string;\n count: number;\n percentage: number;\n }>;\n /** LTV trend over time */\n trendData: TimeSeriesData;\n}\n\n// ============================================================================\n// CUSTOMER LTV CLASS\n// ============================================================================\n\n/**\n * CustomerLTV - Calculate and track customer lifetime value.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides LTV tracking capabilities including:\n * - Customer value calculation\n * - Acquisition cost tracking\n * - LTV:CAC ratio analysis\n * - Customer segmentation by value\n * - Cohort-based LTV analysis\n * \n * @example\n * ```typescript\n * const ltv = new CustomerLTV(webId, endpoint, apiKey);\n * \n * // Get individual customer value\n * const value = await ltv.getCustomerValue('user_123');\n * console.log(`LTV: $${value.totalRevenue.amount / 100}`);\n * \n * // Record acquisition cost\n * await ltv.recordAcquisitionCost({\n * userId: 'user_123',\n * cost: { amount: 5000, currency: 'USD' },\n * channel: 'facebook_ads',\n * campaign: 'spring_campaign'\n * });\n * ```\n */\nexport class CustomerLTV extends FlowGridTransport {\n /**\n * Records customer acquisition cost.\n * \n * @param config - Acquisition cost configuration\n * @returns Promise resolving to LTV response\n * \n * @example\n * ```typescript\n * await ltv.recordAcquisitionCost({\n * userId: 'user_123',\n * cost: { amount: 2500, currency: 'USD' }, // $25.00\n * channel: 'google_ads',\n * campaign: 'brand_terms'\n * });\n * ```\n */\n async recordAcquisitionCost(config: AcquisitionCostConfig): Promise<LTVResponse> {\n return await this.init(\"record_acquisition_cost\", {\n type: \"ecommerce\",\n subtype: \"acquisition_cost\",\n userId: config.userId,\n cost: config.cost,\n channel: config.channel,\n campaign: config.campaign,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Updates customer segment based on value.\n * \n * @param userId - Customer/user identifier\n * @param segment - New segment\n * @returns Promise resolving to LTV response\n */\n async updateSegment(\n userId: string,\n segment: 'low' | 'medium' | 'high' | 'vip'\n ): Promise<LTVResponse> {\n return await this.init(\"update_customer_segment\", {\n type: \"ecommerce\",\n subtype: \"update_customer_segment\",\n userId,\n segment,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default CustomerLTV;\n","/**\n * @fileoverview Ecommerce - Search Analytics\n * @module features/ecommerce/search\n * \n * @description\n * Track site search behavior to improve product discovery\n * and conversion from search results.\n * \n * @useCases\n * - Track search queries and results\n * - Identify zero-result searches\n * - Measure search-to-purchase conversion\n * - Analyze popular search terms\n * - Optimize search suggestions\n * \n * @metrics\n * - Search volume\n * - Zero-result rate\n * - Search refinement rate\n * - Click-through rate from search\n * - Conversion from search\n * \n * @chartData\n * - Word cloud: Popular search terms\n * - Bar chart: Top queries\n * - Table: Zero-result queries\n * - Funnel: Search to purchase\n * \n * @example\n * ```typescript\n * const search = new SearchAnalytics(webId, endpoint, apiKey);\n * \n * // Track search\n * await search.track({\n * query: 'wireless headphones',\n * resultsCount: 42,\n * filters: { brand: 'Sony' }\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { Product, DateRangeFilter, TimeSeriesData } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Search query configuration.\n */\nexport interface SearchConfig {\n /** Search query */\n query: string;\n /** Number of results */\n resultsCount: number;\n /** Search category/scope */\n category?: string;\n /** Applied filters */\n filters?: Record<string, string | string[]>;\n /** Sort order */\n sortBy?: string;\n /** Page number */\n page?: number;\n /** User ID */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n}\n\n/**\n * Search result click configuration.\n */\nexport interface SearchClickConfig {\n /** Original search query */\n query: string;\n /** Product clicked */\n product: Product;\n /** Position in results */\n position: number;\n /** Results page number */\n page?: number;\n}\n\n/**\n * Search response from API.\n */\nexport interface SearchResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n searchId: string;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Search analytics data.\n */\nexport interface SearchAnalyticsData {\n /** Summary metrics */\n summary: {\n totalSearches: number;\n uniqueSearchers: number;\n zeroResultSearches: number;\n zeroResultRate: number;\n avgResultsPerSearch: number;\n searchToClickRate: number;\n searchToConversionRate: number;\n };\n /** Top search queries */\n topQueries: Array<{\n query: string;\n searches: number;\n clicks: number;\n conversions: number;\n ctr: number;\n conversionRate: number;\n }>;\n /** Zero-result queries */\n zeroResultQueries: Array<{\n query: string;\n occurrences: number;\n lastSearched: string;\n }>;\n /** Popular filters */\n popularFilters: Array<{\n filterName: string;\n filterValue: string;\n usageCount: number;\n }>;\n /** Search trends */\n trends: TimeSeriesData;\n /** Search to purchase funnel */\n funnel: {\n searches: number;\n resultsViewed: number;\n productClicked: number;\n addedToCart: number;\n purchased: number;\n };\n}\n\n// ============================================================================\n// SEARCH ANALYTICS CLASS\n// ============================================================================\n\n/**\n * SearchAnalytics - Track site search behavior.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides search analytics including:\n * - Search query tracking\n * - Result click tracking\n * - Zero-result detection\n * - Search refinement tracking\n * - Search to conversion analysis\n * \n * @example\n * ```typescript\n * const search = new SearchAnalytics(webId, endpoint, apiKey);\n * \n * // Track search\n * await search.track({\n * query: 'running shoes',\n * resultsCount: 156,\n * filters: { size: '10', color: 'black' },\n * sortBy: 'price_asc'\n * });\n * \n * // Track click from search results\n * await search.trackClick({\n * query: 'running shoes',\n * product: clickedProduct,\n * position: 3\n * });\n * ```\n */\nexport class SearchAnalytics extends FlowGridTransport {\n /**\n * Tracks a search query.\n * \n * @param config - Search configuration\n * @returns Promise resolving to search response\n */\n async track(config: SearchConfig): Promise<SearchResponse> {\n return await this.init(\"site_search\", {\n type: \"ecommerce\",\n subtype: \"site_search\",\n query: config.query,\n resultsCount: config.resultsCount,\n hasResults: config.resultsCount > 0,\n category: config.category,\n filters: config.filters,\n sortBy: config.sortBy,\n page: config.page || 1,\n userId: config.userId,\n sessionId: config.sessionId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks a click on search result.\n * \n * @param config - Search click configuration\n * @returns Promise resolving to search response\n */\n async trackClick(config: SearchClickConfig): Promise<SearchResponse> {\n return await this.init(\"search_result_click\", {\n type: \"ecommerce\",\n subtype: \"search_result_click\",\n query: config.query,\n product: config.product,\n position: config.position,\n page: config.page || 1,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks search refinement (modifying search).\n * \n * @param originalQuery - Original search query\n * @param refinedQuery - New/refined query\n * @param refinementType - Type of refinement\n * @returns Promise resolving to search response\n */\n async trackRefinement(\n originalQuery: string,\n refinedQuery: string,\n refinementType: 'query_change' | 'add_filter' | 'remove_filter' | 'sort_change'\n ): Promise<SearchResponse> {\n return await this.init(\"search_refinement\", {\n type: \"ecommerce\",\n subtype: \"search_refinement\",\n originalQuery,\n refinedQuery,\n refinementType,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks autocomplete/suggestion selection.\n * \n * @param partialQuery - Partial query typed\n * @param selectedSuggestion - Suggestion selected\n * @param suggestionPosition - Position of suggestion\n * @returns Promise resolving to search response\n */\n async trackSuggestion(\n partialQuery: string,\n selectedSuggestion: string,\n suggestionPosition: number\n ): Promise<SearchResponse> {\n return await this.init(\"search_suggestion\", {\n type: \"ecommerce\",\n subtype: \"search_suggestion\",\n partialQuery,\n selectedSuggestion,\n suggestionPosition,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default SearchAnalytics;\n","/**\n * @fileoverview Ecommerce - Subscription & Recurring Revenue\n * @module features/ecommerce/subscriptions\n * \n * @description\n * Track subscription lifecycle events for SaaS and subscription\n * ecommerce businesses.\n * \n * @useCases\n * - Track subscription signups\n * - Monitor subscription changes (upgrades/downgrades)\n * - Track cancellations and churn\n * - Calculate MRR/ARR metrics\n * - Analyze subscription cohorts\n * \n * @metrics\n * - Monthly Recurring Revenue (MRR)\n * - Annual Recurring Revenue (ARR)\n * - Churn rate\n * - Expansion revenue\n * - Net revenue retention\n * \n * @chartData\n * - Line chart: MRR over time\n * - Waterfall: MRR movement\n * - Bar chart: Revenue by plan\n * - Cohort: Subscription retention\n * \n * @example\n * ```typescript\n * const subscriptions = new Subscriptions(webId, endpoint, apiKey);\n * \n * // Track subscription start\n * await subscriptions.start({\n * subscriptionId: 'sub_123',\n * userId: 'user_456',\n * plan: 'pro',\n * mrr: { amount: 4900, currency: 'USD' },\n * billingCycle: 'monthly'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { MoneyValue, CurrencyCode, DateRangeFilter, TimeSeriesData } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Subscription start configuration.\n */\nexport interface SubscriptionStartConfig {\n /** Subscription ID */\n subscriptionId: string;\n /** User ID */\n userId: string;\n /** Plan name */\n plan: string;\n /** Monthly recurring revenue */\n mrr: MoneyValue;\n /** Billing cycle */\n billingCycle: 'monthly' | 'quarterly' | 'yearly';\n /** Trial period (if applicable) */\n trialDays?: number;\n /** Coupon applied */\n coupon?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Subscription change configuration.\n */\nexport interface SubscriptionChangeConfig {\n /** Subscription ID */\n subscriptionId: string;\n /** User ID */\n userId: string;\n /** Previous plan */\n previousPlan: string;\n /** New plan */\n newPlan: string;\n /** Previous MRR */\n previousMrr: MoneyValue;\n /** New MRR */\n newMrr: MoneyValue;\n /** Change type */\n changeType: 'upgrade' | 'downgrade' | 'cross_grade';\n}\n\n/**\n * Subscription cancellation configuration.\n */\nexport interface SubscriptionCancelConfig {\n /** Subscription ID */\n subscriptionId: string;\n /** User ID */\n userId: string;\n /** Plan being cancelled */\n plan: string;\n /** Lost MRR */\n lostMrr: MoneyValue;\n /** Cancellation reason */\n reason?: string;\n /** Feedback provided */\n feedback?: string;\n /** Whether cancelled immediately or at period end */\n immediate: boolean;\n}\n\n/**\n * Subscription response from API.\n */\nexport interface SubscriptionResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n subscriptionId: string;\n tracked: boolean;\n };\n timestamp: string;\n}\n\n/**\n * Subscription analytics data.\n */\nexport interface SubscriptionAnalyticsData {\n /** Summary metrics */\n summary: {\n totalMrr: MoneyValue;\n totalArr: MoneyValue;\n activeSubscriptions: number;\n newSubscriptions: number;\n churnedSubscriptions: number;\n churnRate: number;\n expansionMrr: MoneyValue;\n contractionMrr: MoneyValue;\n netMrrMovement: MoneyValue;\n netRevenueRetention: number;\n avgRevenuePerUser: MoneyValue;\n };\n /** MRR by plan */\n byPlan: Array<{\n plan: string;\n subscriptions: number;\n mrr: MoneyValue;\n percentage: number;\n }>;\n /** MRR waterfall */\n mrrMovement: {\n startingMrr: MoneyValue;\n newMrr: MoneyValue;\n expansionMrr: MoneyValue;\n contractionMrr: MoneyValue;\n churnedMrr: MoneyValue;\n endingMrr: MoneyValue;\n };\n /** MRR trend */\n mrrTrend: TimeSeriesData;\n /** Churn by reason */\n churnByReason: Array<{\n reason: string;\n count: number;\n lostMrr: MoneyValue;\n }>;\n /** Trial conversion rate */\n trialMetrics: {\n trialsStarted: number;\n trialsConverted: number;\n conversionRate: number;\n };\n}\n\n// ============================================================================\n// SUBSCRIPTIONS CLASS\n// ============================================================================\n\n/**\n * Subscriptions - Track subscription lifecycle events.\n * \n * @extends FlowGridTransport\n * \n * @description\n * Provides subscription tracking including:\n * - Subscription starts (new MRR)\n * - Plan changes (expansion/contraction)\n * - Cancellations (churned MRR)\n * - Renewals\n * - Trial conversions\n * \n * @example\n * ```typescript\n * const subscriptions = new Subscriptions(webId, endpoint, apiKey);\n * \n * // New subscription\n * await subscriptions.start({\n * subscriptionId: 'sub_abc123',\n * userId: 'user_456',\n * plan: 'professional',\n * mrr: { amount: 9900, currency: 'USD' },\n * billingCycle: 'monthly',\n * trialDays: 14\n * });\n * \n * // Upgrade\n * await subscriptions.change({\n * subscriptionId: 'sub_abc123',\n * userId: 'user_456',\n * previousPlan: 'professional',\n * newPlan: 'enterprise',\n * previousMrr: { amount: 9900, currency: 'USD' },\n * newMrr: { amount: 29900, currency: 'USD' },\n * changeType: 'upgrade'\n * });\n * ```\n */\nexport class Subscriptions extends FlowGridTransport {\n /**\n * Tracks subscription start.\n * \n * @param config - Subscription start configuration\n * @returns Promise resolving to subscription response\n */\n async start(config: SubscriptionStartConfig): Promise<SubscriptionResponse> {\n return await this.init(\"subscription_start\", {\n type: \"ecommerce\",\n subtype: \"subscription_start\",\n subscriptionId: config.subscriptionId,\n userId: config.userId,\n plan: config.plan,\n mrr: config.mrr,\n billingCycle: config.billingCycle,\n trialDays: config.trialDays,\n coupon: config.coupon,\n isTrialing: (config.trialDays || 0) > 0,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks subscription plan change.\n * \n * @param config - Subscription change configuration\n * @returns Promise resolving to subscription response\n */\n async change(config: SubscriptionChangeConfig): Promise<SubscriptionResponse> {\n const mrrDiff = config.newMrr.amount - config.previousMrr.amount;\n \n return await this.init(\"subscription_change\", {\n type: \"ecommerce\",\n subtype: \"subscription_change\",\n subscriptionId: config.subscriptionId,\n userId: config.userId,\n previousPlan: config.previousPlan,\n newPlan: config.newPlan,\n previousMrr: config.previousMrr,\n newMrr: config.newMrr,\n mrrChange: mrrDiff,\n changeType: config.changeType,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks subscription cancellation.\n * \n * @param config - Cancellation configuration\n * @returns Promise resolving to subscription response\n */\n async cancel(config: SubscriptionCancelConfig): Promise<SubscriptionResponse> {\n return await this.init(\"subscription_cancel\", {\n type: \"ecommerce\",\n subtype: \"subscription_cancel\",\n subscriptionId: config.subscriptionId,\n userId: config.userId,\n plan: config.plan,\n lostMrr: config.lostMrr,\n reason: config.reason,\n feedback: config.feedback,\n immediate: config.immediate,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks subscription renewal.\n * \n * @param subscriptionId - Subscription ID\n * @param userId - User ID\n * @param mrr - Renewed MRR\n * @returns Promise resolving to subscription response\n */\n async renew(\n subscriptionId: string,\n userId: string,\n mrr: MoneyValue\n ): Promise<SubscriptionResponse> {\n return await this.init(\"subscription_renew\", {\n type: \"ecommerce\",\n subtype: \"subscription_renew\",\n subscriptionId,\n userId,\n mrr,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks trial conversion to paid.\n * \n * @param subscriptionId - Subscription ID\n * @param userId - User ID\n * @param plan - Converted to plan\n * @param mrr - New MRR\n * @returns Promise resolving to subscription response\n */\n async trialConverted(\n subscriptionId: string,\n userId: string,\n plan: string,\n mrr: MoneyValue\n ): Promise<SubscriptionResponse> {\n return await this.init(\"trial_converted\", {\n type: \"ecommerce\",\n subtype: \"trial_converted\",\n subscriptionId,\n userId,\n plan,\n mrr,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Tracks trial expiration without conversion.\n * \n * @param subscriptionId - Subscription ID\n * @param userId - User ID\n * @returns Promise resolving to subscription response\n */\n async trialExpired(\n subscriptionId: string,\n userId: string\n ): Promise<SubscriptionResponse> {\n return await this.init(\"trial_expired\", {\n type: \"ecommerce\",\n subtype: \"trial_expired\",\n subscriptionId,\n userId,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n\nexport default Subscriptions;\n","/**\n * @fileoverview Enterprise - Engagement Analytics\n * @module features/enterprise/engagement\n * \n * @description\n * Track deep user engagement beyond activation including\n * feature dwell time, session depth, and content consumption.\n * \n * @useCases\n * - Measure feature dwell time\n * - Track session depth and engagement\n * - Monitor content consumption patterns\n * - Distinguish active vs passive users\n * - Correlate engagement with retention\n * \n * @metrics\n * - Average engagement time\n * - Feature dwell time\n * - Session depth score\n * - Content consumption rate\n * - Active user ratio\n * \n * @chartData\n * - Line chart: Engagement over time\n * - Bar chart: Engagement by feature\n * - Heatmap: Engagement by time of day\n * - Distribution: User engagement scores\n * \n * @example\n * ```typescript\n * const engagement = new Engagement(webId, endpoint, apiKey);\n * \n * // Track feature dwell time\n * await engagement.trackDwellTime({\n * featureId: 'dashboard',\n * userId: 'user_123',\n * dwellTimeMs: 45000\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData, TimeGranularity, ActiveUsersConfig, ActiveUsersResponse, ActiveUserRatios } from \"../../types\";\nimport { isBrowser, getDocument, getWindow, combineTeardowns, type Teardown } from \"../../utils/browser\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Configuration for tracking feature dwell time.\n */\nexport interface DwellTimeConfig {\n /** Feature identifier */\n featureId: string;\n /** User ID */\n userId?: string;\n /** Session ID */\n sessionId?: string;\n /** Time spent on feature (ms) */\n dwellTimeMs: number;\n /** Whether user was actively interacting */\n wasActive?: boolean;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Configuration for tracking session depth.\n */\nexport interface SessionDepthConfig {\n /** Session ID */\n sessionId: string;\n /** User ID */\n userId?: string;\n /** Number of pages/screens visited */\n pagesVisited: number;\n /** Number of features used */\n featuresUsed: number;\n /** Number of actions taken */\n actionsTaken: number;\n /** Total session duration (ms) */\n durationMs: number;\n}\n\n/**\n * Configuration for tracking content consumption.\n */\nexport interface ContentConsumptionConfig {\n /** Content identifier */\n contentId: string;\n /** Content type */\n contentType: 'article' | 'video' | 'audio' | 'document' | 'course' | 'other';\n /** User ID */\n userId?: string;\n /** Percentage consumed (0-100) */\n percentageConsumed: number;\n /** Time spent consuming (ms) */\n timeSpentMs: number;\n /** Whether content was completed */\n completed?: boolean;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * User activity classification.\n */\nexport interface UserActivityConfig {\n /** User ID */\n userId: string;\n /** Activity type */\n activityType: 'active' | 'passive' | 'idle';\n /** Duration in this state (ms) */\n durationMs: number;\n /** Session ID */\n sessionId?: string;\n}\n\n/**\n * Engagement score configuration.\n */\nexport interface EngagementScoreConfig {\n /** User ID */\n userId: string;\n /** Time period for score calculation */\n period?: 'day' | 'week' | 'month';\n}\n\n/**\n * Engagement analytics filter.\n */\nexport interface EngagementAnalyticsFilter extends DateRangeFilter {\n /** Filter by feature */\n featureId?: string;\n /** Filter by user segment */\n segment?: string;\n /** Minimum engagement score */\n minScore?: number;\n}\n\n/**\n * Engagement response from API.\n */\nexport interface EngagementResponse {\n eventName: string;\n properties: Record<string, unknown>;\n response: {\n tracked: boolean;\n engagementId: string;\n timestamp: string;\n };\n}\n\n/**\n * Engagement score result.\n */\nexport interface EngagementScore {\n userId: string;\n score: number;\n percentile: number;\n breakdown: {\n dwellTime: number;\n sessionDepth: number;\n contentConsumption: number;\n activityLevel: number;\n };\n trend: 'increasing' | 'stable' | 'decreasing';\n period: string;\n}\n\n/**\n * Engagement analytics result.\n */\nexport interface EngagementAnalytics {\n averageEngagementScore: number;\n averageDwellTimeMs: number;\n averageSessionDepth: number;\n activeUserRatio: number;\n contentCompletionRate: number;\n topEngagedFeatures: Array<{\n featureId: string;\n averageDwellTime: number;\n userCount: number;\n }>;\n engagementTrend: TimeSeriesData;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Calculate engagement score from multiple factors.\n */\nexport function calculateEngagementScore(\n dwellTime: number,\n sessionDepth: number,\n activityRatio: number,\n contentCompletion: number\n): number {\n const weights = {\n dwellTime: 0.25,\n sessionDepth: 0.25,\n activityRatio: 0.30,\n contentCompletion: 0.20\n };\n\n return Math.round(\n (dwellTime * weights.dwellTime +\n sessionDepth * weights.sessionDepth +\n activityRatio * weights.activityRatio +\n contentCompletion * weights.contentCompletion) * 100\n ) / 100;\n}\n\n/**\n * Classify user engagement level.\n */\nexport function classifyEngagementLevel(score: number): 'low' | 'medium' | 'high' | 'power' {\n if (score < 25) return 'low';\n if (score < 50) return 'medium';\n if (score < 75) return 'high';\n return 'power';\n}\n\n/**\n * Calculate session depth score.\n */\nexport function calculateSessionDepthScore(\n pagesVisited: number,\n featuresUsed: number,\n actionsTaken: number\n): number {\n const pageScore = Math.min(pagesVisited / 10, 1) * 30;\n const featureScore = Math.min(featuresUsed / 5, 1) * 40;\n const actionScore = Math.min(actionsTaken / 20, 1) * 30;\n return Math.round(pageScore + featureScore + actionScore);\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Engagement analytics tracking class.\n */\nexport class Engagement extends FlowGridTransport {\n /**\n * Track feature dwell time.\n */\n async trackDwellTime(config: DwellTimeConfig): Promise<EngagementResponse> {\n return await this.initFeature(\"engagement.dwell_time\", {\n type: \"engagement\",\n featureId: config.featureId,\n userId: config.userId,\n sessionId: config.sessionId,\n dwellTimeMs: config.dwellTimeMs,\n wasActive: config.wasActive ?? true,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track session depth.\n */\n async trackSessionDepth(config: SessionDepthConfig): Promise<EngagementResponse> {\n const depthScore = calculateSessionDepthScore(\n config.pagesVisited,\n config.featuresUsed,\n config.actionsTaken\n );\n\n return await this.initFeature(\"engagement.session_depth\", {\n type: \"engagement\",\n sessionId: config.sessionId,\n userId: config.userId,\n pagesVisited: config.pagesVisited,\n featuresUsed: config.featuresUsed,\n actionsTaken: config.actionsTaken,\n durationMs: config.durationMs,\n depthScore,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track content consumption.\n */\n async trackContentConsumption(config: ContentConsumptionConfig): Promise<EngagementResponse> {\n return await this.initFeature(\"engagement.content_consumption\", {\n type: \"engagement\",\n contentId: config.contentId,\n contentType: config.contentType,\n userId: config.userId,\n percentageConsumed: config.percentageConsumed,\n timeSpentMs: config.timeSpentMs,\n completed: config.completed ?? config.percentageConsumed >= 90,\n ...config.properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track user activity state.\n */\n async trackUserActivity(config: UserActivityConfig): Promise<EngagementResponse> {\n return await this.initFeature(\"engagement.user_activity\", {\n type: \"engagement\",\n userId: config.userId,\n activityType: config.activityType,\n durationMs: config.durationMs,\n sessionId: config.sessionId,\n timestamp: new Date().toISOString()\n });\n }\n\n // ---------------------------------------------------------------------------\n // DAU / WAU / MAU\n // ---------------------------------------------------------------------------\n\n /**\n * Auto-accumulate dwell time on a feature while the page is visible. Returns\n * a teardown that emits a single `trackDwellTime` event with the elapsed\n * active milliseconds.\n */\n autoTrackDwell(\n featureId: string,\n options: { userId?: string; sessionId?: string } = {},\n ): Teardown {\n if (!isBrowser()) return () => {};\n const doc = getDocument();\n if (!doc) return () => {};\n\n let activeMs = 0;\n let lastTick = doc.visibilityState === \"visible\" ? Date.now() : 0;\n\n const onVisibility = () => {\n const now = Date.now();\n if (doc.visibilityState === \"visible\") {\n lastTick = now;\n } else if (lastTick) {\n activeMs += now - lastTick;\n lastTick = 0;\n }\n };\n doc.addEventListener(\"visibilitychange\", onVisibility);\n\n let torndown = false;\n return () => {\n if (torndown) return;\n torndown = true;\n doc.removeEventListener(\"visibilitychange\", onVisibility);\n if (lastTick) {\n activeMs += Date.now() - lastTick;\n lastTick = 0;\n }\n if (activeMs > 0) {\n void this.trackDwellTime({\n featureId,\n dwellTimeMs: activeMs,\n userId: options.userId,\n sessionId: options.sessionId,\n wasActive: true,\n });\n }\n };\n }\n\n /**\n * Auto-track session-level engagement signals in the browser:\n *\n * - **Session depth** — counts SPA navigations, click/keyboard actions, and\n * total session duration; emits a single `trackSessionDepth` on\n * `pagehide`.\n * - **User activity** — classifies the user as `active` (recent input),\n * `passive` (visible but idle) or `idle` (tab hidden), and emits\n * `trackUserActivity` on every state transition with the time spent in\n * the previous state.\n *\n * The session id is read from the same `sessionStorage` key written by\n * {@link Sessions.autoTrack} (`flowgrid:sessionId`) so the two modules\n * stay correlated. If no session id is present, a synthetic one is\n * generated for the page lifetime.\n *\n * Safe no-op outside the browser.\n *\n * @example\n * ```ts\n * const stop = fg.engagement.client.autoTrack({ userId: \"u_1\" });\n * // ...later\n * stop();\n * ```\n */\n autoTrack(options: {\n userId?: string;\n sessionId?: string;\n /** Idle threshold (ms) without input before a visible user is \"passive\". Default 30s. */\n idleAfterMs?: number;\n /** Activity polling interval (ms). Default 5s. */\n pollMs?: number;\n } = {}): Teardown {\n if (!isBrowser()) return () => {};\n const win = getWindow();\n const doc = getDocument();\n if (!win || !doc) return () => {};\n\n const idleAfterMs = options.idleAfterMs ?? 30_000;\n const pollMs = options.pollMs ?? 5_000;\n\n // Resolve session id: prefer the one written by Sessions.autoTrack so\n // depth / activity events line up with the canonical session.\n let sessionId = options.sessionId;\n if (!sessionId) {\n try { sessionId = win.sessionStorage.getItem(\"flowgrid:sessionId\") || undefined; } catch { /* private mode */ }\n }\n if (!sessionId) {\n sessionId = `eng_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\n }\n\n const startedAt = Date.now();\n let pagesVisited = 1;\n const featuresUsed = new Set<string>();\n let actionsTaken = 0;\n let lastInputAt = Date.now();\n\n // Activity state\n type ActivityType = \"active\" | \"passive\" | \"idle\";\n let currentState: ActivityType =\n doc.visibilityState === \"visible\" ? \"active\" : \"idle\";\n let stateEnteredAt = Date.now();\n\n // --- SPA navigation count\n const origPush = win.history.pushState;\n const origReplace = win.history.replaceState;\n const onNav = () => { pagesVisited++; };\n win.history.pushState = function (...args: Parameters<typeof origPush>) {\n const r = origPush.apply(this, args);\n onNav();\n return r;\n };\n win.history.replaceState = function (...args: Parameters<typeof origReplace>) {\n const r = origReplace.apply(this, args);\n onNav();\n return r;\n };\n win.addEventListener(\"popstate\", onNav);\n\n // --- User input → action count + activity ping\n const onInput = (ev: Event) => {\n actionsTaken++;\n lastInputAt = Date.now();\n // Optionally collect feature ids from a `data-flowgrid-feature` attribute.\n const target = ev.target as Element | null;\n const featureAttr = target?.closest?.(\"[data-flowgrid-feature]\")\n ?.getAttribute(\"data-flowgrid-feature\");\n if (featureAttr) featuresUsed.add(featureAttr);\n };\n doc.addEventListener(\"click\", onInput, { capture: true });\n doc.addEventListener(\"keydown\", onInput, { capture: true });\n doc.addEventListener(\"scroll\", onInput, { capture: true, passive: true });\n\n const transition = (next: ActivityType) => {\n if (next === currentState) return;\n const now = Date.now();\n const durationMs = now - stateEnteredAt;\n const prev = currentState;\n currentState = next;\n stateEnteredAt = now;\n if (durationMs > 0 && options.userId) {\n void this.trackUserActivity({\n userId: options.userId,\n activityType: prev,\n durationMs,\n sessionId,\n });\n }\n };\n\n // --- Periodic activity classifier\n const tick = () => {\n const now = Date.now();\n let next: ActivityType;\n if (doc.visibilityState !== \"visible\") next = \"idle\";\n else if (now - lastInputAt < idleAfterMs) next = \"active\";\n else next = \"passive\";\n transition(next);\n };\n const ticker = win.setInterval(tick, pollMs);\n\n const onVisibility = () => tick();\n doc.addEventListener(\"visibilitychange\", onVisibility);\n\n // --- Emit final session depth on pagehide\n let depthSent = false;\n const sendDepth = () => {\n if (depthSent) return;\n depthSent = true;\n transition(doc.visibilityState === \"visible\" ? currentState : \"idle\");\n const durationMs = Date.now() - startedAt;\n if (durationMs <= 0) return;\n void this.trackSessionDepth({\n sessionId: sessionId!,\n userId: options.userId,\n pagesVisited,\n featuresUsed: featuresUsed.size,\n actionsTaken,\n durationMs,\n });\n };\n win.addEventListener(\"pagehide\", sendDepth);\n\n return combineTeardowns(\n () => win.clearInterval(ticker),\n () => doc.removeEventListener(\"visibilitychange\", onVisibility),\n () => doc.removeEventListener(\"click\", onInput, true),\n () => doc.removeEventListener(\"keydown\", onInput, true),\n () => doc.removeEventListener(\"scroll\", onInput, true),\n () => win.removeEventListener(\"popstate\", onNav),\n () => win.removeEventListener(\"pagehide\", sendDepth),\n () => { win.history.pushState = origPush; win.history.replaceState = origReplace; },\n () => sendDepth(),\n );\n }\n}\n","/**\n * @fileoverview Enterprise - Advanced Cohorts & Segmentation\n * @module features/enterprise/cohorts\n * \n * @description\n * Generate behavioral and acquisition cohorts for granular analysis.\n * Segment users by behavior, acquisition source, and custom criteria.\n * \n * @useCases\n * - Create behavior-based cohorts\n * - Segment by acquisition source\n * - Track paid vs free user cohorts\n * - Dynamic segmentation rules\n * - Cohort comparison analysis\n * \n * @metrics\n * - Cohort size\n * - Cohort retention\n * - Cohort conversion\n * - Segment growth rate\n * - Cross-segment behavior\n * \n * @chartData\n * - Bar chart: Cohort sizes\n * - Line chart: Cohort trends\n * - Heatmap: Cohort retention matrix\n * - Comparison: Cohort A vs B\n * \n * @example\n * ```typescript\n * const cohorts = new Cohorts(webId, endpoint, apiKey);\n * \n * // Create a behavioral cohort\n * await cohorts.createCohort({\n * name: 'Power Users',\n * type: 'behavioral',\n * rules: [{ attribute: 'sessions_per_week', operator: 'gte', value: 5 }]\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Cohort rule operators.\n */\nexport type CohortOperator = \n | 'equals' | 'not_equals'\n | 'contains' | 'not_contains'\n | 'gt' | 'gte' | 'lt' | 'lte'\n | 'in' | 'not_in'\n | 'between' | 'exists' | 'not_exists';\n\n/**\n * Cohort rule definition.\n */\nexport interface CohortRule {\n /** Attribute to evaluate */\n attribute: string;\n /** Comparison operator */\n operator: CohortOperator;\n /** Value to compare against */\n value: unknown;\n /** Logical operator for combining rules */\n logicalOperator?: 'and' | 'or';\n}\n\n/**\n * Cohort type classification.\n */\nexport type CohortType = \n | 'behavioral' // Based on user actions\n | 'acquisition' // Based on how users were acquired\n | 'demographic' // Based on user traits\n | 'lifecycle' // Based on user lifecycle stage\n | 'custom'; // Custom rules\n\n/**\n * Cohort definition configuration.\n */\nexport interface CohortDefinition {\n /** Unique cohort identifier */\n cohortId?: string;\n /** Cohort name */\n name: string;\n /** Cohort description */\n description?: string;\n /** Cohort type */\n type: CohortType;\n /** Rules for cohort membership */\n rules: CohortRule[];\n /** Whether cohort membership is dynamic */\n dynamic?: boolean;\n /** Time window for evaluation (for behavioral cohorts) */\n timeWindow?: {\n value: number;\n unit: 'hours' | 'days' | 'weeks' | 'months';\n };\n}\n\n/**\n * Segment definition configuration.\n */\nexport interface SegmentDefinition {\n /** Segment identifier */\n segmentId?: string;\n /** Segment name */\n name: string;\n /** Segment description */\n description?: string;\n /** Segmentation attribute */\n attribute: string;\n /** Segment values/buckets */\n buckets: Array<{\n name: string;\n rules: CohortRule[];\n }>;\n}\n\n/**\n * User cohort assignment.\n */\nexport interface CohortAssignment {\n /** User ID */\n userId: string;\n /** Cohort ID */\n cohortId: string;\n /** Assignment timestamp */\n assignedAt: string;\n /** Whether user currently matches cohort rules */\n isActive: boolean;\n}\n\n/**\n * Cohort comparison configuration.\n */\nexport interface CohortComparisonConfig {\n /** First cohort ID */\n cohortA: string;\n /** Second cohort ID */\n cohortB: string;\n /** Metrics to compare */\n metrics: string[];\n /** Date range for comparison */\n filter?: DateRangeFilter;\n}\n\n/**\n * Cohort analytics filter.\n */\nexport interface CohortAnalyticsFilter extends DateRangeFilter {\n /** Filter by cohort type */\n type?: CohortType;\n /** Minimum cohort size */\n minSize?: number;\n}\n\n/**\n * Cohort response from API.\n */\nexport interface CohortResponse {\n cohortId: string;\n name: string;\n type: CohortType;\n size: number;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Cohort member.\n */\nexport interface CohortMember {\n userId: string;\n joinedAt: string;\n traits: Record<string, unknown>;\n isActive: boolean;\n}\n\n/**\n * Cohort analytics result.\n */\nexport interface CohortAnalytics {\n cohortId: string;\n name: string;\n currentSize: number;\n growthRate: number;\n retention: {\n day1: number;\n day7: number;\n day30: number;\n };\n conversion: number;\n avgEngagementScore: number;\n}\n\n/**\n * Cohort comparison result.\n */\nexport interface CohortComparison {\n cohortA: CohortAnalytics;\n cohortB: CohortAnalytics;\n differences: Record<string, {\n cohortAValue: number;\n cohortBValue: number;\n percentDiff: number;\n significant: boolean;\n }>;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Evaluate if a user matches cohort rules.\n */\nexport function evaluateCohortRules(\n userAttributes: Record<string, unknown>,\n rules: CohortRule[]\n): boolean {\n let result = true;\n let currentOperator: 'and' | 'or' = 'and';\n\n for (const rule of rules) {\n const attributeValue = userAttributes[rule.attribute];\n const ruleResult = evaluateRule(attributeValue, rule.operator, rule.value);\n\n if (currentOperator === 'and') {\n result = result && ruleResult;\n } else {\n result = result || ruleResult;\n }\n\n currentOperator = rule.logicalOperator ?? 'and';\n }\n\n return result;\n}\n\n/**\n * Evaluate a single rule.\n */\nfunction evaluateRule(\n attributeValue: unknown,\n operator: CohortOperator,\n ruleValue: unknown\n): boolean {\n switch (operator) {\n case 'equals':\n return attributeValue === ruleValue;\n case 'not_equals':\n return attributeValue !== ruleValue;\n case 'contains':\n return String(attributeValue).includes(String(ruleValue));\n case 'not_contains':\n return !String(attributeValue).includes(String(ruleValue));\n case 'gt':\n return Number(attributeValue) > Number(ruleValue);\n case 'gte':\n return Number(attributeValue) >= Number(ruleValue);\n case 'lt':\n return Number(attributeValue) < Number(ruleValue);\n case 'lte':\n return Number(attributeValue) <= Number(ruleValue);\n case 'in':\n return Array.isArray(ruleValue) && ruleValue.includes(attributeValue);\n case 'not_in':\n return Array.isArray(ruleValue) && !ruleValue.includes(attributeValue);\n case 'exists':\n return attributeValue !== undefined && attributeValue !== null;\n case 'not_exists':\n return attributeValue === undefined || attributeValue === null;\n case 'between':\n if (Array.isArray(ruleValue) && ruleValue.length === 2) {\n const num = Number(attributeValue);\n return num >= Number(ruleValue[0]) && num <= Number(ruleValue[1]);\n }\n return false;\n default:\n return false;\n }\n}\n\n/**\n * Generate cohort ID from name.\n */\nexport function generateCohortId(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_|_$/g, '');\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Advanced cohorts and segmentation class.\n */\nexport class Cohorts extends FlowGridTransport {\n /**\n * Create a new cohort.\n */\n async createCohort(definition: CohortDefinition): Promise<CohortResponse> {\n const cohortId = definition.cohortId ?? generateCohortId(definition.name);\n\n return await this.initFeature(\"cohorts.create\", {\n type: \"cohorts\",\n cohortId,\n name: definition.name,\n description: definition.description,\n cohortType: definition.type,\n rules: definition.rules,\n dynamic: definition.dynamic ?? true,\n timeWindow: definition.timeWindow,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Update an existing cohort.\n */\n async updateCohort(cohortId: string, updates: Partial<CohortDefinition>): Promise<CohortResponse> {\n const { type: cohortType, ...rest } = updates;\n return await this.initFeature(\"cohorts.update\", {\n type: \"cohorts\",\n cohortId,\n cohortType,\n ...rest,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Delete a cohort.\n */\n async deleteCohort(cohortId: string): Promise<{ deleted: boolean }> {\n return await this.initFeature(\"cohorts.delete\", {\n type: \"cohorts\",\n cohortId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * List all cohorts.\n */\n async listCohorts(filter?: CohortAnalyticsFilter): Promise<CohortResponse[]> {\n return await this.initFeature(\"cohorts.list\", {\n type: \"cohorts\",\n filter,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Check if user belongs to cohort.\n */\n async isUserInCohort(userId: string, cohortId: string): Promise<{ isMember: boolean }> {\n return await this.initFeature(\"cohorts.check_membership\", {\n type: \"cohorts\",\n userId,\n cohortId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Create a segment.\n */\n async createSegment(definition: SegmentDefinition): Promise<{ segmentId: string }> {\n return await this.initFeature(\"cohorts.create_segment\", {\n type: \"cohorts\",\n ...definition,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Compare two cohorts.\n */\n async compareCohorts(config: CohortComparisonConfig): Promise<CohortComparison> {\n return await this.initFeature(\"cohorts.compare\", {\n type: \"cohorts\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * @fileoverview Enterprise - Churn & Predictive Analytics\n * @module features/enterprise/churn\n * \n * @description\n * Predict and measure churn proactively using usage patterns,\n * engagement signals, and predictive scoring models.\n * \n * @useCases\n * - Detect usage decay patterns\n * - Identify at-risk users\n * - Predict churn probability\n * - Correlate NPS with churn\n * - Track churn prevention success\n * \n * @metrics\n * - Churn rate\n * - Churn risk score\n * - Days to churn prediction\n * - At-risk user count\n * - Prevention success rate\n * \n * @chartData\n * - Line chart: Churn rate over time\n * - Distribution: Risk score distribution\n * - Bar chart: Churn by segment\n * - Funnel: Churn prevention funnel\n * \n * @example\n * ```typescript\n * const churn = new ChurnAnalytics(webId, endpoint, apiKey);\n * \n * // Get user churn risk\n * const risk = await churn.getUserRiskScore('user_123');\n * \n * // Get at-risk users\n * const atRisk = await churn.getAtRiskUsers({ minScore: 70 });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData, TimeGranularity } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Churn risk factors.\n */\nexport interface ChurnRiskFactors {\n /** Days since last activity */\n daysSinceLastActivity: number;\n /** Usage trend (negative = declining) */\n usageTrend: number;\n /** Session frequency change */\n sessionFrequencyChange: number;\n /** Feature usage breadth change */\n featureUsageChange: number;\n /** Support tickets opened */\n supportTickets: number;\n /** NPS score (if available) */\n npsScore?: number;\n /** Payment failures */\n paymentFailures: number;\n /** Contract/subscription end approaching */\n daysUntilRenewal?: number;\n}\n\n/**\n * Churn risk score result.\n */\nexport interface ChurnRiskScore {\n /** User ID */\n userId: string;\n /** Risk score (0-100, higher = more likely to churn) */\n score: number;\n /** Risk level classification */\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n /** Predicted days until churn */\n predictedDaysToChurn?: number;\n /** Top contributing factors */\n topFactors: Array<{\n factor: string;\n contribution: number;\n value: unknown;\n }>;\n /** Recommended actions */\n recommendations: string[];\n /** Last updated */\n updatedAt: string;\n}\n\n/**\n * Usage decay configuration.\n */\nexport interface UsageDecayConfig {\n /** User ID */\n userId: string;\n /** Metric to track decay */\n metric: 'sessions' | 'events' | 'features' | 'time_spent';\n /** Comparison periods */\n periods: {\n current: DateRangeFilter;\n previous: DateRangeFilter;\n };\n}\n\n/**\n * Usage decay result.\n */\nexport interface UsageDecay {\n userId: string;\n metric: string;\n currentValue: number;\n previousValue: number;\n changePercent: number;\n isDecaying: boolean;\n decayRate: number;\n}\n\n/**\n * NPS tracking configuration.\n */\nexport interface NPSConfig {\n /** User ID */\n userId: string;\n /** NPS score (0-10) */\n score: number;\n /** Feedback comment */\n feedback?: string;\n /** Survey context */\n context?: string;\n}\n\n/**\n * Churn event configuration.\n */\nexport interface ChurnEventConfig {\n /** User ID */\n userId: string;\n /** Churn type */\n churnType: 'voluntary' | 'involuntary' | 'downgrade';\n /** Churn reason */\n reason?: string;\n /** Subscription/account value lost */\n valueLost?: {\n amount: number;\n currency: string;\n };\n /** Win-back attempted */\n winbackAttempted?: boolean;\n}\n\n/**\n * Prevention action configuration.\n */\nexport interface PreventionActionConfig {\n /** User ID */\n userId: string;\n /** Action type */\n actionType: 'outreach' | 'discount' | 'feature_unlock' | 'support_call' | 'other';\n /** Action details */\n details?: Record<string, unknown>;\n /** Outcome */\n outcome?: 'success' | 'pending' | 'failed';\n}\n\n/**\n * At-risk users filter.\n */\nexport interface AtRiskUsersFilter extends DateRangeFilter {\n /** Minimum risk score */\n minScore?: number;\n /** Risk level filter */\n riskLevel?: 'low' | 'medium' | 'high' | 'critical';\n /** User segment */\n segment?: string;\n /** Limit results */\n limit?: number;\n}\n\n/**\n * Churn analytics result.\n */\nexport interface ChurnAnalyticsResult {\n /** Total churn rate */\n churnRate: number;\n /** Voluntary churn rate */\n voluntaryChurnRate: number;\n /** Involuntary churn rate */\n involuntaryChurnRate: number;\n /** At-risk user count */\n atRiskUserCount: number;\n /** Revenue at risk */\n revenueAtRisk: {\n amount: number;\n currency: string;\n };\n /** Prevention success rate */\n preventionSuccessRate: number;\n /** Average NPS of churned users */\n avgChurnedNPS: number;\n /** Top churn reasons */\n topReasons: Array<{ reason: string; count: number; percentage: number }>;\n /** Churn trend */\n trend: TimeSeriesData;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Calculate churn risk score from factors.\n */\nexport function calculateChurnRiskScore(factors: ChurnRiskFactors): number {\n const weights = {\n daysSinceLastActivity: 0.25,\n usageTrend: 0.20,\n sessionFrequencyChange: 0.15,\n featureUsageChange: 0.10,\n supportTickets: 0.10,\n npsScore: 0.10,\n paymentFailures: 0.05,\n daysUntilRenewal: 0.05\n };\n\n let score = 0;\n\n // Days since last activity (0-30 days mapped to 0-100)\n score += Math.min(factors.daysSinceLastActivity / 30, 1) * 100 * weights.daysSinceLastActivity;\n\n // Usage trend (negative trend increases risk)\n score += Math.max(0, -factors.usageTrend) * weights.usageTrend;\n\n // Session frequency change (negative increases risk)\n score += Math.max(0, -factors.sessionFrequencyChange) * weights.sessionFrequencyChange;\n\n // Feature usage change (negative increases risk)\n score += Math.max(0, -factors.featureUsageChange) * weights.featureUsageChange;\n\n // Support tickets (more tickets = higher risk)\n score += Math.min(factors.supportTickets * 10, 100) * weights.supportTickets;\n\n // NPS score (lower NPS = higher risk)\n if (factors.npsScore !== undefined) {\n score += (100 - factors.npsScore * 10) * weights.npsScore;\n }\n\n // Payment failures\n score += Math.min(factors.paymentFailures * 25, 100) * weights.paymentFailures;\n\n // Days until renewal (closer = higher urgency)\n if (factors.daysUntilRenewal !== undefined) {\n score += Math.max(0, 100 - factors.daysUntilRenewal) * weights.daysUntilRenewal;\n }\n\n return Math.round(Math.min(score, 100));\n}\n\n/**\n * Classify risk level from score.\n */\nexport function classifyRiskLevel(score: number): 'low' | 'medium' | 'high' | 'critical' {\n if (score < 25) return 'low';\n if (score < 50) return 'medium';\n if (score < 75) return 'high';\n return 'critical';\n}\n\n/**\n * Generate churn prevention recommendations.\n */\nexport function generateRecommendations(\n riskFactors: Array<{ factor: string; contribution: number }>\n): string[] {\n const recommendations: string[] = [];\n \n const factorActions: Record<string, string> = {\n daysSinceLastActivity: 'Send a re-engagement email or push notification',\n usageTrend: 'Schedule a product walkthrough or training session',\n sessionFrequencyChange: 'Offer incentives to increase usage frequency',\n featureUsageChange: 'Highlight underutilized features via in-app messaging',\n supportTickets: 'Escalate to customer success for personalized support',\n npsScore: 'Conduct a follow-up call to address concerns',\n paymentFailures: 'Reach out to resolve payment issues proactively',\n daysUntilRenewal: 'Start renewal conversation early with value recap'\n };\n\n for (const factor of riskFactors.slice(0, 3)) {\n if (factorActions[factor.factor]) {\n recommendations.push(factorActions[factor.factor]);\n }\n }\n\n return recommendations;\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Churn and predictive analytics class.\n */\nexport class ChurnAnalytics extends FlowGridTransport {\n /**\n * Track usage decay.\n */\n async trackUsageDecay(config: UsageDecayConfig): Promise<UsageDecay> {\n return await this.initFeature(\"churn.usage_decay\", {\n type: \"churn\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track NPS score.\n */\n async trackNPS(config: NPSConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"churn.nps\", {\n type: \"churn\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track churn event.\n */\n async trackChurn(config: ChurnEventConfig): Promise<{ tracked: boolean; churnId: string }> {\n return await this.initFeature(\"churn.churn_event\", {\n type: \"churn\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track churn prevention action.\n */\n async trackPreventionAction(config: PreventionActionConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"churn.prevention_action\", {\n type: \"churn\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Update prevention action outcome.\n */\n async updatePreventionOutcome(\n userId: string,\n actionType: string,\n outcome: 'success' | 'failed'\n ): Promise<{ updated: boolean }> {\n return await this.initFeature(\"churn.update_prevention_outcome\", {\n type: \"churn\",\n userId,\n actionType,\n outcome,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * @fileoverview Enterprise - Revenue & Monetization Analytics\n * @module features/enterprise/monetization\n * \n * @description\n * Track detailed revenue and monetization KPIs including ARPU,\n * cohort-based revenue, and pricing plan impact analysis.\n * \n * @useCases\n * - Calculate ARPU/ARPA per segment\n * - Track cohort-based revenue\n * - Analyze pricing plan impact\n * - Revenue forecasting\n * - Expansion revenue tracking\n * \n * @metrics\n * - ARPU (Average Revenue Per User)\n * - ARPA (Average Revenue Per Account)\n * - Revenue by cohort\n * - Revenue by plan\n * - Expansion revenue\n * - Net Revenue Retention\n * \n * @chartData\n * - Line chart: Revenue over time\n * - Bar chart: Revenue by segment\n * - Waterfall: Revenue movement\n * - Cohort: Revenue retention\n * \n * @example\n * ```typescript\n * const monetization = new Monetization(webId, endpoint, apiKey);\n * \n * // Get ARPU by segment\n * const arpu = await monetization.getARPU({ segment: 'enterprise' });\n * \n * // Track revenue event\n * await monetization.trackRevenue({\n * userId: 'user_123',\n * amount: 99.00,\n * currency: 'USD',\n * type: 'subscription'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData, TimeGranularity, MoneyValue, CurrencyCode } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Revenue event types.\n */\nexport type RevenueType = \n | 'subscription'\n | 'one_time'\n | 'expansion'\n | 'renewal'\n | 'downgrade'\n | 'refund'\n | 'credit';\n\n/**\n * Revenue tracking configuration.\n */\nexport interface RevenueTrackConfig {\n /** User ID */\n userId: string;\n /** Account/company ID (for B2B) */\n accountId?: string;\n /** Revenue amount */\n amount: number;\n /** Currency code */\n currency: CurrencyCode;\n /** Revenue type */\n type: RevenueType;\n /** Associated plan/product */\n planId?: string;\n /** Transaction ID */\n transactionId?: string;\n /** Billing period */\n billingPeriod?: 'monthly' | 'quarterly' | 'annual';\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * ARPU calculation configuration.\n */\nexport interface ARPUConfig {\n /** Date range */\n filter?: DateRangeFilter;\n /** Segment by attribute */\n segment?: string;\n /** User type filter */\n userType?: 'all' | 'paid' | 'free';\n /** Calculation period */\n period?: 'daily' | 'monthly' | 'annual';\n}\n\n/**\n * ARPU result.\n */\nexport interface ARPUResult {\n /** ARPU value */\n arpu: MoneyValue;\n /** Number of users in calculation */\n userCount: number;\n /** Total revenue in period */\n totalRevenue: MoneyValue;\n /** Period of calculation */\n period: string;\n /** Comparison with previous period */\n change?: {\n absolute: MoneyValue;\n percentage: number;\n };\n}\n\n/**\n * Cohort revenue configuration.\n */\nexport interface CohortRevenueConfig {\n /** Cohort identifier or definition */\n cohortId?: string;\n /** Cohort start date */\n cohortDate?: string;\n /** Periods to track */\n periods: number;\n /** Granularity */\n granularity: 'week' | 'month' | 'quarter';\n}\n\n/**\n * Cohort revenue result.\n */\nexport interface CohortRevenueResult {\n cohortId: string;\n cohortDate: string;\n cohortSize: number;\n periods: Array<{\n period: number;\n revenue: MoneyValue;\n arpu: MoneyValue;\n retainedUsers: number;\n retentionRate: number;\n cumulativeRevenue: MoneyValue;\n }>;\n ltvProjection: MoneyValue;\n}\n\n/**\n * Plan analysis configuration.\n */\nexport interface PlanAnalysisConfig {\n /** Date range */\n filter?: DateRangeFilter;\n /** Specific plans to analyze */\n planIds?: string[];\n}\n\n/**\n * Plan analysis result.\n */\nexport interface PlanAnalysis {\n planId: string;\n planName: string;\n activeUsers: number;\n revenue: MoneyValue;\n arpu: MoneyValue;\n churnRate: number;\n upgrades: number;\n downgrades: number;\n growthRate: number;\n}\n\n/**\n * Revenue breakdown configuration.\n */\nexport interface RevenueBreakdownConfig {\n /** Date range */\n filter?: DateRangeFilter;\n /** Breakdown dimension */\n dimension: 'type' | 'plan' | 'segment' | 'country' | 'source';\n}\n\n/**\n * Revenue breakdown result.\n */\nexport interface RevenueBreakdown {\n dimension: string;\n breakdown: Array<{\n value: string;\n revenue: MoneyValue;\n percentage: number;\n userCount: number;\n }>;\n total: MoneyValue;\n}\n\n/**\n * Net revenue retention configuration.\n */\nexport interface NRRConfig {\n /** Date range */\n filter?: DateRangeFilter;\n /** Calculation period */\n period?: 'monthly' | 'quarterly' | 'annual';\n}\n\n/**\n * Net revenue retention result.\n */\nexport interface NRRResult {\n /** Net Revenue Retention rate */\n nrr: number;\n /** Gross Revenue Retention */\n grr: number;\n /** Starting MRR */\n startingMRR: MoneyValue;\n /** Expansion revenue */\n expansion: MoneyValue;\n /** Contraction revenue */\n contraction: MoneyValue;\n /** Churned revenue */\n churned: MoneyValue;\n /** Ending MRR */\n endingMRR: MoneyValue;\n /** Period */\n period: string;\n}\n\n/**\n * Revenue forecast configuration.\n */\nexport interface RevenueForecastConfig {\n /** Periods to forecast */\n periods: number;\n /** Granularity */\n granularity: 'month' | 'quarter';\n /** Include confidence intervals */\n includeConfidence?: boolean;\n}\n\n/**\n * Revenue forecast result.\n */\nexport interface RevenueForecast {\n forecasts: Array<{\n period: string;\n predicted: MoneyValue;\n confidence?: {\n low: MoneyValue;\n high: MoneyValue;\n };\n }>;\n model: string;\n accuracy: number;\n}\n\n/**\n * Monetization analytics result.\n */\nexport interface MonetizationAnalytics {\n totalRevenue: MoneyValue;\n mrr: MoneyValue;\n arr: MoneyValue;\n arpu: MoneyValue;\n nrr: number;\n grr: number;\n expansionRate: number;\n revenueGrowthRate: number;\n paidUserCount: number;\n conversionRate: number;\n revenueByType: RevenueBreakdown;\n trend: TimeSeriesData;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Calculate ARPU from total revenue and user count.\n */\nexport function calculateARPU(\n totalRevenue: number,\n userCount: number,\n currency: CurrencyCode\n): MoneyValue {\n const arpu = userCount > 0 ? totalRevenue / userCount : 0;\n return {\n amount: Math.round(arpu * 100) / 100,\n currency\n };\n}\n\n/**\n * Calculate Net Revenue Retention.\n */\nexport function calculateNRR(\n startingMRR: number,\n expansion: number,\n contraction: number,\n churned: number\n): number {\n if (startingMRR === 0) return 0;\n return Math.round(((startingMRR + expansion - contraction - churned) / startingMRR) * 10000) / 100;\n}\n\n/**\n * Calculate Gross Revenue Retention.\n */\nexport function calculateGRR(\n startingMRR: number,\n contraction: number,\n churned: number\n): number {\n if (startingMRR === 0) return 0;\n return Math.round(((startingMRR - contraction - churned) / startingMRR) * 10000) / 100;\n}\n\n/**\n * Convert monthly to annual revenue.\n */\nexport function monthlyToAnnual(mrr: MoneyValue): MoneyValue {\n return {\n amount: mrr.amount * 12,\n currency: mrr.currency\n };\n}\n\n/**\n * Calculate LTV from ARPU and churn rate.\n */\nexport function calculateLTV(arpu: number, monthlyChurnRate: number, currency: CurrencyCode): MoneyValue {\n if (monthlyChurnRate <= 0) {\n return { amount: arpu * 60, currency }; // Cap at 5 years\n }\n const ltv = arpu / monthlyChurnRate;\n return {\n amount: Math.round(ltv * 100) / 100,\n currency\n };\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Revenue and monetization analytics class.\n */\nexport class Monetization extends FlowGridTransport {\n /**\n * Track revenue event.\n */\n async trackRevenue(config: RevenueTrackConfig): Promise<{ tracked: boolean; revenueId: string }> {\n const { type: revenueType, ...restConfig } = config;\n return await this.initFeature(\"monetization.revenue\", {\n type: \"monetization\",\n revenueType,\n ...restConfig,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track expansion revenue.\n */\n async trackExpansion(\n userId: string,\n fromPlan: string,\n toPlan: string,\n additionalRevenue: MoneyValue\n ): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"monetization.expansion\", {\n type: \"monetization\",\n userId,\n fromPlan,\n toPlan,\n additionalRevenue,\n revenueType: 'expansion',\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track contraction/downgrade.\n */\n async trackContraction(\n userId: string,\n fromPlan: string,\n toPlan: string,\n reducedRevenue: MoneyValue\n ): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"monetization.contraction\", {\n type: \"monetization\",\n userId,\n fromPlan,\n toPlan,\n reducedRevenue,\n revenueType: 'downgrade',\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * @fileoverview Enterprise - Multi-Path Funnels & Micro-Conversions\n * @module features/enterprise/multi-path-funnels\n * \n * @description\n * Track complex user journeys and micro-conversions with support\n * for non-linear funnel analysis and segment-based drop-off.\n * \n * @useCases\n * - Define multi-path funnels\n * - Track micro-conversions\n * - Analyze drop-off by segment\n * - Non-linear journey tracking\n * - Onboarding step analysis\n * \n * @metrics\n * - Path completion rates\n * - Micro-conversion rates\n * - Drop-off by segment\n * - Time between steps\n * - Alternative path analysis\n * \n * @chartData\n * - Sankey diagram: User flow paths\n * - Funnel chart: Multi-path visualization\n * - Heatmap: Drop-off by segment\n * - Timeline: Step progression\n * \n * @example\n * ```typescript\n * const funnels = new MultiPathFunnels(webId, endpoint, apiKey);\n * \n * // Define a multi-path funnel\n * await funnels.defineFunnel({\n * name: 'Onboarding',\n * paths: [\n * { steps: ['signup', 'profile', 'first_action'] },\n * { steps: ['signup', 'skip_profile', 'first_action'] }\n * ]\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Funnel path definition.\n */\nexport interface FunnelPath {\n /** Path identifier */\n pathId?: string;\n /** Path name */\n name?: string;\n /** Ordered list of step events */\n steps: string[];\n /** Whether steps must be in order */\n ordered?: boolean;\n /** Maximum time window between first and last step */\n timeWindowMs?: number;\n}\n\n/**\n * Multi-path funnel definition.\n */\nexport interface MultiPathFunnelDefinition {\n /** Funnel identifier */\n funnelId?: string;\n /** Funnel name */\n name: string;\n /** Funnel description */\n description?: string;\n /** Alternative paths to conversion */\n paths: FunnelPath[];\n /** Micro-conversion definitions */\n microConversions?: MicroConversionDefinition[];\n /** Goal event (final conversion) */\n goalEvent: string;\n}\n\n/**\n * Micro-conversion definition.\n */\nexport interface MicroConversionDefinition {\n /** Micro-conversion identifier */\n id: string;\n /** Display name */\n name: string;\n /** Event that triggers this micro-conversion */\n event: string;\n /** Weight/importance (0-1) */\n weight?: number;\n /** Prerequisite micro-conversions */\n prerequisites?: string[];\n}\n\n/**\n * Funnel step tracking configuration.\n */\nexport interface MultiPathStepConfig {\n /** Funnel ID */\n funnelId: string;\n /** Step/event name */\n step: string;\n /** User ID */\n userId: string;\n /** Session ID */\n sessionId?: string;\n /** Path ID (if known) */\n pathId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Micro-conversion tracking configuration.\n */\nexport interface MicroConversionConfig {\n /** Micro-conversion ID */\n conversionId: string;\n /** User ID */\n userId: string;\n /** Session ID */\n sessionId?: string;\n /** Value associated with conversion */\n value?: number;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Funnel analysis configuration.\n */\nexport interface FunnelAnalysisConfig {\n /** Funnel ID */\n funnelId: string;\n /** Date range */\n filter?: DateRangeFilter;\n /** Segment by attribute */\n segmentBy?: string;\n /** Include path breakdown */\n includePaths?: boolean;\n /** Include micro-conversions */\n includeMicroConversions?: boolean;\n}\n\n/**\n * Path analysis result.\n */\nexport interface PathAnalysis {\n pathId: string;\n pathName: string;\n steps: string[];\n userCount: number;\n completionRate: number;\n avgTimeToComplete: number;\n stepAnalysis: Array<{\n step: string;\n entered: number;\n completed: number;\n dropOffRate: number;\n avgTimeSpent: number;\n }>;\n}\n\n/**\n * Micro-conversion analysis.\n */\nexport interface MicroConversionAnalysis {\n id: string;\n name: string;\n completions: number;\n completionRate: number;\n avgValue: number;\n correlation: number; // Correlation with goal conversion\n}\n\n/**\n * Multi-path funnel analysis result.\n */\nexport interface MultiPathFunnelAnalysis {\n funnelId: string;\n funnelName: string;\n totalUsers: number;\n goalCompletions: number;\n overallConversionRate: number;\n paths: PathAnalysis[];\n microConversions?: MicroConversionAnalysis[];\n topDropOffPoints: Array<{\n step: string;\n dropOffRate: number;\n userCount: number;\n }>;\n avgTimeToConversion: number;\n}\n\n/**\n * Segment drop-off analysis.\n */\nexport interface SegmentDropOffAnalysis {\n funnelId: string;\n segmentAttribute: string;\n segments: Array<{\n segment: string;\n conversionRate: number;\n dropOffByStep: Array<{\n step: string;\n dropOffRate: number;\n }>;\n }>;\n bestPerformingSegment: string;\n worstPerformingSegment: string;\n}\n\n/**\n * User journey configuration.\n */\nexport interface UserJourneyConfig {\n /** User ID */\n userId: string;\n /** Funnel ID */\n funnelId: string;\n /** Date range */\n filter?: DateRangeFilter;\n}\n\n/**\n * User journey result.\n */\nexport interface UserJourney {\n userId: string;\n funnelId: string;\n currentPath: string;\n stepsCompleted: Array<{\n step: string;\n timestamp: string;\n properties?: Record<string, unknown>;\n }>;\n microConversions: Array<{\n id: string;\n timestamp: string;\n }>;\n goalReached: boolean;\n goalReachedAt?: string;\n timeInFunnel: number;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Calculate funnel conversion rate.\n */\nexport function calculateConversionRate(entered: number, completed: number): number {\n if (entered === 0) return 0;\n return Math.round((completed / entered) * 10000) / 100;\n}\n\n/**\n * Calculate drop-off rate between steps.\n */\nexport function calculateDropOffRate(previousStep: number, currentStep: number): number {\n if (previousStep === 0) return 0;\n return Math.round(((previousStep - currentStep) / previousStep) * 10000) / 100;\n}\n\n/**\n * Find the best performing path.\n */\nexport function findBestPath(paths: PathAnalysis[]): PathAnalysis | null {\n if (paths.length === 0) return null;\n return paths.reduce((best, current) => \n current.completionRate > best.completionRate ? current : best\n );\n}\n\n/**\n * Calculate weighted micro-conversion score.\n */\nexport function calculateMicroConversionScore(\n completedConversions: MicroConversionAnalysis[],\n definitions: MicroConversionDefinition[]\n): number {\n let totalWeight = 0;\n let weightedScore = 0;\n\n for (const def of definitions) {\n const weight = def.weight ?? 1;\n totalWeight += weight;\n \n const completed = completedConversions.find(c => c.id === def.id);\n if (completed) {\n weightedScore += weight * completed.completionRate;\n }\n }\n\n return totalWeight > 0 ? Math.round((weightedScore / totalWeight) * 100) / 100 : 0;\n}\n\n/**\n * Generate path ID from steps.\n */\nexport function generatePathId(steps: string[]): string {\n return steps.join('_').toLowerCase().replace(/[^a-z0-9_]/g, '');\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Multi-path funnels and micro-conversions class.\n */\nexport class MultiPathFunnels extends FlowGridTransport {\n /**\n * Define a multi-path funnel.\n */\n async defineFunnel(definition: MultiPathFunnelDefinition): Promise<{ funnelId: string }> {\n const funnelId = definition.funnelId ?? \n definition.name.toLowerCase().replace(/[^a-z0-9]+/g, '_');\n\n const pathsWithIds = definition.paths.map(path => ({\n ...path,\n pathId: path.pathId ?? generatePathId(path.steps)\n }));\n\n return await this.initFeature(\"multi_path_funnels.define\", {\n type: \"multi_path_funnels\",\n funnelId,\n name: definition.name,\n description: definition.description,\n paths: pathsWithIds,\n microConversions: definition.microConversions,\n goalEvent: definition.goalEvent,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Update funnel definition.\n */\n async updateFunnel(\n funnelId: string,\n updates: Partial<MultiPathFunnelDefinition>\n ): Promise<{ updated: boolean }> {\n return await this.initFeature(\"multi_path_funnels.update\", {\n type: \"multi_path_funnels\",\n funnelId,\n ...updates,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Delete funnel.\n */\n async deleteFunnel(funnelId: string): Promise<{ deleted: boolean }> {\n return await this.initFeature(\"multi_path_funnels.delete\", {\n type: \"multi_path_funnels\",\n funnelId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track funnel step.\n */\n async trackStep(config: MultiPathStepConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"multi_path_funnels.track_step\", {\n type: \"multi_path_funnels\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track micro-conversion.\n */\n async trackMicroConversion(config: MicroConversionConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"multi_path_funnels.track_micro_conversion\", {\n type: \"multi_path_funnels\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track goal completion.\n */\n async trackGoal(\n funnelId: string,\n userId: string,\n properties?: Record<string, unknown>\n ): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"multi_path_funnels.track_goal\", {\n type: \"multi_path_funnels\",\n funnelId,\n userId,\n ...properties,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Get funnel analysis.\n */\n async analyzeFunnel(config: FunnelAnalysisConfig): Promise<MultiPathFunnelAnalysis> {\n return await this.initFeature(\"multi_path_funnels.analyze\", {\n type: \"multi_path_funnels\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Get path comparison.\n */\n async comparePaths(\n funnelId: string,\n filter?: DateRangeFilter\n ): Promise<PathAnalysis[]> {\n return await this.initFeature(\"multi_path_funnels.compare_paths\", {\n type: \"multi_path_funnels\",\n funnelId,\n filter,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * List all funnels.\n */\n async listFunnels(): Promise<Array<{\n funnelId: string;\n name: string;\n pathCount: number;\n createdAt: string;\n }>> {\n return await this.initFeature(\"multi_path_funnels.list\", {\n type: \"multi_path_funnels\",\n timestamp: new Date().toISOString()\n });\n }\n}\n","/**\n * @fileoverview Enterprise - Customer Support & Experience Analytics\n * @module features/enterprise/support\n * \n * @description\n * Link support interactions to retention and conversion metrics.\n * Track ticket volume, response times, and satisfaction scores.\n * \n * @useCases\n * - Track support ticket volume\n * - Monitor response and resolution times\n * - Correlate CSAT/NPS with retention\n * - Track feature complaints\n * - Measure support impact on conversion\n * \n * @metrics\n * - Ticket volume\n * - Average response time\n * - Average resolution time\n * - CSAT score\n * - First contact resolution rate\n * \n * @chartData\n * - Line chart: Ticket volume over time\n * - Bar chart: Tickets by category\n * - Distribution: Resolution time\n * - Correlation: Support vs retention\n * \n * @example\n * ```typescript\n * const support = new SupportAnalytics(webId, endpoint, apiKey);\n * \n * // Track support ticket\n * await support.trackTicket({\n * ticketId: 'ticket_123',\n * userId: 'user_456',\n * category: 'billing',\n * priority: 'high'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData, TimeGranularity } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Ticket priority levels.\n */\nexport type TicketPriority = 'low' | 'medium' | 'high' | 'urgent';\n\n/**\n * Ticket status.\n */\nexport type TicketStatus = 'open' | 'pending' | 'in_progress' | 'resolved' | 'closed';\n\n/**\n * Support channel.\n */\nexport type SupportChannel = 'email' | 'chat' | 'phone' | 'social' | 'self_service' | 'other';\n\n/**\n * Ticket creation configuration.\n */\nexport interface TicketConfig {\n /** Ticket ID */\n ticketId: string;\n /** User ID */\n userId: string;\n /** Account/company ID */\n accountId?: string;\n /** Ticket subject */\n subject: string;\n /** Ticket category */\n category: string;\n /** Sub-category */\n subCategory?: string;\n /** Priority level */\n priority: TicketPriority;\n /** Support channel */\n channel: SupportChannel;\n /** Related feature (if any) */\n featureId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Ticket update configuration.\n */\nexport interface TicketUpdateConfig {\n /** Ticket ID */\n ticketId: string;\n /** New status */\n status: TicketStatus;\n /** Assigned agent ID */\n agentId?: string;\n /** Response time (ms) - first response */\n responseTimeMs?: number;\n /** Resolution time (ms) - time to resolve */\n resolutionTimeMs?: number;\n /** Number of interactions */\n interactionCount?: number;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * CSAT tracking configuration.\n */\nexport interface CSATConfig {\n /** Ticket ID */\n ticketId: string;\n /** User ID */\n userId: string;\n /** CSAT score (1-5) */\n score: number;\n /** Feedback comment */\n feedback?: string;\n /** Agent ID */\n agentId?: string;\n}\n\n/**\n * Feature complaint configuration.\n */\nexport interface FeatureComplaintConfig {\n /** User ID */\n userId: string;\n /** Feature ID */\n featureId: string;\n /** Complaint type */\n complaintType: 'bug' | 'usability' | 'missing_feature' | 'performance' | 'other';\n /** Description */\n description?: string;\n /** Severity */\n severity: 'minor' | 'moderate' | 'major' | 'critical';\n /** Associated ticket ID */\n ticketId?: string;\n}\n\n/**\n * Support analytics filter.\n */\nexport interface SupportAnalyticsFilter extends DateRangeFilter {\n /** Filter by category */\n category?: string;\n /** Filter by priority */\n priority?: TicketPriority;\n /** Filter by channel */\n channel?: SupportChannel;\n /** Filter by status */\n status?: TicketStatus;\n}\n\n/**\n * Ticket analytics result.\n */\nexport interface TicketAnalytics {\n /** Total tickets */\n totalTickets: number;\n /** Open tickets */\n openTickets: number;\n /** Resolved tickets */\n resolvedTickets: number;\n /** Average response time (ms) */\n avgResponseTimeMs: number;\n /** Average resolution time (ms) */\n avgResolutionTimeMs: number;\n /** First contact resolution rate */\n fcrRate: number;\n /** Average CSAT score */\n avgCSAT: number;\n /** Tickets by category */\n byCategory: Array<{ category: string; count: number; percentage: number }>;\n /** Tickets by priority */\n byPriority: Array<{ priority: TicketPriority; count: number; percentage: number }>;\n /** Tickets by channel */\n byChannel: Array<{ channel: SupportChannel; count: number; percentage: number }>;\n}\n\n/**\n * Support impact analysis.\n */\nexport interface SupportImpactAnalysis {\n /** Correlation with retention */\n retentionCorrelation: number;\n /** Correlation with churn */\n churnCorrelation: number;\n /** Users with support tickets */\n usersWithTickets: number;\n /** Churn rate for users with tickets */\n ticketUserChurnRate: number;\n /** Churn rate for users without tickets */\n noTicketUserChurnRate: number;\n /** Impact of quick resolution on retention */\n quickResolutionRetentionLift: number;\n}\n\n/**\n * Feature complaint summary.\n */\nexport interface FeatureComplaintSummary {\n /** Feature ID */\n featureId: string;\n /** Feature name */\n featureName?: string;\n /** Total complaints */\n totalComplaints: number;\n /** By complaint type */\n byType: Array<{ type: string; count: number }>;\n /** By severity */\n bySeverity: Array<{ severity: string; count: number }>;\n /** Trend direction */\n trend: 'increasing' | 'stable' | 'decreasing';\n}\n\n/**\n * Agent performance.\n */\nexport interface AgentPerformance {\n agentId: string;\n agentName?: string;\n ticketsHandled: number;\n avgResponseTimeMs: number;\n avgResolutionTimeMs: number;\n avgCSAT: number;\n fcrRate: number;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Calculate first contact resolution rate.\n */\nexport function calculateFCRRate(\n resolvedFirstContact: number,\n totalResolved: number\n): number {\n if (totalResolved === 0) return 0;\n return Math.round((resolvedFirstContact / totalResolved) * 10000) / 100;\n}\n\n/**\n * Calculate average response time.\n */\nexport function calculateAvgResponseTime(\n responseTimes: number[]\n): number {\n if (responseTimes.length === 0) return 0;\n const sum = responseTimes.reduce((a, b) => a + b, 0);\n return Math.round(sum / responseTimes.length);\n}\n\n/**\n * Classify CSAT score.\n */\nexport function classifyCSAT(score: number): 'poor' | 'fair' | 'good' | 'excellent' {\n if (score < 2) return 'poor';\n if (score < 3) return 'fair';\n if (score < 4) return 'good';\n return 'excellent';\n}\n\n/**\n * Format duration in human-readable format.\n */\nexport function formatDuration(ms: number): string {\n if (ms < 60000) return `${Math.round(ms / 1000)}s`;\n if (ms < 3600000) return `${Math.round(ms / 60000)}m`;\n if (ms < 86400000) return `${Math.round(ms / 3600000)}h`;\n return `${Math.round(ms / 86400000)}d`;\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Customer support and experience analytics class.\n */\nexport class SupportAnalytics extends FlowGridTransport {\n /**\n * Track new support ticket.\n */\n async trackTicket(config: TicketConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"support.ticket_created\", {\n type: \"support\",\n ...config,\n status: 'open' as TicketStatus,\n createdAt: new Date().toISOString(),\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Update ticket status.\n */\n async updateTicket(config: TicketUpdateConfig): Promise<{ updated: boolean }> {\n return await this.initFeature(\"support.ticket_updated\", {\n type: \"support\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track ticket response.\n */\n async trackResponse(\n ticketId: string,\n agentId: string,\n responseTimeMs: number\n ): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"support.ticket_response\", {\n type: \"support\",\n ticketId,\n agentId,\n responseTimeMs,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track ticket resolution.\n */\n async trackResolution(\n ticketId: string,\n resolutionTimeMs: number,\n interactionCount: number\n ): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"support.ticket_resolved\", {\n type: \"support\",\n ticketId,\n resolutionTimeMs,\n interactionCount,\n firstContactResolution: interactionCount === 1,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track CSAT score.\n */\n async trackCSAT(config: CSATConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"support.csat\", {\n type: \"support\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track feature complaint.\n */\n async trackFeatureComplaint(config: FeatureComplaintConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"support.feature_complaint\", {\n type: \"support\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * @fileoverview Enterprise - Marketing & Acquisition Analytics\n * @module features/enterprise/acquisition\n * \n * @description\n * Deep attribution and acquisition insights including CAC breakdown,\n * trial-to-paid funnel tracking, and campaign performance by cohort.\n * \n * @useCases\n * - Track customer acquisition cost by channel\n * - Monitor trial → paid → upgrade funnel\n * - Analyze campaign performance\n * - Multi-touch attribution\n * - Marketing ROI calculation\n * \n * @metrics\n * - Customer Acquisition Cost (CAC)\n * - Trial conversion rate\n * - Paid conversion rate\n * - Campaign ROI\n * - Channel effectiveness\n * \n * @chartData\n * - Bar chart: CAC by channel\n * - Funnel: Trial to paid conversion\n * - Line chart: Campaign performance\n * - Pie chart: Acquisition source mix\n * \n * @example\n * ```typescript\n * const acquisition = new AcquisitionAnalytics(webId, endpoint, apiKey);\n * \n * // Track acquisition\n * await acquisition.trackAcquisition({\n * userId: 'user_123',\n * source: 'google_ads',\n * campaign: 'summer_2026'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData, MoneyValue, CurrencyCode } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Acquisition source types.\n */\nexport type AcquisitionSource = \n | 'organic'\n | 'paid_search'\n | 'paid_social'\n | 'organic_social'\n | 'email'\n | 'referral'\n | 'affiliate'\n | 'direct'\n | 'content'\n | 'other';\n\n/**\n * User lifecycle stage.\n */\nexport type LifecycleStage = \n | 'visitor'\n | 'lead'\n | 'trial'\n | 'paid'\n | 'churned'\n | 'resurrected';\n\n/**\n * Acquisition tracking configuration.\n */\nexport interface AcquisitionConfig {\n /** User ID */\n userId: string;\n /** Acquisition source */\n source: AcquisitionSource;\n /** Campaign name/ID */\n campaign?: string;\n /** Medium */\n medium?: string;\n /** Channel */\n channel?: string;\n /** Referring URL */\n referrer?: string;\n /** Landing page */\n landingPage?: string;\n /** UTM parameters */\n utmParams?: {\n source?: string;\n medium?: string;\n campaign?: string;\n term?: string;\n content?: string;\n };\n /** Acquisition cost (if known) */\n cost?: MoneyValue;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Campaign definition.\n */\nexport interface CampaignDefinition {\n /** Campaign ID */\n campaignId: string;\n /** Campaign name */\n name: string;\n /** Description */\n description?: string;\n /** Start date */\n startDate: string;\n /** End date */\n endDate?: string;\n /** Budget */\n budget: MoneyValue;\n /** Target acquisition count */\n targetAcquisitions?: number;\n /** Channel */\n channel: AcquisitionSource;\n /** Tags */\n tags?: string[];\n}\n\n/**\n * Campaign spend tracking.\n */\nexport interface CampaignSpendConfig {\n /** Campaign ID */\n campaignId: string;\n /** Spend amount */\n amount: MoneyValue;\n /** Spend date */\n date: string;\n /** Impressions */\n impressions?: number;\n /** Clicks */\n clicks?: number;\n}\n\n/**\n * Lifecycle transition configuration.\n */\nexport interface LifecycleTransitionConfig {\n /** User ID */\n userId: string;\n /** Previous stage */\n fromStage: LifecycleStage;\n /** New stage */\n toStage: LifecycleStage;\n /** Revenue associated (if applicable) */\n revenue?: MoneyValue;\n}\n\n/**\n * CAC configuration.\n */\nexport interface CACConfig {\n /** Date range */\n filter?: DateRangeFilter;\n /** Breakdown dimension */\n breakdown?: 'channel' | 'campaign' | 'source';\n /** Include only paid channels */\n paidOnly?: boolean;\n}\n\n/**\n * CAC result.\n */\nexport interface CACResult {\n /** Overall CAC */\n cac: MoneyValue;\n /** Total spend */\n totalSpend: MoneyValue;\n /** Total acquisitions */\n totalAcquisitions: number;\n /** Breakdown (if requested) */\n breakdown?: Array<{\n dimension: string;\n cac: MoneyValue;\n spend: MoneyValue;\n acquisitions: number;\n }>;\n}\n\n/**\n * Trial funnel configuration.\n */\nexport interface TrialFunnelConfig {\n /** Date range */\n filter?: DateRangeFilter;\n /** Segment by attribute */\n segmentBy?: string;\n}\n\n/**\n * Trial funnel result.\n */\nexport interface TrialFunnelResult {\n /** Visitors */\n visitors: number;\n /** Signups */\n signups: number;\n /** Trial starts */\n trialStarts: number;\n /** Trial to paid conversions */\n trialToPaid: number;\n /** Paid upgrades */\n upgrades: number;\n /** Conversion rates */\n rates: {\n visitorToSignup: number;\n signupToTrial: number;\n trialToPaid: number;\n paidToUpgrade: number;\n overallConversion: number;\n };\n /** Average time in trial */\n avgTrialDays: number;\n}\n\n/**\n * Campaign performance result.\n */\nexport interface CampaignPerformance {\n campaignId: string;\n name: string;\n spend: MoneyValue;\n impressions: number;\n clicks: number;\n acquisitions: number;\n revenue: MoneyValue;\n metrics: {\n ctr: number; // Click-through rate\n cpc: MoneyValue; // Cost per click\n cpa: MoneyValue; // Cost per acquisition\n roas: number; // Return on ad spend\n roi: number; // Return on investment\n };\n trend: 'improving' | 'stable' | 'declining';\n}\n\n/**\n * Attribution model types.\n */\nexport type AttributionModel = \n | 'first_touch'\n | 'last_touch'\n | 'linear'\n | 'time_decay'\n | 'position_based';\n\n/**\n * Attribution analysis configuration.\n */\nexport interface AttributionAnalysisConfig {\n /** Attribution model */\n model: AttributionModel;\n /** Date range */\n filter?: DateRangeFilter;\n /** Conversion event */\n conversionEvent?: string;\n}\n\n/**\n * Attribution result.\n */\nexport interface AttributionResult {\n model: AttributionModel;\n channels: Array<{\n channel: string;\n conversions: number;\n revenue: MoneyValue;\n contribution: number;\n }>;\n touchpointAnalysis: {\n avgTouchpoints: number;\n avgDaysToConvert: number;\n topPaths: Array<{\n path: string[];\n count: number;\n conversionRate: number;\n }>;\n };\n}\n\n/**\n * Acquisition analytics result.\n */\nexport interface AcquisitionAnalyticType {\n totalAcquisitions: number;\n cac: MoneyValue;\n ltv: MoneyValue;\n ltvCacRatio: number;\n topChannels: Array<{\n channel: AcquisitionSource;\n acquisitions: number;\n percentage: number;\n cac: MoneyValue;\n }>;\n trialConversionRate: number;\n paidConversionRate: number;\n trend: TimeSeriesData;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Calculate CAC.\n */\nexport function calculateCAC(\n totalSpend: number,\n totalAcquisitions: number,\n currency: CurrencyCode\n): MoneyValue {\n if (totalAcquisitions === 0) {\n return { amount: 0, currency };\n }\n return {\n amount: Math.round((totalSpend / totalAcquisitions) * 100) / 100,\n currency\n };\n}\n\n/**\n * Calculate ROAS (Return on Ad Spend).\n */\nexport function calculateROAS(revenue: number, spend: number): number {\n if (spend === 0) return 0;\n return Math.round((revenue / spend) * 100) / 100;\n}\n\n/**\n * Calculate LTV:CAC ratio.\n */\nexport function calculateLTVCACRatio(ltv: number, cac: number): number {\n if (cac === 0) return 0;\n return Math.round((ltv / cac) * 100) / 100;\n}\n\n/**\n * Parse UTM parameters from URL.\n */\nexport function parseUTMParams(url: string): Record<string, string> {\n const params: Record<string, string> = {};\n try {\n const urlObj = new URL(url);\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];\n for (const key of utmKeys) {\n const value = urlObj.searchParams.get(key);\n if (value) {\n params[key.replace('utm_', '')] = value;\n }\n }\n } catch {\n // Invalid URL, return empty object\n }\n return params;\n}\n\n/**\n * Classify acquisition source from UTM parameters.\n */\nexport function classifySource(utmSource?: string, utmMedium?: string): AcquisitionSource {\n if (!utmSource && !utmMedium) return 'direct';\n \n const source = utmSource?.toLowerCase() ?? '';\n const medium = utmMedium?.toLowerCase() ?? '';\n\n if (medium.includes('cpc') || medium.includes('paid')) {\n if (source.includes('facebook') || source.includes('instagram') || source.includes('linkedin')) {\n return 'paid_social';\n }\n return 'paid_search';\n }\n\n if (source.includes('facebook') || source.includes('twitter') || source.includes('linkedin')) {\n return 'organic_social';\n }\n\n if (medium === 'email') return 'email';\n if (medium === 'referral') return 'referral';\n if (medium === 'affiliate') return 'affiliate';\n\n return 'organic';\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Marketing and acquisition analytics class.\n */\nexport class AcquisitionAnalytics extends FlowGridTransport {\n /**\n * Track user acquisition.\n */\n async trackAcquisition(config: AcquisitionConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"acquisition.acquired\", {\n type: \"acquisition\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track lifecycle transition.\n */\n async trackLifecycleTransition(\n config: LifecycleTransitionConfig\n ): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"acquisition.lifecycle_transition\", {\n type: \"acquisition\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Create campaign.\n */\n async createCampaign(definition: CampaignDefinition): Promise<{ created: boolean }> {\n return await this.initFeature(\"acquisition.create_campaign\", {\n type: \"acquisition\",\n ...definition,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track campaign spend.\n */\n async trackCampaignSpend(config: CampaignSpendConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"acquisition.campaign_spend\", {\n type: \"acquisition\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * @fileoverview Enterprise - Behavioral Analytics & Path Analysis\n * @module features/enterprise/paths\n * \n * @description\n * Track full user navigation and feature usage sequences.\n * Identify common paths, dead-ends, and UX friction points.\n * \n * @useCases\n * - Sequence analysis of feature usage\n * - Dead-end screen detection\n * - Most common path identification\n * - User journey mapping\n * - UX friction detection\n * \n * @metrics\n * - Path frequency\n * - Path completion rate\n * - Dead-end rate\n * - Average path length\n * - Time per path\n * \n * @chartData\n * - Sankey diagram: User flow\n * - Tree map: Path distribution\n * - Heatmap: Screen transitions\n * - Timeline: User journeys\n * \n * @example\n * ```typescript\n * const paths = new PathAnalytics(webId, endpoint, apiKey);\n * \n * // Track screen/page transition\n * await paths.trackTransition({\n * userId: 'user_123',\n * fromScreen: 'dashboard',\n * toScreen: 'settings'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Screen/page transition configuration.\n */\nexport interface TransitionConfig {\n /** User ID */\n userId: string;\n /** Session ID */\n sessionId?: string;\n /** Source screen/page */\n fromScreen: string;\n /** Destination screen/page */\n toScreen: string;\n /** Time spent on source screen (ms) */\n timeSpentMs?: number;\n /** Trigger action */\n trigger?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Feature sequence configuration.\n */\nexport interface FeatureSequenceConfig {\n /** User ID */\n userId: string;\n /** Session ID */\n sessionId?: string;\n /** Feature/action name */\n feature: string;\n /** Sequence order in session */\n order: number;\n /** Time spent (ms) */\n timeSpentMs?: number;\n /** Whether action was successful */\n successful?: boolean;\n}\n\n/**\n * Path definition.\n */\nexport interface PathDefinition {\n /** Path identifier */\n pathId?: string;\n /** Path name */\n name: string;\n /** Description */\n description?: string;\n /** Ordered list of screens/steps */\n screens: string[];\n /** Goal screen (optional) */\n goal?: string;\n /** Tags */\n tags?: string[];\n}\n\n/**\n * Path analysis configuration.\n */\nexport interface PathAnalysisConfig {\n /** Date range */\n filter?: DateRangeFilter;\n /** Starting screen */\n startScreen?: string;\n /** Ending screen */\n endScreen?: string;\n /** Minimum path occurrences */\n minOccurrences?: number;\n /** Maximum path length */\n maxLength?: number;\n}\n\n/**\n * Path analytics result.\n */\nexport interface PathResult {\n /** Path screens */\n path: string[];\n /** Number of users who took this path */\n userCount: number;\n /** Percentage of total users */\n percentage: number;\n /** Average time to complete path (ms) */\n avgTimeMs: number;\n /** Completion rate (if goal defined) */\n completionRate?: number;\n /** Drop-off at each step */\n dropOffByStep?: Array<{\n step: string;\n dropOffRate: number;\n }>;\n}\n\n/**\n * Dead-end screen.\n */\nexport interface DeadEndScreen {\n /** Screen name */\n screen: string;\n /** Exit rate (users who leave from this screen) */\n exitRate: number;\n /** User count */\n userCount: number;\n /** Average time before exit (ms) */\n avgTimeBeforeExitMs: number;\n /** Previous screens (where users came from) */\n previousScreens: Array<{ screen: string; count: number }>;\n /** Is this a dead-end (high exit, not intended end point) */\n isDeadEnd: boolean;\n}\n\n/**\n * Screen transition matrix.\n */\nexport interface TransitionMatrix {\n /** All screens */\n screens: string[];\n /** Transition probabilities (screens.length x screens.length) */\n matrix: number[][];\n /** Total transitions */\n totalTransitions: number;\n}\n\n/**\n * User journey configuration.\n */\nexport interface UserJourneyConfig {\n /** User ID */\n userId: string;\n /** Session ID (optional, get all sessions if not provided) */\n sessionId?: string;\n /** Date range */\n filter?: DateRangeFilter;\n}\n\n/**\n * User journey result.\n */\nexport interface UserJourney {\n userId: string;\n sessions: Array<{\n sessionId: string;\n startTime: string;\n endTime: string;\n path: Array<{\n screen: string;\n timestamp: string;\n timeSpentMs: number;\n actions?: string[];\n }>;\n totalDurationMs: number;\n screenCount: number;\n }>;\n}\n\n/**\n * Friction point.\n */\nexport interface FrictionPoint {\n /** Screen or step */\n location: string;\n /** Friction type */\n type: 'high_exit' | 'long_dwell' | 'rage_clicks' | 'back_navigation' | 'error';\n /** Severity score (0-100) */\n severity: number;\n /** Affected users */\n affectedUsers: number;\n /** Suggested improvement */\n suggestion?: string;\n}\n\n/**\n * Path comparison.\n */\nexport interface PathComparison {\n /** Paths being compared */\n paths: PathResult[];\n /** Statistical significance */\n significant: boolean;\n /** Winner (if significant) */\n winner?: string;\n /** Metrics comparison */\n comparison: {\n metric: string;\n values: Record<string, number>;\n difference: number;\n }[];\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Convert path array to string identifier.\n */\nexport function pathToString(path: string[]): string {\n return path.join(' → ');\n}\n\n/**\n * Convert string identifier to path array.\n */\nexport function stringToPath(pathString: string): string[] {\n return pathString.split(' → ').map(s => s.trim());\n}\n\n/**\n * Calculate exit rate.\n */\nexport function calculateExitRate(exits: number, entries: number): number {\n if (entries === 0) return 0;\n return Math.round((exits / entries) * 10000) / 100;\n}\n\n/**\n * Identify if a screen is a dead-end.\n */\nexport function isDeadEnd(\n exitRate: number,\n isIntendedEndPoint: boolean,\n threshold: number = 50\n): boolean {\n return exitRate > threshold && !isIntendedEndPoint;\n}\n\n/**\n * Calculate path similarity (Jaccard index).\n */\nexport function calculatePathSimilarity(path1: string[], path2: string[]): number {\n const set1 = new Set(path1);\n const set2 = new Set(path2);\n const intersection = new Set([...set1].filter(x => set2.has(x)));\n const union = new Set([...set1, ...set2]);\n return intersection.size / union.size;\n}\n\n/**\n * Find common sub-paths.\n */\nexport function findCommonSubPaths(\n paths: string[][],\n minLength: number = 2\n): Array<{ subPath: string[]; count: number }> {\n const subPathCounts = new Map<string, number>();\n\n for (const path of paths) {\n for (let i = 0; i <= path.length - minLength; i++) {\n for (let j = i + minLength; j <= path.length; j++) {\n const subPath = path.slice(i, j);\n const key = pathToString(subPath);\n subPathCounts.set(key, (subPathCounts.get(key) ?? 0) + 1);\n }\n }\n }\n\n return Array.from(subPathCounts.entries())\n .filter(([, count]) => count > 1)\n .map(([key, count]) => ({ subPath: stringToPath(key), count }))\n .sort((a, b) => b.count - a.count);\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Behavioral analytics and path analysis class.\n */\nexport class PathAnalytics extends FlowGridTransport {\n /**\n * Track screen/page transition.\n */\n async trackTransition(config: TransitionConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"paths.transition\", {\n type: \"paths\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track feature sequence.\n */\n async trackFeatureSequence(config: FeatureSequenceConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"paths.feature_sequence\", {\n type: \"paths\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Define a path for tracking.\n */\n async definePath(definition: PathDefinition): Promise<{ pathId: string }> {\n return await this.initFeature(\"paths.define_path\", {\n type: \"paths\",\n ...definition,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Compare paths.\n */\n async comparePaths(\n paths: string[][],\n filter?: DateRangeFilter\n ): Promise<PathComparison> {\n return await this.initFeature(\"paths.compare_paths\", {\n type: \"paths\",\n paths,\n filter,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * @fileoverview Enterprise - Alerts & Anomaly Detection\n * @module features/enterprise/alerts\n * \n * @description\n * Proactively monitor anomalies in key metrics and trigger alerts.\n * Detect activation drops, error spikes, and custom threshold breaches.\n * \n * @useCases\n * - Monitor for activation drops\n * - Detect error/churn spikes\n * - Set custom alert rules\n * - Threshold monitoring\n * - Real-time anomaly detection\n * \n * @metrics\n * - Alert frequency\n * - Time to detection\n * - False positive rate\n * - Alert resolution time\n * - Metric anomaly score\n * \n * @chartData\n * - Line chart: Metric with anomaly markers\n * - Timeline: Alert history\n * - Bar chart: Alerts by type\n * - Dashboard: Alert status\n * \n * @example\n * ```typescript\n * const alerts = new AlertsAnalytics(webId, endpoint, apiKey);\n * \n * // Create an alert rule\n * await alerts.createAlert({\n * name: 'Activation Drop',\n * metric: 'activation_rate',\n * condition: 'drops_below',\n * threshold: 50,\n * severity: 'high'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData, TimeGranularity } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Alert condition types.\n */\nexport type AlertCondition = \n | 'exceeds'\n | 'drops_below'\n | 'changes_by'\n | 'anomaly_detected'\n | 'no_data';\n\n/**\n * Alert severity levels.\n */\nexport type AlertSeverity = 'info' | 'warning' | 'high' | 'critical';\n\n/**\n * Alert status.\n */\nexport type AlertStatus = 'active' | 'acknowledged' | 'resolved' | 'muted';\n\n/**\n * Notification channel.\n */\nexport type NotificationChannel = 'email' | 'slack' | 'webhook' | 'pagerduty' | 'sms';\n\n/**\n * Alert rule definition.\n */\nexport interface AlertRuleDefinition {\n /** Alert ID */\n alertId?: string;\n /** Alert name */\n name: string;\n /** Description */\n description?: string;\n /** Metric to monitor */\n metric: string;\n /** Condition type */\n condition: AlertCondition;\n /** Threshold value */\n threshold: number;\n /** Change percentage (for changes_by condition) */\n changePercent?: number;\n /** Comparison window */\n window?: {\n value: number;\n unit: 'minutes' | 'hours' | 'days';\n };\n /** Alert severity */\n severity: AlertSeverity;\n /** Notification channels */\n channels: NotificationChannel[];\n /** Notification recipients */\n recipients?: string[];\n /** Custom filters */\n filters?: Record<string, unknown>;\n /** Is alert enabled */\n enabled?: boolean;\n /** Cooldown period (minutes) */\n cooldownMinutes?: number;\n /** Tags */\n tags?: string[];\n}\n\n/**\n * Alert instance (triggered alert).\n */\nexport interface AlertInstance {\n /** Instance ID */\n instanceId: string;\n /** Alert rule ID */\n alertId: string;\n /** Alert name */\n alertName: string;\n /** Triggered at */\n triggeredAt: string;\n /** Current value that triggered alert */\n currentValue: number;\n /** Threshold value */\n thresholdValue: number;\n /** Severity */\n severity: AlertSeverity;\n /** Status */\n status: AlertStatus;\n /** Acknowledged by */\n acknowledgedBy?: string;\n /** Acknowledged at */\n acknowledgedAt?: string;\n /** Resolved at */\n resolvedAt?: string;\n /** Resolution notes */\n resolutionNotes?: string;\n}\n\n/**\n * Anomaly detection configuration.\n */\nexport interface AnomalyDetectionConfig {\n /** Metric to analyze */\n metric: string;\n /** Lookback period */\n lookbackDays: number;\n /** Sensitivity (0-1, higher = more sensitive) */\n sensitivity?: number;\n /** Detection method */\n method?: 'statistical' | 'ml' | 'hybrid';\n}\n\n/**\n * Detected anomaly.\n */\nexport interface Anomaly {\n /** Anomaly ID */\n anomalyId: string;\n /** Metric */\n metric: string;\n /** Detected at */\n detectedAt: string;\n /** Expected value */\n expectedValue: number;\n /** Actual value */\n actualValue: number;\n /** Deviation percentage */\n deviationPercent: number;\n /** Anomaly score (0-1) */\n anomalyScore: number;\n /** Direction */\n direction: 'up' | 'down';\n /** Severity */\n severity: AlertSeverity;\n /** Is confirmed anomaly */\n isConfirmed: boolean;\n}\n\n/**\n * Alert notification configuration.\n */\nexport interface NotificationConfig {\n /** Channel */\n channel: NotificationChannel;\n /** Channel-specific config */\n config: {\n /** Email addresses (for email channel) */\n emails?: string[];\n /** Slack webhook URL (for slack channel) */\n slackWebhook?: string;\n /** Webhook URL (for webhook channel) */\n webhookUrl?: string;\n /** PagerDuty routing key */\n pagerDutyKey?: string;\n /** Phone numbers (for SMS) */\n phoneNumbers?: string[];\n };\n}\n\n/**\n * Alert analytics filter.\n */\nexport interface AlertAnalyticsFilter extends DateRangeFilter {\n /** Filter by severity */\n severity?: AlertSeverity;\n /** Filter by status */\n status?: AlertStatus;\n /** Filter by metric */\n metric?: string;\n}\n\n/**\n * Alert analytics result.\n */\nexport interface AlertAnalytics {\n /** Total alerts triggered */\n totalAlerts: number;\n /** By severity */\n bySeverity: Record<AlertSeverity, number>;\n /** By status */\n byStatus: Record<AlertStatus, number>;\n /** Average time to acknowledge (ms) */\n avgTimeToAcknowledgeMs: number;\n /** Average time to resolve (ms) */\n avgTimeToResolveMs: number;\n /** Top triggered alerts */\n topAlerts: Array<{\n alertId: string;\n name: string;\n count: number;\n }>;\n /** Alert trend */\n trend: TimeSeriesData;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Calculate standard deviation.\n */\nexport function calculateStdDev(values: number[]): number {\n if (values.length === 0) return 0;\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\n const squareDiffs = values.map(value => Math.pow(value - mean, 2));\n const avgSquareDiff = squareDiffs.reduce((a, b) => a + b, 0) / squareDiffs.length;\n return Math.sqrt(avgSquareDiff);\n}\n\n/**\n * Calculate Z-score for anomaly detection.\n */\nexport function calculateZScore(value: number, mean: number, stdDev: number): number {\n if (stdDev === 0) return 0;\n return (value - mean) / stdDev;\n}\n\n/**\n * Determine if value is anomalous based on Z-score.\n */\nexport function isAnomaly(\n zScore: number,\n sensitivity: number = 0.5\n): boolean {\n // Higher sensitivity = lower threshold for anomaly detection\n const threshold = 4 - (sensitivity * 2); // Ranges from 2 to 4\n return Math.abs(zScore) > threshold;\n}\n\n/**\n * Calculate anomaly score (0-1).\n */\nexport function calculateAnomalyScore(zScore: number): number {\n // Normalize Z-score to 0-1 range\n const absZ = Math.abs(zScore);\n if (absZ <= 2) return absZ / 10;\n if (absZ <= 3) return 0.2 + (absZ - 2) * 0.3;\n if (absZ <= 4) return 0.5 + (absZ - 3) * 0.3;\n return Math.min(0.8 + (absZ - 4) * 0.1, 1);\n}\n\n/**\n * Classify severity from anomaly score.\n */\nexport function classifySeverity(anomalyScore: number): AlertSeverity {\n if (anomalyScore < 0.25) return 'info';\n if (anomalyScore < 0.5) return 'warning';\n if (anomalyScore < 0.75) return 'high';\n return 'critical';\n}\n\n/**\n * Check if alert condition is met.\n */\nexport function checkAlertCondition(\n currentValue: number,\n condition: AlertCondition,\n threshold: number,\n previousValue?: number,\n changePercent?: number\n): boolean {\n switch (condition) {\n case 'exceeds':\n return currentValue > threshold;\n case 'drops_below':\n return currentValue < threshold;\n case 'changes_by':\n if (previousValue === undefined || changePercent === undefined) return false;\n const change = Math.abs((currentValue - previousValue) / previousValue) * 100;\n return change >= changePercent;\n case 'no_data':\n return currentValue === 0 || currentValue === null;\n default:\n return false;\n }\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Alerts and anomaly detection class.\n */\nexport class AlertsAnalytics extends FlowGridTransport {\n /**\n * Create an alert rule.\n */\n async createAlert(definition: AlertRuleDefinition): Promise<{ alertId: string }> {\n return await this.initFeature(\"alerts.create\", {\n type: \"alerts\",\n ...definition,\n alertId: definition.alertId ?? \n definition.name.toLowerCase().replace(/[^a-z0-9]+/g, '_'),\n enabled: definition.enabled ?? true,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Update an alert rule.\n */\n async updateAlert(\n alertId: string,\n updates: Partial<AlertRuleDefinition>\n ): Promise<{ updated: boolean }> {\n return await this.initFeature(\"alerts.update\", {\n type: \"alerts\",\n alertId,\n ...updates,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Delete an alert rule.\n */\n async deleteAlert(alertId: string): Promise<{ deleted: boolean }> {\n return await this.initFeature(\"alerts.delete\", {\n type: \"alerts\",\n alertId,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Enable/disable an alert.\n */\n async toggleAlert(alertId: string, enabled: boolean): Promise<{ updated: boolean }> {\n return await this.initFeature(\"alerts.toggle\", {\n type: \"alerts\",\n alertId,\n enabled,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * List all alert rules.\n */\n async listAlerts(\n enabled?: boolean\n ): Promise<Array<AlertRuleDefinition & { alertId: string }>> {\n return await this.initFeature(\"alerts.list\", {\n type: \"alerts\",\n enabled,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Acknowledge an alert.\n */\n async acknowledgeAlert(\n instanceId: string,\n acknowledgedBy: string\n ): Promise<{ acknowledged: boolean }> {\n return await this.initFeature(\"alerts.acknowledge\", {\n type: \"alerts\",\n instanceId,\n acknowledgedBy,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Resolve an alert.\n */\n async resolveAlert(\n instanceId: string,\n notes?: string\n ): Promise<{ resolved: boolean }> {\n return await this.initFeature(\"alerts.resolve\", {\n type: \"alerts\",\n instanceId,\n notes,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Mute an alert temporarily.\n */\n async muteAlert(alertId: string, durationMinutes: number): Promise<{ muted: boolean }> {\n return await this.initFeature(\"alerts.mute\", {\n type: \"alerts\",\n alertId,\n durationMinutes,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Run anomaly detection.\n */\n async detectAnomalies(config: AnomalyDetectionConfig): Promise<Anomaly[]> {\n return await this.initFeature(\"alerts.detect_anomalies\", {\n type: \"alerts\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Configure notification channel.\n */\n async configureNotification(config: NotificationConfig): Promise<{ configured: boolean }> {\n return await this.initFeature(\"alerts.configure_notification\", {\n type: \"alerts\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Test notification channel.\n */\n async testNotification(channel: NotificationChannel): Promise<{ success: boolean }> {\n return await this.initFeature(\"alerts.test_notification\", {\n type: \"alerts\",\n channel,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * @fileoverview Enterprise - Security & Compliance Analytics\n * @module features/enterprise/security\n * \n * @description\n * Track activity for security, privacy, and regulatory compliance.\n * Monitor login attempts, role changes, and compliance events.\n * \n * @useCases\n * - Track failed login attempts\n * - Monitor role/permission changes\n * - GDPR/CCPA compliance events\n * - Audit logging\n * - Security anomaly detection\n * \n * @metrics\n * - Failed login rate\n * - Suspicious activity count\n * - Role change frequency\n * - Data access patterns\n * - Compliance event count\n * \n * @chartData\n * - Line chart: Security events over time\n * - Bar chart: Events by type\n * - Table: Audit log\n * - Heatmap: Access patterns\n * \n * @example\n * ```typescript\n * const security = new SecurityAnalytics(webId, endpoint, apiKey);\n * \n * // Track login attempt\n * await security.trackLoginAttempt({\n * userId: 'user_123',\n * success: false,\n * reason: 'invalid_password'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Security event types.\n */\nexport type SecurityEventType = \n | 'login_attempt'\n | 'login_success'\n | 'login_failure'\n | 'logout'\n | 'password_change'\n | 'password_reset'\n | 'mfa_enabled'\n | 'mfa_disabled'\n | 'role_change'\n | 'permission_change'\n | 'data_access'\n | 'data_export'\n | 'data_deletion'\n | 'api_key_created'\n | 'api_key_revoked'\n | 'suspicious_activity';\n\n/**\n * Compliance event types.\n */\nexport type ComplianceEventType = \n | 'consent_given'\n | 'consent_withdrawn'\n | 'data_access_request'\n | 'data_deletion_request'\n | 'data_portability_request'\n | 'privacy_policy_update'\n | 'opt_out'\n | 'opt_in';\n\n/**\n * Login attempt configuration.\n */\nexport interface LoginAttemptConfig {\n /** User ID or email */\n userId: string;\n /** Whether login was successful */\n success: boolean;\n /** Failure reason (if failed) */\n reason?: string;\n /** IP address */\n ipAddress?: string;\n /** User agent */\n userAgent?: string;\n /** Device info */\n device?: string;\n /** Location */\n location?: {\n country?: string;\n city?: string;\n };\n /** MFA used */\n mfaUsed?: boolean;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Role change configuration.\n */\nexport interface RoleChangeConfig {\n /** User ID being changed */\n userId: string;\n /** Who made the change */\n changedBy: string;\n /** Previous role */\n previousRole: string;\n /** New role */\n newRole: string;\n /** Reason for change */\n reason?: string;\n}\n\n/**\n * Permission change configuration.\n */\nexport interface PermissionChangeConfig {\n /** User ID being changed */\n userId: string;\n /** Who made the change */\n changedBy: string;\n /** Permission being changed */\n permission: string;\n /** Action */\n action: 'granted' | 'revoked';\n /** Resource scope */\n resourceScope?: string;\n}\n\n/**\n * Data access configuration.\n */\nexport interface DataAccessConfig {\n /** User ID accessing data */\n userId: string;\n /** Resource type */\n resourceType: string;\n /** Resource ID */\n resourceId?: string;\n /** Access type */\n accessType: 'read' | 'write' | 'delete' | 'export';\n /** IP address */\n ipAddress?: string;\n /** Query/filter used */\n query?: Record<string, unknown>;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Compliance event configuration.\n */\nexport interface ComplianceEventConfig {\n /** User ID */\n userId: string;\n /** Event type */\n eventType: ComplianceEventType;\n /** Regulation */\n regulation?: 'GDPR' | 'CCPA' | 'HIPAA' | 'SOC2' | 'other';\n /** Details */\n details?: Record<string, unknown>;\n /** Consent scope (for consent events) */\n consentScope?: string[];\n /** Request ID (for data requests) */\n requestId?: string;\n /** Custom properties */\n properties?: Record<string, unknown>;\n}\n\n/**\n * Audit log entry.\n */\nexport interface AuditLogEntry {\n /** Entry ID */\n entryId: string;\n /** Timestamp */\n timestamp: string;\n /** Event type */\n eventType: SecurityEventType | ComplianceEventType;\n /** Actor (who performed the action) */\n actor: {\n userId: string;\n userEmail?: string;\n ipAddress?: string;\n };\n /** Target (what was affected) */\n target?: {\n type: string;\n id: string;\n name?: string;\n };\n /** Action details */\n details: Record<string, unknown>;\n /** Severity */\n severity: 'low' | 'medium' | 'high' | 'critical';\n /** Was action successful */\n success: boolean;\n}\n\n/**\n * Security analytics filter.\n */\nexport interface SecurityAnalyticsFilter extends DateRangeFilter {\n /** Event type filter */\n eventType?: SecurityEventType | SecurityEventType[];\n /** User ID filter */\n userId?: string;\n /** Severity filter */\n severity?: 'low' | 'medium' | 'high' | 'critical';\n /** Success filter */\n success?: boolean;\n}\n\n/**\n * Security risk assessment.\n */\nexport interface SecurityRiskAssessment {\n /** User ID */\n userId: string;\n /** Risk score (0-100) */\n riskScore: number;\n /** Risk level */\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n /** Risk factors */\n factors: Array<{\n factor: string;\n contribution: number;\n details: string;\n }>;\n /** Last assessment date */\n assessedAt: string;\n /** Recommended actions */\n recommendations: string[];\n}\n\n/**\n * Security analytics result.\n */\nexport interface SecurityAnalyticsResult {\n /** Total security events */\n totalEvents: number;\n /** Failed login count */\n failedLogins: number;\n /** Failed login rate */\n failedLoginRate: number;\n /** Suspicious activity count */\n suspiciousActivityCount: number;\n /** Role changes */\n roleChanges: number;\n /** Data access events */\n dataAccessEvents: number;\n /** By event type */\n byEventType: Array<{ type: string; count: number }>;\n /** High risk users */\n highRiskUsers: number;\n /** Trend */\n trend: TimeSeriesData;\n}\n\n/**\n * Compliance report.\n */\nexport interface ComplianceReport {\n /** Report period */\n period: DateRangeFilter;\n /** Regulation */\n regulation: string;\n /** Consent stats */\n consentStats: {\n totalConsents: number;\n activeConsents: number;\n withdrawals: number;\n };\n /** Data requests */\n dataRequests: {\n accessRequests: number;\n deletionRequests: number;\n portabilityRequests: number;\n avgResponseTimeHours: number;\n };\n /** Compliance score */\n complianceScore: number;\n /** Issues */\n issues: Array<{\n type: string;\n severity: string;\n description: string;\n }>;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Classify risk level from score.\n */\nexport function classifyRiskLevel(score: number): 'low' | 'medium' | 'high' | 'critical' {\n if (score < 25) return 'low';\n if (score < 50) return 'medium';\n if (score < 75) return 'high';\n return 'critical';\n}\n\n/**\n * Calculate failed login rate.\n */\nexport function calculateFailedLoginRate(failed: number, total: number): number {\n if (total === 0) return 0;\n return Math.round((failed / total) * 10000) / 100;\n}\n\n/**\n * Check if login pattern is suspicious.\n */\nexport function isSuspiciousLoginPattern(\n failedAttempts: number,\n timeWindowMinutes: number,\n threshold: number = 5\n): boolean {\n return failedAttempts >= threshold && timeWindowMinutes <= 15;\n}\n\n/**\n * Determine event severity.\n */\nexport function determineEventSeverity(\n eventType: SecurityEventType,\n success: boolean\n): 'low' | 'medium' | 'high' | 'critical' {\n const criticalEvents: SecurityEventType[] = ['suspicious_activity'];\n const highEvents: SecurityEventType[] = ['role_change', 'permission_change', 'data_deletion', 'api_key_revoked'];\n const mediumEvents: SecurityEventType[] = ['login_failure', 'password_reset', 'data_export'];\n\n if (criticalEvents.includes(eventType)) return 'critical';\n if (highEvents.includes(eventType)) return 'high';\n if (mediumEvents.includes(eventType)) return !success ? 'high' : 'medium';\n return 'low';\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Security and compliance analytics class.\n */\nexport class SecurityAnalytics extends FlowGridTransport {\n /**\n * Track login attempt.\n */\n async trackLoginAttempt(config: LoginAttemptConfig): Promise<{ tracked: boolean }> {\n const eventType: SecurityEventType = config.success ? 'login_success' : 'login_failure';\n const severity = determineEventSeverity(eventType, config.success);\n\n return await this.initFeature(\"security.login_attempt\", {\n type: \"security\",\n ...config,\n eventType,\n severity,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track logout.\n */\n async trackLogout(userId: string, sessionId?: string): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"security.logout\", {\n type: \"security\",\n userId,\n sessionId,\n eventType: 'logout' as SecurityEventType,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track password change.\n */\n async trackPasswordChange(userId: string, forced: boolean = false): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"security.password_change\", {\n type: \"security\",\n userId,\n forced,\n eventType: 'password_change' as SecurityEventType,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track role change.\n */\n async trackRoleChange(config: RoleChangeConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"security.role_change\", {\n type: \"security\",\n ...config,\n eventType: 'role_change' as SecurityEventType,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track permission change.\n */\n async trackPermissionChange(config: PermissionChangeConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"security.permission_change\", {\n type: \"security\",\n ...config,\n eventType: 'permission_change' as SecurityEventType,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track data access.\n */\n async trackDataAccess(config: DataAccessConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"security.data_access\", {\n type: \"security\",\n ...config,\n eventType: 'data_access' as SecurityEventType,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track data export.\n */\n async trackDataExport(\n userId: string,\n resourceType: string,\n recordCount: number\n ): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"security.data_export\", {\n type: \"security\",\n userId,\n resourceType,\n recordCount,\n eventType: 'data_export' as SecurityEventType,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track suspicious activity.\n */\n async trackSuspiciousActivity(\n userId: string,\n activityType: string,\n details: Record<string, unknown>\n ): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"security.suspicious_activity\", {\n type: \"security\",\n userId,\n activityType,\n details,\n eventType: 'suspicious_activity' as SecurityEventType,\n severity: 'critical',\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Track compliance event.\n */\n async trackComplianceEvent(config: ComplianceEventConfig): Promise<{ tracked: boolean }> {\n return await this.initFeature(\"security.compliance_event\", {\n type: \"security\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * @fileoverview Enterprise - Product Usage Forecasting\n * @module features/enterprise/forecasting\n * \n * @description\n * Predict usage, adoption, and revenue trends using historical data\n * and machine learning models.\n * \n * @useCases\n * - Project active user growth\n * - Forecast feature adoption\n * - Predict churn and revenue\n * - Capacity planning\n * - Trend analysis\n * \n * @metrics\n * - Predicted DAU/MAU\n * - Feature adoption forecast\n * - Revenue projection\n * - Churn prediction\n * - Forecast accuracy\n * \n * @chartData\n * - Line chart: Forecast with confidence\n * - Area chart: Prediction range\n * - Comparison: Predicted vs actual\n * - Table: Forecast metrics\n * \n * @example\n * ```typescript\n * const forecasting = new Forecasting(webId, endpoint, apiKey);\n * \n * // Get user growth forecast\n * const forecast = await forecasting.forecastActiveUsers({\n * metric: 'dau',\n * periods: 30,\n * granularity: 'day'\n * });\n * ```\n */\n\nimport { FlowGridTransport } from \"../../client/transport\";\nimport { DateRangeFilter, TimeSeriesData, TimeGranularity, MoneyValue, CurrencyCode } from \"../../types\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Forecast model types.\n */\nexport type ForecastModel = \n | 'linear'\n | 'exponential'\n | 'arima'\n | 'prophet'\n | 'ensemble';\n\n/**\n * Metric types for forecasting.\n */\nexport type ForecastMetric = \n | 'dau' // Daily Active Users\n | 'wau' // Weekly Active Users\n | 'mau' // Monthly Active Users\n | 'signups' // New signups\n | 'revenue' // Revenue\n | 'mrr' // Monthly Recurring Revenue\n | 'churn_rate' // Churn rate\n | 'feature_usage' // Feature usage\n | 'sessions' // Session count\n | 'events' // Event count\n | 'custom'; // Custom metric\n\n/**\n * Base forecast configuration.\n */\nexport interface ForecastConfig {\n /** Metric to forecast */\n metric: ForecastMetric;\n /** Number of periods to forecast */\n periods: number;\n /** Time granularity */\n granularity: TimeGranularity;\n /** Historical data range to use */\n historicalRange?: DateRangeFilter;\n /** Forecast model to use */\n model?: ForecastModel;\n /** Include confidence intervals */\n includeConfidence?: boolean;\n /** Confidence level (0-1, default 0.95) */\n confidenceLevel?: number;\n /** Custom metric name (if metric is 'custom') */\n customMetricName?: string;\n}\n\n/**\n * Forecast data point.\n */\nexport interface ForecastDataPoint {\n /** Period/date */\n period: string;\n /** Predicted value */\n predicted: number;\n /** Lower bound (if confidence included) */\n lower?: number;\n /** Upper bound (if confidence included) */\n upper?: number;\n /** Actual value (if historical/backtested) */\n actual?: number;\n}\n\n/**\n * Forecast result.\n */\nexport interface ForecastResult {\n /** Metric being forecasted */\n metric: ForecastMetric;\n /** Model used */\n model: ForecastModel;\n /** Granularity */\n granularity: TimeGranularity;\n /** Forecast data points */\n forecast: ForecastDataPoint[];\n /** Summary statistics */\n summary: {\n startValue: number;\n endValue: number;\n totalChange: number;\n changePercent: number;\n trend: 'growing' | 'stable' | 'declining';\n avgGrowthRate: number;\n };\n /** Model accuracy (based on backtesting) */\n accuracy: {\n mape: number; // Mean Absolute Percentage Error\n rmse: number; // Root Mean Square Error\n r2: number; // R-squared\n };\n /** Generated at */\n generatedAt: string;\n}\n\n/**\n * Revenue forecast configuration.\n */\nexport interface RevenueForecastConfig extends Omit<ForecastConfig, 'metric'> {\n /** Currency */\n currency?: CurrencyCode;\n /** Include MRR components */\n includeMRRComponents?: boolean;\n}\n\n/**\n * Revenue forecast result.\n */\nexport interface RevenueForecastResult extends ForecastResult {\n /** Currency */\n currency: CurrencyCode;\n /** MRR components (if included) */\n mrrComponents?: {\n newBusiness: ForecastDataPoint[];\n expansion: ForecastDataPoint[];\n contraction: ForecastDataPoint[];\n churn: ForecastDataPoint[];\n };\n}\n\n/**\n * Feature adoption forecast configuration.\n */\nexport interface FeatureAdoptionForecastConfig extends Omit<ForecastConfig, 'metric'> {\n /** Feature ID */\n featureId: string;\n /** Adoption metric */\n adoptionMetric?: 'users' | 'usage_count' | 'adoption_rate';\n}\n\n/**\n * Churn forecast configuration.\n */\nexport interface ChurnForecastConfig extends Omit<ForecastConfig, 'metric'> {\n /** User segment */\n segment?: string;\n /** Include user-level predictions */\n includeUserPredictions?: boolean;\n /** Top N at-risk users to include */\n topAtRiskUsers?: number;\n}\n\n/**\n * Churn forecast result.\n */\nexport interface ChurnForecastResult extends ForecastResult {\n /** Predicted churned user count */\n predictedChurnedUsers: number;\n /** Predicted revenue at risk */\n revenueAtRisk?: MoneyValue;\n /** Top at-risk users (if requested) */\n atRiskUsers?: Array<{\n userId: string;\n churnProbability: number;\n predictedChurnDate: string;\n estimatedValue: MoneyValue;\n }>;\n}\n\n/**\n * Capacity planning configuration.\n */\nexport interface CapacityPlanningConfig {\n /** Metrics to include */\n metrics: Array<'users' | 'sessions' | 'events' | 'api_calls' | 'storage'>;\n /** Periods to forecast */\n periods: number;\n /** Granularity */\n granularity: 'week' | 'month' | 'quarter';\n /** Current capacity limits */\n currentLimits?: Record<string, number>;\n}\n\n/**\n * Capacity planning result.\n */\nexport interface CapacityPlanningResult {\n /** Forecasts by metric */\n forecasts: Record<string, ForecastResult>;\n /** Capacity alerts */\n alerts: Array<{\n metric: string;\n currentUsage: number;\n limit: number;\n predictedExceedDate?: string;\n recommendation: string;\n }>;\n /** Overall growth rate */\n overallGrowthRate: number;\n}\n\n/**\n * Scenario configuration.\n */\nexport interface ScenarioConfig {\n /** Base forecast configuration */\n baseConfig: ForecastConfig;\n /** Scenario adjustments */\n scenarios: Array<{\n name: string;\n adjustments: {\n growthMultiplier?: number;\n seasonalAdjustment?: number;\n oneTimeImpact?: { period: string; value: number };\n };\n }>;\n}\n\n/**\n * Scenario comparison result.\n */\nexport interface ScenarioComparison {\n /** Base forecast */\n baseline: ForecastResult;\n /** Scenario forecasts */\n scenarios: Array<{\n name: string;\n forecast: ForecastResult;\n differenceFromBaseline: number;\n }>;\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Calculate MAPE (Mean Absolute Percentage Error).\n */\nexport function calculateMAPE(actual: number[], predicted: number[]): number {\n if (actual.length !== predicted.length || actual.length === 0) return 0;\n \n let sum = 0;\n let count = 0;\n \n for (let i = 0; i < actual.length; i++) {\n if (actual[i] !== 0) {\n sum += Math.abs((actual[i] - predicted[i]) / actual[i]);\n count++;\n }\n }\n \n return count > 0 ? Math.round((sum / count) * 10000) / 100 : 0;\n}\n\n/**\n * Calculate RMSE (Root Mean Square Error).\n */\nexport function calculateRMSE(actual: number[], predicted: number[]): number {\n if (actual.length !== predicted.length || actual.length === 0) return 0;\n \n let sumSquaredError = 0;\n for (let i = 0; i < actual.length; i++) {\n sumSquaredError += Math.pow(actual[i] - predicted[i], 2);\n }\n \n return Math.round(Math.sqrt(sumSquaredError / actual.length) * 100) / 100;\n}\n\n/**\n * Calculate R-squared.\n */\nexport function calculateR2(actual: number[], predicted: number[]): number {\n if (actual.length !== predicted.length || actual.length === 0) return 0;\n \n const mean = actual.reduce((a, b) => a + b, 0) / actual.length;\n \n let ssRes = 0;\n let ssTot = 0;\n \n for (let i = 0; i < actual.length; i++) {\n ssRes += Math.pow(actual[i] - predicted[i], 2);\n ssTot += Math.pow(actual[i] - mean, 2);\n }\n \n return ssTot !== 0 ? Math.round((1 - ssRes / ssTot) * 10000) / 10000 : 0;\n}\n\n/**\n * Classify trend direction.\n */\nexport function classifyTrend(\n startValue: number,\n endValue: number,\n threshold: number = 5\n): 'growing' | 'stable' | 'declining' {\n if (startValue === 0) return endValue > 0 ? 'growing' : 'stable';\n \n const changePercent = ((endValue - startValue) / startValue) * 100;\n \n if (changePercent > threshold) return 'growing';\n if (changePercent < -threshold) return 'declining';\n return 'stable';\n}\n\n/**\n * Calculate average growth rate.\n */\nexport function calculateAvgGrowthRate(values: number[]): number {\n if (values.length < 2) return 0;\n \n let totalGrowth = 0;\n let count = 0;\n \n for (let i = 1; i < values.length; i++) {\n if (values[i - 1] !== 0) {\n totalGrowth += (values[i] - values[i - 1]) / values[i - 1];\n count++;\n }\n }\n \n return count > 0 ? Math.round((totalGrowth / count) * 10000) / 100 : 0;\n}\n\n/**\n * Apply confidence interval.\n */\nexport function applyConfidenceInterval(\n predicted: number,\n stdError: number,\n confidenceLevel: number = 0.95\n): { lower: number; upper: number } {\n // Z-score for common confidence levels\n const zScores: Record<number, number> = {\n 0.90: 1.645,\n 0.95: 1.96,\n 0.99: 2.576\n };\n \n const z = zScores[confidenceLevel] ?? 1.96;\n const margin = z * stdError;\n \n return {\n lower: Math.max(0, predicted - margin),\n upper: predicted + margin\n };\n}\n\n// ============================================================================\n// MAIN CLASS\n// ============================================================================\n\n/**\n * Product usage forecasting class.\n */\nexport class Forecasting extends FlowGridTransport {\n /**\n * Forecast active users.\n */\n async forecastActiveUsers(config: ForecastConfig): Promise<ForecastResult> {\n return await this.initFeature(\"forecasting.active_users\", {\n type: \"forecasting\",\n ...config,\n model: config.model ?? 'ensemble',\n includeConfidence: config.includeConfidence ?? true,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Forecast revenue.\n */\n async forecastRevenue(config: RevenueForecastConfig): Promise<RevenueForecastResult> {\n return await this.initFeature(\"forecasting.revenue\", {\n type: \"forecasting\",\n ...config,\n metric: 'revenue' as ForecastMetric,\n currency: config.currency ?? 'USD',\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Forecast MRR.\n */\n async forecastMRR(config: RevenueForecastConfig): Promise<RevenueForecastResult> {\n return await this.initFeature(\"forecasting.mrr\", {\n type: \"forecasting\",\n ...config,\n metric: 'mrr' as ForecastMetric,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Forecast feature adoption.\n */\n async forecastFeatureAdoption(\n config: FeatureAdoptionForecastConfig\n ): Promise<ForecastResult> {\n return await this.initFeature(\"forecasting.feature_adoption\", {\n type: \"forecasting\",\n ...config,\n metric: 'feature_usage' as ForecastMetric,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Forecast churn.\n */\n async forecastChurn(config: ChurnForecastConfig): Promise<ChurnForecastResult> {\n return await this.initFeature(\"forecasting.churn\", {\n type: \"forecasting\",\n ...config,\n metric: 'churn_rate' as ForecastMetric,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Forecast signups.\n */\n async forecastSignups(config: ForecastConfig): Promise<ForecastResult> {\n return await this.initFeature(\"forecasting.signups\", {\n type: \"forecasting\",\n ...config,\n metric: 'signups' as ForecastMetric,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Compare forecast scenarios.\n */\n async compareScenarios(config: ScenarioConfig): Promise<ScenarioComparison> {\n return await this.initFeature(\"forecasting.scenarios\", {\n type: \"forecasting\",\n ...config,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Forecast custom metric.\n */\n async forecastCustomMetric(\n metricName: string,\n config: Omit<ForecastConfig, 'metric' | 'customMetricName'>\n ): Promise<ForecastResult> {\n return await this.initFeature(\"forecasting.custom\", {\n type: \"forecasting\",\n ...config,\n metric: 'custom' as ForecastMetric,\n customMetricName: metricName,\n timestamp: new Date().toISOString()\n });\n }\n\n}\n","/**\n * Activation shortcuts — one helper per event, positional args, sensible defaults.\n * Underlying class accessible via `.client`.\n */\nimport { Activation } from \"../../features/core/activation\";\n\nexport class ActivationTracker {\n constructor(public readonly client: Activation) {}\n\n /** New user signup. */\n signup(userId: string, method: string, source?: string, props?: Record<string, unknown>) {\n return this.client.trackSignup(userId, method, source, props);\n }\n\n /** Step in an onboarding flow (e.g. `step 2 of 5`). */\n onboardingStep(\n userId: string,\n stepId: string,\n stepName: string,\n stepOrder: number,\n totalSteps: number,\n extra?: { skipped?: boolean; timeSpent?: number; properties?: Record<string, unknown> }\n ) {\n return this.client.trackOnboardingStep({\n userId,\n stepId,\n stepName,\n stepOrder,\n totalSteps,\n ...extra,\n });\n }\n\n /** All onboarding steps finished. */\n onboardingComplete(userId: string, totalTimeSpent: number, stepsCompleted: number, stepsSkipped = 0) {\n return this.client.completeOnboarding(userId, totalTimeSpent, stepsCompleted, stepsSkipped);\n }\n\n /** First meaningful action after signup (\"aha\" moment). */\n firstAction(userId: string, actionName: string, timeSinceSignup: number, properties?: Record<string, unknown>) {\n return this.client.trackFirstAction({ userId, actionName, timeSinceSignup, properties });\n }\n\n /** Generic activation event. */\n event(eventName: string, properties: Record<string, unknown> = {}) {\n return this.client.create({ eventName, properties });\n }\n\n}\n","/**\n * Feature usage shortcuts.\n */\nimport { TrackFeature } from \"../../features/core/track-feature\";\n\nexport type FeatureAction = \"viewed\" | \"used\" | \"completed\" | \"abandoned\";\n\nexport class FeatureTracker {\n constructor(public readonly client: TrackFeature) {}\n\n /** Track that a user used a feature. */\n used(featureId: string, featureName: string, action: FeatureAction = \"used\", properties?: Record<string, unknown>) {\n return this.client.trackUsage({ featureId, featureName, action, properties });\n }\n\n /** Create / register a feature event (advanced — see `client.create`). */\n create(userId: string, action: string, featureName: string, properties?: Record<string, unknown>) {\n return this.client.create({ userId, action, properties: { featureName, ...properties } });\n }\n}\n","/**\n * AI prompt tracking shortcuts.\n */\nimport { TrackPrompt, PromptFeedbackConfig } from \"../../features/core/track-prompt\";\n\nexport class PromptTracker {\n constructor(public readonly client: TrackPrompt) {}\n\n /** A user submitted a prompt. */\n submitted(promptId: string, promptType: string, properties?: Record<string, unknown>) {\n return this.client.trackSubmission({ promptId, promptType, properties });\n }\n\n /** The model returned a response. */\n responded(promptId: string, responseTime: number, completed: boolean, properties?: Record<string, unknown>) {\n return this.client.trackResponse({ promptId, responseTime, completed, properties });\n }\n\n /** User feedback on a prompt response (thumbs up/down etc.). */\n feedback(promptId: string, feedbackType: PromptFeedbackConfig[\"feedbackType\"], properties?: Record<string, unknown>) {\n return this.client.trackFeedback({ promptId, feedbackType, properties });\n }\n\n /** Multi-turn conversation summary. */\n conversation(conversationId: string, userId: string, turnCount: number, totalDuration: number) {\n return this.client.trackConversation(conversationId, userId, turnCount, totalDuration);\n }\n\n /** Generic prompt event. */\n event(eventName: string, properties: Record<string, unknown> = {}) {\n return this.client.create({ eventName, properties });\n }\n}\n","/**\n * Experiment tracker — A/B testing API.\n *\n * Covers the full A/B test lifecycle:\n * 1. `define()` — register an experiment (one-time admin setup).\n * 2. `init()` — initialise the client-side engine (browser only).\n * 3. `assign()` / `variant()` — get a user's variant.\n * 4. `exposure()` — log that the user saw the assigned variant.\n * 5. `conversion()` — log a success metric.\n *\n * The browser flow is the simplest:\n * ```ts\n * await fg.experiments.init([{ experimentId, variants: [...] }]);\n * const variant = fg.experiments.variant(experimentId);\n * if (variant === \"B\") renderNewCheckout();\n * await fg.experiments.exposure(experimentId, userId, variant);\n * // …user converts…\n * await fg.experiments.conversion(experimentId, userId, variant, \"purchase\", 1);\n * ```\n */\nimport {\n Experiment,\n ExperimentDefinition,\n ExperimentInitConfig,\n} from \"../../features/core/experiment\";\nimport type { ServerCookieReader } from \"../../utils/identity\";\n\nexport class ExperimentTracker {\n constructor(public readonly client: Experiment) {}\n\n // ---------------------------------------------------------------------------\n // SETUP\n // ---------------------------------------------------------------------------\n\n /**\n * Define an experiment. Run this once during admin setup.\n *\n * @example\n * ```ts\n * await fg.experiments.define({\n * experimentId: \"checkout_v2\",\n * name: \"New checkout flow\",\n * variants: [\n * { id: \"control\", weight: 50 },\n * { id: \"B\", weight: 50 },\n * ],\n * });\n * ```\n */\n define(definition: ExperimentDefinition) {\n return this.client.define(definition);\n }\n\n /**\n * Initialise the client-side engine (browser only).\n *\n * Verifies experiments, performs weighted-random assignment, and\n * persists assignments in `localStorage` so the same visitor always\n * sees the same variant.\n */\n init(experiments: ExperimentInitConfig[]) {\n return this.client.initExperiments(experiments);\n }\n\n // ---------------------------------------------------------------------------\n // ASSIGNMENT\n // ---------------------------------------------------------------------------\n\n /**\n * Synchronously read the locally-cached variant assignment.\n * Returns `null` if no assignment exists. Browser-only.\n */\n variant(experimentId: string): string | null {\n return this.client.getLocalVariant(experimentId);\n }\n\n /**\n * Explicitly assign (or override) a user's variant. Use this for\n * targeted assignments or admin overrides.\n */\n assign(\n experimentId: string,\n userId: string,\n variantId: string,\n source: \"random\" | \"targeted\" | \"override\" = \"targeted\"\n ) {\n return this.client.assign({ experimentId, userId, variantId, source });\n }\n\n // ---------------------------------------------------------------------------\n // EXPOSURE & CONVERSION\n // ---------------------------------------------------------------------------\n\n /**\n * Record that a user was exposed to (saw / used) their variant.\n * Call this when the variant is rendered.\n */\n exposure(experimentId: string, userId: string, variantId: string) {\n return this.client.trackExposure(experimentId, userId, variantId);\n }\n\n /**\n * Record a conversion against a specific user's variant (server-side).\n *\n * @example\n * ```ts\n * await fg.experiments.conversion(\"checkout_v2\", \"u_1\", \"B\", \"purchase\", 49.99);\n * ```\n */\n conversion(\n experimentId: string,\n userId: string,\n variantId: string,\n metricName: string,\n value: number = 1\n ) {\n return this.client.trackConversion({\n experimentId,\n userId,\n variantId,\n metricName,\n value,\n });\n }\n\n /**\n * Browser-side conversion using the locally-cached variant assignment.\n * No-op if the visitor has no assignment for this experiment.\n *\n * @example\n * ```ts\n * await fg.experiments.localConversion(\"checkout_v2\", \"purchase\", 49.99);\n * ```\n */\n localConversion(experimentId: string, metricName: string = \"conversion\", value: number = 1) {\n return this.client.trackLocalConversion(experimentId, metricName, value);\n }\n\n // ---------------------------------------------------------------------------\n // SSR / COOKIE HYDRATION\n //\n // The underlying engine mirrors assignments to a `fg_exp_assignments`\n // cookie so that server-rendered HTML can pick the right variant before\n // any JS executes. These helpers wire the cookie into common runtimes.\n // ---------------------------------------------------------------------------\n\n /**\n * Hydrate assignments from a server cookie reader (Next.js `cookies()`,\n * Nuxt `useCookie()`, etc.). Call this once per request before reading\n * `variant()` server-side.\n *\n * @example\n * ```ts\n * import { cookies } from \"next/headers\";\n * fg.experiments.hydrateFromCookies(cookies());\n * const variant = fg.experiments.variant(\"checkout_v2\");\n * ```\n */\n hydrateFromCookies(reader: ServerCookieReader) {\n this.client.hydrateFromCookies(reader);\n }\n\n /**\n * Hydrate assignments from a raw `Cookie` header (Workers, Bun, Hono, etc.).\n */\n hydrateFromCookieHeader(cookieHeader: string | null | undefined) {\n this.client.hydrateFromCookieHeader(cookieHeader);\n }\n\n /**\n * Inject assignments resolved server-side. Use when the assignment was\n * computed without a cookie (e.g. logged-in user fetched from DB).\n */\n injectAssignments(assignments: Record<string, string>) {\n this.client.injectAssignments(assignments);\n }\n\n /**\n * Snapshot of all known assignments. Useful for SSR payload hand-off.\n */\n getAssignments(): Record<string, string> {\n return this.client.getAssignments();\n }\n\n /**\n * Build a `Set-Cookie` header value seeding the visitor's browser with\n * the current assignment map.\n *\n * @example\n * ```ts\n * res.headers.set(\"Set-Cookie\", fg.experiments.serializeAssignmentCookie());\n * ```\n */\n serializeAssignmentCookie(): string {\n return this.client.serializeAssignmentCookie();\n }\n\n /** Wipe all locally-cached assignments (cookie + localStorage). */\n clearAssignments() {\n this.client.clearAssignments();\n }\n}\n","/**\n * Page view shortcuts. Browser fields auto-detected when available.\n */\nimport { PageViews } from \"../../features/analytics/page-views\";\n\nfunction browserDefaults() {\n const isBrowser = typeof window !== \"undefined\" && typeof document !== \"undefined\";\n return {\n url: isBrowser ? window.location.href : \"\",\n path: isBrowser ? window.location.pathname : \"\",\n title: isBrowser ? document.title : undefined,\n referrer: isBrowser ? document.referrer : undefined,\n };\n}\n\nexport class PageViewTracker {\n constructor(public readonly client: PageViews) {}\n\n /**\n * Track a page view. With no args, auto-detects from `window`/`document`.\n * Pass a path or full URL to override.\n */\n view(\n pathOrUrl?: string,\n properties?: Record<string, unknown>,\n opts?: { title?: string; referrer?: string; userId?: string; sessionId?: string }\n ) {\n const d = browserDefaults();\n const isFullUrl = pathOrUrl && /^https?:\\/\\//i.test(pathOrUrl);\n const url = isFullUrl ? pathOrUrl! : d.url;\n const path = isFullUrl ? new URL(pathOrUrl!).pathname : (pathOrUrl ?? d.path);\n return this.client.track({\n url,\n path,\n title: opts?.title ?? d.title,\n referrer: opts?.referrer ?? d.referrer,\n userId: opts?.userId,\n sessionId: opts?.sessionId,\n properties,\n });\n }\n\n /** Record scroll depth (0-100). */\n scroll(path: string, scrollDepth: number, timeAtDepth?: number) {\n return this.client.trackScrollDepth({ path, scrollDepth, timeAtDepth });\n }\n\n /** Record time spent on a page (seconds). */\n time(path: string, duration: number) {\n return this.client.trackTimeOnPage({ path, duration });\n }\n\n /** Record page exit. */\n exit(path: string, duration: number, scrollDepth: number) {\n return this.client.trackExit(path, duration, scrollDepth);\n }\n\n /** Auto-track SPA route changes, scroll-depth thresholds, and time-on-page. */\n autoTrack(options?: { userId?: string; sessionId?: string }) {\n return this.client.autoTrack(options);\n }\n}\n","/**\n * Session lifecycle shortcuts.\n */\nimport { Sessions } from \"../../features/analytics/sessions\";\n\nexport class SessionTracker {\n constructor(public readonly client: Sessions) {}\n\n /** Start a new session. */\n start(opts?: Parameters<Sessions[\"start\"]>[0]) {\n return this.client.start(opts);\n }\n\n /** Update an active session with new properties. */\n update(sessionId: string, properties: Record<string, unknown>) {\n return this.client.update(sessionId, properties);\n }\n\n /** End a session. */\n end(sessionId: string) {\n return this.client.end(sessionId);\n }\n\n /** Heartbeat to keep a session alive. */\n heartbeat(sessionId: string) {\n return this.client.heartbeat(sessionId);\n }\n\n /** Auto-manage browser session lifecycle (start, heartbeat, end on pagehide). */\n autoTrack(config?: Parameters<Sessions[\"autoTrack\"]>[0], options?: { heartbeatMs?: number }) {\n return this.client.autoTrack(config, options);\n }\n}\n","/**\n * Custom event shortcuts.\n */\nimport { Events } from \"../../features/analytics/events\";\n\nexport class EventTracker {\n constructor(public readonly client: Events) {}\n\n /** Track a custom event. */\n track(eventName: string, properties?: Record<string, unknown>, opts?: { userId?: string; sessionId?: string }) {\n return this.client.track({ eventName, properties, userId: opts?.userId, sessionId: opts?.sessionId });\n }\n\n /** Track many events in one request. */\n batch(events: Array<{ eventName: string; properties?: Record<string, unknown> }>) {\n return this.client.trackBatch({ events });\n }\n\n /** Track a click on a tagged element. */\n click(elementId: string, elementText: string, properties?: Record<string, unknown>) {\n return this.client.trackClick({ elementId, elementText, properties });\n }\n\n /** Track a form interaction. */\n form(formId: string, formName: string, properties?: Record<string, unknown>) {\n return this.client.trackForm({ formId, formName, properties });\n }\n\n /** Track a search query. */\n search(query: string, category: string, properties?: Record<string, unknown>) {\n return this.client.trackSearch({ query, category, properties });\n }\n\n /** Track a runtime error. */\n error(message: string, type: string, properties?: Record<string, unknown>) {\n return this.client.trackError({ message, type, properties });\n }\n}\n","/**\n * User identification shortcuts.\n */\nimport { Identify } from \"../../features/analytics/identify\";\n\nexport class IdentifyTracker {\n constructor(public readonly client: Identify) {}\n\n /** Identify a user with traits. */\n user(userId: string, traits?: Record<string, unknown>, anonymousId?: string) {\n return this.client.user({ userId, anonymousId, traits: traits });\n }\n\n /** Update traits on an existing user. */\n updateTraits(userId: string, traits: Record<string, unknown>) {\n return this.client.updateTraits(userId, traits);\n }\n\n /** Alias an anonymous ID to a known user ID. */\n alias(previousId: string, userId: string) {\n return this.client.alias({ previousId, userId });\n }\n\n /** Associate a user with a group/company. */\n group(userId: string, groupId: string, traits?: Record<string, unknown>) {\n return this.client.group({ userId, groupId, traits: traits });\n }\n}\n","/**\n * Funnel shortcuts.\n */\nimport { Funnels } from \"../../features/analytics/funnels\";\n\nexport class FunnelTracker {\n constructor(public readonly client: Funnels) {}\n\n /** Define a new funnel (admin / setup). */\n define(definition: Parameters<Funnels[\"define\"]>[0]) {\n return this.client.define(definition);\n }\n\n /** Record a step completion in a funnel. */\n step(funnelId: string, step: string, stepNumber: number, userId?: string, properties?: Record<string, unknown>) {\n return this.client.trackStep({ funnelId, step, stepNumber, userId, properties });\n }\n\n /** Mark a funnel as completed. */\n complete(funnelId: string, userId?: string, properties?: Record<string, unknown>) {\n return this.client.trackComplete(funnelId, userId, properties);\n }\n\n /** Mark a funnel as abandoned. */\n abandon(funnelId: string, lastStep: string, userId?: string, reason?: string) {\n return this.client.trackAbandon(funnelId, lastStep, userId, reason);\n }\n}\n","/**\n * Retention shortcuts.\n */\nimport { Retention } from \"../../features/analytics/retention\";\n\nexport class RetentionTracker {\n constructor(public readonly client: Retention) {}\n\n /** Record that a user was active. */\n active(userId: string, properties?: Record<string, unknown>) {\n return this.client.trackActivity({ userId, properties });\n }\n}\n","/**\n * Multi-touch attribution shortcuts.\n */\nimport { Attribution, ConversionEvent } from \"../../features/analytics/attribution\";\n\nexport class AttributionTracker {\n constructor(public readonly client: Attribution) {}\n\n /** Record a marketing touchpoint. */\n touchpoint(userId: string, channel: string, properties?: Record<string, unknown>) {\n return this.client.trackTouchpoint({ userId, channel, properties });\n }\n\n /** Record a conversion that should be attributed. */\n conversion(userId: string, conversionType: ConversionEvent[\"conversionType\"], properties?: Record<string, unknown>) {\n return this.client.recordConversion({ userId, conversionType, properties });\n }\n\n /** Auto-capture a touchpoint from `utm_*` params + `document.referrer`. */\n captureFromUrl(userId: string) {\n return this.client.captureFromUrl(userId);\n }\n}\n","/**\n * Heatmap shortcuts.\n */\nimport { Heatmaps } from \"../../features/analytics/heatmaps\";\n\nexport class HeatmapTracker {\n constructor(public readonly client: Heatmaps) {}\n\n /** Record a click point. */\n click(pageUrl: string, x: number, y: number, viewportWidth: number, viewportHeight: number) {\n return this.client.trackClick({ pageUrl, x, y, viewportWidth, viewportHeight });\n }\n\n /** Record a mouse-movement path. */\n movement(pageUrl: string, path: Array<{ x: number; y: number; t: number }>, viewport: { width: number; height: number }) {\n return this.client.trackMovement({ pageUrl, path, viewport });\n }\n\n /** Record scroll behaviour. */\n scroll(pageUrl: string, maxScrollDepth: number, pageHeight: number, viewportHeight: number) {\n return this.client.trackScroll({ pageUrl, maxScrollDepth, pageHeight, viewportHeight });\n }\n\n /** Auto-attach click + scroll listeners (and optionally mousemove). */\n autoTrack(options?: { movement?: boolean; userId?: string; sessionId?: string }) {\n return this.client.autoTrack(options);\n }\n}\n","/**\n * Performance shortcuts.\n */\nimport { PerformanceTracking } from \"../../features/analytics/performance\";\n\ntype ResourceType = \"script\" | \"stylesheet\" | \"image\" | \"font\" | \"xhr\" | \"fetch\" | \"other\";\n\nexport class PerformanceTracker {\n constructor(public readonly client: PerformanceTracking) {}\n\n /** Report Core Web Vitals (LCP/FID/CLS/INP/TTFB). */\n webVitals(pageUrl: string, vitals: Record<string, number>) {\n return this.client.trackWebVitals({ pageUrl, ...vitals });\n }\n\n /** Report page-load timing. */\n pageLoad(pageUrl: string, timings: Record<string, number>) {\n return this.client.trackPageLoad({ pageUrl, ...timings });\n }\n\n /** Report a single resource load. */\n resource(pageUrl: string, resourceUrl: string, resourceType: ResourceType, duration: number) {\n return this.client.trackResource({ pageUrl, resourceUrl, resourceType, duration });\n }\n\n /** Auto-collect Core Web Vitals + navigation timing from the browser. */\n autoTrack(options?: { userId?: string; resources?: boolean; minDuration?: number }) {\n return this.client.autoTrack(options);\n }\n}\n","/**\n * Session Replay shortcut wrapper.\n */\nimport {\n SessionReplay,\n type SessionReplayFlushMetadata,\n type SessionReplayFlushReason,\n type SessionReplayOptions,\n type SessionReplayStatus,\n} from \"../../features/analytics/replay\";\nimport type { Teardown } from \"../../utils/browser\";\n\nexport class ReplayTracker {\n constructor(public readonly client: SessionReplay) {}\n\n /**\n * Start recording the current page. Returns a teardown that stops capture\n * and flushes the final buffer.\n *\n * @example\n * ```ts\n * const stop = await fg.replay.start({ sampleRate: 1.0, maskAllInputs: true });\n * ```\n */\n start(options?: SessionReplayOptions): Promise<Teardown> {\n return this.client.start(options ?? {});\n }\n\n /** Enable replay and start recording immediately. */\n enable(options?: SessionReplayOptions): Promise<Teardown> {\n return this.client.enable(options ?? {});\n }\n\n /** Disable replay and stop any active recorder. */\n disable(): void {\n this.client.disable();\n }\n\n /** Stop the active recorder and flush a final chunk. */\n stop(reason?: SessionReplayFlushReason): void {\n this.client.stop(reason);\n }\n\n /** Flush buffered events without stopping recording. */\n flush(reason?: SessionReplayFlushReason): Promise<void> {\n return this.client.flush(reason ?? \"manual\");\n }\n\n /** Bind a known user ID to subsequent replay chunks. */\n identify(userId: string): void {\n this.client.identify(userId);\n }\n\n /** Read recorder lifecycle and health state. */\n status(): SessionReplayStatus {\n return this.client.getStatus();\n }\n\n /** Send a pre-recorded rrweb chunk for custom recorder integrations. */\n sendChunk(\n sessionId: string,\n events: unknown[],\n options?: Parameters<SessionReplay[\"sendChunk\"]>[2],\n ): Promise<void> {\n return this.client.sendChunk(sessionId, events, options ?? {});\n }\n}\n\nexport type { SessionReplayFlushMetadata, SessionReplayFlushReason, SessionReplayOptions, SessionReplayStatus };\n","/**\n * Product shortcuts.\n */\nimport { Products } from \"../../features/ecommerce/products\";\nimport type { Product } from \"../../types\";\n\nexport class ProductTracker {\n constructor(public readonly client: Products) {}\n\n /** Track a product detail view. */\n view(product: Pick<Product, \"productId\" | \"name\" | \"price\" | \"currency\"> & Partial<Product>, properties?: Record<string, unknown>) {\n return this.client.view({ ...product, properties });\n }\n\n /** Track a product list impression. */\n impression(listId: string, listName: string, products: Product[]) {\n return this.client.impression({ list: { listId, listName, products } });\n }\n\n /** Track a click on a product in a list. */\n click(product: Product, listId: string, position: number) {\n return this.client.click({ product, listId, position });\n }\n}\n","/**\n * Cart shortcuts.\n */\nimport { CartTracking } from \"../../features/ecommerce/cart\";\nimport type { Product, Cart } from \"../../types\";\n\nexport class CartTracker {\n constructor(public readonly client: CartTracking) {}\n\n /** Add a product to cart. */\n add(product: Product, quantity = 1, cartId?: string) {\n return this.client.addItem({ product, quantity, cartId });\n }\n\n /** Remove a product from cart. */\n remove(product: Product, quantity = 1, cartId?: string) {\n return this.client.removeItem({ product, quantity, cartId });\n }\n\n /** Change the quantity of a cart item. */\n update(product: Product, previousQuantity: number, newQuantity: number, cartId?: string) {\n return this.client.updateItem({ product, previousQuantity, newQuantity, cartId });\n }\n\n /** Track a cart view. */\n view(cart: Cart) {\n return this.client.view({ cart });\n }\n}\n","/**\n * Checkout shortcuts.\n */\nimport { Checkout } from \"../../features/ecommerce/checkout\";\nimport type { Cart, ShippingInfo, PaymentInfo, CheckoutStep } from \"../../types\";\n\nexport class CheckoutTracker {\n constructor(public readonly client: Checkout) {}\n\n /** Begin checkout for the current cart. */\n begin(cart: Cart) {\n return this.client.begin({ cart });\n }\n\n /** Move to a checkout step. */\n step(step: CheckoutStep, stepNumber: number, cart: Cart) {\n return this.client.step({ step, stepNumber, cart });\n }\n\n /** Add shipping info. */\n shipping(cart: Cart, shipping: ShippingInfo) {\n return this.client.addShipping({ cart, shipping });\n }\n\n /** Add payment info. */\n payment(cart: Cart, payment: PaymentInfo) {\n return this.client.addPayment({ cart, payment });\n }\n}\n","/**\n * Purchase shortcuts.\n */\nimport { Purchases } from \"../../features/ecommerce/purchases\";\nimport type { Order } from \"../../types\";\n\nexport class PurchaseTracker {\n constructor(public readonly client: Purchases) {}\n\n /** Track a completed purchase. */\n complete(order: Order) {\n return this.client.track({ order });\n }\n}\n","/**\n * Refund shortcuts.\n */\nimport { Refunds } from \"../../features/ecommerce/refunds\";\nimport type { CartItem } from \"../../types\";\n\nexport class RefundTracker {\n constructor(public readonly client: Refunds) {}\n\n /** Customer requested a refund. */\n request(orderId: string, items?: CartItem[], reason?: string) {\n return this.client.request(orderId, items, reason);\n }\n\n /** Refund approved. */\n approve(refundId: string, approvedAmount: number) {\n return this.client.approve(refundId, approvedAmount);\n }\n\n /** Refund denied. */\n deny(refundId: string, reason: string) {\n return this.client.deny(refundId, reason);\n }\n\n /** Track a completed refund (partial or full). */\n complete(\n orderId: string,\n refundId: string,\n amount: number,\n currency: string,\n reason: string,\n isFullRefund = false\n ) {\n return this.client.track({ orderId, refundId, amount, currency, reason, isFullRefund });\n }\n}\n","/**\n * Promotion shortcuts.\n */\nimport { Promotions } from \"../../features/ecommerce/promotions\";\n\nexport class PromotionTracker {\n constructor(public readonly client: Promotions) {}\n\n /** A user saw a promotion. */\n view(promotionId: string, name: string, creative: string, position: string) {\n return this.client.view({ promotionId, name, creative, position });\n }\n\n /** A user clicked a promotion. */\n click(promotionId: string, name: string, creative: string, position: string) {\n return this.client.click({ promotionId, name, creative, position });\n }\n\n /** A coupon was applied. */\n coupon(\n code: string,\n orderId: string,\n discountValue: number,\n discountType: \"percentage\" | \"fixed\",\n orderValueBefore: number,\n orderValueAfter: number\n ) {\n return this.client.couponUsed({\n code,\n orderId,\n discountValue,\n discountType,\n orderValueBefore,\n orderValueAfter,\n });\n }\n}\n","/**\n * Wishlist shortcuts.\n */\nimport { WishlistTracking } from \"../../features/ecommerce/wishlist\";\nimport type { Product, Wishlist } from \"../../types\";\n\nexport class WishlistTracker {\n constructor(public readonly client: WishlistTracking) {}\n\n /** Add a product to wishlist. */\n add(product: Product, wishlistId?: string) {\n return this.client.add({ product, wishlistId });\n }\n\n /** Remove a product from wishlist. */\n remove(product: Product, wishlistId?: string) {\n return this.client.remove({ product, wishlistId });\n }\n\n /** Track a wishlist view. */\n view(wishlist: Wishlist) {\n return this.client.view(wishlist);\n }\n\n /** Move a wishlist item into the cart. */\n moveToCart(product: Product, wishlistId?: string) {\n return this.client.moveToCart(product, wishlistId);\n }\n\n /** Wishlist was shared. */\n share(wishlistId: string, method: \"email\" | \"link\" | \"social\") {\n return this.client.share(wishlistId, method);\n }\n}\n","/**\n * Customer LTV shortcuts.\n */\nimport { CustomerLTV } from \"../../features/ecommerce/ltv\";\nimport type { MoneyValue } from \"../../types\";\n\ntype LTVSegment = \"low\" | \"medium\" | \"high\" | \"vip\";\n\nexport class LTVTracker {\n constructor(public readonly client: CustomerLTV) {}\n\n /** Record a customer acquisition cost (CAC). */\n acquisitionCost(userId: string, cost: MoneyValue, channel: string) {\n return this.client.recordAcquisitionCost({ userId, cost, channel });\n }\n\n /** Move a user into a different LTV segment. */\n segment(userId: string, newSegment: LTVSegment) {\n return this.client.updateSegment(userId, newSegment);\n }\n}\n","/**\n * Site search shortcuts.\n */\nimport { SearchAnalytics } from \"../../features/ecommerce/search\";\nimport type { Product } from \"../../types\";\n\ntype RefinementType = \"query_change\" | \"add_filter\" | \"remove_filter\" | \"sort_change\";\n\nexport class SearchTracker {\n constructor(public readonly client: SearchAnalytics) {}\n\n /** A user searched. */\n query(query: string, resultsCount: number, extra?: { category?: string; filters?: Record<string, string | string[]>; userId?: string; sessionId?: string }) {\n return this.client.track({ query, resultsCount, ...extra });\n }\n\n /** A user clicked a search result. */\n click(query: string, product: Product, position: number) {\n return this.client.trackClick({ query, product, position });\n }\n\n /** A user refined an existing search. */\n refine(originalQuery: string, refinedQuery: string, refinementType: RefinementType) {\n return this.client.trackRefinement(originalQuery, refinedQuery, refinementType);\n }\n\n /** Autocomplete suggestion accepted. */\n suggestion(partialQuery: string, selectedSuggestion: string, suggestionPosition: number) {\n return this.client.trackSuggestion(partialQuery, selectedSuggestion, suggestionPosition);\n }\n}\n","/**\n * Subscription shortcuts.\n */\nimport { Subscriptions } from \"../../features/ecommerce/subscriptions\";\nimport type { MoneyValue } from \"../../types\";\n\nexport class SubscriptionTracker {\n constructor(public readonly client: Subscriptions) {}\n\n /** New subscription started. */\n start(\n subscriptionId: string,\n userId: string,\n plan: string,\n mrr: MoneyValue,\n billingCycle: \"monthly\" | \"quarterly\" | \"yearly\"\n ) {\n return this.client.start({ subscriptionId, userId, plan, mrr, billingCycle });\n }\n\n /** Plan changed (upgrade / downgrade). */\n change(\n subscriptionId: string,\n userId: string,\n previousPlan: string,\n newPlan: string,\n previousMrr: MoneyValue,\n newMrr: MoneyValue,\n changeType: \"upgrade\" | \"downgrade\" | \"cross_grade\"\n ) {\n return this.client.change({\n subscriptionId,\n userId,\n previousPlan,\n newPlan,\n previousMrr,\n newMrr,\n changeType,\n });\n }\n\n /** Subscription cancelled. */\n cancel(subscriptionId: string, userId: string, plan: string, lostMrr: MoneyValue, immediate = false) {\n return this.client.cancel({ subscriptionId, userId, plan, lostMrr, immediate });\n }\n\n /** Subscription renewed. */\n renew(subscriptionId: string, userId: string, mrr: MoneyValue) {\n return this.client.renew(subscriptionId, userId, mrr);\n }\n\n /** Trial converted to paid. */\n trialConverted(\n subscriptionId: string,\n userId: string,\n plan: string,\n mrr: MoneyValue\n ) {\n return this.client.trialConverted(subscriptionId, userId, plan, mrr);\n }\n\n /** Trial expired without converting. */\n trialExpired(subscriptionId: string, userId: string) {\n return this.client.trialExpired(subscriptionId, userId);\n }\n}\n","/**\n * Engagement shortcuts.\n */\nimport { Engagement, ContentConsumptionConfig, UserActivityConfig } from \"../../features/enterprise/engagement\";\n\nexport class EngagementTracker {\n constructor(public readonly client: Engagement) {}\n\n /** Time spent dwelling on a feature (ms). */\n dwell(featureId: string, dwellTimeMs: number, properties?: Record<string, unknown>) {\n return this.client.trackDwellTime({ featureId, dwellTimeMs, properties });\n }\n\n /** End-of-session depth metrics. */\n sessionDepth(\n sessionId: string,\n pagesVisited: number,\n featuresUsed: number,\n actionsTaken: number,\n durationMs: number\n ) {\n return this.client.trackSessionDepth({\n sessionId,\n pagesVisited,\n featuresUsed,\n actionsTaken,\n durationMs,\n });\n }\n\n /** How much of a content piece a user consumed. */\n contentConsumption(\n contentId: string,\n contentType: ContentConsumptionConfig[\"contentType\"],\n percentageConsumed: number,\n timeSpentMs: number\n ) {\n return this.client.trackContentConsumption({\n contentId,\n contentType,\n percentageConsumed,\n timeSpentMs,\n });\n }\n\n /** User activity ping. */\n activity(userId: string, activityType: UserActivityConfig[\"activityType\"], durationMs: number) {\n return this.client.trackUserActivity({ userId, activityType, durationMs });\n }\n\n /** Auto-track dwell time on a feature; returns a teardown that emits the event. */\n autoTrackDwell(featureId: string, options?: { userId?: string; sessionId?: string }) {\n return this.client.autoTrackDwell(featureId, options);\n }\n\n /**\n * Auto-track session-level engagement (session depth + activity transitions).\n * Returns a teardown function. Safe no-op outside the browser.\n */\n autoTrack(options?: { userId?: string; sessionId?: string; idleAfterMs?: number; pollMs?: number }) {\n return this.client.autoTrack(options);\n }\n}\n","/**\n * Cohort shortcuts.\n */\nimport { Cohorts } from \"../../features/enterprise/cohorts\";\n\nexport class CohortTracker {\n constructor(public readonly client: Cohorts) {}\n\n /** Define a new cohort (admin / setup). */\n create(definition: Parameters<Cohorts[\"createCohort\"]>[0]) {\n return this.client.createCohort(definition);\n }\n\n /** Define a new segment. */\n segment(definition: Parameters<Cohorts[\"createSegment\"]>[0]) {\n return this.client.createSegment(definition);\n }\n\n /** Check whether a user is in a cohort. */\n isMember(userId: string, cohortId: string) {\n return this.client.isUserInCohort(userId, cohortId);\n }\n}\n","/**\n * Churn shortcuts.\n */\nimport { ChurnAnalytics, UsageDecayConfig, PreventionActionConfig } from \"../../features/enterprise/churn\";\n\nexport class ChurnTracker {\n constructor(public readonly client: ChurnAnalytics) {}\n\n /** Track usage decay over time. */\n decay(userId: string, metric: UsageDecayConfig[\"metric\"], periods: UsageDecayConfig[\"periods\"]) {\n return this.client.trackUsageDecay({ userId, metric, periods });\n }\n\n /** Record an NPS / CSAT-style score. */\n nps(userId: string, score: number, feedback?: string) {\n return this.client.trackNPS({ userId, score, feedback });\n }\n\n /** Record an actual churn event. */\n churned(userId: string, churnType: \"voluntary\" | \"involuntary\", reason?: string) {\n return this.client.trackChurn({ userId, churnType, reason });\n }\n\n /** Record a retention/save action. */\n prevention(userId: string, actionType: PreventionActionConfig[\"actionType\"], details?: Record<string, unknown>) {\n return this.client.trackPreventionAction({ userId, actionType, details });\n }\n}\n","/**\n * Monetization shortcuts.\n */\nimport { Monetization, RevenueType } from \"../../features/enterprise/monetization\";\nimport type { CurrencyCode } from \"../../types\";\n\nexport class MonetizationTracker {\n constructor(public readonly client: Monetization) {}\n\n /** Track a revenue event. */\n revenue(\n userId: string,\n amount: number,\n currency: CurrencyCode,\n type: RevenueType,\n properties?: Record<string, unknown>\n ) {\n return this.client.trackRevenue({ userId, amount, currency, type, properties });\n }\n}\n","/**\n * Multi-path funnel shortcuts.\n */\nimport { MultiPathFunnels } from \"../../features/enterprise/multi-path-funnels\";\n\nexport class MultiPathFunnelTracker {\n constructor(public readonly client: MultiPathFunnels) {}\n\n /** Define a multi-path funnel. */\n define(definition: Parameters<MultiPathFunnels[\"defineFunnel\"]>[0]) {\n return this.client.defineFunnel(definition);\n }\n\n /** Record a step in a multi-path funnel. */\n step(funnelId: string, step: string, userId: string, properties?: Record<string, unknown>) {\n return this.client.trackStep({ funnelId, step, userId, properties });\n }\n\n /** Record a micro-conversion within a funnel. */\n microConversion(conversionId: string, userId: string, properties?: Record<string, unknown>) {\n return this.client.trackMicroConversion({ conversionId, userId, properties });\n }\n}\n","/**\n * Support shortcuts.\n */\nimport { SupportAnalytics, FeatureComplaintConfig } from \"../../features/enterprise/support\";\nimport type { SupportChannel, TicketStatus } from \"../../features/enterprise/support\";\n\nexport class SupportTracker {\n constructor(public readonly client: SupportAnalytics) {}\n\n /** New support ticket created. */\n ticket(\n ticketId: string,\n userId: string,\n subject: string,\n category: string,\n priority: \"low\" | \"medium\" | \"high\" | \"urgent\",\n channel: SupportChannel\n ) {\n return this.client.trackTicket({ ticketId, userId, subject, category, priority, channel });\n }\n\n /** Update an existing ticket. */\n update(ticketId: string, status: TicketStatus, properties?: Record<string, unknown>) {\n return this.client.updateTicket({ ticketId, status, properties });\n }\n\n /** Customer satisfaction (CSAT) response. */\n csat(ticketId: string, userId: string, score: number, feedback?: string) {\n return this.client.trackCSAT({ ticketId, userId, score, feedback });\n }\n\n /** Complaint about a specific feature. */\n featureComplaint(\n userId: string,\n featureId: string,\n complaintType: FeatureComplaintConfig[\"complaintType\"],\n severity: FeatureComplaintConfig[\"severity\"]\n ) {\n return this.client.trackFeatureComplaint({ userId, featureId, complaintType, severity });\n }\n}\n","/**\n * Acquisition shortcuts.\n */\nimport { AcquisitionAnalytics, AcquisitionSource, LifecycleStage } from \"../../features/enterprise/acquisition\";\nimport type { MoneyValue } from \"../../types\";\n\nexport class AcquisitionTracker {\n constructor(public readonly client: AcquisitionAnalytics) {}\n\n /** Track how a user was acquired. */\n acquired(userId: string, source: AcquisitionSource, properties?: Record<string, unknown>) {\n return this.client.trackAcquisition({ userId, source, properties });\n }\n\n /** Create a marketing campaign. */\n campaign(definition: Parameters<AcquisitionAnalytics[\"createCampaign\"]>[0]) {\n return this.client.createCampaign(definition);\n }\n\n /** Record campaign spend. */\n spend(campaignId: string, amount: MoneyValue, date: string) {\n return this.client.trackCampaignSpend({ campaignId, amount, date });\n }\n\n /** Track a lifecycle stage transition. */\n lifecycle(userId: string, fromStage: LifecycleStage, toStage: LifecycleStage) {\n return this.client.trackLifecycleTransition({ userId, fromStage, toStage });\n }\n}\n","/**\n * Path / journey shortcuts.\n */\nimport { PathAnalytics } from \"../../features/enterprise/paths\";\n\nexport class PathTracker {\n constructor(public readonly client: PathAnalytics) {}\n\n /** Record a screen-to-screen transition. */\n transition(userId: string, fromScreen: string, toScreen: string, properties?: Record<string, unknown>) {\n return this.client.trackTransition({ userId, fromScreen, toScreen, properties });\n }\n\n /** Record a feature usage in sequence. */\n sequence(userId: string, feature: string, order: number) {\n return this.client.trackFeatureSequence({ userId, feature, order });\n }\n\n /** Define an expected user path. */\n define(definition: Parameters<PathAnalytics[\"definePath\"]>[0]) {\n return this.client.definePath(definition);\n }\n}\n","/**\n * Alert shortcuts.\n */\nimport { AlertsAnalytics } from \"../../features/enterprise/alerts\";\n\nexport class AlertTracker {\n constructor(public readonly client: AlertsAnalytics) {}\n\n /** Create an alert rule. */\n create(definition: Parameters<AlertsAnalytics[\"createAlert\"]>[0]) {\n return this.client.createAlert(definition);\n }\n\n /** Update an alert rule. */\n update(alertId: string, updates: Record<string, unknown>) {\n return this.client.updateAlert(alertId, updates);\n }\n\n /** Delete an alert rule. */\n delete(alertId: string) {\n return this.client.deleteAlert(alertId);\n }\n\n /** Acknowledge a triggered alert instance. */\n acknowledge(instanceId: string, acknowledgedBy: string) {\n return this.client.acknowledgeAlert(instanceId, acknowledgedBy);\n }\n\n /** Resolve a triggered alert instance. */\n resolve(instanceId: string, notes?: string) {\n return this.client.resolveAlert(instanceId, notes);\n }\n\n /** Mute an alert rule for a number of minutes. */\n mute(alertId: string, durationMinutes: number) {\n return this.client.muteAlert(alertId, durationMinutes);\n }\n}\n","/**\n * Security shortcuts.\n */\nimport { SecurityAnalytics, DataAccessConfig, ComplianceEventConfig } from \"../../features/enterprise/security\";\n\nexport class SecurityTracker {\n constructor(public readonly client: SecurityAnalytics) {}\n\n /** Login attempt (success or failure). */\n login(userId: string, success: boolean, properties?: Record<string, unknown>) {\n return this.client.trackLoginAttempt({ userId, success, properties });\n }\n\n /** A user role changed. */\n roleChange(userId: string, changedBy: string, previousRole: string, newRole: string) {\n return this.client.trackRoleChange({ userId, changedBy, previousRole, newRole });\n }\n\n /** A permission was granted or revoked. */\n permissionChange(userId: string, changedBy: string, permission: string, action: \"granted\" | \"revoked\") {\n return this.client.trackPermissionChange({ userId, changedBy, permission, action });\n }\n\n /** A user accessed sensitive data. */\n dataAccess(userId: string, resourceType: string, accessType: DataAccessConfig[\"accessType\"], properties?: Record<string, unknown>) {\n return this.client.trackDataAccess({ userId, resourceType, accessType, properties });\n }\n\n /** A compliance-relevant event occurred (GDPR/SOC2 etc.). */\n compliance(userId: string, eventType: ComplianceEventConfig[\"eventType\"], properties?: Record<string, unknown>) {\n return this.client.trackComplianceEvent({ userId, eventType, properties });\n }\n}\n","/**\n * Forecasting shortcuts.\n */\nimport { Forecasting, ForecastMetric } from \"../../features/enterprise/forecasting\";\n\ntype Granularity = \"day\" | \"week\" | \"month\";\n\nexport class ForecastingTracker {\n constructor(public readonly client: Forecasting) {}\n\n /** Forecast active users. */\n activeUsers(metric: ForecastMetric, periods: number, granularity: Granularity) {\n return this.client.forecastActiveUsers({ metric, periods, granularity });\n }\n\n /** Forecast revenue. */\n revenue(periods: number, granularity: Granularity) {\n return this.client.forecastRevenue({ periods, granularity });\n }\n\n /** Forecast adoption of a specific feature. */\n featureAdoption(featureId: string, periods: number, granularity: Granularity) {\n return this.client.forecastFeatureAdoption({ featureId, periods, granularity });\n }\n\n /** Forecast churn. */\n churn(periods: number, granularity: Granularity) {\n return this.client.forecastChurn({ periods, granularity });\n }\n}\n","/**\n * @fileoverview Unified FlowGrid SDK facade.\n * @module flowgrid\n *\n * @description\n * A single class that aggregates every feature module so consumers can\n * instantiate the SDK once and access all tracking domains from one object.\n *\n * Every namespace returns an ergonomic *shortcut* wrapper exposing\n * positional-arg methods for the 80% case. The raw underlying class is\n * always available on `.client` for advanced configuration.\n *\n * @example\n * ```ts\n * import { FlowGrid } from \"flowgrid-sdk\";\n *\n * const fg = new FlowGrid(\"web_123\", \"https://core.flow-grid.xyz\", \"sk_live_xxx\");\n *\n * // Top-level shortcuts (the 80% case)\n * fg.track(\"signup_completed\", { plan: \"pro\" });\n * fg.page();\n * fg.identifyUser(\"u_1\", { email: \"alice@example.com\" });\n *\n * // Per-feature shortcuts\n * fg.cart.add({ productId: \"sku_1\", name: \"Tee\", price: 29, currency: \"USD\" });\n * fg.experiments.assign(\"checkout_v2\", \"u_1\");\n *\n * // Power-user escape hatch — raw class with full config surface\n * fg.events.client.track({ eventName: \"x\", sessionId: \"...\", category: \"...\" });\n * ```\n */\n\nimport { FlowGridTransport, FlowGridTransportConfig } from \"./client/transport\";\nimport { IdentityManager } from \"./utils/identity\";\n\nimport { Activation, TrackFeature, TrackPrompt, Experiment } from \"./features/core\";\nimport {\n PageViews,\n Sessions,\n Events,\n Identify,\n Funnels,\n Retention,\n Attribution,\n Heatmaps,\n PerformanceTracking,\n SessionReplay,\n} from \"./features/analytics\";\nimport {\n Products,\n CartTracking,\n Checkout,\n Purchases,\n Refunds,\n Promotions,\n WishlistTracking,\n CustomerLTV,\n SearchAnalytics,\n Subscriptions,\n} from \"./features/ecommerce\";\nimport {\n Engagement,\n Cohorts,\n ChurnAnalytics,\n Monetization,\n MultiPathFunnels,\n SupportAnalytics,\n AcquisitionAnalytics,\n PathAnalytics,\n AlertsAnalytics,\n SecurityAnalytics,\n Forecasting,\n} from \"./features/enterprise\";\n\nimport {\n ActivationTracker,\n ExperimentTracker,\n FeatureTracker,\n PromptTracker,\n EventTracker,\n PageViewTracker,\n SessionTracker,\n IdentifyTracker,\n FunnelTracker,\n RetentionTracker,\n AttributionTracker,\n HeatmapTracker,\n PerformanceTracker,\n ReplayTracker,\n ProductTracker,\n CartTracker,\n CheckoutTracker,\n PurchaseTracker,\n RefundTracker,\n PromotionTracker,\n WishlistTracker,\n SubscriptionTracker,\n LTVTracker,\n SearchTracker,\n EngagementTracker,\n CohortTracker,\n ChurnTracker,\n MonetizationTracker,\n MultiPathFunnelTracker,\n SupportTracker,\n AcquisitionTracker,\n PathTracker,\n AlertTracker,\n SecurityTracker,\n ForecastingTracker,\n} from \"./tracking\";\n\ntype Ctor<T> = new (\n webId: string,\n endpoint: string,\n apiKey: string,\n visitorId?: string,\n identityManager?: IdentityManager,\n config?: FlowGridTransportConfig\n) => T;\n\n// ============================================================================\n// PUBLIC INIT TYPES\n// ============================================================================\n\n/** Granular auto-instrumentation toggles. */\nexport interface AutoTrackOptions {\n sessions?: boolean;\n pageViews?: boolean;\n performance?: boolean | { resources?: boolean; minDuration?: number };\n heatmaps?: boolean | { movement?: boolean };\n attribution?: boolean;\n replay?: boolean | import(\"./features/analytics/replay\").SessionReplayOptions;\n /** Auto-track session depth + user activity transitions. Default on. */\n engagement?: boolean | { idleAfterMs?: number; pollMs?: number };\n}\n\n/** Top-level config for `FlowGrid.init()`. */\nexport interface FlowGridInitConfig {\n\n /** Public web/site identifier (e.g. `\"wx_abc123\"`). Required. */\n webId: string;\n\n /** Public API key. Required. */\n apiKey: string;\n\n /**\n * API base URL. Defaults to `\"https://core.flow-grid.xyz\"` — most users never\n * need to set this.\n */\n endpoint?: string;\n\n /**\n * Identify the user up-front so every subsequent event is attributed.\n * Equivalent to calling `fg.identifyUser(userId, traits)` after init.\n */\n user?: { userId: string; traits?: Record<string, unknown> };\n\n /**\n * Browser auto-instrumentation. `true` (default) turns on sessions, page\n * views, performance, heatmaps, and attribution. Pass an object to control\n * individual features, or `false` to opt out completely.\n */\n autoTrack?: boolean | AutoTrackOptions;\n\n /**\n * Session replay (rrweb). Off by default — opt in by passing `true` or an\n * options object. Requires the `rrweb` package (already a dependency).\n */\n replay?: boolean | import(\"./features/analytics/replay\").SessionReplayOptions;\n\n /**\n * Initial consent state. Equivalent to calling\n * `FlowGrid.setConsent({ analytics, marketing })` before any tracking.\n */\n consent?: { analytics?: boolean; marketing?: boolean };\n\n /** Low-level transport tunables (sampling, DNT, bot detection). */\n transport?: FlowGridTransportConfig;\n\n /** Optional pre-resolved visitor ID (server-side hydration). */\n visitorId?: string;\n\n /** Optional identity manager (advanced — visitor/session lifecycle). */\n identityManager?: IdentityManager;\n \n}\n\nconst DEFAULT_ENDPOINT = \"https://core.flow-grid.xyz\";\n\n/**\n * Unified FlowGrid SDK client. Instantiate once, use everywhere.\n *\n * Each feature is exposed as a lazily-initialised shortcut wrapper, so the\n * SDK has zero overhead for unused features.\n */\nexport class FlowGrid {\n /** Singleton created by {@link FlowGrid.init}. */\n private static _instance: FlowGrid | null = null;\n /** Teardown for the auto-instrumentation started during `init()`. */\n private _autoTrackStop: (() => void) | null = null;\n\n private readonly webId: string;\n private readonly endpoint: string;\n private readonly apiKey: string;\n private readonly visitorId?: string;\n private readonly identityManager?: IdentityManager;\n private readonly config?: FlowGridTransportConfig;\n\n private readonly _raw = new Map<string, unknown>();\n private readonly _wrapped = new Map<string, unknown>();\n\n /**\n * One-line init. Idempotent — calling twice returns the same instance and\n * logs a warning instead of starting auto-instrumentation again.\n *\n * @example\n * ```ts\n * // Painless: one line, sane defaults, everything on.\n * const fg = FlowGrid.init({ webId: \"wx_xxx\", apiKey: \"pk_xxx\" });\n *\n * // Or be explicit:\n * const fg = FlowGrid.init({\n * webId: \"wx_xxx\",\n * apiKey: \"pk_xxx\",\n * user: { userId: \"u_1\", traits: { plan: \"pro\" } },\n * replay: { sampleRate: 0.25, maskAllInputs: true },\n * consent: { analytics: true },\n * });\n * ```\n */\n static init(config: FlowGridInitConfig): FlowGrid {\n if (FlowGrid._instance) {\n if (typeof console !== \"undefined\") {\n console.warn(\"[FlowGrid] init() called more than once — returning existing instance.\");\n }\n return FlowGrid._instance;\n }\n\n if (!config?.webId || !config?.apiKey) {\n throw new Error(\"FlowGrid.init: `webId` and `apiKey` are required.\");\n }\n\n if (config.consent) {\n FlowGrid.setConsent(config.consent);\n }\n\n const fg = new FlowGrid(\n config.webId,\n config.endpoint ?? DEFAULT_ENDPOINT,\n config.apiKey,\n config.visitorId,\n config.identityManager,\n config.transport,\n );\n FlowGrid._instance = fg;\n\n // Identify the user before auto-instrumentation so the very first events\n // (session_start, page_view) carry the userId.\n if (config.user?.userId) {\n void fg.identifyUser(config.user.userId, config.user.traits);\n }\n\n const autoTrack = config.autoTrack;\n const replay = config.replay;\n const autoOpts: AutoTrackOptions =\n autoTrack === false ? { sessions: false, pageViews: false, performance: false, heatmaps: false, attribution: false, engagement: false }\n : autoTrack === true || autoTrack === undefined ? {}\n : autoTrack;\n\n if (replay !== undefined && autoOpts.replay === undefined) {\n autoOpts.replay = replay;\n }\n\n fg._autoTrackStop = fg.autoTrack({\n ...autoOpts,\n userId: config.user?.userId ?? (autoOpts as { userId?: string }).userId,\n });\n\n return fg;\n }\n\n /** Returns the singleton created by {@link FlowGrid.init}, if any. */\n static instance(): FlowGrid | null {\n return FlowGrid._instance;\n }\n\n /**\n * Reset the singleton — primarily for tests / hot-reload. Tears down any\n * active auto-instrumentation.\n */\n static reset(): void {\n if (FlowGrid._instance?._autoTrackStop) {\n try { FlowGrid._instance._autoTrackStop(); } catch { /* noop */ }\n }\n FlowGrid._instance = null;\n }\n\n /**\n * Explicit constructor for advanced cases (multi-tenant SSR, tests). Most\n * apps should use the static {@link FlowGrid.init} instead.\n */\n constructor(\n webId: string,\n endpoint: string,\n apiKey: string,\n visitorId?: string,\n identityManager?: IdentityManager,\n config?: FlowGridTransportConfig\n ) {\n this.webId = webId;\n this.endpoint = endpoint;\n this.apiKey = apiKey;\n this.visitorId = visitorId;\n this.identityManager = identityManager ?? new IdentityManager(visitorId ? { visitorId } : undefined);\n this.config = config;\n }\n\n private raw<T>(key: string, Klass: Ctor<T>): T {\n let instance = this._raw.get(key) as T | undefined;\n if (!instance) {\n instance = new Klass(\n this.webId,\n this.endpoint,\n this.apiKey,\n this.visitorId,\n this.identityManager,\n this.config\n );\n this._raw.set(key, instance);\n }\n return instance;\n }\n\n private wrap<W, T>(key: string, Klass: Ctor<T>, Wrapper: new (client: T) => W): W {\n let instance = this._wrapped.get(key) as W | undefined;\n if (!instance) {\n instance = new Wrapper(this.raw(key, Klass));\n this._wrapped.set(key, instance);\n }\n return instance;\n }\n\n // ---- Core ----\n get activation(): ActivationTracker { return this.wrap(\"activation\", Activation, ActivationTracker); }\n get features(): FeatureTracker { return this.wrap(\"features\", TrackFeature, FeatureTracker); }\n get prompts(): PromptTracker { return this.wrap(\"prompts\", TrackPrompt, PromptTracker); }\n get experiments(): ExperimentTracker { return this.wrap(\"experiments\", Experiment, ExperimentTracker); }\n\n // ---- Analytics ----\n get pageViews(): PageViewTracker { return this.wrap(\"pageViews\", PageViews, PageViewTracker); }\n get sessions(): SessionTracker { return this.wrap(\"sessions\", Sessions, SessionTracker); }\n get events(): EventTracker { return this.wrap(\"events\", Events, EventTracker); }\n get identify(): IdentifyTracker { return this.wrap(\"identify\", Identify, IdentifyTracker); }\n get funnels(): FunnelTracker { return this.wrap(\"funnels\", Funnels, FunnelTracker); }\n get retention(): RetentionTracker { return this.wrap(\"retention\", Retention, RetentionTracker); }\n get attribution(): AttributionTracker { return this.wrap(\"attribution\", Attribution, AttributionTracker); }\n get heatmaps(): HeatmapTracker { return this.wrap(\"heatmaps\", Heatmaps, HeatmapTracker); }\n get performance(): PerformanceTracker { return this.wrap(\"performance\", PerformanceTracking, PerformanceTracker); }\n get replay(): ReplayTracker { return this.wrap(\"replay\", SessionReplay, ReplayTracker); }\n\n // ---- Ecommerce ----\n get products(): ProductTracker { return this.wrap(\"products\", Products, ProductTracker); }\n get cart(): CartTracker { return this.wrap(\"cart\", CartTracking, CartTracker); }\n get checkout(): CheckoutTracker { return this.wrap(\"checkout\", Checkout, CheckoutTracker); }\n get purchases(): PurchaseTracker { return this.wrap(\"purchases\", Purchases, PurchaseTracker); }\n get refunds(): RefundTracker { return this.wrap(\"refunds\", Refunds, RefundTracker); }\n get promotions(): PromotionTracker { return this.wrap(\"promotions\", Promotions, PromotionTracker); }\n get wishlist(): WishlistTracker { return this.wrap(\"wishlist\", WishlistTracking, WishlistTracker); }\n get ltv(): LTVTracker { return this.wrap(\"ltv\", CustomerLTV, LTVTracker); }\n get search(): SearchTracker { return this.wrap(\"search\", SearchAnalytics, SearchTracker); }\n get subscriptions(): SubscriptionTracker { return this.wrap(\"subscriptions\", Subscriptions, SubscriptionTracker); }\n\n // ---- Enterprise ----\n get engagement(): EngagementTracker { return this.wrap(\"engagement\", Engagement, EngagementTracker); }\n get cohorts(): CohortTracker { return this.wrap(\"cohorts\", Cohorts, CohortTracker); }\n get churn(): ChurnTracker { return this.wrap(\"churn\", ChurnAnalytics, ChurnTracker); }\n get monetization(): MonetizationTracker { return this.wrap(\"monetization\", Monetization, MonetizationTracker); }\n get multiPathFunnels(): MultiPathFunnelTracker { return this.wrap(\"multiPathFunnels\", MultiPathFunnels, MultiPathFunnelTracker); }\n get support(): SupportTracker { return this.wrap(\"support\", SupportAnalytics, SupportTracker); }\n get acquisition(): AcquisitionTracker { return this.wrap(\"acquisition\", AcquisitionAnalytics, AcquisitionTracker); }\n get paths(): PathTracker { return this.wrap(\"paths\", PathAnalytics, PathTracker); }\n get alerts(): AlertTracker { return this.wrap(\"alerts\", AlertsAnalytics, AlertTracker); }\n get security(): SecurityTracker { return this.wrap(\"security\", SecurityAnalytics, SecurityTracker); }\n get forecasting(): ForecastingTracker { return this.wrap(\"forecasting\", Forecasting, ForecastingTracker); }\n\n // ---- Consent passthrough (static on transport) ----\n static setConsent = FlowGridTransport.setConsent.bind(FlowGridTransport);\n static hasConsent = FlowGridTransport.hasConsent.bind(FlowGridTransport);\n\n // ==========================================================================\n // TOP-LEVEL SHORTCUTS — the 80% case\n // ==========================================================================\n\n /**\n * Track a custom event.\n *\n * @example\n * ```ts\n * fg.track(\"signup_completed\", { plan: \"pro\" });\n * ```\n */\n track(\n eventName: string,\n properties?: Record<string, unknown>,\n options?: { userId?: string; sessionId?: string }\n ) {\n return this.events.track(eventName, properties, options);\n }\n\n /**\n * Record an experiment exposure for a user.\n *\n * For the browser-cached flow, prefer:\n * ```ts\n * await fg.experiments.init([{ experimentId, variants: [...] }]);\n * const variant = fg.experiments.variant(experimentId);\n * fg.experiment(\"checkout_v2\", { userId, variant });\n * ```\n */\n experiment(\n experimentId: string,\n options: { variant: string; userId: string }\n ) {\n return this.experiments.exposure(experimentId, options.userId, options.variant);\n }\n\n /**\n * Identify a user.\n *\n * @example\n * ```ts\n * fg.identifyUser(\"u_1\", { plan: \"pro\", email: \"alice@example.com\" });\n * ```\n */\n identifyUser(userId: string, traits?: Record<string, unknown>, anonymousId?: string) {\n return this.identify.user(userId, traits, anonymousId);\n }\n\n /**\n * Track a page view. Auto-detects URL/path/title/referrer in the browser.\n *\n * @example\n * ```ts\n * fg.page(); // auto-detect everything\n * fg.page(\"/pricing\", { plan: \"pro\" }); // override path + properties\n * ```\n */\n page(\n pathOrUrl?: string,\n properties?: Record<string, unknown>,\n options?: { title?: string; referrer?: string; userId?: string; sessionId?: string }\n ) {\n return this.pageViews.view(pathOrUrl, properties, options);\n }\n\n /**\n * Enable browser-side auto-instrumentation in a single call. Subscribes to:\n *\n * - **Sessions** — start, heartbeat, and end on `pagehide`\n * - **Page views** — initial view + SPA `pushState`/`popstate` + scroll-depth + time-on-page\n * - **Performance** — Core Web Vitals via `web-vitals` + navigation timing\n * - **Heatmaps** — click + scroll listeners\n * - **Engagement** — session depth, action count, and active/passive/idle transitions\n * - **Attribution** — UTM + referrer parsing on first load (requires `userId`)\n *\n * Each section can be disabled by setting it to `false`. Returns a single\n * teardown function that detaches every listener; safe no-op on the server.\n *\n * @example\n * ```ts\n * const stop = fg.autoTrack({ userId: \"u_1\" });\n * // ...later\n * stop();\n * ```\n */\n autoTrack(options: {\n userId?: string;\n sessions?: boolean;\n pageViews?: boolean;\n performance?: boolean | { resources?: boolean; minDuration?: number };\n heatmaps?: boolean | { movement?: boolean };\n attribution?: boolean;\n replay?: boolean | import(\"./features/analytics/replay\").SessionReplayOptions;\n engagement?: boolean | { idleAfterMs?: number; pollMs?: number };\n } = {}): () => void {\n const teardowns: Array<() => void> = [];\n const ctx = { userId: options.userId };\n\n if (options.sessions !== false) {\n teardowns.push(this.sessions.autoTrack(ctx.userId ? { user: { userId: ctx.userId } } : {}));\n }\n if (options.pageViews !== false) {\n teardowns.push(this.pageViews.autoTrack(ctx));\n }\n if (options.performance !== false) {\n const perfOpts = typeof options.performance === \"object\" ? options.performance : {};\n teardowns.push(this.performance.autoTrack({ ...perfOpts, userId: ctx.userId }));\n }\n if (options.heatmaps !== false) {\n const hmOpts = typeof options.heatmaps === \"object\" ? options.heatmaps : {};\n teardowns.push(this.heatmaps.autoTrack({ ...hmOpts, userId: ctx.userId }));\n }\n if (options.engagement !== false) {\n const engOpts = typeof options.engagement === \"object\" ? options.engagement : {};\n teardowns.push(this.engagement.client.autoTrack({ ...engOpts, userId: ctx.userId }));\n }\n if (options.attribution !== false && ctx.userId) {\n this.attribution.captureFromUrl(ctx.userId);\n }\n if (options.replay) {\n const replayOpts = typeof options.replay === \"object\" ? options.replay : {};\n // start() is async; track its resolved teardown so the outer stop()\n // tears down recording even if the user calls it before rrweb resolved.\n let resolvedStop: (() => void) | null = null;\n let stopRequested = false;\n void this.replay.start({ userId: ctx.userId, ...replayOpts }).then(stop => {\n if (stopRequested) { try { stop(); } catch { /* noop */ } }\n else { resolvedStop = stop; }\n });\n teardowns.push(() => {\n stopRequested = true;\n if (resolvedStop) { try { resolvedStop(); } catch { /* noop */ } }\n });\n }\n\n return () => { for (const t of teardowns) { try { t(); } catch { /* swallow */ } } };\n }\n}\n\nexport default FlowGrid;\n"],"names":["root","factory","exports","module","define","amd","this","inProgress","dataWebpackPrefix","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","m","d","definition","key","o","Object","defineProperty","enumerable","get","f","e","chunkId","Promise","all","keys","reduce","promises","u","g","globalThis","Function","window","obj","prop","prototype","hasOwnProperty","call","l","url","done","push","script","needAttach","scripts","document","getElementsByTagName","i","length","s","getAttribute","createElement","charset","nc","setAttribute","src","onScriptComplete","prev","event","onerror","onload","clearTimeout","timeout","doneFns","parentNode","removeChild","forEach","fn","setTimeout","bind","type","target","head","appendChild","r","Symbol","toStringTag","value","scriptUrl","importScripts","location","currentScript","tagName","toUpperCase","test","Error","replace","p","installedChunks","j","installedChunkData","promise","resolve","reject","error","errorType","realSrc","message","name","request","webpackJsonpCallback","parentChunkLoadingFunction","data","chunkIds","moreModules","runtime","some","id","chunkLoadingGlobal","FlowGridTransport","constructor","webId","endpoint","apiKey","visitorId","identityManager","config","trim","normalizeEndpoint","transportConfig","botDetection","respectDNT","sampleRate","drainEventBuffer","setConsent","consent","assign","hasConsent","category","isLikelyBot","navigator","webdriver","userAgent","isDNTEnabled","globalPrivacyControl","doNotTrack","getDeviceContext","_screen_width","screen","width","_screen_height","height","_device_type","_language","language","sendViaBeacon","eventName","properties","sendBeacon","resolvedVisitorId","getVisitorId","callType","encodeURIComponent","payload","JSON","stringify","web_id","visitor_id","event_name","Blob","postRaw","body","options","analytics","useBeacon","fetch","method","headers","keepalive","bufferEvent","localStorage","raw","getItem","EVENT_BUFFER_KEY","buffer","parse","MAX_BUFFER_EVENTS","serialized","TextEncoder","encode","MAX_BUFFER_SIZE","setItem","removeItem","evt","catch","init","validateInput","_bot","enriched","executeRequest","initFeature","extraHeaders","attempt","controller","AbortController","timeoutId","abort","TIMEOUT_MS","res","signal","status","MAX_RETRIES","backoff","ok","text","safeRead","statusText","json","includes","ms","Math","pow","MAX_PAYLOAD_SIZE","sensitiveKeys","lower","toLowerCase","console","warn","clean","startsWith","getCookie","match","cookie","RegExp","marketing","LEGACY_VISITOR_COOKIE","SESSION_KEY","SESSION_TOUCH_KEY","IdentityManager","sessionId","memoryStore","cookieDomain","visitorMaxAgeDays","sessionTimeoutMinutes","storage","detectBrowser","serverCookies","compat","resolveVisitorId","getSessionId","getMemorySessionId","existing","sessionStorage","lastTouch","Date","now","parseInt","String","newSession","generateSessionId","setVisitorId","persistVisitorId","clearSession","clearAll","deleteCookie","visitorCookieName","isBrowser","trackJsId","legacyId","readCookie","readLocalStorage","removeLegacyCookie","cookieId","lsId","serverVal","readServerCookie","newId","generateVisitorId","cookieName","writeCookie","result","maxAgeDays","maxAge","domain","secure","protocol","uuidV4","randomHex","crypto","randomUUID","c","random","toString","bytes","Uint8Array","getRandomValues","floor","Array","from","b","padStart","join","Activation","create","timestamp","toISOString","trackOnboardingStep","subtype","userId","stepId","stepName","stepOrder","totalSteps","progress","round","timeSpent","skipped","completeOnboarding","totalTimeSpent","stepsCompleted","stepsSkipped","completionRate","trackFirstAction","actionName","timeSinceSignup","source","trackSignup","TrackFeature","action","trackUsage","featureId","featureName","duration","success","TrackPrompt","trackSubmission","promptId","promptType","model","inputTokens","conversationId","trackResponse","responseTime","outputTokens","completed","qualityScore","trackFeedback","feedbackType","rating","comment","trackConversation","turnCount","totalDuration","fnv1a","input","hash","charCodeAt","ASSIGNMENT_STORAGE_KEY","ASSIGNMENT_COOKIE_KEY","Experiment","experiments","assignments","parseAssignmentCookie","decoded","decodeURIComponent","parsed","readAssignmentCookie","writeAssignmentCookie","ASSIGNMENT_COOKIE_MAX_AGE_DAYS","sameSite","loadAssignments","stored","cookieAssignments","saveAssignments","injectAssignments","getAssignments","hydrateFromCookies","reader","hydrateFromCookieHeader","cookieHeader","parts","split","prefix","find","slice","serializeAssignmentCookie","clearAssignments","getOrCreateAnonId","ANON_ID_KEY","deterministicAssign","experimentId","variants","hashValue","totalWeight","v","weight","bucket","cumulative","assignVariant","assignedVariantId","variantId","assignmentSource","verifyExperiments","configs","map","exp","experiment_id","response","isArray","item","verified","initExperiments","getLocalVariant","trackLocalConversion","metricName","metricValue","track","variant","trackConversion","trackExposure","getWindow","getDocument","combineTeardowns","fns","PageViews","path","title","referrer","trackScrollDepth","scrollDepth","min","max","timeAtDepth","trackTimeOnPage","engaged","trackExit","autoTrack","win","doc","currentPath","pathname","pageStart","maxDepth","sentDepths","Set","fireView","href","flushTimeOnPage","onRouteChange","clear","origPush","history","pushState","origReplace","replaceState","args","apply","dispatchEvent","Event","popHandler","locHandler","addEventListener","onScroll","docEl","documentElement","scrollTop","scrollY","scrollHeight","innerHeight","depth","t","has","add","passive","onHide","visibilityState","removeEventListener","Sessions","start","user","device","utm","utmSource","medium","utmMedium","campaign","utmCampaign","landingPage","update","end","heartbeat","heartbeatMs","STORE_KEY","startPromise","then","beat","setInterval","clearInterval","Events","label","nonInteraction","trackBatch","events","count","trackClick","trackForm","trackSearch","query","resultsCount","resultClicked","clickedPosition","filters","trackError","stack","fatal","context","userAction","Identify","anonymousId","traits","updateTraits","alias","previousId","group","groupId","reset","Funnels","funnelId","description","steps","trackStep","step","stepNumber","trackComplete","trackAbandon","lastStep","reason","analyze","filter","range","compare","baselineFilter","comparisonFilter","list","Retention","trackActivity","trackLifecycleChange","stage","previousStage","Attribution","trackTouchpoint","channel","content","term","recordConversion","conversionType","conversionId","captureFromUrl","params","URLSearchParams","search","utmTerm","utmContent","Heatmaps","lastMovementTime","lastScrollTime","pageUrl","x","y","normalizedX","viewportWidth","normalizedY","viewportHeight","elementSelector","elementText","substring","trackMovement","MOVEMENT_THROTTLE_MS","recorded","interactionId","viewport","trackScroll","SCROLL_THROTTLE_MS","maxScrollDepth","pageHeight","timeAtDepths","trackRageClick","clickCount","onClick","el","clientX","clientY","innerWidth","className","textContent","capture","top","moveTeardown","movement","onMove","PerformanceTracking","trackWebVitals","trackPageLoad","trackResource","trackApiCall","statusCode","teardowns","cancelled","wv","send","metric","onLCP","onCLS","onINP","onFCP","onTTFB","onFID","reportNavigation","nav","performance","getEntriesByType","dnsTime","domainLookupEnd","domainLookupStart","tcpTime","connectEnd","connectStart","ttfb","responseStart","requestStart","domContentLoaded","domContentLoadedEventEnd","loadTime","loadEventEnd","domInteractive","transferSize","readyState","onLoad","once","resources","PerformanceObserver","minDuration","obs","entry","getEntries","initiator","initiatorType","resourceUrl","resourceType","observe","buffered","disconnect","STORAGE_KEY","RECORDER_VERSION","SessionReplay","disabled","active","state","enabled","setState","stopped","emitStatus","stop","rrweb","handleError","toError","phase","resolveSessionId","normalizedOptions","normalizeOptions","startedAtMs","boundUserId","startedAt","sequence","bufferBytes","totalBytes","droppedEvents","flushTimer","flush","flushIntervalMs","durationGuard","maxDurationMs","onVisibility","onPageHide","stopRecording","record","emit","captureEvent","maskAllInputs","maskTextClass","blockClass","ignoreClass","cleanupActive","enable","disable","isFinal","eventsCount","byteSize","capturedAt","idempotencyKey","createIdempotencyKey","metadata","postReplayChunk","getPageUrl","privacy","createPrivacyMetadata","recorderVersion","onFlush","identify","getStatus","createStatus","sendChunk","measureEvents","session_id","user_id","started_at","captured_at","page_url","idempotency_key","compression","is_final","chunk_kind","flush_reason","dropped_events","recorder_version","size","onDrop","maxBytes","flushBytes","bufferedEvents","bufferedBytes","lastFlushReason","lastError","onStatus","onError","samplingState","masking_mode","blocked_selectors","selectorList","redacted_fields","consent_state","sampling_state","selector","fresh","generateId","cryptoObj","Products","view","product","productId","brand","price","currency","imageUrl","reviewCount","stockStatus","attributes","searchQuery","impression","productCount","products","click","listId","position","quickView","interaction","CartTracking","addItem","lineTotal","quantity","discount","cartId","updateItem","previousQuantity","newQuantity","quantityChange","cart","cartValue","total","itemCount","abandon","applyCoupon","couponCode","Checkout","begin","option","addShipping","shipping","shippingMethod","shippingCost","cost","addPayment","payment","paymentMethod","paymentAttempt","errorCode","Purchases","order","orderId","items","subtotal","discountTotal","shippingTotal","taxTotal","coupons","affiliation","revenue","sum","attribution","statusChange","newStatus","previousStatus","shipped","delivered","deliveredAt","Refunds","refundId","amount","isFullRefund","initiatedBy","approve","approvedAmount","deny","denialReason","complete","processedAmount","Promotions","promotionId","creative","page","destinationUrl","couponUsed","code","discountValue","discountType","orderValueBefore","orderValueAfter","savings","couponAttempt","failureReason","WishlistTracking","wishlistId","remove","wishlist","moveToCart","share","CustomerLTV","recordAcquisitionCost","updateSegment","segment","SearchAnalytics","hasResults","sortBy","trackRefinement","originalQuery","refinedQuery","refinementType","trackSuggestion","partialQuery","selectedSuggestion","suggestionPosition","Subscriptions","subscriptionId","plan","mrr","billingCycle","trialDays","coupon","isTrialing","change","mrrDiff","newMrr","previousMrr","previousPlan","newPlan","mrrChange","changeType","cancel","lostMrr","feedback","immediate","renew","trialConverted","trialExpired","Engagement","trackDwellTime","dwellTimeMs","wasActive","trackSessionDepth","depthScore","pagesVisited","featuresUsed","actionsTaken","pageScore","featureScore","actionScore","calculateSessionDepthScore","durationMs","trackContentConsumption","contentId","contentType","percentageConsumed","timeSpentMs","trackUserActivity","activityType","autoTrackDwell","activeMs","lastTick","torndown","idleAfterMs","pollMs","lastInputAt","currentState","stateEnteredAt","onNav","onInput","ev","featureAttr","closest","transition","next","tick","ticker","depthSent","sendDepth","Cohorts","createCohort","cohortId","cohortType","rules","dynamic","timeWindow","updateCohort","updates","rest","deleteCohort","listCohorts","isUserInCohort","createSegment","compareCohorts","ChurnAnalytics","trackUsageDecay","trackNPS","trackChurn","trackPreventionAction","updatePreventionOutcome","actionType","outcome","Monetization","trackRevenue","revenueType","restConfig","trackExpansion","fromPlan","toPlan","additionalRevenue","trackContraction","reducedRevenue","MultiPathFunnels","defineFunnel","pathsWithIds","paths","pathId","microConversions","goalEvent","updateFunnel","deleteFunnel","trackMicroConversion","trackGoal","analyzeFunnel","comparePaths","listFunnels","SupportAnalytics","trackTicket","createdAt","updateTicket","ticketId","agentId","responseTimeMs","trackResolution","resolutionTimeMs","interactionCount","firstContactResolution","trackCSAT","trackFeatureComplaint","AcquisitionAnalytics","trackAcquisition","trackLifecycleTransition","createCampaign","trackCampaignSpend","PathAnalytics","trackTransition","trackFeatureSequence","definePath","AlertsAnalytics","createAlert","alertId","updateAlert","deleteAlert","toggleAlert","listAlerts","acknowledgeAlert","instanceId","acknowledgedBy","resolveAlert","notes","muteAlert","durationMinutes","detectAnomalies","configureNotification","testNotification","SecurityAnalytics","trackLoginAttempt","eventType","severity","determineEventSeverity","trackLogout","trackPasswordChange","forced","trackRoleChange","trackPermissionChange","trackDataAccess","trackDataExport","recordCount","trackSuspiciousActivity","details","trackComplianceEvent","Forecasting","forecastActiveUsers","includeConfidence","forecastRevenue","forecastMRR","forecastFeatureAdoption","forecastChurn","forecastSignups","compareScenarios","forecastCustomMetric","customMetricName","ActivationTracker","client","signup","props","onboardingStep","extra","onboardingComplete","firstAction","FeatureTracker","used","PromptTracker","submitted","responded","conversation","ExperimentTracker","exposure","conversion","localConversion","PageViewTracker","pathOrUrl","opts","browserDefaults","isFullUrl","URL","scroll","time","exit","SessionTracker","EventTracker","batch","elementId","form","formId","formName","IdentifyTracker","FunnelTracker","RetentionTracker","AttributionTracker","touchpoint","HeatmapTracker","PerformanceTracker","webVitals","vitals","pageLoad","timings","resource","ReplayTracker","ProductTracker","listName","CartTracker","CheckoutTracker","PurchaseTracker","RefundTracker","PromotionTracker","WishlistTracker","LTVTracker","acquisitionCost","newSegment","SearchTracker","refine","suggestion","SubscriptionTracker","EngagementTracker","dwell","sessionDepth","contentConsumption","activity","CohortTracker","isMember","ChurnTracker","decay","periods","nps","score","churned","churnType","prevention","MonetizationTracker","MultiPathFunnelTracker","microConversion","SupportTracker","ticket","subject","priority","csat","featureComplaint","complaintType","AcquisitionTracker","acquired","spend","campaignId","date","lifecycle","fromStage","toStage","PathTracker","fromScreen","toScreen","feature","AlertTracker","acknowledge","mute","SecurityTracker","login","roleChange","changedBy","previousRole","newRole","permissionChange","permission","dataAccess","accessType","compliance","ForecastingTracker","activeUsers","granularity","featureAdoption","churn","FlowGrid","_instance","fg","transport","identifyUser","replay","autoOpts","sessions","pageViews","heatmaps","engagement","_autoTrackStop","instance","_raw","Map","_wrapped","Klass","set","wrap","Wrapper","activation","features","prompts","funnels","retention","checkout","purchases","refunds","promotions","ltv","subscriptions","cohorts","monetization","multiPathFunnels","support","acquisition","alerts","security","forecasting","experiment","ctx","perfOpts","hmOpts","engOpts","replayOpts","resolvedStop","stopRequested"],"sourceRoot":""}