@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,42 @@
1
+ import { AppConfig, Config, ApiConfig } from '../../types';
2
+ /**
3
+ * Validates the app configuration object (before normalization)
4
+ * This validates the structure and basic types but allows for normalization afterward
5
+ * @param config - The app configuration to validate
6
+ * @throws {ProjectIdValidationError} If project ID validation fails
7
+ * @throws {AppConfigValidationError} If other configuration validation fails
8
+ */
9
+ export declare const validateAppConfig: (config: AppConfig) => void;
10
+ /**
11
+ * Validates and normalizes the app configuration
12
+ * This is the primary validation entry point that ensures consistent behavior
13
+ * @param config - The app configuration to validate and normalize
14
+ * @returns The normalized configuration
15
+ * @throws {ProjectIdValidationError} If project ID validation fails after normalization
16
+ * @throws {AppConfigValidationError} If other configuration validation fails
17
+ */
18
+ export declare const validateAndNormalizeConfig: (config: AppConfig) => AppConfig;
19
+ /**
20
+ * Validates a complete configuration object
21
+ * @param config - The configuration to validate
22
+ * @returns Validation result with errors and warnings
23
+ */
24
+ export declare const validateConfig: (config: Config) => {
25
+ errors: string[];
26
+ warnings: string[];
27
+ };
28
+ /**
29
+ * Validates the final configuration
30
+ * @param config - The configuration to validate
31
+ * @returns Validation result with errors and warnings
32
+ */
33
+ export declare const validateFinalConfig: (config: Config) => {
34
+ errors: string[];
35
+ warnings: string[];
36
+ };
37
+ /**
38
+ * Type guard to check if a JSON response is a valid API config
39
+ * @param json - The JSON to validate
40
+ * @returns True if the JSON is a valid API config
41
+ */
42
+ export declare const isValidConfigApiResponse: (json: unknown) => json is ApiConfig;
@@ -0,0 +1,289 @@
1
+ import { MAX_SESSION_TIMEOUT_MS, MIN_SESSION_TIMEOUT_MS, VALIDATION_MESSAGES } from '../../constants';
2
+ import { Mode } from '../../types';
3
+ import { ProjectIdValidationError, AppConfigValidationError, SessionTimeoutValidationError, SamplingRateValidationError, IntegrationValidationError, } from '../../types/validation-error.types';
4
+ import { debugLog } from '../logging';
5
+ /**
6
+ * Validates the app configuration object (before normalization)
7
+ * This validates the structure and basic types but allows for normalization afterward
8
+ * @param config - The app configuration to validate
9
+ * @throws {ProjectIdValidationError} If project ID validation fails
10
+ * @throws {AppConfigValidationError} If other configuration validation fails
11
+ */
12
+ export const validateAppConfig = (config) => {
13
+ // Validate config exists and has id property
14
+ if (!config || typeof config !== 'object') {
15
+ debugLog.clientError('ConfigValidation', 'Configuration must be an object', { config });
16
+ throw new AppConfigValidationError('Configuration must be an object', 'config');
17
+ }
18
+ // Check if id property exists (allow falsy values to be handled by normalization)
19
+ if (!('id' in config)) {
20
+ debugLog.clientError('ConfigValidation', 'Project ID is missing from configuration');
21
+ throw new ProjectIdValidationError(VALIDATION_MESSAGES.MISSING_PROJECT_ID, 'config');
22
+ }
23
+ // Check basic type - null, undefined, or non-string values should fail here
24
+ if (config.id === null || config.id === undefined || typeof config.id !== 'string') {
25
+ debugLog.clientError('ConfigValidation', 'Project ID must be a non-empty string', {
26
+ providedId: config.id,
27
+ type: typeof config.id,
28
+ });
29
+ throw new ProjectIdValidationError(VALIDATION_MESSAGES.MISSING_PROJECT_ID, 'config');
30
+ }
31
+ if (config.sessionTimeout !== undefined) {
32
+ if (typeof config.sessionTimeout !== 'number' ||
33
+ config.sessionTimeout < MIN_SESSION_TIMEOUT_MS ||
34
+ config.sessionTimeout > MAX_SESSION_TIMEOUT_MS) {
35
+ debugLog.clientError('ConfigValidation', 'Invalid session timeout', {
36
+ provided: config.sessionTimeout,
37
+ min: MIN_SESSION_TIMEOUT_MS,
38
+ max: MAX_SESSION_TIMEOUT_MS,
39
+ });
40
+ throw new SessionTimeoutValidationError(VALIDATION_MESSAGES.INVALID_SESSION_TIMEOUT, 'config');
41
+ }
42
+ }
43
+ if (config.globalMetadata !== undefined) {
44
+ if (typeof config.globalMetadata !== 'object' || config.globalMetadata === null) {
45
+ debugLog.clientError('ConfigValidation', 'Global metadata must be an object', {
46
+ provided: config.globalMetadata,
47
+ type: typeof config.globalMetadata,
48
+ });
49
+ throw new AppConfigValidationError(VALIDATION_MESSAGES.INVALID_GLOBAL_METADATA, 'config');
50
+ }
51
+ }
52
+ if (config.scrollContainerSelectors !== undefined) {
53
+ validateScrollContainerSelectors(config.scrollContainerSelectors);
54
+ }
55
+ if (config.integrations) {
56
+ validateIntegrations(config.integrations);
57
+ }
58
+ if (config.sensitiveQueryParams !== undefined) {
59
+ if (!Array.isArray(config.sensitiveQueryParams)) {
60
+ debugLog.clientError('ConfigValidation', 'Sensitive query params must be an array', {
61
+ provided: config.sensitiveQueryParams,
62
+ type: typeof config.sensitiveQueryParams,
63
+ });
64
+ throw new AppConfigValidationError(VALIDATION_MESSAGES.INVALID_SENSITIVE_QUERY_PARAMS, 'config');
65
+ }
66
+ for (const param of config.sensitiveQueryParams) {
67
+ if (typeof param !== 'string') {
68
+ debugLog.clientError('ConfigValidation', 'All sensitive query params must be strings', {
69
+ param,
70
+ type: typeof param,
71
+ });
72
+ throw new AppConfigValidationError('All sensitive query params must be strings', 'config');
73
+ }
74
+ }
75
+ }
76
+ if (config.errorSampling !== undefined) {
77
+ if (typeof config.errorSampling !== 'number' || config.errorSampling < 0 || config.errorSampling > 1) {
78
+ debugLog.clientError('ConfigValidation', 'Invalid error sampling rate', {
79
+ provided: config.errorSampling,
80
+ expected: '0-1',
81
+ });
82
+ throw new SamplingRateValidationError(VALIDATION_MESSAGES.INVALID_ERROR_SAMPLING_RATE, 'config');
83
+ }
84
+ }
85
+ };
86
+ /**
87
+ * Validates scroll container selectors
88
+ * @param selectors - CSS selectors to validate
89
+ */
90
+ const validateScrollContainerSelectors = (selectors) => {
91
+ const selectorsArray = Array.isArray(selectors) ? selectors : [selectors];
92
+ for (const selector of selectorsArray) {
93
+ if (typeof selector !== 'string' || selector.trim() === '') {
94
+ debugLog.clientError('ConfigValidation', 'Invalid scroll container selector', {
95
+ selector,
96
+ type: typeof selector,
97
+ isEmpty: selector === '' || (typeof selector === 'string' && selector.trim() === ''),
98
+ });
99
+ throw new AppConfigValidationError(VALIDATION_MESSAGES.INVALID_SCROLL_CONTAINER_SELECTORS, 'config');
100
+ }
101
+ // Validate CSS selector syntax but handle invalid selectors gracefully
102
+ if (typeof document !== 'undefined') {
103
+ try {
104
+ document.querySelector(selector);
105
+ }
106
+ catch {
107
+ // Invalid CSS selectors are handled gracefully
108
+ // they will be ignored by the ScrollHandler and it will fall back to window scrolling
109
+ debugLog.clientWarn('ConfigValidation', `Invalid CSS selector will be ignored: "${selector}"`);
110
+ }
111
+ }
112
+ }
113
+ };
114
+ /**
115
+ * Validates integrations configuration
116
+ * @param integrations - Integrations configuration to validate
117
+ */
118
+ const validateIntegrations = (integrations) => {
119
+ if (!integrations)
120
+ return;
121
+ if (integrations.googleAnalytics) {
122
+ if (!integrations.googleAnalytics.measurementId ||
123
+ typeof integrations.googleAnalytics.measurementId !== 'string' ||
124
+ integrations.googleAnalytics.measurementId.trim() === '') {
125
+ debugLog.clientError('ConfigValidation', 'Invalid Google Analytics measurement ID', {
126
+ provided: integrations.googleAnalytics.measurementId,
127
+ type: typeof integrations.googleAnalytics.measurementId,
128
+ });
129
+ throw new IntegrationValidationError(VALIDATION_MESSAGES.INVALID_GOOGLE_ANALYTICS_ID, 'config');
130
+ }
131
+ const measurementId = integrations.googleAnalytics.measurementId.trim();
132
+ if (!measurementId.match(/^(G-|UA-)/)) {
133
+ debugLog.clientError('ConfigValidation', 'Google Analytics measurement ID must start with "G-" or "UA-"', {
134
+ provided: measurementId,
135
+ });
136
+ throw new IntegrationValidationError('Google Analytics measurement ID must start with "G-" or "UA-"', 'config');
137
+ }
138
+ }
139
+ };
140
+ /**
141
+ * Validates and normalizes the app configuration
142
+ * This is the primary validation entry point that ensures consistent behavior
143
+ * @param config - The app configuration to validate and normalize
144
+ * @returns The normalized configuration
145
+ * @throws {ProjectIdValidationError} If project ID validation fails after normalization
146
+ * @throws {AppConfigValidationError} If other configuration validation fails
147
+ */
148
+ export const validateAndNormalizeConfig = (config) => {
149
+ // First validate the structure and basic types
150
+ validateAppConfig(config);
151
+ // Normalize string values
152
+ const normalizedConfig = {
153
+ ...config,
154
+ id: config.id.trim(),
155
+ globalMetadata: config.globalMetadata ?? {},
156
+ sensitiveQueryParams: config.sensitiveQueryParams ?? [],
157
+ };
158
+ // Validate normalized values - this catches whitespace-only IDs
159
+ if (!normalizedConfig.id) {
160
+ debugLog.clientError('ConfigValidation', 'Project ID is empty after trimming whitespace', {
161
+ originalId: config.id,
162
+ normalizedId: normalizedConfig.id,
163
+ });
164
+ throw new ProjectIdValidationError(VALIDATION_MESSAGES.PROJECT_ID_EMPTY_AFTER_TRIM, 'config');
165
+ }
166
+ return normalizedConfig;
167
+ };
168
+ /**
169
+ * Validates sampling rate
170
+ * @param samplingRate - The sampling rate to validate
171
+ * @param errors - Array to push errors to
172
+ */
173
+ const validateSamplingRate = (samplingRate, errors) => {
174
+ if (samplingRate !== undefined) {
175
+ if (typeof samplingRate !== 'number') {
176
+ errors.push('samplingRate must be a number');
177
+ }
178
+ else if (samplingRate < 0 || samplingRate > 1) {
179
+ errors.push('samplingRate must be between 0 and 1');
180
+ }
181
+ }
182
+ };
183
+ /**
184
+ * Validates excluded URL paths
185
+ * @param excludedUrlPaths - The excluded URL paths to validate
186
+ * @param errors - Array to push errors to
187
+ * @param prefix - Optional prefix for error messages
188
+ */
189
+ const validateExcludedUrlPaths = (excludedUrlPaths, errors, prefix = '') => {
190
+ if (excludedUrlPaths !== undefined) {
191
+ if (Array.isArray(excludedUrlPaths)) {
192
+ for (const [index, path] of excludedUrlPaths.entries()) {
193
+ if (typeof path === 'string') {
194
+ try {
195
+ new RegExp(path);
196
+ }
197
+ catch {
198
+ errors.push(`${prefix}excludedUrlPaths[${index}] is not a valid regex pattern`);
199
+ }
200
+ }
201
+ else {
202
+ errors.push(`${prefix}excludedUrlPaths[${index}] must be a string`);
203
+ }
204
+ }
205
+ }
206
+ else {
207
+ errors.push(`${prefix}excludedUrlPaths must be an array`);
208
+ }
209
+ }
210
+ };
211
+ /**
212
+ * Validates a complete configuration object
213
+ * @param config - The configuration to validate
214
+ * @returns Validation result with errors and warnings
215
+ */
216
+ export const validateConfig = (config) => {
217
+ const errors = [];
218
+ const warnings = [];
219
+ if (config.sessionTimeout !== undefined) {
220
+ if (typeof config.sessionTimeout !== 'number') {
221
+ errors.push('sessionTimeout must be a number');
222
+ }
223
+ else if (config.sessionTimeout < MIN_SESSION_TIMEOUT_MS) {
224
+ errors.push('sessionTimeout must be at least 30 seconds (30000ms)');
225
+ }
226
+ else if (config.sessionTimeout > MAX_SESSION_TIMEOUT_MS) {
227
+ warnings.push('sessionTimeout is very long (>24 hours), consider reducing it');
228
+ }
229
+ }
230
+ if (config.globalMetadata !== undefined) {
231
+ if (typeof config.globalMetadata !== 'object' || config.globalMetadata === null) {
232
+ errors.push('globalMetadata must be an object');
233
+ }
234
+ else {
235
+ const metadataSize = JSON.stringify(config.globalMetadata).length;
236
+ if (metadataSize > 10240) {
237
+ errors.push('globalMetadata is too large (max 10KB)');
238
+ }
239
+ if (Object.keys(config.globalMetadata).length > 12) {
240
+ errors.push('globalMetadata has too many keys (max 12)');
241
+ }
242
+ }
243
+ }
244
+ // No custom API endpoints supported
245
+ validateSamplingRate(config.samplingRate, errors);
246
+ if (config.tags !== undefined && !Array.isArray(config.tags)) {
247
+ errors.push('tags must be an array');
248
+ }
249
+ validateExcludedUrlPaths(config.excludedUrlPaths, errors);
250
+ return { errors, warnings };
251
+ };
252
+ /**
253
+ * Validates the final configuration
254
+ * @param config - The configuration to validate
255
+ * @returns Validation result with errors and warnings
256
+ */
257
+ export const validateFinalConfig = (config) => {
258
+ const errors = [];
259
+ const warnings = [];
260
+ validateSamplingRate(config.samplingRate, errors);
261
+ validateExcludedUrlPaths(config.excludedUrlPaths, errors);
262
+ // No custom API endpoints supported
263
+ return { errors, warnings };
264
+ };
265
+ /**
266
+ * Type guard to check if a JSON response is a valid API config
267
+ * @param json - The JSON to validate
268
+ * @returns True if the JSON is a valid API config
269
+ */
270
+ export const isValidConfigApiResponse = (json) => {
271
+ try {
272
+ if (typeof json !== 'object' || !json) {
273
+ return false;
274
+ }
275
+ const response = json;
276
+ const result = {
277
+ mode: response['mode'] === undefined || [Mode.QA, Mode.DEBUG].includes(response['mode']),
278
+ samplingRate: response['samplingRate'] === undefined ||
279
+ (typeof response['samplingRate'] === 'number' && response['samplingRate'] > 0 && response['samplingRate'] <= 1),
280
+ tags: response['tags'] === undefined || Array.isArray(response['tags']),
281
+ excludedUrlPaths: response['excludedUrlPaths'] === undefined || Array.isArray(response['excludedUrlPaths']),
282
+ ipExcluded: response['ipExcluded'] === undefined || typeof response['ipExcluded'] === 'boolean',
283
+ };
284
+ return Object.values(result).every(Boolean);
285
+ }
286
+ catch {
287
+ return false;
288
+ }
289
+ };
@@ -0,0 +1,12 @@
1
+ import { MetadataType } from '../../types';
2
+ /**
3
+ * Validates a complete event with name and optional metadata
4
+ * @param eventName - The event name to validate
5
+ * @param metadata - Optional metadata to validate
6
+ * @returns Validation result with sanitized metadata if valid
7
+ */
8
+ export declare const isEventValid: (eventName: string, metadata?: Record<string, unknown>) => {
9
+ valid: boolean;
10
+ error?: string;
11
+ sanitizedMetadata?: Record<string, MetadataType>;
12
+ };
@@ -0,0 +1,26 @@
1
+ import { isValidEventName, isValidMetadata } from './metadata-validations.utils';
2
+ import { debugLog } from '../logging';
3
+ /**
4
+ * Validates a complete event with name and optional metadata
5
+ * @param eventName - The event name to validate
6
+ * @param metadata - Optional metadata to validate
7
+ * @returns Validation result with sanitized metadata if valid
8
+ */
9
+ export const isEventValid = (eventName, metadata) => {
10
+ const nameValidation = isValidEventName(eventName);
11
+ if (!nameValidation.valid) {
12
+ debugLog.clientError('EventValidation', 'Event name validation failed', { eventName, error: nameValidation.error });
13
+ return nameValidation;
14
+ }
15
+ if (!metadata) {
16
+ return { valid: true };
17
+ }
18
+ const metadataValidation = isValidMetadata(eventName, metadata, 'customEvent');
19
+ if (!metadataValidation.valid) {
20
+ debugLog.clientError('EventValidation', 'Event metadata validation failed', {
21
+ eventName,
22
+ error: metadataValidation.error,
23
+ });
24
+ }
25
+ return metadataValidation;
26
+ };
@@ -0,0 +1,5 @@
1
+ export * from './config-validations.utils';
2
+ export * from './event-validations.utils';
3
+ export * from './metadata-validations.utils';
4
+ export * from './type-guards.utils';
5
+ export * from './url-validations.utils';
@@ -0,0 +1,5 @@
1
+ export * from './config-validations.utils';
2
+ export * from './event-validations.utils';
3
+ export * from './metadata-validations.utils';
4
+ export * from './type-guards.utils';
5
+ export * from './url-validations.utils';
@@ -0,0 +1,22 @@
1
+ import { MetadataType } from '../../types';
2
+ /**
3
+ * Validates an event name
4
+ * @param eventName - The event name to validate
5
+ * @returns Validation result with error message if invalid
6
+ */
7
+ export declare const isValidEventName: (eventName: string) => {
8
+ valid: boolean;
9
+ error?: string;
10
+ };
11
+ /**
12
+ * Validates metadata for events
13
+ * @param eventName - The event name (for error messages)
14
+ * @param metadata - The metadata to validate
15
+ * @param type - Type of metadata (globalMetadata or customEvent)
16
+ * @returns Validation result with sanitized metadata if valid
17
+ */
18
+ export declare const isValidMetadata: (eventName: string, metadata: Record<string, unknown>, type?: "globalMetadata" | "customEvent") => {
19
+ valid: boolean;
20
+ error?: string;
21
+ sanitizedMetadata?: Record<string, MetadataType>;
22
+ };
@@ -0,0 +1,110 @@
1
+ import { MAX_CUSTOM_EVENT_ARRAY_SIZE, MAX_CUSTOM_EVENT_KEYS, MAX_CUSTOM_EVENT_NAME_LENGTH, MAX_CUSTOM_EVENT_STRING_SIZE, MAX_STRING_LENGTH, } from '../../constants';
2
+ import { sanitizeMetadata } from '../security/sanitize.utils';
3
+ import { isOnlyPrimitiveFields } from './type-guards.utils';
4
+ /**
5
+ * Validates an event name
6
+ * @param eventName - The event name to validate
7
+ * @returns Validation result with error message if invalid
8
+ */
9
+ export const isValidEventName = (eventName) => {
10
+ if (typeof eventName !== 'string') {
11
+ return {
12
+ valid: false,
13
+ error: 'Event name must be a string',
14
+ };
15
+ }
16
+ if (eventName.length === 0) {
17
+ return {
18
+ valid: false,
19
+ error: 'Event name cannot be empty',
20
+ };
21
+ }
22
+ if (eventName.length > MAX_CUSTOM_EVENT_NAME_LENGTH) {
23
+ return {
24
+ valid: false,
25
+ error: `Event name is too long (max ${MAX_CUSTOM_EVENT_NAME_LENGTH} characters)`,
26
+ };
27
+ }
28
+ if (eventName.includes('<') || eventName.includes('>') || eventName.includes('&')) {
29
+ return {
30
+ valid: false,
31
+ error: 'Event name contains invalid characters',
32
+ };
33
+ }
34
+ const reservedWords = ['constructor', 'prototype', '__proto__', 'eval', 'function', 'var', 'let', 'const'];
35
+ if (reservedWords.includes(eventName.toLowerCase())) {
36
+ return {
37
+ valid: false,
38
+ error: 'Event name cannot be a reserved word',
39
+ };
40
+ }
41
+ return { valid: true };
42
+ };
43
+ /**
44
+ * Validates metadata for events
45
+ * @param eventName - The event name (for error messages)
46
+ * @param metadata - The metadata to validate
47
+ * @param type - Type of metadata (globalMetadata or customEvent)
48
+ * @returns Validation result with sanitized metadata if valid
49
+ */
50
+ export const isValidMetadata = (eventName, metadata, type) => {
51
+ const sanitizedMetadata = sanitizeMetadata(metadata);
52
+ const intro = type && type === 'customEvent' ? `${type} "${eventName}" metadata error` : `${eventName} metadata error`;
53
+ if (!isOnlyPrimitiveFields(sanitizedMetadata)) {
54
+ return {
55
+ valid: false,
56
+ error: `${intro}: object has invalid types. Valid types are string, number, boolean or string arrays.`,
57
+ };
58
+ }
59
+ let jsonString;
60
+ try {
61
+ jsonString = JSON.stringify(sanitizedMetadata);
62
+ }
63
+ catch {
64
+ return {
65
+ valid: false,
66
+ error: `${intro}: object contains circular references or cannot be serialized.`,
67
+ };
68
+ }
69
+ if (jsonString.length > MAX_CUSTOM_EVENT_STRING_SIZE) {
70
+ return {
71
+ valid: false,
72
+ error: `${intro}: object is too large (max ${MAX_CUSTOM_EVENT_STRING_SIZE / 1024} KB).`,
73
+ };
74
+ }
75
+ const keyCount = Object.keys(sanitizedMetadata).length;
76
+ if (keyCount > MAX_CUSTOM_EVENT_KEYS) {
77
+ return {
78
+ valid: false,
79
+ error: `${intro}: object has too many keys (max ${MAX_CUSTOM_EVENT_KEYS} keys).`,
80
+ };
81
+ }
82
+ for (const [key, value] of Object.entries(sanitizedMetadata)) {
83
+ if (Array.isArray(value)) {
84
+ if (value.length > MAX_CUSTOM_EVENT_ARRAY_SIZE) {
85
+ return {
86
+ valid: false,
87
+ error: `${intro}: array property "${key}" is too large (max ${MAX_CUSTOM_EVENT_ARRAY_SIZE} items).`,
88
+ };
89
+ }
90
+ for (const item of value) {
91
+ if (typeof item === 'string' && item.length > 500) {
92
+ return {
93
+ valid: false,
94
+ error: `${intro}: array property "${key}" contains strings that are too long (max 500 characters).`,
95
+ };
96
+ }
97
+ }
98
+ }
99
+ if (typeof value === 'string' && value.length > MAX_STRING_LENGTH) {
100
+ return {
101
+ valid: false,
102
+ error: `${intro}: property "${key}" is too long (max ${MAX_STRING_LENGTH} characters).`,
103
+ };
104
+ }
105
+ }
106
+ return {
107
+ valid: true,
108
+ sanitizedMetadata,
109
+ };
110
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Checks if an object contains only primitive fields (string, number, boolean, or string arrays)
3
+ * @param object - The object to check
4
+ * @returns True if the object contains only primitive fields
5
+ */
6
+ export declare const isOnlyPrimitiveFields: (object: Record<string, unknown>) => boolean;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Checks if an object contains only primitive fields (string, number, boolean, or string arrays)
3
+ * @param object - The object to check
4
+ * @returns True if the object contains only primitive fields
5
+ */
6
+ export const isOnlyPrimitiveFields = (object) => {
7
+ if (typeof object !== 'object' || object === null) {
8
+ return false;
9
+ }
10
+ for (const value of Object.values(object)) {
11
+ if (value === null || value === undefined) {
12
+ continue;
13
+ }
14
+ const type = typeof value;
15
+ if (type === 'string' || type === 'number' || type === 'boolean') {
16
+ continue;
17
+ }
18
+ if (Array.isArray(value)) {
19
+ if (!value.every((item) => typeof item === 'string')) {
20
+ return false;
21
+ }
22
+ continue;
23
+ }
24
+ return false;
25
+ }
26
+ return true;
27
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Validates if a URL is valid and optionally allows HTTP URLs
3
+ * @param url - The URL to validate
4
+ * @param allowHttp - Whether to allow HTTP URLs (default: false)
5
+ * @returns True if the URL is valid, false otherwise
6
+ */
7
+ export declare const isValidUrl: (url: string, allowHttp?: boolean) => boolean;
8
+ /**
9
+ * Validates a URL field in configuration
10
+ * @param url - The URL to validate
11
+ * @param allowHttp - Whether to allow HTTP URLs
12
+ * @param fieldName - The name of the field being validated
13
+ * @param errors - Array to push errors to
14
+ */
15
+ export declare const validateUrl: (url: unknown, allowHttp: boolean | undefined, fieldName: string, errors: string[]) => void;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Validates if a URL is valid and optionally allows HTTP URLs
3
+ * @param url - The URL to validate
4
+ * @param allowHttp - Whether to allow HTTP URLs (default: false)
5
+ * @returns True if the URL is valid, false otherwise
6
+ */
7
+ export const isValidUrl = (url, allowHttp = false) => {
8
+ try {
9
+ const parsed = new URL(url);
10
+ const isHttps = parsed.protocol === 'https:';
11
+ const isHttp = parsed.protocol === 'http:';
12
+ return isHttps || (allowHttp && isHttp);
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ };
18
+ /**
19
+ * Validates a URL field in configuration
20
+ * @param url - The URL to validate
21
+ * @param allowHttp - Whether to allow HTTP URLs
22
+ * @param fieldName - The name of the field being validated
23
+ * @param errors - Array to push errors to
24
+ */
25
+ export const validateUrl = (url, allowHttp, fieldName, errors) => {
26
+ if (url !== undefined) {
27
+ if (typeof url === 'string') {
28
+ try {
29
+ const parsed = new URL(url);
30
+ if (parsed.protocol === 'http:' && !allowHttp) {
31
+ errors.push(`${fieldName} using http requires allowHttp=true`);
32
+ }
33
+ }
34
+ catch {
35
+ errors.push(`${fieldName} must be a valid URL`);
36
+ }
37
+ }
38
+ else {
39
+ errors.push(`${fieldName} must be a string`);
40
+ }
41
+ }
42
+ };