Comparing version 1.2.0 to 1.3.0
export * from 'koishi-core'; | ||
export * from 'koishi-utils'; | ||
export { AppConfig } from './worker'; | ||
declare const version: any; | ||
export { version }; |
@@ -10,2 +10,3 @@ "use strict"; | ||
const utils_1 = require("./utils"); | ||
const js_yaml_1 = require("js-yaml"); | ||
const prompts_1 = __importDefault(require("prompts")); | ||
@@ -52,8 +53,18 @@ async function createConfig(options) { | ||
}); | ||
return succeed && data; | ||
if (!succeed) | ||
return; | ||
const config = {}; | ||
for (const key in data) { | ||
if (data[key]) | ||
config[key] = data[key]; | ||
} | ||
config.plugins = ['common', 'schedule']; | ||
return config; | ||
} | ||
const supportedTypes = ['js', 'json', 'yml', 'yaml']; | ||
function default_1(cli) { | ||
cli.command('init [file]', 'initialize a koishi.config.js file') | ||
cli.command('init [file]', 'initialize a koishi configuration file') | ||
.option('-f, --forced', 'overwrite config file if it exists') | ||
.action(async (file, options) => { | ||
// resolve file path | ||
const path = path_1.resolve(process.cwd(), String(file || 'koishi.config.js')); | ||
@@ -64,2 +75,13 @@ if (!options.forced && fs_1.existsSync(path)) { | ||
} | ||
// parse extension | ||
const extension = path_1.extname(path).slice(1); | ||
if (!extension) { | ||
utils_1.logger.error(`configuration file should have an extension, received "${file}"`); | ||
process.exit(1); | ||
} | ||
else if (!supportedTypes.includes(extension)) { | ||
utils_1.logger.error(`configuration file type "${extension}" is currently not supported`); | ||
process.exit(1); | ||
} | ||
// create configurations | ||
const config = await createConfig(options); | ||
@@ -70,18 +92,17 @@ if (!config) { | ||
} | ||
const output = ['module.exports = {']; | ||
output.push(` type: "${config.type}",`); | ||
if (config.port) | ||
output.push(` port: ${config.port},`); | ||
output.push(` server: ${JSON.stringify(config.server)},`); | ||
if (config.selfId) | ||
output.push(` selfId: ${config.selfId},`); | ||
if (config.secret) | ||
output.push(` secret: ${JSON.stringify(config.secret)},`); | ||
if (config.token) | ||
output.push(` token: ${JSON.stringify(config.token)},`); | ||
output.push(' plugins: ['); | ||
output.push(' ["common"],'); | ||
output.push(' ],'); | ||
output.push('}\n'); | ||
fs_1.writeFileSync(path, output.join('\n')); | ||
// generate output | ||
let output; | ||
switch (extension) { | ||
case 'yml': | ||
case 'yaml': | ||
output = js_yaml_1.safeDump(config); | ||
break; | ||
default: | ||
output = JSON.stringify(config, null, 2); | ||
if (extension === 'js') { | ||
output = 'module.exports = ' + output.replace(/^(\s+)"([\w$]+)":/mg, '$1$2:'); | ||
} | ||
} | ||
// write to file | ||
fs_1.writeFileSync(path, output); | ||
utils_1.logger.success(`created config file: ${path}`); | ||
@@ -88,0 +109,0 @@ process.exit(0); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const perf_hooks_1 = require("perf_hooks"); | ||
const koishi_utils_1 = require("koishi-utils"); | ||
const child_process_1 = require("child_process"); | ||
@@ -15,5 +16,2 @@ const path_1 = require("path"); | ||
} | ||
else if (data.type === 'error') { | ||
utils_1.logger.error(data.message); | ||
} | ||
}); | ||
@@ -31,3 +29,3 @@ child.on('exit', (code) => { | ||
else { | ||
utils_1.logger.warning('an error was encounted. restarting...'); | ||
utils_1.logger.warn('an error was encounted. restarting...'); | ||
} | ||
@@ -40,4 +38,19 @@ createWorker(); | ||
.alias('start') | ||
.option('--log-level <level>', 'specify log level (default: 3)') | ||
.option('--silent', 'use log level 0 (print no message)') | ||
.option('--debug', 'use log level 4 (print all messages)') | ||
.action((file, options) => { | ||
process.env.KOISHI_BASE_PATH = path_1.resolve(process.cwd(), file || ''); | ||
let logLevel = options.logLevel; | ||
if (options.silent) | ||
logLevel = 0; | ||
if (options.debug) | ||
logLevel = 4; | ||
if (logLevel !== undefined) { | ||
if (!koishi_utils_1.isInteger(logLevel) || logLevel < 0) { | ||
utils_1.logger.error('log level should be a positive integer.'); | ||
process.exit(1); | ||
} | ||
process.env.KOISHI_LOG_LEVEL = '' + logLevel; | ||
} | ||
process.env.KOISHI_CONFIG_FILE = file || ''; | ||
createWorker(); | ||
@@ -44,0 +57,0 @@ }); |
export declare namespace logger { | ||
function info(...args: any[]): void; | ||
function error(...args: any[]): void; | ||
function warning(...args: any[]): void; | ||
function success(...args: any[]): void; | ||
function info(message: string, logLevel?: number): void; | ||
function error(message: string, logLevel?: number): void; | ||
function warn(message: string, logLevel?: number): void; | ||
function success(message: string, logLevel?: number): void; | ||
function debug(message: string, logLevel?: number): void; | ||
} |
@@ -9,18 +9,32 @@ "use strict"; | ||
(function (logger) { | ||
function info(...args) { | ||
console.log(`${kleur_1.default.blue('info')}`, ...args); | ||
function info(message, logLevel) { | ||
if (logLevel < 3) | ||
return; | ||
console.log(`${kleur_1.default.blue('info')}`, message); | ||
} | ||
logger.info = info; | ||
function error(...args) { | ||
console.log(`${kleur_1.default.red('error')}`, ...args); | ||
function error(message, logLevel) { | ||
if (logLevel < 1) | ||
return; | ||
console.log(`${kleur_1.default.red('error')}`, message); | ||
} | ||
logger.error = error; | ||
function warning(...args) { | ||
console.log(`${kleur_1.default.yellow('warning')}`, ...args); | ||
function warn(message, logLevel) { | ||
if (logLevel < 2) | ||
return; | ||
console.log(`${kleur_1.default.yellow('warning')}`, message); | ||
} | ||
logger.warning = warning; | ||
function success(...args) { | ||
console.log(`${kleur_1.default.green('success')}`, ...args); | ||
logger.warn = warn; | ||
function success(message, logLevel) { | ||
if (logLevel < 1) | ||
return; | ||
console.log(`${kleur_1.default.green('success')}`, message); | ||
} | ||
logger.success = success; | ||
function debug(message, logLevel) { | ||
if (logLevel < 4) | ||
return; | ||
console.log(`${kleur_1.default.magenta('debug')}`, message); | ||
} | ||
logger.debug = debug; | ||
})(logger = exports.logger || (exports.logger = {})); |
@@ -0,1 +1,8 @@ | ||
import { AppOptions, Plugin } from 'koishi-core'; | ||
declare type PluginConfig = (string | [string | Plugin, any])[]; | ||
export interface AppConfig extends AppOptions { | ||
plugins?: PluginConfig | Record<string, PluginConfig>; | ||
logLevel?: number; | ||
logFilter?: Record<string, number>; | ||
} | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const koishi_core_1 = require("koishi-core"); | ||
const path_1 = require("path"); | ||
const koishi_utils_1 = require("koishi-utils"); | ||
const perf_hooks_1 = require("perf_hooks"); | ||
const kleur_1 = require("kleur"); | ||
const path_1 = require("path"); | ||
const utils_1 = require("./utils"); | ||
const util_1 = require("util"); | ||
const fs_1 = require("fs"); | ||
const js_yaml_1 = require("js-yaml"); | ||
const { version } = require('../package'); | ||
let baseLogLevel = 3; | ||
if (process.env.KOISHI_LOG_LEVEL !== undefined) { | ||
baseLogLevel = +process.env.KOISHI_LOG_LEVEL; | ||
} | ||
process.on('uncaughtException', ({ message }) => { | ||
process.send({ | ||
type: 'error', | ||
message, | ||
}, () => { | ||
process.exit(-1); | ||
}); | ||
utils_1.logger.error(message, baseLogLevel); | ||
process.exit(-1); | ||
}); | ||
const noModule = new Set(); | ||
function loadFromModules(modules, message) { | ||
for (const name of modules) { | ||
if (noModule.has(name)) | ||
continue; | ||
try { | ||
return require(name); | ||
} | ||
catch (e) { | ||
noModule.add(name); | ||
} | ||
} | ||
throw new Error(message); | ||
} | ||
const base = process.env.KOISHI_BASE_PATH; | ||
const cwd = process.cwd(); | ||
function loadEcosystem(type, name) { | ||
let depName; | ||
const modules = [path_1.resolve(cwd, name)]; | ||
const prefix = `koishi-${type}-`; | ||
if (name.includes(prefix)) { | ||
depName = name; | ||
modules.unshift(name); | ||
} | ||
else { | ||
const index = name.lastIndexOf('/'); | ||
depName = name.slice(0, index + 1) + prefix + name.slice(index + 1); | ||
modules.unshift(name.slice(0, index + 1) + prefix + name.slice(index + 1)); | ||
} | ||
return loadFromModules([ | ||
depName, | ||
path_1.resolve(base, name), | ||
], `cannot resolve ${type} ${name}`); | ||
for (const name of modules) { | ||
try { | ||
return require(name); | ||
} | ||
catch { } | ||
} | ||
throw new Error(`cannot resolve ${type} ${name}`); | ||
} | ||
function loadPlugins(ctx, plugins) { | ||
for (const [plugin, options] of plugins) { | ||
const resolved = typeof plugin === 'string' ? loadEcosystem('plugin', plugin) : plugin; | ||
ctx.plugin(resolved, options); | ||
if (resolved.name) | ||
utils_1.logger.info(`apply plugin ${kleur_1.cyan(resolved.name)}`); | ||
for (const item of plugins) { | ||
let plugin, options; | ||
if (typeof item === 'string') { | ||
plugin = loadEcosystem('plugin', item); | ||
} | ||
else { | ||
plugin = typeof item[0] === 'string' ? loadEcosystem('plugin', item[0]) : item[0]; | ||
options = item[1]; | ||
} | ||
ctx.plugin(plugin, options); | ||
if (plugin.name) | ||
utils_1.logger.info(`apply plugin ${kleur_1.cyan(plugin.name)}`, baseLogLevel); | ||
} | ||
@@ -60,3 +59,3 @@ } | ||
if (resolved) | ||
utils_1.logger.info(`apply database ${kleur_1.cyan(name)}`); | ||
utils_1.logger.info(`apply database ${kleur_1.cyan(name)}`, baseLogLevel); | ||
} | ||
@@ -74,6 +73,24 @@ const app = new koishi_core_1.App(config); | ||
} | ||
const config = loadFromModules([ | ||
path_1.resolve(base, 'koishi.config'), | ||
base, | ||
], 'config file not found.'); | ||
const configFile = path_1.resolve(cwd, process.env.KOISHI_CONFIG_FILE || 'koishi.config'); | ||
const extension = path_1.extname(configFile); | ||
let config; | ||
function tryCallback(callback) { | ||
try { | ||
return callback(); | ||
} | ||
catch { } | ||
} | ||
if (['.js', '.json'].includes(extension)) { | ||
config = tryCallback(() => require(configFile)); | ||
} | ||
else if (['.yaml', '.yml'].includes(extension)) { | ||
config = tryCallback(() => js_yaml_1.safeLoad(fs_1.readFileSync(configFile, 'utf8'))); | ||
} | ||
else { | ||
config = tryCallback(() => require(configFile)) | ||
|| tryCallback(() => js_yaml_1.safeLoad(fs_1.readFileSync(configFile + '.yml', 'utf8'))) | ||
|| tryCallback(() => js_yaml_1.safeLoad(fs_1.readFileSync(configFile + '.yaml', 'utf8'))); | ||
} | ||
if (!config) | ||
throw new Error('config file not found.'); | ||
if (Array.isArray(config)) { | ||
@@ -105,17 +122,24 @@ config.forEach(conf => prepareApp(conf)); | ||
for (const text of textSet) { | ||
utils_1.logger.info(text); | ||
utils_1.logger.info(text, baseLogLevel); | ||
} | ||
} | ||
const time = Math.max(0, perf_hooks_1.performance.now() - +process.env.KOISHI_START_TIME).toFixed(); | ||
utils_1.logger.success(`bot started successfully in ${time} ms`); | ||
utils_1.logger.success(`bot started successfully in ${time} ms`, baseLogLevel); | ||
process.send({ type: 'start' }); | ||
}); | ||
process.on('unhandledRejection', (error) => { | ||
utils_1.logger.warn(util_1.format(error), baseLogLevel); | ||
}); | ||
koishi_core_1.appList.forEach((app) => { | ||
app.receiver.on('error', (error) => { | ||
utils_1.logger.warning(error); | ||
}); | ||
const { logLevel = 0, logFilter = {} } = app.options; | ||
for (const type of koishi_core_1.logTypes) { | ||
app.receiver.on(`logger/${type}`, (scope, message) => { | ||
var _a; | ||
utils_1.logger[type](message, Math.min((_a = logFilter[scope], (_a !== null && _a !== void 0 ? _a : logLevel)), baseLogLevel)); | ||
}); | ||
} | ||
}); | ||
koishi_core_1.startAll().catch((error) => { | ||
utils_1.logger.error(error); | ||
utils_1.logger.error(error, baseLogLevel); | ||
process.exit(-1); | ||
}); |
{ | ||
"name": "koishi", | ||
"description": "A QQ bot framework based on CQHTTP", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"main": "dist/index.js", | ||
@@ -26,3 +26,3 @@ "typings": "dist/index.d.ts", | ||
}, | ||
"homepage": "https://github.com/koishijs/koishi#readme", | ||
"homepage": "https://koishi.js.org", | ||
"keywords": [ | ||
@@ -37,9 +37,12 @@ "bot", | ||
"devDependencies": { | ||
"@types/js-yaml": "^3.12.1", | ||
"@types/prompts": "^2.0.3" | ||
}, | ||
"dependencies": { | ||
"cac": "^6.5.3", | ||
"cac": "^6.5.4", | ||
"js-yaml": "^3.13.1", | ||
"kleur": "^3.0.3", | ||
"koishi-core": "^1.2.0", | ||
"koishi-plugin-common": "^1.0.3", | ||
"koishi-core": "^1.3.0", | ||
"koishi-plugin-common": "^1.0.4", | ||
"koishi-plugin-schedule": "^1.0.0", | ||
"koishi-utils": "^1.0.2", | ||
@@ -46,0 +49,0 @@ "prompts": "^2.3.0" |
@@ -1,3 +0,6 @@ | ||
<img width="160" src="https://koishijs.github.io/koishi.png" alt="logo"> | ||
<img width="160" src="https://koishi.js.org/koishi.png" alt="logo"> | ||
[](https://github.com/koishijs/koishi/actions?query=workflow:CI) | ||
[](https://www.npmjs.com/package/koishi) | ||
# Koishi | ||
@@ -15,3 +18,3 @@ | ||
参见:[快速上手](https://koishijs.github.io/guide/getting-started.html) / [配置文件](https://koishijs.github.io/guide/config-file.html) | ||
参见:[快速上手](https://koishi.js.org/guide/getting-started.html) / [配置文件](https://koishi.js.org/guide/config-file.html) | ||
@@ -22,13 +25,13 @@ ### 功能强大的 API | ||
- [Receiver](https://koishijs.github.io/guide/receive-and-send.html#接收器):将收到的信息转化为事件进行分发,且同时支持 HTTP 和 WebSocket | ||
- [Sender](https://koishijs.github.io/guide/receive-and-send.html#发送器):完美契合 CQHTTP API 的一套异步发送器,同样支持 HTTP 和 WebSocket | ||
- [Middleware](https://koishijs.github.io/guide/receive-and-send.html#中间件):支持异步操作的中间件系统,可以让你高效地处理每一条信息 | ||
- [Context](https://koishijs.github.io/guide/plugin-and-context.html#创建上下文):用上下文描述了机器人可能的运行环境,让你得以对不同的群进行不同的处理 | ||
- [Plugin](https://koishijs.github.io/guide/plugin-and-context.html#使用插件):将逻辑以插件的形式封装,可以实现更好的模块化和配置化 | ||
- [Command](https://koishijs.github.io/guide/command-system.html):Koishi 的核心功能之一,使用链式调用轻松创建指令,同时提供了大量的实用特性 | ||
- [Database](https://koishijs.github.io/guide/using-database.html):内置的数据库系统,但并不依赖具体的数据库实现,无论何种数据库都可以在 Koishi 中使用 | ||
- [Receiver](https://koishi.js.org/guide/receive-and-send.html#接收器):将收到的信息转化为事件进行分发,且同时支持 HTTP 和 WebSocket | ||
- [Sender](https://koishi.js.org/guide/receive-and-send.html#发送器):完美契合 CQHTTP API 的一套异步发送器,同样支持 HTTP 和 WebSocket | ||
- [Middleware](https://koishi.js.org/guide/receive-and-send.html#中间件):支持异步操作的中间件系统,可以让你高效地处理每一条信息 | ||
- [Context](https://koishi.js.org/guide/plugin-and-context.html#创建上下文):用上下文描述了机器人可能的运行环境,让你得以对不同的群进行不同的处理 | ||
- [Plugin](https://koishi.js.org/guide/plugin-and-context.html#使用插件):将逻辑以插件的形式封装,可以实现更好的模块化和配置化 | ||
- [Command](https://koishi.js.org/guide/command-system.html):Koishi 的核心功能之一,使用链式调用轻松创建指令,同时提供了大量的实用特性 | ||
- [Database](https://koishi.js.org/guide/using-database.html):内置的数据库系统,但并不依赖具体的数据库实现,无论何种数据库都可以在 Koishi 中使用 | ||
每一个部分都经过了精心的编写,可以让你轻松实现任何需求。 | ||
参见:[API 文档](https://koishijs.github.io/api/index.html) | ||
参见:[API 文档](https://koishi.js.org/api/index.html) | ||
@@ -39,3 +42,3 @@ ### 丰富的生态系统 | ||
参见:[官方插件](https://koishijs.github.io/plugins/common.html) | ||
参见:[官方插件](https://koishi.js.org/plugins/common.html) | ||
@@ -46,3 +49,3 @@ ### 多机器人支持 | ||
参见:[多机器人开发](https://koishijs.github.io/guide/multiple-bots.html) | ||
参见:[多机器人开发](https://koishi.js.org/guide/multiple-bots.html) | ||
@@ -63,5 +66,5 @@ ### 类型与单元测试 | ||
| 特性 | koishi<br>1.0.0 | cqhttp<br>1.1.1 | cq-websocket<br>2.0.2 | lemon-bot<br>0.5.1 | @ionjs/core<br>0.6.5 | | ||
| 特性 | [koishi<br>1.3.0](https://www.npmjs.com/package/koishi/v/1.3.0) | [cqhttp<br>1.2.0](https://www.npmjs.com/package/cqhttp/v/1.2.0) | [cq-websocket<br>2.0.2](https://www.npmjs.com/package/cq-websocket/v/2.0.2) | [lemon-bot<br>0.6.0](https://www.npmjs.com/package/lemon-bot/v/0.6.0) | [@ionjs/core<br>0.6.5](https://www.npmjs.com/package/@ionjs/core/v/0.6.5) | | ||
|:--:|:--:|:--:|:--:|:--:|:--:| | ||
| 依赖数量 | [17](http://npm.anvaka.com/#/view/2d/koishi/1.0.0-alpha.6) | [63](http://npm.anvaka.com/#/view/2d/cqhttp/1.1.1) | [37](http://npm.anvaka.com/#/view/2d/cq-websocket/2.0.2) | [55](http://npm.anvaka.com/#/view/2d/lemon-bot/0.5.1) | [73](http://npm.anvaka.com/#/view/2d/%2540ionjs%252Fcore/0.6.5) | | ||
| 依赖数量 | [22](http://npm.anvaka.com/#/view/2d/koishi/1.3.0) / [10](http://npm.anvaka.com/#/view/2d/koishi-core/1.3.0) | [62](http://npm.anvaka.com/#/view/2d/cqhttp/1.1.1) | [37](http://npm.anvaka.com/#/view/2d/cq-websocket/2.0.2) | [65](http://npm.anvaka.com/#/view/2d/lemon-bot/0.6.0) | [73](http://npm.anvaka.com/#/view/2d/%2540ionjs%252Fcore/0.6.5) | | ||
| HTTP | ✔️ | ✔️ | ❌ | ✔️ | ✔️ | | ||
@@ -75,4 +78,5 @@ | WebSocket | ✔️ | ❌ | ✔️ | ❌ | ❌ | | ||
| 指令 | ✔️ | ❌ | ❌ | ✔️ | ❌ | | ||
| 会话 | ❌ | ❌ | ❌ | ✔️ | ✔️ | | ||
注:依赖数量如果表示为 X/Y,则 X 表示命令行工具依赖数量, Y 表示核心库依赖数量。 | ||
## 安装 | ||
@@ -103,3 +107,3 @@ | ||
完整的文档在 [这里](https://koishijs.github.io/guide/getting-started.html)。 | ||
完整的文档在 [这里](https://koishi.js.org/guide/getting-started.html)。 | ||
@@ -122,3 +126,3 @@ ## 更新日志 | ||
与上面类似,但是针对的是 [这个项目](https://github.com/koishijs/koishijs.github.io)。 | ||
与上面类似,但是针对的是 [这个项目](https://github.com/koishijs/koishi.js.org)。 | ||
@@ -125,0 +129,0 @@ ### 开发 Koishi 插件 |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
21406
397
132
8
2
14
+ Addedjs-yaml@^3.13.1
+ Addedargparse@1.0.10(transitive)
+ Addedesprima@4.0.1(transitive)
+ Addedjs-yaml@3.14.1(transitive)
+ Addedkoishi-plugin-schedule@1.1.0(transitive)
+ Addedsprintf-js@1.0.3(transitive)
Updatedcac@^6.5.4
Updatedkoishi-core@^1.3.0
Updatedkoishi-plugin-common@^1.0.4