@reliverse/relinka 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/main.d.ts +22 -1
- package/bin/main.js +58 -1
- package/bin/relinka-impl/deprecated/components/levels/levels.d.ts +13 -0
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/modes/basic.d.ts +3 -4
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/modes/basic.js +0 -1
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/modes/browser.d.ts +6 -6
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/modes/browser.js +3 -2
- package/bin/relinka-impl/deprecated/components/modes/shared.d.ts +2 -0
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/relinka-deprecated/mod.d.ts +3 -4
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/relinka-deprecated/mod.js +0 -1
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/relinka-deprecated/relinka.d.ts +18 -18
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/relinka-deprecated/relinka.js +6 -6
- package/bin/relinka-impl/deprecated/components/relinka-deprecated/relinka.test.d.ts +1 -0
- package/bin/relinka-impl/deprecated/components/relinka-deprecated/relinka.test.js +57 -0
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/reporters/basic.d.ts +3 -3
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/reporters/browser.d.ts +1 -1
- package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/reporters/fancy.d.ts +2 -2
- package/bin/relinka-impl/impl-mod.d.ts +20 -0
- package/bin/relinka-impl/impl-mod.js +454 -0
- package/bin/{libs/core/core-impl/deprecated/types/mod.d.ts → relinka-types.d.ts} +51 -7
- package/package.json +9 -76
- package/bin/libs/core/core-impl/deprecated/components/core/core.d.ts +0 -1
- package/bin/libs/core/core-impl/deprecated/components/core/core.js +0 -1
- package/bin/libs/core/core-impl/deprecated/components/levels/levels.d.ts +0 -26
- package/bin/libs/core/core-impl/deprecated/components/modes/shared.d.ts +0 -3
- package/bin/libs/core/core-impl/deprecated/utils/mod.d.ts +0 -3
- package/bin/libs/core/core-impl/deprecated/utils/mod.js +0 -9
- package/bin/libs/core/core-main.d.ts +0 -23
- package/bin/libs/core/core-main.js +0 -49
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/levels/levels.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/modes/shared.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/relinka-deprecated/logger.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/relinka-deprecated/logger.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/reporters/basic.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/reporters/browser.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/components/reporters/fancy.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/box.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/box.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/deprecatedColors.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/deprecatedColors.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/error.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/error.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/format.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/format.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/log.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/log.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/stream.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/stream.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/string.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/string.js +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/tree.d.ts +0 -0
- /package/bin/{libs/core/core-impl → relinka-impl}/deprecated/utils/tree.js +0 -0
- /package/bin/{libs/core/core-impl/deprecated/types/mod.js → relinka-types.js} +0 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { re } from "@reliverse/relico";
|
|
2
|
+
import { loadConfig } from "c12";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import { createJiti } from "jiti";
|
|
5
|
+
import path from "pathe";
|
|
6
|
+
const DEFAULT_RELINKA_CONFIG = {
|
|
7
|
+
debug: false,
|
|
8
|
+
dirs: {
|
|
9
|
+
dailyLogs: false,
|
|
10
|
+
logDir: ".reliverse",
|
|
11
|
+
maxLogFiles: 0,
|
|
12
|
+
specialDirs: {
|
|
13
|
+
distDirNames: ["dist", "dist-jsr", "dist-npm", "dist-libs"],
|
|
14
|
+
useParentConfigInDist: true
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
disableColors: false,
|
|
18
|
+
logFilePath: "relinka.log",
|
|
19
|
+
saveLogsToFile: false,
|
|
20
|
+
withTimestamp: false
|
|
21
|
+
};
|
|
22
|
+
const SUPPORTED_EXTENSIONS = [".ts", ".js", ".mjs", ".cjs", ".json"];
|
|
23
|
+
function isDebugEnabled(config) {
|
|
24
|
+
return config?.debug ?? DEFAULT_RELINKA_CONFIG.debug;
|
|
25
|
+
}
|
|
26
|
+
function isColorEnabled(config) {
|
|
27
|
+
return !(config?.disableColors ?? DEFAULT_RELINKA_CONFIG.disableColors);
|
|
28
|
+
}
|
|
29
|
+
function getLogDir(config) {
|
|
30
|
+
return config?.dirs?.logDir ?? DEFAULT_RELINKA_CONFIG.dirs.logDir;
|
|
31
|
+
}
|
|
32
|
+
function isDailyLogsEnabled(config) {
|
|
33
|
+
return config?.dirs?.dailyLogs ?? DEFAULT_RELINKA_CONFIG.dirs.dailyLogs;
|
|
34
|
+
}
|
|
35
|
+
function shouldSaveLogs(config) {
|
|
36
|
+
return config?.saveLogsToFile ?? DEFAULT_RELINKA_CONFIG.saveLogsToFile;
|
|
37
|
+
}
|
|
38
|
+
function getMaxLogFiles(config) {
|
|
39
|
+
return config?.dirs?.maxLogFiles ?? DEFAULT_RELINKA_CONFIG.dirs.maxLogFiles;
|
|
40
|
+
}
|
|
41
|
+
function getBaseLogName(config) {
|
|
42
|
+
return config?.logFilePath ?? DEFAULT_RELINKA_CONFIG.logFilePath;
|
|
43
|
+
}
|
|
44
|
+
const getEnvBoolean = (envVarName) => {
|
|
45
|
+
const value = process.env[envVarName];
|
|
46
|
+
if (value === void 0 || value === "") return void 0;
|
|
47
|
+
const lowerValue = value.toLowerCase().trim();
|
|
48
|
+
return !["0", "false"].includes(lowerValue);
|
|
49
|
+
};
|
|
50
|
+
const getEnvString = (envVarName) => {
|
|
51
|
+
return process.env[envVarName] || void 0;
|
|
52
|
+
};
|
|
53
|
+
const getEnvNumber = (envVarName) => {
|
|
54
|
+
const value = process.env[envVarName];
|
|
55
|
+
if (value === void 0) return void 0;
|
|
56
|
+
const parsed = Number.parseInt(value, 10);
|
|
57
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
58
|
+
};
|
|
59
|
+
const getEnvOverrides = () => {
|
|
60
|
+
const overrides = {};
|
|
61
|
+
const dirsOverride = {};
|
|
62
|
+
const specialDirsOverride = {};
|
|
63
|
+
const debug = getEnvBoolean("RELINKA_DEBUG");
|
|
64
|
+
if (debug !== void 0) overrides.debug = debug;
|
|
65
|
+
const withTimestamp = getEnvBoolean("RELINKA_TIMESTAMP");
|
|
66
|
+
if (withTimestamp !== void 0) overrides.withTimestamp = withTimestamp;
|
|
67
|
+
const disableColors = getEnvBoolean("RELINKA_DISABLE_COLORS");
|
|
68
|
+
if (disableColors !== void 0) overrides.disableColors = disableColors;
|
|
69
|
+
const saveLogsToFile = getEnvBoolean("RELINKA_SAVE_LOGS");
|
|
70
|
+
if (saveLogsToFile !== void 0) overrides.saveLogsToFile = saveLogsToFile;
|
|
71
|
+
const logFilePath = getEnvString("RELINKA_LOG_FILE");
|
|
72
|
+
if (logFilePath !== void 0) overrides.logFilePath = logFilePath;
|
|
73
|
+
const logDir = getEnvString("RELINKA_LOG_DIR");
|
|
74
|
+
if (logDir !== void 0) dirsOverride.logDir = logDir;
|
|
75
|
+
const dailyLogs = getEnvBoolean("RELINKA_DAILY_LOGS");
|
|
76
|
+
if (dailyLogs !== void 0) dirsOverride.dailyLogs = dailyLogs;
|
|
77
|
+
const maxLogFiles = getEnvNumber("RELINKA_MAX_LOG_FILES");
|
|
78
|
+
if (maxLogFiles !== void 0) dirsOverride.maxLogFiles = maxLogFiles;
|
|
79
|
+
const useParentConfig = getEnvBoolean("RELINKA_USE_PARENT_CONFIG");
|
|
80
|
+
if (useParentConfig !== void 0) {
|
|
81
|
+
specialDirsOverride.useParentConfigInDist = useParentConfig;
|
|
82
|
+
}
|
|
83
|
+
if (Object.keys(specialDirsOverride).length > 0) {
|
|
84
|
+
dirsOverride.specialDirs = specialDirsOverride;
|
|
85
|
+
}
|
|
86
|
+
if (Object.keys(dirsOverride).length > 0) {
|
|
87
|
+
overrides.dirs = dirsOverride;
|
|
88
|
+
}
|
|
89
|
+
return overrides;
|
|
90
|
+
};
|
|
91
|
+
let currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
92
|
+
let isConfigInitialized = false;
|
|
93
|
+
let resolveConfigPromise;
|
|
94
|
+
export const configPromise = new Promise((resolve) => {
|
|
95
|
+
resolveConfigPromise = resolve;
|
|
96
|
+
});
|
|
97
|
+
const findConfigFile = (basePath) => {
|
|
98
|
+
for (const ext of SUPPORTED_EXTENSIONS) {
|
|
99
|
+
const filePath = basePath + ext;
|
|
100
|
+
if (fs.existsSync(filePath)) {
|
|
101
|
+
return filePath;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return void 0;
|
|
105
|
+
};
|
|
106
|
+
const initializeConfig = async () => {
|
|
107
|
+
try {
|
|
108
|
+
const envOverrides = getEnvOverrides();
|
|
109
|
+
const projectRoot = process.cwd();
|
|
110
|
+
const reliverseDir = path.resolve(projectRoot, ".reliverse");
|
|
111
|
+
const configName = "relinka";
|
|
112
|
+
const resolveConfig = async (id, options) => {
|
|
113
|
+
if (id !== configName) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const effectiveCwd = options.cwd || projectRoot;
|
|
117
|
+
const _jitiRequire = createJiti(effectiveCwd, options.jitiOptions);
|
|
118
|
+
const loadAndExtract = async (filePath) => {
|
|
119
|
+
try {
|
|
120
|
+
const loadedModule = await _jitiRequire.import(filePath);
|
|
121
|
+
const configData = loadedModule.default || loadedModule;
|
|
122
|
+
return configData;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error(
|
|
125
|
+
`[Relinka Config Error] Failed to load or parse config from ${filePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
126
|
+
);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const reliverseBasePath = path.resolve(reliverseDir, configName);
|
|
131
|
+
const reliverseConfigFile = findConfigFile(reliverseBasePath);
|
|
132
|
+
if (reliverseConfigFile) {
|
|
133
|
+
const config = await loadAndExtract(reliverseConfigFile);
|
|
134
|
+
if (config !== null) {
|
|
135
|
+
return { config, source: reliverseConfigFile };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const rootBasePath = path.resolve(effectiveCwd, configName);
|
|
139
|
+
const rootConfigFile = findConfigFile(rootBasePath);
|
|
140
|
+
if (rootConfigFile) {
|
|
141
|
+
const config = await loadAndExtract(rootConfigFile);
|
|
142
|
+
if (config !== null) {
|
|
143
|
+
return { config, source: rootConfigFile };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
};
|
|
148
|
+
const loadedConfigResult = await loadConfig({
|
|
149
|
+
name: configName,
|
|
150
|
+
cwd: projectRoot,
|
|
151
|
+
resolve: resolveConfig,
|
|
152
|
+
packageJson: "relinka",
|
|
153
|
+
dotenv: true,
|
|
154
|
+
defaults: DEFAULT_RELINKA_CONFIG,
|
|
155
|
+
overrides: envOverrides
|
|
156
|
+
});
|
|
157
|
+
currentConfig = loadedConfigResult.config ?? { ...DEFAULT_RELINKA_CONFIG };
|
|
158
|
+
isConfigInitialized = true;
|
|
159
|
+
const customResolvedLayer = loadedConfigResult.layers?.find(
|
|
160
|
+
(layer) => layer.source?.includes(configName)
|
|
161
|
+
);
|
|
162
|
+
if (customResolvedLayer?.source) {
|
|
163
|
+
console.log(
|
|
164
|
+
`[Relinka Config] Loaded main configuration from: ${path.relative(
|
|
165
|
+
projectRoot,
|
|
166
|
+
customResolvedLayer.source
|
|
167
|
+
)}`
|
|
168
|
+
);
|
|
169
|
+
} else {
|
|
170
|
+
const pkgJsonLayer = loadedConfigResult.layers?.find(
|
|
171
|
+
(layer) => layer.source?.endsWith("package.json")
|
|
172
|
+
);
|
|
173
|
+
if (pkgJsonLayer?.config) {
|
|
174
|
+
console.log("[Relinka Config] Loaded configuration from package.json.");
|
|
175
|
+
} else {
|
|
176
|
+
console.log(
|
|
177
|
+
"[Relinka Config] No config file or package.json entry found. Using defaults and environment variables."
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (isDebugEnabled(currentConfig)) {
|
|
182
|
+
console.log(
|
|
183
|
+
"[Relinka Config Debug] Final configuration object:",
|
|
184
|
+
JSON.stringify(currentConfig, null, 2)
|
|
185
|
+
);
|
|
186
|
+
console.log(
|
|
187
|
+
"[Relinka Config Debug] Resolved layers:",
|
|
188
|
+
loadedConfigResult.layers?.map((l) => ({
|
|
189
|
+
config: l.config ? "[Object]" : null,
|
|
190
|
+
source: l.source ? path.relative(projectRoot, l.source) : void 0,
|
|
191
|
+
meta: l.meta
|
|
192
|
+
}))
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
if (resolveConfigPromise) {
|
|
196
|
+
resolveConfigPromise(currentConfig);
|
|
197
|
+
}
|
|
198
|
+
return currentConfig;
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error(
|
|
201
|
+
`[Relinka Config Error] Failed during configuration loading process: ${error instanceof Error ? error.message : String(error)}`
|
|
202
|
+
);
|
|
203
|
+
currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
204
|
+
isConfigInitialized = true;
|
|
205
|
+
if (resolveConfigPromise) {
|
|
206
|
+
resolveConfigPromise(currentConfig);
|
|
207
|
+
}
|
|
208
|
+
return currentConfig;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
initializeConfig().catch((err) => {
|
|
212
|
+
console.error(
|
|
213
|
+
`[Relinka Config Error] Unhandled error during initial configuration load: ${err instanceof Error ? err.message : String(err)}`
|
|
214
|
+
);
|
|
215
|
+
if (!isConfigInitialized) {
|
|
216
|
+
currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
217
|
+
isConfigInitialized = true;
|
|
218
|
+
if (resolveConfigPromise) {
|
|
219
|
+
resolveConfigPromise(currentConfig);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
const getTimestamp = (config) => {
|
|
224
|
+
if (!config?.withTimestamp) return "";
|
|
225
|
+
const now = /* @__PURE__ */ new Date();
|
|
226
|
+
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(
|
|
227
|
+
2,
|
|
228
|
+
"0"
|
|
229
|
+
)}-${String(now.getDate()).padStart(2, "0")} ${String(
|
|
230
|
+
now.getHours()
|
|
231
|
+
).padStart(2, "0")}:${String(now.getMinutes()).padStart(
|
|
232
|
+
2,
|
|
233
|
+
"0"
|
|
234
|
+
)}:${String(now.getSeconds()).padStart(2, "0")}.${String(
|
|
235
|
+
now.getMilliseconds()
|
|
236
|
+
).padStart(3, "0")}`;
|
|
237
|
+
};
|
|
238
|
+
const getLogFilePath = (config) => {
|
|
239
|
+
const logDir = getLogDir(config);
|
|
240
|
+
const daily = isDailyLogsEnabled(config);
|
|
241
|
+
let finalLogName = getBaseLogName(config);
|
|
242
|
+
if (daily) {
|
|
243
|
+
const now = /* @__PURE__ */ new Date();
|
|
244
|
+
const datePrefix = `${now.getFullYear()}-${String(
|
|
245
|
+
now.getMonth() + 1
|
|
246
|
+
).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}-`;
|
|
247
|
+
finalLogName = datePrefix + finalLogName;
|
|
248
|
+
}
|
|
249
|
+
if (finalLogName && !finalLogName.endsWith(".log")) {
|
|
250
|
+
finalLogName += ".log";
|
|
251
|
+
}
|
|
252
|
+
const effectiveLogName = finalLogName || "relinka.log";
|
|
253
|
+
return path.resolve(process.cwd(), logDir, effectiveLogName);
|
|
254
|
+
};
|
|
255
|
+
const formatLogMessage = (config, level, msg, details) => {
|
|
256
|
+
const timestamp = getTimestamp(config);
|
|
257
|
+
let detailsStr = "";
|
|
258
|
+
if (details !== void 0) {
|
|
259
|
+
if (details instanceof Error) {
|
|
260
|
+
detailsStr = `
|
|
261
|
+
Stack Trace: ${details.stack || details.message}`;
|
|
262
|
+
} else if (typeof details === "object" && details !== null) {
|
|
263
|
+
try {
|
|
264
|
+
detailsStr = ` ${JSON.stringify(details)}`;
|
|
265
|
+
} catch {
|
|
266
|
+
detailsStr = " [object Object]";
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
detailsStr = ` ${String(details)}`;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const paddedLevel = level.padEnd(7, " ");
|
|
273
|
+
return timestamp ? `[${timestamp}] ${paddedLevel} ${msg}${detailsStr}` : `${paddedLevel} ${msg}${detailsStr}`;
|
|
274
|
+
};
|
|
275
|
+
const logToConsole = (config, level, formattedMessage) => {
|
|
276
|
+
if (!isColorEnabled(config)) {
|
|
277
|
+
switch (level) {
|
|
278
|
+
case "ERROR":
|
|
279
|
+
console.error(formattedMessage);
|
|
280
|
+
break;
|
|
281
|
+
default:
|
|
282
|
+
console.log(formattedMessage);
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
switch (level) {
|
|
286
|
+
case "ERROR":
|
|
287
|
+
console.error(re.redBright(formattedMessage));
|
|
288
|
+
break;
|
|
289
|
+
case "WARN":
|
|
290
|
+
console.warn(re.yellowBright(formattedMessage));
|
|
291
|
+
break;
|
|
292
|
+
case "SUCCESS":
|
|
293
|
+
console.log(re.greenBright(formattedMessage));
|
|
294
|
+
break;
|
|
295
|
+
case "INFO":
|
|
296
|
+
console.log(re.cyanBright(formattedMessage));
|
|
297
|
+
break;
|
|
298
|
+
default:
|
|
299
|
+
console.log(re.dim(formattedMessage));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
const getLogFilesSortedByDate = async (config) => {
|
|
304
|
+
const logDirectoryPath = path.resolve(process.cwd(), getLogDir(config));
|
|
305
|
+
const debugEnabled = isDebugEnabled(config);
|
|
306
|
+
try {
|
|
307
|
+
if (!await fs.pathExists(logDirectoryPath)) {
|
|
308
|
+
if (debugEnabled) {
|
|
309
|
+
console.log(
|
|
310
|
+
`[Relinka FS Debug] Log directory does not exist: ${logDirectoryPath}`
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
return [];
|
|
314
|
+
}
|
|
315
|
+
const files = await fs.readdir(logDirectoryPath);
|
|
316
|
+
const logFilesPromises = files.filter((file) => file.endsWith(".log")).map(async (file) => {
|
|
317
|
+
const filePath = path.join(logDirectoryPath, file);
|
|
318
|
+
try {
|
|
319
|
+
const stats = await fs.stat(filePath);
|
|
320
|
+
return stats.isFile() ? { path: filePath, mtime: stats.mtime.getTime() } : null;
|
|
321
|
+
} catch (statError) {
|
|
322
|
+
if (debugEnabled) {
|
|
323
|
+
console.error(
|
|
324
|
+
`[Relinka FS Debug] Error stating file ${filePath}: ${statError instanceof Error ? statError.message : String(statError)}`
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
const logFiles = (await Promise.all(logFilesPromises)).filter(
|
|
331
|
+
(fileInfo) => Boolean(fileInfo)
|
|
332
|
+
);
|
|
333
|
+
return logFiles.sort((a, b) => b.mtime - a.mtime);
|
|
334
|
+
} catch (readDirError) {
|
|
335
|
+
if (debugEnabled) {
|
|
336
|
+
console.error(
|
|
337
|
+
`[Relinka FS Error] Error reading log directory ${logDirectoryPath}: ${readDirError instanceof Error ? readDirError.message : String(readDirError)}`
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
return [];
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
const deleteFiles = async (filePaths, config) => {
|
|
344
|
+
const debugEnabled = isDebugEnabled(config);
|
|
345
|
+
const deletePromises = filePaths.map(async (filePath) => {
|
|
346
|
+
try {
|
|
347
|
+
await fs.unlink(filePath);
|
|
348
|
+
} catch (unlinkErr) {
|
|
349
|
+
if (debugEnabled) {
|
|
350
|
+
console.error(
|
|
351
|
+
`[Relinka FS Error] Failed to delete log file ${filePath}: ${unlinkErr instanceof Error ? unlinkErr.message : String(unlinkErr)}`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
await Promise.all(deletePromises);
|
|
357
|
+
};
|
|
358
|
+
const cleanupOldLogFiles = async (config) => {
|
|
359
|
+
const maxFiles = getMaxLogFiles(config);
|
|
360
|
+
const debugEnabled = isDebugEnabled(config);
|
|
361
|
+
if (!shouldSaveLogs(config) || maxFiles <= 0) return;
|
|
362
|
+
try {
|
|
363
|
+
const sortedLogFiles = await getLogFilesSortedByDate(config);
|
|
364
|
+
if (sortedLogFiles.length > maxFiles) {
|
|
365
|
+
const filesToDelete = sortedLogFiles.slice(maxFiles).map((f) => f.path);
|
|
366
|
+
if (filesToDelete.length > 0) {
|
|
367
|
+
await deleteFiles(filesToDelete, config);
|
|
368
|
+
if (debugEnabled) {
|
|
369
|
+
console.log(
|
|
370
|
+
`[Relinka Cleanup] Deleted ${filesToDelete.length} old log file(s). Kept ${maxFiles}.`
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
} catch (err) {
|
|
376
|
+
if (debugEnabled) {
|
|
377
|
+
console.error(
|
|
378
|
+
`[Relinka Cleanup Error] Failed during log cleanup: ${err instanceof Error ? err.message : String(err)}`
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
const appendToLogFile = async (config, absoluteLogFilePath, logMessage) => {
|
|
384
|
+
const debugEnabled = isDebugEnabled(config);
|
|
385
|
+
try {
|
|
386
|
+
await fs.ensureDir(path.dirname(absoluteLogFilePath));
|
|
387
|
+
await fs.appendFile(absoluteLogFilePath, `${logMessage}
|
|
388
|
+
`);
|
|
389
|
+
} catch (err) {
|
|
390
|
+
if (debugEnabled) {
|
|
391
|
+
console.error(
|
|
392
|
+
`[Relinka File Error] Failed to write to log file ${absoluteLogFilePath}: ${err instanceof Error ? err.message : String(err)}`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
export const relinka = (type, message, ...args) => {
|
|
398
|
+
const configToUse = currentConfig;
|
|
399
|
+
if (message === "") {
|
|
400
|
+
console.log();
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const logLevelLabel = type === "verbose" ? "DEBUG" : type.toUpperCase();
|
|
404
|
+
if (logLevelLabel === "DEBUG" && !isDebugEnabled(configToUse)) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const details = args.length > 0 ? args.length === 1 ? args[0] : args : void 0;
|
|
408
|
+
const formattedMessage = formatLogMessage(
|
|
409
|
+
configToUse,
|
|
410
|
+
logLevelLabel,
|
|
411
|
+
message,
|
|
412
|
+
details
|
|
413
|
+
);
|
|
414
|
+
logToConsole(configToUse, logLevelLabel, formattedMessage);
|
|
415
|
+
};
|
|
416
|
+
export const relinkaAsync = async (type, message, ...args) => {
|
|
417
|
+
const loadedConfig = await configPromise;
|
|
418
|
+
if (message === "") {
|
|
419
|
+
console.log();
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const logLevelLabel = type === "verbose" ? "DEBUG" : type.toUpperCase();
|
|
423
|
+
if (logLevelLabel === "DEBUG" && !isDebugEnabled(loadedConfig)) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
const details = args.length > 0 ? args.length === 1 ? args[0] : args : void 0;
|
|
427
|
+
const formattedMessage = formatLogMessage(
|
|
428
|
+
loadedConfig,
|
|
429
|
+
logLevelLabel,
|
|
430
|
+
message,
|
|
431
|
+
details
|
|
432
|
+
);
|
|
433
|
+
logToConsole(loadedConfig, logLevelLabel, formattedMessage);
|
|
434
|
+
if (shouldSaveLogs(loadedConfig)) {
|
|
435
|
+
const absoluteLogFilePath = getLogFilePath(loadedConfig);
|
|
436
|
+
try {
|
|
437
|
+
await appendToLogFile(
|
|
438
|
+
loadedConfig,
|
|
439
|
+
absoluteLogFilePath,
|
|
440
|
+
formattedMessage
|
|
441
|
+
);
|
|
442
|
+
await cleanupOldLogFiles(loadedConfig);
|
|
443
|
+
} catch (err) {
|
|
444
|
+
if (isDebugEnabled(loadedConfig)) {
|
|
445
|
+
console.error(
|
|
446
|
+
`[Relinka File Async Error] Error during file logging/cleanup process: ${err instanceof Error ? err.message : String(err)}`
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
export const defineConfig = (config) => {
|
|
453
|
+
return config;
|
|
454
|
+
};
|
|
@@ -1,10 +1,54 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
|
|
3
|
-
export type
|
|
2
|
+
/** Configuration for special directory handling. */
|
|
3
|
+
export type RelinkaSpecialDirsConfig = {
|
|
4
|
+
distDirNames?: string[];
|
|
5
|
+
useParentConfigInDist?: boolean;
|
|
6
|
+
};
|
|
7
|
+
/** Configuration for directory-related settings. */
|
|
8
|
+
export type RelinkaDirsConfig = {
|
|
9
|
+
dailyLogs?: boolean;
|
|
10
|
+
logDir?: string;
|
|
11
|
+
maxLogFiles?: number;
|
|
12
|
+
specialDirs?: RelinkaSpecialDirsConfig;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Configuration options for the Relinka logger.
|
|
16
|
+
* All properties are optional to allow for partial configuration.
|
|
17
|
+
* Defaults will be applied during initialization.
|
|
18
|
+
*/
|
|
19
|
+
export type RelinkaConfig = {
|
|
20
|
+
debug?: boolean;
|
|
21
|
+
dirs?: RelinkaDirsConfig;
|
|
22
|
+
disableColors?: boolean;
|
|
23
|
+
logFilePath?: string;
|
|
24
|
+
saveLogsToFile?: boolean;
|
|
25
|
+
withTimestamp?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/** Represents information about a log file for cleanup purposes. */
|
|
28
|
+
export type LogFileInfo = {
|
|
29
|
+
path: string;
|
|
30
|
+
mtime: number;
|
|
31
|
+
};
|
|
32
|
+
/** Log level types used by the logger. */
|
|
33
|
+
export type LogLevel = "error" | "info" | "success" | "verbose" | "warn";
|
|
34
|
+
/**
|
|
35
|
+
* Defines the level of logs as specific numbers or special number types.
|
|
36
|
+
*
|
|
37
|
+
* @type {0 | 1 | 2 | 3 | 4 | 5 | (number & {})} LogLevelDeprecated - Represents the log level.
|
|
38
|
+
* @default 0 - Represents the default log level.
|
|
39
|
+
*/
|
|
40
|
+
export type LogLevelDeprecated = 0 | 1 | 2 | 3 | 4 | 5 | (number & {});
|
|
41
|
+
/**
|
|
42
|
+
* Lists the types of log messages supported by the system.
|
|
43
|
+
*
|
|
44
|
+
* @type {"silent" | "fatal" | "error" | "warn" | "log" | "info" | "success" | "fail" | "ready" | "start" | "box" | "debug" | "trace" | "verbose"} LogTypeDeprecated - Represents the specific type of log message.
|
|
45
|
+
*/
|
|
46
|
+
export type LogTypeDeprecated = "silent" | "fatal" | "error" | "warn" | "log" | "info" | "success" | "fail" | "ready" | "start" | "box" | "debug" | "trace" | "verbose";
|
|
47
|
+
export type RelinkaOptionsDeprecated = {
|
|
4
48
|
/**
|
|
5
|
-
* An array of
|
|
49
|
+
* An array of RelinkaReporterDeprecated instances used to handle and output log messages.
|
|
6
50
|
*/
|
|
7
|
-
reporters:
|
|
51
|
+
reporters: RelinkaReporterDeprecated[];
|
|
8
52
|
/**
|
|
9
53
|
* A record mapping LogTypeDeprecated to InputLogObject, defining the log configuration for each log type.
|
|
10
54
|
* See {@link LogTypeDeprecated} and {@link InputLogObject}.
|
|
@@ -138,13 +182,13 @@ export type LogObject = {
|
|
|
138
182
|
*/
|
|
139
183
|
[key: string]: unknown;
|
|
140
184
|
} & InputLogObject;
|
|
141
|
-
export type
|
|
185
|
+
export type RelinkaReporterDeprecated = {
|
|
142
186
|
/**
|
|
143
187
|
* Defines how a log message is processed and displayed by this reporter.
|
|
144
188
|
* @param logObj The LogObject containing the log information to process. See {@link LogObject}.
|
|
145
|
-
* @param ctx An object containing context information such as options. See {@link
|
|
189
|
+
* @param ctx An object containing context information such as options. See {@link RelinkaOptionsDeprecated}.
|
|
146
190
|
*/
|
|
147
191
|
log: (logObj: LogObject, ctx: {
|
|
148
|
-
options:
|
|
192
|
+
options: RelinkaOptionsDeprecated;
|
|
149
193
|
}) => void;
|
|
150
194
|
};
|
package/package.json
CHANGED
|
@@ -1,88 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
+
"description": "@reliverse/relinka is a powerful logger for your terminal.",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"name": "@reliverse/relinka",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"version": "1.3.6",
|
|
2
7
|
"dependencies": {
|
|
3
|
-
"@figliolia/chalk-animation": "^1.0.4",
|
|
4
8
|
"@reliverse/relico": "^1.0.2",
|
|
5
9
|
"@reliverse/runtime": "^1.0.3",
|
|
6
|
-
"
|
|
7
|
-
"ansi-diff-stream": "^1.2.1",
|
|
8
|
-
"ansi-escapes": "^7.0.0",
|
|
9
|
-
"chalk": "^5.4.1",
|
|
10
|
-
"cli-spinners": "^3.2.0",
|
|
11
|
-
"cli-styles": "^1.0.0",
|
|
12
|
-
"cli-width": "^4.1.0",
|
|
13
|
-
"confbox": "^0.2.1",
|
|
10
|
+
"c12": "^3.0.2",
|
|
14
11
|
"defu": "^6.1.4",
|
|
15
|
-
"destr": "^2.0.3",
|
|
16
|
-
"detect-package-manager": "^3.0.2",
|
|
17
|
-
"external-editor": "^3.1.0",
|
|
18
|
-
"fast-glob": "^3.3.3",
|
|
19
|
-
"figlet": "^1.8.0",
|
|
20
12
|
"fs-extra": "^11.3.0",
|
|
21
|
-
"get-pixels": "^3.3.3",
|
|
22
|
-
"globby": "^14.1.0",
|
|
23
|
-
"gradient-string": "^3.0.0",
|
|
24
|
-
"kleur": "^4.1.5",
|
|
25
|
-
"log-update": "^6.1.0",
|
|
26
|
-
"mri": "^1.2.0",
|
|
27
|
-
"mute-stream": "^2.0.0",
|
|
28
|
-
"node-emoji": "^2.2.0",
|
|
29
|
-
"nypm": "^0.6.0",
|
|
30
|
-
"ora": "^8.2.0",
|
|
31
13
|
"pathe": "^2.0.3",
|
|
32
|
-
"precision": "^1.0.1",
|
|
33
|
-
"seventh": "^0.9.2",
|
|
34
|
-
"signal-exit": "^4.1.0",
|
|
35
|
-
"sisteransi": "^1.0.5",
|
|
36
|
-
"std-env": "^3.8.1",
|
|
37
|
-
"string-width": "^7.2.0",
|
|
38
|
-
"strip-ansi": "^7.1.0",
|
|
39
|
-
"terminal-size": "^4.0.0",
|
|
40
|
-
"ts-regex-builder": "^1.8.2",
|
|
41
|
-
"window-size": "^1.1.1",
|
|
42
|
-
"wrap-ansi": "^9.0.0"
|
|
43
|
-
},
|
|
44
|
-
"description": "@reliverse/relinka is a powerful logger for your terminal.",
|
|
45
|
-
"homepage": "https://docs.reliverse.org",
|
|
46
|
-
"license": "MIT",
|
|
47
|
-
"name": "@reliverse/relinka",
|
|
48
|
-
"type": "module",
|
|
49
|
-
"version": "1.3.4",
|
|
50
|
-
"devDependencies": {
|
|
51
|
-
"@arethetypeswrong/cli": "^0.17.4",
|
|
52
|
-
"@biomejs/biome": "1.9.4",
|
|
53
|
-
"@cspell/dict-npm": "^5.1.32",
|
|
54
|
-
"@eslint/js": "^9.23.0",
|
|
55
|
-
"@reliverse/relidler-cfg": "^1.1.3",
|
|
56
|
-
"@stylistic/eslint-plugin": "^4.2.0",
|
|
57
|
-
"@types/ansi-diff-stream": "^1.2.3",
|
|
58
|
-
"@types/bun": "^1.2.8",
|
|
59
|
-
"@types/chalk-animation": "^1.6.3",
|
|
60
|
-
"@types/figlet": "^1.7.0",
|
|
61
|
-
"@types/fs-extra": "^11.0.4",
|
|
62
|
-
"@types/mute-stream": "^0.0.4",
|
|
63
|
-
"@types/node": "^22.13.16",
|
|
64
|
-
"@types/sentencer": "^0.2.3",
|
|
65
|
-
"@types/signal-exit": "^4.0.0",
|
|
66
|
-
"@types/strip-comments": "^2.0.4",
|
|
67
|
-
"@types/window-size": "^1.1.4",
|
|
68
|
-
"c12": "^3.0.2",
|
|
69
|
-
"citty": "^0.1.6",
|
|
70
|
-
"eslint": "^9.23.0",
|
|
71
|
-
"eslint-plugin-no-relative-import-paths": "^1.6.1",
|
|
72
|
-
"eslint-plugin-perfectionist": "^4.10.1",
|
|
73
|
-
"execa": "^9.5.2",
|
|
74
|
-
"jiti": "^2.4.2",
|
|
75
|
-
"knip": "^5.46.4",
|
|
76
|
-
"mock-stdin": "^1.0.0",
|
|
77
14
|
"printj": "^1.3.1",
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"tsx": "^4.19.3",
|
|
81
|
-
"typescript": "^5.8.2",
|
|
82
|
-
"typescript-eslint": "^8.29.0",
|
|
83
|
-
"unbuild": "^3.5.0",
|
|
84
|
-
"vitest": "^3.1.1"
|
|
15
|
+
"std-env": "^3.8.1",
|
|
16
|
+
"string-width": "^7.2.0"
|
|
85
17
|
},
|
|
18
|
+
"devDependencies": {},
|
|
86
19
|
"exports": {
|
|
87
20
|
".": "./bin/main.js"
|
|
88
21
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "../modes/shared.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "../modes/shared.js";
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { LogObject } from "../../types/mod.js";
|
|
2
|
-
/**
|
|
3
|
-
* Defines the level of logs as specific numbers or special number types.
|
|
4
|
-
*
|
|
5
|
-
* @type {0 | 1 | 2 | 3 | 4 | 5 | (number & {})} LogLevelDeprecated - Represents the log level.
|
|
6
|
-
* @default 0 - Represents the default log level.
|
|
7
|
-
*/
|
|
8
|
-
export type LogLevelDeprecated = 0 | 1 | 2 | 3 | 4 | 5 | (number & {});
|
|
9
|
-
/**
|
|
10
|
-
* A mapping of `LogTypeDeprecated` to its corresponding numeric log level.
|
|
11
|
-
*
|
|
12
|
-
* @type {Record<LogTypeDeprecated, number>} LogLevelsDeprecated - key-value pairs of log types to their numeric levels. See {@link LogTypeDeprecated}.
|
|
13
|
-
*/
|
|
14
|
-
export declare const LogLevelsDeprecated: Record<LogTypeDeprecated, number>;
|
|
15
|
-
/**
|
|
16
|
-
* Lists the types of log messages supported by the system.
|
|
17
|
-
*
|
|
18
|
-
* @type {"silent" | "fatal" | "error" | "warn" | "log" | "info" | "success" | "fail" | "ready" | "start" | "box" | "debug" | "trace" | "verbose"} LogTypeDeprecated - Represents the specific type of log message.
|
|
19
|
-
*/
|
|
20
|
-
export type LogTypeDeprecated = "silent" | "fatal" | "error" | "warn" | "log" | "info" | "success" | "fail" | "ready" | "start" | "box" | "debug" | "trace" | "verbose";
|
|
21
|
-
/**
|
|
22
|
-
* Maps `LogTypeDeprecated` to a `Partial<LogObject>`, primarily defining the log level.
|
|
23
|
-
*
|
|
24
|
-
* @type {Record<LogTypeDeprecated, Partial<LogObject>>} LogTypesDeprecated - key-value pairs of log types to partial log objects, specifying log levels. See {@link LogTypeDeprecated} and {@link LogObject}.
|
|
25
|
-
*/
|
|
26
|
-
export declare const LogTypesDeprecated: Record<LogTypeDeprecated, Partial<LogObject>>;
|