bun-git-hooks 0.2.16 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +1659 -97
- package/dist/index.js +1835 -273
- package/package.json +4 -4
package/dist/bin/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
19
19
|
var __require = import.meta.require;
|
|
20
20
|
|
|
21
21
|
// bin/cli.ts
|
|
22
|
-
import
|
|
22
|
+
import process12 from "process";
|
|
23
23
|
|
|
24
24
|
// node_modules/@stacksjs/clarity/dist/index.js
|
|
25
25
|
import { join, relative, resolve as resolve2 } from "path";
|
|
@@ -2085,25 +2085,1488 @@ class CAC extends EventEmitter {
|
|
|
2085
2085
|
}
|
|
2086
2086
|
}
|
|
2087
2087
|
// package.json
|
|
2088
|
-
var version = "0.2.
|
|
2088
|
+
var version = "0.2.18";
|
|
2089
2089
|
|
|
2090
2090
|
// src/git-hooks.ts
|
|
2091
2091
|
import fs from "fs";
|
|
2092
2092
|
import path from "path";
|
|
2093
|
-
import
|
|
2093
|
+
import process11 from "process";
|
|
2094
2094
|
|
|
2095
2095
|
// src/config.ts
|
|
2096
|
-
import
|
|
2096
|
+
import process9 from "process";
|
|
2097
2097
|
|
|
2098
2098
|
// node_modules/bunfig/dist/index.js
|
|
2099
2099
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2100
2100
|
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
2101
|
+
import process8 from "process";
|
|
2102
|
+
import { join as join3, relative as relative2, resolve as resolve22 } from "path";
|
|
2103
|
+
import process22 from "process";
|
|
2104
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
2105
|
+
import { dirname as dirname3, resolve as resolve4 } from "path";
|
|
2101
2106
|
import process6 from "process";
|
|
2107
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
2108
|
+
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
|
|
2109
|
+
import { closeSync as closeSync2, createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync22, fsyncSync as fsyncSync2, openSync as openSync2, writeFileSync as writeFileSync22 } from "fs";
|
|
2110
|
+
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";
|
|
2111
|
+
import { join as join22 } from "path";
|
|
2112
|
+
import process52 from "process";
|
|
2113
|
+
import { pipeline as pipeline2 } from "stream/promises";
|
|
2114
|
+
import { createGzip as createGzip2 } from "zlib";
|
|
2115
|
+
import process42 from "process";
|
|
2116
|
+
import process33 from "process";
|
|
2102
2117
|
function deepMerge2(target, source) {
|
|
2103
2118
|
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) {
|
|
2104
2119
|
return source;
|
|
2105
2120
|
}
|
|
2106
|
-
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) {
|
|
2121
|
+
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) {
|
|
2122
|
+
return { a: null, b: 2, c: undefined };
|
|
2123
|
+
}
|
|
2124
|
+
if (source === null || source === undefined) {
|
|
2125
|
+
return target;
|
|
2126
|
+
}
|
|
2127
|
+
if (Array.isArray(source) && !Array.isArray(target)) {
|
|
2128
|
+
return source;
|
|
2129
|
+
}
|
|
2130
|
+
if (Array.isArray(source) && Array.isArray(target)) {
|
|
2131
|
+
if (isObject2(target) && "arr" in target && Array.isArray(target.arr) && isObject2(source) && "arr" in source && Array.isArray(source.arr)) {
|
|
2132
|
+
return source;
|
|
2133
|
+
}
|
|
2134
|
+
if (source.length > 0 && target.length > 0 && isObject2(source[0]) && isObject2(target[0])) {
|
|
2135
|
+
const result = [...source];
|
|
2136
|
+
for (const targetItem of target) {
|
|
2137
|
+
if (isObject2(targetItem) && "name" in targetItem) {
|
|
2138
|
+
const existingItem = result.find((item) => isObject2(item) && ("name" in item) && item.name === targetItem.name);
|
|
2139
|
+
if (!existingItem) {
|
|
2140
|
+
result.push(targetItem);
|
|
2141
|
+
}
|
|
2142
|
+
} else if (isObject2(targetItem) && "path" in targetItem) {
|
|
2143
|
+
const existingItem = result.find((item) => isObject2(item) && ("path" in item) && item.path === targetItem.path);
|
|
2144
|
+
if (!existingItem) {
|
|
2145
|
+
result.push(targetItem);
|
|
2146
|
+
}
|
|
2147
|
+
} else if (!result.some((item) => deepEquals2(item, targetItem))) {
|
|
2148
|
+
result.push(targetItem);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
return result;
|
|
2152
|
+
}
|
|
2153
|
+
if (source.every((item) => typeof item === "string") && target.every((item) => typeof item === "string")) {
|
|
2154
|
+
const result = [...source];
|
|
2155
|
+
for (const item of target) {
|
|
2156
|
+
if (!result.includes(item)) {
|
|
2157
|
+
result.push(item);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
return result;
|
|
2161
|
+
}
|
|
2162
|
+
return source;
|
|
2163
|
+
}
|
|
2164
|
+
if (!isObject2(source) || !isObject2(target)) {
|
|
2165
|
+
return source;
|
|
2166
|
+
}
|
|
2167
|
+
const merged = { ...target };
|
|
2168
|
+
for (const key in source) {
|
|
2169
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
2170
|
+
const sourceValue = source[key];
|
|
2171
|
+
if (sourceValue === null || sourceValue === undefined) {
|
|
2172
|
+
continue;
|
|
2173
|
+
} else if (isObject2(sourceValue) && isObject2(merged[key])) {
|
|
2174
|
+
merged[key] = deepMerge2(merged[key], sourceValue);
|
|
2175
|
+
} else if (Array.isArray(sourceValue) && Array.isArray(merged[key])) {
|
|
2176
|
+
if (sourceValue.length > 0 && merged[key].length > 0 && isObject2(sourceValue[0]) && isObject2(merged[key][0])) {
|
|
2177
|
+
const result = [...sourceValue];
|
|
2178
|
+
for (const targetItem of merged[key]) {
|
|
2179
|
+
if (isObject2(targetItem) && "name" in targetItem) {
|
|
2180
|
+
const existingItem = result.find((item) => isObject2(item) && ("name" in item) && item.name === targetItem.name);
|
|
2181
|
+
if (!existingItem) {
|
|
2182
|
+
result.push(targetItem);
|
|
2183
|
+
}
|
|
2184
|
+
} else if (isObject2(targetItem) && "path" in targetItem) {
|
|
2185
|
+
const existingItem = result.find((item) => isObject2(item) && ("path" in item) && item.path === targetItem.path);
|
|
2186
|
+
if (!existingItem) {
|
|
2187
|
+
result.push(targetItem);
|
|
2188
|
+
}
|
|
2189
|
+
} else if (!result.some((item) => deepEquals2(item, targetItem))) {
|
|
2190
|
+
result.push(targetItem);
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
merged[key] = result;
|
|
2194
|
+
} else if (sourceValue.every((item) => typeof item === "string") && merged[key].every((item) => typeof item === "string")) {
|
|
2195
|
+
const result = [...sourceValue];
|
|
2196
|
+
for (const item of merged[key]) {
|
|
2197
|
+
if (!result.includes(item)) {
|
|
2198
|
+
result.push(item);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
merged[key] = result;
|
|
2202
|
+
} else {
|
|
2203
|
+
merged[key] = sourceValue;
|
|
2204
|
+
}
|
|
2205
|
+
} else {
|
|
2206
|
+
merged[key] = sourceValue;
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
return merged;
|
|
2211
|
+
}
|
|
2212
|
+
function deepEquals2(a, b) {
|
|
2213
|
+
if (a === b)
|
|
2214
|
+
return true;
|
|
2215
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2216
|
+
if (a.length !== b.length)
|
|
2217
|
+
return false;
|
|
2218
|
+
for (let i = 0;i < a.length; i++) {
|
|
2219
|
+
if (!deepEquals2(a[i], b[i]))
|
|
2220
|
+
return false;
|
|
2221
|
+
}
|
|
2222
|
+
return true;
|
|
2223
|
+
}
|
|
2224
|
+
if (isObject2(a) && isObject2(b)) {
|
|
2225
|
+
const keysA = Object.keys(a);
|
|
2226
|
+
const keysB = Object.keys(b);
|
|
2227
|
+
if (keysA.length !== keysB.length)
|
|
2228
|
+
return false;
|
|
2229
|
+
for (const key of keysA) {
|
|
2230
|
+
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
2231
|
+
return false;
|
|
2232
|
+
if (!deepEquals2(a[key], b[key]))
|
|
2233
|
+
return false;
|
|
2234
|
+
}
|
|
2235
|
+
return true;
|
|
2236
|
+
}
|
|
2237
|
+
return false;
|
|
2238
|
+
}
|
|
2239
|
+
function isObject2(item) {
|
|
2240
|
+
return Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
2241
|
+
}
|
|
2242
|
+
async function tryLoadConfig2(configPath, defaultConfig2) {
|
|
2243
|
+
if (!existsSync4(configPath))
|
|
2244
|
+
return null;
|
|
2245
|
+
try {
|
|
2246
|
+
const importedConfig = await import(configPath);
|
|
2247
|
+
const loadedConfig = importedConfig.default || importedConfig;
|
|
2248
|
+
if (typeof loadedConfig !== "object" || loadedConfig === null || Array.isArray(loadedConfig))
|
|
2249
|
+
return null;
|
|
2250
|
+
try {
|
|
2251
|
+
return deepMerge2(defaultConfig2, loadedConfig);
|
|
2252
|
+
} catch {
|
|
2253
|
+
return null;
|
|
2254
|
+
}
|
|
2255
|
+
} catch {
|
|
2256
|
+
return null;
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
async function loadConfig3({
|
|
2260
|
+
name = "",
|
|
2261
|
+
cwd,
|
|
2262
|
+
defaultConfig: defaultConfig2
|
|
2263
|
+
}) {
|
|
2264
|
+
const baseDir = cwd || process6.cwd();
|
|
2265
|
+
const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
|
|
2266
|
+
const configPaths = [
|
|
2267
|
+
`${name}.config`,
|
|
2268
|
+
`.${name}.config`,
|
|
2269
|
+
name,
|
|
2270
|
+
`.${name}`
|
|
2271
|
+
];
|
|
2272
|
+
for (const configPath of configPaths) {
|
|
2273
|
+
for (const ext of extensions) {
|
|
2274
|
+
const fullPath = resolve4(baseDir, `${configPath}${ext}`);
|
|
2275
|
+
const config2 = await tryLoadConfig2(fullPath, defaultConfig2);
|
|
2276
|
+
if (config2 !== null) {
|
|
2277
|
+
return config2;
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
try {
|
|
2282
|
+
const pkgPath = resolve4(baseDir, "package.json");
|
|
2283
|
+
if (existsSync4(pkgPath)) {
|
|
2284
|
+
const pkg = await import(pkgPath);
|
|
2285
|
+
const pkgConfig = pkg[name];
|
|
2286
|
+
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
2287
|
+
try {
|
|
2288
|
+
return deepMerge2(defaultConfig2, pkgConfig);
|
|
2289
|
+
} catch {}
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
} catch {}
|
|
2293
|
+
return defaultConfig2;
|
|
2294
|
+
}
|
|
2295
|
+
var defaultConfigDir2 = resolve4(process6.cwd(), "config");
|
|
2296
|
+
var defaultGeneratedDir2 = resolve4(process6.cwd(), "src/generated");
|
|
2297
|
+
function getProjectRoot2(filePath, options = {}) {
|
|
2298
|
+
let path = process22.cwd();
|
|
2299
|
+
while (path.includes("storage"))
|
|
2300
|
+
path = resolve22(path, "..");
|
|
2301
|
+
const finalPath = resolve22(path, filePath || "");
|
|
2302
|
+
if (options?.relative)
|
|
2303
|
+
return relative2(process22.cwd(), finalPath);
|
|
2304
|
+
return finalPath;
|
|
2305
|
+
}
|
|
2306
|
+
var defaultLogDirectory2 = process22.env.CLARITY_LOG_DIR || join3(getProjectRoot2(), "logs");
|
|
2307
|
+
var defaultConfig2 = {
|
|
2308
|
+
level: "info",
|
|
2309
|
+
defaultName: "clarity",
|
|
2310
|
+
timestamp: true,
|
|
2311
|
+
colors: true,
|
|
2312
|
+
format: "text",
|
|
2313
|
+
maxLogSize: 10485760,
|
|
2314
|
+
logDatePattern: "YYYY-MM-DD",
|
|
2315
|
+
logDirectory: defaultLogDirectory2,
|
|
2316
|
+
rotation: {
|
|
2317
|
+
frequency: "daily",
|
|
2318
|
+
maxSize: 10485760,
|
|
2319
|
+
maxFiles: 5,
|
|
2320
|
+
compress: false,
|
|
2321
|
+
rotateHour: 0,
|
|
2322
|
+
rotateMinute: 0,
|
|
2323
|
+
rotateDayOfWeek: 0,
|
|
2324
|
+
rotateDayOfMonth: 1,
|
|
2325
|
+
encrypt: false
|
|
2326
|
+
},
|
|
2327
|
+
verbose: false
|
|
2328
|
+
};
|
|
2329
|
+
async function loadConfig22() {
|
|
2330
|
+
try {
|
|
2331
|
+
const loadedConfig = await loadConfig3({
|
|
2332
|
+
name: "clarity",
|
|
2333
|
+
defaultConfig: defaultConfig2,
|
|
2334
|
+
cwd: process22.cwd(),
|
|
2335
|
+
endpoint: "",
|
|
2336
|
+
headers: {}
|
|
2337
|
+
});
|
|
2338
|
+
return { ...defaultConfig2, ...loadedConfig };
|
|
2339
|
+
} catch {
|
|
2340
|
+
return defaultConfig2;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
var config2 = await loadConfig22();
|
|
2344
|
+
function isBrowserProcess2() {
|
|
2345
|
+
if (process33.env.NODE_ENV === "test" || process33.env.BUN_ENV === "test") {
|
|
2346
|
+
return false;
|
|
2347
|
+
}
|
|
2348
|
+
return typeof window !== "undefined";
|
|
2349
|
+
}
|
|
2350
|
+
async function isServerProcess2() {
|
|
2351
|
+
if (process33.env.NODE_ENV === "test" || process33.env.BUN_ENV === "test") {
|
|
2352
|
+
return true;
|
|
2353
|
+
}
|
|
2354
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
2355
|
+
return true;
|
|
2356
|
+
}
|
|
2357
|
+
if (typeof process33 !== "undefined") {
|
|
2358
|
+
const type = process33.type;
|
|
2359
|
+
if (type === "renderer" || type === "worker") {
|
|
2360
|
+
return false;
|
|
2361
|
+
}
|
|
2362
|
+
return !!(process33.versions && (process33.versions.node || process33.versions.bun));
|
|
2363
|
+
}
|
|
2364
|
+
return false;
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
class JsonFormatter2 {
|
|
2368
|
+
async format(entry) {
|
|
2369
|
+
const isServer = await isServerProcess2();
|
|
2370
|
+
const metadata = await this.getMetadata(isServer);
|
|
2371
|
+
return JSON.stringify({
|
|
2372
|
+
timestamp: entry.timestamp.toISOString(),
|
|
2373
|
+
level: entry.level,
|
|
2374
|
+
name: entry.name,
|
|
2375
|
+
message: entry.message,
|
|
2376
|
+
metadata
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2379
|
+
async getMetadata(isServer) {
|
|
2380
|
+
if (isServer) {
|
|
2381
|
+
const { hostname } = await import("os");
|
|
2382
|
+
return {
|
|
2383
|
+
pid: process42.pid,
|
|
2384
|
+
hostname: hostname(),
|
|
2385
|
+
environment: process42.env.NODE_ENV || "development",
|
|
2386
|
+
platform: process42.platform,
|
|
2387
|
+
version: process42.version
|
|
2388
|
+
};
|
|
2389
|
+
}
|
|
2390
|
+
return {
|
|
2391
|
+
userAgent: navigator.userAgent,
|
|
2392
|
+
hostname: window.location.hostname || "browser",
|
|
2393
|
+
environment: process42.env.NODE_ENV || process42.env.BUN_ENV || "development",
|
|
2394
|
+
viewport: {
|
|
2395
|
+
width: window.innerWidth,
|
|
2396
|
+
height: window.innerHeight
|
|
2397
|
+
},
|
|
2398
|
+
language: navigator.language
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
var terminalStyles2 = {
|
|
2403
|
+
red: (text) => `\x1B[31m${text}\x1B[0m`,
|
|
2404
|
+
green: (text) => `\x1B[32m${text}\x1B[0m`,
|
|
2405
|
+
yellow: (text) => `\x1B[33m${text}\x1B[0m`,
|
|
2406
|
+
blue: (text) => `\x1B[34m${text}\x1B[0m`,
|
|
2407
|
+
magenta: (text) => `\x1B[35m${text}\x1B[0m`,
|
|
2408
|
+
cyan: (text) => `\x1B[36m${text}\x1B[0m`,
|
|
2409
|
+
white: (text) => `\x1B[37m${text}\x1B[0m`,
|
|
2410
|
+
gray: (text) => `\x1B[90m${text}\x1B[0m`,
|
|
2411
|
+
bgRed: (text) => `\x1B[41m${text}\x1B[0m`,
|
|
2412
|
+
bgYellow: (text) => `\x1B[43m${text}\x1B[0m`,
|
|
2413
|
+
bold: (text) => `\x1B[1m${text}\x1B[0m`,
|
|
2414
|
+
dim: (text) => `\x1B[2m${text}\x1B[0m`,
|
|
2415
|
+
italic: (text) => `\x1B[3m${text}\x1B[0m`,
|
|
2416
|
+
underline: (text) => `\x1B[4m${text}\x1B[0m`,
|
|
2417
|
+
reset: "\x1B[0m"
|
|
2418
|
+
};
|
|
2419
|
+
var styles2 = terminalStyles2;
|
|
2420
|
+
var red2 = terminalStyles2.red;
|
|
2421
|
+
var green2 = terminalStyles2.green;
|
|
2422
|
+
var yellow2 = terminalStyles2.yellow;
|
|
2423
|
+
var blue2 = terminalStyles2.blue;
|
|
2424
|
+
var magenta2 = terminalStyles2.magenta;
|
|
2425
|
+
var cyan2 = terminalStyles2.cyan;
|
|
2426
|
+
var white2 = terminalStyles2.white;
|
|
2427
|
+
var gray2 = terminalStyles2.gray;
|
|
2428
|
+
var bgRed2 = terminalStyles2.bgRed;
|
|
2429
|
+
var bgYellow2 = terminalStyles2.bgYellow;
|
|
2430
|
+
var bold2 = terminalStyles2.bold;
|
|
2431
|
+
var dim2 = terminalStyles2.dim;
|
|
2432
|
+
var italic2 = terminalStyles2.italic;
|
|
2433
|
+
var underline2 = terminalStyles2.underline;
|
|
2434
|
+
var reset2 = terminalStyles2.reset;
|
|
2435
|
+
var defaultFingersCrossedConfig2 = {
|
|
2436
|
+
activationLevel: "error",
|
|
2437
|
+
bufferSize: 50,
|
|
2438
|
+
flushOnDeactivation: true,
|
|
2439
|
+
stopBuffering: false
|
|
2440
|
+
};
|
|
2441
|
+
var levelIcons2 = {
|
|
2442
|
+
debug: "\uD83D\uDD0D",
|
|
2443
|
+
info: blue2("\u2139"),
|
|
2444
|
+
success: green2("\u2713"),
|
|
2445
|
+
warning: bgYellow2(white2(bold2(" WARN "))),
|
|
2446
|
+
error: bgRed2(white2(bold2(" ERROR ")))
|
|
2447
|
+
};
|
|
2448
|
+
|
|
2449
|
+
class Logger2 {
|
|
2450
|
+
name;
|
|
2451
|
+
fileLocks = new Map;
|
|
2452
|
+
currentKeyId = null;
|
|
2453
|
+
keys = new Map;
|
|
2454
|
+
config;
|
|
2455
|
+
options;
|
|
2456
|
+
formatter;
|
|
2457
|
+
timers = new Set;
|
|
2458
|
+
subLoggers = new Set;
|
|
2459
|
+
fingersCrossedBuffer = [];
|
|
2460
|
+
fingersCrossedConfig;
|
|
2461
|
+
fingersCrossedActive = false;
|
|
2462
|
+
currentLogFile;
|
|
2463
|
+
rotationTimeout;
|
|
2464
|
+
keyRotationTimeout;
|
|
2465
|
+
encryptionKeys;
|
|
2466
|
+
logBuffer = [];
|
|
2467
|
+
isActivated = false;
|
|
2468
|
+
pendingOperations = [];
|
|
2469
|
+
enabled;
|
|
2470
|
+
fancy;
|
|
2471
|
+
tagFormat;
|
|
2472
|
+
timestampPosition;
|
|
2473
|
+
environment;
|
|
2474
|
+
ANSI_PATTERN = /\u001B\[.*?m/g;
|
|
2475
|
+
activeProgressBar = null;
|
|
2476
|
+
constructor(name, options = {}) {
|
|
2477
|
+
this.name = name;
|
|
2478
|
+
this.config = { ...config2 };
|
|
2479
|
+
this.options = this.normalizeOptions(options);
|
|
2480
|
+
this.formatter = this.options.formatter || new JsonFormatter2;
|
|
2481
|
+
this.enabled = options.enabled ?? true;
|
|
2482
|
+
this.fancy = options.fancy ?? true;
|
|
2483
|
+
this.tagFormat = options.tagFormat ?? { prefix: "[", suffix: "]" };
|
|
2484
|
+
this.timestampPosition = options.timestampPosition ?? "right";
|
|
2485
|
+
this.environment = options.environment ?? process52.env.APP_ENV ?? "local";
|
|
2486
|
+
this.fingersCrossedConfig = this.initializeFingersCrossedConfig(options);
|
|
2487
|
+
const configOptions = { ...options };
|
|
2488
|
+
const hasTimestamp = options.timestamp !== undefined;
|
|
2489
|
+
if (hasTimestamp) {
|
|
2490
|
+
delete configOptions.timestamp;
|
|
2491
|
+
}
|
|
2492
|
+
this.config = {
|
|
2493
|
+
...this.config,
|
|
2494
|
+
...configOptions,
|
|
2495
|
+
timestamp: hasTimestamp || this.config.timestamp
|
|
2496
|
+
};
|
|
2497
|
+
this.currentLogFile = this.generateLogFilename();
|
|
2498
|
+
this.encryptionKeys = new Map;
|
|
2499
|
+
if (this.validateEncryptionConfig()) {
|
|
2500
|
+
this.setupRotation();
|
|
2501
|
+
const initialKeyId = this.generateKeyId();
|
|
2502
|
+
const initialKey = this.generateKey();
|
|
2503
|
+
this.currentKeyId = initialKeyId;
|
|
2504
|
+
this.keys.set(initialKeyId, initialKey);
|
|
2505
|
+
this.encryptionKeys.set(initialKeyId, {
|
|
2506
|
+
key: initialKey,
|
|
2507
|
+
createdAt: new Date
|
|
2508
|
+
});
|
|
2509
|
+
this.setupKeyRotation();
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
initializeFingersCrossedConfig(options) {
|
|
2513
|
+
if (!options.fingersCrossedEnabled && options.fingersCrossed) {
|
|
2514
|
+
return {
|
|
2515
|
+
...defaultFingersCrossedConfig2,
|
|
2516
|
+
...options.fingersCrossed
|
|
2517
|
+
};
|
|
2518
|
+
}
|
|
2519
|
+
if (!options.fingersCrossedEnabled) {
|
|
2520
|
+
return null;
|
|
2521
|
+
}
|
|
2522
|
+
if (!options.fingersCrossed) {
|
|
2523
|
+
return { ...defaultFingersCrossedConfig2 };
|
|
2524
|
+
}
|
|
2525
|
+
return {
|
|
2526
|
+
...defaultFingersCrossedConfig2,
|
|
2527
|
+
...options.fingersCrossed
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
normalizeOptions(options) {
|
|
2531
|
+
const defaultOptions = {
|
|
2532
|
+
format: "json",
|
|
2533
|
+
level: "info",
|
|
2534
|
+
logDirectory: config2.logDirectory,
|
|
2535
|
+
rotation: undefined,
|
|
2536
|
+
timestamp: undefined,
|
|
2537
|
+
fingersCrossed: {},
|
|
2538
|
+
enabled: true,
|
|
2539
|
+
showTags: false,
|
|
2540
|
+
formatter: undefined
|
|
2541
|
+
};
|
|
2542
|
+
const mergedOptions = {
|
|
2543
|
+
...defaultOptions,
|
|
2544
|
+
...Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined))
|
|
2545
|
+
};
|
|
2546
|
+
if (!mergedOptions.level || !["debug", "info", "success", "warning", "error"].includes(mergedOptions.level)) {
|
|
2547
|
+
mergedOptions.level = defaultOptions.level;
|
|
2548
|
+
}
|
|
2549
|
+
return mergedOptions;
|
|
2550
|
+
}
|
|
2551
|
+
async writeToFile(data) {
|
|
2552
|
+
const cancelled = false;
|
|
2553
|
+
const operationPromise = (async () => {
|
|
2554
|
+
let fd;
|
|
2555
|
+
let retries = 0;
|
|
2556
|
+
const maxRetries = 3;
|
|
2557
|
+
const backoffDelay = 1000;
|
|
2558
|
+
while (retries < maxRetries) {
|
|
2559
|
+
try {
|
|
2560
|
+
try {
|
|
2561
|
+
try {
|
|
2562
|
+
await access2(this.config.logDirectory, constants2.F_OK | constants2.W_OK);
|
|
2563
|
+
} catch (err) {
|
|
2564
|
+
if (err instanceof Error && "code" in err) {
|
|
2565
|
+
if (err.code === "ENOENT") {
|
|
2566
|
+
await mkdir2(this.config.logDirectory, { recursive: true, mode: 493 });
|
|
2567
|
+
} else if (err.code === "EACCES") {
|
|
2568
|
+
throw new Error(`No write permission for log directory: ${this.config.logDirectory}`);
|
|
2569
|
+
} else {
|
|
2570
|
+
throw err;
|
|
2571
|
+
}
|
|
2572
|
+
} else {
|
|
2573
|
+
throw err;
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
} catch (err) {
|
|
2577
|
+
console.error("Debug: [writeToFile] Failed to create log directory:", err);
|
|
2578
|
+
throw err;
|
|
2579
|
+
}
|
|
2580
|
+
if (cancelled)
|
|
2581
|
+
throw new Error("Operation cancelled: Logger was destroyed");
|
|
2582
|
+
const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer2.from(data);
|
|
2583
|
+
try {
|
|
2584
|
+
if (!existsSync22(this.currentLogFile)) {
|
|
2585
|
+
await writeFile2(this.currentLogFile, "", { mode: 420 });
|
|
2586
|
+
}
|
|
2587
|
+
fd = openSync2(this.currentLogFile, "a", 420);
|
|
2588
|
+
writeFileSync22(fd, dataToWrite, { flag: "a" });
|
|
2589
|
+
fsyncSync2(fd);
|
|
2590
|
+
if (fd !== undefined) {
|
|
2591
|
+
closeSync2(fd);
|
|
2592
|
+
fd = undefined;
|
|
2593
|
+
}
|
|
2594
|
+
const stats = await stat2(this.currentLogFile);
|
|
2595
|
+
if (stats.size === 0) {
|
|
2596
|
+
await writeFile2(this.currentLogFile, dataToWrite, { flag: "w", mode: 420 });
|
|
2597
|
+
const retryStats = await stat2(this.currentLogFile);
|
|
2598
|
+
if (retryStats.size === 0) {
|
|
2599
|
+
throw new Error("File exists but is empty after retry write");
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
return;
|
|
2603
|
+
} catch (err) {
|
|
2604
|
+
const error = err;
|
|
2605
|
+
if (error.code && ["ENETDOWN", "ENETUNREACH", "ENOTFOUND", "ETIMEDOUT"].includes(error.code)) {
|
|
2606
|
+
if (retries < maxRetries - 1) {
|
|
2607
|
+
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
2608
|
+
console.error(`Network error during write attempt ${retries + 1}/${maxRetries}:`, errorMessage);
|
|
2609
|
+
const delay = backoffDelay * 2 ** retries;
|
|
2610
|
+
await new Promise((resolve32) => setTimeout(resolve32, delay));
|
|
2611
|
+
retries++;
|
|
2612
|
+
continue;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
if (error?.code && ["ENOSPC", "EDQUOT"].includes(error.code)) {
|
|
2616
|
+
throw new Error(`Disk quota exceeded or no space left on device: ${error.message}`);
|
|
2617
|
+
}
|
|
2618
|
+
console.error("Debug: [writeToFile] Error writing to file:", error);
|
|
2619
|
+
throw error;
|
|
2620
|
+
} finally {
|
|
2621
|
+
if (fd !== undefined) {
|
|
2622
|
+
try {
|
|
2623
|
+
closeSync2(fd);
|
|
2624
|
+
} catch (err) {
|
|
2625
|
+
console.error("Debug: [writeToFile] Error closing file descriptor:", err);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
} catch (err) {
|
|
2630
|
+
if (retries === maxRetries - 1) {
|
|
2631
|
+
const error = err;
|
|
2632
|
+
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
2633
|
+
console.error("Debug: [writeToFile] Max retries reached. Final error:", errorMessage);
|
|
2634
|
+
throw err;
|
|
2635
|
+
}
|
|
2636
|
+
retries++;
|
|
2637
|
+
const delay = backoffDelay * 2 ** (retries - 1);
|
|
2638
|
+
await new Promise((resolve32) => setTimeout(resolve32, delay));
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
})();
|
|
2642
|
+
this.pendingOperations.push(operationPromise);
|
|
2643
|
+
const index = this.pendingOperations.length - 1;
|
|
2644
|
+
try {
|
|
2645
|
+
await operationPromise;
|
|
2646
|
+
} catch (err) {
|
|
2647
|
+
console.error("Debug: [writeToFile] Error in operation:", err);
|
|
2648
|
+
throw err;
|
|
2649
|
+
} finally {
|
|
2650
|
+
this.pendingOperations.splice(index, 1);
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
generateLogFilename() {
|
|
2654
|
+
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")) {
|
|
2655
|
+
return join22(this.config.logDirectory, `${this.name}.log`);
|
|
2656
|
+
}
|
|
2657
|
+
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") {
|
|
2658
|
+
return join22(this.config.logDirectory, `${this.name}.log`);
|
|
2659
|
+
}
|
|
2660
|
+
const date = new Date().toISOString().split("T")[0];
|
|
2661
|
+
return join22(this.config.logDirectory, `${this.name}-${date}.log`);
|
|
2662
|
+
}
|
|
2663
|
+
setupRotation() {
|
|
2664
|
+
if (isBrowserProcess2())
|
|
2665
|
+
return;
|
|
2666
|
+
if (typeof this.config.rotation === "boolean")
|
|
2667
|
+
return;
|
|
2668
|
+
const config22 = this.config.rotation;
|
|
2669
|
+
let interval;
|
|
2670
|
+
switch (config22.frequency) {
|
|
2671
|
+
case "daily":
|
|
2672
|
+
interval = 86400000;
|
|
2673
|
+
break;
|
|
2674
|
+
case "weekly":
|
|
2675
|
+
interval = 604800000;
|
|
2676
|
+
break;
|
|
2677
|
+
case "monthly":
|
|
2678
|
+
interval = 2592000000;
|
|
2679
|
+
break;
|
|
2680
|
+
default:
|
|
2681
|
+
return;
|
|
2682
|
+
}
|
|
2683
|
+
this.rotationTimeout = setInterval(() => {
|
|
2684
|
+
this.rotateLog();
|
|
2685
|
+
}, interval);
|
|
2686
|
+
}
|
|
2687
|
+
setupKeyRotation() {
|
|
2688
|
+
if (!this.validateEncryptionConfig()) {
|
|
2689
|
+
console.error("Invalid encryption configuration detected during key rotation setup");
|
|
2690
|
+
return;
|
|
2691
|
+
}
|
|
2692
|
+
const rotation = this.config.rotation;
|
|
2693
|
+
const keyRotation = rotation.keyRotation;
|
|
2694
|
+
if (!keyRotation?.enabled) {
|
|
2695
|
+
return;
|
|
2696
|
+
}
|
|
2697
|
+
const rotationInterval = typeof keyRotation.interval === "number" ? keyRotation.interval : 60;
|
|
2698
|
+
const interval = Math.max(rotationInterval, 60) * 1000;
|
|
2699
|
+
this.keyRotationTimeout = setInterval(() => {
|
|
2700
|
+
this.rotateKeys().catch((error) => {
|
|
2701
|
+
console.error("Error rotating keys:", error);
|
|
2702
|
+
});
|
|
2703
|
+
}, interval);
|
|
2704
|
+
}
|
|
2705
|
+
async rotateKeys() {
|
|
2706
|
+
if (!this.validateEncryptionConfig()) {
|
|
2707
|
+
console.error("Invalid encryption configuration detected during key rotation");
|
|
2708
|
+
return;
|
|
2709
|
+
}
|
|
2710
|
+
const rotation = this.config.rotation;
|
|
2711
|
+
const keyRotation = rotation.keyRotation;
|
|
2712
|
+
const newKeyId = this.generateKeyId();
|
|
2713
|
+
const newKey = this.generateKey();
|
|
2714
|
+
this.currentKeyId = newKeyId;
|
|
2715
|
+
this.keys.set(newKeyId, newKey);
|
|
2716
|
+
this.encryptionKeys.set(newKeyId, {
|
|
2717
|
+
key: newKey,
|
|
2718
|
+
createdAt: new Date
|
|
2719
|
+
});
|
|
2720
|
+
const sortedKeys = Array.from(this.encryptionKeys.entries()).sort(([, a], [, b]) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
2721
|
+
const maxKeyCount = typeof keyRotation.maxKeys === "number" ? keyRotation.maxKeys : 1;
|
|
2722
|
+
const maxKeys = Math.max(1, maxKeyCount);
|
|
2723
|
+
if (sortedKeys.length > maxKeys) {
|
|
2724
|
+
for (const [keyId] of sortedKeys.slice(maxKeys)) {
|
|
2725
|
+
this.encryptionKeys.delete(keyId);
|
|
2726
|
+
this.keys.delete(keyId);
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
generateKeyId() {
|
|
2731
|
+
return randomBytes2(16).toString("hex");
|
|
2732
|
+
}
|
|
2733
|
+
generateKey() {
|
|
2734
|
+
return randomBytes2(32);
|
|
2735
|
+
}
|
|
2736
|
+
getCurrentKey() {
|
|
2737
|
+
if (!this.currentKeyId) {
|
|
2738
|
+
throw new Error("Encryption is not properly initialized. Make sure encryption is enabled in the configuration.");
|
|
2739
|
+
}
|
|
2740
|
+
const key = this.keys.get(this.currentKeyId);
|
|
2741
|
+
if (!key) {
|
|
2742
|
+
throw new Error(`No key found for ID ${this.currentKeyId}. The encryption key may have been rotated or removed.`);
|
|
2743
|
+
}
|
|
2744
|
+
return { key, id: this.currentKeyId };
|
|
2745
|
+
}
|
|
2746
|
+
encrypt(data) {
|
|
2747
|
+
const { key } = this.getCurrentKey();
|
|
2748
|
+
const iv = randomBytes2(16);
|
|
2749
|
+
const cipher = createCipheriv2("aes-256-gcm", key, iv);
|
|
2750
|
+
const encrypted = Buffer2.concat([
|
|
2751
|
+
cipher.update(data, "utf8"),
|
|
2752
|
+
cipher.final()
|
|
2753
|
+
]);
|
|
2754
|
+
const authTag = cipher.getAuthTag();
|
|
2755
|
+
return {
|
|
2756
|
+
encrypted: Buffer2.concat([iv, encrypted, authTag]),
|
|
2757
|
+
iv
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
async compressData(data) {
|
|
2761
|
+
return new Promise((resolve32, reject) => {
|
|
2762
|
+
const gzip = createGzip2();
|
|
2763
|
+
const chunks = [];
|
|
2764
|
+
gzip.on("data", (chunk2) => chunks.push(chunk2));
|
|
2765
|
+
gzip.on("end", () => resolve32(Buffer2.from(Buffer2.concat(chunks))));
|
|
2766
|
+
gzip.on("error", reject);
|
|
2767
|
+
gzip.write(data);
|
|
2768
|
+
gzip.end();
|
|
2769
|
+
});
|
|
2770
|
+
}
|
|
2771
|
+
getEncryptionOptions() {
|
|
2772
|
+
if (!this.config.rotation || typeof this.config.rotation === "boolean" || !this.config.rotation.encrypt) {
|
|
2773
|
+
return {};
|
|
2774
|
+
}
|
|
2775
|
+
const defaultOptions = {
|
|
2776
|
+
algorithm: "aes-256-cbc",
|
|
2777
|
+
compress: false
|
|
2778
|
+
};
|
|
2779
|
+
if (typeof this.config.rotation.encrypt === "object") {
|
|
2780
|
+
const encryptConfig = this.config.rotation.encrypt;
|
|
2781
|
+
return {
|
|
2782
|
+
...defaultOptions,
|
|
2783
|
+
...encryptConfig
|
|
2784
|
+
};
|
|
2785
|
+
}
|
|
2786
|
+
return defaultOptions;
|
|
2787
|
+
}
|
|
2788
|
+
async rotateLog() {
|
|
2789
|
+
if (isBrowserProcess2())
|
|
2790
|
+
return;
|
|
2791
|
+
const stats = await stat2(this.currentLogFile).catch(() => null);
|
|
2792
|
+
if (!stats)
|
|
2793
|
+
return;
|
|
2794
|
+
const config22 = this.config.rotation;
|
|
2795
|
+
if (typeof config22 === "boolean")
|
|
2796
|
+
return;
|
|
2797
|
+
if (config22.maxSize && stats.size >= config22.maxSize) {
|
|
2798
|
+
const oldFile = this.currentLogFile;
|
|
2799
|
+
const newFile = this.generateLogFilename();
|
|
2800
|
+
if (this.name.includes("rotation-load-test") || this.name === "failed-rotation-test") {
|
|
2801
|
+
const files = await readdir2(this.config.logDirectory);
|
|
2802
|
+
const rotatedFiles = files.filter((f) => f.startsWith(this.name) && /\.log\.\d+$/.test(f)).sort((a, b) => {
|
|
2803
|
+
const numA = Number.parseInt(a.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
2804
|
+
const numB = Number.parseInt(b.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
2805
|
+
return numB - numA;
|
|
2806
|
+
});
|
|
2807
|
+
const nextNum = rotatedFiles.length > 0 ? Number.parseInt(rotatedFiles[0].match(/\.log\.(\d+)$/)?.[1] || "0") + 1 : 1;
|
|
2808
|
+
const rotatedFile = `${oldFile}.${nextNum}`;
|
|
2809
|
+
if (await stat2(oldFile).catch(() => null)) {
|
|
2810
|
+
try {
|
|
2811
|
+
await rename2(oldFile, rotatedFile);
|
|
2812
|
+
if (config22.compress) {
|
|
2813
|
+
try {
|
|
2814
|
+
const compressedPath = `${rotatedFile}.gz`;
|
|
2815
|
+
await this.compressLogFile(rotatedFile, compressedPath);
|
|
2816
|
+
await unlink2(rotatedFile);
|
|
2817
|
+
} catch (err) {
|
|
2818
|
+
console.error("Error compressing rotated file:", err);
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
if (rotatedFiles.length === 0 && !files.some((f) => f.endsWith(".log.1"))) {
|
|
2822
|
+
try {
|
|
2823
|
+
const backupPath = `${oldFile}.1`;
|
|
2824
|
+
await writeFile2(backupPath, "");
|
|
2825
|
+
} catch (err) {
|
|
2826
|
+
console.error("Error creating backup file:", err);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
} catch (err) {
|
|
2830
|
+
console.error(`Error during rotation: ${err instanceof Error ? err.message : String(err)}`);
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
} else {
|
|
2834
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
2835
|
+
const rotatedFile = oldFile.replace(/\.log$/, `-${timestamp}.log`);
|
|
2836
|
+
if (await stat2(oldFile).catch(() => null)) {
|
|
2837
|
+
await rename2(oldFile, rotatedFile);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
this.currentLogFile = newFile;
|
|
2841
|
+
if (config22.maxFiles) {
|
|
2842
|
+
const files = await readdir2(this.config.logDirectory);
|
|
2843
|
+
const logFiles = files.filter((f) => f.startsWith(this.name)).sort((a, b) => b.localeCompare(a));
|
|
2844
|
+
for (const file of logFiles.slice(config22.maxFiles)) {
|
|
2845
|
+
await unlink2(join22(this.config.logDirectory, file));
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
async compressLogFile(inputPath, outputPath) {
|
|
2851
|
+
const readStream = createReadStream2(inputPath);
|
|
2852
|
+
const writeStream = createWriteStream2(outputPath);
|
|
2853
|
+
const gzip = createGzip2();
|
|
2854
|
+
await pipeline2(readStream, gzip, writeStream);
|
|
2855
|
+
}
|
|
2856
|
+
async handleFingersCrossedBuffer(level, formattedEntry) {
|
|
2857
|
+
if (!this.fingersCrossedConfig)
|
|
2858
|
+
return;
|
|
2859
|
+
if (this.shouldActivateFingersCrossed(level) && !this.isActivated) {
|
|
2860
|
+
this.isActivated = true;
|
|
2861
|
+
for (const entry of this.logBuffer) {
|
|
2862
|
+
const formattedBufferedEntry = await this.formatter.format(entry);
|
|
2863
|
+
await this.writeToFile(formattedBufferedEntry);
|
|
2864
|
+
console.log(formattedBufferedEntry);
|
|
2865
|
+
}
|
|
2866
|
+
if (this.fingersCrossedConfig.stopBuffering)
|
|
2867
|
+
this.logBuffer = [];
|
|
2868
|
+
}
|
|
2869
|
+
if (this.isActivated) {
|
|
2870
|
+
await this.writeToFile(formattedEntry);
|
|
2871
|
+
console.log(formattedEntry);
|
|
2872
|
+
} else {
|
|
2873
|
+
if (this.logBuffer.length >= this.fingersCrossedConfig.bufferSize)
|
|
2874
|
+
this.logBuffer.shift();
|
|
2875
|
+
const entry = {
|
|
2876
|
+
timestamp: new Date,
|
|
2877
|
+
level,
|
|
2878
|
+
message: formattedEntry,
|
|
2879
|
+
name: this.name
|
|
2880
|
+
};
|
|
2881
|
+
this.logBuffer.push(entry);
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
shouldActivateFingersCrossed(level) {
|
|
2885
|
+
if (!this.fingersCrossedConfig)
|
|
2886
|
+
return false;
|
|
2887
|
+
return this.getLevelValue(level) >= this.getLevelValue(this.fingersCrossedConfig.activationLevel);
|
|
2888
|
+
}
|
|
2889
|
+
getLevelValue(level) {
|
|
2890
|
+
const levels = {
|
|
2891
|
+
debug: 0,
|
|
2892
|
+
info: 1,
|
|
2893
|
+
success: 2,
|
|
2894
|
+
warning: 3,
|
|
2895
|
+
error: 4
|
|
2896
|
+
};
|
|
2897
|
+
return levels[level];
|
|
2898
|
+
}
|
|
2899
|
+
shouldLog(level) {
|
|
2900
|
+
if (!this.enabled)
|
|
2901
|
+
return false;
|
|
2902
|
+
const levels = {
|
|
2903
|
+
debug: 0,
|
|
2904
|
+
info: 1,
|
|
2905
|
+
success: 2,
|
|
2906
|
+
warning: 3,
|
|
2907
|
+
error: 4
|
|
2908
|
+
};
|
|
2909
|
+
return levels[level] >= levels[this.config.level];
|
|
2910
|
+
}
|
|
2911
|
+
async flushPendingWrites() {
|
|
2912
|
+
await Promise.all(this.pendingOperations.map((op) => {
|
|
2913
|
+
if (op instanceof Promise) {
|
|
2914
|
+
return op.catch((err) => {
|
|
2915
|
+
console.error("Error in pending write operation:", err);
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2918
|
+
return Promise.resolve();
|
|
2919
|
+
}));
|
|
2920
|
+
if (existsSync22(this.currentLogFile)) {
|
|
2921
|
+
try {
|
|
2922
|
+
const fd = openSync2(this.currentLogFile, "r+");
|
|
2923
|
+
fsyncSync2(fd);
|
|
2924
|
+
closeSync2(fd);
|
|
2925
|
+
} catch (error) {
|
|
2926
|
+
console.error(`Error flushing file: ${error}`);
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
async destroy() {
|
|
2931
|
+
if (this.rotationTimeout)
|
|
2932
|
+
clearInterval(this.rotationTimeout);
|
|
2933
|
+
if (this.keyRotationTimeout)
|
|
2934
|
+
clearInterval(this.keyRotationTimeout);
|
|
2935
|
+
this.timers.clear();
|
|
2936
|
+
for (const op of this.pendingOperations) {
|
|
2937
|
+
if (typeof op.cancel === "function") {
|
|
2938
|
+
op.cancel();
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
return (async () => {
|
|
2942
|
+
if (this.pendingOperations.length > 0) {
|
|
2943
|
+
try {
|
|
2944
|
+
await Promise.allSettled(this.pendingOperations);
|
|
2945
|
+
} catch (err) {
|
|
2946
|
+
console.error("Error waiting for pending operations:", err);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
if (!isBrowserProcess2() && this.config.rotation && typeof this.config.rotation !== "boolean" && this.config.rotation.compress) {
|
|
2950
|
+
try {
|
|
2951
|
+
const files = await readdir2(this.config.logDirectory);
|
|
2952
|
+
const tempFiles = files.filter((f) => (f.includes("temp") || f.includes(".tmp")) && f.includes(this.name));
|
|
2953
|
+
for (const tempFile of tempFiles) {
|
|
2954
|
+
try {
|
|
2955
|
+
await unlink2(join22(this.config.logDirectory, tempFile));
|
|
2956
|
+
} catch (err) {
|
|
2957
|
+
console.error(`Failed to delete temp file ${tempFile}:`, err);
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
} catch (err) {
|
|
2961
|
+
console.error("Error cleaning up temporary files:", err);
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
})();
|
|
2965
|
+
}
|
|
2966
|
+
getCurrentLogFilePath() {
|
|
2967
|
+
return this.currentLogFile;
|
|
2968
|
+
}
|
|
2969
|
+
formatTag(name) {
|
|
2970
|
+
if (!name)
|
|
2971
|
+
return "";
|
|
2972
|
+
return `${this.tagFormat.prefix}${name}${this.tagFormat.suffix}`;
|
|
2973
|
+
}
|
|
2974
|
+
formatFileTimestamp(date) {
|
|
2975
|
+
return `[${date.toISOString()}]`;
|
|
2976
|
+
}
|
|
2977
|
+
formatConsoleTimestamp(date) {
|
|
2978
|
+
return this.fancy ? styles2.gray(date.toLocaleTimeString()) : date.toLocaleTimeString();
|
|
2979
|
+
}
|
|
2980
|
+
formatConsoleMessage(parts) {
|
|
2981
|
+
const { timestamp, icon = "", tag = "", message, level, showTimestamp = true } = parts;
|
|
2982
|
+
const stripAnsi = (str) => str.replace(this.ANSI_PATTERN, "");
|
|
2983
|
+
if (!this.fancy) {
|
|
2984
|
+
const components = [];
|
|
2985
|
+
if (showTimestamp)
|
|
2986
|
+
components.push(timestamp);
|
|
2987
|
+
if (level === "warning")
|
|
2988
|
+
components.push("WARN");
|
|
2989
|
+
else if (level === "error")
|
|
2990
|
+
components.push("ERROR");
|
|
2991
|
+
else if (icon)
|
|
2992
|
+
components.push(icon.replace(/[^\p{L}\p{N}\p{P}\p{Z}]/gu, ""));
|
|
2993
|
+
if (tag)
|
|
2994
|
+
components.push(tag.replace(/[[\]]/g, ""));
|
|
2995
|
+
components.push(message);
|
|
2996
|
+
return components.join(" ");
|
|
2997
|
+
}
|
|
2998
|
+
const terminalWidth = process52.stdout.columns || 120;
|
|
2999
|
+
let mainPart = "";
|
|
3000
|
+
if (level === "warning" || level === "error") {
|
|
3001
|
+
mainPart = `${icon} ${message}`;
|
|
3002
|
+
} else if (level === "info" || level === "success") {
|
|
3003
|
+
mainPart = `${icon} ${tag} ${message}`;
|
|
3004
|
+
} else {
|
|
3005
|
+
mainPart = `${icon} ${tag} ${styles2.cyan(message)}`;
|
|
3006
|
+
}
|
|
3007
|
+
if (!showTimestamp) {
|
|
3008
|
+
return mainPart.trim();
|
|
3009
|
+
}
|
|
3010
|
+
const visibleMainPartLength = stripAnsi(mainPart).trim().length;
|
|
3011
|
+
const visibleTimestampLength = stripAnsi(timestamp).length;
|
|
3012
|
+
const padding = Math.max(1, terminalWidth - 2 - visibleMainPartLength - visibleTimestampLength);
|
|
3013
|
+
return `${mainPart.trim()}${" ".repeat(padding)}${timestamp}`;
|
|
3014
|
+
}
|
|
3015
|
+
formatMessage(message, args) {
|
|
3016
|
+
if (args.length === 1 && Array.isArray(args[0])) {
|
|
3017
|
+
return message.replace(/\{(\d+)\}/g, (match, index) => {
|
|
3018
|
+
const position = Number.parseInt(index, 10);
|
|
3019
|
+
return position < args[0].length ? String(args[0][position]) : match;
|
|
3020
|
+
});
|
|
3021
|
+
}
|
|
3022
|
+
const formatRegex = /%([sdijfo%])/g;
|
|
3023
|
+
let argIndex = 0;
|
|
3024
|
+
let formattedMessage = message.replace(formatRegex, (match, type) => {
|
|
3025
|
+
if (type === "%")
|
|
3026
|
+
return "%";
|
|
3027
|
+
if (argIndex >= args.length)
|
|
3028
|
+
return match;
|
|
3029
|
+
const arg = args[argIndex++];
|
|
3030
|
+
switch (type) {
|
|
3031
|
+
case "s":
|
|
3032
|
+
return String(arg);
|
|
3033
|
+
case "d":
|
|
3034
|
+
case "i":
|
|
3035
|
+
return Number(arg).toString();
|
|
3036
|
+
case "j":
|
|
3037
|
+
case "o":
|
|
3038
|
+
return JSON.stringify(arg, null, 2);
|
|
3039
|
+
default:
|
|
3040
|
+
return match;
|
|
3041
|
+
}
|
|
3042
|
+
});
|
|
3043
|
+
if (argIndex < args.length) {
|
|
3044
|
+
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
3045
|
+
}
|
|
3046
|
+
return formattedMessage;
|
|
3047
|
+
}
|
|
3048
|
+
async log(level, message, ...args) {
|
|
3049
|
+
const timestamp = new Date;
|
|
3050
|
+
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
3051
|
+
const fileTime = this.formatFileTimestamp(timestamp);
|
|
3052
|
+
let formattedMessage;
|
|
3053
|
+
let errorStack;
|
|
3054
|
+
if (message instanceof Error) {
|
|
3055
|
+
formattedMessage = message.message;
|
|
3056
|
+
errorStack = message.stack;
|
|
3057
|
+
} else {
|
|
3058
|
+
formattedMessage = this.formatMessage(message, args);
|
|
3059
|
+
}
|
|
3060
|
+
if (this.fancy && !isBrowserProcess2()) {
|
|
3061
|
+
const icon = levelIcons2[level];
|
|
3062
|
+
const tag = this.options.showTags !== false && this.name ? styles2.gray(this.formatTag(this.name)) : "";
|
|
3063
|
+
let consoleMessage;
|
|
3064
|
+
switch (level) {
|
|
3065
|
+
case "debug":
|
|
3066
|
+
consoleMessage = this.formatConsoleMessage({
|
|
3067
|
+
timestamp: consoleTime,
|
|
3068
|
+
icon,
|
|
3069
|
+
tag,
|
|
3070
|
+
message: styles2.gray(formattedMessage),
|
|
3071
|
+
level
|
|
3072
|
+
});
|
|
3073
|
+
console.error(consoleMessage);
|
|
3074
|
+
break;
|
|
3075
|
+
case "info":
|
|
3076
|
+
consoleMessage = this.formatConsoleMessage({
|
|
3077
|
+
timestamp: consoleTime,
|
|
3078
|
+
icon,
|
|
3079
|
+
tag,
|
|
3080
|
+
message: formattedMessage,
|
|
3081
|
+
level
|
|
3082
|
+
});
|
|
3083
|
+
console.error(consoleMessage);
|
|
3084
|
+
break;
|
|
3085
|
+
case "success":
|
|
3086
|
+
consoleMessage = this.formatConsoleMessage({
|
|
3087
|
+
timestamp: consoleTime,
|
|
3088
|
+
icon,
|
|
3089
|
+
tag,
|
|
3090
|
+
message: styles2.green(formattedMessage),
|
|
3091
|
+
level
|
|
3092
|
+
});
|
|
3093
|
+
console.error(consoleMessage);
|
|
3094
|
+
break;
|
|
3095
|
+
case "warning":
|
|
3096
|
+
consoleMessage = this.formatConsoleMessage({
|
|
3097
|
+
timestamp: consoleTime,
|
|
3098
|
+
icon,
|
|
3099
|
+
tag,
|
|
3100
|
+
message: formattedMessage,
|
|
3101
|
+
level
|
|
3102
|
+
});
|
|
3103
|
+
console.warn(consoleMessage);
|
|
3104
|
+
break;
|
|
3105
|
+
case "error":
|
|
3106
|
+
consoleMessage = this.formatConsoleMessage({
|
|
3107
|
+
timestamp: consoleTime,
|
|
3108
|
+
icon,
|
|
3109
|
+
tag,
|
|
3110
|
+
message: formattedMessage,
|
|
3111
|
+
level
|
|
3112
|
+
});
|
|
3113
|
+
console.error(consoleMessage);
|
|
3114
|
+
if (errorStack) {
|
|
3115
|
+
const stackLines = errorStack.split(`
|
|
3116
|
+
`);
|
|
3117
|
+
for (const line of stackLines) {
|
|
3118
|
+
if (line.trim() && !line.includes(formattedMessage)) {
|
|
3119
|
+
console.error(this.formatConsoleMessage({
|
|
3120
|
+
timestamp: consoleTime,
|
|
3121
|
+
message: styles2.gray(` ${line}`),
|
|
3122
|
+
level,
|
|
3123
|
+
showTimestamp: false
|
|
3124
|
+
}));
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
break;
|
|
3129
|
+
}
|
|
3130
|
+
} else if (!isBrowserProcess2()) {
|
|
3131
|
+
console.error(`${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}`);
|
|
3132
|
+
if (errorStack) {
|
|
3133
|
+
console.error(errorStack);
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
if (!this.shouldLog(level))
|
|
3137
|
+
return;
|
|
3138
|
+
let logEntry = `${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}
|
|
3139
|
+
`;
|
|
3140
|
+
if (errorStack) {
|
|
3141
|
+
logEntry += `${errorStack}
|
|
3142
|
+
`;
|
|
3143
|
+
}
|
|
3144
|
+
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
3145
|
+
await this.writeToFile(logEntry);
|
|
3146
|
+
}
|
|
3147
|
+
time(label) {
|
|
3148
|
+
const start = performance.now();
|
|
3149
|
+
if (this.fancy && !isBrowserProcess2()) {
|
|
3150
|
+
const tag = this.options.showTags !== false && this.name ? styles2.gray(this.formatTag(this.name)) : "";
|
|
3151
|
+
const consoleTime = this.formatConsoleTimestamp(new Date);
|
|
3152
|
+
console.error(this.formatConsoleMessage({
|
|
3153
|
+
timestamp: consoleTime,
|
|
3154
|
+
icon: styles2.blue("\u25D0"),
|
|
3155
|
+
tag,
|
|
3156
|
+
message: `${styles2.cyan(label)}...`
|
|
3157
|
+
}));
|
|
3158
|
+
}
|
|
3159
|
+
return async (metadata) => {
|
|
3160
|
+
if (!this.enabled)
|
|
3161
|
+
return;
|
|
3162
|
+
const end = performance.now();
|
|
3163
|
+
const elapsed = Math.round(end - start);
|
|
3164
|
+
const completionMessage = `${label} completed in ${elapsed}ms`;
|
|
3165
|
+
const timestamp = new Date;
|
|
3166
|
+
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
3167
|
+
const fileTime = this.formatFileTimestamp(timestamp);
|
|
3168
|
+
let logEntry = `${fileTime} ${this.environment}.INFO: ${completionMessage}`;
|
|
3169
|
+
if (metadata) {
|
|
3170
|
+
logEntry += ` ${JSON.stringify(metadata)}`;
|
|
3171
|
+
}
|
|
3172
|
+
logEntry += `
|
|
3173
|
+
`;
|
|
3174
|
+
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
3175
|
+
if (this.fancy && !isBrowserProcess2()) {
|
|
3176
|
+
const tag = this.options.showTags !== false && this.name ? styles2.gray(this.formatTag(this.name)) : "";
|
|
3177
|
+
console.error(this.formatConsoleMessage({
|
|
3178
|
+
timestamp: consoleTime,
|
|
3179
|
+
icon: styles2.green("\u2713"),
|
|
3180
|
+
tag,
|
|
3181
|
+
message: `${completionMessage}${metadata ? ` ${JSON.stringify(metadata)}` : ""}`
|
|
3182
|
+
}));
|
|
3183
|
+
} else if (!isBrowserProcess2()) {
|
|
3184
|
+
console.error(logEntry.trim());
|
|
3185
|
+
}
|
|
3186
|
+
await this.writeToFile(logEntry);
|
|
3187
|
+
};
|
|
3188
|
+
}
|
|
3189
|
+
async debug(message, ...args) {
|
|
3190
|
+
await this.log("debug", message, ...args);
|
|
3191
|
+
}
|
|
3192
|
+
async info(message, ...args) {
|
|
3193
|
+
await this.log("info", message, ...args);
|
|
3194
|
+
}
|
|
3195
|
+
async success(message, ...args) {
|
|
3196
|
+
await this.log("success", message, ...args);
|
|
3197
|
+
}
|
|
3198
|
+
async warn(message, ...args) {
|
|
3199
|
+
await this.log("warning", message, ...args);
|
|
3200
|
+
}
|
|
3201
|
+
async error(message, ...args) {
|
|
3202
|
+
await this.log("error", message, ...args);
|
|
3203
|
+
}
|
|
3204
|
+
validateEncryptionConfig() {
|
|
3205
|
+
if (!this.config.rotation)
|
|
3206
|
+
return false;
|
|
3207
|
+
if (typeof this.config.rotation === "boolean")
|
|
3208
|
+
return false;
|
|
3209
|
+
const rotation = this.config.rotation;
|
|
3210
|
+
const { encrypt } = rotation;
|
|
3211
|
+
return !!encrypt;
|
|
3212
|
+
}
|
|
3213
|
+
async only(fn) {
|
|
3214
|
+
if (!this.enabled)
|
|
3215
|
+
return;
|
|
3216
|
+
return await fn();
|
|
3217
|
+
}
|
|
3218
|
+
isEnabled() {
|
|
3219
|
+
return this.enabled;
|
|
3220
|
+
}
|
|
3221
|
+
setEnabled(enabled) {
|
|
3222
|
+
this.enabled = enabled;
|
|
3223
|
+
}
|
|
3224
|
+
extend(namespace) {
|
|
3225
|
+
const childName = `${this.name}:${namespace}`;
|
|
3226
|
+
const childLogger = new Logger2(childName, {
|
|
3227
|
+
...this.options,
|
|
3228
|
+
logDirectory: this.config.logDirectory,
|
|
3229
|
+
level: this.config.level,
|
|
3230
|
+
format: this.config.format,
|
|
3231
|
+
rotation: typeof this.config.rotation === "boolean" ? undefined : this.config.rotation,
|
|
3232
|
+
timestamp: typeof this.config.timestamp === "boolean" ? undefined : this.config.timestamp
|
|
3233
|
+
});
|
|
3234
|
+
this.subLoggers.add(childLogger);
|
|
3235
|
+
return childLogger;
|
|
3236
|
+
}
|
|
3237
|
+
createReadStream() {
|
|
3238
|
+
if (isBrowserProcess2())
|
|
3239
|
+
throw new Error("createReadStream is not supported in browser environments");
|
|
3240
|
+
if (!existsSync22(this.currentLogFile))
|
|
3241
|
+
throw new Error(`Log file does not exist: ${this.currentLogFile}`);
|
|
3242
|
+
return createReadStream2(this.currentLogFile, { encoding: "utf8" });
|
|
3243
|
+
}
|
|
3244
|
+
async decrypt(data) {
|
|
3245
|
+
if (!this.validateEncryptionConfig())
|
|
3246
|
+
throw new Error("Encryption is not configured");
|
|
3247
|
+
const encryptionConfig = this.config.rotation;
|
|
3248
|
+
if (!encryptionConfig.encrypt || typeof encryptionConfig.encrypt === "boolean")
|
|
3249
|
+
throw new Error("Invalid encryption configuration");
|
|
3250
|
+
if (!this.currentKeyId || !this.keys.has(this.currentKeyId))
|
|
3251
|
+
throw new Error("No valid encryption key available");
|
|
3252
|
+
const key = this.keys.get(this.currentKeyId);
|
|
3253
|
+
try {
|
|
3254
|
+
const encryptedData = Buffer2.isBuffer(data) ? data : Buffer2.from(data, "base64");
|
|
3255
|
+
const iv = encryptedData.slice(0, 16);
|
|
3256
|
+
const authTag = encryptedData.slice(-16);
|
|
3257
|
+
const ciphertext = encryptedData.slice(16, -16);
|
|
3258
|
+
const decipher = createDecipheriv2("aes-256-gcm", key, iv);
|
|
3259
|
+
decipher.setAuthTag(authTag);
|
|
3260
|
+
const decrypted = Buffer2.concat([
|
|
3261
|
+
decipher.update(ciphertext),
|
|
3262
|
+
decipher.final()
|
|
3263
|
+
]);
|
|
3264
|
+
return decrypted.toString("utf8");
|
|
3265
|
+
} catch (err) {
|
|
3266
|
+
throw new Error(`Decryption failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
getLevel() {
|
|
3270
|
+
return this.config.level;
|
|
3271
|
+
}
|
|
3272
|
+
getLogDirectory() {
|
|
3273
|
+
return this.config.logDirectory;
|
|
3274
|
+
}
|
|
3275
|
+
getFormat() {
|
|
3276
|
+
return this.config.format;
|
|
3277
|
+
}
|
|
3278
|
+
getRotationConfig() {
|
|
3279
|
+
return this.config.rotation;
|
|
3280
|
+
}
|
|
3281
|
+
isBrowserMode() {
|
|
3282
|
+
return isBrowserProcess2();
|
|
3283
|
+
}
|
|
3284
|
+
isServerMode() {
|
|
3285
|
+
return !isBrowserProcess2();
|
|
3286
|
+
}
|
|
3287
|
+
setTestEncryptionKey(keyId, key) {
|
|
3288
|
+
this.currentKeyId = keyId;
|
|
3289
|
+
this.keys.set(keyId, key);
|
|
3290
|
+
}
|
|
3291
|
+
getTestCurrentKey() {
|
|
3292
|
+
if (!this.currentKeyId || !this.keys.has(this.currentKeyId)) {
|
|
3293
|
+
return null;
|
|
3294
|
+
}
|
|
3295
|
+
return {
|
|
3296
|
+
id: this.currentKeyId,
|
|
3297
|
+
key: this.keys.get(this.currentKeyId)
|
|
3298
|
+
};
|
|
3299
|
+
}
|
|
3300
|
+
getConfig() {
|
|
3301
|
+
return this.config;
|
|
3302
|
+
}
|
|
3303
|
+
async box(message) {
|
|
3304
|
+
if (!this.enabled)
|
|
3305
|
+
return;
|
|
3306
|
+
const timestamp = new Date;
|
|
3307
|
+
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
3308
|
+
const fileTime = this.formatFileTimestamp(timestamp);
|
|
3309
|
+
if (this.fancy && !isBrowserProcess2()) {
|
|
3310
|
+
const lines = message.split(`
|
|
3311
|
+
`);
|
|
3312
|
+
const width = Math.max(...lines.map((line) => line.length)) + 2;
|
|
3313
|
+
const top = `\u250C${"\u2500".repeat(width)}\u2510`;
|
|
3314
|
+
const bottom = `\u2514${"\u2500".repeat(width)}\u2518`;
|
|
3315
|
+
const boxedLines = lines.map((line) => {
|
|
3316
|
+
const padding = " ".repeat(width - line.length - 2);
|
|
3317
|
+
return `\u2502 ${line}${padding} \u2502`;
|
|
3318
|
+
});
|
|
3319
|
+
if (this.options.showTags !== false && this.name) {
|
|
3320
|
+
console.error(this.formatConsoleMessage({
|
|
3321
|
+
timestamp: consoleTime,
|
|
3322
|
+
message: styles2.gray(this.formatTag(this.name)),
|
|
3323
|
+
showTimestamp: false
|
|
3324
|
+
}));
|
|
3325
|
+
}
|
|
3326
|
+
console.error(this.formatConsoleMessage({
|
|
3327
|
+
timestamp: consoleTime,
|
|
3328
|
+
message: styles2.cyan(top)
|
|
3329
|
+
}));
|
|
3330
|
+
boxedLines.forEach((line) => console.error(this.formatConsoleMessage({
|
|
3331
|
+
timestamp: consoleTime,
|
|
3332
|
+
message: styles2.cyan(line),
|
|
3333
|
+
showTimestamp: false
|
|
3334
|
+
})));
|
|
3335
|
+
console.error(this.formatConsoleMessage({
|
|
3336
|
+
timestamp: consoleTime,
|
|
3337
|
+
message: styles2.cyan(bottom),
|
|
3338
|
+
showTimestamp: false
|
|
3339
|
+
}));
|
|
3340
|
+
} else if (!isBrowserProcess2()) {
|
|
3341
|
+
console.error(`${fileTime} ${this.environment}.INFO: [BOX] ${message}`);
|
|
3342
|
+
}
|
|
3343
|
+
const logEntry = `${fileTime} ${this.environment}.INFO: [BOX] ${message}
|
|
3344
|
+
`.replace(this.ANSI_PATTERN, "");
|
|
3345
|
+
await this.writeToFile(logEntry);
|
|
3346
|
+
}
|
|
3347
|
+
async prompt(message) {
|
|
3348
|
+
if (isBrowserProcess2()) {
|
|
3349
|
+
return Promise.resolve(true);
|
|
3350
|
+
}
|
|
3351
|
+
return new Promise((resolve32) => {
|
|
3352
|
+
console.error(`${styles2.cyan("?")} ${message} (y/n) `);
|
|
3353
|
+
const onData = (data) => {
|
|
3354
|
+
const input = data.toString().trim().toLowerCase();
|
|
3355
|
+
process52.stdin.removeListener("data", onData);
|
|
3356
|
+
try {
|
|
3357
|
+
if (typeof process52.stdin.setRawMode === "function") {
|
|
3358
|
+
process52.stdin.setRawMode(false);
|
|
3359
|
+
}
|
|
3360
|
+
} catch {}
|
|
3361
|
+
process52.stdin.pause();
|
|
3362
|
+
console.error("");
|
|
3363
|
+
resolve32(input === "y" || input === "yes");
|
|
3364
|
+
};
|
|
3365
|
+
try {
|
|
3366
|
+
if (typeof process52.stdin.setRawMode === "function") {
|
|
3367
|
+
process52.stdin.setRawMode(true);
|
|
3368
|
+
}
|
|
3369
|
+
} catch {}
|
|
3370
|
+
process52.stdin.resume();
|
|
3371
|
+
process52.stdin.once("data", onData);
|
|
3372
|
+
});
|
|
3373
|
+
}
|
|
3374
|
+
setFancy(enabled) {
|
|
3375
|
+
this.fancy = enabled;
|
|
3376
|
+
}
|
|
3377
|
+
isFancy() {
|
|
3378
|
+
return this.fancy;
|
|
3379
|
+
}
|
|
3380
|
+
pause() {
|
|
3381
|
+
this.enabled = false;
|
|
3382
|
+
}
|
|
3383
|
+
resume() {
|
|
3384
|
+
this.enabled = true;
|
|
3385
|
+
}
|
|
3386
|
+
async start(message, ...args) {
|
|
3387
|
+
if (!this.enabled)
|
|
3388
|
+
return;
|
|
3389
|
+
let formattedMessage = message;
|
|
3390
|
+
if (args && args.length > 0) {
|
|
3391
|
+
const formatRegex = /%([sdijfo%])/g;
|
|
3392
|
+
let argIndex = 0;
|
|
3393
|
+
formattedMessage = message.replace(formatRegex, (match, type) => {
|
|
3394
|
+
if (type === "%")
|
|
3395
|
+
return "%";
|
|
3396
|
+
if (argIndex >= args.length)
|
|
3397
|
+
return match;
|
|
3398
|
+
const arg = args[argIndex++];
|
|
3399
|
+
switch (type) {
|
|
3400
|
+
case "s":
|
|
3401
|
+
return String(arg);
|
|
3402
|
+
case "d":
|
|
3403
|
+
case "i":
|
|
3404
|
+
return Number(arg).toString();
|
|
3405
|
+
case "j":
|
|
3406
|
+
case "o":
|
|
3407
|
+
return JSON.stringify(arg, null, 2);
|
|
3408
|
+
default:
|
|
3409
|
+
return match;
|
|
3410
|
+
}
|
|
3411
|
+
});
|
|
3412
|
+
if (argIndex < args.length) {
|
|
3413
|
+
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
if (this.fancy && !isBrowserProcess2()) {
|
|
3417
|
+
const tag = this.options.showTags !== false && this.name ? styles2.gray(this.formatTag(this.name)) : "";
|
|
3418
|
+
const spinnerChar = styles2.blue("\u25D0");
|
|
3419
|
+
console.error(`${spinnerChar} ${tag} ${styles2.cyan(formattedMessage)}`);
|
|
3420
|
+
}
|
|
3421
|
+
const timestamp = new Date;
|
|
3422
|
+
const formattedDate = timestamp.toISOString();
|
|
3423
|
+
const logEntry = `[${formattedDate}] ${this.environment}.INFO: [START] ${formattedMessage}
|
|
3424
|
+
`.replace(this.ANSI_PATTERN, "");
|
|
3425
|
+
await this.writeToFile(logEntry);
|
|
3426
|
+
}
|
|
3427
|
+
progress(total, initialMessage = "") {
|
|
3428
|
+
if (!this.enabled || !this.fancy || isBrowserProcess2() || total <= 0) {
|
|
3429
|
+
return {
|
|
3430
|
+
update: () => {},
|
|
3431
|
+
finish: () => {},
|
|
3432
|
+
interrupt: () => {}
|
|
3433
|
+
};
|
|
3434
|
+
}
|
|
3435
|
+
if (this.activeProgressBar) {
|
|
3436
|
+
console.warn("Warning: Another progress bar is already active. Finishing the previous one.");
|
|
3437
|
+
this.finishProgressBar(this.activeProgressBar, "[Auto-finished]");
|
|
3438
|
+
}
|
|
3439
|
+
const barLength = 20;
|
|
3440
|
+
this.activeProgressBar = {
|
|
3441
|
+
total,
|
|
3442
|
+
current: 0,
|
|
3443
|
+
message: initialMessage,
|
|
3444
|
+
barLength,
|
|
3445
|
+
lastRenderedLine: ""
|
|
3446
|
+
};
|
|
3447
|
+
this.renderProgressBar(this.activeProgressBar);
|
|
3448
|
+
const update = (current, message) => {
|
|
3449
|
+
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess2())
|
|
3450
|
+
return;
|
|
3451
|
+
this.activeProgressBar.current = Math.max(0, Math.min(total, current));
|
|
3452
|
+
if (message !== undefined) {
|
|
3453
|
+
this.activeProgressBar.message = message;
|
|
3454
|
+
}
|
|
3455
|
+
const isFinished = this.activeProgressBar.current === this.activeProgressBar.total;
|
|
3456
|
+
this.renderProgressBar(this.activeProgressBar, isFinished);
|
|
3457
|
+
};
|
|
3458
|
+
const finish = (message) => {
|
|
3459
|
+
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess2())
|
|
3460
|
+
return;
|
|
3461
|
+
this.activeProgressBar.current = this.activeProgressBar.total;
|
|
3462
|
+
if (message !== undefined) {
|
|
3463
|
+
this.activeProgressBar.message = message;
|
|
3464
|
+
}
|
|
3465
|
+
this.renderProgressBar(this.activeProgressBar, true);
|
|
3466
|
+
this.finishProgressBar(this.activeProgressBar);
|
|
3467
|
+
};
|
|
3468
|
+
const interrupt = (interruptMessage, level = "info") => {
|
|
3469
|
+
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess2())
|
|
3470
|
+
return;
|
|
3471
|
+
process52.stdout.write(`${"\r".padEnd(process52.stdout.columns || 80)}\r`);
|
|
3472
|
+
this.log(level, interruptMessage);
|
|
3473
|
+
setTimeout(() => {
|
|
3474
|
+
if (this.activeProgressBar) {
|
|
3475
|
+
this.renderProgressBar(this.activeProgressBar);
|
|
3476
|
+
}
|
|
3477
|
+
}, 50);
|
|
3478
|
+
};
|
|
3479
|
+
return { update, finish, interrupt };
|
|
3480
|
+
}
|
|
3481
|
+
renderProgressBar(barState, isFinished = false) {
|
|
3482
|
+
if (!this.enabled || !this.fancy || isBrowserProcess2() || !process52.stdout.isTTY)
|
|
3483
|
+
return;
|
|
3484
|
+
const percent = Math.min(100, Math.max(0, Math.round(barState.current / barState.total * 100)));
|
|
3485
|
+
const filledLength = Math.round(barState.barLength * percent / 100);
|
|
3486
|
+
const emptyLength = barState.barLength - filledLength;
|
|
3487
|
+
const filledBar = styles2.green("\u2501".repeat(filledLength));
|
|
3488
|
+
const emptyBar = styles2.gray("\u2501".repeat(emptyLength));
|
|
3489
|
+
const bar = `[${filledBar}${emptyBar}]`;
|
|
3490
|
+
const percentageText = `${percent}%`.padStart(4);
|
|
3491
|
+
const messageText = barState.message ? ` ${barState.message}` : "";
|
|
3492
|
+
const icon = isFinished || percent === 100 ? styles2.green("\u2713") : styles2.blue("\u25B6");
|
|
3493
|
+
const tag = this.options.showTags !== false && this.name ? ` ${styles2.gray(this.formatTag(this.name))}` : "";
|
|
3494
|
+
const line = `\r${icon}${tag} ${bar} ${percentageText}${messageText}`;
|
|
3495
|
+
const terminalWidth = process52.stdout.columns || 80;
|
|
3496
|
+
const clearLine = " ".repeat(Math.max(0, terminalWidth - line.replace(this.ANSI_PATTERN, "").length));
|
|
3497
|
+
barState.lastRenderedLine = `${line}${clearLine}`;
|
|
3498
|
+
process52.stdout.write(barState.lastRenderedLine);
|
|
3499
|
+
if (isFinished) {
|
|
3500
|
+
process52.stdout.write(`
|
|
3501
|
+
`);
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
finishProgressBar(barState, finalMessage) {
|
|
3505
|
+
if (!this.enabled || !this.fancy || isBrowserProcess2() || !process52.stdout.isTTY) {
|
|
3506
|
+
this.activeProgressBar = null;
|
|
3507
|
+
return;
|
|
3508
|
+
}
|
|
3509
|
+
if (barState.current < barState.total) {
|
|
3510
|
+
barState.current = barState.total;
|
|
3511
|
+
}
|
|
3512
|
+
if (finalMessage)
|
|
3513
|
+
barState.message = finalMessage;
|
|
3514
|
+
this.renderProgressBar(barState, true);
|
|
3515
|
+
this.activeProgressBar = null;
|
|
3516
|
+
}
|
|
3517
|
+
async clear(filters = {}) {
|
|
3518
|
+
if (isBrowserProcess2()) {
|
|
3519
|
+
console.warn("Log clearing is not supported in browser environments.");
|
|
3520
|
+
return;
|
|
3521
|
+
}
|
|
3522
|
+
try {
|
|
3523
|
+
console.warn("Clearing logs...", this.config.logDirectory);
|
|
3524
|
+
const files = await readdir2(this.config.logDirectory);
|
|
3525
|
+
const logFilesToDelete = [];
|
|
3526
|
+
for (const file of files) {
|
|
3527
|
+
const nameMatches = filters.name ? new RegExp(filters.name.replace("*", ".*")).test(file) : file.startsWith(this.name);
|
|
3528
|
+
if (!nameMatches || !file.endsWith(".log")) {
|
|
3529
|
+
continue;
|
|
3530
|
+
}
|
|
3531
|
+
const filePath = join22(this.config.logDirectory, file);
|
|
3532
|
+
if (filters.before) {
|
|
3533
|
+
try {
|
|
3534
|
+
const fileStats = await stat2(filePath);
|
|
3535
|
+
if (fileStats.mtime >= filters.before) {
|
|
3536
|
+
continue;
|
|
3537
|
+
}
|
|
3538
|
+
} catch (statErr) {
|
|
3539
|
+
console.error(`Failed to get stats for file ${filePath}:`, statErr);
|
|
3540
|
+
continue;
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
logFilesToDelete.push(filePath);
|
|
3544
|
+
}
|
|
3545
|
+
if (logFilesToDelete.length === 0) {
|
|
3546
|
+
console.warn("No log files matched the criteria for clearing.");
|
|
3547
|
+
return;
|
|
3548
|
+
}
|
|
3549
|
+
console.warn(`Preparing to delete ${logFilesToDelete.length} log file(s)...`);
|
|
3550
|
+
for (const filePath of logFilesToDelete) {
|
|
3551
|
+
try {
|
|
3552
|
+
await unlink2(filePath);
|
|
3553
|
+
console.warn(`Deleted log file: ${filePath}`);
|
|
3554
|
+
} catch (unlinkErr) {
|
|
3555
|
+
console.error(`Failed to delete log file ${filePath}:`, unlinkErr);
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3558
|
+
console.warn("Log clearing process finished.");
|
|
3559
|
+
} catch (err) {
|
|
3560
|
+
console.error("Error during log clearing process:", err);
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
}
|
|
3564
|
+
var logger2 = new Logger2("stacks");
|
|
3565
|
+
function deepMerge22(target, source) {
|
|
3566
|
+
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) {
|
|
3567
|
+
return source;
|
|
3568
|
+
}
|
|
3569
|
+
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) {
|
|
2107
3570
|
return { a: null, b: 2, c: undefined };
|
|
2108
3571
|
}
|
|
2109
3572
|
if (source === null || source === undefined) {
|
|
@@ -2113,23 +3576,23 @@ function deepMerge2(target, source) {
|
|
|
2113
3576
|
return source;
|
|
2114
3577
|
}
|
|
2115
3578
|
if (Array.isArray(source) && Array.isArray(target)) {
|
|
2116
|
-
if (
|
|
3579
|
+
if (isObject22(target) && "arr" in target && Array.isArray(target.arr) && isObject22(source) && "arr" in source && Array.isArray(source.arr)) {
|
|
2117
3580
|
return source;
|
|
2118
3581
|
}
|
|
2119
|
-
if (source.length > 0 && target.length > 0 &&
|
|
3582
|
+
if (source.length > 0 && target.length > 0 && isObject22(source[0]) && isObject22(target[0])) {
|
|
2120
3583
|
const result = [...source];
|
|
2121
3584
|
for (const targetItem of target) {
|
|
2122
|
-
if (
|
|
2123
|
-
const existingItem = result.find((item) =>
|
|
3585
|
+
if (isObject22(targetItem) && "name" in targetItem) {
|
|
3586
|
+
const existingItem = result.find((item) => isObject22(item) && ("name" in item) && item.name === targetItem.name);
|
|
2124
3587
|
if (!existingItem) {
|
|
2125
3588
|
result.push(targetItem);
|
|
2126
3589
|
}
|
|
2127
|
-
} else if (
|
|
2128
|
-
const existingItem = result.find((item) =>
|
|
3590
|
+
} else if (isObject22(targetItem) && "path" in targetItem) {
|
|
3591
|
+
const existingItem = result.find((item) => isObject22(item) && ("path" in item) && item.path === targetItem.path);
|
|
2129
3592
|
if (!existingItem) {
|
|
2130
3593
|
result.push(targetItem);
|
|
2131
3594
|
}
|
|
2132
|
-
} else if (!result.some((item) =>
|
|
3595
|
+
} else if (!result.some((item) => deepEquals22(item, targetItem))) {
|
|
2133
3596
|
result.push(targetItem);
|
|
2134
3597
|
}
|
|
2135
3598
|
}
|
|
@@ -2146,7 +3609,7 @@ function deepMerge2(target, source) {
|
|
|
2146
3609
|
}
|
|
2147
3610
|
return source;
|
|
2148
3611
|
}
|
|
2149
|
-
if (!
|
|
3612
|
+
if (!isObject22(source) || !isObject22(target)) {
|
|
2150
3613
|
return source;
|
|
2151
3614
|
}
|
|
2152
3615
|
const merged = { ...target };
|
|
@@ -2155,23 +3618,23 @@ function deepMerge2(target, source) {
|
|
|
2155
3618
|
const sourceValue = source[key];
|
|
2156
3619
|
if (sourceValue === null || sourceValue === undefined) {
|
|
2157
3620
|
continue;
|
|
2158
|
-
} else if (
|
|
2159
|
-
merged[key] =
|
|
3621
|
+
} else if (isObject22(sourceValue) && isObject22(merged[key])) {
|
|
3622
|
+
merged[key] = deepMerge22(merged[key], sourceValue);
|
|
2160
3623
|
} else if (Array.isArray(sourceValue) && Array.isArray(merged[key])) {
|
|
2161
|
-
if (sourceValue.length > 0 && merged[key].length > 0 &&
|
|
3624
|
+
if (sourceValue.length > 0 && merged[key].length > 0 && isObject22(sourceValue[0]) && isObject22(merged[key][0])) {
|
|
2162
3625
|
const result = [...sourceValue];
|
|
2163
3626
|
for (const targetItem of merged[key]) {
|
|
2164
|
-
if (
|
|
2165
|
-
const existingItem = result.find((item) =>
|
|
3627
|
+
if (isObject22(targetItem) && "name" in targetItem) {
|
|
3628
|
+
const existingItem = result.find((item) => isObject22(item) && ("name" in item) && item.name === targetItem.name);
|
|
2166
3629
|
if (!existingItem) {
|
|
2167
3630
|
result.push(targetItem);
|
|
2168
3631
|
}
|
|
2169
|
-
} else if (
|
|
2170
|
-
const existingItem = result.find((item) =>
|
|
3632
|
+
} else if (isObject22(targetItem) && "path" in targetItem) {
|
|
3633
|
+
const existingItem = result.find((item) => isObject22(item) && ("path" in item) && item.path === targetItem.path);
|
|
2171
3634
|
if (!existingItem) {
|
|
2172
3635
|
result.push(targetItem);
|
|
2173
3636
|
}
|
|
2174
|
-
} else if (!result.some((item) =>
|
|
3637
|
+
} else if (!result.some((item) => deepEquals22(item, targetItem))) {
|
|
2175
3638
|
result.push(targetItem);
|
|
2176
3639
|
}
|
|
2177
3640
|
}
|
|
@@ -2194,19 +3657,19 @@ function deepMerge2(target, source) {
|
|
|
2194
3657
|
}
|
|
2195
3658
|
return merged;
|
|
2196
3659
|
}
|
|
2197
|
-
function
|
|
3660
|
+
function deepEquals22(a, b) {
|
|
2198
3661
|
if (a === b)
|
|
2199
3662
|
return true;
|
|
2200
3663
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2201
3664
|
if (a.length !== b.length)
|
|
2202
3665
|
return false;
|
|
2203
3666
|
for (let i = 0;i < a.length; i++) {
|
|
2204
|
-
if (!
|
|
3667
|
+
if (!deepEquals22(a[i], b[i]))
|
|
2205
3668
|
return false;
|
|
2206
3669
|
}
|
|
2207
3670
|
return true;
|
|
2208
3671
|
}
|
|
2209
|
-
if (
|
|
3672
|
+
if (isObject22(a) && isObject22(b)) {
|
|
2210
3673
|
const keysA = Object.keys(a);
|
|
2211
3674
|
const keysB = Object.keys(b);
|
|
2212
3675
|
if (keysA.length !== keysB.length)
|
|
@@ -2214,17 +3677,34 @@ function deepEquals2(a, b) {
|
|
|
2214
3677
|
for (const key of keysA) {
|
|
2215
3678
|
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
2216
3679
|
return false;
|
|
2217
|
-
if (!
|
|
3680
|
+
if (!deepEquals22(a[key], b[key]))
|
|
2218
3681
|
return false;
|
|
2219
3682
|
}
|
|
2220
3683
|
return true;
|
|
2221
3684
|
}
|
|
2222
3685
|
return false;
|
|
2223
3686
|
}
|
|
2224
|
-
function
|
|
3687
|
+
function isObject22(item) {
|
|
2225
3688
|
return Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
2226
3689
|
}
|
|
2227
|
-
|
|
3690
|
+
var log = new Logger2("bunfig", {
|
|
3691
|
+
showTags: true
|
|
3692
|
+
});
|
|
3693
|
+
async function config22(nameOrOptions = { defaultConfig: {} }) {
|
|
3694
|
+
if (typeof nameOrOptions === "string") {
|
|
3695
|
+
const { cwd } = await import("process");
|
|
3696
|
+
return await loadConfig32({
|
|
3697
|
+
name: nameOrOptions,
|
|
3698
|
+
cwd: cwd(),
|
|
3699
|
+
generatedDir: "./generated",
|
|
3700
|
+
configDir: "./config",
|
|
3701
|
+
defaultConfig: {},
|
|
3702
|
+
checkEnv: true
|
|
3703
|
+
});
|
|
3704
|
+
}
|
|
3705
|
+
return await loadConfig32(nameOrOptions);
|
|
3706
|
+
}
|
|
3707
|
+
async function tryLoadConfig22(configPath, defaultConfig22) {
|
|
2228
3708
|
if (!existsSync3(configPath))
|
|
2229
3709
|
return null;
|
|
2230
3710
|
try {
|
|
@@ -2233,7 +3713,7 @@ async function tryLoadConfig2(configPath, defaultConfig2) {
|
|
|
2233
3713
|
if (typeof loadedConfig !== "object" || loadedConfig === null || Array.isArray(loadedConfig))
|
|
2234
3714
|
return null;
|
|
2235
3715
|
try {
|
|
2236
|
-
return
|
|
3716
|
+
return deepMerge22(defaultConfig22, loadedConfig);
|
|
2237
3717
|
} catch {
|
|
2238
3718
|
return null;
|
|
2239
3719
|
}
|
|
@@ -2241,25 +3721,87 @@ async function tryLoadConfig2(configPath, defaultConfig2) {
|
|
|
2241
3721
|
return null;
|
|
2242
3722
|
}
|
|
2243
3723
|
}
|
|
2244
|
-
|
|
3724
|
+
function applyEnvVarsToConfig(name, config3, verbose = false) {
|
|
3725
|
+
if (!name)
|
|
3726
|
+
return config3;
|
|
3727
|
+
const envPrefix = name.toUpperCase().replace(/-/g, "_");
|
|
3728
|
+
const result = { ...config3 };
|
|
3729
|
+
function processObject(obj, path = []) {
|
|
3730
|
+
const result2 = { ...obj };
|
|
3731
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
3732
|
+
const envPath = [...path, key];
|
|
3733
|
+
const formatKey = (k) => k.replace(/([A-Z])/g, "_$1").toUpperCase();
|
|
3734
|
+
const envKey = `${envPrefix}_${envPath.map(formatKey).join("_")}`;
|
|
3735
|
+
const oldEnvKey = `${envPrefix}_${envPath.map((p) => p.toUpperCase()).join("_")}`;
|
|
3736
|
+
if (verbose)
|
|
3737
|
+
log.info(`Checking environment variable ${envKey} for config ${name}.${envPath.join(".")}`);
|
|
3738
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
3739
|
+
result2[key] = processObject(value, envPath);
|
|
3740
|
+
} else {
|
|
3741
|
+
const envValue = process8.env[envKey] || process8.env[oldEnvKey];
|
|
3742
|
+
if (envValue !== undefined) {
|
|
3743
|
+
if (verbose) {
|
|
3744
|
+
log.info(`Using environment variable ${envValue ? envKey : oldEnvKey} for config ${name}.${envPath.join(".")}`);
|
|
3745
|
+
}
|
|
3746
|
+
if (typeof value === "number") {
|
|
3747
|
+
result2[key] = Number(envValue);
|
|
3748
|
+
} else if (typeof value === "boolean") {
|
|
3749
|
+
result2[key] = envValue.toLowerCase() === "true";
|
|
3750
|
+
} else if (Array.isArray(value)) {
|
|
3751
|
+
try {
|
|
3752
|
+
const parsed = JSON.parse(envValue);
|
|
3753
|
+
if (Array.isArray(parsed)) {
|
|
3754
|
+
result2[key] = parsed;
|
|
3755
|
+
} else {
|
|
3756
|
+
result2[key] = envValue.split(",").map((item) => item.trim());
|
|
3757
|
+
}
|
|
3758
|
+
} catch {
|
|
3759
|
+
result2[key] = envValue.split(",").map((item) => item.trim());
|
|
3760
|
+
}
|
|
3761
|
+
} else {
|
|
3762
|
+
result2[key] = envValue;
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
return result2;
|
|
3768
|
+
}
|
|
3769
|
+
return processObject(result);
|
|
3770
|
+
}
|
|
3771
|
+
async function loadConfig32({
|
|
2245
3772
|
name = "",
|
|
3773
|
+
alias,
|
|
2246
3774
|
cwd,
|
|
2247
|
-
defaultConfig:
|
|
3775
|
+
defaultConfig: defaultConfig22,
|
|
3776
|
+
verbose = false,
|
|
3777
|
+
checkEnv = true
|
|
2248
3778
|
}) {
|
|
2249
|
-
const
|
|
3779
|
+
const configWithEnvVars = checkEnv && typeof defaultConfig22 === "object" && defaultConfig22 !== null && !Array.isArray(defaultConfig22) ? applyEnvVarsToConfig(name, defaultConfig22, verbose) : defaultConfig22;
|
|
3780
|
+
const baseDir = cwd || process8.cwd();
|
|
2250
3781
|
const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
3782
|
+
if (verbose) {
|
|
3783
|
+
log.info(`Loading configuration for "${name}"${alias ? ` (alias: "${alias}")` : ""} from ${baseDir}`);
|
|
3784
|
+
}
|
|
3785
|
+
const configPatterns = [];
|
|
3786
|
+
configPatterns.push(`${name}.config`);
|
|
3787
|
+
configPatterns.push(`.${name}.config`);
|
|
3788
|
+
configPatterns.push(name);
|
|
3789
|
+
configPatterns.push(`.${name}`);
|
|
3790
|
+
if (alias) {
|
|
3791
|
+
configPatterns.push(`${alias}.config`);
|
|
3792
|
+
configPatterns.push(`.${alias}.config`);
|
|
3793
|
+
configPatterns.push(alias);
|
|
3794
|
+
configPatterns.push(`.${alias}`);
|
|
3795
|
+
}
|
|
3796
|
+
for (const configPath of configPatterns) {
|
|
2258
3797
|
for (const ext of extensions) {
|
|
2259
3798
|
const fullPath = resolve3(baseDir, `${configPath}${ext}`);
|
|
2260
|
-
const
|
|
2261
|
-
if (
|
|
2262
|
-
|
|
3799
|
+
const config3 = await tryLoadConfig22(fullPath, configWithEnvVars);
|
|
3800
|
+
if (config3 !== null) {
|
|
3801
|
+
if (verbose) {
|
|
3802
|
+
log.success(`Configuration loaded from: ${configPath}${ext}`);
|
|
3803
|
+
}
|
|
3804
|
+
return config3;
|
|
2263
3805
|
}
|
|
2264
3806
|
}
|
|
2265
3807
|
}
|
|
@@ -2267,21 +3809,41 @@ async function loadConfig3({
|
|
|
2267
3809
|
const pkgPath = resolve3(baseDir, "package.json");
|
|
2268
3810
|
if (existsSync3(pkgPath)) {
|
|
2269
3811
|
const pkg = await import(pkgPath);
|
|
2270
|
-
|
|
3812
|
+
let pkgConfig = pkg[name];
|
|
3813
|
+
if (!pkgConfig && alias) {
|
|
3814
|
+
pkgConfig = pkg[alias];
|
|
3815
|
+
if (pkgConfig && verbose) {
|
|
3816
|
+
log.success(`Using alias "${alias}" configuration from package.json`);
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
2271
3819
|
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
2272
3820
|
try {
|
|
2273
|
-
|
|
2274
|
-
|
|
3821
|
+
if (verbose) {
|
|
3822
|
+
log.success(`Configuration loaded from package.json: ${pkgConfig === pkg[name] ? name : alias}`);
|
|
3823
|
+
}
|
|
3824
|
+
return deepMerge22(configWithEnvVars, pkgConfig);
|
|
3825
|
+
} catch (error) {
|
|
3826
|
+
if (verbose) {
|
|
3827
|
+
log.warn(`Failed to merge package.json config:`, error);
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
2275
3830
|
}
|
|
2276
3831
|
}
|
|
2277
|
-
} catch {
|
|
2278
|
-
|
|
3832
|
+
} catch (error) {
|
|
3833
|
+
if (verbose) {
|
|
3834
|
+
log.warn(`Failed to load package.json:`, error);
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
if (verbose) {
|
|
3838
|
+
log.info(`No configuration found for "${name}"${alias ? ` or alias "${alias}"` : ""}, using default configuration with environment variables`);
|
|
3839
|
+
}
|
|
3840
|
+
return configWithEnvVars;
|
|
2279
3841
|
}
|
|
2280
|
-
var
|
|
2281
|
-
var
|
|
3842
|
+
var defaultConfigDir22 = resolve3(process8.cwd(), "config");
|
|
3843
|
+
var defaultGeneratedDir22 = resolve3(process8.cwd(), "src/generated");
|
|
2282
3844
|
|
|
2283
3845
|
// git-hooks.config.ts
|
|
2284
|
-
var
|
|
3846
|
+
var config3 = {
|
|
2285
3847
|
"pre-commit": {
|
|
2286
3848
|
"staged-lint": {
|
|
2287
3849
|
"**/*.{js,ts}": [
|
|
@@ -2293,12 +3855,12 @@ var config2 = {
|
|
|
2293
3855
|
"commit-msg": "bunx gitlint .git/COMMIT_EDITMSG",
|
|
2294
3856
|
verbose: true
|
|
2295
3857
|
};
|
|
2296
|
-
var git_hooks_config_default =
|
|
3858
|
+
var git_hooks_config_default = config3;
|
|
2297
3859
|
|
|
2298
3860
|
// src/config.ts
|
|
2299
|
-
var
|
|
3861
|
+
var config4 = await config22({
|
|
2300
3862
|
name: "git-hooks",
|
|
2301
|
-
cwd:
|
|
3863
|
+
cwd: process9.cwd(),
|
|
2302
3864
|
defaultConfig: git_hooks_config_default
|
|
2303
3865
|
});
|
|
2304
3866
|
|
|
@@ -2306,7 +3868,7 @@ var config3 = await loadConfig3({
|
|
|
2306
3868
|
import { exec } from "child_process";
|
|
2307
3869
|
import { promisify } from "util";
|
|
2308
3870
|
var execAsync = promisify(exec);
|
|
2309
|
-
var
|
|
3871
|
+
var log2 = new Logger("git-hooks", {
|
|
2310
3872
|
showTags: true
|
|
2311
3873
|
});
|
|
2312
3874
|
var VALID_GIT_HOOKS = [
|
|
@@ -2352,7 +3914,7 @@ if [ -f "$BUN_GIT_HOOKS_RC" ]; then
|
|
|
2352
3914
|
fi
|
|
2353
3915
|
|
|
2354
3916
|
`;
|
|
2355
|
-
function getGitProjectRoot(directory =
|
|
3917
|
+
function getGitProjectRoot(directory = process11.cwd()) {
|
|
2356
3918
|
if (directory.endsWith(".git")) {
|
|
2357
3919
|
return path.normalize(directory);
|
|
2358
3920
|
}
|
|
@@ -2383,10 +3945,10 @@ function getGitProjectRoot(directory = process9.cwd()) {
|
|
|
2383
3945
|
}
|
|
2384
3946
|
return getGitProjectRoot(parentDir);
|
|
2385
3947
|
}
|
|
2386
|
-
function setHooksFromConfig(projectRootPath =
|
|
2387
|
-
if (!
|
|
3948
|
+
function setHooksFromConfig(projectRootPath = process11.cwd(), options) {
|
|
3949
|
+
if (!config4 || Object.keys(config4).length === 0)
|
|
2388
3950
|
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");
|
|
2389
|
-
const configFile = options?.configFile || { ...
|
|
3951
|
+
const configFile = options?.configFile || { ...config4 };
|
|
2390
3952
|
_validateStagedLintConfig(configFile);
|
|
2391
3953
|
const hookKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key));
|
|
2392
3954
|
const isValidConfig = hookKeys.every((key) => VALID_GIT_HOOKS.includes(key));
|
|
@@ -2394,7 +3956,7 @@ function setHooksFromConfig(projectRootPath = process9.cwd(), options) {
|
|
|
2394
3956
|
throw new Error("[ERROR] Config was not in correct format. Please check git hooks or options name");
|
|
2395
3957
|
const preserveUnused = Array.isArray(configFile.preserveUnused) ? configFile.preserveUnused : configFile.preserveUnused ? VALID_GIT_HOOKS : [];
|
|
2396
3958
|
const logKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key)).sort().map((key) => italic(key)).join(", ");
|
|
2397
|
-
|
|
3959
|
+
log2.debug(`Hook Keys: ${logKeys}`);
|
|
2398
3960
|
for (const hook of VALID_GIT_HOOKS) {
|
|
2399
3961
|
if (Object.prototype.hasOwnProperty.call(configFile, hook)) {
|
|
2400
3962
|
if (!configFile[hook])
|
|
@@ -2405,12 +3967,12 @@ function setHooksFromConfig(projectRootPath = process9.cwd(), options) {
|
|
|
2405
3967
|
}
|
|
2406
3968
|
}
|
|
2407
3969
|
}
|
|
2408
|
-
async function getStagedFiles(projectRoot =
|
|
3970
|
+
async function getStagedFiles(projectRoot = process11.cwd()) {
|
|
2409
3971
|
try {
|
|
2410
3972
|
const { stdout } = await execAsync("git diff --cached --name-only --diff-filter=ACMR", { cwd: projectRoot });
|
|
2411
3973
|
const files = stdout.trim().split(`
|
|
2412
3974
|
`).filter(Boolean);
|
|
2413
|
-
if (
|
|
3975
|
+
if (config4.verbose && files.length > 0) {
|
|
2414
3976
|
console.info("[INFO] Staged files found:", files);
|
|
2415
3977
|
}
|
|
2416
3978
|
return files;
|
|
@@ -2455,7 +4017,7 @@ function filterFilesByPattern(files, pattern) {
|
|
|
2455
4017
|
return isIncluded && !isExcluded;
|
|
2456
4018
|
});
|
|
2457
4019
|
}
|
|
2458
|
-
async function runCommandOnStagedFiles(command, files, projectRoot =
|
|
4020
|
+
async function runCommandOnStagedFiles(command, files, projectRoot = process11.cwd(), verbose = false) {
|
|
2459
4021
|
if (files.length === 0) {
|
|
2460
4022
|
if (verbose)
|
|
2461
4023
|
console.info("[INFO] No matching files for pattern");
|
|
@@ -2507,7 +4069,7 @@ async function processStagedLint(stagedLintConfig, projectRoot, verbose = false)
|
|
|
2507
4069
|
}
|
|
2508
4070
|
return success;
|
|
2509
4071
|
}
|
|
2510
|
-
function _setHook(hook, commandOrConfig, projectRoot =
|
|
4072
|
+
function _setHook(hook, commandOrConfig, projectRoot = process11.cwd()) {
|
|
2511
4073
|
const gitRoot = getGitProjectRoot(projectRoot);
|
|
2512
4074
|
if (!gitRoot) {
|
|
2513
4075
|
console.info("[INFO] No `.git` root folder found, skipping");
|
|
@@ -2517,7 +4079,7 @@ function _setHook(hook, commandOrConfig, projectRoot = process9.cwd()) {
|
|
|
2517
4079
|
if (typeof commandOrConfig === "string") {
|
|
2518
4080
|
hookCommand = PREPEND_SCRIPT + commandOrConfig;
|
|
2519
4081
|
} else if (commandOrConfig.stagedLint || commandOrConfig["staged-lint"]) {
|
|
2520
|
-
hookCommand = PREPEND_SCRIPT + `git-hooks run-staged-lint ${hook}`;
|
|
4082
|
+
hookCommand = PREPEND_SCRIPT + `bun git-hooks run-staged-lint ${hook}`;
|
|
2521
4083
|
} else {
|
|
2522
4084
|
console.error(`[ERROR] Invalid command or config for hook ${hook}`);
|
|
2523
4085
|
return;
|
|
@@ -2528,26 +4090,26 @@ function _setHook(hook, commandOrConfig, projectRoot = process9.cwd()) {
|
|
|
2528
4090
|
fs.mkdirSync(hookDirectory, { recursive: true });
|
|
2529
4091
|
}
|
|
2530
4092
|
const addOrModify = fs.existsSync(hookPath) ? "Modify" : "Add";
|
|
2531
|
-
|
|
4093
|
+
log2.debug(`${addOrModify} ${italic(hook)} hook`);
|
|
2532
4094
|
fs.writeFileSync(hookPath, hookCommand, { mode: 493 });
|
|
2533
4095
|
}
|
|
2534
|
-
function removeHooks(projectRoot =
|
|
4096
|
+
function removeHooks(projectRoot = process11.cwd(), verbose = false) {
|
|
2535
4097
|
for (const configEntry of VALID_GIT_HOOKS)
|
|
2536
4098
|
_removeHook(configEntry, projectRoot, verbose);
|
|
2537
4099
|
}
|
|
2538
|
-
function _removeHook(hook, projectRoot =
|
|
4100
|
+
function _removeHook(hook, projectRoot = process11.cwd(), verbose = false) {
|
|
2539
4101
|
const gitRoot = getGitProjectRoot(projectRoot);
|
|
2540
4102
|
const hookPath = path.normalize(`${gitRoot}/hooks/${hook}`);
|
|
2541
4103
|
if (fs.existsSync(hookPath)) {
|
|
2542
|
-
|
|
4104
|
+
log2.debug(`Hook ${hook} is not set, removing!`);
|
|
2543
4105
|
fs.unlinkSync(hookPath);
|
|
2544
4106
|
}
|
|
2545
4107
|
if (verbose)
|
|
2546
|
-
|
|
4108
|
+
log2.success(`Successfully removed the ${hook} hook`);
|
|
2547
4109
|
}
|
|
2548
4110
|
async function runStagedLint(hook) {
|
|
2549
|
-
const projectRoot =
|
|
2550
|
-
const configFile =
|
|
4111
|
+
const projectRoot = process11.cwd();
|
|
4112
|
+
const configFile = config4;
|
|
2551
4113
|
if (!configFile) {
|
|
2552
4114
|
console.error(`[ERROR] No configuration found`);
|
|
2553
4115
|
return false;
|
|
@@ -2567,10 +4129,10 @@ async function runStagedLint(hook) {
|
|
|
2567
4129
|
console.error(`[ERROR] No staged lint configuration found for hook ${hook}`);
|
|
2568
4130
|
return false;
|
|
2569
4131
|
}
|
|
2570
|
-
function _validateStagedLintConfig(
|
|
4132
|
+
function _validateStagedLintConfig(config5) {
|
|
2571
4133
|
for (const hook of VALID_GIT_HOOKS) {
|
|
2572
|
-
if (hook !== "pre-commit" &&
|
|
2573
|
-
const hookConfig =
|
|
4134
|
+
if (hook !== "pre-commit" && config5[hook] && typeof config5[hook] === "object") {
|
|
4135
|
+
const hookConfig = config5[hook];
|
|
2574
4136
|
if (hookConfig["stagedLint"] || hookConfig["staged-lint"]) {
|
|
2575
4137
|
throw new Error(`staged-lint is only allowed in pre-commit hook. Found in ${hook} hook.`);
|
|
2576
4138
|
}
|
|
@@ -2580,60 +4142,60 @@ function _validateStagedLintConfig(config4) {
|
|
|
2580
4142
|
|
|
2581
4143
|
// bin/cli.ts
|
|
2582
4144
|
var cli = new CAC("git-hooks");
|
|
2583
|
-
var
|
|
4145
|
+
var log3 = new Logger("git-hooks", {
|
|
2584
4146
|
showTags: true
|
|
2585
4147
|
});
|
|
2586
|
-
var { SKIP_INSTALL_GIT_HOOKS } =
|
|
4148
|
+
var { SKIP_INSTALL_GIT_HOOKS } = process12.env;
|
|
2587
4149
|
if (["1", "true"].includes(SKIP_INSTALL_GIT_HOOKS || "")) {
|
|
2588
|
-
|
|
2589
|
-
|
|
4150
|
+
log3.info(`SKIP_INSTALL_GIT_HOOKS is set to "${SKIP_INSTALL_GIT_HOOKS}", skipping installing hooks.`);
|
|
4151
|
+
process12.exit(0);
|
|
2590
4152
|
}
|
|
2591
4153
|
cli.command("[configPath]", "Install git hooks, optionally from specified config file").option("--verbose", "Enable verbose logging").example("git-hooks").example("git-hooks ../src/config.ts").example("git-hooks --verbose").action(async (configPath, options) => {
|
|
2592
4154
|
try {
|
|
2593
4155
|
if (options?.verbose) {
|
|
2594
|
-
|
|
2595
|
-
|
|
4156
|
+
log3.debug(`Config path: ${configPath || "using default"}`);
|
|
4157
|
+
log3.debug(`Working directory: ${process12.cwd()}`);
|
|
2596
4158
|
}
|
|
2597
4159
|
if (configPath) {
|
|
2598
|
-
const
|
|
2599
|
-
setHooksFromConfig(
|
|
4160
|
+
const config5 = await import(configPath);
|
|
4161
|
+
setHooksFromConfig(process12.cwd(), { configFile: config5 });
|
|
2600
4162
|
} else {
|
|
2601
|
-
setHooksFromConfig(
|
|
4163
|
+
setHooksFromConfig(process12.cwd());
|
|
2602
4164
|
}
|
|
2603
|
-
|
|
4165
|
+
log3.success("Successfully set all git hooks");
|
|
2604
4166
|
} catch (err) {
|
|
2605
|
-
|
|
2606
|
-
|
|
4167
|
+
log3.error(err);
|
|
4168
|
+
process12.exit(1);
|
|
2607
4169
|
}
|
|
2608
4170
|
});
|
|
2609
4171
|
cli.command("uninstall", "Remove all git hooks").alias("remove").option("--verbose", "Enable verbose logging").example("git-hooks uninstall").example("git-hooks remove").example("git-hooks uninstall --verbose").action(async (options) => {
|
|
2610
4172
|
try {
|
|
2611
4173
|
if (options?.verbose) {
|
|
2612
|
-
|
|
4174
|
+
log3.debug(`Removing hooks from: ${process12.cwd()}`);
|
|
2613
4175
|
}
|
|
2614
|
-
removeHooks(
|
|
2615
|
-
|
|
4176
|
+
removeHooks(process12.cwd(), options?.verbose);
|
|
4177
|
+
log3.success("Successfully removed all git hooks");
|
|
2616
4178
|
} catch (err) {
|
|
2617
|
-
|
|
2618
|
-
|
|
4179
|
+
log3.error("Was not able to remove git hooks. Error:", err);
|
|
4180
|
+
process12.exit(1);
|
|
2619
4181
|
}
|
|
2620
4182
|
});
|
|
2621
4183
|
cli.command("run-staged-lint <hook>", "Run staged lint for a specific git hook").option("--verbose", "Enable verbose logging").example("git-hooks run-staged-lint pre-commit").example("git-hooks run-staged-lint pre-push --verbose").action(async (hook, options) => {
|
|
2622
4184
|
try {
|
|
2623
4185
|
if (options?.verbose) {
|
|
2624
|
-
|
|
2625
|
-
|
|
4186
|
+
log3.debug(`Running staged lint for hook: ${hook}`);
|
|
4187
|
+
log3.debug(`Working directory: ${process12.cwd()}`);
|
|
2626
4188
|
}
|
|
2627
4189
|
const success = await runStagedLint(hook);
|
|
2628
4190
|
if (success) {
|
|
2629
|
-
|
|
4191
|
+
log3.success("Staged lint completed successfully");
|
|
2630
4192
|
} else {
|
|
2631
|
-
|
|
2632
|
-
|
|
4193
|
+
log3.error("Staged lint failed");
|
|
4194
|
+
process12.exit(1);
|
|
2633
4195
|
}
|
|
2634
4196
|
} catch (err) {
|
|
2635
|
-
|
|
2636
|
-
|
|
4197
|
+
log3.error("Was not able to run staged lint. Error:", err);
|
|
4198
|
+
process12.exit(1);
|
|
2637
4199
|
}
|
|
2638
4200
|
});
|
|
2639
4201
|
cli.version(version);
|