@alemonjs/qq-bot 2.1.35 → 2.1.37
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/LICENSE +21 -0
- package/README.md +66 -1981
- package/lib/config.d.ts +2 -0
- package/lib/format.d.ts +4 -1
- package/lib/format.js +68 -4
- package/lib/framework-actions.d.ts +75 -0
- package/lib/framework-actions.js +620 -0
- package/lib/framework-events.d.ts +10 -0
- package/lib/framework-events.js +182 -0
- package/lib/hook.d.ts +16 -12
- package/lib/hook.js +5 -9
- package/lib/index.d.ts +5 -1
- package/lib/index.websoket.js +6 -2
- package/lib/message/AUDIO_EVENT.d.ts +20 -0
- package/lib/message/AUDIO_EVENT.js +1 -0
- package/lib/message/FORUM_EVENT.d.ts +33 -0
- package/lib/message/FORUM_EVENT.js +1 -0
- package/lib/message/GUILD_AUDIT.d.ts +14 -0
- package/lib/message/GUILD_AUDIT.js +1 -0
- package/lib/message/INTERACTION_CREATE.d.ts +13 -20
- package/lib/message/MESSAGE_CREATE.d.ts +3 -9
- package/lib/message/MESSAGE_DELETE.d.ts +15 -1
- package/lib/message/group/C2C_MESSAGE_CREATE.d.ts +3 -13
- package/lib/message/group/C2C_MSG_RECEIVE.d.ts +1 -1
- package/lib/message/group/C2C_MSG_REJECT.d.ts +1 -1
- package/lib/message/group/FRIEND_ADD.d.ts +7 -1
- package/lib/message/group/FRIEND_DEL.d.ts +4 -1
- package/lib/message/group/GROUP_AT_MESSAGE_CREATE.d.ts +6 -27
- package/lib/message/group/GROUP_MEMBER_ADD.d.ts +4 -2
- package/lib/message/group/GROUP_MEMBER_REMOVE.d.ts +4 -2
- package/lib/message/group/GROUP_MESSAGE_CREATE.d.ts +6 -27
- package/lib/message/group/GROUP_MSG_RECEIVE.d.ts +1 -1
- package/lib/message/group/GROUP_MSG_REJECT.d.ts +1 -1
- package/lib/message/group/MESSAGE_AUDIT_PASS.d.ts +2 -0
- package/lib/message/group/MESSAGE_AUDIT_REJECT.d.ts +2 -0
- package/lib/message/group/SUBSCRIBE_MESSAGE_STATUS.d.ts +17 -0
- package/lib/message/group/SUBSCRIBE_MESSAGE_STATUS.js +1 -0
- package/lib/register.d.ts +1 -0
- package/lib/register.js +279 -115
- package/lib/sdk/api.d.ts +93 -14
- package/lib/sdk/api.js +241 -45
- package/lib/sdk/client.webhook.js +2 -1
- package/lib/sdk/client.websoket.js +2 -1
- package/lib/sdk/intents.d.ts +1 -0
- package/lib/sdk/intents.js +1 -0
- package/lib/sdk/message.d.ts +1 -1
- package/lib/sdk/message.group.d.ts +4 -2
- package/lib/sdk/message.guild.d.ts +19 -0
- package/lib/sdk/non-channel-types.d.ts +138 -0
- package/lib/sdk/non-channel-types.js +1 -0
- package/lib/sdk/registry.js +2 -2
- package/lib/sdk/typing.d.ts +13 -1
- package/lib/sends.d.ts +3 -3
- package/lib/sends.js +57 -71
- package/lib/upload.js +13 -37
- package/package.json +8 -5
|
@@ -15,6 +15,9 @@ import { GUILD_UPDATE_TYPE } from "../message/GUILD_UPDATE.js";
|
|
|
15
15
|
import { GUILD_MEMBER_ADD_TYPE } from "../message/GUILD_MEMBER_ADD.js";
|
|
16
16
|
import { GUILD_MEMBER_REMOVE_TYPE } from "../message/GUILD_MEMBER_REMOVE.js";
|
|
17
17
|
import { GUILD_MEMBER_UPDATE_TYPE } from "../message/GUILD_MEMBER_UPDATE.js";
|
|
18
|
+
import { GUILD_AUDIT_TYPE } from "../message/GUILD_AUDIT.js";
|
|
19
|
+
import { FORUM_EVENT_TYPE } from "../message/FORUM_EVENT.js";
|
|
20
|
+
import { AUDIO_EVENT_TYPE, AUDIO_OR_LIVE_CHANNEL_MEMBER_EVENT_TYPE } from "../message/AUDIO_EVENT.js";
|
|
18
21
|
import { READY_TYPE } from "../message/READY.js";
|
|
19
22
|
//#region src/sdk/message.guild.d.ts
|
|
20
23
|
type QQBotGuildEventMap = {
|
|
@@ -35,6 +38,22 @@ type QQBotGuildEventMap = {
|
|
|
35
38
|
MESSAGE_REACTION_REMOVE: MESSAGE_REACTION_REMOVE_TYPE;
|
|
36
39
|
AT_MESSAGE_CREATE: AT_MESSAGE_CREATE_TYPE;
|
|
37
40
|
PUBLIC_MESSAGE_DELETE: PUBLIC_MESSAGE_DELETE_TYPE;
|
|
41
|
+
MESSAGE_AUDIT_PASS: GUILD_AUDIT_TYPE;
|
|
42
|
+
MESSAGE_AUDIT_REJECT: GUILD_AUDIT_TYPE;
|
|
43
|
+
FORUM_THREAD_CREATE: FORUM_EVENT_TYPE;
|
|
44
|
+
FORUM_THREAD_UPDATE: FORUM_EVENT_TYPE;
|
|
45
|
+
FORUM_THREAD_DELETE: FORUM_EVENT_TYPE;
|
|
46
|
+
FORUM_POST_CREATE: FORUM_EVENT_TYPE;
|
|
47
|
+
FORUM_POST_DELETE: FORUM_EVENT_TYPE;
|
|
48
|
+
FORUM_REPLY_CREATE: FORUM_EVENT_TYPE;
|
|
49
|
+
FORUM_REPLY_DELETE: FORUM_EVENT_TYPE;
|
|
50
|
+
FORUM_PUBLISH_AUDIT_RESULT: FORUM_EVENT_TYPE;
|
|
51
|
+
AUDIO_START: AUDIO_EVENT_TYPE;
|
|
52
|
+
AUDIO_FINISH: AUDIO_EVENT_TYPE;
|
|
53
|
+
AUDIO_ON_MIC: AUDIO_EVENT_TYPE;
|
|
54
|
+
AUDIO_OFF_MIC: AUDIO_EVENT_TYPE;
|
|
55
|
+
AUDIO_OR_LIVE_CHANNEL_MEMBER_ENTER: AUDIO_OR_LIVE_CHANNEL_MEMBER_EVENT_TYPE;
|
|
56
|
+
AUDIO_OR_LIVE_CHANNEL_MEMBER_EXIT: AUDIO_OR_LIVE_CHANNEL_MEMBER_EVENT_TYPE;
|
|
38
57
|
READY: READY_TYPE;
|
|
39
58
|
};
|
|
40
59
|
//#endregion
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
//#region src/sdk/non-channel-types.d.ts
|
|
2
|
+
/** 群聊、单聊服务端接口模型,依据 docs/official/non-channel 快照。 */
|
|
3
|
+
type QQBotPage = {
|
|
4
|
+
cursor?: string;
|
|
5
|
+
limit?: number;
|
|
6
|
+
};
|
|
7
|
+
type QQBotMenuItem = {
|
|
8
|
+
name?: string;
|
|
9
|
+
type?: 'switch' | 'send_message' | 'link' | 'menu';
|
|
10
|
+
send_message?: string;
|
|
11
|
+
link?: string;
|
|
12
|
+
switch?: {
|
|
13
|
+
switch_id?: string;
|
|
14
|
+
default?: boolean;
|
|
15
|
+
};
|
|
16
|
+
sub_menu_items?: {
|
|
17
|
+
name?: string;
|
|
18
|
+
type?: 'send_message' | 'link';
|
|
19
|
+
send_message?: string;
|
|
20
|
+
link?: string;
|
|
21
|
+
}[];
|
|
22
|
+
};
|
|
23
|
+
type QQBotMenu = {
|
|
24
|
+
items?: QQBotMenuItem[];
|
|
25
|
+
};
|
|
26
|
+
type QQBotPanel = {
|
|
27
|
+
items?: {
|
|
28
|
+
name?: string;
|
|
29
|
+
desc?: string;
|
|
30
|
+
type?: 'command' | 'link';
|
|
31
|
+
only_admin?: boolean;
|
|
32
|
+
link?: string;
|
|
33
|
+
}[];
|
|
34
|
+
remark?: string;
|
|
35
|
+
version?: number;
|
|
36
|
+
};
|
|
37
|
+
/** 本次仅开放非频道场景。 */
|
|
38
|
+
type QQBotPanelScope = 'c2c' | 'group';
|
|
39
|
+
type QQBotPanelCreate = {
|
|
40
|
+
scope: QQBotPanelScope;
|
|
41
|
+
target_type?: 'all' | 'specific';
|
|
42
|
+
user_openids?: string[];
|
|
43
|
+
group_openids?: string[];
|
|
44
|
+
panel: QQBotPanel;
|
|
45
|
+
};
|
|
46
|
+
type QQBotPanelRecord = QQBotPanelCreate & {
|
|
47
|
+
panel_id: string;
|
|
48
|
+
created_at?: string;
|
|
49
|
+
updated_at?: string;
|
|
50
|
+
version?: number;
|
|
51
|
+
};
|
|
52
|
+
type QQBotGroupMember = {
|
|
53
|
+
member_openid: string;
|
|
54
|
+
username: string;
|
|
55
|
+
member_role: 'member' | 'owner' | 'admin';
|
|
56
|
+
bot: boolean;
|
|
57
|
+
joined_at: string;
|
|
58
|
+
union_openid?: string;
|
|
59
|
+
};
|
|
60
|
+
type QQBotBlacklistUser = {
|
|
61
|
+
member_openid: string;
|
|
62
|
+
username: string;
|
|
63
|
+
banned_at: string;
|
|
64
|
+
bot: boolean;
|
|
65
|
+
union_openid?: string;
|
|
66
|
+
};
|
|
67
|
+
type QQBotMessageResult = {
|
|
68
|
+
id: string;
|
|
69
|
+
timestamp: string;
|
|
70
|
+
ext_info?: {
|
|
71
|
+
ref_idx?: string;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
type QQBotMessageUser = {
|
|
75
|
+
id: string;
|
|
76
|
+
username?: string;
|
|
77
|
+
bot?: boolean;
|
|
78
|
+
union_openid?: string;
|
|
79
|
+
union_user_account?: string;
|
|
80
|
+
user_openid?: string;
|
|
81
|
+
member_openid?: string;
|
|
82
|
+
member_role?: 'member' | 'admin' | 'owner';
|
|
83
|
+
};
|
|
84
|
+
type QQBotAttachment = {
|
|
85
|
+
id?: string;
|
|
86
|
+
url?: string;
|
|
87
|
+
filename?: string;
|
|
88
|
+
width?: number;
|
|
89
|
+
height?: number;
|
|
90
|
+
size?: number;
|
|
91
|
+
content_type?: string;
|
|
92
|
+
voice_wav_url?: string;
|
|
93
|
+
asr_refer_text?: string;
|
|
94
|
+
};
|
|
95
|
+
type QQBotArkData = {
|
|
96
|
+
prompt?: string;
|
|
97
|
+
ark_type?: string;
|
|
98
|
+
ark_name?: string;
|
|
99
|
+
fields?: Record<string, unknown>;
|
|
100
|
+
};
|
|
101
|
+
type QQBotMessageElement = {
|
|
102
|
+
msg_idx?: string;
|
|
103
|
+
author?: QQBotMessageUser;
|
|
104
|
+
message_type?: number;
|
|
105
|
+
content?: string;
|
|
106
|
+
attachments?: QQBotAttachment[];
|
|
107
|
+
ark_data?: QQBotArkData;
|
|
108
|
+
msg_elements?: QQBotMessageElement[];
|
|
109
|
+
};
|
|
110
|
+
type QQBotMessageContent = {
|
|
111
|
+
attachments?: QQBotAttachment[];
|
|
112
|
+
ark_data?: QQBotArkData;
|
|
113
|
+
msg_elements?: QQBotMessageElement[];
|
|
114
|
+
message_scene?: {
|
|
115
|
+
ext: string[];
|
|
116
|
+
source?: string;
|
|
117
|
+
};
|
|
118
|
+
message_type?: number;
|
|
119
|
+
};
|
|
120
|
+
type QQBotInteractionResolved = {
|
|
121
|
+
button_data?: string;
|
|
122
|
+
button_id?: string | number;
|
|
123
|
+
user_id?: string;
|
|
124
|
+
feature_id?: string;
|
|
125
|
+
message_id?: string;
|
|
126
|
+
feedback_opt?: 'LIKE' | 'UNLIKE';
|
|
127
|
+
checked?: number;
|
|
128
|
+
action?: string;
|
|
129
|
+
message_scene?: {
|
|
130
|
+
ext?: string[];
|
|
131
|
+
};
|
|
132
|
+
authorize_data?: {
|
|
133
|
+
opt_scene?: string;
|
|
134
|
+
scope?: string;
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
//#endregion
|
|
138
|
+
export { QQBotArkData, QQBotAttachment, QQBotBlacklistUser, QQBotGroupMember, QQBotInteractionResolved, QQBotMenu, QQBotMenuItem, QQBotMessageContent, QQBotMessageElement, QQBotMessageResult, QQBotMessageUser, QQBotPage, QQBotPanel, QQBotPanelCreate, QQBotPanelRecord, QQBotPanelScope };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/lib/sdk/registry.js
CHANGED
|
@@ -80,7 +80,7 @@ var QQBotRegistry = class {
|
|
|
80
80
|
}
|
|
81
81
|
#requestedBotId(data) {
|
|
82
82
|
const payload = data?.payload || {};
|
|
83
|
-
return payload.target?.BotId
|
|
83
|
+
return payload.params?.target?.BotId ?? payload.target?.BotId ?? payload.BotId ?? payload.event?.BotId ?? payload.event?.Platform?.BotId;
|
|
84
84
|
}
|
|
85
85
|
#select(data) {
|
|
86
86
|
const requested = this.#requestedBotId(data);
|
|
@@ -94,7 +94,7 @@ var QQBotRegistry = class {
|
|
|
94
94
|
}
|
|
95
95
|
async #onAction(data, consume) {
|
|
96
96
|
if (data?.action === "connection.status") {
|
|
97
|
-
const botId = data
|
|
97
|
+
const botId = this.#requestedBotId(data);
|
|
98
98
|
const status = this.getConnectionStatus(botId);
|
|
99
99
|
if (botId && !status.bots.length) consume([createResult(ResultCode.FailParams, `BotId ${botId} is not configured`, null)]);
|
|
100
100
|
else consume([createResult(ResultCode.Ok, data.action, status)]);
|
package/lib/sdk/typing.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { SessionStore } from "./session.js";
|
|
|
4
4
|
type MessageType = 0 | 1 | 2 | 3 | 4 | 6 | 7;
|
|
5
5
|
type FileType = 1 | 2 | 3 | 4;
|
|
6
6
|
interface ButtonType {
|
|
7
|
+
group_id?: string;
|
|
7
8
|
id: string;
|
|
8
9
|
render_data: {
|
|
9
10
|
label: string;
|
|
@@ -14,6 +15,15 @@ interface ButtonType {
|
|
|
14
15
|
type: number;
|
|
15
16
|
permission: {
|
|
16
17
|
type: number;
|
|
18
|
+
specify_user_ids?: string[];
|
|
19
|
+
specify_role_ids?: string[];
|
|
20
|
+
};
|
|
21
|
+
anchor?: number;
|
|
22
|
+
click_limit?: number;
|
|
23
|
+
modal?: {
|
|
24
|
+
content?: string;
|
|
25
|
+
confirm_text?: string;
|
|
26
|
+
cancel_text?: string;
|
|
17
27
|
};
|
|
18
28
|
reply?: boolean;
|
|
19
29
|
enter?: boolean;
|
|
@@ -35,6 +45,8 @@ interface KeyboardType {
|
|
|
35
45
|
};
|
|
36
46
|
}
|
|
37
47
|
interface MarkdownType {
|
|
48
|
+
template_id?: number;
|
|
49
|
+
force_verify_image_resource?: boolean;
|
|
38
50
|
/** markdown 模版id,申请模版后获得 */
|
|
39
51
|
custom_template_id?: string;
|
|
40
52
|
/** 原生 markdown 文本内容(内邀使用) */
|
|
@@ -60,7 +72,7 @@ interface ApiRequestData {
|
|
|
60
72
|
msg_id?: string;
|
|
61
73
|
msg_seq?: number;
|
|
62
74
|
/**
|
|
63
|
-
*
|
|
75
|
+
* 互动召回消息,与 msg_id/event_id 互斥
|
|
64
76
|
*/
|
|
65
77
|
is_wakeup?: boolean;
|
|
66
78
|
/**
|
package/lib/sends.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { QQBotAPI } from "./sdk/api.js";
|
|
2
|
-
import { ClientAPIMessageResult, DataEnums } from "alemonjs";
|
|
2
|
+
import { ClientAPIMessageResult, DataEnums, MessageDelivery } from "alemonjs";
|
|
3
3
|
//#region src/sends.d.ts
|
|
4
4
|
type Client = typeof QQBotAPI.prototype;
|
|
5
5
|
/**
|
|
@@ -9,7 +9,7 @@ declare const GROUP_AT_MESSAGE_CREATE: (client: Client, event: {
|
|
|
9
9
|
ChannelId: string;
|
|
10
10
|
MessageId?: string;
|
|
11
11
|
_tag?: string;
|
|
12
|
-
}, val: DataEnums[], options?: {
|
|
12
|
+
}, val: DataEnums[], options?: MessageDelivery & {
|
|
13
13
|
forceVerifyImageResource?: boolean;
|
|
14
14
|
}) => Promise<ClientAPIMessageResult[]>;
|
|
15
15
|
/**
|
|
@@ -19,7 +19,7 @@ declare const C2C_MESSAGE_CREATE: (client: Client, event: {
|
|
|
19
19
|
UserId: string;
|
|
20
20
|
MessageId?: string;
|
|
21
21
|
_tag?: string;
|
|
22
|
-
}, val: DataEnums[], options?: {
|
|
22
|
+
}, val: DataEnums[], options?: MessageDelivery & {
|
|
23
23
|
forceVerifyImageResource?: boolean;
|
|
24
24
|
}) => Promise<ClientAPIMessageResult[]>;
|
|
25
25
|
/**
|
package/lib/sends.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getQQBotConfig } from "./config.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createMarkdownText, dataEnumToText, formatQQContent } from "./format.js";
|
|
3
3
|
import { ResultCode, createResult, logger } from "alemonjs";
|
|
4
4
|
import { readFileSync } from "fs";
|
|
5
5
|
import axios from "axios";
|
|
@@ -172,47 +172,6 @@ const createArkListData = (value) => {
|
|
|
172
172
|
]
|
|
173
173
|
};
|
|
174
174
|
};
|
|
175
|
-
const mdFormatters = {
|
|
176
|
-
"MD.title": (value) => `# ${value} `,
|
|
177
|
-
"MD.subtitle": (value) => `## ${value} `,
|
|
178
|
-
"MD.text": (value) => `${value} `,
|
|
179
|
-
"MD.bold": (value) => `**${value}** `,
|
|
180
|
-
"MD.divider": () => "\n***\n",
|
|
181
|
-
"MD.italic": (value) => `__${value}__ `,
|
|
182
|
-
"MD.italicStar": (value) => `*${value}* `,
|
|
183
|
-
"MD.strikethrough": (value) => `~~${value}~~ `,
|
|
184
|
-
"MD.blockquote": (value) => `\n> ${value} `,
|
|
185
|
-
"MD.newline": () => "\n",
|
|
186
|
-
"MD.link": (value) => {
|
|
187
|
-
if (!value?.text && !value?.url) return "";
|
|
188
|
-
if (!value?.text || !value?.url) return `<${value?.url ?? value?.text}> `;
|
|
189
|
-
return `[🔗${value?.text}](${value?.url}) `;
|
|
190
|
-
},
|
|
191
|
-
"MD.image": (value, options) => `\n\n`,
|
|
192
|
-
"MD.mention": (value, options) => {
|
|
193
|
-
const { belong } = options || {};
|
|
194
|
-
if (belong === "channel") return "";
|
|
195
|
-
if (belong === "user") return `<qqbot-at-user id="${value}" />`;
|
|
196
|
-
if (value === "everyone") return "<qqbot-at-everyone />";
|
|
197
|
-
return `<qqbot-at-user id="${value}" />`;
|
|
198
|
-
},
|
|
199
|
-
"MD.content": (value) => `${value}`,
|
|
200
|
-
"MD.button": (title, options) => {
|
|
201
|
-
const { data, autoEnter } = options || {};
|
|
202
|
-
if (autoEnter) return `<qqbot-cmd-enter text="${data}" show="${title}" />`;
|
|
203
|
-
return `<qqbot-cmd-input text="${data}" show="${title}" />`;
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
const createMarkdownText = (data) => {
|
|
207
|
-
return data.map((mdItem) => {
|
|
208
|
-
if (mdFormatters[mdItem.type]) return mdFormatters[mdItem.type](mdItem?.value, mdItem?.options);
|
|
209
|
-
if (mdItem.type === "MD.list" && typeof mdItem.value !== "string") return `${mdItem.value.map((listItem) => {
|
|
210
|
-
return typeof listItem.value === "object" ? `\n${listItem.value.index}. ${listItem.value.text}` : `\n- ${listItem.value}`;
|
|
211
|
-
}).join("")}\n`;
|
|
212
|
-
if (mdItem.type === "MD.code") return `\n\`\`\`${mdItem?.options?.language || ""}\n${mdItem.value}\n\`\`\`\n`;
|
|
213
|
-
return String(mdItem["value"] || "");
|
|
214
|
-
}).join("");
|
|
215
|
-
};
|
|
216
175
|
const formatMention = (item, mode) => {
|
|
217
176
|
if (mode === "guild-direct") return "";
|
|
218
177
|
const value = item.value;
|
|
@@ -373,18 +332,18 @@ const resolveMediaUrl = async (media, uploadMedia) => {
|
|
|
373
332
|
}
|
|
374
333
|
};
|
|
375
334
|
/** 移除富媒体占位符(dataEnumToText 降级产生的 [视频]/[音频]/[附件]) */
|
|
376
|
-
const stripMediaPlaceholders = (text) => text.replace(/\[附件[^\]]*\]/g, "").replace(/\[音频\]/g, "").replace(/\[视频\]/g, "").
|
|
377
|
-
/** 当 markdownToText 选项开启时,将 Markdown 和按钮降级为纯文本并追加到 content */
|
|
378
|
-
const flattenMdToText = (content, val) => {
|
|
379
|
-
const mdItems = val.filter((item) => item.type === "Markdown");
|
|
380
|
-
const btnItems = val.filter((item) => item.type === "BT.group");
|
|
381
|
-
const parts = [content];
|
|
382
|
-
for (const item of mdItems) if (item.type === "Markdown" && typeof item.value !== "string") parts.push(markdownToText(item.value));
|
|
383
|
-
for (const item of btnItems) if (item.type === "BT.group" && typeof item.value !== "string") parts.push(buttonsToText(item.value));
|
|
384
|
-
return parts.filter(Boolean).join("\n").replace(/^[^\S\n\r]+|[^\S\n\r]+$/g, "");
|
|
385
|
-
};
|
|
335
|
+
const stripMediaPlaceholders = (text) => text.replace(/\[附件[^\]]*\]/g, "").replace(/\[音频\]/g, "").replace(/\[视频\]/g, "").trim();
|
|
386
336
|
/** Open API 通用发送逻辑(群组 / C2C) */
|
|
387
337
|
const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMessage, label, options) => {
|
|
338
|
+
if (options?.wakeup && (options.replyId || options.eventId) || options?.replyId && options?.eventId) return [createResult(ResultCode.FailParams, "wakeup, replyId and eventId are mutually exclusive", null)];
|
|
339
|
+
if (options?.wakeup || options?.replyId || options?.eventId) {
|
|
340
|
+
baseParams = {};
|
|
341
|
+
if (options.wakeup) baseParams.is_wakeup = true;
|
|
342
|
+
else if (options.eventId) baseParams.event_id = options.eventId;
|
|
343
|
+
else baseParams.msg_id = options.replyId;
|
|
344
|
+
}
|
|
345
|
+
if (options?.sequence !== void 0) baseParams.msg_seq = options.sequence;
|
|
346
|
+
if (options?.referenceId) baseParams.message_reference = { message_id: options.referenceId };
|
|
388
347
|
const config = getQQBotConfig();
|
|
389
348
|
const mdToText = config.markdownToText === true;
|
|
390
349
|
const media = filterMedia(val);
|
|
@@ -392,40 +351,51 @@ const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMes
|
|
|
392
351
|
const fileInfo = await resolveMediaUrl(media, uploadMedia);
|
|
393
352
|
if (!fileInfo) return [createResult(ResultCode.Fail, "媒体上传失败", null)];
|
|
394
353
|
const res = await sendMessage({
|
|
395
|
-
content: stripMediaPlaceholders(
|
|
354
|
+
content: stripMediaPlaceholders(formatQQContent(val, (item) => extractContent([item], "group"), true, config.hideUnsupported)),
|
|
396
355
|
media: { file_info: fileInfo },
|
|
397
356
|
msg_type: 7,
|
|
398
357
|
...baseParams
|
|
399
358
|
});
|
|
400
|
-
return [createResult(ResultCode.Ok, label, {
|
|
359
|
+
return [createResult(ResultCode.Ok, label, {
|
|
360
|
+
id: res.id,
|
|
361
|
+
...res.timestamp !== void 0 && { timestamp: res.timestamp },
|
|
362
|
+
...res.ext_info?.ref_idx !== void 0 && { referenceId: res.ext_info.ref_idx }
|
|
363
|
+
})];
|
|
401
364
|
}
|
|
402
365
|
if (config.hideUnsupported === true && !content && !buildMdAndButtonsParams(val) && !buildArkParams(val)) {
|
|
403
366
|
logger.info("[qq-bot] hideUnsupported: 消息内容转换后为空,跳过发送");
|
|
404
367
|
return [];
|
|
405
368
|
}
|
|
406
369
|
if (mdToText) {
|
|
407
|
-
const textContent =
|
|
370
|
+
const textContent = formatQQContent(val, (item) => extractContent([item], "group"), true, config.hideUnsupported);
|
|
408
371
|
if (textContent) {
|
|
409
372
|
const res = await sendMessage({
|
|
410
373
|
content: textContent,
|
|
411
374
|
msg_type: 0,
|
|
412
375
|
...baseParams
|
|
413
376
|
});
|
|
414
|
-
return [createResult(ResultCode.Ok, label, {
|
|
377
|
+
return [createResult(ResultCode.Ok, label, {
|
|
378
|
+
id: res.id,
|
|
379
|
+
...res.timestamp !== void 0 && { timestamp: res.timestamp },
|
|
380
|
+
...res.ext_info?.ref_idx !== void 0 && { referenceId: res.ext_info.ref_idx }
|
|
381
|
+
})];
|
|
415
382
|
}
|
|
416
383
|
return [];
|
|
417
384
|
}
|
|
418
385
|
const mdParams = buildMdAndButtonsParams(val);
|
|
419
386
|
if (mdParams) {
|
|
420
|
-
if (mdParams.markdown?.content
|
|
387
|
+
if (mdParams.markdown?.content) mdParams.markdown.content = formatQQContent(val, (item) => extractContent([item], "group"));
|
|
388
|
+
if (mdParams.markdown && options?.forceVerifyImageResource !== void 0) mdParams.markdown.force_verify_image_resource = options.forceVerifyImageResource;
|
|
421
389
|
const res = await sendMessage({
|
|
422
|
-
content,
|
|
423
390
|
msg_type: 2,
|
|
424
391
|
...mdParams,
|
|
425
|
-
...baseParams
|
|
426
|
-
force_verify_image_resource: options?.forceVerifyImageResource
|
|
392
|
+
...baseParams
|
|
427
393
|
});
|
|
428
|
-
return [createResult(ResultCode.Ok, label, {
|
|
394
|
+
return [createResult(ResultCode.Ok, label, {
|
|
395
|
+
id: res.id,
|
|
396
|
+
...res.timestamp !== void 0 && { timestamp: res.timestamp },
|
|
397
|
+
...res.ext_info?.ref_idx !== void 0 && { referenceId: res.ext_info.ref_idx }
|
|
398
|
+
})];
|
|
429
399
|
}
|
|
430
400
|
const arkParams = buildArkParams(val);
|
|
431
401
|
if (arkParams) {
|
|
@@ -435,7 +405,11 @@ const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMes
|
|
|
435
405
|
...arkParams,
|
|
436
406
|
...baseParams
|
|
437
407
|
});
|
|
438
|
-
return [createResult(ResultCode.Ok, label, {
|
|
408
|
+
return [createResult(ResultCode.Ok, label, {
|
|
409
|
+
id: res.id,
|
|
410
|
+
...res.timestamp !== void 0 && { timestamp: res.timestamp },
|
|
411
|
+
...res.ext_info?.ref_idx !== void 0 && { referenceId: res.ext_info.ref_idx }
|
|
412
|
+
})];
|
|
439
413
|
}
|
|
440
414
|
if (content) {
|
|
441
415
|
const res = await sendMessage({
|
|
@@ -443,7 +417,11 @@ const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMes
|
|
|
443
417
|
msg_type: 0,
|
|
444
418
|
...baseParams
|
|
445
419
|
});
|
|
446
|
-
return [createResult(ResultCode.Ok, label, {
|
|
420
|
+
return [createResult(ResultCode.Ok, label, {
|
|
421
|
+
id: res.id,
|
|
422
|
+
...res.timestamp !== void 0 && { timestamp: res.timestamp },
|
|
423
|
+
...res.ext_info?.ref_idx !== void 0 && { referenceId: res.ext_info.ref_idx }
|
|
424
|
+
})];
|
|
447
425
|
}
|
|
448
426
|
return [];
|
|
449
427
|
};
|
|
@@ -463,14 +441,14 @@ const resolveImageBuffer = async (images) => {
|
|
|
463
441
|
return null;
|
|
464
442
|
};
|
|
465
443
|
/** Guild API 通用发送逻辑(频道公聊 / 频道私聊) */
|
|
466
|
-
const sendGuildMessage = async (content, val, baseParams, sendMessage, label) => {
|
|
444
|
+
const sendGuildMessage = async (content, val, baseParams, sendMessage, label, mode) => {
|
|
467
445
|
const config = getQQBotConfig();
|
|
468
446
|
const mdToText = config.markdownToText === true;
|
|
469
447
|
const images = filterImages(val);
|
|
470
448
|
if (images.length > 0) {
|
|
471
449
|
const imageBuffer = await resolveImageBuffer(images);
|
|
472
450
|
const res = await sendMessage({
|
|
473
|
-
content:
|
|
451
|
+
content: formatQQContent(val, (item) => extractContent([item], mode), true, config.hideUnsupported),
|
|
474
452
|
...baseParams
|
|
475
453
|
}, imageBuffer);
|
|
476
454
|
return [createResult(ResultCode.Ok, label, { id: res?.id })];
|
|
@@ -480,7 +458,7 @@ const sendGuildMessage = async (content, val, baseParams, sendMessage, label) =>
|
|
|
480
458
|
return [];
|
|
481
459
|
}
|
|
482
460
|
if (mdToText) {
|
|
483
|
-
const textContent =
|
|
461
|
+
const textContent = formatQQContent(val, (item) => extractContent([item], mode), true, config.hideUnsupported);
|
|
484
462
|
if (textContent) {
|
|
485
463
|
const res = await sendMessage({
|
|
486
464
|
content: textContent,
|
|
@@ -492,13 +470,17 @@ const sendGuildMessage = async (content, val, baseParams, sendMessage, label) =>
|
|
|
492
470
|
}
|
|
493
471
|
const mdParams = buildMdAndButtonsParams(val);
|
|
494
472
|
if (mdParams) {
|
|
495
|
-
if (mdParams.markdown?.content
|
|
473
|
+
if (mdParams.markdown?.content) mdParams.markdown.content = formatQQContent(val, (item) => extractContent([item], mode));
|
|
496
474
|
const res = await sendMessage({
|
|
497
475
|
content: "",
|
|
498
476
|
...mdParams,
|
|
499
477
|
...baseParams
|
|
500
478
|
});
|
|
501
|
-
return [createResult(ResultCode.Ok, label, {
|
|
479
|
+
return [createResult(ResultCode.Ok, label, {
|
|
480
|
+
id: res.id,
|
|
481
|
+
...res.timestamp !== void 0 && { timestamp: res.timestamp },
|
|
482
|
+
...res.ext_info?.ref_idx !== void 0 && { referenceId: res.ext_info.ref_idx }
|
|
483
|
+
})];
|
|
502
484
|
}
|
|
503
485
|
const arkParams = buildArkParams(val);
|
|
504
486
|
if (arkParams) {
|
|
@@ -507,7 +489,11 @@ const sendGuildMessage = async (content, val, baseParams, sendMessage, label) =>
|
|
|
507
489
|
...arkParams,
|
|
508
490
|
...baseParams
|
|
509
491
|
});
|
|
510
|
-
return [createResult(ResultCode.Ok, label, {
|
|
492
|
+
return [createResult(ResultCode.Ok, label, {
|
|
493
|
+
id: res.id,
|
|
494
|
+
...res.timestamp !== void 0 && { timestamp: res.timestamp },
|
|
495
|
+
...res.ext_info?.ref_idx !== void 0 && { referenceId: res.ext_info.ref_idx }
|
|
496
|
+
})];
|
|
511
497
|
}
|
|
512
498
|
if (content) {
|
|
513
499
|
const res = await sendMessage({
|
|
@@ -549,7 +535,7 @@ const DIRECT_MESSAGE_CREATE = async (client, event, val) => {
|
|
|
549
535
|
const baseParams = buildBaseParams(event._tag, event.MessageId, "INTERACTION_CREATE_GUILD");
|
|
550
536
|
const content = extractContent(val, "guild-direct");
|
|
551
537
|
try {
|
|
552
|
-
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.dmsMessages(event.UserId, data, buf), "client.dmsMessage");
|
|
538
|
+
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.dmsMessages(event.UserId, data, buf), "client.dmsMessage", "guild-direct");
|
|
553
539
|
} catch (err) {
|
|
554
540
|
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
555
541
|
}
|
|
@@ -561,7 +547,7 @@ const MESSAGE_CREATE = async (client, event, val) => {
|
|
|
561
547
|
const baseParams = buildBaseParams(event._tag, event.MessageId, "INTERACTION_CREATE_GUILD");
|
|
562
548
|
const content = extractContent(val, "guild-public");
|
|
563
549
|
try {
|
|
564
|
-
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.channelsMessages(event.ChannelId, data, buf), "client.channelsMessagesPost");
|
|
550
|
+
return await sendGuildMessage(content, val, baseParams, (data, buf) => client.channelsMessages(event.ChannelId, data, buf), "client.channelsMessagesPost", "guild-public");
|
|
565
551
|
} catch (err) {
|
|
566
552
|
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
567
553
|
}
|
package/lib/upload.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
1
|
+
import { readFileSync, statSync } from "fs";
|
|
2
2
|
import { createHash } from "crypto";
|
|
3
3
|
|
|
4
4
|
//#region src/upload.ts
|
|
@@ -47,42 +47,18 @@ const computeFileDigests = (filePath) => {
|
|
|
47
47
|
* @param file 本地文件路径或文件内容
|
|
48
48
|
* @param options 上传选项
|
|
49
49
|
*/
|
|
50
|
-
const chunkedUpload =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
md5_10m
|
|
63
|
-
};
|
|
64
|
-
const prepare = await (scope === "user" ? client.usersUploadPrepare(openId, prepareData) : client.groupUploadPrepare(openId, prepareData));
|
|
65
|
-
const blockSize = Number(prepare.block_size);
|
|
66
|
-
for (const part of prepare.parts) {
|
|
67
|
-
const start = part.index * blockSize;
|
|
68
|
-
const chunk = Buffer.from(buffer.subarray(start, start + Number(part.block_size)));
|
|
69
|
-
const partMd5 = createHash("md5").update(chunk).digest("hex");
|
|
70
|
-
await client.uploadPartDirect(part.presigned_url, chunk);
|
|
71
|
-
const finishData = {
|
|
72
|
-
upload_id: prepare.upload_id,
|
|
73
|
-
part_index: part.index,
|
|
74
|
-
block_size: part.block_size,
|
|
75
|
-
md5: partMd5
|
|
76
|
-
};
|
|
77
|
-
await (scope === "user" ? client.usersUploadPartFinish(openId, finishData) : client.groupUploadPartFinish(openId, finishData));
|
|
78
|
-
}
|
|
79
|
-
const merge = {
|
|
80
|
-
file_type: options.file_type,
|
|
81
|
-
upload_id: prepare.upload_id,
|
|
82
|
-
file_name,
|
|
83
|
-
srv_send_msg: options.srv_send_msg
|
|
84
|
-
};
|
|
85
|
-
return scope === "user" ? client.postRichMediaByUser(openId, merge) : client.postRichMediaByGroup(openId, merge);
|
|
50
|
+
const chunkedUpload = (client, scope, openId, file, options) => {
|
|
51
|
+
return client.postChunkedRichMedia({
|
|
52
|
+
scope: scope === "user" ? "c2c" : "group",
|
|
53
|
+
targetId: openId,
|
|
54
|
+
fileType: options.file_type,
|
|
55
|
+
...typeof file === "string" ? {
|
|
56
|
+
filePath: file,
|
|
57
|
+
size: statSync(file).size
|
|
58
|
+
} : { data: file },
|
|
59
|
+
name: options.file_name ?? (typeof file === "string" ? file.split(/[\\/]/).pop() : void 0),
|
|
60
|
+
send: options.srv_send_msg
|
|
61
|
+
});
|
|
86
62
|
};
|
|
87
63
|
|
|
88
64
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alemonjs/qq-bot",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.37",
|
|
4
4
|
"description": "QQ官方平台",
|
|
5
5
|
"author": "lemonade",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
"build": "lvy build",
|
|
11
11
|
"test:ws": "yarn build && node tests/websocket.integration.mjs",
|
|
12
12
|
"test:send": "yarn build && node tests/use-send.notice.mjs",
|
|
13
|
-
"test:
|
|
13
|
+
"test:channel": "yarn --cwd ../alemonjs build && yarn build && node tests/channel.contract.mjs",
|
|
14
|
+
"test:qr": "yarn build && node tests/qr-auth.mjs",
|
|
15
|
+
"test:non-channel": "yarn build && node tests/non-channel.contract.mjs && node tests/framework.contract.mjs && node tests/non-channel.transport.mjs && node tests/media-upload.contract.mjs && node tests/routing.contract.mjs && node tests/lifecycle.contract.mjs && tsc -p tests/tsconfig.non-channel.json",
|
|
16
|
+
"docs:snapshot": "python3 scripts/snapshot-official.py"
|
|
14
17
|
},
|
|
15
18
|
"dependencies": {
|
|
16
19
|
"@noble/curves": "^1.7.0",
|
|
@@ -30,7 +33,7 @@
|
|
|
30
33
|
"yaml": "^2.5.1"
|
|
31
34
|
},
|
|
32
35
|
"peerDependencies": {
|
|
33
|
-
"alemonjs": "^2.1.0
|
|
36
|
+
"alemonjs": "^2.1.0"
|
|
34
37
|
},
|
|
35
38
|
"types": "lib",
|
|
36
39
|
"exports": {
|
|
@@ -97,5 +100,5 @@
|
|
|
97
100
|
"type": "git",
|
|
98
101
|
"url": "https://github.com/lemonade-lab/alemonjs.git"
|
|
99
102
|
},
|
|
100
|
-
"gitHead": "
|
|
101
|
-
}
|
|
103
|
+
"gitHead": "77aa1dad52568d709a460b1cdd32db6c36b6f0c2"
|
|
104
|
+
}
|