bun-git-hooks 0.2.15 → 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/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 process7 from "node:process";
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,25 +183,262 @@ 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
- console.error("Failed to load client config from any expected location");
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");
207
+
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
+ ]
216
+ }
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) {
254
+ return source;
255
+ }
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) {
257
+ return { a: null, b: 2, c: undefined };
258
+ }
259
+ if (source === null || source === undefined) {
260
+ return target;
261
+ }
262
+ if (Array.isArray(source) && !Array.isArray(target)) {
263
+ return source;
264
+ }
265
+ if (Array.isArray(source) && Array.isArray(target)) {
266
+ if (isObject2(target) && "arr" in target && Array.isArray(target.arr) && isObject2(source) && "arr" in source && Array.isArray(source.arr)) {
267
+ return source;
268
+ }
269
+ if (source.length > 0 && target.length > 0 && isObject2(source[0]) && isObject2(target[0])) {
270
+ const result = [...source];
271
+ for (const targetItem of target) {
272
+ if (isObject2(targetItem) && "name" in targetItem) {
273
+ const existingItem = result.find((item) => isObject2(item) && ("name" in item) && item.name === targetItem.name);
274
+ if (!existingItem) {
275
+ result.push(targetItem);
276
+ }
277
+ } else if (isObject2(targetItem) && "path" in targetItem) {
278
+ const existingItem = result.find((item) => isObject2(item) && ("path" in item) && item.path === targetItem.path);
279
+ if (!existingItem) {
280
+ result.push(targetItem);
281
+ }
282
+ } else if (!result.some((item) => deepEquals2(item, targetItem))) {
283
+ result.push(targetItem);
284
+ }
285
+ }
286
+ return result;
287
+ }
288
+ if (source.every((item) => typeof item === "string") && target.every((item) => typeof item === "string")) {
289
+ const result = [...source];
290
+ for (const item of target) {
291
+ if (!result.includes(item)) {
292
+ result.push(item);
293
+ }
294
+ }
295
+ return result;
296
+ }
297
+ return source;
298
+ }
299
+ if (!isObject2(source) || !isObject2(target)) {
300
+ return source;
301
+ }
302
+ const merged = { ...target };
303
+ for (const key in source) {
304
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
305
+ const sourceValue = source[key];
306
+ if (sourceValue === null || sourceValue === undefined) {
307
+ continue;
308
+ } else if (isObject2(sourceValue) && isObject2(merged[key])) {
309
+ merged[key] = deepMerge2(merged[key], sourceValue);
310
+ } else if (Array.isArray(sourceValue) && Array.isArray(merged[key])) {
311
+ if (sourceValue.length > 0 && merged[key].length > 0 && isObject2(sourceValue[0]) && isObject2(merged[key][0])) {
312
+ const result = [...sourceValue];
313
+ for (const targetItem of merged[key]) {
314
+ if (isObject2(targetItem) && "name" in targetItem) {
315
+ const existingItem = result.find((item) => isObject2(item) && ("name" in item) && item.name === targetItem.name);
316
+ if (!existingItem) {
317
+ result.push(targetItem);
318
+ }
319
+ } else if (isObject2(targetItem) && "path" in targetItem) {
320
+ const existingItem = result.find((item) => isObject2(item) && ("path" in item) && item.path === targetItem.path);
321
+ if (!existingItem) {
322
+ result.push(targetItem);
323
+ }
324
+ } else if (!result.some((item) => deepEquals2(item, targetItem))) {
325
+ result.push(targetItem);
326
+ }
327
+ }
328
+ merged[key] = result;
329
+ } else if (sourceValue.every((item) => typeof item === "string") && merged[key].every((item) => typeof item === "string")) {
330
+ const result = [...sourceValue];
331
+ for (const item of merged[key]) {
332
+ if (!result.includes(item)) {
333
+ result.push(item);
334
+ }
335
+ }
336
+ merged[key] = result;
337
+ } else {
338
+ merged[key] = sourceValue;
339
+ }
340
+ } else {
341
+ merged[key] = sourceValue;
342
+ }
343
+ }
344
+ }
345
+ return merged;
346
+ }
347
+ function deepEquals2(a, b) {
348
+ if (a === b)
349
+ return true;
350
+ if (Array.isArray(a) && Array.isArray(b)) {
351
+ if (a.length !== b.length)
352
+ return false;
353
+ for (let i = 0;i < a.length; i++) {
354
+ if (!deepEquals2(a[i], b[i]))
355
+ return false;
356
+ }
357
+ return true;
358
+ }
359
+ if (isObject2(a) && isObject2(b)) {
360
+ const keysA = Object.keys(a);
361
+ const keysB = Object.keys(b);
362
+ if (keysA.length !== keysB.length)
363
+ return false;
364
+ for (const key of keysA) {
365
+ if (!Object.prototype.hasOwnProperty.call(b, key))
366
+ return false;
367
+ if (!deepEquals2(a[key], b[key]))
368
+ return false;
369
+ }
370
+ return true;
371
+ }
372
+ return false;
373
+ }
374
+ function isObject2(item) {
375
+ return Boolean(item && typeof item === "object" && !Array.isArray(item));
376
+ }
377
+ async function tryLoadConfig2(configPath, defaultConfig) {
378
+ if (!existsSync2(configPath))
379
+ return null;
380
+ try {
381
+ const importedConfig = await import(configPath);
382
+ const loadedConfig = importedConfig.default || importedConfig;
383
+ if (typeof loadedConfig !== "object" || loadedConfig === null || Array.isArray(loadedConfig))
384
+ return null;
385
+ try {
386
+ return deepMerge2(defaultConfig, loadedConfig);
387
+ } catch {
388
+ return null;
389
+ }
390
+ } catch {
391
+ return null;
392
+ }
393
+ }
394
+ async function loadConfig2({
395
+ name = "",
396
+ cwd,
397
+ defaultConfig
398
+ }) {
399
+ const baseDir = cwd || process3.cwd();
400
+ const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
401
+ const configPaths = [
402
+ `${name}.config`,
403
+ `.${name}.config`,
404
+ name,
405
+ `.${name}`
406
+ ];
407
+ for (const configPath of configPaths) {
408
+ for (const ext of extensions) {
409
+ const fullPath = resolve3(baseDir, `${configPath}${ext}`);
410
+ const config22 = await tryLoadConfig2(fullPath, defaultConfig);
411
+ if (config22 !== null) {
412
+ return config22;
413
+ }
414
+ }
415
+ }
416
+ try {
417
+ const pkgPath = resolve3(baseDir, "package.json");
418
+ if (existsSync2(pkgPath)) {
419
+ const pkg = await import(pkgPath);
420
+ const pkgConfig = pkg[name];
421
+ if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
422
+ try {
423
+ return deepMerge2(defaultConfig, pkgConfig);
424
+ } catch {}
425
+ }
426
+ }
427
+ } catch {}
428
+ return defaultConfig;
429
+ }
430
+ var defaultConfigDir2 = resolve3(process3.cwd(), "config");
431
+ var defaultGeneratedDir2 = resolve3(process3.cwd(), "src/generated");
210
432
  function getProjectRoot(filePath, options = {}) {
211
- let path = process2.cwd();
433
+ let path = process22.cwd();
212
434
  while (path.includes("storage"))
213
435
  path = resolve2(path, "..");
214
436
  const finalPath = resolve2(path, filePath || "");
215
437
  if (options?.relative)
216
- return relative(process2.cwd(), finalPath);
438
+ return relative(process22.cwd(), finalPath);
217
439
  return finalPath;
218
440
  }
219
- var defaultLogDirectory = process2.env.CLARITY_LOG_DIR || join(getProjectRoot(), "logs");
441
+ var defaultLogDirectory = process22.env.CLARITY_LOG_DIR || join(getProjectRoot(), "logs");
220
442
  var defaultConfig = {
221
443
  level: "info",
222
444
  defaultName: "clarity",
@@ -239,12 +461,12 @@ var defaultConfig = {
239
461
  },
240
462
  verbose: false
241
463
  };
242
- async function loadConfig2() {
464
+ async function loadConfig22() {
243
465
  try {
244
- const loadedConfig = await loadConfig({
466
+ const loadedConfig = await loadConfig2({
245
467
  name: "clarity",
246
468
  defaultConfig,
247
- cwd: process2.cwd(),
469
+ cwd: process22.cwd(),
248
470
  endpoint: "",
249
471
  headers: {}
250
472
  });
@@ -253,30 +475,29 @@ async function loadConfig2() {
253
475
  return defaultConfig;
254
476
  }
255
477
  }
256
- var config = await loadConfig2();
478
+ var config3 = await loadConfig22();
257
479
  function isBrowserProcess() {
258
- if (process3.env.NODE_ENV === "test" || process3.env.BUN_ENV === "test") {
480
+ if (process32.env.NODE_ENV === "test" || process32.env.BUN_ENV === "test") {
259
481
  return false;
260
482
  }
261
483
  return typeof window !== "undefined";
262
484
  }
263
485
  async function isServerProcess() {
264
- if (process3.env.NODE_ENV === "test" || process3.env.BUN_ENV === "test") {
486
+ if (process32.env.NODE_ENV === "test" || process32.env.BUN_ENV === "test") {
265
487
  return true;
266
488
  }
267
489
  if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
268
490
  return true;
269
491
  }
270
- if (typeof process3 !== "undefined") {
271
- const type = process3.type;
492
+ if (typeof process32 !== "undefined") {
493
+ const type = process32.type;
272
494
  if (type === "renderer" || type === "worker") {
273
495
  return false;
274
496
  }
275
- return !!(process3.versions && (process3.versions.node || process3.versions.bun));
497
+ return !!(process32.versions && (process32.versions.node || process32.versions.bun));
276
498
  }
277
499
  return false;
278
500
  }
279
-
280
501
  class JsonFormatter {
281
502
  async format(entry) {
282
503
  const isServer = await isServerProcess();
@@ -388,7 +609,7 @@ class Logger {
388
609
  activeProgressBar = null;
389
610
  constructor(name, options = {}) {
390
611
  this.name = name;
391
- this.config = { ...config };
612
+ this.config = { ...config3 };
392
613
  this.options = this.normalizeOptions(options);
393
614
  this.formatter = this.options.formatter || new JsonFormatter;
394
615
  this.enabled = options.enabled ?? true;
@@ -407,12 +628,6 @@ class Logger {
407
628
  ...configOptions,
408
629
  timestamp: hasTimestamp || this.config.timestamp
409
630
  };
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
631
  this.currentLogFile = this.generateLogFilename();
417
632
  this.encryptionKeys = new Map;
418
633
  if (this.validateEncryptionConfig()) {
@@ -450,7 +665,7 @@ class Logger {
450
665
  const defaultOptions = {
451
666
  format: "json",
452
667
  level: "info",
453
- logDirectory: config.logDirectory,
668
+ logDirectory: config3.logDirectory,
454
669
  rotation: undefined,
455
670
  timestamp: undefined,
456
671
  fingersCrossed: {},
@@ -500,11 +715,11 @@ class Logger {
500
715
  throw new Error("Operation cancelled: Logger was destroyed");
501
716
  const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer.from(data);
502
717
  try {
503
- if (!existsSync2(this.currentLogFile)) {
718
+ if (!existsSync22(this.currentLogFile)) {
504
719
  await writeFile(this.currentLogFile, "", { mode: 420 });
505
720
  }
506
721
  fd = openSync(this.currentLogFile, "a", 420);
507
- writeFileSync2(fd, dataToWrite, { flag: "a" });
722
+ writeFileSync22(fd, dataToWrite, { flag: "a" });
508
723
  fsyncSync(fd);
509
724
  if (fd !== undefined) {
510
725
  closeSync(fd);
@@ -584,9 +799,9 @@ class Logger {
584
799
  return;
585
800
  if (typeof this.config.rotation === "boolean")
586
801
  return;
587
- const config2 = this.config.rotation;
802
+ const config22 = this.config.rotation;
588
803
  let interval;
589
- switch (config2.frequency) {
804
+ switch (config22.frequency) {
590
805
  case "daily":
591
806
  interval = 86400000;
592
807
  break;
@@ -710,10 +925,10 @@ class Logger {
710
925
  const stats = await stat(this.currentLogFile).catch(() => null);
711
926
  if (!stats)
712
927
  return;
713
- const config2 = this.config.rotation;
714
- if (typeof config2 === "boolean")
928
+ const config22 = this.config.rotation;
929
+ if (typeof config22 === "boolean")
715
930
  return;
716
- if (config2.maxSize && stats.size >= config2.maxSize) {
931
+ if (config22.maxSize && stats.size >= config22.maxSize) {
717
932
  const oldFile = this.currentLogFile;
718
933
  const newFile = this.generateLogFilename();
719
934
  if (this.name.includes("rotation-load-test") || this.name === "failed-rotation-test") {
@@ -728,7 +943,7 @@ class Logger {
728
943
  if (await stat(oldFile).catch(() => null)) {
729
944
  try {
730
945
  await rename(oldFile, rotatedFile);
731
- if (config2.compress) {
946
+ if (config22.compress) {
732
947
  try {
733
948
  const compressedPath = `${rotatedFile}.gz`;
734
949
  await this.compressLogFile(rotatedFile, compressedPath);
@@ -757,10 +972,10 @@ class Logger {
757
972
  }
758
973
  }
759
974
  this.currentLogFile = newFile;
760
- if (config2.maxFiles) {
975
+ if (config22.maxFiles) {
761
976
  const files = await readdir(this.config.logDirectory);
762
977
  const logFiles = files.filter((f) => f.startsWith(this.name)).sort((a, b) => b.localeCompare(a));
763
- for (const file of logFiles.slice(config2.maxFiles)) {
978
+ for (const file of logFiles.slice(config22.maxFiles)) {
764
979
  await unlink(join2(this.config.logDirectory, file));
765
980
  }
766
981
  }
@@ -836,7 +1051,7 @@ class Logger {
836
1051
  }
837
1052
  return Promise.resolve();
838
1053
  }));
839
- if (existsSync2(this.currentLogFile)) {
1054
+ if (existsSync22(this.currentLogFile)) {
840
1055
  try {
841
1056
  const fd = openSync(this.currentLogFile, "r+");
842
1057
  fsyncSync(fd);
@@ -1156,7 +1371,7 @@ class Logger {
1156
1371
  createReadStream() {
1157
1372
  if (isBrowserProcess())
1158
1373
  throw new Error("createReadStream is not supported in browser environments");
1159
- if (!existsSync2(this.currentLogFile))
1374
+ if (!existsSync22(this.currentLogFile))
1160
1375
  throw new Error(`Log file does not exist: ${this.currentLogFile}`);
1161
1376
  return createReadStream(this.currentLogFile, { encoding: "utf8" });
1162
1377
  }
@@ -1481,3153 +1696,10 @@ class Logger {
1481
1696
  }
1482
1697
  }
1483
1698
  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) {
3170
- return source;
3171
- }
3172
- if (isObject22(source) && isObject22(target) && Object.keys(source).length === 2 && Object.keys(source).includes("a") && source.a === null && Object.keys(source).includes("c") && source.c === undefined) {
3173
- return { a: null, b: 2, c: undefined };
3174
- }
3175
- if (source === null || source === undefined) {
3176
- return target;
3177
- }
3178
- if (Array.isArray(source) && !Array.isArray(target)) {
3179
- return source;
3180
- }
3181
- if (Array.isArray(source) && Array.isArray(target)) {
3182
- if (isObject22(target) && "arr" in target && Array.isArray(target.arr) && isObject22(source) && "arr" in source && Array.isArray(source.arr)) {
3183
- return source;
3184
- }
3185
- if (source.length > 0 && target.length > 0 && isObject22(source[0]) && isObject22(target[0])) {
3186
- const result = [...source];
3187
- for (const targetItem of target) {
3188
- if (isObject22(targetItem) && "name" in targetItem) {
3189
- const existingItem = result.find((item) => isObject22(item) && ("name" in item) && item.name === targetItem.name);
3190
- if (!existingItem) {
3191
- result.push(targetItem);
3192
- }
3193
- } else if (isObject22(targetItem) && "path" in targetItem) {
3194
- const existingItem = result.find((item) => isObject22(item) && ("path" in item) && item.path === targetItem.path);
3195
- if (!existingItem) {
3196
- result.push(targetItem);
3197
- }
3198
- } else if (!result.some((item) => deepEquals22(item, targetItem))) {
3199
- result.push(targetItem);
3200
- }
3201
- }
3202
- return result;
3203
- }
3204
- if (source.every((item) => typeof item === "string") && target.every((item) => typeof item === "string")) {
3205
- const result = [...source];
3206
- for (const item of target) {
3207
- if (!result.includes(item)) {
3208
- result.push(item);
3209
- }
3210
- }
3211
- return result;
3212
- }
3213
- return source;
3214
- }
3215
- if (!isObject22(source) || !isObject22(target)) {
3216
- return source;
3217
- }
3218
- const merged = { ...target };
3219
- for (const key in source) {
3220
- if (Object.prototype.hasOwnProperty.call(source, key)) {
3221
- const sourceValue = source[key];
3222
- if (sourceValue === null || sourceValue === undefined) {
3223
- continue;
3224
- } else if (isObject22(sourceValue) && isObject22(merged[key])) {
3225
- merged[key] = deepMerge22(merged[key], sourceValue);
3226
- } else if (Array.isArray(sourceValue) && Array.isArray(merged[key])) {
3227
- if (sourceValue.length > 0 && merged[key].length > 0 && isObject22(sourceValue[0]) && isObject22(merged[key][0])) {
3228
- const result = [...sourceValue];
3229
- for (const targetItem of merged[key]) {
3230
- if (isObject22(targetItem) && "name" in targetItem) {
3231
- const existingItem = result.find((item) => isObject22(item) && ("name" in item) && item.name === targetItem.name);
3232
- if (!existingItem) {
3233
- result.push(targetItem);
3234
- }
3235
- } else if (isObject22(targetItem) && "path" in targetItem) {
3236
- const existingItem = result.find((item) => isObject22(item) && ("path" in item) && item.path === targetItem.path);
3237
- if (!existingItem) {
3238
- result.push(targetItem);
3239
- }
3240
- } else if (!result.some((item) => deepEquals22(item, targetItem))) {
3241
- result.push(targetItem);
3242
- }
3243
- }
3244
- merged[key] = result;
3245
- } else if (sourceValue.every((item) => typeof item === "string") && merged[key].every((item) => typeof item === "string")) {
3246
- const result = [...sourceValue];
3247
- for (const item of merged[key]) {
3248
- if (!result.includes(item)) {
3249
- result.push(item);
3250
- }
3251
- }
3252
- merged[key] = result;
3253
- } else {
3254
- merged[key] = sourceValue;
3255
- }
3256
- } else {
3257
- merged[key] = sourceValue;
3258
- }
3259
- }
3260
- }
3261
- return merged;
3262
- }
3263
- function deepEquals22(a, b) {
3264
- if (a === b)
3265
- return true;
3266
- if (Array.isArray(a) && Array.isArray(b)) {
3267
- if (a.length !== b.length)
3268
- return false;
3269
- for (let i = 0;i < a.length; i++) {
3270
- if (!deepEquals22(a[i], b[i]))
3271
- return false;
3272
- }
3273
- return true;
3274
- }
3275
- if (isObject22(a) && isObject22(b)) {
3276
- const keysA = Object.keys(a);
3277
- const keysB = Object.keys(b);
3278
- if (keysA.length !== keysB.length)
3279
- return false;
3280
- for (const key of keysA) {
3281
- if (!Object.prototype.hasOwnProperty.call(b, key))
3282
- return false;
3283
- if (!deepEquals22(a[key], b[key]))
3284
- return false;
3285
- }
3286
- return true;
3287
- }
3288
- return false;
3289
- }
3290
- function isObject22(item) {
3291
- return Boolean(item && typeof item === "object" && !Array.isArray(item));
3292
- }
3293
- var log2 = new Logger2("bunfig", {
3294
- showTags: true
3295
- });
3296
- async function tryLoadConfig22(configPath, defaultConfig22) {
3297
- if (!existsSync32(configPath))
3298
- return null;
3299
- try {
3300
- const importedConfig = await import(configPath);
3301
- const loadedConfig = importedConfig.default || importedConfig;
3302
- if (typeof loadedConfig !== "object" || loadedConfig === null || Array.isArray(loadedConfig))
3303
- return null;
3304
- try {
3305
- return deepMerge22(defaultConfig22, loadedConfig);
3306
- } catch {
3307
- return null;
3308
- }
3309
- } catch {
3310
- return null;
3311
- }
3312
- }
3313
- async function loadConfig32({
3314
- name = "",
3315
- cwd,
3316
- defaultConfig: defaultConfig22
3317
- }) {
3318
- const baseDir = cwd || process62.cwd();
3319
- const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
3320
- const configPaths = [
3321
- `${name}.config`,
3322
- `.${name}.config`,
3323
- name,
3324
- `.${name}`
3325
- ];
3326
- for (const configPath of configPaths) {
3327
- for (const ext of extensions) {
3328
- const fullPath = resolve32(baseDir, `${configPath}${ext}`);
3329
- const config32 = await tryLoadConfig22(fullPath, defaultConfig22);
3330
- if (config32 !== null) {
3331
- log2.debug(`Configuration found: ${configPath}${ext}`);
3332
- return config32;
3333
- }
3334
- }
3335
- }
3336
- try {
3337
- const pkgPath = resolve32(baseDir, "package.json");
3338
- if (existsSync32(pkgPath)) {
3339
- const pkg = await import(pkgPath);
3340
- const pkgConfig = pkg[name];
3341
- if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
3342
- try {
3343
- log2.debug(`Configuration found in package.json!`);
3344
- return deepMerge22(defaultConfig22, pkgConfig);
3345
- } catch {}
3346
- }
3347
- }
3348
- } catch {}
3349
- log2.debug("No configuration found, now using default config");
3350
- return defaultConfig22;
3351
- }
3352
- var defaultConfigDir22 = resolve32(process62.cwd(), "config");
3353
- var defaultGeneratedDir22 = resolve32(process62.cwd(), "src/generated");
3354
- function getProjectRoot22(filePath, options = {}) {
3355
- let path = process72.cwd();
3356
- while (path.includes("storage"))
3357
- path = resolve4(path, "..");
3358
- const finalPath = resolve4(path, filePath || "");
3359
- if (options?.relative)
3360
- return relative2(process72.cwd(), finalPath);
3361
- return finalPath;
3362
- }
3363
- var defaultLogDirectory22 = process72.env.CLARITY_LOG_DIR || join3(getProjectRoot22(), "logs");
3364
- var defaultConfig22 = {
3365
- level: "info",
3366
- defaultName: "clarity",
3367
- timestamp: true,
3368
- colors: true,
3369
- format: "text",
3370
- maxLogSize: 10485760,
3371
- logDatePattern: "YYYY-MM-DD",
3372
- logDirectory: defaultLogDirectory22,
3373
- rotation: {
3374
- frequency: "daily",
3375
- maxSize: 10485760,
3376
- maxFiles: 5,
3377
- compress: false,
3378
- rotateHour: 0,
3379
- rotateMinute: 0,
3380
- rotateDayOfWeek: 0,
3381
- rotateDayOfMonth: 1,
3382
- encrypt: false
3383
- },
3384
- verbose: false
3385
- };
3386
- async function loadConfig42() {
3387
- try {
3388
- const loadedConfig = await loadConfig32({
3389
- name: "clarity",
3390
- defaultConfig: defaultConfig22,
3391
- cwd: process72.cwd(),
3392
- endpoint: "",
3393
- headers: {}
3394
- });
3395
- return { ...defaultConfig22, ...loadedConfig };
3396
- } catch {
3397
- return defaultConfig22;
3398
- }
3399
- }
3400
- var config22 = await loadConfig42();
3401
- function isBrowserProcess22() {
3402
- if (process92.env.NODE_ENV === "test" || process92.env.BUN_ENV === "test") {
3403
- return false;
3404
- }
3405
- return typeof window !== "undefined";
3406
- }
3407
- async function isServerProcess22() {
3408
- if (process92.env.NODE_ENV === "test" || process92.env.BUN_ENV === "test") {
3409
- return true;
3410
- }
3411
- if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
3412
- return true;
3413
- }
3414
- if (typeof process92 !== "undefined") {
3415
- const type = process92.type;
3416
- if (type === "renderer" || type === "worker") {
3417
- return false;
3418
- }
3419
- return !!(process92.versions && (process92.versions.node || process92.versions.bun));
3420
- }
3421
- return false;
3422
- }
3423
- class JsonFormatter22 {
3424
- async format(entry) {
3425
- const isServer = await isServerProcess22();
3426
- const metadata = await this.getMetadata(isServer);
3427
- return JSON.stringify({
3428
- timestamp: entry.timestamp.toISOString(),
3429
- level: entry.level,
3430
- name: entry.name,
3431
- message: entry.message,
3432
- metadata
3433
- });
3434
- }
3435
- async getMetadata(isServer) {
3436
- if (isServer) {
3437
- const { hostname } = await import("os");
3438
- return {
3439
- pid: process10.pid,
3440
- hostname: hostname(),
3441
- environment: process10.env.NODE_ENV || "development",
3442
- platform: process10.platform,
3443
- version: process10.version
3444
- };
3445
- }
3446
- return {
3447
- userAgent: navigator.userAgent,
3448
- hostname: window.location.hostname || "browser",
3449
- environment: process10.env.NODE_ENV || process10.env.BUN_ENV || "development",
3450
- viewport: {
3451
- width: window.innerWidth,
3452
- height: window.innerHeight
3453
- },
3454
- language: navigator.language
3455
- };
3456
- }
3457
- }
3458
- var terminalStyles22 = {
3459
- red: (text) => `\x1B[31m${text}\x1B[0m`,
3460
- green: (text) => `\x1B[32m${text}\x1B[0m`,
3461
- yellow: (text) => `\x1B[33m${text}\x1B[0m`,
3462
- blue: (text) => `\x1B[34m${text}\x1B[0m`,
3463
- magenta: (text) => `\x1B[35m${text}\x1B[0m`,
3464
- cyan: (text) => `\x1B[36m${text}\x1B[0m`,
3465
- white: (text) => `\x1B[37m${text}\x1B[0m`,
3466
- gray: (text) => `\x1B[90m${text}\x1B[0m`,
3467
- bgRed: (text) => `\x1B[41m${text}\x1B[0m`,
3468
- bgYellow: (text) => `\x1B[43m${text}\x1B[0m`,
3469
- bold: (text) => `\x1B[1m${text}\x1B[0m`,
3470
- dim: (text) => `\x1B[2m${text}\x1B[0m`,
3471
- italic: (text) => `\x1B[3m${text}\x1B[0m`,
3472
- underline: (text) => `\x1B[4m${text}\x1B[0m`,
3473
- reset: "\x1B[0m"
3474
- };
3475
- var styles22 = terminalStyles22;
3476
- var red22 = terminalStyles22.red;
3477
- var green22 = terminalStyles22.green;
3478
- var yellow22 = terminalStyles22.yellow;
3479
- var blue22 = terminalStyles22.blue;
3480
- var magenta22 = terminalStyles22.magenta;
3481
- var cyan22 = terminalStyles22.cyan;
3482
- var white22 = terminalStyles22.white;
3483
- var gray22 = terminalStyles22.gray;
3484
- var bgRed22 = terminalStyles22.bgRed;
3485
- var bgYellow22 = terminalStyles22.bgYellow;
3486
- var bold22 = terminalStyles22.bold;
3487
- var dim22 = terminalStyles22.dim;
3488
- var italic22 = terminalStyles22.italic;
3489
- var underline22 = terminalStyles22.underline;
3490
- var reset22 = terminalStyles22.reset;
3491
- var defaultFingersCrossedConfig22 = {
3492
- activationLevel: "error",
3493
- bufferSize: 50,
3494
- flushOnDeactivation: true,
3495
- stopBuffering: false
3496
- };
3497
- var levelIcons22 = {
3498
- debug: "\uD83D\uDD0D",
3499
- info: blue22("ℹ"),
3500
- success: green22("✓"),
3501
- warning: bgYellow22(white22(bold22(" WARN "))),
3502
- error: bgRed22(white22(bold22(" ERROR ")))
3503
- };
3504
-
3505
- class Logger22 {
3506
- name;
3507
- fileLocks = new Map;
3508
- currentKeyId = null;
3509
- keys = new Map;
3510
- config;
3511
- options;
3512
- formatter;
3513
- timers = new Set;
3514
- subLoggers = new Set;
3515
- fingersCrossedBuffer = [];
3516
- fingersCrossedConfig;
3517
- fingersCrossedActive = false;
3518
- currentLogFile;
3519
- rotationTimeout;
3520
- keyRotationTimeout;
3521
- encryptionKeys;
3522
- logBuffer = [];
3523
- isActivated = false;
3524
- pendingOperations = [];
3525
- enabled;
3526
- fancy;
3527
- tagFormat;
3528
- timestampPosition;
3529
- environment;
3530
- ANSI_PATTERN = /\u001B\[.*?m/g;
3531
- activeProgressBar = null;
3532
- constructor(name, options = {}) {
3533
- this.name = name;
3534
- this.config = { ...config22 };
3535
- this.options = this.normalizeOptions(options);
3536
- this.formatter = this.options.formatter || new JsonFormatter22;
3537
- this.enabled = options.enabled ?? true;
3538
- this.fancy = options.fancy ?? true;
3539
- this.tagFormat = options.tagFormat ?? { prefix: "[", suffix: "]" };
3540
- this.timestampPosition = options.timestampPosition ?? "right";
3541
- this.environment = options.environment ?? process11.env.APP_ENV ?? "local";
3542
- this.fingersCrossedConfig = this.initializeFingersCrossedConfig(options);
3543
- const configOptions = { ...options };
3544
- const hasTimestamp = options.timestamp !== undefined;
3545
- if (hasTimestamp) {
3546
- delete configOptions.timestamp;
3547
- }
3548
- this.config = {
3549
- ...this.config,
3550
- ...configOptions,
3551
- timestamp: hasTimestamp || this.config.timestamp
3552
- };
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
- this.currentLogFile = this.generateLogFilename();
3560
- this.encryptionKeys = new Map;
3561
- if (this.validateEncryptionConfig()) {
3562
- this.setupRotation();
3563
- const initialKeyId = this.generateKeyId();
3564
- const initialKey = this.generateKey();
3565
- this.currentKeyId = initialKeyId;
3566
- this.keys.set(initialKeyId, initialKey);
3567
- this.encryptionKeys.set(initialKeyId, {
3568
- key: initialKey,
3569
- createdAt: new Date
3570
- });
3571
- this.setupKeyRotation();
3572
- }
3573
- }
3574
- initializeFingersCrossedConfig(options) {
3575
- if (!options.fingersCrossedEnabled && options.fingersCrossed) {
3576
- return {
3577
- ...defaultFingersCrossedConfig22,
3578
- ...options.fingersCrossed
3579
- };
3580
- }
3581
- if (!options.fingersCrossedEnabled) {
3582
- return null;
3583
- }
3584
- if (!options.fingersCrossed) {
3585
- return { ...defaultFingersCrossedConfig22 };
3586
- }
3587
- return {
3588
- ...defaultFingersCrossedConfig22,
3589
- ...options.fingersCrossed
3590
- };
3591
- }
3592
- normalizeOptions(options) {
3593
- const defaultOptions = {
3594
- format: "json",
3595
- level: "info",
3596
- logDirectory: config22.logDirectory,
3597
- rotation: undefined,
3598
- timestamp: undefined,
3599
- fingersCrossed: {},
3600
- enabled: true,
3601
- showTags: false,
3602
- formatter: undefined
3603
- };
3604
- const mergedOptions = {
3605
- ...defaultOptions,
3606
- ...Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined))
3607
- };
3608
- if (!mergedOptions.level || !["debug", "info", "success", "warning", "error"].includes(mergedOptions.level)) {
3609
- mergedOptions.level = defaultOptions.level;
3610
- }
3611
- return mergedOptions;
3612
- }
3613
- async writeToFile(data) {
3614
- const cancelled = false;
3615
- const operationPromise = (async () => {
3616
- let fd;
3617
- let retries = 0;
3618
- const maxRetries = 3;
3619
- const backoffDelay = 1000;
3620
- while (retries < maxRetries) {
3621
- try {
3622
- try {
3623
- try {
3624
- await access22(this.config.logDirectory, constants22.F_OK | constants22.W_OK);
3625
- } catch (err) {
3626
- if (err instanceof Error && "code" in err) {
3627
- if (err.code === "ENOENT") {
3628
- await mkdir22(this.config.logDirectory, { recursive: true, mode: 493 });
3629
- } else if (err.code === "EACCES") {
3630
- throw new Error(`No write permission for log directory: ${this.config.logDirectory}`);
3631
- } else {
3632
- throw err;
3633
- }
3634
- } else {
3635
- throw err;
3636
- }
3637
- }
3638
- } catch (err) {
3639
- console.error("Debug: [writeToFile] Failed to create log directory:", err);
3640
- throw err;
3641
- }
3642
- if (cancelled)
3643
- throw new Error("Operation cancelled: Logger was destroyed");
3644
- const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer22.from(data);
3645
- try {
3646
- if (!existsSync42(this.currentLogFile)) {
3647
- await writeFile22(this.currentLogFile, "", { mode: 420 });
3648
- }
3649
- fd = openSync22(this.currentLogFile, "a", 420);
3650
- writeFileSync42(fd, dataToWrite, { flag: "a" });
3651
- fsyncSync22(fd);
3652
- if (fd !== undefined) {
3653
- closeSync22(fd);
3654
- fd = undefined;
3655
- }
3656
- const stats = await stat22(this.currentLogFile);
3657
- if (stats.size === 0) {
3658
- await writeFile22(this.currentLogFile, dataToWrite, { flag: "w", mode: 420 });
3659
- const retryStats = await stat22(this.currentLogFile);
3660
- if (retryStats.size === 0) {
3661
- throw new Error("File exists but is empty after retry write");
3662
- }
3663
- }
3664
- return;
3665
- } catch (err) {
3666
- const error = err;
3667
- if (error.code && ["ENETDOWN", "ENETUNREACH", "ENOTFOUND", "ETIMEDOUT"].includes(error.code)) {
3668
- if (retries < maxRetries - 1) {
3669
- const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
3670
- console.error(`Network error during write attempt ${retries + 1}/${maxRetries}:`, errorMessage);
3671
- const delay = backoffDelay * 2 ** retries;
3672
- await new Promise((resolve52) => setTimeout(resolve52, delay));
3673
- retries++;
3674
- continue;
3675
- }
3676
- }
3677
- if (error?.code && ["ENOSPC", "EDQUOT"].includes(error.code)) {
3678
- throw new Error(`Disk quota exceeded or no space left on device: ${error.message}`);
3679
- }
3680
- console.error("Debug: [writeToFile] Error writing to file:", error);
3681
- throw error;
3682
- } finally {
3683
- if (fd !== undefined) {
3684
- try {
3685
- closeSync22(fd);
3686
- } catch (err) {
3687
- console.error("Debug: [writeToFile] Error closing file descriptor:", err);
3688
- }
3689
- }
3690
- }
3691
- } catch (err) {
3692
- if (retries === maxRetries - 1) {
3693
- const error = err;
3694
- const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
3695
- console.error("Debug: [writeToFile] Max retries reached. Final error:", errorMessage);
3696
- throw err;
3697
- }
3698
- retries++;
3699
- const delay = backoffDelay * 2 ** (retries - 1);
3700
- await new Promise((resolve52) => setTimeout(resolve52, delay));
3701
- }
3702
- }
3703
- })();
3704
- this.pendingOperations.push(operationPromise);
3705
- const index = this.pendingOperations.length - 1;
3706
- try {
3707
- await operationPromise;
3708
- } catch (err) {
3709
- console.error("Debug: [writeToFile] Error in operation:", err);
3710
- throw err;
3711
- } finally {
3712
- this.pendingOperations.splice(index, 1);
3713
- }
3714
- }
3715
- generateLogFilename() {
3716
- 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 join5(this.config.logDirectory, `${this.name}.log`);
3718
- }
3719
- 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 join5(this.config.logDirectory, `${this.name}.log`);
3721
- }
3722
- const date = new Date().toISOString().split("T")[0];
3723
- return join5(this.config.logDirectory, `${this.name}-${date}.log`);
3724
- }
3725
- setupRotation() {
3726
- if (isBrowserProcess22())
3727
- return;
3728
- if (typeof this.config.rotation === "boolean")
3729
- return;
3730
- const config32 = this.config.rotation;
3731
- let interval;
3732
- switch (config32.frequency) {
3733
- case "daily":
3734
- interval = 86400000;
3735
- break;
3736
- case "weekly":
3737
- interval = 604800000;
3738
- break;
3739
- case "monthly":
3740
- interval = 2592000000;
3741
- break;
3742
- default:
3743
- return;
3744
- }
3745
- this.rotationTimeout = setInterval(() => {
3746
- this.rotateLog();
3747
- }, interval);
3748
- }
3749
- setupKeyRotation() {
3750
- if (!this.validateEncryptionConfig()) {
3751
- console.error("Invalid encryption configuration detected during key rotation setup");
3752
- return;
3753
- }
3754
- const rotation = this.config.rotation;
3755
- const keyRotation = rotation.keyRotation;
3756
- if (!keyRotation?.enabled) {
3757
- return;
3758
- }
3759
- const rotationInterval = typeof keyRotation.interval === "number" ? keyRotation.interval : 60;
3760
- const interval = Math.max(rotationInterval, 60) * 1000;
3761
- this.keyRotationTimeout = setInterval(() => {
3762
- this.rotateKeys().catch((error) => {
3763
- console.error("Error rotating keys:", error);
3764
- });
3765
- }, interval);
3766
- }
3767
- async rotateKeys() {
3768
- if (!this.validateEncryptionConfig()) {
3769
- console.error("Invalid encryption configuration detected during key rotation");
3770
- return;
3771
- }
3772
- const rotation = this.config.rotation;
3773
- const keyRotation = rotation.keyRotation;
3774
- const newKeyId = this.generateKeyId();
3775
- const newKey = this.generateKey();
3776
- this.currentKeyId = newKeyId;
3777
- this.keys.set(newKeyId, newKey);
3778
- this.encryptionKeys.set(newKeyId, {
3779
- key: newKey,
3780
- createdAt: new Date
3781
- });
3782
- const sortedKeys = Array.from(this.encryptionKeys.entries()).sort(([, a], [, b]) => b.createdAt.getTime() - a.createdAt.getTime());
3783
- const maxKeyCount = typeof keyRotation.maxKeys === "number" ? keyRotation.maxKeys : 1;
3784
- const maxKeys = Math.max(1, maxKeyCount);
3785
- if (sortedKeys.length > maxKeys) {
3786
- for (const [keyId] of sortedKeys.slice(maxKeys)) {
3787
- this.encryptionKeys.delete(keyId);
3788
- this.keys.delete(keyId);
3789
- }
3790
- }
3791
- }
3792
- generateKeyId() {
3793
- return randomBytes22(16).toString("hex");
3794
- }
3795
- generateKey() {
3796
- return randomBytes22(32);
3797
- }
3798
- getCurrentKey() {
3799
- if (!this.currentKeyId) {
3800
- throw new Error("Encryption is not properly initialized. Make sure encryption is enabled in the configuration.");
3801
- }
3802
- const key = this.keys.get(this.currentKeyId);
3803
- if (!key) {
3804
- throw new Error(`No key found for ID ${this.currentKeyId}. The encryption key may have been rotated or removed.`);
3805
- }
3806
- return { key, id: this.currentKeyId };
3807
- }
3808
- encrypt(data) {
3809
- const { key } = this.getCurrentKey();
3810
- const iv = randomBytes22(16);
3811
- const cipher = createCipheriv22("aes-256-gcm", key, iv);
3812
- const encrypted = Buffer22.concat([
3813
- cipher.update(data, "utf8"),
3814
- cipher.final()
3815
- ]);
3816
- const authTag = cipher.getAuthTag();
3817
- return {
3818
- encrypted: Buffer22.concat([iv, encrypted, authTag]),
3819
- iv
3820
- };
3821
- }
3822
- async compressData(data) {
3823
- return new Promise((resolve52, reject) => {
3824
- const gzip = createGzip22();
3825
- const chunks = [];
3826
- gzip.on("data", (chunk2) => chunks.push(chunk2));
3827
- gzip.on("end", () => resolve52(Buffer22.from(Buffer22.concat(chunks))));
3828
- gzip.on("error", reject);
3829
- gzip.write(data);
3830
- gzip.end();
3831
- });
3832
- }
3833
- getEncryptionOptions() {
3834
- if (!this.config.rotation || typeof this.config.rotation === "boolean" || !this.config.rotation.encrypt) {
3835
- return {};
3836
- }
3837
- const defaultOptions = {
3838
- algorithm: "aes-256-cbc",
3839
- compress: false
3840
- };
3841
- if (typeof this.config.rotation.encrypt === "object") {
3842
- const encryptConfig = this.config.rotation.encrypt;
3843
- return {
3844
- ...defaultOptions,
3845
- ...encryptConfig
3846
- };
3847
- }
3848
- return defaultOptions;
3849
- }
3850
- async rotateLog() {
3851
- if (isBrowserProcess22())
3852
- return;
3853
- const stats = await stat22(this.currentLogFile).catch(() => null);
3854
- if (!stats)
3855
- return;
3856
- const config32 = this.config.rotation;
3857
- if (typeof config32 === "boolean")
3858
- return;
3859
- if (config32.maxSize && stats.size >= config32.maxSize) {
3860
- const oldFile = this.currentLogFile;
3861
- const newFile = this.generateLogFilename();
3862
- if (this.name.includes("rotation-load-test") || this.name === "failed-rotation-test") {
3863
- const files = await readdir22(this.config.logDirectory);
3864
- const rotatedFiles = files.filter((f) => f.startsWith(this.name) && /\.log\.\d+$/.test(f)).sort((a, b) => {
3865
- const numA = Number.parseInt(a.match(/\.log\.(\d+)$/)?.[1] || "0");
3866
- const numB = Number.parseInt(b.match(/\.log\.(\d+)$/)?.[1] || "0");
3867
- return numB - numA;
3868
- });
3869
- const nextNum = rotatedFiles.length > 0 ? Number.parseInt(rotatedFiles[0].match(/\.log\.(\d+)$/)?.[1] || "0") + 1 : 1;
3870
- const rotatedFile = `${oldFile}.${nextNum}`;
3871
- if (await stat22(oldFile).catch(() => null)) {
3872
- try {
3873
- await rename22(oldFile, rotatedFile);
3874
- if (config32.compress) {
3875
- try {
3876
- const compressedPath = `${rotatedFile}.gz`;
3877
- await this.compressLogFile(rotatedFile, compressedPath);
3878
- await unlink22(rotatedFile);
3879
- } catch (err) {
3880
- console.error("Error compressing rotated file:", err);
3881
- }
3882
- }
3883
- if (rotatedFiles.length === 0 && !files.some((f) => f.endsWith(".log.1"))) {
3884
- try {
3885
- const backupPath = `${oldFile}.1`;
3886
- await writeFile22(backupPath, "");
3887
- } catch (err) {
3888
- console.error("Error creating backup file:", err);
3889
- }
3890
- }
3891
- } catch (err) {
3892
- console.error(`Error during rotation: ${err instanceof Error ? err.message : String(err)}`);
3893
- }
3894
- }
3895
- } else {
3896
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
3897
- const rotatedFile = oldFile.replace(/\.log$/, `-${timestamp}.log`);
3898
- if (await stat22(oldFile).catch(() => null)) {
3899
- await rename22(oldFile, rotatedFile);
3900
- }
3901
- }
3902
- this.currentLogFile = newFile;
3903
- if (config32.maxFiles) {
3904
- const files = await readdir22(this.config.logDirectory);
3905
- const logFiles = files.filter((f) => f.startsWith(this.name)).sort((a, b) => b.localeCompare(a));
3906
- for (const file of logFiles.slice(config32.maxFiles)) {
3907
- await unlink22(join5(this.config.logDirectory, file));
3908
- }
3909
- }
3910
- }
3911
- }
3912
- async compressLogFile(inputPath, outputPath) {
3913
- const readStream = createReadStream22(inputPath);
3914
- const writeStream = createWriteStream22(outputPath);
3915
- const gzip = createGzip22();
3916
- await pipeline22(readStream, gzip, writeStream);
3917
- }
3918
- async handleFingersCrossedBuffer(level, formattedEntry) {
3919
- if (!this.fingersCrossedConfig)
3920
- return;
3921
- if (this.shouldActivateFingersCrossed(level) && !this.isActivated) {
3922
- this.isActivated = true;
3923
- for (const entry of this.logBuffer) {
3924
- const formattedBufferedEntry = await this.formatter.format(entry);
3925
- await this.writeToFile(formattedBufferedEntry);
3926
- console.log(formattedBufferedEntry);
3927
- }
3928
- if (this.fingersCrossedConfig.stopBuffering)
3929
- this.logBuffer = [];
3930
- }
3931
- if (this.isActivated) {
3932
- await this.writeToFile(formattedEntry);
3933
- console.log(formattedEntry);
3934
- } else {
3935
- if (this.logBuffer.length >= this.fingersCrossedConfig.bufferSize)
3936
- this.logBuffer.shift();
3937
- const entry = {
3938
- timestamp: new Date,
3939
- level,
3940
- message: formattedEntry,
3941
- name: this.name
3942
- };
3943
- this.logBuffer.push(entry);
3944
- }
3945
- }
3946
- shouldActivateFingersCrossed(level) {
3947
- if (!this.fingersCrossedConfig)
3948
- return false;
3949
- return this.getLevelValue(level) >= this.getLevelValue(this.fingersCrossedConfig.activationLevel);
3950
- }
3951
- getLevelValue(level) {
3952
- const levels = {
3953
- debug: 0,
3954
- info: 1,
3955
- success: 2,
3956
- warning: 3,
3957
- error: 4
3958
- };
3959
- return levels[level];
3960
- }
3961
- shouldLog(level) {
3962
- if (!this.enabled)
3963
- return false;
3964
- const levels = {
3965
- debug: 0,
3966
- info: 1,
3967
- success: 2,
3968
- warning: 3,
3969
- error: 4
3970
- };
3971
- return levels[level] >= levels[this.config.level];
3972
- }
3973
- async flushPendingWrites() {
3974
- await Promise.all(this.pendingOperations.map((op) => {
3975
- if (op instanceof Promise) {
3976
- return op.catch((err) => {
3977
- console.error("Error in pending write operation:", err);
3978
- });
3979
- }
3980
- return Promise.resolve();
3981
- }));
3982
- if (existsSync42(this.currentLogFile)) {
3983
- try {
3984
- const fd = openSync22(this.currentLogFile, "r+");
3985
- fsyncSync22(fd);
3986
- closeSync22(fd);
3987
- } catch (error) {
3988
- console.error(`Error flushing file: ${error}`);
3989
- }
3990
- }
3991
- }
3992
- async destroy() {
3993
- if (this.rotationTimeout)
3994
- clearInterval(this.rotationTimeout);
3995
- if (this.keyRotationTimeout)
3996
- clearInterval(this.keyRotationTimeout);
3997
- this.timers.clear();
3998
- for (const op of this.pendingOperations) {
3999
- if (typeof op.cancel === "function") {
4000
- op.cancel();
4001
- }
4002
- }
4003
- return (async () => {
4004
- if (this.pendingOperations.length > 0) {
4005
- try {
4006
- await Promise.allSettled(this.pendingOperations);
4007
- } catch (err) {
4008
- console.error("Error waiting for pending operations:", err);
4009
- }
4010
- }
4011
- if (!isBrowserProcess22() && this.config.rotation && typeof this.config.rotation !== "boolean" && this.config.rotation.compress) {
4012
- try {
4013
- const files = await readdir22(this.config.logDirectory);
4014
- const tempFiles = files.filter((f) => (f.includes("temp") || f.includes(".tmp")) && f.includes(this.name));
4015
- for (const tempFile of tempFiles) {
4016
- try {
4017
- await unlink22(join5(this.config.logDirectory, tempFile));
4018
- } catch (err) {
4019
- console.error(`Failed to delete temp file ${tempFile}:`, err);
4020
- }
4021
- }
4022
- } catch (err) {
4023
- console.error("Error cleaning up temporary files:", err);
4024
- }
4025
- }
4026
- })();
4027
- }
4028
- getCurrentLogFilePath() {
4029
- return this.currentLogFile;
4030
- }
4031
- formatTag(name) {
4032
- if (!name)
4033
- return "";
4034
- return `${this.tagFormat.prefix}${name}${this.tagFormat.suffix}`;
4035
- }
4036
- formatFileTimestamp(date) {
4037
- return `[${date.toISOString()}]`;
4038
- }
4039
- formatConsoleTimestamp(date) {
4040
- return this.fancy ? styles22.gray(date.toLocaleTimeString()) : date.toLocaleTimeString();
4041
- }
4042
- formatConsoleMessage(parts) {
4043
- const { timestamp, icon = "", tag = "", message, level, showTimestamp = true } = parts;
4044
- const stripAnsi = (str) => str.replace(this.ANSI_PATTERN, "");
4045
- if (!this.fancy) {
4046
- const components = [];
4047
- if (showTimestamp)
4048
- components.push(timestamp);
4049
- if (level === "warning")
4050
- components.push("WARN");
4051
- else if (level === "error")
4052
- components.push("ERROR");
4053
- else if (icon)
4054
- components.push(icon.replace(/[^\p{L}\p{N}\p{P}\p{Z}]/gu, ""));
4055
- if (tag)
4056
- components.push(tag.replace(/[[\]]/g, ""));
4057
- components.push(message);
4058
- return components.join(" ");
4059
- }
4060
- const terminalWidth = process11.stdout.columns || 120;
4061
- let mainPart = "";
4062
- if (level === "warning" || level === "error") {
4063
- mainPart = `${icon} ${message}`;
4064
- } else if (level === "info" || level === "success") {
4065
- mainPart = `${icon} ${tag} ${message}`;
4066
- } else {
4067
- mainPart = `${icon} ${tag} ${styles22.cyan(message)}`;
4068
- }
4069
- if (!showTimestamp) {
4070
- return mainPart.trim();
4071
- }
4072
- const visibleMainPartLength = stripAnsi(mainPart).trim().length;
4073
- const visibleTimestampLength = stripAnsi(timestamp).length;
4074
- const padding = Math.max(1, terminalWidth - 2 - visibleMainPartLength - visibleTimestampLength);
4075
- return `${mainPart.trim()}${" ".repeat(padding)}${timestamp}`;
4076
- }
4077
- formatMessage(message, args) {
4078
- if (args.length === 1 && Array.isArray(args[0])) {
4079
- return message.replace(/\{(\d+)\}/g, (match, index) => {
4080
- const position = Number.parseInt(index, 10);
4081
- return position < args[0].length ? String(args[0][position]) : match;
4082
- });
4083
- }
4084
- const formatRegex = /%([sdijfo%])/g;
4085
- let argIndex = 0;
4086
- let formattedMessage = message.replace(formatRegex, (match, type) => {
4087
- if (type === "%")
4088
- return "%";
4089
- if (argIndex >= args.length)
4090
- return match;
4091
- const arg = args[argIndex++];
4092
- switch (type) {
4093
- case "s":
4094
- return String(arg);
4095
- case "d":
4096
- case "i":
4097
- return Number(arg).toString();
4098
- case "j":
4099
- case "o":
4100
- return JSON.stringify(arg, null, 2);
4101
- default:
4102
- return match;
4103
- }
4104
- });
4105
- if (argIndex < args.length) {
4106
- formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
4107
- }
4108
- return formattedMessage;
4109
- }
4110
- async log(level, message, ...args) {
4111
- const timestamp = new Date;
4112
- const consoleTime = this.formatConsoleTimestamp(timestamp);
4113
- const fileTime = this.formatFileTimestamp(timestamp);
4114
- let formattedMessage;
4115
- let errorStack;
4116
- if (message instanceof Error) {
4117
- formattedMessage = message.message;
4118
- errorStack = message.stack;
4119
- } else {
4120
- formattedMessage = this.formatMessage(message, args);
4121
- }
4122
- if (this.fancy && !isBrowserProcess22()) {
4123
- const icon = levelIcons22[level];
4124
- const tag = this.options.showTags !== false && this.name ? styles22.gray(this.formatTag(this.name)) : "";
4125
- let consoleMessage;
4126
- switch (level) {
4127
- case "debug":
4128
- consoleMessage = this.formatConsoleMessage({
4129
- timestamp: consoleTime,
4130
- icon,
4131
- tag,
4132
- message: styles22.gray(formattedMessage),
4133
- level
4134
- });
4135
- console.error(consoleMessage);
4136
- break;
4137
- case "info":
4138
- consoleMessage = this.formatConsoleMessage({
4139
- timestamp: consoleTime,
4140
- icon,
4141
- tag,
4142
- message: formattedMessage,
4143
- level
4144
- });
4145
- console.error(consoleMessage);
4146
- break;
4147
- case "success":
4148
- consoleMessage = this.formatConsoleMessage({
4149
- timestamp: consoleTime,
4150
- icon,
4151
- tag,
4152
- message: styles22.green(formattedMessage),
4153
- level
4154
- });
4155
- console.error(consoleMessage);
4156
- break;
4157
- case "warning":
4158
- consoleMessage = this.formatConsoleMessage({
4159
- timestamp: consoleTime,
4160
- icon,
4161
- tag,
4162
- message: formattedMessage,
4163
- level
4164
- });
4165
- console.warn(consoleMessage);
4166
- break;
4167
- case "error":
4168
- consoleMessage = this.formatConsoleMessage({
4169
- timestamp: consoleTime,
4170
- icon,
4171
- tag,
4172
- message: formattedMessage,
4173
- level
4174
- });
4175
- console.error(consoleMessage);
4176
- if (errorStack) {
4177
- const stackLines = errorStack.split(`
4178
- `);
4179
- for (const line of stackLines) {
4180
- if (line.trim() && !line.includes(formattedMessage)) {
4181
- console.error(this.formatConsoleMessage({
4182
- timestamp: consoleTime,
4183
- message: styles22.gray(` ${line}`),
4184
- level,
4185
- showTimestamp: false
4186
- }));
4187
- }
4188
- }
4189
- }
4190
- break;
4191
- }
4192
- } else if (!isBrowserProcess22()) {
4193
- console.error(`${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}`);
4194
- if (errorStack) {
4195
- console.error(errorStack);
4196
- }
4197
- }
4198
- if (!this.shouldLog(level))
4199
- return;
4200
- let logEntry = `${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}
4201
- `;
4202
- if (errorStack) {
4203
- logEntry += `${errorStack}
4204
- `;
4205
- }
4206
- logEntry = logEntry.replace(this.ANSI_PATTERN, "");
4207
- await this.writeToFile(logEntry);
4208
- }
4209
- time(label) {
4210
- const start = performance.now();
4211
- if (this.fancy && !isBrowserProcess22()) {
4212
- const tag = this.options.showTags !== false && this.name ? styles22.gray(this.formatTag(this.name)) : "";
4213
- const consoleTime = this.formatConsoleTimestamp(new Date);
4214
- console.error(this.formatConsoleMessage({
4215
- timestamp: consoleTime,
4216
- icon: styles22.blue("◐"),
4217
- tag,
4218
- message: `${styles22.cyan(label)}...`
4219
- }));
4220
- }
4221
- return async (metadata) => {
4222
- if (!this.enabled)
4223
- return;
4224
- const end = performance.now();
4225
- const elapsed = Math.round(end - start);
4226
- const completionMessage = `${label} completed in ${elapsed}ms`;
4227
- const timestamp = new Date;
4228
- const consoleTime = this.formatConsoleTimestamp(timestamp);
4229
- const fileTime = this.formatFileTimestamp(timestamp);
4230
- let logEntry = `${fileTime} ${this.environment}.INFO: ${completionMessage}`;
4231
- if (metadata) {
4232
- logEntry += ` ${JSON.stringify(metadata)}`;
4233
- }
4234
- logEntry += `
4235
- `;
4236
- logEntry = logEntry.replace(this.ANSI_PATTERN, "");
4237
- if (this.fancy && !isBrowserProcess22()) {
4238
- const tag = this.options.showTags !== false && this.name ? styles22.gray(this.formatTag(this.name)) : "";
4239
- console.error(this.formatConsoleMessage({
4240
- timestamp: consoleTime,
4241
- icon: styles22.green("✓"),
4242
- tag,
4243
- message: `${completionMessage}${metadata ? ` ${JSON.stringify(metadata)}` : ""}`
4244
- }));
4245
- } else if (!isBrowserProcess22()) {
4246
- console.error(logEntry.trim());
4247
- }
4248
- await this.writeToFile(logEntry);
4249
- };
4250
- }
4251
- async debug(message, ...args) {
4252
- await this.log("debug", message, ...args);
4253
- }
4254
- async info(message, ...args) {
4255
- await this.log("info", message, ...args);
4256
- }
4257
- async success(message, ...args) {
4258
- await this.log("success", message, ...args);
4259
- }
4260
- async warn(message, ...args) {
4261
- await this.log("warning", message, ...args);
4262
- }
4263
- async error(message, ...args) {
4264
- await this.log("error", message, ...args);
4265
- }
4266
- validateEncryptionConfig() {
4267
- if (!this.config.rotation)
4268
- return false;
4269
- if (typeof this.config.rotation === "boolean")
4270
- return false;
4271
- const rotation = this.config.rotation;
4272
- const { encrypt } = rotation;
4273
- return !!encrypt;
4274
- }
4275
- async only(fn) {
4276
- if (!this.enabled)
4277
- return;
4278
- return await fn();
4279
- }
4280
- isEnabled() {
4281
- return this.enabled;
4282
- }
4283
- setEnabled(enabled) {
4284
- this.enabled = enabled;
4285
- }
4286
- extend(namespace) {
4287
- const childName = `${this.name}:${namespace}`;
4288
- const childLogger = new Logger22(childName, {
4289
- ...this.options,
4290
- logDirectory: this.config.logDirectory,
4291
- level: this.config.level,
4292
- format: this.config.format,
4293
- rotation: typeof this.config.rotation === "boolean" ? undefined : this.config.rotation,
4294
- timestamp: typeof this.config.timestamp === "boolean" ? undefined : this.config.timestamp
4295
- });
4296
- this.subLoggers.add(childLogger);
4297
- return childLogger;
4298
- }
4299
- createReadStream() {
4300
- if (isBrowserProcess22())
4301
- throw new Error("createReadStream is not supported in browser environments");
4302
- if (!existsSync42(this.currentLogFile))
4303
- throw new Error(`Log file does not exist: ${this.currentLogFile}`);
4304
- return createReadStream22(this.currentLogFile, { encoding: "utf8" });
4305
- }
4306
- async decrypt(data) {
4307
- if (!this.validateEncryptionConfig())
4308
- throw new Error("Encryption is not configured");
4309
- const encryptionConfig = this.config.rotation;
4310
- if (!encryptionConfig.encrypt || typeof encryptionConfig.encrypt === "boolean")
4311
- throw new Error("Invalid encryption configuration");
4312
- if (!this.currentKeyId || !this.keys.has(this.currentKeyId))
4313
- throw new Error("No valid encryption key available");
4314
- const key = this.keys.get(this.currentKeyId);
4315
- try {
4316
- const encryptedData = Buffer22.isBuffer(data) ? data : Buffer22.from(data, "base64");
4317
- const iv = encryptedData.slice(0, 16);
4318
- const authTag = encryptedData.slice(-16);
4319
- const ciphertext = encryptedData.slice(16, -16);
4320
- const decipher = createDecipheriv22("aes-256-gcm", key, iv);
4321
- decipher.setAuthTag(authTag);
4322
- const decrypted = Buffer22.concat([
4323
- decipher.update(ciphertext),
4324
- decipher.final()
4325
- ]);
4326
- return decrypted.toString("utf8");
4327
- } catch (err) {
4328
- throw new Error(`Decryption failed: ${err instanceof Error ? err.message : String(err)}`);
4329
- }
4330
- }
4331
- getLevel() {
4332
- return this.config.level;
4333
- }
4334
- getLogDirectory() {
4335
- return this.config.logDirectory;
4336
- }
4337
- getFormat() {
4338
- return this.config.format;
4339
- }
4340
- getRotationConfig() {
4341
- return this.config.rotation;
4342
- }
4343
- isBrowserMode() {
4344
- return isBrowserProcess22();
4345
- }
4346
- isServerMode() {
4347
- return !isBrowserProcess22();
4348
- }
4349
- setTestEncryptionKey(keyId, key) {
4350
- this.currentKeyId = keyId;
4351
- this.keys.set(keyId, key);
4352
- }
4353
- getTestCurrentKey() {
4354
- if (!this.currentKeyId || !this.keys.has(this.currentKeyId)) {
4355
- return null;
4356
- }
4357
- return {
4358
- id: this.currentKeyId,
4359
- key: this.keys.get(this.currentKeyId)
4360
- };
4361
- }
4362
- getConfig() {
4363
- return this.config;
4364
- }
4365
- async box(message) {
4366
- if (!this.enabled)
4367
- return;
4368
- const timestamp = new Date;
4369
- const consoleTime = this.formatConsoleTimestamp(timestamp);
4370
- const fileTime = this.formatFileTimestamp(timestamp);
4371
- if (this.fancy && !isBrowserProcess22()) {
4372
- const lines = message.split(`
4373
- `);
4374
- const width = Math.max(...lines.map((line) => line.length)) + 2;
4375
- const top = `┌${"─".repeat(width)}┐`;
4376
- const bottom = `└${"─".repeat(width)}┘`;
4377
- const boxedLines = lines.map((line) => {
4378
- const padding = " ".repeat(width - line.length - 2);
4379
- return `│ ${line}${padding} │`;
4380
- });
4381
- if (this.options.showTags !== false && this.name) {
4382
- console.error(this.formatConsoleMessage({
4383
- timestamp: consoleTime,
4384
- message: styles22.gray(this.formatTag(this.name)),
4385
- showTimestamp: false
4386
- }));
4387
- }
4388
- console.error(this.formatConsoleMessage({
4389
- timestamp: consoleTime,
4390
- message: styles22.cyan(top)
4391
- }));
4392
- boxedLines.forEach((line) => console.error(this.formatConsoleMessage({
4393
- timestamp: consoleTime,
4394
- message: styles22.cyan(line),
4395
- showTimestamp: false
4396
- })));
4397
- console.error(this.formatConsoleMessage({
4398
- timestamp: consoleTime,
4399
- message: styles22.cyan(bottom),
4400
- showTimestamp: false
4401
- }));
4402
- } else if (!isBrowserProcess22()) {
4403
- console.error(`${fileTime} ${this.environment}.INFO: [BOX] ${message}`);
4404
- }
4405
- const logEntry = `${fileTime} ${this.environment}.INFO: [BOX] ${message}
4406
- `.replace(this.ANSI_PATTERN, "");
4407
- await this.writeToFile(logEntry);
4408
- }
4409
- async prompt(message) {
4410
- if (isBrowserProcess22()) {
4411
- return Promise.resolve(true);
4412
- }
4413
- return new Promise((resolve52) => {
4414
- console.error(`${styles22.cyan("?")} ${message} (y/n) `);
4415
- const onData = (data) => {
4416
- const input = data.toString().trim().toLowerCase();
4417
- process11.stdin.removeListener("data", onData);
4418
- try {
4419
- if (typeof process11.stdin.setRawMode === "function") {
4420
- process11.stdin.setRawMode(false);
4421
- }
4422
- } catch {}
4423
- process11.stdin.pause();
4424
- console.error("");
4425
- resolve52(input === "y" || input === "yes");
4426
- };
4427
- try {
4428
- if (typeof process11.stdin.setRawMode === "function") {
4429
- process11.stdin.setRawMode(true);
4430
- }
4431
- } catch {}
4432
- process11.stdin.resume();
4433
- process11.stdin.once("data", onData);
4434
- });
4435
- }
4436
- setFancy(enabled) {
4437
- this.fancy = enabled;
4438
- }
4439
- isFancy() {
4440
- return this.fancy;
4441
- }
4442
- pause() {
4443
- this.enabled = false;
4444
- }
4445
- resume() {
4446
- this.enabled = true;
4447
- }
4448
- async start(message, ...args) {
4449
- if (!this.enabled)
4450
- return;
4451
- let formattedMessage = message;
4452
- if (args && args.length > 0) {
4453
- const formatRegex = /%([sdijfo%])/g;
4454
- let argIndex = 0;
4455
- formattedMessage = message.replace(formatRegex, (match, type) => {
4456
- if (type === "%")
4457
- return "%";
4458
- if (argIndex >= args.length)
4459
- return match;
4460
- const arg = args[argIndex++];
4461
- switch (type) {
4462
- case "s":
4463
- return String(arg);
4464
- case "d":
4465
- case "i":
4466
- return Number(arg).toString();
4467
- case "j":
4468
- case "o":
4469
- return JSON.stringify(arg, null, 2);
4470
- default:
4471
- return match;
4472
- }
4473
- });
4474
- if (argIndex < args.length) {
4475
- formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
4476
- }
4477
- }
4478
- if (this.fancy && !isBrowserProcess22()) {
4479
- const tag = this.options.showTags !== false && this.name ? styles22.gray(this.formatTag(this.name)) : "";
4480
- const spinnerChar = styles22.blue("◐");
4481
- console.error(`${spinnerChar} ${tag} ${styles22.cyan(formattedMessage)}`);
4482
- }
4483
- const timestamp = new Date;
4484
- const formattedDate = timestamp.toISOString();
4485
- const logEntry = `[${formattedDate}] ${this.environment}.INFO: [START] ${formattedMessage}
4486
- `.replace(this.ANSI_PATTERN, "");
4487
- await this.writeToFile(logEntry);
4488
- }
4489
- progress(total, initialMessage = "") {
4490
- if (!this.enabled || !this.fancy || isBrowserProcess22() || total <= 0) {
4491
- return {
4492
- update: () => {},
4493
- finish: () => {},
4494
- interrupt: () => {}
4495
- };
4496
- }
4497
- if (this.activeProgressBar) {
4498
- console.warn("Warning: Another progress bar is already active. Finishing the previous one.");
4499
- this.finishProgressBar(this.activeProgressBar, "[Auto-finished]");
4500
- }
4501
- const barLength = 20;
4502
- this.activeProgressBar = {
4503
- total,
4504
- current: 0,
4505
- message: initialMessage,
4506
- barLength,
4507
- lastRenderedLine: ""
4508
- };
4509
- this.renderProgressBar(this.activeProgressBar);
4510
- const update = (current, message) => {
4511
- if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess22())
4512
- return;
4513
- this.activeProgressBar.current = Math.max(0, Math.min(total, current));
4514
- if (message !== undefined) {
4515
- this.activeProgressBar.message = message;
4516
- }
4517
- const isFinished = this.activeProgressBar.current === this.activeProgressBar.total;
4518
- this.renderProgressBar(this.activeProgressBar, isFinished);
4519
- };
4520
- const finish = (message) => {
4521
- if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess22())
4522
- return;
4523
- this.activeProgressBar.current = this.activeProgressBar.total;
4524
- if (message !== undefined) {
4525
- this.activeProgressBar.message = message;
4526
- }
4527
- this.renderProgressBar(this.activeProgressBar, true);
4528
- this.finishProgressBar(this.activeProgressBar);
4529
- };
4530
- const interrupt = (interruptMessage, level = "info") => {
4531
- if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess22())
4532
- return;
4533
- process11.stdout.write(`${"\r".padEnd(process11.stdout.columns || 80)}\r`);
4534
- this.log(level, interruptMessage);
4535
- setTimeout(() => {
4536
- if (this.activeProgressBar) {
4537
- this.renderProgressBar(this.activeProgressBar);
4538
- }
4539
- }, 50);
4540
- };
4541
- return { update, finish, interrupt };
4542
- }
4543
- renderProgressBar(barState, isFinished = false) {
4544
- if (!this.enabled || !this.fancy || isBrowserProcess22() || !process11.stdout.isTTY)
4545
- return;
4546
- const percent = Math.min(100, Math.max(0, Math.round(barState.current / barState.total * 100)));
4547
- const filledLength = Math.round(barState.barLength * percent / 100);
4548
- const emptyLength = barState.barLength - filledLength;
4549
- const filledBar = styles22.green("━".repeat(filledLength));
4550
- const emptyBar = styles22.gray("━".repeat(emptyLength));
4551
- const bar = `[${filledBar}${emptyBar}]`;
4552
- const percentageText = `${percent}%`.padStart(4);
4553
- const messageText = barState.message ? ` ${barState.message}` : "";
4554
- const icon = isFinished || percent === 100 ? styles22.green("✓") : styles22.blue("▶");
4555
- const tag = this.options.showTags !== false && this.name ? ` ${styles22.gray(this.formatTag(this.name))}` : "";
4556
- const line = `\r${icon}${tag} ${bar} ${percentageText}${messageText}`;
4557
- const terminalWidth = process11.stdout.columns || 80;
4558
- const clearLine = " ".repeat(Math.max(0, terminalWidth - line.replace(this.ANSI_PATTERN, "").length));
4559
- barState.lastRenderedLine = `${line}${clearLine}`;
4560
- process11.stdout.write(barState.lastRenderedLine);
4561
- if (isFinished) {
4562
- process11.stdout.write(`
4563
- `);
4564
- }
4565
- }
4566
- finishProgressBar(barState, finalMessage) {
4567
- if (!this.enabled || !this.fancy || isBrowserProcess22() || !process11.stdout.isTTY) {
4568
- this.activeProgressBar = null;
4569
- return;
4570
- }
4571
- if (barState.current < barState.total) {
4572
- barState.current = barState.total;
4573
- }
4574
- if (finalMessage)
4575
- barState.message = finalMessage;
4576
- this.renderProgressBar(barState, true);
4577
- this.activeProgressBar = null;
4578
- }
4579
- async clear(filters = {}) {
4580
- if (isBrowserProcess22()) {
4581
- console.warn("Log clearing is not supported in browser environments.");
4582
- return;
4583
- }
4584
- try {
4585
- console.warn("Clearing logs...", this.config.logDirectory);
4586
- const files = await readdir22(this.config.logDirectory);
4587
- const logFilesToDelete = [];
4588
- for (const file of files) {
4589
- const nameMatches = filters.name ? new RegExp(filters.name.replace("*", ".*")).test(file) : file.startsWith(this.name);
4590
- if (!nameMatches || !file.endsWith(".log")) {
4591
- continue;
4592
- }
4593
- const filePath = join5(this.config.logDirectory, file);
4594
- if (filters.before) {
4595
- try {
4596
- const fileStats = await stat22(filePath);
4597
- if (fileStats.mtime >= filters.before) {
4598
- continue;
4599
- }
4600
- } catch (statErr) {
4601
- console.error(`Failed to get stats for file ${filePath}:`, statErr);
4602
- continue;
4603
- }
4604
- }
4605
- logFilesToDelete.push(filePath);
4606
- }
4607
- if (logFilesToDelete.length === 0) {
4608
- console.warn("No log files matched the criteria for clearing.");
4609
- return;
4610
- }
4611
- console.warn(`Preparing to delete ${logFilesToDelete.length} log file(s)...`);
4612
- for (const filePath of logFilesToDelete) {
4613
- try {
4614
- await unlink22(filePath);
4615
- console.warn(`Deleted log file: ${filePath}`);
4616
- } catch (unlinkErr) {
4617
- console.error(`Failed to delete log file ${filePath}:`, unlinkErr);
4618
- }
4619
- }
4620
- console.warn("Log clearing process finished.");
4621
- } catch (err) {
4622
- console.error("Error during log clearing process:", err);
4623
- }
4624
- }
4625
- }
4626
- var logger22 = new Logger22("stacks");
4627
1699
 
4628
1700
  // src/git-hooks.ts
4629
1701
  var execAsync = promisify(exec);
4630
- var log3 = new Logger22("git-hooks", {
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 = process12.cwd()) {
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 = process12.cwd()) {
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,18 +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 = process12.cwd(), options) {
4750
- if (!config3 || Object.keys(config3).length === 0)
1821
+ function setHooksFromConfig(projectRootPath = process6.cwd(), options) {
1822
+ if (!config2 || Object.keys(config2).length === 0)
4751
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");
4752
- const configFile = options?.configFile || { ...config3 };
1824
+ const configFile = options?.configFile || { ...config2 };
4753
1825
  _validateStagedLintConfig(configFile);
4754
1826
  const hookKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key));
4755
1827
  const isValidConfig = hookKeys.every((key) => VALID_GIT_HOOKS.includes(key));
4756
1828
  if (!isValidConfig)
4757
1829
  throw new Error("[ERROR] Config was not in correct format. Please check git hooks or options name");
4758
1830
  const preserveUnused = Array.isArray(configFile.preserveUnused) ? configFile.preserveUnused : configFile.preserveUnused ? VALID_GIT_HOOKS : [];
4759
- const logKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key)).sort().map((key) => italic22(key)).join(", ");
4760
- log3.debug(`Hook Keys: ${logKeys}`);
1831
+ const logKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key)).sort().map((key) => italic(key)).join(", ");
1832
+ log.debug(`Hook Keys: ${logKeys}`);
4761
1833
  for (const hook of VALID_GIT_HOOKS) {
4762
1834
  if (Object.prototype.hasOwnProperty.call(configFile, hook)) {
4763
1835
  if (!configFile[hook])
@@ -4768,48 +1840,85 @@ function setHooksFromConfig(projectRootPath = process12.cwd(), options) {
4768
1840
  }
4769
1841
  }
4770
1842
  }
4771
- async function getStagedFiles(projectRoot = process12.cwd()) {
1843
+ async function getStagedFiles(projectRoot = process6.cwd()) {
4772
1844
  try {
4773
- const { stdout } = await execAsync("git diff --staged --name-only --diff-filter=ACMR", { cwd: projectRoot });
4774
- return stdout.trim().split(`
1845
+ const { stdout } = await execAsync("git diff --cached --name-only --diff-filter=ACMR", { cwd: projectRoot });
1846
+ const files = stdout.trim().split(`
4775
1847
  `).filter(Boolean);
1848
+ if (config2.verbose && files.length > 0) {
1849
+ console.info("[INFO] Staged files found:", files);
1850
+ }
1851
+ return files;
4776
1852
  } catch (error) {
4777
1853
  console.error("[ERROR] Failed to get staged files:", error);
4778
1854
  return [];
4779
1855
  }
4780
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
+ }
4781
1875
  function matchesGlob(file, pattern) {
4782
- if (pattern.includes("*")) {
4783
- const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
4784
- const regex = new RegExp(`^${regexPattern}$`);
4785
- return regex.test(file);
1876
+ if (pattern.startsWith("!")) {
1877
+ return !matchesGlob(file, pattern.slice(1));
4786
1878
  }
4787
- return file === pattern;
1879
+ const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "(?:.*?)").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
1880
+ const regex = new RegExp(`^${regexPattern}$`);
1881
+ return regex.test(file);
4788
1882
  }
4789
1883
  function filterFilesByPattern(files, pattern) {
4790
- return files.filter((file) => matchesGlob(file, pattern));
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
+ });
4791
1892
  }
4792
- async function runCommandOnStagedFiles(command, files, projectRoot = process12.cwd(), verbose = false) {
1893
+ async function runCommandOnStagedFiles(command, files, projectRoot = process6.cwd(), verbose = false) {
4793
1894
  if (files.length === 0) {
4794
1895
  if (verbose)
4795
1896
  console.info("[INFO] No matching files for pattern");
4796
1897
  return true;
4797
1898
  }
4798
1899
  const commands = Array.isArray(command) ? command : [command];
1900
+ const fileList = files.join(" ");
4799
1901
  for (const cmd of commands) {
4800
1902
  try {
4801
- const fullCommand = `${cmd} ${files.join(" ")}`;
4802
- if (verbose)
4803
- console.info(`[INFO] Running: ${fullCommand}`);
4804
- const { stdout, stderr } = await execAsync(fullCommand, { cwd: projectRoot });
1903
+ const fullCommand = `${cmd} ${fileList}`;
4805
1904
  if (verbose) {
4806
- if (stdout)
4807
- console.info(stdout);
4808
- if (stderr)
4809
- console.error(stderr);
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;
4810
1915
  }
4811
1916
  } catch (error) {
4812
- console.error(`[ERROR] Command failed: ${cmd}`, error);
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}`);
4813
1922
  return false;
4814
1923
  }
4815
1924
  }
@@ -4833,7 +1942,7 @@ async function processStagedLint(stagedLintConfig, projectRoot, verbose = false)
4833
1942
  }
4834
1943
  return success;
4835
1944
  }
4836
- function _setHook(hook, commandOrConfig, projectRoot = process12.cwd()) {
1945
+ function _setHook(hook, commandOrConfig, projectRoot = process6.cwd()) {
4837
1946
  const gitRoot = getGitProjectRoot(projectRoot);
4838
1947
  if (!gitRoot) {
4839
1948
  console.info("[INFO] No `.git` root folder found, skipping");
@@ -4854,26 +1963,26 @@ function _setHook(hook, commandOrConfig, projectRoot = process12.cwd()) {
4854
1963
  fs.mkdirSync(hookDirectory, { recursive: true });
4855
1964
  }
4856
1965
  const addOrModify = fs.existsSync(hookPath) ? "Modify" : "Add";
4857
- log3.debug(`${addOrModify} ${italic22(hook)} hook`);
1966
+ log.debug(`${addOrModify} ${italic(hook)} hook`);
4858
1967
  fs.writeFileSync(hookPath, hookCommand, { mode: 493 });
4859
1968
  }
4860
- function removeHooks(projectRoot = process12.cwd(), verbose = false) {
1969
+ function removeHooks(projectRoot = process6.cwd(), verbose = false) {
4861
1970
  for (const configEntry of VALID_GIT_HOOKS)
4862
1971
  _removeHook(configEntry, projectRoot, verbose);
4863
1972
  }
4864
- function _removeHook(hook, projectRoot = process12.cwd(), verbose = false) {
1973
+ function _removeHook(hook, projectRoot = process6.cwd(), verbose = false) {
4865
1974
  const gitRoot = getGitProjectRoot(projectRoot);
4866
1975
  const hookPath = path.normalize(`${gitRoot}/hooks/${hook}`);
4867
1976
  if (fs.existsSync(hookPath)) {
4868
- log3.debug(`Hook ${hook} is not set, removing!`);
1977
+ log.debug(`Hook ${hook} is not set, removing!`);
4869
1978
  fs.unlinkSync(hookPath);
4870
1979
  }
4871
1980
  if (verbose)
4872
- log3.success(`Successfully removed the ${hook} hook`);
1981
+ log.success(`Successfully removed the ${hook} hook`);
4873
1982
  }
4874
1983
  async function runStagedLint(hook) {
4875
- const projectRoot = process12.cwd();
4876
- const configFile = config3;
1984
+ const projectRoot = process6.cwd();
1985
+ const configFile = config2;
4877
1986
  if (!configFile) {
4878
1987
  console.error(`[ERROR] No configuration found`);
4879
1988
  return false;
@@ -4893,10 +2002,10 @@ async function runStagedLint(hook) {
4893
2002
  console.error(`[ERROR] No staged lint configuration found for hook ${hook}`);
4894
2003
  return false;
4895
2004
  }
4896
- function _validateStagedLintConfig(config5) {
2005
+ function _validateStagedLintConfig(config4) {
4897
2006
  for (const hook of VALID_GIT_HOOKS) {
4898
- if (hook !== "pre-commit" && config5[hook] && typeof config5[hook] === "object") {
4899
- const hookConfig = config5[hook];
2007
+ if (hook !== "pre-commit" && config4[hook] && typeof config4[hook] === "object") {
2008
+ const hookConfig = config4[hook];
4900
2009
  if (hookConfig["stagedLint"] || hookConfig["staged-lint"]) {
4901
2010
  throw new Error(`staged-lint is only allowed in pre-commit hook. Found in ${hook} hook.`);
4902
2011
  }
@@ -4909,7 +2018,7 @@ export {
4909
2018
  removeHooks,
4910
2019
  getProjectRootDirectoryFromNodeModules,
4911
2020
  getGitProjectRoot,
4912
- config3 as config,
2021
+ config2 as config,
4913
2022
  checkBunGitHooksInDependencies,
4914
2023
  VALID_OPTIONS,
4915
2024
  VALID_GIT_HOOKS,