node-karin 0.6.12 → 0.6.13

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.
@@ -2,7 +2,7 @@ import fs from 'fs';
2
2
  import { randomUUID } from 'crypto';
3
3
  import { listener } from '../../core/index.js';
4
4
  import { KarinMessage } from '../../event/index.js';
5
- import { config, common, YamlEditor } from '../../utils/index.js';
5
+ import { config, common, YamlEditor, logger } from '../../utils/index.js';
6
6
  const { enable, msgToFile, token: oldToken, ip } = config.Config.AdapterInput;
7
7
  /**
8
8
  * - 标准输入输出适配器
@@ -153,17 +153,9 @@ export declare class AdapterOneBot11 implements KarinAdapter {
153
153
  SetGroupWholeBan(group_id: string, is_ban?: boolean): Promise<void>;
154
154
  /**
155
155
  * 设置群管理员
156
- * @param {{
157
- * group_id:string,
158
- * target_uid?:string,
159
- * target_uin?:string,
160
- * is_admin:boolean
161
- * }} options - 设置管理员选项
162
- * @param options.group_id - 群组ID
163
- * @param options.target_uid - 要设置为管理员的用户uid
164
- * @param options.target_uin - 要设置为管理员的用户uin
165
- * @param options.is_admin - 是否设置为管理员
166
- * @returns {Promise<SetGroupAdminResponse>} - 设置群管理员操作的响应
156
+ * @param group_id - 群号
157
+ * @param target_uid_or_uin - 目标用户ID
158
+ * @param is_admin - 是否设置为管理员
167
159
  */
168
160
  SetGroupAdmin(group_id: string, target_uid_or_uin: string, is_admin: boolean): Promise<void>;
169
161
  /**
@@ -213,7 +213,7 @@ export class AdapterOneBot11 {
213
213
  uid: data.user_id + '',
214
214
  uin: data.user_id + '',
215
215
  nick: '',
216
- role: '',
216
+ role: 'unknown',
217
217
  };
218
218
  const contact = {
219
219
  scene: ('group_id' in data ? 'group' : 'friend'),
@@ -223,8 +223,9 @@ export class AdapterOneBot11 {
223
223
  switch (data.notice_type) {
224
224
  // 群文件上传
225
225
  case 'group_upload': {
226
+ const group_id = data.group_id + '';
226
227
  const content = {
227
- group_id: data.group_id + '',
228
+ group_id,
228
229
  operator_uid: data.user_id + '',
229
230
  operator_uin: data.user_id + '',
230
231
  file_id: data.file.id,
@@ -242,6 +243,7 @@ export class AdapterOneBot11 {
242
243
  content,
243
244
  sender,
244
245
  contact,
246
+ group_id,
245
247
  sub_event: 'group_file_uploaded',
246
248
  };
247
249
  notice = new KarinNotice(options);
@@ -249,8 +251,9 @@ export class AdapterOneBot11 {
249
251
  }
250
252
  // 群管理员变动
251
253
  case 'group_admin': {
254
+ const group_id = data.group_id + '';
252
255
  const content = {
253
- group_id: data.group_id + '',
256
+ group_id,
254
257
  target_uid: data.user_id + '',
255
258
  target_uin: data.user_id + '',
256
259
  is_admin: data.sub_type === 'set',
@@ -263,6 +266,7 @@ export class AdapterOneBot11 {
263
266
  sender,
264
267
  contact,
265
268
  content,
269
+ group_id,
266
270
  sub_event: 'group_admin_changed',
267
271
  };
268
272
  notice = new KarinNotice(options);
@@ -270,10 +274,11 @@ export class AdapterOneBot11 {
270
274
  }
271
275
  // 群成员减少
272
276
  case 'group_decrease': {
277
+ const group_id = data.group_id + '';
273
278
  const content = {
274
- group_id: data.group_id + '',
275
- operator_uid: data.operator_id || '',
276
- operator_uin: data.operator_id || '',
279
+ group_id,
280
+ operator_uid: (data.operator_id + '') || '',
281
+ operator_uin: (data.operator_id + '') || '',
277
282
  target_uid: data.user_id || '',
278
283
  target_uin: data.user_id || '',
279
284
  type: data.sub_type,
@@ -286,6 +291,7 @@ export class AdapterOneBot11 {
286
291
  sender,
287
292
  contact,
288
293
  content,
294
+ group_id,
289
295
  sub_event: 'group_member_decrease',
290
296
  };
291
297
  notice = new KarinNotice(options);
@@ -293,8 +299,9 @@ export class AdapterOneBot11 {
293
299
  }
294
300
  // 群成员增加
295
301
  case 'group_increase': {
302
+ const group_id = data.group_id + '';
296
303
  const content = {
297
- group_id: data.group_id + '',
304
+ group_id,
298
305
  operator_uid: (data.operator_id || '') + '',
299
306
  operator_uin: (data.operator_id || '') + '',
300
307
  target_uid: (data.user_id || '') + '',
@@ -309,6 +316,7 @@ export class AdapterOneBot11 {
309
316
  sender,
310
317
  contact,
311
318
  content,
319
+ group_id,
312
320
  sub_event: 'group_member_increase',
313
321
  };
314
322
  notice = new KarinNotice(options);
@@ -316,10 +324,11 @@ export class AdapterOneBot11 {
316
324
  }
317
325
  // 群禁言事件
318
326
  case 'group_ban': {
327
+ const group_id = data.group_id + '';
319
328
  const content = {
320
- group_id: data.group_id,
321
- operator_uid: data.operator_id || '',
322
- operator_uin: data.operator_id || '',
329
+ group_id,
330
+ operator_uid: (data.operator_id + '') || '',
331
+ operator_uin: (data.operator_id + '') || '',
323
332
  target_uid: data.user_id || '',
324
333
  target_uin: data.user_id || '',
325
334
  duration: data.duration,
@@ -333,6 +342,7 @@ export class AdapterOneBot11 {
333
342
  sender,
334
343
  contact,
335
344
  content,
345
+ group_id,
336
346
  sub_event: 'group_member_ban',
337
347
  };
338
348
  notice = new KarinNotice(options);
@@ -343,10 +353,11 @@ export class AdapterOneBot11 {
343
353
  this.logger('info', `[好友添加]:${JSON.stringify(data)}`);
344
354
  break;
345
355
  case 'group_recall': {
356
+ const group_id = data.group_id + '';
346
357
  const content = {
347
- group_id: data.group_id,
348
- operator_uid: data.operator_id || '',
349
- operator_uin: data.operator_id || '',
358
+ group_id,
359
+ operator_uid: (data.operator_id + '') || '',
360
+ operator_uin: (data.operator_id + '') || '',
350
361
  target_uid: data.user_id || '',
351
362
  target_uin: data.user_id || '',
352
363
  message_id: data.message_id,
@@ -360,6 +371,7 @@ export class AdapterOneBot11 {
360
371
  sender,
361
372
  contact,
362
373
  content,
374
+ group_id,
363
375
  sub_event: 'group_recall',
364
376
  };
365
377
  notice = new KarinNotice(options);
@@ -388,8 +400,9 @@ export class AdapterOneBot11 {
388
400
  case 'notify':
389
401
  switch (data.sub_type) {
390
402
  case 'poke': {
403
+ const group_id = 'group_id' in data ? data.group_id + '' : '';
391
404
  const content = {
392
- group_id: data.group_id + '',
405
+ group_id,
393
406
  operator_uid: data.user_id + '',
394
407
  operator_uin: data.user_id + '',
395
408
  target_uid: data.target_id + '',
@@ -406,6 +419,7 @@ export class AdapterOneBot11 {
406
419
  sender,
407
420
  contact,
408
421
  content,
422
+ group_id,
409
423
  sub_event: data.group_id ? 'group_poke' : 'private_poke',
410
424
  };
411
425
  notice = new KarinNotice(options);
@@ -422,8 +436,9 @@ export class AdapterOneBot11 {
422
436
  }
423
437
  break;
424
438
  case 'group_msg_emoji_like': {
439
+ const group_id = data.group_id + '';
425
440
  const content = {
426
- group_id: data.group_id + '',
441
+ group_id,
427
442
  message_id: data.message_id,
428
443
  face_id: data.likes[0].emoji_id,
429
444
  is_set: true,
@@ -436,6 +451,7 @@ export class AdapterOneBot11 {
436
451
  sender,
437
452
  contact,
438
453
  content,
454
+ group_id,
439
455
  sub_event: 'group_message_reaction',
440
456
  };
441
457
  notice = new KarinNotice(options);
@@ -465,7 +481,7 @@ export class AdapterOneBot11 {
465
481
  uid: data.user_id + '',
466
482
  uin: data.user_id + '',
467
483
  nick: '',
468
- role: '',
484
+ role: 'unknown',
469
485
  },
470
486
  sub_event: 'private_apply',
471
487
  content: {
@@ -492,7 +508,7 @@ export class AdapterOneBot11 {
492
508
  uid: data.user_id + '',
493
509
  uin: data.user_id + '',
494
510
  nick: '',
495
- role: '',
511
+ role: 'unknown',
496
512
  },
497
513
  sub_event: data.sub_type === 'add' ? 'group_apply' : 'invited_group',
498
514
  content: {
@@ -871,17 +887,9 @@ export class AdapterOneBot11 {
871
887
  }
872
888
  /**
873
889
  * 设置群管理员
874
- * @param {{
875
- * group_id:string,
876
- * target_uid?:string,
877
- * target_uin?:string,
878
- * is_admin:boolean
879
- * }} options - 设置管理员选项
880
- * @param options.group_id - 群组ID
881
- * @param options.target_uid - 要设置为管理员的用户uid
882
- * @param options.target_uin - 要设置为管理员的用户uin
883
- * @param options.is_admin - 是否设置为管理员
884
- * @returns {Promise<SetGroupAdminResponse>} - 设置群管理员操作的响应
890
+ * @param group_id - 群号
891
+ * @param target_uid_or_uin - 目标用户ID
892
+ * @param is_admin - 是否设置为管理员
885
893
  */
886
894
  async SetGroupAdmin(group_id, target_uid_or_uin, is_admin) {
887
895
  const user_id = Number(target_uid_or_uin);
@@ -163,7 +163,7 @@ class Listeners extends EventEmitter {
163
163
  /** 标准化 */
164
164
  const NewElements = common.makeMessage(elements)
165
165
  /** 结果 */
166
- let result = { message_id: '' }
166
+ let result = {}
167
167
  const reply_log = common.makeMessageLog(NewElements)
168
168
  const self_id = bot.account.uid || bot.account.uin
169
169
  if (contact.scene === 'group') {
@@ -123,14 +123,23 @@ class PluginLoader {
123
123
  this.getApps(dir, this.isTs, true)
124
124
  continue
125
125
  }
126
- /** 入口文件 */
126
+ /** package */
127
+ const pack = common.readJson(`${PluginPath}/package.json`)
128
+ /** 旧版本入口文件 */
127
129
  const index = this.getIndex(PluginPath, process.env.karin_app_lang)
128
130
  if (index) {
129
131
  this.FileList.push({ dir, name: index })
130
132
  this.isDev && this.watchList.push({ dir, name: index })
131
133
  }
134
+ /** 新版本入口 */
135
+ if (pack.main) {
136
+ const { dir: dirName, pop } = common.splitPath(pack.main)
137
+ const dirPath = `${dir}/${dirName}`
138
+ this.FileList.push({ dir: dirPath, name: pop })
139
+ this.isDev && this.watchList.push({ dir: dirPath, name: pop })
140
+ }
132
141
  /** 检查是否存在karin.apps */
133
- const pack = common.readJson(`${PluginPath}/package.json`)
142
+ const outDir = (pack?.karin?.outDir || 'dist')
134
143
  if (pack && pack?.karin?.apps) {
135
144
  const cfg = pack.karin.apps
136
145
  if (Array.isArray(cfg)) {
@@ -144,8 +153,8 @@ class PluginLoader {
144
153
  /** ts环境 全部加载 如果存在编译产物 则不加载ts */
145
154
  if (this.isTs) {
146
155
  /** 编译产物 存在不加载ts */
147
- if (common.exists(`${PluginPath}/dist/apps`)) {
148
- this.getApps((`${dir}/dist/apps`), false)
156
+ if (common.exists(`${PluginPath}/${outDir}/apps`)) {
157
+ this.getApps((`${dir}/${outDir}/apps`), false)
149
158
  continue
150
159
  }
151
160
  /** ts */
@@ -157,7 +166,7 @@ class PluginLoader {
157
166
  /** js环境 */
158
167
  if (common.isDir(`${PluginPath}/apps`)) { this.getApps(`${dir}/apps`, false) }
159
168
  /** 这里需要判断下 不然ts环境下会重复加载 */
160
- if (!this.isTs && common.isDir(`${PluginPath}/dist/apps`)) { this.getApps(`${dir}/dist/apps`, false) }
169
+ if (!this.isTs && common.isDir(`${PluginPath}/${outDir}/apps`)) { this.getApps(`${dir}/${outDir}/apps`, false) }
161
170
  }
162
171
  }
163
172
 
@@ -247,6 +256,9 @@ class PluginLoader {
247
256
  if (!App?.name) { return logger.error(`[${dir}][${name}] 插件名称错误`) }
248
257
  App.file.dir = dir
249
258
  App.file.name = name
259
+ App.rule.forEach((v, index) => {
260
+ App.rule[index].log = v.log === false ? (id, log) => logger.bot('debug', id, log) : (id, log) => logger.bot('mark', id, log)
261
+ })
250
262
  /** handler */
251
263
  App.task = this.addTaskFnc(dir, App)
252
264
  this.PluginList[index] = App
@@ -16,7 +16,7 @@ export default class EventHandler {
16
16
  this.config = {}
17
17
  this.GroupMsgPrint = false
18
18
  /** 加入e.bot */
19
- Object.defineProperty(this.e, 'bot', { value: listener.getBot(this.e.self_id) })
19
+ !this.e.bot && Object.defineProperty(this.e, 'bot', { value: listener.getBot(this.e.self_id) })
20
20
  if (this.e.group_id) { this.config = config.group(this.e.group_id) }
21
21
  }
22
22
 
@@ -25,7 +25,6 @@ export class MessageHandler extends EventHandler {
25
25
  logger.debug('[消息拦截] 响应模式不匹配')
26
26
  return
27
27
  }
28
- this.GroupMsgPrint = false
29
28
  /** 处理回复 */
30
29
  this.reply()
31
30
  /** 处理消息 */
@@ -51,8 +50,9 @@ export class MessageHandler extends EventHandler {
51
50
  if ('GroupCD' in this.config && !review.PluginEnable(app, this.config)) { continue }
52
51
  /** 判断子事件 */
53
52
  if (v.event && !this.filtEvent(v.event)) { continue }
54
- this.e.logFnc = `[${app.file.dir}][${app.name}][${v.fnc}]`
55
- const logFnc = logger.fnc(`[${app.name}][${v.fnc}]`)
53
+ const fncName = app.file.type === 'function' ? 'default' : v.fnc
54
+ this.e.logFnc = `[${app.file.dir}][${app.name}][${fncName}]`
55
+ const logFnc = logger.fnc(`[${app.name}][${fncName}]`)
56
56
  this.GroupMsgPrint && typeof v.log === 'function' && v.log(this.e.self_id, `${logFnc}${this.e.logText} ${lodash.truncate(this.e.msg, { length: 80 })}`)
57
57
  /** 判断权限 */
58
58
  if (!this.filterPermission(v.permission)) { break a }
@@ -165,13 +165,15 @@ export class MessageHandler extends EventHandler {
165
165
  logs.push(`[json:${JSON.stringify(val.data)}]`)
166
166
  break
167
167
  case 'markdown': {
168
- if (val.content) {
169
- logs.push(`[markdown:${val.content}]`)
170
- } else {
171
- const content = { id: val.custom_template_id }
172
- for (const v of val.params) { content[v.key] = v.values[0] }
173
- logs.push(`[markdown:${JSON.stringify(content)}]`)
174
- }
168
+ logs.push(`[markdown:${val.content}]`)
169
+ break
170
+ }
171
+ case 'markdown_tpl': {
172
+ const params = val.params
173
+ if (!params) { break }
174
+ const content = { id: val.custom_template_id }
175
+ for (const v of params) { content[v.key] = v.values[0] }
176
+ logs.push(`[markdown_tpl:${JSON.stringify(content)}]`)
175
177
  break
176
178
  }
177
179
  case 'rows': {
@@ -1,5 +1,5 @@
1
1
  import { KarinEvent } from './event.js';
2
- import { contact, Sender, EventToSubEvent, RequestType, KarinRequestEvent } from '../types/index.js';
2
+ import { contact, Sender, EventToSubEvent, RequestType } from '../types/index.js';
3
3
  /**
4
4
  * - 请求事件基类
5
5
  */
@@ -45,5 +45,5 @@ export declare class KarinRequest extends KarinEvent {
45
45
  /**
46
46
  * - 事件对应的内容参数
47
47
  */
48
- content: KarinRequestEvent;
48
+ content: RequestType[EventToSubEvent['request']];
49
49
  }
@@ -5,7 +5,6 @@ import { KarinEvent } from './event.js'
5
5
  export class KarinRequest extends KarinEvent {
6
6
  constructor ({ self_id, event_id, user_id, time, contact, sender, sub_event, content, group_id = '' }) {
7
7
  super({ event: 'request', event_id, self_id, user_id, group_id, time, contact, sender, sub_event })
8
- // ...
9
8
  this.content = content
10
9
  }
11
10
 
@@ -21,14 +21,14 @@ export class RenderClient extends RenderBase {
21
21
  this.index = 0
22
22
  this.retry = 0
23
23
  this.reg = new RegExp(`(${process.cwd().replace(/\\/g, '\\\\')}|${process.cwd().replace(/\\/g, '/')})`, 'g')
24
- /** 连接ws */
25
- this.ws = new WebSocket(this.url)
26
24
  }
27
25
 
28
26
  /**
29
27
  * 初始化
30
28
  */
31
29
  async start () {
30
+ /** 连接ws */
31
+ this.ws = new WebSocket(this.url)
32
32
  /** 建立连接 */
33
33
  this.ws.on('open', () => {
34
34
  logger.mark(`[渲染器:${this.id}][WebSocket] 建立连接:${logger.green(this.url)}`)
@@ -105,9 +105,10 @@ export interface KarinAdapter {
105
105
  /**
106
106
  * - 头像大小,默认需要为`0`,请开发者注意
107
107
  */
108
- size?: number): string;
108
+ size?: 0 | 40 | 100 | 140): string;
109
109
  /**
110
- * - 获取群头像
110
+ * 获取群头像url
111
+ * @returns 头像的url地址
111
112
  */
112
113
  getGroupAvatar(
113
114
  /**
@@ -117,7 +118,7 @@ export interface KarinAdapter {
117
118
  /**
118
119
  * - 头像大小,默认`0`
119
120
  */
120
- size?: number,
121
+ size?: 0 | 40 | 100 | 140,
121
122
  /**
122
123
  * - 历史头像记录,默认`0`,若要获取历史群头像则填写1,2,3...
123
124
  */
@@ -141,7 +142,8 @@ export interface KarinAdapter {
141
142
  /**
142
143
  * - 消息ID
143
144
  */
144
- message_id: string;
145
+ message_id?: string;
146
+ [key: string]: any;
145
147
  }>;
146
148
  /**
147
149
  * - 上传合并转发消息返回一个资源ID
@@ -193,7 +195,7 @@ export interface KarinAdapter {
193
195
  /**
194
196
  * - 消息ID
195
197
  */
196
- message_id: string): Promise<void>;
198
+ message_id: string): Promise<void | boolean>;
197
199
  /**
198
200
  * - 获取消息
199
201
  */
@@ -281,7 +283,7 @@ export interface KarinAdapter {
281
283
  /**
282
284
  * - 赞的次数,默认为10
283
285
  */
284
- vote_count: number): Promise<void>;
286
+ vote_count: number): Promise<void | boolean>;
285
287
  /**
286
288
  * - 群踢人
287
289
  */
@@ -554,7 +556,7 @@ export interface KarinAdapter {
554
556
  message_id?: string;
555
557
  }>;
556
558
  /**
557
- * 对消息进行表情回应
559
+ * 对消息进行表情回应 icqq需要传递seq
558
560
  * @param Contact - 联系人信息
559
561
  * @param message_id - 消息ID
560
562
  * @param face_id - 表情ID
@@ -1,4 +1,4 @@
1
- export type ElementType = 'text' | 'at' | 'face' | 'bubble_face' | 'reply' | 'image' | 'voice' | 'video' | 'basketball' | 'dice' | 'rps' | 'poke' | 'music' | 'weather' | 'location' | 'share' | 'gift' | 'market_face' | 'forward' | 'contact' | 'json' | 'xml' | 'file' | 'markdown' | 'keyboard' | 'node' | 'rows' | 'record' | 'long_msg';
1
+ export type ElementType = 'text' | 'at' | 'face' | 'bubble_face' | 'reply' | 'image' | 'voice' | 'video' | 'basketball' | 'dice' | 'rps' | 'poke' | 'music' | 'weather' | 'location' | 'share' | 'gift' | 'market_face' | 'forward' | 'contact' | 'json' | 'xml' | 'file' | 'markdown' | 'markdown_tpl' | 'keyboard' | 'node' | 'rows' | 'record' | 'long_msg';
2
2
  export interface Element {
3
3
  /**
4
4
  * - 元素类型
@@ -444,36 +444,18 @@ export interface ContentElement extends Element {
444
444
  * - 原生markdown内容
445
445
  */
446
446
  content: string;
447
+ config?: {
448
+ /** 未知的参数 */
449
+ unknown?: number;
450
+ time: number;
451
+ token: string;
452
+ };
447
453
  }
448
454
  /**
449
455
  * - 模板 Markdown 元素
450
456
  */
451
457
  export interface TemplateElement extends Element {
452
- type: 'markdown';
453
- /**
454
- * - 模板ID
455
- */
456
- custom_template_id: string;
457
- /**
458
- * - 模板参数
459
- */
460
- params: Array<{
461
- /**
462
- * - 模板参数键名称
463
- */
464
- key: string;
465
- /**
466
- * - 模板参数值
467
- */
468
- values: Array<string>;
469
- }>;
470
- }
471
- /**
472
- * - Markdown元素
473
- */
474
- export interface MarkdownElement extends Element {
475
- type: 'markdown';
476
- content: string;
458
+ type: 'markdown_tpl';
477
459
  /**
478
460
  * - 模板ID
479
461
  */
@@ -566,7 +548,7 @@ export interface LongMsgElement extends Element {
566
548
  */
567
549
  id: string;
568
550
  }
569
- export type KarinElement = TextElement | AtElement | FaceElement | BubbleFaceElement | ReplyElement | ImageElement | VoiceElement | VideoElement | BasketballElement | DiceElement | RpsElement | PokeElement | MusicElement | WeatherElement | LocationElement | ShareElement | GiftElement | MarketFaceElement | ForwardElement | ContactElement | JsonElement | XmlElement | FileElement | MarkdownElement | ButtonElement | RowElement | RecordElement | LongMsgElement;
551
+ export type KarinElement = TextElement | AtElement | FaceElement | BubbleFaceElement | ReplyElement | ImageElement | VoiceElement | VideoElement | BasketballElement | DiceElement | RpsElement | PokeElement | MusicElement | WeatherElement | LocationElement | ShareElement | GiftElement | MarketFaceElement | ForwardElement | ContactElement | JsonElement | XmlElement | FileElement | ButtonElement | RowElement | RecordElement | LongMsgElement | TemplateElement | ContentElement;
570
552
  /**
571
553
  * - 构建自定义转发节点 此元素仅可通过专用接口发送 不支持混合发送
572
554
  */
@@ -61,6 +61,18 @@ export declare const common: {
61
61
  * - 解析json文件
62
62
  */
63
63
  readJson(file: string): any;
64
+ /**
65
+ * - 写入json文件
66
+ */
67
+ writeJson(file: string, data: any): boolean;
68
+ /**
69
+ * - 解析yaml文件
70
+ */
71
+ readYaml(file: string): any;
72
+ /**
73
+ * - 写入yaml文件
74
+ */
75
+ writeYaml(file: string, data: any): boolean;
64
76
  /**
65
77
  * 根据文件后缀名从指定路径下读取符合要求的文件
66
78
  * @param path - 路径
@@ -70,10 +82,22 @@ export declare const common: {
70
82
  */
71
83
  readDir(_path: string, ext: string | string[]): string[] | null;
72
84
  /**
73
- * 传入 import.meta.url 自动构建../
85
+ * 根据传入的 import.meta.url 计算相对于项目根目录的路径,返回需要的 '../' 层级。
74
86
  * @param url - import.meta.url
87
+ * @returns 相对路径的层级数量,用 '../' 表示
88
+ * @example
89
+ * // 在 plugins/karin-plugin-example/index.ts 中使用
90
+ * common.urlToPath(import.meta.url) // 返回 '../../'
75
91
  */
76
92
  urlToPath(url: string): string;
93
+ /**
94
+ * 传入相对路径 分割为两部分 1为文件夹路径 2为文件名 文件夹路径无前缀开头
95
+ * @param _path - 路径
96
+ */
97
+ splitPath(_path: string): {
98
+ dir: string;
99
+ pop: string;
100
+ };
77
101
  /**
78
102
  * 将文件转换为不带前缀的base64字符串
79
103
  * @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
@@ -106,10 +130,9 @@ export declare const common: {
106
130
  makeMessage(elements: string | KarinElement | (string | KarinElement)[]): Array<KarinElement>;
107
131
  /**
108
132
  * 制作简单转发,返回segment.node[]。仅简单包装node,也可以自己组装
109
- * @param {Array<{object}> | object} elements
133
+ * @param elements
110
134
  * @param fakeUin 用户id
111
135
  * @param fakeNick 用户昵称
112
- * @return {Array<KarinNodeElement>}
113
136
  */
114
137
  makeForward(elements: KarinElement | KarinElement[], fakeUin: string, fakeNick: string): Array<KarinNodeElement>;
115
138
  /**
@@ -2,7 +2,7 @@ import { promisify } from 'util'
2
2
  import { fileURLToPath } from 'url'
3
3
  import { pipeline, Readable } from 'stream'
4
4
  import { logger, segment } from '../utils/index.js'
5
- import { fs, path, axios, lodash } from '../modules.js'
5
+ import { fs, path, axios, lodash, yaml as Yaml } from '../modules.js'
6
6
  /**
7
7
  * 常用方法
8
8
  */
@@ -136,11 +136,49 @@ export const common = new (class Common {
136
136
  try {
137
137
  return JSON.parse(fs.readFileSync(file, 'utf8'))
138
138
  } catch (error) {
139
- logger.error('读取json文件错误:' + error)
139
+ logger.error('[common] 读取json文件错误:' + error)
140
140
  return null
141
141
  }
142
142
  }
143
143
 
144
+ /**
145
+ * - 写入json文件
146
+ */
147
+ writeJson (file, data) {
148
+ try {
149
+ fs.writeFileSync(file, JSON.stringify(data, null, 2))
150
+ return true
151
+ } catch (error) {
152
+ logger.error('[common] 写入json文件错误:' + error)
153
+ return false
154
+ }
155
+ }
156
+
157
+ /**
158
+ * - 解析yaml文件
159
+ */
160
+ readYaml (file) {
161
+ try {
162
+ return Yaml.parse(fs.readFileSync(file, 'utf8'))
163
+ } catch (error) {
164
+ logger.error('[common] 读取yaml文件错误:' + error)
165
+ return null
166
+ }
167
+ }
168
+
169
+ /**
170
+ * - 写入yaml文件
171
+ */
172
+ writeYaml (file, data) {
173
+ try {
174
+ fs.writeFileSync(file, Yaml.stringify(data))
175
+ return true
176
+ } catch (error) {
177
+ logger.error('[common] 写入yaml文件错误:' + error)
178
+ return false
179
+ }
180
+ }
181
+
144
182
  /**
145
183
  * 根据文件后缀名从指定路径下读取符合要求的文件
146
184
  * @param path - 路径
@@ -162,25 +200,40 @@ export const common = new (class Common {
162
200
  }
163
201
 
164
202
  /**
165
- * 传入 import.meta.url 自动构建../
203
+ * 根据传入的 import.meta.url 计算相对于项目根目录的路径,返回需要的 '../' 层级。
166
204
  * @param url - import.meta.url
205
+ * @returns 相对路径的层级数量,用 '../' 表示
206
+ * @example
207
+ * // 在 plugins/karin-plugin-example/index.ts 中使用
208
+ * common.urlToPath(import.meta.url) // 返回 '../../'
167
209
  */
168
210
  urlToPath (url) {
169
- // 获取当前文件的绝对路径
211
+ /** 当前文件的绝对路径 */
170
212
  const filePath = fileURLToPath(url)
171
- // 获取当前文件所在目录的绝对路径
213
+ /** 当前文件所在目录的绝对路径 */
172
214
  const dirPath = path.dirname(filePath)
173
- // 获取项目根目录
215
+ /** 项目根目录 */
174
216
  const rootPath = process.cwd()
175
- // 计算当前文件到项目根目录的相对路径
217
+ /** 当前文件到项目根目录的相对路径 */
176
218
  const relativePath = path.relative(dirPath, rootPath)
177
- // 计算返回上一级目录的数量
219
+ /** 相对路径的层级数量 */
178
220
  const upLevelsCount = relativePath.split(path.sep).length
179
- // 生成相应数量的 '../'
221
+ /** 返回构建的路径 */
180
222
  const upPath = lodash.repeat('../', upLevelsCount)
181
223
  return upPath
182
224
  }
183
225
 
226
+ /**
227
+ * 传入相对路径 分割为两部分 1为文件夹路径 2为文件名 文件夹路径无前缀开头
228
+ * @param _path - 路径
229
+ */
230
+ splitPath (_path) {
231
+ const list = _path.replace(/\\/g, '/').split('/')
232
+ const pop = list.pop() || ''
233
+ const dir = path.join(...list)
234
+ return { dir, pop }
235
+ }
236
+
184
237
  /**
185
238
  * 将文件转换为不带前缀的base64字符串
186
239
  * @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
@@ -297,10 +350,9 @@ export const common = new (class Common {
297
350
 
298
351
  /**
299
352
  * 制作简单转发,返回segment.node[]。仅简单包装node,也可以自己组装
300
- * @param {Array<{object}> | object} elements
353
+ * @param elements
301
354
  * @param fakeUin 用户id
302
355
  * @param fakeNick 用户昵称
303
- * @return {Array<KarinNodeElement>}
304
356
  */
305
357
  makeForward (elements, fakeUin, fakeNick) {
306
358
  if (!Array.isArray(elements)) { elements = [elements] }
@@ -406,13 +458,15 @@ export const common = new (class Common {
406
458
  logs.push(`[json:${val.data}]`)
407
459
  break
408
460
  case 'markdown': {
409
- if (val.content) {
410
- logs.push(`[markdown:${val.content}]`)
411
- } else {
412
- const content = { id: val.custom_template_id }
413
- for (const v of val.params) { content[v.key] = v.values[0] }
414
- logs.push(`[markdown:${JSON.stringify(content)}]`)
415
- }
461
+ logs.push(`[markdown:${val.content}]`)
462
+ break
463
+ }
464
+ case 'markdown_tpl': {
465
+ const params = val.params
466
+ if (!params) { break }
467
+ const content = { id: val.custom_template_id }
468
+ for (const v of params) { content[v.key] = v.values[0] }
469
+ logs.push(`[markdown_tpl:${JSON.stringify(content)}]`)
416
470
  break
417
471
  }
418
472
  case 'rows': {
@@ -1,4 +1,4 @@
1
- import { TextElement, AtElement, ImageElement, FaceElement, BubbleFaceElement, ReplyElement, VoiceElement, VideoElement, BasketballElement, DiceElement, RpsElement, PokeElement, MusicElement, WeatherElement, LocationElement, ShareElement, GiftElement, MarketFaceElement, ForwardElement, ContactElement, JsonElement, XmlElement, FileElement, ButtonElement, CustomMusicElemen, TemplateElement, ContentElement, KarinNodeElement, KarinElement } from '../types/index.js';
1
+ import { TextElement, AtElement, ImageElement, FaceElement, BubbleFaceElement, ReplyElement, VoiceElement, VideoElement, BasketballElement, DiceElement, RpsElement, PokeElement, MusicElement, WeatherElement, LocationElement, ShareElement, GiftElement, MarketFaceElement, ForwardElement, ContactElement, JsonElement, XmlElement, FileElement, ButtonElement, CustomMusicElemen, TemplateElement, ContentElement, KarinNodeElement, KarinElement, LongMsgElement } from '../types/index.js';
2
2
  export declare const segment: {
3
3
  /**
4
4
  * 纯文本
@@ -78,7 +78,7 @@ export declare const segment: {
78
78
  */
79
79
  record(file: string, magic?: boolean, md5?: string, name?: string): VoiceElement;
80
80
  /**
81
- * 语音
81
+ * 语音 即将废弃 请使用segment.record
82
82
  * @param file - 语音URL或路径、Base64
83
83
  * @param magic - 是否魔法语音,默认为 false
84
84
  * @param md5 - 语音md5
@@ -241,21 +241,23 @@ export declare const segment: {
241
241
  */
242
242
  md5?: string;
243
243
  }): FileElement;
244
+ /**
245
+ * 长消息
246
+ * @param id - ID
247
+ */
248
+ long_msg(id: string): LongMsgElement;
244
249
  /**
245
250
  * Markdown
246
251
  * @param content - 原生markdown内容
247
- * @returns {ContentElement} Markdown元素
252
+ * @param config - 未知的参数
248
253
  */
249
- markdown(content: string, params?: Array<{
250
- /**
251
- * - 模板参数键名称
252
- */
253
- key: string;
254
- /**
255
- * - 模板参数值
256
- */
257
- values: Array<string>;
258
- }>): ContentElement | TemplateElement;
254
+ markdown(content: ContentElement["content"], config?: ContentElement["config"]): ContentElement;
255
+ /**
256
+ * 构建模板Markdown
257
+ * @param custom_template_id - 模板ID
258
+ * @param params - 模板markdown参数
259
+ */
260
+ markdown_tpl(custom_template_id: TemplateElement["custom_template_id"], params: TemplateElement["params"]): TemplateElement;
259
261
  /**
260
262
  * 按钮
261
263
  * @param data - 按钮数据
@@ -112,7 +112,7 @@ export const segment = new (class Segment {
112
112
  }
113
113
 
114
114
  /**
115
- * 语音
115
+ * 语音 即将废弃 请使用segment.record
116
116
  * @param file - 语音URL或路径、Base64
117
117
  * @param magic - 是否魔法语音,默认为 false
118
118
  * @param md5 - 语音md5
@@ -384,29 +384,47 @@ export const segment = new (class Segment {
384
384
  }
385
385
  }
386
386
 
387
+ /**
388
+ * 长消息
389
+ * @param id - ID
390
+ */
391
+ long_msg (id) {
392
+ return {
393
+ type: 'long_msg',
394
+ id,
395
+ }
396
+ }
397
+
387
398
  /**
388
399
  * Markdown
389
400
  * @param content - 原生markdown内容
390
- * @returns {ContentElement} Markdown元素
401
+ * @param config - 未知的参数
391
402
  */
392
- markdown (
403
+ markdown (content, config) {
404
+ return {
405
+ type: 'markdown',
406
+ content,
407
+ config,
408
+ }
409
+ }
410
+
411
+ /**
412
+ * 构建模板Markdown
413
+ * @param custom_template_id - 模板ID
414
+ * @param params - 模板markdown参数
415
+ */
416
+ markdown_tpl (
393
417
  /**
394
- * - 原生markdown内容 或 模板ID
418
+ * - 模板ID
395
419
  */
396
- content,
420
+ custom_template_id,
397
421
  /**
398
- * - 模板markdown参数 原生markdown内容时无效
399
- */
400
- params = []) {
401
- if (typeof content === 'string') {
402
- return {
403
- type: 'markdown',
404
- content,
405
- }
406
- }
422
+ * - 模板markdown参数
423
+ */
424
+ params) {
407
425
  return {
408
- type: 'markdown',
409
- custom_template_id: content,
426
+ type: 'markdown_tpl',
427
+ custom_template_id,
410
428
  params,
411
429
  }
412
430
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-karin",
3
- "version": "0.6.12",
3
+ "version": "0.6.13",
4
4
  "private": false,
5
5
  "description": "基于 Kritor 进行开发的nodejs机器人框架",
6
6
  "homepage": "https://github.com/KarinJS/Karin",
@@ -58,7 +58,6 @@
58
58
  "dependencies": {
59
59
  "@grpc/grpc-js": "1.10.10",
60
60
  "@grpc/proto-loader": "0.7.13",
61
- "@inquirer/prompts": "^5.0.7",
62
61
  "art-template": "4.13.2",
63
62
  "axios": "1.7.2",
64
63
  "chalk": "5.3.0",