observability-toolkit 1.6.0 → 1.8.2
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 +221 -91
- package/dist/backends/index.d.ts +146 -0
- package/dist/backends/index.d.ts.map +1 -1
- package/dist/backends/index.js +65 -1
- package/dist/backends/index.js.map +1 -1
- package/dist/backends/local-jsonl-boolean-search.test.js +1 -23
- package/dist/backends/local-jsonl-boolean-search.test.js.map +1 -1
- package/dist/backends/local-jsonl.d.ts +4 -1
- package/dist/backends/local-jsonl.d.ts.map +1 -1
- package/dist/backends/local-jsonl.js +216 -6
- package/dist/backends/local-jsonl.js.map +1 -1
- package/dist/backends/local-jsonl.test.js +715 -26
- package/dist/backends/local-jsonl.test.js.map +1 -1
- package/dist/backends/signoz-api.d.ts +32 -0
- package/dist/backends/signoz-api.d.ts.map +1 -1
- package/dist/backends/signoz-api.js +237 -33
- package/dist/backends/signoz-api.js.map +1 -1
- package/dist/backends/signoz-api.test.js +410 -63
- package/dist/backends/signoz-api.test.js.map +1 -1
- package/dist/lib/constants.d.ts +16 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +121 -5
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/constants.test.js +202 -15
- package/dist/lib/constants.test.js.map +1 -1
- package/dist/lib/error-sanitizer.d.ts +57 -0
- package/dist/lib/error-sanitizer.d.ts.map +1 -0
- package/dist/lib/error-sanitizer.js +197 -0
- package/dist/lib/error-sanitizer.js.map +1 -0
- package/dist/lib/error-sanitizer.test.d.ts +8 -0
- package/dist/lib/error-sanitizer.test.d.ts.map +1 -0
- package/dist/lib/error-sanitizer.test.js +342 -0
- package/dist/lib/error-sanitizer.test.js.map +1 -0
- package/dist/lib/file-utils.d.ts +210 -0
- package/dist/lib/file-utils.d.ts.map +1 -1
- package/dist/lib/file-utils.js +529 -14
- package/dist/lib/file-utils.js.map +1 -1
- package/dist/lib/file-utils.test.js +657 -3
- package/dist/lib/file-utils.test.js.map +1 -1
- package/dist/lib/indexer.d.ts +19 -1
- package/dist/lib/indexer.d.ts.map +1 -1
- package/dist/lib/indexer.js +84 -8
- package/dist/lib/indexer.js.map +1 -1
- package/dist/lib/indexer.test.js +187 -16
- package/dist/lib/indexer.test.js.map +1 -1
- package/dist/lib/input-validator.d.ts +98 -0
- package/dist/lib/input-validator.d.ts.map +1 -0
- package/dist/lib/input-validator.js +245 -0
- package/dist/lib/input-validator.js.map +1 -0
- package/dist/lib/input-validator.test.d.ts +2 -0
- package/dist/lib/input-validator.test.d.ts.map +1 -0
- package/dist/lib/input-validator.test.js +287 -0
- package/dist/lib/input-validator.test.js.map +1 -0
- package/dist/lib/query-sanitizer.d.ts +95 -0
- package/dist/lib/query-sanitizer.d.ts.map +1 -0
- package/dist/lib/query-sanitizer.js +187 -0
- package/dist/lib/query-sanitizer.js.map +1 -0
- package/dist/lib/query-sanitizer.test.d.ts +5 -0
- package/dist/lib/query-sanitizer.test.d.ts.map +1 -0
- package/dist/lib/query-sanitizer.test.js +299 -0
- package/dist/lib/query-sanitizer.test.js.map +1 -0
- package/dist/server.d.ts +49 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +97 -13
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +202 -0
- package/dist/server.test.js.map +1 -1
- package/dist/test-helpers/file-utils.d.ts +26 -0
- package/dist/test-helpers/file-utils.d.ts.map +1 -0
- package/dist/test-helpers/file-utils.js +43 -0
- package/dist/test-helpers/file-utils.js.map +1 -0
- package/dist/test-helpers/mock-backends.d.ts +28 -0
- package/dist/test-helpers/mock-backends.d.ts.map +1 -0
- package/dist/test-helpers/mock-backends.js +31 -0
- package/dist/test-helpers/mock-backends.js.map +1 -0
- package/dist/tools/health-check.js +1 -1
- package/dist/tools/health-check.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/query-evaluations.d.ts +183 -0
- package/dist/tools/query-evaluations.d.ts.map +1 -0
- package/dist/tools/query-evaluations.js +351 -0
- package/dist/tools/query-evaluations.js.map +1 -0
- package/dist/tools/query-evaluations.test.d.ts +5 -0
- package/dist/tools/query-evaluations.test.d.ts.map +1 -0
- package/dist/tools/query-evaluations.test.js +743 -0
- package/dist/tools/query-evaluations.test.js.map +1 -0
- package/dist/tools/query-llm-events.d.ts +62 -11
- package/dist/tools/query-llm-events.d.ts.map +1 -1
- package/dist/tools/query-llm-events.js +97 -37
- package/dist/tools/query-llm-events.js.map +1 -1
- package/dist/tools/query-llm-events.test.js +253 -0
- package/dist/tools/query-llm-events.test.js.map +1 -1
- package/dist/tools/query-logs.d.ts +32 -18
- package/dist/tools/query-logs.d.ts.map +1 -1
- package/dist/tools/query-logs.js +77 -44
- package/dist/tools/query-logs.js.map +1 -1
- package/dist/tools/query-logs.test.js +226 -64
- package/dist/tools/query-logs.test.js.map +1 -1
- package/dist/tools/query-metrics.d.ts +24 -24
- package/dist/tools/query-metrics.d.ts.map +1 -1
- package/dist/tools/query-metrics.js +102 -54
- package/dist/tools/query-metrics.js.map +1 -1
- package/dist/tools/query-metrics.test.js +35 -36
- package/dist/tools/query-metrics.test.js.map +1 -1
- package/dist/tools/query-traces.d.ts +66 -22
- package/dist/tools/query-traces.d.ts.map +1 -1
- package/dist/tools/query-traces.js +86 -42
- package/dist/tools/query-traces.js.map +1 -1
- package/dist/tools/query-traces.test.js +458 -36
- package/dist/tools/query-traces.test.js.map +1 -1
- package/package.json +1 -3
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input validation utilities for observability-toolkit MCP server
|
|
3
|
+
*
|
|
4
|
+
* Enforces strict limits on user inputs to prevent:
|
|
5
|
+
* - Resource exhaustion (unbounded queries)
|
|
6
|
+
* - Regex denial of service (ReDoS)
|
|
7
|
+
* - Invalid date ranges
|
|
8
|
+
*/
|
|
9
|
+
// Validation constants
|
|
10
|
+
export const MAX_LIMIT = 1000;
|
|
11
|
+
export const MAX_DATE_RANGE_DAYS = 365;
|
|
12
|
+
export const MAX_REGEX_LENGTH = 200;
|
|
13
|
+
export const MAX_REGEX_GROUPS = 10;
|
|
14
|
+
export const DEFAULT_LIMIT = 50;
|
|
15
|
+
export const MAX_DURATION_MS = 86400000; // 24 hours
|
|
16
|
+
/**
|
|
17
|
+
* Custom error class for input validation failures.
|
|
18
|
+
* Provides structured error information for user-friendly error responses.
|
|
19
|
+
*/
|
|
20
|
+
export class InputValidationError extends Error {
|
|
21
|
+
/** Field that failed validation */
|
|
22
|
+
field;
|
|
23
|
+
/** Constraint that was violated */
|
|
24
|
+
constraint;
|
|
25
|
+
constructor(message, field, constraint) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = 'InputValidationError';
|
|
28
|
+
this.field = field;
|
|
29
|
+
this.constraint = constraint;
|
|
30
|
+
// Maintain proper stack trace in V8 environments
|
|
31
|
+
if (Error.captureStackTrace) {
|
|
32
|
+
Error.captureStackTrace(this, InputValidationError);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validate and clamp the limit parameter.
|
|
38
|
+
*
|
|
39
|
+
* @param limit - User-provided limit (undefined uses default)
|
|
40
|
+
* @returns Clamped limit between 1 and MAX_LIMIT
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* validateLimit(undefined) // returns 50 (default)
|
|
44
|
+
* validateLimit(5000) // returns 1000 (clamped to max)
|
|
45
|
+
* validateLimit(0) // returns 1 (minimum)
|
|
46
|
+
* validateLimit(-10) // returns 1 (minimum)
|
|
47
|
+
*/
|
|
48
|
+
export function validateLimit(limit) {
|
|
49
|
+
if (limit === undefined || limit === null) {
|
|
50
|
+
return DEFAULT_LIMIT;
|
|
51
|
+
}
|
|
52
|
+
// Clamp to valid range [1, MAX_LIMIT]
|
|
53
|
+
return Math.max(1, Math.min(limit, MAX_LIMIT));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Validate and clamp duration parameters.
|
|
57
|
+
*
|
|
58
|
+
* @param duration - User-provided duration in milliseconds (undefined passes through)
|
|
59
|
+
* @param field - Field name for error messages ('minDurationMs' or 'maxDurationMs')
|
|
60
|
+
* @returns Clamped duration between 0 and MAX_DURATION_MS, or undefined if not provided
|
|
61
|
+
* @throws InputValidationError if duration is negative
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* validateDuration(undefined, 'minDurationMs') // returns undefined
|
|
65
|
+
* validateDuration(5000, 'minDurationMs') // returns 5000
|
|
66
|
+
* validateDuration(100000000, 'maxDurationMs') // returns 86400000 (clamped to max)
|
|
67
|
+
* validateDuration(-10, 'minDurationMs') // throws: negative duration
|
|
68
|
+
*/
|
|
69
|
+
export function validateDuration(duration, field) {
|
|
70
|
+
if (duration === undefined || duration === null) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
// Reject negative values
|
|
74
|
+
if (duration < 0) {
|
|
75
|
+
throw new InputValidationError(`${field} cannot be negative: ${duration}`, field, 'range');
|
|
76
|
+
}
|
|
77
|
+
// Clamp to MAX_DURATION_MS
|
|
78
|
+
return Math.min(duration, MAX_DURATION_MS);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Parse a date string in YYYY-MM-DD format.
|
|
82
|
+
* Returns null if the format is invalid.
|
|
83
|
+
*/
|
|
84
|
+
function parseDateString(dateStr) {
|
|
85
|
+
const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
86
|
+
if (!match) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const year = parseInt(match[1], 10);
|
|
90
|
+
const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed
|
|
91
|
+
const day = parseInt(match[3], 10);
|
|
92
|
+
// Validate date components
|
|
93
|
+
if (month < 0 || month > 11 || day < 1 || day > 31) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const date = new Date(year, month, day);
|
|
97
|
+
// Check for date overflow (e.g., Feb 30 becomes Mar 2)
|
|
98
|
+
if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return date;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Validate date range parameters.
|
|
105
|
+
*
|
|
106
|
+
* Validates:
|
|
107
|
+
* - Date format (YYYY-MM-DD)
|
|
108
|
+
* - startDate is not after endDate
|
|
109
|
+
* - Range does not exceed MAX_DATE_RANGE_DAYS
|
|
110
|
+
*
|
|
111
|
+
* @param startDate - Optional start date string (YYYY-MM-DD)
|
|
112
|
+
* @param endDate - Optional end date string (YYYY-MM-DD)
|
|
113
|
+
* @returns Parsed Date objects for start and end
|
|
114
|
+
* @throws InputValidationError if validation fails
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* validateDateRange('2024-01-01', '2024-01-31') // valid
|
|
118
|
+
* validateDateRange(undefined, undefined) // defaults to today
|
|
119
|
+
* validateDateRange('2024-01-15', '2024-01-01') // throws: start after end
|
|
120
|
+
*/
|
|
121
|
+
export function validateDateRange(startDate, endDate) {
|
|
122
|
+
const now = new Date();
|
|
123
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
124
|
+
// Parse end date first (used for default start calculation)
|
|
125
|
+
let end;
|
|
126
|
+
if (endDate) {
|
|
127
|
+
const parsed = parseDateString(endDate);
|
|
128
|
+
if (!parsed) {
|
|
129
|
+
throw new InputValidationError(`Invalid endDate format: "${endDate}". Expected YYYY-MM-DD.`, 'endDate', 'format');
|
|
130
|
+
}
|
|
131
|
+
end = parsed;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Default to today
|
|
135
|
+
end = today;
|
|
136
|
+
}
|
|
137
|
+
// Parse start date
|
|
138
|
+
let start;
|
|
139
|
+
if (startDate) {
|
|
140
|
+
const parsed = parseDateString(startDate);
|
|
141
|
+
if (!parsed) {
|
|
142
|
+
throw new InputValidationError(`Invalid startDate format: "${startDate}". Expected YYYY-MM-DD.`, 'startDate', 'format');
|
|
143
|
+
}
|
|
144
|
+
start = parsed;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Default to MAX_DATE_RANGE_DAYS before end date (to ensure valid range)
|
|
148
|
+
start = new Date(end.getTime() - MAX_DATE_RANGE_DAYS * 24 * 60 * 60 * 1000);
|
|
149
|
+
}
|
|
150
|
+
// Validate start is not after end
|
|
151
|
+
if (start > end) {
|
|
152
|
+
throw new InputValidationError(`startDate (${startDate || start.toISOString().split('T')[0]}) cannot be after endDate (${endDate || end.toISOString().split('T')[0]}).`, 'startDate', 'range');
|
|
153
|
+
}
|
|
154
|
+
// Validate range does not exceed maximum (only when both are explicitly provided)
|
|
155
|
+
if (startDate && endDate) {
|
|
156
|
+
const rangeDays = Math.ceil((end.getTime() - start.getTime()) / (24 * 60 * 60 * 1000));
|
|
157
|
+
if (rangeDays > MAX_DATE_RANGE_DAYS) {
|
|
158
|
+
throw new InputValidationError(`Date range of ${rangeDays} days exceeds maximum of ${MAX_DATE_RANGE_DAYS} days.`, 'dateRange', 'maxRange');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return { start, end };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Count the number of capture groups in a regex pattern.
|
|
165
|
+
* Handles escaped parentheses and non-capturing groups.
|
|
166
|
+
*/
|
|
167
|
+
function countRegexGroups(pattern) {
|
|
168
|
+
let count = 0;
|
|
169
|
+
let escaped = false;
|
|
170
|
+
let inCharClass = false;
|
|
171
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
172
|
+
const char = pattern[i];
|
|
173
|
+
if (escaped) {
|
|
174
|
+
escaped = false;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (char === '\\') {
|
|
178
|
+
escaped = true;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (char === '[') {
|
|
182
|
+
inCharClass = true;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (char === ']' && inCharClass) {
|
|
186
|
+
inCharClass = false;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (inCharClass) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
// Check for opening parenthesis that starts a capturing group
|
|
193
|
+
if (char === '(') {
|
|
194
|
+
// Look ahead to check for non-capturing group (?:, (?=, (?!, (?<= etc.
|
|
195
|
+
const next = pattern[i + 1];
|
|
196
|
+
if (next !== '?') {
|
|
197
|
+
count++;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return count;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Validate a regex pattern for safety and correctness.
|
|
205
|
+
*
|
|
206
|
+
* Validates:
|
|
207
|
+
* - Pattern length does not exceed MAX_REGEX_LENGTH
|
|
208
|
+
* - Number of capture groups does not exceed MAX_REGEX_GROUPS
|
|
209
|
+
* - Pattern compiles successfully
|
|
210
|
+
*
|
|
211
|
+
* @param pattern - Regex pattern string to validate
|
|
212
|
+
* @throws InputValidationError if validation fails
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* validateRegexPattern('error.*timeout') // valid
|
|
216
|
+
* validateRegexPattern('(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)') // throws: too many groups
|
|
217
|
+
* validateRegexPattern('[invalid') // throws: invalid syntax
|
|
218
|
+
*/
|
|
219
|
+
export function validateRegexPattern(pattern) {
|
|
220
|
+
// Validate length
|
|
221
|
+
if (pattern.length > MAX_REGEX_LENGTH) {
|
|
222
|
+
throw new InputValidationError(`Pattern length of ${pattern.length} exceeds maximum of ${MAX_REGEX_LENGTH} characters.`, 'pattern', 'maxLength');
|
|
223
|
+
}
|
|
224
|
+
// Count capture groups before attempting compilation
|
|
225
|
+
const groupCount = countRegexGroups(pattern);
|
|
226
|
+
if (groupCount > MAX_REGEX_GROUPS) {
|
|
227
|
+
throw new InputValidationError(`Pattern has ${groupCount} capture groups, exceeding maximum of ${MAX_REGEX_GROUPS}.`, 'pattern', 'maxGroups');
|
|
228
|
+
}
|
|
229
|
+
// Attempt compilation to check syntax
|
|
230
|
+
try {
|
|
231
|
+
new RegExp(pattern);
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
235
|
+
throw new InputValidationError(`Invalid regex pattern: ${message}`, 'pattern', 'syntax');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Helper to check if an error is an InputValidationError.
|
|
240
|
+
* Useful for catch blocks.
|
|
241
|
+
*/
|
|
242
|
+
export function isInputValidationError(error) {
|
|
243
|
+
return error instanceof InputValidationError;
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=input-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-validator.js","sourceRoot":"","sources":["../../src/lib/input-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,uBAAuB;AACvB,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC;AAC9B,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAChC,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC,CAAC,WAAW;AAEpD;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,mCAAmC;IAC1B,KAAK,CAAS;IACvB,mCAAmC;IAC1B,UAAU,CAAS;IAE5B,YAAY,OAAe,EAAE,KAAa,EAAE,UAAkB;QAC5D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,iDAAiD;QACjD,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;CACF;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,sCAAsC;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAA4B,EAC5B,KAAwC;IAExC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,yBAAyB;IACzB,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,MAAM,IAAI,oBAAoB,CAC5B,GAAG,KAAK,wBAAwB,QAAQ,EAAE,EAC1C,KAAK,EACL,OAAO,CACR,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,0BAA0B;IACpE,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEnC,2BAA2B;IAC3B,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAExC,uDAAuD;IACvD,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,EAAE,CAAC;QACvF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAkB,EAClB,OAAgB;IAEhB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAEzE,4DAA4D;IAC5D,IAAI,GAAS,CAAC;IACd,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,oBAAoB,CAC5B,4BAA4B,OAAO,yBAAyB,EAC5D,SAAS,EACT,QAAQ,CACT,CAAC;QACJ,CAAC;QACD,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;SAAM,CAAC;QACN,mBAAmB;QACnB,GAAG,GAAG,KAAK,CAAC;IACd,CAAC;IAED,mBAAmB;IACnB,IAAI,KAAW,CAAC;IAChB,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,oBAAoB,CAC5B,8BAA8B,SAAS,yBAAyB,EAChE,WAAW,EACX,QAAQ,CACT,CAAC;QACJ,CAAC;QACD,KAAK,GAAG,MAAM,CAAC;IACjB,CAAC;SAAM,CAAC;QACN,yEAAyE;QACzE,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,mBAAmB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,kCAAkC;IAClC,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;QAChB,MAAM,IAAI,oBAAoB,CAC5B,cAAc,SAAS,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,8BAA8B,OAAO,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EACxI,WAAW,EACX,OAAO,CACR,CAAC;IACJ,CAAC;IAED,kFAAkF;IAClF,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QACvF,IAAI,SAAS,GAAG,mBAAmB,EAAE,CAAC;YACpC,MAAM,IAAI,oBAAoB,CAC5B,iBAAiB,SAAS,4BAA4B,mBAAmB,QAAQ,EACjF,WAAW,EACX,UAAU,CACX,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,WAAW,GAAG,KAAK,CAAC;IAExB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAExB,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,GAAG,IAAI,CAAC;YACf,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,WAAW,GAAG,IAAI,CAAC;YACnB,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC;YAChC,WAAW,GAAG,KAAK,CAAC;YACpB,SAAS;QACX,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,SAAS;QACX,CAAC;QAED,8DAA8D;QAC9D,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,uEAAuE;YACvE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5B,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACjB,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,kBAAkB;IAClB,IAAI,OAAO,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;QACtC,MAAM,IAAI,oBAAoB,CAC5B,qBAAqB,OAAO,CAAC,MAAM,uBAAuB,gBAAgB,cAAc,EACxF,SAAS,EACT,WAAW,CACZ,CAAC;IACJ,CAAC;IAED,qDAAqD;IACrD,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,UAAU,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,IAAI,oBAAoB,CAC5B,eAAe,UAAU,yCAAyC,gBAAgB,GAAG,EACrF,SAAS,EACT,WAAW,CACZ,CAAC;IACJ,CAAC;IAED,sCAAsC;IACtC,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,oBAAoB,CAC5B,0BAA0B,OAAO,EAAE,EACnC,SAAS,EACT,QAAQ,CACT,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,OAAO,KAAK,YAAY,oBAAoB,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-validator.test.d.ts","sourceRoot":"","sources":["../../src/lib/input-validator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { validateLimit, validateDuration, validateDateRange, validateRegexPattern, InputValidationError, isInputValidationError, MAX_LIMIT, MAX_DATE_RANGE_DAYS, MAX_REGEX_LENGTH, MAX_REGEX_GROUPS, DEFAULT_LIMIT, MAX_DURATION_MS, } from './input-validator.js';
|
|
4
|
+
describe('input-validator', () => {
|
|
5
|
+
describe('validateLimit', () => {
|
|
6
|
+
it('should return default limit when undefined', () => {
|
|
7
|
+
const result = validateLimit(undefined);
|
|
8
|
+
assert.strictEqual(result, DEFAULT_LIMIT);
|
|
9
|
+
});
|
|
10
|
+
it('should return default limit when null', () => {
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
const result = validateLimit(null);
|
|
13
|
+
assert.strictEqual(result, DEFAULT_LIMIT);
|
|
14
|
+
});
|
|
15
|
+
it('should return value when within valid range', () => {
|
|
16
|
+
assert.strictEqual(validateLimit(100), 100);
|
|
17
|
+
assert.strictEqual(validateLimit(500), 500);
|
|
18
|
+
assert.strictEqual(validateLimit(1), 1);
|
|
19
|
+
});
|
|
20
|
+
it('should clamp to MAX_LIMIT when value exceeds maximum', () => {
|
|
21
|
+
assert.strictEqual(validateLimit(5000), MAX_LIMIT);
|
|
22
|
+
assert.strictEqual(validateLimit(1001), MAX_LIMIT);
|
|
23
|
+
assert.strictEqual(validateLimit(Number.MAX_SAFE_INTEGER), MAX_LIMIT);
|
|
24
|
+
});
|
|
25
|
+
it('should clamp to 1 when value is zero or negative', () => {
|
|
26
|
+
assert.strictEqual(validateLimit(0), 1);
|
|
27
|
+
assert.strictEqual(validateLimit(-1), 1);
|
|
28
|
+
assert.strictEqual(validateLimit(-100), 1);
|
|
29
|
+
});
|
|
30
|
+
it('should handle edge cases', () => {
|
|
31
|
+
assert.strictEqual(validateLimit(MAX_LIMIT), MAX_LIMIT);
|
|
32
|
+
assert.strictEqual(validateLimit(1), 1);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('validateDuration', () => {
|
|
36
|
+
it('should return undefined when undefined', () => {
|
|
37
|
+
const result = validateDuration(undefined, 'minDurationMs');
|
|
38
|
+
assert.strictEqual(result, undefined);
|
|
39
|
+
});
|
|
40
|
+
it('should return undefined when null', () => {
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
const result = validateDuration(null, 'minDurationMs');
|
|
43
|
+
assert.strictEqual(result, undefined);
|
|
44
|
+
});
|
|
45
|
+
it('should return value when within valid range', () => {
|
|
46
|
+
assert.strictEqual(validateDuration(0, 'minDurationMs'), 0);
|
|
47
|
+
assert.strictEqual(validateDuration(1000, 'minDurationMs'), 1000);
|
|
48
|
+
assert.strictEqual(validateDuration(5000, 'maxDurationMs'), 5000);
|
|
49
|
+
assert.strictEqual(validateDuration(MAX_DURATION_MS, 'maxDurationMs'), MAX_DURATION_MS);
|
|
50
|
+
});
|
|
51
|
+
it('should clamp to MAX_DURATION_MS when value exceeds maximum', () => {
|
|
52
|
+
assert.strictEqual(validateDuration(MAX_DURATION_MS + 1, 'minDurationMs'), MAX_DURATION_MS);
|
|
53
|
+
assert.strictEqual(validateDuration(100000000, 'maxDurationMs'), MAX_DURATION_MS);
|
|
54
|
+
assert.strictEqual(validateDuration(Number.MAX_SAFE_INTEGER, 'minDurationMs'), MAX_DURATION_MS);
|
|
55
|
+
});
|
|
56
|
+
it('should throw when value is negative', () => {
|
|
57
|
+
assert.throws(() => validateDuration(-1, 'minDurationMs'), (err) => {
|
|
58
|
+
assert.strictEqual(err.field, 'minDurationMs');
|
|
59
|
+
assert.strictEqual(err.constraint, 'range');
|
|
60
|
+
assert.ok(err.message.includes('cannot be negative'));
|
|
61
|
+
return true;
|
|
62
|
+
});
|
|
63
|
+
assert.throws(() => validateDuration(-100, 'maxDurationMs'), (err) => {
|
|
64
|
+
assert.strictEqual(err.field, 'maxDurationMs');
|
|
65
|
+
assert.strictEqual(err.constraint, 'range');
|
|
66
|
+
return true;
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
it('should handle edge cases', () => {
|
|
70
|
+
assert.strictEqual(validateDuration(0, 'minDurationMs'), 0);
|
|
71
|
+
assert.strictEqual(validateDuration(MAX_DURATION_MS, 'maxDurationMs'), MAX_DURATION_MS);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('validateDateRange', () => {
|
|
75
|
+
it('should parse valid date strings', () => {
|
|
76
|
+
const result = validateDateRange('2024-01-01', '2024-01-31');
|
|
77
|
+
assert.strictEqual(result.start.getFullYear(), 2024);
|
|
78
|
+
assert.strictEqual(result.start.getMonth(), 0); // January
|
|
79
|
+
assert.strictEqual(result.start.getDate(), 1);
|
|
80
|
+
assert.strictEqual(result.end.getFullYear(), 2024);
|
|
81
|
+
assert.strictEqual(result.end.getMonth(), 0);
|
|
82
|
+
assert.strictEqual(result.end.getDate(), 31);
|
|
83
|
+
});
|
|
84
|
+
it('should return defaults when both dates undefined', () => {
|
|
85
|
+
const result = validateDateRange(undefined, undefined);
|
|
86
|
+
const today = new Date();
|
|
87
|
+
// End should be today
|
|
88
|
+
assert.strictEqual(result.end.getFullYear(), today.getFullYear());
|
|
89
|
+
assert.strictEqual(result.end.getMonth(), today.getMonth());
|
|
90
|
+
assert.strictEqual(result.end.getDate(), today.getDate());
|
|
91
|
+
// Start should be MAX_DATE_RANGE_DAYS ago
|
|
92
|
+
const expectedStart = new Date(today.getTime() - MAX_DATE_RANGE_DAYS * 24 * 60 * 60 * 1000);
|
|
93
|
+
assert.strictEqual(result.start.getFullYear(), expectedStart.getFullYear());
|
|
94
|
+
assert.strictEqual(result.start.getMonth(), expectedStart.getMonth());
|
|
95
|
+
assert.strictEqual(result.start.getDate(), expectedStart.getDate());
|
|
96
|
+
});
|
|
97
|
+
it('should throw on invalid startDate format', () => {
|
|
98
|
+
assert.throws(() => validateDateRange('invalid', '2024-01-31'), (err) => {
|
|
99
|
+
assert.strictEqual(err.field, 'startDate');
|
|
100
|
+
assert.strictEqual(err.constraint, 'format');
|
|
101
|
+
assert.ok(err.message.includes('Invalid startDate format'));
|
|
102
|
+
return true;
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
it('should throw on invalid endDate format', () => {
|
|
106
|
+
assert.throws(() => validateDateRange('2024-01-01', 'not-a-date'), (err) => {
|
|
107
|
+
assert.strictEqual(err.field, 'endDate');
|
|
108
|
+
assert.strictEqual(err.constraint, 'format');
|
|
109
|
+
assert.ok(err.message.includes('Invalid endDate format'));
|
|
110
|
+
return true;
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
it('should throw on partial date format', () => {
|
|
114
|
+
assert.throws(() => validateDateRange('2024-01', '2024-01-31'), (err) => {
|
|
115
|
+
assert.strictEqual(err.field, 'startDate');
|
|
116
|
+
assert.strictEqual(err.constraint, 'format');
|
|
117
|
+
return true;
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
it('should throw on invalid date like Feb 30', () => {
|
|
121
|
+
assert.throws(() => validateDateRange('2024-02-30', '2024-03-01'), (err) => {
|
|
122
|
+
assert.strictEqual(err.field, 'startDate');
|
|
123
|
+
assert.strictEqual(err.constraint, 'format');
|
|
124
|
+
return true;
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
it('should throw on invalid month', () => {
|
|
128
|
+
assert.throws(() => validateDateRange('2024-13-01', '2024-12-31'), (err) => {
|
|
129
|
+
assert.strictEqual(err.field, 'startDate');
|
|
130
|
+
assert.strictEqual(err.constraint, 'format');
|
|
131
|
+
return true;
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
it('should throw when startDate is after endDate', () => {
|
|
135
|
+
assert.throws(() => validateDateRange('2024-12-31', '2024-01-01'), (err) => {
|
|
136
|
+
assert.strictEqual(err.field, 'startDate');
|
|
137
|
+
assert.strictEqual(err.constraint, 'range');
|
|
138
|
+
assert.ok(err.message.includes('cannot be after'));
|
|
139
|
+
return true;
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
it('should throw when date range exceeds maximum', () => {
|
|
143
|
+
// Calculate dates that exceed MAX_DATE_RANGE_DAYS
|
|
144
|
+
const start = '2022-01-01';
|
|
145
|
+
const end = '2024-01-01'; // ~730 days
|
|
146
|
+
assert.throws(() => validateDateRange(start, end), (err) => {
|
|
147
|
+
assert.strictEqual(err.field, 'dateRange');
|
|
148
|
+
assert.strictEqual(err.constraint, 'maxRange');
|
|
149
|
+
assert.ok(err.message.includes(`exceeds maximum of ${MAX_DATE_RANGE_DAYS}`));
|
|
150
|
+
return true;
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
it('should allow range exactly at maximum', () => {
|
|
154
|
+
const start = new Date();
|
|
155
|
+
start.setDate(start.getDate() - MAX_DATE_RANGE_DAYS);
|
|
156
|
+
const startStr = start.toISOString().split('T')[0];
|
|
157
|
+
const endStr = new Date().toISOString().split('T')[0];
|
|
158
|
+
// Should not throw
|
|
159
|
+
const result = validateDateRange(startStr, endStr);
|
|
160
|
+
assert.ok(result.start);
|
|
161
|
+
assert.ok(result.end);
|
|
162
|
+
});
|
|
163
|
+
it('should handle same start and end date', () => {
|
|
164
|
+
const result = validateDateRange('2024-06-15', '2024-06-15');
|
|
165
|
+
assert.strictEqual(result.start.getTime(), result.end.getTime());
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe('validateRegexPattern', () => {
|
|
169
|
+
it('should accept valid simple patterns', () => {
|
|
170
|
+
assert.doesNotThrow(() => validateRegexPattern('error'));
|
|
171
|
+
assert.doesNotThrow(() => validateRegexPattern('error.*timeout'));
|
|
172
|
+
assert.doesNotThrow(() => validateRegexPattern('^start'));
|
|
173
|
+
assert.doesNotThrow(() => validateRegexPattern('end$'));
|
|
174
|
+
});
|
|
175
|
+
it('should accept patterns with allowed capture groups', () => {
|
|
176
|
+
assert.doesNotThrow(() => validateRegexPattern('(foo)'));
|
|
177
|
+
assert.doesNotThrow(() => validateRegexPattern('(a)(b)(c)'));
|
|
178
|
+
// 10 groups is the max
|
|
179
|
+
assert.doesNotThrow(() => validateRegexPattern('(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)'));
|
|
180
|
+
});
|
|
181
|
+
it('should accept non-capturing groups without counting', () => {
|
|
182
|
+
// Non-capturing groups don't count toward limit
|
|
183
|
+
assert.doesNotThrow(() => validateRegexPattern('(?:foo)'));
|
|
184
|
+
assert.doesNotThrow(() => validateRegexPattern('(?:a)(?:b)(?:c)(?:d)(?:e)(?:f)(?:g)(?:h)(?:i)(?:j)(?:k)'));
|
|
185
|
+
});
|
|
186
|
+
it('should accept lookahead/lookbehind without counting', () => {
|
|
187
|
+
assert.doesNotThrow(() => validateRegexPattern('(?=foo)'));
|
|
188
|
+
assert.doesNotThrow(() => validateRegexPattern('(?!foo)'));
|
|
189
|
+
assert.doesNotThrow(() => validateRegexPattern('(?<=foo)'));
|
|
190
|
+
assert.doesNotThrow(() => validateRegexPattern('(?<!foo)'));
|
|
191
|
+
});
|
|
192
|
+
it('should throw when pattern exceeds max length', () => {
|
|
193
|
+
const longPattern = 'a'.repeat(MAX_REGEX_LENGTH + 1);
|
|
194
|
+
assert.throws(() => validateRegexPattern(longPattern), (err) => {
|
|
195
|
+
assert.strictEqual(err.field, 'pattern');
|
|
196
|
+
assert.strictEqual(err.constraint, 'maxLength');
|
|
197
|
+
assert.ok(err.message.includes(`exceeds maximum of ${MAX_REGEX_LENGTH}`));
|
|
198
|
+
return true;
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
it('should throw when pattern has too many capture groups', () => {
|
|
202
|
+
// 11 groups exceeds the limit of 10
|
|
203
|
+
const manyGroups = '(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)';
|
|
204
|
+
assert.throws(() => validateRegexPattern(manyGroups), (err) => {
|
|
205
|
+
assert.strictEqual(err.field, 'pattern');
|
|
206
|
+
assert.strictEqual(err.constraint, 'maxGroups');
|
|
207
|
+
assert.ok(err.message.includes(`exceeding maximum of ${MAX_REGEX_GROUPS}`));
|
|
208
|
+
return true;
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
it('should throw on invalid regex syntax', () => {
|
|
212
|
+
assert.throws(() => validateRegexPattern('[invalid'), (err) => {
|
|
213
|
+
assert.strictEqual(err.field, 'pattern');
|
|
214
|
+
assert.strictEqual(err.constraint, 'syntax');
|
|
215
|
+
assert.ok(err.message.includes('Invalid regex pattern'));
|
|
216
|
+
return true;
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
it('should throw on unclosed parenthesis', () => {
|
|
220
|
+
assert.throws(() => validateRegexPattern('(unclosed'), (err) => {
|
|
221
|
+
assert.strictEqual(err.field, 'pattern');
|
|
222
|
+
assert.strictEqual(err.constraint, 'syntax');
|
|
223
|
+
return true;
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
it('should handle escaped parentheses', () => {
|
|
227
|
+
// Escaped parens don't count as groups
|
|
228
|
+
assert.doesNotThrow(() => validateRegexPattern('\\(not a group\\)'));
|
|
229
|
+
assert.doesNotThrow(() => validateRegexPattern('\\(\\)\\(\\)\\(\\)\\(\\)\\(\\)\\(\\)\\(\\)\\(\\)\\(\\)\\(\\)\\(\\)'));
|
|
230
|
+
});
|
|
231
|
+
it('should handle parentheses inside character classes', () => {
|
|
232
|
+
// Parens inside [] don't count as groups
|
|
233
|
+
assert.doesNotThrow(() => validateRegexPattern('[(]'));
|
|
234
|
+
assert.doesNotThrow(() => validateRegexPattern('[()]'));
|
|
235
|
+
});
|
|
236
|
+
it('should handle complex patterns', () => {
|
|
237
|
+
// Mix of real groups, non-capturing, and escaped
|
|
238
|
+
assert.doesNotThrow(() => validateRegexPattern('(a)(?:b)\\(c\\)[d]'));
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
describe('InputValidationError', () => {
|
|
242
|
+
it('should have correct properties', () => {
|
|
243
|
+
const error = new InputValidationError('Test message', 'testField', 'testConstraint');
|
|
244
|
+
assert.strictEqual(error.message, 'Test message');
|
|
245
|
+
assert.strictEqual(error.field, 'testField');
|
|
246
|
+
assert.strictEqual(error.constraint, 'testConstraint');
|
|
247
|
+
assert.strictEqual(error.name, 'InputValidationError');
|
|
248
|
+
});
|
|
249
|
+
it('should be instanceof Error', () => {
|
|
250
|
+
const error = new InputValidationError('Test', 'field', 'constraint');
|
|
251
|
+
assert.ok(error instanceof Error);
|
|
252
|
+
assert.ok(error instanceof InputValidationError);
|
|
253
|
+
});
|
|
254
|
+
it('should have stack trace', () => {
|
|
255
|
+
const error = new InputValidationError('Test', 'field', 'constraint');
|
|
256
|
+
assert.ok(error.stack);
|
|
257
|
+
assert.ok(error.stack.includes('InputValidationError'));
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
describe('isInputValidationError', () => {
|
|
261
|
+
it('should return true for InputValidationError', () => {
|
|
262
|
+
const error = new InputValidationError('Test', 'field', 'constraint');
|
|
263
|
+
assert.strictEqual(isInputValidationError(error), true);
|
|
264
|
+
});
|
|
265
|
+
it('should return false for regular Error', () => {
|
|
266
|
+
const error = new Error('Test');
|
|
267
|
+
assert.strictEqual(isInputValidationError(error), false);
|
|
268
|
+
});
|
|
269
|
+
it('should return false for non-error objects', () => {
|
|
270
|
+
assert.strictEqual(isInputValidationError({ message: 'fake' }), false);
|
|
271
|
+
assert.strictEqual(isInputValidationError(null), false);
|
|
272
|
+
assert.strictEqual(isInputValidationError(undefined), false);
|
|
273
|
+
assert.strictEqual(isInputValidationError('string'), false);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
describe('constants', () => {
|
|
277
|
+
it('should export expected constant values', () => {
|
|
278
|
+
assert.strictEqual(MAX_LIMIT, 1000);
|
|
279
|
+
assert.strictEqual(MAX_DATE_RANGE_DAYS, 365);
|
|
280
|
+
assert.strictEqual(MAX_REGEX_LENGTH, 200);
|
|
281
|
+
assert.strictEqual(MAX_REGEX_GROUPS, 10);
|
|
282
|
+
assert.strictEqual(DEFAULT_LIMIT, 50);
|
|
283
|
+
assert.strictEqual(MAX_DURATION_MS, 86400000); // 24 hours
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
//# sourceMappingURL=input-validator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-validator.test.js","sourceRoot":"","sources":["../../src/lib/input-validator.test.ts"],"names":[],"mappings":"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"}
|