napcat-sdk 0.1.1 → 0.2.0

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/dist/index.mjs CHANGED
@@ -1,56 +1,35 @@
1
1
  import crypto from "node:crypto";
2
2
  import mitt from "mitt";
3
3
 
4
+ //#region src/logger.ts
5
+ const noop = () => {};
6
+ const ABSTRACT_LOGGER = {
7
+ fatal: noop,
8
+ error: noop,
9
+ warn: noop,
10
+ info: noop,
11
+ debug: noop,
12
+ trace: noop
13
+ };
14
+ const CONSOLE_LOGGER = {
15
+ fatal: console.error.bind(console, "[FATAL]"),
16
+ error: console.error.bind(console, "[ERROR]"),
17
+ warn: console.warn.bind(console, "[WARN]"),
18
+ info: console.info.bind(console, "[INFO]"),
19
+ debug: console.debug.bind(console, "[DEBUG]"),
20
+ trace: console.trace.bind(console, "[TRACE]")
21
+ };
22
+
23
+ //#endregion
4
24
  //#region package.json
5
25
  var name$1 = "napcat-sdk";
6
- var version$1 = "0.1.1";
7
- var package_default = {
8
- name: name$1,
9
- type: "module",
10
- version: version$1,
11
- packageManager: "pnpm@10.26.0",
12
- description: "A simple SDK for NapCat OneBot v11.",
13
- keywords: [
14
- "napcat",
15
- "onebot",
16
- "onebot v11",
17
- "sdk"
18
- ],
19
- homepage: "https://github.com/vikiboss/mioki#readme",
20
- files: ["dist"],
21
- bugs: { "url": "https://github.com/vikiboss/mioki/issues" },
22
- repository: {
23
- "type": "git",
24
- "url": "git+https://github.com/vikiboss/mioki.git",
25
- "directory": "packages/napcat-sdk"
26
- },
27
- scripts: {
28
- "dev": "tsdown -w",
29
- "build": "tsdown"
30
- },
31
- exports: {
32
- ".": {
33
- "require": "./dist/index.cjs",
34
- "import": "./dist/index.mjs",
35
- "types": "./dist/index.d.ts"
36
- },
37
- "./package.json": "./package.json"
38
- },
39
- author: "Viki <hi@viki.moe> (https://github.com/vikiboss)",
40
- license: "MIT",
41
- devDependencies: {
42
- "@types/node": "catalog:dev",
43
- "tsdown": "catalog:dev",
44
- "typescript": "catalog:dev"
45
- },
46
- dependencies: { "mitt": "^3.0.1" }
47
- };
26
+ var version$1 = "0.2.0";
48
27
 
49
28
  //#endregion
50
29
  //#region src/segment.ts
51
- function createSegment(type$1, data) {
30
+ function createSegment(type, data) {
52
31
  return {
53
- type: type$1,
32
+ type,
54
33
  ...data
55
34
  };
56
35
  }
@@ -76,9 +55,9 @@ const segment = {
76
55
  }),
77
56
  mface: (options) => createSegment("mface", { ...options }),
78
57
  bface: (id) => createSegment("bface", { id }),
79
- contact: (type$1, id) => createSegment("contact", {
58
+ contact: (type, id) => createSegment("contact", {
80
59
  id,
81
- sub_type: type$1
60
+ sub_type: type
82
61
  }),
83
62
  poke: () => createSegment("poke", {}),
84
63
  music: (platform, id) => createSegment("music", {
@@ -92,6 +71,7 @@ const segment = {
92
71
  title,
93
72
  ...options
94
73
  }),
74
+ node: (options) => createSegment("node", { ...options }),
95
75
  forward: (id) => createSegment("forward", { id }),
96
76
  json: (data) => createSegment("json", { data }),
97
77
  file: (file, options) => createSegment("file", {
@@ -102,101 +82,6 @@ const segment = {
102
82
  lightapp: () => createSegment("lightapp", {})
103
83
  };
104
84
 
105
- //#endregion
106
- //#region src/logger.ts
107
- const LOG_LEVEL_KEYS = Object.keys({
108
- fatal: 0,
109
- error: 1,
110
- warn: 2,
111
- info: 3,
112
- debug: 4,
113
- trace: 5
114
- });
115
- const noop = () => {};
116
- const ABSTRACT_LOGGER = Object.fromEntries(LOG_LEVEL_KEYS.map((level) => [level, noop]));
117
- const CONSOLE_LOGGER = Object.fromEntries(LOG_LEVEL_KEYS.map((level) => [level, (...args) => {
118
- console[level === "fatal" ? "error" : level === "trace" ? "debug" : level](...args);
119
- }]));
120
-
121
- //#endregion
122
- //#region src/onebot.ts
123
- /**
124
- * NapCat 通知类型映射表(notify 类型)
125
- * @description 将 NapCat 特有的通知类型映射到标准的 notice_type 和 sub_type
126
- */
127
- const NAPCAT_NOTICE_NOTIFY_MAP = {
128
- input_status: {
129
- notice_type: "friend",
130
- sub_type: "input"
131
- },
132
- profile_like: {
133
- notice_type: "friend",
134
- sub_type: "like"
135
- },
136
- title: {
137
- notice_type: "group",
138
- sub_type: "title"
139
- }
140
- };
141
- /**
142
- * NapCat 通知事件映射表(notice 类型)
143
- * @description 将 NapCat 的原始通知事件类型映射到标准的 notice_type 和 sub_type
144
- */
145
- const NAPCAT_NOTICE_EVENT_MAP = {
146
- friend_add: {
147
- notice_type: "friend",
148
- sub_type: "increase"
149
- },
150
- friend_recall: {
151
- notice_type: "friend",
152
- sub_type: "recall"
153
- },
154
- offline_file: {
155
- notice_type: "friend",
156
- sub_type: "offline_file"
157
- },
158
- client_status: {
159
- notice_type: "client",
160
- sub_type: "status"
161
- },
162
- group_admin: {
163
- notice_type: "group",
164
- sub_type: "admin"
165
- },
166
- group_ban: {
167
- notice_type: "group",
168
- sub_type: "ban"
169
- },
170
- group_card: {
171
- notice_type: "group",
172
- sub_type: "card"
173
- },
174
- group_upload: {
175
- notice_type: "group",
176
- sub_type: "upload"
177
- },
178
- group_decrease: {
179
- notice_type: "group",
180
- sub_type: "decrease"
181
- },
182
- group_increase: {
183
- notice_type: "group",
184
- sub_type: "increase"
185
- },
186
- group_msg_emoji_like: {
187
- notice_type: "group",
188
- sub_type: "reaction"
189
- },
190
- essence: {
191
- notice_type: "group",
192
- sub_type: "essence"
193
- },
194
- group_recall: {
195
- notice_type: "group",
196
- sub_type: "recall"
197
- }
198
- };
199
-
200
85
  //#endregion
201
86
  //#region src/napcat.ts
202
87
  const name = name$1;
@@ -214,6 +99,14 @@ var NapCat = class {
214
99
  #event = mitt();
215
100
  /** Echo 事件发射器 */
216
101
  #echoEvent = mitt();
102
+ /** 机器人 ID */
103
+ #uin = 0;
104
+ /** 机器人昵称 */
105
+ #nickname = "-";
106
+ /** 机器人状态 */
107
+ #online = false;
108
+ /** Cookies 缓存 */
109
+ #cookieCache = /* @__PURE__ */ new Map();
217
110
  constructor(options) {
218
111
  this.options = options;
219
112
  }
@@ -243,6 +136,24 @@ var NapCat = class {
243
136
  get segment() {
244
137
  return segment;
245
138
  }
139
+ /**
140
+ * 机器人 QQ 号
141
+ */
142
+ get user_id() {
143
+ return this.uin;
144
+ }
145
+ /**
146
+ * 机器人 QQ 号
147
+ */
148
+ get uin() {
149
+ return this.#uin;
150
+ }
151
+ /**
152
+ * 机器人昵称
153
+ */
154
+ get nickname() {
155
+ return this.#nickname;
156
+ }
246
157
  /** 生成唯一的 echo ID */
247
158
  #echoId() {
248
159
  return crypto.randomBytes(16).toString("hex");
@@ -279,9 +190,9 @@ var NapCat = class {
279
190
  type: "at",
280
191
  data: { qq: String(item.qq) }
281
192
  };
282
- const { type: type$1, ...data } = item;
193
+ const { type, ...data } = item;
283
194
  return {
284
- type: type$1,
195
+ type,
285
196
  data
286
197
  };
287
198
  });
@@ -305,6 +216,7 @@ var NapCat = class {
305
216
  ...extraInfo,
306
217
  group_id,
307
218
  group_name,
219
+ napcat: this,
308
220
  doSign: () => this.api("set_group_sign", { group_id }),
309
221
  getInfo: () => this.api("get_group_info", { group_id }),
310
222
  getMemberList: async () => this.api("get_group_member_list", { group_id }),
@@ -338,6 +250,7 @@ var NapCat = class {
338
250
  ...extraInfo,
339
251
  user_id,
340
252
  nickname,
253
+ napcat: this,
341
254
  delete: (block, both) => this.api("delete_friend", {
342
255
  user_id,
343
256
  temp_block: block,
@@ -347,24 +260,37 @@ var NapCat = class {
347
260
  getInfo: () => this.api("get_stranger_info", { user_id })
348
261
  };
349
262
  }
350
- /** 构建群消息事件 */
263
+ /** 构建私聊消息事件 */
351
264
  #buildPrivateMessageEvent(event) {
265
+ const quote_id = event.message.find((el) => el.type === "reply")?.data?.id || null;
352
266
  return {
353
267
  ...event,
354
- message: (event.message || []).map((el) => ({
268
+ quote_id,
269
+ getQuoteMessage: async () => {
270
+ if (!quote_id) return null;
271
+ const event$1 = await this.api("get_msg", { message_id: quote_id });
272
+ return this.#buildPrivateMessageEvent(event$1);
273
+ },
274
+ message: (event.message || []).filter((e) => e.type !== "reply").map((el) => ({
355
275
  type: el.type,
356
276
  ...el.data
357
277
  })),
358
278
  friend: this.#buildFriend(event.user_id, event.sender?.nickname || ""),
359
- recall: () => this.api("delete_msg", { message_id: event.message_id }),
360
279
  reply: (sendable, reply = false) => this.sendPrivateMsg(event.user_id, this.#wrapReply(sendable, event.message_id, reply))
361
280
  };
362
281
  }
363
282
  /** 构建群消息事件对象 */
364
283
  #buildGroupMessageEvent(event) {
284
+ const quote_id = event.message.find((el) => el.type === "reply")?.data?.id || null;
365
285
  return {
366
286
  ...event,
367
- message: (event.message || []).map((el) => ({
287
+ quote_id,
288
+ getQuoteMessage: async () => {
289
+ if (!quote_id) return null;
290
+ const event$1 = await this.api("get_msg", { message_id: quote_id });
291
+ return this.#buildGroupMessageEvent(event$1);
292
+ },
293
+ message: (event.message || []).filter((e) => e.type !== "reply").map((el) => ({
368
294
  type: el.type,
369
295
  ...el.data
370
296
  })),
@@ -398,7 +324,20 @@ var NapCat = class {
398
324
  this.#event.emit("meta_event", data);
399
325
  if (data.meta_event_type) {
400
326
  this.#event.emit(`meta_event.${data.meta_event_type}`, data);
401
- if (data.sub_type) this.#event.emit(`meta_event.${data.meta_event_type}.${data.sub_type}`, data);
327
+ if (data.sub_type) {
328
+ if (data.sub_type === "connect") {
329
+ this.#uin = data.self_id;
330
+ this.#online = true;
331
+ this.#event.emit("napcat.connected", {
332
+ uin: this.#uin,
333
+ ts: data.time * 1e3
334
+ });
335
+ this.getLoginInfo().then((info) => {
336
+ this.#nickname = info.nickname;
337
+ });
338
+ }
339
+ this.#event.emit(`meta_event.${data.meta_event_type}.${data.sub_type}`, data);
340
+ }
402
341
  }
403
342
  break;
404
343
  case "message":
@@ -494,24 +433,34 @@ var NapCat = class {
494
433
  }
495
434
  /** 获取一个群的信息,可以用于发送群消息等操作 */
496
435
  async pickGroup(group_id) {
497
- const groupInfo = await this.api("get_group_info", { group_id });
498
- return this.#buildGroup(group_id, groupInfo.group_name, groupInfo);
436
+ try {
437
+ const groupInfo = await this.api("get_group_info", { group_id });
438
+ return this.#buildGroup(group_id, groupInfo.group_name, groupInfo);
439
+ } catch (err) {
440
+ this.logger.warn(`Error to pickGroup ${group_id}: ${err?.message || err}`);
441
+ return null;
442
+ }
499
443
  }
500
444
  /** 获取一个好友的信息,可以用于发送私聊消息等操作 */
501
445
  async pickFriend(user_id) {
502
- const friendInfo = await this.api("get_stranger_info", { user_id });
503
- return this.#buildFriend(user_id, friendInfo.nickname, friendInfo);
446
+ try {
447
+ const friendInfo = await this.api("get_stranger_info", { user_id });
448
+ return this.#buildFriend(user_id, friendInfo.nickname, friendInfo);
449
+ } catch (err) {
450
+ this.logger.warn(`Error to pickFriend ${user_id}: ${err?.message || err}`);
451
+ return null;
452
+ }
504
453
  }
505
454
  /**
506
455
  * 注册一次性事件监听器
507
456
  */
508
- once(type$1, handler) {
457
+ once(type, handler) {
509
458
  const onceHandler = (event) => {
510
459
  handler(event);
511
- this.#event.off(type$1, onceHandler);
460
+ this.#event.off(type, onceHandler);
512
461
  };
513
- this.logger.debug(`registering once: ${String(type$1)}`);
514
- this.#event.on(type$1, onceHandler);
462
+ this.logger.debug(`registering once: ${String(type)}`);
463
+ this.#event.on(type, onceHandler);
515
464
  }
516
465
  /**
517
466
  * 注册事件监听器,支持主类型或者点分子类型
@@ -520,17 +469,20 @@ var NapCat = class {
520
469
  *
521
470
  * 如果需要移除监听器,请调用 `off` 方法
522
471
  */
523
- on(type$1, handler) {
524
- this.logger.debug(`registering: ${String(type$1)}`);
525
- this.#event.on(type$1, handler);
472
+ on(type, handler) {
473
+ this.logger.debug(`registering: ${String(type)}`);
474
+ this.#event.on(type, handler);
526
475
  }
527
476
  /**
528
477
  * 移除事件监听器
529
478
  */
530
- off(type$1, handler) {
531
- this.logger.debug(`unregistering: ${String(type$1)}`);
532
- this.#event.off(type$1, handler);
479
+ off(type, handler) {
480
+ this.logger.debug(`unregistering: ${String(type)}`);
481
+ this.#event.off(type, handler);
533
482
  }
483
+ /**
484
+ * 调用 NapCat API
485
+ */
534
486
  api(action, params = {}) {
535
487
  this.#ensureWsConnection(this.#ws);
536
488
  this.logger.debug(`calling api action: ${action} with params: ${JSON.stringify(params)}`);
@@ -560,10 +512,81 @@ var NapCat = class {
560
512
  message: this.#normalizeSendable(sendable)
561
513
  });
562
514
  }
515
+ /**
516
+ * 机器人是否在线
517
+ */
518
+ isOnline() {
519
+ return this.#ws?.readyState === WebSocket.OPEN && this.#online;
520
+ }
521
+ /**
522
+ * 计算 GTK 值
523
+ */
524
+ getGTk(pskey) {
525
+ let gkt = 5381;
526
+ for (let i = 0, len = pskey.length; i < len; ++i) gkt += (gkt << 5) + pskey.charCodeAt(i);
527
+ return gkt & 2147483647;
528
+ }
529
+ /**
530
+ * 获取 NapCat 原始 Cookie 相关信息
531
+ */
532
+ getNapCatCookies(domain) {
533
+ return this.api("get_cookies", { domain });
534
+ }
535
+ /**
536
+ * 获取版本信息
537
+ */
538
+ getVersionInfo() {
539
+ return this.api("get_version_info");
540
+ }
541
+ /**
542
+ * 获取登录信息
543
+ */
544
+ getLoginInfo() {
545
+ return this.api("get_login_info");
546
+ }
547
+ /**
548
+ * 获取 Cookie 相关信息
549
+ */
550
+ async getCookie(domain) {
551
+ const cache = this.#cookieCache.get(domain);
552
+ if (cache) return cache;
553
+ const { cookies: cookieString, bkn } = await this.getNapCatCookies(domain);
554
+ const skey = cookieString.match(/skey=([^;]*)/)?.[1] || "";
555
+ const pskey = cookieString.match(/pskey=([^;]*)/)?.[1] || "";
556
+ const gtk = this.getGTk(pskey);
557
+ const returns = {
558
+ pskey,
559
+ skey,
560
+ uin: this.uin,
561
+ gtk: String(gtk),
562
+ bkn,
563
+ cookie: `uin=${this.uin}; skey=${skey}; p_uin=${this.uin}; p_skey=${pskey};`,
564
+ legacyCookie: `uin=o${this.uin}; skey=${skey}; p_uin=o${this.uin}; p_skey=${pskey};`
565
+ };
566
+ this.#cookieCache.set(domain, returns);
567
+ setTimeout(() => {
568
+ this.#cookieCache.delete(domain);
569
+ }, 1e3 * 60 * 60);
570
+ return returns;
571
+ }
572
+ /**
573
+ * 通过域名获取 Pskey
574
+ */
575
+ async getPskey(domain) {
576
+ const { pskey } = await this.getCookie(domain);
577
+ return pskey;
578
+ }
579
+ /**
580
+ * 获取 Bkn 值
581
+ */
582
+ async getBkn() {
583
+ const { bkn } = await this.getCookie("vip.qq.com");
584
+ return bkn;
585
+ }
563
586
  /** 启动 NapCat SDK 实例,建立 WebSocket 连接 */
564
- async bootstrap() {
565
- const { logger: _, ...config } = this.#config;
566
- this.logger.info(`bootstrap with config: ${JSON.stringify(config)}`);
587
+ async run() {
588
+ const { logger: _, token: __, ...config } = this.#config;
589
+ this.logger.info(`run with config: ${JSON.stringify(config)}`);
567
590
  return new Promise((resolve, reject) => {
568
591
  const ws = new WebSocket(this.#buildWsUrl());
569
592
  ws.onmessage = (event) => {
@@ -582,16 +605,18 @@ var NapCat = class {
582
605
  this.#bindInternalEvents(data);
583
606
  };
584
607
  ws.onclose = () => {
608
+ this.#online = false;
585
609
  this.logger.info("closed");
586
610
  this.#event.emit("ws.close");
587
611
  };
588
612
  ws.onerror = (error) => {
613
+ this.#online = false;
589
614
  this.logger.error(`error: ${error}`);
590
615
  this.#event.emit("ws.error", error);
591
616
  reject(error);
592
617
  };
593
618
  ws.onopen = () => {
594
- this.logger.info("connected");
619
+ this.logger.info("NapCat connected");
595
620
  this.#event.emit("ws.open");
596
621
  resolve();
597
622
  };
@@ -600,7 +625,7 @@ var NapCat = class {
600
625
  });
601
626
  }
602
627
  /** 销毁 NapCat SDK 实例,关闭 WebSocket 连接 */
603
- async destroy() {
628
+ close() {
604
629
  if (this.#ws) {
605
630
  this.logger.info("destroying NapCat SDK instance...");
606
631
  this.#ws.close();
@@ -609,7 +634,83 @@ var NapCat = class {
609
634
  } else this.logger.warn("NapCat SDK instance is not initialized.");
610
635
  }
611
636
  };
637
+ /**
638
+ * NapCat 通知类型映射表(notify 类型)
639
+ * @description 将 NapCat 特有的通知类型映射到标准的 notice_type 和 sub_type
640
+ */
641
+ const NAPCAT_NOTICE_NOTIFY_MAP = {
642
+ input_status: {
643
+ notice_type: "friend",
644
+ sub_type: "input"
645
+ },
646
+ profile_like: {
647
+ notice_type: "friend",
648
+ sub_type: "like"
649
+ },
650
+ title: {
651
+ notice_type: "group",
652
+ sub_type: "title"
653
+ }
654
+ };
655
+ /**
656
+ * NapCat 通知事件映射表(notice 类型)
657
+ * @description 将 NapCat 的原始通知事件类型映射到标准的 notice_type 和 sub_type
658
+ */
659
+ const NAPCAT_NOTICE_EVENT_MAP = {
660
+ friend_add: {
661
+ notice_type: "friend",
662
+ sub_type: "increase"
663
+ },
664
+ friend_recall: {
665
+ notice_type: "friend",
666
+ sub_type: "recall"
667
+ },
668
+ offline_file: {
669
+ notice_type: "friend",
670
+ sub_type: "offline_file"
671
+ },
672
+ client_status: {
673
+ notice_type: "client",
674
+ sub_type: "status"
675
+ },
676
+ group_admin: {
677
+ notice_type: "group",
678
+ sub_type: "admin"
679
+ },
680
+ group_ban: {
681
+ notice_type: "group",
682
+ sub_type: "ban"
683
+ },
684
+ group_card: {
685
+ notice_type: "group",
686
+ sub_type: "card"
687
+ },
688
+ group_upload: {
689
+ notice_type: "group",
690
+ sub_type: "upload"
691
+ },
692
+ group_decrease: {
693
+ notice_type: "group",
694
+ sub_type: "decrease"
695
+ },
696
+ group_increase: {
697
+ notice_type: "group",
698
+ sub_type: "increase"
699
+ },
700
+ group_msg_emoji_like: {
701
+ notice_type: "group",
702
+ sub_type: "reaction"
703
+ },
704
+ essence: {
705
+ notice_type: "group",
706
+ sub_type: "essence"
707
+ },
708
+ group_recall: {
709
+ notice_type: "group",
710
+ sub_type: "recall"
711
+ }
712
+ };
612
713
 
613
714
  //#endregion
614
- export { ABSTRACT_LOGGER, CONSOLE_LOGGER, DEFAULT_NAPCAT_OPTIONS, NapCat, package_default as PKG, name, segment, version };
715
+ export { ABSTRACT_LOGGER, CONSOLE_LOGGER, NapCat, name, noop, segment, version };
615
716
  //# sourceMappingURL=index.mjs.map