node-karin
Version:
Lightweight, efficient, concise, and stable robot framework.
1,508 lines (1,497 loc) • 983 kB
JavaScript
import fs24 from 'fs';
import path from 'path';
import require$$2 from 'os';
import require$$22 from 'crypto';
import { fileURLToPath } from 'url';
import fs5, { promises, existsSync as existsSync$1 } from 'node:fs';
import YAML, { isMap, isSeq, isPair } from 'yaml';
import { spawn, execSync, exec as exec$2 } from 'node:child_process';
import path4, { join } from 'node:path';
import chokidar from 'chokidar';
import axios8, { AxiosError } from 'axios';
import util5, { promisify } from 'node:util';
import { pipeline, Readable } from 'node:stream';
import lodash3 from 'lodash';
import { URL as URL$1, pathToFileURL, fileURLToPath as fileURLToPath$1 } from 'node:url';
import { createRequire } from 'module';
import crypto, { randomUUID, createHmac } from 'node:crypto';
import { EventEmitter } from 'node:events';
import WebSocket, { WebSocket as WebSocket$1, WebSocketServer } from 'ws';
import require$$02 from 'buffer';
import require$$32 from 'stream';
import require$$5 from 'util';
import os, { homedir } from 'node:os';
import { isPromise } from 'util/types';
import { exec as exec$1, spawn as spawn$1 } from 'child_process';
import { lookup } from 'dns/promises';
import { createServer as createServer$1 } from 'node:net';
import sqlite3 from 'sqlite3';
import template from 'art-template';
import schedule from 'node-schedule';
import moment from 'moment';
import { createClient } from 'redis';
import chalk2 from 'chalk';
import log4js from 'log4js';
import express2, { Router } from 'express';
import { createServer } from 'node:http';
import { createBrotliDecompress } from 'node:zlib';
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
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;
}
function requireMain() {
if (hasRequiredMain) return main$1.exports;
hasRequiredMain = 1;
const fs37 = fs24;
const path36 = path;
const os5 = require$$2;
const crypto9 = require$$22;
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(message2) {
console.log(`[dotenv@${version2}][WARN] ${message2}`);
}
function _debug(message2) {
console.log(`[dotenv@${version2}][DEBUG] ${message2}`);
}
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 (fs37.existsSync(filepath)) {
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
}
}
} else {
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
}
} else {
possibleVaultPath = path36.resolve(process.cwd(), ".env.vault");
}
if (fs37.existsSync(possibleVaultPath)) {
return possibleVaultPath;
}
return null;
}
function _resolveHome(envPath) {
return envPath[0] === "~" ? path36.join(os5.homedir(), envPath.slice(1)) : envPath;
}
function _configVault2(options) {
const debug3 = Boolean(options && options.debug);
if (debug3) {
_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 = path36.resolve(process.cwd(), ".env");
let encoding = "utf8";
const debug3 = Boolean(options && options.debug);
if (options && options.encoding) {
encoding = options.encoding;
} else {
if (debug3) {
_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 path210 of optionPaths) {
try {
const parsed = DotenvModule.parse(fs37.readFileSync(path210, { encoding }));
DotenvModule.populate(parsedAll, parsed, options);
} catch (e) {
if (debug3) {
_debug(`Failed to load ${path210} ${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 config3(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 = crypto9.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 debug3 = 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 (debug3) {
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: config3,
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 main$1, version, require$$4, hasRequiredMain, mainExports, main, dotenv;
var init_main_D88Wwqn3 = __esm({
"../../node_modules/.pnpm/@karinjs+dotenv@1.1.2/node_modules/@karinjs/dotenv/dist/main-D88Wwqn3.js"() {
main$1 = { exports: {} };
version = "16.5.0";
require$$4 = {
version
};
mainExports = requireMain();
main = /* @__PURE__ */ getDefaultExportFromCjs(mainExports);
dotenv = /* @__PURE__ */ _mergeNamespaces({
__proto__: null,
default: main
}, [mainExports]);
}
});
// ../../node_modules/.pnpm/@karinjs+dotenv@1.1.2/node_modules/@karinjs/dotenv/dist/index.js
var _configVault, _parseVault;
var init_dist = __esm({
"../../node_modules/.pnpm/@karinjs+dotenv@1.1.2/node_modules/@karinjs/dotenv/dist/index.js"() {
init_main_D88Wwqn3();
({
_configVault: (
// @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 init_dotenv = __esm({
"../../node_modules/.pnpm/@karinjs+dotenv@1.1.2/node_modules/@karinjs/dotenv/index.js"() {
init_dist();
init_dist();
app = dotenv.default;
dotenv_default = app;
}
});
var filename, karinPathRoot, karinPathMain, karinPathPlugins, isPackaged, karinPathDefaultConfig, karinPathDefaultView, karinPathComment, karinPathBase, karinPathConfig, karinPathData, karinPathTemp, karinPathResource, karinPathDb, karinPathTaskDb, karinPathRedisSqlite3, karinPathKv, karinPathLogs, karinPathHtml, karinPathPm2Config, karinPathConsole, karinPathSandboxData, karinPathSandboxTemp, karinDir, karinMain, pluginDir, isPkg, defaultConfigPath, defaultViewPath, commentPath, basePath, configPath, dataPath, tempPath, resourcePath, dbPath, redisSqlite3Path, kvPath, logsPath, htmlPath, pm2Path, consolePath, sandboxDataPath, sandboxTempPath, root_default;
var init_root = __esm({
"src/root.ts"() {
filename = fileURLToPath(import.meta.url);
karinPathRoot = Object.freeze(path.join(filename, "../..").replace(/\\/g, "/"));
karinPathMain = Object.freeze(path.join(karinPathRoot, "dist", "index.js"));
karinPathPlugins = Object.freeze(path.join(process.cwd(), "plugins"));
isPackaged = Object.freeze(filename.includes("node_modules"));
karinPathDefaultConfig = Object.freeze(path.join(karinPathRoot, "default", "config"));
karinPathDefaultView = Object.freeze(path.join(karinPathRoot, "default", "view"));
karinPathComment = Object.freeze(path.join(karinPathRoot, "default", "comment"));
karinPathBase = Object.freeze(path.join(process.cwd(), "@karinjs"));
karinPathConfig = Object.freeze(path.join(karinPathBase, "config"));
karinPathData = Object.freeze(path.join(karinPathBase, "data"));
karinPathTemp = Object.freeze(path.join(karinPathBase, "temp"));
karinPathResource = Object.freeze(path.join(karinPathBase, "resource"));
karinPathDb = Object.freeze(path.join(karinPathData, "db"));
karinPathTaskDb = Object.freeze(path.join(karinPathDb, "task"));
karinPathRedisSqlite3 = Object.freeze(path.join(karinPathDb, "redis-sqlite3"));
karinPathKv = Object.freeze(path.join(karinPathDb, "kv"));
karinPathLogs = Object.freeze(path.join(karinPathBase, "logs"));
karinPathHtml = Object.freeze(path.join(karinPathTemp, "html"));
karinPathPm2Config = Object.freeze(path.join(karinPathConfig, "pm2.yaml"));
karinPathConsole = Object.freeze(path.join(karinPathTemp, "console"));
karinPathSandboxData = Object.freeze(path.join(karinPathData, "sandbox"));
karinPathSandboxTemp = Object.freeze(path.join(karinPathTemp, "sandbox"));
karinDir = karinPathRoot;
karinMain = karinPathMain;
pluginDir = karinPathPlugins;
isPkg = isPackaged;
defaultConfigPath = karinPathDefaultConfig;
defaultViewPath = karinPathDefaultView;
commentPath = karinPathComment;
basePath = karinPathBase;
configPath = karinPathConfig;
dataPath = karinPathData;
tempPath = karinPathTemp;
resourcePath = karinPathResource;
dbPath = karinPathDb;
redisSqlite3Path = karinPathRedisSqlite3;
kvPath = karinPathKv;
logsPath = karinPathLogs;
htmlPath = karinPathHtml;
pm2Path = karinPathPm2Config;
consolePath = karinPathConsole;
sandboxDataPath = karinPathSandboxData;
sandboxTempPath = karinPathSandboxTemp;
root_default = {
// 新常量
karinPathRoot,
karinPathMain,
karinPathPlugins,
isPackaged,
karinPathDefaultConfig,
karinPathDefaultView,
karinPathComment,
karinPathBase,
karinPathConfig,
karinPathData,
karinPathTemp,
karinPathResource,
karinPathDb,
karinPathRedisSqlite3,
karinPathKv,
karinPathLogs,
karinPathHtml,
karinPathPm2Config,
karinPathConsole,
karinPathSandboxData,
karinPathSandboxTemp,
karinPathTaskDb,
// 旧常量,保持兼容性
karinDir,
karinMain,
pluginDir,
isPkg,
defaultConfigPath,
defaultViewPath,
commentPath,
basePath,
configPath,
dataPath,
tempPath,
resourcePath,
dbPath,
redisSqlite3Path,
kvPath,
logsPath,
htmlPath,
pm2Path,
consolePath,
sandboxDataPath,
sandboxTempPath
};
}
});
var IS_PNPM10, isWin, isDev, isTsx, isTs, isPnpm10, isWorkspace, setProcessEnv, setVersion, setRuntime, getModuleType;
var init_env = __esm({
"src/env/env/index.ts"() {
IS_PNPM10 = null;
isWin = () => process.platform === "win32";
isDev = () => process.env.NODE_ENV === "development";
isTsx = () => process.env.RUNTIME === "tsx";
isTs = () => isTsx();
isPnpm10 = () => {
try {
if (IS_PNPM10 === null) {
const version2 = execSync("pnpm -v").toString().trim();
const majorVersion = parseInt(version2.split(".")[0], 10);
IS_PNPM10 = !isNaN(majorVersion) && majorVersion >= 10;
}
return IS_PNPM10;
} catch {
IS_PNPM10 = false;
return false;
}
};
isWorkspace = () => {
const workspace = fs5.existsSync(`${process.cwd()}/pnpm-workspace.yaml`);
if (!workspace) return false;
const data = YAML.parse(fs5.readFileSync(`${process.cwd()}/pnpm-workspace.yaml`, "utf-8"));
return Array.isArray(data.packages) && data.packages.length > 0;
};
setProcessEnv = (key, value) => {
process.env[key] = value + "";
return value;
};
setVersion = (version2) => setProcessEnv("KARIN_VERSION", version2);
setRuntime = (runtime) => setProcessEnv("RUNTIME", runtime);
getModuleType = () => {
if (isTs()) {
return [".ts", ".js", ".cts", ".mts", ".mjs", ".cjs"];
}
return [".js", ".cjs", ".mjs"];
};
}
});
// src/env/key/redis.ts
var REDIS_PLUGIN_LIST_CACHE_KEY, REDIS_DEPENDENCIES_LIST_CACHE_KEY, REDIS_PLUGIN_MARKET_LIST_CACHE_KEY, REDIS_LOCAL_PLUGIN_LIST_CACHE_KEY, REDIS_LOCAL_PLUGIN_LIST_CACHE_KEY_FRONTEND, REDIS_DEPENDENCIES_LIST_CACHE_EXPIRE, REDIS_PLUGIN_MARKET_LIST_CACHE_EXPIRE, REDIS_PLUGIN_LIST_CACHE_EXPIRE, REDIS_LOCAL_PLUGIN_LIST_CACHE_EXPIRE_FRONTEND;
var init_redis = __esm({
"src/env/key/redis.ts"() {
REDIS_PLUGIN_LIST_CACHE_KEY = "karin:market:plugin:list";
REDIS_DEPENDENCIES_LIST_CACHE_KEY = "karin:dependencies:list";
REDIS_PLUGIN_MARKET_LIST_CACHE_KEY = "karin:market:plugin:list:v2";
REDIS_LOCAL_PLUGIN_LIST_CACHE_KEY = "karin:local:plugin:list";
REDIS_LOCAL_PLUGIN_LIST_CACHE_KEY_FRONTEND = "karin:local:plugin:list:frontend";
REDIS_DEPENDENCIES_LIST_CACHE_EXPIRE = 24 * 60 * 60;
REDIS_PLUGIN_MARKET_LIST_CACHE_EXPIRE = 24 * 60 * 60;
REDIS_PLUGIN_LIST_CACHE_EXPIRE = 24 * 60 * 60;
REDIS_LOCAL_PLUGIN_LIST_CACHE_EXPIRE_FRONTEND = 24 * 60 * 60;
}
});
// src/env/key/event.ts
var ONLINE;
var init_event = __esm({
"src/env/key/event.ts"() {
ONLINE = "online";
}
});
// src/env/key/index.ts
var init_key = __esm({
"src/env/key/index.ts"() {
init_redis();
init_event();
}
});
// src/env/index.ts
var init_env2 = __esm({
"src/env/index.ts"() {
init_env();
init_key();
}
});
var cache, clearRequireFile, clearRequire, requireFile, requireFileSync, fileReady, fileCache, touchRequireFile, parseContent;
var init_require = __esm({
"src/utils/fs/require.ts"() {
cache = /* @__PURE__ */ new Map();
clearRequireFile = (filePath) => {
const absPath2 = path4.resolve(filePath).replace(/\\/g, "/");
return cache.has(absPath2) && cache.delete(absPath2);
};
clearRequire = () => cache.clear();
requireFile = async (filePath, options = {}) => {
const now = Date.now();
const absPath2 = path4.resolve(filePath).replace(/\\/g, "/");
const { encoding = "utf-8", force = false, ex = 300, size = 0, parser: parser2, type, readCache } = options;
const data = fileReady(absPath2, now, force, ex, readCache);
if (data !== false) return data;
const content = await fs5.promises.readFile(absPath2, encoding);
return fileCache(content, absPath2, ex, now, size, encoding, parser2, type);
};
requireFileSync = (filePath, options = {}) => {
const now = Date.now();
const absPath2 = path4.resolve(filePath).replace(/\\/g, "/");
const { encoding = "utf-8", force = false, ex = 300, size = 0, parser: parser2, type, readCache } = options;
const data = fileReady(absPath2, now, force, ex, readCache);
if (data !== false) return data;
const content = fs5.readFileSync(absPath2, encoding);
return fileCache(content, absPath2, ex, now, size, encoding, parser2, type);
};
fileReady = (absPath2, now, force, ex, readCache) => {
if (!force) {
const cached = cache.get(absPath2);
if (cached) {
if (cached.expiry === 0 || cached.expiry > now) {
if (ex <= 0) return cached.data;
touchRequireFile(absPath2, ex);
return cached.data;
} else {
cache.delete(absPath2);
}
}
if (readCache) return void 0;
}
return false;
};
fileCache = (content, absPath2, ex, now, size, encoding, parser2, type) => {
if (size > 0 && Buffer.byteLength(content, encoding) > size) {
return parseContent(absPath2, content, parser2, type);
}
const data = parseContent(absPath2, content, parser2, type);
const expiry = ex === 0 ? 0 : now + ex * 1e3;
cache.set(absPath2, { data, expiry });
return data;
};
touchRequireFile = async (filePath, ex) => {
const entry = cache.get(filePath);
if (entry) {
entry.expiry = Date.now() + ex * 1e3;
cache.set(filePath, entry);
}
};
parseContent = (absPath2, content, parser2, type) => {
if (parser2) return parser2(content);
if (type) {
if (type === "json") return JSON.parse(content);
if (type === "yaml" || type === "yml") return YAML.parse(content);
}
if (absPath2.endsWith(".json")) return JSON.parse(content);
if (absPath2.endsWith(".yaml") || absPath2.endsWith(".yml")) return YAML.parse(content);
return content;
};
setInterval(() => {
const now = Date.now();
for (const [key, entry] of cache.entries()) {
if (entry.expiry === 0) continue;
if (entry.expiry <= now) cache.delete(key);
}
}, 6e4);
}
});
// src/utils/config/pkg.ts
var pkg;
var init_pkg = __esm({
"src/utils/config/pkg.ts"() {
init_root();
init_require();
pkg = () => requireFileSync(`${karinDir}/package.json`);
}
});
// src/utils/config/default.ts
var defaultConfig;
var init_default = __esm({
"src/utils/config/default.ts"() {
defaultConfig = Object.freeze({
adapter: {
console: {
isLocal: true,
token: "",
host: ""
},
onebot: {
ws_server: {
enable: true,
timeout: 120
},
ws_client: [
{
enable: false,
url: "ws://127.0.0.1:7778",
token: ""
}
],
http_server: [
{
enable: false,
self_id: "default",
url: "http://127.0.0.1:6099",
token: "",
api_token: "",
post_token: ""
}
]
}
},
config: {
master: [
"console"
],
admin: [],
user: {
enable_list: [],
disable_list: []
},
friend: {
enable: true,
enable_list: [],
disable_list: [],
log_enable_list: [],
log_disable_list: []
},
group: {
enable: true,
enable_list: [],
disable_list: [],
log_enable_list: [],
log_disable_list: []
},
directs: {
enable: true,
enable_list: [],
disable_list: [],
log_enable_list: [],
log_disable_list: []
},
guilds: {
enable: true,
enable_list: [],
disable_list: [],
log_enable_list: [],
log_disable_list: []
},
channels: {
enable: true,
enable_list: [],
disable_list: [],
log_enable_list: [],
log_disable_list: []
}
},
groups: [
{
key: "default",
inherit: true,
cd: 0,
userCD: 0,
mode: 0,
alias: [],
enable: [],
disable: [],
member_enable: [],
member_disable: []
},
{
key: "global",
inherit: true,
cd: 0,
userCD: 0,
mode: 0,
alias: [],
enable: [],
disable: [],
member_enable: [],
member_disable: []
},
{
key: "Bot:selfId",
inherit: true,
cd: 0,
userCD: 0,
mode: 0,
alias: [],
enable: [],
disable: [],
member_enable: [],
member_disable: []
},
{
key: "Bot:selfId:groupId",
inherit: true,
cd: 0,
userCD: 0,
mode: 0,
alias: [],
enable: [],
disable: [],
member_enable: [],
member_disable: []
},
{
key: "Bot:selfId:guildId",
inherit: true,
cd: 0,
userCD: 0,
mode: 0,
alias: [],
enable: [],
disable: [],
member_enable: [],
member_disable: []
},
{
key: "Bot:selfId:guildId:channelId",
inherit: true,
cd: 0,
userCD: 0,
mode: 0,
alias: [],
enable: [],
disable: [],
member_enable: [],
member_disable: []
}
],
pm2: {
lines: 1e3,
apps: [
{
name: "karin",
script: "index.js",
autorestart: true,
max_restarts: 60,
max_memory_restart: "1G",
restart_delay: 2e3,
merge_logs: true,
error_file: "./@karinjs/logs/pm2_error.log",
out_file: "./@karinjs/logs/pm2_out.log"
}
]
},
privates: [
{
key: "default",
inherit: true,
cd: 0,
mode: 0,
alias: [],
enable: [],
disable: []
},
{
key: "global",
inherit: true,
cd: 0,
mode: 0,
alias: [],
enable: [],
disable: []
},
{
key: "Bot:selfId",
inherit: true,
cd: 0,
mode: 0,
alias: [],
enable: [],
disable: []
},
{
key: "Bot:selfId:userId",
inherit: true,
cd: 0,
mode: 0,
alias: [],
enable: [],
disable: []
}
],
redis: {
url: "redis://127.0.0.1:6379",
username: "",
password: "",
database: 0
},
render: {
ws_server: {
enable: true
},
ws_client: [
{
enable: false,
url: "ws://127.0.0.1:7005",
token: "123456",
isSnapka: false,
reconnectTime: 5e3,
heartbeatTime: 3e4
}
],
http_server: [
{
enable: false,
url: "http://127.0.0.1:7005",
token: "123456",
isSnapka: false
}
]
}
});
}
});
var cache2, watch, watchAndMerge, Watch, Watcher;
var init_watch = __esm({
"src/utils/fs/watch.ts"() {
init_require();
cache2 = /* @__PURE__ */ new Map();
watch = (file2, fnc2, options) => {
const isWatch = cache2.get(file2);
if (isWatch) {
isWatch.close();
cache2.delete(file2);
}
const watcher2 = chokidar.watch(file2);
cache2.set(file2, watcher2);
watcher2.on("change", async () => {
logger.info(`[watch][change] ${path4.relative(process.cwd(), file2).replace(/\\/g, "/")}`);
const oldData = requireFileSync(file2, { ...options, readCache: true });
clearRequireFile(file2);
const newData = requireFileSync(file2, { ...options, force: true });
typeof fnc2 === "function" && fnc2(oldData, newData);
});
watcher2.on("unlink", () => {
logger.info(`[watch][unlink] ${path4.relative(process.cwd(), file2).replace(/\\/g, "/")}`);
clearRequireFile(file2);
});
watcher2.once("close", () => {
cache2.delete(file2);
clearRequireFile(file2);
});
return new Watch(file2, watcher2, options);
};
watchAndMerge = (dynamicFile, defaultCFile, fnc2) => {
const watcher2 = watch(dynamicFile, fnc2);
return new Watcher(dynamicFile, defaultCFile, watcher2.watcher, watcher2.options);
};
Watch = class {
watcher;
file;
options;
constructor(file2, watcher2, options) {
this.watcher = watcher2;
this.file = file2;
this.options = options;
}
/**
* @description 获取配置数据
*/
get value() {
return requireFileSync(this.file, this.options);
}
/**
* @description 关闭监听器并清理全部缓存
*/
close() {
clearRequireFile(this.file);
return this.watcher.close();
}
};
Watcher = class {
watcher;
dynamicFile;
defaultCFile;
options;
constructor(dynamicFile, defaultCfgFile, watcher2, options) {
this.watcher = watcher2;
this.dynamicFile = dynamicFile;
this.defaultCFile = defaultCfgFile;
this.options = options;
}
/**
* @description 获取配置数据
*/
get value() {
const dynamicData = requireFileSync(this.dynamicFile, this.options);
const defaultData = requireFileSync(this.defaultCFile, this.options);
if (typeof defaultData === "object" && typeof dynamicData === "object") {
return { ...defaultData, ...dynamicData };
}
if (Array.isArray(defaultData) && Array.isArray(dynamicData)) {
return [...defaultData, ...dynamicData];
}
return dynamicData;
}
/**
* @description 关闭监听器并清理全部缓存
*/
close() {
clearRequireFile(this.defaultCFile);
return this.watcher.close();
}
};
}
});
var exists, isDir, isFile, mkdir, existToMkdir;
var init_fsPromises = __esm({
"src/utils/fs/fsPromises.ts"() {
exists = async (file2) => {
try {
await fs5.promises.access(file2, fs5.constants.F_OK);
return true;
} catch {
return false;
}
};
isDir = async (file2) => {
try {
const stat = await fs5.promises.stat(file2);
return stat.isDirectory();
} catch {
return false;
}
};
isFile = async (file2) => {
try {
const stat = await fs5.promises.stat(file2);
return stat.isFile();
} catch {
return false;
}
};
mkdir = async (dirname) => {
try {
await fs5.promises.mkdir(dirname, { recursive: true });
return true;
} catch {
return false;
}
};
existToMkdir = async (file2) => {
try {
if (!await exists(file2)) await mkdir(file2);
return true;
} catch {
return false;
}
};
}
});
var existsSync, isDirSync, isFileSync, mkdirSync, existToMkdirSync, rmSync;
var init_fsSync = __esm({
"src/utils/fs/fsSync.ts"() {
existsSync = (file2) => {
return fs5.existsSync(file2);
};
isDirSync = (file2) => {
try {
return fs5.statSync(file2).isDirectory();
} catch {
return false;
}
};
isFileSync = (file2) => {
try {
return fs5.statSync(file2).isFile();
} catch {
return false;
}
};
mkdirSync = (dirname) => {
try {
fs5.mkdirSync(dirname, { recursive: true });
return true;
} catch {
return false;
}
};
existToMkdirSync = (file2) => {
try {
if (!fs5.existsSync(file2)) mkdirSync(file2);
return true;
} catch {
return false;
}
};
rmSync = fs5.rmSync;
}
});
var streamPipeline, sep, downloadFile, downFile, absPath, createPluginDir, getFiles, copyFilesSync, copyFiles, copyConfigSync, copyConfig, getAllFilesSync, getAllFiles;
var init_file = __esm({
"src/utils/fs/file.ts"() {
init_root();
streamPipeline = promisify(pipeline);
sep = path4.sep === "/" ? /^file:\/\// : /^file:[/]{2,3}/;
downloadFile = async (fileUrl, savePath, options = {}) => {
try {
await fs5.promises.mkdir(path4.dirname(savePath), { recursive: true });
const response = await axios8.get(fileUrl, { ...options, responseType: "stream" });
await streamPipeline(response.data, fs5.createWriteStream(savePath));
if (options.returnBoolean) {
return true;
}
return { success: true, data: response.data };
} catch (error) {
if (options.returnBoolean) {
return false;
}
return { success: false, data: error };
}
};
downFile = async (fileUrl, savePath, param = {}) => {
return downloadFile(fileUrl, savePath, { ...param, returnBoolean: true });
};
absPath = (file2, absPath2 = true, prefix = false) => {
file2 = file2.replace(/\\/g, "/");
if (file2.startsWith("file://")) file2 = file2.replace(sep, "");
file2 = path4.normalize(file2);
if (absPath2) file2 = path4.resolve(file2);
if (prefix) file2 = "file://" + file2;
return file2.replace(/\\/g, "/");
};
createPluginDir = async (name, files) => {
if (!Array.isArray(files)) files = ["config", "data", "resources"];
if (files.length === 0) return;
const isOrgPkg = name.startsWith("@") && name.includes("/");
let pluginPath = isOrgPkg ? path4.join(karinPathBase, name.replace("/", "-")) : path4.join(karinPathBase, name);
if (isOrgPkg && !fs5.existsSync(pluginPath)) {
const [orgName, pkgName] = name.split("/");
pluginPath = path4.join(karinPathBase, orgName, pkgName);
}
await Promise.all(files.map((file2) => {
const filePath = path4.join(pluginPath, file2);
if (!fs5.existsSync(filePath)) return fs5.promises.mkdir(filePath, { recursive: true });
return Promise.resolve();
}));
};
getFiles = (filePath, suffixs = []) => {
if (!fs5.existsSync(filePath)) {
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${filePath}`);
}
let files = fs5.readdirSync(filePath, { withFileTypes: true }).filter((file2) => file2.isFile()).map((file2) => file2.name);
if (suffixs.length) {
const normalizedSuffixs = suffixs.map((suffix) => suffix.startsWith(".") ? suffix : `.${suffix}`);
files = files.filter((file2) => {
const suffix = path4.extname(file2);
return suffix && normalizedSuffixs.includes(suffix);
});
}
return files;
};
copyFilesSync = (files, defaulPath, userPath) => {
files.forEach((file2) => {
const defaulFile = path4.join(defaulPath, file2);
const userFile = path4.join(userPath, file2);
if (!fs5.existsSync(userFile)) {
fs5.copyFileSync(defaulFile, userFile);
}
});
};
copyFiles = async (files, defaulPath, userPath) => {
await Promise.all(files.map(async (file2) => {
const defaulFile = path4.join(defaulPath, file2);
const userFile = path4.join(userPath, file2);
if (!fs5.existsSync(userFile)) {
await fs5.promises.copyFile(defaulFile, userFile);
}
}));
};
copyConfigSync = (defaulPath, userPath, suffixs = [], isThrow = false) => {
try {
const files = getFiles(defaulPath, suffixs);
fs5.mkdirSync(userPath, { recursive: true });
fs5.mkdirSync(defaulPath, { recursive: true });
copyFilesSync(files, defaulPath, userPath);
return true;
} catch (error) {
if (isThrow) throw error;
return false;
}
};
copyConfig = async (defaulPath, userPath, suffixs = [], isThrow = false) => {
try {
const files = getFiles(defaulPath, suffixs);
await Promise.all([
fs5.promises.mkdir(userPath, { recursive: true }),
fs5.promises.mkdir(defaulPath, { recursive: true })
]);
await copyFiles(files, defaulPath, userPath);
return true;
} catch (error) {
if (isThrow) throw error;
return false;
}
};
getAllFilesSync = (dir, options = {}) => {
const { suffixs = [], exclude = [], returnType = "rel" } = options;
const result = [];
const readDirRecursive = (currentDir, prefix = "") => {
const files = fs5.readdirSync(currentDir, { withFileTypes: true });
for (const file2 of files) {
const relativePath = path4.join(prefix, file2.name);
const fullPath = path4.join(currentDir, file2.name);
if (file2.isDirectory()) {
readDirRecursive(fullPath, relativePath);
} else if (file2.isFile()) {
const suffix = path4.extname(file2.name);
if (suffixs.length > 0) {
const normalizedSuffixs = suffixs.map((s) => s.startsWith(".") ? s : `.${s}`);
if (normalizedSuffixs.includes(suffix)) {
result.push(returnType === "abs" ? fullPath : relativePath);
}
} else if (exclude.length > 0) {
const normalizedExclude = exclude.map((s) => s.startsWith(".") ? s : `.${s}`);
if (!normalizedExclude.includes(suffix)) {
result.push(returnType === "abs" ? fullPath : relativePath);
}
} else {
result.push(returnType === "abs" ? fullPath : relativePath);
}
}
}
};
if (!fs5.existsSync(dir)) {
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${dir}`);
}
readDirRecursive(dir);
return result;
};
getAllFiles = async (dir, options = {}) => {
const { suffixs = [], exclude = [], returnType = "rel" } = options;
const result = [];
const readDirRecursive = async (currentDir, prefix = "") => {
const files = await fs5.promises.readdir(currentDir, { withFileTypes: true });
await Promise.all(files.map(async (file2) => {
const relativePath = path4.join(prefix, file2.name);
const fullPath = path4.join(currentDir, file2.name);
if (file2.isDirectory()) {
await readDirRecursive(fullPath, relativePath);
} else if (file2.isFile()) {
const suffix = path4.extname(file2.name);
if (suffixs.length > 0) {
const normalizedSuffixs = suffixs.map((s) => s.startsWith(".") ? s : `.${s}`);
if (normalizedSuffixs.includes(suffix)) {
result.push(returnType === "abs" ? fullPath : relativePath);
}
} else if (exclude.length > 0) {
const normalizedExclude = exclude.map((s) => s.startsWith(".") ? s : `.${s}`);
if (!normalizedExclude.includes(suffix)) {
result.push(returnType === "abs" ? fullPath : relativePath);
}
} else {
result.push(returnType === "abs" ? fullPath : relativePath);
}
}
}));
};
if (!fs5.existsSync(dir)) {
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${dir}`);
}
await readDirRecursive(dir);
return result;
};
}
});
var base64, buffer, stream, readFile, randomStr;
var init_data = __esm({
"src/utils/fs/data.ts"() {
init_file();
base64 = async (data, options = { http: false }) => {
if (typeof data !== "string") {
if (Buffer.isBuffer(data)) return data.toString("base64");
if (data instanceof Uint8Array) return Buffer.from(data).toString("base64");
if (data instanceof Readable) return (await stream(data)).toString("base64");
return data;
}
if (data.startsWith("base64://")) return data.replace("base64://", "");
if (data.startsWith("http")) {
if (options.http) return data;
const response = await axios8.get(data, { responseType: "stream" });
const buffer2 = await stream(response.data);
return buffer2.toString("base64");
}
const files = data.replace(sep, "");
if (fs5.existsSync(files)) return (await fs5.promises.readFile(files)).toString("base64");
return Buffer.from(data, "base64").toString("base64");
};
buffer = async (data, options) => {
if (typeof data !== "string") {
if (Buffer.isBuffer(data)) return data;
if (data instanceof Uint8Array) return Buffer.from(data);
if (data instanceof Readable) return await stream(data);
return data;
}
if (data.startsWith("base64://")) {
return Buffer.from(data.replace("base64://", ""), "base64");
}
if (data.startsWith("http")) {
if (options?.http) return data;
const response = await axios8.get(data, { responseType: "arraybuffer" });
return Buffer.from(response.data, "binary");
}
const files = data.replace(sep, "");
if (fs5.existsSync(files)) return fs5.readFileSync(files);
return Buffer.from(data);
};
stream = (stream2) => new Promise((resolve, reject) => {
const chunks = [];
stream2.on("data", (chunk) => chunks.push(chunk));
stream2.on("end", () => resolve(Buffer.concat(chunks)));
stream2.on("error", (error) => reject(error));
});
readFile = async (path36) => {
try {
const data = await fs5.promises.readFile(path36);
return data;
} catch (error) {
logger.error(error);
return null;
}
};
randomStr = (length = 8) => {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join("");
};
}
});
var readJsonSync, writeJsonSync, readJson, writeJson, json;
var init_json = __esm({
"src/utils/fs/json.ts"() {
readJsonSync = (path36, isThrow = false) => {
try {
const data = fs5.readFileSync(path36, "utf8");
return JSON.parse(data);
} catch (error) {
if (isThrow) throw error;
return null;
}
};
writeJsonSync = (path36, data, isThrow = false) => {
try {
fs5.writeFileSync(path36, JSON.stringify(data, null, 2));
return true;
} catch (error) {
if (isThrow) throw error;
return false;
}
};
readJson = async (path36, isThrow = false) => {
try {
const data = await fs5.promises.readFile(path36, "utf8");
return JSON.parse(data);
} catch (error) {
if (isThrow) throw error;
return null;
}
};
writeJson = async (path36, data, isThrow = false) => {
try {
await fs5.promises.writeFile(path36, JSON.stringify(data, null, 2));
return true;
} catch (error) {
if (isThrow) throw error;
return false;
}
};
json = {
/** 同步读取 */
readSync: readJsonSync,
/** 同步写入 */
writeSync: writeJsonSync,
/** 异步读取 */
read: readJson,
/** 异步写入 */
write: writeJson
};
}
});
var filesByExt, splitPath, getRelPath, urlToPath, isSubPath, formatPath, isPathEqual;
var init_path = __esm({
"src/utils/fs/path.ts"() {
init_file();
filesByExt = (filePath, ext, returnType = "name") => {
if (!fs5.existsSync(filePath) || !fs5.statSync(filePath).isDirectory()) return [];
const files = fs5.readdirSync(filePath, { withFileTypes: true });
const list2 = [];
if (!Array.isArray(ext)) ext = [ext];
const allFiles = (dir, entry) => {
if (entry.isDirectory()) {
const subFiles = filesByExt(path4.join(dir, entry.name), ext, returnType);
list2.push(...subFiles);
} else if (ext.includes(path4.extname(entry.name))) {
if (returnType === "name") {
list2.push(entry.name);
} else if (returnType === "rel") {
const file2 = path4.resolve(dir, entry.name);
list2.push(path4.relative(process.cwd(), file2));
} else if (returnType === "abs") {
list2.push(formatPath(path4.resolve(dir, entry.name)));
}
}
};
files.forEach((entry) => allFiles(filePath, entry));
return list2;
};
splitPath = (filePath) => {
const dirname = path4.dirname(filePath).replace(sep, "");
const basename = path4.basename(filePath);
return { dirname, basename };
};
getRelPath = (filePath) => filePath.replace(/\\+/g, "/").replace(/\.+\/+|\/+$/g, "");
urlToPath = (url) => {
const filePath = fileURLToPath$1(url);
const rel = path4.relative(path4.dirname(filePath), process.cwd());
const upLevelsCount = rel.split(path4.sep).length;
return lodash3.repeat("../", upLevelsCount);
};
isSubPath = (root, target, isAbs = true) => {
if (isAbs) {
root = path4.resolve(root);
target = path4.resolve(target);
}
const relative = path4.relative(root, target);
return relative && !relative.startsWith("..") && !path4.isAbsolute(relative);
};
formatPath = (filePath) => {
return path4.resolve(filePath).replace(/\\/g, "/");
};
isPathEqual = (path1, path210) => {
if (path1 === path210) return true;
path1 = formatPath(path1);
path210 = formatPath(path210);
if (path1 === path210) return true;
if (process.platform === "win32") {
return path1.toLowerCase() === path210.toLowerCase();
}
return false;
};
}
});
// src/plugin/system/cache.ts
var cache3;
var init_cache = __esm({
"src/plugin/system/cache.ts"() {
cache3 = {
index: {},
accept: [],
command: [],
task: [],
button: [],
handler: {},
missing: /* @__PURE__ */ new Map(),
watcher: /* @__PURE__ */ new Map(),
count: {
accept: 0,
command: 0,
task: 0,
button: 0,
handler: {
key: 0,
fnc: 0
}
},
static: []
};
}
});
var pkgRoot, getPluginInfo, isPlugin;
var init_pkg2 = __esm({
"src/utils/fs/pkg.ts"() {
init_cache();
init_require();
pkgRoot = (name, rootPath) => {
let dir;
if (import.meta.url) {
const require2 = createRequire(rootPath || import.meta.url);
dir = require2.resolve(name);
} else {
__require.resolve(name);
dir = __require.resolve(name);
}
try {
if (existsSync$1(path4.join(dir, "package.json"))) {
return path4.resolve(dir);
}
while (true) {
dir = path4.dirname(dir);
if (existsSync$1(path4.join(dir, "package.json"))) {
return path4.resolve(dir);
}
if (dir === path4.dirname(dir)) {
throw new Error(`[common] \u672A\u627E\u5230\u5305${name}\u7684\u6839\u76EE\u5F55`);
}
}
} finally {
delete __require.cache[__require.resolve(name)];
}
};
getPluginInfo = (name) => {
const list2 = Object.values(cache3.index);
const plugin = list2.find((item) => item.name === name);
if (!plugin) return null;
const info = {
get pkg() {
if (!plugin.pkgPath) return null;
return requireFileSync(plugin.pkgPath);
}
};
return Object.assign(plugin, info);
};
isPlugin = (name) => {
return !!getPluginInfo(name);
};
}
});
// src/utils/fs/static.ts
var isPublic;
var init_static = __esm({
"src/utils/fs/static.ts"() {
init_path();
init_cache();
isPublic = (filePath) => {
try {
for (const item of cache3.static) {
if (isSubPat