@tracelog/lib 0.0.1

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 (301) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +217 -0
  3. package/dist/browser/tracelog.js +4040 -0
  4. package/dist/browser/web-vitals-CCnqwnC8.mjs +198 -0
  5. package/dist/cjs/api.d.ts +46 -0
  6. package/dist/cjs/api.js +224 -0
  7. package/dist/cjs/app.constants.d.ts +1 -0
  8. package/dist/cjs/app.constants.js +5 -0
  9. package/dist/cjs/app.d.ts +59 -0
  10. package/dist/cjs/app.js +272 -0
  11. package/dist/cjs/app.types.d.ts +6 -0
  12. package/dist/cjs/app.types.js +22 -0
  13. package/dist/cjs/constants/api.constants.d.ts +4 -0
  14. package/dist/cjs/constants/api.constants.js +18 -0
  15. package/dist/cjs/constants/browser.constants.d.ts +3 -0
  16. package/dist/cjs/constants/browser.constants.js +41 -0
  17. package/dist/cjs/constants/index.d.ts +8 -0
  18. package/dist/cjs/constants/index.js +24 -0
  19. package/dist/cjs/constants/initialization.constants.d.ts +40 -0
  20. package/dist/cjs/constants/initialization.constants.js +48 -0
  21. package/dist/cjs/constants/limits.constants.d.ts +25 -0
  22. package/dist/cjs/constants/limits.constants.js +40 -0
  23. package/dist/cjs/constants/security.constants.d.ts +1 -0
  24. package/dist/cjs/constants/security.constants.js +12 -0
  25. package/dist/cjs/constants/storage.constants.d.ts +9 -0
  26. package/dist/cjs/constants/storage.constants.js +22 -0
  27. package/dist/cjs/constants/timing.constants.d.ts +22 -0
  28. package/dist/cjs/constants/timing.constants.js +34 -0
  29. package/dist/cjs/constants/validation.constants.d.ts +13 -0
  30. package/dist/cjs/constants/validation.constants.js +31 -0
  31. package/dist/cjs/handlers/click.handler.d.ts +17 -0
  32. package/dist/cjs/handlers/click.handler.js +199 -0
  33. package/dist/cjs/handlers/error.handler.d.ts +15 -0
  34. package/dist/cjs/handlers/error.handler.js +97 -0
  35. package/dist/cjs/handlers/network.handler.d.ts +16 -0
  36. package/dist/cjs/handlers/network.handler.js +136 -0
  37. package/dist/cjs/handlers/page-view.handler.d.ts +15 -0
  38. package/dist/cjs/handlers/page-view.handler.js +83 -0
  39. package/dist/cjs/handlers/performance.handler.d.ts +19 -0
  40. package/dist/cjs/handlers/performance.handler.js +255 -0
  41. package/dist/cjs/handlers/scroll.handler.d.ts +16 -0
  42. package/dist/cjs/handlers/scroll.handler.js +138 -0
  43. package/dist/cjs/handlers/session.handler.d.ts +29 -0
  44. package/dist/cjs/handlers/session.handler.js +357 -0
  45. package/dist/cjs/integrations/google-analytics.integration.d.ts +18 -0
  46. package/dist/cjs/integrations/google-analytics.integration.js +159 -0
  47. package/dist/cjs/listeners/activity-listener-manager.d.ts +8 -0
  48. package/dist/cjs/listeners/activity-listener-manager.js +32 -0
  49. package/dist/cjs/listeners/index.d.ts +6 -0
  50. package/dist/cjs/listeners/index.js +14 -0
  51. package/dist/cjs/listeners/input-listener-managers.d.ts +15 -0
  52. package/dist/cjs/listeners/input-listener-managers.js +58 -0
  53. package/dist/cjs/listeners/listeners.types.d.ts +4 -0
  54. package/dist/cjs/listeners/listeners.types.js +2 -0
  55. package/dist/cjs/listeners/touch-listener-manager.d.ts +10 -0
  56. package/dist/cjs/listeners/touch-listener-manager.js +56 -0
  57. package/dist/cjs/listeners/unload-listener-manager.d.ts +8 -0
  58. package/dist/cjs/listeners/unload-listener-manager.js +30 -0
  59. package/dist/cjs/listeners/visibility-listener-manager.d.ts +12 -0
  60. package/dist/cjs/listeners/visibility-listener-manager.js +83 -0
  61. package/dist/cjs/managers/api.manager.d.ts +3 -0
  62. package/dist/cjs/managers/api.manager.js +14 -0
  63. package/dist/cjs/managers/config.manager.d.ts +7 -0
  64. package/dist/cjs/managers/config.manager.js +94 -0
  65. package/dist/cjs/managers/cross-tab-session.manager.d.ts +170 -0
  66. package/dist/cjs/managers/cross-tab-session.manager.js +730 -0
  67. package/dist/cjs/managers/event.manager.d.ts +61 -0
  68. package/dist/cjs/managers/event.manager.js +508 -0
  69. package/dist/cjs/managers/sampling.manager.d.ts +8 -0
  70. package/dist/cjs/managers/sampling.manager.js +53 -0
  71. package/dist/cjs/managers/sender.manager.d.ts +46 -0
  72. package/dist/cjs/managers/sender.manager.js +304 -0
  73. package/dist/cjs/managers/session-recovery.manager.d.ts +65 -0
  74. package/dist/cjs/managers/session-recovery.manager.js +237 -0
  75. package/dist/cjs/managers/session.manager.d.ts +72 -0
  76. package/dist/cjs/managers/session.manager.js +587 -0
  77. package/dist/cjs/managers/state.manager.d.ts +5 -0
  78. package/dist/cjs/managers/state.manager.js +23 -0
  79. package/dist/cjs/managers/storage.manager.d.ts +10 -0
  80. package/dist/cjs/managers/storage.manager.js +81 -0
  81. package/dist/cjs/managers/tags.manager.d.ts +12 -0
  82. package/dist/cjs/managers/tags.manager.js +289 -0
  83. package/dist/cjs/managers/user.manager.d.ts +7 -0
  84. package/dist/cjs/managers/user.manager.js +22 -0
  85. package/dist/cjs/public-api.d.ts +1 -0
  86. package/dist/cjs/public-api.js +37 -0
  87. package/dist/cjs/types/api.types.d.ts +21 -0
  88. package/dist/cjs/types/api.types.js +25 -0
  89. package/dist/cjs/types/common.types.d.ts +1 -0
  90. package/dist/cjs/types/common.types.js +2 -0
  91. package/dist/cjs/types/config.types.d.ts +104 -0
  92. package/dist/cjs/types/config.types.js +2 -0
  93. package/dist/cjs/types/device.types.d.ts +6 -0
  94. package/dist/cjs/types/device.types.js +10 -0
  95. package/dist/cjs/types/event.types.d.ts +104 -0
  96. package/dist/cjs/types/event.types.js +25 -0
  97. package/dist/cjs/types/index.d.ts +13 -0
  98. package/dist/cjs/types/index.js +29 -0
  99. package/dist/cjs/types/log.types.d.ts +4 -0
  100. package/dist/cjs/types/log.types.js +2 -0
  101. package/dist/cjs/types/mode.types.d.ts +7 -0
  102. package/dist/cjs/types/mode.types.js +11 -0
  103. package/dist/cjs/types/queue.types.d.ts +23 -0
  104. package/dist/cjs/types/queue.types.js +2 -0
  105. package/dist/cjs/types/session.types.d.ts +65 -0
  106. package/dist/cjs/types/session.types.js +2 -0
  107. package/dist/cjs/types/state.types.d.ts +12 -0
  108. package/dist/cjs/types/state.types.js +2 -0
  109. package/dist/cjs/types/tag.types.d.ts +43 -0
  110. package/dist/cjs/types/tag.types.js +31 -0
  111. package/dist/cjs/types/validation-error.types.d.ts +42 -0
  112. package/dist/cjs/types/validation-error.types.js +68 -0
  113. package/dist/cjs/types/web-vitals.types.d.ts +6 -0
  114. package/dist/cjs/types/web-vitals.types.js +2 -0
  115. package/dist/cjs/types/window.types.d.ts +17 -0
  116. package/dist/cjs/types/window.types.js +2 -0
  117. package/dist/cjs/utils/browser/device-detector.utils.d.ts +6 -0
  118. package/dist/cjs/utils/browser/device-detector.utils.js +71 -0
  119. package/dist/cjs/utils/browser/index.d.ts +2 -0
  120. package/dist/cjs/utils/browser/index.js +18 -0
  121. package/dist/cjs/utils/browser/utm-params.utils.d.ts +6 -0
  122. package/dist/cjs/utils/browser/utm-params.utils.js +37 -0
  123. package/dist/cjs/utils/data/index.d.ts +1 -0
  124. package/dist/cjs/utils/data/index.js +17 -0
  125. package/dist/cjs/utils/data/uuid.utils.d.ts +5 -0
  126. package/dist/cjs/utils/data/uuid.utils.js +18 -0
  127. package/dist/cjs/utils/index.d.ts +6 -0
  128. package/dist/cjs/utils/index.js +22 -0
  129. package/dist/cjs/utils/logging/debug-logger.utils.d.ts +56 -0
  130. package/dist/cjs/utils/logging/debug-logger.utils.js +139 -0
  131. package/dist/cjs/utils/logging/index.d.ts +1 -0
  132. package/dist/cjs/utils/logging/index.js +5 -0
  133. package/dist/cjs/utils/network/index.d.ts +1 -0
  134. package/dist/cjs/utils/network/index.js +17 -0
  135. package/dist/cjs/utils/network/url.utils.d.ts +20 -0
  136. package/dist/cjs/utils/network/url.utils.js +172 -0
  137. package/dist/cjs/utils/security/index.d.ts +1 -0
  138. package/dist/cjs/utils/security/index.js +17 -0
  139. package/dist/cjs/utils/security/sanitize.utils.d.ts +32 -0
  140. package/dist/cjs/utils/security/sanitize.utils.js +319 -0
  141. package/dist/cjs/utils/validations/config-validations.utils.d.ts +42 -0
  142. package/dist/cjs/utils/validations/config-validations.utils.js +297 -0
  143. package/dist/cjs/utils/validations/event-validations.utils.d.ts +12 -0
  144. package/dist/cjs/utils/validations/event-validations.utils.js +30 -0
  145. package/dist/cjs/utils/validations/index.d.ts +5 -0
  146. package/dist/cjs/utils/validations/index.js +21 -0
  147. package/dist/cjs/utils/validations/metadata-validations.utils.d.ts +22 -0
  148. package/dist/cjs/utils/validations/metadata-validations.utils.js +115 -0
  149. package/dist/cjs/utils/validations/type-guards.utils.d.ts +6 -0
  150. package/dist/cjs/utils/validations/type-guards.utils.js +31 -0
  151. package/dist/cjs/utils/validations/url-validations.utils.d.ts +15 -0
  152. package/dist/cjs/utils/validations/url-validations.utils.js +47 -0
  153. package/dist/esm/api.d.ts +46 -0
  154. package/dist/esm/api.js +183 -0
  155. package/dist/esm/app.constants.d.ts +1 -0
  156. package/dist/esm/app.constants.js +1 -0
  157. package/dist/esm/app.d.ts +59 -0
  158. package/dist/esm/app.js +268 -0
  159. package/dist/esm/app.types.d.ts +6 -0
  160. package/dist/esm/app.types.js +6 -0
  161. package/dist/esm/constants/api.constants.d.ts +4 -0
  162. package/dist/esm/constants/api.constants.js +14 -0
  163. package/dist/esm/constants/browser.constants.d.ts +3 -0
  164. package/dist/esm/constants/browser.constants.js +38 -0
  165. package/dist/esm/constants/index.d.ts +8 -0
  166. package/dist/esm/constants/index.js +8 -0
  167. package/dist/esm/constants/initialization.constants.d.ts +40 -0
  168. package/dist/esm/constants/initialization.constants.js +45 -0
  169. package/dist/esm/constants/limits.constants.d.ts +25 -0
  170. package/dist/esm/constants/limits.constants.js +37 -0
  171. package/dist/esm/constants/security.constants.d.ts +1 -0
  172. package/dist/esm/constants/security.constants.js +9 -0
  173. package/dist/esm/constants/storage.constants.d.ts +9 -0
  174. package/dist/esm/constants/storage.constants.js +11 -0
  175. package/dist/esm/constants/timing.constants.d.ts +22 -0
  176. package/dist/esm/constants/timing.constants.js +31 -0
  177. package/dist/esm/constants/validation.constants.d.ts +13 -0
  178. package/dist/esm/constants/validation.constants.js +28 -0
  179. package/dist/esm/handlers/click.handler.d.ts +17 -0
  180. package/dist/esm/handlers/click.handler.js +195 -0
  181. package/dist/esm/handlers/error.handler.d.ts +15 -0
  182. package/dist/esm/handlers/error.handler.js +93 -0
  183. package/dist/esm/handlers/network.handler.d.ts +16 -0
  184. package/dist/esm/handlers/network.handler.js +132 -0
  185. package/dist/esm/handlers/page-view.handler.d.ts +15 -0
  186. package/dist/esm/handlers/page-view.handler.js +79 -0
  187. package/dist/esm/handlers/performance.handler.d.ts +19 -0
  188. package/dist/esm/handlers/performance.handler.js +218 -0
  189. package/dist/esm/handlers/scroll.handler.d.ts +16 -0
  190. package/dist/esm/handlers/scroll.handler.js +134 -0
  191. package/dist/esm/handlers/session.handler.d.ts +29 -0
  192. package/dist/esm/handlers/session.handler.js +353 -0
  193. package/dist/esm/integrations/google-analytics.integration.d.ts +18 -0
  194. package/dist/esm/integrations/google-analytics.integration.js +155 -0
  195. package/dist/esm/listeners/activity-listener-manager.d.ts +8 -0
  196. package/dist/esm/listeners/activity-listener-manager.js +28 -0
  197. package/dist/esm/listeners/index.d.ts +6 -0
  198. package/dist/esm/listeners/index.js +5 -0
  199. package/dist/esm/listeners/input-listener-managers.d.ts +15 -0
  200. package/dist/esm/listeners/input-listener-managers.js +53 -0
  201. package/dist/esm/listeners/listeners.types.d.ts +4 -0
  202. package/dist/esm/listeners/listeners.types.js +1 -0
  203. package/dist/esm/listeners/touch-listener-manager.d.ts +10 -0
  204. package/dist/esm/listeners/touch-listener-manager.js +52 -0
  205. package/dist/esm/listeners/unload-listener-manager.d.ts +8 -0
  206. package/dist/esm/listeners/unload-listener-manager.js +26 -0
  207. package/dist/esm/listeners/visibility-listener-manager.d.ts +12 -0
  208. package/dist/esm/listeners/visibility-listener-manager.js +79 -0
  209. package/dist/esm/managers/api.manager.d.ts +3 -0
  210. package/dist/esm/managers/api.manager.js +10 -0
  211. package/dist/esm/managers/config.manager.d.ts +7 -0
  212. package/dist/esm/managers/config.manager.js +90 -0
  213. package/dist/esm/managers/cross-tab-session.manager.d.ts +170 -0
  214. package/dist/esm/managers/cross-tab-session.manager.js +726 -0
  215. package/dist/esm/managers/event.manager.d.ts +61 -0
  216. package/dist/esm/managers/event.manager.js +504 -0
  217. package/dist/esm/managers/sampling.manager.d.ts +8 -0
  218. package/dist/esm/managers/sampling.manager.js +49 -0
  219. package/dist/esm/managers/sender.manager.d.ts +46 -0
  220. package/dist/esm/managers/sender.manager.js +300 -0
  221. package/dist/esm/managers/session-recovery.manager.d.ts +65 -0
  222. package/dist/esm/managers/session-recovery.manager.js +233 -0
  223. package/dist/esm/managers/session.manager.d.ts +72 -0
  224. package/dist/esm/managers/session.manager.js +583 -0
  225. package/dist/esm/managers/state.manager.d.ts +5 -0
  226. package/dist/esm/managers/state.manager.js +19 -0
  227. package/dist/esm/managers/storage.manager.d.ts +10 -0
  228. package/dist/esm/managers/storage.manager.js +77 -0
  229. package/dist/esm/managers/tags.manager.d.ts +12 -0
  230. package/dist/esm/managers/tags.manager.js +285 -0
  231. package/dist/esm/managers/user.manager.d.ts +7 -0
  232. package/dist/esm/managers/user.manager.js +18 -0
  233. package/dist/esm/public-api.d.ts +1 -0
  234. package/dist/esm/public-api.js +1 -0
  235. package/dist/esm/types/api.types.d.ts +21 -0
  236. package/dist/esm/types/api.types.js +22 -0
  237. package/dist/esm/types/common.types.d.ts +1 -0
  238. package/dist/esm/types/common.types.js +1 -0
  239. package/dist/esm/types/config.types.d.ts +104 -0
  240. package/dist/esm/types/config.types.js +1 -0
  241. package/dist/esm/types/device.types.d.ts +6 -0
  242. package/dist/esm/types/device.types.js +7 -0
  243. package/dist/esm/types/event.types.d.ts +104 -0
  244. package/dist/esm/types/event.types.js +22 -0
  245. package/dist/esm/types/index.d.ts +13 -0
  246. package/dist/esm/types/index.js +13 -0
  247. package/dist/esm/types/log.types.d.ts +4 -0
  248. package/dist/esm/types/log.types.js +1 -0
  249. package/dist/esm/types/mode.types.d.ts +7 -0
  250. package/dist/esm/types/mode.types.js +8 -0
  251. package/dist/esm/types/queue.types.d.ts +23 -0
  252. package/dist/esm/types/queue.types.js +1 -0
  253. package/dist/esm/types/session.types.d.ts +65 -0
  254. package/dist/esm/types/session.types.js +1 -0
  255. package/dist/esm/types/state.types.d.ts +12 -0
  256. package/dist/esm/types/state.types.js +1 -0
  257. package/dist/esm/types/tag.types.d.ts +43 -0
  258. package/dist/esm/types/tag.types.js +28 -0
  259. package/dist/esm/types/validation-error.types.d.ts +42 -0
  260. package/dist/esm/types/validation-error.types.js +59 -0
  261. package/dist/esm/types/web-vitals.types.d.ts +6 -0
  262. package/dist/esm/types/web-vitals.types.js +1 -0
  263. package/dist/esm/types/window.types.d.ts +17 -0
  264. package/dist/esm/types/window.types.js +1 -0
  265. package/dist/esm/utils/browser/device-detector.utils.d.ts +6 -0
  266. package/dist/esm/utils/browser/device-detector.utils.js +67 -0
  267. package/dist/esm/utils/browser/index.d.ts +2 -0
  268. package/dist/esm/utils/browser/index.js +2 -0
  269. package/dist/esm/utils/browser/utm-params.utils.d.ts +6 -0
  270. package/dist/esm/utils/browser/utm-params.utils.js +33 -0
  271. package/dist/esm/utils/data/index.d.ts +1 -0
  272. package/dist/esm/utils/data/index.js +1 -0
  273. package/dist/esm/utils/data/uuid.utils.d.ts +5 -0
  274. package/dist/esm/utils/data/uuid.utils.js +14 -0
  275. package/dist/esm/utils/index.d.ts +6 -0
  276. package/dist/esm/utils/index.js +6 -0
  277. package/dist/esm/utils/logging/debug-logger.utils.d.ts +56 -0
  278. package/dist/esm/utils/logging/debug-logger.utils.js +136 -0
  279. package/dist/esm/utils/logging/index.d.ts +1 -0
  280. package/dist/esm/utils/logging/index.js +1 -0
  281. package/dist/esm/utils/network/index.d.ts +1 -0
  282. package/dist/esm/utils/network/index.js +1 -0
  283. package/dist/esm/utils/network/url.utils.d.ts +20 -0
  284. package/dist/esm/utils/network/url.utils.js +166 -0
  285. package/dist/esm/utils/security/index.d.ts +1 -0
  286. package/dist/esm/utils/security/index.js +1 -0
  287. package/dist/esm/utils/security/sanitize.utils.d.ts +32 -0
  288. package/dist/esm/utils/security/sanitize.utils.js +311 -0
  289. package/dist/esm/utils/validations/config-validations.utils.d.ts +42 -0
  290. package/dist/esm/utils/validations/config-validations.utils.js +289 -0
  291. package/dist/esm/utils/validations/event-validations.utils.d.ts +12 -0
  292. package/dist/esm/utils/validations/event-validations.utils.js +26 -0
  293. package/dist/esm/utils/validations/index.d.ts +5 -0
  294. package/dist/esm/utils/validations/index.js +5 -0
  295. package/dist/esm/utils/validations/metadata-validations.utils.d.ts +22 -0
  296. package/dist/esm/utils/validations/metadata-validations.utils.js +110 -0
  297. package/dist/esm/utils/validations/type-guards.utils.d.ts +6 -0
  298. package/dist/esm/utils/validations/type-guards.utils.js +27 -0
  299. package/dist/esm/utils/validations/url-validations.utils.d.ts +15 -0
  300. package/dist/esm/utils/validations/url-validations.utils.js +42 -0
  301. package/package.json +80 -0
@@ -0,0 +1,17 @@
1
+ import { EventManager } from '../managers/event.manager';
2
+ import { StateManager } from '../managers/state.manager';
3
+ export declare class ClickHandler extends StateManager {
4
+ private readonly eventManager;
5
+ private clickHandler?;
6
+ constructor(eventManager: EventManager);
7
+ startTracking(): void;
8
+ stopTracking(): void;
9
+ private findTrackingElement;
10
+ private getRelevantClickElement;
11
+ private calculateClickCoordinates;
12
+ private extractTrackingData;
13
+ private generateClickData;
14
+ private getRelevantText;
15
+ private extractElementAttributes;
16
+ private createCustomEventData;
17
+ }
@@ -0,0 +1,195 @@
1
+ import { HTML_DATA_ATTR_PREFIX, MAX_TEXT_LENGTH, INTERACTIVE_SELECTORS } from '../constants';
2
+ import { EventType } from '../types';
3
+ import { StateManager } from '../managers/state.manager';
4
+ import { debugLog } from '../utils/logging';
5
+ export class ClickHandler extends StateManager {
6
+ constructor(eventManager) {
7
+ super();
8
+ this.eventManager = eventManager;
9
+ }
10
+ startTracking() {
11
+ if (this.clickHandler) {
12
+ debugLog.debug('ClickHandler', 'Click tracking already active');
13
+ return;
14
+ }
15
+ debugLog.debug('ClickHandler', 'Starting click tracking');
16
+ this.clickHandler = (event) => {
17
+ const mouseEvent = event;
18
+ const target = mouseEvent.target;
19
+ const clickedElement = target instanceof HTMLElement
20
+ ? target
21
+ : target instanceof Node && target.parentElement instanceof HTMLElement
22
+ ? target.parentElement
23
+ : null;
24
+ if (!clickedElement) {
25
+ debugLog.warn('ClickHandler', 'Click target not found or not an element');
26
+ return;
27
+ }
28
+ debugLog.info('ClickHandler', '🖱️ Click detected on element', {
29
+ tagName: clickedElement.tagName,
30
+ className: clickedElement.className || 'none',
31
+ textContent: clickedElement.textContent?.slice(0, 50) ?? 'empty',
32
+ });
33
+ const trackingElement = this.findTrackingElement(clickedElement);
34
+ const relevantClickElement = this.getRelevantClickElement(clickedElement);
35
+ const coordinates = this.calculateClickCoordinates(mouseEvent, clickedElement);
36
+ if (trackingElement) {
37
+ const trackingData = this.extractTrackingData(trackingElement);
38
+ if (trackingData) {
39
+ const attributeData = this.createCustomEventData(trackingData);
40
+ this.eventManager.track({
41
+ type: EventType.CUSTOM,
42
+ custom_event: {
43
+ name: attributeData.name,
44
+ ...(attributeData.value && { metadata: { value: attributeData.value } }),
45
+ },
46
+ });
47
+ }
48
+ }
49
+ const clickData = this.generateClickData(clickedElement, relevantClickElement, coordinates);
50
+ this.eventManager.track({
51
+ type: EventType.CLICK,
52
+ click_data: clickData,
53
+ });
54
+ };
55
+ window.addEventListener('click', this.clickHandler, true);
56
+ }
57
+ stopTracking() {
58
+ if (this.clickHandler) {
59
+ window.removeEventListener('click', this.clickHandler, true);
60
+ this.clickHandler = undefined;
61
+ }
62
+ }
63
+ findTrackingElement(element) {
64
+ if (element.hasAttribute(`${HTML_DATA_ATTR_PREFIX}-name`)) {
65
+ return element;
66
+ }
67
+ const closest = element.closest(`[${HTML_DATA_ATTR_PREFIX}-name]`);
68
+ return closest || undefined;
69
+ }
70
+ getRelevantClickElement(element) {
71
+ for (const selector of INTERACTIVE_SELECTORS) {
72
+ try {
73
+ if (element.matches(selector)) {
74
+ return element;
75
+ }
76
+ }
77
+ catch (error) {
78
+ debugLog.warn('ClickHandler', 'Invalid selector in interactive elements check', {
79
+ selector,
80
+ error: error instanceof Error ? error.message : 'Unknown error',
81
+ });
82
+ continue;
83
+ }
84
+ }
85
+ for (const selector of INTERACTIVE_SELECTORS) {
86
+ try {
87
+ const parent = element.closest(selector);
88
+ if (parent) {
89
+ return parent;
90
+ }
91
+ }
92
+ catch (error) {
93
+ debugLog.warn('ClickHandler', 'Invalid selector in parent element search', {
94
+ selector,
95
+ error: error instanceof Error ? error.message : 'Unknown error',
96
+ });
97
+ continue;
98
+ }
99
+ }
100
+ return element;
101
+ }
102
+ calculateClickCoordinates(event, element) {
103
+ const rect = element.getBoundingClientRect();
104
+ const x = event.clientX;
105
+ const y = event.clientY;
106
+ const relativeX = rect.width > 0 ? Math.max(0, Math.min(1, Number(((x - rect.left) / rect.width).toFixed(3)))) : 0;
107
+ const relativeY = rect.height > 0 ? Math.max(0, Math.min(1, Number(((y - rect.top) / rect.height).toFixed(3)))) : 0;
108
+ return { x, y, relativeX, relativeY };
109
+ }
110
+ extractTrackingData(trackingElement) {
111
+ const name = trackingElement.getAttribute(`${HTML_DATA_ATTR_PREFIX}-name`);
112
+ const value = trackingElement.getAttribute(`${HTML_DATA_ATTR_PREFIX}-value`);
113
+ if (!name) {
114
+ return undefined;
115
+ }
116
+ return {
117
+ element: trackingElement,
118
+ name,
119
+ ...(value && { value }),
120
+ };
121
+ }
122
+ generateClickData(clickedElement, relevantElement, coordinates) {
123
+ const { x, y, relativeX, relativeY } = coordinates;
124
+ const text = this.getRelevantText(clickedElement, relevantElement);
125
+ const attributes = this.extractElementAttributes(relevantElement);
126
+ const href = relevantElement.getAttribute('href');
127
+ const title = relevantElement.getAttribute('title');
128
+ const alt = relevantElement.getAttribute('alt');
129
+ const role = relevantElement.getAttribute('role');
130
+ const ariaLabel = relevantElement.getAttribute('aria-label');
131
+ const className = typeof relevantElement.className === 'string' ? relevantElement.className : String(relevantElement.className);
132
+ return {
133
+ x,
134
+ y,
135
+ relativeX,
136
+ relativeY,
137
+ tag: relevantElement.tagName.toLowerCase(),
138
+ ...(relevantElement.id && { id: relevantElement.id }),
139
+ ...(relevantElement.className && { class: className }),
140
+ ...(text && { text }),
141
+ ...(href && { href }),
142
+ ...(title && { title }),
143
+ ...(alt && { alt }),
144
+ ...(role && { role }),
145
+ ...(ariaLabel && { ariaLabel }),
146
+ ...(Object.keys(attributes).length > 0 && { dataAttributes: attributes }),
147
+ };
148
+ }
149
+ getRelevantText(clickedElement, relevantElement) {
150
+ const LARGE_CONTAINER_TAGS = ['main', 'section', 'article', 'body', 'html', 'header', 'footer', 'aside', 'nav'];
151
+ const clickedText = clickedElement.textContent?.trim() ?? '';
152
+ const relevantText = relevantElement.textContent?.trim() ?? '';
153
+ if (!clickedText && !relevantText) {
154
+ return '';
155
+ }
156
+ // Strategy 1: If clicked element has reasonable text, use it
157
+ if (clickedText && clickedText.length <= MAX_TEXT_LENGTH) {
158
+ return clickedText;
159
+ }
160
+ // Strategy 2: For large containers with excessive text, avoid using container text
161
+ const isLargeContainer = LARGE_CONTAINER_TAGS.includes(relevantElement.tagName.toLowerCase());
162
+ const hasExcessiveText = relevantText.length > MAX_TEXT_LENGTH * 2; // 510 chars
163
+ if (isLargeContainer && hasExcessiveText) {
164
+ // Use clicked element text if available and reasonable, otherwise empty
165
+ return clickedText && clickedText.length <= MAX_TEXT_LENGTH ? clickedText : '';
166
+ }
167
+ // Strategy 3: Use relevant text but truncate if needed
168
+ if (relevantText.length <= MAX_TEXT_LENGTH) {
169
+ return relevantText;
170
+ }
171
+ // Strategy 4: If clicked text is much shorter than relevant text, prefer clicked text
172
+ if (clickedText && clickedText.length < relevantText.length * 0.1) {
173
+ return clickedText.length <= MAX_TEXT_LENGTH ? clickedText : clickedText.slice(0, MAX_TEXT_LENGTH - 3) + '...';
174
+ }
175
+ // Fallback: truncate relevant text to exactly MAX_TEXT_LENGTH including ellipsis
176
+ return relevantText.slice(0, MAX_TEXT_LENGTH - 3) + '...';
177
+ }
178
+ extractElementAttributes(element) {
179
+ const commonAttributes = ['id', 'class', 'data-testid', 'aria-label', 'title', 'href', 'type', 'name'];
180
+ const result = {};
181
+ for (const attributeName of commonAttributes) {
182
+ const value = element.getAttribute(attributeName);
183
+ if (value) {
184
+ result[attributeName] = value;
185
+ }
186
+ }
187
+ return result;
188
+ }
189
+ createCustomEventData(trackingData) {
190
+ return {
191
+ name: trackingData.name,
192
+ ...(trackingData.value && { value: trackingData.value }),
193
+ };
194
+ }
195
+ }
@@ -0,0 +1,15 @@
1
+ import { EventManager } from '../managers/event.manager';
2
+ import { StateManager } from '../managers/state.manager';
3
+ export declare class ErrorHandler extends StateManager {
4
+ private readonly eventManager;
5
+ private readonly piiPatterns;
6
+ constructor(eventManager: EventManager);
7
+ startTracking(): void;
8
+ stopTracking(): void;
9
+ private setupErrorListener;
10
+ private setupUnhandledRejectionListener;
11
+ private readonly handleError;
12
+ private readonly handleUnhandledRejection;
13
+ private sanitizeText;
14
+ private shouldSample;
15
+ }
@@ -0,0 +1,93 @@
1
+ import { StateManager } from '../managers/state.manager';
2
+ import { ErrorType, EventType } from '../types';
3
+ import { debugLog } from '../utils/logging';
4
+ export class ErrorHandler extends StateManager {
5
+ constructor(eventManager) {
6
+ super();
7
+ this.piiPatterns = [
8
+ /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
9
+ /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g,
10
+ /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
11
+ /\b[A-Z]{2}\d{2}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
12
+ ];
13
+ this.handleError = (event) => {
14
+ const config = this.get('config');
15
+ if (!this.shouldSample(config?.errorSampling ?? 0.1)) {
16
+ debugLog.debug('ErrorHandler', `Error not sampled, skipping (errorSampling: ${config?.errorSampling})`, {
17
+ errorSampling: config?.errorSampling,
18
+ });
19
+ return;
20
+ }
21
+ debugLog.warn('ErrorHandler', `JavaScript error captured: ${event.message} (filename: ${event.filename}, lineno: ${event.lineno})`, {
22
+ message: event.message,
23
+ filename: event.filename,
24
+ lineno: event.lineno,
25
+ });
26
+ this.eventManager.track({
27
+ type: EventType.ERROR,
28
+ error_data: {
29
+ type: ErrorType.JS_ERROR,
30
+ message: this.sanitizeText(event.message || 'Unknown error'),
31
+ },
32
+ });
33
+ };
34
+ this.handleUnhandledRejection = (event) => {
35
+ const config = this.get('config');
36
+ if (!this.shouldSample(config?.errorSampling ?? 0.1)) {
37
+ debugLog.debug('ErrorHandler', 'Promise rejection not sampled, skipping', {
38
+ errorSampling: config?.errorSampling,
39
+ });
40
+ return;
41
+ }
42
+ debugLog.warn('ErrorHandler', `Unhandled promise rejection captured (reason: ${typeof event.reason})`, {
43
+ reason: typeof event.reason,
44
+ });
45
+ let reason = 'Unknown rejection';
46
+ if (event.reason) {
47
+ if (typeof event.reason === 'string') {
48
+ reason = event.reason;
49
+ }
50
+ else if (event.reason instanceof Error) {
51
+ reason = event.reason.message || event.reason.toString();
52
+ }
53
+ else {
54
+ reason = String(event.reason);
55
+ }
56
+ }
57
+ this.eventManager.track({
58
+ type: EventType.ERROR,
59
+ error_data: {
60
+ type: ErrorType.PROMISE_REJECTION,
61
+ message: this.sanitizeText(reason),
62
+ },
63
+ });
64
+ };
65
+ this.eventManager = eventManager;
66
+ }
67
+ startTracking() {
68
+ debugLog.debug('ErrorHandler', 'Starting error tracking');
69
+ this.setupErrorListener();
70
+ this.setupUnhandledRejectionListener();
71
+ }
72
+ stopTracking() {
73
+ debugLog.debug('ErrorHandler', 'Stopping error tracking');
74
+ window.removeEventListener('error', this.handleError);
75
+ window.removeEventListener('unhandledrejection', this.handleUnhandledRejection);
76
+ }
77
+ setupErrorListener() {
78
+ window.addEventListener('error', this.handleError);
79
+ }
80
+ setupUnhandledRejectionListener() {
81
+ window.addEventListener('unhandledrejection', this.handleUnhandledRejection);
82
+ }
83
+ sanitizeText(text) {
84
+ let sanitized = text;
85
+ for (const pattern of this.piiPatterns) {
86
+ sanitized = sanitized.replace(pattern, '[REDACTED]');
87
+ }
88
+ return sanitized;
89
+ }
90
+ shouldSample(rate) {
91
+ return Math.random() < rate;
92
+ }
93
+ }
@@ -0,0 +1,16 @@
1
+ import { EventManager } from '../managers/event.manager';
2
+ import { StateManager } from '../managers/state.manager';
3
+ export declare class NetworkHandler extends StateManager {
4
+ private readonly eventManager;
5
+ private readonly originalFetch;
6
+ private readonly originalXHROpen;
7
+ private readonly originalXHRSend;
8
+ constructor(eventManager: EventManager);
9
+ startTracking(): void;
10
+ stopTracking(): void;
11
+ private interceptFetch;
12
+ private interceptXHR;
13
+ private trackNetworkError;
14
+ private normalizeUrlForTracking;
15
+ private shouldSample;
16
+ }
@@ -0,0 +1,132 @@
1
+ import { StateManager } from '../managers/state.manager';
2
+ import { ErrorType, EventType } from '../types';
3
+ import { normalizeUrl } from '../utils';
4
+ import { debugLog } from '../utils/logging';
5
+ export class NetworkHandler extends StateManager {
6
+ constructor(eventManager) {
7
+ super();
8
+ this.eventManager = eventManager;
9
+ this.originalFetch = window.fetch;
10
+ this.originalXHROpen = XMLHttpRequest.prototype.open;
11
+ this.originalXHRSend = XMLHttpRequest.prototype.send;
12
+ }
13
+ startTracking() {
14
+ debugLog.debug('NetworkHandler', 'Starting network error tracking');
15
+ this.interceptFetch();
16
+ this.interceptXHR();
17
+ }
18
+ stopTracking() {
19
+ debugLog.debug('NetworkHandler', 'Stopping network error tracking');
20
+ window.fetch = this.originalFetch;
21
+ XMLHttpRequest.prototype.open = this.originalXHROpen;
22
+ XMLHttpRequest.prototype.send = this.originalXHRSend;
23
+ }
24
+ interceptFetch() {
25
+ window.fetch = async (input, init) => {
26
+ const startTime = Date.now();
27
+ const url = typeof input === 'string' ? input : input.toString();
28
+ const method = init?.method ?? 'GET';
29
+ try {
30
+ const response = await this.originalFetch(input, init);
31
+ const duration = Date.now() - startTime;
32
+ if (!response.ok) {
33
+ debugLog.debug('NetworkHandler', 'Fetch error detected', {
34
+ method,
35
+ url: this.normalizeUrlForTracking(url),
36
+ status: response.status,
37
+ statusText: response.statusText,
38
+ });
39
+ this.trackNetworkError(method.toUpperCase(), this.normalizeUrlForTracking(url), response.status, response.statusText, duration);
40
+ }
41
+ return response;
42
+ }
43
+ catch (error) {
44
+ const duration = Date.now() - startTime;
45
+ const errorMessage = error instanceof Error ? error.message : 'Network Error';
46
+ debugLog.debug('NetworkHandler', 'Fetch exception caught', {
47
+ method,
48
+ url: this.normalizeUrlForTracking(url),
49
+ error: errorMessage,
50
+ });
51
+ this.trackNetworkError(method.toUpperCase(), this.normalizeUrlForTracking(url), undefined, errorMessage, duration);
52
+ throw error;
53
+ }
54
+ };
55
+ }
56
+ interceptXHR() {
57
+ const trackNetworkError = this.trackNetworkError.bind(this);
58
+ const normalizeUrlForTracking = this.normalizeUrlForTracking.bind(this);
59
+ const originalXHROpen = this.originalXHROpen;
60
+ const originalXHRSend = this.originalXHRSend;
61
+ XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
62
+ const asyncMode = async ?? true;
63
+ const extendedThis = this;
64
+ extendedThis._tracelogStartTime = Date.now();
65
+ extendedThis._tracelogMethod = method.toUpperCase();
66
+ extendedThis._tracelogUrl = url.toString();
67
+ return originalXHROpen.call(this, method, url, asyncMode, user, password);
68
+ };
69
+ XMLHttpRequest.prototype.send = function (body) {
70
+ const xhr = this;
71
+ const startTime = xhr._tracelogStartTime ?? Date.now();
72
+ const method = xhr._tracelogMethod ?? 'GET';
73
+ const url = xhr._tracelogUrl ?? '';
74
+ const originalOnReadyStateChange = xhr.onreadystatechange;
75
+ xhr.onreadystatechange = (ev) => {
76
+ if (xhr.readyState === XMLHttpRequest.DONE) {
77
+ const duration = Date.now() - startTime;
78
+ if (xhr.status === 0 || xhr.status >= 400) {
79
+ const statusText = xhr.statusText || 'Request Failed';
80
+ debugLog.debug('NetworkHandler', 'XHR error detected', {
81
+ method,
82
+ url: normalizeUrlForTracking(url),
83
+ status: xhr.status,
84
+ statusText,
85
+ });
86
+ trackNetworkError(method, normalizeUrlForTracking(url), xhr.status, statusText, duration);
87
+ }
88
+ }
89
+ if (originalOnReadyStateChange) {
90
+ return originalOnReadyStateChange.call(xhr, ev);
91
+ }
92
+ };
93
+ return originalXHRSend.call(this, body);
94
+ };
95
+ }
96
+ trackNetworkError(method, url, status, statusText, duration) {
97
+ const config = this.get('config');
98
+ if (!this.shouldSample(config?.errorSampling ?? 0.1)) {
99
+ debugLog.debug('NetworkHandler', `Network error not sampled, skipping (errorSampling: ${config?.errorSampling}, method: ${method}, url: ${url})`, {
100
+ errorSampling: config?.errorSampling,
101
+ method,
102
+ url,
103
+ });
104
+ return;
105
+ }
106
+ debugLog.warn('NetworkHandler', `Network error tracked: ${method} ${url} (status: ${status}, statusText: ${statusText}, duration: ${duration}ms)`, { method, url, status, statusText, duration });
107
+ this.eventManager.track({
108
+ type: EventType.ERROR,
109
+ error_data: {
110
+ type: ErrorType.NETWORK_ERROR,
111
+ message: statusText,
112
+ method,
113
+ url,
114
+ status,
115
+ statusText,
116
+ duration,
117
+ },
118
+ });
119
+ }
120
+ normalizeUrlForTracking(url) {
121
+ try {
122
+ const config = this.get('config');
123
+ return normalizeUrl(url, config?.sensitiveQueryParams);
124
+ }
125
+ catch {
126
+ return url;
127
+ }
128
+ }
129
+ shouldSample(rate) {
130
+ return Math.random() < rate;
131
+ }
132
+ }
@@ -0,0 +1,15 @@
1
+ import { StateManager } from '../managers/state.manager';
2
+ import { EventManager } from '../managers/event.manager';
3
+ export declare class PageViewHandler extends StateManager {
4
+ private readonly eventManager;
5
+ private readonly onTrack;
6
+ private originalPushState?;
7
+ private originalReplaceState?;
8
+ constructor(eventManager: EventManager, onTrack: () => void);
9
+ startTracking(): void;
10
+ stopTracking(): void;
11
+ private patchHistory;
12
+ private readonly trackCurrentPage;
13
+ private trackInitialPageView;
14
+ private extractPageViewData;
15
+ }
@@ -0,0 +1,79 @@
1
+ import { EventType } from '../types';
2
+ import { normalizeUrl } from '../utils';
3
+ import { StateManager } from '../managers/state.manager';
4
+ import { debugLog } from '../utils/logging';
5
+ export class PageViewHandler extends StateManager {
6
+ constructor(eventManager, onTrack) {
7
+ super();
8
+ this.trackCurrentPage = () => {
9
+ const rawUrl = window.location.href;
10
+ const normalizedUrl = normalizeUrl(rawUrl, this.get('config').sensitiveQueryParams);
11
+ if (this.get('pageUrl') !== normalizedUrl) {
12
+ const fromUrl = this.get('pageUrl');
13
+ debugLog.debug('PageViewHandler', 'Page navigation detected', { from: fromUrl, to: normalizedUrl });
14
+ this.set('pageUrl', normalizedUrl);
15
+ this.eventManager.track({
16
+ type: EventType.PAGE_VIEW,
17
+ page_url: this.get('pageUrl'),
18
+ from_page_url: fromUrl,
19
+ ...(this.extractPageViewData() && { page_view: this.extractPageViewData() }),
20
+ });
21
+ this.onTrack();
22
+ }
23
+ };
24
+ this.eventManager = eventManager;
25
+ this.onTrack = onTrack;
26
+ }
27
+ startTracking() {
28
+ debugLog.debug('PageViewHandler', 'Starting page view tracking');
29
+ this.trackInitialPageView();
30
+ this.trackCurrentPage();
31
+ window.addEventListener('popstate', this.trackCurrentPage);
32
+ window.addEventListener('hashchange', this.trackCurrentPage);
33
+ this.patchHistory('pushState');
34
+ this.patchHistory('replaceState');
35
+ }
36
+ stopTracking() {
37
+ debugLog.debug('PageViewHandler', 'Stopping page view tracking');
38
+ window.removeEventListener('popstate', this.trackCurrentPage);
39
+ window.removeEventListener('hashchange', this.trackCurrentPage);
40
+ if (this.originalPushState) {
41
+ window.history.pushState = this.originalPushState;
42
+ }
43
+ if (this.originalReplaceState) {
44
+ window.history.replaceState = this.originalReplaceState;
45
+ }
46
+ }
47
+ patchHistory(method) {
48
+ if (method === 'pushState' && !this.originalPushState) {
49
+ this.originalPushState = window.history.pushState;
50
+ }
51
+ else if (method === 'replaceState' && !this.originalReplaceState) {
52
+ this.originalReplaceState = window.history.replaceState;
53
+ }
54
+ const original = window.history[method];
55
+ window.history[method] = (...args) => {
56
+ original.apply(window.history, args);
57
+ this.trackCurrentPage();
58
+ };
59
+ }
60
+ trackInitialPageView() {
61
+ this.eventManager.track({
62
+ type: EventType.PAGE_VIEW,
63
+ page_url: this.get('pageUrl'),
64
+ ...(this.extractPageViewData() && { page_view: this.extractPageViewData() }),
65
+ });
66
+ this.onTrack();
67
+ }
68
+ extractPageViewData() {
69
+ const location = window.location;
70
+ const data = {
71
+ ...(document.referrer && { referrer: document.referrer }),
72
+ ...(document.title && { title: document.title }),
73
+ ...(location.pathname && { pathname: location.pathname }),
74
+ ...(location.search && { search: location.search }),
75
+ ...(location.hash && { hash: location.hash }),
76
+ };
77
+ return Object.values(data).some((value) => !!value) ? data : undefined;
78
+ }
79
+ }
@@ -0,0 +1,19 @@
1
+ import { EventManager } from '../managers/event.manager';
2
+ import { StateManager } from '../managers/state.manager';
3
+ export declare class PerformanceHandler extends StateManager {
4
+ private readonly eventManager;
5
+ private readonly reportedByNav;
6
+ private readonly observers;
7
+ private lastLongTaskSentAt;
8
+ constructor(eventManager: EventManager);
9
+ startTracking(): Promise<void>;
10
+ stopTracking(): void;
11
+ private observeWebVitalsFallback;
12
+ private initWebVitals;
13
+ private reportTTFB;
14
+ private observeLongTasks;
15
+ private sendVital;
16
+ private trackWebVital;
17
+ private getNavigationId;
18
+ private safeObserve;
19
+ }