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.cjs CHANGED
@@ -30,56 +30,35 @@ node_crypto = __toESM(node_crypto);
30
30
  let mitt = require("mitt");
31
31
  mitt = __toESM(mitt);
32
32
 
33
+ //#region src/logger.ts
34
+ const noop = () => {};
35
+ const ABSTRACT_LOGGER = {
36
+ fatal: noop,
37
+ error: noop,
38
+ warn: noop,
39
+ info: noop,
40
+ debug: noop,
41
+ trace: noop
42
+ };
43
+ const CONSOLE_LOGGER = {
44
+ fatal: console.error.bind(console, "[FATAL]"),
45
+ error: console.error.bind(console, "[ERROR]"),
46
+ warn: console.warn.bind(console, "[WARN]"),
47
+ info: console.info.bind(console, "[INFO]"),
48
+ debug: console.debug.bind(console, "[DEBUG]"),
49
+ trace: console.trace.bind(console, "[TRACE]")
50
+ };
51
+
52
+ //#endregion
33
53
  //#region package.json
34
54
  var name$1 = "napcat-sdk";
35
- var version$1 = "0.1.1";
36
- var package_default = {
37
- name: name$1,
38
- type: "module",
39
- version: version$1,
40
- packageManager: "pnpm@10.26.0",
41
- description: "A simple SDK for NapCat OneBot v11.",
42
- keywords: [
43
- "napcat",
44
- "onebot",
45
- "onebot v11",
46
- "sdk"
47
- ],
48
- homepage: "https://github.com/vikiboss/mioki#readme",
49
- files: ["dist"],
50
- bugs: { "url": "https://github.com/vikiboss/mioki/issues" },
51
- repository: {
52
- "type": "git",
53
- "url": "git+https://github.com/vikiboss/mioki.git",
54
- "directory": "packages/napcat-sdk"
55
- },
56
- scripts: {
57
- "dev": "tsdown -w",
58
- "build": "tsdown"
59
- },
60
- exports: {
61
- ".": {
62
- "require": "./dist/index.cjs",
63
- "import": "./dist/index.mjs",
64
- "types": "./dist/index.d.ts"
65
- },
66
- "./package.json": "./package.json"
67
- },
68
- author: "Viki <hi@viki.moe> (https://github.com/vikiboss)",
69
- license: "MIT",
70
- devDependencies: {
71
- "@types/node": "catalog:dev",
72
- "tsdown": "catalog:dev",
73
- "typescript": "catalog:dev"
74
- },
75
- dependencies: { "mitt": "^3.0.1" }
76
- };
55
+ var version$1 = "0.2.0";
77
56
 
78
57
  //#endregion
79
58
  //#region src/segment.ts
80
- function createSegment(type$1, data) {
59
+ function createSegment(type, data) {
81
60
  return {
82
- type: type$1,
61
+ type,
83
62
  ...data
84
63
  };
85
64
  }
@@ -105,9 +84,9 @@ const segment = {
105
84
  }),
106
85
  mface: (options) => createSegment("mface", { ...options }),
107
86
  bface: (id) => createSegment("bface", { id }),
108
- contact: (type$1, id) => createSegment("contact", {
87
+ contact: (type, id) => createSegment("contact", {
109
88
  id,
110
- sub_type: type$1
89
+ sub_type: type
111
90
  }),
112
91
  poke: () => createSegment("poke", {}),
113
92
  music: (platform, id) => createSegment("music", {
@@ -121,6 +100,7 @@ const segment = {
121
100
  title,
122
101
  ...options
123
102
  }),
103
+ node: (options) => createSegment("node", { ...options }),
124
104
  forward: (id) => createSegment("forward", { id }),
125
105
  json: (data) => createSegment("json", { data }),
126
106
  file: (file, options) => createSegment("file", {
@@ -131,101 +111,6 @@ const segment = {
131
111
  lightapp: () => createSegment("lightapp", {})
132
112
  };
133
113
 
134
- //#endregion
135
- //#region src/logger.ts
136
- const LOG_LEVEL_KEYS = Object.keys({
137
- fatal: 0,
138
- error: 1,
139
- warn: 2,
140
- info: 3,
141
- debug: 4,
142
- trace: 5
143
- });
144
- const noop = () => {};
145
- const ABSTRACT_LOGGER = Object.fromEntries(LOG_LEVEL_KEYS.map((level) => [level, noop]));
146
- const CONSOLE_LOGGER = Object.fromEntries(LOG_LEVEL_KEYS.map((level) => [level, (...args) => {
147
- console[level === "fatal" ? "error" : level === "trace" ? "debug" : level](...args);
148
- }]));
149
-
150
- //#endregion
151
- //#region src/onebot.ts
152
- /**
153
- * NapCat 通知类型映射表(notify 类型)
154
- * @description 将 NapCat 特有的通知类型映射到标准的 notice_type 和 sub_type
155
- */
156
- const NAPCAT_NOTICE_NOTIFY_MAP = {
157
- input_status: {
158
- notice_type: "friend",
159
- sub_type: "input"
160
- },
161
- profile_like: {
162
- notice_type: "friend",
163
- sub_type: "like"
164
- },
165
- title: {
166
- notice_type: "group",
167
- sub_type: "title"
168
- }
169
- };
170
- /**
171
- * NapCat 通知事件映射表(notice 类型)
172
- * @description 将 NapCat 的原始通知事件类型映射到标准的 notice_type 和 sub_type
173
- */
174
- const NAPCAT_NOTICE_EVENT_MAP = {
175
- friend_add: {
176
- notice_type: "friend",
177
- sub_type: "increase"
178
- },
179
- friend_recall: {
180
- notice_type: "friend",
181
- sub_type: "recall"
182
- },
183
- offline_file: {
184
- notice_type: "friend",
185
- sub_type: "offline_file"
186
- },
187
- client_status: {
188
- notice_type: "client",
189
- sub_type: "status"
190
- },
191
- group_admin: {
192
- notice_type: "group",
193
- sub_type: "admin"
194
- },
195
- group_ban: {
196
- notice_type: "group",
197
- sub_type: "ban"
198
- },
199
- group_card: {
200
- notice_type: "group",
201
- sub_type: "card"
202
- },
203
- group_upload: {
204
- notice_type: "group",
205
- sub_type: "upload"
206
- },
207
- group_decrease: {
208
- notice_type: "group",
209
- sub_type: "decrease"
210
- },
211
- group_increase: {
212
- notice_type: "group",
213
- sub_type: "increase"
214
- },
215
- group_msg_emoji_like: {
216
- notice_type: "group",
217
- sub_type: "reaction"
218
- },
219
- essence: {
220
- notice_type: "group",
221
- sub_type: "essence"
222
- },
223
- group_recall: {
224
- notice_type: "group",
225
- sub_type: "recall"
226
- }
227
- };
228
-
229
114
  //#endregion
230
115
  //#region src/napcat.ts
231
116
  const name = name$1;
@@ -243,6 +128,14 @@ var NapCat = class {
243
128
  #event = (0, mitt.default)();
244
129
  /** Echo 事件发射器 */
245
130
  #echoEvent = (0, mitt.default)();
131
+ /** 机器人 ID */
132
+ #uin = 0;
133
+ /** 机器人昵称 */
134
+ #nickname = "-";
135
+ /** 机器人状态 */
136
+ #online = false;
137
+ /** Cookies 缓存 */
138
+ #cookieCache = /* @__PURE__ */ new Map();
246
139
  constructor(options) {
247
140
  this.options = options;
248
141
  }
@@ -272,6 +165,24 @@ var NapCat = class {
272
165
  get segment() {
273
166
  return segment;
274
167
  }
168
+ /**
169
+ * 机器人 QQ 号
170
+ */
171
+ get user_id() {
172
+ return this.uin;
173
+ }
174
+ /**
175
+ * 机器人 QQ 号
176
+ */
177
+ get uin() {
178
+ return this.#uin;
179
+ }
180
+ /**
181
+ * 机器人昵称
182
+ */
183
+ get nickname() {
184
+ return this.#nickname;
185
+ }
275
186
  /** 生成唯一的 echo ID */
276
187
  #echoId() {
277
188
  return node_crypto.default.randomBytes(16).toString("hex");
@@ -308,9 +219,9 @@ var NapCat = class {
308
219
  type: "at",
309
220
  data: { qq: String(item.qq) }
310
221
  };
311
- const { type: type$1, ...data } = item;
222
+ const { type, ...data } = item;
312
223
  return {
313
- type: type$1,
224
+ type,
314
225
  data
315
226
  };
316
227
  });
@@ -334,6 +245,7 @@ var NapCat = class {
334
245
  ...extraInfo,
335
246
  group_id,
336
247
  group_name,
248
+ napcat: this,
337
249
  doSign: () => this.api("set_group_sign", { group_id }),
338
250
  getInfo: () => this.api("get_group_info", { group_id }),
339
251
  getMemberList: async () => this.api("get_group_member_list", { group_id }),
@@ -367,6 +279,7 @@ var NapCat = class {
367
279
  ...extraInfo,
368
280
  user_id,
369
281
  nickname,
282
+ napcat: this,
370
283
  delete: (block, both) => this.api("delete_friend", {
371
284
  user_id,
372
285
  temp_block: block,
@@ -376,24 +289,37 @@ var NapCat = class {
376
289
  getInfo: () => this.api("get_stranger_info", { user_id })
377
290
  };
378
291
  }
379
- /** 构建群消息事件 */
292
+ /** 构建私聊消息事件 */
380
293
  #buildPrivateMessageEvent(event) {
294
+ const quote_id = event.message.find((el) => el.type === "reply")?.data?.id || null;
381
295
  return {
382
296
  ...event,
383
- message: (event.message || []).map((el) => ({
297
+ quote_id,
298
+ getQuoteMessage: async () => {
299
+ if (!quote_id) return null;
300
+ const event$1 = await this.api("get_msg", { message_id: quote_id });
301
+ return this.#buildPrivateMessageEvent(event$1);
302
+ },
303
+ message: (event.message || []).filter((e) => e.type !== "reply").map((el) => ({
384
304
  type: el.type,
385
305
  ...el.data
386
306
  })),
387
307
  friend: this.#buildFriend(event.user_id, event.sender?.nickname || ""),
388
- recall: () => this.api("delete_msg", { message_id: event.message_id }),
389
308
  reply: (sendable, reply = false) => this.sendPrivateMsg(event.user_id, this.#wrapReply(sendable, event.message_id, reply))
390
309
  };
391
310
  }
392
311
  /** 构建群消息事件对象 */
393
312
  #buildGroupMessageEvent(event) {
313
+ const quote_id = event.message.find((el) => el.type === "reply")?.data?.id || null;
394
314
  return {
395
315
  ...event,
396
- message: (event.message || []).map((el) => ({
316
+ quote_id,
317
+ getQuoteMessage: async () => {
318
+ if (!quote_id) return null;
319
+ const event$1 = await this.api("get_msg", { message_id: quote_id });
320
+ return this.#buildGroupMessageEvent(event$1);
321
+ },
322
+ message: (event.message || []).filter((e) => e.type !== "reply").map((el) => ({
397
323
  type: el.type,
398
324
  ...el.data
399
325
  })),
@@ -427,7 +353,20 @@ var NapCat = class {
427
353
  this.#event.emit("meta_event", data);
428
354
  if (data.meta_event_type) {
429
355
  this.#event.emit(`meta_event.${data.meta_event_type}`, data);
430
- if (data.sub_type) this.#event.emit(`meta_event.${data.meta_event_type}.${data.sub_type}`, data);
356
+ if (data.sub_type) {
357
+ if (data.sub_type === "connect") {
358
+ this.#uin = data.self_id;
359
+ this.#online = true;
360
+ this.#event.emit("napcat.connected", {
361
+ uin: this.#uin,
362
+ ts: data.time * 1e3
363
+ });
364
+ this.getLoginInfo().then((info) => {
365
+ this.#nickname = info.nickname;
366
+ });
367
+ }
368
+ this.#event.emit(`meta_event.${data.meta_event_type}.${data.sub_type}`, data);
369
+ }
431
370
  }
432
371
  break;
433
372
  case "message":
@@ -523,24 +462,34 @@ var NapCat = class {
523
462
  }
524
463
  /** 获取一个群的信息,可以用于发送群消息等操作 */
525
464
  async pickGroup(group_id) {
526
- const groupInfo = await this.api("get_group_info", { group_id });
527
- return this.#buildGroup(group_id, groupInfo.group_name, groupInfo);
465
+ try {
466
+ const groupInfo = await this.api("get_group_info", { group_id });
467
+ return this.#buildGroup(group_id, groupInfo.group_name, groupInfo);
468
+ } catch (err) {
469
+ this.logger.warn(`Error to pickGroup ${group_id}: ${err?.message || err}`);
470
+ return null;
471
+ }
528
472
  }
529
473
  /** 获取一个好友的信息,可以用于发送私聊消息等操作 */
530
474
  async pickFriend(user_id) {
531
- const friendInfo = await this.api("get_stranger_info", { user_id });
532
- return this.#buildFriend(user_id, friendInfo.nickname, friendInfo);
475
+ try {
476
+ const friendInfo = await this.api("get_stranger_info", { user_id });
477
+ return this.#buildFriend(user_id, friendInfo.nickname, friendInfo);
478
+ } catch (err) {
479
+ this.logger.warn(`Error to pickFriend ${user_id}: ${err?.message || err}`);
480
+ return null;
481
+ }
533
482
  }
534
483
  /**
535
484
  * 注册一次性事件监听器
536
485
  */
537
- once(type$1, handler) {
486
+ once(type, handler) {
538
487
  const onceHandler = (event) => {
539
488
  handler(event);
540
- this.#event.off(type$1, onceHandler);
489
+ this.#event.off(type, onceHandler);
541
490
  };
542
- this.logger.debug(`registering once: ${String(type$1)}`);
543
- this.#event.on(type$1, onceHandler);
491
+ this.logger.debug(`registering once: ${String(type)}`);
492
+ this.#event.on(type, onceHandler);
544
493
  }
545
494
  /**
546
495
  * 注册事件监听器,支持主类型或者点分子类型
@@ -549,17 +498,20 @@ var NapCat = class {
549
498
  *
550
499
  * 如果需要移除监听器,请调用 `off` 方法
551
500
  */
552
- on(type$1, handler) {
553
- this.logger.debug(`registering: ${String(type$1)}`);
554
- this.#event.on(type$1, handler);
501
+ on(type, handler) {
502
+ this.logger.debug(`registering: ${String(type)}`);
503
+ this.#event.on(type, handler);
555
504
  }
556
505
  /**
557
506
  * 移除事件监听器
558
507
  */
559
- off(type$1, handler) {
560
- this.logger.debug(`unregistering: ${String(type$1)}`);
561
- this.#event.off(type$1, handler);
508
+ off(type, handler) {
509
+ this.logger.debug(`unregistering: ${String(type)}`);
510
+ this.#event.off(type, handler);
562
511
  }
512
+ /**
513
+ * 调用 NapCat API
514
+ */
563
515
  api(action, params = {}) {
564
516
  this.#ensureWsConnection(this.#ws);
565
517
  this.logger.debug(`calling api action: ${action} with params: ${JSON.stringify(params)}`);
@@ -589,10 +541,81 @@ var NapCat = class {
589
541
  message: this.#normalizeSendable(sendable)
590
542
  });
591
543
  }
544
+ /**
545
+ * 机器人是否在线
546
+ */
547
+ isOnline() {
548
+ return this.#ws?.readyState === WebSocket.OPEN && this.#online;
549
+ }
550
+ /**
551
+ * 计算 GTK 值
552
+ */
553
+ getGTk(pskey) {
554
+ let gkt = 5381;
555
+ for (let i = 0, len = pskey.length; i < len; ++i) gkt += (gkt << 5) + pskey.charCodeAt(i);
556
+ return gkt & 2147483647;
557
+ }
558
+ /**
559
+ * 获取 NapCat 原始 Cookie 相关信息
560
+ */
561
+ getNapCatCookies(domain) {
562
+ return this.api("get_cookies", { domain });
563
+ }
564
+ /**
565
+ * 获取版本信息
566
+ */
567
+ getVersionInfo() {
568
+ return this.api("get_version_info");
569
+ }
570
+ /**
571
+ * 获取登录信息
572
+ */
573
+ getLoginInfo() {
574
+ return this.api("get_login_info");
575
+ }
576
+ /**
577
+ * 获取 Cookie 相关信息
578
+ */
579
+ async getCookie(domain) {
580
+ const cache = this.#cookieCache.get(domain);
581
+ if (cache) return cache;
582
+ const { cookies: cookieString, bkn } = await this.getNapCatCookies(domain);
583
+ const skey = cookieString.match(/skey=([^;]*)/)?.[1] || "";
584
+ const pskey = cookieString.match(/pskey=([^;]*)/)?.[1] || "";
585
+ const gtk = this.getGTk(pskey);
586
+ const returns = {
587
+ pskey,
588
+ skey,
589
+ uin: this.uin,
590
+ gtk: String(gtk),
591
+ bkn,
592
+ cookie: `uin=${this.uin}; skey=${skey}; p_uin=${this.uin}; p_skey=${pskey};`,
593
+ legacyCookie: `uin=o${this.uin}; skey=${skey}; p_uin=o${this.uin}; p_skey=${pskey};`
594
+ };
595
+ this.#cookieCache.set(domain, returns);
596
+ setTimeout(() => {
597
+ this.#cookieCache.delete(domain);
598
+ }, 1e3 * 60 * 60);
599
+ return returns;
600
+ }
601
+ /**
602
+ * 通过域名获取 Pskey
603
+ */
604
+ async getPskey(domain) {
605
+ const { pskey } = await this.getCookie(domain);
606
+ return pskey;
607
+ }
608
+ /**
609
+ * 获取 Bkn 值
610
+ */
611
+ async getBkn() {
612
+ const { bkn } = await this.getCookie("vip.qq.com");
613
+ return bkn;
614
+ }
592
615
  /** 启动 NapCat SDK 实例,建立 WebSocket 连接 */
593
- async bootstrap() {
594
- const { logger: _, ...config } = this.#config;
595
- this.logger.info(`bootstrap with config: ${JSON.stringify(config)}`);
616
+ async run() {
617
+ const { logger: _, token: __, ...config } = this.#config;
618
+ this.logger.info(`run with config: ${JSON.stringify(config)}`);
596
619
  return new Promise((resolve, reject) => {
597
620
  const ws = new WebSocket(this.#buildWsUrl());
598
621
  ws.onmessage = (event) => {
@@ -611,16 +634,18 @@ var NapCat = class {
611
634
  this.#bindInternalEvents(data);
612
635
  };
613
636
  ws.onclose = () => {
637
+ this.#online = false;
614
638
  this.logger.info("closed");
615
639
  this.#event.emit("ws.close");
616
640
  };
617
641
  ws.onerror = (error) => {
642
+ this.#online = false;
618
643
  this.logger.error(`error: ${error}`);
619
644
  this.#event.emit("ws.error", error);
620
645
  reject(error);
621
646
  };
622
647
  ws.onopen = () => {
623
- this.logger.info("connected");
648
+ this.logger.info("NapCat connected");
624
649
  this.#event.emit("ws.open");
625
650
  resolve();
626
651
  };
@@ -629,7 +654,7 @@ var NapCat = class {
629
654
  });
630
655
  }
631
656
  /** 销毁 NapCat SDK 实例,关闭 WebSocket 连接 */
632
- async destroy() {
657
+ close() {
633
658
  if (this.#ws) {
634
659
  this.logger.info("destroying NapCat SDK instance...");
635
660
  this.#ws.close();
@@ -638,19 +663,89 @@ var NapCat = class {
638
663
  } else this.logger.warn("NapCat SDK instance is not initialized.");
639
664
  }
640
665
  };
666
+ /**
667
+ * NapCat 通知类型映射表(notify 类型)
668
+ * @description 将 NapCat 特有的通知类型映射到标准的 notice_type 和 sub_type
669
+ */
670
+ const NAPCAT_NOTICE_NOTIFY_MAP = {
671
+ input_status: {
672
+ notice_type: "friend",
673
+ sub_type: "input"
674
+ },
675
+ profile_like: {
676
+ notice_type: "friend",
677
+ sub_type: "like"
678
+ },
679
+ title: {
680
+ notice_type: "group",
681
+ sub_type: "title"
682
+ }
683
+ };
684
+ /**
685
+ * NapCat 通知事件映射表(notice 类型)
686
+ * @description 将 NapCat 的原始通知事件类型映射到标准的 notice_type 和 sub_type
687
+ */
688
+ const NAPCAT_NOTICE_EVENT_MAP = {
689
+ friend_add: {
690
+ notice_type: "friend",
691
+ sub_type: "increase"
692
+ },
693
+ friend_recall: {
694
+ notice_type: "friend",
695
+ sub_type: "recall"
696
+ },
697
+ offline_file: {
698
+ notice_type: "friend",
699
+ sub_type: "offline_file"
700
+ },
701
+ client_status: {
702
+ notice_type: "client",
703
+ sub_type: "status"
704
+ },
705
+ group_admin: {
706
+ notice_type: "group",
707
+ sub_type: "admin"
708
+ },
709
+ group_ban: {
710
+ notice_type: "group",
711
+ sub_type: "ban"
712
+ },
713
+ group_card: {
714
+ notice_type: "group",
715
+ sub_type: "card"
716
+ },
717
+ group_upload: {
718
+ notice_type: "group",
719
+ sub_type: "upload"
720
+ },
721
+ group_decrease: {
722
+ notice_type: "group",
723
+ sub_type: "decrease"
724
+ },
725
+ group_increase: {
726
+ notice_type: "group",
727
+ sub_type: "increase"
728
+ },
729
+ group_msg_emoji_like: {
730
+ notice_type: "group",
731
+ sub_type: "reaction"
732
+ },
733
+ essence: {
734
+ notice_type: "group",
735
+ sub_type: "essence"
736
+ },
737
+ group_recall: {
738
+ notice_type: "group",
739
+ sub_type: "recall"
740
+ }
741
+ };
641
742
 
642
743
  //#endregion
643
744
  exports.ABSTRACT_LOGGER = ABSTRACT_LOGGER;
644
745
  exports.CONSOLE_LOGGER = CONSOLE_LOGGER;
645
- exports.DEFAULT_NAPCAT_OPTIONS = DEFAULT_NAPCAT_OPTIONS;
646
746
  exports.NapCat = NapCat;
647
- Object.defineProperty(exports, 'PKG', {
648
- enumerable: true,
649
- get: function () {
650
- return package_default;
651
- }
652
- });
653
747
  exports.name = name;
748
+ exports.noop = noop;
654
749
  exports.segment = segment;
655
750
  exports.version = version;
656
751
  //# sourceMappingURL=index.cjs.map