@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,587 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionManager = void 0;
4
+ const constants_1 = require("../constants");
5
+ const types_1 = require("../types");
6
+ const utils_1 = require("../utils");
7
+ const logging_1 = require("../utils/logging");
8
+ const listeners_1 = require("../listeners");
9
+ const state_manager_1 = require("./state.manager");
10
+ const session_recovery_manager_1 = require("./session-recovery.manager");
11
+ class SessionManager extends state_manager_1.StateManager {
12
+ constructor(onActivity, onInactivity, eventManager, storageManager, sessionEndConfig) {
13
+ super();
14
+ this.eventManager = null;
15
+ this.storageManager = null;
16
+ this.listenerManagers = [];
17
+ // Recovery manager
18
+ this.recoveryManager = null;
19
+ this.isSessionActive = false;
20
+ this.lastActivityTime = 0;
21
+ this.inactivityTimer = null;
22
+ this.sessionStartTime = 0;
23
+ this.throttleTimeout = null;
24
+ // Track visibility change timeout for proper cleanup
25
+ this.visibilityChangeTimeout = null;
26
+ // Session End Management
27
+ this.pendingSessionEnd = false;
28
+ this.sessionEndPromise = null;
29
+ this.sessionEndLock = Promise.resolve({
30
+ success: true,
31
+ reason: 'manual_stop',
32
+ timestamp: Date.now(),
33
+ eventsFlushed: 0,
34
+ method: 'async',
35
+ });
36
+ this.cleanupHandlers = [];
37
+ this.sessionEndReason = null;
38
+ this.sessionEndPriority = {
39
+ page_unload: 4,
40
+ manual_stop: 3,
41
+ orphaned_cleanup: 2,
42
+ inactivity: 1,
43
+ tab_closed: 0,
44
+ };
45
+ this.sessionEndStats = {
46
+ totalSessionEnds: 0,
47
+ successfulEnds: 0,
48
+ failedEnds: 0,
49
+ duplicatePrevented: 0,
50
+ reasonCounts: {
51
+ inactivity: 0,
52
+ page_unload: 0,
53
+ manual_stop: 0,
54
+ orphaned_cleanup: 0,
55
+ tab_closed: 0,
56
+ },
57
+ };
58
+ // Session health monitoring
59
+ this.sessionHealth = {
60
+ recoveryAttempts: 0,
61
+ sessionTimeouts: 0,
62
+ crossTabConflicts: 0,
63
+ lastHealthCheck: Date.now(),
64
+ };
65
+ this.handleActivity = () => {
66
+ const now = Date.now();
67
+ if (now - this.lastActivityTime < this.config.throttleDelay) {
68
+ return;
69
+ }
70
+ this.lastActivityTime = now;
71
+ if (this.isSessionActive) {
72
+ // Always call onActivity to update cross-tab session activity
73
+ this.onActivity();
74
+ this.resetInactivityTimer();
75
+ }
76
+ else {
77
+ if (this.throttleTimeout) {
78
+ clearTimeout(this.throttleTimeout);
79
+ this.throttleTimeout = null;
80
+ }
81
+ this.throttleTimeout = window.setTimeout(() => {
82
+ this.onActivity();
83
+ this.throttleTimeout = null;
84
+ }, 100);
85
+ }
86
+ };
87
+ this.handleInactivity = () => {
88
+ // Track session timeout for health monitoring
89
+ this.trackSessionHealth('timeout');
90
+ this.onInactivity();
91
+ };
92
+ this.handleVisibilityChange = () => {
93
+ if (document.hidden) {
94
+ if (this.isSessionActive) {
95
+ if (this.inactivityTimer) {
96
+ clearTimeout(this.inactivityTimer);
97
+ this.inactivityTimer = null;
98
+ }
99
+ this.inactivityTimer = window.setTimeout(this.handleInactivity, this.config.visibilityTimeout);
100
+ }
101
+ }
102
+ else {
103
+ this.handleActivity();
104
+ }
105
+ };
106
+ this.resetInactivityTimer = () => {
107
+ if (this.inactivityTimer) {
108
+ clearTimeout(this.inactivityTimer);
109
+ this.inactivityTimer = null;
110
+ }
111
+ if (this.isSessionActive) {
112
+ this.inactivityTimer = window.setTimeout(() => {
113
+ this.handleInactivity();
114
+ }, this.config.timeout);
115
+ }
116
+ };
117
+ this.config = {
118
+ throttleDelay: constants_1.DEFAULT_THROTTLE_DELAY_MS,
119
+ visibilityTimeout: constants_1.DEFAULT_VISIBILITY_TIMEOUT_MS,
120
+ motionThreshold: constants_1.DEFAULT_MOTION_THRESHOLD,
121
+ timeout: this.get('config')?.sessionTimeout ?? constants_1.DEFAULT_SESSION_TIMEOUT_MS,
122
+ };
123
+ this.sessionEndConfig = {
124
+ enablePageUnloadHandlers: true,
125
+ syncTimeoutMs: 1000,
126
+ maxRetries: 2,
127
+ debugMode: false,
128
+ ...sessionEndConfig,
129
+ };
130
+ this.onActivity = onActivity;
131
+ this.onInactivity = onInactivity;
132
+ this.eventManager = eventManager ?? null;
133
+ this.storageManager = storageManager ?? null;
134
+ this.deviceCapabilities = this.detectDeviceCapabilities();
135
+ this.initializeRecoveryManager();
136
+ this.initializeListenerManagers();
137
+ this.setupAllListeners();
138
+ if (this.sessionEndConfig.enablePageUnloadHandlers) {
139
+ this.setupPageUnloadHandlers();
140
+ }
141
+ logging_1.debugLog.debug('SessionManager', 'SessionManager initialized', {
142
+ sessionTimeout: this.config.timeout,
143
+ deviceCapabilities: this.deviceCapabilities,
144
+ unloadHandlersEnabled: this.sessionEndConfig.enablePageUnloadHandlers,
145
+ });
146
+ }
147
+ /**
148
+ * Initialize recovery manager
149
+ */
150
+ initializeRecoveryManager() {
151
+ if (!this.storageManager)
152
+ return;
153
+ const projectId = this.get('config')?.id;
154
+ if (!projectId)
155
+ return;
156
+ try {
157
+ // Initialize session recovery manager (always enabled)
158
+ this.recoveryManager = new session_recovery_manager_1.SessionRecoveryManager(this.storageManager, projectId, this.eventManager ?? undefined);
159
+ logging_1.debugLog.debug('SessionManager', 'Recovery manager initialized', { projectId });
160
+ }
161
+ catch (error) {
162
+ logging_1.debugLog.error('SessionManager', 'Failed to initialize recovery manager', { error, projectId });
163
+ }
164
+ }
165
+ /**
166
+ * Store session context for recovery
167
+ */
168
+ storeSessionContextForRecovery() {
169
+ if (!this.recoveryManager)
170
+ return;
171
+ const sessionId = this.get('sessionId');
172
+ if (!sessionId)
173
+ return;
174
+ const sessionContext = {
175
+ sessionId,
176
+ startTime: this.sessionStartTime,
177
+ lastActivity: this.lastActivityTime,
178
+ tabCount: 1, // This will be updated by cross-tab manager
179
+ recoveryAttempts: 0,
180
+ metadata: {
181
+ userAgent: navigator.userAgent,
182
+ pageUrl: this.get('pageUrl'),
183
+ },
184
+ };
185
+ this.recoveryManager.storeSessionContextForRecovery(sessionContext);
186
+ }
187
+ startSession() {
188
+ const now = Date.now();
189
+ // Attempt session recovery first
190
+ let sessionId = '';
191
+ let wasRecovered = false;
192
+ if (this.recoveryManager?.hasRecoverableSession()) {
193
+ const recoveryResult = this.recoveryManager.attemptSessionRecovery();
194
+ if (recoveryResult.recovered && recoveryResult.recoveredSessionId) {
195
+ sessionId = recoveryResult.recoveredSessionId;
196
+ wasRecovered = true;
197
+ // Track session recovery for health monitoring
198
+ this.trackSessionHealth('recovery');
199
+ // Update session timing from recovery context
200
+ if (recoveryResult.context) {
201
+ this.sessionStartTime = recoveryResult.context.startTime;
202
+ this.lastActivityTime = now;
203
+ }
204
+ else {
205
+ this.sessionStartTime = now;
206
+ this.lastActivityTime = now;
207
+ }
208
+ logging_1.debugLog.info('SessionManager', 'Session successfully recovered', {
209
+ sessionId,
210
+ recoveryAttempts: this.sessionHealth.recoveryAttempts,
211
+ });
212
+ }
213
+ }
214
+ // If no recovery, create new session
215
+ if (!wasRecovered) {
216
+ sessionId = (0, utils_1.generateUUID)();
217
+ this.sessionStartTime = now;
218
+ this.lastActivityTime = now;
219
+ logging_1.debugLog.info('SessionManager', 'New session started', { sessionId });
220
+ }
221
+ this.isSessionActive = true;
222
+ this.resetInactivityTimer();
223
+ // Store session context for future recovery
224
+ this.storeSessionContextForRecovery();
225
+ return { sessionId, recovered: wasRecovered };
226
+ }
227
+ endSession() {
228
+ if (this.sessionStartTime === 0) {
229
+ return 0;
230
+ }
231
+ const durationMs = Date.now() - this.sessionStartTime;
232
+ this.sessionStartTime = 0;
233
+ this.isSessionActive = false;
234
+ if (this.inactivityTimer) {
235
+ clearTimeout(this.inactivityTimer);
236
+ this.inactivityTimer = null;
237
+ }
238
+ return durationMs;
239
+ }
240
+ destroy() {
241
+ this.clearTimers();
242
+ this.cleanupAllListeners();
243
+ this.resetState();
244
+ this.cleanupHandlers.forEach((cleanup) => cleanup());
245
+ this.cleanupHandlers = [];
246
+ this.pendingSessionEnd = false;
247
+ this.sessionEndPromise = null;
248
+ this.sessionEndLock = Promise.resolve({
249
+ success: true,
250
+ reason: 'manual_stop',
251
+ timestamp: Date.now(),
252
+ eventsFlushed: 0,
253
+ method: 'async',
254
+ });
255
+ if (this.recoveryManager) {
256
+ this.recoveryManager.cleanupOldRecoveryAttempts();
257
+ this.recoveryManager = null;
258
+ }
259
+ }
260
+ detectDeviceCapabilities() {
261
+ const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
262
+ const hasMouse = window.matchMedia('(pointer: fine)').matches;
263
+ const hasKeyboard = !window.matchMedia('(pointer: coarse)').matches;
264
+ const isMobile = (0, utils_1.getDeviceType)() === types_1.DeviceType.Mobile;
265
+ return { hasTouch, hasMouse, hasKeyboard, isMobile };
266
+ }
267
+ initializeListenerManagers() {
268
+ this.listenerManagers.push(new listeners_1.ActivityListenerManager(this.handleActivity));
269
+ if (this.deviceCapabilities.hasTouch) {
270
+ this.listenerManagers.push(new listeners_1.TouchListenerManager(this.handleActivity, this.config.motionThreshold));
271
+ }
272
+ if (this.deviceCapabilities.hasMouse) {
273
+ this.listenerManagers.push(new listeners_1.MouseListenerManager(this.handleActivity));
274
+ }
275
+ if (this.deviceCapabilities.hasKeyboard) {
276
+ this.listenerManagers.push(new listeners_1.KeyboardListenerManager(this.handleActivity));
277
+ }
278
+ this.listenerManagers.push(new listeners_1.VisibilityListenerManager(this.handleActivity, this.handleVisibilityChange, this.deviceCapabilities.isMobile));
279
+ this.listenerManagers.push(new listeners_1.UnloadListenerManager(this.handleInactivity));
280
+ }
281
+ setupAllListeners() {
282
+ this.listenerManagers.forEach((manager) => manager.setup());
283
+ }
284
+ cleanupAllListeners() {
285
+ this.listenerManagers.forEach((manager) => manager.cleanup());
286
+ }
287
+ clearTimers() {
288
+ if (this.inactivityTimer) {
289
+ clearTimeout(this.inactivityTimer);
290
+ this.inactivityTimer = null;
291
+ }
292
+ if (this.throttleTimeout) {
293
+ clearTimeout(this.throttleTimeout);
294
+ this.throttleTimeout = null;
295
+ }
296
+ }
297
+ resetState() {
298
+ this.isSessionActive = false;
299
+ this.lastActivityTime = 0;
300
+ this.sessionStartTime = 0;
301
+ }
302
+ clearInactivityTimer() {
303
+ if (this.inactivityTimer) {
304
+ clearTimeout(this.inactivityTimer);
305
+ this.inactivityTimer = null;
306
+ }
307
+ }
308
+ shouldProceedWithSessionEnd(reason) {
309
+ return !this.sessionEndReason || this.sessionEndPriority[reason] > this.sessionEndPriority[this.sessionEndReason];
310
+ }
311
+ async waitForCompletion() {
312
+ if (this.sessionEndPromise) {
313
+ return await this.sessionEndPromise;
314
+ }
315
+ return {
316
+ success: false,
317
+ reason: 'inactivity',
318
+ timestamp: Date.now(),
319
+ eventsFlushed: 0,
320
+ method: 'async',
321
+ };
322
+ }
323
+ async endSessionManaged(reason) {
324
+ return (this.sessionEndLock = this.sessionEndLock.then(async () => {
325
+ this.sessionEndStats.totalSessionEnds++;
326
+ this.sessionEndStats.reasonCounts[reason]++;
327
+ if (this.pendingSessionEnd) {
328
+ this.sessionEndStats.duplicatePrevented++;
329
+ logging_1.debugLog.debug('SessionManager', 'Session end already pending, waiting for completion', { reason });
330
+ return this.waitForCompletion();
331
+ }
332
+ if (!this.shouldProceedWithSessionEnd(reason)) {
333
+ if (this.sessionEndConfig.debugMode) {
334
+ logging_1.debugLog.debug('SessionManager', `Session end skipped due to lower priority. Current: ${this.sessionEndReason}, Requested: ${reason}`);
335
+ }
336
+ return {
337
+ success: false,
338
+ reason,
339
+ timestamp: Date.now(),
340
+ eventsFlushed: 0,
341
+ method: 'async',
342
+ };
343
+ }
344
+ this.sessionEndReason = reason;
345
+ this.pendingSessionEnd = true;
346
+ this.sessionEndPromise = this.performSessionEnd(reason, 'async');
347
+ try {
348
+ const result = await this.sessionEndPromise;
349
+ return result;
350
+ }
351
+ finally {
352
+ this.pendingSessionEnd = false;
353
+ this.sessionEndPromise = null;
354
+ this.sessionEndReason = null;
355
+ }
356
+ }));
357
+ }
358
+ endSessionSafely(reason, options) {
359
+ const shouldUseSync = options?.forceSync ?? (options?.allowSync && ['page_unload', 'tab_closed'].includes(reason));
360
+ if (shouldUseSync) {
361
+ return this.endSessionManagedSync(reason);
362
+ }
363
+ return this.endSessionManaged(reason);
364
+ }
365
+ isPendingSessionEnd() {
366
+ return this.pendingSessionEnd;
367
+ }
368
+ /**
369
+ * Track session health events for monitoring and diagnostics
370
+ */
371
+ trackSessionHealth(event) {
372
+ const now = Date.now();
373
+ // Update health counters
374
+ switch (event) {
375
+ case 'recovery':
376
+ this.sessionHealth.recoveryAttempts++;
377
+ break;
378
+ case 'timeout':
379
+ this.sessionHealth.sessionTimeouts++;
380
+ break;
381
+ case 'conflict':
382
+ this.sessionHealth.crossTabConflicts++;
383
+ break;
384
+ }
385
+ this.sessionHealth.lastHealthCheck = now;
386
+ // Send health degradation event if recovery attempts are high
387
+ if (this.sessionHealth.recoveryAttempts > 3 && this.eventManager) {
388
+ this.eventManager.track({
389
+ type: types_1.EventType.CUSTOM,
390
+ custom_event: {
391
+ name: 'session_health_degraded',
392
+ metadata: {
393
+ ...this.sessionHealth,
394
+ event_trigger: event,
395
+ },
396
+ },
397
+ });
398
+ if (this.sessionEndConfig.debugMode) {
399
+ logging_1.debugLog.warn('SessionManager', `Session health degraded: ${this.sessionHealth.recoveryAttempts} recovery attempts`);
400
+ }
401
+ }
402
+ if (this.sessionEndConfig.debugMode) {
403
+ logging_1.debugLog.debug('SessionManager', `Session health event tracked: ${event}`);
404
+ }
405
+ }
406
+ async performSessionEnd(reason, method) {
407
+ const timestamp = Date.now();
408
+ let eventsFlushed = 0;
409
+ try {
410
+ logging_1.debugLog.info('SessionManager', 'Starting session end', { method, reason, timestamp });
411
+ if (this.eventManager) {
412
+ this.eventManager.track({
413
+ type: types_1.EventType.SESSION_END,
414
+ session_end_reason: reason,
415
+ });
416
+ eventsFlushed = this.eventManager.getQueueLength();
417
+ const flushResult = await this.eventManager.flushImmediately();
418
+ this.cleanupSession();
419
+ const result = {
420
+ success: flushResult,
421
+ reason,
422
+ timestamp,
423
+ eventsFlushed,
424
+ method,
425
+ };
426
+ if (flushResult) {
427
+ this.sessionEndStats.successfulEnds++;
428
+ }
429
+ else {
430
+ this.sessionEndStats.failedEnds++;
431
+ }
432
+ return result;
433
+ }
434
+ this.cleanupSession();
435
+ const result = {
436
+ success: true,
437
+ reason,
438
+ timestamp,
439
+ eventsFlushed: 0,
440
+ method,
441
+ };
442
+ this.sessionEndStats.successfulEnds++;
443
+ return result;
444
+ }
445
+ catch (error) {
446
+ this.sessionEndStats.failedEnds++;
447
+ logging_1.debugLog.error('SessionManager', 'Session end failed', { error, reason, method });
448
+ this.cleanupSession();
449
+ return {
450
+ success: false,
451
+ reason,
452
+ timestamp,
453
+ eventsFlushed,
454
+ method,
455
+ };
456
+ }
457
+ }
458
+ cleanupSession() {
459
+ this.endSession();
460
+ this.clearTimers();
461
+ this.set('sessionId', null);
462
+ this.set('hasStartSession', false);
463
+ }
464
+ endSessionManagedSync(reason) {
465
+ this.sessionEndStats.totalSessionEnds++;
466
+ this.sessionEndStats.reasonCounts[reason]++;
467
+ if (this.pendingSessionEnd) {
468
+ this.sessionEndStats.duplicatePrevented++;
469
+ logging_1.debugLog.warn('SessionManager', 'Sync session end called while async end pending', { reason });
470
+ }
471
+ if (!this.shouldProceedWithSessionEnd(reason)) {
472
+ if (this.sessionEndConfig.debugMode) {
473
+ logging_1.debugLog.debug('SessionManager', `Sync session end skipped due to lower priority. Current: ${this.sessionEndReason}, Requested: ${reason}`);
474
+ }
475
+ return {
476
+ success: false,
477
+ reason,
478
+ timestamp: Date.now(),
479
+ eventsFlushed: 0,
480
+ method: 'sync',
481
+ };
482
+ }
483
+ this.sessionEndReason = reason;
484
+ this.pendingSessionEnd = true;
485
+ try {
486
+ return this.performSessionEndSync(reason);
487
+ }
488
+ finally {
489
+ this.pendingSessionEnd = false;
490
+ this.sessionEndPromise = null;
491
+ this.sessionEndReason = null;
492
+ }
493
+ }
494
+ performSessionEndSync(reason) {
495
+ const timestamp = Date.now();
496
+ let eventsFlushed = 0;
497
+ try {
498
+ if (this.eventManager) {
499
+ this.eventManager.track({
500
+ type: types_1.EventType.SESSION_END,
501
+ session_end_reason: reason,
502
+ });
503
+ eventsFlushed = this.eventManager.getQueueLength();
504
+ const success = this.eventManager.flushImmediatelySync();
505
+ this.cleanupSession();
506
+ const result = {
507
+ success,
508
+ reason,
509
+ timestamp,
510
+ eventsFlushed,
511
+ method: 'sync',
512
+ };
513
+ if (success) {
514
+ this.sessionEndStats.successfulEnds++;
515
+ }
516
+ else {
517
+ this.sessionEndStats.failedEnds++;
518
+ }
519
+ return result;
520
+ }
521
+ this.cleanupSession();
522
+ const result = {
523
+ success: true,
524
+ reason,
525
+ timestamp,
526
+ eventsFlushed: 0,
527
+ method: 'sync',
528
+ };
529
+ this.sessionEndStats.successfulEnds++;
530
+ return result;
531
+ }
532
+ catch (error) {
533
+ this.sessionEndStats.failedEnds++;
534
+ this.cleanupSession();
535
+ logging_1.debugLog.error('SessionManager', 'Sync session end failed', { error, reason });
536
+ return {
537
+ success: false,
538
+ reason,
539
+ timestamp,
540
+ eventsFlushed,
541
+ method: 'sync',
542
+ };
543
+ }
544
+ }
545
+ setupPageUnloadHandlers() {
546
+ let unloadHandled = false;
547
+ const handlePageUnload = () => {
548
+ if (unloadHandled || !this.get('sessionId')) {
549
+ return;
550
+ }
551
+ unloadHandled = true;
552
+ this.clearInactivityTimer();
553
+ this.endSessionSafely('page_unload', { forceSync: true });
554
+ };
555
+ // Primary handler for modern browsers
556
+ const beforeUnloadHandler = () => {
557
+ handlePageUnload();
558
+ };
559
+ // Fallback for older browsers and mobile Safari
560
+ const pageHideHandler = (event) => {
561
+ if (!event.persisted) {
562
+ handlePageUnload();
563
+ }
564
+ };
565
+ // Delayed handler for visibility changes (gives time for page transitions)
566
+ const visibilityChangeHandler = () => {
567
+ if (document.visibilityState === 'hidden' && this.get('sessionId') && !unloadHandled) {
568
+ this.visibilityChangeTimeout = window.setTimeout(() => {
569
+ if (document.visibilityState === 'hidden' && this.get('sessionId') && !unloadHandled) {
570
+ handlePageUnload();
571
+ }
572
+ this.visibilityChangeTimeout = null;
573
+ }, 1000);
574
+ }
575
+ };
576
+ window.addEventListener('beforeunload', beforeUnloadHandler);
577
+ window.addEventListener('pagehide', pageHideHandler);
578
+ document.addEventListener('visibilitychange', visibilityChangeHandler);
579
+ this.cleanupHandlers.push(() => window.removeEventListener('beforeunload', beforeUnloadHandler), () => window.removeEventListener('pagehide', pageHideHandler), () => document.removeEventListener('visibilitychange', visibilityChangeHandler), () => {
580
+ if (this.visibilityChangeTimeout) {
581
+ clearTimeout(this.visibilityChangeTimeout);
582
+ this.visibilityChangeTimeout = null;
583
+ }
584
+ });
585
+ }
586
+ }
587
+ exports.SessionManager = SessionManager;
@@ -0,0 +1,5 @@
1
+ import { State } from '../types';
2
+ export declare abstract class StateManager {
3
+ protected get<T extends keyof State>(key: T): State[T];
4
+ protected set<T extends keyof State>(key: T, value: State[T]): void;
5
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StateManager = void 0;
4
+ const logging_1 = require("../utils/logging");
5
+ const globalState = {};
6
+ class StateManager {
7
+ get(key) {
8
+ return globalState[key];
9
+ }
10
+ set(key, value) {
11
+ const oldValue = globalState[key];
12
+ globalState[key] = value;
13
+ // Log critical state changes
14
+ if (key === 'sessionId' || key === 'config' || key === 'hasStartSession') {
15
+ logging_1.debugLog.debug('StateManager', 'Critical state updated', {
16
+ key,
17
+ oldValue: key === 'config' ? !!oldValue : oldValue,
18
+ newValue: key === 'config' ? !!value : value,
19
+ });
20
+ }
21
+ }
22
+ }
23
+ exports.StateManager = StateManager;
@@ -0,0 +1,10 @@
1
+ export declare class StorageManager {
2
+ private readonly storage;
3
+ private readonly fallbackStorage;
4
+ private storageAvailable;
5
+ constructor();
6
+ getItem(key: string): string | null;
7
+ setItem(key: string, value: string): void;
8
+ removeItem(key: string): void;
9
+ private init;
10
+ }