node-karin
Version:
Lightweight, efficient, concise, and stable robot framework.
661 lines (657 loc) • 23.3 kB
JavaScript
import os from 'node:os';
import fs from 'node:fs';
import require$$0 from 'fs';
import require$$1 from 'path';
import require$$2 from 'os';
import require$$3 from 'crypto';
import path from 'node:path';
import { createServer } from 'node:net';
import { fileURLToPath } from 'node:url';
import { fork } from 'node:child_process';
// src/start/index.ts
function _mergeNamespaces(n, m) {
for (var i = 0; i < m.length; i++) {
const e = m[i];
if (typeof e !== "string" && !Array.isArray(e)) {
for (const k in e) {
if (k !== "default" && !(k in n)) {
const d = Object.getOwnPropertyDescriptor(e, k);
if (d) {
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
}
}
return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
}
function getDefaultExportFromCjs(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
}
var main$1 = { exports: {} };
var version = "16.5.0";
var require$$4 = {
version
};
var hasRequiredMain;
function requireMain() {
if (hasRequiredMain) return main$1.exports;
hasRequiredMain = 1;
const fs2 = require$$0;
const path2 = require$$1;
const os2 = require$$2;
const crypto = require$$3;
const packageJson = require$$4;
const version2 = packageJson.version;
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
function parse2(src) {
const obj = {};
let lines = src.toString();
lines = lines.replace(/\r\n?/mg, "\n");
let match;
while ((match = LINE.exec(lines)) != null) {
const key = match[1];
let value = match[2] || "";
value = value.trim();
const maybeQuote = value[0];
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
if (maybeQuote === '"') {
value = value.replace(/\\n/g, "\n");
value = value.replace(/\\r/g, "\r");
}
obj[key] = value;
}
return obj;
}
function _parseVault2(options) {
const vaultPath = _vaultPath(options);
const result = DotenvModule.configDotenv({ path: vaultPath });
if (!result.parsed) {
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
err.code = "MISSING_DATA";
throw err;
}
const keys = _dotenvKey(options).split(",");
const length = keys.length;
let decrypted;
for (let i = 0; i < length; i++) {
try {
const key = keys[i].trim();
const attrs = _instructions(result, key);
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
break;
} catch (error) {
if (i + 1 >= length) {
throw error;
}
}
}
return DotenvModule.parse(decrypted);
}
function _warn(message) {
console.log(`[dotenv@${version2}][WARN] ${message}`);
}
function _debug(message) {
console.log(`[dotenv@${version2}][DEBUG] ${message}`);
}
function _dotenvKey(options) {
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
return options.DOTENV_KEY;
}
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
return process.env.DOTENV_KEY;
}
return "";
}
function _instructions(result, dotenvKey) {
let uri;
try {
uri = new URL(dotenvKey);
} catch (error) {
if (error.code === "ERR_INVALID_URL") {
const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
err.code = "INVALID_DOTENV_KEY";
throw err;
}
throw error;
}
const key = uri.password;
if (!key) {
const err = new Error("INVALID_DOTENV_KEY: Missing key part");
err.code = "INVALID_DOTENV_KEY";
throw err;
}
const environment = uri.searchParams.get("environment");
if (!environment) {
const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
err.code = "INVALID_DOTENV_KEY";
throw err;
}
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
const ciphertext = result.parsed[environmentKey];
if (!ciphertext) {
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
throw err;
}
return { ciphertext, key };
}
function _vaultPath(options) {
let possibleVaultPath = null;
if (options && options.path && options.path.length > 0) {
if (Array.isArray(options.path)) {
for (const filepath of options.path) {
if (fs2.existsSync(filepath)) {
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
}
}
} else {
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
}
} else {
possibleVaultPath = path2.resolve(process.cwd(), ".env.vault");
}
if (fs2.existsSync(possibleVaultPath)) {
return possibleVaultPath;
}
return null;
}
function _resolveHome(envPath) {
return envPath[0] === "~" ? path2.join(os2.homedir(), envPath.slice(1)) : envPath;
}
function _configVault2(options) {
const debug = Boolean(options && options.debug);
if (debug) {
_debug("Loading env from encrypted .env.vault");
}
const parsed = DotenvModule._parseVault(options);
let processEnv = process.env;
if (options && options.processEnv != null) {
processEnv = options.processEnv;
}
DotenvModule.populate(processEnv, parsed, options);
return { parsed };
}
function configDotenv2(options) {
const dotenvPath = path2.resolve(process.cwd(), ".env");
let encoding = "utf8";
const debug = Boolean(options && options.debug);
if (options && options.encoding) {
encoding = options.encoding;
} else {
if (debug) {
_debug("No encoding is specified. UTF-8 is used by default");
}
}
let optionPaths = [dotenvPath];
if (options && options.path) {
if (!Array.isArray(options.path)) {
optionPaths = [_resolveHome(options.path)];
} else {
optionPaths = [];
for (const filepath of options.path) {
optionPaths.push(_resolveHome(filepath));
}
}
}
let lastError;
const parsedAll = {};
for (const path22 of optionPaths) {
try {
const parsed = DotenvModule.parse(fs2.readFileSync(path22, { encoding }));
DotenvModule.populate(parsedAll, parsed, options);
} catch (e) {
if (debug) {
_debug(`Failed to load ${path22} ${e.message}`);
}
lastError = e;
}
}
let processEnv = process.env;
if (options && options.processEnv != null) {
processEnv = options.processEnv;
}
DotenvModule.populate(processEnv, parsedAll, options);
if (lastError) {
return { parsed: parsedAll, error: lastError };
} else {
return { parsed: parsedAll };
}
}
function config2(options) {
if (_dotenvKey(options).length === 0) {
return DotenvModule.configDotenv(options);
}
const vaultPath = _vaultPath(options);
if (!vaultPath) {
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
return DotenvModule.configDotenv(options);
}
return DotenvModule._configVault(options);
}
function decrypt2(encrypted, keyStr) {
const key = Buffer.from(keyStr.slice(-64), "hex");
let ciphertext = Buffer.from(encrypted, "base64");
const nonce = ciphertext.subarray(0, 12);
const authTag = ciphertext.subarray(-16);
ciphertext = ciphertext.subarray(12, -16);
try {
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
aesgcm.setAuthTag(authTag);
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
} catch (error) {
const isRange = error instanceof RangeError;
const invalidKeyLength = error.message === "Invalid key length";
const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
if (isRange || invalidKeyLength) {
const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
err.code = "INVALID_DOTENV_KEY";
throw err;
} else if (decryptionFailed) {
const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
err.code = "DECRYPTION_FAILED";
throw err;
} else {
throw error;
}
}
}
function populate2(processEnv, parsed, options = {}) {
const debug = Boolean(options && options.debug);
const override = Boolean(options && options.override);
if (typeof parsed !== "object") {
const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
err.code = "OBJECT_REQUIRED";
throw err;
}
for (const key of Object.keys(parsed)) {
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
if (override === true) {
processEnv[key] = parsed[key];
}
if (debug) {
if (override === true) {
_debug(`"${key}" is already defined and WAS overwritten`);
} else {
_debug(`"${key}" is already defined and was NOT overwritten`);
}
}
} else {
processEnv[key] = parsed[key];
}
}
}
const DotenvModule = {
configDotenv: configDotenv2,
_configVault: _configVault2,
_parseVault: _parseVault2,
config: config2,
decrypt: decrypt2,
parse: parse2,
populate: populate2
};
main$1.exports.configDotenv = DotenvModule.configDotenv;
main$1.exports._configVault = DotenvModule._configVault;
main$1.exports._parseVault = DotenvModule._parseVault;
main$1.exports.config = DotenvModule.config;
main$1.exports.decrypt = DotenvModule.decrypt;
main$1.exports.parse = DotenvModule.parse;
main$1.exports.populate = DotenvModule.populate;
main$1.exports = DotenvModule;
return main$1.exports;
}
var mainExports = requireMain();
var main = /* @__PURE__ */ getDefaultExportFromCjs(mainExports);
var dotenv = /* @__PURE__ */ _mergeNamespaces({
__proto__: null,
default: main
}, [mainExports]);
// ../../node_modules/.pnpm/@karinjs+dotenv@1.1.2/node_modules/@karinjs/dotenv/dist/index.js
var {
// @ts-ignore
_configVault,
_parseVault
} = dotenv;
mainExports.config;
mainExports.configDotenv;
mainExports.decrypt;
mainExports.parse;
mainExports.populate;
// ../../node_modules/.pnpm/@karinjs+dotenv@1.1.2/node_modules/@karinjs/dotenv/index.js
var app = dotenv.default;
var dotenv_default = app;
var ProcessManager = class {
/** 是否已经启动 */
isStarted = false;
/** 子进程实例 */
childProcess = null;
/** 重启延迟时间 */
RESTART_DELAY_MS = 200;
/** 模块名称 */
MODULE_NAME = "ProcessManager";
/** 启动时间 */
startTime = Date.now();
/** 进程统计信息 */
processStats = {
/** 重启次数 */
restartCount: 0,
/** 最后重启时间 */
lastRestartTime: 0
};
/** 默认HTTP端口 */
DEFAULT_HTTP_PORT = 7777;
// ANSI 颜色代码
COLORS = {
green: "\x1B[32m",
yellow: "\x1B[33m",
red: "\x1B[31m",
blue: "\x1B[34m",
magenta: "\x1B[35m",
cyan: "\x1B[36m",
gray: "\x1B[90m",
reset: "\x1B[0m"
};
/** exit 事件监听器引用 */
exitListenerRef = null;
constructor() {
process.on("exit", this.stop.bind(this));
this.logSystemInfo();
}
/**
* 启动子进程
*/
start(options = {}) {
if (this.isAlreadyRunning()) {
this.log(`\u5B50\u8FDB\u7A0B\u5DF2\u5728\u8FD0\u884C | PID: ${this.childProcess.pid}`);
return this.childProcess;
}
this.isStarted = true;
const entryPath = this.resolveEntryPath();
const args = options.reloadDeps ? [`--reload-timestamp=${Date.now()}`] : [];
this.childProcess = fork(entryPath, args);
const pid = this.childProcess.pid;
this.setupEventListeners();
this.log(`\u542F\u52A8\u5B50\u8FDB\u7A0B | PID: ${pid} | \u5165\u53E3: ${path.basename(entryPath)} | \u53C2\u6570: ${args.join(" ") || "\u65E0"}`);
return this.childProcess;
}
/**
* 重启子进程
*/
async restart(reloadDeps = false) {
if (!this.childProcess) {
this.logWarn("\u91CD\u542F\u5931\u8D25 | \u539F\u56E0: \u5B50\u8FDB\u7A0B\u4E0D\u5B58\u5728 | \u64CD\u4F5C: \u76F4\u63A5\u542F\u52A8\u65B0\u8FDB\u7A0B");
return this.start({ reloadDeps });
}
const oldPid = this.childProcess.pid;
this.processStats.restartCount++;
this.processStats.lastRestartTime = Date.now();
this.log(`\u51C6\u5907\u91CD\u542F\u5B50\u8FDB\u7A0B | \u5F53\u524DPID: ${oldPid} | \u91CD\u8F7D\u4F9D\u8D56: ${reloadDeps ? "\u662F" : "\u5426"} | \u91CD\u542F\u6B21\u6570: ${this.processStats.restartCount}`);
try {
await this.terminateChildProcess();
this.isStarted = false;
const newChild = this.start({ reloadDeps });
const duration = Date.now() - this.processStats.lastRestartTime;
this.log(`\u91CD\u542F\u5B8C\u6210 | \u65E7PID: ${oldPid} | \u65B0PID: ${newChild.pid} | \u8017\u65F6: ${duration}ms`);
return newChild;
} catch (error) {
if (error.code === "ESRCH") {
this.logWarn(`\u91CD\u542F\u8FC7\u7A0B\u4E2D\u53D1\u73B0\u8FDB\u7A0B\u5DF2\u4E0D\u5B58\u5728 | \u9519\u8BEF\u7801: ${error.code} | \u64CD\u4F5C: \u542F\u52A8\u65B0\u8FDB\u7A0B`);
this.isStarted = false;
return this.start({ reloadDeps: true });
}
this.logError(`\u91CD\u542F\u5931\u8D25 | \u9519\u8BEF: ${error.message} | \u4EE3\u7801: ${error.code || "\u672A\u77E5"}`);
return null;
}
}
/**
* 停止子进程并退出父进程
*/
stop() {
if (this.childProcess) {
const pid = this.childProcess.pid;
const uptime = this.getProcessUptime();
this.log(`\u6B63\u5728\u5173\u95ED\u5B50\u8FDB\u7A0B | PID: ${pid} | \u8FD0\u884C\u65F6\u95F4: ${uptime}`);
this.terminateChildProcess();
this.childProcess = null;
this.isStarted = false;
}
const totalUptime = this.getTotalUptime();
this.log(`\u7236\u8FDB\u7A0B\u9000\u51FA | \u603B\u8FD0\u884C\u65F6\u95F4: ${totalUptime} | \u91CD\u542F\u6B21\u6570: ${this.processStats.restartCount}`);
process.exit(0);
}
/**
* 检查子进程是否已经在运行
*/
isAlreadyRunning() {
return this.isStarted && this.childProcess !== null;
}
/**
* 设置子进程事件监听器
*/
setupEventListeners() {
if (!this.childProcess) return;
this.childProcess.on("message", this.handleChildMessage.bind(this));
if (this.exitListenerRef) {
this.childProcess.off("exit", this.exitListenerRef);
}
this.exitListenerRef = this.handleChildExit.bind(this);
this.childProcess.once("exit", this.exitListenerRef);
}
/**
* 处理子进程发送的消息
*/
async handleChildMessage(message) {
if (typeof message !== "string") return;
try {
const { type, reloadDeps } = JSON.parse(message);
if (type === "restart" || type === "rs") {
this.log(`\u6536\u5230\u6D88\u606F | \u7C7B\u578B: restart | \u91CD\u8F7D\u4F9D\u8D56: ${reloadDeps ? "\u662F" : "\u5426"}`);
const child = await this.restart(reloadDeps);
if (!child) {
this.logWarn("\u91CD\u542F\u64CD\u4F5C\u5931\u8D25 | \u65E0\u6CD5\u83B7\u53D6\u65B0\u7684\u5B50\u8FDB\u7A0B");
} else {
this.childProcess = child;
}
return;
}
if (type === "stop") {
this.log("\u6536\u5230\u6D88\u606F | \u7C7B\u578B: stop | \u64CD\u4F5C: \u505C\u6B62\u8FDB\u7A0B");
this.stop();
return;
}
this.logWarn(`\u6536\u5230\u672A\u77E5\u6D88\u606F | \u7C7B\u578B: ${type || "\u672A\u77E5"} | \u5185\u5BB9: ${JSON.stringify(message).substring(0, 100)}`);
} catch (error) {
this.logError(`\u6D88\u606F\u5904\u7406\u9519\u8BEF | \u539F\u59CB\u6D88\u606F: ${String(message).substring(0, 50)}`, error);
}
}
/**
* 处理子进程退出事件
*/
handleChildExit(code, signal) {
const exitType = signal ? `\u4FE1\u53F7: ${signal}` : `\u9000\u51FA\u7801: ${code ?? "\u672A\u77E5"}`;
const uptime = this.getProcessUptime();
this.log(`\u5B50\u8FDB\u7A0B\u9000\u51FA | ${exitType} | \u8FD0\u884C\u65F6\u95F4: ${uptime}`);
this.stop();
}
/**
* 等待端口释放
* @param port - 需要检查的端口号
* @param maxAttempts - 最大尝试次数
* @param interval - 检查间隔(ms)
* @returns 端口是否可用
*/
async waitForPortRelease(port, maxAttempts = 30, interval = 500) {
const checkPort = (port2) => {
return new Promise((resolve) => {
const server = createServer();
server.once("error", () => {
server.close();
resolve(false);
});
server.once("listening", () => {
server.close();
resolve(true);
});
server.listen(port2, "127.0.0.1");
});
};
const isProcessAlive = (pid) => {
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
};
for (let attempt = 0; attempt < maxAttempts; attempt++) {
if (this.childProcess?.pid && !isProcessAlive(this.childProcess.pid)) {
this.log(`\u5B50\u8FDB\u7A0B\u5DF2\u9000\u51FA | PID: ${this.childProcess.pid}`);
const portAvailable2 = await checkPort(port);
if (portAvailable2) {
this.log(`\u7AEF\u53E3 ${port} \u5DF2\u91CA\u653E\uFF0C\u53EF\u4EE5\u4F7F\u7528`);
return true;
} else {
this.logWarn(`\u5B50\u8FDB\u7A0B\u5DF2\u9000\u51FA\uFF0C\u4F46\u7AEF\u53E3 ${port} \u4ECD\u88AB\u5360\u7528 (\u53EF\u80FD\u88AB\u5176\u4ED6\u8FDB\u7A0B\u5360\u7528)`);
}
}
const portAvailable = await checkPort(port);
if (portAvailable) {
this.log(`\u7AEF\u53E3 ${port} \u5DF2\u91CA\u653E\uFF0C\u53EF\u4EE5\u4F7F\u7528`);
return true;
}
this.logWarn(`\u7AEF\u53E3 ${port} \u4ECD\u88AB\u5360\u7528\uFF0C\u7B49\u5F85\u91CA\u653E... (${attempt + 1}/${maxAttempts})`);
try {
if (this?.childProcess?.pid && isProcessAlive(this.childProcess.pid)) {
this.log(`\u5C1D\u8BD5\u7EC8\u6B62\u5B50\u8FDB\u7A0B | PID: ${this.childProcess.pid}`);
process.kill(this.childProcess.pid);
}
} catch {
}
await new Promise((resolve) => setTimeout(resolve, interval));
}
this.logError(`\u7AEF\u53E3 ${port} \u5728 ${maxAttempts} \u6B21\u5C1D\u8BD5\u540E\u4ECD\u88AB\u5360\u7528`);
return false;
}
/**
* 获取HTTP端口号
* @returns HTTP端口号
*/
getHttpPort() {
try {
const envPath = path.resolve(process.cwd(), ".env");
if (fs.existsSync(envPath)) {
const envConfig = dotenv_default.parse(fs.readFileSync(envPath));
if (envConfig.HTTP_PORT) {
return Number(envConfig.HTTP_PORT);
}
}
return this.DEFAULT_HTTP_PORT;
} catch (error) {
this.logWarn(`\u8BFB\u53D6HTTP\u7AEF\u53E3\u5931\u8D25: ${error.message}\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u7AEF\u53E3${this.DEFAULT_HTTP_PORT}`);
return this.DEFAULT_HTTP_PORT;
}
}
/**
* 终止子进程
*/
async terminateChildProcess() {
if (!this.childProcess) return;
if (this.exitListenerRef) {
this.childProcess.off("exit", this.exitListenerRef);
this.exitListenerRef = null;
}
try {
const pid = this.childProcess.pid;
this.log(`\u53D1\u9001\u7EC8\u6B62\u4FE1\u53F7 | PID: ${pid} | \u4FE1\u53F7: SIGTERM`);
this.childProcess.kill("SIGTERM");
this.log(`\u7B49\u5F85\u8FDB\u7A0B\u7EC8\u6B62 | PID: ${pid} | \u8D85\u65F6: ${this.RESTART_DELAY_MS}ms`);
const port = this.getHttpPort();
await this.waitForPortRelease(port);
try {
if (this?.childProcess?.pid) {
this.log(`\u786E\u4FDD\u8FDB\u7A0B\u7EC8\u6B62 | PID: ${pid} | \u53D1\u9001\u5F3A\u5236\u7EC8\u6B62\u4FE1\u53F7`);
process.kill(this.childProcess.pid);
}
} catch {
}
} catch {
}
}
/**
* 解析子进程入口文件路径
*/
resolveEntryPath() {
const currentFilePath = fileURLToPath(import.meta.url);
const currentDirPath = path.dirname(currentFilePath);
const isESM = import.meta.url.includes(".mjs");
const localEntryPath = path.join(currentDirPath, isESM ? "app.mjs" : "app.ts");
return fs.existsSync(localEntryPath) ? localEntryPath : path.join(process.cwd(), "node_modules", "node-karin", "dist", "start", "app.mjs");
}
/**
* 获取当前时间戳,格式为 HH:MM:SS.mmm
*/
getTimestamp() {
const now = /* @__PURE__ */ new Date();
const hours = now.getHours().toString().padStart(2, "0");
const minutes = now.getMinutes().toString().padStart(2, "0");
const seconds = now.getSeconds().toString().padStart(2, "0");
const milliseconds = now.getMilliseconds().toString().padStart(3, "0");
return `${hours}:${minutes}:${seconds}.${milliseconds}`;
}
/**
* 创建日志前缀
*/
createLogPrefix(level) {
const timestamp = this.getTimestamp();
const prefix = `[Karin][${timestamp}][${level}]`;
return `${this.COLORS.green}${prefix}${this.COLORS.reset}`;
}
/**
* 获取进程运行时间的友好字符串
*/
getProcessUptime() {
if (!this.childProcess?.pid) return "0s";
const uptime = (Date.now() - this.processStats.lastRestartTime) / 1e3;
if (uptime < 60) return `${uptime.toFixed(1)}s`;
if (uptime < 3600) return `${(uptime / 60).toFixed(1)}m`;
return `${(uptime / 3600).toFixed(1)}h`;
}
/**
* 获取总运行时间的友好字符串
*/
getTotalUptime() {
const uptime = (Date.now() - this.startTime) / 1e3;
if (uptime < 60) return `${uptime.toFixed(1)}s`;
if (uptime < 3600) return `${(uptime / 60).toFixed(1)}m`;
return `${(uptime / 3600).toFixed(1)}h`;
}
/**
* 输出系统信息
*/
logSystemInfo() {
const nodeVersion = process.version;
const platform = `${os.platform()} ${os.release()}`;
const cpus = os.cpus().length;
const memory = `${Math.round(os.totalmem() / 1024 / 1024 / 1024)}GB`;
this.log(`\u7CFB\u7EDF\u4FE1\u606F | Node: ${nodeVersion} | \u5E73\u53F0: ${platform} | CPU\u6838\u5FC3: ${cpus} | \u5185\u5B58: ${memory}`);
}
/**
* 日志输出方法
*/
log(message) {
console.log(`${this.createLogPrefix("INFO" /* INFO */)} [${this.MODULE_NAME}] ${message}`);
}
logWarn(message) {
console.warn(`${this.createLogPrefix("WARN" /* WARN */)} [${this.MODULE_NAME}] ${message}`);
}
logError(message, error) {
console.error(`${this.createLogPrefix("ERROR" /* ERROR */)} [${this.MODULE_NAME}] ${message}`, error || "");
}
// private logDebug(message: string): void {
// console.debug(`${this.createLogPrefix(LogLevel.DEBUG)} [${this.MODULE_NAME}] ${message}`)
// }
};
new ProcessManager().start();