@tracelog/lib 0.5.4 → 0.6.0

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 (200) hide show
  1. package/README.md +157 -180
  2. package/dist/browser/tracelog.esm.js +1007 -1357
  3. package/dist/browser/tracelog.js +2 -2
  4. package/dist/cjs/api.d.ts +12 -2
  5. package/dist/cjs/api.js +63 -27
  6. package/dist/cjs/app.d.ts +2 -2
  7. package/dist/cjs/app.js +26 -32
  8. package/dist/cjs/constants/config.constants.d.ts +4 -2
  9. package/dist/cjs/constants/config.constants.js +6 -18
  10. package/dist/cjs/constants/index.d.ts +0 -1
  11. package/dist/cjs/constants/index.js +0 -1
  12. package/dist/cjs/constants/storage.constants.d.ts +3 -2
  13. package/dist/cjs/constants/storage.constants.js +4 -4
  14. package/dist/cjs/handlers/click.handler.js +3 -6
  15. package/dist/cjs/handlers/error.handler.js +1 -11
  16. package/dist/cjs/handlers/page-view.handler.js +0 -4
  17. package/dist/cjs/handlers/performance.handler.js +14 -29
  18. package/dist/cjs/handlers/scroll.handler.js +7 -6
  19. package/dist/cjs/handlers/session.handler.js +7 -6
  20. package/dist/cjs/integrations/google-analytics.integration.js +2 -6
  21. package/dist/cjs/listeners/activity-listener-manager.js +3 -3
  22. package/dist/cjs/listeners/input-listener-managers.js +3 -3
  23. package/dist/cjs/listeners/touch-listener-manager.js +3 -3
  24. package/dist/cjs/listeners/unload-listener-manager.js +3 -3
  25. package/dist/cjs/listeners/visibility-listener-manager.js +3 -3
  26. package/dist/cjs/managers/event.manager.d.ts +2 -1
  27. package/dist/cjs/managers/event.manager.js +60 -38
  28. package/dist/cjs/managers/sender.manager.js +29 -36
  29. package/dist/cjs/managers/session.manager.js +5 -13
  30. package/dist/cjs/managers/state.manager.d.ts +0 -3
  31. package/dist/cjs/managers/state.manager.js +1 -43
  32. package/dist/cjs/managers/storage.manager.d.ts +16 -2
  33. package/dist/cjs/managers/storage.manager.js +73 -19
  34. package/dist/cjs/managers/user.manager.d.ts +1 -1
  35. package/dist/cjs/managers/user.manager.js +2 -2
  36. package/dist/cjs/public-api.d.ts +3 -3
  37. package/dist/cjs/public-api.js +1 -1
  38. package/dist/cjs/test-bridge.d.ts +1 -0
  39. package/dist/cjs/test-bridge.js +37 -2
  40. package/dist/cjs/types/config.types.d.ts +15 -18
  41. package/dist/cjs/types/config.types.js +6 -0
  42. package/dist/cjs/types/event.types.d.ts +1 -13
  43. package/dist/cjs/types/index.d.ts +0 -2
  44. package/dist/cjs/types/index.js +0 -2
  45. package/dist/cjs/types/mode.types.d.ts +1 -2
  46. package/dist/cjs/types/mode.types.js +0 -1
  47. package/dist/cjs/types/queue.types.d.ts +0 -6
  48. package/dist/cjs/types/state.types.d.ts +2 -0
  49. package/dist/cjs/types/test-bridge.types.d.ts +2 -2
  50. package/dist/cjs/types/validation-error.types.d.ts +0 -6
  51. package/dist/cjs/types/validation-error.types.js +1 -10
  52. package/dist/cjs/utils/browser/device-detector.utils.js +2 -24
  53. package/dist/cjs/utils/browser/index.d.ts +1 -0
  54. package/dist/cjs/utils/browser/index.js +1 -0
  55. package/dist/cjs/utils/browser/qa-mode.utils.d.ts +13 -0
  56. package/dist/cjs/utils/browser/qa-mode.utils.js +43 -0
  57. package/dist/cjs/utils/browser/utm-params.utils.js +0 -15
  58. package/dist/cjs/utils/data/uuid.utils.d.ts +13 -0
  59. package/dist/cjs/utils/data/uuid.utils.js +37 -1
  60. package/dist/cjs/utils/index.d.ts +1 -1
  61. package/dist/cjs/utils/index.js +1 -1
  62. package/dist/cjs/utils/logging.utils.d.ts +6 -0
  63. package/dist/cjs/utils/logging.utils.js +25 -0
  64. package/dist/cjs/utils/network/index.d.ts +0 -1
  65. package/dist/cjs/utils/network/index.js +0 -1
  66. package/dist/cjs/utils/network/url.utils.d.ts +2 -8
  67. package/dist/cjs/utils/network/url.utils.js +46 -90
  68. package/dist/cjs/utils/security/sanitize.utils.d.ts +1 -13
  69. package/dist/cjs/utils/security/sanitize.utils.js +15 -178
  70. package/dist/cjs/utils/validations/config-validations.utils.d.ts +3 -9
  71. package/dist/cjs/utils/validations/config-validations.utils.js +48 -94
  72. package/dist/cjs/utils/validations/event-validations.utils.js +11 -5
  73. package/dist/cjs/utils/validations/index.d.ts +0 -1
  74. package/dist/cjs/utils/validations/index.js +0 -1
  75. package/dist/cjs/utils/validations/metadata-validations.utils.js +0 -1
  76. package/dist/cjs/utils/validations/type-guards.utils.d.ts +2 -2
  77. package/dist/cjs/utils/validations/type-guards.utils.js +50 -4
  78. package/dist/esm/api.d.ts +12 -2
  79. package/dist/esm/api.js +62 -27
  80. package/dist/esm/app.d.ts +2 -2
  81. package/dist/esm/app.js +28 -34
  82. package/dist/esm/constants/config.constants.d.ts +4 -2
  83. package/dist/esm/constants/config.constants.js +4 -16
  84. package/dist/esm/constants/index.d.ts +0 -1
  85. package/dist/esm/constants/index.js +0 -1
  86. package/dist/esm/constants/storage.constants.d.ts +3 -2
  87. package/dist/esm/constants/storage.constants.js +3 -2
  88. package/dist/esm/handlers/click.handler.js +3 -6
  89. package/dist/esm/handlers/error.handler.js +1 -11
  90. package/dist/esm/handlers/page-view.handler.js +0 -4
  91. package/dist/esm/handlers/performance.handler.js +14 -29
  92. package/dist/esm/handlers/scroll.handler.js +7 -6
  93. package/dist/esm/handlers/session.handler.js +7 -6
  94. package/dist/esm/integrations/google-analytics.integration.js +3 -7
  95. package/dist/esm/listeners/activity-listener-manager.js +3 -3
  96. package/dist/esm/listeners/input-listener-managers.js +3 -3
  97. package/dist/esm/listeners/touch-listener-manager.js +3 -3
  98. package/dist/esm/listeners/unload-listener-manager.js +3 -3
  99. package/dist/esm/listeners/visibility-listener-manager.js +3 -3
  100. package/dist/esm/managers/event.manager.d.ts +2 -1
  101. package/dist/esm/managers/event.manager.js +62 -40
  102. package/dist/esm/managers/sender.manager.js +31 -38
  103. package/dist/esm/managers/session.manager.js +5 -13
  104. package/dist/esm/managers/state.manager.d.ts +0 -3
  105. package/dist/esm/managers/state.manager.js +1 -43
  106. package/dist/esm/managers/storage.manager.d.ts +16 -2
  107. package/dist/esm/managers/storage.manager.js +73 -19
  108. package/dist/esm/managers/user.manager.d.ts +1 -1
  109. package/dist/esm/managers/user.manager.js +2 -2
  110. package/dist/esm/public-api.d.ts +3 -3
  111. package/dist/esm/public-api.js +1 -1
  112. package/dist/esm/test-bridge.d.ts +1 -0
  113. package/dist/esm/test-bridge.js +37 -2
  114. package/dist/esm/types/config.types.d.ts +15 -18
  115. package/dist/esm/types/config.types.js +5 -1
  116. package/dist/esm/types/event.types.d.ts +1 -13
  117. package/dist/esm/types/index.d.ts +0 -2
  118. package/dist/esm/types/index.js +0 -2
  119. package/dist/esm/types/mode.types.d.ts +1 -2
  120. package/dist/esm/types/mode.types.js +0 -1
  121. package/dist/esm/types/queue.types.d.ts +0 -6
  122. package/dist/esm/types/state.types.d.ts +2 -0
  123. package/dist/esm/types/test-bridge.types.d.ts +2 -2
  124. package/dist/esm/types/validation-error.types.d.ts +0 -6
  125. package/dist/esm/types/validation-error.types.js +0 -8
  126. package/dist/esm/utils/browser/device-detector.utils.js +2 -24
  127. package/dist/esm/utils/browser/index.d.ts +1 -0
  128. package/dist/esm/utils/browser/index.js +1 -0
  129. package/dist/esm/utils/browser/qa-mode.utils.d.ts +13 -0
  130. package/dist/esm/utils/browser/qa-mode.utils.js +39 -0
  131. package/dist/esm/utils/browser/utm-params.utils.js +0 -15
  132. package/dist/esm/utils/data/uuid.utils.d.ts +13 -0
  133. package/dist/esm/utils/data/uuid.utils.js +35 -0
  134. package/dist/esm/utils/index.d.ts +1 -1
  135. package/dist/esm/utils/index.js +1 -1
  136. package/dist/esm/utils/logging.utils.d.ts +6 -0
  137. package/dist/esm/utils/logging.utils.js +20 -0
  138. package/dist/esm/utils/network/index.d.ts +0 -1
  139. package/dist/esm/utils/network/index.js +0 -1
  140. package/dist/esm/utils/network/url.utils.d.ts +2 -8
  141. package/dist/esm/utils/network/url.utils.js +45 -88
  142. package/dist/esm/utils/security/sanitize.utils.d.ts +1 -13
  143. package/dist/esm/utils/security/sanitize.utils.js +15 -176
  144. package/dist/esm/utils/validations/config-validations.utils.d.ts +3 -9
  145. package/dist/esm/utils/validations/config-validations.utils.js +49 -94
  146. package/dist/esm/utils/validations/event-validations.utils.js +11 -5
  147. package/dist/esm/utils/validations/index.d.ts +0 -1
  148. package/dist/esm/utils/validations/index.js +0 -1
  149. package/dist/esm/utils/validations/metadata-validations.utils.js +0 -1
  150. package/dist/esm/utils/validations/type-guards.utils.d.ts +2 -2
  151. package/dist/esm/utils/validations/type-guards.utils.js +50 -4
  152. package/package.json +1 -1
  153. package/dist/cjs/app.types.d.ts +0 -2
  154. package/dist/cjs/app.types.js +0 -12
  155. package/dist/cjs/constants/api.constants.d.ts +0 -6
  156. package/dist/cjs/constants/api.constants.js +0 -14
  157. package/dist/cjs/managers/api.manager.d.ts +0 -13
  158. package/dist/cjs/managers/api.manager.js +0 -44
  159. package/dist/cjs/managers/config.builder.d.ts +0 -33
  160. package/dist/cjs/managers/config.builder.js +0 -116
  161. package/dist/cjs/managers/config.manager.d.ts +0 -56
  162. package/dist/cjs/managers/config.manager.js +0 -157
  163. package/dist/cjs/managers/tags.manager.d.ts +0 -36
  164. package/dist/cjs/managers/tags.manager.js +0 -171
  165. package/dist/cjs/types/api.types.d.ts +0 -52
  166. package/dist/cjs/types/api.types.js +0 -56
  167. package/dist/cjs/types/tag.types.d.ts +0 -43
  168. package/dist/cjs/types/tag.types.js +0 -31
  169. package/dist/cjs/utils/logging/debug-logger.utils.d.ts +0 -14
  170. package/dist/cjs/utils/logging/debug-logger.utils.js +0 -47
  171. package/dist/cjs/utils/logging/index.d.ts +0 -1
  172. package/dist/cjs/utils/logging/index.js +0 -5
  173. package/dist/cjs/utils/network/fetch-with-timeout.utils.d.ts +0 -4
  174. package/dist/cjs/utils/network/fetch-with-timeout.utils.js +0 -25
  175. package/dist/cjs/utils/validations/url-validations.utils.d.ts +0 -15
  176. package/dist/cjs/utils/validations/url-validations.utils.js +0 -47
  177. package/dist/esm/app.types.d.ts +0 -2
  178. package/dist/esm/app.types.js +0 -1
  179. package/dist/esm/constants/api.constants.d.ts +0 -6
  180. package/dist/esm/constants/api.constants.js +0 -11
  181. package/dist/esm/managers/api.manager.d.ts +0 -13
  182. package/dist/esm/managers/api.manager.js +0 -41
  183. package/dist/esm/managers/config.builder.d.ts +0 -33
  184. package/dist/esm/managers/config.builder.js +0 -112
  185. package/dist/esm/managers/config.manager.d.ts +0 -56
  186. package/dist/esm/managers/config.manager.js +0 -153
  187. package/dist/esm/managers/tags.manager.d.ts +0 -36
  188. package/dist/esm/managers/tags.manager.js +0 -167
  189. package/dist/esm/types/api.types.d.ts +0 -52
  190. package/dist/esm/types/api.types.js +0 -53
  191. package/dist/esm/types/tag.types.d.ts +0 -43
  192. package/dist/esm/types/tag.types.js +0 -28
  193. package/dist/esm/utils/logging/debug-logger.utils.d.ts +0 -14
  194. package/dist/esm/utils/logging/debug-logger.utils.js +0 -44
  195. package/dist/esm/utils/logging/index.d.ts +0 -1
  196. package/dist/esm/utils/logging/index.js +0 -1
  197. package/dist/esm/utils/network/fetch-with-timeout.utils.d.ts +0 -4
  198. package/dist/esm/utils/network/fetch-with-timeout.utils.js +0 -22
  199. package/dist/esm/utils/validations/url-validations.utils.d.ts +0 -15
  200. package/dist/esm/utils/validations/url-validations.utils.js +0 -42
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sanitizeMetadata = exports.sanitizeApiConfig = exports.sanitizePathString = exports.sanitizeString = void 0;
3
+ exports.sanitizeMetadata = exports.sanitizeString = void 0;
4
4
  const constants_1 = require("../../constants");
5
- const logging_1 = require("../logging");
5
+ const logging_utils_1 = require("../logging.utils");
6
6
  /**
7
7
  * Sanitizes a string value to prevent XSS attacks
8
8
  * @param value - The string to sanitize
@@ -10,19 +10,13 @@ const logging_1 = require("../logging");
10
10
  */
11
11
  const sanitizeString = (value) => {
12
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
13
  return '';
15
14
  }
16
- const originalLength = value.length;
17
15
  let sanitized = value;
18
16
  // Limit string length
19
17
  if (value.length > constants_1.MAX_STRING_LENGTH) {
20
18
  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
- });
19
+ // Silent truncation - this is expected behavior for long strings
26
20
  }
27
21
  // Remove potential XSS patterns
28
22
  let xssPatternMatches = 0;
@@ -34,9 +28,11 @@ const sanitizeString = (value) => {
34
28
  }
35
29
  }
36
30
  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
31
+ (0, logging_utils_1.log)('warn', 'XSS patterns detected and removed', {
32
+ data: {
33
+ patternMatches: xssPatternMatches,
34
+ originalValue: value.slice(0, 100),
35
+ },
40
36
  });
41
37
  }
42
38
  // Basic HTML entity encoding for critical characters
@@ -48,42 +44,9 @@ const sanitizeString = (value) => {
48
44
  .replaceAll("'", ''')
49
45
  .replaceAll('/', '/');
50
46
  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
47
  return result;
60
48
  };
61
49
  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('&', '&')
80
- .replaceAll('<', '&lt;')
81
- .replaceAll('>', '&gt;')
82
- .replaceAll('"', '&quot;')
83
- .replaceAll("'", '&#x27;');
84
- return sanitized.trim();
85
- };
86
- exports.sanitizePathString = sanitizePathString;
87
50
  /**
88
51
  * Sanitizes any value recursively with depth protection
89
52
  * @param value - The value to sanitize
@@ -93,10 +56,7 @@ exports.sanitizePathString = sanitizePathString;
93
56
  const sanitizeValue = (value, depth = 0) => {
94
57
  // Prevent infinite recursion
95
58
  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
- });
59
+ // Silent depth limit - prevents stack overflow
100
60
  return null;
101
61
  }
102
62
  if (value === null || value === undefined) {
@@ -107,7 +67,7 @@ const sanitizeValue = (value, depth = 0) => {
107
67
  }
108
68
  if (typeof value === 'number') {
109
69
  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) });
70
+ // Silent normalization - invalid numbers become 0
111
71
  return 0;
112
72
  }
113
73
  return value;
@@ -116,34 +76,17 @@ const sanitizeValue = (value, depth = 0) => {
116
76
  return value;
117
77
  }
118
78
  if (Array.isArray(value)) {
119
- const originalLength = value.length;
120
79
  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
- }
80
+ // Silent array length limit
128
81
  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
- }
82
+ // Silent filter - empty arrays are valid results
132
83
  return sanitizedArray;
133
84
  }
134
85
  if (typeof value === 'object') {
135
86
  const sanitizedObject = {};
136
87
  const entries = Object.entries(value);
137
- const originalKeysCount = entries.length;
138
88
  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;
89
+ // Silent object keys limit
147
90
  for (const [key, value_] of limitedEntries) {
148
91
  const sanitizedKey = (0, exports.sanitizeString)(key);
149
92
  if (sanitizedKey) {
@@ -151,135 +94,29 @@ const sanitizeValue = (value, depth = 0) => {
151
94
  if (sanitizedValue !== null) {
152
95
  sanitizedObject[sanitizedKey] = sanitizedValue;
153
96
  }
154
- else {
155
- filteredKeysCount++;
156
- }
157
- }
158
- else {
159
- filteredKeysCount++;
160
97
  }
161
98
  }
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
99
  return sanitizedObject;
170
100
  }
171
- logging_1.debugLog.debug('Sanitize', 'Unknown value type sanitized to null', { type: typeof value, depth });
172
101
  return null;
173
102
  };
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 if (key === 'samplingRate') {
215
- const sanitizedValue = sanitizeValue(value);
216
- if (typeof sanitizedValue === 'number') {
217
- safeData.samplingRate = sanitizedValue;
218
- }
219
- }
220
- else {
221
- const sanitizedValue = sanitizeValue(value);
222
- if (sanitizedValue !== null) {
223
- safeData[key] = sanitizedValue;
224
- }
225
- else {
226
- logging_1.debugLog.warn('Sanitize', 'API config value sanitized to null', { key, originalValue: value });
227
- }
228
- }
229
- processedKeys++;
230
- }
231
- else {
232
- filteredKeys++;
233
- logging_1.debugLog.debug('Sanitize', 'API config key not allowed', { key });
234
- }
235
- }
236
- logging_1.debugLog.info('Sanitize', 'API config sanitization completed', {
237
- originalKeys: originalKeys.length,
238
- processedKeys,
239
- filteredKeys,
240
- finalKeys: Object.keys(safeData).length,
241
- });
242
- }
243
- catch (error) {
244
- logging_1.debugLog.error('Sanitize', 'API config sanitization failed', {
245
- error: error instanceof Error ? error.message : error,
246
- });
247
- throw new Error(`API config sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
248
- }
249
- return safeData;
250
- };
251
- exports.sanitizeApiConfig = sanitizeApiConfig;
252
103
  /**
253
104
  * Sanitizes user metadata for custom events
254
105
  * @param metadata - The metadata to sanitize
255
106
  * @returns The sanitized metadata
256
107
  */
257
108
  const sanitizeMetadata = (metadata) => {
258
- logging_1.debugLog.debug('Sanitize', 'Starting metadata sanitization', { hasMetadata: metadata != null });
259
109
  if (typeof metadata !== 'object' || metadata === null) {
260
- logging_1.debugLog.debug('Sanitize', 'Metadata is not an object, returning empty object', {
261
- metadata,
262
- type: typeof metadata,
263
- });
264
110
  return {};
265
111
  }
266
112
  try {
267
- const originalKeys = Object.keys(metadata).length;
268
113
  const sanitized = sanitizeValue(metadata);
269
114
  const result = typeof sanitized === 'object' && sanitized !== null ? sanitized : {};
270
- const finalKeys = Object.keys(result).length;
271
- logging_1.debugLog.debug('Sanitize', 'Metadata sanitization completed', {
272
- originalKeys,
273
- finalKeys,
274
- keysFiltered: originalKeys - finalKeys,
275
- });
276
115
  return result;
277
116
  }
278
117
  catch (error) {
279
- logging_1.debugLog.error('Sanitize', 'Metadata sanitization failed', {
280
- error: error instanceof Error ? error.message : error,
281
- });
282
- throw new Error(`Metadata sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
118
+ const errorMessage = error instanceof Error ? error.message : String(error);
119
+ throw new Error(`[TraceLog] Metadata sanitization failed: ${errorMessage}`);
283
120
  }
284
121
  };
285
122
  exports.sanitizeMetadata = sanitizeMetadata;
@@ -1,4 +1,4 @@
1
- import { AppConfig, ApiConfig } from '../../types';
1
+ import { Config } from '../../types';
2
2
  /**
3
3
  * Validates the app configuration object (before normalization)
4
4
  * This validates the structure and basic types but allows for normalization afterward
@@ -6,7 +6,7 @@ import { AppConfig, ApiConfig } from '../../types';
6
6
  * @throws {ProjectIdValidationError} If project ID validation fails
7
7
  * @throws {AppConfigValidationError} If other configuration validation fails
8
8
  */
9
- export declare const validateAppConfig: (config: AppConfig) => void;
9
+ export declare const validateAppConfig: (config: Config) => void;
10
10
  /**
11
11
  * Validates and normalizes the app configuration
12
12
  * This is the primary validation entry point that ensures consistent behavior
@@ -15,10 +15,4 @@ export declare const validateAppConfig: (config: AppConfig) => void;
15
15
  * @throws {ProjectIdValidationError} If project ID validation fails after normalization
16
16
  * @throws {AppConfigValidationError} If other configuration validation fails
17
17
  */
18
- export declare const validateAndNormalizeConfig: (config: AppConfig) => AppConfig;
19
- /**
20
- * Type guard to check if a JSON response is a valid API config
21
- * @param json - The JSON to validate
22
- * @returns True if the JSON is a valid API config
23
- */
24
- export declare const isValidConfigApiResponse: (json: unknown) => json is ApiConfig;
18
+ export declare const validateAndNormalizeConfig: (config: Config) => Config;
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isValidConfigApiResponse = exports.validateAndNormalizeConfig = exports.validateAppConfig = void 0;
3
+ exports.validateAndNormalizeConfig = exports.validateAppConfig = void 0;
4
4
  const constants_1 = require("../../constants");
5
- const types_1 = require("../../types");
6
5
  const validation_error_types_1 = require("../../types/validation-error.types");
7
- const logging_1 = require("../logging");
6
+ const logging_utils_1 = require("../logging.utils");
8
7
  /**
9
8
  * Validates the app configuration object (before normalization)
10
9
  * This validates the structure and basic types but allows for normalization afterward
@@ -13,42 +12,18 @@ const logging_1 = require("../logging");
13
12
  * @throws {AppConfigValidationError} If other configuration validation fails
14
13
  */
15
14
  const validateAppConfig = (config) => {
16
- // Validate config exists and has id property
17
15
  if (!config || typeof config !== 'object') {
18
- logging_1.debugLog.clientError('ConfigValidation', 'Configuration must be an object', { config });
19
16
  throw new validation_error_types_1.AppConfigValidationError('Configuration must be an object', 'config');
20
17
  }
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
18
  if (config.sessionTimeout !== undefined) {
35
19
  if (typeof config.sessionTimeout !== 'number' ||
36
20
  config.sessionTimeout < constants_1.MIN_SESSION_TIMEOUT_MS ||
37
21
  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
22
  throw new validation_error_types_1.SessionTimeoutValidationError(constants_1.VALIDATION_MESSAGES.INVALID_SESSION_TIMEOUT, 'config');
44
23
  }
45
24
  }
46
25
  if (config.globalMetadata !== undefined) {
47
26
  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
27
  throw new validation_error_types_1.AppConfigValidationError(constants_1.VALIDATION_MESSAGES.INVALID_GLOBAL_METADATA, 'config');
53
28
  }
54
29
  }
@@ -60,31 +35,29 @@ const validateAppConfig = (config) => {
60
35
  }
61
36
  if (config.sensitiveQueryParams !== undefined) {
62
37
  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
38
  throw new validation_error_types_1.AppConfigValidationError(constants_1.VALIDATION_MESSAGES.INVALID_SENSITIVE_QUERY_PARAMS, 'config');
68
39
  }
69
40
  for (const param of config.sensitiveQueryParams) {
70
41
  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
42
  throw new validation_error_types_1.AppConfigValidationError('All sensitive query params must be strings', 'config');
76
43
  }
77
44
  }
78
45
  }
79
46
  if (config.errorSampling !== undefined) {
80
47
  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
48
  throw new validation_error_types_1.SamplingRateValidationError(constants_1.VALIDATION_MESSAGES.INVALID_ERROR_SAMPLING_RATE, 'config');
86
49
  }
87
50
  }
51
+ if (config.samplingRate !== undefined) {
52
+ if (typeof config.samplingRate !== 'number' || config.samplingRate < 0 || config.samplingRate > 1) {
53
+ throw new validation_error_types_1.SamplingRateValidationError(constants_1.VALIDATION_MESSAGES.INVALID_SAMPLING_RATE, 'config');
54
+ }
55
+ }
56
+ if (config.allowHttp !== undefined) {
57
+ if (typeof config.allowHttp !== 'boolean') {
58
+ throw new validation_error_types_1.AppConfigValidationError('allowHttp must be a boolean', 'config');
59
+ }
60
+ }
88
61
  };
89
62
  exports.validateAppConfig = validateAppConfig;
90
63
  /**
@@ -136,19 +109,25 @@ const validateScrollContainerSelectors = (selectors) => {
136
109
  const selectorsArray = Array.isArray(selectors) ? selectors : [selectors];
137
110
  for (const selector of selectorsArray) {
138
111
  if (typeof selector !== 'string' || selector.trim() === '') {
139
- logging_1.debugLog.clientError('ConfigValidation', 'Invalid scroll container selector', {
140
- selector,
141
- type: typeof selector,
142
- isEmpty: selector === '' || (typeof selector === 'string' && selector.trim() === ''),
112
+ (0, logging_utils_1.log)('error', 'Invalid scroll container selector', {
113
+ showToClient: true,
114
+ data: {
115
+ selector,
116
+ type: typeof selector,
117
+ isEmpty: selector === '' || (typeof selector === 'string' && selector.trim() === ''),
118
+ },
143
119
  });
144
120
  throw new validation_error_types_1.AppConfigValidationError(constants_1.VALIDATION_MESSAGES.INVALID_SCROLL_CONTAINER_SELECTORS, 'config');
145
121
  }
146
122
  // Validate CSS selector syntax using regex-based validation (XSS prevention)
147
123
  // This validates syntax WITHOUT executing document.querySelector()
148
124
  if (!isValidCssSelectorSyntax(selector)) {
149
- logging_1.debugLog.clientError('ConfigValidation', 'Invalid or potentially unsafe CSS selector', {
150
- selector,
151
- reason: 'Failed security validation',
125
+ (0, logging_utils_1.log)('error', 'Invalid or potentially unsafe CSS selector', {
126
+ showToClient: true,
127
+ data: {
128
+ selector,
129
+ reason: 'Failed security validation',
130
+ },
152
131
  });
153
132
  throw new validation_error_types_1.AppConfigValidationError('Invalid or potentially unsafe CSS selector', 'config');
154
133
  }
@@ -159,23 +138,34 @@ const validateScrollContainerSelectors = (selectors) => {
159
138
  * @param integrations - Integrations configuration to validate
160
139
  */
161
140
  const validateIntegrations = (integrations) => {
162
- if (!integrations)
141
+ if (!integrations) {
163
142
  return;
143
+ }
144
+ if (integrations.tracelog) {
145
+ if (!integrations.tracelog.projectId ||
146
+ typeof integrations.tracelog.projectId !== 'string' ||
147
+ integrations.tracelog.projectId.trim() === '') {
148
+ throw new validation_error_types_1.IntegrationValidationError(constants_1.VALIDATION_MESSAGES.INVALID_TRACELOG_PROJECT_ID, 'config');
149
+ }
150
+ }
151
+ if (integrations.custom) {
152
+ if (!integrations.custom.apiUrl ||
153
+ typeof integrations.custom.apiUrl !== 'string' ||
154
+ integrations.custom.apiUrl.trim() === '') {
155
+ throw new validation_error_types_1.IntegrationValidationError(constants_1.VALIDATION_MESSAGES.INVALID_CUSTOM_API_URL, 'config');
156
+ }
157
+ if (!integrations.custom.apiUrl.startsWith('http')) {
158
+ throw new validation_error_types_1.IntegrationValidationError('Custom API URL must start with "http"', 'config');
159
+ }
160
+ }
164
161
  if (integrations.googleAnalytics) {
165
162
  if (!integrations.googleAnalytics.measurementId ||
166
163
  typeof integrations.googleAnalytics.measurementId !== 'string' ||
167
164
  integrations.googleAnalytics.measurementId.trim() === '') {
168
- logging_1.debugLog.clientError('ConfigValidation', 'Invalid Google Analytics measurement ID', {
169
- provided: integrations.googleAnalytics.measurementId,
170
- type: typeof integrations.googleAnalytics.measurementId,
171
- });
172
165
  throw new validation_error_types_1.IntegrationValidationError(constants_1.VALIDATION_MESSAGES.INVALID_GOOGLE_ANALYTICS_ID, 'config');
173
166
  }
174
167
  const measurementId = integrations.googleAnalytics.measurementId.trim();
175
168
  if (!measurementId.match(/^(G-|UA-)/)) {
176
- logging_1.debugLog.clientError('ConfigValidation', 'Google Analytics measurement ID must start with "G-" or "UA-"', {
177
- provided: measurementId,
178
- });
179
169
  throw new validation_error_types_1.IntegrationValidationError('Google Analytics measurement ID must start with "G-" or "UA-"', 'config');
180
170
  }
181
171
  }
@@ -189,52 +179,16 @@ const validateIntegrations = (integrations) => {
189
179
  * @throws {AppConfigValidationError} If other configuration validation fails
190
180
  */
191
181
  const validateAndNormalizeConfig = (config) => {
192
- // First validate the structure and basic types
193
182
  (0, exports.validateAppConfig)(config);
194
- // Normalize string values
195
183
  const normalizedConfig = {
196
184
  ...config,
197
- id: config.id.trim(),
185
+ sessionTimeout: config.sessionTimeout ?? constants_1.DEFAULT_SESSION_TIMEOUT,
198
186
  globalMetadata: config.globalMetadata ?? {},
199
187
  sensitiveQueryParams: config.sensitiveQueryParams ?? [],
188
+ errorSampling: config.errorSampling ?? 1,
189
+ samplingRate: config.samplingRate ?? 1,
190
+ allowHttp: config.allowHttp ?? false,
200
191
  };
201
- // Validate normalized values - this catches whitespace-only IDs
202
- if (!normalizedConfig.id) {
203
- logging_1.debugLog.clientError('ConfigValidation', 'Project ID is empty after trimming whitespace', {
204
- originalId: config.id,
205
- normalizedId: normalizedConfig.id,
206
- });
207
- throw new validation_error_types_1.ProjectIdValidationError(constants_1.VALIDATION_MESSAGES.PROJECT_ID_EMPTY_AFTER_TRIM, 'config');
208
- }
209
192
  return normalizedConfig;
210
193
  };
211
194
  exports.validateAndNormalizeConfig = validateAndNormalizeConfig;
212
- /**
213
- * Type guard to check if a JSON response is a valid API config
214
- * @param json - The JSON to validate
215
- * @returns True if the JSON is a valid API config
216
- */
217
- const isValidConfigApiResponse = (json) => {
218
- try {
219
- if (typeof json !== 'object' || !json) {
220
- return false;
221
- }
222
- const response = json;
223
- const result = {
224
- mode: response['mode'] === undefined || [types_1.Mode.QA, types_1.Mode.DEBUG].includes(response['mode']),
225
- // Zero is valid for samplingRate (means "sample nothing")
226
- samplingRate: response['samplingRate'] === undefined ||
227
- (typeof response['samplingRate'] === 'number' &&
228
- response['samplingRate'] >= 0 &&
229
- response['samplingRate'] <= 1),
230
- tags: response['tags'] === undefined || Array.isArray(response['tags']),
231
- excludedUrlPaths: response['excludedUrlPaths'] === undefined || Array.isArray(response['excludedUrlPaths']),
232
- ipExcluded: response['ipExcluded'] === undefined || typeof response['ipExcluded'] === 'boolean',
233
- };
234
- return Object.values(result).every(Boolean);
235
- }
236
- catch {
237
- return false;
238
- }
239
- };
240
- exports.isValidConfigApiResponse = isValidConfigApiResponse;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isEventValid = void 0;
4
+ const logging_utils_1 = require("../logging.utils");
4
5
  const metadata_validations_utils_1 = require("./metadata-validations.utils");
5
- const logging_1 = require("../logging");
6
6
  /**
7
7
  * Validates a complete event with name and optional metadata
8
8
  * @param eventName - The event name to validate
@@ -12,7 +12,10 @@ const logging_1 = require("../logging");
12
12
  const isEventValid = (eventName, metadata) => {
13
13
  const nameValidation = (0, metadata_validations_utils_1.isValidEventName)(eventName);
14
14
  if (!nameValidation.valid) {
15
- logging_1.debugLog.clientError('EventValidation', 'Event name validation failed', { eventName, error: nameValidation.error });
15
+ (0, logging_utils_1.log)('error', 'Event name validation failed', {
16
+ showToClient: true,
17
+ data: { eventName, error: nameValidation.error },
18
+ });
16
19
  return nameValidation;
17
20
  }
18
21
  if (!metadata) {
@@ -20,9 +23,12 @@ const isEventValid = (eventName, metadata) => {
20
23
  }
21
24
  const metadataValidation = (0, metadata_validations_utils_1.isValidMetadata)(eventName, metadata, 'customEvent');
22
25
  if (!metadataValidation.valid) {
23
- logging_1.debugLog.clientError('EventValidation', 'Event metadata validation failed', {
24
- eventName,
25
- error: metadataValidation.error,
26
+ (0, logging_utils_1.log)('error', 'Event metadata validation failed', {
27
+ showToClient: true,
28
+ data: {
29
+ eventName,
30
+ error: metadataValidation.error,
31
+ },
26
32
  });
27
33
  }
28
34
  return metadataValidation;
@@ -2,4 +2,3 @@ export * from './config-validations.utils';
2
2
  export * from './event-validations.utils';
3
3
  export * from './metadata-validations.utils';
4
4
  export * from './type-guards.utils';
5
- export * from './url-validations.utils';
@@ -18,4 +18,3 @@ __exportStar(require("./config-validations.utils"), exports);
18
18
  __exportStar(require("./event-validations.utils"), exports);
19
19
  __exportStar(require("./metadata-validations.utils"), exports);
20
20
  __exportStar(require("./type-guards.utils"), exports);
21
- __exportStar(require("./url-validations.utils"), exports);
@@ -142,7 +142,6 @@ const isValidMetadata = (eventName, metadata, type) => {
142
142
  sanitizedArray.push(itemValidation.sanitizedMetadata);
143
143
  }
144
144
  }
145
- // Allow empty arrays after sanitization
146
145
  return {
147
146
  valid: true,
148
147
  sanitizedMetadata: sanitizedArray,
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Checks if an object contains only primitive fields (string, number, boolean, or string arrays)
2
+ * Checks if an object contains only primitive fields, string arrays, or arrays of flat objects
3
3
  * @param object - The object to check
4
- * @returns True if the object contains only primitive fields
4
+ * @returns True if the object contains only valid fields
5
5
  */
6
6
  export declare const isOnlyPrimitiveFields: (object: Record<string, unknown>) => boolean;