@openclaw/feishu 2026.5.2-beta.2 → 2026.5.3-beta.1
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/accounts-Ba3-WP1z.js +423 -0
- package/dist/api.js +2280 -0
- package/dist/app-registration-B8qc1MCM.js +184 -0
- package/dist/audio-preflight.runtime-BPlzkO3l.js +7 -0
- package/dist/card-interaction-BfRLgvw_.js +96 -0
- package/dist/channel-CSD_Jt8I.js +1668 -0
- package/dist/channel-entry.js +22 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-DYsXcD36.js +700 -0
- package/dist/client-DBVoQL5w.js +157 -0
- package/dist/contract-api.js +9 -0
- package/dist/conversation-id-DWS3Ep2A.js +139 -0
- package/dist/directory.static-f3EeoRJd.js +44 -0
- package/dist/drive-C5eJLJr7.js +883 -0
- package/dist/index.js +68 -0
- package/dist/monitor-CT189QfR.js +60 -0
- package/dist/monitor.account-dJV2jO8C.js +4990 -0
- package/dist/monitor.state-DYM02ipp.js +100 -0
- package/dist/policy-D6c-wMPl.js +118 -0
- package/dist/probe-BNzzU_uR.js +149 -0
- package/dist/rolldown-runtime-DUslC3ob.js +14 -0
- package/dist/runtime-CG0DuRCy.js +8 -0
- package/dist/runtime-api.js +14 -0
- package/dist/secret-contract-Dm4Z_zQN.js +119 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/security-audit-DqJdocrN.js +11 -0
- package/dist/security-audit-shared-ByuMx9cJ.js +38 -0
- package/dist/security-contract-api.js +2 -0
- package/dist/send-DowxxbpH.js +1218 -0
- package/dist/session-conversation-B4nrW-vo.js +27 -0
- package/dist/session-key-api.js +2 -0
- package/dist/setup-api.js +2 -0
- package/dist/setup-entry.js +15 -0
- package/dist/subagent-hooks-C3UhPVLV.js +227 -0
- package/dist/subagent-hooks-api.js +23 -0
- package/dist/targets-JMFJRKSe.js +48 -0
- package/dist/thread-bindings-BmS6TLes.js +222 -0
- package/package.json +15 -6
- package/api.ts +0 -31
- package/channel-entry.ts +0 -20
- package/channel-plugin-api.ts +0 -1
- package/contract-api.ts +0 -16
- package/index.ts +0 -82
- package/runtime-api.ts +0 -55
- package/secret-contract-api.ts +0 -5
- package/security-contract-api.ts +0 -1
- package/session-key-api.ts +0 -1
- package/setup-api.ts +0 -3
- package/setup-entry.test.ts +0 -14
- package/setup-entry.ts +0 -13
- package/src/accounts.test.ts +0 -459
- package/src/accounts.ts +0 -326
- package/src/app-registration.ts +0 -331
- package/src/approval-auth.test.ts +0 -24
- package/src/approval-auth.ts +0 -25
- package/src/async.test.ts +0 -35
- package/src/async.ts +0 -104
- package/src/audio-preflight.runtime.ts +0 -9
- package/src/bitable.test.ts +0 -131
- package/src/bitable.ts +0 -762
- package/src/bot-content.ts +0 -474
- package/src/bot-group-name.test.ts +0 -108
- package/src/bot-runtime-api.ts +0 -12
- package/src/bot-sender-name.ts +0 -125
- package/src/bot.broadcast.test.ts +0 -463
- package/src/bot.card-action.test.ts +0 -577
- package/src/bot.checkBotMentioned.test.ts +0 -265
- package/src/bot.helpers.test.ts +0 -118
- package/src/bot.stripBotMention.test.ts +0 -126
- package/src/bot.test.ts +0 -3040
- package/src/bot.ts +0 -1559
- package/src/card-action.ts +0 -447
- package/src/card-interaction.test.ts +0 -129
- package/src/card-interaction.ts +0 -159
- package/src/card-test-helpers.ts +0 -47
- package/src/card-ux-approval.ts +0 -65
- package/src/card-ux-launcher.test.ts +0 -99
- package/src/card-ux-launcher.ts +0 -121
- package/src/card-ux-shared.ts +0 -33
- package/src/channel-runtime-api.ts +0 -16
- package/src/channel.runtime.ts +0 -47
- package/src/channel.test.ts +0 -959
- package/src/channel.ts +0 -1313
- package/src/chat-schema.ts +0 -25
- package/src/chat.test.ts +0 -196
- package/src/chat.ts +0 -188
- package/src/client.test.ts +0 -433
- package/src/client.ts +0 -290
- package/src/comment-dispatcher-runtime-api.ts +0 -6
- package/src/comment-dispatcher.test.ts +0 -169
- package/src/comment-dispatcher.ts +0 -107
- package/src/comment-handler-runtime-api.ts +0 -3
- package/src/comment-handler.test.ts +0 -486
- package/src/comment-handler.ts +0 -309
- package/src/comment-reaction.test.ts +0 -166
- package/src/comment-reaction.ts +0 -259
- package/src/comment-shared.test.ts +0 -182
- package/src/comment-shared.ts +0 -406
- package/src/comment-target.ts +0 -44
- package/src/config-schema.test.ts +0 -309
- package/src/config-schema.ts +0 -333
- package/src/conversation-id.test.ts +0 -18
- package/src/conversation-id.ts +0 -199
- package/src/dedup-runtime-api.ts +0 -1
- package/src/dedup.ts +0 -141
- package/src/directory.static.ts +0 -61
- package/src/directory.test.ts +0 -136
- package/src/directory.ts +0 -124
- package/src/doc-schema.ts +0 -182
- package/src/docx-batch-insert.test.ts +0 -91
- package/src/docx-batch-insert.ts +0 -223
- package/src/docx-color-text.ts +0 -154
- package/src/docx-table-ops.test.ts +0 -53
- package/src/docx-table-ops.ts +0 -316
- package/src/docx-types.ts +0 -38
- package/src/docx.account-selection.test.ts +0 -79
- package/src/docx.test.ts +0 -685
- package/src/docx.ts +0 -1616
- package/src/drive-schema.ts +0 -92
- package/src/drive.test.ts +0 -1219
- package/src/drive.ts +0 -829
- package/src/dynamic-agent.ts +0 -137
- package/src/event-types.ts +0 -45
- package/src/external-keys.test.ts +0 -20
- package/src/external-keys.ts +0 -19
- package/src/lifecycle.test-support.ts +0 -220
- package/src/media.test.ts +0 -900
- package/src/media.ts +0 -861
- package/src/mention-target.types.ts +0 -5
- package/src/mention.ts +0 -114
- package/src/message-action-contract.ts +0 -13
- package/src/monitor-state-runtime-api.ts +0 -7
- package/src/monitor-transport-runtime-api.ts +0 -7
- package/src/monitor.account.ts +0 -468
- package/src/monitor.acp-init-failure.lifecycle.test-support.ts +0 -219
- package/src/monitor.bot-identity.ts +0 -86
- package/src/monitor.bot-menu-handler.ts +0 -165
- package/src/monitor.bot-menu.lifecycle.test-support.ts +0 -224
- package/src/monitor.bot-menu.test.ts +0 -178
- package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +0 -264
- package/src/monitor.card-action.lifecycle.test-support.ts +0 -373
- package/src/monitor.cleanup.test.ts +0 -376
- package/src/monitor.comment-notice-handler.ts +0 -105
- package/src/monitor.comment.test.ts +0 -937
- package/src/monitor.comment.ts +0 -1386
- package/src/monitor.lifecycle.test.ts +0 -4
- package/src/monitor.message-handler.ts +0 -339
- package/src/monitor.reaction.lifecycle.test-support.ts +0 -68
- package/src/monitor.reaction.test.ts +0 -713
- package/src/monitor.startup.test.ts +0 -192
- package/src/monitor.startup.ts +0 -74
- package/src/monitor.state.defaults.test.ts +0 -46
- package/src/monitor.state.ts +0 -170
- package/src/monitor.synthetic-error.ts +0 -18
- package/src/monitor.test-mocks.ts +0 -45
- package/src/monitor.transport.ts +0 -424
- package/src/monitor.ts +0 -100
- package/src/monitor.webhook-e2e.test.ts +0 -272
- package/src/monitor.webhook-security.test.ts +0 -264
- package/src/monitor.webhook.test-helpers.ts +0 -116
- package/src/outbound-runtime-api.ts +0 -1
- package/src/outbound.test.ts +0 -935
- package/src/outbound.ts +0 -718
- package/src/perm-schema.ts +0 -52
- package/src/perm.ts +0 -170
- package/src/pins.ts +0 -108
- package/src/policy.test.ts +0 -334
- package/src/policy.ts +0 -236
- package/src/post.test.ts +0 -105
- package/src/post.ts +0 -275
- package/src/probe.test.ts +0 -275
- package/src/probe.ts +0 -166
- package/src/processing-claims.ts +0 -59
- package/src/qr-terminal.ts +0 -1
- package/src/reactions.ts +0 -123
- package/src/reasoning-preview.test.ts +0 -59
- package/src/reasoning-preview.ts +0 -20
- package/src/reply-dispatcher-runtime-api.ts +0 -7
- package/src/reply-dispatcher.test.ts +0 -1144
- package/src/reply-dispatcher.ts +0 -650
- package/src/runtime.ts +0 -9
- package/src/secret-contract.ts +0 -145
- package/src/secret-input.ts +0 -1
- package/src/security-audit-shared.ts +0 -69
- package/src/security-audit.test.ts +0 -61
- package/src/security-audit.ts +0 -1
- package/src/send-result.ts +0 -29
- package/src/send-target.test.ts +0 -80
- package/src/send-target.ts +0 -35
- package/src/send.reply-fallback.test.ts +0 -292
- package/src/send.test.ts +0 -550
- package/src/send.ts +0 -800
- package/src/sequential-key.test.ts +0 -72
- package/src/sequential-key.ts +0 -28
- package/src/sequential-queue.test.ts +0 -92
- package/src/sequential-queue.ts +0 -16
- package/src/session-conversation.ts +0 -42
- package/src/session-route.ts +0 -48
- package/src/setup-core.ts +0 -51
- package/src/setup-surface.test.ts +0 -174
- package/src/setup-surface.ts +0 -581
- package/src/streaming-card.test.ts +0 -190
- package/src/streaming-card.ts +0 -490
- package/src/subagent-hooks.test.ts +0 -603
- package/src/subagent-hooks.ts +0 -397
- package/src/targets.ts +0 -97
- package/src/test-support/lifecycle-test-support.ts +0 -453
- package/src/thread-bindings.test.ts +0 -143
- package/src/thread-bindings.ts +0 -330
- package/src/tool-account-routing.test.ts +0 -187
- package/src/tool-account.test.ts +0 -44
- package/src/tool-account.ts +0 -93
- package/src/tool-factory-test-harness.ts +0 -79
- package/src/tool-result.test.ts +0 -32
- package/src/tool-result.ts +0 -16
- package/src/tools-config.test.ts +0 -21
- package/src/tools-config.ts +0 -22
- package/src/types.ts +0 -104
- package/src/typing.test.ts +0 -144
- package/src/typing.ts +0 -214
- package/src/wiki-schema.ts +0 -55
- package/src/wiki.ts +0 -227
- package/subagent-hooks-api.ts +0 -31
- package/tsconfig.json +0 -16
|
@@ -0,0 +1,700 @@
|
|
|
1
|
+
import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount, y as parseFeishuCommentTarget } from "./accounts-Ba3-WP1z.js";
|
|
2
|
+
import { r as createFeishuCardInteractionEnvelope } from "./card-interaction-BfRLgvw_.js";
|
|
3
|
+
import { n as listFeishuDirectoryPeers, t as listFeishuDirectoryGroups } from "./directory.static-f3EeoRJd.js";
|
|
4
|
+
import { r as createFeishuClient } from "./client-DBVoQL5w.js";
|
|
5
|
+
import { c as getChatInfo, l as getChatMembers, r as cleanupAmbientCommentTypingReaction, t as deliverCommentThreadText, u as getFeishuMemberInfo } from "./drive-C5eJLJr7.js";
|
|
6
|
+
import { chunkTextForOutbound } from "./runtime-api.js";
|
|
7
|
+
import { _ as shouldSuppressFeishuTextForVoiceMedia, a as sendCardFeishu, c as sendStructuredCardFeishu, g as sendMediaFeishu, i as resolveFeishuCardTemplate, n as getMessageFeishu, o as sendMarkdownCardFeishu, s as sendMessageFeishu, t as editMessageFeishu } from "./send-DowxxbpH.js";
|
|
8
|
+
import { t as probeFeishu } from "./probe-BNzzU_uR.js";
|
|
9
|
+
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
|
10
|
+
import { interactiveReplyToPresentation, normalizeInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
|
|
14
|
+
import { resolvePayloadMediaUrls, sendPayloadMediaSequenceAndFinalize, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
|
|
15
|
+
//#region extensions/feishu/src/directory.ts
|
|
16
|
+
async function listFeishuDirectoryPeersLive(params) {
|
|
17
|
+
const account = resolveFeishuAccount({
|
|
18
|
+
cfg: params.cfg,
|
|
19
|
+
accountId: params.accountId
|
|
20
|
+
});
|
|
21
|
+
if (!account.configured) return listFeishuDirectoryPeers(params);
|
|
22
|
+
try {
|
|
23
|
+
const client = createFeishuClient(account);
|
|
24
|
+
const peers = [];
|
|
25
|
+
const limit = params.limit ?? 50;
|
|
26
|
+
const response = await client.contact.user.list({ params: { page_size: Math.min(limit, 50) } });
|
|
27
|
+
if (response.code !== 0) throw new Error(response.msg || `code ${response.code}`);
|
|
28
|
+
const q = normalizeLowercaseStringOrEmpty(params.query);
|
|
29
|
+
for (const user of response.data?.items ?? []) {
|
|
30
|
+
if (user.open_id) {
|
|
31
|
+
const name = user.name || "";
|
|
32
|
+
if (!q || normalizeLowercaseStringOrEmpty(user.open_id).includes(q) || normalizeLowercaseStringOrEmpty(name).includes(q)) peers.push({
|
|
33
|
+
kind: "user",
|
|
34
|
+
id: user.open_id,
|
|
35
|
+
name: name || void 0
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (peers.length >= limit) break;
|
|
39
|
+
}
|
|
40
|
+
return peers;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (params.fallbackToStatic === false) throw err instanceof Error ? err : /* @__PURE__ */ new Error("Feishu live peer lookup failed");
|
|
43
|
+
return listFeishuDirectoryPeers(params);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function listFeishuDirectoryGroupsLive(params) {
|
|
47
|
+
const account = resolveFeishuAccount({
|
|
48
|
+
cfg: params.cfg,
|
|
49
|
+
accountId: params.accountId
|
|
50
|
+
});
|
|
51
|
+
if (!account.configured) return listFeishuDirectoryGroups(params);
|
|
52
|
+
try {
|
|
53
|
+
const client = createFeishuClient(account);
|
|
54
|
+
const groups = [];
|
|
55
|
+
const limit = params.limit ?? 50;
|
|
56
|
+
const response = await client.im.chat.list({ params: { page_size: Math.min(limit, 100) } });
|
|
57
|
+
if (response.code !== 0) throw new Error(response.msg || `code ${response.code}`);
|
|
58
|
+
const q = normalizeLowercaseStringOrEmpty(params.query);
|
|
59
|
+
for (const chat of response.data?.items ?? []) {
|
|
60
|
+
if (chat.chat_id) {
|
|
61
|
+
const name = chat.name || "";
|
|
62
|
+
if (!q || normalizeLowercaseStringOrEmpty(chat.chat_id).includes(q) || normalizeLowercaseStringOrEmpty(name).includes(q)) groups.push({
|
|
63
|
+
kind: "group",
|
|
64
|
+
id: chat.chat_id,
|
|
65
|
+
name: name || void 0
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (groups.length >= limit) break;
|
|
69
|
+
}
|
|
70
|
+
return groups;
|
|
71
|
+
} catch (err) {
|
|
72
|
+
if (params.fallbackToStatic === false) throw err instanceof Error ? err : /* @__PURE__ */ new Error("Feishu live group lookup failed");
|
|
73
|
+
return listFeishuDirectoryGroups(params);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region extensions/feishu/src/outbound.ts
|
|
78
|
+
const RENDERED_FEISHU_CARD = Symbol("openclaw.renderedFeishuCard");
|
|
79
|
+
function normalizePossibleLocalImagePath(text) {
|
|
80
|
+
const raw = text?.trim();
|
|
81
|
+
if (!raw) return null;
|
|
82
|
+
if (/\s/.test(raw)) return null;
|
|
83
|
+
if (/^(https?:\/\/|data:|file:\/\/)/i.test(raw)) return null;
|
|
84
|
+
const ext = normalizeLowercaseStringOrEmpty(path.extname(raw));
|
|
85
|
+
if (![
|
|
86
|
+
".jpg",
|
|
87
|
+
".jpeg",
|
|
88
|
+
".png",
|
|
89
|
+
".gif",
|
|
90
|
+
".webp",
|
|
91
|
+
".bmp",
|
|
92
|
+
".ico",
|
|
93
|
+
".tiff"
|
|
94
|
+
].includes(ext)) return null;
|
|
95
|
+
if (!path.isAbsolute(raw)) return null;
|
|
96
|
+
if (!fs.existsSync(raw)) return null;
|
|
97
|
+
try {
|
|
98
|
+
if (!fs.statSync(raw).isFile()) return null;
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return raw;
|
|
103
|
+
}
|
|
104
|
+
function shouldUseCard(text) {
|
|
105
|
+
return /```[\s\S]*?```/.test(text) || /\|.+\|[\r\n]+\|[-:| ]+\|/.test(text);
|
|
106
|
+
}
|
|
107
|
+
function isRecord$1(value) {
|
|
108
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
109
|
+
}
|
|
110
|
+
function escapeFeishuCardMarkdownText(text) {
|
|
111
|
+
return text.replace(/[&<>]/g, (char) => {
|
|
112
|
+
switch (char) {
|
|
113
|
+
case "&": return "&";
|
|
114
|
+
case "<": return "<";
|
|
115
|
+
case ">": return ">";
|
|
116
|
+
default: return char;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function resolveSafeFeishuButtonUrl(url) {
|
|
121
|
+
const trimmed = url?.trim();
|
|
122
|
+
if (!trimmed) return;
|
|
123
|
+
try {
|
|
124
|
+
const parsed = new URL(trimmed);
|
|
125
|
+
return parsed.protocol === "https:" || parsed.protocol === "http:" ? trimmed : void 0;
|
|
126
|
+
} catch {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function markRenderedFeishuCard(card) {
|
|
131
|
+
Object.defineProperty(card, RENDERED_FEISHU_CARD, {
|
|
132
|
+
value: true,
|
|
133
|
+
enumerable: false
|
|
134
|
+
});
|
|
135
|
+
return card;
|
|
136
|
+
}
|
|
137
|
+
function sanitizeNativeFeishuCardButton(button) {
|
|
138
|
+
if (!isRecord$1(button)) return;
|
|
139
|
+
const text = isRecord$1(button.text) && typeof button.text.content === "string" ? button.text.content : void 0;
|
|
140
|
+
if (!text?.trim()) return;
|
|
141
|
+
const style = button.type === "danger" ? "danger" : button.type === "primary" ? "primary" : void 0;
|
|
142
|
+
const rendered = {
|
|
143
|
+
tag: "button",
|
|
144
|
+
text: {
|
|
145
|
+
tag: "plain_text",
|
|
146
|
+
content: text
|
|
147
|
+
},
|
|
148
|
+
type: mapFeishuButtonType(style)
|
|
149
|
+
};
|
|
150
|
+
const safeUrl = resolveSafeFeishuButtonUrl(typeof button.url === "string" ? button.url : void 0);
|
|
151
|
+
if (safeUrl) rendered.url = safeUrl;
|
|
152
|
+
if (isRecord$1(button.value) && button.value.oc === "ocf1") rendered.value = button.value;
|
|
153
|
+
return rendered.url || rendered.value ? rendered : void 0;
|
|
154
|
+
}
|
|
155
|
+
function sanitizeNativeFeishuCardElement(element) {
|
|
156
|
+
if (!isRecord$1(element) || typeof element.tag !== "string") return;
|
|
157
|
+
if (element.tag === "hr") return { tag: "hr" };
|
|
158
|
+
if (element.tag === "markdown" && typeof element.content === "string") return {
|
|
159
|
+
tag: "markdown",
|
|
160
|
+
content: escapeFeishuCardMarkdownText(element.content)
|
|
161
|
+
};
|
|
162
|
+
if (element.tag === "action" && Array.isArray(element.actions)) {
|
|
163
|
+
const actions = element.actions.map((action) => sanitizeNativeFeishuCardButton(action)).filter((action) => Boolean(action));
|
|
164
|
+
return actions.length > 0 ? {
|
|
165
|
+
tag: "action",
|
|
166
|
+
actions
|
|
167
|
+
} : void 0;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function sanitizeNativeFeishuCard(card) {
|
|
171
|
+
const body = isRecord$1(card.body) ? card.body : void 0;
|
|
172
|
+
const elements = (Array.isArray(body?.elements) ? body.elements : []).map((element) => sanitizeNativeFeishuCardElement(element)).filter((element) => Boolean(element));
|
|
173
|
+
if (elements.length === 0) return;
|
|
174
|
+
const header = isRecord$1(card.header) ? card.header : void 0;
|
|
175
|
+
const title = isRecord$1(header?.title) && typeof header.title.content === "string" ? header.title.content : void 0;
|
|
176
|
+
return markRenderedFeishuCard({
|
|
177
|
+
schema: "2.0",
|
|
178
|
+
config: { width_mode: "fill" },
|
|
179
|
+
...title?.trim() ? { header: {
|
|
180
|
+
title: {
|
|
181
|
+
tag: "plain_text",
|
|
182
|
+
content: title
|
|
183
|
+
},
|
|
184
|
+
template: resolveFeishuCardTemplate(typeof header?.template === "string" ? header.template : void 0) ?? "blue"
|
|
185
|
+
} } : {},
|
|
186
|
+
body: { elements }
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function readNativeFeishuCard(payload) {
|
|
190
|
+
const feishuData = payload.channelData?.feishu;
|
|
191
|
+
if (!isRecord$1(feishuData)) return;
|
|
192
|
+
const card = feishuData.card ?? feishuData.interactiveCard;
|
|
193
|
+
if (!isRecord$1(card)) return;
|
|
194
|
+
if (card[RENDERED_FEISHU_CARD] === true) return card;
|
|
195
|
+
return sanitizeNativeFeishuCard(card);
|
|
196
|
+
}
|
|
197
|
+
function mapFeishuButtonType(style) {
|
|
198
|
+
if (style === "primary" || style === "success") return "primary";
|
|
199
|
+
if (style === "danger") return "danger";
|
|
200
|
+
return "default";
|
|
201
|
+
}
|
|
202
|
+
function buildFeishuPayloadButton(button) {
|
|
203
|
+
const rendered = {
|
|
204
|
+
tag: "button",
|
|
205
|
+
text: {
|
|
206
|
+
tag: "plain_text",
|
|
207
|
+
content: button.label
|
|
208
|
+
},
|
|
209
|
+
type: mapFeishuButtonType(button.style)
|
|
210
|
+
};
|
|
211
|
+
if (button.url) {
|
|
212
|
+
const safeUrl = resolveSafeFeishuButtonUrl(button.url);
|
|
213
|
+
if (safeUrl) rendered.url = safeUrl;
|
|
214
|
+
}
|
|
215
|
+
if (button.value) rendered.value = createFeishuCardInteractionEnvelope({
|
|
216
|
+
k: "quick",
|
|
217
|
+
a: "feishu.payload.button",
|
|
218
|
+
q: button.value
|
|
219
|
+
});
|
|
220
|
+
return rendered.url || rendered.value ? rendered : void 0;
|
|
221
|
+
}
|
|
222
|
+
function buildFeishuCardElementForBlock(block) {
|
|
223
|
+
if (block.type === "text") return {
|
|
224
|
+
tag: "markdown",
|
|
225
|
+
content: escapeFeishuCardMarkdownText(block.text)
|
|
226
|
+
};
|
|
227
|
+
if (block.type === "context") return {
|
|
228
|
+
tag: "markdown",
|
|
229
|
+
content: `<font color='grey'>${escapeFeishuCardMarkdownText(block.text)}</font>`
|
|
230
|
+
};
|
|
231
|
+
if (block.type === "divider") return { tag: "hr" };
|
|
232
|
+
if (block.type === "buttons") {
|
|
233
|
+
const actions = block.buttons.map((button) => buildFeishuPayloadButton(button)).filter((button) => Boolean(button));
|
|
234
|
+
if (actions.length === 0) return;
|
|
235
|
+
return {
|
|
236
|
+
tag: "action",
|
|
237
|
+
actions
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const labels = block.options.map((option) => `- ${option.label}`).join("\n");
|
|
241
|
+
return {
|
|
242
|
+
tag: "markdown",
|
|
243
|
+
content: `${escapeFeishuCardMarkdownText(block.placeholder?.trim() || "Options")}:\n${escapeFeishuCardMarkdownText(labels)}`
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function buildFeishuPayloadCard(params) {
|
|
247
|
+
const nativeCard = readNativeFeishuCard(params.payload);
|
|
248
|
+
if (nativeCard) return nativeCard;
|
|
249
|
+
const interactive = normalizeInteractiveReply(params.payload.interactive);
|
|
250
|
+
const presentation = normalizeMessagePresentation(params.payload.presentation) ?? (interactive ? interactiveReplyToPresentation(interactive) : void 0);
|
|
251
|
+
if (!presentation && !interactive) return;
|
|
252
|
+
const text = resolveInteractiveTextFallback({
|
|
253
|
+
text: params.text ?? params.payload.text,
|
|
254
|
+
interactive
|
|
255
|
+
});
|
|
256
|
+
const elements = [];
|
|
257
|
+
if (text?.trim()) elements.push({
|
|
258
|
+
tag: "markdown",
|
|
259
|
+
content: escapeFeishuCardMarkdownText(text)
|
|
260
|
+
});
|
|
261
|
+
for (const block of presentation?.blocks ?? []) {
|
|
262
|
+
const element = buildFeishuCardElementForBlock(block);
|
|
263
|
+
if (element) elements.push(element);
|
|
264
|
+
}
|
|
265
|
+
if (elements.length === 0) elements.push({
|
|
266
|
+
tag: "markdown",
|
|
267
|
+
content: renderMessagePresentationFallbackText({
|
|
268
|
+
text,
|
|
269
|
+
presentation
|
|
270
|
+
})
|
|
271
|
+
});
|
|
272
|
+
const identityTitle = params.identity ? params.identity.emoji ? `${params.identity.emoji} ${params.identity.name ?? ""}`.trim() : params.identity.name ?? "" : "";
|
|
273
|
+
const title = presentation?.title ?? identityTitle;
|
|
274
|
+
const template = resolveFeishuCardTemplate(presentation?.tone === "danger" ? "red" : presentation?.tone === "warning" ? "orange" : presentation?.tone === "success" ? "green" : "blue");
|
|
275
|
+
return markRenderedFeishuCard({
|
|
276
|
+
schema: "2.0",
|
|
277
|
+
config: { width_mode: "fill" },
|
|
278
|
+
...title ? { header: {
|
|
279
|
+
title: {
|
|
280
|
+
tag: "plain_text",
|
|
281
|
+
content: title
|
|
282
|
+
},
|
|
283
|
+
template: template ?? "blue"
|
|
284
|
+
} } : {},
|
|
285
|
+
body: { elements }
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
function renderFeishuPresentationPayload({ payload, presentation, ctx }) {
|
|
289
|
+
const card = buildFeishuPayloadCard({
|
|
290
|
+
payload,
|
|
291
|
+
text: payload.text,
|
|
292
|
+
identity: ctx.identity
|
|
293
|
+
});
|
|
294
|
+
if (!card) return null;
|
|
295
|
+
const existingFeishuData = isRecord$1(payload.channelData?.feishu) ? payload.channelData.feishu : void 0;
|
|
296
|
+
return {
|
|
297
|
+
...payload,
|
|
298
|
+
text: renderMessagePresentationFallbackText({
|
|
299
|
+
text: payload.text,
|
|
300
|
+
presentation
|
|
301
|
+
}),
|
|
302
|
+
channelData: {
|
|
303
|
+
...payload.channelData,
|
|
304
|
+
feishu: {
|
|
305
|
+
...existingFeishuData,
|
|
306
|
+
card
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function resolveReplyToMessageId(params) {
|
|
312
|
+
const replyToId = params.replyToId?.trim();
|
|
313
|
+
if (replyToId) return replyToId;
|
|
314
|
+
if (params.threadId == null) return;
|
|
315
|
+
return String(params.threadId).trim() || void 0;
|
|
316
|
+
}
|
|
317
|
+
async function sendCommentThreadReply(params) {
|
|
318
|
+
const target = parseFeishuCommentTarget(params.to);
|
|
319
|
+
if (!target) return null;
|
|
320
|
+
const client = createFeishuClient(resolveFeishuAccount({
|
|
321
|
+
cfg: params.cfg,
|
|
322
|
+
accountId: params.accountId
|
|
323
|
+
}));
|
|
324
|
+
const replyId = params.replyId?.trim();
|
|
325
|
+
try {
|
|
326
|
+
const result = await deliverCommentThreadText(client, {
|
|
327
|
+
file_token: target.fileToken,
|
|
328
|
+
file_type: target.fileType,
|
|
329
|
+
comment_id: target.commentId,
|
|
330
|
+
content: params.text
|
|
331
|
+
});
|
|
332
|
+
return {
|
|
333
|
+
messageId: typeof result.reply_id === "string" && result.reply_id || typeof result.comment_id === "string" && result.comment_id || "",
|
|
334
|
+
chatId: target.commentId,
|
|
335
|
+
result
|
|
336
|
+
};
|
|
337
|
+
} finally {
|
|
338
|
+
if (replyId) cleanupAmbientCommentTypingReaction({
|
|
339
|
+
client,
|
|
340
|
+
deliveryContext: {
|
|
341
|
+
channel: "feishu",
|
|
342
|
+
to: params.to,
|
|
343
|
+
threadId: replyId
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
async function sendOutboundText(params) {
|
|
349
|
+
const { cfg, to, text, accountId, replyToMessageId } = params;
|
|
350
|
+
const commentResult = await sendCommentThreadReply({
|
|
351
|
+
cfg,
|
|
352
|
+
to,
|
|
353
|
+
text,
|
|
354
|
+
replyId: replyToMessageId,
|
|
355
|
+
accountId
|
|
356
|
+
});
|
|
357
|
+
if (commentResult) return commentResult;
|
|
358
|
+
const renderMode = resolveFeishuAccount({
|
|
359
|
+
cfg,
|
|
360
|
+
accountId
|
|
361
|
+
}).config?.renderMode ?? "auto";
|
|
362
|
+
if (renderMode === "card" || renderMode === "auto" && shouldUseCard(text)) return sendMarkdownCardFeishu({
|
|
363
|
+
cfg,
|
|
364
|
+
to,
|
|
365
|
+
text,
|
|
366
|
+
accountId,
|
|
367
|
+
replyToMessageId
|
|
368
|
+
});
|
|
369
|
+
return sendMessageFeishu({
|
|
370
|
+
cfg,
|
|
371
|
+
to,
|
|
372
|
+
text,
|
|
373
|
+
accountId,
|
|
374
|
+
replyToMessageId
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
const feishuOutbound = {
|
|
378
|
+
deliveryMode: "direct",
|
|
379
|
+
chunker: chunkTextForOutbound,
|
|
380
|
+
chunkerMode: "markdown",
|
|
381
|
+
textChunkLimit: 4e3,
|
|
382
|
+
presentationCapabilities: {
|
|
383
|
+
supported: true,
|
|
384
|
+
buttons: true,
|
|
385
|
+
selects: false,
|
|
386
|
+
context: true,
|
|
387
|
+
divider: true
|
|
388
|
+
},
|
|
389
|
+
renderPresentation: renderFeishuPresentationPayload,
|
|
390
|
+
sendPayload: async (ctx) => {
|
|
391
|
+
const card = buildFeishuPayloadCard({
|
|
392
|
+
payload: ctx.payload,
|
|
393
|
+
text: ctx.text,
|
|
394
|
+
identity: ctx.identity
|
|
395
|
+
});
|
|
396
|
+
if (!card) return await sendTextMediaPayload({
|
|
397
|
+
channel: "feishu",
|
|
398
|
+
ctx,
|
|
399
|
+
adapter: feishuOutbound
|
|
400
|
+
});
|
|
401
|
+
const replyToMessageId = resolveReplyToMessageId({
|
|
402
|
+
replyToId: ctx.replyToId,
|
|
403
|
+
threadId: ctx.threadId
|
|
404
|
+
});
|
|
405
|
+
if (parseFeishuCommentTarget(ctx.to)) return await sendTextMediaPayload({
|
|
406
|
+
channel: "feishu",
|
|
407
|
+
ctx: {
|
|
408
|
+
...ctx,
|
|
409
|
+
payload: {
|
|
410
|
+
...ctx.payload,
|
|
411
|
+
text: renderMessagePresentationFallbackText({
|
|
412
|
+
text: ctx.payload.text,
|
|
413
|
+
presentation: normalizeMessagePresentation(ctx.payload.presentation) ?? (() => {
|
|
414
|
+
const interactive = normalizeInteractiveReply(ctx.payload.interactive);
|
|
415
|
+
return interactive ? interactiveReplyToPresentation(interactive) : void 0;
|
|
416
|
+
})()
|
|
417
|
+
}),
|
|
418
|
+
interactive: void 0,
|
|
419
|
+
presentation: void 0,
|
|
420
|
+
channelData: void 0
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
adapter: feishuOutbound
|
|
424
|
+
});
|
|
425
|
+
const mediaUrls = resolvePayloadMediaUrls(ctx.payload).map((entry) => entry.trim()).filter(Boolean);
|
|
426
|
+
return attachChannelToResult("feishu", await sendPayloadMediaSequenceAndFinalize({
|
|
427
|
+
text: ctx.payload.text ?? "",
|
|
428
|
+
mediaUrls,
|
|
429
|
+
send: async ({ mediaUrl }) => await sendMediaFeishu({
|
|
430
|
+
cfg: ctx.cfg,
|
|
431
|
+
to: ctx.to,
|
|
432
|
+
mediaUrl,
|
|
433
|
+
accountId: ctx.accountId ?? void 0,
|
|
434
|
+
mediaLocalRoots: ctx.mediaLocalRoots,
|
|
435
|
+
replyToMessageId,
|
|
436
|
+
...ctx.payload.audioAsVoice === true || ctx.audioAsVoice === true ? { audioAsVoice: true } : {}
|
|
437
|
+
}),
|
|
438
|
+
finalize: async () => await sendCardFeishu({
|
|
439
|
+
cfg: ctx.cfg,
|
|
440
|
+
to: ctx.to,
|
|
441
|
+
card,
|
|
442
|
+
replyToMessageId,
|
|
443
|
+
replyInThread: ctx.threadId != null && !ctx.replyToId,
|
|
444
|
+
accountId: ctx.accountId ?? void 0
|
|
445
|
+
})
|
|
446
|
+
}));
|
|
447
|
+
},
|
|
448
|
+
...createAttachedChannelResultAdapter({
|
|
449
|
+
channel: "feishu",
|
|
450
|
+
sendText: async ({ cfg, to, text, accountId, replyToId, threadId, mediaLocalRoots, identity }) => {
|
|
451
|
+
const replyToMessageId = resolveReplyToMessageId({
|
|
452
|
+
replyToId,
|
|
453
|
+
threadId
|
|
454
|
+
});
|
|
455
|
+
const localImagePath = normalizePossibleLocalImagePath(text);
|
|
456
|
+
if (localImagePath) try {
|
|
457
|
+
return await sendMediaFeishu({
|
|
458
|
+
cfg,
|
|
459
|
+
to,
|
|
460
|
+
mediaUrl: localImagePath,
|
|
461
|
+
accountId: accountId ?? void 0,
|
|
462
|
+
replyToMessageId,
|
|
463
|
+
mediaLocalRoots
|
|
464
|
+
});
|
|
465
|
+
} catch (err) {
|
|
466
|
+
console.error(`[feishu] local image path auto-send failed:`, err);
|
|
467
|
+
}
|
|
468
|
+
if (parseFeishuCommentTarget(to)) return await sendOutboundText({
|
|
469
|
+
cfg,
|
|
470
|
+
to,
|
|
471
|
+
text,
|
|
472
|
+
accountId: accountId ?? void 0,
|
|
473
|
+
replyToMessageId
|
|
474
|
+
});
|
|
475
|
+
const renderMode = resolveFeishuAccount({
|
|
476
|
+
cfg,
|
|
477
|
+
accountId: accountId ?? void 0
|
|
478
|
+
}).config?.renderMode ?? "auto";
|
|
479
|
+
if (renderMode === "card" || renderMode === "auto" && shouldUseCard(text)) {
|
|
480
|
+
const header = identity ? {
|
|
481
|
+
title: identity.emoji ? `${identity.emoji} ${identity.name ?? ""}`.trim() : identity.name ?? "",
|
|
482
|
+
template: "blue"
|
|
483
|
+
} : void 0;
|
|
484
|
+
return await sendStructuredCardFeishu({
|
|
485
|
+
cfg,
|
|
486
|
+
to,
|
|
487
|
+
text,
|
|
488
|
+
replyToMessageId,
|
|
489
|
+
replyInThread: threadId != null && !replyToId,
|
|
490
|
+
accountId: accountId ?? void 0,
|
|
491
|
+
header: header?.title ? header : void 0
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return await sendOutboundText({
|
|
495
|
+
cfg,
|
|
496
|
+
to,
|
|
497
|
+
text,
|
|
498
|
+
accountId: accountId ?? void 0,
|
|
499
|
+
replyToMessageId
|
|
500
|
+
});
|
|
501
|
+
},
|
|
502
|
+
sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, accountId, mediaLocalRoots, replyToId, threadId }) => {
|
|
503
|
+
const replyToMessageId = resolveReplyToMessageId({
|
|
504
|
+
replyToId,
|
|
505
|
+
threadId
|
|
506
|
+
});
|
|
507
|
+
if (parseFeishuCommentTarget(to)) return await sendOutboundText({
|
|
508
|
+
cfg,
|
|
509
|
+
to,
|
|
510
|
+
text: [text?.trim(), mediaUrl?.trim()].filter(Boolean).join("\n\n") || mediaUrl || text || "",
|
|
511
|
+
accountId: accountId ?? void 0,
|
|
512
|
+
replyToMessageId
|
|
513
|
+
});
|
|
514
|
+
const suppressTextForVoiceMedia = mediaUrl !== void 0 && shouldSuppressFeishuTextForVoiceMedia({
|
|
515
|
+
mediaUrl,
|
|
516
|
+
audioAsVoice
|
|
517
|
+
});
|
|
518
|
+
if (text?.trim() && !suppressTextForVoiceMedia) await sendOutboundText({
|
|
519
|
+
cfg,
|
|
520
|
+
to,
|
|
521
|
+
text,
|
|
522
|
+
accountId: accountId ?? void 0,
|
|
523
|
+
replyToMessageId
|
|
524
|
+
});
|
|
525
|
+
if (mediaUrl) try {
|
|
526
|
+
const result = await sendMediaFeishu({
|
|
527
|
+
cfg,
|
|
528
|
+
to,
|
|
529
|
+
mediaUrl,
|
|
530
|
+
accountId: accountId ?? void 0,
|
|
531
|
+
mediaLocalRoots,
|
|
532
|
+
replyToMessageId,
|
|
533
|
+
...audioAsVoice === true ? { audioAsVoice: true } : {}
|
|
534
|
+
});
|
|
535
|
+
if (result.voiceIntentDegradedToFile && text?.trim()) await sendOutboundText({
|
|
536
|
+
cfg,
|
|
537
|
+
to,
|
|
538
|
+
text,
|
|
539
|
+
accountId: accountId ?? void 0,
|
|
540
|
+
replyToMessageId
|
|
541
|
+
});
|
|
542
|
+
return result;
|
|
543
|
+
} catch (err) {
|
|
544
|
+
console.error(`[feishu] sendMediaFeishu failed:`, err);
|
|
545
|
+
return await sendOutboundText({
|
|
546
|
+
cfg,
|
|
547
|
+
to,
|
|
548
|
+
text: [text?.trim(), `📎 ${mediaUrl}`].filter(Boolean).join("\n\n"),
|
|
549
|
+
accountId: accountId ?? void 0,
|
|
550
|
+
replyToMessageId
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
return await sendOutboundText({
|
|
554
|
+
cfg,
|
|
555
|
+
to,
|
|
556
|
+
text: text ?? "",
|
|
557
|
+
accountId: accountId ?? void 0,
|
|
558
|
+
replyToMessageId
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
})
|
|
562
|
+
};
|
|
563
|
+
//#endregion
|
|
564
|
+
//#region extensions/feishu/src/pins.ts
|
|
565
|
+
function assertFeishuPinApiSuccess(response, action) {
|
|
566
|
+
if (response.code !== 0) throw new Error(`Feishu ${action} failed: ${response.msg || `code ${response.code}`}`);
|
|
567
|
+
}
|
|
568
|
+
function normalizePin(pin) {
|
|
569
|
+
return {
|
|
570
|
+
messageId: pin.message_id,
|
|
571
|
+
chatId: pin.chat_id,
|
|
572
|
+
operatorId: pin.operator_id,
|
|
573
|
+
operatorIdType: pin.operator_id_type,
|
|
574
|
+
createTime: pin.create_time
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
async function createPinFeishu(params) {
|
|
578
|
+
const account = resolveFeishuRuntimeAccount({
|
|
579
|
+
cfg: params.cfg,
|
|
580
|
+
accountId: params.accountId
|
|
581
|
+
});
|
|
582
|
+
if (!account.configured) throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
583
|
+
const response = await createFeishuClient(account).im.pin.create({ data: { message_id: params.messageId } });
|
|
584
|
+
assertFeishuPinApiSuccess(response, "pin create");
|
|
585
|
+
return response.data?.pin ? normalizePin(response.data.pin) : null;
|
|
586
|
+
}
|
|
587
|
+
async function removePinFeishu(params) {
|
|
588
|
+
const account = resolveFeishuRuntimeAccount({
|
|
589
|
+
cfg: params.cfg,
|
|
590
|
+
accountId: params.accountId
|
|
591
|
+
});
|
|
592
|
+
if (!account.configured) throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
593
|
+
assertFeishuPinApiSuccess(await createFeishuClient(account).im.pin.delete({ path: { message_id: params.messageId } }), "pin delete");
|
|
594
|
+
}
|
|
595
|
+
async function listPinsFeishu(params) {
|
|
596
|
+
const account = resolveFeishuRuntimeAccount({
|
|
597
|
+
cfg: params.cfg,
|
|
598
|
+
accountId: params.accountId
|
|
599
|
+
});
|
|
600
|
+
if (!account.configured) throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
601
|
+
const response = await createFeishuClient(account).im.pin.list({ params: {
|
|
602
|
+
chat_id: params.chatId,
|
|
603
|
+
...params.startTime ? { start_time: params.startTime } : {},
|
|
604
|
+
...params.endTime ? { end_time: params.endTime } : {},
|
|
605
|
+
...typeof params.pageSize === "number" ? { page_size: Math.max(1, Math.min(100, Math.floor(params.pageSize))) } : {},
|
|
606
|
+
...params.pageToken ? { page_token: params.pageToken } : {}
|
|
607
|
+
} });
|
|
608
|
+
assertFeishuPinApiSuccess(response, "pin list");
|
|
609
|
+
return {
|
|
610
|
+
chatId: params.chatId,
|
|
611
|
+
pins: (response.data?.items ?? []).map(normalizePin),
|
|
612
|
+
hasMore: response.data?.has_more === true,
|
|
613
|
+
pageToken: response.data?.page_token
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region extensions/feishu/src/reactions.ts
|
|
618
|
+
function resolveConfiguredFeishuClient(params) {
|
|
619
|
+
const account = resolveFeishuRuntimeAccount(params);
|
|
620
|
+
if (!account.configured) throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
621
|
+
return createFeishuClient(account);
|
|
622
|
+
}
|
|
623
|
+
function assertFeishuReactionApiSuccess(response, action) {
|
|
624
|
+
if (response.code !== 0) throw new Error(`Feishu ${action} failed: ${response.msg || `code ${response.code}`}`);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Add a reaction (emoji) to a message.
|
|
628
|
+
* @param emojiType - Feishu emoji type, e.g., "SMILE", "THUMBSUP", "HEART"
|
|
629
|
+
* @see https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce
|
|
630
|
+
*/
|
|
631
|
+
async function addReactionFeishu(params) {
|
|
632
|
+
const { cfg, messageId, emojiType, accountId } = params;
|
|
633
|
+
const response = await resolveConfiguredFeishuClient({
|
|
634
|
+
cfg,
|
|
635
|
+
accountId
|
|
636
|
+
}).im.messageReaction.create({
|
|
637
|
+
path: { message_id: messageId },
|
|
638
|
+
data: { reaction_type: { emoji_type: emojiType } }
|
|
639
|
+
});
|
|
640
|
+
assertFeishuReactionApiSuccess(response, "add reaction");
|
|
641
|
+
const reactionId = response.data?.reaction_id;
|
|
642
|
+
if (!reactionId) throw new Error("Feishu add reaction failed: no reaction_id returned");
|
|
643
|
+
return { reactionId };
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Remove a reaction from a message.
|
|
647
|
+
*/
|
|
648
|
+
async function removeReactionFeishu(params) {
|
|
649
|
+
const { cfg, messageId, reactionId, accountId } = params;
|
|
650
|
+
assertFeishuReactionApiSuccess(await resolveConfiguredFeishuClient({
|
|
651
|
+
cfg,
|
|
652
|
+
accountId
|
|
653
|
+
}).im.messageReaction.delete({ path: {
|
|
654
|
+
message_id: messageId,
|
|
655
|
+
reaction_id: reactionId
|
|
656
|
+
} }), "remove reaction");
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* List all reactions for a message.
|
|
660
|
+
*/
|
|
661
|
+
async function listReactionsFeishu(params) {
|
|
662
|
+
const { cfg, messageId, emojiType, accountId } = params;
|
|
663
|
+
const response = await resolveConfiguredFeishuClient({
|
|
664
|
+
cfg,
|
|
665
|
+
accountId
|
|
666
|
+
}).im.messageReaction.list({
|
|
667
|
+
path: { message_id: messageId },
|
|
668
|
+
params: emojiType ? { reaction_type: emojiType } : void 0
|
|
669
|
+
});
|
|
670
|
+
assertFeishuReactionApiSuccess(response, "list reactions");
|
|
671
|
+
return (response.data?.items ?? []).map((item) => ({
|
|
672
|
+
reactionId: item.reaction_id ?? "",
|
|
673
|
+
emojiType: item.reaction_type?.emoji_type ?? "",
|
|
674
|
+
operatorType: item.operator_type === "app" ? "app" : "user",
|
|
675
|
+
operatorId: item.operator_id?.open_id ?? item.operator_id?.user_id ?? item.operator_id?.union_id ?? ""
|
|
676
|
+
}));
|
|
677
|
+
}
|
|
678
|
+
//#endregion
|
|
679
|
+
//#region extensions/feishu/src/channel.runtime.ts
|
|
680
|
+
const feishuChannelRuntime = {
|
|
681
|
+
listFeishuDirectoryGroupsLive,
|
|
682
|
+
listFeishuDirectoryPeersLive,
|
|
683
|
+
feishuOutbound: { ...feishuOutbound },
|
|
684
|
+
createPinFeishu,
|
|
685
|
+
listPinsFeishu,
|
|
686
|
+
removePinFeishu,
|
|
687
|
+
probeFeishu,
|
|
688
|
+
addReactionFeishu,
|
|
689
|
+
listReactionsFeishu,
|
|
690
|
+
removeReactionFeishu,
|
|
691
|
+
getChatInfo,
|
|
692
|
+
getChatMembers,
|
|
693
|
+
getFeishuMemberInfo,
|
|
694
|
+
editMessageFeishu,
|
|
695
|
+
getMessageFeishu,
|
|
696
|
+
sendCardFeishu,
|
|
697
|
+
sendMessageFeishu
|
|
698
|
+
};
|
|
699
|
+
//#endregion
|
|
700
|
+
export { feishuChannelRuntime };
|