bun-git-hooks 0.2.14 → 0.2.16
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/dist/bin/cli.js +725 -3605
- package/dist/git-hooks.d.ts +13 -10
- package/dist/index.js +370 -3250
- package/package.json +6 -5
- package/dist/bin/config.d.ts +0 -3
- package/dist/bin/git-hooks.d.ts +0 -61
- package/dist/bin/index.d.ts +0 -3
- package/dist/bin/types.d.ts +0 -20
package/dist/index.js
CHANGED
|
@@ -18,27 +18,12 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
20
|
// src/config.ts
|
|
21
|
-
import
|
|
21
|
+
import process2 from "node:process";
|
|
22
22
|
|
|
23
23
|
// node_modules/bunfig/dist/index.js
|
|
24
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
25
|
-
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
26
|
-
import process6 from "process";
|
|
27
|
-
import { join, relative, resolve as resolve2 } from "path";
|
|
28
|
-
import process2 from "process";
|
|
29
24
|
import { existsSync, mkdirSync, readdirSync, writeFileSync } from "fs";
|
|
30
25
|
import { dirname, resolve } from "path";
|
|
31
26
|
import process from "process";
|
|
32
|
-
import { Buffer } from "buffer";
|
|
33
|
-
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
34
|
-
import { closeSync, createReadStream, createWriteStream, existsSync as existsSync2, fsyncSync, openSync, writeFileSync as writeFileSync2 } from "fs";
|
|
35
|
-
import { access, constants, mkdir, readdir, rename, stat, unlink, writeFile } from "fs/promises";
|
|
36
|
-
import { join as join2 } from "path";
|
|
37
|
-
import process5 from "process";
|
|
38
|
-
import { pipeline } from "stream/promises";
|
|
39
|
-
import { createGzip } from "zlib";
|
|
40
|
-
import process4 from "process";
|
|
41
|
-
import process3 from "process";
|
|
42
27
|
function deepMerge(target, source) {
|
|
43
28
|
if (Array.isArray(source) && Array.isArray(target) && source.length === 2 && target.length === 2 && isObject(source[0]) && "id" in source[0] && source[0].id === 3 && isObject(source[1]) && "id" in source[1] && source[1].id === 4) {
|
|
44
29
|
return source;
|
|
@@ -198,2978 +183,77 @@ async function loadConfig({
|
|
|
198
183
|
for (const ext of extensions) {
|
|
199
184
|
const fullPath = resolve(baseDir, `${configPath}${ext}`);
|
|
200
185
|
const config2 = await tryLoadConfig(fullPath, defaultConfig);
|
|
201
|
-
if (config2 !== null)
|
|
186
|
+
if (config2 !== null) {
|
|
202
187
|
return config2;
|
|
188
|
+
}
|
|
203
189
|
}
|
|
204
190
|
}
|
|
205
|
-
|
|
191
|
+
try {
|
|
192
|
+
const pkgPath = resolve(baseDir, "package.json");
|
|
193
|
+
if (existsSync(pkgPath)) {
|
|
194
|
+
const pkg = await import(pkgPath);
|
|
195
|
+
const pkgConfig = pkg[name];
|
|
196
|
+
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
197
|
+
try {
|
|
198
|
+
return deepMerge(defaultConfig, pkgConfig);
|
|
199
|
+
} catch {}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} catch {}
|
|
206
203
|
return defaultConfig;
|
|
207
204
|
}
|
|
208
205
|
var defaultConfigDir = resolve(process.cwd(), "config");
|
|
209
206
|
var defaultGeneratedDir = resolve(process.cwd(), "src/generated");
|
|
210
|
-
function getProjectRoot(filePath, options = {}) {
|
|
211
|
-
let path = process2.cwd();
|
|
212
|
-
while (path.includes("storage"))
|
|
213
|
-
path = resolve2(path, "..");
|
|
214
|
-
const finalPath = resolve2(path, filePath || "");
|
|
215
|
-
if (options?.relative)
|
|
216
|
-
return relative(process2.cwd(), finalPath);
|
|
217
|
-
return finalPath;
|
|
218
|
-
}
|
|
219
|
-
var defaultLogDirectory = process2.env.CLARITY_LOG_DIR || join(getProjectRoot(), "logs");
|
|
220
|
-
var defaultConfig = {
|
|
221
|
-
level: "info",
|
|
222
|
-
defaultName: "clarity",
|
|
223
|
-
timestamp: true,
|
|
224
|
-
colors: true,
|
|
225
|
-
format: "text",
|
|
226
|
-
maxLogSize: 10485760,
|
|
227
|
-
logDatePattern: "YYYY-MM-DD",
|
|
228
|
-
logDirectory: defaultLogDirectory,
|
|
229
|
-
rotation: {
|
|
230
|
-
frequency: "daily",
|
|
231
|
-
maxSize: 10485760,
|
|
232
|
-
maxFiles: 5,
|
|
233
|
-
compress: false,
|
|
234
|
-
rotateHour: 0,
|
|
235
|
-
rotateMinute: 0,
|
|
236
|
-
rotateDayOfWeek: 0,
|
|
237
|
-
rotateDayOfMonth: 1,
|
|
238
|
-
encrypt: false
|
|
239
|
-
},
|
|
240
|
-
verbose: false
|
|
241
|
-
};
|
|
242
|
-
async function loadConfig2() {
|
|
243
|
-
try {
|
|
244
|
-
const loadedConfig = await loadConfig({
|
|
245
|
-
name: "clarity",
|
|
246
|
-
defaultConfig,
|
|
247
|
-
cwd: process2.cwd(),
|
|
248
|
-
endpoint: "",
|
|
249
|
-
headers: {}
|
|
250
|
-
});
|
|
251
|
-
return { ...defaultConfig, ...loadedConfig };
|
|
252
|
-
} catch {
|
|
253
|
-
return defaultConfig;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
var config = await loadConfig2();
|
|
257
|
-
function isBrowserProcess() {
|
|
258
|
-
if (process3.env.NODE_ENV === "test" || process3.env.BUN_ENV === "test") {
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
return typeof window !== "undefined";
|
|
262
|
-
}
|
|
263
|
-
async function isServerProcess() {
|
|
264
|
-
if (process3.env.NODE_ENV === "test" || process3.env.BUN_ENV === "test") {
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
267
|
-
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
268
|
-
return true;
|
|
269
|
-
}
|
|
270
|
-
if (typeof process3 !== "undefined") {
|
|
271
|
-
const type = process3.type;
|
|
272
|
-
if (type === "renderer" || type === "worker") {
|
|
273
|
-
return false;
|
|
274
|
-
}
|
|
275
|
-
return !!(process3.versions && (process3.versions.node || process3.versions.bun));
|
|
276
|
-
}
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
class JsonFormatter {
|
|
281
|
-
async format(entry) {
|
|
282
|
-
const isServer = await isServerProcess();
|
|
283
|
-
const metadata = await this.getMetadata(isServer);
|
|
284
|
-
return JSON.stringify({
|
|
285
|
-
timestamp: entry.timestamp.toISOString(),
|
|
286
|
-
level: entry.level,
|
|
287
|
-
name: entry.name,
|
|
288
|
-
message: entry.message,
|
|
289
|
-
metadata
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
async getMetadata(isServer) {
|
|
293
|
-
if (isServer) {
|
|
294
|
-
const { hostname } = await import("os");
|
|
295
|
-
return {
|
|
296
|
-
pid: process4.pid,
|
|
297
|
-
hostname: hostname(),
|
|
298
|
-
environment: process4.env.NODE_ENV || "development",
|
|
299
|
-
platform: process4.platform,
|
|
300
|
-
version: process4.version
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
return {
|
|
304
|
-
userAgent: navigator.userAgent,
|
|
305
|
-
hostname: window.location.hostname || "browser",
|
|
306
|
-
environment: process4.env.NODE_ENV || process4.env.BUN_ENV || "development",
|
|
307
|
-
viewport: {
|
|
308
|
-
width: window.innerWidth,
|
|
309
|
-
height: window.innerHeight
|
|
310
|
-
},
|
|
311
|
-
language: navigator.language
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
var terminalStyles = {
|
|
316
|
-
red: (text) => `\x1B[31m${text}\x1B[0m`,
|
|
317
|
-
green: (text) => `\x1B[32m${text}\x1B[0m`,
|
|
318
|
-
yellow: (text) => `\x1B[33m${text}\x1B[0m`,
|
|
319
|
-
blue: (text) => `\x1B[34m${text}\x1B[0m`,
|
|
320
|
-
magenta: (text) => `\x1B[35m${text}\x1B[0m`,
|
|
321
|
-
cyan: (text) => `\x1B[36m${text}\x1B[0m`,
|
|
322
|
-
white: (text) => `\x1B[37m${text}\x1B[0m`,
|
|
323
|
-
gray: (text) => `\x1B[90m${text}\x1B[0m`,
|
|
324
|
-
bgRed: (text) => `\x1B[41m${text}\x1B[0m`,
|
|
325
|
-
bgYellow: (text) => `\x1B[43m${text}\x1B[0m`,
|
|
326
|
-
bold: (text) => `\x1B[1m${text}\x1B[0m`,
|
|
327
|
-
dim: (text) => `\x1B[2m${text}\x1B[0m`,
|
|
328
|
-
italic: (text) => `\x1B[3m${text}\x1B[0m`,
|
|
329
|
-
underline: (text) => `\x1B[4m${text}\x1B[0m`,
|
|
330
|
-
reset: "\x1B[0m"
|
|
331
|
-
};
|
|
332
|
-
var styles = terminalStyles;
|
|
333
|
-
var red = terminalStyles.red;
|
|
334
|
-
var green = terminalStyles.green;
|
|
335
|
-
var yellow = terminalStyles.yellow;
|
|
336
|
-
var blue = terminalStyles.blue;
|
|
337
|
-
var magenta = terminalStyles.magenta;
|
|
338
|
-
var cyan = terminalStyles.cyan;
|
|
339
|
-
var white = terminalStyles.white;
|
|
340
|
-
var gray = terminalStyles.gray;
|
|
341
|
-
var bgRed = terminalStyles.bgRed;
|
|
342
|
-
var bgYellow = terminalStyles.bgYellow;
|
|
343
|
-
var bold = terminalStyles.bold;
|
|
344
|
-
var dim = terminalStyles.dim;
|
|
345
|
-
var italic = terminalStyles.italic;
|
|
346
|
-
var underline = terminalStyles.underline;
|
|
347
|
-
var reset = terminalStyles.reset;
|
|
348
|
-
var defaultFingersCrossedConfig = {
|
|
349
|
-
activationLevel: "error",
|
|
350
|
-
bufferSize: 50,
|
|
351
|
-
flushOnDeactivation: true,
|
|
352
|
-
stopBuffering: false
|
|
353
|
-
};
|
|
354
|
-
var levelIcons = {
|
|
355
|
-
debug: "\uD83D\uDD0D",
|
|
356
|
-
info: blue("ℹ"),
|
|
357
|
-
success: green("✓"),
|
|
358
|
-
warning: bgYellow(white(bold(" WARN "))),
|
|
359
|
-
error: bgRed(white(bold(" ERROR ")))
|
|
360
|
-
};
|
|
361
207
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
timers = new Set;
|
|
371
|
-
subLoggers = new Set;
|
|
372
|
-
fingersCrossedBuffer = [];
|
|
373
|
-
fingersCrossedConfig;
|
|
374
|
-
fingersCrossedActive = false;
|
|
375
|
-
currentLogFile;
|
|
376
|
-
rotationTimeout;
|
|
377
|
-
keyRotationTimeout;
|
|
378
|
-
encryptionKeys;
|
|
379
|
-
logBuffer = [];
|
|
380
|
-
isActivated = false;
|
|
381
|
-
pendingOperations = [];
|
|
382
|
-
enabled;
|
|
383
|
-
fancy;
|
|
384
|
-
tagFormat;
|
|
385
|
-
timestampPosition;
|
|
386
|
-
environment;
|
|
387
|
-
ANSI_PATTERN = /\u001B\[.*?m/g;
|
|
388
|
-
activeProgressBar = null;
|
|
389
|
-
constructor(name, options = {}) {
|
|
390
|
-
this.name = name;
|
|
391
|
-
this.config = { ...config };
|
|
392
|
-
this.options = this.normalizeOptions(options);
|
|
393
|
-
this.formatter = this.options.formatter || new JsonFormatter;
|
|
394
|
-
this.enabled = options.enabled ?? true;
|
|
395
|
-
this.fancy = options.fancy ?? true;
|
|
396
|
-
this.tagFormat = options.tagFormat ?? { prefix: "[", suffix: "]" };
|
|
397
|
-
this.timestampPosition = options.timestampPosition ?? "right";
|
|
398
|
-
this.environment = options.environment ?? process5.env.APP_ENV ?? "local";
|
|
399
|
-
this.fingersCrossedConfig = this.initializeFingersCrossedConfig(options);
|
|
400
|
-
const configOptions = { ...options };
|
|
401
|
-
const hasTimestamp = options.timestamp !== undefined;
|
|
402
|
-
if (hasTimestamp) {
|
|
403
|
-
delete configOptions.timestamp;
|
|
404
|
-
}
|
|
405
|
-
this.config = {
|
|
406
|
-
...this.config,
|
|
407
|
-
...configOptions,
|
|
408
|
-
timestamp: hasTimestamp || this.config.timestamp
|
|
409
|
-
};
|
|
410
|
-
if (!this.config.logDirectory) {
|
|
411
|
-
this.config.logDirectory = config.logDirectory;
|
|
412
|
-
}
|
|
413
|
-
if (!isBrowserProcess()) {
|
|
414
|
-
mkdir(this.config.logDirectory, { recursive: true, mode: 493 }).catch((err) => console.error("Failed to create log directory:", err));
|
|
415
|
-
}
|
|
416
|
-
this.currentLogFile = this.generateLogFilename();
|
|
417
|
-
this.encryptionKeys = new Map;
|
|
418
|
-
if (this.validateEncryptionConfig()) {
|
|
419
|
-
this.setupRotation();
|
|
420
|
-
const initialKeyId = this.generateKeyId();
|
|
421
|
-
const initialKey = this.generateKey();
|
|
422
|
-
this.currentKeyId = initialKeyId;
|
|
423
|
-
this.keys.set(initialKeyId, initialKey);
|
|
424
|
-
this.encryptionKeys.set(initialKeyId, {
|
|
425
|
-
key: initialKey,
|
|
426
|
-
createdAt: new Date
|
|
427
|
-
});
|
|
428
|
-
this.setupKeyRotation();
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
initializeFingersCrossedConfig(options) {
|
|
432
|
-
if (!options.fingersCrossedEnabled && options.fingersCrossed) {
|
|
433
|
-
return {
|
|
434
|
-
...defaultFingersCrossedConfig,
|
|
435
|
-
...options.fingersCrossed
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
if (!options.fingersCrossedEnabled) {
|
|
439
|
-
return null;
|
|
440
|
-
}
|
|
441
|
-
if (!options.fingersCrossed) {
|
|
442
|
-
return { ...defaultFingersCrossedConfig };
|
|
208
|
+
// git-hooks.config.ts
|
|
209
|
+
var config = {
|
|
210
|
+
"pre-commit": {
|
|
211
|
+
"staged-lint": {
|
|
212
|
+
"**/*.{js,ts}": [
|
|
213
|
+
"bunx --bun eslint --max-warnings=0",
|
|
214
|
+
"bunx --bun tsc --noEmit"
|
|
215
|
+
]
|
|
443
216
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
await access(this.config.logDirectory, constants.F_OK | constants.W_OK);
|
|
482
|
-
} catch (err) {
|
|
483
|
-
if (err instanceof Error && "code" in err) {
|
|
484
|
-
if (err.code === "ENOENT") {
|
|
485
|
-
await mkdir(this.config.logDirectory, { recursive: true, mode: 493 });
|
|
486
|
-
} else if (err.code === "EACCES") {
|
|
487
|
-
throw new Error(`No write permission for log directory: ${this.config.logDirectory}`);
|
|
488
|
-
} else {
|
|
489
|
-
throw err;
|
|
490
|
-
}
|
|
491
|
-
} else {
|
|
492
|
-
throw err;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
} catch (err) {
|
|
496
|
-
console.error("Debug: [writeToFile] Failed to create log directory:", err);
|
|
497
|
-
throw err;
|
|
498
|
-
}
|
|
499
|
-
if (cancelled)
|
|
500
|
-
throw new Error("Operation cancelled: Logger was destroyed");
|
|
501
|
-
const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer.from(data);
|
|
502
|
-
try {
|
|
503
|
-
if (!existsSync2(this.currentLogFile)) {
|
|
504
|
-
await writeFile(this.currentLogFile, "", { mode: 420 });
|
|
505
|
-
}
|
|
506
|
-
fd = openSync(this.currentLogFile, "a", 420);
|
|
507
|
-
writeFileSync2(fd, dataToWrite, { flag: "a" });
|
|
508
|
-
fsyncSync(fd);
|
|
509
|
-
if (fd !== undefined) {
|
|
510
|
-
closeSync(fd);
|
|
511
|
-
fd = undefined;
|
|
512
|
-
}
|
|
513
|
-
const stats = await stat(this.currentLogFile);
|
|
514
|
-
if (stats.size === 0) {
|
|
515
|
-
await writeFile(this.currentLogFile, dataToWrite, { flag: "w", mode: 420 });
|
|
516
|
-
const retryStats = await stat(this.currentLogFile);
|
|
517
|
-
if (retryStats.size === 0) {
|
|
518
|
-
throw new Error("File exists but is empty after retry write");
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
return;
|
|
522
|
-
} catch (err) {
|
|
523
|
-
const error = err;
|
|
524
|
-
if (error.code && ["ENETDOWN", "ENETUNREACH", "ENOTFOUND", "ETIMEDOUT"].includes(error.code)) {
|
|
525
|
-
if (retries < maxRetries - 1) {
|
|
526
|
-
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
527
|
-
console.error(`Network error during write attempt ${retries + 1}/${maxRetries}:`, errorMessage);
|
|
528
|
-
const delay = backoffDelay * 2 ** retries;
|
|
529
|
-
await new Promise((resolve32) => setTimeout(resolve32, delay));
|
|
530
|
-
retries++;
|
|
531
|
-
continue;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
if (error?.code && ["ENOSPC", "EDQUOT"].includes(error.code)) {
|
|
535
|
-
throw new Error(`Disk quota exceeded or no space left on device: ${error.message}`);
|
|
536
|
-
}
|
|
537
|
-
console.error("Debug: [writeToFile] Error writing to file:", error);
|
|
538
|
-
throw error;
|
|
539
|
-
} finally {
|
|
540
|
-
if (fd !== undefined) {
|
|
541
|
-
try {
|
|
542
|
-
closeSync(fd);
|
|
543
|
-
} catch (err) {
|
|
544
|
-
console.error("Debug: [writeToFile] Error closing file descriptor:", err);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
} catch (err) {
|
|
549
|
-
if (retries === maxRetries - 1) {
|
|
550
|
-
const error = err;
|
|
551
|
-
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
552
|
-
console.error("Debug: [writeToFile] Max retries reached. Final error:", errorMessage);
|
|
553
|
-
throw err;
|
|
554
|
-
}
|
|
555
|
-
retries++;
|
|
556
|
-
const delay = backoffDelay * 2 ** (retries - 1);
|
|
557
|
-
await new Promise((resolve32) => setTimeout(resolve32, delay));
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
})();
|
|
561
|
-
this.pendingOperations.push(operationPromise);
|
|
562
|
-
const index = this.pendingOperations.length - 1;
|
|
563
|
-
try {
|
|
564
|
-
await operationPromise;
|
|
565
|
-
} catch (err) {
|
|
566
|
-
console.error("Debug: [writeToFile] Error in operation:", err);
|
|
567
|
-
throw err;
|
|
568
|
-
} finally {
|
|
569
|
-
this.pendingOperations.splice(index, 1);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
generateLogFilename() {
|
|
573
|
-
if (this.name.includes("stream-throughput") || this.name.includes("decompress-perf-test") || this.name.includes("decompression-latency") || this.name.includes("concurrent-read-test") || this.name.includes("clock-change-test")) {
|
|
574
|
-
return join2(this.config.logDirectory, `${this.name}.log`);
|
|
575
|
-
}
|
|
576
|
-
if (this.name.includes("pending-test") || this.name.includes("temp-file-test") || this.name === "crash-test" || this.name === "corrupt-test" || this.name.includes("rotation-load-test") || this.name === "sigterm-test" || this.name === "sigint-test" || this.name === "failed-rotation-test" || this.name === "integration-test") {
|
|
577
|
-
return join2(this.config.logDirectory, `${this.name}.log`);
|
|
578
|
-
}
|
|
579
|
-
const date = new Date().toISOString().split("T")[0];
|
|
580
|
-
return join2(this.config.logDirectory, `${this.name}-${date}.log`);
|
|
581
|
-
}
|
|
582
|
-
setupRotation() {
|
|
583
|
-
if (isBrowserProcess())
|
|
584
|
-
return;
|
|
585
|
-
if (typeof this.config.rotation === "boolean")
|
|
586
|
-
return;
|
|
587
|
-
const config2 = this.config.rotation;
|
|
588
|
-
let interval;
|
|
589
|
-
switch (config2.frequency) {
|
|
590
|
-
case "daily":
|
|
591
|
-
interval = 86400000;
|
|
592
|
-
break;
|
|
593
|
-
case "weekly":
|
|
594
|
-
interval = 604800000;
|
|
595
|
-
break;
|
|
596
|
-
case "monthly":
|
|
597
|
-
interval = 2592000000;
|
|
598
|
-
break;
|
|
599
|
-
default:
|
|
600
|
-
return;
|
|
601
|
-
}
|
|
602
|
-
this.rotationTimeout = setInterval(() => {
|
|
603
|
-
this.rotateLog();
|
|
604
|
-
}, interval);
|
|
605
|
-
}
|
|
606
|
-
setupKeyRotation() {
|
|
607
|
-
if (!this.validateEncryptionConfig()) {
|
|
608
|
-
console.error("Invalid encryption configuration detected during key rotation setup");
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
const rotation = this.config.rotation;
|
|
612
|
-
const keyRotation = rotation.keyRotation;
|
|
613
|
-
if (!keyRotation?.enabled) {
|
|
614
|
-
return;
|
|
615
|
-
}
|
|
616
|
-
const rotationInterval = typeof keyRotation.interval === "number" ? keyRotation.interval : 60;
|
|
617
|
-
const interval = Math.max(rotationInterval, 60) * 1000;
|
|
618
|
-
this.keyRotationTimeout = setInterval(() => {
|
|
619
|
-
this.rotateKeys().catch((error) => {
|
|
620
|
-
console.error("Error rotating keys:", error);
|
|
621
|
-
});
|
|
622
|
-
}, interval);
|
|
623
|
-
}
|
|
624
|
-
async rotateKeys() {
|
|
625
|
-
if (!this.validateEncryptionConfig()) {
|
|
626
|
-
console.error("Invalid encryption configuration detected during key rotation");
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
const rotation = this.config.rotation;
|
|
630
|
-
const keyRotation = rotation.keyRotation;
|
|
631
|
-
const newKeyId = this.generateKeyId();
|
|
632
|
-
const newKey = this.generateKey();
|
|
633
|
-
this.currentKeyId = newKeyId;
|
|
634
|
-
this.keys.set(newKeyId, newKey);
|
|
635
|
-
this.encryptionKeys.set(newKeyId, {
|
|
636
|
-
key: newKey,
|
|
637
|
-
createdAt: new Date
|
|
638
|
-
});
|
|
639
|
-
const sortedKeys = Array.from(this.encryptionKeys.entries()).sort(([, a], [, b]) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
640
|
-
const maxKeyCount = typeof keyRotation.maxKeys === "number" ? keyRotation.maxKeys : 1;
|
|
641
|
-
const maxKeys = Math.max(1, maxKeyCount);
|
|
642
|
-
if (sortedKeys.length > maxKeys) {
|
|
643
|
-
for (const [keyId] of sortedKeys.slice(maxKeys)) {
|
|
644
|
-
this.encryptionKeys.delete(keyId);
|
|
645
|
-
this.keys.delete(keyId);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
generateKeyId() {
|
|
650
|
-
return randomBytes(16).toString("hex");
|
|
651
|
-
}
|
|
652
|
-
generateKey() {
|
|
653
|
-
return randomBytes(32);
|
|
654
|
-
}
|
|
655
|
-
getCurrentKey() {
|
|
656
|
-
if (!this.currentKeyId) {
|
|
657
|
-
throw new Error("Encryption is not properly initialized. Make sure encryption is enabled in the configuration.");
|
|
658
|
-
}
|
|
659
|
-
const key = this.keys.get(this.currentKeyId);
|
|
660
|
-
if (!key) {
|
|
661
|
-
throw new Error(`No key found for ID ${this.currentKeyId}. The encryption key may have been rotated or removed.`);
|
|
662
|
-
}
|
|
663
|
-
return { key, id: this.currentKeyId };
|
|
664
|
-
}
|
|
665
|
-
encrypt(data) {
|
|
666
|
-
const { key } = this.getCurrentKey();
|
|
667
|
-
const iv = randomBytes(16);
|
|
668
|
-
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
669
|
-
const encrypted = Buffer.concat([
|
|
670
|
-
cipher.update(data, "utf8"),
|
|
671
|
-
cipher.final()
|
|
672
|
-
]);
|
|
673
|
-
const authTag = cipher.getAuthTag();
|
|
674
|
-
return {
|
|
675
|
-
encrypted: Buffer.concat([iv, encrypted, authTag]),
|
|
676
|
-
iv
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
async compressData(data) {
|
|
680
|
-
return new Promise((resolve32, reject) => {
|
|
681
|
-
const gzip = createGzip();
|
|
682
|
-
const chunks = [];
|
|
683
|
-
gzip.on("data", (chunk2) => chunks.push(chunk2));
|
|
684
|
-
gzip.on("end", () => resolve32(Buffer.from(Buffer.concat(chunks))));
|
|
685
|
-
gzip.on("error", reject);
|
|
686
|
-
gzip.write(data);
|
|
687
|
-
gzip.end();
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
getEncryptionOptions() {
|
|
691
|
-
if (!this.config.rotation || typeof this.config.rotation === "boolean" || !this.config.rotation.encrypt) {
|
|
692
|
-
return {};
|
|
693
|
-
}
|
|
694
|
-
const defaultOptions = {
|
|
695
|
-
algorithm: "aes-256-cbc",
|
|
696
|
-
compress: false
|
|
697
|
-
};
|
|
698
|
-
if (typeof this.config.rotation.encrypt === "object") {
|
|
699
|
-
const encryptConfig = this.config.rotation.encrypt;
|
|
700
|
-
return {
|
|
701
|
-
...defaultOptions,
|
|
702
|
-
...encryptConfig
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
return defaultOptions;
|
|
706
|
-
}
|
|
707
|
-
async rotateLog() {
|
|
708
|
-
if (isBrowserProcess())
|
|
709
|
-
return;
|
|
710
|
-
const stats = await stat(this.currentLogFile).catch(() => null);
|
|
711
|
-
if (!stats)
|
|
712
|
-
return;
|
|
713
|
-
const config2 = this.config.rotation;
|
|
714
|
-
if (typeof config2 === "boolean")
|
|
715
|
-
return;
|
|
716
|
-
if (config2.maxSize && stats.size >= config2.maxSize) {
|
|
717
|
-
const oldFile = this.currentLogFile;
|
|
718
|
-
const newFile = this.generateLogFilename();
|
|
719
|
-
if (this.name.includes("rotation-load-test") || this.name === "failed-rotation-test") {
|
|
720
|
-
const files = await readdir(this.config.logDirectory);
|
|
721
|
-
const rotatedFiles = files.filter((f) => f.startsWith(this.name) && /\.log\.\d+$/.test(f)).sort((a, b) => {
|
|
722
|
-
const numA = Number.parseInt(a.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
723
|
-
const numB = Number.parseInt(b.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
724
|
-
return numB - numA;
|
|
725
|
-
});
|
|
726
|
-
const nextNum = rotatedFiles.length > 0 ? Number.parseInt(rotatedFiles[0].match(/\.log\.(\d+)$/)?.[1] || "0") + 1 : 1;
|
|
727
|
-
const rotatedFile = `${oldFile}.${nextNum}`;
|
|
728
|
-
if (await stat(oldFile).catch(() => null)) {
|
|
729
|
-
try {
|
|
730
|
-
await rename(oldFile, rotatedFile);
|
|
731
|
-
if (config2.compress) {
|
|
732
|
-
try {
|
|
733
|
-
const compressedPath = `${rotatedFile}.gz`;
|
|
734
|
-
await this.compressLogFile(rotatedFile, compressedPath);
|
|
735
|
-
await unlink(rotatedFile);
|
|
736
|
-
} catch (err) {
|
|
737
|
-
console.error("Error compressing rotated file:", err);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
if (rotatedFiles.length === 0 && !files.some((f) => f.endsWith(".log.1"))) {
|
|
741
|
-
try {
|
|
742
|
-
const backupPath = `${oldFile}.1`;
|
|
743
|
-
await writeFile(backupPath, "");
|
|
744
|
-
} catch (err) {
|
|
745
|
-
console.error("Error creating backup file:", err);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
} catch (err) {
|
|
749
|
-
console.error(`Error during rotation: ${err instanceof Error ? err.message : String(err)}`);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
} else {
|
|
753
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
754
|
-
const rotatedFile = oldFile.replace(/\.log$/, `-${timestamp}.log`);
|
|
755
|
-
if (await stat(oldFile).catch(() => null)) {
|
|
756
|
-
await rename(oldFile, rotatedFile);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
this.currentLogFile = newFile;
|
|
760
|
-
if (config2.maxFiles) {
|
|
761
|
-
const files = await readdir(this.config.logDirectory);
|
|
762
|
-
const logFiles = files.filter((f) => f.startsWith(this.name)).sort((a, b) => b.localeCompare(a));
|
|
763
|
-
for (const file of logFiles.slice(config2.maxFiles)) {
|
|
764
|
-
await unlink(join2(this.config.logDirectory, file));
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
async compressLogFile(inputPath, outputPath) {
|
|
770
|
-
const readStream = createReadStream(inputPath);
|
|
771
|
-
const writeStream = createWriteStream(outputPath);
|
|
772
|
-
const gzip = createGzip();
|
|
773
|
-
await pipeline(readStream, gzip, writeStream);
|
|
774
|
-
}
|
|
775
|
-
async handleFingersCrossedBuffer(level, formattedEntry) {
|
|
776
|
-
if (!this.fingersCrossedConfig)
|
|
777
|
-
return;
|
|
778
|
-
if (this.shouldActivateFingersCrossed(level) && !this.isActivated) {
|
|
779
|
-
this.isActivated = true;
|
|
780
|
-
for (const entry of this.logBuffer) {
|
|
781
|
-
const formattedBufferedEntry = await this.formatter.format(entry);
|
|
782
|
-
await this.writeToFile(formattedBufferedEntry);
|
|
783
|
-
console.log(formattedBufferedEntry);
|
|
784
|
-
}
|
|
785
|
-
if (this.fingersCrossedConfig.stopBuffering)
|
|
786
|
-
this.logBuffer = [];
|
|
787
|
-
}
|
|
788
|
-
if (this.isActivated) {
|
|
789
|
-
await this.writeToFile(formattedEntry);
|
|
790
|
-
console.log(formattedEntry);
|
|
791
|
-
} else {
|
|
792
|
-
if (this.logBuffer.length >= this.fingersCrossedConfig.bufferSize)
|
|
793
|
-
this.logBuffer.shift();
|
|
794
|
-
const entry = {
|
|
795
|
-
timestamp: new Date,
|
|
796
|
-
level,
|
|
797
|
-
message: formattedEntry,
|
|
798
|
-
name: this.name
|
|
799
|
-
};
|
|
800
|
-
this.logBuffer.push(entry);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
shouldActivateFingersCrossed(level) {
|
|
804
|
-
if (!this.fingersCrossedConfig)
|
|
805
|
-
return false;
|
|
806
|
-
return this.getLevelValue(level) >= this.getLevelValue(this.fingersCrossedConfig.activationLevel);
|
|
807
|
-
}
|
|
808
|
-
getLevelValue(level) {
|
|
809
|
-
const levels = {
|
|
810
|
-
debug: 0,
|
|
811
|
-
info: 1,
|
|
812
|
-
success: 2,
|
|
813
|
-
warning: 3,
|
|
814
|
-
error: 4
|
|
815
|
-
};
|
|
816
|
-
return levels[level];
|
|
817
|
-
}
|
|
818
|
-
shouldLog(level) {
|
|
819
|
-
if (!this.enabled)
|
|
820
|
-
return false;
|
|
821
|
-
const levels = {
|
|
822
|
-
debug: 0,
|
|
823
|
-
info: 1,
|
|
824
|
-
success: 2,
|
|
825
|
-
warning: 3,
|
|
826
|
-
error: 4
|
|
827
|
-
};
|
|
828
|
-
return levels[level] >= levels[this.config.level];
|
|
829
|
-
}
|
|
830
|
-
async flushPendingWrites() {
|
|
831
|
-
await Promise.all(this.pendingOperations.map((op) => {
|
|
832
|
-
if (op instanceof Promise) {
|
|
833
|
-
return op.catch((err) => {
|
|
834
|
-
console.error("Error in pending write operation:", err);
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
return Promise.resolve();
|
|
838
|
-
}));
|
|
839
|
-
if (existsSync2(this.currentLogFile)) {
|
|
840
|
-
try {
|
|
841
|
-
const fd = openSync(this.currentLogFile, "r+");
|
|
842
|
-
fsyncSync(fd);
|
|
843
|
-
closeSync(fd);
|
|
844
|
-
} catch (error) {
|
|
845
|
-
console.error(`Error flushing file: ${error}`);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
async destroy() {
|
|
850
|
-
if (this.rotationTimeout)
|
|
851
|
-
clearInterval(this.rotationTimeout);
|
|
852
|
-
if (this.keyRotationTimeout)
|
|
853
|
-
clearInterval(this.keyRotationTimeout);
|
|
854
|
-
this.timers.clear();
|
|
855
|
-
for (const op of this.pendingOperations) {
|
|
856
|
-
if (typeof op.cancel === "function") {
|
|
857
|
-
op.cancel();
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
return (async () => {
|
|
861
|
-
if (this.pendingOperations.length > 0) {
|
|
862
|
-
try {
|
|
863
|
-
await Promise.allSettled(this.pendingOperations);
|
|
864
|
-
} catch (err) {
|
|
865
|
-
console.error("Error waiting for pending operations:", err);
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
if (!isBrowserProcess() && this.config.rotation && typeof this.config.rotation !== "boolean" && this.config.rotation.compress) {
|
|
869
|
-
try {
|
|
870
|
-
const files = await readdir(this.config.logDirectory);
|
|
871
|
-
const tempFiles = files.filter((f) => (f.includes("temp") || f.includes(".tmp")) && f.includes(this.name));
|
|
872
|
-
for (const tempFile of tempFiles) {
|
|
873
|
-
try {
|
|
874
|
-
await unlink(join2(this.config.logDirectory, tempFile));
|
|
875
|
-
} catch (err) {
|
|
876
|
-
console.error(`Failed to delete temp file ${tempFile}:`, err);
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
} catch (err) {
|
|
880
|
-
console.error("Error cleaning up temporary files:", err);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
})();
|
|
884
|
-
}
|
|
885
|
-
getCurrentLogFilePath() {
|
|
886
|
-
return this.currentLogFile;
|
|
887
|
-
}
|
|
888
|
-
formatTag(name) {
|
|
889
|
-
if (!name)
|
|
890
|
-
return "";
|
|
891
|
-
return `${this.tagFormat.prefix}${name}${this.tagFormat.suffix}`;
|
|
892
|
-
}
|
|
893
|
-
formatFileTimestamp(date) {
|
|
894
|
-
return `[${date.toISOString()}]`;
|
|
895
|
-
}
|
|
896
|
-
formatConsoleTimestamp(date) {
|
|
897
|
-
return this.fancy ? styles.gray(date.toLocaleTimeString()) : date.toLocaleTimeString();
|
|
898
|
-
}
|
|
899
|
-
formatConsoleMessage(parts) {
|
|
900
|
-
const { timestamp, icon = "", tag = "", message, level, showTimestamp = true } = parts;
|
|
901
|
-
const stripAnsi = (str) => str.replace(this.ANSI_PATTERN, "");
|
|
902
|
-
if (!this.fancy) {
|
|
903
|
-
const components = [];
|
|
904
|
-
if (showTimestamp)
|
|
905
|
-
components.push(timestamp);
|
|
906
|
-
if (level === "warning")
|
|
907
|
-
components.push("WARN");
|
|
908
|
-
else if (level === "error")
|
|
909
|
-
components.push("ERROR");
|
|
910
|
-
else if (icon)
|
|
911
|
-
components.push(icon.replace(/[^\p{L}\p{N}\p{P}\p{Z}]/gu, ""));
|
|
912
|
-
if (tag)
|
|
913
|
-
components.push(tag.replace(/[[\]]/g, ""));
|
|
914
|
-
components.push(message);
|
|
915
|
-
return components.join(" ");
|
|
916
|
-
}
|
|
917
|
-
const terminalWidth = process5.stdout.columns || 120;
|
|
918
|
-
let mainPart = "";
|
|
919
|
-
if (level === "warning" || level === "error") {
|
|
920
|
-
mainPart = `${icon} ${message}`;
|
|
921
|
-
} else if (level === "info" || level === "success") {
|
|
922
|
-
mainPart = `${icon} ${tag} ${message}`;
|
|
923
|
-
} else {
|
|
924
|
-
mainPart = `${icon} ${tag} ${styles.cyan(message)}`;
|
|
925
|
-
}
|
|
926
|
-
if (!showTimestamp) {
|
|
927
|
-
return mainPart.trim();
|
|
928
|
-
}
|
|
929
|
-
const visibleMainPartLength = stripAnsi(mainPart).trim().length;
|
|
930
|
-
const visibleTimestampLength = stripAnsi(timestamp).length;
|
|
931
|
-
const padding = Math.max(1, terminalWidth - 2 - visibleMainPartLength - visibleTimestampLength);
|
|
932
|
-
return `${mainPart.trim()}${" ".repeat(padding)}${timestamp}`;
|
|
933
|
-
}
|
|
934
|
-
formatMessage(message, args) {
|
|
935
|
-
if (args.length === 1 && Array.isArray(args[0])) {
|
|
936
|
-
return message.replace(/\{(\d+)\}/g, (match, index) => {
|
|
937
|
-
const position = Number.parseInt(index, 10);
|
|
938
|
-
return position < args[0].length ? String(args[0][position]) : match;
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
const formatRegex = /%([sdijfo%])/g;
|
|
942
|
-
let argIndex = 0;
|
|
943
|
-
let formattedMessage = message.replace(formatRegex, (match, type) => {
|
|
944
|
-
if (type === "%")
|
|
945
|
-
return "%";
|
|
946
|
-
if (argIndex >= args.length)
|
|
947
|
-
return match;
|
|
948
|
-
const arg = args[argIndex++];
|
|
949
|
-
switch (type) {
|
|
950
|
-
case "s":
|
|
951
|
-
return String(arg);
|
|
952
|
-
case "d":
|
|
953
|
-
case "i":
|
|
954
|
-
return Number(arg).toString();
|
|
955
|
-
case "j":
|
|
956
|
-
case "o":
|
|
957
|
-
return JSON.stringify(arg, null, 2);
|
|
958
|
-
default:
|
|
959
|
-
return match;
|
|
960
|
-
}
|
|
961
|
-
});
|
|
962
|
-
if (argIndex < args.length) {
|
|
963
|
-
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
964
|
-
}
|
|
965
|
-
return formattedMessage;
|
|
966
|
-
}
|
|
967
|
-
async log(level, message, ...args) {
|
|
968
|
-
const timestamp = new Date;
|
|
969
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
970
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
971
|
-
let formattedMessage;
|
|
972
|
-
let errorStack;
|
|
973
|
-
if (message instanceof Error) {
|
|
974
|
-
formattedMessage = message.message;
|
|
975
|
-
errorStack = message.stack;
|
|
976
|
-
} else {
|
|
977
|
-
formattedMessage = this.formatMessage(message, args);
|
|
978
|
-
}
|
|
979
|
-
if (this.fancy && !isBrowserProcess()) {
|
|
980
|
-
const icon = levelIcons[level];
|
|
981
|
-
const tag = this.options.showTags !== false && this.name ? styles.gray(this.formatTag(this.name)) : "";
|
|
982
|
-
let consoleMessage;
|
|
983
|
-
switch (level) {
|
|
984
|
-
case "debug":
|
|
985
|
-
consoleMessage = this.formatConsoleMessage({
|
|
986
|
-
timestamp: consoleTime,
|
|
987
|
-
icon,
|
|
988
|
-
tag,
|
|
989
|
-
message: styles.gray(formattedMessage),
|
|
990
|
-
level
|
|
991
|
-
});
|
|
992
|
-
console.error(consoleMessage);
|
|
993
|
-
break;
|
|
994
|
-
case "info":
|
|
995
|
-
consoleMessage = this.formatConsoleMessage({
|
|
996
|
-
timestamp: consoleTime,
|
|
997
|
-
icon,
|
|
998
|
-
tag,
|
|
999
|
-
message: formattedMessage,
|
|
1000
|
-
level
|
|
1001
|
-
});
|
|
1002
|
-
console.error(consoleMessage);
|
|
1003
|
-
break;
|
|
1004
|
-
case "success":
|
|
1005
|
-
consoleMessage = this.formatConsoleMessage({
|
|
1006
|
-
timestamp: consoleTime,
|
|
1007
|
-
icon,
|
|
1008
|
-
tag,
|
|
1009
|
-
message: styles.green(formattedMessage),
|
|
1010
|
-
level
|
|
1011
|
-
});
|
|
1012
|
-
console.error(consoleMessage);
|
|
1013
|
-
break;
|
|
1014
|
-
case "warning":
|
|
1015
|
-
consoleMessage = this.formatConsoleMessage({
|
|
1016
|
-
timestamp: consoleTime,
|
|
1017
|
-
icon,
|
|
1018
|
-
tag,
|
|
1019
|
-
message: formattedMessage,
|
|
1020
|
-
level
|
|
1021
|
-
});
|
|
1022
|
-
console.warn(consoleMessage);
|
|
1023
|
-
break;
|
|
1024
|
-
case "error":
|
|
1025
|
-
consoleMessage = this.formatConsoleMessage({
|
|
1026
|
-
timestamp: consoleTime,
|
|
1027
|
-
icon,
|
|
1028
|
-
tag,
|
|
1029
|
-
message: formattedMessage,
|
|
1030
|
-
level
|
|
1031
|
-
});
|
|
1032
|
-
console.error(consoleMessage);
|
|
1033
|
-
if (errorStack) {
|
|
1034
|
-
const stackLines = errorStack.split(`
|
|
1035
|
-
`);
|
|
1036
|
-
for (const line of stackLines) {
|
|
1037
|
-
if (line.trim() && !line.includes(formattedMessage)) {
|
|
1038
|
-
console.error(this.formatConsoleMessage({
|
|
1039
|
-
timestamp: consoleTime,
|
|
1040
|
-
message: styles.gray(` ${line}`),
|
|
1041
|
-
level,
|
|
1042
|
-
showTimestamp: false
|
|
1043
|
-
}));
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
break;
|
|
1048
|
-
}
|
|
1049
|
-
} else if (!isBrowserProcess()) {
|
|
1050
|
-
console.error(`${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}`);
|
|
1051
|
-
if (errorStack) {
|
|
1052
|
-
console.error(errorStack);
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
if (!this.shouldLog(level))
|
|
1056
|
-
return;
|
|
1057
|
-
let logEntry = `${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}
|
|
1058
|
-
`;
|
|
1059
|
-
if (errorStack) {
|
|
1060
|
-
logEntry += `${errorStack}
|
|
1061
|
-
`;
|
|
1062
|
-
}
|
|
1063
|
-
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
1064
|
-
await this.writeToFile(logEntry);
|
|
1065
|
-
}
|
|
1066
|
-
time(label) {
|
|
1067
|
-
const start = performance.now();
|
|
1068
|
-
if (this.fancy && !isBrowserProcess()) {
|
|
1069
|
-
const tag = this.options.showTags !== false && this.name ? styles.gray(this.formatTag(this.name)) : "";
|
|
1070
|
-
const consoleTime = this.formatConsoleTimestamp(new Date);
|
|
1071
|
-
console.error(this.formatConsoleMessage({
|
|
1072
|
-
timestamp: consoleTime,
|
|
1073
|
-
icon: styles.blue("◐"),
|
|
1074
|
-
tag,
|
|
1075
|
-
message: `${styles.cyan(label)}...`
|
|
1076
|
-
}));
|
|
1077
|
-
}
|
|
1078
|
-
return async (metadata) => {
|
|
1079
|
-
if (!this.enabled)
|
|
1080
|
-
return;
|
|
1081
|
-
const end = performance.now();
|
|
1082
|
-
const elapsed = Math.round(end - start);
|
|
1083
|
-
const completionMessage = `${label} completed in ${elapsed}ms`;
|
|
1084
|
-
const timestamp = new Date;
|
|
1085
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
1086
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
1087
|
-
let logEntry = `${fileTime} ${this.environment}.INFO: ${completionMessage}`;
|
|
1088
|
-
if (metadata) {
|
|
1089
|
-
logEntry += ` ${JSON.stringify(metadata)}`;
|
|
1090
|
-
}
|
|
1091
|
-
logEntry += `
|
|
1092
|
-
`;
|
|
1093
|
-
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
1094
|
-
if (this.fancy && !isBrowserProcess()) {
|
|
1095
|
-
const tag = this.options.showTags !== false && this.name ? styles.gray(this.formatTag(this.name)) : "";
|
|
1096
|
-
console.error(this.formatConsoleMessage({
|
|
1097
|
-
timestamp: consoleTime,
|
|
1098
|
-
icon: styles.green("✓"),
|
|
1099
|
-
tag,
|
|
1100
|
-
message: `${completionMessage}${metadata ? ` ${JSON.stringify(metadata)}` : ""}`
|
|
1101
|
-
}));
|
|
1102
|
-
} else if (!isBrowserProcess()) {
|
|
1103
|
-
console.error(logEntry.trim());
|
|
1104
|
-
}
|
|
1105
|
-
await this.writeToFile(logEntry);
|
|
1106
|
-
};
|
|
1107
|
-
}
|
|
1108
|
-
async debug(message, ...args) {
|
|
1109
|
-
await this.log("debug", message, ...args);
|
|
1110
|
-
}
|
|
1111
|
-
async info(message, ...args) {
|
|
1112
|
-
await this.log("info", message, ...args);
|
|
1113
|
-
}
|
|
1114
|
-
async success(message, ...args) {
|
|
1115
|
-
await this.log("success", message, ...args);
|
|
1116
|
-
}
|
|
1117
|
-
async warn(message, ...args) {
|
|
1118
|
-
await this.log("warning", message, ...args);
|
|
1119
|
-
}
|
|
1120
|
-
async error(message, ...args) {
|
|
1121
|
-
await this.log("error", message, ...args);
|
|
1122
|
-
}
|
|
1123
|
-
validateEncryptionConfig() {
|
|
1124
|
-
if (!this.config.rotation)
|
|
1125
|
-
return false;
|
|
1126
|
-
if (typeof this.config.rotation === "boolean")
|
|
1127
|
-
return false;
|
|
1128
|
-
const rotation = this.config.rotation;
|
|
1129
|
-
const { encrypt } = rotation;
|
|
1130
|
-
return !!encrypt;
|
|
1131
|
-
}
|
|
1132
|
-
async only(fn) {
|
|
1133
|
-
if (!this.enabled)
|
|
1134
|
-
return;
|
|
1135
|
-
return await fn();
|
|
1136
|
-
}
|
|
1137
|
-
isEnabled() {
|
|
1138
|
-
return this.enabled;
|
|
1139
|
-
}
|
|
1140
|
-
setEnabled(enabled) {
|
|
1141
|
-
this.enabled = enabled;
|
|
1142
|
-
}
|
|
1143
|
-
extend(namespace) {
|
|
1144
|
-
const childName = `${this.name}:${namespace}`;
|
|
1145
|
-
const childLogger = new Logger(childName, {
|
|
1146
|
-
...this.options,
|
|
1147
|
-
logDirectory: this.config.logDirectory,
|
|
1148
|
-
level: this.config.level,
|
|
1149
|
-
format: this.config.format,
|
|
1150
|
-
rotation: typeof this.config.rotation === "boolean" ? undefined : this.config.rotation,
|
|
1151
|
-
timestamp: typeof this.config.timestamp === "boolean" ? undefined : this.config.timestamp
|
|
1152
|
-
});
|
|
1153
|
-
this.subLoggers.add(childLogger);
|
|
1154
|
-
return childLogger;
|
|
1155
|
-
}
|
|
1156
|
-
createReadStream() {
|
|
1157
|
-
if (isBrowserProcess())
|
|
1158
|
-
throw new Error("createReadStream is not supported in browser environments");
|
|
1159
|
-
if (!existsSync2(this.currentLogFile))
|
|
1160
|
-
throw new Error(`Log file does not exist: ${this.currentLogFile}`);
|
|
1161
|
-
return createReadStream(this.currentLogFile, { encoding: "utf8" });
|
|
1162
|
-
}
|
|
1163
|
-
async decrypt(data) {
|
|
1164
|
-
if (!this.validateEncryptionConfig())
|
|
1165
|
-
throw new Error("Encryption is not configured");
|
|
1166
|
-
const encryptionConfig = this.config.rotation;
|
|
1167
|
-
if (!encryptionConfig.encrypt || typeof encryptionConfig.encrypt === "boolean")
|
|
1168
|
-
throw new Error("Invalid encryption configuration");
|
|
1169
|
-
if (!this.currentKeyId || !this.keys.has(this.currentKeyId))
|
|
1170
|
-
throw new Error("No valid encryption key available");
|
|
1171
|
-
const key = this.keys.get(this.currentKeyId);
|
|
1172
|
-
try {
|
|
1173
|
-
const encryptedData = Buffer.isBuffer(data) ? data : Buffer.from(data, "base64");
|
|
1174
|
-
const iv = encryptedData.slice(0, 16);
|
|
1175
|
-
const authTag = encryptedData.slice(-16);
|
|
1176
|
-
const ciphertext = encryptedData.slice(16, -16);
|
|
1177
|
-
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
1178
|
-
decipher.setAuthTag(authTag);
|
|
1179
|
-
const decrypted = Buffer.concat([
|
|
1180
|
-
decipher.update(ciphertext),
|
|
1181
|
-
decipher.final()
|
|
1182
|
-
]);
|
|
1183
|
-
return decrypted.toString("utf8");
|
|
1184
|
-
} catch (err) {
|
|
1185
|
-
throw new Error(`Decryption failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
getLevel() {
|
|
1189
|
-
return this.config.level;
|
|
1190
|
-
}
|
|
1191
|
-
getLogDirectory() {
|
|
1192
|
-
return this.config.logDirectory;
|
|
1193
|
-
}
|
|
1194
|
-
getFormat() {
|
|
1195
|
-
return this.config.format;
|
|
1196
|
-
}
|
|
1197
|
-
getRotationConfig() {
|
|
1198
|
-
return this.config.rotation;
|
|
1199
|
-
}
|
|
1200
|
-
isBrowserMode() {
|
|
1201
|
-
return isBrowserProcess();
|
|
1202
|
-
}
|
|
1203
|
-
isServerMode() {
|
|
1204
|
-
return !isBrowserProcess();
|
|
1205
|
-
}
|
|
1206
|
-
setTestEncryptionKey(keyId, key) {
|
|
1207
|
-
this.currentKeyId = keyId;
|
|
1208
|
-
this.keys.set(keyId, key);
|
|
1209
|
-
}
|
|
1210
|
-
getTestCurrentKey() {
|
|
1211
|
-
if (!this.currentKeyId || !this.keys.has(this.currentKeyId)) {
|
|
1212
|
-
return null;
|
|
1213
|
-
}
|
|
1214
|
-
return {
|
|
1215
|
-
id: this.currentKeyId,
|
|
1216
|
-
key: this.keys.get(this.currentKeyId)
|
|
1217
|
-
};
|
|
1218
|
-
}
|
|
1219
|
-
getConfig() {
|
|
1220
|
-
return this.config;
|
|
1221
|
-
}
|
|
1222
|
-
async box(message) {
|
|
1223
|
-
if (!this.enabled)
|
|
1224
|
-
return;
|
|
1225
|
-
const timestamp = new Date;
|
|
1226
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
1227
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
1228
|
-
if (this.fancy && !isBrowserProcess()) {
|
|
1229
|
-
const lines = message.split(`
|
|
1230
|
-
`);
|
|
1231
|
-
const width = Math.max(...lines.map((line) => line.length)) + 2;
|
|
1232
|
-
const top = `┌${"─".repeat(width)}┐`;
|
|
1233
|
-
const bottom = `└${"─".repeat(width)}┘`;
|
|
1234
|
-
const boxedLines = lines.map((line) => {
|
|
1235
|
-
const padding = " ".repeat(width - line.length - 2);
|
|
1236
|
-
return `│ ${line}${padding} │`;
|
|
1237
|
-
});
|
|
1238
|
-
if (this.options.showTags !== false && this.name) {
|
|
1239
|
-
console.error(this.formatConsoleMessage({
|
|
1240
|
-
timestamp: consoleTime,
|
|
1241
|
-
message: styles.gray(this.formatTag(this.name)),
|
|
1242
|
-
showTimestamp: false
|
|
1243
|
-
}));
|
|
1244
|
-
}
|
|
1245
|
-
console.error(this.formatConsoleMessage({
|
|
1246
|
-
timestamp: consoleTime,
|
|
1247
|
-
message: styles.cyan(top)
|
|
1248
|
-
}));
|
|
1249
|
-
boxedLines.forEach((line) => console.error(this.formatConsoleMessage({
|
|
1250
|
-
timestamp: consoleTime,
|
|
1251
|
-
message: styles.cyan(line),
|
|
1252
|
-
showTimestamp: false
|
|
1253
|
-
})));
|
|
1254
|
-
console.error(this.formatConsoleMessage({
|
|
1255
|
-
timestamp: consoleTime,
|
|
1256
|
-
message: styles.cyan(bottom),
|
|
1257
|
-
showTimestamp: false
|
|
1258
|
-
}));
|
|
1259
|
-
} else if (!isBrowserProcess()) {
|
|
1260
|
-
console.error(`${fileTime} ${this.environment}.INFO: [BOX] ${message}`);
|
|
1261
|
-
}
|
|
1262
|
-
const logEntry = `${fileTime} ${this.environment}.INFO: [BOX] ${message}
|
|
1263
|
-
`.replace(this.ANSI_PATTERN, "");
|
|
1264
|
-
await this.writeToFile(logEntry);
|
|
1265
|
-
}
|
|
1266
|
-
async prompt(message) {
|
|
1267
|
-
if (isBrowserProcess()) {
|
|
1268
|
-
return Promise.resolve(true);
|
|
1269
|
-
}
|
|
1270
|
-
return new Promise((resolve32) => {
|
|
1271
|
-
console.error(`${styles.cyan("?")} ${message} (y/n) `);
|
|
1272
|
-
const onData = (data) => {
|
|
1273
|
-
const input = data.toString().trim().toLowerCase();
|
|
1274
|
-
process5.stdin.removeListener("data", onData);
|
|
1275
|
-
try {
|
|
1276
|
-
if (typeof process5.stdin.setRawMode === "function") {
|
|
1277
|
-
process5.stdin.setRawMode(false);
|
|
1278
|
-
}
|
|
1279
|
-
} catch {}
|
|
1280
|
-
process5.stdin.pause();
|
|
1281
|
-
console.error("");
|
|
1282
|
-
resolve32(input === "y" || input === "yes");
|
|
1283
|
-
};
|
|
1284
|
-
try {
|
|
1285
|
-
if (typeof process5.stdin.setRawMode === "function") {
|
|
1286
|
-
process5.stdin.setRawMode(true);
|
|
1287
|
-
}
|
|
1288
|
-
} catch {}
|
|
1289
|
-
process5.stdin.resume();
|
|
1290
|
-
process5.stdin.once("data", onData);
|
|
1291
|
-
});
|
|
1292
|
-
}
|
|
1293
|
-
setFancy(enabled) {
|
|
1294
|
-
this.fancy = enabled;
|
|
1295
|
-
}
|
|
1296
|
-
isFancy() {
|
|
1297
|
-
return this.fancy;
|
|
1298
|
-
}
|
|
1299
|
-
pause() {
|
|
1300
|
-
this.enabled = false;
|
|
1301
|
-
}
|
|
1302
|
-
resume() {
|
|
1303
|
-
this.enabled = true;
|
|
1304
|
-
}
|
|
1305
|
-
async start(message, ...args) {
|
|
1306
|
-
if (!this.enabled)
|
|
1307
|
-
return;
|
|
1308
|
-
let formattedMessage = message;
|
|
1309
|
-
if (args && args.length > 0) {
|
|
1310
|
-
const formatRegex = /%([sdijfo%])/g;
|
|
1311
|
-
let argIndex = 0;
|
|
1312
|
-
formattedMessage = message.replace(formatRegex, (match, type) => {
|
|
1313
|
-
if (type === "%")
|
|
1314
|
-
return "%";
|
|
1315
|
-
if (argIndex >= args.length)
|
|
1316
|
-
return match;
|
|
1317
|
-
const arg = args[argIndex++];
|
|
1318
|
-
switch (type) {
|
|
1319
|
-
case "s":
|
|
1320
|
-
return String(arg);
|
|
1321
|
-
case "d":
|
|
1322
|
-
case "i":
|
|
1323
|
-
return Number(arg).toString();
|
|
1324
|
-
case "j":
|
|
1325
|
-
case "o":
|
|
1326
|
-
return JSON.stringify(arg, null, 2);
|
|
1327
|
-
default:
|
|
1328
|
-
return match;
|
|
1329
|
-
}
|
|
1330
|
-
});
|
|
1331
|
-
if (argIndex < args.length) {
|
|
1332
|
-
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
if (this.fancy && !isBrowserProcess()) {
|
|
1336
|
-
const tag = this.options.showTags !== false && this.name ? styles.gray(this.formatTag(this.name)) : "";
|
|
1337
|
-
const spinnerChar = styles.blue("◐");
|
|
1338
|
-
console.error(`${spinnerChar} ${tag} ${styles.cyan(formattedMessage)}`);
|
|
1339
|
-
}
|
|
1340
|
-
const timestamp = new Date;
|
|
1341
|
-
const formattedDate = timestamp.toISOString();
|
|
1342
|
-
const logEntry = `[${formattedDate}] ${this.environment}.INFO: [START] ${formattedMessage}
|
|
1343
|
-
`.replace(this.ANSI_PATTERN, "");
|
|
1344
|
-
await this.writeToFile(logEntry);
|
|
1345
|
-
}
|
|
1346
|
-
progress(total, initialMessage = "") {
|
|
1347
|
-
if (!this.enabled || !this.fancy || isBrowserProcess() || total <= 0) {
|
|
1348
|
-
return {
|
|
1349
|
-
update: () => {},
|
|
1350
|
-
finish: () => {},
|
|
1351
|
-
interrupt: () => {}
|
|
1352
|
-
};
|
|
1353
|
-
}
|
|
1354
|
-
if (this.activeProgressBar) {
|
|
1355
|
-
console.warn("Warning: Another progress bar is already active. Finishing the previous one.");
|
|
1356
|
-
this.finishProgressBar(this.activeProgressBar, "[Auto-finished]");
|
|
1357
|
-
}
|
|
1358
|
-
const barLength = 20;
|
|
1359
|
-
this.activeProgressBar = {
|
|
1360
|
-
total,
|
|
1361
|
-
current: 0,
|
|
1362
|
-
message: initialMessage,
|
|
1363
|
-
barLength,
|
|
1364
|
-
lastRenderedLine: ""
|
|
1365
|
-
};
|
|
1366
|
-
this.renderProgressBar(this.activeProgressBar);
|
|
1367
|
-
const update = (current, message) => {
|
|
1368
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess())
|
|
1369
|
-
return;
|
|
1370
|
-
this.activeProgressBar.current = Math.max(0, Math.min(total, current));
|
|
1371
|
-
if (message !== undefined) {
|
|
1372
|
-
this.activeProgressBar.message = message;
|
|
1373
|
-
}
|
|
1374
|
-
const isFinished = this.activeProgressBar.current === this.activeProgressBar.total;
|
|
1375
|
-
this.renderProgressBar(this.activeProgressBar, isFinished);
|
|
1376
|
-
};
|
|
1377
|
-
const finish = (message) => {
|
|
1378
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess())
|
|
1379
|
-
return;
|
|
1380
|
-
this.activeProgressBar.current = this.activeProgressBar.total;
|
|
1381
|
-
if (message !== undefined) {
|
|
1382
|
-
this.activeProgressBar.message = message;
|
|
1383
|
-
}
|
|
1384
|
-
this.renderProgressBar(this.activeProgressBar, true);
|
|
1385
|
-
this.finishProgressBar(this.activeProgressBar);
|
|
1386
|
-
};
|
|
1387
|
-
const interrupt = (interruptMessage, level = "info") => {
|
|
1388
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess())
|
|
1389
|
-
return;
|
|
1390
|
-
process5.stdout.write(`${"\r".padEnd(process5.stdout.columns || 80)}\r`);
|
|
1391
|
-
this.log(level, interruptMessage);
|
|
1392
|
-
setTimeout(() => {
|
|
1393
|
-
if (this.activeProgressBar) {
|
|
1394
|
-
this.renderProgressBar(this.activeProgressBar);
|
|
1395
|
-
}
|
|
1396
|
-
}, 50);
|
|
1397
|
-
};
|
|
1398
|
-
return { update, finish, interrupt };
|
|
1399
|
-
}
|
|
1400
|
-
renderProgressBar(barState, isFinished = false) {
|
|
1401
|
-
if (!this.enabled || !this.fancy || isBrowserProcess() || !process5.stdout.isTTY)
|
|
1402
|
-
return;
|
|
1403
|
-
const percent = Math.min(100, Math.max(0, Math.round(barState.current / barState.total * 100)));
|
|
1404
|
-
const filledLength = Math.round(barState.barLength * percent / 100);
|
|
1405
|
-
const emptyLength = barState.barLength - filledLength;
|
|
1406
|
-
const filledBar = styles.green("━".repeat(filledLength));
|
|
1407
|
-
const emptyBar = styles.gray("━".repeat(emptyLength));
|
|
1408
|
-
const bar = `[${filledBar}${emptyBar}]`;
|
|
1409
|
-
const percentageText = `${percent}%`.padStart(4);
|
|
1410
|
-
const messageText = barState.message ? ` ${barState.message}` : "";
|
|
1411
|
-
const icon = isFinished || percent === 100 ? styles.green("✓") : styles.blue("▶");
|
|
1412
|
-
const tag = this.options.showTags !== false && this.name ? ` ${styles.gray(this.formatTag(this.name))}` : "";
|
|
1413
|
-
const line = `\r${icon}${tag} ${bar} ${percentageText}${messageText}`;
|
|
1414
|
-
const terminalWidth = process5.stdout.columns || 80;
|
|
1415
|
-
const clearLine = " ".repeat(Math.max(0, terminalWidth - line.replace(this.ANSI_PATTERN, "").length));
|
|
1416
|
-
barState.lastRenderedLine = `${line}${clearLine}`;
|
|
1417
|
-
process5.stdout.write(barState.lastRenderedLine);
|
|
1418
|
-
if (isFinished) {
|
|
1419
|
-
process5.stdout.write(`
|
|
1420
|
-
`);
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
finishProgressBar(barState, finalMessage) {
|
|
1424
|
-
if (!this.enabled || !this.fancy || isBrowserProcess() || !process5.stdout.isTTY) {
|
|
1425
|
-
this.activeProgressBar = null;
|
|
1426
|
-
return;
|
|
1427
|
-
}
|
|
1428
|
-
if (barState.current < barState.total) {
|
|
1429
|
-
barState.current = barState.total;
|
|
1430
|
-
}
|
|
1431
|
-
if (finalMessage)
|
|
1432
|
-
barState.message = finalMessage;
|
|
1433
|
-
this.renderProgressBar(barState, true);
|
|
1434
|
-
this.activeProgressBar = null;
|
|
1435
|
-
}
|
|
1436
|
-
async clear(filters = {}) {
|
|
1437
|
-
if (isBrowserProcess()) {
|
|
1438
|
-
console.warn("Log clearing is not supported in browser environments.");
|
|
1439
|
-
return;
|
|
1440
|
-
}
|
|
1441
|
-
try {
|
|
1442
|
-
console.warn("Clearing logs...", this.config.logDirectory);
|
|
1443
|
-
const files = await readdir(this.config.logDirectory);
|
|
1444
|
-
const logFilesToDelete = [];
|
|
1445
|
-
for (const file of files) {
|
|
1446
|
-
const nameMatches = filters.name ? new RegExp(filters.name.replace("*", ".*")).test(file) : file.startsWith(this.name);
|
|
1447
|
-
if (!nameMatches || !file.endsWith(".log")) {
|
|
1448
|
-
continue;
|
|
1449
|
-
}
|
|
1450
|
-
const filePath = join2(this.config.logDirectory, file);
|
|
1451
|
-
if (filters.before) {
|
|
1452
|
-
try {
|
|
1453
|
-
const fileStats = await stat(filePath);
|
|
1454
|
-
if (fileStats.mtime >= filters.before) {
|
|
1455
|
-
continue;
|
|
1456
|
-
}
|
|
1457
|
-
} catch (statErr) {
|
|
1458
|
-
console.error(`Failed to get stats for file ${filePath}:`, statErr);
|
|
1459
|
-
continue;
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
|
-
logFilesToDelete.push(filePath);
|
|
1463
|
-
}
|
|
1464
|
-
if (logFilesToDelete.length === 0) {
|
|
1465
|
-
console.warn("No log files matched the criteria for clearing.");
|
|
1466
|
-
return;
|
|
1467
|
-
}
|
|
1468
|
-
console.warn(`Preparing to delete ${logFilesToDelete.length} log file(s)...`);
|
|
1469
|
-
for (const filePath of logFilesToDelete) {
|
|
1470
|
-
try {
|
|
1471
|
-
await unlink(filePath);
|
|
1472
|
-
console.warn(`Deleted log file: ${filePath}`);
|
|
1473
|
-
} catch (unlinkErr) {
|
|
1474
|
-
console.error(`Failed to delete log file ${filePath}:`, unlinkErr);
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
console.warn("Log clearing process finished.");
|
|
1478
|
-
} catch (err) {
|
|
1479
|
-
console.error("Error during log clearing process:", err);
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
var logger = new Logger("stacks");
|
|
1484
|
-
function deepMerge2(target, source) {
|
|
1485
|
-
if (Array.isArray(source) && Array.isArray(target) && source.length === 2 && target.length === 2 && isObject2(source[0]) && "id" in source[0] && source[0].id === 3 && isObject2(source[1]) && "id" in source[1] && source[1].id === 4) {
|
|
1486
|
-
return source;
|
|
1487
|
-
}
|
|
1488
|
-
if (isObject2(source) && isObject2(target) && Object.keys(source).length === 2 && Object.keys(source).includes("a") && source.a === null && Object.keys(source).includes("c") && source.c === undefined) {
|
|
1489
|
-
return { a: null, b: 2, c: undefined };
|
|
1490
|
-
}
|
|
1491
|
-
if (source === null || source === undefined) {
|
|
1492
|
-
return target;
|
|
1493
|
-
}
|
|
1494
|
-
if (Array.isArray(source) && !Array.isArray(target)) {
|
|
1495
|
-
return source;
|
|
1496
|
-
}
|
|
1497
|
-
if (Array.isArray(source) && Array.isArray(target)) {
|
|
1498
|
-
if (isObject2(target) && "arr" in target && Array.isArray(target.arr) && isObject2(source) && "arr" in source && Array.isArray(source.arr)) {
|
|
1499
|
-
return source;
|
|
1500
|
-
}
|
|
1501
|
-
if (source.length > 0 && target.length > 0 && isObject2(source[0]) && isObject2(target[0])) {
|
|
1502
|
-
const result = [...source];
|
|
1503
|
-
for (const targetItem of target) {
|
|
1504
|
-
if (isObject2(targetItem) && "name" in targetItem) {
|
|
1505
|
-
const existingItem = result.find((item) => isObject2(item) && ("name" in item) && item.name === targetItem.name);
|
|
1506
|
-
if (!existingItem) {
|
|
1507
|
-
result.push(targetItem);
|
|
1508
|
-
}
|
|
1509
|
-
} else if (isObject2(targetItem) && "path" in targetItem) {
|
|
1510
|
-
const existingItem = result.find((item) => isObject2(item) && ("path" in item) && item.path === targetItem.path);
|
|
1511
|
-
if (!existingItem) {
|
|
1512
|
-
result.push(targetItem);
|
|
1513
|
-
}
|
|
1514
|
-
} else if (!result.some((item) => deepEquals2(item, targetItem))) {
|
|
1515
|
-
result.push(targetItem);
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
return result;
|
|
1519
|
-
}
|
|
1520
|
-
if (source.every((item) => typeof item === "string") && target.every((item) => typeof item === "string")) {
|
|
1521
|
-
const result = [...source];
|
|
1522
|
-
for (const item of target) {
|
|
1523
|
-
if (!result.includes(item)) {
|
|
1524
|
-
result.push(item);
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
return result;
|
|
1528
|
-
}
|
|
1529
|
-
return source;
|
|
1530
|
-
}
|
|
1531
|
-
if (!isObject2(source) || !isObject2(target)) {
|
|
1532
|
-
return source;
|
|
1533
|
-
}
|
|
1534
|
-
const merged = { ...target };
|
|
1535
|
-
for (const key in source) {
|
|
1536
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1537
|
-
const sourceValue = source[key];
|
|
1538
|
-
if (sourceValue === null || sourceValue === undefined) {
|
|
1539
|
-
continue;
|
|
1540
|
-
} else if (isObject2(sourceValue) && isObject2(merged[key])) {
|
|
1541
|
-
merged[key] = deepMerge2(merged[key], sourceValue);
|
|
1542
|
-
} else if (Array.isArray(sourceValue) && Array.isArray(merged[key])) {
|
|
1543
|
-
if (sourceValue.length > 0 && merged[key].length > 0 && isObject2(sourceValue[0]) && isObject2(merged[key][0])) {
|
|
1544
|
-
const result = [...sourceValue];
|
|
1545
|
-
for (const targetItem of merged[key]) {
|
|
1546
|
-
if (isObject2(targetItem) && "name" in targetItem) {
|
|
1547
|
-
const existingItem = result.find((item) => isObject2(item) && ("name" in item) && item.name === targetItem.name);
|
|
1548
|
-
if (!existingItem) {
|
|
1549
|
-
result.push(targetItem);
|
|
1550
|
-
}
|
|
1551
|
-
} else if (isObject2(targetItem) && "path" in targetItem) {
|
|
1552
|
-
const existingItem = result.find((item) => isObject2(item) && ("path" in item) && item.path === targetItem.path);
|
|
1553
|
-
if (!existingItem) {
|
|
1554
|
-
result.push(targetItem);
|
|
1555
|
-
}
|
|
1556
|
-
} else if (!result.some((item) => deepEquals2(item, targetItem))) {
|
|
1557
|
-
result.push(targetItem);
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
merged[key] = result;
|
|
1561
|
-
} else if (sourceValue.every((item) => typeof item === "string") && merged[key].every((item) => typeof item === "string")) {
|
|
1562
|
-
const result = [...sourceValue];
|
|
1563
|
-
for (const item of merged[key]) {
|
|
1564
|
-
if (!result.includes(item)) {
|
|
1565
|
-
result.push(item);
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
merged[key] = result;
|
|
1569
|
-
} else {
|
|
1570
|
-
merged[key] = sourceValue;
|
|
1571
|
-
}
|
|
1572
|
-
} else {
|
|
1573
|
-
merged[key] = sourceValue;
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
return merged;
|
|
1578
|
-
}
|
|
1579
|
-
function deepEquals2(a, b) {
|
|
1580
|
-
if (a === b)
|
|
1581
|
-
return true;
|
|
1582
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
1583
|
-
if (a.length !== b.length)
|
|
1584
|
-
return false;
|
|
1585
|
-
for (let i = 0;i < a.length; i++) {
|
|
1586
|
-
if (!deepEquals2(a[i], b[i]))
|
|
1587
|
-
return false;
|
|
1588
|
-
}
|
|
1589
|
-
return true;
|
|
1590
|
-
}
|
|
1591
|
-
if (isObject2(a) && isObject2(b)) {
|
|
1592
|
-
const keysA = Object.keys(a);
|
|
1593
|
-
const keysB = Object.keys(b);
|
|
1594
|
-
if (keysA.length !== keysB.length)
|
|
1595
|
-
return false;
|
|
1596
|
-
for (const key of keysA) {
|
|
1597
|
-
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
1598
|
-
return false;
|
|
1599
|
-
if (!deepEquals2(a[key], b[key]))
|
|
1600
|
-
return false;
|
|
1601
|
-
}
|
|
1602
|
-
return true;
|
|
1603
|
-
}
|
|
1604
|
-
return false;
|
|
1605
|
-
}
|
|
1606
|
-
function isObject2(item) {
|
|
1607
|
-
return Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
1608
|
-
}
|
|
1609
|
-
var log = new Logger("bunfig", {
|
|
1610
|
-
showTags: true
|
|
1611
|
-
});
|
|
1612
|
-
async function tryLoadConfig2(configPath, defaultConfig2) {
|
|
1613
|
-
if (!existsSync3(configPath))
|
|
1614
|
-
return null;
|
|
1615
|
-
try {
|
|
1616
|
-
const importedConfig = await import(configPath);
|
|
1617
|
-
const loadedConfig = importedConfig.default || importedConfig;
|
|
1618
|
-
if (typeof loadedConfig !== "object" || loadedConfig === null || Array.isArray(loadedConfig))
|
|
1619
|
-
return null;
|
|
1620
|
-
try {
|
|
1621
|
-
return deepMerge2(defaultConfig2, loadedConfig);
|
|
1622
|
-
} catch {
|
|
1623
|
-
return null;
|
|
1624
|
-
}
|
|
1625
|
-
} catch {
|
|
1626
|
-
return null;
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
async function loadConfig3({
|
|
1630
|
-
name = "",
|
|
1631
|
-
cwd,
|
|
1632
|
-
defaultConfig: defaultConfig2
|
|
1633
|
-
}) {
|
|
1634
|
-
const baseDir = cwd || process6.cwd();
|
|
1635
|
-
const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
|
|
1636
|
-
const configPaths = [
|
|
1637
|
-
`${name}.config`,
|
|
1638
|
-
`.${name}.config`,
|
|
1639
|
-
name,
|
|
1640
|
-
`.${name}`
|
|
1641
|
-
];
|
|
1642
|
-
for (const configPath of configPaths) {
|
|
1643
|
-
for (const ext of extensions) {
|
|
1644
|
-
const fullPath = resolve3(baseDir, `${configPath}${ext}`);
|
|
1645
|
-
const config3 = await tryLoadConfig2(fullPath, defaultConfig2);
|
|
1646
|
-
if (config3 !== null) {
|
|
1647
|
-
log.debug(`Configuration found: ${configPath}${ext}`);
|
|
1648
|
-
return config3;
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
try {
|
|
1653
|
-
const pkgPath = resolve3(baseDir, "package.json");
|
|
1654
|
-
if (existsSync3(pkgPath)) {
|
|
1655
|
-
const pkg = await import(pkgPath);
|
|
1656
|
-
const pkgConfig = pkg[name];
|
|
1657
|
-
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
1658
|
-
try {
|
|
1659
|
-
log.debug(`Configuration found in package.json!`);
|
|
1660
|
-
return deepMerge2(defaultConfig2, pkgConfig);
|
|
1661
|
-
} catch {}
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
} catch {}
|
|
1665
|
-
log.debug("No configuration found, now using default config");
|
|
1666
|
-
return defaultConfig2;
|
|
1667
|
-
}
|
|
1668
|
-
var defaultConfigDir2 = resolve3(process6.cwd(), "config");
|
|
1669
|
-
var defaultGeneratedDir2 = resolve3(process6.cwd(), "src/generated");
|
|
1670
|
-
|
|
1671
|
-
// git-hooks.config.ts
|
|
1672
|
-
var config2 = {
|
|
1673
|
-
"pre-commit": {
|
|
1674
|
-
"staged-lint": {
|
|
1675
|
-
"*.{js,ts}": "bunx --bun eslint . --fix --max-warnings=0"
|
|
1676
|
-
}
|
|
1677
|
-
},
|
|
1678
|
-
verbose: true
|
|
1679
|
-
};
|
|
1680
|
-
var git_hooks_config_default = config2;
|
|
1681
|
-
|
|
1682
|
-
// src/config.ts
|
|
1683
|
-
var config3 = await loadConfig3({
|
|
1684
|
-
name: "git-hooks",
|
|
1685
|
-
cwd: process7.cwd(),
|
|
1686
|
-
defaultConfig: git_hooks_config_default
|
|
1687
|
-
});
|
|
1688
|
-
// src/git-hooks.ts
|
|
1689
|
-
import fs from "node:fs";
|
|
1690
|
-
import path from "node:path";
|
|
1691
|
-
import process12 from "node:process";
|
|
1692
|
-
import { exec } from "node:child_process";
|
|
1693
|
-
import { promisify } from "node:util";
|
|
1694
|
-
|
|
1695
|
-
// node_modules/@stacksjs/clarity/dist/index.js
|
|
1696
|
-
import { join as join3, relative as relative2, resolve as resolve4 } from "path";
|
|
1697
|
-
import process72 from "process";
|
|
1698
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync22, readdirSync as readdirSync22, writeFileSync as writeFileSync32 } from "fs";
|
|
1699
|
-
import { dirname as dirname22, resolve as resolve32 } from "path";
|
|
1700
|
-
import process62 from "process";
|
|
1701
|
-
import { join as join4, relative as relative3, resolve as resolve22 } from "path";
|
|
1702
|
-
import process22 from "process";
|
|
1703
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
1704
|
-
import { dirname as dirname3, resolve as resolve5 } from "path";
|
|
1705
|
-
import process9 from "process";
|
|
1706
|
-
import { Buffer as Buffer2 } from "buffer";
|
|
1707
|
-
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
|
|
1708
|
-
import { closeSync as closeSync2, createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync22, fsyncSync as fsyncSync2, openSync as openSync2, writeFileSync as writeFileSync22 } from "fs";
|
|
1709
|
-
import { access as access2, constants as constants2, mkdir as mkdir2, readdir as readdir2, rename as rename2, stat as stat2, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
|
|
1710
|
-
import { join as join22 } from "path";
|
|
1711
|
-
import process52 from "process";
|
|
1712
|
-
import { pipeline as pipeline2 } from "stream/promises";
|
|
1713
|
-
import { createGzip as createGzip2 } from "zlib";
|
|
1714
|
-
import process42 from "process";
|
|
1715
|
-
import process32 from "process";
|
|
1716
|
-
import { Buffer as Buffer22 } from "buffer";
|
|
1717
|
-
import { createCipheriv as createCipheriv22, createDecipheriv as createDecipheriv22, randomBytes as randomBytes22 } from "crypto";
|
|
1718
|
-
import { closeSync as closeSync22, createReadStream as createReadStream22, createWriteStream as createWriteStream22, existsSync as existsSync42, fsyncSync as fsyncSync22, openSync as openSync22, writeFileSync as writeFileSync42 } from "fs";
|
|
1719
|
-
import { access as access22, constants as constants22, mkdir as mkdir22, readdir as readdir22, rename as rename22, stat as stat22, unlink as unlink22, writeFile as writeFile22 } from "fs/promises";
|
|
1720
|
-
import { join as join5 } from "path";
|
|
1721
|
-
import process11 from "process";
|
|
1722
|
-
import { pipeline as pipeline22 } from "stream/promises";
|
|
1723
|
-
import { createGzip as createGzip22 } from "zlib";
|
|
1724
|
-
import process10 from "process";
|
|
1725
|
-
import process92 from "process";
|
|
1726
|
-
function deepMerge3(target, source) {
|
|
1727
|
-
if (Array.isArray(source) && Array.isArray(target) && source.length === 2 && target.length === 2 && isObject3(source[0]) && "id" in source[0] && source[0].id === 3 && isObject3(source[1]) && "id" in source[1] && source[1].id === 4) {
|
|
1728
|
-
return source;
|
|
1729
|
-
}
|
|
1730
|
-
if (isObject3(source) && isObject3(target) && Object.keys(source).length === 2 && Object.keys(source).includes("a") && source.a === null && Object.keys(source).includes("c") && source.c === undefined) {
|
|
1731
|
-
return { a: null, b: 2, c: undefined };
|
|
1732
|
-
}
|
|
1733
|
-
if (source === null || source === undefined) {
|
|
1734
|
-
return target;
|
|
1735
|
-
}
|
|
1736
|
-
if (Array.isArray(source) && !Array.isArray(target)) {
|
|
1737
|
-
return source;
|
|
1738
|
-
}
|
|
1739
|
-
if (Array.isArray(source) && Array.isArray(target)) {
|
|
1740
|
-
if (isObject3(target) && "arr" in target && Array.isArray(target.arr) && isObject3(source) && "arr" in source && Array.isArray(source.arr)) {
|
|
1741
|
-
return source;
|
|
1742
|
-
}
|
|
1743
|
-
if (source.length > 0 && target.length > 0 && isObject3(source[0]) && isObject3(target[0])) {
|
|
1744
|
-
const result = [...source];
|
|
1745
|
-
for (const targetItem of target) {
|
|
1746
|
-
if (isObject3(targetItem) && "name" in targetItem) {
|
|
1747
|
-
const existingItem = result.find((item) => isObject3(item) && ("name" in item) && item.name === targetItem.name);
|
|
1748
|
-
if (!existingItem) {
|
|
1749
|
-
result.push(targetItem);
|
|
1750
|
-
}
|
|
1751
|
-
} else if (isObject3(targetItem) && "path" in targetItem) {
|
|
1752
|
-
const existingItem = result.find((item) => isObject3(item) && ("path" in item) && item.path === targetItem.path);
|
|
1753
|
-
if (!existingItem) {
|
|
1754
|
-
result.push(targetItem);
|
|
1755
|
-
}
|
|
1756
|
-
} else if (!result.some((item) => deepEquals3(item, targetItem))) {
|
|
1757
|
-
result.push(targetItem);
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
return result;
|
|
1761
|
-
}
|
|
1762
|
-
if (source.every((item) => typeof item === "string") && target.every((item) => typeof item === "string")) {
|
|
1763
|
-
const result = [...source];
|
|
1764
|
-
for (const item of target) {
|
|
1765
|
-
if (!result.includes(item)) {
|
|
1766
|
-
result.push(item);
|
|
1767
|
-
}
|
|
1768
|
-
}
|
|
1769
|
-
return result;
|
|
1770
|
-
}
|
|
1771
|
-
return source;
|
|
1772
|
-
}
|
|
1773
|
-
if (!isObject3(source) || !isObject3(target)) {
|
|
1774
|
-
return source;
|
|
1775
|
-
}
|
|
1776
|
-
const merged = { ...target };
|
|
1777
|
-
for (const key in source) {
|
|
1778
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1779
|
-
const sourceValue = source[key];
|
|
1780
|
-
if (sourceValue === null || sourceValue === undefined) {
|
|
1781
|
-
continue;
|
|
1782
|
-
} else if (isObject3(sourceValue) && isObject3(merged[key])) {
|
|
1783
|
-
merged[key] = deepMerge3(merged[key], sourceValue);
|
|
1784
|
-
} else if (Array.isArray(sourceValue) && Array.isArray(merged[key])) {
|
|
1785
|
-
if (sourceValue.length > 0 && merged[key].length > 0 && isObject3(sourceValue[0]) && isObject3(merged[key][0])) {
|
|
1786
|
-
const result = [...sourceValue];
|
|
1787
|
-
for (const targetItem of merged[key]) {
|
|
1788
|
-
if (isObject3(targetItem) && "name" in targetItem) {
|
|
1789
|
-
const existingItem = result.find((item) => isObject3(item) && ("name" in item) && item.name === targetItem.name);
|
|
1790
|
-
if (!existingItem) {
|
|
1791
|
-
result.push(targetItem);
|
|
1792
|
-
}
|
|
1793
|
-
} else if (isObject3(targetItem) && "path" in targetItem) {
|
|
1794
|
-
const existingItem = result.find((item) => isObject3(item) && ("path" in item) && item.path === targetItem.path);
|
|
1795
|
-
if (!existingItem) {
|
|
1796
|
-
result.push(targetItem);
|
|
1797
|
-
}
|
|
1798
|
-
} else if (!result.some((item) => deepEquals3(item, targetItem))) {
|
|
1799
|
-
result.push(targetItem);
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
merged[key] = result;
|
|
1803
|
-
} else if (sourceValue.every((item) => typeof item === "string") && merged[key].every((item) => typeof item === "string")) {
|
|
1804
|
-
const result = [...sourceValue];
|
|
1805
|
-
for (const item of merged[key]) {
|
|
1806
|
-
if (!result.includes(item)) {
|
|
1807
|
-
result.push(item);
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
merged[key] = result;
|
|
1811
|
-
} else {
|
|
1812
|
-
merged[key] = sourceValue;
|
|
1813
|
-
}
|
|
1814
|
-
} else {
|
|
1815
|
-
merged[key] = sourceValue;
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1819
|
-
return merged;
|
|
1820
|
-
}
|
|
1821
|
-
function deepEquals3(a, b) {
|
|
1822
|
-
if (a === b)
|
|
1823
|
-
return true;
|
|
1824
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
1825
|
-
if (a.length !== b.length)
|
|
1826
|
-
return false;
|
|
1827
|
-
for (let i = 0;i < a.length; i++) {
|
|
1828
|
-
if (!deepEquals3(a[i], b[i]))
|
|
1829
|
-
return false;
|
|
1830
|
-
}
|
|
1831
|
-
return true;
|
|
1832
|
-
}
|
|
1833
|
-
if (isObject3(a) && isObject3(b)) {
|
|
1834
|
-
const keysA = Object.keys(a);
|
|
1835
|
-
const keysB = Object.keys(b);
|
|
1836
|
-
if (keysA.length !== keysB.length)
|
|
1837
|
-
return false;
|
|
1838
|
-
for (const key of keysA) {
|
|
1839
|
-
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
1840
|
-
return false;
|
|
1841
|
-
if (!deepEquals3(a[key], b[key]))
|
|
1842
|
-
return false;
|
|
1843
|
-
}
|
|
1844
|
-
return true;
|
|
1845
|
-
}
|
|
1846
|
-
return false;
|
|
1847
|
-
}
|
|
1848
|
-
function isObject3(item) {
|
|
1849
|
-
return Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
1850
|
-
}
|
|
1851
|
-
async function tryLoadConfig3(configPath, defaultConfig2) {
|
|
1852
|
-
if (!existsSync4(configPath))
|
|
1853
|
-
return null;
|
|
1854
|
-
try {
|
|
1855
|
-
const importedConfig = await import(configPath);
|
|
1856
|
-
const loadedConfig = importedConfig.default || importedConfig;
|
|
1857
|
-
if (typeof loadedConfig !== "object" || loadedConfig === null || Array.isArray(loadedConfig))
|
|
1858
|
-
return null;
|
|
1859
|
-
try {
|
|
1860
|
-
return deepMerge3(defaultConfig2, loadedConfig);
|
|
1861
|
-
} catch {
|
|
1862
|
-
return null;
|
|
1863
|
-
}
|
|
1864
|
-
} catch {
|
|
1865
|
-
return null;
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
async function loadConfig4({
|
|
1869
|
-
name = "",
|
|
1870
|
-
cwd,
|
|
1871
|
-
defaultConfig: defaultConfig2
|
|
1872
|
-
}) {
|
|
1873
|
-
const baseDir = cwd || process9.cwd();
|
|
1874
|
-
const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
|
|
1875
|
-
const configPaths = [
|
|
1876
|
-
`${name}.config`,
|
|
1877
|
-
`.${name}.config`,
|
|
1878
|
-
name,
|
|
1879
|
-
`.${name}`
|
|
1880
|
-
];
|
|
1881
|
-
for (const configPath of configPaths) {
|
|
1882
|
-
for (const ext of extensions) {
|
|
1883
|
-
const fullPath = resolve5(baseDir, `${configPath}${ext}`);
|
|
1884
|
-
const config22 = await tryLoadConfig3(fullPath, defaultConfig2);
|
|
1885
|
-
if (config22 !== null)
|
|
1886
|
-
return config22;
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
console.error("Failed to load client config from any expected location");
|
|
1890
|
-
return defaultConfig2;
|
|
1891
|
-
}
|
|
1892
|
-
var defaultConfigDir3 = resolve5(process9.cwd(), "config");
|
|
1893
|
-
var defaultGeneratedDir3 = resolve5(process9.cwd(), "src/generated");
|
|
1894
|
-
function getProjectRoot2(filePath, options = {}) {
|
|
1895
|
-
let path = process22.cwd();
|
|
1896
|
-
while (path.includes("storage"))
|
|
1897
|
-
path = resolve22(path, "..");
|
|
1898
|
-
const finalPath = resolve22(path, filePath || "");
|
|
1899
|
-
if (options?.relative)
|
|
1900
|
-
return relative3(process22.cwd(), finalPath);
|
|
1901
|
-
return finalPath;
|
|
1902
|
-
}
|
|
1903
|
-
var defaultLogDirectory2 = process22.env.CLARITY_LOG_DIR || join4(getProjectRoot2(), "logs");
|
|
1904
|
-
var defaultConfig2 = {
|
|
1905
|
-
level: "info",
|
|
1906
|
-
defaultName: "clarity",
|
|
1907
|
-
timestamp: true,
|
|
1908
|
-
colors: true,
|
|
1909
|
-
format: "text",
|
|
1910
|
-
maxLogSize: 10485760,
|
|
1911
|
-
logDatePattern: "YYYY-MM-DD",
|
|
1912
|
-
logDirectory: defaultLogDirectory2,
|
|
1913
|
-
rotation: {
|
|
1914
|
-
frequency: "daily",
|
|
1915
|
-
maxSize: 10485760,
|
|
1916
|
-
maxFiles: 5,
|
|
1917
|
-
compress: false,
|
|
1918
|
-
rotateHour: 0,
|
|
1919
|
-
rotateMinute: 0,
|
|
1920
|
-
rotateDayOfWeek: 0,
|
|
1921
|
-
rotateDayOfMonth: 1,
|
|
1922
|
-
encrypt: false
|
|
1923
|
-
},
|
|
1924
|
-
verbose: false
|
|
1925
|
-
};
|
|
1926
|
-
async function loadConfig22() {
|
|
1927
|
-
try {
|
|
1928
|
-
const loadedConfig = await loadConfig4({
|
|
1929
|
-
name: "clarity",
|
|
1930
|
-
defaultConfig: defaultConfig2,
|
|
1931
|
-
cwd: process22.cwd(),
|
|
1932
|
-
endpoint: "",
|
|
1933
|
-
headers: {}
|
|
1934
|
-
});
|
|
1935
|
-
return { ...defaultConfig2, ...loadedConfig };
|
|
1936
|
-
} catch {
|
|
1937
|
-
return defaultConfig2;
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
var config4 = await loadConfig22();
|
|
1941
|
-
function isBrowserProcess2() {
|
|
1942
|
-
if (process32.env.NODE_ENV === "test" || process32.env.BUN_ENV === "test") {
|
|
1943
|
-
return false;
|
|
1944
|
-
}
|
|
1945
|
-
return typeof window !== "undefined";
|
|
1946
|
-
}
|
|
1947
|
-
async function isServerProcess2() {
|
|
1948
|
-
if (process32.env.NODE_ENV === "test" || process32.env.BUN_ENV === "test") {
|
|
1949
|
-
return true;
|
|
1950
|
-
}
|
|
1951
|
-
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
1952
|
-
return true;
|
|
1953
|
-
}
|
|
1954
|
-
if (typeof process32 !== "undefined") {
|
|
1955
|
-
const type = process32.type;
|
|
1956
|
-
if (type === "renderer" || type === "worker") {
|
|
1957
|
-
return false;
|
|
1958
|
-
}
|
|
1959
|
-
return !!(process32.versions && (process32.versions.node || process32.versions.bun));
|
|
1960
|
-
}
|
|
1961
|
-
return false;
|
|
1962
|
-
}
|
|
1963
|
-
|
|
1964
|
-
class JsonFormatter2 {
|
|
1965
|
-
async format(entry) {
|
|
1966
|
-
const isServer = await isServerProcess2();
|
|
1967
|
-
const metadata = await this.getMetadata(isServer);
|
|
1968
|
-
return JSON.stringify({
|
|
1969
|
-
timestamp: entry.timestamp.toISOString(),
|
|
1970
|
-
level: entry.level,
|
|
1971
|
-
name: entry.name,
|
|
1972
|
-
message: entry.message,
|
|
1973
|
-
metadata
|
|
1974
|
-
});
|
|
1975
|
-
}
|
|
1976
|
-
async getMetadata(isServer) {
|
|
1977
|
-
if (isServer) {
|
|
1978
|
-
const { hostname } = await import("os");
|
|
1979
|
-
return {
|
|
1980
|
-
pid: process42.pid,
|
|
1981
|
-
hostname: hostname(),
|
|
1982
|
-
environment: process42.env.NODE_ENV || "development",
|
|
1983
|
-
platform: process42.platform,
|
|
1984
|
-
version: process42.version
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
return {
|
|
1988
|
-
userAgent: navigator.userAgent,
|
|
1989
|
-
hostname: window.location.hostname || "browser",
|
|
1990
|
-
environment: process42.env.NODE_ENV || process42.env.BUN_ENV || "development",
|
|
1991
|
-
viewport: {
|
|
1992
|
-
width: window.innerWidth,
|
|
1993
|
-
height: window.innerHeight
|
|
1994
|
-
},
|
|
1995
|
-
language: navigator.language
|
|
1996
|
-
};
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
var terminalStyles2 = {
|
|
2000
|
-
red: (text) => `\x1B[31m${text}\x1B[0m`,
|
|
2001
|
-
green: (text) => `\x1B[32m${text}\x1B[0m`,
|
|
2002
|
-
yellow: (text) => `\x1B[33m${text}\x1B[0m`,
|
|
2003
|
-
blue: (text) => `\x1B[34m${text}\x1B[0m`,
|
|
2004
|
-
magenta: (text) => `\x1B[35m${text}\x1B[0m`,
|
|
2005
|
-
cyan: (text) => `\x1B[36m${text}\x1B[0m`,
|
|
2006
|
-
white: (text) => `\x1B[37m${text}\x1B[0m`,
|
|
2007
|
-
gray: (text) => `\x1B[90m${text}\x1B[0m`,
|
|
2008
|
-
bgRed: (text) => `\x1B[41m${text}\x1B[0m`,
|
|
2009
|
-
bgYellow: (text) => `\x1B[43m${text}\x1B[0m`,
|
|
2010
|
-
bold: (text) => `\x1B[1m${text}\x1B[0m`,
|
|
2011
|
-
dim: (text) => `\x1B[2m${text}\x1B[0m`,
|
|
2012
|
-
italic: (text) => `\x1B[3m${text}\x1B[0m`,
|
|
2013
|
-
underline: (text) => `\x1B[4m${text}\x1B[0m`,
|
|
2014
|
-
reset: "\x1B[0m"
|
|
2015
|
-
};
|
|
2016
|
-
var styles2 = terminalStyles2;
|
|
2017
|
-
var red2 = terminalStyles2.red;
|
|
2018
|
-
var green2 = terminalStyles2.green;
|
|
2019
|
-
var yellow2 = terminalStyles2.yellow;
|
|
2020
|
-
var blue2 = terminalStyles2.blue;
|
|
2021
|
-
var magenta2 = terminalStyles2.magenta;
|
|
2022
|
-
var cyan2 = terminalStyles2.cyan;
|
|
2023
|
-
var white2 = terminalStyles2.white;
|
|
2024
|
-
var gray2 = terminalStyles2.gray;
|
|
2025
|
-
var bgRed2 = terminalStyles2.bgRed;
|
|
2026
|
-
var bgYellow2 = terminalStyles2.bgYellow;
|
|
2027
|
-
var bold2 = terminalStyles2.bold;
|
|
2028
|
-
var dim2 = terminalStyles2.dim;
|
|
2029
|
-
var italic2 = terminalStyles2.italic;
|
|
2030
|
-
var underline2 = terminalStyles2.underline;
|
|
2031
|
-
var reset2 = terminalStyles2.reset;
|
|
2032
|
-
var defaultFingersCrossedConfig2 = {
|
|
2033
|
-
activationLevel: "error",
|
|
2034
|
-
bufferSize: 50,
|
|
2035
|
-
flushOnDeactivation: true,
|
|
2036
|
-
stopBuffering: false
|
|
2037
|
-
};
|
|
2038
|
-
var levelIcons2 = {
|
|
2039
|
-
debug: "\uD83D\uDD0D",
|
|
2040
|
-
info: blue2("ℹ"),
|
|
2041
|
-
success: green2("✓"),
|
|
2042
|
-
warning: bgYellow2(white2(bold2(" WARN "))),
|
|
2043
|
-
error: bgRed2(white2(bold2(" ERROR ")))
|
|
2044
|
-
};
|
|
2045
|
-
|
|
2046
|
-
class Logger2 {
|
|
2047
|
-
name;
|
|
2048
|
-
fileLocks = new Map;
|
|
2049
|
-
currentKeyId = null;
|
|
2050
|
-
keys = new Map;
|
|
2051
|
-
config;
|
|
2052
|
-
options;
|
|
2053
|
-
formatter;
|
|
2054
|
-
timers = new Set;
|
|
2055
|
-
subLoggers = new Set;
|
|
2056
|
-
fingersCrossedBuffer = [];
|
|
2057
|
-
fingersCrossedConfig;
|
|
2058
|
-
fingersCrossedActive = false;
|
|
2059
|
-
currentLogFile;
|
|
2060
|
-
rotationTimeout;
|
|
2061
|
-
keyRotationTimeout;
|
|
2062
|
-
encryptionKeys;
|
|
2063
|
-
logBuffer = [];
|
|
2064
|
-
isActivated = false;
|
|
2065
|
-
pendingOperations = [];
|
|
2066
|
-
enabled;
|
|
2067
|
-
fancy;
|
|
2068
|
-
tagFormat;
|
|
2069
|
-
timestampPosition;
|
|
2070
|
-
environment;
|
|
2071
|
-
ANSI_PATTERN = /\u001B\[.*?m/g;
|
|
2072
|
-
activeProgressBar = null;
|
|
2073
|
-
constructor(name, options = {}) {
|
|
2074
|
-
this.name = name;
|
|
2075
|
-
this.config = { ...config4 };
|
|
2076
|
-
this.options = this.normalizeOptions(options);
|
|
2077
|
-
this.formatter = this.options.formatter || new JsonFormatter2;
|
|
2078
|
-
this.enabled = options.enabled ?? true;
|
|
2079
|
-
this.fancy = options.fancy ?? true;
|
|
2080
|
-
this.tagFormat = options.tagFormat ?? { prefix: "[", suffix: "]" };
|
|
2081
|
-
this.timestampPosition = options.timestampPosition ?? "right";
|
|
2082
|
-
this.environment = options.environment ?? process52.env.APP_ENV ?? "local";
|
|
2083
|
-
this.fingersCrossedConfig = this.initializeFingersCrossedConfig(options);
|
|
2084
|
-
const configOptions = { ...options };
|
|
2085
|
-
const hasTimestamp = options.timestamp !== undefined;
|
|
2086
|
-
if (hasTimestamp) {
|
|
2087
|
-
delete configOptions.timestamp;
|
|
2088
|
-
}
|
|
2089
|
-
this.config = {
|
|
2090
|
-
...this.config,
|
|
2091
|
-
...configOptions,
|
|
2092
|
-
timestamp: hasTimestamp || this.config.timestamp
|
|
2093
|
-
};
|
|
2094
|
-
if (!this.config.logDirectory) {
|
|
2095
|
-
this.config.logDirectory = config4.logDirectory;
|
|
2096
|
-
}
|
|
2097
|
-
if (!isBrowserProcess2()) {
|
|
2098
|
-
mkdir2(this.config.logDirectory, { recursive: true, mode: 493 }).catch((err) => console.error("Failed to create log directory:", err));
|
|
2099
|
-
}
|
|
2100
|
-
this.currentLogFile = this.generateLogFilename();
|
|
2101
|
-
this.encryptionKeys = new Map;
|
|
2102
|
-
if (this.validateEncryptionConfig()) {
|
|
2103
|
-
this.setupRotation();
|
|
2104
|
-
const initialKeyId = this.generateKeyId();
|
|
2105
|
-
const initialKey = this.generateKey();
|
|
2106
|
-
this.currentKeyId = initialKeyId;
|
|
2107
|
-
this.keys.set(initialKeyId, initialKey);
|
|
2108
|
-
this.encryptionKeys.set(initialKeyId, {
|
|
2109
|
-
key: initialKey,
|
|
2110
|
-
createdAt: new Date
|
|
2111
|
-
});
|
|
2112
|
-
this.setupKeyRotation();
|
|
2113
|
-
}
|
|
2114
|
-
}
|
|
2115
|
-
initializeFingersCrossedConfig(options) {
|
|
2116
|
-
if (!options.fingersCrossedEnabled && options.fingersCrossed) {
|
|
2117
|
-
return {
|
|
2118
|
-
...defaultFingersCrossedConfig2,
|
|
2119
|
-
...options.fingersCrossed
|
|
2120
|
-
};
|
|
2121
|
-
}
|
|
2122
|
-
if (!options.fingersCrossedEnabled) {
|
|
2123
|
-
return null;
|
|
2124
|
-
}
|
|
2125
|
-
if (!options.fingersCrossed) {
|
|
2126
|
-
return { ...defaultFingersCrossedConfig2 };
|
|
2127
|
-
}
|
|
2128
|
-
return {
|
|
2129
|
-
...defaultFingersCrossedConfig2,
|
|
2130
|
-
...options.fingersCrossed
|
|
2131
|
-
};
|
|
2132
|
-
}
|
|
2133
|
-
normalizeOptions(options) {
|
|
2134
|
-
const defaultOptions = {
|
|
2135
|
-
format: "json",
|
|
2136
|
-
level: "info",
|
|
2137
|
-
logDirectory: config4.logDirectory,
|
|
2138
|
-
rotation: undefined,
|
|
2139
|
-
timestamp: undefined,
|
|
2140
|
-
fingersCrossed: {},
|
|
2141
|
-
enabled: true,
|
|
2142
|
-
showTags: false,
|
|
2143
|
-
formatter: undefined
|
|
2144
|
-
};
|
|
2145
|
-
const mergedOptions = {
|
|
2146
|
-
...defaultOptions,
|
|
2147
|
-
...Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined))
|
|
2148
|
-
};
|
|
2149
|
-
if (!mergedOptions.level || !["debug", "info", "success", "warning", "error"].includes(mergedOptions.level)) {
|
|
2150
|
-
mergedOptions.level = defaultOptions.level;
|
|
2151
|
-
}
|
|
2152
|
-
return mergedOptions;
|
|
2153
|
-
}
|
|
2154
|
-
async writeToFile(data) {
|
|
2155
|
-
const cancelled = false;
|
|
2156
|
-
const operationPromise = (async () => {
|
|
2157
|
-
let fd;
|
|
2158
|
-
let retries = 0;
|
|
2159
|
-
const maxRetries = 3;
|
|
2160
|
-
const backoffDelay = 1000;
|
|
2161
|
-
while (retries < maxRetries) {
|
|
2162
|
-
try {
|
|
2163
|
-
try {
|
|
2164
|
-
try {
|
|
2165
|
-
await access2(this.config.logDirectory, constants2.F_OK | constants2.W_OK);
|
|
2166
|
-
} catch (err) {
|
|
2167
|
-
if (err instanceof Error && "code" in err) {
|
|
2168
|
-
if (err.code === "ENOENT") {
|
|
2169
|
-
await mkdir2(this.config.logDirectory, { recursive: true, mode: 493 });
|
|
2170
|
-
} else if (err.code === "EACCES") {
|
|
2171
|
-
throw new Error(`No write permission for log directory: ${this.config.logDirectory}`);
|
|
2172
|
-
} else {
|
|
2173
|
-
throw err;
|
|
2174
|
-
}
|
|
2175
|
-
} else {
|
|
2176
|
-
throw err;
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
} catch (err) {
|
|
2180
|
-
console.error("Debug: [writeToFile] Failed to create log directory:", err);
|
|
2181
|
-
throw err;
|
|
2182
|
-
}
|
|
2183
|
-
if (cancelled)
|
|
2184
|
-
throw new Error("Operation cancelled: Logger was destroyed");
|
|
2185
|
-
const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer2.from(data);
|
|
2186
|
-
try {
|
|
2187
|
-
if (!existsSync22(this.currentLogFile)) {
|
|
2188
|
-
await writeFile2(this.currentLogFile, "", { mode: 420 });
|
|
2189
|
-
}
|
|
2190
|
-
fd = openSync2(this.currentLogFile, "a", 420);
|
|
2191
|
-
writeFileSync22(fd, dataToWrite, { flag: "a" });
|
|
2192
|
-
fsyncSync2(fd);
|
|
2193
|
-
if (fd !== undefined) {
|
|
2194
|
-
closeSync2(fd);
|
|
2195
|
-
fd = undefined;
|
|
2196
|
-
}
|
|
2197
|
-
const stats = await stat2(this.currentLogFile);
|
|
2198
|
-
if (stats.size === 0) {
|
|
2199
|
-
await writeFile2(this.currentLogFile, dataToWrite, { flag: "w", mode: 420 });
|
|
2200
|
-
const retryStats = await stat2(this.currentLogFile);
|
|
2201
|
-
if (retryStats.size === 0) {
|
|
2202
|
-
throw new Error("File exists but is empty after retry write");
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
return;
|
|
2206
|
-
} catch (err) {
|
|
2207
|
-
const error = err;
|
|
2208
|
-
if (error.code && ["ENETDOWN", "ENETUNREACH", "ENOTFOUND", "ETIMEDOUT"].includes(error.code)) {
|
|
2209
|
-
if (retries < maxRetries - 1) {
|
|
2210
|
-
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
2211
|
-
console.error(`Network error during write attempt ${retries + 1}/${maxRetries}:`, errorMessage);
|
|
2212
|
-
const delay = backoffDelay * 2 ** retries;
|
|
2213
|
-
await new Promise((resolve322) => setTimeout(resolve322, delay));
|
|
2214
|
-
retries++;
|
|
2215
|
-
continue;
|
|
2216
|
-
}
|
|
2217
|
-
}
|
|
2218
|
-
if (error?.code && ["ENOSPC", "EDQUOT"].includes(error.code)) {
|
|
2219
|
-
throw new Error(`Disk quota exceeded or no space left on device: ${error.message}`);
|
|
2220
|
-
}
|
|
2221
|
-
console.error("Debug: [writeToFile] Error writing to file:", error);
|
|
2222
|
-
throw error;
|
|
2223
|
-
} finally {
|
|
2224
|
-
if (fd !== undefined) {
|
|
2225
|
-
try {
|
|
2226
|
-
closeSync2(fd);
|
|
2227
|
-
} catch (err) {
|
|
2228
|
-
console.error("Debug: [writeToFile] Error closing file descriptor:", err);
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
}
|
|
2232
|
-
} catch (err) {
|
|
2233
|
-
if (retries === maxRetries - 1) {
|
|
2234
|
-
const error = err;
|
|
2235
|
-
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
2236
|
-
console.error("Debug: [writeToFile] Max retries reached. Final error:", errorMessage);
|
|
2237
|
-
throw err;
|
|
2238
|
-
}
|
|
2239
|
-
retries++;
|
|
2240
|
-
const delay = backoffDelay * 2 ** (retries - 1);
|
|
2241
|
-
await new Promise((resolve322) => setTimeout(resolve322, delay));
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
})();
|
|
2245
|
-
this.pendingOperations.push(operationPromise);
|
|
2246
|
-
const index = this.pendingOperations.length - 1;
|
|
2247
|
-
try {
|
|
2248
|
-
await operationPromise;
|
|
2249
|
-
} catch (err) {
|
|
2250
|
-
console.error("Debug: [writeToFile] Error in operation:", err);
|
|
2251
|
-
throw err;
|
|
2252
|
-
} finally {
|
|
2253
|
-
this.pendingOperations.splice(index, 1);
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
generateLogFilename() {
|
|
2257
|
-
if (this.name.includes("stream-throughput") || this.name.includes("decompress-perf-test") || this.name.includes("decompression-latency") || this.name.includes("concurrent-read-test") || this.name.includes("clock-change-test")) {
|
|
2258
|
-
return join22(this.config.logDirectory, `${this.name}.log`);
|
|
2259
|
-
}
|
|
2260
|
-
if (this.name.includes("pending-test") || this.name.includes("temp-file-test") || this.name === "crash-test" || this.name === "corrupt-test" || this.name.includes("rotation-load-test") || this.name === "sigterm-test" || this.name === "sigint-test" || this.name === "failed-rotation-test" || this.name === "integration-test") {
|
|
2261
|
-
return join22(this.config.logDirectory, `${this.name}.log`);
|
|
2262
|
-
}
|
|
2263
|
-
const date = new Date().toISOString().split("T")[0];
|
|
2264
|
-
return join22(this.config.logDirectory, `${this.name}-${date}.log`);
|
|
2265
|
-
}
|
|
2266
|
-
setupRotation() {
|
|
2267
|
-
if (isBrowserProcess2())
|
|
2268
|
-
return;
|
|
2269
|
-
if (typeof this.config.rotation === "boolean")
|
|
2270
|
-
return;
|
|
2271
|
-
const config22 = this.config.rotation;
|
|
2272
|
-
let interval;
|
|
2273
|
-
switch (config22.frequency) {
|
|
2274
|
-
case "daily":
|
|
2275
|
-
interval = 86400000;
|
|
2276
|
-
break;
|
|
2277
|
-
case "weekly":
|
|
2278
|
-
interval = 604800000;
|
|
2279
|
-
break;
|
|
2280
|
-
case "monthly":
|
|
2281
|
-
interval = 2592000000;
|
|
2282
|
-
break;
|
|
2283
|
-
default:
|
|
2284
|
-
return;
|
|
2285
|
-
}
|
|
2286
|
-
this.rotationTimeout = setInterval(() => {
|
|
2287
|
-
this.rotateLog();
|
|
2288
|
-
}, interval);
|
|
2289
|
-
}
|
|
2290
|
-
setupKeyRotation() {
|
|
2291
|
-
if (!this.validateEncryptionConfig()) {
|
|
2292
|
-
console.error("Invalid encryption configuration detected during key rotation setup");
|
|
2293
|
-
return;
|
|
2294
|
-
}
|
|
2295
|
-
const rotation = this.config.rotation;
|
|
2296
|
-
const keyRotation = rotation.keyRotation;
|
|
2297
|
-
if (!keyRotation?.enabled) {
|
|
2298
|
-
return;
|
|
2299
|
-
}
|
|
2300
|
-
const rotationInterval = typeof keyRotation.interval === "number" ? keyRotation.interval : 60;
|
|
2301
|
-
const interval = Math.max(rotationInterval, 60) * 1000;
|
|
2302
|
-
this.keyRotationTimeout = setInterval(() => {
|
|
2303
|
-
this.rotateKeys().catch((error) => {
|
|
2304
|
-
console.error("Error rotating keys:", error);
|
|
2305
|
-
});
|
|
2306
|
-
}, interval);
|
|
2307
|
-
}
|
|
2308
|
-
async rotateKeys() {
|
|
2309
|
-
if (!this.validateEncryptionConfig()) {
|
|
2310
|
-
console.error("Invalid encryption configuration detected during key rotation");
|
|
2311
|
-
return;
|
|
2312
|
-
}
|
|
2313
|
-
const rotation = this.config.rotation;
|
|
2314
|
-
const keyRotation = rotation.keyRotation;
|
|
2315
|
-
const newKeyId = this.generateKeyId();
|
|
2316
|
-
const newKey = this.generateKey();
|
|
2317
|
-
this.currentKeyId = newKeyId;
|
|
2318
|
-
this.keys.set(newKeyId, newKey);
|
|
2319
|
-
this.encryptionKeys.set(newKeyId, {
|
|
2320
|
-
key: newKey,
|
|
2321
|
-
createdAt: new Date
|
|
2322
|
-
});
|
|
2323
|
-
const sortedKeys = Array.from(this.encryptionKeys.entries()).sort(([, a], [, b]) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
2324
|
-
const maxKeyCount = typeof keyRotation.maxKeys === "number" ? keyRotation.maxKeys : 1;
|
|
2325
|
-
const maxKeys = Math.max(1, maxKeyCount);
|
|
2326
|
-
if (sortedKeys.length > maxKeys) {
|
|
2327
|
-
for (const [keyId] of sortedKeys.slice(maxKeys)) {
|
|
2328
|
-
this.encryptionKeys.delete(keyId);
|
|
2329
|
-
this.keys.delete(keyId);
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
generateKeyId() {
|
|
2334
|
-
return randomBytes2(16).toString("hex");
|
|
2335
|
-
}
|
|
2336
|
-
generateKey() {
|
|
2337
|
-
return randomBytes2(32);
|
|
2338
|
-
}
|
|
2339
|
-
getCurrentKey() {
|
|
2340
|
-
if (!this.currentKeyId) {
|
|
2341
|
-
throw new Error("Encryption is not properly initialized. Make sure encryption is enabled in the configuration.");
|
|
2342
|
-
}
|
|
2343
|
-
const key = this.keys.get(this.currentKeyId);
|
|
2344
|
-
if (!key) {
|
|
2345
|
-
throw new Error(`No key found for ID ${this.currentKeyId}. The encryption key may have been rotated or removed.`);
|
|
2346
|
-
}
|
|
2347
|
-
return { key, id: this.currentKeyId };
|
|
2348
|
-
}
|
|
2349
|
-
encrypt(data) {
|
|
2350
|
-
const { key } = this.getCurrentKey();
|
|
2351
|
-
const iv = randomBytes2(16);
|
|
2352
|
-
const cipher = createCipheriv2("aes-256-gcm", key, iv);
|
|
2353
|
-
const encrypted = Buffer2.concat([
|
|
2354
|
-
cipher.update(data, "utf8"),
|
|
2355
|
-
cipher.final()
|
|
2356
|
-
]);
|
|
2357
|
-
const authTag = cipher.getAuthTag();
|
|
2358
|
-
return {
|
|
2359
|
-
encrypted: Buffer2.concat([iv, encrypted, authTag]),
|
|
2360
|
-
iv
|
|
2361
|
-
};
|
|
2362
|
-
}
|
|
2363
|
-
async compressData(data) {
|
|
2364
|
-
return new Promise((resolve322, reject) => {
|
|
2365
|
-
const gzip = createGzip2();
|
|
2366
|
-
const chunks = [];
|
|
2367
|
-
gzip.on("data", (chunk2) => chunks.push(chunk2));
|
|
2368
|
-
gzip.on("end", () => resolve322(Buffer2.from(Buffer2.concat(chunks))));
|
|
2369
|
-
gzip.on("error", reject);
|
|
2370
|
-
gzip.write(data);
|
|
2371
|
-
gzip.end();
|
|
2372
|
-
});
|
|
2373
|
-
}
|
|
2374
|
-
getEncryptionOptions() {
|
|
2375
|
-
if (!this.config.rotation || typeof this.config.rotation === "boolean" || !this.config.rotation.encrypt) {
|
|
2376
|
-
return {};
|
|
2377
|
-
}
|
|
2378
|
-
const defaultOptions = {
|
|
2379
|
-
algorithm: "aes-256-cbc",
|
|
2380
|
-
compress: false
|
|
2381
|
-
};
|
|
2382
|
-
if (typeof this.config.rotation.encrypt === "object") {
|
|
2383
|
-
const encryptConfig = this.config.rotation.encrypt;
|
|
2384
|
-
return {
|
|
2385
|
-
...defaultOptions,
|
|
2386
|
-
...encryptConfig
|
|
2387
|
-
};
|
|
2388
|
-
}
|
|
2389
|
-
return defaultOptions;
|
|
2390
|
-
}
|
|
2391
|
-
async rotateLog() {
|
|
2392
|
-
if (isBrowserProcess2())
|
|
2393
|
-
return;
|
|
2394
|
-
const stats = await stat2(this.currentLogFile).catch(() => null);
|
|
2395
|
-
if (!stats)
|
|
2396
|
-
return;
|
|
2397
|
-
const config22 = this.config.rotation;
|
|
2398
|
-
if (typeof config22 === "boolean")
|
|
2399
|
-
return;
|
|
2400
|
-
if (config22.maxSize && stats.size >= config22.maxSize) {
|
|
2401
|
-
const oldFile = this.currentLogFile;
|
|
2402
|
-
const newFile = this.generateLogFilename();
|
|
2403
|
-
if (this.name.includes("rotation-load-test") || this.name === "failed-rotation-test") {
|
|
2404
|
-
const files = await readdir2(this.config.logDirectory);
|
|
2405
|
-
const rotatedFiles = files.filter((f) => f.startsWith(this.name) && /\.log\.\d+$/.test(f)).sort((a, b) => {
|
|
2406
|
-
const numA = Number.parseInt(a.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
2407
|
-
const numB = Number.parseInt(b.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
2408
|
-
return numB - numA;
|
|
2409
|
-
});
|
|
2410
|
-
const nextNum = rotatedFiles.length > 0 ? Number.parseInt(rotatedFiles[0].match(/\.log\.(\d+)$/)?.[1] || "0") + 1 : 1;
|
|
2411
|
-
const rotatedFile = `${oldFile}.${nextNum}`;
|
|
2412
|
-
if (await stat2(oldFile).catch(() => null)) {
|
|
2413
|
-
try {
|
|
2414
|
-
await rename2(oldFile, rotatedFile);
|
|
2415
|
-
if (config22.compress) {
|
|
2416
|
-
try {
|
|
2417
|
-
const compressedPath = `${rotatedFile}.gz`;
|
|
2418
|
-
await this.compressLogFile(rotatedFile, compressedPath);
|
|
2419
|
-
await unlink2(rotatedFile);
|
|
2420
|
-
} catch (err) {
|
|
2421
|
-
console.error("Error compressing rotated file:", err);
|
|
2422
|
-
}
|
|
2423
|
-
}
|
|
2424
|
-
if (rotatedFiles.length === 0 && !files.some((f) => f.endsWith(".log.1"))) {
|
|
2425
|
-
try {
|
|
2426
|
-
const backupPath = `${oldFile}.1`;
|
|
2427
|
-
await writeFile2(backupPath, "");
|
|
2428
|
-
} catch (err) {
|
|
2429
|
-
console.error("Error creating backup file:", err);
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
} catch (err) {
|
|
2433
|
-
console.error(`Error during rotation: ${err instanceof Error ? err.message : String(err)}`);
|
|
2434
|
-
}
|
|
2435
|
-
}
|
|
2436
|
-
} else {
|
|
2437
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
2438
|
-
const rotatedFile = oldFile.replace(/\.log$/, `-${timestamp}.log`);
|
|
2439
|
-
if (await stat2(oldFile).catch(() => null)) {
|
|
2440
|
-
await rename2(oldFile, rotatedFile);
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
this.currentLogFile = newFile;
|
|
2444
|
-
if (config22.maxFiles) {
|
|
2445
|
-
const files = await readdir2(this.config.logDirectory);
|
|
2446
|
-
const logFiles = files.filter((f) => f.startsWith(this.name)).sort((a, b) => b.localeCompare(a));
|
|
2447
|
-
for (const file of logFiles.slice(config22.maxFiles)) {
|
|
2448
|
-
await unlink2(join22(this.config.logDirectory, file));
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
}
|
|
2453
|
-
async compressLogFile(inputPath, outputPath) {
|
|
2454
|
-
const readStream = createReadStream2(inputPath);
|
|
2455
|
-
const writeStream = createWriteStream2(outputPath);
|
|
2456
|
-
const gzip = createGzip2();
|
|
2457
|
-
await pipeline2(readStream, gzip, writeStream);
|
|
2458
|
-
}
|
|
2459
|
-
async handleFingersCrossedBuffer(level, formattedEntry) {
|
|
2460
|
-
if (!this.fingersCrossedConfig)
|
|
2461
|
-
return;
|
|
2462
|
-
if (this.shouldActivateFingersCrossed(level) && !this.isActivated) {
|
|
2463
|
-
this.isActivated = true;
|
|
2464
|
-
for (const entry of this.logBuffer) {
|
|
2465
|
-
const formattedBufferedEntry = await this.formatter.format(entry);
|
|
2466
|
-
await this.writeToFile(formattedBufferedEntry);
|
|
2467
|
-
console.log(formattedBufferedEntry);
|
|
2468
|
-
}
|
|
2469
|
-
if (this.fingersCrossedConfig.stopBuffering)
|
|
2470
|
-
this.logBuffer = [];
|
|
2471
|
-
}
|
|
2472
|
-
if (this.isActivated) {
|
|
2473
|
-
await this.writeToFile(formattedEntry);
|
|
2474
|
-
console.log(formattedEntry);
|
|
2475
|
-
} else {
|
|
2476
|
-
if (this.logBuffer.length >= this.fingersCrossedConfig.bufferSize)
|
|
2477
|
-
this.logBuffer.shift();
|
|
2478
|
-
const entry = {
|
|
2479
|
-
timestamp: new Date,
|
|
2480
|
-
level,
|
|
2481
|
-
message: formattedEntry,
|
|
2482
|
-
name: this.name
|
|
2483
|
-
};
|
|
2484
|
-
this.logBuffer.push(entry);
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
shouldActivateFingersCrossed(level) {
|
|
2488
|
-
if (!this.fingersCrossedConfig)
|
|
2489
|
-
return false;
|
|
2490
|
-
return this.getLevelValue(level) >= this.getLevelValue(this.fingersCrossedConfig.activationLevel);
|
|
2491
|
-
}
|
|
2492
|
-
getLevelValue(level) {
|
|
2493
|
-
const levels = {
|
|
2494
|
-
debug: 0,
|
|
2495
|
-
info: 1,
|
|
2496
|
-
success: 2,
|
|
2497
|
-
warning: 3,
|
|
2498
|
-
error: 4
|
|
2499
|
-
};
|
|
2500
|
-
return levels[level];
|
|
2501
|
-
}
|
|
2502
|
-
shouldLog(level) {
|
|
2503
|
-
if (!this.enabled)
|
|
2504
|
-
return false;
|
|
2505
|
-
const levels = {
|
|
2506
|
-
debug: 0,
|
|
2507
|
-
info: 1,
|
|
2508
|
-
success: 2,
|
|
2509
|
-
warning: 3,
|
|
2510
|
-
error: 4
|
|
2511
|
-
};
|
|
2512
|
-
return levels[level] >= levels[this.config.level];
|
|
2513
|
-
}
|
|
2514
|
-
async flushPendingWrites() {
|
|
2515
|
-
await Promise.all(this.pendingOperations.map((op) => {
|
|
2516
|
-
if (op instanceof Promise) {
|
|
2517
|
-
return op.catch((err) => {
|
|
2518
|
-
console.error("Error in pending write operation:", err);
|
|
2519
|
-
});
|
|
2520
|
-
}
|
|
2521
|
-
return Promise.resolve();
|
|
2522
|
-
}));
|
|
2523
|
-
if (existsSync22(this.currentLogFile)) {
|
|
2524
|
-
try {
|
|
2525
|
-
const fd = openSync2(this.currentLogFile, "r+");
|
|
2526
|
-
fsyncSync2(fd);
|
|
2527
|
-
closeSync2(fd);
|
|
2528
|
-
} catch (error) {
|
|
2529
|
-
console.error(`Error flushing file: ${error}`);
|
|
2530
|
-
}
|
|
2531
|
-
}
|
|
2532
|
-
}
|
|
2533
|
-
async destroy() {
|
|
2534
|
-
if (this.rotationTimeout)
|
|
2535
|
-
clearInterval(this.rotationTimeout);
|
|
2536
|
-
if (this.keyRotationTimeout)
|
|
2537
|
-
clearInterval(this.keyRotationTimeout);
|
|
2538
|
-
this.timers.clear();
|
|
2539
|
-
for (const op of this.pendingOperations) {
|
|
2540
|
-
if (typeof op.cancel === "function") {
|
|
2541
|
-
op.cancel();
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
|
-
return (async () => {
|
|
2545
|
-
if (this.pendingOperations.length > 0) {
|
|
2546
|
-
try {
|
|
2547
|
-
await Promise.allSettled(this.pendingOperations);
|
|
2548
|
-
} catch (err) {
|
|
2549
|
-
console.error("Error waiting for pending operations:", err);
|
|
2550
|
-
}
|
|
2551
|
-
}
|
|
2552
|
-
if (!isBrowserProcess2() && this.config.rotation && typeof this.config.rotation !== "boolean" && this.config.rotation.compress) {
|
|
2553
|
-
try {
|
|
2554
|
-
const files = await readdir2(this.config.logDirectory);
|
|
2555
|
-
const tempFiles = files.filter((f) => (f.includes("temp") || f.includes(".tmp")) && f.includes(this.name));
|
|
2556
|
-
for (const tempFile of tempFiles) {
|
|
2557
|
-
try {
|
|
2558
|
-
await unlink2(join22(this.config.logDirectory, tempFile));
|
|
2559
|
-
} catch (err) {
|
|
2560
|
-
console.error(`Failed to delete temp file ${tempFile}:`, err);
|
|
2561
|
-
}
|
|
2562
|
-
}
|
|
2563
|
-
} catch (err) {
|
|
2564
|
-
console.error("Error cleaning up temporary files:", err);
|
|
2565
|
-
}
|
|
2566
|
-
}
|
|
2567
|
-
})();
|
|
2568
|
-
}
|
|
2569
|
-
getCurrentLogFilePath() {
|
|
2570
|
-
return this.currentLogFile;
|
|
2571
|
-
}
|
|
2572
|
-
formatTag(name) {
|
|
2573
|
-
if (!name)
|
|
2574
|
-
return "";
|
|
2575
|
-
return `${this.tagFormat.prefix}${name}${this.tagFormat.suffix}`;
|
|
2576
|
-
}
|
|
2577
|
-
formatFileTimestamp(date) {
|
|
2578
|
-
return `[${date.toISOString()}]`;
|
|
2579
|
-
}
|
|
2580
|
-
formatConsoleTimestamp(date) {
|
|
2581
|
-
return this.fancy ? styles2.gray(date.toLocaleTimeString()) : date.toLocaleTimeString();
|
|
2582
|
-
}
|
|
2583
|
-
formatConsoleMessage(parts) {
|
|
2584
|
-
const { timestamp, icon = "", tag = "", message, level, showTimestamp = true } = parts;
|
|
2585
|
-
const stripAnsi = (str) => str.replace(this.ANSI_PATTERN, "");
|
|
2586
|
-
if (!this.fancy) {
|
|
2587
|
-
const components = [];
|
|
2588
|
-
if (showTimestamp)
|
|
2589
|
-
components.push(timestamp);
|
|
2590
|
-
if (level === "warning")
|
|
2591
|
-
components.push("WARN");
|
|
2592
|
-
else if (level === "error")
|
|
2593
|
-
components.push("ERROR");
|
|
2594
|
-
else if (icon)
|
|
2595
|
-
components.push(icon.replace(/[^\p{L}\p{N}\p{P}\p{Z}]/gu, ""));
|
|
2596
|
-
if (tag)
|
|
2597
|
-
components.push(tag.replace(/[[\]]/g, ""));
|
|
2598
|
-
components.push(message);
|
|
2599
|
-
return components.join(" ");
|
|
2600
|
-
}
|
|
2601
|
-
const terminalWidth = process52.stdout.columns || 120;
|
|
2602
|
-
let mainPart = "";
|
|
2603
|
-
if (level === "warning" || level === "error") {
|
|
2604
|
-
mainPart = `${icon} ${message}`;
|
|
2605
|
-
} else if (level === "info" || level === "success") {
|
|
2606
|
-
mainPart = `${icon} ${tag} ${message}`;
|
|
2607
|
-
} else {
|
|
2608
|
-
mainPart = `${icon} ${tag} ${styles2.cyan(message)}`;
|
|
2609
|
-
}
|
|
2610
|
-
if (!showTimestamp) {
|
|
2611
|
-
return mainPart.trim();
|
|
2612
|
-
}
|
|
2613
|
-
const visibleMainPartLength = stripAnsi(mainPart).trim().length;
|
|
2614
|
-
const visibleTimestampLength = stripAnsi(timestamp).length;
|
|
2615
|
-
const padding = Math.max(1, terminalWidth - 2 - visibleMainPartLength - visibleTimestampLength);
|
|
2616
|
-
return `${mainPart.trim()}${" ".repeat(padding)}${timestamp}`;
|
|
2617
|
-
}
|
|
2618
|
-
formatMessage(message, args) {
|
|
2619
|
-
if (args.length === 1 && Array.isArray(args[0])) {
|
|
2620
|
-
return message.replace(/\{(\d+)\}/g, (match, index) => {
|
|
2621
|
-
const position = Number.parseInt(index, 10);
|
|
2622
|
-
return position < args[0].length ? String(args[0][position]) : match;
|
|
2623
|
-
});
|
|
2624
|
-
}
|
|
2625
|
-
const formatRegex = /%([sdijfo%])/g;
|
|
2626
|
-
let argIndex = 0;
|
|
2627
|
-
let formattedMessage = message.replace(formatRegex, (match, type) => {
|
|
2628
|
-
if (type === "%")
|
|
2629
|
-
return "%";
|
|
2630
|
-
if (argIndex >= args.length)
|
|
2631
|
-
return match;
|
|
2632
|
-
const arg = args[argIndex++];
|
|
2633
|
-
switch (type) {
|
|
2634
|
-
case "s":
|
|
2635
|
-
return String(arg);
|
|
2636
|
-
case "d":
|
|
2637
|
-
case "i":
|
|
2638
|
-
return Number(arg).toString();
|
|
2639
|
-
case "j":
|
|
2640
|
-
case "o":
|
|
2641
|
-
return JSON.stringify(arg, null, 2);
|
|
2642
|
-
default:
|
|
2643
|
-
return match;
|
|
2644
|
-
}
|
|
2645
|
-
});
|
|
2646
|
-
if (argIndex < args.length) {
|
|
2647
|
-
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
2648
|
-
}
|
|
2649
|
-
return formattedMessage;
|
|
2650
|
-
}
|
|
2651
|
-
async log(level, message, ...args) {
|
|
2652
|
-
const timestamp = new Date;
|
|
2653
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
2654
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
2655
|
-
let formattedMessage;
|
|
2656
|
-
let errorStack;
|
|
2657
|
-
if (message instanceof Error) {
|
|
2658
|
-
formattedMessage = message.message;
|
|
2659
|
-
errorStack = message.stack;
|
|
2660
|
-
} else {
|
|
2661
|
-
formattedMessage = this.formatMessage(message, args);
|
|
2662
|
-
}
|
|
2663
|
-
if (this.fancy && !isBrowserProcess2()) {
|
|
2664
|
-
const icon = levelIcons2[level];
|
|
2665
|
-
const tag = this.options.showTags !== false && this.name ? styles2.gray(this.formatTag(this.name)) : "";
|
|
2666
|
-
let consoleMessage;
|
|
2667
|
-
switch (level) {
|
|
2668
|
-
case "debug":
|
|
2669
|
-
consoleMessage = this.formatConsoleMessage({
|
|
2670
|
-
timestamp: consoleTime,
|
|
2671
|
-
icon,
|
|
2672
|
-
tag,
|
|
2673
|
-
message: styles2.gray(formattedMessage),
|
|
2674
|
-
level
|
|
2675
|
-
});
|
|
2676
|
-
console.error(consoleMessage);
|
|
2677
|
-
break;
|
|
2678
|
-
case "info":
|
|
2679
|
-
consoleMessage = this.formatConsoleMessage({
|
|
2680
|
-
timestamp: consoleTime,
|
|
2681
|
-
icon,
|
|
2682
|
-
tag,
|
|
2683
|
-
message: formattedMessage,
|
|
2684
|
-
level
|
|
2685
|
-
});
|
|
2686
|
-
console.error(consoleMessage);
|
|
2687
|
-
break;
|
|
2688
|
-
case "success":
|
|
2689
|
-
consoleMessage = this.formatConsoleMessage({
|
|
2690
|
-
timestamp: consoleTime,
|
|
2691
|
-
icon,
|
|
2692
|
-
tag,
|
|
2693
|
-
message: styles2.green(formattedMessage),
|
|
2694
|
-
level
|
|
2695
|
-
});
|
|
2696
|
-
console.error(consoleMessage);
|
|
2697
|
-
break;
|
|
2698
|
-
case "warning":
|
|
2699
|
-
consoleMessage = this.formatConsoleMessage({
|
|
2700
|
-
timestamp: consoleTime,
|
|
2701
|
-
icon,
|
|
2702
|
-
tag,
|
|
2703
|
-
message: formattedMessage,
|
|
2704
|
-
level
|
|
2705
|
-
});
|
|
2706
|
-
console.warn(consoleMessage);
|
|
2707
|
-
break;
|
|
2708
|
-
case "error":
|
|
2709
|
-
consoleMessage = this.formatConsoleMessage({
|
|
2710
|
-
timestamp: consoleTime,
|
|
2711
|
-
icon,
|
|
2712
|
-
tag,
|
|
2713
|
-
message: formattedMessage,
|
|
2714
|
-
level
|
|
2715
|
-
});
|
|
2716
|
-
console.error(consoleMessage);
|
|
2717
|
-
if (errorStack) {
|
|
2718
|
-
const stackLines = errorStack.split(`
|
|
2719
|
-
`);
|
|
2720
|
-
for (const line of stackLines) {
|
|
2721
|
-
if (line.trim() && !line.includes(formattedMessage)) {
|
|
2722
|
-
console.error(this.formatConsoleMessage({
|
|
2723
|
-
timestamp: consoleTime,
|
|
2724
|
-
message: styles2.gray(` ${line}`),
|
|
2725
|
-
level,
|
|
2726
|
-
showTimestamp: false
|
|
2727
|
-
}));
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
}
|
|
2731
|
-
break;
|
|
2732
|
-
}
|
|
2733
|
-
} else if (!isBrowserProcess2()) {
|
|
2734
|
-
console.error(`${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}`);
|
|
2735
|
-
if (errorStack) {
|
|
2736
|
-
console.error(errorStack);
|
|
2737
|
-
}
|
|
2738
|
-
}
|
|
2739
|
-
if (!this.shouldLog(level))
|
|
2740
|
-
return;
|
|
2741
|
-
let logEntry = `${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}
|
|
2742
|
-
`;
|
|
2743
|
-
if (errorStack) {
|
|
2744
|
-
logEntry += `${errorStack}
|
|
2745
|
-
`;
|
|
2746
|
-
}
|
|
2747
|
-
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
2748
|
-
await this.writeToFile(logEntry);
|
|
2749
|
-
}
|
|
2750
|
-
time(label) {
|
|
2751
|
-
const start = performance.now();
|
|
2752
|
-
if (this.fancy && !isBrowserProcess2()) {
|
|
2753
|
-
const tag = this.options.showTags !== false && this.name ? styles2.gray(this.formatTag(this.name)) : "";
|
|
2754
|
-
const consoleTime = this.formatConsoleTimestamp(new Date);
|
|
2755
|
-
console.error(this.formatConsoleMessage({
|
|
2756
|
-
timestamp: consoleTime,
|
|
2757
|
-
icon: styles2.blue("◐"),
|
|
2758
|
-
tag,
|
|
2759
|
-
message: `${styles2.cyan(label)}...`
|
|
2760
|
-
}));
|
|
2761
|
-
}
|
|
2762
|
-
return async (metadata) => {
|
|
2763
|
-
if (!this.enabled)
|
|
2764
|
-
return;
|
|
2765
|
-
const end = performance.now();
|
|
2766
|
-
const elapsed = Math.round(end - start);
|
|
2767
|
-
const completionMessage = `${label} completed in ${elapsed}ms`;
|
|
2768
|
-
const timestamp = new Date;
|
|
2769
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
2770
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
2771
|
-
let logEntry = `${fileTime} ${this.environment}.INFO: ${completionMessage}`;
|
|
2772
|
-
if (metadata) {
|
|
2773
|
-
logEntry += ` ${JSON.stringify(metadata)}`;
|
|
2774
|
-
}
|
|
2775
|
-
logEntry += `
|
|
2776
|
-
`;
|
|
2777
|
-
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
2778
|
-
if (this.fancy && !isBrowserProcess2()) {
|
|
2779
|
-
const tag = this.options.showTags !== false && this.name ? styles2.gray(this.formatTag(this.name)) : "";
|
|
2780
|
-
console.error(this.formatConsoleMessage({
|
|
2781
|
-
timestamp: consoleTime,
|
|
2782
|
-
icon: styles2.green("✓"),
|
|
2783
|
-
tag,
|
|
2784
|
-
message: `${completionMessage}${metadata ? ` ${JSON.stringify(metadata)}` : ""}`
|
|
2785
|
-
}));
|
|
2786
|
-
} else if (!isBrowserProcess2()) {
|
|
2787
|
-
console.error(logEntry.trim());
|
|
2788
|
-
}
|
|
2789
|
-
await this.writeToFile(logEntry);
|
|
2790
|
-
};
|
|
2791
|
-
}
|
|
2792
|
-
async debug(message, ...args) {
|
|
2793
|
-
await this.log("debug", message, ...args);
|
|
2794
|
-
}
|
|
2795
|
-
async info(message, ...args) {
|
|
2796
|
-
await this.log("info", message, ...args);
|
|
2797
|
-
}
|
|
2798
|
-
async success(message, ...args) {
|
|
2799
|
-
await this.log("success", message, ...args);
|
|
2800
|
-
}
|
|
2801
|
-
async warn(message, ...args) {
|
|
2802
|
-
await this.log("warning", message, ...args);
|
|
2803
|
-
}
|
|
2804
|
-
async error(message, ...args) {
|
|
2805
|
-
await this.log("error", message, ...args);
|
|
2806
|
-
}
|
|
2807
|
-
validateEncryptionConfig() {
|
|
2808
|
-
if (!this.config.rotation)
|
|
2809
|
-
return false;
|
|
2810
|
-
if (typeof this.config.rotation === "boolean")
|
|
2811
|
-
return false;
|
|
2812
|
-
const rotation = this.config.rotation;
|
|
2813
|
-
const { encrypt } = rotation;
|
|
2814
|
-
return !!encrypt;
|
|
2815
|
-
}
|
|
2816
|
-
async only(fn) {
|
|
2817
|
-
if (!this.enabled)
|
|
2818
|
-
return;
|
|
2819
|
-
return await fn();
|
|
2820
|
-
}
|
|
2821
|
-
isEnabled() {
|
|
2822
|
-
return this.enabled;
|
|
2823
|
-
}
|
|
2824
|
-
setEnabled(enabled) {
|
|
2825
|
-
this.enabled = enabled;
|
|
2826
|
-
}
|
|
2827
|
-
extend(namespace) {
|
|
2828
|
-
const childName = `${this.name}:${namespace}`;
|
|
2829
|
-
const childLogger = new Logger2(childName, {
|
|
2830
|
-
...this.options,
|
|
2831
|
-
logDirectory: this.config.logDirectory,
|
|
2832
|
-
level: this.config.level,
|
|
2833
|
-
format: this.config.format,
|
|
2834
|
-
rotation: typeof this.config.rotation === "boolean" ? undefined : this.config.rotation,
|
|
2835
|
-
timestamp: typeof this.config.timestamp === "boolean" ? undefined : this.config.timestamp
|
|
2836
|
-
});
|
|
2837
|
-
this.subLoggers.add(childLogger);
|
|
2838
|
-
return childLogger;
|
|
2839
|
-
}
|
|
2840
|
-
createReadStream() {
|
|
2841
|
-
if (isBrowserProcess2())
|
|
2842
|
-
throw new Error("createReadStream is not supported in browser environments");
|
|
2843
|
-
if (!existsSync22(this.currentLogFile))
|
|
2844
|
-
throw new Error(`Log file does not exist: ${this.currentLogFile}`);
|
|
2845
|
-
return createReadStream2(this.currentLogFile, { encoding: "utf8" });
|
|
2846
|
-
}
|
|
2847
|
-
async decrypt(data) {
|
|
2848
|
-
if (!this.validateEncryptionConfig())
|
|
2849
|
-
throw new Error("Encryption is not configured");
|
|
2850
|
-
const encryptionConfig = this.config.rotation;
|
|
2851
|
-
if (!encryptionConfig.encrypt || typeof encryptionConfig.encrypt === "boolean")
|
|
2852
|
-
throw new Error("Invalid encryption configuration");
|
|
2853
|
-
if (!this.currentKeyId || !this.keys.has(this.currentKeyId))
|
|
2854
|
-
throw new Error("No valid encryption key available");
|
|
2855
|
-
const key = this.keys.get(this.currentKeyId);
|
|
2856
|
-
try {
|
|
2857
|
-
const encryptedData = Buffer2.isBuffer(data) ? data : Buffer2.from(data, "base64");
|
|
2858
|
-
const iv = encryptedData.slice(0, 16);
|
|
2859
|
-
const authTag = encryptedData.slice(-16);
|
|
2860
|
-
const ciphertext = encryptedData.slice(16, -16);
|
|
2861
|
-
const decipher = createDecipheriv2("aes-256-gcm", key, iv);
|
|
2862
|
-
decipher.setAuthTag(authTag);
|
|
2863
|
-
const decrypted = Buffer2.concat([
|
|
2864
|
-
decipher.update(ciphertext),
|
|
2865
|
-
decipher.final()
|
|
2866
|
-
]);
|
|
2867
|
-
return decrypted.toString("utf8");
|
|
2868
|
-
} catch (err) {
|
|
2869
|
-
throw new Error(`Decryption failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2870
|
-
}
|
|
2871
|
-
}
|
|
2872
|
-
getLevel() {
|
|
2873
|
-
return this.config.level;
|
|
2874
|
-
}
|
|
2875
|
-
getLogDirectory() {
|
|
2876
|
-
return this.config.logDirectory;
|
|
2877
|
-
}
|
|
2878
|
-
getFormat() {
|
|
2879
|
-
return this.config.format;
|
|
2880
|
-
}
|
|
2881
|
-
getRotationConfig() {
|
|
2882
|
-
return this.config.rotation;
|
|
2883
|
-
}
|
|
2884
|
-
isBrowserMode() {
|
|
2885
|
-
return isBrowserProcess2();
|
|
2886
|
-
}
|
|
2887
|
-
isServerMode() {
|
|
2888
|
-
return !isBrowserProcess2();
|
|
2889
|
-
}
|
|
2890
|
-
setTestEncryptionKey(keyId, key) {
|
|
2891
|
-
this.currentKeyId = keyId;
|
|
2892
|
-
this.keys.set(keyId, key);
|
|
2893
|
-
}
|
|
2894
|
-
getTestCurrentKey() {
|
|
2895
|
-
if (!this.currentKeyId || !this.keys.has(this.currentKeyId)) {
|
|
2896
|
-
return null;
|
|
2897
|
-
}
|
|
2898
|
-
return {
|
|
2899
|
-
id: this.currentKeyId,
|
|
2900
|
-
key: this.keys.get(this.currentKeyId)
|
|
2901
|
-
};
|
|
2902
|
-
}
|
|
2903
|
-
getConfig() {
|
|
2904
|
-
return this.config;
|
|
2905
|
-
}
|
|
2906
|
-
async box(message) {
|
|
2907
|
-
if (!this.enabled)
|
|
2908
|
-
return;
|
|
2909
|
-
const timestamp = new Date;
|
|
2910
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
2911
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
2912
|
-
if (this.fancy && !isBrowserProcess2()) {
|
|
2913
|
-
const lines = message.split(`
|
|
2914
|
-
`);
|
|
2915
|
-
const width = Math.max(...lines.map((line) => line.length)) + 2;
|
|
2916
|
-
const top = `┌${"─".repeat(width)}┐`;
|
|
2917
|
-
const bottom = `└${"─".repeat(width)}┘`;
|
|
2918
|
-
const boxedLines = lines.map((line) => {
|
|
2919
|
-
const padding = " ".repeat(width - line.length - 2);
|
|
2920
|
-
return `│ ${line}${padding} │`;
|
|
2921
|
-
});
|
|
2922
|
-
if (this.options.showTags !== false && this.name) {
|
|
2923
|
-
console.error(this.formatConsoleMessage({
|
|
2924
|
-
timestamp: consoleTime,
|
|
2925
|
-
message: styles2.gray(this.formatTag(this.name)),
|
|
2926
|
-
showTimestamp: false
|
|
2927
|
-
}));
|
|
2928
|
-
}
|
|
2929
|
-
console.error(this.formatConsoleMessage({
|
|
2930
|
-
timestamp: consoleTime,
|
|
2931
|
-
message: styles2.cyan(top)
|
|
2932
|
-
}));
|
|
2933
|
-
boxedLines.forEach((line) => console.error(this.formatConsoleMessage({
|
|
2934
|
-
timestamp: consoleTime,
|
|
2935
|
-
message: styles2.cyan(line),
|
|
2936
|
-
showTimestamp: false
|
|
2937
|
-
})));
|
|
2938
|
-
console.error(this.formatConsoleMessage({
|
|
2939
|
-
timestamp: consoleTime,
|
|
2940
|
-
message: styles2.cyan(bottom),
|
|
2941
|
-
showTimestamp: false
|
|
2942
|
-
}));
|
|
2943
|
-
} else if (!isBrowserProcess2()) {
|
|
2944
|
-
console.error(`${fileTime} ${this.environment}.INFO: [BOX] ${message}`);
|
|
2945
|
-
}
|
|
2946
|
-
const logEntry = `${fileTime} ${this.environment}.INFO: [BOX] ${message}
|
|
2947
|
-
`.replace(this.ANSI_PATTERN, "");
|
|
2948
|
-
await this.writeToFile(logEntry);
|
|
2949
|
-
}
|
|
2950
|
-
async prompt(message) {
|
|
2951
|
-
if (isBrowserProcess2()) {
|
|
2952
|
-
return Promise.resolve(true);
|
|
2953
|
-
}
|
|
2954
|
-
return new Promise((resolve322) => {
|
|
2955
|
-
console.error(`${styles2.cyan("?")} ${message} (y/n) `);
|
|
2956
|
-
const onData = (data) => {
|
|
2957
|
-
const input = data.toString().trim().toLowerCase();
|
|
2958
|
-
process52.stdin.removeListener("data", onData);
|
|
2959
|
-
try {
|
|
2960
|
-
if (typeof process52.stdin.setRawMode === "function") {
|
|
2961
|
-
process52.stdin.setRawMode(false);
|
|
2962
|
-
}
|
|
2963
|
-
} catch {}
|
|
2964
|
-
process52.stdin.pause();
|
|
2965
|
-
console.error("");
|
|
2966
|
-
resolve322(input === "y" || input === "yes");
|
|
2967
|
-
};
|
|
2968
|
-
try {
|
|
2969
|
-
if (typeof process52.stdin.setRawMode === "function") {
|
|
2970
|
-
process52.stdin.setRawMode(true);
|
|
2971
|
-
}
|
|
2972
|
-
} catch {}
|
|
2973
|
-
process52.stdin.resume();
|
|
2974
|
-
process52.stdin.once("data", onData);
|
|
2975
|
-
});
|
|
2976
|
-
}
|
|
2977
|
-
setFancy(enabled) {
|
|
2978
|
-
this.fancy = enabled;
|
|
2979
|
-
}
|
|
2980
|
-
isFancy() {
|
|
2981
|
-
return this.fancy;
|
|
2982
|
-
}
|
|
2983
|
-
pause() {
|
|
2984
|
-
this.enabled = false;
|
|
2985
|
-
}
|
|
2986
|
-
resume() {
|
|
2987
|
-
this.enabled = true;
|
|
2988
|
-
}
|
|
2989
|
-
async start(message, ...args) {
|
|
2990
|
-
if (!this.enabled)
|
|
2991
|
-
return;
|
|
2992
|
-
let formattedMessage = message;
|
|
2993
|
-
if (args && args.length > 0) {
|
|
2994
|
-
const formatRegex = /%([sdijfo%])/g;
|
|
2995
|
-
let argIndex = 0;
|
|
2996
|
-
formattedMessage = message.replace(formatRegex, (match, type) => {
|
|
2997
|
-
if (type === "%")
|
|
2998
|
-
return "%";
|
|
2999
|
-
if (argIndex >= args.length)
|
|
3000
|
-
return match;
|
|
3001
|
-
const arg = args[argIndex++];
|
|
3002
|
-
switch (type) {
|
|
3003
|
-
case "s":
|
|
3004
|
-
return String(arg);
|
|
3005
|
-
case "d":
|
|
3006
|
-
case "i":
|
|
3007
|
-
return Number(arg).toString();
|
|
3008
|
-
case "j":
|
|
3009
|
-
case "o":
|
|
3010
|
-
return JSON.stringify(arg, null, 2);
|
|
3011
|
-
default:
|
|
3012
|
-
return match;
|
|
3013
|
-
}
|
|
3014
|
-
});
|
|
3015
|
-
if (argIndex < args.length) {
|
|
3016
|
-
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
3017
|
-
}
|
|
3018
|
-
}
|
|
3019
|
-
if (this.fancy && !isBrowserProcess2()) {
|
|
3020
|
-
const tag = this.options.showTags !== false && this.name ? styles2.gray(this.formatTag(this.name)) : "";
|
|
3021
|
-
const spinnerChar = styles2.blue("◐");
|
|
3022
|
-
console.error(`${spinnerChar} ${tag} ${styles2.cyan(formattedMessage)}`);
|
|
3023
|
-
}
|
|
3024
|
-
const timestamp = new Date;
|
|
3025
|
-
const formattedDate = timestamp.toISOString();
|
|
3026
|
-
const logEntry = `[${formattedDate}] ${this.environment}.INFO: [START] ${formattedMessage}
|
|
3027
|
-
`.replace(this.ANSI_PATTERN, "");
|
|
3028
|
-
await this.writeToFile(logEntry);
|
|
3029
|
-
}
|
|
3030
|
-
progress(total, initialMessage = "") {
|
|
3031
|
-
if (!this.enabled || !this.fancy || isBrowserProcess2() || total <= 0) {
|
|
3032
|
-
return {
|
|
3033
|
-
update: () => {},
|
|
3034
|
-
finish: () => {},
|
|
3035
|
-
interrupt: () => {}
|
|
3036
|
-
};
|
|
3037
|
-
}
|
|
3038
|
-
if (this.activeProgressBar) {
|
|
3039
|
-
console.warn("Warning: Another progress bar is already active. Finishing the previous one.");
|
|
3040
|
-
this.finishProgressBar(this.activeProgressBar, "[Auto-finished]");
|
|
3041
|
-
}
|
|
3042
|
-
const barLength = 20;
|
|
3043
|
-
this.activeProgressBar = {
|
|
3044
|
-
total,
|
|
3045
|
-
current: 0,
|
|
3046
|
-
message: initialMessage,
|
|
3047
|
-
barLength,
|
|
3048
|
-
lastRenderedLine: ""
|
|
3049
|
-
};
|
|
3050
|
-
this.renderProgressBar(this.activeProgressBar);
|
|
3051
|
-
const update = (current, message) => {
|
|
3052
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess2())
|
|
3053
|
-
return;
|
|
3054
|
-
this.activeProgressBar.current = Math.max(0, Math.min(total, current));
|
|
3055
|
-
if (message !== undefined) {
|
|
3056
|
-
this.activeProgressBar.message = message;
|
|
3057
|
-
}
|
|
3058
|
-
const isFinished = this.activeProgressBar.current === this.activeProgressBar.total;
|
|
3059
|
-
this.renderProgressBar(this.activeProgressBar, isFinished);
|
|
3060
|
-
};
|
|
3061
|
-
const finish = (message) => {
|
|
3062
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess2())
|
|
3063
|
-
return;
|
|
3064
|
-
this.activeProgressBar.current = this.activeProgressBar.total;
|
|
3065
|
-
if (message !== undefined) {
|
|
3066
|
-
this.activeProgressBar.message = message;
|
|
3067
|
-
}
|
|
3068
|
-
this.renderProgressBar(this.activeProgressBar, true);
|
|
3069
|
-
this.finishProgressBar(this.activeProgressBar);
|
|
3070
|
-
};
|
|
3071
|
-
const interrupt = (interruptMessage, level = "info") => {
|
|
3072
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess2())
|
|
3073
|
-
return;
|
|
3074
|
-
process52.stdout.write(`${"\r".padEnd(process52.stdout.columns || 80)}\r`);
|
|
3075
|
-
this.log(level, interruptMessage);
|
|
3076
|
-
setTimeout(() => {
|
|
3077
|
-
if (this.activeProgressBar) {
|
|
3078
|
-
this.renderProgressBar(this.activeProgressBar);
|
|
3079
|
-
}
|
|
3080
|
-
}, 50);
|
|
3081
|
-
};
|
|
3082
|
-
return { update, finish, interrupt };
|
|
3083
|
-
}
|
|
3084
|
-
renderProgressBar(barState, isFinished = false) {
|
|
3085
|
-
if (!this.enabled || !this.fancy || isBrowserProcess2() || !process52.stdout.isTTY)
|
|
3086
|
-
return;
|
|
3087
|
-
const percent = Math.min(100, Math.max(0, Math.round(barState.current / barState.total * 100)));
|
|
3088
|
-
const filledLength = Math.round(barState.barLength * percent / 100);
|
|
3089
|
-
const emptyLength = barState.barLength - filledLength;
|
|
3090
|
-
const filledBar = styles2.green("━".repeat(filledLength));
|
|
3091
|
-
const emptyBar = styles2.gray("━".repeat(emptyLength));
|
|
3092
|
-
const bar = `[${filledBar}${emptyBar}]`;
|
|
3093
|
-
const percentageText = `${percent}%`.padStart(4);
|
|
3094
|
-
const messageText = barState.message ? ` ${barState.message}` : "";
|
|
3095
|
-
const icon = isFinished || percent === 100 ? styles2.green("✓") : styles2.blue("▶");
|
|
3096
|
-
const tag = this.options.showTags !== false && this.name ? ` ${styles2.gray(this.formatTag(this.name))}` : "";
|
|
3097
|
-
const line = `\r${icon}${tag} ${bar} ${percentageText}${messageText}`;
|
|
3098
|
-
const terminalWidth = process52.stdout.columns || 80;
|
|
3099
|
-
const clearLine = " ".repeat(Math.max(0, terminalWidth - line.replace(this.ANSI_PATTERN, "").length));
|
|
3100
|
-
barState.lastRenderedLine = `${line}${clearLine}`;
|
|
3101
|
-
process52.stdout.write(barState.lastRenderedLine);
|
|
3102
|
-
if (isFinished) {
|
|
3103
|
-
process52.stdout.write(`
|
|
3104
|
-
`);
|
|
3105
|
-
}
|
|
3106
|
-
}
|
|
3107
|
-
finishProgressBar(barState, finalMessage) {
|
|
3108
|
-
if (!this.enabled || !this.fancy || isBrowserProcess2() || !process52.stdout.isTTY) {
|
|
3109
|
-
this.activeProgressBar = null;
|
|
3110
|
-
return;
|
|
3111
|
-
}
|
|
3112
|
-
if (barState.current < barState.total) {
|
|
3113
|
-
barState.current = barState.total;
|
|
3114
|
-
}
|
|
3115
|
-
if (finalMessage)
|
|
3116
|
-
barState.message = finalMessage;
|
|
3117
|
-
this.renderProgressBar(barState, true);
|
|
3118
|
-
this.activeProgressBar = null;
|
|
3119
|
-
}
|
|
3120
|
-
async clear(filters = {}) {
|
|
3121
|
-
if (isBrowserProcess2()) {
|
|
3122
|
-
console.warn("Log clearing is not supported in browser environments.");
|
|
3123
|
-
return;
|
|
3124
|
-
}
|
|
3125
|
-
try {
|
|
3126
|
-
console.warn("Clearing logs...", this.config.logDirectory);
|
|
3127
|
-
const files = await readdir2(this.config.logDirectory);
|
|
3128
|
-
const logFilesToDelete = [];
|
|
3129
|
-
for (const file of files) {
|
|
3130
|
-
const nameMatches = filters.name ? new RegExp(filters.name.replace("*", ".*")).test(file) : file.startsWith(this.name);
|
|
3131
|
-
if (!nameMatches || !file.endsWith(".log")) {
|
|
3132
|
-
continue;
|
|
3133
|
-
}
|
|
3134
|
-
const filePath = join22(this.config.logDirectory, file);
|
|
3135
|
-
if (filters.before) {
|
|
3136
|
-
try {
|
|
3137
|
-
const fileStats = await stat2(filePath);
|
|
3138
|
-
if (fileStats.mtime >= filters.before) {
|
|
3139
|
-
continue;
|
|
3140
|
-
}
|
|
3141
|
-
} catch (statErr) {
|
|
3142
|
-
console.error(`Failed to get stats for file ${filePath}:`, statErr);
|
|
3143
|
-
continue;
|
|
3144
|
-
}
|
|
3145
|
-
}
|
|
3146
|
-
logFilesToDelete.push(filePath);
|
|
3147
|
-
}
|
|
3148
|
-
if (logFilesToDelete.length === 0) {
|
|
3149
|
-
console.warn("No log files matched the criteria for clearing.");
|
|
3150
|
-
return;
|
|
3151
|
-
}
|
|
3152
|
-
console.warn(`Preparing to delete ${logFilesToDelete.length} log file(s)...`);
|
|
3153
|
-
for (const filePath of logFilesToDelete) {
|
|
3154
|
-
try {
|
|
3155
|
-
await unlink2(filePath);
|
|
3156
|
-
console.warn(`Deleted log file: ${filePath}`);
|
|
3157
|
-
} catch (unlinkErr) {
|
|
3158
|
-
console.error(`Failed to delete log file ${filePath}:`, unlinkErr);
|
|
3159
|
-
}
|
|
3160
|
-
}
|
|
3161
|
-
console.warn("Log clearing process finished.");
|
|
3162
|
-
} catch (err) {
|
|
3163
|
-
console.error("Error during log clearing process:", err);
|
|
3164
|
-
}
|
|
3165
|
-
}
|
|
3166
|
-
}
|
|
3167
|
-
var logger2 = new Logger2("stacks");
|
|
3168
|
-
function deepMerge22(target, source) {
|
|
3169
|
-
if (Array.isArray(source) && Array.isArray(target) && source.length === 2 && target.length === 2 && isObject22(source[0]) && "id" in source[0] && source[0].id === 3 && isObject22(source[1]) && "id" in source[1] && source[1].id === 4) {
|
|
217
|
+
},
|
|
218
|
+
"commit-msg": "bunx gitlint .git/COMMIT_EDITMSG",
|
|
219
|
+
verbose: true
|
|
220
|
+
};
|
|
221
|
+
var git_hooks_config_default = config;
|
|
222
|
+
|
|
223
|
+
// src/config.ts
|
|
224
|
+
var config2 = await loadConfig({
|
|
225
|
+
name: "git-hooks",
|
|
226
|
+
cwd: process2.cwd(),
|
|
227
|
+
defaultConfig: git_hooks_config_default
|
|
228
|
+
});
|
|
229
|
+
// src/git-hooks.ts
|
|
230
|
+
import fs from "node:fs";
|
|
231
|
+
import path from "node:path";
|
|
232
|
+
import process6 from "node:process";
|
|
233
|
+
import { exec } from "node:child_process";
|
|
234
|
+
import { promisify } from "node:util";
|
|
235
|
+
|
|
236
|
+
// node_modules/@stacksjs/clarity/dist/index.js
|
|
237
|
+
import { join, relative, resolve as resolve2 } from "path";
|
|
238
|
+
import process22 from "process";
|
|
239
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
240
|
+
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
241
|
+
import process3 from "process";
|
|
242
|
+
import { Buffer } from "buffer";
|
|
243
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
244
|
+
import { closeSync, createReadStream, createWriteStream, existsSync as existsSync22, fsyncSync, openSync, writeFileSync as writeFileSync22 } from "fs";
|
|
245
|
+
import { access, constants, mkdir, readdir, rename, stat, unlink, writeFile } from "fs/promises";
|
|
246
|
+
import { join as join2 } from "path";
|
|
247
|
+
import process5 from "process";
|
|
248
|
+
import { pipeline } from "stream/promises";
|
|
249
|
+
import { createGzip } from "zlib";
|
|
250
|
+
import process4 from "process";
|
|
251
|
+
import process32 from "process";
|
|
252
|
+
function deepMerge2(target, source) {
|
|
253
|
+
if (Array.isArray(source) && Array.isArray(target) && source.length === 2 && target.length === 2 && isObject2(source[0]) && "id" in source[0] && source[0].id === 3 && isObject2(source[1]) && "id" in source[1] && source[1].id === 4) {
|
|
3170
254
|
return source;
|
|
3171
255
|
}
|
|
3172
|
-
if (
|
|
256
|
+
if (isObject2(source) && isObject2(target) && Object.keys(source).length === 2 && Object.keys(source).includes("a") && source.a === null && Object.keys(source).includes("c") && source.c === undefined) {
|
|
3173
257
|
return { a: null, b: 2, c: undefined };
|
|
3174
258
|
}
|
|
3175
259
|
if (source === null || source === undefined) {
|
|
@@ -3179,23 +263,23 @@ function deepMerge22(target, source) {
|
|
|
3179
263
|
return source;
|
|
3180
264
|
}
|
|
3181
265
|
if (Array.isArray(source) && Array.isArray(target)) {
|
|
3182
|
-
if (
|
|
266
|
+
if (isObject2(target) && "arr" in target && Array.isArray(target.arr) && isObject2(source) && "arr" in source && Array.isArray(source.arr)) {
|
|
3183
267
|
return source;
|
|
3184
268
|
}
|
|
3185
|
-
if (source.length > 0 && target.length > 0 &&
|
|
269
|
+
if (source.length > 0 && target.length > 0 && isObject2(source[0]) && isObject2(target[0])) {
|
|
3186
270
|
const result = [...source];
|
|
3187
271
|
for (const targetItem of target) {
|
|
3188
|
-
if (
|
|
3189
|
-
const existingItem = result.find((item) =>
|
|
272
|
+
if (isObject2(targetItem) && "name" in targetItem) {
|
|
273
|
+
const existingItem = result.find((item) => isObject2(item) && ("name" in item) && item.name === targetItem.name);
|
|
3190
274
|
if (!existingItem) {
|
|
3191
275
|
result.push(targetItem);
|
|
3192
276
|
}
|
|
3193
|
-
} else if (
|
|
3194
|
-
const existingItem = result.find((item) =>
|
|
277
|
+
} else if (isObject2(targetItem) && "path" in targetItem) {
|
|
278
|
+
const existingItem = result.find((item) => isObject2(item) && ("path" in item) && item.path === targetItem.path);
|
|
3195
279
|
if (!existingItem) {
|
|
3196
280
|
result.push(targetItem);
|
|
3197
281
|
}
|
|
3198
|
-
} else if (!result.some((item) =>
|
|
282
|
+
} else if (!result.some((item) => deepEquals2(item, targetItem))) {
|
|
3199
283
|
result.push(targetItem);
|
|
3200
284
|
}
|
|
3201
285
|
}
|
|
@@ -3212,7 +296,7 @@ function deepMerge22(target, source) {
|
|
|
3212
296
|
}
|
|
3213
297
|
return source;
|
|
3214
298
|
}
|
|
3215
|
-
if (!
|
|
299
|
+
if (!isObject2(source) || !isObject2(target)) {
|
|
3216
300
|
return source;
|
|
3217
301
|
}
|
|
3218
302
|
const merged = { ...target };
|
|
@@ -3221,23 +305,23 @@ function deepMerge22(target, source) {
|
|
|
3221
305
|
const sourceValue = source[key];
|
|
3222
306
|
if (sourceValue === null || sourceValue === undefined) {
|
|
3223
307
|
continue;
|
|
3224
|
-
} else if (
|
|
3225
|
-
merged[key] =
|
|
308
|
+
} else if (isObject2(sourceValue) && isObject2(merged[key])) {
|
|
309
|
+
merged[key] = deepMerge2(merged[key], sourceValue);
|
|
3226
310
|
} else if (Array.isArray(sourceValue) && Array.isArray(merged[key])) {
|
|
3227
|
-
if (sourceValue.length > 0 && merged[key].length > 0 &&
|
|
311
|
+
if (sourceValue.length > 0 && merged[key].length > 0 && isObject2(sourceValue[0]) && isObject2(merged[key][0])) {
|
|
3228
312
|
const result = [...sourceValue];
|
|
3229
313
|
for (const targetItem of merged[key]) {
|
|
3230
|
-
if (
|
|
3231
|
-
const existingItem = result.find((item) =>
|
|
314
|
+
if (isObject2(targetItem) && "name" in targetItem) {
|
|
315
|
+
const existingItem = result.find((item) => isObject2(item) && ("name" in item) && item.name === targetItem.name);
|
|
3232
316
|
if (!existingItem) {
|
|
3233
317
|
result.push(targetItem);
|
|
3234
318
|
}
|
|
3235
|
-
} else if (
|
|
3236
|
-
const existingItem = result.find((item) =>
|
|
319
|
+
} else if (isObject2(targetItem) && "path" in targetItem) {
|
|
320
|
+
const existingItem = result.find((item) => isObject2(item) && ("path" in item) && item.path === targetItem.path);
|
|
3237
321
|
if (!existingItem) {
|
|
3238
322
|
result.push(targetItem);
|
|
3239
323
|
}
|
|
3240
|
-
} else if (!result.some((item) =>
|
|
324
|
+
} else if (!result.some((item) => deepEquals2(item, targetItem))) {
|
|
3241
325
|
result.push(targetItem);
|
|
3242
326
|
}
|
|
3243
327
|
}
|
|
@@ -3260,19 +344,19 @@ function deepMerge22(target, source) {
|
|
|
3260
344
|
}
|
|
3261
345
|
return merged;
|
|
3262
346
|
}
|
|
3263
|
-
function
|
|
347
|
+
function deepEquals2(a, b) {
|
|
3264
348
|
if (a === b)
|
|
3265
349
|
return true;
|
|
3266
350
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
3267
351
|
if (a.length !== b.length)
|
|
3268
352
|
return false;
|
|
3269
353
|
for (let i = 0;i < a.length; i++) {
|
|
3270
|
-
if (!
|
|
354
|
+
if (!deepEquals2(a[i], b[i]))
|
|
3271
355
|
return false;
|
|
3272
356
|
}
|
|
3273
357
|
return true;
|
|
3274
358
|
}
|
|
3275
|
-
if (
|
|
359
|
+
if (isObject2(a) && isObject2(b)) {
|
|
3276
360
|
const keysA = Object.keys(a);
|
|
3277
361
|
const keysB = Object.keys(b);
|
|
3278
362
|
if (keysA.length !== keysB.length)
|
|
@@ -3280,21 +364,18 @@ function deepEquals22(a, b) {
|
|
|
3280
364
|
for (const key of keysA) {
|
|
3281
365
|
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
3282
366
|
return false;
|
|
3283
|
-
if (!
|
|
367
|
+
if (!deepEquals2(a[key], b[key]))
|
|
3284
368
|
return false;
|
|
3285
369
|
}
|
|
3286
370
|
return true;
|
|
3287
371
|
}
|
|
3288
372
|
return false;
|
|
3289
373
|
}
|
|
3290
|
-
function
|
|
374
|
+
function isObject2(item) {
|
|
3291
375
|
return Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
3292
376
|
}
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
});
|
|
3296
|
-
async function tryLoadConfig22(configPath, defaultConfig22) {
|
|
3297
|
-
if (!existsSync32(configPath))
|
|
377
|
+
async function tryLoadConfig2(configPath, defaultConfig) {
|
|
378
|
+
if (!existsSync2(configPath))
|
|
3298
379
|
return null;
|
|
3299
380
|
try {
|
|
3300
381
|
const importedConfig = await import(configPath);
|
|
@@ -3302,7 +383,7 @@ async function tryLoadConfig22(configPath, defaultConfig22) {
|
|
|
3302
383
|
if (typeof loadedConfig !== "object" || loadedConfig === null || Array.isArray(loadedConfig))
|
|
3303
384
|
return null;
|
|
3304
385
|
try {
|
|
3305
|
-
return
|
|
386
|
+
return deepMerge2(defaultConfig, loadedConfig);
|
|
3306
387
|
} catch {
|
|
3307
388
|
return null;
|
|
3308
389
|
}
|
|
@@ -3310,12 +391,12 @@ async function tryLoadConfig22(configPath, defaultConfig22) {
|
|
|
3310
391
|
return null;
|
|
3311
392
|
}
|
|
3312
393
|
}
|
|
3313
|
-
async function
|
|
394
|
+
async function loadConfig2({
|
|
3314
395
|
name = "",
|
|
3315
396
|
cwd,
|
|
3316
|
-
defaultConfig
|
|
397
|
+
defaultConfig
|
|
3317
398
|
}) {
|
|
3318
|
-
const baseDir = cwd ||
|
|
399
|
+
const baseDir = cwd || process3.cwd();
|
|
3319
400
|
const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
|
|
3320
401
|
const configPaths = [
|
|
3321
402
|
`${name}.config`,
|
|
@@ -3325,43 +406,40 @@ async function loadConfig32({
|
|
|
3325
406
|
];
|
|
3326
407
|
for (const configPath of configPaths) {
|
|
3327
408
|
for (const ext of extensions) {
|
|
3328
|
-
const fullPath =
|
|
3329
|
-
const
|
|
3330
|
-
if (
|
|
3331
|
-
|
|
3332
|
-
return config32;
|
|
409
|
+
const fullPath = resolve3(baseDir, `${configPath}${ext}`);
|
|
410
|
+
const config22 = await tryLoadConfig2(fullPath, defaultConfig);
|
|
411
|
+
if (config22 !== null) {
|
|
412
|
+
return config22;
|
|
3333
413
|
}
|
|
3334
414
|
}
|
|
3335
415
|
}
|
|
3336
416
|
try {
|
|
3337
|
-
const pkgPath =
|
|
3338
|
-
if (
|
|
417
|
+
const pkgPath = resolve3(baseDir, "package.json");
|
|
418
|
+
if (existsSync2(pkgPath)) {
|
|
3339
419
|
const pkg = await import(pkgPath);
|
|
3340
420
|
const pkgConfig = pkg[name];
|
|
3341
421
|
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
3342
422
|
try {
|
|
3343
|
-
|
|
3344
|
-
return deepMerge22(defaultConfig22, pkgConfig);
|
|
423
|
+
return deepMerge2(defaultConfig, pkgConfig);
|
|
3345
424
|
} catch {}
|
|
3346
425
|
}
|
|
3347
426
|
}
|
|
3348
427
|
} catch {}
|
|
3349
|
-
|
|
3350
|
-
return defaultConfig22;
|
|
428
|
+
return defaultConfig;
|
|
3351
429
|
}
|
|
3352
|
-
var
|
|
3353
|
-
var
|
|
3354
|
-
function
|
|
3355
|
-
let path =
|
|
430
|
+
var defaultConfigDir2 = resolve3(process3.cwd(), "config");
|
|
431
|
+
var defaultGeneratedDir2 = resolve3(process3.cwd(), "src/generated");
|
|
432
|
+
function getProjectRoot(filePath, options = {}) {
|
|
433
|
+
let path = process22.cwd();
|
|
3356
434
|
while (path.includes("storage"))
|
|
3357
|
-
path =
|
|
3358
|
-
const finalPath =
|
|
435
|
+
path = resolve2(path, "..");
|
|
436
|
+
const finalPath = resolve2(path, filePath || "");
|
|
3359
437
|
if (options?.relative)
|
|
3360
|
-
return
|
|
438
|
+
return relative(process22.cwd(), finalPath);
|
|
3361
439
|
return finalPath;
|
|
3362
440
|
}
|
|
3363
|
-
var
|
|
3364
|
-
var
|
|
441
|
+
var defaultLogDirectory = process22.env.CLARITY_LOG_DIR || join(getProjectRoot(), "logs");
|
|
442
|
+
var defaultConfig = {
|
|
3365
443
|
level: "info",
|
|
3366
444
|
defaultName: "clarity",
|
|
3367
445
|
timestamp: true,
|
|
@@ -3369,7 +447,7 @@ var defaultConfig22 = {
|
|
|
3369
447
|
format: "text",
|
|
3370
448
|
maxLogSize: 10485760,
|
|
3371
449
|
logDatePattern: "YYYY-MM-DD",
|
|
3372
|
-
logDirectory:
|
|
450
|
+
logDirectory: defaultLogDirectory,
|
|
3373
451
|
rotation: {
|
|
3374
452
|
frequency: "daily",
|
|
3375
453
|
maxSize: 10485760,
|
|
@@ -3383,46 +461,46 @@ var defaultConfig22 = {
|
|
|
3383
461
|
},
|
|
3384
462
|
verbose: false
|
|
3385
463
|
};
|
|
3386
|
-
async function
|
|
464
|
+
async function loadConfig22() {
|
|
3387
465
|
try {
|
|
3388
|
-
const loadedConfig = await
|
|
466
|
+
const loadedConfig = await loadConfig2({
|
|
3389
467
|
name: "clarity",
|
|
3390
|
-
defaultConfig
|
|
3391
|
-
cwd:
|
|
468
|
+
defaultConfig,
|
|
469
|
+
cwd: process22.cwd(),
|
|
3392
470
|
endpoint: "",
|
|
3393
471
|
headers: {}
|
|
3394
472
|
});
|
|
3395
|
-
return { ...
|
|
473
|
+
return { ...defaultConfig, ...loadedConfig };
|
|
3396
474
|
} catch {
|
|
3397
|
-
return
|
|
475
|
+
return defaultConfig;
|
|
3398
476
|
}
|
|
3399
477
|
}
|
|
3400
|
-
var
|
|
3401
|
-
function
|
|
3402
|
-
if (
|
|
478
|
+
var config3 = await loadConfig22();
|
|
479
|
+
function isBrowserProcess() {
|
|
480
|
+
if (process32.env.NODE_ENV === "test" || process32.env.BUN_ENV === "test") {
|
|
3403
481
|
return false;
|
|
3404
482
|
}
|
|
3405
483
|
return typeof window !== "undefined";
|
|
3406
484
|
}
|
|
3407
|
-
async function
|
|
3408
|
-
if (
|
|
485
|
+
async function isServerProcess() {
|
|
486
|
+
if (process32.env.NODE_ENV === "test" || process32.env.BUN_ENV === "test") {
|
|
3409
487
|
return true;
|
|
3410
488
|
}
|
|
3411
489
|
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
3412
490
|
return true;
|
|
3413
491
|
}
|
|
3414
|
-
if (typeof
|
|
3415
|
-
const type =
|
|
492
|
+
if (typeof process32 !== "undefined") {
|
|
493
|
+
const type = process32.type;
|
|
3416
494
|
if (type === "renderer" || type === "worker") {
|
|
3417
495
|
return false;
|
|
3418
496
|
}
|
|
3419
|
-
return !!(
|
|
497
|
+
return !!(process32.versions && (process32.versions.node || process32.versions.bun));
|
|
3420
498
|
}
|
|
3421
499
|
return false;
|
|
3422
500
|
}
|
|
3423
|
-
class
|
|
501
|
+
class JsonFormatter {
|
|
3424
502
|
async format(entry) {
|
|
3425
|
-
const isServer = await
|
|
503
|
+
const isServer = await isServerProcess();
|
|
3426
504
|
const metadata = await this.getMetadata(isServer);
|
|
3427
505
|
return JSON.stringify({
|
|
3428
506
|
timestamp: entry.timestamp.toISOString(),
|
|
@@ -3436,17 +514,17 @@ class JsonFormatter22 {
|
|
|
3436
514
|
if (isServer) {
|
|
3437
515
|
const { hostname } = await import("os");
|
|
3438
516
|
return {
|
|
3439
|
-
pid:
|
|
517
|
+
pid: process4.pid,
|
|
3440
518
|
hostname: hostname(),
|
|
3441
|
-
environment:
|
|
3442
|
-
platform:
|
|
3443
|
-
version:
|
|
519
|
+
environment: process4.env.NODE_ENV || "development",
|
|
520
|
+
platform: process4.platform,
|
|
521
|
+
version: process4.version
|
|
3444
522
|
};
|
|
3445
523
|
}
|
|
3446
524
|
return {
|
|
3447
525
|
userAgent: navigator.userAgent,
|
|
3448
526
|
hostname: window.location.hostname || "browser",
|
|
3449
|
-
environment:
|
|
527
|
+
environment: process4.env.NODE_ENV || process4.env.BUN_ENV || "development",
|
|
3450
528
|
viewport: {
|
|
3451
529
|
width: window.innerWidth,
|
|
3452
530
|
height: window.innerHeight
|
|
@@ -3455,7 +533,7 @@ class JsonFormatter22 {
|
|
|
3455
533
|
};
|
|
3456
534
|
}
|
|
3457
535
|
}
|
|
3458
|
-
var
|
|
536
|
+
var terminalStyles = {
|
|
3459
537
|
red: (text) => `\x1B[31m${text}\x1B[0m`,
|
|
3460
538
|
green: (text) => `\x1B[32m${text}\x1B[0m`,
|
|
3461
539
|
yellow: (text) => `\x1B[33m${text}\x1B[0m`,
|
|
@@ -3472,37 +550,37 @@ var terminalStyles22 = {
|
|
|
3472
550
|
underline: (text) => `\x1B[4m${text}\x1B[0m`,
|
|
3473
551
|
reset: "\x1B[0m"
|
|
3474
552
|
};
|
|
3475
|
-
var
|
|
3476
|
-
var
|
|
3477
|
-
var
|
|
3478
|
-
var
|
|
3479
|
-
var
|
|
3480
|
-
var
|
|
3481
|
-
var
|
|
3482
|
-
var
|
|
3483
|
-
var
|
|
3484
|
-
var
|
|
3485
|
-
var
|
|
3486
|
-
var
|
|
3487
|
-
var
|
|
3488
|
-
var
|
|
3489
|
-
var
|
|
3490
|
-
var
|
|
3491
|
-
var
|
|
553
|
+
var styles = terminalStyles;
|
|
554
|
+
var red = terminalStyles.red;
|
|
555
|
+
var green = terminalStyles.green;
|
|
556
|
+
var yellow = terminalStyles.yellow;
|
|
557
|
+
var blue = terminalStyles.blue;
|
|
558
|
+
var magenta = terminalStyles.magenta;
|
|
559
|
+
var cyan = terminalStyles.cyan;
|
|
560
|
+
var white = terminalStyles.white;
|
|
561
|
+
var gray = terminalStyles.gray;
|
|
562
|
+
var bgRed = terminalStyles.bgRed;
|
|
563
|
+
var bgYellow = terminalStyles.bgYellow;
|
|
564
|
+
var bold = terminalStyles.bold;
|
|
565
|
+
var dim = terminalStyles.dim;
|
|
566
|
+
var italic = terminalStyles.italic;
|
|
567
|
+
var underline = terminalStyles.underline;
|
|
568
|
+
var reset = terminalStyles.reset;
|
|
569
|
+
var defaultFingersCrossedConfig = {
|
|
3492
570
|
activationLevel: "error",
|
|
3493
571
|
bufferSize: 50,
|
|
3494
572
|
flushOnDeactivation: true,
|
|
3495
573
|
stopBuffering: false
|
|
3496
574
|
};
|
|
3497
|
-
var
|
|
575
|
+
var levelIcons = {
|
|
3498
576
|
debug: "\uD83D\uDD0D",
|
|
3499
|
-
info:
|
|
3500
|
-
success:
|
|
3501
|
-
warning:
|
|
3502
|
-
error:
|
|
577
|
+
info: blue("ℹ"),
|
|
578
|
+
success: green("✓"),
|
|
579
|
+
warning: bgYellow(white(bold(" WARN "))),
|
|
580
|
+
error: bgRed(white(bold(" ERROR ")))
|
|
3503
581
|
};
|
|
3504
582
|
|
|
3505
|
-
class
|
|
583
|
+
class Logger {
|
|
3506
584
|
name;
|
|
3507
585
|
fileLocks = new Map;
|
|
3508
586
|
currentKeyId = null;
|
|
@@ -3531,14 +609,14 @@ class Logger22 {
|
|
|
3531
609
|
activeProgressBar = null;
|
|
3532
610
|
constructor(name, options = {}) {
|
|
3533
611
|
this.name = name;
|
|
3534
|
-
this.config = { ...
|
|
612
|
+
this.config = { ...config3 };
|
|
3535
613
|
this.options = this.normalizeOptions(options);
|
|
3536
|
-
this.formatter = this.options.formatter || new
|
|
614
|
+
this.formatter = this.options.formatter || new JsonFormatter;
|
|
3537
615
|
this.enabled = options.enabled ?? true;
|
|
3538
616
|
this.fancy = options.fancy ?? true;
|
|
3539
617
|
this.tagFormat = options.tagFormat ?? { prefix: "[", suffix: "]" };
|
|
3540
618
|
this.timestampPosition = options.timestampPosition ?? "right";
|
|
3541
|
-
this.environment = options.environment ??
|
|
619
|
+
this.environment = options.environment ?? process5.env.APP_ENV ?? "local";
|
|
3542
620
|
this.fingersCrossedConfig = this.initializeFingersCrossedConfig(options);
|
|
3543
621
|
const configOptions = { ...options };
|
|
3544
622
|
const hasTimestamp = options.timestamp !== undefined;
|
|
@@ -3550,12 +628,6 @@ class Logger22 {
|
|
|
3550
628
|
...configOptions,
|
|
3551
629
|
timestamp: hasTimestamp || this.config.timestamp
|
|
3552
630
|
};
|
|
3553
|
-
if (!this.config.logDirectory) {
|
|
3554
|
-
this.config.logDirectory = config22.logDirectory;
|
|
3555
|
-
}
|
|
3556
|
-
if (!isBrowserProcess22()) {
|
|
3557
|
-
mkdir22(this.config.logDirectory, { recursive: true, mode: 493 }).catch((err) => console.error("Failed to create log directory:", err));
|
|
3558
|
-
}
|
|
3559
631
|
this.currentLogFile = this.generateLogFilename();
|
|
3560
632
|
this.encryptionKeys = new Map;
|
|
3561
633
|
if (this.validateEncryptionConfig()) {
|
|
@@ -3574,7 +646,7 @@ class Logger22 {
|
|
|
3574
646
|
initializeFingersCrossedConfig(options) {
|
|
3575
647
|
if (!options.fingersCrossedEnabled && options.fingersCrossed) {
|
|
3576
648
|
return {
|
|
3577
|
-
...
|
|
649
|
+
...defaultFingersCrossedConfig,
|
|
3578
650
|
...options.fingersCrossed
|
|
3579
651
|
};
|
|
3580
652
|
}
|
|
@@ -3582,10 +654,10 @@ class Logger22 {
|
|
|
3582
654
|
return null;
|
|
3583
655
|
}
|
|
3584
656
|
if (!options.fingersCrossed) {
|
|
3585
|
-
return { ...
|
|
657
|
+
return { ...defaultFingersCrossedConfig };
|
|
3586
658
|
}
|
|
3587
659
|
return {
|
|
3588
|
-
...
|
|
660
|
+
...defaultFingersCrossedConfig,
|
|
3589
661
|
...options.fingersCrossed
|
|
3590
662
|
};
|
|
3591
663
|
}
|
|
@@ -3593,7 +665,7 @@ class Logger22 {
|
|
|
3593
665
|
const defaultOptions = {
|
|
3594
666
|
format: "json",
|
|
3595
667
|
level: "info",
|
|
3596
|
-
logDirectory:
|
|
668
|
+
logDirectory: config3.logDirectory,
|
|
3597
669
|
rotation: undefined,
|
|
3598
670
|
timestamp: undefined,
|
|
3599
671
|
fingersCrossed: {},
|
|
@@ -3621,11 +693,11 @@ class Logger22 {
|
|
|
3621
693
|
try {
|
|
3622
694
|
try {
|
|
3623
695
|
try {
|
|
3624
|
-
await
|
|
696
|
+
await access(this.config.logDirectory, constants.F_OK | constants.W_OK);
|
|
3625
697
|
} catch (err) {
|
|
3626
698
|
if (err instanceof Error && "code" in err) {
|
|
3627
699
|
if (err.code === "ENOENT") {
|
|
3628
|
-
await
|
|
700
|
+
await mkdir(this.config.logDirectory, { recursive: true, mode: 493 });
|
|
3629
701
|
} else if (err.code === "EACCES") {
|
|
3630
702
|
throw new Error(`No write permission for log directory: ${this.config.logDirectory}`);
|
|
3631
703
|
} else {
|
|
@@ -3641,22 +713,22 @@ class Logger22 {
|
|
|
3641
713
|
}
|
|
3642
714
|
if (cancelled)
|
|
3643
715
|
throw new Error("Operation cancelled: Logger was destroyed");
|
|
3644
|
-
const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted :
|
|
716
|
+
const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer.from(data);
|
|
3645
717
|
try {
|
|
3646
|
-
if (!
|
|
3647
|
-
await
|
|
718
|
+
if (!existsSync22(this.currentLogFile)) {
|
|
719
|
+
await writeFile(this.currentLogFile, "", { mode: 420 });
|
|
3648
720
|
}
|
|
3649
|
-
fd =
|
|
3650
|
-
|
|
3651
|
-
|
|
721
|
+
fd = openSync(this.currentLogFile, "a", 420);
|
|
722
|
+
writeFileSync22(fd, dataToWrite, { flag: "a" });
|
|
723
|
+
fsyncSync(fd);
|
|
3652
724
|
if (fd !== undefined) {
|
|
3653
|
-
|
|
725
|
+
closeSync(fd);
|
|
3654
726
|
fd = undefined;
|
|
3655
727
|
}
|
|
3656
|
-
const stats = await
|
|
728
|
+
const stats = await stat(this.currentLogFile);
|
|
3657
729
|
if (stats.size === 0) {
|
|
3658
|
-
await
|
|
3659
|
-
const retryStats = await
|
|
730
|
+
await writeFile(this.currentLogFile, dataToWrite, { flag: "w", mode: 420 });
|
|
731
|
+
const retryStats = await stat(this.currentLogFile);
|
|
3660
732
|
if (retryStats.size === 0) {
|
|
3661
733
|
throw new Error("File exists but is empty after retry write");
|
|
3662
734
|
}
|
|
@@ -3669,7 +741,7 @@ class Logger22 {
|
|
|
3669
741
|
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
3670
742
|
console.error(`Network error during write attempt ${retries + 1}/${maxRetries}:`, errorMessage);
|
|
3671
743
|
const delay = backoffDelay * 2 ** retries;
|
|
3672
|
-
await new Promise((
|
|
744
|
+
await new Promise((resolve32) => setTimeout(resolve32, delay));
|
|
3673
745
|
retries++;
|
|
3674
746
|
continue;
|
|
3675
747
|
}
|
|
@@ -3682,7 +754,7 @@ class Logger22 {
|
|
|
3682
754
|
} finally {
|
|
3683
755
|
if (fd !== undefined) {
|
|
3684
756
|
try {
|
|
3685
|
-
|
|
757
|
+
closeSync(fd);
|
|
3686
758
|
} catch (err) {
|
|
3687
759
|
console.error("Debug: [writeToFile] Error closing file descriptor:", err);
|
|
3688
760
|
}
|
|
@@ -3697,7 +769,7 @@ class Logger22 {
|
|
|
3697
769
|
}
|
|
3698
770
|
retries++;
|
|
3699
771
|
const delay = backoffDelay * 2 ** (retries - 1);
|
|
3700
|
-
await new Promise((
|
|
772
|
+
await new Promise((resolve32) => setTimeout(resolve32, delay));
|
|
3701
773
|
}
|
|
3702
774
|
}
|
|
3703
775
|
})();
|
|
@@ -3714,22 +786,22 @@ class Logger22 {
|
|
|
3714
786
|
}
|
|
3715
787
|
generateLogFilename() {
|
|
3716
788
|
if (this.name.includes("stream-throughput") || this.name.includes("decompress-perf-test") || this.name.includes("decompression-latency") || this.name.includes("concurrent-read-test") || this.name.includes("clock-change-test")) {
|
|
3717
|
-
return
|
|
789
|
+
return join2(this.config.logDirectory, `${this.name}.log`);
|
|
3718
790
|
}
|
|
3719
791
|
if (this.name.includes("pending-test") || this.name.includes("temp-file-test") || this.name === "crash-test" || this.name === "corrupt-test" || this.name.includes("rotation-load-test") || this.name === "sigterm-test" || this.name === "sigint-test" || this.name === "failed-rotation-test" || this.name === "integration-test") {
|
|
3720
|
-
return
|
|
792
|
+
return join2(this.config.logDirectory, `${this.name}.log`);
|
|
3721
793
|
}
|
|
3722
794
|
const date = new Date().toISOString().split("T")[0];
|
|
3723
|
-
return
|
|
795
|
+
return join2(this.config.logDirectory, `${this.name}-${date}.log`);
|
|
3724
796
|
}
|
|
3725
797
|
setupRotation() {
|
|
3726
|
-
if (
|
|
798
|
+
if (isBrowserProcess())
|
|
3727
799
|
return;
|
|
3728
800
|
if (typeof this.config.rotation === "boolean")
|
|
3729
801
|
return;
|
|
3730
|
-
const
|
|
802
|
+
const config22 = this.config.rotation;
|
|
3731
803
|
let interval;
|
|
3732
|
-
switch (
|
|
804
|
+
switch (config22.frequency) {
|
|
3733
805
|
case "daily":
|
|
3734
806
|
interval = 86400000;
|
|
3735
807
|
break;
|
|
@@ -3790,10 +862,10 @@ class Logger22 {
|
|
|
3790
862
|
}
|
|
3791
863
|
}
|
|
3792
864
|
generateKeyId() {
|
|
3793
|
-
return
|
|
865
|
+
return randomBytes(16).toString("hex");
|
|
3794
866
|
}
|
|
3795
867
|
generateKey() {
|
|
3796
|
-
return
|
|
868
|
+
return randomBytes(32);
|
|
3797
869
|
}
|
|
3798
870
|
getCurrentKey() {
|
|
3799
871
|
if (!this.currentKeyId) {
|
|
@@ -3807,24 +879,24 @@ class Logger22 {
|
|
|
3807
879
|
}
|
|
3808
880
|
encrypt(data) {
|
|
3809
881
|
const { key } = this.getCurrentKey();
|
|
3810
|
-
const iv =
|
|
3811
|
-
const cipher =
|
|
3812
|
-
const encrypted =
|
|
882
|
+
const iv = randomBytes(16);
|
|
883
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
884
|
+
const encrypted = Buffer.concat([
|
|
3813
885
|
cipher.update(data, "utf8"),
|
|
3814
886
|
cipher.final()
|
|
3815
887
|
]);
|
|
3816
888
|
const authTag = cipher.getAuthTag();
|
|
3817
889
|
return {
|
|
3818
|
-
encrypted:
|
|
890
|
+
encrypted: Buffer.concat([iv, encrypted, authTag]),
|
|
3819
891
|
iv
|
|
3820
892
|
};
|
|
3821
893
|
}
|
|
3822
894
|
async compressData(data) {
|
|
3823
|
-
return new Promise((
|
|
3824
|
-
const gzip =
|
|
895
|
+
return new Promise((resolve32, reject) => {
|
|
896
|
+
const gzip = createGzip();
|
|
3825
897
|
const chunks = [];
|
|
3826
898
|
gzip.on("data", (chunk2) => chunks.push(chunk2));
|
|
3827
|
-
gzip.on("end", () =>
|
|
899
|
+
gzip.on("end", () => resolve32(Buffer.from(Buffer.concat(chunks))));
|
|
3828
900
|
gzip.on("error", reject);
|
|
3829
901
|
gzip.write(data);
|
|
3830
902
|
gzip.end();
|
|
@@ -3848,19 +920,19 @@ class Logger22 {
|
|
|
3848
920
|
return defaultOptions;
|
|
3849
921
|
}
|
|
3850
922
|
async rotateLog() {
|
|
3851
|
-
if (
|
|
923
|
+
if (isBrowserProcess())
|
|
3852
924
|
return;
|
|
3853
|
-
const stats = await
|
|
925
|
+
const stats = await stat(this.currentLogFile).catch(() => null);
|
|
3854
926
|
if (!stats)
|
|
3855
927
|
return;
|
|
3856
|
-
const
|
|
3857
|
-
if (typeof
|
|
928
|
+
const config22 = this.config.rotation;
|
|
929
|
+
if (typeof config22 === "boolean")
|
|
3858
930
|
return;
|
|
3859
|
-
if (
|
|
931
|
+
if (config22.maxSize && stats.size >= config22.maxSize) {
|
|
3860
932
|
const oldFile = this.currentLogFile;
|
|
3861
933
|
const newFile = this.generateLogFilename();
|
|
3862
934
|
if (this.name.includes("rotation-load-test") || this.name === "failed-rotation-test") {
|
|
3863
|
-
const files = await
|
|
935
|
+
const files = await readdir(this.config.logDirectory);
|
|
3864
936
|
const rotatedFiles = files.filter((f) => f.startsWith(this.name) && /\.log\.\d+$/.test(f)).sort((a, b) => {
|
|
3865
937
|
const numA = Number.parseInt(a.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
3866
938
|
const numB = Number.parseInt(b.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
@@ -3868,14 +940,14 @@ class Logger22 {
|
|
|
3868
940
|
});
|
|
3869
941
|
const nextNum = rotatedFiles.length > 0 ? Number.parseInt(rotatedFiles[0].match(/\.log\.(\d+)$/)?.[1] || "0") + 1 : 1;
|
|
3870
942
|
const rotatedFile = `${oldFile}.${nextNum}`;
|
|
3871
|
-
if (await
|
|
943
|
+
if (await stat(oldFile).catch(() => null)) {
|
|
3872
944
|
try {
|
|
3873
|
-
await
|
|
3874
|
-
if (
|
|
945
|
+
await rename(oldFile, rotatedFile);
|
|
946
|
+
if (config22.compress) {
|
|
3875
947
|
try {
|
|
3876
948
|
const compressedPath = `${rotatedFile}.gz`;
|
|
3877
949
|
await this.compressLogFile(rotatedFile, compressedPath);
|
|
3878
|
-
await
|
|
950
|
+
await unlink(rotatedFile);
|
|
3879
951
|
} catch (err) {
|
|
3880
952
|
console.error("Error compressing rotated file:", err);
|
|
3881
953
|
}
|
|
@@ -3883,7 +955,7 @@ class Logger22 {
|
|
|
3883
955
|
if (rotatedFiles.length === 0 && !files.some((f) => f.endsWith(".log.1"))) {
|
|
3884
956
|
try {
|
|
3885
957
|
const backupPath = `${oldFile}.1`;
|
|
3886
|
-
await
|
|
958
|
+
await writeFile(backupPath, "");
|
|
3887
959
|
} catch (err) {
|
|
3888
960
|
console.error("Error creating backup file:", err);
|
|
3889
961
|
}
|
|
@@ -3895,25 +967,25 @@ class Logger22 {
|
|
|
3895
967
|
} else {
|
|
3896
968
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
3897
969
|
const rotatedFile = oldFile.replace(/\.log$/, `-${timestamp}.log`);
|
|
3898
|
-
if (await
|
|
3899
|
-
await
|
|
970
|
+
if (await stat(oldFile).catch(() => null)) {
|
|
971
|
+
await rename(oldFile, rotatedFile);
|
|
3900
972
|
}
|
|
3901
973
|
}
|
|
3902
974
|
this.currentLogFile = newFile;
|
|
3903
|
-
if (
|
|
3904
|
-
const files = await
|
|
975
|
+
if (config22.maxFiles) {
|
|
976
|
+
const files = await readdir(this.config.logDirectory);
|
|
3905
977
|
const logFiles = files.filter((f) => f.startsWith(this.name)).sort((a, b) => b.localeCompare(a));
|
|
3906
|
-
for (const file of logFiles.slice(
|
|
3907
|
-
await
|
|
978
|
+
for (const file of logFiles.slice(config22.maxFiles)) {
|
|
979
|
+
await unlink(join2(this.config.logDirectory, file));
|
|
3908
980
|
}
|
|
3909
981
|
}
|
|
3910
982
|
}
|
|
3911
983
|
}
|
|
3912
984
|
async compressLogFile(inputPath, outputPath) {
|
|
3913
|
-
const readStream =
|
|
3914
|
-
const writeStream =
|
|
3915
|
-
const gzip =
|
|
3916
|
-
await
|
|
985
|
+
const readStream = createReadStream(inputPath);
|
|
986
|
+
const writeStream = createWriteStream(outputPath);
|
|
987
|
+
const gzip = createGzip();
|
|
988
|
+
await pipeline(readStream, gzip, writeStream);
|
|
3917
989
|
}
|
|
3918
990
|
async handleFingersCrossedBuffer(level, formattedEntry) {
|
|
3919
991
|
if (!this.fingersCrossedConfig)
|
|
@@ -3979,11 +1051,11 @@ class Logger22 {
|
|
|
3979
1051
|
}
|
|
3980
1052
|
return Promise.resolve();
|
|
3981
1053
|
}));
|
|
3982
|
-
if (
|
|
1054
|
+
if (existsSync22(this.currentLogFile)) {
|
|
3983
1055
|
try {
|
|
3984
|
-
const fd =
|
|
3985
|
-
|
|
3986
|
-
|
|
1056
|
+
const fd = openSync(this.currentLogFile, "r+");
|
|
1057
|
+
fsyncSync(fd);
|
|
1058
|
+
closeSync(fd);
|
|
3987
1059
|
} catch (error) {
|
|
3988
1060
|
console.error(`Error flushing file: ${error}`);
|
|
3989
1061
|
}
|
|
@@ -4008,13 +1080,13 @@ class Logger22 {
|
|
|
4008
1080
|
console.error("Error waiting for pending operations:", err);
|
|
4009
1081
|
}
|
|
4010
1082
|
}
|
|
4011
|
-
if (!
|
|
1083
|
+
if (!isBrowserProcess() && this.config.rotation && typeof this.config.rotation !== "boolean" && this.config.rotation.compress) {
|
|
4012
1084
|
try {
|
|
4013
|
-
const files = await
|
|
1085
|
+
const files = await readdir(this.config.logDirectory);
|
|
4014
1086
|
const tempFiles = files.filter((f) => (f.includes("temp") || f.includes(".tmp")) && f.includes(this.name));
|
|
4015
1087
|
for (const tempFile of tempFiles) {
|
|
4016
1088
|
try {
|
|
4017
|
-
await
|
|
1089
|
+
await unlink(join2(this.config.logDirectory, tempFile));
|
|
4018
1090
|
} catch (err) {
|
|
4019
1091
|
console.error(`Failed to delete temp file ${tempFile}:`, err);
|
|
4020
1092
|
}
|
|
@@ -4037,7 +1109,7 @@ class Logger22 {
|
|
|
4037
1109
|
return `[${date.toISOString()}]`;
|
|
4038
1110
|
}
|
|
4039
1111
|
formatConsoleTimestamp(date) {
|
|
4040
|
-
return this.fancy ?
|
|
1112
|
+
return this.fancy ? styles.gray(date.toLocaleTimeString()) : date.toLocaleTimeString();
|
|
4041
1113
|
}
|
|
4042
1114
|
formatConsoleMessage(parts) {
|
|
4043
1115
|
const { timestamp, icon = "", tag = "", message, level, showTimestamp = true } = parts;
|
|
@@ -4057,14 +1129,14 @@ class Logger22 {
|
|
|
4057
1129
|
components.push(message);
|
|
4058
1130
|
return components.join(" ");
|
|
4059
1131
|
}
|
|
4060
|
-
const terminalWidth =
|
|
1132
|
+
const terminalWidth = process5.stdout.columns || 120;
|
|
4061
1133
|
let mainPart = "";
|
|
4062
1134
|
if (level === "warning" || level === "error") {
|
|
4063
1135
|
mainPart = `${icon} ${message}`;
|
|
4064
1136
|
} else if (level === "info" || level === "success") {
|
|
4065
1137
|
mainPart = `${icon} ${tag} ${message}`;
|
|
4066
1138
|
} else {
|
|
4067
|
-
mainPart = `${icon} ${tag} ${
|
|
1139
|
+
mainPart = `${icon} ${tag} ${styles.cyan(message)}`;
|
|
4068
1140
|
}
|
|
4069
1141
|
if (!showTimestamp) {
|
|
4070
1142
|
return mainPart.trim();
|
|
@@ -4119,9 +1191,9 @@ class Logger22 {
|
|
|
4119
1191
|
} else {
|
|
4120
1192
|
formattedMessage = this.formatMessage(message, args);
|
|
4121
1193
|
}
|
|
4122
|
-
if (this.fancy && !
|
|
4123
|
-
const icon =
|
|
4124
|
-
const tag = this.options.showTags !== false && this.name ?
|
|
1194
|
+
if (this.fancy && !isBrowserProcess()) {
|
|
1195
|
+
const icon = levelIcons[level];
|
|
1196
|
+
const tag = this.options.showTags !== false && this.name ? styles.gray(this.formatTag(this.name)) : "";
|
|
4125
1197
|
let consoleMessage;
|
|
4126
1198
|
switch (level) {
|
|
4127
1199
|
case "debug":
|
|
@@ -4129,7 +1201,7 @@ class Logger22 {
|
|
|
4129
1201
|
timestamp: consoleTime,
|
|
4130
1202
|
icon,
|
|
4131
1203
|
tag,
|
|
4132
|
-
message:
|
|
1204
|
+
message: styles.gray(formattedMessage),
|
|
4133
1205
|
level
|
|
4134
1206
|
});
|
|
4135
1207
|
console.error(consoleMessage);
|
|
@@ -4149,7 +1221,7 @@ class Logger22 {
|
|
|
4149
1221
|
timestamp: consoleTime,
|
|
4150
1222
|
icon,
|
|
4151
1223
|
tag,
|
|
4152
|
-
message:
|
|
1224
|
+
message: styles.green(formattedMessage),
|
|
4153
1225
|
level
|
|
4154
1226
|
});
|
|
4155
1227
|
console.error(consoleMessage);
|
|
@@ -4180,7 +1252,7 @@ class Logger22 {
|
|
|
4180
1252
|
if (line.trim() && !line.includes(formattedMessage)) {
|
|
4181
1253
|
console.error(this.formatConsoleMessage({
|
|
4182
1254
|
timestamp: consoleTime,
|
|
4183
|
-
message:
|
|
1255
|
+
message: styles.gray(` ${line}`),
|
|
4184
1256
|
level,
|
|
4185
1257
|
showTimestamp: false
|
|
4186
1258
|
}));
|
|
@@ -4189,7 +1261,7 @@ class Logger22 {
|
|
|
4189
1261
|
}
|
|
4190
1262
|
break;
|
|
4191
1263
|
}
|
|
4192
|
-
} else if (!
|
|
1264
|
+
} else if (!isBrowserProcess()) {
|
|
4193
1265
|
console.error(`${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}`);
|
|
4194
1266
|
if (errorStack) {
|
|
4195
1267
|
console.error(errorStack);
|
|
@@ -4208,14 +1280,14 @@ class Logger22 {
|
|
|
4208
1280
|
}
|
|
4209
1281
|
time(label) {
|
|
4210
1282
|
const start = performance.now();
|
|
4211
|
-
if (this.fancy && !
|
|
4212
|
-
const tag = this.options.showTags !== false && this.name ?
|
|
1283
|
+
if (this.fancy && !isBrowserProcess()) {
|
|
1284
|
+
const tag = this.options.showTags !== false && this.name ? styles.gray(this.formatTag(this.name)) : "";
|
|
4213
1285
|
const consoleTime = this.formatConsoleTimestamp(new Date);
|
|
4214
1286
|
console.error(this.formatConsoleMessage({
|
|
4215
1287
|
timestamp: consoleTime,
|
|
4216
|
-
icon:
|
|
1288
|
+
icon: styles.blue("◐"),
|
|
4217
1289
|
tag,
|
|
4218
|
-
message: `${
|
|
1290
|
+
message: `${styles.cyan(label)}...`
|
|
4219
1291
|
}));
|
|
4220
1292
|
}
|
|
4221
1293
|
return async (metadata) => {
|
|
@@ -4234,15 +1306,15 @@ class Logger22 {
|
|
|
4234
1306
|
logEntry += `
|
|
4235
1307
|
`;
|
|
4236
1308
|
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
4237
|
-
if (this.fancy && !
|
|
4238
|
-
const tag = this.options.showTags !== false && this.name ?
|
|
1309
|
+
if (this.fancy && !isBrowserProcess()) {
|
|
1310
|
+
const tag = this.options.showTags !== false && this.name ? styles.gray(this.formatTag(this.name)) : "";
|
|
4239
1311
|
console.error(this.formatConsoleMessage({
|
|
4240
1312
|
timestamp: consoleTime,
|
|
4241
|
-
icon:
|
|
1313
|
+
icon: styles.green("✓"),
|
|
4242
1314
|
tag,
|
|
4243
1315
|
message: `${completionMessage}${metadata ? ` ${JSON.stringify(metadata)}` : ""}`
|
|
4244
1316
|
}));
|
|
4245
|
-
} else if (!
|
|
1317
|
+
} else if (!isBrowserProcess()) {
|
|
4246
1318
|
console.error(logEntry.trim());
|
|
4247
1319
|
}
|
|
4248
1320
|
await this.writeToFile(logEntry);
|
|
@@ -4285,7 +1357,7 @@ class Logger22 {
|
|
|
4285
1357
|
}
|
|
4286
1358
|
extend(namespace) {
|
|
4287
1359
|
const childName = `${this.name}:${namespace}`;
|
|
4288
|
-
const childLogger = new
|
|
1360
|
+
const childLogger = new Logger(childName, {
|
|
4289
1361
|
...this.options,
|
|
4290
1362
|
logDirectory: this.config.logDirectory,
|
|
4291
1363
|
level: this.config.level,
|
|
@@ -4297,11 +1369,11 @@ class Logger22 {
|
|
|
4297
1369
|
return childLogger;
|
|
4298
1370
|
}
|
|
4299
1371
|
createReadStream() {
|
|
4300
|
-
if (
|
|
1372
|
+
if (isBrowserProcess())
|
|
4301
1373
|
throw new Error("createReadStream is not supported in browser environments");
|
|
4302
|
-
if (!
|
|
1374
|
+
if (!existsSync22(this.currentLogFile))
|
|
4303
1375
|
throw new Error(`Log file does not exist: ${this.currentLogFile}`);
|
|
4304
|
-
return
|
|
1376
|
+
return createReadStream(this.currentLogFile, { encoding: "utf8" });
|
|
4305
1377
|
}
|
|
4306
1378
|
async decrypt(data) {
|
|
4307
1379
|
if (!this.validateEncryptionConfig())
|
|
@@ -4313,13 +1385,13 @@ class Logger22 {
|
|
|
4313
1385
|
throw new Error("No valid encryption key available");
|
|
4314
1386
|
const key = this.keys.get(this.currentKeyId);
|
|
4315
1387
|
try {
|
|
4316
|
-
const encryptedData =
|
|
1388
|
+
const encryptedData = Buffer.isBuffer(data) ? data : Buffer.from(data, "base64");
|
|
4317
1389
|
const iv = encryptedData.slice(0, 16);
|
|
4318
1390
|
const authTag = encryptedData.slice(-16);
|
|
4319
1391
|
const ciphertext = encryptedData.slice(16, -16);
|
|
4320
|
-
const decipher =
|
|
1392
|
+
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
4321
1393
|
decipher.setAuthTag(authTag);
|
|
4322
|
-
const decrypted =
|
|
1394
|
+
const decrypted = Buffer.concat([
|
|
4323
1395
|
decipher.update(ciphertext),
|
|
4324
1396
|
decipher.final()
|
|
4325
1397
|
]);
|
|
@@ -4341,10 +1413,10 @@ class Logger22 {
|
|
|
4341
1413
|
return this.config.rotation;
|
|
4342
1414
|
}
|
|
4343
1415
|
isBrowserMode() {
|
|
4344
|
-
return
|
|
1416
|
+
return isBrowserProcess();
|
|
4345
1417
|
}
|
|
4346
1418
|
isServerMode() {
|
|
4347
|
-
return !
|
|
1419
|
+
return !isBrowserProcess();
|
|
4348
1420
|
}
|
|
4349
1421
|
setTestEncryptionKey(keyId, key) {
|
|
4350
1422
|
this.currentKeyId = keyId;
|
|
@@ -4368,7 +1440,7 @@ class Logger22 {
|
|
|
4368
1440
|
const timestamp = new Date;
|
|
4369
1441
|
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
4370
1442
|
const fileTime = this.formatFileTimestamp(timestamp);
|
|
4371
|
-
if (this.fancy && !
|
|
1443
|
+
if (this.fancy && !isBrowserProcess()) {
|
|
4372
1444
|
const lines = message.split(`
|
|
4373
1445
|
`);
|
|
4374
1446
|
const width = Math.max(...lines.map((line) => line.length)) + 2;
|
|
@@ -4381,25 +1453,25 @@ class Logger22 {
|
|
|
4381
1453
|
if (this.options.showTags !== false && this.name) {
|
|
4382
1454
|
console.error(this.formatConsoleMessage({
|
|
4383
1455
|
timestamp: consoleTime,
|
|
4384
|
-
message:
|
|
1456
|
+
message: styles.gray(this.formatTag(this.name)),
|
|
4385
1457
|
showTimestamp: false
|
|
4386
1458
|
}));
|
|
4387
1459
|
}
|
|
4388
1460
|
console.error(this.formatConsoleMessage({
|
|
4389
1461
|
timestamp: consoleTime,
|
|
4390
|
-
message:
|
|
1462
|
+
message: styles.cyan(top)
|
|
4391
1463
|
}));
|
|
4392
1464
|
boxedLines.forEach((line) => console.error(this.formatConsoleMessage({
|
|
4393
1465
|
timestamp: consoleTime,
|
|
4394
|
-
message:
|
|
1466
|
+
message: styles.cyan(line),
|
|
4395
1467
|
showTimestamp: false
|
|
4396
1468
|
})));
|
|
4397
1469
|
console.error(this.formatConsoleMessage({
|
|
4398
1470
|
timestamp: consoleTime,
|
|
4399
|
-
message:
|
|
1471
|
+
message: styles.cyan(bottom),
|
|
4400
1472
|
showTimestamp: false
|
|
4401
1473
|
}));
|
|
4402
|
-
} else if (!
|
|
1474
|
+
} else if (!isBrowserProcess()) {
|
|
4403
1475
|
console.error(`${fileTime} ${this.environment}.INFO: [BOX] ${message}`);
|
|
4404
1476
|
}
|
|
4405
1477
|
const logEntry = `${fileTime} ${this.environment}.INFO: [BOX] ${message}
|
|
@@ -4407,30 +1479,30 @@ class Logger22 {
|
|
|
4407
1479
|
await this.writeToFile(logEntry);
|
|
4408
1480
|
}
|
|
4409
1481
|
async prompt(message) {
|
|
4410
|
-
if (
|
|
1482
|
+
if (isBrowserProcess()) {
|
|
4411
1483
|
return Promise.resolve(true);
|
|
4412
1484
|
}
|
|
4413
|
-
return new Promise((
|
|
4414
|
-
console.error(`${
|
|
1485
|
+
return new Promise((resolve32) => {
|
|
1486
|
+
console.error(`${styles.cyan("?")} ${message} (y/n) `);
|
|
4415
1487
|
const onData = (data) => {
|
|
4416
1488
|
const input = data.toString().trim().toLowerCase();
|
|
4417
|
-
|
|
1489
|
+
process5.stdin.removeListener("data", onData);
|
|
4418
1490
|
try {
|
|
4419
|
-
if (typeof
|
|
4420
|
-
|
|
1491
|
+
if (typeof process5.stdin.setRawMode === "function") {
|
|
1492
|
+
process5.stdin.setRawMode(false);
|
|
4421
1493
|
}
|
|
4422
1494
|
} catch {}
|
|
4423
|
-
|
|
1495
|
+
process5.stdin.pause();
|
|
4424
1496
|
console.error("");
|
|
4425
|
-
|
|
1497
|
+
resolve32(input === "y" || input === "yes");
|
|
4426
1498
|
};
|
|
4427
1499
|
try {
|
|
4428
|
-
if (typeof
|
|
4429
|
-
|
|
1500
|
+
if (typeof process5.stdin.setRawMode === "function") {
|
|
1501
|
+
process5.stdin.setRawMode(true);
|
|
4430
1502
|
}
|
|
4431
1503
|
} catch {}
|
|
4432
|
-
|
|
4433
|
-
|
|
1504
|
+
process5.stdin.resume();
|
|
1505
|
+
process5.stdin.once("data", onData);
|
|
4434
1506
|
});
|
|
4435
1507
|
}
|
|
4436
1508
|
setFancy(enabled) {
|
|
@@ -4475,10 +1547,10 @@ class Logger22 {
|
|
|
4475
1547
|
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
4476
1548
|
}
|
|
4477
1549
|
}
|
|
4478
|
-
if (this.fancy && !
|
|
4479
|
-
const tag = this.options.showTags !== false && this.name ?
|
|
4480
|
-
const spinnerChar =
|
|
4481
|
-
console.error(`${spinnerChar} ${tag} ${
|
|
1550
|
+
if (this.fancy && !isBrowserProcess()) {
|
|
1551
|
+
const tag = this.options.showTags !== false && this.name ? styles.gray(this.formatTag(this.name)) : "";
|
|
1552
|
+
const spinnerChar = styles.blue("◐");
|
|
1553
|
+
console.error(`${spinnerChar} ${tag} ${styles.cyan(formattedMessage)}`);
|
|
4482
1554
|
}
|
|
4483
1555
|
const timestamp = new Date;
|
|
4484
1556
|
const formattedDate = timestamp.toISOString();
|
|
@@ -4487,7 +1559,7 @@ class Logger22 {
|
|
|
4487
1559
|
await this.writeToFile(logEntry);
|
|
4488
1560
|
}
|
|
4489
1561
|
progress(total, initialMessage = "") {
|
|
4490
|
-
if (!this.enabled || !this.fancy ||
|
|
1562
|
+
if (!this.enabled || !this.fancy || isBrowserProcess() || total <= 0) {
|
|
4491
1563
|
return {
|
|
4492
1564
|
update: () => {},
|
|
4493
1565
|
finish: () => {},
|
|
@@ -4508,7 +1580,7 @@ class Logger22 {
|
|
|
4508
1580
|
};
|
|
4509
1581
|
this.renderProgressBar(this.activeProgressBar);
|
|
4510
1582
|
const update = (current, message) => {
|
|
4511
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy ||
|
|
1583
|
+
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess())
|
|
4512
1584
|
return;
|
|
4513
1585
|
this.activeProgressBar.current = Math.max(0, Math.min(total, current));
|
|
4514
1586
|
if (message !== undefined) {
|
|
@@ -4518,7 +1590,7 @@ class Logger22 {
|
|
|
4518
1590
|
this.renderProgressBar(this.activeProgressBar, isFinished);
|
|
4519
1591
|
};
|
|
4520
1592
|
const finish = (message) => {
|
|
4521
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy ||
|
|
1593
|
+
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess())
|
|
4522
1594
|
return;
|
|
4523
1595
|
this.activeProgressBar.current = this.activeProgressBar.total;
|
|
4524
1596
|
if (message !== undefined) {
|
|
@@ -4528,9 +1600,9 @@ class Logger22 {
|
|
|
4528
1600
|
this.finishProgressBar(this.activeProgressBar);
|
|
4529
1601
|
};
|
|
4530
1602
|
const interrupt = (interruptMessage, level = "info") => {
|
|
4531
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy ||
|
|
1603
|
+
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess())
|
|
4532
1604
|
return;
|
|
4533
|
-
|
|
1605
|
+
process5.stdout.write(`${"\r".padEnd(process5.stdout.columns || 80)}\r`);
|
|
4534
1606
|
this.log(level, interruptMessage);
|
|
4535
1607
|
setTimeout(() => {
|
|
4536
1608
|
if (this.activeProgressBar) {
|
|
@@ -4541,30 +1613,30 @@ class Logger22 {
|
|
|
4541
1613
|
return { update, finish, interrupt };
|
|
4542
1614
|
}
|
|
4543
1615
|
renderProgressBar(barState, isFinished = false) {
|
|
4544
|
-
if (!this.enabled || !this.fancy ||
|
|
1616
|
+
if (!this.enabled || !this.fancy || isBrowserProcess() || !process5.stdout.isTTY)
|
|
4545
1617
|
return;
|
|
4546
1618
|
const percent = Math.min(100, Math.max(0, Math.round(barState.current / barState.total * 100)));
|
|
4547
1619
|
const filledLength = Math.round(barState.barLength * percent / 100);
|
|
4548
1620
|
const emptyLength = barState.barLength - filledLength;
|
|
4549
|
-
const filledBar =
|
|
4550
|
-
const emptyBar =
|
|
1621
|
+
const filledBar = styles.green("━".repeat(filledLength));
|
|
1622
|
+
const emptyBar = styles.gray("━".repeat(emptyLength));
|
|
4551
1623
|
const bar = `[${filledBar}${emptyBar}]`;
|
|
4552
1624
|
const percentageText = `${percent}%`.padStart(4);
|
|
4553
1625
|
const messageText = barState.message ? ` ${barState.message}` : "";
|
|
4554
|
-
const icon = isFinished || percent === 100 ?
|
|
4555
|
-
const tag = this.options.showTags !== false && this.name ? ` ${
|
|
1626
|
+
const icon = isFinished || percent === 100 ? styles.green("✓") : styles.blue("▶");
|
|
1627
|
+
const tag = this.options.showTags !== false && this.name ? ` ${styles.gray(this.formatTag(this.name))}` : "";
|
|
4556
1628
|
const line = `\r${icon}${tag} ${bar} ${percentageText}${messageText}`;
|
|
4557
|
-
const terminalWidth =
|
|
1629
|
+
const terminalWidth = process5.stdout.columns || 80;
|
|
4558
1630
|
const clearLine = " ".repeat(Math.max(0, terminalWidth - line.replace(this.ANSI_PATTERN, "").length));
|
|
4559
1631
|
barState.lastRenderedLine = `${line}${clearLine}`;
|
|
4560
|
-
|
|
1632
|
+
process5.stdout.write(barState.lastRenderedLine);
|
|
4561
1633
|
if (isFinished) {
|
|
4562
|
-
|
|
1634
|
+
process5.stdout.write(`
|
|
4563
1635
|
`);
|
|
4564
1636
|
}
|
|
4565
1637
|
}
|
|
4566
1638
|
finishProgressBar(barState, finalMessage) {
|
|
4567
|
-
if (!this.enabled || !this.fancy ||
|
|
1639
|
+
if (!this.enabled || !this.fancy || isBrowserProcess() || !process5.stdout.isTTY) {
|
|
4568
1640
|
this.activeProgressBar = null;
|
|
4569
1641
|
return;
|
|
4570
1642
|
}
|
|
@@ -4577,23 +1649,23 @@ class Logger22 {
|
|
|
4577
1649
|
this.activeProgressBar = null;
|
|
4578
1650
|
}
|
|
4579
1651
|
async clear(filters = {}) {
|
|
4580
|
-
if (
|
|
1652
|
+
if (isBrowserProcess()) {
|
|
4581
1653
|
console.warn("Log clearing is not supported in browser environments.");
|
|
4582
1654
|
return;
|
|
4583
1655
|
}
|
|
4584
1656
|
try {
|
|
4585
1657
|
console.warn("Clearing logs...", this.config.logDirectory);
|
|
4586
|
-
const files = await
|
|
1658
|
+
const files = await readdir(this.config.logDirectory);
|
|
4587
1659
|
const logFilesToDelete = [];
|
|
4588
1660
|
for (const file of files) {
|
|
4589
1661
|
const nameMatches = filters.name ? new RegExp(filters.name.replace("*", ".*")).test(file) : file.startsWith(this.name);
|
|
4590
1662
|
if (!nameMatches || !file.endsWith(".log")) {
|
|
4591
1663
|
continue;
|
|
4592
1664
|
}
|
|
4593
|
-
const filePath =
|
|
1665
|
+
const filePath = join2(this.config.logDirectory, file);
|
|
4594
1666
|
if (filters.before) {
|
|
4595
1667
|
try {
|
|
4596
|
-
const fileStats = await
|
|
1668
|
+
const fileStats = await stat(filePath);
|
|
4597
1669
|
if (fileStats.mtime >= filters.before) {
|
|
4598
1670
|
continue;
|
|
4599
1671
|
}
|
|
@@ -4611,7 +1683,7 @@ class Logger22 {
|
|
|
4611
1683
|
console.warn(`Preparing to delete ${logFilesToDelete.length} log file(s)...`);
|
|
4612
1684
|
for (const filePath of logFilesToDelete) {
|
|
4613
1685
|
try {
|
|
4614
|
-
await
|
|
1686
|
+
await unlink(filePath);
|
|
4615
1687
|
console.warn(`Deleted log file: ${filePath}`);
|
|
4616
1688
|
} catch (unlinkErr) {
|
|
4617
1689
|
console.error(`Failed to delete log file ${filePath}:`, unlinkErr);
|
|
@@ -4623,11 +1695,11 @@ class Logger22 {
|
|
|
4623
1695
|
}
|
|
4624
1696
|
}
|
|
4625
1697
|
}
|
|
4626
|
-
var
|
|
1698
|
+
var logger = new Logger("stacks");
|
|
4627
1699
|
|
|
4628
1700
|
// src/git-hooks.ts
|
|
4629
1701
|
var execAsync = promisify(exec);
|
|
4630
|
-
var
|
|
1702
|
+
var log = new Logger("git-hooks", {
|
|
4631
1703
|
showTags: true
|
|
4632
1704
|
});
|
|
4633
1705
|
var VALID_GIT_HOOKS = [
|
|
@@ -4673,7 +1745,7 @@ if [ -f "$BUN_GIT_HOOKS_RC" ]; then
|
|
|
4673
1745
|
fi
|
|
4674
1746
|
|
|
4675
1747
|
`;
|
|
4676
|
-
function getGitProjectRoot(directory =
|
|
1748
|
+
function getGitProjectRoot(directory = process6.cwd()) {
|
|
4677
1749
|
if (directory.endsWith(".git")) {
|
|
4678
1750
|
return path.normalize(directory);
|
|
4679
1751
|
}
|
|
@@ -4735,7 +1807,7 @@ function checkBunGitHooksInDependencies(projectRootPath) {
|
|
|
4735
1807
|
}
|
|
4736
1808
|
return "bun-git-hooks" in packageJsonContent.devDependencies;
|
|
4737
1809
|
}
|
|
4738
|
-
function _getPackageJson(projectPath =
|
|
1810
|
+
function _getPackageJson(projectPath = process6.cwd()) {
|
|
4739
1811
|
if (typeof projectPath !== "string") {
|
|
4740
1812
|
throw new TypeError("projectPath is not a string");
|
|
4741
1813
|
}
|
|
@@ -4746,17 +1818,18 @@ function _getPackageJson(projectPath = process12.cwd()) {
|
|
|
4746
1818
|
const packageJsonDataRaw = fs.readFileSync(targetPackageJson, { encoding: "utf-8" });
|
|
4747
1819
|
return { packageJsonContent: JSON.parse(packageJsonDataRaw), packageJsonPath: targetPackageJson };
|
|
4748
1820
|
}
|
|
4749
|
-
function setHooksFromConfig(projectRootPath =
|
|
4750
|
-
if (!
|
|
4751
|
-
throw new Error("[ERROR] Config was not found! Please add `.git-hooks.config.{ts,js,mjs,cjs,
|
|
4752
|
-
const configFile = options?.configFile
|
|
1821
|
+
function setHooksFromConfig(projectRootPath = process6.cwd(), options) {
|
|
1822
|
+
if (!config2 || Object.keys(config2).length === 0)
|
|
1823
|
+
throw new Error("[ERROR] Config was not found! Please add `.git-hooks.config.{ts,js,mjs,cjs,json}` or `git-hooks.config.{ts,js,mjs,cjs,json}` or the `git-hooks` entry in package.json.\r\nCheck README for details");
|
|
1824
|
+
const configFile = options?.configFile || { ...config2 };
|
|
1825
|
+
_validateStagedLintConfig(configFile);
|
|
4753
1826
|
const hookKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key));
|
|
4754
1827
|
const isValidConfig = hookKeys.every((key) => VALID_GIT_HOOKS.includes(key));
|
|
4755
1828
|
if (!isValidConfig)
|
|
4756
1829
|
throw new Error("[ERROR] Config was not in correct format. Please check git hooks or options name");
|
|
4757
1830
|
const preserveUnused = Array.isArray(configFile.preserveUnused) ? configFile.preserveUnused : configFile.preserveUnused ? VALID_GIT_HOOKS : [];
|
|
4758
|
-
const logKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key)).sort().map((key) =>
|
|
4759
|
-
|
|
1831
|
+
const logKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key)).sort().map((key) => italic(key)).join(", ");
|
|
1832
|
+
log.debug(`Hook Keys: ${logKeys}`);
|
|
4760
1833
|
for (const hook of VALID_GIT_HOOKS) {
|
|
4761
1834
|
if (Object.prototype.hasOwnProperty.call(configFile, hook)) {
|
|
4762
1835
|
if (!configFile[hook])
|
|
@@ -4767,48 +1840,85 @@ function setHooksFromConfig(projectRootPath = process12.cwd(), options) {
|
|
|
4767
1840
|
}
|
|
4768
1841
|
}
|
|
4769
1842
|
}
|
|
4770
|
-
async function getStagedFiles(projectRoot =
|
|
1843
|
+
async function getStagedFiles(projectRoot = process6.cwd()) {
|
|
4771
1844
|
try {
|
|
4772
|
-
const { stdout } = await execAsync("git diff --
|
|
4773
|
-
|
|
1845
|
+
const { stdout } = await execAsync("git diff --cached --name-only --diff-filter=ACMR", { cwd: projectRoot });
|
|
1846
|
+
const files = stdout.trim().split(`
|
|
4774
1847
|
`).filter(Boolean);
|
|
1848
|
+
if (config2.verbose && files.length > 0) {
|
|
1849
|
+
console.info("[INFO] Staged files found:", files);
|
|
1850
|
+
}
|
|
1851
|
+
return files;
|
|
4775
1852
|
} catch (error) {
|
|
4776
1853
|
console.error("[ERROR] Failed to get staged files:", error);
|
|
4777
1854
|
return [];
|
|
4778
1855
|
}
|
|
4779
1856
|
}
|
|
1857
|
+
function expandBracePattern(pattern) {
|
|
1858
|
+
const braceMatch = pattern.match(/{([^}]+)}/g);
|
|
1859
|
+
if (!braceMatch)
|
|
1860
|
+
return [pattern];
|
|
1861
|
+
const results = [pattern];
|
|
1862
|
+
braceMatch.forEach((brace) => {
|
|
1863
|
+
const options = brace.slice(1, -1).split(",");
|
|
1864
|
+
const newResults = [];
|
|
1865
|
+
results.forEach((result) => {
|
|
1866
|
+
options.forEach((option) => {
|
|
1867
|
+
newResults.push(result.replace(brace, option.trim()));
|
|
1868
|
+
});
|
|
1869
|
+
});
|
|
1870
|
+
results.length = 0;
|
|
1871
|
+
results.push(...newResults);
|
|
1872
|
+
});
|
|
1873
|
+
return results;
|
|
1874
|
+
}
|
|
4780
1875
|
function matchesGlob(file, pattern) {
|
|
4781
|
-
if (pattern.
|
|
4782
|
-
|
|
4783
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
4784
|
-
return regex.test(file);
|
|
1876
|
+
if (pattern.startsWith("!")) {
|
|
1877
|
+
return !matchesGlob(file, pattern.slice(1));
|
|
4785
1878
|
}
|
|
4786
|
-
|
|
1879
|
+
const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "(?:.*?)").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
|
|
1880
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
1881
|
+
return regex.test(file);
|
|
4787
1882
|
}
|
|
4788
1883
|
function filterFilesByPattern(files, pattern) {
|
|
4789
|
-
|
|
1884
|
+
const expandedPatterns = expandBracePattern(pattern);
|
|
1885
|
+
const includePatterns = expandedPatterns.filter((p) => !p.startsWith("!"));
|
|
1886
|
+
const excludePatterns = expandedPatterns.filter((p) => p.startsWith("!"));
|
|
1887
|
+
return files.filter((file) => {
|
|
1888
|
+
const isIncluded = includePatterns.some((p) => matchesGlob(file, p));
|
|
1889
|
+
const isExcluded = excludePatterns.some((p) => matchesGlob(file, p.slice(1)));
|
|
1890
|
+
return isIncluded && !isExcluded;
|
|
1891
|
+
});
|
|
4790
1892
|
}
|
|
4791
|
-
async function runCommandOnStagedFiles(command, files, projectRoot =
|
|
1893
|
+
async function runCommandOnStagedFiles(command, files, projectRoot = process6.cwd(), verbose = false) {
|
|
4792
1894
|
if (files.length === 0) {
|
|
4793
1895
|
if (verbose)
|
|
4794
1896
|
console.info("[INFO] No matching files for pattern");
|
|
4795
1897
|
return true;
|
|
4796
1898
|
}
|
|
4797
1899
|
const commands = Array.isArray(command) ? command : [command];
|
|
1900
|
+
const fileList = files.join(" ");
|
|
4798
1901
|
for (const cmd of commands) {
|
|
4799
1902
|
try {
|
|
4800
|
-
const fullCommand = `${cmd} ${
|
|
4801
|
-
if (verbose)
|
|
4802
|
-
console.info(`[INFO] Running: ${fullCommand}`);
|
|
4803
|
-
const { stdout, stderr } = await execAsync(fullCommand, { cwd: projectRoot });
|
|
1903
|
+
const fullCommand = `${cmd} ${fileList}`;
|
|
4804
1904
|
if (verbose) {
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
1905
|
+
console.info("[INFO] Running command:", cmd);
|
|
1906
|
+
console.info("[INFO] On files:", files);
|
|
1907
|
+
}
|
|
1908
|
+
const { stdout, stderr } = await execAsync(fullCommand, { cwd: projectRoot });
|
|
1909
|
+
if (stdout && (verbose || stdout.includes("error") || stdout.includes("warning"))) {
|
|
1910
|
+
console.info(stdout);
|
|
1911
|
+
}
|
|
1912
|
+
if (stderr) {
|
|
1913
|
+
console.error("[ERROR] Command output:", stderr);
|
|
1914
|
+
return false;
|
|
4809
1915
|
}
|
|
4810
1916
|
} catch (error) {
|
|
4811
|
-
|
|
1917
|
+
if (error.stdout)
|
|
1918
|
+
console.info(error.stdout);
|
|
1919
|
+
if (error.stderr)
|
|
1920
|
+
console.error("[ERROR] Command stderr:", error.stderr);
|
|
1921
|
+
console.error(`[ERROR] Command failed: ${cmd}`);
|
|
4812
1922
|
return false;
|
|
4813
1923
|
}
|
|
4814
1924
|
}
|
|
@@ -4832,7 +1942,7 @@ async function processStagedLint(stagedLintConfig, projectRoot, verbose = false)
|
|
|
4832
1942
|
}
|
|
4833
1943
|
return success;
|
|
4834
1944
|
}
|
|
4835
|
-
function _setHook(hook, commandOrConfig, projectRoot =
|
|
1945
|
+
function _setHook(hook, commandOrConfig, projectRoot = process6.cwd()) {
|
|
4836
1946
|
const gitRoot = getGitProjectRoot(projectRoot);
|
|
4837
1947
|
if (!gitRoot) {
|
|
4838
1948
|
console.info("[INFO] No `.git` root folder found, skipping");
|
|
@@ -4853,26 +1963,26 @@ function _setHook(hook, commandOrConfig, projectRoot = process12.cwd()) {
|
|
|
4853
1963
|
fs.mkdirSync(hookDirectory, { recursive: true });
|
|
4854
1964
|
}
|
|
4855
1965
|
const addOrModify = fs.existsSync(hookPath) ? "Modify" : "Add";
|
|
4856
|
-
|
|
1966
|
+
log.debug(`${addOrModify} ${italic(hook)} hook`);
|
|
4857
1967
|
fs.writeFileSync(hookPath, hookCommand, { mode: 493 });
|
|
4858
1968
|
}
|
|
4859
|
-
function removeHooks(projectRoot =
|
|
1969
|
+
function removeHooks(projectRoot = process6.cwd(), verbose = false) {
|
|
4860
1970
|
for (const configEntry of VALID_GIT_HOOKS)
|
|
4861
1971
|
_removeHook(configEntry, projectRoot, verbose);
|
|
4862
1972
|
}
|
|
4863
|
-
function _removeHook(hook, projectRoot =
|
|
1973
|
+
function _removeHook(hook, projectRoot = process6.cwd(), verbose = false) {
|
|
4864
1974
|
const gitRoot = getGitProjectRoot(projectRoot);
|
|
4865
1975
|
const hookPath = path.normalize(`${gitRoot}/hooks/${hook}`);
|
|
4866
1976
|
if (fs.existsSync(hookPath)) {
|
|
4867
|
-
|
|
1977
|
+
log.debug(`Hook ${hook} is not set, removing!`);
|
|
4868
1978
|
fs.unlinkSync(hookPath);
|
|
4869
1979
|
}
|
|
4870
1980
|
if (verbose)
|
|
4871
|
-
|
|
1981
|
+
log.success(`Successfully removed the ${hook} hook`);
|
|
4872
1982
|
}
|
|
4873
1983
|
async function runStagedLint(hook) {
|
|
4874
|
-
const projectRoot =
|
|
4875
|
-
const configFile =
|
|
1984
|
+
const projectRoot = process6.cwd();
|
|
1985
|
+
const configFile = config2;
|
|
4876
1986
|
if (!configFile) {
|
|
4877
1987
|
console.error(`[ERROR] No configuration found`);
|
|
4878
1988
|
return false;
|
|
@@ -4892,13 +2002,23 @@ async function runStagedLint(hook) {
|
|
|
4892
2002
|
console.error(`[ERROR] No staged lint configuration found for hook ${hook}`);
|
|
4893
2003
|
return false;
|
|
4894
2004
|
}
|
|
2005
|
+
function _validateStagedLintConfig(config4) {
|
|
2006
|
+
for (const hook of VALID_GIT_HOOKS) {
|
|
2007
|
+
if (hook !== "pre-commit" && config4[hook] && typeof config4[hook] === "object") {
|
|
2008
|
+
const hookConfig = config4[hook];
|
|
2009
|
+
if (hookConfig["stagedLint"] || hookConfig["staged-lint"]) {
|
|
2010
|
+
throw new Error(`staged-lint is only allowed in pre-commit hook. Found in ${hook} hook.`);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
4895
2015
|
export {
|
|
4896
2016
|
setHooksFromConfig,
|
|
4897
2017
|
runStagedLint,
|
|
4898
2018
|
removeHooks,
|
|
4899
2019
|
getProjectRootDirectoryFromNodeModules,
|
|
4900
2020
|
getGitProjectRoot,
|
|
4901
|
-
|
|
2021
|
+
config2 as config,
|
|
4902
2022
|
checkBunGitHooksInDependencies,
|
|
4903
2023
|
VALID_OPTIONS,
|
|
4904
2024
|
VALID_GIT_HOOKS,
|