@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.
- package/README.md +157 -180
- package/dist/browser/tracelog.esm.js +1007 -1357
- package/dist/browser/tracelog.js +2 -2
- package/dist/cjs/api.d.ts +12 -2
- package/dist/cjs/api.js +63 -27
- package/dist/cjs/app.d.ts +2 -2
- package/dist/cjs/app.js +26 -32
- package/dist/cjs/constants/config.constants.d.ts +4 -2
- package/dist/cjs/constants/config.constants.js +6 -18
- package/dist/cjs/constants/index.d.ts +0 -1
- package/dist/cjs/constants/index.js +0 -1
- package/dist/cjs/constants/storage.constants.d.ts +3 -2
- package/dist/cjs/constants/storage.constants.js +4 -4
- package/dist/cjs/handlers/click.handler.js +3 -6
- package/dist/cjs/handlers/error.handler.js +1 -11
- package/dist/cjs/handlers/page-view.handler.js +0 -4
- package/dist/cjs/handlers/performance.handler.js +14 -29
- package/dist/cjs/handlers/scroll.handler.js +7 -6
- package/dist/cjs/handlers/session.handler.js +7 -6
- package/dist/cjs/integrations/google-analytics.integration.js +2 -6
- package/dist/cjs/listeners/activity-listener-manager.js +3 -3
- package/dist/cjs/listeners/input-listener-managers.js +3 -3
- package/dist/cjs/listeners/touch-listener-manager.js +3 -3
- package/dist/cjs/listeners/unload-listener-manager.js +3 -3
- package/dist/cjs/listeners/visibility-listener-manager.js +3 -3
- package/dist/cjs/managers/event.manager.d.ts +2 -1
- package/dist/cjs/managers/event.manager.js +60 -38
- package/dist/cjs/managers/sender.manager.js +29 -36
- package/dist/cjs/managers/session.manager.js +5 -13
- package/dist/cjs/managers/state.manager.d.ts +0 -3
- package/dist/cjs/managers/state.manager.js +1 -43
- package/dist/cjs/managers/storage.manager.d.ts +16 -2
- package/dist/cjs/managers/storage.manager.js +73 -19
- package/dist/cjs/managers/user.manager.d.ts +1 -1
- package/dist/cjs/managers/user.manager.js +2 -2
- package/dist/cjs/public-api.d.ts +3 -3
- package/dist/cjs/public-api.js +1 -1
- package/dist/cjs/test-bridge.d.ts +1 -0
- package/dist/cjs/test-bridge.js +37 -2
- package/dist/cjs/types/config.types.d.ts +15 -18
- package/dist/cjs/types/config.types.js +6 -0
- package/dist/cjs/types/event.types.d.ts +1 -13
- package/dist/cjs/types/index.d.ts +0 -2
- package/dist/cjs/types/index.js +0 -2
- package/dist/cjs/types/mode.types.d.ts +1 -2
- package/dist/cjs/types/mode.types.js +0 -1
- package/dist/cjs/types/queue.types.d.ts +0 -6
- package/dist/cjs/types/state.types.d.ts +2 -0
- package/dist/cjs/types/test-bridge.types.d.ts +2 -2
- package/dist/cjs/types/validation-error.types.d.ts +0 -6
- package/dist/cjs/types/validation-error.types.js +1 -10
- package/dist/cjs/utils/browser/device-detector.utils.js +2 -24
- package/dist/cjs/utils/browser/index.d.ts +1 -0
- package/dist/cjs/utils/browser/index.js +1 -0
- package/dist/cjs/utils/browser/qa-mode.utils.d.ts +13 -0
- package/dist/cjs/utils/browser/qa-mode.utils.js +43 -0
- package/dist/cjs/utils/browser/utm-params.utils.js +0 -15
- package/dist/cjs/utils/data/uuid.utils.d.ts +13 -0
- package/dist/cjs/utils/data/uuid.utils.js +37 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/utils/index.js +1 -1
- package/dist/cjs/utils/logging.utils.d.ts +6 -0
- package/dist/cjs/utils/logging.utils.js +25 -0
- package/dist/cjs/utils/network/index.d.ts +0 -1
- package/dist/cjs/utils/network/index.js +0 -1
- package/dist/cjs/utils/network/url.utils.d.ts +2 -8
- package/dist/cjs/utils/network/url.utils.js +46 -90
- package/dist/cjs/utils/security/sanitize.utils.d.ts +1 -13
- package/dist/cjs/utils/security/sanitize.utils.js +15 -178
- package/dist/cjs/utils/validations/config-validations.utils.d.ts +3 -9
- package/dist/cjs/utils/validations/config-validations.utils.js +48 -94
- package/dist/cjs/utils/validations/event-validations.utils.js +11 -5
- package/dist/cjs/utils/validations/index.d.ts +0 -1
- package/dist/cjs/utils/validations/index.js +0 -1
- package/dist/cjs/utils/validations/metadata-validations.utils.js +0 -1
- package/dist/cjs/utils/validations/type-guards.utils.d.ts +2 -2
- package/dist/cjs/utils/validations/type-guards.utils.js +50 -4
- package/dist/esm/api.d.ts +12 -2
- package/dist/esm/api.js +62 -27
- package/dist/esm/app.d.ts +2 -2
- package/dist/esm/app.js +28 -34
- package/dist/esm/constants/config.constants.d.ts +4 -2
- package/dist/esm/constants/config.constants.js +4 -16
- package/dist/esm/constants/index.d.ts +0 -1
- package/dist/esm/constants/index.js +0 -1
- package/dist/esm/constants/storage.constants.d.ts +3 -2
- package/dist/esm/constants/storage.constants.js +3 -2
- package/dist/esm/handlers/click.handler.js +3 -6
- package/dist/esm/handlers/error.handler.js +1 -11
- package/dist/esm/handlers/page-view.handler.js +0 -4
- package/dist/esm/handlers/performance.handler.js +14 -29
- package/dist/esm/handlers/scroll.handler.js +7 -6
- package/dist/esm/handlers/session.handler.js +7 -6
- package/dist/esm/integrations/google-analytics.integration.js +3 -7
- package/dist/esm/listeners/activity-listener-manager.js +3 -3
- package/dist/esm/listeners/input-listener-managers.js +3 -3
- package/dist/esm/listeners/touch-listener-manager.js +3 -3
- package/dist/esm/listeners/unload-listener-manager.js +3 -3
- package/dist/esm/listeners/visibility-listener-manager.js +3 -3
- package/dist/esm/managers/event.manager.d.ts +2 -1
- package/dist/esm/managers/event.manager.js +62 -40
- package/dist/esm/managers/sender.manager.js +31 -38
- package/dist/esm/managers/session.manager.js +5 -13
- package/dist/esm/managers/state.manager.d.ts +0 -3
- package/dist/esm/managers/state.manager.js +1 -43
- package/dist/esm/managers/storage.manager.d.ts +16 -2
- package/dist/esm/managers/storage.manager.js +73 -19
- package/dist/esm/managers/user.manager.d.ts +1 -1
- package/dist/esm/managers/user.manager.js +2 -2
- package/dist/esm/public-api.d.ts +3 -3
- package/dist/esm/public-api.js +1 -1
- package/dist/esm/test-bridge.d.ts +1 -0
- package/dist/esm/test-bridge.js +37 -2
- package/dist/esm/types/config.types.d.ts +15 -18
- package/dist/esm/types/config.types.js +5 -1
- package/dist/esm/types/event.types.d.ts +1 -13
- package/dist/esm/types/index.d.ts +0 -2
- package/dist/esm/types/index.js +0 -2
- package/dist/esm/types/mode.types.d.ts +1 -2
- package/dist/esm/types/mode.types.js +0 -1
- package/dist/esm/types/queue.types.d.ts +0 -6
- package/dist/esm/types/state.types.d.ts +2 -0
- package/dist/esm/types/test-bridge.types.d.ts +2 -2
- package/dist/esm/types/validation-error.types.d.ts +0 -6
- package/dist/esm/types/validation-error.types.js +0 -8
- package/dist/esm/utils/browser/device-detector.utils.js +2 -24
- package/dist/esm/utils/browser/index.d.ts +1 -0
- package/dist/esm/utils/browser/index.js +1 -0
- package/dist/esm/utils/browser/qa-mode.utils.d.ts +13 -0
- package/dist/esm/utils/browser/qa-mode.utils.js +39 -0
- package/dist/esm/utils/browser/utm-params.utils.js +0 -15
- package/dist/esm/utils/data/uuid.utils.d.ts +13 -0
- package/dist/esm/utils/data/uuid.utils.js +35 -0
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/logging.utils.d.ts +6 -0
- package/dist/esm/utils/logging.utils.js +20 -0
- package/dist/esm/utils/network/index.d.ts +0 -1
- package/dist/esm/utils/network/index.js +0 -1
- package/dist/esm/utils/network/url.utils.d.ts +2 -8
- package/dist/esm/utils/network/url.utils.js +45 -88
- package/dist/esm/utils/security/sanitize.utils.d.ts +1 -13
- package/dist/esm/utils/security/sanitize.utils.js +15 -176
- package/dist/esm/utils/validations/config-validations.utils.d.ts +3 -9
- package/dist/esm/utils/validations/config-validations.utils.js +49 -94
- package/dist/esm/utils/validations/event-validations.utils.js +11 -5
- package/dist/esm/utils/validations/index.d.ts +0 -1
- package/dist/esm/utils/validations/index.js +0 -1
- package/dist/esm/utils/validations/metadata-validations.utils.js +0 -1
- package/dist/esm/utils/validations/type-guards.utils.d.ts +2 -2
- package/dist/esm/utils/validations/type-guards.utils.js +50 -4
- package/package.json +1 -1
- package/dist/cjs/app.types.d.ts +0 -2
- package/dist/cjs/app.types.js +0 -12
- package/dist/cjs/constants/api.constants.d.ts +0 -6
- package/dist/cjs/constants/api.constants.js +0 -14
- package/dist/cjs/managers/api.manager.d.ts +0 -13
- package/dist/cjs/managers/api.manager.js +0 -44
- package/dist/cjs/managers/config.builder.d.ts +0 -33
- package/dist/cjs/managers/config.builder.js +0 -116
- package/dist/cjs/managers/config.manager.d.ts +0 -56
- package/dist/cjs/managers/config.manager.js +0 -157
- package/dist/cjs/managers/tags.manager.d.ts +0 -36
- package/dist/cjs/managers/tags.manager.js +0 -171
- package/dist/cjs/types/api.types.d.ts +0 -52
- package/dist/cjs/types/api.types.js +0 -56
- package/dist/cjs/types/tag.types.d.ts +0 -43
- package/dist/cjs/types/tag.types.js +0 -31
- package/dist/cjs/utils/logging/debug-logger.utils.d.ts +0 -14
- package/dist/cjs/utils/logging/debug-logger.utils.js +0 -47
- package/dist/cjs/utils/logging/index.d.ts +0 -1
- package/dist/cjs/utils/logging/index.js +0 -5
- package/dist/cjs/utils/network/fetch-with-timeout.utils.d.ts +0 -4
- package/dist/cjs/utils/network/fetch-with-timeout.utils.js +0 -25
- package/dist/cjs/utils/validations/url-validations.utils.d.ts +0 -15
- package/dist/cjs/utils/validations/url-validations.utils.js +0 -47
- package/dist/esm/app.types.d.ts +0 -2
- package/dist/esm/app.types.js +0 -1
- package/dist/esm/constants/api.constants.d.ts +0 -6
- package/dist/esm/constants/api.constants.js +0 -11
- package/dist/esm/managers/api.manager.d.ts +0 -13
- package/dist/esm/managers/api.manager.js +0 -41
- package/dist/esm/managers/config.builder.d.ts +0 -33
- package/dist/esm/managers/config.builder.js +0 -112
- package/dist/esm/managers/config.manager.d.ts +0 -56
- package/dist/esm/managers/config.manager.js +0 -153
- package/dist/esm/managers/tags.manager.d.ts +0 -36
- package/dist/esm/managers/tags.manager.js +0 -167
- package/dist/esm/types/api.types.d.ts +0 -52
- package/dist/esm/types/api.types.js +0 -53
- package/dist/esm/types/tag.types.d.ts +0 -43
- package/dist/esm/types/tag.types.js +0 -28
- package/dist/esm/utils/logging/debug-logger.utils.d.ts +0 -14
- package/dist/esm/utils/logging/debug-logger.utils.js +0 -44
- package/dist/esm/utils/logging/index.d.ts +0 -1
- package/dist/esm/utils/logging/index.js +0 -1
- package/dist/esm/utils/network/fetch-with-timeout.utils.d.ts +0 -4
- package/dist/esm/utils/network/fetch-with-timeout.utils.js +0 -22
- package/dist/esm/utils/validations/url-validations.utils.d.ts +0 -15
- 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.
|
|
3
|
+
exports.sanitizeMetadata = exports.sanitizeString = void 0;
|
|
4
4
|
const constants_1 = require("../../constants");
|
|
5
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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('<', '<')
|
|
81
|
-
.replaceAll('>', '>')
|
|
82
|
-
.replaceAll('"', '"')
|
|
83
|
-
.replaceAll("'", ''');
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
280
|
-
|
|
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 {
|
|
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:
|
|
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:
|
|
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.
|
|
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
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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;
|
|
@@ -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);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Checks if an object contains only primitive fields
|
|
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
|
|
4
|
+
* @returns True if the object contains only valid fields
|
|
5
5
|
*/
|
|
6
6
|
export declare const isOnlyPrimitiveFields: (object: Record<string, unknown>) => boolean;
|