@tracelog/lib 0.1.0 → 0.2.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 (228) hide show
  1. package/README.md +58 -24
  2. package/dist/browser/tracelog.js +1928 -3297
  3. package/dist/cjs/api.d.ts +33 -19
  4. package/dist/cjs/api.js +111 -156
  5. package/dist/cjs/app.constants.d.ts +74 -1
  6. package/dist/cjs/app.constants.js +77 -3
  7. package/dist/cjs/app.d.ts +29 -44
  8. package/dist/cjs/app.js +114 -212
  9. package/dist/cjs/app.types.d.ts +2 -7
  10. package/dist/cjs/app.types.js +10 -21
  11. package/dist/cjs/constants/api.constants.js +11 -5
  12. package/dist/cjs/constants/config.constants.d.ts +75 -0
  13. package/dist/cjs/constants/config.constants.js +178 -0
  14. package/dist/cjs/constants/error.constants.d.ts +29 -0
  15. package/dist/cjs/constants/error.constants.js +50 -0
  16. package/dist/cjs/constants/index.d.ts +3 -6
  17. package/dist/cjs/constants/index.js +3 -6
  18. package/dist/cjs/constants/performance.constants.d.ts +28 -0
  19. package/dist/cjs/constants/performance.constants.js +43 -0
  20. package/dist/cjs/handlers/click.handler.d.ts +1 -0
  21. package/dist/cjs/handlers/click.handler.js +30 -49
  22. package/dist/cjs/handlers/error.handler.d.ts +11 -6
  23. package/dist/cjs/handlers/error.handler.js +91 -51
  24. package/dist/cjs/handlers/page-view.handler.js +38 -29
  25. package/dist/cjs/handlers/performance.handler.d.ts +3 -0
  26. package/dist/cjs/handlers/performance.handler.js +76 -37
  27. package/dist/cjs/handlers/scroll.handler.d.ts +16 -10
  28. package/dist/cjs/handlers/scroll.handler.js +119 -185
  29. package/dist/cjs/handlers/session.handler.d.ts +6 -20
  30. package/dist/cjs/handlers/session.handler.js +38 -326
  31. package/dist/cjs/integrations/google-analytics.integration.d.ts +0 -1
  32. package/dist/cjs/integrations/google-analytics.integration.js +27 -98
  33. package/dist/cjs/listeners/input-listener-managers.d.ts +18 -9
  34. package/dist/cjs/listeners/input-listener-managers.js +24 -33
  35. package/dist/cjs/listeners/touch-listener-manager.d.ts +1 -3
  36. package/dist/cjs/listeners/touch-listener-manager.js +1 -23
  37. package/dist/cjs/listeners/visibility-listener-manager.d.ts +1 -4
  38. package/dist/cjs/listeners/visibility-listener-manager.js +6 -42
  39. package/dist/cjs/managers/api.manager.d.ts +13 -3
  40. package/dist/cjs/managers/api.manager.js +35 -5
  41. package/dist/cjs/managers/config.manager.d.ts +53 -3
  42. package/dist/cjs/managers/config.manager.js +131 -62
  43. package/dist/cjs/managers/event.manager.d.ts +57 -36
  44. package/dist/cjs/managers/event.manager.js +266 -417
  45. package/dist/cjs/managers/sender.manager.d.ts +40 -22
  46. package/dist/cjs/managers/sender.manager.js +200 -198
  47. package/dist/cjs/managers/session.manager.d.ts +80 -66
  48. package/dist/cjs/managers/session.manager.js +267 -522
  49. package/dist/cjs/managers/state.manager.d.ts +33 -0
  50. package/dist/cjs/managers/state.manager.js +79 -6
  51. package/dist/cjs/managers/storage.manager.d.ts +26 -2
  52. package/dist/cjs/managers/storage.manager.js +67 -34
  53. package/dist/cjs/managers/tags.manager.d.ts +31 -7
  54. package/dist/cjs/managers/tags.manager.js +123 -241
  55. package/dist/cjs/managers/user.manager.d.ts +14 -5
  56. package/dist/cjs/managers/user.manager.js +17 -9
  57. package/dist/cjs/public-api.d.ts +10 -1
  58. package/dist/cjs/public-api.js +18 -24
  59. package/dist/cjs/test-bridge.d.ts +48 -0
  60. package/dist/cjs/test-bridge.js +110 -0
  61. package/dist/cjs/types/api.types.d.ts +21 -6
  62. package/dist/cjs/types/api.types.js +21 -6
  63. package/dist/cjs/types/config.types.d.ts +22 -84
  64. package/dist/cjs/types/emitter.types.d.ts +11 -0
  65. package/dist/cjs/types/emitter.types.js +8 -0
  66. package/dist/cjs/types/event.types.d.ts +8 -11
  67. package/dist/cjs/types/index.d.ts +3 -1
  68. package/dist/cjs/types/index.js +3 -1
  69. package/dist/cjs/types/queue.types.d.ts +1 -0
  70. package/dist/cjs/types/session.types.d.ts +0 -64
  71. package/dist/cjs/types/state.types.d.ts +1 -0
  72. package/dist/cjs/types/test-bridge.types.d.ts +38 -0
  73. package/dist/cjs/types/validation-error.types.d.ts +7 -0
  74. package/dist/cjs/types/validation-error.types.js +11 -1
  75. package/dist/cjs/types/window.types.d.ts +1 -8
  76. package/dist/cjs/utils/data/uuid.utils.d.ts +1 -1
  77. package/dist/cjs/utils/data/uuid.utils.js +7 -5
  78. package/dist/cjs/utils/emitter.utils.d.ts +8 -0
  79. package/dist/cjs/utils/emitter.utils.js +33 -0
  80. package/dist/cjs/utils/index.d.ts +1 -0
  81. package/dist/cjs/utils/index.js +1 -0
  82. package/dist/cjs/utils/logging/debug-logger.utils.d.ts +10 -51
  83. package/dist/cjs/utils/logging/debug-logger.utils.js +36 -127
  84. package/dist/cjs/utils/network/fetch-with-timeout.utils.d.ts +4 -0
  85. package/dist/cjs/utils/network/fetch-with-timeout.utils.js +25 -0
  86. package/dist/cjs/utils/network/index.d.ts +1 -0
  87. package/dist/cjs/utils/network/index.js +1 -0
  88. package/dist/cjs/utils/network/url.utils.js +2 -42
  89. package/dist/cjs/utils/security/sanitize.utils.d.ts +1 -8
  90. package/dist/cjs/utils/security/sanitize.utils.js +7 -41
  91. package/dist/cjs/utils/validations/config-validations.utils.d.ts +7 -0
  92. package/dist/cjs/utils/validations/config-validations.utils.js +77 -22
  93. package/dist/esm/api.d.ts +33 -19
  94. package/dist/esm/api.js +105 -118
  95. package/dist/esm/app.constants.d.ts +74 -1
  96. package/dist/esm/app.constants.js +76 -1
  97. package/dist/esm/app.d.ts +29 -44
  98. package/dist/esm/app.js +115 -213
  99. package/dist/esm/app.types.d.ts +2 -7
  100. package/dist/esm/app.types.js +1 -7
  101. package/dist/esm/constants/api.constants.js +10 -4
  102. package/dist/esm/constants/config.constants.d.ts +75 -0
  103. package/dist/esm/constants/config.constants.js +174 -0
  104. package/dist/esm/constants/error.constants.d.ts +29 -0
  105. package/dist/esm/constants/error.constants.js +47 -0
  106. package/dist/esm/constants/index.d.ts +3 -6
  107. package/dist/esm/constants/index.js +3 -6
  108. package/dist/esm/constants/performance.constants.d.ts +28 -0
  109. package/dist/esm/constants/performance.constants.js +40 -0
  110. package/dist/esm/handlers/click.handler.d.ts +1 -0
  111. package/dist/esm/handlers/click.handler.js +30 -49
  112. package/dist/esm/handlers/error.handler.d.ts +11 -6
  113. package/dist/esm/handlers/error.handler.js +91 -51
  114. package/dist/esm/handlers/page-view.handler.js +38 -29
  115. package/dist/esm/handlers/performance.handler.d.ts +3 -0
  116. package/dist/esm/handlers/performance.handler.js +71 -32
  117. package/dist/esm/handlers/scroll.handler.d.ts +16 -10
  118. package/dist/esm/handlers/scroll.handler.js +120 -186
  119. package/dist/esm/handlers/session.handler.d.ts +6 -20
  120. package/dist/esm/handlers/session.handler.js +38 -326
  121. package/dist/esm/integrations/google-analytics.integration.d.ts +0 -1
  122. package/dist/esm/integrations/google-analytics.integration.js +27 -98
  123. package/dist/esm/listeners/input-listener-managers.d.ts +18 -9
  124. package/dist/esm/listeners/input-listener-managers.js +23 -32
  125. package/dist/esm/listeners/touch-listener-manager.d.ts +1 -3
  126. package/dist/esm/listeners/touch-listener-manager.js +1 -23
  127. package/dist/esm/listeners/visibility-listener-manager.d.ts +1 -4
  128. package/dist/esm/listeners/visibility-listener-manager.js +6 -42
  129. package/dist/esm/managers/api.manager.d.ts +13 -3
  130. package/dist/esm/managers/api.manager.js +34 -3
  131. package/dist/esm/managers/config.manager.d.ts +53 -3
  132. package/dist/esm/managers/config.manager.js +133 -64
  133. package/dist/esm/managers/event.manager.d.ts +57 -36
  134. package/dist/esm/managers/event.manager.js +268 -419
  135. package/dist/esm/managers/sender.manager.d.ts +40 -22
  136. package/dist/esm/managers/sender.manager.js +201 -199
  137. package/dist/esm/managers/session.manager.d.ts +80 -66
  138. package/dist/esm/managers/session.manager.js +269 -524
  139. package/dist/esm/managers/state.manager.d.ts +33 -0
  140. package/dist/esm/managers/state.manager.js +78 -6
  141. package/dist/esm/managers/storage.manager.d.ts +26 -2
  142. package/dist/esm/managers/storage.manager.js +66 -33
  143. package/dist/esm/managers/tags.manager.d.ts +31 -7
  144. package/dist/esm/managers/tags.manager.js +124 -242
  145. package/dist/esm/managers/user.manager.d.ts +14 -5
  146. package/dist/esm/managers/user.manager.js +17 -9
  147. package/dist/esm/public-api.d.ts +10 -1
  148. package/dist/esm/public-api.js +14 -1
  149. package/dist/esm/test-bridge.d.ts +48 -0
  150. package/dist/esm/test-bridge.js +106 -0
  151. package/dist/esm/types/api.types.d.ts +21 -6
  152. package/dist/esm/types/api.types.js +21 -6
  153. package/dist/esm/types/config.types.d.ts +22 -84
  154. package/dist/esm/types/emitter.types.d.ts +11 -0
  155. package/dist/esm/types/emitter.types.js +5 -0
  156. package/dist/esm/types/event.types.d.ts +8 -11
  157. package/dist/esm/types/index.d.ts +3 -1
  158. package/dist/esm/types/index.js +3 -1
  159. package/dist/esm/types/queue.types.d.ts +1 -0
  160. package/dist/esm/types/session.types.d.ts +0 -64
  161. package/dist/esm/types/state.types.d.ts +1 -0
  162. package/dist/esm/types/test-bridge.types.d.ts +38 -0
  163. package/dist/esm/types/validation-error.types.d.ts +7 -0
  164. package/dist/esm/types/validation-error.types.js +9 -0
  165. package/dist/esm/types/window.types.d.ts +1 -8
  166. package/dist/esm/utils/data/uuid.utils.d.ts +1 -1
  167. package/dist/esm/utils/data/uuid.utils.js +7 -5
  168. package/dist/esm/utils/emitter.utils.d.ts +8 -0
  169. package/dist/esm/utils/emitter.utils.js +29 -0
  170. package/dist/esm/utils/index.d.ts +1 -0
  171. package/dist/esm/utils/index.js +1 -0
  172. package/dist/esm/utils/logging/debug-logger.utils.d.ts +10 -51
  173. package/dist/esm/utils/logging/debug-logger.utils.js +36 -127
  174. package/dist/esm/utils/network/fetch-with-timeout.utils.d.ts +4 -0
  175. package/dist/esm/utils/network/fetch-with-timeout.utils.js +22 -0
  176. package/dist/esm/utils/network/index.d.ts +1 -0
  177. package/dist/esm/utils/network/index.js +1 -0
  178. package/dist/esm/utils/network/url.utils.js +2 -42
  179. package/dist/esm/utils/security/sanitize.utils.d.ts +1 -8
  180. package/dist/esm/utils/security/sanitize.utils.js +6 -39
  181. package/dist/esm/utils/validations/config-validations.utils.d.ts +7 -0
  182. package/dist/esm/utils/validations/config-validations.utils.js +76 -22
  183. package/package.json +23 -16
  184. package/dist/browser/web-vitals-CCnqwnC8.mjs +0 -198
  185. package/dist/cjs/constants/browser.constants.d.ts +0 -3
  186. package/dist/cjs/constants/browser.constants.js +0 -41
  187. package/dist/cjs/constants/initialization.constants.d.ts +0 -40
  188. package/dist/cjs/constants/initialization.constants.js +0 -48
  189. package/dist/cjs/constants/limits.constants.d.ts +0 -27
  190. package/dist/cjs/constants/limits.constants.js +0 -43
  191. package/dist/cjs/constants/security.constants.d.ts +0 -1
  192. package/dist/cjs/constants/security.constants.js +0 -12
  193. package/dist/cjs/constants/timing.constants.d.ts +0 -22
  194. package/dist/cjs/constants/timing.constants.js +0 -34
  195. package/dist/cjs/constants/validation.constants.d.ts +0 -13
  196. package/dist/cjs/constants/validation.constants.js +0 -31
  197. package/dist/cjs/handlers/network.handler.d.ts +0 -16
  198. package/dist/cjs/handlers/network.handler.js +0 -136
  199. package/dist/cjs/managers/cross-tab-session.manager.d.ts +0 -170
  200. package/dist/cjs/managers/cross-tab-session.manager.js +0 -730
  201. package/dist/cjs/managers/sampling.manager.d.ts +0 -8
  202. package/dist/cjs/managers/sampling.manager.js +0 -53
  203. package/dist/cjs/managers/session-recovery.manager.d.ts +0 -65
  204. package/dist/cjs/managers/session-recovery.manager.js +0 -237
  205. package/dist/cjs/types/web-vitals.types.d.ts +0 -6
  206. package/dist/esm/constants/browser.constants.d.ts +0 -3
  207. package/dist/esm/constants/browser.constants.js +0 -38
  208. package/dist/esm/constants/initialization.constants.d.ts +0 -40
  209. package/dist/esm/constants/initialization.constants.js +0 -45
  210. package/dist/esm/constants/limits.constants.d.ts +0 -27
  211. package/dist/esm/constants/limits.constants.js +0 -40
  212. package/dist/esm/constants/security.constants.d.ts +0 -1
  213. package/dist/esm/constants/security.constants.js +0 -9
  214. package/dist/esm/constants/timing.constants.d.ts +0 -22
  215. package/dist/esm/constants/timing.constants.js +0 -31
  216. package/dist/esm/constants/validation.constants.d.ts +0 -13
  217. package/dist/esm/constants/validation.constants.js +0 -28
  218. package/dist/esm/handlers/network.handler.d.ts +0 -16
  219. package/dist/esm/handlers/network.handler.js +0 -132
  220. package/dist/esm/managers/cross-tab-session.manager.d.ts +0 -170
  221. package/dist/esm/managers/cross-tab-session.manager.js +0 -726
  222. package/dist/esm/managers/sampling.manager.d.ts +0 -8
  223. package/dist/esm/managers/sampling.manager.js +0 -49
  224. package/dist/esm/managers/session-recovery.manager.d.ts +0 -65
  225. package/dist/esm/managers/session-recovery.manager.js +0 -233
  226. package/dist/esm/types/web-vitals.types.d.ts +0 -6
  227. /package/dist/cjs/types/{web-vitals.types.js → test-bridge.types.js} +0 -0
  228. /package/dist/esm/types/{web-vitals.types.js → test-bridge.types.js} +0 -0
@@ -9,51 +9,31 @@ class ScrollHandler extends state_manager_1.StateManager {
9
9
  constructor(eventManager) {
10
10
  super();
11
11
  this.containers = [];
12
- this.pendingSelectors = [];
13
- this.mutationObserver = null;
14
- this.windowFallbackNeeded = false;
12
+ this.limitWarningLogged = false;
13
+ this.minDepthChange = constants_1.MIN_SCROLL_DEPTH_CHANGE;
14
+ this.minIntervalMs = constants_1.SCROLL_MIN_EVENT_INTERVAL_MS;
15
+ this.maxEventsPerSession = constants_1.MAX_SCROLL_EVENTS_PER_SESSION;
15
16
  this.eventManager = eventManager;
16
17
  }
17
18
  startTracking() {
19
+ this.limitWarningLogged = false;
20
+ this.applyConfigOverrides();
21
+ this.set('scrollEventCount', 0);
18
22
  const raw = this.get('config').scrollContainerSelectors;
19
23
  const selectors = Array.isArray(raw) ? raw : typeof raw === 'string' ? [raw] : [];
20
- logging_1.debugLog.debug('ScrollHandler', 'Starting scroll tracking', { selectorsCount: selectors.length });
21
- // No custom selectors: track window immediately
22
- if (selectors.length === 0) {
23
- this.setupScrollContainer(window);
24
- return;
24
+ const elements = selectors
25
+ .map((sel) => this.safeQuerySelector(sel))
26
+ .filter((element) => element instanceof HTMLElement);
27
+ if (elements.length === 0) {
28
+ elements.push(window);
25
29
  }
26
- const foundElements = [];
27
- const notFoundSelectors = [];
28
- for (const selector of selectors) {
29
- const element = this.safeQuerySelector(selector);
30
- if (element instanceof HTMLElement) {
31
- foundElements.push(element);
32
- }
33
- else if (element === null) {
34
- notFoundSelectors.push(selector);
35
- }
36
- }
37
- // Setup found elements
38
- for (const element of foundElements) {
30
+ for (const element of elements) {
39
31
  this.setupScrollContainer(element);
40
32
  }
41
- // If we have pending selectors, set up retry logic
42
- if (notFoundSelectors.length > 0) {
43
- this.windowFallbackNeeded = true;
44
- this.setupPendingSelectors(notFoundSelectors);
45
- }
46
- else if (this.containers.length === 0) {
47
- // No elements found and none pending: use window fallback immediately
48
- this.setupScrollContainer(window);
49
- }
50
33
  }
51
34
  stopTracking() {
52
- logging_1.debugLog.debug('ScrollHandler', 'Stopping scroll tracking', { containersCount: this.containers.length });
53
35
  for (const container of this.containers) {
54
- if (container.debounceTimer) {
55
- clearTimeout(container.debounceTimer);
56
- }
36
+ this.clearContainerTimer(container);
57
37
  if (container.element instanceof Window) {
58
38
  window.removeEventListener('scroll', container.listener);
59
39
  }
@@ -62,43 +42,38 @@ class ScrollHandler extends state_manager_1.StateManager {
62
42
  }
63
43
  }
64
44
  this.containers.length = 0;
65
- if (this.mutationObserver) {
66
- this.mutationObserver.disconnect();
67
- this.mutationObserver = null;
68
- }
69
- this.pendingSelectors.length = 0;
45
+ this.set('scrollEventCount', 0);
46
+ this.limitWarningLogged = false;
70
47
  }
71
48
  setupScrollContainer(element) {
72
- // Skip if already tracking this element
73
- if (this.containers.some((c) => c.element === element)) {
49
+ // Skip setup for non-scrollable elements
50
+ if (element !== window && !this.isElementScrollable(element)) {
74
51
  return;
75
52
  }
76
- const container = {
77
- element,
78
- lastScrollPos: this.getScrollTop(element),
79
- debounceTimer: null,
80
- listener: () => { },
81
- };
82
53
  const handleScroll = () => {
83
54
  if (this.get('suppressNextScroll')) {
84
- this.set('suppressNextScroll', false);
85
55
  return;
86
56
  }
87
- if (container.debounceTimer) {
88
- clearTimeout(container.debounceTimer);
89
- }
57
+ this.clearContainerTimer(container);
90
58
  container.debounceTimer = window.setTimeout(() => {
91
59
  const scrollData = this.calculateScrollData(container);
92
60
  if (scrollData) {
93
- this.eventManager.track({
94
- type: types_1.EventType.SCROLL,
95
- scroll_data: scrollData,
96
- });
61
+ const now = Date.now();
62
+ this.processScrollEvent(container, scrollData, now);
97
63
  }
98
64
  container.debounceTimer = null;
99
65
  }, constants_1.SCROLL_DEBOUNCE_TIME_MS);
100
66
  };
101
- container.listener = handleScroll;
67
+ const initialScrollTop = this.getScrollTop(element);
68
+ const container = {
69
+ element,
70
+ lastScrollPos: initialScrollTop,
71
+ lastDepth: this.calculateScrollDepth(initialScrollTop, this.getScrollHeight(element), this.getViewportHeight(element)),
72
+ lastDirection: types_1.ScrollDirection.DOWN,
73
+ lastEventTime: 0,
74
+ debounceTimer: null,
75
+ listener: handleScroll,
76
+ };
102
77
  this.containers.push(container);
103
78
  if (element instanceof Window) {
104
79
  window.addEventListener('scroll', handleScroll, { passive: true });
@@ -107,43 +82,95 @@ class ScrollHandler extends state_manager_1.StateManager {
107
82
  element.addEventListener('scroll', handleScroll, { passive: true });
108
83
  }
109
84
  }
85
+ processScrollEvent(container, scrollData, timestamp) {
86
+ if (!this.shouldEmitScrollEvent(container, scrollData, timestamp)) {
87
+ return;
88
+ }
89
+ container.lastEventTime = timestamp;
90
+ container.lastDepth = scrollData.depth;
91
+ container.lastDirection = scrollData.direction;
92
+ const currentCount = this.get('scrollEventCount') ?? 0;
93
+ this.set('scrollEventCount', currentCount + 1);
94
+ this.eventManager.track({
95
+ type: types_1.EventType.SCROLL,
96
+ scroll_data: scrollData,
97
+ });
98
+ }
99
+ shouldEmitScrollEvent(container, scrollData, timestamp) {
100
+ if (this.hasReachedSessionLimit()) {
101
+ this.logLimitOnce();
102
+ return false;
103
+ }
104
+ if (!this.hasElapsedMinimumInterval(container, timestamp)) {
105
+ return false;
106
+ }
107
+ if (!this.hasSignificantDepthChange(container, scrollData.depth)) {
108
+ return false;
109
+ }
110
+ return true;
111
+ }
112
+ hasReachedSessionLimit() {
113
+ const currentCount = this.get('scrollEventCount') ?? 0;
114
+ return currentCount >= this.maxEventsPerSession;
115
+ }
116
+ hasElapsedMinimumInterval(container, timestamp) {
117
+ if (container.lastEventTime === 0) {
118
+ return true;
119
+ }
120
+ return timestamp - container.lastEventTime >= this.minIntervalMs;
121
+ }
122
+ hasSignificantDepthChange(container, newDepth) {
123
+ return Math.abs(newDepth - container.lastDepth) >= this.minDepthChange;
124
+ }
125
+ logLimitOnce() {
126
+ if (this.limitWarningLogged) {
127
+ return;
128
+ }
129
+ this.limitWarningLogged = true;
130
+ logging_1.debugLog.warn('ScrollHandler', 'Max scroll events per session reached', {
131
+ limit: this.maxEventsPerSession,
132
+ });
133
+ }
134
+ applyConfigOverrides() {
135
+ this.minDepthChange = constants_1.MIN_SCROLL_DEPTH_CHANGE;
136
+ this.minIntervalMs = constants_1.SCROLL_MIN_EVENT_INTERVAL_MS;
137
+ this.maxEventsPerSession = constants_1.MAX_SCROLL_EVENTS_PER_SESSION;
138
+ }
139
+ isWindowScrollable() {
140
+ return document.documentElement.scrollHeight > window.innerHeight;
141
+ }
142
+ clearContainerTimer(container) {
143
+ if (container.debounceTimer !== null) {
144
+ clearTimeout(container.debounceTimer);
145
+ container.debounceTimer = null;
146
+ }
147
+ }
148
+ getScrollDirection(current, previous) {
149
+ return current > previous ? types_1.ScrollDirection.DOWN : types_1.ScrollDirection.UP;
150
+ }
151
+ calculateScrollDepth(scrollTop, scrollHeight, viewportHeight) {
152
+ if (scrollHeight <= viewportHeight) {
153
+ return 0;
154
+ }
155
+ const maxScrollTop = scrollHeight - viewportHeight;
156
+ return Math.min(100, Math.max(0, Math.floor((scrollTop / maxScrollTop) * 100)));
157
+ }
110
158
  calculateScrollData(container) {
111
159
  const { element, lastScrollPos } = container;
112
160
  const scrollTop = this.getScrollTop(element);
113
- const viewportHeight = this.getViewportHeight(element);
114
- const scrollHeight = this.getScrollHeight(element);
115
- const viewportWidth = this.getViewportWidth(element);
116
- const scrollWidth = this.getScrollWidth(element);
117
- // Dynamic validation: check if element is scrollable at runtime
118
- if (element instanceof HTMLElement) {
119
- // Check if element has scrollable overflow style (can change dynamically)
120
- if (!this.hasScrollableOverflow(element)) {
121
- return null;
122
- }
123
- // Check if content exceeds viewport (vertical OR horizontal)
124
- const hasVerticalScroll = scrollHeight > viewportHeight;
125
- const hasHorizontalScroll = scrollWidth > viewportWidth;
126
- if (!hasVerticalScroll && !hasHorizontalScroll) {
127
- return null;
128
- }
129
- }
130
- // For Window: check if content is scrollable (vertical or horizontal)
131
- if (element instanceof Window) {
132
- const hasVerticalScroll = scrollHeight > viewportHeight;
133
- const hasHorizontalScroll = scrollWidth > viewportWidth;
134
- if (!hasVerticalScroll && !hasHorizontalScroll) {
135
- return null;
136
- }
137
- }
138
- const direction = scrollTop > lastScrollPos ? types_1.ScrollDirection.DOWN : types_1.ScrollDirection.UP;
139
- const depth = scrollHeight > viewportHeight
140
- ? Math.min(100, Math.max(0, Math.floor((scrollTop / (scrollHeight - viewportHeight)) * 100)))
141
- : 0;
142
- // Only update if scroll position changed significantly
161
+ // Early return: check significant movement first (cheapest check)
143
162
  const positionDelta = Math.abs(scrollTop - lastScrollPos);
144
163
  if (positionDelta < constants_1.SIGNIFICANT_SCROLL_DELTA) {
145
164
  return null;
146
165
  }
166
+ // Early return: check if window is scrollable
167
+ if (element === window && !this.isWindowScrollable()) {
168
+ return null;
169
+ }
170
+ const viewportHeight = this.getViewportHeight(element);
171
+ const scrollHeight = this.getScrollHeight(element);
172
+ const direction = this.getScrollDirection(scrollTop, lastScrollPos);
173
+ const depth = this.calculateScrollDepth(scrollTop, scrollHeight, viewportHeight);
147
174
  container.lastScrollPos = scrollTop;
148
175
  return { depth, direction };
149
176
  }
@@ -156,20 +183,17 @@ class ScrollHandler extends state_manager_1.StateManager {
156
183
  getScrollHeight(element) {
157
184
  return element instanceof Window ? document.documentElement.scrollHeight : element.scrollHeight;
158
185
  }
159
- getViewportWidth(element) {
160
- return element instanceof Window ? window.innerWidth : element.clientWidth;
161
- }
162
- getScrollWidth(element) {
163
- return element instanceof Window ? document.documentElement.scrollWidth : element.scrollWidth;
164
- }
165
- hasScrollableOverflow(element) {
186
+ isElementScrollable(element) {
166
187
  const style = getComputedStyle(element);
167
- return (style.overflowY === 'auto' ||
188
+ const hasScrollableOverflow = style.overflowY === 'auto' ||
168
189
  style.overflowY === 'scroll' ||
169
190
  style.overflowX === 'auto' ||
170
191
  style.overflowX === 'scroll' ||
171
192
  style.overflow === 'auto' ||
172
- style.overflow === 'scroll');
193
+ style.overflow === 'scroll';
194
+ // Element must have scrollable overflow AND content that exceeds the container
195
+ const hasOverflowContent = element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
196
+ return hasScrollableOverflow && hasOverflowContent;
173
197
  }
174
198
  safeQuerySelector(selector) {
175
199
  try {
@@ -184,95 +208,5 @@ class ScrollHandler extends state_manager_1.StateManager {
184
208
  return null;
185
209
  }
186
210
  }
187
- setupPendingSelectors(selectors) {
188
- logging_1.debugLog.debug('ScrollHandler', 'Setting up pending selectors with retry logic', {
189
- selectors,
190
- maxRetries: constants_1.MAX_RETRY_ATTEMPTS,
191
- });
192
- for (const selector of selectors) {
193
- this.pendingSelectors.push({ selector, retryCount: 0 });
194
- }
195
- this.startMutationObserver();
196
- this.retryPendingSelectors();
197
- }
198
- startMutationObserver() {
199
- if (this.mutationObserver)
200
- return;
201
- this.mutationObserver = new MutationObserver(() => {
202
- this.checkPendingSelectors();
203
- });
204
- this.mutationObserver.observe(document.body, {
205
- childList: true,
206
- subtree: true,
207
- });
208
- logging_1.debugLog.debug('ScrollHandler', 'MutationObserver started for pending selectors');
209
- }
210
- checkPendingSelectors() {
211
- const remaining = [];
212
- for (const pending of this.pendingSelectors) {
213
- const element = this.safeQuerySelector(pending.selector);
214
- if (element instanceof HTMLElement) {
215
- logging_1.debugLog.debug('ScrollHandler', 'Found pending selector', { selector: pending.selector });
216
- this.setupScrollContainer(element);
217
- }
218
- else {
219
- remaining.push(pending);
220
- }
221
- }
222
- this.pendingSelectors.length = 0;
223
- this.pendingSelectors.push(...remaining);
224
- if (this.pendingSelectors.length === 0 && this.mutationObserver) {
225
- this.mutationObserver.disconnect();
226
- this.mutationObserver = null;
227
- logging_1.debugLog.debug('ScrollHandler', 'All pending selectors resolved, MutationObserver stopped');
228
- }
229
- }
230
- retryPendingSelectors() {
231
- setTimeout(() => {
232
- if (this.pendingSelectors.length === 0)
233
- return;
234
- const remaining = [];
235
- for (const pending of this.pendingSelectors) {
236
- pending.retryCount++;
237
- const element = this.safeQuerySelector(pending.selector);
238
- if (element instanceof HTMLElement) {
239
- logging_1.debugLog.debug('ScrollHandler', 'Retry found pending selector', {
240
- selector: pending.selector,
241
- retryCount: pending.retryCount,
242
- });
243
- this.setupScrollContainer(element);
244
- }
245
- else if (pending.retryCount < constants_1.MAX_RETRY_ATTEMPTS) {
246
- remaining.push(pending);
247
- }
248
- else {
249
- logging_1.debugLog.clientWarn('ScrollHandler', 'Selector not found after max retries', {
250
- selector: pending.selector,
251
- maxRetries: constants_1.MAX_RETRY_ATTEMPTS,
252
- });
253
- }
254
- }
255
- this.pendingSelectors.length = 0;
256
- this.pendingSelectors.push(...remaining);
257
- if (this.pendingSelectors.length > 0) {
258
- this.retryPendingSelectors();
259
- }
260
- else {
261
- // All retries complete
262
- if (this.mutationObserver) {
263
- this.mutationObserver.disconnect();
264
- this.mutationObserver = null;
265
- }
266
- // Apply window fallback if needed and no containers were set up
267
- if (this.windowFallbackNeeded && this.containers.length === 0) {
268
- logging_1.debugLog.debug('ScrollHandler', 'No scroll containers found, using window fallback');
269
- this.setupScrollContainer(window);
270
- }
271
- logging_1.debugLog.debug('ScrollHandler', 'All pending selectors resolved or timed out', {
272
- containersCount: this.containers.length,
273
- });
274
- }
275
- }, constants_1.RETRY_DELAY_MS);
276
- }
277
211
  }
278
212
  exports.ScrollHandler = ScrollHandler;
@@ -4,26 +4,12 @@ import { StorageManager } from '../managers/storage.manager';
4
4
  export declare class SessionHandler extends StateManager {
5
5
  private readonly eventManager;
6
6
  private readonly storageManager;
7
- private readonly sessionStorageKey;
8
7
  private sessionManager;
9
- private recoveryManager;
10
- private _crossTabSessionManager;
11
- private heartbeatInterval;
12
- private _isInitializingCrossTab;
13
- private get crossTabSessionManager();
14
- private shouldUseCrossTabs;
8
+ private destroyed;
15
9
  constructor(storageManager: StorageManager, eventManager: EventManager);
16
- startTracking(): void;
17
- stopTracking(): void;
18
- private initializeSessionRecoveryManager;
19
- private initializeCrossTabSessionManager;
20
- private createOrJoinSession;
21
- private forceCleanupSession;
22
- private trackSession;
23
- private startInitialSession;
24
- private checkOrphanedSessions;
25
- private persistSession;
26
- private clearPersistedSession;
27
- private startHeartbeat;
28
- private stopHeartbeat;
10
+ startTracking(): Promise<void>;
11
+ private isActive;
12
+ private cleanupSessionManager;
13
+ stopTracking(): Promise<void>;
14
+ destroy(): void;
29
15
  }