@alemonjs/qq-bot 2.1.36 → 2.1.38

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.
Files changed (60) hide show
  1. package/README.md +68 -1979
  2. package/lib/config.d.ts +5 -0
  3. package/lib/framework-actions.d.ts +75 -0
  4. package/lib/framework-actions.js +620 -0
  5. package/lib/framework-events.d.ts +10 -0
  6. package/lib/framework-events.js +182 -0
  7. package/lib/hook.d.ts +16 -12
  8. package/lib/hook.js +5 -9
  9. package/lib/index.d.ts +6 -1
  10. package/lib/index.js +2 -1
  11. package/lib/index.websoket.js +6 -2
  12. package/lib/message/AUDIO_EVENT.d.ts +20 -0
  13. package/lib/message/AUDIO_EVENT.js +1 -0
  14. package/lib/message/FORUM_EVENT.d.ts +33 -0
  15. package/lib/message/FORUM_EVENT.js +1 -0
  16. package/lib/message/GUILD_AUDIT.d.ts +14 -0
  17. package/lib/message/GUILD_AUDIT.js +1 -0
  18. package/lib/message/INTERACTION_CREATE.d.ts +13 -20
  19. package/lib/message/MESSAGE_CREATE.d.ts +3 -9
  20. package/lib/message/MESSAGE_DELETE.d.ts +15 -1
  21. package/lib/message/group/C2C_MESSAGE_CREATE.d.ts +3 -13
  22. package/lib/message/group/C2C_MSG_RECEIVE.d.ts +1 -1
  23. package/lib/message/group/C2C_MSG_REJECT.d.ts +1 -1
  24. package/lib/message/group/FRIEND_ADD.d.ts +7 -1
  25. package/lib/message/group/FRIEND_DEL.d.ts +4 -1
  26. package/lib/message/group/GROUP_AT_MESSAGE_CREATE.d.ts +6 -27
  27. package/lib/message/group/GROUP_MEMBER_ADD.d.ts +4 -2
  28. package/lib/message/group/GROUP_MEMBER_REMOVE.d.ts +4 -2
  29. package/lib/message/group/GROUP_MESSAGE_CREATE.d.ts +6 -27
  30. package/lib/message/group/GROUP_MSG_RECEIVE.d.ts +1 -1
  31. package/lib/message/group/GROUP_MSG_REJECT.d.ts +1 -1
  32. package/lib/message/group/MESSAGE_AUDIT_PASS.d.ts +2 -0
  33. package/lib/message/group/MESSAGE_AUDIT_REJECT.d.ts +2 -0
  34. package/lib/message/group/SUBSCRIBE_MESSAGE_STATUS.d.ts +17 -0
  35. package/lib/message/group/SUBSCRIBE_MESSAGE_STATUS.js +1 -0
  36. package/lib/register.d.ts +1 -0
  37. package/lib/register.js +287 -115
  38. package/lib/sdk/api.d.ts +93 -14
  39. package/lib/sdk/api.js +241 -45
  40. package/lib/sdk/client.webhook.js +39 -19
  41. package/lib/sdk/client.websoket.js +2 -1
  42. package/lib/sdk/instance.d.ts +1 -6
  43. package/lib/sdk/instance.js +20 -66
  44. package/lib/sdk/intents.d.ts +1 -0
  45. package/lib/sdk/intents.js +1 -0
  46. package/lib/sdk/message.d.ts +1 -1
  47. package/lib/sdk/message.group.d.ts +4 -2
  48. package/lib/sdk/message.guild.d.ts +19 -0
  49. package/lib/sdk/non-channel-types.d.ts +138 -0
  50. package/lib/sdk/non-channel-types.js +1 -0
  51. package/lib/sdk/registry.js +2 -2
  52. package/lib/sdk/typing.d.ts +13 -1
  53. package/lib/sdk/webhook.secret.d.ts +1 -1
  54. package/lib/sdk/webhook.secret.js +10 -5
  55. package/lib/sends.d.ts +3 -3
  56. package/lib/sends.js +46 -10
  57. package/lib/text-sanitizer.d.ts +13 -0
  58. package/lib/text-sanitizer.js +26 -0
  59. package/lib/upload.js +13 -37
  60. package/package.json +8 -6
@@ -9,6 +9,7 @@ import { v4 } from "uuid";
9
9
  //#region src/sdk/client.webhook.ts
10
10
  const normalizeGatewayMessage = (message) => {
11
11
  if (!message?.id || !message?.d || typeof message.d !== "object" || Array.isArray(message.d)) return message;
12
+ if (message.t === "INTERACTION_CREATE") message.d.event_id = message.id;
12
13
  if (message.d.id === void 0 || message.d.id === null || message.d.id === "") message.d.id = message.id;
13
14
  return message;
14
15
  };
@@ -23,7 +24,7 @@ var QQBotClient = class extends QQBotAPI {
23
24
  * @param opstion
24
25
  */
25
26
  constructor(opstion) {
26
- super(opstion);
27
+ super({ ...opstion });
27
28
  }
28
29
  /**
29
30
  * 注册事件处理程序
@@ -67,7 +68,13 @@ var QQBotClient = class extends QQBotAPI {
67
68
  if (!ws) {
68
69
  this.#setTimeoutBotConfig();
69
70
  this.#app = new Koa();
70
- this.#app.use(bodyParser());
71
+ this.#app.use(bodyParser({
72
+ enableTypes: ["json"],
73
+ onerror: (_error, ctx) => {
74
+ ctx.status = 400;
75
+ ctx.body = { msg: "invalid json" };
76
+ }
77
+ }));
71
78
  const router = new Router();
72
79
  const port = this.config.get("port");
73
80
  const secret = this.config.get("secret");
@@ -77,31 +84,39 @@ var QQBotClient = class extends QQBotAPI {
77
84
  port: port ? Number(port) : 17157
78
85
  };
79
86
  const ntqqWebhook = new WebhookAPI({ secret: cfg.secret });
80
- this.#app.use(async (ctx, next) => {
81
- let rawData = "";
82
- ctx.req.on("data", (chunk) => rawData += chunk);
83
- ctx.req.on("end", () => ctx.request.rawBody = rawData);
84
- await next();
85
- });
86
87
  router.post(route, (ctx) => {
87
- const sign = ctx.req.headers["x-signature-ed25519"];
88
- const timestamp = ctx.req.headers["x-signature-timestamp"];
89
- const rawBody = ctx.request.rawBody;
90
- if (!ntqqWebhook.validSign(timestamp, rawBody, String(sign))) {
88
+ const request = ctx.request;
89
+ const body = request.body;
90
+ if (!body || typeof body !== "object" || Array.isArray(body) || !Number.isInteger(body.op)) {
91
+ ctx.status = 400;
92
+ ctx.body = { msg: "invalid payload" };
93
+ return;
94
+ }
95
+ if (body.op !== 13 && !ntqqWebhook.validSign(ctx.get("x-signature-timestamp"), request.rawBody, ctx.get("x-signature-ed25519"))) {
91
96
  ctx.status = 400;
92
97
  ctx.body = { msg: "invalid signature" };
93
98
  return;
94
99
  }
95
- const body = normalizeGatewayMessage(ctx.request.body);
96
- if (+body.op === 13) {
100
+ if (body.op === 13) {
101
+ if (typeof body.d?.plain_token !== "string" || !body.d.plain_token || typeof body.d?.event_ts !== "string" || !body.d.event_ts) {
102
+ ctx.status = 400;
103
+ ctx.body = { msg: "invalid validation" };
104
+ return;
105
+ }
97
106
  ctx.status = 200;
98
107
  ctx.body = {
99
108
  plain_token: body.d.plain_token,
100
109
  signature: ntqqWebhook.getSign(body.d.event_ts, body.d.plain_token)
101
110
  };
102
- } else if (+body.op === 0) {
111
+ } else if (body.op === 0) {
112
+ if (typeof body.t !== "string" || !body.t || !body.d || typeof body.d !== "object" || Array.isArray(body.d)) {
113
+ ctx.status = 400;
114
+ ctx.body = { msg: "invalid dispatch" };
115
+ return;
116
+ }
117
+ normalizeGatewayMessage(body);
103
118
  ctx.status = 204;
104
- for (const event of this.#events[body.t] || []) event(body.d);
119
+ this.#dispatch(body);
105
120
  const accessToken = this.config.get("access_token");
106
121
  for (const client of this.#client) try {
107
122
  if (accessToken) body["access_token"] = accessToken;
@@ -130,7 +145,7 @@ var QQBotClient = class extends QQBotAPI {
130
145
  ws.on("message", (message) => {
131
146
  try {
132
147
  const body = normalizeGatewayMessage(JSON.parse(message.toString()));
133
- for (const event of this.#events[body.t] || []) event(body.d);
148
+ this.#dispatch(body);
134
149
  } catch (e) {
135
150
  this.#error(e);
136
151
  }
@@ -153,7 +168,7 @@ var QQBotClient = class extends QQBotAPI {
153
168
  const body = normalizeGatewayMessage(JSON.parse(data.toString()));
154
169
  const accessToken = body["access_token"];
155
170
  if (accessToken) this.config.set("access_token", accessToken);
156
- for (const event of this.#events[body.t] || []) event(body.d);
171
+ this.#dispatch(body);
157
172
  } catch (e) {
158
173
  this.#error(e);
159
174
  }
@@ -176,12 +191,17 @@ var QQBotClient = class extends QQBotAPI {
176
191
  this.#error(e);
177
192
  }
178
193
  }
194
+ /** Acknowledge receipt without waiting for application work. Each listener
195
+ * owns its failure path so a rejection cannot escape the transport. */
196
+ #dispatch(body) {
197
+ for (const event of this.#events[body.t] || []) Promise.resolve().then(() => event(body.d)).catch((error) => this.#error(error));
198
+ }
179
199
  /**
180
200
  *
181
201
  * @param error
182
202
  */
183
203
  #error(error) {
184
- if (this.#events["ERROR"]) for (const event of this.#events["ERROR"] || []) event(error);
204
+ for (const event of this.#events["ERROR"] || []) Promise.resolve().then(() => event(error)).catch((failure) => console.error("[qq-bot] ERROR listener failed", failure instanceof Error ? failure.name : "UnknownError"));
185
205
  }
186
206
  };
187
207
 
@@ -6,6 +6,7 @@ import WebSocket$1 from "ws";
6
6
  //#region src/sdk/client.websoket.ts
7
7
  const normalizeGatewayMessage = (message) => {
8
8
  if (!message?.id || !message?.d || typeof message.d !== "object" || Array.isArray(message.d)) return message;
9
+ if (message.t === "INTERACTION_CREATE") message.d.event_id = message.id;
9
10
  if (message.d.id === void 0 || message.d.id === null || message.d.id === "") message.d.id = message.id;
10
11
  return message;
11
12
  };
@@ -37,7 +38,7 @@ var QQBotClients = class extends QQBotAPI {
37
38
  * @param option
38
39
  */
39
40
  constructor(option) {
40
- super(option);
41
+ super({ ...option });
41
42
  this.#sessionStore = option.sessionStore || new FileSessionStore();
42
43
  }
43
44
  async #loadSession() {
@@ -1,11 +1,6 @@
1
1
  import { AxiosInstance, AxiosRequestConfig } from "axios";
2
2
  //#region src/sdk/instance.d.ts
3
- /**
4
- * 基础请求
5
- * @param service
6
- * @param options
7
- * @returns
8
- */
3
+ /** Preserve native platform failure payloads for existing SDK and Action callers. */
9
4
  declare const createAxiosInstance: (service: AxiosInstance, options: AxiosRequestConfig) => Promise<any>;
10
5
  //#endregion
11
6
  export { createAxiosInstance };
@@ -1,75 +1,29 @@
1
1
  import { logger } from "alemonjs";
2
2
 
3
3
  //#region src/sdk/instance.ts
4
- const filterHeaders = (headers = {}) => {
5
- if (!headers) return headers;
6
- const filtered = {};
7
- const sensitiveKeys = [
8
- /^authorization$/i,
9
- /^cookie$/i,
10
- /^set-cookie$/i,
11
- /token/i,
12
- /key/i,
13
- /jwt/i,
14
- /^session[-_]id$/i,
15
- /^uid$/i,
16
- /^user[-_]id$/i
17
- ];
18
- for (const key in headers) {
19
- if (/^_/.test(key)) continue;
20
- if (typeof key === "symbol") continue;
21
- if (typeof headers[key] === "function") continue;
22
- if (sensitiveKeys.some((re) => re.test(key))) filtered[key] = "******";
23
- else filtered[key] = headers[key];
24
- }
25
- return filtered;
26
- };
27
- const filterConfig = (config = {}) => {
28
- if (!config) return config;
29
- const filtered = {};
30
- for (const key in config) {
31
- if (/^_/.test(key)) continue;
32
- if (typeof key === "symbol") continue;
33
- if (typeof config[key] === "function") continue;
34
- filtered[key] = config[key];
35
- }
36
- return filtered;
37
- };
38
- const filterRequest = (request = {}) => {
39
- if (!request) return request;
40
- const filtered = {};
41
- for (const key in request) {
42
- if (/^_/.test(key)) continue;
43
- if (typeof key === "symbol") continue;
44
- if (typeof request[key] === "function") continue;
45
- filtered[key] = request[key];
46
- }
47
- return filtered;
48
- };
4
+ /** Log an allowlist of diagnostics. Axios config/request objects may contain
5
+ * credentials, signed URLs, message bodies, buffers and circular references. */
49
6
  const loggerError = (err) => {
50
- logger.error("[axios] error", {
51
- config: {
52
- headers: filterHeaders(err?.config?.headers),
53
- params: err?.config?.params,
54
- data: err?.config?.data
55
- },
56
- response: {
57
- status: err?.response?.status,
58
- statusText: err?.response?.statusText,
59
- headers: filterHeaders(err?.response?.headers),
60
- config: filterConfig(err?.response?.config),
61
- request: filterRequest(err?.response?.request),
62
- data: err?.response?.data
63
- },
64
- message: err?.message
7
+ const config = err?.config;
8
+ let path;
9
+ try {
10
+ path = new URL(config?.url ?? "", config?.baseURL || "http://localhost").pathname;
11
+ } catch {
12
+ path = void 0;
13
+ }
14
+ const headers = err?.response?.headers;
15
+ const data = err?.response?.data;
16
+ const scalarCode = (value) => typeof value === "number" || typeof value === "string" && /^[\w-]{1,64}$/.test(value) ? value : void 0;
17
+ logger.error("[qq-bot] HTTP request failed", {
18
+ method: typeof config?.method === "string" ? config.method.toUpperCase() : void 0,
19
+ path,
20
+ status: err?.response?.status,
21
+ code: scalarCode(data?.code ?? data?.err_code),
22
+ transportCode: scalarCode(err?.code),
23
+ traceId: headers?.["x-tps-trace-id"] ?? headers?.["x-trace-id"]
65
24
  });
66
25
  };
67
- /**
68
- * 基础请求
69
- * @param service
70
- * @param options
71
- * @returns
72
- */
26
+ /** Preserve native platform failure payloads for existing SDK and Action callers. */
73
27
  const createAxiosInstance = async (service, options) => {
74
28
  try {
75
29
  return (await service(options))?.data ?? {};
@@ -32,6 +32,7 @@ GROUP_MEMBER_EVENT (1 << 24)
32
32
 
33
33
 
34
34
  GROUP_AND_C2C_EVENT (1 << 25)
35
+ - SUBSCRIBE_MESSAGE_STATUS // 订阅模板授权状态变化
35
36
  - C2C_MESSAGE_CREATE // 用户单聊发消息给机器人时候
36
37
  - FRIEND_ADD // 用户添加使用机器人
37
38
  - FRIEND_DEL // 用户删除机器人
@@ -32,6 +32,7 @@ GROUP_MEMBER_EVENT (1 << 24)
32
32
 
33
33
 
34
34
  GROUP_AND_C2C_EVENT (1 << 25)
35
+ - SUBSCRIBE_MESSAGE_STATUS // 订阅模板授权状态变化
35
36
  - C2C_MESSAGE_CREATE // 用户单聊发消息给机器人时候
36
37
  - FRIEND_ADD // 用户添加使用机器人
37
38
  - FRIEND_DEL // 用户删除机器人
@@ -1,6 +1,6 @@
1
1
  import { QQBotGroupEventMap } from "./message.group.js";
2
- import { QQBotGuildEventMap } from "./message.guild.js";
3
2
  import { QQBotPublicEventMap } from "./message.public.js";
3
+ import { QQBotGuildEventMap } from "./message.guild.js";
4
4
  //#region src/sdk/message.d.ts
5
5
  type QQBotEventMap = QQBotGroupEventMap & QQBotGuildEventMap & QQBotPublicEventMap;
6
6
  //#endregion
@@ -1,3 +1,6 @@
1
+ import { SUBSCRIBE_MESSAGE_STATUS_TYPE } from "../message/group/SUBSCRIBE_MESSAGE_STATUS.js";
2
+ import { GROUP_MEMBER_ADD } from "../message/group/GROUP_MEMBER_ADD.js";
3
+ import { GROUP_MEMBER_REMOVE } from "../message/group/GROUP_MEMBER_REMOVE.js";
1
4
  import { GROUP_AT_MESSAGE_CREATE_TYPE } from "../message/group/GROUP_AT_MESSAGE_CREATE.js";
2
5
  import { GROUP_MESSAGE_CREATE_TYPE } from "../message/group/GROUP_MESSAGE_CREATE.js";
3
6
  import { C2C_MESSAGE_CREATE_TYPE } from "../message/group/C2C_MESSAGE_CREATE.js";
@@ -13,10 +16,9 @@ import { MESSAGE_AUDIT_PASS_TYPE } from "../message/group/MESSAGE_AUDIT_PASS.js"
13
16
  import { MESSAGE_AUDIT_REJECT_TYPE } from "../message/group/MESSAGE_AUDIT_REJECT.js";
14
17
  import { GROUP_JOIN_REQUEST_TYPE } from "../message/group/GROUP_JOIN_REQUEST.js";
15
18
  import { ERROR_TYPE } from "../message/ERROR.js";
16
- import { GROUP_MEMBER_REMOVE } from "../message/group/GROUP_MEMBER_REMOVE.js";
17
- import { GROUP_MEMBER_ADD } from "../message/group/GROUP_MEMBER_ADD.js";
18
19
  //#region src/sdk/message.group.d.ts
19
20
  type QQBotGroupEventMap = {
21
+ SUBSCRIBE_MESSAGE_STATUS: SUBSCRIBE_MESSAGE_STATUS_TYPE;
20
22
  C2C_MESSAGE_CREATE: C2C_MESSAGE_CREATE_TYPE;
21
23
  C2C_MSG_REJECT: C2C_MSG_REJECT_TYPE;
22
24
  C2C_MSG_RECEIVE: C2C_MSG_RECEIVE_TYPE;
@@ -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 { };
@@ -80,7 +80,7 @@ var QQBotRegistry = class {
80
80
  }
81
81
  #requestedBotId(data) {
82
82
  const payload = data?.payload || {};
83
- return payload.target?.BotId || payload.BotId || payload.event?.BotId || payload.event?.Platform?.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?.payload?.BotId;
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)]);
@@ -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
- * 互动召回消息,true 时不校验 msg_id/event_id 有效期
75
+ * 互动召回消息,与 msg_id/event_id 互斥
64
76
  */
65
77
  is_wakeup?: boolean;
66
78
  /**
@@ -13,7 +13,7 @@ declare class WebhookAPI {
13
13
  * @param sign
14
14
  * @returns
15
15
  */
16
- validSign(ts: any, body: any, sign: any): boolean;
16
+ validSign(ts: unknown, body: unknown, sign: unknown): boolean;
17
17
  /**
18
18
  * 生成签名
19
19
  * @param eventTs
@@ -14,11 +14,16 @@ var WebhookAPI = class {
14
14
  * @returns
15
15
  */
16
16
  validSign(ts, body, sign) {
17
- const { publicKey } = this.getKey();
18
- const sig = Buffer.isBuffer(sign) ? sign : Buffer.from(sign, "hex");
19
- const httpBody = Buffer.from(body);
20
- const msg = Buffer.from(ts + httpBody);
21
- return ed25519.verify(sig, msg, publicKey);
17
+ if (typeof ts !== "string" || !ts || typeof body !== "string" && !Buffer.isBuffer(body)) return false;
18
+ if (!Buffer.isBuffer(sign) && (typeof sign !== "string" || !/^[a-f\d]{128}$/i.test(sign))) return false;
19
+ try {
20
+ const { publicKey } = this.getKey();
21
+ const sig = Buffer.isBuffer(sign) ? sign : Buffer.from(sign, "hex");
22
+ const msg = Buffer.concat([Buffer.from(ts), Buffer.isBuffer(body) ? body : Buffer.from(body)]);
23
+ return ed25519.verify(sig, msg, publicKey);
24
+ } catch {
25
+ return false;
26
+ }
22
27
  }
23
28
  /**
24
29
  * 生成签名
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
  /**