@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,319 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeUrl = exports.sanitizeMetadata = exports.sanitizeApiConfig = exports.sanitizePathString = exports.sanitizeString = void 0;
4
+ const constants_1 = require("../../constants");
5
+ const logging_1 = require("../logging");
6
+ /**
7
+ * Sanitizes a string value to prevent XSS attacks
8
+ * @param value - The string to sanitize
9
+ * @returns The sanitized string
10
+ */
11
+ const sanitizeString = (value) => {
12
+ if (!value || typeof value !== 'string' || value.trim().length === 0) {
13
+ logging_1.debugLog.debug('Sanitize', 'String sanitization skipped - empty or invalid input', { value, type: typeof value });
14
+ return '';
15
+ }
16
+ const originalLength = value.length;
17
+ let sanitized = value;
18
+ // Limit string length
19
+ if (value.length > constants_1.MAX_STRING_LENGTH) {
20
+ sanitized = value.slice(0, Math.max(0, constants_1.MAX_STRING_LENGTH));
21
+ logging_1.debugLog.warn('Sanitize', 'String truncated due to length limit', {
22
+ originalLength,
23
+ maxLength: constants_1.MAX_STRING_LENGTH,
24
+ truncatedLength: sanitized.length,
25
+ });
26
+ }
27
+ // Remove potential XSS patterns
28
+ let xssPatternMatches = 0;
29
+ for (const pattern of constants_1.XSS_PATTERNS) {
30
+ const beforeReplace = sanitized;
31
+ sanitized = sanitized.replace(pattern, '');
32
+ if (beforeReplace !== sanitized) {
33
+ xssPatternMatches++;
34
+ }
35
+ }
36
+ if (xssPatternMatches > 0) {
37
+ logging_1.debugLog.warn('Sanitize', 'XSS patterns detected and removed', {
38
+ patternMatches: xssPatternMatches,
39
+ originalValue: value.slice(0, 100), // Log first 100 chars for debugging
40
+ });
41
+ }
42
+ // Basic HTML entity encoding for critical characters
43
+ sanitized = sanitized
44
+ .replaceAll('&', '&')
45
+ .replaceAll('<', '&lt;')
46
+ .replaceAll('>', '&gt;')
47
+ .replaceAll('"', '&quot;')
48
+ .replaceAll("'", '&#x27;')
49
+ .replaceAll('/', '&#x2F;');
50
+ const result = sanitized.trim();
51
+ if (originalLength > 50 || xssPatternMatches > 0) {
52
+ logging_1.debugLog.debug('Sanitize', 'String sanitization completed', {
53
+ originalLength,
54
+ sanitizedLength: result.length,
55
+ xssPatternMatches,
56
+ wasTruncated: originalLength > constants_1.MAX_STRING_LENGTH,
57
+ });
58
+ }
59
+ return result;
60
+ };
61
+ exports.sanitizeString = sanitizeString;
62
+ /**
63
+ * Sanitizes a path string for route exclusion checks
64
+ * @param value - The path string to sanitize
65
+ * @returns The sanitized path string
66
+ */
67
+ const sanitizePathString = (value) => {
68
+ if (typeof value !== 'string') {
69
+ return '';
70
+ }
71
+ if (value.length > constants_1.MAX_STRING_LENGTH) {
72
+ value = value.slice(0, Math.max(0, constants_1.MAX_STRING_LENGTH));
73
+ }
74
+ let sanitized = value;
75
+ for (const pattern of constants_1.XSS_PATTERNS) {
76
+ sanitized = sanitized.replace(pattern, '');
77
+ }
78
+ sanitized = sanitized
79
+ .replaceAll('&', '&amp;')
80
+ .replaceAll('<', '&lt;')
81
+ .replaceAll('>', '&gt;')
82
+ .replaceAll('"', '&quot;')
83
+ .replaceAll("'", '&#x27;');
84
+ return sanitized.trim();
85
+ };
86
+ exports.sanitizePathString = sanitizePathString;
87
+ /**
88
+ * Sanitizes any value recursively with depth protection
89
+ * @param value - The value to sanitize
90
+ * @param depth - Current recursion depth
91
+ * @returns The sanitized value
92
+ */
93
+ const sanitizeValue = (value, depth = 0) => {
94
+ // Prevent infinite recursion
95
+ if (depth > constants_1.MAX_OBJECT_DEPTH) {
96
+ logging_1.debugLog.warn('Sanitize', 'Maximum object depth exceeded during sanitization', {
97
+ depth,
98
+ maxDepth: constants_1.MAX_OBJECT_DEPTH,
99
+ });
100
+ return null;
101
+ }
102
+ if (value === null || value === undefined) {
103
+ return null;
104
+ }
105
+ if (typeof value === 'string') {
106
+ return (0, exports.sanitizeString)(value);
107
+ }
108
+ if (typeof value === 'number') {
109
+ if (!Number.isFinite(value) || value < -Number.MAX_SAFE_INTEGER || value > Number.MAX_SAFE_INTEGER) {
110
+ logging_1.debugLog.warn('Sanitize', 'Invalid number sanitized to 0', { value, isFinite: Number.isFinite(value) });
111
+ return 0;
112
+ }
113
+ return value;
114
+ }
115
+ if (typeof value === 'boolean') {
116
+ return value;
117
+ }
118
+ if (Array.isArray(value)) {
119
+ const originalLength = value.length;
120
+ const limitedArray = value.slice(0, constants_1.MAX_ARRAY_LENGTH);
121
+ if (originalLength > constants_1.MAX_ARRAY_LENGTH) {
122
+ logging_1.debugLog.warn('Sanitize', 'Array truncated due to length limit', {
123
+ originalLength,
124
+ maxLength: constants_1.MAX_ARRAY_LENGTH,
125
+ depth,
126
+ });
127
+ }
128
+ const sanitizedArray = limitedArray.map((item) => sanitizeValue(item, depth + 1)).filter((item) => item !== null);
129
+ if (originalLength > 0 && sanitizedArray.length === 0) {
130
+ logging_1.debugLog.warn('Sanitize', 'All array items were filtered out during sanitization', { originalLength, depth });
131
+ }
132
+ return sanitizedArray;
133
+ }
134
+ if (typeof value === 'object') {
135
+ const sanitizedObject = {};
136
+ const entries = Object.entries(value);
137
+ const originalKeysCount = entries.length;
138
+ const limitedEntries = entries.slice(0, 20);
139
+ if (originalKeysCount > 20) {
140
+ logging_1.debugLog.warn('Sanitize', 'Object keys truncated due to limit', {
141
+ originalKeys: originalKeysCount,
142
+ maxKeys: 20,
143
+ depth,
144
+ });
145
+ }
146
+ let filteredKeysCount = 0;
147
+ for (const [key, value_] of limitedEntries) {
148
+ const sanitizedKey = (0, exports.sanitizeString)(key);
149
+ if (sanitizedKey) {
150
+ const sanitizedValue = sanitizeValue(value_, depth + 1);
151
+ if (sanitizedValue !== null) {
152
+ sanitizedObject[sanitizedKey] = sanitizedValue;
153
+ }
154
+ else {
155
+ filteredKeysCount++;
156
+ }
157
+ }
158
+ else {
159
+ filteredKeysCount++;
160
+ }
161
+ }
162
+ if (filteredKeysCount > 0) {
163
+ logging_1.debugLog.debug('Sanitize', 'Object properties filtered during sanitization', {
164
+ filteredKeysCount,
165
+ remainingKeys: Object.keys(sanitizedObject).length,
166
+ depth,
167
+ });
168
+ }
169
+ return sanitizedObject;
170
+ }
171
+ logging_1.debugLog.debug('Sanitize', 'Unknown value type sanitized to null', { type: typeof value, depth });
172
+ return null;
173
+ };
174
+ /**
175
+ * Sanitizes API configuration data with strict validation
176
+ * @param data - The API config data to sanitize
177
+ * @returns The sanitized API config
178
+ */
179
+ const sanitizeApiConfig = (data) => {
180
+ logging_1.debugLog.debug('Sanitize', 'Starting API config sanitization');
181
+ const safeData = {};
182
+ if (typeof data !== 'object' || data === null) {
183
+ logging_1.debugLog.warn('Sanitize', 'API config data is not an object', { data, type: typeof data });
184
+ return safeData;
185
+ }
186
+ try {
187
+ const originalKeys = Object.keys(data);
188
+ let processedKeys = 0;
189
+ let filteredKeys = 0;
190
+ for (const key of originalKeys) {
191
+ if (constants_1.ALLOWED_API_CONFIG_KEYS.has(key)) {
192
+ const value = data[key];
193
+ if (key === 'excludedUrlPaths') {
194
+ const paths = Array.isArray(value) ? value : typeof value === 'string' ? [value] : [];
195
+ const originalPathsCount = paths.length;
196
+ safeData.excludedUrlPaths = paths.map((path) => (0, exports.sanitizePathString)(String(path))).filter(Boolean);
197
+ const filteredPathsCount = originalPathsCount - safeData.excludedUrlPaths.length;
198
+ if (filteredPathsCount > 0) {
199
+ logging_1.debugLog.warn('Sanitize', 'Some excluded URL paths were filtered during sanitization', {
200
+ originalCount: originalPathsCount,
201
+ filteredCount: filteredPathsCount,
202
+ });
203
+ }
204
+ }
205
+ else if (key === 'tags') {
206
+ if (Array.isArray(value)) {
207
+ safeData.tags = value;
208
+ logging_1.debugLog.debug('Sanitize', 'Tags processed', { count: value.length });
209
+ }
210
+ else {
211
+ logging_1.debugLog.warn('Sanitize', 'Tags value is not an array', { value, type: typeof value });
212
+ }
213
+ }
214
+ else {
215
+ const sanitizedValue = sanitizeValue(value);
216
+ if (sanitizedValue !== null) {
217
+ safeData[key] = sanitizedValue;
218
+ }
219
+ else {
220
+ logging_1.debugLog.warn('Sanitize', 'API config value sanitized to null', { key, originalValue: value });
221
+ }
222
+ }
223
+ processedKeys++;
224
+ }
225
+ else {
226
+ filteredKeys++;
227
+ logging_1.debugLog.debug('Sanitize', 'API config key not allowed', { key });
228
+ }
229
+ }
230
+ logging_1.debugLog.info('Sanitize', 'API config sanitization completed', {
231
+ originalKeys: originalKeys.length,
232
+ processedKeys,
233
+ filteredKeys,
234
+ finalKeys: Object.keys(safeData).length,
235
+ });
236
+ }
237
+ catch (error) {
238
+ logging_1.debugLog.error('Sanitize', 'API config sanitization failed', {
239
+ error: error instanceof Error ? error.message : error,
240
+ });
241
+ throw new Error(`API config sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
242
+ }
243
+ return safeData;
244
+ };
245
+ exports.sanitizeApiConfig = sanitizeApiConfig;
246
+ /**
247
+ * Sanitizes user metadata for custom events
248
+ * @param metadata - The metadata to sanitize
249
+ * @returns The sanitized metadata
250
+ */
251
+ const sanitizeMetadata = (metadata) => {
252
+ logging_1.debugLog.debug('Sanitize', 'Starting metadata sanitization', { hasMetadata: metadata != null });
253
+ if (typeof metadata !== 'object' || metadata === null) {
254
+ logging_1.debugLog.debug('Sanitize', 'Metadata is not an object, returning empty object', {
255
+ metadata,
256
+ type: typeof metadata,
257
+ });
258
+ return {};
259
+ }
260
+ try {
261
+ const originalKeys = Object.keys(metadata).length;
262
+ const sanitized = sanitizeValue(metadata);
263
+ const result = typeof sanitized === 'object' && sanitized !== null ? sanitized : {};
264
+ const finalKeys = Object.keys(result).length;
265
+ logging_1.debugLog.debug('Sanitize', 'Metadata sanitization completed', {
266
+ originalKeys,
267
+ finalKeys,
268
+ keysFiltered: originalKeys - finalKeys,
269
+ });
270
+ return result;
271
+ }
272
+ catch (error) {
273
+ logging_1.debugLog.error('Sanitize', 'Metadata sanitization failed', {
274
+ error: error instanceof Error ? error.message : error,
275
+ });
276
+ throw new Error(`Metadata sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
277
+ }
278
+ };
279
+ exports.sanitizeMetadata = sanitizeMetadata;
280
+ /**
281
+ * Sanitizes URL strings for tracking
282
+ * @param url - The URL to sanitize
283
+ * @returns The sanitized URL
284
+ */
285
+ const sanitizeUrl = (url) => {
286
+ logging_1.debugLog.debug('Sanitize', 'Starting URL sanitization', { urlLength: typeof url === 'string' ? url.length : 0 });
287
+ if (typeof url !== 'string') {
288
+ logging_1.debugLog.warn('Sanitize', 'URL is not a string', { url, type: typeof url });
289
+ return '';
290
+ }
291
+ try {
292
+ // Basic URL validation
293
+ const urlObject = new URL(url);
294
+ // Only allow http/https protocols
295
+ if (!['http:', 'https:'].includes(urlObject.protocol)) {
296
+ logging_1.debugLog.warn('Sanitize', 'URL protocol not allowed', {
297
+ protocol: urlObject.protocol,
298
+ allowedProtocols: ['http:', 'https:'],
299
+ });
300
+ return '';
301
+ }
302
+ // Sanitize the URL string
303
+ const result = (0, exports.sanitizeString)(urlObject.href);
304
+ logging_1.debugLog.debug('Sanitize', 'URL sanitization completed via URL object', {
305
+ originalLength: url.length,
306
+ sanitizedLength: result.length,
307
+ protocol: urlObject.protocol,
308
+ });
309
+ return result;
310
+ }
311
+ catch {
312
+ // If URL parsing fails, sanitize as string
313
+ logging_1.debugLog.warn('Sanitize', 'URL parsing failed, falling back to string sanitization', {
314
+ urlPreview: url.slice(0, 100),
315
+ });
316
+ return (0, exports.sanitizeString)(url);
317
+ }
318
+ };
319
+ exports.sanitizeUrl = sanitizeUrl;
@@ -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,297 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isValidConfigApiResponse = exports.validateFinalConfig = exports.validateConfig = exports.validateAndNormalizeConfig = exports.validateAppConfig = void 0;
4
+ const constants_1 = require("../../constants");
5
+ const types_1 = require("../../types");
6
+ const validation_error_types_1 = require("../../types/validation-error.types");
7
+ const logging_1 = require("../logging");
8
+ /**
9
+ * Validates the app configuration object (before normalization)
10
+ * This validates the structure and basic types but allows for normalization afterward
11
+ * @param config - The app configuration to validate
12
+ * @throws {ProjectIdValidationError} If project ID validation fails
13
+ * @throws {AppConfigValidationError} If other configuration validation fails
14
+ */
15
+ const validateAppConfig = (config) => {
16
+ // Validate config exists and has id property
17
+ if (!config || typeof config !== 'object') {
18
+ logging_1.debugLog.clientError('ConfigValidation', 'Configuration must be an object', { config });
19
+ throw new validation_error_types_1.AppConfigValidationError('Configuration must be an object', 'config');
20
+ }
21
+ // Check if id property exists (allow falsy values to be handled by normalization)
22
+ if (!('id' in config)) {
23
+ logging_1.debugLog.clientError('ConfigValidation', 'Project ID is missing from configuration');
24
+ throw new validation_error_types_1.ProjectIdValidationError(constants_1.VALIDATION_MESSAGES.MISSING_PROJECT_ID, 'config');
25
+ }
26
+ // Check basic type - null, undefined, or non-string values should fail here
27
+ if (config.id === null || config.id === undefined || typeof config.id !== 'string') {
28
+ logging_1.debugLog.clientError('ConfigValidation', 'Project ID must be a non-empty string', {
29
+ providedId: config.id,
30
+ type: typeof config.id,
31
+ });
32
+ throw new validation_error_types_1.ProjectIdValidationError(constants_1.VALIDATION_MESSAGES.MISSING_PROJECT_ID, 'config');
33
+ }
34
+ if (config.sessionTimeout !== undefined) {
35
+ if (typeof config.sessionTimeout !== 'number' ||
36
+ config.sessionTimeout < constants_1.MIN_SESSION_TIMEOUT_MS ||
37
+ config.sessionTimeout > constants_1.MAX_SESSION_TIMEOUT_MS) {
38
+ logging_1.debugLog.clientError('ConfigValidation', 'Invalid session timeout', {
39
+ provided: config.sessionTimeout,
40
+ min: constants_1.MIN_SESSION_TIMEOUT_MS,
41
+ max: constants_1.MAX_SESSION_TIMEOUT_MS,
42
+ });
43
+ throw new validation_error_types_1.SessionTimeoutValidationError(constants_1.VALIDATION_MESSAGES.INVALID_SESSION_TIMEOUT, 'config');
44
+ }
45
+ }
46
+ if (config.globalMetadata !== undefined) {
47
+ if (typeof config.globalMetadata !== 'object' || config.globalMetadata === null) {
48
+ logging_1.debugLog.clientError('ConfigValidation', 'Global metadata must be an object', {
49
+ provided: config.globalMetadata,
50
+ type: typeof config.globalMetadata,
51
+ });
52
+ throw new validation_error_types_1.AppConfigValidationError(constants_1.VALIDATION_MESSAGES.INVALID_GLOBAL_METADATA, 'config');
53
+ }
54
+ }
55
+ if (config.scrollContainerSelectors !== undefined) {
56
+ validateScrollContainerSelectors(config.scrollContainerSelectors);
57
+ }
58
+ if (config.integrations) {
59
+ validateIntegrations(config.integrations);
60
+ }
61
+ if (config.sensitiveQueryParams !== undefined) {
62
+ if (!Array.isArray(config.sensitiveQueryParams)) {
63
+ logging_1.debugLog.clientError('ConfigValidation', 'Sensitive query params must be an array', {
64
+ provided: config.sensitiveQueryParams,
65
+ type: typeof config.sensitiveQueryParams,
66
+ });
67
+ throw new validation_error_types_1.AppConfigValidationError(constants_1.VALIDATION_MESSAGES.INVALID_SENSITIVE_QUERY_PARAMS, 'config');
68
+ }
69
+ for (const param of config.sensitiveQueryParams) {
70
+ if (typeof param !== 'string') {
71
+ logging_1.debugLog.clientError('ConfigValidation', 'All sensitive query params must be strings', {
72
+ param,
73
+ type: typeof param,
74
+ });
75
+ throw new validation_error_types_1.AppConfigValidationError('All sensitive query params must be strings', 'config');
76
+ }
77
+ }
78
+ }
79
+ if (config.errorSampling !== undefined) {
80
+ if (typeof config.errorSampling !== 'number' || config.errorSampling < 0 || config.errorSampling > 1) {
81
+ logging_1.debugLog.clientError('ConfigValidation', 'Invalid error sampling rate', {
82
+ provided: config.errorSampling,
83
+ expected: '0-1',
84
+ });
85
+ throw new validation_error_types_1.SamplingRateValidationError(constants_1.VALIDATION_MESSAGES.INVALID_ERROR_SAMPLING_RATE, 'config');
86
+ }
87
+ }
88
+ };
89
+ exports.validateAppConfig = validateAppConfig;
90
+ /**
91
+ * Validates scroll container selectors
92
+ * @param selectors - CSS selectors to validate
93
+ */
94
+ const validateScrollContainerSelectors = (selectors) => {
95
+ const selectorsArray = Array.isArray(selectors) ? selectors : [selectors];
96
+ for (const selector of selectorsArray) {
97
+ if (typeof selector !== 'string' || selector.trim() === '') {
98
+ logging_1.debugLog.clientError('ConfigValidation', 'Invalid scroll container selector', {
99
+ selector,
100
+ type: typeof selector,
101
+ isEmpty: selector === '' || (typeof selector === 'string' && selector.trim() === ''),
102
+ });
103
+ throw new validation_error_types_1.AppConfigValidationError(constants_1.VALIDATION_MESSAGES.INVALID_SCROLL_CONTAINER_SELECTORS, 'config');
104
+ }
105
+ // Validate CSS selector syntax but handle invalid selectors gracefully
106
+ if (typeof document !== 'undefined') {
107
+ try {
108
+ document.querySelector(selector);
109
+ }
110
+ catch {
111
+ // Invalid CSS selectors are handled gracefully
112
+ // they will be ignored by the ScrollHandler and it will fall back to window scrolling
113
+ logging_1.debugLog.clientWarn('ConfigValidation', `Invalid CSS selector will be ignored: "${selector}"`);
114
+ }
115
+ }
116
+ }
117
+ };
118
+ /**
119
+ * Validates integrations configuration
120
+ * @param integrations - Integrations configuration to validate
121
+ */
122
+ const validateIntegrations = (integrations) => {
123
+ if (!integrations)
124
+ return;
125
+ if (integrations.googleAnalytics) {
126
+ if (!integrations.googleAnalytics.measurementId ||
127
+ typeof integrations.googleAnalytics.measurementId !== 'string' ||
128
+ integrations.googleAnalytics.measurementId.trim() === '') {
129
+ logging_1.debugLog.clientError('ConfigValidation', 'Invalid Google Analytics measurement ID', {
130
+ provided: integrations.googleAnalytics.measurementId,
131
+ type: typeof integrations.googleAnalytics.measurementId,
132
+ });
133
+ throw new validation_error_types_1.IntegrationValidationError(constants_1.VALIDATION_MESSAGES.INVALID_GOOGLE_ANALYTICS_ID, 'config');
134
+ }
135
+ const measurementId = integrations.googleAnalytics.measurementId.trim();
136
+ if (!measurementId.match(/^(G-|UA-)/)) {
137
+ logging_1.debugLog.clientError('ConfigValidation', 'Google Analytics measurement ID must start with "G-" or "UA-"', {
138
+ provided: measurementId,
139
+ });
140
+ throw new validation_error_types_1.IntegrationValidationError('Google Analytics measurement ID must start with "G-" or "UA-"', 'config');
141
+ }
142
+ }
143
+ };
144
+ /**
145
+ * Validates and normalizes the app configuration
146
+ * This is the primary validation entry point that ensures consistent behavior
147
+ * @param config - The app configuration to validate and normalize
148
+ * @returns The normalized configuration
149
+ * @throws {ProjectIdValidationError} If project ID validation fails after normalization
150
+ * @throws {AppConfigValidationError} If other configuration validation fails
151
+ */
152
+ const validateAndNormalizeConfig = (config) => {
153
+ // First validate the structure and basic types
154
+ (0, exports.validateAppConfig)(config);
155
+ // Normalize string values
156
+ const normalizedConfig = {
157
+ ...config,
158
+ id: config.id.trim(),
159
+ globalMetadata: config.globalMetadata ?? {},
160
+ sensitiveQueryParams: config.sensitiveQueryParams ?? [],
161
+ };
162
+ // Validate normalized values - this catches whitespace-only IDs
163
+ if (!normalizedConfig.id) {
164
+ logging_1.debugLog.clientError('ConfigValidation', 'Project ID is empty after trimming whitespace', {
165
+ originalId: config.id,
166
+ normalizedId: normalizedConfig.id,
167
+ });
168
+ throw new validation_error_types_1.ProjectIdValidationError(constants_1.VALIDATION_MESSAGES.PROJECT_ID_EMPTY_AFTER_TRIM, 'config');
169
+ }
170
+ return normalizedConfig;
171
+ };
172
+ exports.validateAndNormalizeConfig = validateAndNormalizeConfig;
173
+ /**
174
+ * Validates sampling rate
175
+ * @param samplingRate - The sampling rate to validate
176
+ * @param errors - Array to push errors to
177
+ */
178
+ const validateSamplingRate = (samplingRate, errors) => {
179
+ if (samplingRate !== undefined) {
180
+ if (typeof samplingRate !== 'number') {
181
+ errors.push('samplingRate must be a number');
182
+ }
183
+ else if (samplingRate < 0 || samplingRate > 1) {
184
+ errors.push('samplingRate must be between 0 and 1');
185
+ }
186
+ }
187
+ };
188
+ /**
189
+ * Validates excluded URL paths
190
+ * @param excludedUrlPaths - The excluded URL paths to validate
191
+ * @param errors - Array to push errors to
192
+ * @param prefix - Optional prefix for error messages
193
+ */
194
+ const validateExcludedUrlPaths = (excludedUrlPaths, errors, prefix = '') => {
195
+ if (excludedUrlPaths !== undefined) {
196
+ if (Array.isArray(excludedUrlPaths)) {
197
+ for (const [index, path] of excludedUrlPaths.entries()) {
198
+ if (typeof path === 'string') {
199
+ try {
200
+ new RegExp(path);
201
+ }
202
+ catch {
203
+ errors.push(`${prefix}excludedUrlPaths[${index}] is not a valid regex pattern`);
204
+ }
205
+ }
206
+ else {
207
+ errors.push(`${prefix}excludedUrlPaths[${index}] must be a string`);
208
+ }
209
+ }
210
+ }
211
+ else {
212
+ errors.push(`${prefix}excludedUrlPaths must be an array`);
213
+ }
214
+ }
215
+ };
216
+ /**
217
+ * Validates a complete configuration object
218
+ * @param config - The configuration to validate
219
+ * @returns Validation result with errors and warnings
220
+ */
221
+ const validateConfig = (config) => {
222
+ const errors = [];
223
+ const warnings = [];
224
+ if (config.sessionTimeout !== undefined) {
225
+ if (typeof config.sessionTimeout !== 'number') {
226
+ errors.push('sessionTimeout must be a number');
227
+ }
228
+ else if (config.sessionTimeout < constants_1.MIN_SESSION_TIMEOUT_MS) {
229
+ errors.push('sessionTimeout must be at least 30 seconds (30000ms)');
230
+ }
231
+ else if (config.sessionTimeout > constants_1.MAX_SESSION_TIMEOUT_MS) {
232
+ warnings.push('sessionTimeout is very long (>24 hours), consider reducing it');
233
+ }
234
+ }
235
+ if (config.globalMetadata !== undefined) {
236
+ if (typeof config.globalMetadata !== 'object' || config.globalMetadata === null) {
237
+ errors.push('globalMetadata must be an object');
238
+ }
239
+ else {
240
+ const metadataSize = JSON.stringify(config.globalMetadata).length;
241
+ if (metadataSize > 10240) {
242
+ errors.push('globalMetadata is too large (max 10KB)');
243
+ }
244
+ if (Object.keys(config.globalMetadata).length > 12) {
245
+ errors.push('globalMetadata has too many keys (max 12)');
246
+ }
247
+ }
248
+ }
249
+ // No custom API endpoints supported
250
+ validateSamplingRate(config.samplingRate, errors);
251
+ if (config.tags !== undefined && !Array.isArray(config.tags)) {
252
+ errors.push('tags must be an array');
253
+ }
254
+ validateExcludedUrlPaths(config.excludedUrlPaths, errors);
255
+ return { errors, warnings };
256
+ };
257
+ exports.validateConfig = validateConfig;
258
+ /**
259
+ * Validates the final configuration
260
+ * @param config - The configuration to validate
261
+ * @returns Validation result with errors and warnings
262
+ */
263
+ const validateFinalConfig = (config) => {
264
+ const errors = [];
265
+ const warnings = [];
266
+ validateSamplingRate(config.samplingRate, errors);
267
+ validateExcludedUrlPaths(config.excludedUrlPaths, errors);
268
+ // No custom API endpoints supported
269
+ return { errors, warnings };
270
+ };
271
+ exports.validateFinalConfig = validateFinalConfig;
272
+ /**
273
+ * Type guard to check if a JSON response is a valid API config
274
+ * @param json - The JSON to validate
275
+ * @returns True if the JSON is a valid API config
276
+ */
277
+ const isValidConfigApiResponse = (json) => {
278
+ try {
279
+ if (typeof json !== 'object' || !json) {
280
+ return false;
281
+ }
282
+ const response = json;
283
+ const result = {
284
+ mode: response['mode'] === undefined || [types_1.Mode.QA, types_1.Mode.DEBUG].includes(response['mode']),
285
+ samplingRate: response['samplingRate'] === undefined ||
286
+ (typeof response['samplingRate'] === 'number' && response['samplingRate'] > 0 && response['samplingRate'] <= 1),
287
+ tags: response['tags'] === undefined || Array.isArray(response['tags']),
288
+ excludedUrlPaths: response['excludedUrlPaths'] === undefined || Array.isArray(response['excludedUrlPaths']),
289
+ ipExcluded: response['ipExcluded'] === undefined || typeof response['ipExcluded'] === 'boolean',
290
+ };
291
+ return Object.values(result).every(Boolean);
292
+ }
293
+ catch {
294
+ return false;
295
+ }
296
+ };
297
+ exports.isValidConfigApiResponse = isValidConfigApiResponse;
@@ -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
+ };