node-karin 0.6.28 → 0.7.1

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 CHANGED
@@ -1,3 +1,5 @@
1
+ ![karin](https://socialify.git.ci/karinjs/karin/image?description=1&font=Bitter&forks=1&issues=1&language=1&logo=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F162426977%3Fs%3D400%26u%3D8ae82fa0321857b24c7ed33a3d0d0d51323d3cfc%26v%3D4&name=1&owner=1&pattern=Plus&pulls=1&stargazers=1&theme=Light)
2
+
1
3
  [![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)
2
4
 
3
5
  [文档](https://karinjs.github.io/Karin/)
@@ -4,7 +4,7 @@ lines: 1000
4
4
  apps:
5
5
  - name: "Karin"
6
6
  # 入口
7
- script: "./lib/index.js"
7
+ script: "./node_modules/node-karin/lib/index.js"
8
8
  # 进程守护
9
9
  autorestart: true
10
10
  # 每分钟最大重启数量
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs'
3
+ import path from 'path'
4
+ import yaml from 'yaml'
5
+ import axios from 'axios'
6
+ import { fileURLToPath } from 'url'
7
+ import { program } from 'commander'
8
+ import { exec as execCmd, spawn } from 'child_process'
9
+ class KarinCli {
10
+ child
11
+ filename
12
+ karinDir
13
+ file
14
+ constructor () {
15
+ process.env.karin_app_start_count = '0'
16
+ /** 当前文件绝对路径 */
17
+ this.filename = fileURLToPath(import.meta.url)
18
+ /** karin目录 */
19
+ this.karinDir = path.join(path.dirname(this.filename), '../..')
20
+ /** 入口文件(注意后缀) */
21
+ this.file = path.join(path.dirname(this.filename), '../index')
22
+ this.child = null
23
+ }
24
+
25
+ /**
26
+ * 获取pkg
27
+ */
28
+ get pkg () {
29
+ const filePath = path.join(this.karinDir, 'package.json')
30
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'))
31
+ return data
32
+ }
33
+
34
+ /**
35
+ * 获取配置文件路径
36
+ * @param name - 配置文件名
37
+ */
38
+ getConfigPath (name) {
39
+ const filePath = `./config/config/${name}.yaml`
40
+ if (!fs.existsSync(filePath)) { return `${this.karinDir}/config/config/${name}.yaml` }
41
+ return filePath
42
+ }
43
+
44
+ /**
45
+ * 获取pm2配置
46
+ * @param name - 配置文件名
47
+ */
48
+ getConfigData (name) {
49
+ const _path = this.getConfigPath(name)
50
+ const data = yaml.parse(fs.readFileSync(_path, 'utf-8'))
51
+ return data
52
+ }
53
+
54
+ /**
55
+ * 启动
56
+ * @param mode - 模式
57
+ * @param lang - 语言环境
58
+ * @param runner - 运行器
59
+ */
60
+ start (mode, lang, runner) {
61
+ process.env.karin_app_mode = mode
62
+ process.env.karin_app_lang = lang
63
+ process.env.karin_app_runner = runner
64
+ let cmd
65
+ switch (runner) {
66
+ case 'node' /* Runner.Node */:
67
+ cmd = [this.file + '.js']
68
+ break
69
+ case 'tsx' /* Runner.Tsx */:
70
+ cmd = [this.file + '.ts']
71
+ break
72
+ case 'pm2' /* Runner.Pm2 */: {
73
+ this.pm2()
74
+ return
75
+ }
76
+ }
77
+ /** 启动 */
78
+ this.child = spawn(runner, cmd, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], cwd: process.cwd(), env: process.env })
79
+ /** 监听退出 */
80
+ this.child.once('exit', (code) => process.exit(code))
81
+ /** 监听子进程消息 */
82
+ this.child.on('message', (data) => {
83
+ /** pm2重启 */
84
+ if (data.env.pm_id) { return this.restart() }
85
+ try {
86
+ /** 先结束进程 */
87
+ this.child.kill('SIGINT')
88
+ /** 停止监听 */
89
+ this.child.removeAllListeners()
90
+ /** 重启次数+1 */
91
+ const count = Number(process.env.karin_app_start_count) || 0
92
+ process.env.karin_app_start_count = String(count + 1)
93
+ } catch { }
94
+ return this.start(mode, lang, runner)
95
+ })
96
+ }
97
+
98
+ /**
99
+ * pm2重启
100
+ */
101
+ async restart () {
102
+ const pm2Cfg = this.getConfigData('pm2')
103
+ const serverCfg = this.getConfigData('server')
104
+ /** 尝试获取pm2的进程id */
105
+ const port = serverCfg?.http?.port || 7000
106
+ const res = await this.Axios(`http://127.0.0.1:${port}/api/ping`, 1000)
107
+ if (res) {
108
+ await this.exec(`pm2 restart ${res.pm2_id}`)
109
+ } else {
110
+ await this.exec(`pm2 restart ${pm2Cfg?.apps[0]?.name || 'Karin'}`)
111
+ }
112
+ console.log('pm2服务已重启')
113
+ process.exit(0)
114
+ }
115
+
116
+ /**
117
+ * pm2启动
118
+ */
119
+ async pm2 () {
120
+ console.log('pm2启动中...')
121
+ const filePath = this.getConfigPath('pm2')
122
+ const data = this.getConfigData('pm2')
123
+ /** 修正入口文件路径 兼容0.6.28以前的版本 */
124
+ if (!fs.existsSync('./src') && filePath === './config/config/pm2.yaml') {
125
+ const script = './node_modules/node-karin/lib/index.js'
126
+ if (data.apps[0].script !== script) {
127
+ data.apps[0].script = script
128
+ fs.writeFileSync(filePath, yaml.stringify(data))
129
+ }
130
+ }
131
+ const cmd = `pm2 start ${filePath} --env ${JSON.stringify(process.env)}`
132
+ await this.exec(cmd)
133
+ console.log('pm2服务已启动 可执行 【npx karin log】 查看日志')
134
+ process.exit(0)
135
+ }
136
+
137
+ /**
138
+ * pm2结束进程
139
+ */
140
+ async stop () {
141
+ console.log('pm2服务停止中...')
142
+ const pm2Cfg = this.getConfigData('pm2')
143
+ const serverCfg = this.getConfigData('server')
144
+ const port = serverCfg?.http?.port || 7000
145
+ const res = await this.Axios(`http://127.0.0.1:${port}/api/ping`, 1000)
146
+ if (res) {
147
+ await this.exec(`pm2 delete ${res.pm2_id}`)
148
+ } else {
149
+ await this.exec(`pm2 delete ${pm2Cfg?.apps[0]?.name || 'Karin'}`)
150
+ }
151
+ console.log('pm2服务已停止')
152
+ process.exit(0)
153
+ }
154
+
155
+ /**
156
+ * pm2查看日志
157
+ */
158
+ async log () {
159
+ const pm2Cfg = this.getConfigData('pm2')
160
+ const serverCfg = this.getConfigData('server')
161
+ const port = serverCfg?.http?.port || 7000
162
+ const res = await this.Axios(`http://127.0.0.1:${port}/api/ping`, 1000)
163
+ const lines = pm2Cfg?.lines || 1000
164
+ const cmd = process.platform === 'win32' ? 'pm2.cmd' : 'pm2'
165
+ const type = res ? res.pm_id : pm2Cfg?.apps[0]?.name || 'Karin'
166
+ spawn(cmd, ['logs', type, '--lines', lines], { stdio: 'inherit', shell: true, cwd: process.cwd() })
167
+ }
168
+
169
+ /**
170
+ * 封装exec
171
+ * @param cmd - 命令
172
+ */
173
+ exec (cmd) {
174
+ return new Promise((resolve, reject) => {
175
+ execCmd(cmd, (error, stdout, stderr) => {
176
+ if (stdout) { return resolve(stdout) }
177
+ if (error) { return reject(error) }
178
+ return reject(stderr)
179
+ })
180
+ })
181
+ }
182
+
183
+ /**
184
+ * 封装axios 超时返回false
185
+ * @param url - 请求地址
186
+ * @param timeout - 超时时间
187
+ * @returns - 请求结果
188
+ */
189
+ async Axios (url, timeout) {
190
+ try {
191
+ const res = await axios.get(url, { timeout })
192
+ return res.data
193
+ } catch {
194
+ return false
195
+ }
196
+ }
197
+ }
198
+ const cli = new KarinCli()
199
+ program.version(cli.pkg.version, '-v, --version', '显示版本号')
200
+ program.command('.').description('启动karin').action(() => cli.start('prod' /* Mode.Prod */, 'js' /* Lang.Js */, 'node' /* Runner.Node */))
201
+ program.command('start').description('启动karin').action(() => cli.start('prod' /* Mode.Prod */, 'js' /* Lang.Js */, 'node' /* Runner.Node */))
202
+ program.command('pm2').description('后台运行karin').action(() => cli.start('prod' /* Mode.Prod */, 'js' /* Lang.Js */, 'pm2' /* Runner.Pm2 */))
203
+ program.command('stop').description('停止后台运行').action(() => cli.stop())
204
+ program.command('rs').description('重启pm2服务').action(() => cli.restart())
205
+ program.command('dev').description('TypeScript开发模式').action(() => cli.start('dev' /* Mode.Dev */, 'ts' /* Lang.Ts */, 'tsx' /* Runner.Tsx */))
206
+ program.command('debug').description('JavaScript调试模式').action(() => cli.start('dev' /* Mode.Dev */, 'js' /* Lang.Js */, 'node' /* Runner.Node */))
207
+ program.command('log').description('查看日志').action(() => cli.log())
208
+ program.parse(process.argv)
package/lib/cli/up.d.ts CHANGED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/lib/cli/up.js CHANGED
@@ -1 +1,35 @@
1
- 'use strict'
1
+ #!/usr/bin/env node
2
+ import { exec } from 'child_process'
3
+ import { KarinInit } from '../utils/init.js'
4
+ /** 获取包管理器 */
5
+ const pkg = new KarinInit().getRegistry()
6
+ let cmd = ''
7
+ /** 更新所有依赖到最新版本 */
8
+ switch (pkg) {
9
+ case 'pnpm': {
10
+ cmd = 'pnpm update --latest'
11
+ break
12
+ }
13
+ case 'yarn': {
14
+ cmd = 'yarn upgrade --latest'
15
+ break
16
+ }
17
+ case 'npm': {
18
+ cmd = 'npm update --latest'
19
+ break
20
+ }
21
+ case 'cnpm': {
22
+ cmd = 'cnpm update --latest'
23
+ break
24
+ }
25
+ }
26
+ exec(cmd, (error, stdout, stderr) => {
27
+ if (error) {
28
+ console.error('[更新依赖] 发送错误:')
29
+ console.error(`error.stack: ${error.stack}`)
30
+ console.error(`error.message: ${error.message}`)
31
+ return
32
+ }
33
+ console.log(`[更新依赖] 更新完成: ${stdout}`)
34
+ console.log(`[更新依赖] 更新错误: ${stderr}`)
35
+ })
package/lib/core/init.js CHANGED
@@ -12,19 +12,31 @@ process.title = 'Karin'
12
12
  * 设置时区
13
13
  */
14
14
  process.env.TZ = 'Asia/Shanghai'
15
- /**
16
- * 设置应用模式
17
- */
18
- process.env.karin_app_mode = process.argv[2]?.includes('dev') ? 'dev' : 'prod'
19
- /**
20
- * 设置语言环境
21
- */
22
- process.env.karin_app_lang = JSON.stringify(process.execArgv).includes('tsx@') ? 'ts' : 'js'
23
- if (process.env.karin_app_lang === 'ts') {
24
- process.env.karin_app_mode = 'dev'
25
- logger.mark(`当前为 ${logger.green('TypeScript')} 开发模式`)
26
- }
27
- if (process.env.npm_lifecycle_event === 'npx' && process.env.npm_lifecycle_script === 'debug') {
28
- process.env.karin_app_mode = 'dev'
29
- logger.mark(`当前为 ${logger.green('JavaScript')} 开发模式`)
15
+ const init = () => {
16
+ if (!process.env.karin_app_lang) { process.env.karin_app_lang = 'js' }
17
+ if (!process.env.karin_app_mode) { process.env.karin_app_mode = 'prod' }
18
+ if (!process.env.karin_app_runner) { process.env.karin_app_runner = 'node' }
19
+ if (!process.env.karin_app_start_count) { process.env.karin_app_start_count = '0' }
20
+ /** 正常启动 */
21
+ if (process.env.karin_app_runner === 'node' && process.env.karin_app_lang === 'js' && process.env.karin_app_mode === 'prod') {
22
+ logger.debug('当前为 JavaScript 生产模式')
23
+ return
24
+ }
25
+ /** pm2 */
26
+ if (process.env.karin_app_runner === 'pm2') {
27
+ logger.info('当前为 PM2 模式')
28
+ return
29
+ }
30
+ /** js开发模式 */
31
+ if (process.env.karin_app_lang === 'js' && process.env.karin_app_mode === 'dev') {
32
+ logger.info('当前为 JavaScript 开发模式')
33
+ return
34
+ }
35
+ /** ts开发模式 */
36
+ if (process.env.karin_app_lang === 'ts' && process.env.karin_app_mode === 'dev') {
37
+ logger.info('当前为 TypeScript 开发模式')
38
+ return
39
+ }
40
+ logger.error('未知的启动模式')
30
41
  }
42
+ init()
@@ -49,6 +49,8 @@ export interface OptionsElement extends OptionsCommand {
49
49
  stop?: boolean;
50
50
  }
51
51
  export declare class Karin {
52
+ start: boolean;
53
+ constructor();
52
54
  /**
53
55
  * @param reg - 正则表达式
54
56
  * @param fnc - 函数
@@ -140,5 +142,7 @@ export declare class Karin {
140
142
  */
141
143
  replyMsg?: string;
142
144
  }): Promise<KarinMessage>;
145
+ run(): void;
143
146
  }
144
- export {};
147
+ export declare const karin: Karin;
148
+ export default karin;
package/lib/core/karin.js CHANGED
@@ -1,9 +1,17 @@
1
+ import { server } from './server.js'
2
+ import { stateArr } from './plugin.js'
1
3
  import PluginApp from './plugin.app.js'
2
4
  import { common } from '../utils/index.js'
3
- import { render } from '../render/index.js'
4
- import { stateArr } from './plugin.js'
5
5
  import { listener } from './listener.js'
6
+ import onebot11 from '../adapter/onebot/11/index.js'
7
+ import { render, RenderServer } from '../render/index.js'
6
8
  export class Karin {
9
+ start
10
+ constructor () {
11
+ this.start = false
12
+ this.run()
13
+ }
14
+
7
15
  /**
8
16
  * - 快速构建命令
9
17
  * @param reg - 正则表达式
@@ -141,4 +149,15 @@ export class Karin {
141
149
  listener.once(`ctx:${key}`, (e) => resolve(e))
142
150
  })
143
151
  }
152
+
153
+ run () {
154
+ if (this.start) { return }
155
+ this.start = true
156
+ server.init()
157
+ listener.emit('load.plugin')
158
+ listener.emit('adapter', RenderServer)
159
+ listener.emit('adapter', onebot11)
160
+ }
144
161
  }
162
+ export const karin = new Karin()
163
+ export default karin
@@ -168,3 +168,7 @@ export declare const stateArr: stateArrType;
168
168
  export interface ExtendedPlugin extends Plugin {
169
169
  accept: (e: KarinNoticeType | KarinRequestType) => Promise<void>;
170
170
  }
171
+ /**
172
+ * @description 即将废弃,请使用 `Plugin`
173
+ */
174
+ export declare const plugin: typeof Plugin;
@@ -139,3 +139,7 @@ export class Plugin {
139
139
  * 上下文状态
140
140
  */
141
141
  export const stateArr = {}
142
+ /**
143
+ * @description 即将废弃,请使用 `Plugin`
144
+ */
145
+ export const plugin = Plugin
@@ -77,6 +77,16 @@ declare class PluginLoader {
77
77
  pkgJson: {
78
78
  [key: string]: any;
79
79
  };
80
+ /**
81
+ * - 依赖缺失收集
82
+ */
83
+ dependErr: {
84
+ [key: string]: {
85
+ dir: dirName;
86
+ name: fileName;
87
+ depend: string;
88
+ };
89
+ };
80
90
  constructor();
81
91
  /**
82
92
  * 插件初始化
@@ -106,6 +116,10 @@ declare class PluginLoader {
106
116
  * @param isMain - 是否为主入口文件
107
117
  */
108
118
  createdApp(dir: dirName, name: fileName, isOrderBy?: boolean, isNpm?: boolean, isMain?: boolean): Promise<boolean>;
119
+ /**
120
+ * 打印依赖缺失
121
+ */
122
+ printDependErr(): void;
109
123
  /**
110
124
  * 新增rule
111
125
  */
@@ -62,6 +62,10 @@ class PluginLoader {
62
62
  * - 所有插件包package.json
63
63
  */
64
64
  pkgJson
65
+ /**
66
+ * - 依赖缺失收集
67
+ */
68
+ dependErr
65
69
  constructor () {
66
70
  this.index = 0
67
71
  this.dir = './plugins'
@@ -78,6 +82,7 @@ class PluginLoader {
78
82
  this.buttonIds = []
79
83
  this.handlerIds = {}
80
84
  this.pkgJson = {}
85
+ this.dependErr = {}
81
86
  }
82
87
 
83
88
  /**
@@ -101,6 +106,8 @@ class PluginLoader {
101
106
  promises.push(...npm.map(async ({ dir, name, isMain }) => await this.createdApp(dir, name, false, true, isMain)))
102
107
  /** 等待所有插件加载完成 */
103
108
  await Promise.all(promises)
109
+ /** 打印依赖缺失 */
110
+ this.printDependErr()
104
111
  /** 释放缓存 */
105
112
  this.FileList = []
106
113
  /** 优先级排序并打印插件信息 */
@@ -310,14 +317,13 @@ class PluginLoader {
310
317
  return true
311
318
  } catch (error) {
312
319
  if (/Cannot find package '(.+?)'/.exec(error)?.[1]) {
313
- const pack = /Cannot find package '(.+?)'/.exec(error)?.[1] || ''
314
- logger.error(logger.red('--------插件载入错误--------'))
315
- logger.mark(`错误: [${dir}][${name}] 缺少必要的依赖项: ${logger.red(pack)}`)
316
- logger.mark(`操作:请尝试在命令终端中执行 ${logger.red('pnpm i -P')} 命令安装依赖项`)
317
- logger.mark('提示:如安装后仍未解决,可选择以下方案')
318
- logger.mark(` 1.手工安装依赖: ${logger.red('pnpm i ' + pack)}`)
319
- logger.mark(` 2.联系插件作者:联系插件作者将 ${logger.red(pack)} 依赖项添加至插件的packageon文件中的dependencies字段中`)
320
- logger.error(logger.red('-----------------------------'))
320
+ const key = `${dir}.${name}`
321
+ if (this.dependErr[key]) { return false }
322
+ this.dependErr[key] = {
323
+ dir,
324
+ name,
325
+ depend: /Cannot find package '(.+?)'/.exec(error)?.[1] || '',
326
+ }
321
327
  } else {
322
328
  logger.error(`载入插件错误:${logger.red(`${dir}/${name}`)}`)
323
329
  logger.error(error)
@@ -326,6 +332,28 @@ class PluginLoader {
326
332
  }
327
333
  }
328
334
 
335
+ /**
336
+ * 打印依赖缺失
337
+ */
338
+ printDependErr () {
339
+ try {
340
+ const keys = Object.keys(this.dependErr)
341
+ if (!keys.length) { return }
342
+ const msg = [
343
+ '-----依赖缺失----',
344
+ ]
345
+ keys.forEach(key => {
346
+ const { dir, name, depend } = this.dependErr[key]
347
+ msg.push(`[${dir}][${name}] 缺少依赖:${logger.red(depend)}`)
348
+ })
349
+ msg.push('-------------------')
350
+ logger.error(msg.join('\n'))
351
+ } finally {
352
+ /** 回收缓存 */
353
+ this.dependErr = {}
354
+ }
355
+ }
356
+
329
357
  /**
330
358
  * 新增rule
331
359
  */
@@ -55,13 +55,13 @@ export default class Process {
55
55
  /**
56
56
  * 使用api来检查后台
57
57
  */
58
- const res = await common.axios(host + '/pm2', 'get', { timeout: 100 })
58
+ const res = await common.axios(host + '/ping', 'get', { timeout: 100 })
59
59
  if (!res) { return this }
60
60
  logger.mark(logger.red('检测到后台进程 正在关闭'))
61
61
  /** 发退出信号 */
62
62
  await common.axios(host + '/exit', 'get', { timeout: 10 })
63
63
  for (let i = 0; i < 50; i++) {
64
- const res = await common.axios(host + '/pm2', 'get', { timeout: 100 })
64
+ const res = await common.axios(host + '/ping', 'get', { timeout: 100 })
65
65
  /** 请求成功继续循环 */
66
66
  if (res) { continue }
67
67
  /** 请求异常即代表后台进程已关闭 */
@@ -53,13 +53,20 @@ export const server = new (class Server {
53
53
  }
54
54
  })
55
55
  /** GET接口 - 获取当前启动信息 */
56
- this.app.get('/api/pm2', (req, res) => {
56
+ this.app.get('/api/ping', (req, res) => {
57
57
  /** 只允许本机ip访问 */
58
58
  if (req.hostname === 'localhost' || req.hostname === '127.0.0.1') {
59
59
  const data = {
60
60
  pm2_id: process.env.pm_id || '',
61
+ uptime: process.uptime(),
62
+ karin_app_mode: process.env.karin_app_mode,
63
+ karin_app_lang: process.env.karin_app_lang,
64
+ karin_app_runner: process.env.karin_app_runner,
65
+ karin_app_start_count: process.env.karin_app_start_count,
61
66
  }
62
67
  res.json(data)
68
+ } else {
69
+ res.status(403).json({ error: '禁止访问', message: '无效的请求' })
63
70
  }
64
71
  })
65
72
  /** GET接口 - 退出当前进程 */
@@ -10,25 +10,21 @@ export default class RedisLevel {
10
10
  get(key: string): Promise<string | null>;
11
11
  /**
12
12
  * set 设置数据
13
- * @param {string} key 键
14
- * @param {string} value 值
15
- * @param {object} [options] 选项
16
- * @param [options.EX] 过期时间 单位秒
17
- * @returns {Promise<void>|Error}
13
+ * @param key 键
14
+ * @param value 值
15
+ * @param options 选项
18
16
  */
19
17
  set(key: string, value: string, options?: {
20
18
  EX: number;
21
19
  } | undefined): Promise<void>;
22
20
  /**
23
21
  * del 删除数据
24
- * @param {string} key 键
25
- * @returns {Promise<void>|Error}
22
+ * @param key 键
26
23
  */
27
24
  del(key: string): Promise<void>;
28
25
  /**
29
26
  * keys 获取所有键
30
- * @param {string} [prefix] 前缀
31
- * @returns {Promise<string[]>|Error} 键列表
27
+ * @param prefix 前缀
32
28
  */
33
29
  keys(prefix?: string): Promise<string[]>;
34
30
  /**
@@ -89,11 +89,9 @@ export default class RedisLevel {
89
89
 
90
90
  /**
91
91
  * set 设置数据
92
- * @param {string} key 键
93
- * @param {string} value 值
94
- * @param {object} [options] 选项
95
- * @param [options.EX] 过期时间 单位秒
96
- * @returns {Promise<void>|Error}
92
+ * @param key 键
93
+ * @param value 值
94
+ * @param options 选项
97
95
  */
98
96
  async set (key, value, options) {
99
97
  if (options && options.EX) {
@@ -104,8 +102,7 @@ export default class RedisLevel {
104
102
 
105
103
  /**
106
104
  * del 删除数据
107
- * @param {string} key 键
108
- * @returns {Promise<void>|Error}
105
+ * @param key 键
109
106
  */
110
107
  async del (key) {
111
108
  this.#expireMap.delete(key)
@@ -114,22 +111,28 @@ export default class RedisLevel {
114
111
 
115
112
  /**
116
113
  * keys 获取所有键
117
- * @param {string} [prefix] 前缀
118
- * @returns {Promise<string[]>|Error} 键列表
114
+ * @param prefix 前缀
119
115
  */
120
116
  async keys (prefix = '') {
121
- const keys = []
122
- for await (const key of this.#level.keys({ gte: prefix, lt: prefix + '\xFF' })) {
123
- // Check if the key has expired
117
+ /** 去掉末尾的* */
118
+ prefix = prefix.replace(/\*$/, '')
119
+ const list = await this.#level.keys({ gte: prefix, lt: `${prefix}\xFF` }).all()
120
+ this.#checkKeys(list)
121
+ return list
122
+ }
123
+
124
+ /**
125
+ * 给一个kyes 检查是否过期
126
+ * @param keys 键数组
127
+ */
128
+ async #checkKeys (keys) {
129
+ for (const key of keys) {
124
130
  const expire = this.#expireMap.get(key)
125
131
  if (expire && expire < Date.now()) {
126
132
  await this.#level.del(key)
127
133
  this.#expireMap.delete(key)
128
- } else {
129
- keys.push(key)
130
134
  }
131
135
  }
132
- return keys
133
136
  }
134
137
 
135
138
  /**
package/lib/index.d.ts CHANGED
@@ -6,83 +6,4 @@ export * from './render/index.js';
6
6
  export * from './utils/index.js';
7
7
  export * from './types/index.js';
8
8
  export * from './adapter/index.js';
9
- import { Karin, Plugin } from './core/index.js';
10
- /**
11
- * @description 即将废弃,请使用 `Plugin`
12
- */
13
- export declare const plugin: typeof Plugin;
14
- /**
15
- * @description 即将废弃,请使用 `render`
16
- */
17
- export declare const Renderer: {
18
- index: number;
19
- Apps: Array<import("./types/index.js").KarinRenderApp>;
20
- app(data: {
21
- id: string;
22
- type?: "image" | string;
23
- render: import("./types/index.js").KarinRender["render"];
24
- }): number;
25
- unapp(index: number): boolean;
26
- App(id?: string): import("./types/index.js").KarinRenderApp;
27
- render(options: import("./types/index.js").KarinRenderType, id?: string): Promise<string | string[]>;
28
- renderHtml(data: string): Promise<string | string[]>;
29
- };
30
- export declare const Cfg: {
31
- projPath: string;
32
- projConfigPath: string;
33
- pkgPath: string;
34
- pkgConfigPath: string;
35
- change: Map<string, any>;
36
- watcher: Map<string, any>;
37
- review: boolean;
38
- logger: import("log4js").Logger;
39
- initCfg(): Promise<void>;
40
- getPlugins(): Promise<string[]>;
41
- mkdir(dirname: string): boolean;
42
- dirPath(_path: string, plugins: string[]): Promise<void>;
43
- timeout(type?: "ws" | "grpc"): number;
44
- readonly redis: import("./types/index.js").Redis;
45
- readonly master: string[];
46
- readonly admin: string[];
47
- readonly App: import("./types/index.js").App;
48
- readonly Config: import("./types/index.js").Config;
49
- readonly Server: import("./types/index.js").Server;
50
- readonly package: import("./types/index.js").Package;
51
- group(group_id?: string): import("./types/index.js").GroupCfg;
52
- getYaml(type: "defSet" | "config", name: string, isWatch?: boolean): any;
53
- watch(type: "defSet" | "config", name: string, file: string): Promise<true | undefined>;
54
- change_App(): Promise<void>;
55
- change_config(): Promise<void>;
56
- change_group(): Promise<void>;
57
- "__#2@#review"(): Promise<void>;
58
- };
59
- export declare const Update: {
60
- dir: string;
61
- update(path: string, cmd?: string, time?: number): Promise<{
62
- status: string;
63
- data: string;
64
- }>;
65
- getTime(path: string): Promise<string>;
66
- getHash(path: string, short?: boolean): Promise<string>;
67
- getCommit(options: {
68
- path: any;
69
- count?: any;
70
- hash?: any;
71
- branch?: any;
72
- }): Promise<string>;
73
- checkUpdate(path: import("fs").PathLike, time?: number): Promise<{
74
- status: string;
75
- data: string | undefined;
76
- count?: undefined;
77
- } | {
78
- status: string;
79
- data: boolean;
80
- count?: undefined;
81
- } | {
82
- status: string;
83
- data: string;
84
- count: string | number;
85
- }>;
86
- };
87
- export declare const karin: Karin;
88
- export default karin;
9
+ export { karin as default } from './core/index.js';
package/lib/index.js CHANGED
@@ -1,4 +1,3 @@
1
- // 基本模块
2
1
  export * from 'kritor-proto';
3
2
  export * from './core/index.js';
4
3
  export * from './event/index.js';
@@ -7,25 +6,4 @@ export * from './render/index.js';
7
6
  export * from './utils/index.js';
8
7
  export * from './types/index.js';
9
8
  export * from './adapter/index.js';
10
- import { config, update } from './utils/index.js';
11
- import { render } from './render/index.js';
12
- import { RenderServer } from './render/index.js';
13
- import OneBot11 from './adapter/onebot/11/index.js';
14
- import { server, Karin, listener, Plugin } from './core/index.js';
15
- // 初始化
16
- server.init();
17
- listener.emit('load.plugin');
18
- listener.emit('adapter', RenderServer);
19
- listener.emit('adapter', OneBot11);
20
- /**
21
- * @description 即将废弃,请使用 `Plugin`
22
- */
23
- export const plugin = Plugin;
24
- /**
25
- * @description 即将废弃,请使用 `render`
26
- */
27
- export const Renderer = render;
28
- export const Cfg = config;
29
- export const Update = update;
30
- export const karin = new Karin();
31
- export default karin;
9
+ export { karin as default } from './core/index.js';
@@ -1,5 +1,5 @@
1
1
  import { KarinRender, KarinRenderApp, KarinRenderType } from '../types/index.js';
2
- declare class Renderer {
2
+ declare class Renderers {
3
3
  index: number;
4
4
  Apps: Array<KarinRenderApp>;
5
5
  constructor();
@@ -42,5 +42,9 @@ declare class Renderer {
42
42
  /**
43
43
  * 渲染器管理器
44
44
  */
45
- export declare const render: Renderer;
45
+ export declare const render: Renderers;
46
+ /**
47
+ * @description 即将废弃,请使用 `render`
48
+ */
49
+ export declare const Renderer: Renderers;
46
50
  export {};
package/lib/render/app.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { logger } from '../utils/index.js'
2
- class Renderer {
2
+ class Renderers {
3
3
  index
4
4
  Apps
5
5
  constructor () {
@@ -91,4 +91,8 @@ class Renderer {
91
91
  /**
92
92
  * 渲染器管理器
93
93
  */
94
- export const render = new Renderer()
94
+ export const render = new Renderers()
95
+ /**
96
+ * @description 即将废弃,请使用 `render`
97
+ */
98
+ export const Renderer = render
@@ -88,3 +88,88 @@ export declare const config: {
88
88
  change_group(): Promise<void>;
89
89
  "__#2@#review"(): Promise<void>;
90
90
  };
91
+ export declare const Cfg: {
92
+ /**
93
+ * 根项目绝对路径
94
+ */
95
+ projPath: string;
96
+ /**
97
+ * 根项目配置文件夹路径
98
+ */
99
+ projConfigPath: string;
100
+ /**
101
+ * npm包路径
102
+ */
103
+ pkgPath: string;
104
+ /**
105
+ * karin包配置文件夹路径
106
+ */
107
+ pkgConfigPath: string;
108
+ change: Map<string, any>;
109
+ watcher: Map<string, any>;
110
+ review: boolean;
111
+ logger: Logger;
112
+ /** 初始化配置 */
113
+ initCfg(): Promise<void>;
114
+ getPlugins(): Promise<string[]>;
115
+ /**
116
+ * 递归创建目录
117
+ * @param dirname - 要创建的文件夹路径
118
+ */
119
+ mkdir(dirname: string): boolean;
120
+ /**
121
+ * 为每一个插件建立对应的文件夹
122
+ */
123
+ dirPath(_path: string, plugins: string[]): Promise<void>;
124
+ /**
125
+ * 超时时间
126
+ */
127
+ timeout(type?: "ws" | "grpc"): number;
128
+ /**
129
+ * Redis 配置
130
+ * 采用实时读取优化性能
131
+ */
132
+ readonly redis: Redis;
133
+ /**
134
+ * 主人列表
135
+ */
136
+ readonly master: string[];
137
+ /**
138
+ * 管理员列表
139
+ */
140
+ readonly admin: string[];
141
+ /** App管理 */
142
+ readonly App: App;
143
+ /**
144
+ * 基本配置
145
+ */
146
+ readonly Config: Config;
147
+ /**
148
+ * Server 配置文档
149
+ */
150
+ readonly Server: Server;
151
+ /**
152
+ * packageon
153
+ * 实时获取packageon文件
154
+ */
155
+ readonly package: Package;
156
+ /**
157
+ * 获取群配置
158
+ */
159
+ group(group_id?: string): GroupCfg;
160
+ /**
161
+ * 获取配置yaml
162
+ */
163
+ getYaml(type: "defSet" | "config", name: string, isWatch?: boolean): any;
164
+ /**
165
+ * 监听配置文件
166
+ * @param {'defSet'|'config'} type 类型
167
+ * @param {string} name 文件名称 不带后缀
168
+ * @param {string} file 文件路径
169
+ */
170
+ watch(type: "defSet" | "config", name: string, file: string): Promise<true | undefined>;
171
+ change_App(): Promise<void>;
172
+ change_config(): Promise<void>;
173
+ change_group(): Promise<void>;
174
+ "__#2@#review"(): Promise<void>;
175
+ };
@@ -309,3 +309,4 @@ export const config = new (class Cfg {
309
309
  this.review = false
310
310
  }
311
311
  })()
312
+ export const Cfg = config
@@ -61,3 +61,65 @@ export declare const update: {
61
61
  count: string | number;
62
62
  }>;
63
63
  };
64
+ export declare const Update: {
65
+ dir: string;
66
+ /**
67
+ * 更新框架或插件
68
+ * @param path - 插件相对路径
69
+ * @param cmd - 更新命令 默认git pull
70
+ * @param time - 超时时间 默认120s
71
+ */
72
+ update(path: string, cmd?: string, time?: number): Promise<{
73
+ status: string;
74
+ data: string;
75
+ }>;
76
+ /**
77
+ * 获取指定仓库最后一次提交时间日期
78
+ * @param path - 插件相对路径
79
+ */
80
+ getTime(path: string): Promise<string>;
81
+ /**
82
+ * 获取指定仓库最后一次提交哈希值
83
+ * @param {string} path - 插件相对路径
84
+ * @param {boolean} [short] - 是否获取短哈希 默认true
85
+ * @returns {Promise<string>}
86
+ */
87
+ getHash(path: string, short?: boolean): Promise<string>;
88
+ /**
89
+ * 获取指定仓库的提交记录
90
+ * @param {{
91
+ * path: string,
92
+ * count?: number,
93
+ * hash?: string
94
+ * }} options - 参数
95
+ * @param {string} options.path - 插件相对路径
96
+ * @param {number} [options.count] - 获取日志条数 默认1条
97
+ * @param {string} [options.hash] - 指定HEAD
98
+ * @returns {Promise<string>}
99
+ */
100
+ getCommit(options: {
101
+ path: any;
102
+ count?: any;
103
+ hash?: any;
104
+ branch?: any;
105
+ }): Promise<string>;
106
+ /**
107
+ * 检查插件是否有更新
108
+ * @param {string} path - 插件相对路径
109
+ * @param {number} [time] - 超时时间 默认120s
110
+ * @returns {Promise<{status: 'ok'|'failed', data: string|boolean}>}
111
+ */
112
+ checkUpdate(path: fs.PathLike, time?: number): Promise<{
113
+ status: string;
114
+ data: string | undefined;
115
+ count?: undefined;
116
+ } | {
117
+ status: string;
118
+ data: boolean;
119
+ count?: undefined;
120
+ } | {
121
+ status: string;
122
+ data: string;
123
+ count: string | number;
124
+ }>;
125
+ };
@@ -132,3 +132,4 @@ export const update = new (class Update {
132
132
  return { status: 'ok', data, count }
133
133
  }
134
134
  })()
135
+ export const Update = update
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-karin",
3
- "version": "0.6.28",
3
+ "version": "0.7.1",
4
4
  "private": false,
5
5
  "description": "基于 Kritor 进行开发的nodejs机器人框架",
6
6
  "homepage": "https://github.com/KarinJS/Karin",
@@ -17,14 +17,8 @@
17
17
  "main": "./lib/index.js",
18
18
  "types": "./lib/index.d.ts",
19
19
  "bin": {
20
- "app": "lib/index.js",
21
- "debug": "lib/index.js",
22
- "dev": "lib/index.js",
23
20
  "init": "lib/cli/init.js",
24
- "log": "lib/cli/log.js",
25
- "rs": "lib/cli/restart.js",
26
- "start": "lib/cli/start.js",
27
- "stop": "lib/cli/stop.js"
21
+ "karin": "lib/cli/karin.js"
28
22
  },
29
23
  "files": [
30
24
  "/lib/**/*.js",
@@ -49,35 +43,36 @@
49
43
  "sort": "npx sort-package-json"
50
44
  },
51
45
  "dependencies": {
52
- "@grpc/grpc-js": "1.10.11",
46
+ "@grpc/grpc-js": "1.11.1",
53
47
  "@grpc/proto-loader": "0.7.13",
54
48
  "art-template": "4.13.2",
55
49
  "axios": "1.7.2",
56
50
  "chalk": "5.3.0",
57
51
  "chokidar": "3.6.0",
52
+ "commander": "^12.1.0",
58
53
  "express": "4.19.2",
59
- "kritor-proto": "latest",
54
+ "kritor-proto": "^1.0.2",
60
55
  "level": "8.0.1",
61
56
  "lodash": "4.17.21",
62
57
  "log4js": "6.9.1",
63
58
  "moment": "2.30.1",
64
59
  "node-schedule": "2.1.1",
65
- "redis": "4.6.14",
60
+ "redis": "4.6.15",
66
61
  "ws": "8.18.0",
67
62
  "yaml": "2.4.5"
68
63
  },
69
64
  "devDependencies": {
70
- "@types/express": "latest",
71
- "@types/lodash": "latest",
72
- "@types/node": "latest",
73
- "@types/node-schedule": "latest",
74
- "@types/ws": "latest",
75
- "eslint": "latest",
76
- "neostandard": "latest",
77
- "sort-package-json": "latest",
78
- "tsc-alias": "latest",
79
- "tsx": "latest",
80
- "typescript": "latest"
65
+ "@types/express": "^4.17.21",
66
+ "@types/lodash": "^4.17.7",
67
+ "@types/node": "^20.14.11",
68
+ "@types/node-schedule": "^2.1.7",
69
+ "@types/ws": "^8.5.11",
70
+ "eslint": "^9.7.0",
71
+ "neostandard": "^0.11.1",
72
+ "sort-package-json": "^2.10.0",
73
+ "tsc-alias": "^1.8.10",
74
+ "tsx": "^4.16.2",
75
+ "typescript": "^5.5.3"
81
76
  },
82
77
  "engines": {
83
78
  "node": ">=18"
package/lib/cli/log.js DELETED
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs'
3
- import yaml from 'yaml'
4
- import path from 'path'
5
- import { spawn } from 'child_process'
6
- const cwd = process.cwd()
7
- const _path = path.resolve(cwd + '/config/config/pm2.yaml')
8
- const data = yaml.parse(fs.readFileSync(_path, 'utf8'))
9
- const name = data.apps[0].name
10
- const lines = data.lines || 1000
11
- const cmd = process.platform === 'win32' ? 'pm2.cmd' : 'pm2'
12
- spawn(cmd, ['logs', '--lines', lines, name], { stdio: 'inherit', shell: true, cwd })
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs'
3
- import { execSync } from 'child_process'
4
- import { karinDir } from '../core/dir.js'
5
- let config = process.cwd() + '/config/config/pm2.yaml'
6
- if (!fs.existsSync(config)) {
7
- config = `${karinDir}/config/config/pm2.yaml`
8
- }
9
- const cmd = `pm2 restart ${config}`
10
- execSync(cmd, { stdio: 'inherit', cwd: process.cwd(), env: process.env })
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/lib/cli/start.js DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs'
3
- import { execSync } from 'child_process'
4
- import { karinDir } from '../core/dir.js'
5
- let config = process.cwd() + '/config/config/pm2.yaml'
6
- if (!fs.existsSync(config)) {
7
- config = `${karinDir}/config/config/pm2.yaml`
8
- }
9
- const cmd = `pm2 start ${config}`
10
- execSync(cmd, { stdio: 'inherit', cwd: process.cwd(), env: process.env })
package/lib/cli/stop.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/lib/cli/stop.js DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs'
3
- import { execSync } from 'child_process'
4
- import { karinDir } from '../core/dir.js'
5
- let config = process.cwd() + '/config/config/pm2.yaml'
6
- if (!fs.existsSync(config)) {
7
- config = `${karinDir}/config/config/pm2.yaml`
8
- }
9
- const cmd = `pm2 delete ${config}`
10
- execSync(cmd, { stdio: 'inherit', cwd: process.cwd(), env: process.env })
File without changes