node-karin 0.6.13 → 0.6.14

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.
@@ -12,7 +12,8 @@ export declare class AdapterInput implements KarinAdapter {
12
12
  version: KarinAdapter['version'];
13
13
  constructor();
14
14
  get self_id(): string;
15
- stdin(): void;
15
+ stdin(): this;
16
+ init(): void;
16
17
  logger(level: 'info' | 'error' | 'trace' | 'debug' | 'mark' | 'warn' | 'fatal', ...args: any[]): void;
17
18
  GetVersion(): Promise<{
18
19
  name: string;
@@ -9,13 +9,11 @@ const { enable, msgToFile, token: oldToken, ip } = config.Config.AdapterInput;
9
9
  */
10
10
  export class AdapterInput {
11
11
  token;
12
- #stdin;
13
12
  socket;
14
13
  account;
15
14
  adapter;
16
15
  version;
17
16
  constructor() {
18
- this.#stdin = false;
19
17
  this.token = oldToken;
20
18
  this.account = { uid: 'input', uin: 'input', name: 'input' };
21
19
  this.adapter = { id: 'shell', name: 'input', type: 'internal', sub_type: 'internal', start_time: Date.now(), connect: '', index: 0 };
@@ -25,9 +23,6 @@ export class AdapterInput {
25
23
  return this.account.uid;
26
24
  }
27
25
  stdin() {
28
- if (this.#stdin)
29
- return;
30
- this.#stdin = true;
31
26
  if (oldToken === 'AdapterInput') {
32
27
  try {
33
28
  this.token = randomUUID();
@@ -57,8 +52,14 @@ export class AdapterInput {
57
52
  const index = listener.addBot({ bot: this, type: this.adapter.type });
58
53
  if (index)
59
54
  this.adapter.index = index;
55
+ return this;
56
+ }
57
+ init() {
60
58
  process.stdin.on('data', data => this.#input(data.toString()));
61
- process.once('stdin.close', () => process.stdin.removeAllListeners('data'));
59
+ process.once('stdin.close', () => {
60
+ process.stdin.removeAllListeners('data');
61
+ process.stdin.once('stdin.open', () => this.init());
62
+ });
62
63
  }
63
64
  logger(level, ...args) {
64
65
  logger.bot(level, this.account.uid || this.account.uin, ...args);
@@ -89,9 +90,6 @@ export class AdapterInput {
89
90
  };
90
91
  const e = new KarinMessage(message);
91
92
  e.bot = this;
92
- /**
93
- * 快速回复 开发者不应该使用这个方法,应该使用由karin封装过后的reply方法
94
- */
95
93
  e.replyCallback = async (elements) => {
96
94
  this.SendMessage(e.contact, elements);
97
95
  return { message_id: e.message_id };
@@ -111,7 +109,6 @@ export class AdapterInput {
111
109
  const buffer = await common.buffer(file);
112
110
  // 生成文件名 根据type生成不同的文件后缀
113
111
  const name = `${Date.now()}.${type === 'image' ? 'jpg' : type === 'voice' ? 'mp3' : 'file'}`;
114
- // 写入文件
115
112
  fs.writeFileSync(`./temp/input/${name}`, buffer);
116
113
  return `[${type === 'image' ? '图片' : '语音'}: http://${ip}:${config.Server.http.port}/api/input?name=${name}&token=${this.token} ]`;
117
114
  }
@@ -187,4 +184,4 @@ export class AdapterInput {
187
184
  async GetGroupHonor() { throw new Error('Method not implemented.'); }
188
185
  }
189
186
  if (enable)
190
- new AdapterInput().stdin();
187
+ new AdapterInput().stdin().init();
@@ -270,13 +270,26 @@ export declare class AdapterOneBot11 implements KarinAdapter {
270
270
  GetVersion(): Promise<any>;
271
271
  DownloadForwardMessage(): Promise<void>;
272
272
  GetEssenceMessageList(): Promise<void>;
273
+ /**
274
+ * 上传群文件
275
+ * @param group_id - 群号
276
+ * @param file - 本地文件绝对路径
277
+ * @param name - 文件名称 必须提供
278
+ * @param folder - 父目录ID 不提供则上传到根目录
279
+ */
280
+ UploadPrivateFile(group_id: string, file: string, name: string, folder?: string): Promise<any>;
281
+ /**
282
+ * 上传私聊文件
283
+ * @param user_id - 用户ID
284
+ * @param file - 本地文件绝对路径
285
+ * @param name - 文件名称 必须提供
286
+ */
287
+ UploadGroupFile(user_id: string, file: string, name: string): Promise<any>;
273
288
  SetEssenceMessage(): Promise<void>;
274
289
  DeleteEssenceMessage(): Promise<void>;
275
290
  SetFriendApplyResult(): Promise<void>;
276
291
  SetGroupApplyResult(): Promise<void>;
277
292
  SetInvitedJoinGroupResult(): Promise<void>;
278
- UploadPrivateFile(): Promise<void>;
279
- UploadGroupFile(): Promise<void>;
280
293
  sendForwardMessage(contact: contact, elements: KarinNodeElement[]): Promise<{
281
294
  message_id: any;
282
295
  }>;
@@ -1216,13 +1216,30 @@ export class AdapterOneBot11 {
1216
1216
  async GetEssenceMessageList() {
1217
1217
  throw new Error('Method not implemented.');
1218
1218
  }
1219
+ /**
1220
+ * 上传群文件
1221
+ * @param group_id - 群号
1222
+ * @param file - 本地文件绝对路径
1223
+ * @param name - 文件名称 必须提供
1224
+ * @param folder - 父目录ID 不提供则上传到根目录
1225
+ */
1226
+ async UploadPrivateFile(group_id, file, name, folder) {
1227
+ return await this.SendApi('upload_group_file', { group_id, file, name, folder });
1228
+ }
1229
+ /**
1230
+ * 上传私聊文件
1231
+ * @param user_id - 用户ID
1232
+ * @param file - 本地文件绝对路径
1233
+ * @param name - 文件名称 必须提供
1234
+ */
1235
+ async UploadGroupFile(user_id, file, name) {
1236
+ return await this.SendApi('upload_private_file', { user_id, file, name });
1237
+ }
1219
1238
  async SetEssenceMessage() { }
1220
1239
  async DeleteEssenceMessage() { }
1221
1240
  async SetFriendApplyResult() { }
1222
1241
  async SetGroupApplyResult() { }
1223
1242
  async SetInvitedJoinGroupResult() { }
1224
- async UploadPrivateFile() { }
1225
- async UploadGroupFile() { }
1226
1243
  async sendForwardMessage(contact, elements) {
1227
1244
  let message_id = await this.UploadForwardMessage(contact, elements);
1228
1245
  if (this.version.name === 'Lagrange.OneBot') {
@@ -51,10 +51,10 @@ export interface OptionsElement extends OptionsCommand {
51
51
  }
52
52
  export declare class Karin {
53
53
  /**
54
- * @param reg - 正则表达式
55
- * @param fnc - 函数
56
- * @param options - 选项
57
- */
54
+ * @param reg - 正则表达式
55
+ * @param fnc - 函数
56
+ * @param options - 选项
57
+ */
58
58
  command(reg: string | RegExp, fnc: FncFunction, options?: OptionsCommand): PluginApps;
59
59
  /**
60
60
  * @param reg - 正则表达式
package/lib/core/karin.js CHANGED
@@ -11,7 +11,6 @@ export class Karin {
11
11
  * @param options - 选项
12
12
  * @returns - 返回插件对象
13
13
  */
14
-
15
14
  command (reg, second, options = {}) {
16
15
  reg = typeof reg === 'string' ? new RegExp(reg) : reg
17
16
  const fnc = typeof second === 'function'
@@ -19,7 +19,7 @@ export declare const server: {
19
19
  /**
20
20
  * 构建静态资源路径
21
21
  */
22
- staticPath(): void;
22
+ staticPath(): Promise<void>;
23
23
  /** 重启当前HTTP服务器 */
24
24
  "__#17@#restartServer"(): Promise<void>;
25
25
  };
@@ -201,7 +201,7 @@ export const server = new (class Server {
201
201
  /**
202
202
  * 构建静态资源路径
203
203
  */
204
- staticPath () {
204
+ async staticPath () {
205
205
  this.list = []
206
206
  /** 读取./resources文件夹 */
207
207
  const resDir = './resources'
@@ -217,17 +217,32 @@ export const server = new (class Server {
217
217
  const file = `${htmlDir}/${dir}`
218
218
  if (common.isDir(file)) { this.list.push(file.replace('.', '')) }
219
219
  }
220
- /** 读取./plugins/html下所有文件夹 */
220
+ /** 读取./plugins/xxx/resources下所有文件夹 */
221
221
  const pluginsDir = './plugins'
222
222
  const plugins = fs.readdirSync(pluginsDir)
223
223
  for (const dir of plugins) {
224
+ /** 忽略不是karin-plugin-开头 */
225
+ if (!dir.startsWith('karin-plugin-')) { continue }
224
226
  const file = `${pluginsDir}/${dir}`
225
227
  const resFile = `${file}/resources`
226
228
  /** 包含resources文件夹 */
227
229
  if (common.isDir(file) && common.isDir(resFile)) { this.list.push(resFile.replace('.', '')) }
228
- const componentsFile = `${file}/components`
229
- /** 包含components文件夹 兼容mys */
230
+ const componentsFile = `${file}/lib/components`
231
+ /** 包含lib/components文件夹 兼容mys */
230
232
  if (common.isDir(file) && common.isDir(componentsFile)) { this.list.push(componentsFile.replace('.', '')) }
233
+ /** 读取package.json 查找是否存在自定义资源文件入口 */
234
+ const pkgFile = `${file}/package.json`
235
+ if (!common.exists(pkgFile)) { continue }
236
+ const pkg = common.readJson(pkgFile)
237
+ if (!pkg?.karin?.static || !Array.isArray(pkg.karin.static)) { continue }
238
+ /** 标准格式为 lib/test/xxxx */
239
+ for (let staticFile of pkg.karin.static) {
240
+ /** 不允许向上级目录 ../开头等 */
241
+ if (staticFile.startsWith('../')) { continue }
242
+ /** ./开头去掉./ */
243
+ if (staticFile.startsWith('./')) { staticFile = staticFile.slice(2) }
244
+ this.list.push(`${file}/${staticFile}`)
245
+ }
231
246
  }
232
247
  this.reg = new RegExp(`(${this.list.join('|')})`, 'g')
233
248
  }
@@ -88,10 +88,7 @@ export class MessageHandler extends EventHandler {
88
88
  for (const val of this.e.elements) {
89
89
  switch (val.type) {
90
90
  case 'text': {
91
- const msg = (val.text || '')
92
- .replace(/^\s*[#井#]+\s*/, '#')
93
- .replace(/^\s*[\\*※*]+\s*/, '*')
94
- .trim()
91
+ const msg = (val.text || '').replace(/^\s*[#井#]+\s*/, '#').replace(/^\s*[\\*※*]+\s*/, '*').trim()
95
92
  this.e.msg += msg
96
93
  /** 美观一点... */
97
94
  logs.push(msg)
@@ -114,11 +111,9 @@ export class MessageHandler extends EventHandler {
114
111
  break
115
112
  case 'at':
116
113
  /** atBot不计入e.at */
117
- // eslint-disable-next-line eqeqeq
118
- if (val.uid && val.uid == this.e.bot.account.uid) {
114
+ if (val.uid && val.uid === this.e.bot.account.uid) {
119
115
  this.e.atBot = true
120
- // eslint-disable-next-line eqeqeq
121
- } else if (val.uin == this.e.bot.account.uin) {
116
+ } else if (val.uin === this.e.bot.account.uin) {
122
117
  this.e.atBot = true
123
118
  } else if (val.uid && val.uid === 'all') {
124
119
  this.e.atAll = true
@@ -185,6 +180,9 @@ export class MessageHandler extends EventHandler {
185
180
  case 'button':
186
181
  logs.push(`[button:${JSON.stringify(val.data)}]`)
187
182
  break
183
+ case 'long_msg':
184
+ logs.push(`[long_msg:${val.id}]`)
185
+ break
188
186
  default:
189
187
  logs.push(`[未知:${JSON.stringify(val)}]`)
190
188
  }
package/lib/index.d.ts CHANGED
@@ -28,9 +28,10 @@ export declare const Renderer: {
28
28
  renderHtml(data: string): Promise<string | string[]>;
29
29
  };
30
30
  export declare const Cfg: {
31
- dir: string;
32
- _path: string;
33
- npmCfgDir: string;
31
+ projPath: string;
32
+ projConfigPath: string;
33
+ pkgPath: string;
34
+ pkgConfigPath: string;
34
35
  change: Map<string, any>;
35
36
  watcher: Map<string, any>;
36
37
  review: boolean;
@@ -38,7 +39,7 @@ export declare const Cfg: {
38
39
  initCfg(): Promise<void>;
39
40
  getPlugins(): string[];
40
41
  mkdir(dirname: string): boolean;
41
- dirPath(name: string, plugins: string[]): Promise<void>;
42
+ dirPath(_path: string, plugins: string[]): Promise<void>;
42
43
  timeout(type?: "ws" | "grpc"): number;
43
44
  readonly redis: import("./types/index.js").Redis;
44
45
  readonly master: string[];
@@ -28,6 +28,10 @@ export interface AtElement extends Element {
28
28
  * - At的uin
29
29
  */
30
30
  uin?: string;
31
+ /**
32
+ * - At的名称
33
+ */
34
+ name?: string;
31
35
  }
32
36
  /**
33
37
  * - 表情元素
@@ -848,7 +848,7 @@ export type ByPostType<T extends EventPostType> = Extract<OneBot11Event, {
848
848
  /**
849
849
  * - OneBot11公开Api
850
850
  */
851
- export type OneBot11Api = 'send_private_msg' | 'send_group_msg' | 'send_msg' | 'delete_msg' | 'get_msg' | 'get_forward_msg' | 'send_like' | 'set_group_kick' | 'set_group_ban' | 'set_group_anonymous_ban' | 'set_group_whole_ban' | 'set_group_admin' | 'set_group_anonymous' | 'set_group_card' | 'set_group_name' | 'set_group_leave' | 'set_group_special_title' | 'set_friend_add_request' | 'set_group_add_request' | 'get_login_info' | 'get_stranger_info' | 'get_friend_list' | 'get_group_info' | 'get_group_list' | 'get_group_member_info' | 'get_group_member_list' | 'get_group_honor_info' | 'get_cookies' | 'get_csrf_token' | 'get_credentials' | 'get_record' | 'get_image' | 'can_send_image' | 'can_send_record' | 'get_status' | 'get_version_info' | 'set_restart' | 'clean_cache' | 'get_version' | 'send_forward_msg' | 'get_friend_msg_history' | 'get_group_msg_history' | 'set_msg_emoji_like';
851
+ export type OneBot11Api = 'send_private_msg' | 'send_group_msg' | 'send_msg' | 'delete_msg' | 'get_msg' | 'get_forward_msg' | 'send_like' | 'set_group_kick' | 'set_group_ban' | 'set_group_anonymous_ban' | 'set_group_whole_ban' | 'set_group_admin' | 'set_group_anonymous' | 'set_group_card' | 'set_group_name' | 'set_group_leave' | 'set_group_special_title' | 'set_friend_add_request' | 'set_group_add_request' | 'get_login_info' | 'get_stranger_info' | 'get_friend_list' | 'get_group_info' | 'get_group_list' | 'get_group_member_info' | 'get_group_member_list' | 'get_group_honor_info' | 'get_cookies' | 'get_csrf_token' | 'get_credentials' | 'get_record' | 'get_image' | 'can_send_image' | 'can_send_record' | 'get_status' | 'get_version_info' | 'set_restart' | 'clean_cache' | 'get_version' | 'send_forward_msg' | 'get_friend_msg_history' | 'get_group_msg_history' | 'set_msg_emoji_like' | 'upload_group_file' | 'upload_private_file';
852
852
  /**
853
853
  * - OneBot11公开Api参数 params
854
854
  */
@@ -1379,6 +1379,44 @@ export type OneBot11ApiParams = {
1379
1379
  */
1380
1380
  is_set: boolean;
1381
1381
  };
1382
+ /**
1383
+ * 上传群文件
1384
+ */
1385
+ upload_group_file: {
1386
+ /**
1387
+ * - 群号
1388
+ */
1389
+ group_id: number;
1390
+ /**
1391
+ * - 文件路径 需要提供绝对路径
1392
+ */
1393
+ file: string;
1394
+ /**
1395
+ * - 文件名称 必须提供
1396
+ */
1397
+ name: string;
1398
+ /**
1399
+ * - 父目录ID 不提供则上传到根目录
1400
+ */
1401
+ folder?: string;
1402
+ };
1403
+ /**
1404
+ * 上传私聊文件
1405
+ */
1406
+ upload_private_file: {
1407
+ /**
1408
+ * - 对方 QQ 号
1409
+ */
1410
+ user_id: number;
1411
+ /**
1412
+ * - 文件路径 需要提供绝对路径
1413
+ */
1414
+ file: string;
1415
+ /**
1416
+ * - 文件名称 必须提供
1417
+ */
1418
+ name: string;
1419
+ };
1382
1420
  };
1383
1421
  /**
1384
1422
  * - OneBot11公开Api与参数映射
@@ -4,9 +4,22 @@ import { Redis, App, Config, Server, Package, GroupCfg } from '../types/index.js
4
4
  * 配置文件
5
5
  */
6
6
  export declare const config: {
7
- dir: string;
8
- _path: string;
9
- npmCfgDir: string;
7
+ /**
8
+ * 根项目绝对路径
9
+ */
10
+ projPath: string;
11
+ /**
12
+ * 根项目配置文件夹路径
13
+ */
14
+ projConfigPath: string;
15
+ /**
16
+ * npm包路径
17
+ */
18
+ pkgPath: string;
19
+ /**
20
+ * karin包配置文件夹路径
21
+ */
22
+ pkgConfigPath: string;
10
23
  change: Map<string, any>;
11
24
  watcher: Map<string, any>;
12
25
  review: boolean;
@@ -22,7 +35,7 @@ export declare const config: {
22
35
  /**
23
36
  * 为每一个插件建立对应的文件夹
24
37
  */
25
- dirPath(name: string, plugins: string[]): Promise<void>;
38
+ dirPath(_path: string, plugins: string[]): Promise<void>;
26
39
  /**
27
40
  * 超时时间
28
41
  */
@@ -5,17 +5,31 @@ import { fs, yaml as Yaml, chokidar } from '../modules.js'
5
5
  * 配置文件
6
6
  */
7
7
  export const config = new (class Cfg {
8
- dir
9
- _path
10
- npmCfgDir
8
+ /**
9
+ * 根项目绝对路径
10
+ */
11
+ projPath
12
+ /**
13
+ * 根项目配置文件夹路径
14
+ */
15
+ projConfigPath
16
+ /**
17
+ * npm包路径
18
+ */
19
+ pkgPath
20
+ /**
21
+ * karin包配置文件夹路径
22
+ */
23
+ pkgConfigPath
11
24
  change
12
25
  watcher
13
26
  review
14
27
  logger
15
28
  constructor () {
16
- this.dir = karinDir
17
- this._path = process.cwd() + '/config'
18
- this.npmCfgDir = this.dir + '/config/defSet'
29
+ this.projPath = process.cwd()
30
+ this.pkgPath = karinDir
31
+ this.projConfigPath = this.projPath + '/config'
32
+ this.pkgConfigPath = this.pkgPath + '/config/defSet'
19
33
  /** 缓存 */
20
34
  this.change = new Map()
21
35
  /** 监听文件 */
@@ -28,33 +42,36 @@ export const config = new (class Cfg {
28
42
  /** 初始化配置 */
29
43
  async initCfg () {
30
44
  const list = [
31
- this._path,
32
- this._path + '/config',
33
- process.cwd() + '/temp/input',
34
- './plugins',
35
- './plugins/karin-plugin-example',
45
+ this.projPath + '/temp/input',
46
+ this.projPath + '/plugins/karin-plugin-example',
47
+ this.projConfigPath + '/config',
48
+ this.projConfigPath + '/plugin',
36
49
  ]
37
50
  list.forEach(path => this.mkdir(path))
38
- if (this.npmCfgDir !== (this._path + '/defSet').replace(/\\/g, '/')) {
39
- const files = fs.readdirSync(this.npmCfgDir).filter(file => file.endsWith('.yaml'))
51
+ if (this.pkgConfigPath !== (this.projConfigPath + '/defSet').replace(/\\/g, '/')) {
52
+ const files = fs.readdirSync(this.pkgConfigPath).filter(file => file.endsWith('.yaml'))
40
53
  files.forEach(file => {
41
- const path = `${this._path}/config/${file}`
42
- const pathDef = `${this.npmCfgDir}/${file}`
54
+ const path = `${this.projConfigPath}/config/${file}`
55
+ const pathDef = `${this.pkgConfigPath}/${file}`
43
56
  if (!fs.existsSync(path)) { fs.copyFileSync(pathDef, path) }
44
57
  })
45
58
  }
46
- // 创建插件文件夹文件夹
59
+ /** 为每个插件包创建统一存储的文件夹 */
47
60
  const plugins = this.getPlugins()
48
- this.dirPath('data', plugins)
49
- this.dirPath('temp', plugins)
50
- this.dirPath('resources', plugins)
51
- this.dirPath('temp/html', plugins)
61
+ const DataList = [
62
+ 'data',
63
+ 'temp',
64
+ 'resources',
65
+ 'temp/html',
66
+ this.projConfigPath + '/plugin',
67
+ ]
68
+ DataList.forEach(path => this.dirPath(path, plugins))
52
69
  this.logger = (await import('./logger.js')).default
53
70
  }
54
71
 
55
72
  getPlugins () {
56
73
  const files = fs.readdirSync('./plugins', { withFileTypes: true })
57
- // 过滤掉非karin-plugin-开头或karin-adapter-开头的文件夹
74
+ // 过滤掉非karin-plugin-开头的文件夹
58
75
  return files.filter(file => file.isDirectory() && (file.name.startsWith('karin-plugin-'))).map(dir => dir.name)
59
76
  }
60
77
 
@@ -72,11 +89,10 @@ export const config = new (class Cfg {
72
89
  /**
73
90
  * 为每一个插件建立对应的文件夹
74
91
  */
75
- async dirPath (name, plugins) {
76
- name = `./${name}`
77
- this.mkdir(name)
92
+ async dirPath (_path, plugins) {
93
+ this.mkdir(_path)
78
94
  for (const plugin of plugins) {
79
- const path = `${name}/${plugin}`
95
+ const path = `${_path}/${plugin}`
80
96
  this.mkdir(path)
81
97
  }
82
98
  }
@@ -11,9 +11,10 @@ export declare const segment: {
11
11
  * 提供一个uid即可
12
12
  * @param uid - uid
13
13
  * @param uin - uin
14
+ * @param name - 名称
14
15
  * @returns {AtElement} 提及元素
15
16
  */
16
- at(uid: string, uin?: string): AtElement;
17
+ at(uid: string, uin?: string, name?: string): AtElement;
17
18
  /**
18
19
  * 表情
19
20
  * @param id - 表情ID
@@ -16,13 +16,15 @@ export const segment = new (class Segment {
16
16
  * 提供一个uid即可
17
17
  * @param uid - uid
18
18
  * @param uin - uin
19
+ * @param name - 名称
19
20
  * @returns {AtElement} 提及元素
20
21
  */
21
- at (uid, uin) {
22
+ at (uid, uin, name) {
22
23
  return {
23
24
  type: 'at',
24
25
  uid: uid + '',
25
26
  uin: (uin || '') + '',
27
+ name,
26
28
  }
27
29
  }
28
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-karin",
3
- "version": "0.6.13",
3
+ "version": "0.6.14",
4
4
  "private": false,
5
5
  "description": "基于 Kritor 进行开发的nodejs机器人框架",
6
6
  "homepage": "https://github.com/KarinJS/Karin",