@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,304 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SenderManager = void 0;
4
+ const constants_1 = require("../constants");
5
+ const types_1 = require("../types");
6
+ const logging_1 = require("../utils/logging");
7
+ const state_manager_1 = require("./state.manager");
8
+ class SenderManager extends state_manager_1.StateManager {
9
+ constructor(storeManager) {
10
+ super();
11
+ this.retryDelay = constants_1.RETRY_BACKOFF_INITIAL;
12
+ this.retryTimeoutId = null;
13
+ this.lastAsyncSend = 0;
14
+ this.lastSyncSend = 0;
15
+ this.storeManager = storeManager;
16
+ this.queueStorageKey = `${(0, constants_1.QUEUE_KEY)(this.get('config')?.id)}:${this.get('userId')}`;
17
+ this.recoverPersistedEvents();
18
+ }
19
+ async sendEventsQueueAsync(body) {
20
+ return this.executeSend(body, () => this.sendQueueAsync(body));
21
+ }
22
+ sendEventsQueueSync(body) {
23
+ return this.executeSendSync(body, () => this.sendQueueSync(body));
24
+ }
25
+ sendEventsQueue(body) {
26
+ return this.executeSendSync(body, () => this.sendQueue(body));
27
+ }
28
+ recoverPersistedEvents() {
29
+ try {
30
+ const persistedData = this.getPersistedData();
31
+ if (!persistedData || !this.isDataRecent(persistedData) || persistedData.events.length === 0) {
32
+ this.clearPersistedEvents();
33
+ return;
34
+ }
35
+ const recoveryBody = this.createRecoveryBody(persistedData);
36
+ const success = this.sendRecoveredEvents(recoveryBody);
37
+ if (success) {
38
+ logging_1.debugLog.info('SenderManager', 'Persisted events recovered successfully', {
39
+ eventsCount: persistedData.events.length,
40
+ sessionId: persistedData.sessionId,
41
+ });
42
+ this.clearPersistedEvents();
43
+ }
44
+ else {
45
+ logging_1.debugLog.warn('SenderManager', 'Failed to recover persisted events, scheduling retry', {
46
+ eventsCount: persistedData.events.length,
47
+ });
48
+ this.scheduleRetryForRecoveredEvents(recoveryBody);
49
+ }
50
+ }
51
+ catch (error) {
52
+ logging_1.debugLog.error('SenderManager', 'Failed to recover persisted events', { error });
53
+ }
54
+ }
55
+ stop() {
56
+ this.clearRetryTimeout();
57
+ this.resetRetryState();
58
+ }
59
+ /**
60
+ * Sends recovered events without re-deduplication since they were already processed
61
+ */
62
+ sendRecoveredEvents(body) {
63
+ return this.executeSendSync(body, () => this.sendQueue(body));
64
+ }
65
+ /**
66
+ * Schedules retry for recovered events using the specific recovery method
67
+ */
68
+ scheduleRetryForRecoveredEvents(body) {
69
+ if (this.retryTimeoutId !== null) {
70
+ return;
71
+ }
72
+ this.retryTimeoutId = window.setTimeout(() => {
73
+ this.retryTimeoutId = null;
74
+ this.sendRecoveredEvents(body);
75
+ }, this.retryDelay);
76
+ this.retryDelay = Math.min(this.retryDelay * 2, constants_1.RETRY_BACKOFF_MAX);
77
+ }
78
+ canSendAsync() {
79
+ return Date.now() - this.lastAsyncSend >= constants_1.RATE_LIMIT_INTERVAL;
80
+ }
81
+ canSendSync() {
82
+ return Date.now() - this.lastSyncSend >= constants_1.RATE_LIMIT_INTERVAL;
83
+ }
84
+ async sendQueueAsync(body) {
85
+ const { url, payload } = this.prepareRequest(body);
86
+ try {
87
+ const response = await fetch(url, {
88
+ method: 'POST',
89
+ headers: {
90
+ 'Content-Type': 'application/json',
91
+ },
92
+ body: payload,
93
+ });
94
+ return response.ok;
95
+ }
96
+ catch (error) {
97
+ logging_1.debugLog.error('SenderManager', 'Failed to send events async', { error });
98
+ return false;
99
+ }
100
+ }
101
+ sendQueueSync(body) {
102
+ const { url, payload } = this.prepareRequest(body);
103
+ if (this.isSendBeaconAvailable() && navigator.sendBeacon(url, payload)) {
104
+ return true;
105
+ }
106
+ return this.sendSyncXHR(url, payload);
107
+ }
108
+ sendQueue(body) {
109
+ if (!this.isSendBeaconAvailable()) {
110
+ return false;
111
+ }
112
+ const { url, payload } = this.prepareRequest(body);
113
+ return navigator.sendBeacon(url, payload);
114
+ }
115
+ sendSyncXHR(url, payload) {
116
+ try {
117
+ const xhr = new XMLHttpRequest();
118
+ xhr.open('POST', url, false);
119
+ xhr.setRequestHeader('Content-Type', 'application/json');
120
+ xhr.timeout = constants_1.SYNC_XHR_TIMEOUT_MS;
121
+ xhr.send(payload);
122
+ return xhr.status >= 200 && xhr.status < 300;
123
+ }
124
+ catch (error) {
125
+ logging_1.debugLog.error('SenderManager', 'Sync XHR failed', { error });
126
+ return false;
127
+ }
128
+ }
129
+ prepareRequest(body) {
130
+ const useLocalServer = this.get('config').id === types_1.SpecialProjectId.HttpLocal;
131
+ const baseUrl = useLocalServer ? window.location.origin : (this.get('apiUrl') ?? constants_1.API_BASE_URL);
132
+ return {
133
+ url: `${baseUrl}/events`,
134
+ payload: JSON.stringify(body),
135
+ };
136
+ }
137
+ getPersistedData() {
138
+ const persistedDataString = this.storeManager.getItem(this.queueStorageKey);
139
+ return persistedDataString ? JSON.parse(persistedDataString) : null;
140
+ }
141
+ isDataRecent(data) {
142
+ const ageInHours = (Date.now() - data.timestamp) / (1000 * 60 * 60);
143
+ return ageInHours < constants_1.EVENT_EXPIRY_HOURS;
144
+ }
145
+ createRecoveryBody(data) {
146
+ return {
147
+ user_id: data.userId,
148
+ session_id: data.sessionId,
149
+ device: data.device,
150
+ events: data.events,
151
+ ...(data.global_metadata && { global_metadata: data.global_metadata }),
152
+ };
153
+ }
154
+ logQueue(queue) {
155
+ logging_1.debugLog.info('SenderManager', ` ⏩ Queue snapshot`, queue);
156
+ }
157
+ handleSendFailure(body) {
158
+ this.persistFailedEvents(body);
159
+ this.scheduleRetry(body);
160
+ }
161
+ persistFailedEvents(body) {
162
+ try {
163
+ const persistedData = {
164
+ userId: body.user_id,
165
+ sessionId: body.session_id,
166
+ device: body.device,
167
+ events: body.events,
168
+ timestamp: Date.now(),
169
+ ...(body.global_metadata && { global_metadata: body.global_metadata }),
170
+ };
171
+ this.storeManager.setItem(this.queueStorageKey, JSON.stringify(persistedData));
172
+ }
173
+ catch (error) {
174
+ logging_1.debugLog.error('SenderManager', 'Failed to persist events', { error });
175
+ }
176
+ }
177
+ clearPersistedEvents() {
178
+ this.storeManager.removeItem(this.queueStorageKey);
179
+ }
180
+ resetRetryState() {
181
+ this.retryDelay = constants_1.RETRY_BACKOFF_INITIAL;
182
+ this.clearRetryTimeout();
183
+ }
184
+ scheduleRetry(body) {
185
+ if (this.retryTimeoutId !== null) {
186
+ return;
187
+ }
188
+ this.retryTimeoutId = window.setTimeout(() => {
189
+ this.retryTimeoutId = null;
190
+ this.sendEventsQueue(body);
191
+ }, this.retryDelay);
192
+ this.retryDelay = Math.min(this.retryDelay * 2, constants_1.RETRY_BACKOFF_MAX);
193
+ }
194
+ async executeSend(body, sendFn) {
195
+ if (this.shouldSkipSend()) {
196
+ this.logQueue(body);
197
+ return true;
198
+ }
199
+ if (!this.canSendAsync()) {
200
+ logging_1.debugLog.info('SenderManager', `⏱️ Rate limited - skipping async send`, {
201
+ eventsCount: body.events.length,
202
+ timeSinceLastSend: Date.now() - this.lastAsyncSend,
203
+ });
204
+ return false;
205
+ }
206
+ logging_1.debugLog.info('SenderManager', `🌐 Sending events to server (async)`, {
207
+ eventsCount: body.events.length,
208
+ sessionId: body.session_id,
209
+ userId: body.user_id,
210
+ });
211
+ this.lastAsyncSend = Date.now();
212
+ try {
213
+ const success = await sendFn();
214
+ if (success) {
215
+ logging_1.debugLog.info('SenderManager', `✅ Successfully sent events to server`, {
216
+ eventsCount: body.events.length,
217
+ method: 'async',
218
+ });
219
+ this.resetRetryState();
220
+ this.clearPersistedEvents();
221
+ }
222
+ else {
223
+ logging_1.debugLog.warn('SenderManager', 'Failed to send events', {
224
+ eventsCount: body.events.length,
225
+ method: 'async',
226
+ });
227
+ this.handleSendFailure(body);
228
+ }
229
+ return success;
230
+ }
231
+ catch {
232
+ this.handleSendFailure(body);
233
+ return false;
234
+ }
235
+ }
236
+ executeSendSync(body, sendFn) {
237
+ if (this.shouldSkipSend()) {
238
+ this.logQueue(body);
239
+ return true;
240
+ }
241
+ if (!this.canSendSync()) {
242
+ logging_1.debugLog.info('SenderManager', `⏱️ Rate limited - skipping sync send`, {
243
+ eventsCount: body.events.length,
244
+ timeSinceLastSend: Date.now() - this.lastSyncSend,
245
+ });
246
+ return false;
247
+ }
248
+ logging_1.debugLog.info('SenderManager', `🌐 Sending events to server (sync)`, {
249
+ eventsCount: body.events.length,
250
+ sessionId: body.session_id,
251
+ userId: body.user_id,
252
+ method: 'sendBeacon/XHR',
253
+ });
254
+ this.lastSyncSend = Date.now();
255
+ try {
256
+ const success = sendFn();
257
+ if (success) {
258
+ logging_1.debugLog.info('SenderManager', `✅ Successfully sent events to server`, {
259
+ eventsCount: body.events.length,
260
+ method: 'sync',
261
+ });
262
+ this.resetRetryState();
263
+ this.clearPersistedEvents();
264
+ }
265
+ else {
266
+ logging_1.debugLog.warn('SenderManager', 'Failed to send events', {
267
+ eventsCount: body.events.length,
268
+ method: 'sync',
269
+ });
270
+ this.handleSendFailure(body);
271
+ }
272
+ return success;
273
+ }
274
+ catch {
275
+ logging_1.debugLog.info('SenderManager', `💥 Exception during event sending`, {
276
+ eventsCount: body.events.length,
277
+ method: 'sync',
278
+ });
279
+ this.handleSendFailure(body);
280
+ return false;
281
+ }
282
+ }
283
+ shouldSkipSend() {
284
+ const { id, mode } = this.get('config');
285
+ const specialModes = [types_1.Mode.QA, types_1.Mode.DEBUG];
286
+ if (id === types_1.SpecialProjectId.HttpSkip) {
287
+ return true;
288
+ }
289
+ return !!mode && specialModes.includes(mode) && id !== types_1.SpecialProjectId.HttpLocal;
290
+ }
291
+ isSendBeaconAvailable() {
292
+ if (typeof navigator.sendBeacon !== 'function') {
293
+ return false;
294
+ }
295
+ return true;
296
+ }
297
+ clearRetryTimeout() {
298
+ if (this.retryTimeoutId !== null) {
299
+ clearTimeout(this.retryTimeoutId);
300
+ this.retryTimeoutId = null;
301
+ }
302
+ }
303
+ }
304
+ exports.SenderManager = SenderManager;
@@ -0,0 +1,65 @@
1
+ import { SessionRecoveryConfig, SessionContext } from '../types/session.types';
2
+ import { StateManager } from './state.manager';
3
+ import { StorageManager } from './storage.manager';
4
+ import { EventManager } from './event.manager';
5
+ export declare class SessionRecoveryManager extends StateManager {
6
+ private readonly config;
7
+ private readonly storageManager;
8
+ private readonly eventManager;
9
+ private readonly projectId;
10
+ private readonly debugMode;
11
+ constructor(storageManager: StorageManager, projectId: string, eventManager?: EventManager, config?: Partial<SessionRecoveryConfig>);
12
+ /**
13
+ * Attempt to recover a session
14
+ */
15
+ attemptSessionRecovery(currentSessionId?: string): {
16
+ recovered: boolean;
17
+ recoveredSessionId?: string;
18
+ context?: SessionContext;
19
+ };
20
+ /**
21
+ * Calculate the recovery window with bounds checking
22
+ */
23
+ private calculateRecoveryWindow;
24
+ /**
25
+ * Check if session recovery can be attempted
26
+ */
27
+ private canAttemptRecovery;
28
+ /**
29
+ * Store session context for potential recovery
30
+ */
31
+ storeSessionContextForRecovery(sessionContext: SessionContext): void;
32
+ /**
33
+ * Get stored recovery attempts
34
+ */
35
+ private getStoredRecoveryAttempts;
36
+ /**
37
+ * Store recovery attempts
38
+ */
39
+ private storeRecoveryAttempts;
40
+ /**
41
+ * Get the last recovery attempt
42
+ */
43
+ private getLastRecoveryAttempt;
44
+ /**
45
+ * Clean up old recovery attempts
46
+ */
47
+ cleanupOldRecoveryAttempts(): void;
48
+ /**
49
+ * Check if there's a recoverable session.
50
+ * Returns false when no recovery attempts are stored.
51
+ */
52
+ hasRecoverableSession(): boolean;
53
+ /**
54
+ * Get recovery window in milliseconds
55
+ */
56
+ getRecoveryWindowMs(): number;
57
+ /**
58
+ * Get max recovery attempts
59
+ */
60
+ getMaxRecoveryAttempts(): number;
61
+ /**
62
+ * Clear all stored recovery data
63
+ */
64
+ clearRecoveryData(): void;
65
+ }
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionRecoveryManager = void 0;
4
+ const constants_1 = require("../constants");
5
+ const storage_constants_1 = require("../constants/storage.constants");
6
+ const logging_1 = require("../utils/logging");
7
+ const state_manager_1 = require("./state.manager");
8
+ class SessionRecoveryManager extends state_manager_1.StateManager {
9
+ constructor(storageManager, projectId, eventManager, config) {
10
+ super();
11
+ this.storageManager = storageManager;
12
+ this.eventManager = eventManager ?? null;
13
+ this.projectId = projectId;
14
+ this.debugMode = (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') ?? false;
15
+ this.config = {
16
+ recoveryWindowMs: this.calculateRecoveryWindow(),
17
+ maxRecoveryAttempts: constants_1.MAX_SESSION_RECOVERY_ATTEMPTS,
18
+ contextPreservation: true,
19
+ ...config,
20
+ };
21
+ }
22
+ /**
23
+ * Attempt to recover a session
24
+ */
25
+ attemptSessionRecovery(currentSessionId) {
26
+ if (this.debugMode) {
27
+ logging_1.debugLog.debug('SessionRecovery', 'Attempting session recovery');
28
+ }
29
+ // Get stored recovery attempts
30
+ const recoveryAttempts = this.getStoredRecoveryAttempts();
31
+ const lastAttempt = this.getLastRecoveryAttempt();
32
+ // Check if we can recover
33
+ if (!this.canAttemptRecovery(lastAttempt)) {
34
+ if (this.debugMode) {
35
+ logging_1.debugLog.debug('SessionRecovery', 'Session recovery not possible - outside recovery window or max attempts reached');
36
+ }
37
+ return {
38
+ recovered: false,
39
+ };
40
+ }
41
+ // Get the last session context
42
+ const lastSessionContext = lastAttempt?.context;
43
+ if (!lastSessionContext) {
44
+ if (this.debugMode) {
45
+ logging_1.debugLog.debug('SessionRecovery', 'No session context available for recovery');
46
+ }
47
+ return {
48
+ recovered: false,
49
+ };
50
+ }
51
+ // Check if recovery is possible
52
+ const now = Date.now();
53
+ const timeSinceLastActivity = now - lastSessionContext.lastActivity;
54
+ if (timeSinceLastActivity > this.config.recoveryWindowMs) {
55
+ if (this.debugMode) {
56
+ logging_1.debugLog.debug('SessionRecovery', 'Session recovery failed - outside recovery window');
57
+ }
58
+ return {
59
+ recovered: false,
60
+ };
61
+ }
62
+ // Perform recovery
63
+ const recoveredSessionId = lastSessionContext.sessionId;
64
+ const attemptNumber = (lastAttempt?.attempt ?? 0) + 1;
65
+ // Create recovery attempt record
66
+ const recoveryAttempt = {
67
+ sessionId: currentSessionId ?? recoveredSessionId,
68
+ timestamp: now,
69
+ attempt: attemptNumber,
70
+ context: {
71
+ ...lastSessionContext,
72
+ recoveryAttempts: attemptNumber,
73
+ lastActivity: now,
74
+ },
75
+ };
76
+ recoveryAttempts.push(recoveryAttempt);
77
+ this.storeRecoveryAttempts(recoveryAttempts);
78
+ if (this.debugMode) {
79
+ logging_1.debugLog.debug('SessionRecovery', `Session recovery successful: recovery of session ${recoveredSessionId}`);
80
+ }
81
+ return {
82
+ recovered: true,
83
+ recoveredSessionId,
84
+ context: recoveryAttempt.context,
85
+ };
86
+ }
87
+ /**
88
+ * Calculate the recovery window with bounds checking
89
+ */
90
+ calculateRecoveryWindow() {
91
+ const sessionTimeout = this.get('config')?.sessionTimeout ?? constants_1.DEFAULT_SESSION_TIMEOUT_MS;
92
+ const calculatedRecoveryWindow = sessionTimeout * constants_1.SESSION_RECOVERY_WINDOW_MULTIPLIER;
93
+ const boundedRecoveryWindow = Math.max(Math.min(calculatedRecoveryWindow, constants_1.MAX_SESSION_RECOVERY_WINDOW_MS), constants_1.MIN_SESSION_RECOVERY_WINDOW_MS);
94
+ if (this.debugMode) {
95
+ if (calculatedRecoveryWindow > constants_1.MAX_SESSION_RECOVERY_WINDOW_MS) {
96
+ logging_1.debugLog.warn('SessionRecovery', `Recovery window capped at ${constants_1.MAX_SESSION_RECOVERY_WINDOW_MS}ms (24h). Calculated: ${calculatedRecoveryWindow}ms`);
97
+ }
98
+ else if (calculatedRecoveryWindow < constants_1.MIN_SESSION_RECOVERY_WINDOW_MS) {
99
+ logging_1.debugLog.warn('SessionRecovery', `Recovery window increased to minimum ${constants_1.MIN_SESSION_RECOVERY_WINDOW_MS}ms (2min). Calculated: ${calculatedRecoveryWindow}ms`);
100
+ }
101
+ }
102
+ return boundedRecoveryWindow;
103
+ }
104
+ /**
105
+ * Check if session recovery can be attempted
106
+ */
107
+ canAttemptRecovery(lastAttempt) {
108
+ if (!lastAttempt) {
109
+ return true; // First recovery attempt
110
+ }
111
+ const now = Date.now();
112
+ const timeSinceLastActivity = now - lastAttempt.context.lastActivity;
113
+ // Check if within recovery window
114
+ if (timeSinceLastActivity > this.config.recoveryWindowMs) {
115
+ return false;
116
+ }
117
+ // Check max attempts
118
+ if (lastAttempt.attempt >= this.config.maxRecoveryAttempts) {
119
+ return false;
120
+ }
121
+ return true;
122
+ }
123
+ /**
124
+ * Store session context for potential recovery
125
+ */
126
+ storeSessionContextForRecovery(sessionContext) {
127
+ try {
128
+ const recoveryAttempts = this.getStoredRecoveryAttempts();
129
+ // Create a recovery attempt record
130
+ const recoveryAttempt = {
131
+ sessionId: sessionContext.sessionId,
132
+ timestamp: Date.now(),
133
+ attempt: 0,
134
+ context: sessionContext,
135
+ };
136
+ // Add to recovery attempts (keep only the latest few)
137
+ recoveryAttempts.push(recoveryAttempt);
138
+ const maxStoredRecoveryAttempts = 5;
139
+ if (recoveryAttempts.length > maxStoredRecoveryAttempts) {
140
+ recoveryAttempts.splice(0, recoveryAttempts.length - maxStoredRecoveryAttempts);
141
+ }
142
+ this.storeRecoveryAttempts(recoveryAttempts);
143
+ if (this.debugMode) {
144
+ logging_1.debugLog.debug('SessionRecovery', `Stored session context for recovery: ${sessionContext.sessionId}`);
145
+ }
146
+ }
147
+ catch (error) {
148
+ if (this.debugMode) {
149
+ logging_1.debugLog.warn('SessionRecovery', 'Failed to store session context for recovery', { error });
150
+ }
151
+ }
152
+ }
153
+ /**
154
+ * Get stored recovery attempts
155
+ */
156
+ getStoredRecoveryAttempts() {
157
+ try {
158
+ const stored = this.storageManager.getItem((0, storage_constants_1.SESSION_RECOVERY_KEY)(this.projectId));
159
+ return stored ? JSON.parse(stored) : [];
160
+ }
161
+ catch (error) {
162
+ if (this.debugMode) {
163
+ const stored = this.storageManager.getItem((0, storage_constants_1.SESSION_RECOVERY_KEY)(this.projectId));
164
+ logging_1.debugLog.warn('SessionRecovery', `Failed to parse stored recovery attempts for projectId ${this.projectId}. Data: ${stored}`, { error });
165
+ }
166
+ return [];
167
+ }
168
+ }
169
+ /**
170
+ * Store recovery attempts
171
+ */
172
+ storeRecoveryAttempts(attempts) {
173
+ try {
174
+ this.storageManager.setItem((0, storage_constants_1.SESSION_RECOVERY_KEY)(this.projectId), JSON.stringify(attempts));
175
+ }
176
+ catch (error) {
177
+ if (this.debugMode) {
178
+ logging_1.debugLog.warn('SessionRecovery', 'Failed to store recovery attempts', { error });
179
+ }
180
+ }
181
+ }
182
+ /**
183
+ * Get the last recovery attempt
184
+ */
185
+ getLastRecoveryAttempt() {
186
+ const attempts = this.getStoredRecoveryAttempts();
187
+ return attempts.length > 0 ? attempts[attempts.length - 1] : null;
188
+ }
189
+ /**
190
+ * Clean up old recovery attempts
191
+ */
192
+ cleanupOldRecoveryAttempts() {
193
+ const attempts = this.getStoredRecoveryAttempts();
194
+ const now = Date.now();
195
+ // Remove attempts older than recovery window
196
+ const validAttempts = attempts.filter((attempt) => now - attempt.timestamp <= this.config.recoveryWindowMs);
197
+ if (validAttempts.length !== attempts.length) {
198
+ this.storeRecoveryAttempts(validAttempts);
199
+ if (this.debugMode) {
200
+ logging_1.debugLog.debug('SessionRecovery', `Cleaned up ${attempts.length - validAttempts.length} old recovery attempts`);
201
+ }
202
+ }
203
+ }
204
+ /**
205
+ * Check if there's a recoverable session.
206
+ * Returns false when no recovery attempts are stored.
207
+ */
208
+ hasRecoverableSession() {
209
+ const lastAttempt = this.getLastRecoveryAttempt();
210
+ if (!lastAttempt) {
211
+ return false;
212
+ }
213
+ return this.canAttemptRecovery(lastAttempt);
214
+ }
215
+ /**
216
+ * Get recovery window in milliseconds
217
+ */
218
+ getRecoveryWindowMs() {
219
+ return this.config.recoveryWindowMs;
220
+ }
221
+ /**
222
+ * Get max recovery attempts
223
+ */
224
+ getMaxRecoveryAttempts() {
225
+ return this.config.maxRecoveryAttempts;
226
+ }
227
+ /**
228
+ * Clear all stored recovery data
229
+ */
230
+ clearRecoveryData() {
231
+ this.storageManager.removeItem((0, storage_constants_1.SESSION_RECOVERY_KEY)(this.projectId));
232
+ if (this.debugMode) {
233
+ logging_1.debugLog.debug('SessionRecovery', 'Cleared all recovery data');
234
+ }
235
+ }
236
+ }
237
+ exports.SessionRecoveryManager = SessionRecoveryManager;
@@ -0,0 +1,72 @@
1
+ import { SessionEndReason, SessionEndConfig, SessionEndResult } from '../types/session.types';
2
+ import { StateManager } from './state.manager';
3
+ import { EventManager } from './event.manager';
4
+ import { StorageManager } from './storage.manager';
5
+ export declare class SessionManager extends StateManager {
6
+ private readonly config;
7
+ private readonly eventManager;
8
+ private readonly storageManager;
9
+ private readonly listenerManagers;
10
+ private readonly deviceCapabilities;
11
+ private readonly onActivity;
12
+ private readonly onInactivity;
13
+ private recoveryManager;
14
+ private isSessionActive;
15
+ private lastActivityTime;
16
+ private inactivityTimer;
17
+ private sessionStartTime;
18
+ private throttleTimeout;
19
+ private visibilityChangeTimeout;
20
+ private pendingSessionEnd;
21
+ private sessionEndPromise;
22
+ private sessionEndLock;
23
+ private cleanupHandlers;
24
+ private readonly sessionEndConfig;
25
+ private sessionEndReason;
26
+ private readonly sessionEndPriority;
27
+ private readonly sessionEndStats;
28
+ private readonly sessionHealth;
29
+ constructor(onActivity: () => void, onInactivity: () => void, eventManager?: EventManager, storageManager?: StorageManager, sessionEndConfig?: Partial<SessionEndConfig>);
30
+ /**
31
+ * Initialize recovery manager
32
+ */
33
+ private initializeRecoveryManager;
34
+ /**
35
+ * Store session context for recovery
36
+ */
37
+ private storeSessionContextForRecovery;
38
+ startSession(): {
39
+ sessionId: string;
40
+ recovered?: boolean;
41
+ };
42
+ endSession(): number;
43
+ destroy(): void;
44
+ private detectDeviceCapabilities;
45
+ private initializeListenerManagers;
46
+ private setupAllListeners;
47
+ private cleanupAllListeners;
48
+ private clearTimers;
49
+ private resetState;
50
+ private readonly handleActivity;
51
+ private readonly handleInactivity;
52
+ private readonly handleVisibilityChange;
53
+ private readonly resetInactivityTimer;
54
+ clearInactivityTimer(): void;
55
+ private shouldProceedWithSessionEnd;
56
+ private waitForCompletion;
57
+ endSessionManaged(reason: SessionEndReason): Promise<SessionEndResult>;
58
+ endSessionSafely(reason: SessionEndReason, options?: {
59
+ forceSync?: boolean;
60
+ allowSync?: boolean;
61
+ }): Promise<SessionEndResult> | SessionEndResult;
62
+ isPendingSessionEnd(): boolean;
63
+ /**
64
+ * Track session health events for monitoring and diagnostics
65
+ */
66
+ trackSessionHealth(event: 'recovery' | 'timeout' | 'conflict'): void;
67
+ private performSessionEnd;
68
+ private cleanupSession;
69
+ private endSessionManagedSync;
70
+ private performSessionEndSync;
71
+ private setupPageUnloadHandlers;
72
+ }