@openclaw/feishu 2026.3.11 → 2026.3.13
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/package.json +1 -1
- package/src/accounts.test.ts +40 -16
- package/src/accounts.ts +5 -1
- package/src/bot.ts +20 -11
- package/src/channel.ts +2 -2
- package/src/config-schema.test.ts +67 -16
- package/src/config-schema.ts +30 -9
- package/src/dedup.ts +103 -0
- package/src/media.test.ts +38 -61
- package/src/media.ts +64 -76
- package/src/monitor.account.ts +39 -22
- package/src/monitor.reaction.test.ts +134 -65
- package/src/monitor.startup.test.ts +16 -30
- package/src/monitor.transport.ts +104 -6
- package/src/monitor.webhook-e2e.test.ts +214 -0
- package/src/monitor.webhook-security.test.ts +23 -92
- package/src/monitor.webhook.test-helpers.ts +98 -0
- package/src/onboarding.ts +31 -0
- package/src/outbound.test.ts +11 -16
- package/src/probe.test.ts +112 -113
- package/src/reactions.ts +20 -27
- package/src/reply-dispatcher.test.ts +65 -143
- package/src/reply-dispatcher.ts +37 -40
- package/src/send.reply-fallback.test.ts +50 -40
- package/src/send.ts +95 -91
- package/src/types.ts +14 -0
package/src/send.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { parsePostContent } from "./post.js";
|
|
|
7
7
|
import { getFeishuRuntime } from "./runtime.js";
|
|
8
8
|
import { assertFeishuMessageApiSuccess, toFeishuSendResult } from "./send-result.js";
|
|
9
9
|
import { resolveFeishuSendTarget } from "./send-target.js";
|
|
10
|
-
import type { FeishuSendResult } from "./types.js";
|
|
10
|
+
import type { FeishuChatType, FeishuMessageInfo, FeishuSendResult } from "./types.js";
|
|
11
11
|
|
|
12
12
|
const WITHDRAWN_REPLY_ERROR_CODES = new Set([230011, 231003]);
|
|
13
13
|
|
|
@@ -43,6 +43,10 @@ function isWithdrawnReplyError(err: unknown): boolean {
|
|
|
43
43
|
type FeishuCreateMessageClient = {
|
|
44
44
|
im: {
|
|
45
45
|
message: {
|
|
46
|
+
reply: (opts: {
|
|
47
|
+
path: { message_id: string };
|
|
48
|
+
data: { content: string; msg_type: string; reply_in_thread?: true };
|
|
49
|
+
}) => Promise<{ code?: number; msg?: string; data?: { message_id?: string } }>;
|
|
46
50
|
create: (opts: {
|
|
47
51
|
params: { receive_id_type: "chat_id" | "email" | "open_id" | "union_id" | "user_id" };
|
|
48
52
|
data: { receive_id: string; content: string; msg_type: string };
|
|
@@ -51,6 +55,30 @@ type FeishuCreateMessageClient = {
|
|
|
51
55
|
};
|
|
52
56
|
};
|
|
53
57
|
|
|
58
|
+
type FeishuMessageSender = {
|
|
59
|
+
id?: string;
|
|
60
|
+
id_type?: string;
|
|
61
|
+
sender_type?: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type FeishuMessageGetItem = {
|
|
65
|
+
message_id?: string;
|
|
66
|
+
chat_id?: string;
|
|
67
|
+
chat_type?: FeishuChatType;
|
|
68
|
+
msg_type?: string;
|
|
69
|
+
body?: { content?: string };
|
|
70
|
+
sender?: FeishuMessageSender;
|
|
71
|
+
create_time?: string;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
type FeishuGetMessageResponse = {
|
|
75
|
+
code?: number;
|
|
76
|
+
msg?: string;
|
|
77
|
+
data?: FeishuMessageGetItem & {
|
|
78
|
+
items?: FeishuMessageGetItem[];
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
54
82
|
/** Send a direct message as a fallback when a reply target is unavailable. */
|
|
55
83
|
async function sendFallbackDirect(
|
|
56
84
|
client: FeishuCreateMessageClient,
|
|
@@ -74,16 +102,49 @@ async function sendFallbackDirect(
|
|
|
74
102
|
return toFeishuSendResult(response, params.receiveId);
|
|
75
103
|
}
|
|
76
104
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
105
|
+
async function sendReplyOrFallbackDirect(
|
|
106
|
+
client: FeishuCreateMessageClient,
|
|
107
|
+
params: {
|
|
108
|
+
replyToMessageId?: string;
|
|
109
|
+
replyInThread?: boolean;
|
|
110
|
+
content: string;
|
|
111
|
+
msgType: string;
|
|
112
|
+
directParams: {
|
|
113
|
+
receiveId: string;
|
|
114
|
+
receiveIdType: "chat_id" | "email" | "open_id" | "union_id" | "user_id";
|
|
115
|
+
content: string;
|
|
116
|
+
msgType: string;
|
|
117
|
+
};
|
|
118
|
+
directErrorPrefix: string;
|
|
119
|
+
replyErrorPrefix: string;
|
|
120
|
+
},
|
|
121
|
+
): Promise<FeishuSendResult> {
|
|
122
|
+
if (!params.replyToMessageId) {
|
|
123
|
+
return sendFallbackDirect(client, params.directParams, params.directErrorPrefix);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let response: { code?: number; msg?: string; data?: { message_id?: string } };
|
|
127
|
+
try {
|
|
128
|
+
response = await client.im.message.reply({
|
|
129
|
+
path: { message_id: params.replyToMessageId },
|
|
130
|
+
data: {
|
|
131
|
+
content: params.content,
|
|
132
|
+
msg_type: params.msgType,
|
|
133
|
+
...(params.replyInThread ? { reply_in_thread: true } : {}),
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
} catch (err) {
|
|
137
|
+
if (!isWithdrawnReplyError(err)) {
|
|
138
|
+
throw err;
|
|
139
|
+
}
|
|
140
|
+
return sendFallbackDirect(client, params.directParams, params.directErrorPrefix);
|
|
141
|
+
}
|
|
142
|
+
if (shouldFallbackFromReplyTarget(response)) {
|
|
143
|
+
return sendFallbackDirect(client, params.directParams, params.directErrorPrefix);
|
|
144
|
+
}
|
|
145
|
+
assertFeishuMessageApiSuccess(response, params.replyErrorPrefix);
|
|
146
|
+
return toFeishuSendResult(response, params.directParams.receiveId);
|
|
147
|
+
}
|
|
87
148
|
|
|
88
149
|
function parseInteractiveCardContent(parsed: unknown): string {
|
|
89
150
|
if (!parsed || typeof parsed !== "object") {
|
|
@@ -177,34 +238,7 @@ export async function getMessageFeishu(params: {
|
|
|
177
238
|
try {
|
|
178
239
|
const response = (await client.im.message.get({
|
|
179
240
|
path: { message_id: messageId },
|
|
180
|
-
})) as
|
|
181
|
-
code?: number;
|
|
182
|
-
msg?: string;
|
|
183
|
-
data?: {
|
|
184
|
-
items?: Array<{
|
|
185
|
-
message_id?: string;
|
|
186
|
-
chat_id?: string;
|
|
187
|
-
msg_type?: string;
|
|
188
|
-
body?: { content?: string };
|
|
189
|
-
sender?: {
|
|
190
|
-
id?: string;
|
|
191
|
-
id_type?: string;
|
|
192
|
-
sender_type?: string;
|
|
193
|
-
};
|
|
194
|
-
create_time?: string;
|
|
195
|
-
}>;
|
|
196
|
-
message_id?: string;
|
|
197
|
-
chat_id?: string;
|
|
198
|
-
msg_type?: string;
|
|
199
|
-
body?: { content?: string };
|
|
200
|
-
sender?: {
|
|
201
|
-
id?: string;
|
|
202
|
-
id_type?: string;
|
|
203
|
-
sender_type?: string;
|
|
204
|
-
};
|
|
205
|
-
create_time?: string;
|
|
206
|
-
};
|
|
207
|
-
};
|
|
241
|
+
})) as FeishuGetMessageResponse;
|
|
208
242
|
|
|
209
243
|
if (response.code !== 0) {
|
|
210
244
|
return null;
|
|
@@ -228,6 +262,10 @@ export async function getMessageFeishu(params: {
|
|
|
228
262
|
return {
|
|
229
263
|
messageId: item.message_id ?? messageId,
|
|
230
264
|
chatId: item.chat_id ?? "",
|
|
265
|
+
chatType:
|
|
266
|
+
item.chat_type === "group" || item.chat_type === "private" || item.chat_type === "p2p"
|
|
267
|
+
? item.chat_type
|
|
268
|
+
: undefined,
|
|
231
269
|
senderId: item.sender?.id,
|
|
232
270
|
senderOpenId: item.sender?.id_type === "open_id" ? item.sender?.id : undefined,
|
|
233
271
|
senderType: item.sender?.sender_type,
|
|
@@ -295,32 +333,15 @@ export async function sendMessageFeishu(
|
|
|
295
333
|
const { content, msgType } = buildFeishuPostMessagePayload({ messageText });
|
|
296
334
|
|
|
297
335
|
const directParams = { receiveId, receiveIdType, content, msgType };
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
...(replyInThread ? { reply_in_thread: true } : {}),
|
|
308
|
-
},
|
|
309
|
-
});
|
|
310
|
-
} catch (err) {
|
|
311
|
-
if (!isWithdrawnReplyError(err)) {
|
|
312
|
-
throw err;
|
|
313
|
-
}
|
|
314
|
-
return sendFallbackDirect(client, directParams, "Feishu send failed");
|
|
315
|
-
}
|
|
316
|
-
if (shouldFallbackFromReplyTarget(response)) {
|
|
317
|
-
return sendFallbackDirect(client, directParams, "Feishu send failed");
|
|
318
|
-
}
|
|
319
|
-
assertFeishuMessageApiSuccess(response, "Feishu reply failed");
|
|
320
|
-
return toFeishuSendResult(response, receiveId);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return sendFallbackDirect(client, directParams, "Feishu send failed");
|
|
336
|
+
return sendReplyOrFallbackDirect(client, {
|
|
337
|
+
replyToMessageId,
|
|
338
|
+
replyInThread,
|
|
339
|
+
content,
|
|
340
|
+
msgType,
|
|
341
|
+
directParams,
|
|
342
|
+
directErrorPrefix: "Feishu send failed",
|
|
343
|
+
replyErrorPrefix: "Feishu reply failed",
|
|
344
|
+
});
|
|
324
345
|
}
|
|
325
346
|
|
|
326
347
|
export type SendFeishuCardParams = {
|
|
@@ -339,32 +360,15 @@ export async function sendCardFeishu(params: SendFeishuCardParams): Promise<Feis
|
|
|
339
360
|
const content = JSON.stringify(card);
|
|
340
361
|
|
|
341
362
|
const directParams = { receiveId, receiveIdType, content, msgType: "interactive" };
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
...(replyInThread ? { reply_in_thread: true } : {}),
|
|
352
|
-
},
|
|
353
|
-
});
|
|
354
|
-
} catch (err) {
|
|
355
|
-
if (!isWithdrawnReplyError(err)) {
|
|
356
|
-
throw err;
|
|
357
|
-
}
|
|
358
|
-
return sendFallbackDirect(client, directParams, "Feishu card send failed");
|
|
359
|
-
}
|
|
360
|
-
if (shouldFallbackFromReplyTarget(response)) {
|
|
361
|
-
return sendFallbackDirect(client, directParams, "Feishu card send failed");
|
|
362
|
-
}
|
|
363
|
-
assertFeishuMessageApiSuccess(response, "Feishu card reply failed");
|
|
364
|
-
return toFeishuSendResult(response, receiveId);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return sendFallbackDirect(client, directParams, "Feishu card send failed");
|
|
363
|
+
return sendReplyOrFallbackDirect(client, {
|
|
364
|
+
replyToMessageId,
|
|
365
|
+
replyInThread,
|
|
366
|
+
content,
|
|
367
|
+
msgType: "interactive",
|
|
368
|
+
directParams,
|
|
369
|
+
directErrorPrefix: "Feishu card send failed",
|
|
370
|
+
replyErrorPrefix: "Feishu card reply failed",
|
|
371
|
+
});
|
|
368
372
|
}
|
|
369
373
|
|
|
370
374
|
export async function updateCardFeishu(params: {
|
package/src/types.ts
CHANGED
|
@@ -60,6 +60,20 @@ export type FeishuSendResult = {
|
|
|
60
60
|
chatId: string;
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
export type FeishuChatType = "p2p" | "group" | "private";
|
|
64
|
+
|
|
65
|
+
export type FeishuMessageInfo = {
|
|
66
|
+
messageId: string;
|
|
67
|
+
chatId: string;
|
|
68
|
+
chatType?: FeishuChatType;
|
|
69
|
+
senderId?: string;
|
|
70
|
+
senderOpenId?: string;
|
|
71
|
+
senderType?: string;
|
|
72
|
+
content: string;
|
|
73
|
+
contentType: string;
|
|
74
|
+
createTime?: number;
|
|
75
|
+
};
|
|
76
|
+
|
|
63
77
|
export type FeishuProbeResult = BaseProbeResult<string> & {
|
|
64
78
|
appId?: string;
|
|
65
79
|
botName?: string;
|