@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
@@ -2,57 +2,48 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KeyboardListenerManager = exports.MouseListenerManager = void 0;
4
4
  const logging_1 = require("../utils/logging");
5
- class MouseListenerManager {
5
+ /**
6
+ * Base class for input listener managers to reduce code duplication
7
+ */
8
+ class BaseInputListenerManager {
6
9
  constructor(onActivity) {
7
10
  this.options = { passive: true };
8
11
  this.onActivity = onActivity;
9
12
  }
10
13
  setup() {
11
14
  try {
12
- window.addEventListener('mousemove', this.onActivity, this.options);
13
- window.addEventListener('mousedown', this.onActivity, this.options);
14
- window.addEventListener('wheel', this.onActivity, this.options);
15
+ this.events.forEach((event) => {
16
+ window.addEventListener(event, this.onActivity, this.options);
17
+ });
15
18
  }
16
19
  catch (error) {
17
- logging_1.debugLog.error('MouseListenerManager', 'Failed to setup mouse listeners', { error });
18
- throw error;
20
+ logging_1.debugLog.error(this.logPrefix, `Failed to setup ${this.logPrefix.toLowerCase()} listeners`, { error });
19
21
  }
20
22
  }
21
23
  cleanup() {
22
24
  try {
23
- window.removeEventListener('mousemove', this.onActivity);
24
- window.removeEventListener('mousedown', this.onActivity);
25
- window.removeEventListener('wheel', this.onActivity);
25
+ this.events.forEach((event) => {
26
+ window.removeEventListener(event, this.onActivity);
27
+ });
26
28
  }
27
29
  catch (error) {
28
- logging_1.debugLog.warn('MouseListenerManager', 'Error during mouse listeners cleanup', { error });
30
+ logging_1.debugLog.warn(this.logPrefix, `Error during ${this.logPrefix.toLowerCase()} listeners cleanup`, { error });
29
31
  }
30
32
  }
31
33
  }
32
- exports.MouseListenerManager = MouseListenerManager;
33
- class KeyboardListenerManager {
34
- constructor(onActivity) {
35
- this.options = { passive: true };
36
- this.onActivity = onActivity;
34
+ class MouseListenerManager extends BaseInputListenerManager {
35
+ constructor() {
36
+ super(...arguments);
37
+ this.events = ['mousemove', 'mousedown', 'wheel'];
38
+ this.logPrefix = 'MouseListenerManager';
37
39
  }
38
- setup() {
39
- try {
40
- window.addEventListener('keydown', this.onActivity, this.options);
41
- window.addEventListener('keypress', this.onActivity, this.options);
42
- }
43
- catch (error) {
44
- logging_1.debugLog.error('KeyboardListenerManager', 'Failed to setup keyboard listeners', { error });
45
- throw error;
46
- }
47
- }
48
- cleanup() {
49
- try {
50
- window.removeEventListener('keydown', this.onActivity);
51
- window.removeEventListener('keypress', this.onActivity);
52
- }
53
- catch (error) {
54
- logging_1.debugLog.warn('KeyboardListenerManager', 'Error during keyboard listeners cleanup', { error });
55
- }
40
+ }
41
+ exports.MouseListenerManager = MouseListenerManager;
42
+ class KeyboardListenerManager extends BaseInputListenerManager {
43
+ constructor() {
44
+ super(...arguments);
45
+ this.events = ['keydown'];
46
+ this.logPrefix = 'KeyboardListenerManager';
56
47
  }
57
48
  }
58
49
  exports.KeyboardListenerManager = KeyboardListenerManager;
@@ -2,9 +2,7 @@ import { EventListenerManager } from './listeners.types';
2
2
  export declare class TouchListenerManager implements EventListenerManager {
3
3
  private readonly onActivity;
4
4
  private readonly options;
5
- private readonly motionThreshold;
6
- constructor(onActivity: () => void, motionThreshold: number);
5
+ constructor(onActivity: () => void);
7
6
  setup(): void;
8
7
  cleanup(): void;
9
- private readonly handleDeviceMotion;
10
8
  }
@@ -3,24 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TouchListenerManager = void 0;
4
4
  const logging_1 = require("../utils/logging");
5
5
  class TouchListenerManager {
6
- constructor(onActivity, motionThreshold) {
6
+ constructor(onActivity) {
7
7
  this.options = { passive: true };
8
- this.handleDeviceMotion = (event) => {
9
- try {
10
- const acceleration = event.acceleration;
11
- if (acceleration) {
12
- const totalAcceleration = Math.abs(acceleration.x ?? 0) + Math.abs(acceleration.y ?? 0) + Math.abs(acceleration.z ?? 0);
13
- if (totalAcceleration > this.motionThreshold) {
14
- this.onActivity();
15
- }
16
- }
17
- }
18
- catch (error) {
19
- logging_1.debugLog.warn('TouchListenerManager', 'Error handling device motion event', { error });
20
- }
21
- };
22
8
  this.onActivity = onActivity;
23
- this.motionThreshold = motionThreshold;
24
9
  }
25
10
  setup() {
26
11
  try {
@@ -28,10 +13,6 @@ class TouchListenerManager {
28
13
  window.addEventListener('touchmove', this.onActivity, this.options);
29
14
  window.addEventListener('touchend', this.onActivity, this.options);
30
15
  window.addEventListener('orientationchange', this.onActivity, this.options);
31
- const hasDeviceMotion = 'DeviceMotionEvent' in window;
32
- if (hasDeviceMotion) {
33
- window.addEventListener('devicemotion', this.handleDeviceMotion, this.options);
34
- }
35
16
  }
36
17
  catch (error) {
37
18
  logging_1.debugLog.error('TouchListenerManager', 'Failed to setup touch listeners', { error });
@@ -44,9 +25,6 @@ class TouchListenerManager {
44
25
  window.removeEventListener('touchmove', this.onActivity);
45
26
  window.removeEventListener('touchend', this.onActivity);
46
27
  window.removeEventListener('orientationchange', this.onActivity);
47
- if ('DeviceMotionEvent' in window) {
48
- window.removeEventListener('devicemotion', this.handleDeviceMotion);
49
- }
50
28
  }
51
29
  catch (error) {
52
30
  logging_1.debugLog.warn('TouchListenerManager', 'Error during touch listeners cleanup', { error });
@@ -2,11 +2,8 @@ import { EventListenerManager } from './listeners.types';
2
2
  export declare class VisibilityListenerManager implements EventListenerManager {
3
3
  private readonly onActivity;
4
4
  private readonly onVisibilityChange;
5
- private readonly isMobile;
6
5
  private readonly options;
7
- constructor(onActivity: () => void, onVisibilityChange: () => void, isMobile: boolean);
6
+ constructor(onActivity: () => void, onVisibilityChange: () => void);
8
7
  setup(): void;
9
8
  cleanup(): void;
10
- private setupMobileEvents;
11
- private cleanupMobileEvents;
12
9
  }
@@ -3,32 +3,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VisibilityListenerManager = void 0;
4
4
  const logging_1 = require("../utils/logging");
5
5
  class VisibilityListenerManager {
6
- constructor(onActivity, onVisibilityChange, isMobile) {
6
+ constructor(onActivity, onVisibilityChange) {
7
7
  this.options = { passive: true };
8
8
  this.onActivity = onActivity;
9
9
  this.onVisibilityChange = onVisibilityChange;
10
- this.isMobile = isMobile;
11
10
  }
12
11
  setup() {
13
12
  try {
14
- const hasVisibilityAPI = 'visibilityState' in document;
15
- if (hasVisibilityAPI) {
13
+ // Core visibility API support
14
+ if ('visibilityState' in document) {
16
15
  document.addEventListener('visibilitychange', this.onVisibilityChange, this.options);
17
16
  }
17
+ // Window focus/blur events
18
18
  window.addEventListener('blur', this.onVisibilityChange, this.options);
19
19
  window.addEventListener('focus', this.onActivity, this.options);
20
- const hasNetworkAPI = 'onLine' in navigator;
21
- if (hasNetworkAPI) {
20
+ // Basic network status detection
21
+ if ('onLine' in navigator) {
22
22
  window.addEventListener('online', this.onActivity, this.options);
23
23
  window.addEventListener('offline', this.onVisibilityChange, this.options);
24
24
  }
25
- if (this.isMobile) {
26
- this.setupMobileEvents();
27
- }
28
25
  }
29
26
  catch (error) {
30
27
  logging_1.debugLog.error('VisibilityListenerManager', 'Failed to setup visibility listeners', { error });
31
- throw error;
32
28
  }
33
29
  }
34
30
  cleanup() {
@@ -42,42 +38,10 @@ class VisibilityListenerManager {
42
38
  window.removeEventListener('online', this.onActivity);
43
39
  window.removeEventListener('offline', this.onVisibilityChange);
44
40
  }
45
- if (this.isMobile) {
46
- this.cleanupMobileEvents();
47
- }
48
41
  }
49
42
  catch (error) {
50
43
  logging_1.debugLog.warn('VisibilityListenerManager', 'Error during visibility listeners cleanup', { error });
51
44
  }
52
45
  }
53
- setupMobileEvents() {
54
- try {
55
- document.addEventListener('pause', this.onVisibilityChange, this.options);
56
- document.addEventListener('resume', this.onActivity, this.options);
57
- const hasOrientationAPI = 'orientation' in screen;
58
- if (hasOrientationAPI) {
59
- screen.orientation.addEventListener('change', this.onActivity, this.options);
60
- }
61
- window.addEventListener('pageshow', this.onActivity, this.options);
62
- window.addEventListener('pagehide', this.onActivity, this.options);
63
- }
64
- catch (error) {
65
- logging_1.debugLog.warn('VisibilityListenerManager', 'Failed to setup mobile listeners', { error });
66
- }
67
- }
68
- cleanupMobileEvents() {
69
- try {
70
- document.removeEventListener('pause', this.onVisibilityChange);
71
- document.removeEventListener('resume', this.onActivity);
72
- if ('orientation' in screen) {
73
- screen.orientation.removeEventListener('change', this.onActivity);
74
- }
75
- window.removeEventListener('pageshow', this.onActivity);
76
- window.removeEventListener('pagehide', this.onActivity);
77
- }
78
- catch (error) {
79
- logging_1.debugLog.warn('VisibilityListenerManager', 'Error during mobile listeners cleanup', { error });
80
- }
81
- }
82
46
  }
83
47
  exports.VisibilityListenerManager = VisibilityListenerManager;
@@ -1,3 +1,13 @@
1
- export declare class ApiManager {
2
- getUrl(id: string, allowHttp?: boolean): string;
3
- }
1
+ /**
2
+ * Generates API URL for TraceLog service based on project ID
3
+ *
4
+ * Handles two special cases:
5
+ * - 'localhost:PORT' - for local development (generates http://localhost:PORT)
6
+ * - Regular project IDs - generates subdomain URLs via getApiUrl utility
7
+ *
8
+ * @param id Project ID or localhost address
9
+ * @param allowHttp Whether to allow HTTP protocol (default: false)
10
+ * @returns Generated API URL
11
+ * @throws Error if URL generation or validation fails
12
+ */
13
+ export declare function getApiUrlForProject(id: string, allowHttp?: boolean): string;
@@ -1,14 +1,44 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ApiManager = void 0;
3
+ exports.getApiUrlForProject = getApiUrlForProject;
4
4
  const utils_1 = require("../utils");
5
- class ApiManager {
6
- getUrl(id, allowHttp = false) {
5
+ const types_1 = require("../types");
6
+ const logging_1 = require("../utils/logging");
7
+ /**
8
+ * Generates API URL for TraceLog service based on project ID
9
+ *
10
+ * Handles two special cases:
11
+ * - 'localhost:PORT' - for local development (generates http://localhost:PORT)
12
+ * - Regular project IDs - generates subdomain URLs via getApiUrl utility
13
+ *
14
+ * @param id Project ID or localhost address
15
+ * @param allowHttp Whether to allow HTTP protocol (default: false)
16
+ * @returns Generated API URL
17
+ * @throws Error if URL generation or validation fails
18
+ */
19
+ function getApiUrlForProject(id, allowHttp = false) {
20
+ try {
21
+ // Handle localhost development case
22
+ if (id.startsWith(types_1.SpecialProjectId.Localhost)) {
23
+ const url = `http://${id}`;
24
+ if (!(0, utils_1.isValidUrl)(url, true)) {
25
+ throw new Error(`Invalid localhost URL format: ${id}`);
26
+ }
27
+ return url;
28
+ }
29
+ // Handle regular project ID case
7
30
  const url = (0, utils_1.getApiUrl)(id, allowHttp);
8
31
  if (!(0, utils_1.isValidUrl)(url, allowHttp)) {
9
- throw new Error('Invalid URL');
32
+ throw new Error(`Generated API URL failed validation: ${url}`);
10
33
  }
11
34
  return url;
12
35
  }
36
+ catch (error) {
37
+ logging_1.debugLog.error('ApiManager', 'API URL generation failed', {
38
+ projectId: id,
39
+ allowHttp,
40
+ error: error instanceof Error ? error.message : error,
41
+ });
42
+ throw error;
43
+ }
13
44
  }
14
- exports.ApiManager = ApiManager;
@@ -1,7 +1,57 @@
1
1
  import { AppConfig, Config } from '../types';
2
+ /**
3
+ * Configuration manager responsible for loading and merging application configuration.
4
+ *
5
+ * Handles three configuration sources:
6
+ * 1. Default configuration (fallback values)
7
+ * 2. API configuration (server-side settings)
8
+ * 3. App configuration (client initialization settings)
9
+ *
10
+ * Supports special project IDs for development and testing:
11
+ * - 'skip': Bypasses all network calls, uses defaults
12
+ * - 'localhost:PORT': Loads config from local development server
13
+ */
2
14
  export declare class ConfigManager {
15
+ private static readonly LOCALHOST_PATTERN;
16
+ private static readonly PRODUCTION_DOMAINS;
17
+ /**
18
+ * Gets complete configuration by merging default, API, and app configurations.
19
+ *
20
+ * @param apiUrl - Base URL for the configuration API
21
+ * @param appConfig - Client-side configuration from init()
22
+ * @returns Promise<Config> - Merged configuration object
23
+ */
3
24
  get(apiUrl: string, appConfig: AppConfig): Promise<Config>;
4
- private load;
5
- private getUrl;
6
- private getDefaultConfig;
25
+ /**
26
+ * Loads configuration from API and merges with app config.
27
+ */
28
+ private loadFromApi;
29
+ /**
30
+ * Builds the configuration URL based on project type and QA mode.
31
+ */
32
+ private buildConfigUrl;
33
+ /**
34
+ * Builds request headers based on project configuration.
35
+ */
36
+ private buildHeaders;
37
+ /**
38
+ * Parses and validates JSON response from config API.
39
+ */
40
+ private parseJsonResponse;
41
+ /**
42
+ * Validates localhost project ID format and port range.
43
+ */
44
+ private validateLocalhostProjectId;
45
+ /**
46
+ * Checks if QA mode is enabled via URL parameter.
47
+ */
48
+ private isQaModeEnabled;
49
+ /**
50
+ * Merges API configuration with app configuration and applies mode-specific settings.
51
+ */
52
+ private mergeConfigurations;
53
+ /**
54
+ * Creates default configuration for skip mode and fallback scenarios.
55
+ */
56
+ private createDefaultConfig;
7
57
  }
@@ -5,90 +5,159 @@ const constants_1 = require("../constants");
5
5
  const types_1 = require("../types");
6
6
  const utils_1 = require("../utils");
7
7
  const logging_1 = require("../utils/logging");
8
+ /**
9
+ * Configuration manager responsible for loading and merging application configuration.
10
+ *
11
+ * Handles three configuration sources:
12
+ * 1. Default configuration (fallback values)
13
+ * 2. API configuration (server-side settings)
14
+ * 3. App configuration (client initialization settings)
15
+ *
16
+ * Supports special project IDs for development and testing:
17
+ * - 'skip': Bypasses all network calls, uses defaults
18
+ * - 'localhost:PORT': Loads config from local development server
19
+ */
8
20
  class ConfigManager {
21
+ /**
22
+ * Gets complete configuration by merging default, API, and app configurations.
23
+ *
24
+ * @param apiUrl - Base URL for the configuration API
25
+ * @param appConfig - Client-side configuration from init()
26
+ * @returns Promise<Config> - Merged configuration object
27
+ */
9
28
  async get(apiUrl, appConfig) {
10
- if (appConfig.id === types_1.SpecialProjectId.HttpSkip) {
11
- logging_1.debugLog.debug('ConfigManager', 'Using special project id');
12
- return this.getDefaultConfig(appConfig);
29
+ // Handle skip mode - no network calls
30
+ if (appConfig.id === types_1.SpecialProjectId.Skip) {
31
+ return this.createDefaultConfig(appConfig);
13
32
  }
14
- logging_1.debugLog.debug('ConfigManager', 'Loading config from API', { apiUrl, projectId: appConfig.id });
15
- const config = await this.load(apiUrl, appConfig, appConfig.id === types_1.SpecialProjectId.HttpLocal);
16
- logging_1.debugLog.info('ConfigManager', 'Config loaded successfully', {
33
+ const config = await this.loadFromApi(apiUrl, appConfig);
34
+ const { config: normalizedConfig } = (0, utils_1.normalizeConfig)(config);
35
+ logging_1.debugLog.info('ConfigManager', 'Configuration loaded', {
17
36
  projectId: appConfig.id,
18
- mode: config.mode,
19
- hasExcludedPaths: !!config.excludedUrlPaths?.length,
20
- hasGlobalMetadata: !!config.globalMetadata,
37
+ mode: normalizedConfig.mode,
38
+ hasTags: !!normalizedConfig.tags?.length,
39
+ hasExclusions: !!normalizedConfig.excludedUrlPaths?.length,
21
40
  });
22
- return config;
41
+ return normalizedConfig;
23
42
  }
24
- async load(apiUrl, appConfig, useLocalServer) {
43
+ /**
44
+ * Loads configuration from API and merges with app config.
45
+ */
46
+ async loadFromApi(apiUrl, appConfig) {
25
47
  try {
26
- const configUrl = useLocalServer ? `${window.location.origin}/config` : this.getUrl(apiUrl);
27
- if (!configUrl) {
28
- throw new Error('Config URL is not valid or not allowed');
29
- }
30
- const response = await fetch(configUrl, {
48
+ const configUrl = this.buildConfigUrl(apiUrl, appConfig);
49
+ const headers = this.buildHeaders(appConfig);
50
+ const response = await (0, utils_1.fetchWithTimeout)(configUrl, {
31
51
  method: 'GET',
32
- headers: { 'Content-Type': 'application/json' },
52
+ headers,
53
+ timeout: constants_1.REQUEST_TIMEOUT_MS,
33
54
  });
34
55
  if (!response.ok) {
35
- const error = `HTTP ${response.status}: ${response.statusText}`;
36
- logging_1.debugLog.error('ConfigManager', 'Config API request failed', {
37
- status: response.status,
38
- statusText: response.statusText,
39
- configUrl,
40
- });
41
- throw new Error(error);
42
- }
43
- const rawData = await response.json();
44
- if (rawData === undefined || rawData === null || typeof rawData !== 'object' || Array.isArray(rawData)) {
45
- logging_1.debugLog.error('ConfigManager', 'Invalid config API response format', {
46
- responseType: typeof rawData,
47
- isArray: Array.isArray(rawData),
48
- });
49
- throw new Error('Invalid config API response: expected object');
50
- }
51
- const safeApiConfig = (0, utils_1.sanitizeApiConfig)(rawData);
52
- const apiConfig = { ...constants_1.DEFAULT_API_CONFIG, ...safeApiConfig };
53
- const mergedConfig = { ...apiConfig, ...appConfig };
54
- // Check if qaMode=true is in URL and automatically set mode to 'qa'
55
- const urlParameters = new URLSearchParams(window.location.search);
56
- const isQaMode = urlParameters.get('qaMode') === 'true';
57
- if (isQaMode && !mergedConfig.mode) {
58
- mergedConfig.mode = types_1.Mode.QA;
59
- logging_1.debugLog.info('ConfigManager', 'QA mode enabled via URL parameter');
56
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
60
57
  }
61
- const errorSampling = Object.values(types_1.Mode).includes(mergedConfig.mode)
62
- ? 1
63
- : (mergedConfig.errorSampling ?? 0.1);
64
- const finalConfig = { ...mergedConfig, errorSampling };
65
- return finalConfig;
58
+ const rawData = await this.parseJsonResponse(response);
59
+ return this.mergeConfigurations(rawData, appConfig);
66
60
  }
67
61
  catch (error) {
68
62
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
69
- logging_1.debugLog.error('ConfigManager', 'Failed to load config', { error: errorMessage, apiUrl });
70
- throw new Error(`Failed to load config: ${errorMessage}`);
63
+ logging_1.debugLog.error('ConfigManager', 'Failed to load configuration', {
64
+ error: errorMessage,
65
+ apiUrl,
66
+ projectId: appConfig.id,
67
+ });
68
+ throw new Error(`Configuration load failed: ${errorMessage}`);
69
+ }
70
+ }
71
+ /**
72
+ * Builds the configuration URL based on project type and QA mode.
73
+ */
74
+ buildConfigUrl(apiUrl, appConfig) {
75
+ const isLocalhost = appConfig.id.startsWith(types_1.SpecialProjectId.Localhost);
76
+ if (isLocalhost) {
77
+ this.validateLocalhostProjectId(appConfig.id);
78
+ return `http://${appConfig.id}/config`;
79
+ }
80
+ const baseUrl = `${apiUrl}/config`;
81
+ const isQaMode = this.isQaModeEnabled();
82
+ return isQaMode ? `${baseUrl}?qaMode=true` : baseUrl;
83
+ }
84
+ /**
85
+ * Builds request headers based on project configuration.
86
+ */
87
+ buildHeaders(appConfig) {
88
+ const headers = {
89
+ 'Content-Type': 'application/json',
90
+ };
91
+ if (appConfig.id.startsWith(types_1.SpecialProjectId.Localhost)) {
92
+ headers['X-TraceLog-Project'] = appConfig.id;
93
+ }
94
+ return headers;
95
+ }
96
+ /**
97
+ * Parses and validates JSON response from config API.
98
+ */
99
+ async parseJsonResponse(response) {
100
+ const contentType = response.headers.get('content-type');
101
+ if (!contentType?.includes('application/json')) {
102
+ throw new Error('Invalid response content-type, expected JSON');
103
+ }
104
+ const rawData = await response.json();
105
+ if (!rawData || typeof rawData !== 'object' || Array.isArray(rawData)) {
106
+ throw new Error('Invalid response format, expected object');
71
107
  }
108
+ return rawData;
72
109
  }
73
- getUrl(apiUrl) {
74
- const urlParameters = new URLSearchParams(window.location.search);
75
- const isQaMode = urlParameters.get('qaMode') === 'true';
76
- let configUrl = `${apiUrl}/config`;
77
- if (isQaMode) {
78
- configUrl += '?qaMode=true';
110
+ /**
111
+ * Validates localhost project ID format and port range.
112
+ */
113
+ validateLocalhostProjectId(projectId) {
114
+ if (!ConfigManager.LOCALHOST_PATTERN.test(projectId)) {
115
+ throw new Error(`Invalid localhost format. Expected 'localhost:PORT', got '${projectId}'`);
79
116
  }
80
- if (!(0, utils_1.isValidUrl)(configUrl)) {
81
- logging_1.debugLog.clientError('ConfigManager', 'Invalid config URL provided', { configUrl });
82
- throw new Error('Config URL is not valid or not allowed');
117
+ const port = parseInt(projectId.split(':')[1], 10);
118
+ if (port < 1 || port > 65535) {
119
+ throw new Error(`Port must be between 1 and 65535, got ${port}`);
83
120
  }
84
- return configUrl;
85
121
  }
86
- getDefaultConfig(appConfig) {
87
- return (0, constants_1.DEFAULT_CONFIG)({
122
+ /**
123
+ * Checks if QA mode is enabled via URL parameter.
124
+ */
125
+ isQaModeEnabled() {
126
+ const params = new URLSearchParams(window.location.search);
127
+ return params.get('qaMode') === 'true';
128
+ }
129
+ /**
130
+ * Merges API configuration with app configuration and applies mode-specific settings.
131
+ */
132
+ mergeConfigurations(rawApiConfig, appConfig) {
133
+ const safeApiConfig = (0, utils_1.sanitizeApiConfig)(rawApiConfig);
134
+ const apiConfig = { ...constants_1.DEFAULT_API_CONFIG, ...safeApiConfig };
135
+ const mergedConfig = (0, constants_1.DEFAULT_CONFIG)({ ...appConfig, ...apiConfig });
136
+ const { config: normalizedConfig } = (0, utils_1.normalizeConfig)(mergedConfig);
137
+ // Apply QA mode if enabled via URL parameter
138
+ if (this.isQaModeEnabled() && !normalizedConfig.mode) {
139
+ normalizedConfig.mode = types_1.Mode.QA;
140
+ logging_1.debugLog.info('ConfigManager', 'QA mode enabled via URL parameter');
141
+ }
142
+ // Set error sampling based on mode
143
+ const errorSampling = Object.values(types_1.Mode).includes(normalizedConfig.mode)
144
+ ? 1 // Full sampling for debug/qa modes
145
+ : (normalizedConfig.errorSampling ?? 0.1); // Default sampling for production
146
+ return { ...normalizedConfig, errorSampling };
147
+ }
148
+ /**
149
+ * Creates default configuration for skip mode and fallback scenarios.
150
+ */
151
+ createDefaultConfig(appConfig) {
152
+ const defaultConfig = (0, constants_1.DEFAULT_CONFIG)({
88
153
  ...appConfig,
89
154
  errorSampling: 1,
90
- ...(Object.values(types_1.SpecialProjectId).includes(appConfig.id) && { mode: types_1.Mode.DEBUG }),
155
+ ...(appConfig.id === types_1.SpecialProjectId.Skip && { mode: types_1.Mode.DEBUG }),
91
156
  });
157
+ const { config } = (0, utils_1.normalizeConfig)(defaultConfig);
158
+ return config;
92
159
  }
93
160
  }
94
161
  exports.ConfigManager = ConfigManager;
162
+ ConfigManager.LOCALHOST_PATTERN = /^localhost:\d{1,5}$/;
163
+ ConfigManager.PRODUCTION_DOMAINS = [/^https:\/\/.*\.tracelog\.app$/, /^https:\/\/.*\.tracelog\.dev$/];