observability-toolkit 1.3.0 → 1.4.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 +52 -3
- package/dist/backends/index.d.ts +15 -0
- package/dist/backends/index.d.ts.map +1 -1
- package/dist/backends/local-jsonl.d.ts +27 -0
- package/dist/backends/local-jsonl.d.ts.map +1 -1
- package/dist/backends/local-jsonl.js +202 -30
- package/dist/backends/local-jsonl.js.map +1 -1
- package/dist/backends/local-jsonl.test.js +1081 -1
- package/dist/backends/local-jsonl.test.js.map +1 -1
- package/dist/backends/signoz-api.d.ts.map +1 -1
- package/dist/backends/signoz-api.integration.test.d.ts +8 -0
- package/dist/backends/signoz-api.integration.test.d.ts.map +1 -0
- package/dist/backends/signoz-api.integration.test.js +137 -0
- package/dist/backends/signoz-api.integration.test.js.map +1 -0
- package/dist/backends/signoz-api.js +58 -42
- package/dist/backends/signoz-api.js.map +1 -1
- package/dist/backends/signoz-api.test.js +504 -328
- package/dist/backends/signoz-api.test.js.map +1 -1
- package/dist/lib/constants.d.ts +27 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +70 -0
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/constants.test.js +183 -1
- package/dist/lib/constants.test.js.map +1 -1
- package/dist/lib/file-utils.d.ts +53 -1
- package/dist/lib/file-utils.d.ts.map +1 -1
- package/dist/lib/file-utils.js +142 -3
- package/dist/lib/file-utils.js.map +1 -1
- package/dist/lib/file-utils.test.js +228 -1
- package/dist/lib/file-utils.test.js.map +1 -1
- package/dist/server.js +48 -65
- package/dist/server.js.map +1 -1
- package/dist/server.test.d.ts +5 -0
- package/dist/server.test.d.ts.map +1 -0
- package/dist/server.test.js +547 -0
- package/dist/server.test.js.map +1 -0
- package/dist/tools/context-stats.test.js +126 -0
- package/dist/tools/context-stats.test.js.map +1 -1
- package/dist/tools/get-trace-url.d.ts.map +1 -1
- package/dist/tools/get-trace-url.js +5 -1
- package/dist/tools/get-trace-url.js.map +1 -1
- package/dist/tools/get-trace-url.test.js +12 -6
- package/dist/tools/get-trace-url.test.js.map +1 -1
- package/dist/tools/health-check.d.ts +9 -2
- package/dist/tools/health-check.d.ts.map +1 -1
- package/dist/tools/health-check.js +66 -27
- package/dist/tools/health-check.js.map +1 -1
- package/dist/tools/health-check.test.js +89 -96
- package/dist/tools/health-check.test.js.map +1 -1
- package/dist/tools/query-llm-events.d.ts +2 -2
- package/dist/tools/query-llm-events.js +3 -3
- package/dist/tools/query-llm-events.js.map +1 -1
- package/dist/tools/query-logs.d.ts +8 -6
- package/dist/tools/query-logs.d.ts.map +1 -1
- package/dist/tools/query-logs.js +5 -5
- package/dist/tools/query-logs.js.map +1 -1
- package/dist/tools/query-logs.test.js +22 -2
- package/dist/tools/query-logs.test.js.map +1 -1
- package/dist/tools/query-metrics.d.ts +12 -14
- package/dist/tools/query-metrics.d.ts.map +1 -1
- package/dist/tools/query-metrics.js +11 -13
- package/dist/tools/query-metrics.js.map +1 -1
- package/dist/tools/query-metrics.test.js +134 -96
- package/dist/tools/query-metrics.test.js.map +1 -1
- package/dist/tools/query-traces.d.ts +16 -17
- package/dist/tools/query-traces.d.ts.map +1 -1
- package/dist/tools/query-traces.js +11 -14
- package/dist/tools/query-traces.js.map +1 -1
- package/dist/tools/query-traces.test.js +144 -48
- package/dist/tools/query-traces.test.js.map +1 -1
- package/dist/tools/setup-claudeignore.d.ts +36 -10
- package/dist/tools/setup-claudeignore.d.ts.map +1 -1
- package/dist/tools/setup-claudeignore.js +193 -33
- package/dist/tools/setup-claudeignore.js.map +1 -1
- package/dist/tools/setup-claudeignore.test.js +286 -41
- package/dist/tools/setup-claudeignore.test.js.map +1 -1
- package/dist/tools/signoz.integration.test.d.ts +8 -0
- package/dist/tools/signoz.integration.test.d.ts.map +1 -0
- package/dist/tools/signoz.integration.test.js +141 -0
- package/dist/tools/signoz.integration.test.js.map +1 -0
- package/package.json +6 -3
package/dist/lib/file-utils.d.ts
CHANGED
|
@@ -18,18 +18,47 @@ export declare function loadJsonSafe<T>(filePath: string, fallback: T): T;
|
|
|
18
18
|
* Get date string in YYYY-MM-DD format
|
|
19
19
|
*/
|
|
20
20
|
export declare function getDateString(date?: Date): string;
|
|
21
|
+
/**
|
|
22
|
+
* Validate that a path is within allowed base directories
|
|
23
|
+
* Prevents path traversal attacks by resolving symlinks and checking containment
|
|
24
|
+
*/
|
|
25
|
+
export declare function isPathWithinAllowed(targetPath: string, allowedBasePaths: string[]): boolean;
|
|
21
26
|
/**
|
|
22
27
|
* List files in directory matching a pattern
|
|
28
|
+
* @param dir - Directory to list files from
|
|
29
|
+
* @param pattern - RegExp to filter filenames
|
|
30
|
+
* @param allowedBasePaths - Optional list of allowed base directories (for security validation)
|
|
23
31
|
*/
|
|
24
|
-
export declare function listFiles(dir: string, pattern: RegExp): string[];
|
|
32
|
+
export declare function listFiles(dir: string, pattern: RegExp, allowedBasePaths?: string[]): string[];
|
|
25
33
|
/**
|
|
26
34
|
* Parse date from filename like traces-2026-01-28.jsonl
|
|
27
35
|
*/
|
|
28
36
|
export declare function parseDateFromFilename(filename: string): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Statistics from JSONL parsing
|
|
39
|
+
*/
|
|
40
|
+
export interface JsonlParseStats {
|
|
41
|
+
totalLines: number;
|
|
42
|
+
parsedLines: number;
|
|
43
|
+
skippedLines: number;
|
|
44
|
+
emptyLines: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result from readJsonlSyncWithStats
|
|
48
|
+
*/
|
|
49
|
+
export interface ReadJsonlResult<T> {
|
|
50
|
+
data: T[];
|
|
51
|
+
stats: JsonlParseStats;
|
|
52
|
+
}
|
|
29
53
|
/**
|
|
30
54
|
* Read JSONL file and parse each line
|
|
31
55
|
*/
|
|
32
56
|
export declare function readJsonlSync<T>(filePath: string, limit?: number): T[];
|
|
57
|
+
/**
|
|
58
|
+
* Read JSONL file with verbose statistics about parse failures
|
|
59
|
+
* Use this for debugging to see how many lines were skipped
|
|
60
|
+
*/
|
|
61
|
+
export declare function readJsonlSyncWithStats<T>(filePath: string, limit?: number): ReadJsonlResult<T>;
|
|
33
62
|
/**
|
|
34
63
|
* Stream JSONL file line by line (for large files)
|
|
35
64
|
*/
|
|
@@ -40,4 +69,27 @@ export declare function streamJsonl<T>(filePath: string): AsyncGenerator<T>;
|
|
|
40
69
|
export declare function filterByDateRange<T extends {
|
|
41
70
|
timestamp?: string;
|
|
42
71
|
}>(items: T[], startDate?: string, endDate?: string): T[];
|
|
72
|
+
/**
|
|
73
|
+
* Paginate results array with offset and limit
|
|
74
|
+
*/
|
|
75
|
+
export declare function paginateResults<T>(results: T[], offset: number, limit: number): T[];
|
|
76
|
+
/**
|
|
77
|
+
* Check if we've collected enough results for early termination
|
|
78
|
+
*/
|
|
79
|
+
export declare function hasReachedLimit(resultsLength: number, offset: number, limit: number): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Result from cleanupOldFiles operation
|
|
82
|
+
*/
|
|
83
|
+
export interface CleanupResult {
|
|
84
|
+
deleted: number;
|
|
85
|
+
errors: string[];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Clean up old telemetry files based on retention policy
|
|
89
|
+
* @param dir - Directory containing telemetry files
|
|
90
|
+
* @param retentionDays - Number of days to retain files (default: 7)
|
|
91
|
+
* @param allowedBasePaths - Optional list of allowed base directories (for security validation)
|
|
92
|
+
* @returns Object with count of deleted files and any errors encountered
|
|
93
|
+
*/
|
|
94
|
+
export declare function cleanupOldFiles(dir: string, retentionDays?: number, allowedBasePaths?: string[]): CleanupResult;
|
|
43
95
|
//# sourceMappingURL=file-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../../src/lib/file-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASpD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,CASpE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAEhE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE,IAAiB,GAAG,MAAM,CAE7D;AAED
|
|
1
|
+
{"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../../src/lib/file-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASpD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,CASpE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAEhE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE,IAAiB,GAAG,MAAM,CAE7D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,OAAO,CAgB3F;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAyB7F;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGrE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,KAAK,EAAE,eAAe,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAuBtE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAyC9F;AAED;;GAEG;AACH,wBAAuB,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,CAiBzE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAChE,KAAK,EAAE,CAAC,EAAE,EACV,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,CAAC,EAAE,CAQL;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,CAEnF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAE7F;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,aAAa,GAAE,MAAU,EACzB,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAC1B,aAAa,CAkDf"}
|
package/dist/lib/file-utils.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File system utilities for observability-toolkit
|
|
3
3
|
*/
|
|
4
|
-
import { existsSync, readFileSync, readdirSync, statSync, createReadStream } from 'fs';
|
|
5
|
-
import { join, basename } from 'path';
|
|
4
|
+
import { existsSync, readFileSync, readdirSync, statSync, createReadStream, unlinkSync } from 'fs';
|
|
5
|
+
import { join, basename, resolve, normalize } from 'path';
|
|
6
6
|
import { homedir } from 'os';
|
|
7
7
|
import { createInterface } from 'readline';
|
|
8
8
|
/**
|
|
@@ -44,12 +44,42 @@ export function loadJsonSafe(filePath, fallback) {
|
|
|
44
44
|
export function getDateString(date = new Date()) {
|
|
45
45
|
return date.toISOString().split('T')[0];
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Validate that a path is within allowed base directories
|
|
49
|
+
* Prevents path traversal attacks by resolving symlinks and checking containment
|
|
50
|
+
*/
|
|
51
|
+
export function isPathWithinAllowed(targetPath, allowedBasePaths) {
|
|
52
|
+
try {
|
|
53
|
+
// Normalize and resolve the target path
|
|
54
|
+
const normalizedTarget = normalize(resolve(targetPath));
|
|
55
|
+
for (const basePath of allowedBasePaths) {
|
|
56
|
+
const normalizedBase = normalize(resolve(basePath));
|
|
57
|
+
// Check if target starts with base path (with trailing separator to prevent partial matches)
|
|
58
|
+
if (normalizedTarget === normalizedBase || normalizedTarget.startsWith(normalizedBase + '/')) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
47
68
|
/**
|
|
48
69
|
* List files in directory matching a pattern
|
|
70
|
+
* @param dir - Directory to list files from
|
|
71
|
+
* @param pattern - RegExp to filter filenames
|
|
72
|
+
* @param allowedBasePaths - Optional list of allowed base directories (for security validation)
|
|
49
73
|
*/
|
|
50
|
-
export function listFiles(dir, pattern) {
|
|
74
|
+
export function listFiles(dir, pattern, allowedBasePaths) {
|
|
51
75
|
if (!existsSync(dir))
|
|
52
76
|
return [];
|
|
77
|
+
// Security: validate directory is within allowed paths if specified
|
|
78
|
+
if (allowedBasePaths && allowedBasePaths.length > 0) {
|
|
79
|
+
if (!isPathWithinAllowed(dir, allowedBasePaths)) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
53
83
|
try {
|
|
54
84
|
return readdirSync(dir)
|
|
55
85
|
.filter(f => pattern.test(f))
|
|
@@ -103,6 +133,51 @@ export function readJsonlSync(filePath, limit) {
|
|
|
103
133
|
return [];
|
|
104
134
|
}
|
|
105
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Read JSONL file with verbose statistics about parse failures
|
|
138
|
+
* Use this for debugging to see how many lines were skipped
|
|
139
|
+
*/
|
|
140
|
+
export function readJsonlSyncWithStats(filePath, limit) {
|
|
141
|
+
const emptyResult = {
|
|
142
|
+
data: [],
|
|
143
|
+
stats: { totalLines: 0, parsedLines: 0, skippedLines: 0, emptyLines: 0 },
|
|
144
|
+
};
|
|
145
|
+
if (!existsSync(filePath))
|
|
146
|
+
return emptyResult;
|
|
147
|
+
try {
|
|
148
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
149
|
+
const lines = content.trim().split('\n');
|
|
150
|
+
const results = [];
|
|
151
|
+
let skippedLines = 0;
|
|
152
|
+
let emptyLines = 0;
|
|
153
|
+
for (const line of lines) {
|
|
154
|
+
if (limit && results.length >= limit)
|
|
155
|
+
break;
|
|
156
|
+
if (!line.trim()) {
|
|
157
|
+
emptyLines++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
results.push(JSON.parse(line));
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
skippedLines++;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
data: results,
|
|
169
|
+
stats: {
|
|
170
|
+
totalLines: lines.length,
|
|
171
|
+
parsedLines: results.length,
|
|
172
|
+
skippedLines,
|
|
173
|
+
emptyLines,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return emptyResult;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
106
181
|
/**
|
|
107
182
|
* Stream JSONL file line by line (for large files)
|
|
108
183
|
*/
|
|
@@ -140,4 +215,68 @@ export function filterByDateRange(items, startDate, endDate) {
|
|
|
140
215
|
return true;
|
|
141
216
|
});
|
|
142
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Paginate results array with offset and limit
|
|
220
|
+
*/
|
|
221
|
+
export function paginateResults(results, offset, limit) {
|
|
222
|
+
return results.slice(offset, offset + limit);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Check if we've collected enough results for early termination
|
|
226
|
+
*/
|
|
227
|
+
export function hasReachedLimit(resultsLength, offset, limit) {
|
|
228
|
+
return resultsLength >= offset + limit;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Clean up old telemetry files based on retention policy
|
|
232
|
+
* @param dir - Directory containing telemetry files
|
|
233
|
+
* @param retentionDays - Number of days to retain files (default: 7)
|
|
234
|
+
* @param allowedBasePaths - Optional list of allowed base directories (for security validation)
|
|
235
|
+
* @returns Object with count of deleted files and any errors encountered
|
|
236
|
+
*/
|
|
237
|
+
export function cleanupOldFiles(dir, retentionDays = 7, allowedBasePaths) {
|
|
238
|
+
const result = { deleted: 0, errors: [] };
|
|
239
|
+
if (!existsSync(dir)) {
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
242
|
+
// Security: validate directory is within allowed paths if specified
|
|
243
|
+
if (allowedBasePaths && allowedBasePaths.length > 0) {
|
|
244
|
+
if (!isPathWithinAllowed(dir, allowedBasePaths)) {
|
|
245
|
+
result.errors.push(`Directory ${dir} is not within allowed paths`);
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// Calculate cutoff date
|
|
250
|
+
const now = new Date();
|
|
251
|
+
const cutoffDate = new Date(now.getTime() - retentionDays * 24 * 60 * 60 * 1000);
|
|
252
|
+
const cutoffDateStr = getDateString(cutoffDate);
|
|
253
|
+
try {
|
|
254
|
+
// List all .jsonl files
|
|
255
|
+
const files = readdirSync(dir).filter(f => f.endsWith('.jsonl'));
|
|
256
|
+
for (const file of files) {
|
|
257
|
+
const filePath = join(dir, file);
|
|
258
|
+
const fileDate = parseDateFromFilename(file);
|
|
259
|
+
// Skip files without parseable dates (don't delete unknown files)
|
|
260
|
+
if (!fileDate) {
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
// Delete files older than retention period
|
|
264
|
+
if (fileDate < cutoffDateStr) {
|
|
265
|
+
try {
|
|
266
|
+
unlinkSync(filePath);
|
|
267
|
+
result.deleted++;
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
271
|
+
result.errors.push(`Failed to delete ${filePath}: ${message}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
278
|
+
result.errors.push(`Failed to read directory ${dir}: ${message}`);
|
|
279
|
+
}
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
143
282
|
//# sourceMappingURL=file-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-utils.js","sourceRoot":"","sources":["../../src/lib/file-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"file-utils.js","sourceRoot":"","sources":["../../src/lib/file-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import assert from 'node:assert';
|
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import * as os from 'os';
|
|
6
|
-
import { expandTilde, loadJson, loadJsonSafe, getDateString, listFiles, parseDateFromFilename, readJsonlSync, streamJsonl, filterByDateRange, } from './file-utils.js';
|
|
6
|
+
import { expandTilde, loadJson, loadJsonSafe, getDateString, listFiles, parseDateFromFilename, readJsonlSync, readJsonlSyncWithStats, streamJsonl, filterByDateRange, paginateResults, hasReachedLimit, cleanupOldFiles, } from './file-utils.js';
|
|
7
7
|
describe('file-utils', () => {
|
|
8
8
|
let testDir;
|
|
9
9
|
beforeEach(() => {
|
|
@@ -418,5 +418,232 @@ describe('file-utils', () => {
|
|
|
418
418
|
assert.strictEqual(result.length, 2);
|
|
419
419
|
});
|
|
420
420
|
});
|
|
421
|
+
describe('paginateResults', () => {
|
|
422
|
+
const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
423
|
+
it('should return items from offset to offset + limit', () => {
|
|
424
|
+
const result = paginateResults(items, 2, 3);
|
|
425
|
+
assert.deepStrictEqual(result, [3, 4, 5]);
|
|
426
|
+
});
|
|
427
|
+
it('should return from start when offset is 0', () => {
|
|
428
|
+
const result = paginateResults(items, 0, 5);
|
|
429
|
+
assert.deepStrictEqual(result, [1, 2, 3, 4, 5]);
|
|
430
|
+
});
|
|
431
|
+
it('should handle offset at end of array', () => {
|
|
432
|
+
const result = paginateResults(items, 8, 5);
|
|
433
|
+
assert.deepStrictEqual(result, [9, 10]);
|
|
434
|
+
});
|
|
435
|
+
it('should return empty array when offset exceeds length', () => {
|
|
436
|
+
const result = paginateResults(items, 15, 5);
|
|
437
|
+
assert.deepStrictEqual(result, []);
|
|
438
|
+
});
|
|
439
|
+
it('should handle limit larger than remaining items', () => {
|
|
440
|
+
const result = paginateResults(items, 7, 10);
|
|
441
|
+
assert.deepStrictEqual(result, [8, 9, 10]);
|
|
442
|
+
});
|
|
443
|
+
it('should handle empty array', () => {
|
|
444
|
+
const result = paginateResults([], 0, 10);
|
|
445
|
+
assert.deepStrictEqual(result, []);
|
|
446
|
+
});
|
|
447
|
+
it('should work with object arrays', () => {
|
|
448
|
+
const objs = [{ id: 1 }, { id: 2 }, { id: 3 }];
|
|
449
|
+
const result = paginateResults(objs, 1, 2);
|
|
450
|
+
assert.deepStrictEqual(result, [{ id: 2 }, { id: 3 }]);
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
describe('hasReachedLimit', () => {
|
|
454
|
+
it('should return true when results equal offset + limit', () => {
|
|
455
|
+
const result = hasReachedLimit(10, 5, 5);
|
|
456
|
+
assert.strictEqual(result, true);
|
|
457
|
+
});
|
|
458
|
+
it('should return true when results exceed offset + limit', () => {
|
|
459
|
+
const result = hasReachedLimit(15, 5, 5);
|
|
460
|
+
assert.strictEqual(result, true);
|
|
461
|
+
});
|
|
462
|
+
it('should return false when results are less than offset + limit', () => {
|
|
463
|
+
const result = hasReachedLimit(8, 5, 5);
|
|
464
|
+
assert.strictEqual(result, false);
|
|
465
|
+
});
|
|
466
|
+
it('should return false with zero results', () => {
|
|
467
|
+
const result = hasReachedLimit(0, 0, 10);
|
|
468
|
+
assert.strictEqual(result, false);
|
|
469
|
+
});
|
|
470
|
+
it('should handle zero offset', () => {
|
|
471
|
+
const result = hasReachedLimit(10, 0, 10);
|
|
472
|
+
assert.strictEqual(result, true);
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
describe('readJsonlSyncWithStats', () => {
|
|
476
|
+
it('should return data and stats', () => {
|
|
477
|
+
const filePath = path.join(testDir, 'test.jsonl');
|
|
478
|
+
fs.writeFileSync(filePath, '{"id":1}\n{"id":2}\n{"id":3}');
|
|
479
|
+
const result = readJsonlSyncWithStats(filePath);
|
|
480
|
+
assert.ok('data' in result);
|
|
481
|
+
assert.ok('stats' in result);
|
|
482
|
+
assert.strictEqual(result.data.length, 3);
|
|
483
|
+
assert.strictEqual(result.stats.totalLines, 3);
|
|
484
|
+
assert.strictEqual(result.stats.parsedLines, 3);
|
|
485
|
+
assert.strictEqual(result.stats.skippedLines, 0);
|
|
486
|
+
assert.strictEqual(result.stats.emptyLines, 0);
|
|
487
|
+
});
|
|
488
|
+
it('should count skipped lines', () => {
|
|
489
|
+
const filePath = path.join(testDir, 'test.jsonl');
|
|
490
|
+
fs.writeFileSync(filePath, '{"id":1}\n{invalid json}\n{"id":2}\n{also invalid}');
|
|
491
|
+
const result = readJsonlSyncWithStats(filePath);
|
|
492
|
+
assert.strictEqual(result.data.length, 2);
|
|
493
|
+
assert.strictEqual(result.stats.parsedLines, 2);
|
|
494
|
+
assert.strictEqual(result.stats.skippedLines, 2);
|
|
495
|
+
});
|
|
496
|
+
it('should count empty lines', () => {
|
|
497
|
+
const filePath = path.join(testDir, 'test.jsonl');
|
|
498
|
+
// Note: trailing empty lines are removed by trim(), so only internal empty lines are counted
|
|
499
|
+
fs.writeFileSync(filePath, '{"id":1}\n\n \n{"id":2}');
|
|
500
|
+
const result = readJsonlSyncWithStats(filePath);
|
|
501
|
+
assert.strictEqual(result.data.length, 2);
|
|
502
|
+
assert.strictEqual(result.stats.emptyLines, 2);
|
|
503
|
+
});
|
|
504
|
+
it('should respect limit parameter', () => {
|
|
505
|
+
const filePath = path.join(testDir, 'test.jsonl');
|
|
506
|
+
fs.writeFileSync(filePath, '{"id":1}\n{"id":2}\n{"id":3}\n{"id":4}\n{"id":5}');
|
|
507
|
+
const result = readJsonlSyncWithStats(filePath, 3);
|
|
508
|
+
assert.strictEqual(result.data.length, 3);
|
|
509
|
+
assert.strictEqual(result.stats.parsedLines, 3);
|
|
510
|
+
});
|
|
511
|
+
it('should return empty stats for non-existent file', () => {
|
|
512
|
+
const result = readJsonlSyncWithStats(path.join(testDir, 'nonexistent.jsonl'));
|
|
513
|
+
assert.deepStrictEqual(result.data, []);
|
|
514
|
+
assert.strictEqual(result.stats.totalLines, 0);
|
|
515
|
+
assert.strictEqual(result.stats.parsedLines, 0);
|
|
516
|
+
});
|
|
517
|
+
it('should track all stats together', () => {
|
|
518
|
+
const filePath = path.join(testDir, 'test.jsonl');
|
|
519
|
+
fs.writeFileSync(filePath, '{"id":1}\n\n{bad}\n{"id":2}\n \n{invalid}\n{"id":3}');
|
|
520
|
+
const result = readJsonlSyncWithStats(filePath);
|
|
521
|
+
assert.strictEqual(result.data.length, 3);
|
|
522
|
+
assert.strictEqual(result.stats.totalLines, 7);
|
|
523
|
+
assert.strictEqual(result.stats.parsedLines, 3);
|
|
524
|
+
assert.strictEqual(result.stats.skippedLines, 2);
|
|
525
|
+
assert.strictEqual(result.stats.emptyLines, 2);
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
describe('cleanupOldFiles', () => {
|
|
529
|
+
it('should return empty result for non-existent directory', () => {
|
|
530
|
+
const result = cleanupOldFiles(path.join(testDir, 'nonexistent'));
|
|
531
|
+
assert.strictEqual(result.deleted, 0);
|
|
532
|
+
assert.deepStrictEqual(result.errors, []);
|
|
533
|
+
});
|
|
534
|
+
it('should delete files older than retention period', () => {
|
|
535
|
+
// Create files with dates in the past
|
|
536
|
+
const oldDate = '2020-01-01';
|
|
537
|
+
const recentDate = new Date().toISOString().split('T')[0];
|
|
538
|
+
fs.writeFileSync(path.join(testDir, `traces-${oldDate}.jsonl`), '{}');
|
|
539
|
+
fs.writeFileSync(path.join(testDir, `logs-${oldDate}.jsonl`), '{}');
|
|
540
|
+
fs.writeFileSync(path.join(testDir, `traces-${recentDate}.jsonl`), '{}');
|
|
541
|
+
const result = cleanupOldFiles(testDir, 7);
|
|
542
|
+
assert.strictEqual(result.deleted, 2);
|
|
543
|
+
assert.deepStrictEqual(result.errors, []);
|
|
544
|
+
// Verify old files are deleted
|
|
545
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${oldDate}.jsonl`)), false);
|
|
546
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `logs-${oldDate}.jsonl`)), false);
|
|
547
|
+
// Verify recent file is kept
|
|
548
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${recentDate}.jsonl`)), true);
|
|
549
|
+
});
|
|
550
|
+
it('should not delete files within retention period', () => {
|
|
551
|
+
const today = new Date();
|
|
552
|
+
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
|
|
553
|
+
const yesterdayStr = yesterday.toISOString().split('T')[0];
|
|
554
|
+
fs.writeFileSync(path.join(testDir, `traces-${yesterdayStr}.jsonl`), '{}');
|
|
555
|
+
const result = cleanupOldFiles(testDir, 7);
|
|
556
|
+
assert.strictEqual(result.deleted, 0);
|
|
557
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${yesterdayStr}.jsonl`)), true);
|
|
558
|
+
});
|
|
559
|
+
it('should skip files without parseable dates', () => {
|
|
560
|
+
fs.writeFileSync(path.join(testDir, 'some-random-file.jsonl'), '{}');
|
|
561
|
+
fs.writeFileSync(path.join(testDir, 'no-date.jsonl'), '{}');
|
|
562
|
+
const result = cleanupOldFiles(testDir, 7);
|
|
563
|
+
assert.strictEqual(result.deleted, 0);
|
|
564
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, 'some-random-file.jsonl')), true);
|
|
565
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, 'no-date.jsonl')), true);
|
|
566
|
+
});
|
|
567
|
+
it('should only process .jsonl files', () => {
|
|
568
|
+
const oldDate = '2020-01-01';
|
|
569
|
+
fs.writeFileSync(path.join(testDir, `traces-${oldDate}.jsonl`), '{}');
|
|
570
|
+
fs.writeFileSync(path.join(testDir, `traces-${oldDate}.json`), '{}');
|
|
571
|
+
fs.writeFileSync(path.join(testDir, `traces-${oldDate}.txt`), 'text');
|
|
572
|
+
const result = cleanupOldFiles(testDir, 7);
|
|
573
|
+
assert.strictEqual(result.deleted, 1);
|
|
574
|
+
// Only .jsonl file should be deleted
|
|
575
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${oldDate}.jsonl`)), false);
|
|
576
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${oldDate}.json`)), true);
|
|
577
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${oldDate}.txt`)), true);
|
|
578
|
+
});
|
|
579
|
+
it('should respect custom retention period', () => {
|
|
580
|
+
const today = new Date();
|
|
581
|
+
// Create file from 5 days ago
|
|
582
|
+
const fiveDaysAgo = new Date(today.getTime() - 5 * 24 * 60 * 60 * 1000);
|
|
583
|
+
const fiveDaysAgoStr = fiveDaysAgo.toISOString().split('T')[0];
|
|
584
|
+
fs.writeFileSync(path.join(testDir, `traces-${fiveDaysAgoStr}.jsonl`), '{}');
|
|
585
|
+
// With 7 day retention, file should be kept
|
|
586
|
+
let result = cleanupOldFiles(testDir, 7);
|
|
587
|
+
assert.strictEqual(result.deleted, 0);
|
|
588
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${fiveDaysAgoStr}.jsonl`)), true);
|
|
589
|
+
// With 3 day retention, file should be deleted
|
|
590
|
+
result = cleanupOldFiles(testDir, 3);
|
|
591
|
+
assert.strictEqual(result.deleted, 1);
|
|
592
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${fiveDaysAgoStr}.jsonl`)), false);
|
|
593
|
+
});
|
|
594
|
+
it('should handle empty directory', () => {
|
|
595
|
+
const result = cleanupOldFiles(testDir, 7);
|
|
596
|
+
assert.strictEqual(result.deleted, 0);
|
|
597
|
+
assert.deepStrictEqual(result.errors, []);
|
|
598
|
+
});
|
|
599
|
+
it('should reject directories outside allowed paths', () => {
|
|
600
|
+
const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), 'outside-'));
|
|
601
|
+
try {
|
|
602
|
+
fs.writeFileSync(path.join(outsideDir, 'traces-2020-01-01.jsonl'), '{}');
|
|
603
|
+
const result = cleanupOldFiles(outsideDir, 7, [testDir]);
|
|
604
|
+
assert.strictEqual(result.deleted, 0);
|
|
605
|
+
assert.strictEqual(result.errors.length, 1);
|
|
606
|
+
assert(result.errors[0].includes('not within allowed paths'));
|
|
607
|
+
// File should still exist
|
|
608
|
+
assert.strictEqual(fs.existsSync(path.join(outsideDir, 'traces-2020-01-01.jsonl')), true);
|
|
609
|
+
}
|
|
610
|
+
finally {
|
|
611
|
+
fs.rmSync(outsideDir, { recursive: true, force: true });
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
it('should allow directories within allowed paths', () => {
|
|
615
|
+
const subDir = path.join(testDir, 'subdir');
|
|
616
|
+
fs.mkdirSync(subDir);
|
|
617
|
+
fs.writeFileSync(path.join(subDir, 'traces-2020-01-01.jsonl'), '{}');
|
|
618
|
+
const result = cleanupOldFiles(subDir, 7, [testDir]);
|
|
619
|
+
assert.strictEqual(result.deleted, 1);
|
|
620
|
+
assert.deepStrictEqual(result.errors, []);
|
|
621
|
+
});
|
|
622
|
+
it('should handle file types: traces, logs, metrics', () => {
|
|
623
|
+
const oldDate = '2020-01-01';
|
|
624
|
+
fs.writeFileSync(path.join(testDir, `traces-${oldDate}.jsonl`), '{}');
|
|
625
|
+
fs.writeFileSync(path.join(testDir, `logs-${oldDate}.jsonl`), '{}');
|
|
626
|
+
fs.writeFileSync(path.join(testDir, `metrics-${oldDate}.jsonl`), '{}');
|
|
627
|
+
const result = cleanupOldFiles(testDir, 7);
|
|
628
|
+
assert.strictEqual(result.deleted, 3);
|
|
629
|
+
assert.deepStrictEqual(result.errors, []);
|
|
630
|
+
});
|
|
631
|
+
it('should use default retention of 7 days', () => {
|
|
632
|
+
const today = new Date();
|
|
633
|
+
// Create file from 8 days ago
|
|
634
|
+
const eightDaysAgo = new Date(today.getTime() - 8 * 24 * 60 * 60 * 1000);
|
|
635
|
+
const eightDaysAgoStr = eightDaysAgo.toISOString().split('T')[0];
|
|
636
|
+
// Create file from 6 days ago
|
|
637
|
+
const sixDaysAgo = new Date(today.getTime() - 6 * 24 * 60 * 60 * 1000);
|
|
638
|
+
const sixDaysAgoStr = sixDaysAgo.toISOString().split('T')[0];
|
|
639
|
+
fs.writeFileSync(path.join(testDir, `traces-${eightDaysAgoStr}.jsonl`), '{}');
|
|
640
|
+
fs.writeFileSync(path.join(testDir, `traces-${sixDaysAgoStr}.jsonl`), '{}');
|
|
641
|
+
// Use default retention (7 days)
|
|
642
|
+
const result = cleanupOldFiles(testDir);
|
|
643
|
+
assert.strictEqual(result.deleted, 1);
|
|
644
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${eightDaysAgoStr}.jsonl`)), false);
|
|
645
|
+
assert.strictEqual(fs.existsSync(path.join(testDir, `traces-${sixDaysAgoStr}.jsonl`)), true);
|
|
646
|
+
});
|
|
647
|
+
});
|
|
421
648
|
});
|
|
422
649
|
//# sourceMappingURL=file-utils.test.js.map
|