mirai-js 2.8.0 → 2.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -93,8 +93,8 @@ export class Bot implements BotConfigGetable {
93
93
  * @param callback 必选,回调函数
94
94
  * @returns handle 事件处理器的标识,用于移除该处理器
95
95
  */
96
- on<U extends EventType>(eventType: U, callback: Processor<[U]>): number;
97
- on<U extends EventType[]>(eventType: U, callback: Processor<U>): number[];
96
+ on<U extends EventType, E>(eventType: U, callback: Processor<[U], E>): number;
97
+ on<U extends EventType[], E>(eventType: U, callback: Processor<U, E>): number[];
98
98
 
99
99
  /**
100
100
  * @description 添加一个一次性事件处理器,回调一次后自动移除
@@ -298,6 +298,14 @@ export class Bot implements BotConfigGetable {
298
298
  */
299
299
  sendCommand({ command }: Bot.SendCommandOptions): Promise<Bot.MiraiConsoleMessage>;
300
300
 
301
+ /**
302
+ * @description 通过 messageId 获取消息
303
+ * @param {number} target 可选, 目标 qq 号/群号, mah v2.6.0+ 新增该参数
304
+ * @param {number} messageId 必选, 消息 id
305
+ * @returns
306
+ */
307
+ getMessageById({ messageId, target }: Bot.GetMessageByIdOptions): Promise<Bot.MessageFromMessageId>
308
+
301
309
  // 类方法
302
310
  /**
303
311
  * @description 检测该账号是否已经在 mirai-console 登录
@@ -532,6 +540,21 @@ declare namespace Bot {
532
540
  command: string[];
533
541
  }
534
542
 
543
+ interface GetMessageByIdOptions {
544
+ messageId: number;
545
+ target?: number;
546
+ }
547
+
548
+ interface MessageFromMessageId {
549
+ type: 'FriendMessage' | 'GroupMessage' | 'TempMessage';
550
+ messageChain: MessageType[];
551
+ sender: {
552
+ id?: number;
553
+ nickname?: string;
554
+ remark?: string;
555
+ }
556
+ }
557
+
535
558
  interface IsBotLoggedInOptions {
536
559
  baseUrl: string;
537
560
  verifyKey: string;
package/dist/node/Bot.js CHANGED
@@ -67,6 +67,8 @@ const _setGroupConfig = require('./core/setGroupConfig');
67
67
 
68
68
  const _setEssence = require('./core/setEssence');
69
69
 
70
+ const _messageFromId = require('./core/messageFromId');
71
+
70
72
  const {
71
73
  wsStartListening: _startListening,
72
74
  wsStopListening: _stopListening
@@ -1603,6 +1605,39 @@ class Bot extends BotConfigGetable {
1603
1605
  }).reduce((acc, cur) => acc.addText(cur), new Message()).messageChain
1604
1606
  });
1605
1607
  }
1608
+ /**
1609
+ * @description 通过 messageId 获取消息
1610
+ * @param {number} target 可选, 目标 qq 号/群号, mah v2.6.0+ 新增该参数
1611
+ * @param {number} messageId 必选, 消息 id
1612
+ * @returns {Object} 结构 { type, messageChain, sender }
1613
+ */
1614
+
1615
+
1616
+ async getMessageById({
1617
+ messageId,
1618
+ target
1619
+ }) {
1620
+ // 检查对象状态
1621
+ if (!this.config) {
1622
+ throw new Error('getMessageById 请先调用 open,建立一个会话');
1623
+ } // 检查参数
1624
+
1625
+
1626
+ if (!messageId) {
1627
+ throw new Error('getMessageById 缺少必要的 messageId 参数');
1628
+ }
1629
+
1630
+ const {
1631
+ baseUrl,
1632
+ sessionKey
1633
+ } = this.config;
1634
+ return await _messageFromId({
1635
+ baseUrl,
1636
+ sessionKey,
1637
+ target,
1638
+ messageId
1639
+ });
1640
+ }
1606
1641
  /**
1607
1642
  * @description 检测该账号是否已经在 mirai-console 登录
1608
1643
  * @param {string} baseUrl 必选,mirai-api-http server 的地址
@@ -1,7 +1,8 @@
1
- import { Processor, EventType } from './BaseType';
1
+ import { Processor, EventType, MessageChainElementTypes, MessageType } from './BaseType';
2
2
  import { Bot } from './Bot';
3
+ import { ArrayToValuesUnion } from './typeHelpers';
3
4
 
4
- export class Middleware {
5
+ export class Middleware<CTX = { [key: string]: any }> {
5
6
  private middleware: ((data: any, next: Middleware.NextMiddlewareCaller) => any)[];
6
7
  private catcher: (error: any) => any;
7
8
 
@@ -12,44 +13,44 @@ export class Middleware {
12
13
  * @param verifyKey mirai-api-http server 设置的 verifyKey
13
14
  * @param password 欲重新登陆的 qq 密码
14
15
  */
15
- autoReLogin({ bot, baseUrl, verifyKey, password }: Middleware.AutoReLoginOptions): Middleware;
16
+ autoReLogin({ bot, baseUrl, verifyKey, password }: Middleware.AutoReLoginOptions): Middleware<CTX>;
16
17
 
17
18
  /**
18
19
  * @description 自动重建 ws 连接
19
20
  * @param bot 欲重连的 Bot 实例
20
21
  */
21
- autoReconnection(bot: Bot): Middleware;
22
+ autoReconnection(bot: Bot): Middleware<CTX>;
22
23
 
23
24
  /**
24
25
  * @description 过滤出指定类型的消息,消息类型为 key,对应类型的
25
26
  * message 数组为 value,置于 data.classified
26
27
  * @param typeArr message 的类型,例如 Plain Image Voice
27
28
  */
28
- messageProcessor(typeArr: string[]): Middleware;
29
+ messageProcessor<U extends MessageChainElementTypes[]>(typeArr: U): Middleware<CTX & { classified: { [type in ArrayToValuesUnion<U>]: any[] } }>;
29
30
 
30
31
  /**
31
32
  * @description 过滤出字符串类型的 message,并拼接在一起,置于 data.text
32
33
  */
33
- textProcessor(): Middleware;
34
+ textProcessor(): Middleware<CTX & { text: string }>;
34
35
 
35
36
  /**
36
37
  * @description 过滤出消息 id,置于 data.messageId
37
38
  */
38
- messageIdProcessor(): Middleware;
39
+ messageIdProcessor(): Middleware<CTX & { messageId: string }>;
39
40
 
40
41
  /**
41
42
  * @description 过滤指定的群消息
42
43
  * @param groupArr 允许通过的群号数组
43
44
  * @param allow 允许通过还是禁止通过
44
45
  */
45
- groupFilter(groupArr: number[], allow?: boolean): Middleware;
46
+ groupFilter(groupArr: number[], allow?: boolean): Middleware<CTX>;
46
47
 
47
48
  /**
48
49
  * @description 过滤指定的好友消息
49
50
  * @param friendArr 好友 qq 号数组
50
51
  * @param allow 允许通过还是禁止通过
51
52
  */
52
- friendFilter(friendArr: number[], allow?: boolean): Middleware;
53
+ friendFilter(friendArr: number[], allow?: boolean): Middleware<CTX>;
53
54
 
54
55
  /**
55
56
  * @description 过滤指定群的群成员的消息
@@ -57,32 +58,32 @@ export class Middleware {
57
58
  * @param allow 允许通过还是禁止通过
58
59
  * 结构 { number => number[], } key 为允许通过的群号,value 为该群允许通过的成员 qq
59
60
  */
60
- groupMemberFilter(groupMemberMap: Middleware.GroupMemberMap, allow?: boolean): Middleware;
61
+ groupMemberFilter(groupMemberMap: Middleware.GroupMemberMap, allow?: boolean): Middleware<CTX>;
61
62
 
62
63
  /**
63
64
  * @description 这是一个对话锁,保证群中同一成员不能在中途触发处理器
64
65
  * @use 在你需要保护的过程结束后调用 data.unlock 即可
65
66
  */
66
- memberLock({ autoUnlock }?: Middleware.LockOptions): Middleware;
67
+ memberLock({ autoUnlock }?: Middleware.LockOptions): Middleware<CTX & { unlock: () => void }>;
67
68
 
68
69
  /**
69
70
  * @description 这是一个对话锁,保证同一好友不能在中途触发处理器
70
71
  * @use 在你需要保护的过程结束后调用 data.unlock 即可
71
72
  */
72
- friendLock({ autoUnlock }?: Middleware.LockOptions): Middleware;
73
+ friendLock({ autoUnlock }?: Middleware.LockOptions): Middleware<CTX & { unlock: () => void }>;
73
74
 
74
75
  /**
75
76
  * @description 过滤包含指定 @ 信息的消息
76
77
  * @param atArr 必选,qq 号数组
77
78
  * @param allow 可选,允许通过还是禁止通过
78
79
  */
79
- atFilter(friendArr: number[], allow?: boolean): Middleware;
80
+ atFilter(friendArr: number[], allow?: boolean): Middleware<CTX>;
80
81
 
81
82
  /**
82
83
  * @description 用于 NewFriendRequestEvent 的中间件,经过该中间件后,将在 data 下放置三个方法
83
84
  * agree、refuse、refuseAndAddBlacklist,调用后将分别进行好友请求的 同意、拒绝和拒绝并加入黑名单
84
85
  */
85
- friendRequestProcessor(): Middleware;
86
+ friendRequestProcessor(): Middleware<CTX & { agree: () => void, refuse: () => void, refuseAndAddBlacklist: () => void }>;
86
87
 
87
88
  /**
88
89
  * ! mirai-core 的问题,有时候收不到 MemberJoinRequestEvent 事件
@@ -93,9 +94,11 @@ export class Middleware {
93
94
  * ignore 忽略
94
95
  * refuseAndAddBlacklist 拒绝并移入黑名单
95
96
  * ignoreAndAddBlacklist 忽略并移入黑名单
96
- * @param bot 必选,Bot 实例
97
97
  */
98
- memberJoinRequestProcessor(): Middleware;
98
+ memberJoinRequestProcessor(): Middleware<CTX & {
99
+ agree: () => void, refuse: () => void, ignore: () => void,
100
+ refuseAndAddBlacklist: () => void, ignoreAndAddBlacklist: () => void,
101
+ }>;
99
102
 
100
103
  /**
101
104
  * ! 目前被邀请入群不会触发 BotInvitedJoinGroupRequestEvent 事件
@@ -103,32 +106,47 @@ export class Middleware {
103
106
  * @description 用于 BotInvitedJoinGroupRequestEvent 的中间件,经过该中间件后,将在 data 下放置两个方法
104
107
  * agree 同意
105
108
  * refuse 拒绝
106
- * @param bot 必选,Bot 实例
107
109
  */
108
- invitedJoinGroupRequestProcessor(): Middleware;
110
+ invitedJoinGroupRequestProcessor(): Middleware<CTX & { agree: () => void, refuse: () => void }>;
109
111
 
110
112
  /**
111
113
  * @description Waiter 的包装器,提供方便的同步 IO 方式
112
114
  */
113
- syncWrapper(): Middleware;
115
+ syncWrapper(): Middleware<CTX & {
116
+ waitFor: {
117
+ groupMember: (qq: number) => {
118
+ messageChain: () => Promise<MessageType[]>,
119
+ text: () => Promise<string>,
120
+ custom: <R>(processor: () => R) => Promise<R>,
121
+ },
122
+ friend: (qq) => {
123
+ messageChain: () => Promise<MessageType[]>,
124
+ text: () => Promise<string>,
125
+ custom: <R>(processor: () => R) => Promise<R>,
126
+ },
127
+ messageChain: () => Promise<MessageType[]>,
128
+ text: Promise<string>,
129
+ custom: <R>(processor: () => R) => Promise<R>,
130
+ }
131
+ }>;
114
132
 
115
133
  /**
116
134
  * @description 添加一个自定义中间件
117
135
  * @param callback (data, next) => void
118
136
  */
119
- use(callback: (data: any, next: Middleware.NextMiddlewareCaller) => any): Middleware;
137
+ use(callback: (data: CTX, next: Middleware.NextMiddlewareCaller) => any): Middleware<CTX>;
120
138
 
121
139
  /**
122
140
  * @description 使用错误处理器
123
141
  * @param catcher 错误处理器 (err) => void
124
142
  */
125
- catch(catcher: (error: any) => any): Middleware;
143
+ catch(catcher: (error: any) => any): Middleware<CTX>;
126
144
 
127
145
  /**
128
146
  * @description 生成一个带有中间件的事件处理器
129
147
  * @param callback 事件处理器
130
148
  */
131
- done<E extends EventType[] | EventType>(callback: Processor<E extends EventType ? [E] : E>): Processor<E extends EventType ? [E] : E>;
149
+ done<E extends EventType[]>(callback: Processor<E, CTX>): Processor<E, CTX>;
132
150
 
133
151
  }
134
152
 
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ const {
4
+ errCodeMap
5
+ } = require('../util/errCode');
6
+
7
+ const axios = require('axios');
8
+
9
+ const {
10
+ URL
11
+ } = require('../polyfill/URL');
12
+
13
+ const errorHandler = require('../util/errorHandler');
14
+
15
+ const path = require('path');
16
+
17
+ const {
18
+ isBrowserEnv
19
+ } = require('../util/isBrowserEnv');
20
+
21
+ const locationStr = !isBrowserEnv() ? `core.${path.basename(__filename, path.extname(__filename))}` : 'borwser';
22
+ /**
23
+ * @description 通过 messageId 获取消息
24
+ * @param {string} baseUrl mirai-api-http server 的地址
25
+ * @param {string} sessionKey 会话标识
26
+ * @param {number} target qq 号/群号
27
+ * @param {number} messageId 消息 id
28
+ * @returns {Object} 结构 { type, messageChain, sender }
29
+ */
30
+
31
+ module.exports = async ({
32
+ baseUrl,
33
+ sessionKey,
34
+ target,
35
+ messageId
36
+ }) => {
37
+ try {
38
+ // 拼接 url
39
+ const url = new URL('/messageFromId', baseUrl).toString(); // 请求
40
+
41
+ const responseData = await axios.get(url, {
42
+ params: {
43
+ sessionKey,
44
+ target,
45
+ messageId
46
+ }
47
+ });
48
+
49
+ try {
50
+ var {
51
+ data: {
52
+ msg: message,
53
+ code,
54
+ data
55
+ }
56
+ } = responseData;
57
+ } catch (error) {
58
+ throw new Error('请求返回格式出错,请检查 mirai-console');
59
+ } // 抛出 mirai 的异常,到 catch 中处理后再抛出
60
+
61
+
62
+ if (code in errCodeMap) {
63
+ throw new Error(message);
64
+ }
65
+
66
+ return data;
67
+ } catch (error) {
68
+ console.error(`mirai-js: error ${locationStr}`);
69
+ errorHandler(error);
70
+ }
71
+ };
package/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ function fun<T extends string, R extends T>(arr: T[]): R extends T ? R : never {
2
+
3
+ }
4
+
5
+ const r = fun(['a', 'b'])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mirai-js",
3
- "version": "2.8.0",
3
+ "version": "2.8.3",
4
4
  "description": "QQ robot development framework based on Mirai-api-http.",
5
5
  "main": "dist/node/index.js",
6
6
  "scripts": {
package/src/BaseType.d.ts CHANGED
@@ -87,7 +87,7 @@ type MessageId = number;
87
87
  * @see https://github.com/project-mirai/mirai-api-http/blob/master/docs/EventType.md
88
88
  */
89
89
 
90
- type MessageChainElementTypes =
90
+ export type MessageChainElementTypes =
91
91
  | 'Source'
92
92
  | 'Quote'
93
93
  | 'At'
@@ -113,26 +113,6 @@ interface EventBaseType {
113
113
  }
114
114
 
115
115
  // Middleware
116
- interface MessageExtendType {
117
- text?: string;
118
- classified?: {
119
- [key in MessageChainElementTypes]?: any[];
120
- };
121
- messageId?: number;
122
- waitFor?: any
123
- unlock?: () => void;
124
- }
125
- type RequestEventMethods =
126
- | 'agree'
127
- | 'refuse'
128
- | 'ignore'
129
- | 'refuseAndAddBlacklist'
130
- | 'ignoreAndAddBlacklist';
131
-
132
- type RequestEventExtendType = {
133
- [key in RequestEventMethods]?: () => void;
134
- };
135
-
136
116
  interface Member {
137
117
  id: number;
138
118
  memberName: string;
@@ -169,14 +149,12 @@ interface EventEntityMap {
169
149
  type: 'GroupMessage';
170
150
  sender: Member & { group: GroupSenderType },
171
151
  messageChain: MessageType[];
172
- } & EventBaseType &
173
- MessageExtendType,
152
+ } & EventBaseType,
174
153
  FriendMessage: {
175
154
  type: 'FriendMessage';
176
155
  messageChain: MessageType[];
177
156
  sender: Friend
178
- } & EventBaseType &
179
- MessageExtendType,
157
+ } & EventBaseType,
180
158
  BotOnlineEvent: {
181
159
  type: 'BotOnlineEvent',
182
160
  qq: number
@@ -334,7 +312,7 @@ interface EventEntityMap {
334
312
  groupId: number,
335
313
  nick: string,
336
314
  message: string
337
- } & RequestEventExtendType & EventBaseType;
315
+ } & EventBaseType;
338
316
  MemberJoinRequestEvent: {
339
317
  type: 'MemberJoinRequestEvent',
340
318
  eventId: number,
@@ -343,7 +321,7 @@ interface EventEntityMap {
343
321
  groupName: string,
344
322
  nick: string,
345
323
  message: string
346
- } & RequestEventExtendType & EventBaseType;
324
+ } & EventBaseType;
347
325
  BotInvitedJoinGroupRequestEvent: {
348
326
  type: 'MemberJoinRequestEvent',
349
327
  eventId: number,
@@ -352,7 +330,7 @@ interface EventEntityMap {
352
330
  groupName: string,
353
331
  nick: string,
354
332
  message: string
355
- } & RequestEventExtendType & EventBaseType;
333
+ } & EventBaseType;
356
334
  }
357
335
 
358
336
  type EventType = keyof EventEntityMap;
@@ -366,8 +344,7 @@ type GroupPermission = 'OWNER' | 'ADMINISTRATOR' | 'MEMBER';
366
344
  type SEX = 'UNKNOWN' | 'MALE' | 'FEMALE';
367
345
 
368
346
  // 消息处理器
369
- type Processor<U extends EventType[] | 'UnknownEventType' = 'UnknownEventType'> =
370
- (data: U extends 'UnknownEventType' ? EventBaseType : EventEntityMap[ArrayToValuesUnion<U extends 'UnknownEventType' ? never : U>]) => Awaitable<void | any>;
347
+ type Processor<U extends EventType[] = [], Extend = { [key: string]: any }> = (data: EventEntityMap[ArrayToValuesUnion<U>] & Extend) => Awaitable<void | any>;
371
348
 
372
349
  // QQ 自带表情
373
350
  type FaceType =
package/src/Bot.d.ts CHANGED
@@ -93,8 +93,8 @@ export class Bot implements BotConfigGetable {
93
93
  * @param callback 必选,回调函数
94
94
  * @returns handle 事件处理器的标识,用于移除该处理器
95
95
  */
96
- on<U extends EventType>(eventType: U, callback: Processor<[U]>): number;
97
- on<U extends EventType[]>(eventType: U, callback: Processor<U>): number[];
96
+ on<U extends EventType, E>(eventType: U, callback: Processor<[U], E>): number;
97
+ on<U extends EventType[], E>(eventType: U, callback: Processor<U, E>): number[];
98
98
 
99
99
  /**
100
100
  * @description 添加一个一次性事件处理器,回调一次后自动移除
@@ -298,6 +298,14 @@ export class Bot implements BotConfigGetable {
298
298
  */
299
299
  sendCommand({ command }: Bot.SendCommandOptions): Promise<Bot.MiraiConsoleMessage>;
300
300
 
301
+ /**
302
+ * @description 通过 messageId 获取消息
303
+ * @param {number} target 可选, 目标 qq 号/群号, mah v2.6.0+ 新增该参数
304
+ * @param {number} messageId 必选, 消息 id
305
+ * @returns
306
+ */
307
+ getMessageById({ messageId, target }: Bot.GetMessageByIdOptions): Promise<Bot.MessageFromMessageId>
308
+
301
309
  // 类方法
302
310
  /**
303
311
  * @description 检测该账号是否已经在 mirai-console 登录
@@ -532,6 +540,21 @@ declare namespace Bot {
532
540
  command: string[];
533
541
  }
534
542
 
543
+ interface GetMessageByIdOptions {
544
+ messageId: number;
545
+ target?: number;
546
+ }
547
+
548
+ interface MessageFromMessageId {
549
+ type: 'FriendMessage' | 'GroupMessage' | 'TempMessage';
550
+ messageChain: MessageType[];
551
+ sender: {
552
+ id?: number;
553
+ nickname?: string;
554
+ remark?: string;
555
+ }
556
+ }
557
+
535
558
  interface IsBotLoggedInOptions {
536
559
  baseUrl: string;
537
560
  verifyKey: string;
package/src/Bot.js CHANGED
@@ -32,6 +32,7 @@ const _quitGroup = require('./core/quitGroup');
32
32
  const _getGroupConfig = require('./core/getGroupConfig');
33
33
  const _setGroupConfig = require('./core/setGroupConfig');
34
34
  const _setEssence = require('./core/setEssence');
35
+ const _messageFromId = require('./core/messageFromId');
35
36
  const { wsStartListening: _startListening, wsStopListening: _stopListening } = require('./polyfill/wsListener');
36
37
 
37
38
  // 其他
@@ -1143,6 +1144,27 @@ class Bot extends BotConfigGetable {
1143
1144
  });
1144
1145
  }
1145
1146
 
1147
+ /**
1148
+ * @description 通过 messageId 获取消息
1149
+ * @param {number} target 可选, 目标 qq 号/群号, mah v2.6.0+ 新增该参数
1150
+ * @param {number} messageId 必选, 消息 id
1151
+ * @returns {Object} 结构 { type, messageChain, sender }
1152
+ */
1153
+ async getMessageById({ messageId, target }) {
1154
+ // 检查对象状态
1155
+ if (!this.config) {
1156
+ throw new Error('getMessageById 请先调用 open,建立一个会话');
1157
+ }
1158
+
1159
+ // 检查参数
1160
+ if (!messageId) {
1161
+ throw new Error('getMessageById 缺少必要的 messageId 参数');
1162
+ }
1163
+
1164
+ const { baseUrl, sessionKey } = this.config;
1165
+ return await _messageFromId({ baseUrl, sessionKey, target, messageId });
1166
+ }
1167
+
1146
1168
  /**
1147
1169
  * @description 检测该账号是否已经在 mirai-console 登录
1148
1170
  * @param {string} baseUrl 必选,mirai-api-http server 的地址