@reliverse/relinka 1.3.6 → 1.3.8
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 +115 -76
- package/bin/{relinka-impl → core-impl}/deprecated/components/levels/levels.d.ts +13 -13
- package/bin/{relinka-impl → core-impl}/deprecated/components/modes/basic.d.ts +19 -19
- package/bin/{relinka-impl → core-impl}/deprecated/components/modes/browser.d.ts +19 -19
- package/bin/{relinka-impl → core-impl}/deprecated/components/modes/shared.d.ts +2 -2
- package/bin/{relinka-impl → core-impl}/deprecated/components/relinka-deprecated/logger.d.ts +5 -5
- package/bin/{relinka-impl → core-impl}/deprecated/components/relinka-deprecated/mod.d.ts +20 -20
- package/bin/{relinka-impl → core-impl}/deprecated/components/relinka-deprecated/relinka.d.ts +140 -141
- package/bin/{relinka-impl → core-impl}/deprecated/components/relinka-deprecated/relinka.test.d.ts +1 -1
- package/bin/{relinka-impl → core-impl}/deprecated/components/reporters/basic.d.ts +11 -11
- package/bin/{relinka-impl → core-impl}/deprecated/components/reporters/browser.d.ts +10 -10
- package/bin/{relinka-impl → core-impl}/deprecated/components/reporters/fancy.d.ts +10 -10
- package/bin/{relinka-impl → core-impl}/deprecated/utils/box.d.ts +114 -114
- package/bin/{relinka-impl → core-impl}/deprecated/utils/deprecatedColors.d.ts +69 -69
- package/bin/{relinka-impl → core-impl}/deprecated/utils/error.d.ts +6 -6
- package/bin/{relinka-impl → core-impl}/deprecated/utils/format.d.ts +14 -14
- package/bin/{relinka-impl → core-impl}/deprecated/utils/log.d.ts +13 -13
- package/bin/{relinka-impl → core-impl}/deprecated/utils/stream.d.ts +14 -15
- package/bin/{relinka-impl → core-impl}/deprecated/utils/string.d.ts +50 -50
- package/bin/{relinka-impl → core-impl}/deprecated/utils/tree.d.ts +41 -41
- package/bin/core-impl/impl-mod.d.ts +19 -0
- package/bin/core-impl/impl-mod.js +321 -0
- package/bin/{relinka-types.d.ts → core-types.d.ts} +193 -194
- package/bin/main.d.ts +22 -22
- package/bin/main.js +19 -19
- package/package.json +5 -5
- package/bin/relinka-impl/impl-mod.d.ts +0 -20
- package/bin/relinka-impl/impl-mod.js +0 -454
- /package/bin/{relinka-impl → core-impl}/deprecated/components/levels/levels.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/modes/basic.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/modes/browser.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/modes/shared.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/relinka-deprecated/logger.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/relinka-deprecated/mod.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/relinka-deprecated/relinka.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/relinka-deprecated/relinka.test.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/reporters/basic.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/reporters/browser.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/components/reporters/fancy.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/utils/box.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/utils/deprecatedColors.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/utils/error.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/utils/format.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/utils/log.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/utils/stream.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/utils/string.js +0 -0
- /package/bin/{relinka-impl → core-impl}/deprecated/utils/tree.js +0 -0
- /package/bin/{relinka-types.js → core-types.js} +0 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { re } from "@reliverse/relico";
|
|
2
|
+
import { loadConfig } from "c12";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import path from "pathe";
|
|
5
|
+
const DEV_VERBOSE = false;
|
|
6
|
+
const DEFAULT_RELINKA_CONFIG = {
|
|
7
|
+
debug: false,
|
|
8
|
+
dirs: {
|
|
9
|
+
dailyLogs: false,
|
|
10
|
+
logDir: ".reliverse/logs",
|
|
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
|
+
let currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
23
|
+
let isConfigInitialized = false;
|
|
24
|
+
let resolveRelinkaConfig;
|
|
25
|
+
export const relinkaConfig = new Promise((resolve) => {
|
|
26
|
+
resolveRelinkaConfig = resolve;
|
|
27
|
+
});
|
|
28
|
+
async function initializeConfig() {
|
|
29
|
+
try {
|
|
30
|
+
const result = await loadConfig({
|
|
31
|
+
name: "relinka",
|
|
32
|
+
// base name => tries relinka.config.*, .relinkarc, etc.
|
|
33
|
+
cwd: process.cwd(),
|
|
34
|
+
// working directory
|
|
35
|
+
dotenv: false,
|
|
36
|
+
packageJson: false,
|
|
37
|
+
rcFile: false,
|
|
38
|
+
globalRc: false,
|
|
39
|
+
defaults: DEFAULT_RELINKA_CONFIG
|
|
40
|
+
// lowest priority
|
|
41
|
+
// overrides: {}, // highest priority if we would need to forcibly override
|
|
42
|
+
});
|
|
43
|
+
currentConfig = result.config;
|
|
44
|
+
isConfigInitialized = true;
|
|
45
|
+
if (DEV_VERBOSE) {
|
|
46
|
+
console.log(
|
|
47
|
+
"[Relinka Config Debug] Config file used:",
|
|
48
|
+
result.configFile
|
|
49
|
+
);
|
|
50
|
+
console.log("[Relinka Config Debug] All merged layers:", result.layers);
|
|
51
|
+
console.log("[Relinka Config Debug] Final configuration:", currentConfig);
|
|
52
|
+
}
|
|
53
|
+
if (resolveRelinkaConfig) {
|
|
54
|
+
resolveRelinkaConfig(currentConfig);
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error(
|
|
58
|
+
`[Relinka Config Error] Failed to load config: ${err instanceof Error ? err.message : String(err)}`
|
|
59
|
+
);
|
|
60
|
+
currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
61
|
+
isConfigInitialized = true;
|
|
62
|
+
if (resolveRelinkaConfig) {
|
|
63
|
+
resolveRelinkaConfig(currentConfig);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
initializeConfig().catch((err) => {
|
|
68
|
+
console.error(
|
|
69
|
+
`[Relinka Config Error] Unhandled error: ${err instanceof Error ? err.message : String(err)}`
|
|
70
|
+
);
|
|
71
|
+
if (!isConfigInitialized) {
|
|
72
|
+
currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
73
|
+
isConfigInitialized = true;
|
|
74
|
+
if (resolveRelinkaConfig) {
|
|
75
|
+
resolveRelinkaConfig(currentConfig);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
function isDebugEnabled(config) {
|
|
80
|
+
return config.debug ?? DEFAULT_RELINKA_CONFIG.debug;
|
|
81
|
+
}
|
|
82
|
+
function isColorEnabled(config) {
|
|
83
|
+
return !(config.disableColors ?? DEFAULT_RELINKA_CONFIG.disableColors);
|
|
84
|
+
}
|
|
85
|
+
function getLogDir(config) {
|
|
86
|
+
return config.dirs?.logDir ?? DEFAULT_RELINKA_CONFIG.dirs.logDir;
|
|
87
|
+
}
|
|
88
|
+
function isDailyLogsEnabled(config) {
|
|
89
|
+
return config.dirs?.dailyLogs ?? DEFAULT_RELINKA_CONFIG.dirs.dailyLogs;
|
|
90
|
+
}
|
|
91
|
+
function shouldSaveLogs(config) {
|
|
92
|
+
return config.saveLogsToFile ?? DEFAULT_RELINKA_CONFIG.saveLogsToFile;
|
|
93
|
+
}
|
|
94
|
+
function getMaxLogFiles(config) {
|
|
95
|
+
return config.dirs?.maxLogFiles ?? DEFAULT_RELINKA_CONFIG.dirs.maxLogFiles;
|
|
96
|
+
}
|
|
97
|
+
function getBaseLogName(config) {
|
|
98
|
+
return config.logFilePath ?? DEFAULT_RELINKA_CONFIG.logFilePath;
|
|
99
|
+
}
|
|
100
|
+
function getTimestamp(config) {
|
|
101
|
+
if (!config.withTimestamp) return "";
|
|
102
|
+
const now = /* @__PURE__ */ new Date();
|
|
103
|
+
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")} ${String(now.getHours()).padStart(2, "0")}:${String(
|
|
104
|
+
now.getMinutes()
|
|
105
|
+
).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}.${String(now.getMilliseconds()).padStart(3, "0")}`;
|
|
106
|
+
}
|
|
107
|
+
function getLogFilePath(config) {
|
|
108
|
+
const logDir = getLogDir(config);
|
|
109
|
+
const daily = isDailyLogsEnabled(config);
|
|
110
|
+
let finalLogName = getBaseLogName(config);
|
|
111
|
+
if (daily) {
|
|
112
|
+
const now = /* @__PURE__ */ new Date();
|
|
113
|
+
const datePrefix = `${now.getFullYear()}-${String(
|
|
114
|
+
now.getMonth() + 1
|
|
115
|
+
).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}-`;
|
|
116
|
+
finalLogName = datePrefix + finalLogName;
|
|
117
|
+
}
|
|
118
|
+
if (finalLogName && !finalLogName.endsWith(".log")) {
|
|
119
|
+
finalLogName += ".log";
|
|
120
|
+
}
|
|
121
|
+
const effectiveLogName = finalLogName || "relinka.log";
|
|
122
|
+
return path.resolve(process.cwd(), logDir, effectiveLogName);
|
|
123
|
+
}
|
|
124
|
+
function formatLogMessage(config, level, msg, details) {
|
|
125
|
+
const timestamp = getTimestamp(config);
|
|
126
|
+
let detailsStr = "";
|
|
127
|
+
if (details !== void 0) {
|
|
128
|
+
if (details instanceof Error) {
|
|
129
|
+
detailsStr = `
|
|
130
|
+
Stack Trace: ${details.stack || details.message}`;
|
|
131
|
+
} else if (typeof details === "object" && details !== null) {
|
|
132
|
+
try {
|
|
133
|
+
detailsStr = ` ${JSON.stringify(details)}`;
|
|
134
|
+
} catch {
|
|
135
|
+
detailsStr = " [object Object]";
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
detailsStr = ` ${String(details)}`;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const paddedLevel = level.padEnd(7, " ");
|
|
142
|
+
return timestamp ? `[${timestamp}] ${paddedLevel} ${msg}${detailsStr}` : `${paddedLevel} ${msg}${detailsStr}`;
|
|
143
|
+
}
|
|
144
|
+
function logToConsole(config, level, formattedMessage) {
|
|
145
|
+
const COLOR_RESET = "\x1B[0m";
|
|
146
|
+
if (!isColorEnabled(config)) {
|
|
147
|
+
if (level === "ERROR") {
|
|
148
|
+
console.error(formattedMessage);
|
|
149
|
+
} else {
|
|
150
|
+
console.log(formattedMessage);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
switch (level) {
|
|
154
|
+
case "ERROR":
|
|
155
|
+
console.error(re.redBright(formattedMessage) + COLOR_RESET);
|
|
156
|
+
break;
|
|
157
|
+
case "WARN":
|
|
158
|
+
console.warn(re.yellowBright(formattedMessage) + COLOR_RESET);
|
|
159
|
+
break;
|
|
160
|
+
case "SUCCESS":
|
|
161
|
+
console.log(re.greenBright(formattedMessage) + COLOR_RESET);
|
|
162
|
+
break;
|
|
163
|
+
case "INFO":
|
|
164
|
+
console.log(re.cyanBright(formattedMessage) + COLOR_RESET);
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
console.log(re.dim(formattedMessage) + COLOR_RESET);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function getLogFilesSortedByDate(config) {
|
|
172
|
+
const logDirectoryPath = path.resolve(process.cwd(), getLogDir(config));
|
|
173
|
+
if (!await fs.pathExists(logDirectoryPath)) {
|
|
174
|
+
if (isDebugEnabled(config)) {
|
|
175
|
+
console.log(
|
|
176
|
+
`[Relinka FS Debug] Log directory not found: ${logDirectoryPath}`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const files = await fs.readdir(logDirectoryPath);
|
|
183
|
+
const logFilesPromises = files.filter((f) => f.endsWith(".log")).map(async (f) => {
|
|
184
|
+
const filePath = path.join(logDirectoryPath, f);
|
|
185
|
+
try {
|
|
186
|
+
const stats = await fs.stat(filePath);
|
|
187
|
+
if (stats.isFile()) {
|
|
188
|
+
return { path: filePath, mtime: stats.mtime.getTime() };
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
} catch (err) {
|
|
192
|
+
if (isDebugEnabled(config)) {
|
|
193
|
+
console.error(
|
|
194
|
+
`[Relinka FS Debug] Error reading stats for ${filePath}: ${err instanceof Error ? err.message : String(err)}`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
const logFiles = (await Promise.all(logFilesPromises)).filter(
|
|
201
|
+
(f) => Boolean(f)
|
|
202
|
+
);
|
|
203
|
+
return logFiles.sort((a, b) => b.mtime - a.mtime);
|
|
204
|
+
} catch (readErr) {
|
|
205
|
+
if (isDebugEnabled(config)) {
|
|
206
|
+
console.error(
|
|
207
|
+
`[Relinka FS Error] Failed reading log directory ${logDirectoryPath}: ${readErr instanceof Error ? readErr.message : String(readErr)}`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function deleteFiles(filePaths, config) {
|
|
214
|
+
await Promise.all(
|
|
215
|
+
filePaths.map(async (filePath) => {
|
|
216
|
+
try {
|
|
217
|
+
await fs.unlink(filePath);
|
|
218
|
+
} catch (err) {
|
|
219
|
+
if (isDebugEnabled(config)) {
|
|
220
|
+
console.error(
|
|
221
|
+
`[Relinka FS Error] Failed to delete log file ${filePath}: ${err instanceof Error ? err.message : String(err)}`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
async function cleanupOldLogFiles(config) {
|
|
229
|
+
if (!shouldSaveLogs(config) || getMaxLogFiles(config) <= 0) return;
|
|
230
|
+
try {
|
|
231
|
+
const sortedLogFiles = await getLogFilesSortedByDate(config);
|
|
232
|
+
const maxFiles = getMaxLogFiles(config);
|
|
233
|
+
if (sortedLogFiles.length > maxFiles) {
|
|
234
|
+
const filesToDelete = sortedLogFiles.slice(maxFiles).map((f) => f.path);
|
|
235
|
+
if (filesToDelete.length > 0) {
|
|
236
|
+
await deleteFiles(filesToDelete, config);
|
|
237
|
+
if (isDebugEnabled(config)) {
|
|
238
|
+
console.log(
|
|
239
|
+
`[Relinka Cleanup] Deleted ${filesToDelete.length} old log file(s). Kept ${maxFiles}.`
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} catch (err) {
|
|
245
|
+
if (isDebugEnabled(config)) {
|
|
246
|
+
console.error(
|
|
247
|
+
`[Relinka Cleanup Error] Failed during log cleanup: ${err instanceof Error ? err.message : String(err)}`
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function appendToLogFile(config, absoluteLogFilePath, logMessage) {
|
|
253
|
+
try {
|
|
254
|
+
await fs.ensureDir(path.dirname(absoluteLogFilePath));
|
|
255
|
+
await fs.appendFile(absoluteLogFilePath, `${logMessage}
|
|
256
|
+
`);
|
|
257
|
+
} catch (err) {
|
|
258
|
+
if (isDebugEnabled(config)) {
|
|
259
|
+
console.error(
|
|
260
|
+
`[Relinka File Error] Failed to write to log file ${absoluteLogFilePath}: ${err instanceof Error ? err.message : String(err)}`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
export function relinka(type, message, ...args) {
|
|
266
|
+
if (type === "clear") {
|
|
267
|
+
console.clear();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (message === "") {
|
|
271
|
+
console.log();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const logLevelLabel = type === "verbose" ? "DEBUG" : type.toUpperCase();
|
|
275
|
+
if (logLevelLabel === "DEBUG" && !isDebugEnabled(currentConfig)) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const details = args.length > 1 ? args : args[0];
|
|
279
|
+
const formatted = formatLogMessage(
|
|
280
|
+
currentConfig,
|
|
281
|
+
logLevelLabel,
|
|
282
|
+
message,
|
|
283
|
+
details
|
|
284
|
+
);
|
|
285
|
+
logToConsole(currentConfig, logLevelLabel, formatted);
|
|
286
|
+
}
|
|
287
|
+
export async function relinkaAsync(type, message, ...args) {
|
|
288
|
+
await relinkaConfig;
|
|
289
|
+
if (message === "") {
|
|
290
|
+
console.log();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const logLevelLabel = type === "verbose" ? "DEBUG" : type.toUpperCase();
|
|
294
|
+
if (logLevelLabel === "DEBUG" && !isDebugEnabled(currentConfig)) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const details = args.length > 1 ? args : args[0];
|
|
298
|
+
const formatted = formatLogMessage(
|
|
299
|
+
currentConfig,
|
|
300
|
+
logLevelLabel,
|
|
301
|
+
message,
|
|
302
|
+
details
|
|
303
|
+
);
|
|
304
|
+
logToConsole(currentConfig, logLevelLabel, formatted);
|
|
305
|
+
if (shouldSaveLogs(currentConfig)) {
|
|
306
|
+
const absoluteLogFilePath = getLogFilePath(currentConfig);
|
|
307
|
+
try {
|
|
308
|
+
await appendToLogFile(currentConfig, absoluteLogFilePath, formatted);
|
|
309
|
+
await cleanupOldLogFiles(currentConfig);
|
|
310
|
+
} catch (err) {
|
|
311
|
+
if (isDebugEnabled(currentConfig)) {
|
|
312
|
+
console.error(
|
|
313
|
+
`[Relinka File Async Error] Error during file logging/cleanup: ${err instanceof Error ? err.message : String(err)}`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
export function defineConfig(config) {
|
|
320
|
+
return config;
|
|
321
|
+
}
|