@openclaw/feishu 2026.5.2 → 2026.5.3-beta.2

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 (224) hide show
  1. package/dist/accounts-Ba3-WP1z.js +423 -0
  2. package/dist/api.js +2280 -0
  3. package/dist/app-registration-B8qc1MCM.js +184 -0
  4. package/dist/audio-preflight.runtime-BPlzkO3l.js +7 -0
  5. package/dist/card-interaction-BfRLgvw_.js +96 -0
  6. package/dist/channel-CSD_Jt8I.js +1668 -0
  7. package/dist/channel-entry.js +22 -0
  8. package/dist/channel-plugin-api.js +2 -0
  9. package/dist/channel.runtime-DYsXcD36.js +700 -0
  10. package/dist/client-DBVoQL5w.js +157 -0
  11. package/dist/contract-api.js +9 -0
  12. package/dist/conversation-id-DWS3Ep2A.js +139 -0
  13. package/dist/directory.static-f3EeoRJd.js +44 -0
  14. package/dist/drive-C5eJLJr7.js +883 -0
  15. package/dist/index.js +68 -0
  16. package/dist/monitor-CT189QfR.js +60 -0
  17. package/dist/monitor.account-dJV2jO8C.js +4990 -0
  18. package/dist/monitor.state-DYM02ipp.js +100 -0
  19. package/dist/policy-D6c-wMPl.js +118 -0
  20. package/dist/probe-BNzzU_uR.js +149 -0
  21. package/dist/rolldown-runtime-DUslC3ob.js +14 -0
  22. package/dist/runtime-CG0DuRCy.js +8 -0
  23. package/dist/runtime-api.js +14 -0
  24. package/dist/secret-contract-Dm4Z_zQN.js +119 -0
  25. package/dist/secret-contract-api.js +2 -0
  26. package/dist/security-audit-DqJdocrN.js +11 -0
  27. package/dist/security-audit-shared-ByuMx9cJ.js +38 -0
  28. package/dist/security-contract-api.js +2 -0
  29. package/dist/send-DowxxbpH.js +1218 -0
  30. package/dist/session-conversation-B4nrW-vo.js +27 -0
  31. package/dist/session-key-api.js +2 -0
  32. package/dist/setup-api.js +2 -0
  33. package/dist/setup-entry.js +15 -0
  34. package/dist/subagent-hooks-C3UhPVLV.js +227 -0
  35. package/dist/subagent-hooks-api.js +23 -0
  36. package/dist/targets-JMFJRKSe.js +48 -0
  37. package/dist/thread-bindings-BmS6TLes.js +222 -0
  38. package/package.json +15 -6
  39. package/api.ts +0 -31
  40. package/channel-entry.ts +0 -20
  41. package/channel-plugin-api.ts +0 -1
  42. package/contract-api.ts +0 -16
  43. package/index.ts +0 -82
  44. package/runtime-api.ts +0 -55
  45. package/secret-contract-api.ts +0 -5
  46. package/security-contract-api.ts +0 -1
  47. package/session-key-api.ts +0 -1
  48. package/setup-api.ts +0 -3
  49. package/setup-entry.test.ts +0 -14
  50. package/setup-entry.ts +0 -13
  51. package/src/accounts.test.ts +0 -459
  52. package/src/accounts.ts +0 -326
  53. package/src/app-registration.ts +0 -331
  54. package/src/approval-auth.test.ts +0 -24
  55. package/src/approval-auth.ts +0 -25
  56. package/src/async.test.ts +0 -35
  57. package/src/async.ts +0 -104
  58. package/src/audio-preflight.runtime.ts +0 -9
  59. package/src/bitable.test.ts +0 -131
  60. package/src/bitable.ts +0 -762
  61. package/src/bot-content.ts +0 -474
  62. package/src/bot-group-name.test.ts +0 -108
  63. package/src/bot-runtime-api.ts +0 -12
  64. package/src/bot-sender-name.ts +0 -125
  65. package/src/bot.broadcast.test.ts +0 -463
  66. package/src/bot.card-action.test.ts +0 -577
  67. package/src/bot.checkBotMentioned.test.ts +0 -265
  68. package/src/bot.helpers.test.ts +0 -118
  69. package/src/bot.stripBotMention.test.ts +0 -126
  70. package/src/bot.test.ts +0 -3040
  71. package/src/bot.ts +0 -1559
  72. package/src/card-action.ts +0 -447
  73. package/src/card-interaction.test.ts +0 -129
  74. package/src/card-interaction.ts +0 -159
  75. package/src/card-test-helpers.ts +0 -47
  76. package/src/card-ux-approval.ts +0 -65
  77. package/src/card-ux-launcher.test.ts +0 -99
  78. package/src/card-ux-launcher.ts +0 -121
  79. package/src/card-ux-shared.ts +0 -33
  80. package/src/channel-runtime-api.ts +0 -16
  81. package/src/channel.runtime.ts +0 -47
  82. package/src/channel.test.ts +0 -959
  83. package/src/channel.ts +0 -1313
  84. package/src/chat-schema.ts +0 -25
  85. package/src/chat.test.ts +0 -196
  86. package/src/chat.ts +0 -188
  87. package/src/client.test.ts +0 -433
  88. package/src/client.ts +0 -290
  89. package/src/comment-dispatcher-runtime-api.ts +0 -6
  90. package/src/comment-dispatcher.test.ts +0 -169
  91. package/src/comment-dispatcher.ts +0 -107
  92. package/src/comment-handler-runtime-api.ts +0 -3
  93. package/src/comment-handler.test.ts +0 -486
  94. package/src/comment-handler.ts +0 -309
  95. package/src/comment-reaction.test.ts +0 -166
  96. package/src/comment-reaction.ts +0 -259
  97. package/src/comment-shared.test.ts +0 -182
  98. package/src/comment-shared.ts +0 -406
  99. package/src/comment-target.ts +0 -44
  100. package/src/config-schema.test.ts +0 -309
  101. package/src/config-schema.ts +0 -333
  102. package/src/conversation-id.test.ts +0 -18
  103. package/src/conversation-id.ts +0 -199
  104. package/src/dedup-runtime-api.ts +0 -1
  105. package/src/dedup.ts +0 -141
  106. package/src/directory.static.ts +0 -61
  107. package/src/directory.test.ts +0 -136
  108. package/src/directory.ts +0 -124
  109. package/src/doc-schema.ts +0 -182
  110. package/src/docx-batch-insert.test.ts +0 -91
  111. package/src/docx-batch-insert.ts +0 -223
  112. package/src/docx-color-text.ts +0 -154
  113. package/src/docx-table-ops.test.ts +0 -53
  114. package/src/docx-table-ops.ts +0 -316
  115. package/src/docx-types.ts +0 -38
  116. package/src/docx.account-selection.test.ts +0 -79
  117. package/src/docx.test.ts +0 -685
  118. package/src/docx.ts +0 -1616
  119. package/src/drive-schema.ts +0 -92
  120. package/src/drive.test.ts +0 -1219
  121. package/src/drive.ts +0 -829
  122. package/src/dynamic-agent.ts +0 -137
  123. package/src/event-types.ts +0 -45
  124. package/src/external-keys.test.ts +0 -20
  125. package/src/external-keys.ts +0 -19
  126. package/src/lifecycle.test-support.ts +0 -220
  127. package/src/media.test.ts +0 -900
  128. package/src/media.ts +0 -861
  129. package/src/mention-target.types.ts +0 -5
  130. package/src/mention.ts +0 -114
  131. package/src/message-action-contract.ts +0 -13
  132. package/src/monitor-state-runtime-api.ts +0 -7
  133. package/src/monitor-transport-runtime-api.ts +0 -7
  134. package/src/monitor.account.ts +0 -468
  135. package/src/monitor.acp-init-failure.lifecycle.test-support.ts +0 -219
  136. package/src/monitor.bot-identity.ts +0 -86
  137. package/src/monitor.bot-menu-handler.ts +0 -165
  138. package/src/monitor.bot-menu.lifecycle.test-support.ts +0 -224
  139. package/src/monitor.bot-menu.test.ts +0 -178
  140. package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +0 -264
  141. package/src/monitor.card-action.lifecycle.test-support.ts +0 -373
  142. package/src/monitor.cleanup.test.ts +0 -376
  143. package/src/monitor.comment-notice-handler.ts +0 -105
  144. package/src/monitor.comment.test.ts +0 -937
  145. package/src/monitor.comment.ts +0 -1386
  146. package/src/monitor.lifecycle.test.ts +0 -4
  147. package/src/monitor.message-handler.ts +0 -339
  148. package/src/monitor.reaction.lifecycle.test-support.ts +0 -68
  149. package/src/monitor.reaction.test.ts +0 -713
  150. package/src/monitor.startup.test.ts +0 -192
  151. package/src/monitor.startup.ts +0 -74
  152. package/src/monitor.state.defaults.test.ts +0 -46
  153. package/src/monitor.state.ts +0 -170
  154. package/src/monitor.synthetic-error.ts +0 -18
  155. package/src/monitor.test-mocks.ts +0 -45
  156. package/src/monitor.transport.ts +0 -424
  157. package/src/monitor.ts +0 -100
  158. package/src/monitor.webhook-e2e.test.ts +0 -272
  159. package/src/monitor.webhook-security.test.ts +0 -264
  160. package/src/monitor.webhook.test-helpers.ts +0 -116
  161. package/src/outbound-runtime-api.ts +0 -1
  162. package/src/outbound.test.ts +0 -935
  163. package/src/outbound.ts +0 -718
  164. package/src/perm-schema.ts +0 -52
  165. package/src/perm.ts +0 -170
  166. package/src/pins.ts +0 -108
  167. package/src/policy.test.ts +0 -334
  168. package/src/policy.ts +0 -236
  169. package/src/post.test.ts +0 -105
  170. package/src/post.ts +0 -275
  171. package/src/probe.test.ts +0 -275
  172. package/src/probe.ts +0 -166
  173. package/src/processing-claims.ts +0 -59
  174. package/src/qr-terminal.ts +0 -1
  175. package/src/reactions.ts +0 -123
  176. package/src/reasoning-preview.test.ts +0 -59
  177. package/src/reasoning-preview.ts +0 -20
  178. package/src/reply-dispatcher-runtime-api.ts +0 -7
  179. package/src/reply-dispatcher.test.ts +0 -1144
  180. package/src/reply-dispatcher.ts +0 -650
  181. package/src/runtime.ts +0 -9
  182. package/src/secret-contract.ts +0 -145
  183. package/src/secret-input.ts +0 -1
  184. package/src/security-audit-shared.ts +0 -69
  185. package/src/security-audit.test.ts +0 -61
  186. package/src/security-audit.ts +0 -1
  187. package/src/send-result.ts +0 -29
  188. package/src/send-target.test.ts +0 -80
  189. package/src/send-target.ts +0 -35
  190. package/src/send.reply-fallback.test.ts +0 -292
  191. package/src/send.test.ts +0 -550
  192. package/src/send.ts +0 -800
  193. package/src/sequential-key.test.ts +0 -72
  194. package/src/sequential-key.ts +0 -28
  195. package/src/sequential-queue.test.ts +0 -92
  196. package/src/sequential-queue.ts +0 -16
  197. package/src/session-conversation.ts +0 -42
  198. package/src/session-route.ts +0 -48
  199. package/src/setup-core.ts +0 -51
  200. package/src/setup-surface.test.ts +0 -174
  201. package/src/setup-surface.ts +0 -581
  202. package/src/streaming-card.test.ts +0 -190
  203. package/src/streaming-card.ts +0 -490
  204. package/src/subagent-hooks.test.ts +0 -603
  205. package/src/subagent-hooks.ts +0 -397
  206. package/src/targets.ts +0 -97
  207. package/src/test-support/lifecycle-test-support.ts +0 -453
  208. package/src/thread-bindings.test.ts +0 -143
  209. package/src/thread-bindings.ts +0 -330
  210. package/src/tool-account-routing.test.ts +0 -187
  211. package/src/tool-account.test.ts +0 -44
  212. package/src/tool-account.ts +0 -93
  213. package/src/tool-factory-test-harness.ts +0 -79
  214. package/src/tool-result.test.ts +0 -32
  215. package/src/tool-result.ts +0 -16
  216. package/src/tools-config.test.ts +0 -21
  217. package/src/tools-config.ts +0 -22
  218. package/src/types.ts +0 -104
  219. package/src/typing.test.ts +0 -144
  220. package/src/typing.ts +0 -214
  221. package/src/wiki-schema.ts +0 -55
  222. package/src/wiki.ts +0 -227
  223. package/subagent-hooks-api.ts +0 -31
  224. package/tsconfig.json +0 -16
@@ -0,0 +1,100 @@
1
+ import { t as probeFeishu } from "./probe-BNzzU_uR.js";
2
+ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
3
+ import { WEBHOOK_ANOMALY_COUNTER_DEFAULTS, WEBHOOK_RATE_LIMIT_DEFAULTS, createFixedWindowRateLimiter, createWebhookAnomalyTracker } from "openclaw/plugin-sdk/webhook-ingress";
4
+ //#region extensions/feishu/src/monitor.startup.ts
5
+ const FEISHU_STARTUP_BOT_INFO_TIMEOUT_DEFAULT_MS = 3e4;
6
+ const FEISHU_STARTUP_BOT_INFO_TIMEOUT_ENV = "OPENCLAW_FEISHU_STARTUP_PROBE_TIMEOUT_MS";
7
+ function resolveStartupProbeTimeoutMs() {
8
+ const raw = process.env[FEISHU_STARTUP_BOT_INFO_TIMEOUT_ENV];
9
+ if (raw) {
10
+ const parsed = Number(raw);
11
+ if (Number.isFinite(parsed) && parsed > 0) return Math.floor(parsed);
12
+ console.warn(`[feishu] ${FEISHU_STARTUP_BOT_INFO_TIMEOUT_ENV}="${raw}" is invalid; using default ${FEISHU_STARTUP_BOT_INFO_TIMEOUT_DEFAULT_MS}ms`);
13
+ }
14
+ return FEISHU_STARTUP_BOT_INFO_TIMEOUT_DEFAULT_MS;
15
+ }
16
+ const FEISHU_STARTUP_BOT_INFO_TIMEOUT_MS = resolveStartupProbeTimeoutMs();
17
+ function isTimeoutErrorMessage(message) {
18
+ const lower = normalizeLowercaseStringOrEmpty(message);
19
+ return lower.includes("timeout") || lower.includes("timed out");
20
+ }
21
+ function isAbortErrorMessage(message) {
22
+ return normalizeLowercaseStringOrEmpty(message).includes("aborted");
23
+ }
24
+ async function fetchBotIdentityForMonitor(account, options = {}) {
25
+ if (options.abortSignal?.aborted) return {};
26
+ const timeoutMs = options.timeoutMs ?? FEISHU_STARTUP_BOT_INFO_TIMEOUT_MS;
27
+ const result = await probeFeishu(account, {
28
+ timeoutMs,
29
+ abortSignal: options.abortSignal
30
+ });
31
+ if (result.ok) return {
32
+ botOpenId: result.botOpenId,
33
+ botName: result.botName
34
+ };
35
+ const probeError = result.error ?? void 0;
36
+ if (options.abortSignal?.aborted || isAbortErrorMessage(probeError)) return {};
37
+ if (isTimeoutErrorMessage(probeError)) (options.runtime?.error ?? console.error)(`feishu[${account.accountId}]: bot info probe timed out after ${timeoutMs}ms; continuing startup`);
38
+ return {};
39
+ }
40
+ //#endregion
41
+ //#region extensions/feishu/src/monitor.state.ts
42
+ const wsClients = /* @__PURE__ */ new Map();
43
+ const httpServers = /* @__PURE__ */ new Map();
44
+ const botOpenIds = /* @__PURE__ */ new Map();
45
+ const botNames = /* @__PURE__ */ new Map();
46
+ const FEISHU_WEBHOOK_MAX_BODY_BYTES = 64 * 1024;
47
+ const FEISHU_WEBHOOK_BODY_TIMEOUT_MS = 5e3;
48
+ const FEISHU_WEBHOOK_RATE_LIMIT_FALLBACK_DEFAULTS = {
49
+ windowMs: 6e4,
50
+ maxRequests: 120,
51
+ maxTrackedKeys: 4096
52
+ };
53
+ const FEISHU_WEBHOOK_ANOMALY_FALLBACK_DEFAULTS = {
54
+ maxTrackedKeys: 4096,
55
+ ttlMs: 360 * 6e4,
56
+ logEvery: 25
57
+ };
58
+ function coercePositiveInt(value, fallback) {
59
+ if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
60
+ const normalized = Math.floor(value);
61
+ return normalized > 0 ? normalized : fallback;
62
+ }
63
+ function resolveFeishuWebhookRateLimitDefaultsForTest(defaults) {
64
+ const resolved = defaults;
65
+ return {
66
+ windowMs: coercePositiveInt(resolved?.windowMs, FEISHU_WEBHOOK_RATE_LIMIT_FALLBACK_DEFAULTS.windowMs),
67
+ maxRequests: coercePositiveInt(resolved?.maxRequests, FEISHU_WEBHOOK_RATE_LIMIT_FALLBACK_DEFAULTS.maxRequests),
68
+ maxTrackedKeys: coercePositiveInt(resolved?.maxTrackedKeys, FEISHU_WEBHOOK_RATE_LIMIT_FALLBACK_DEFAULTS.maxTrackedKeys)
69
+ };
70
+ }
71
+ function resolveFeishuWebhookAnomalyDefaultsForTest(defaults) {
72
+ const resolved = defaults;
73
+ return {
74
+ maxTrackedKeys: coercePositiveInt(resolved?.maxTrackedKeys, FEISHU_WEBHOOK_ANOMALY_FALLBACK_DEFAULTS.maxTrackedKeys),
75
+ ttlMs: coercePositiveInt(resolved?.ttlMs, FEISHU_WEBHOOK_ANOMALY_FALLBACK_DEFAULTS.ttlMs),
76
+ logEvery: coercePositiveInt(resolved?.logEvery, FEISHU_WEBHOOK_ANOMALY_FALLBACK_DEFAULTS.logEvery)
77
+ };
78
+ }
79
+ const feishuWebhookRateLimitDefaults = resolveFeishuWebhookRateLimitDefaultsForTest(WEBHOOK_RATE_LIMIT_DEFAULTS);
80
+ const feishuWebhookAnomalyDefaults = resolveFeishuWebhookAnomalyDefaultsForTest(WEBHOOK_ANOMALY_COUNTER_DEFAULTS);
81
+ const feishuWebhookRateLimiter = createFixedWindowRateLimiter({
82
+ windowMs: feishuWebhookRateLimitDefaults.windowMs,
83
+ maxRequests: feishuWebhookRateLimitDefaults.maxRequests,
84
+ maxTrackedKeys: feishuWebhookRateLimitDefaults.maxTrackedKeys
85
+ });
86
+ const feishuWebhookAnomalyTracker = createWebhookAnomalyTracker({
87
+ maxTrackedKeys: feishuWebhookAnomalyDefaults.maxTrackedKeys,
88
+ ttlMs: feishuWebhookAnomalyDefaults.ttlMs,
89
+ logEvery: feishuWebhookAnomalyDefaults.logEvery
90
+ });
91
+ function recordWebhookStatus(runtime, accountId, path, statusCode) {
92
+ feishuWebhookAnomalyTracker.record({
93
+ key: `${accountId}:${path}:${statusCode}`,
94
+ statusCode,
95
+ log: runtime?.log ?? console.log,
96
+ message: (count) => `feishu[${accountId}]: webhook anomaly path=${path} status=${statusCode} count=${count}`
97
+ });
98
+ }
99
+ //#endregion
100
+ export { feishuWebhookRateLimiter as a, wsClients as c, botOpenIds as i, fetchBotIdentityForMonitor as l, FEISHU_WEBHOOK_MAX_BODY_BYTES as n, httpServers as o, botNames as r, recordWebhookStatus as s, FEISHU_WEBHOOK_BODY_TIMEOUT_MS as t };
@@ -0,0 +1,118 @@
1
+ import { t as detectIdType } from "./targets-JMFJRKSe.js";
2
+ import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
3
+ import { normalizeAccountId, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
4
+ import { evaluateSenderGroupAccessForPolicy } from "openclaw/plugin-sdk/group-access";
5
+ //#region extensions/feishu/src/policy.ts
6
+ const FEISHU_PROVIDER_PREFIX_RE = /^(feishu|lark):/i;
7
+ function stripRepeatedFeishuProviderPrefixes(raw) {
8
+ let normalized = raw.trim();
9
+ while (FEISHU_PROVIDER_PREFIX_RE.test(normalized)) normalized = normalized.replace(FEISHU_PROVIDER_PREFIX_RE, "").trim();
10
+ return normalized;
11
+ }
12
+ function canonicalizeFeishuAllowlistKey(params) {
13
+ const value = params.value.trim();
14
+ if (!value) return "";
15
+ if (value === "*") return "*";
16
+ return `${params.kind}:${value}`;
17
+ }
18
+ function normalizeFeishuAllowEntry(raw) {
19
+ const trimmed = raw.trim();
20
+ if (!trimmed) return "";
21
+ if (trimmed === "*") return "*";
22
+ const withoutProviderPrefix = stripRepeatedFeishuProviderPrefixes(trimmed);
23
+ if (withoutProviderPrefix === "*") return "*";
24
+ const lowered = normalizeOptionalLowercaseString(withoutProviderPrefix) ?? "";
25
+ if (!lowered) return "";
26
+ if (lowered.startsWith("chat:") || lowered.startsWith("group:") || lowered.startsWith("channel:")) return canonicalizeFeishuAllowlistKey({
27
+ kind: "chat",
28
+ value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
29
+ });
30
+ if (lowered.startsWith("user:") || lowered.startsWith("dm:")) return canonicalizeFeishuAllowlistKey({
31
+ kind: "user",
32
+ value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
33
+ });
34
+ if (lowered.startsWith("open_id:")) return canonicalizeFeishuAllowlistKey({
35
+ kind: "user",
36
+ value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
37
+ });
38
+ const detectedType = detectIdType(withoutProviderPrefix);
39
+ if (detectedType === "chat_id") return canonicalizeFeishuAllowlistKey({
40
+ kind: "chat",
41
+ value: withoutProviderPrefix
42
+ });
43
+ if (detectedType === "open_id" || detectedType === "user_id") return canonicalizeFeishuAllowlistKey({
44
+ kind: "user",
45
+ value: withoutProviderPrefix
46
+ });
47
+ return "";
48
+ }
49
+ function resolveFeishuAllowlistMatch(params) {
50
+ const allowFrom = params.allowFrom.map((entry) => normalizeFeishuAllowEntry(String(entry))).filter(Boolean);
51
+ if (allowFrom.length === 0) return { allowed: false };
52
+ if (allowFrom.includes("*")) return {
53
+ allowed: true,
54
+ matchKey: "*",
55
+ matchSource: "wildcard"
56
+ };
57
+ const senderCandidates = [params.senderId, ...params.senderIds ?? []].map((entry) => normalizeFeishuAllowEntry(entry ?? "")).filter(Boolean);
58
+ for (const senderId of senderCandidates) if (allowFrom.includes(senderId)) return {
59
+ allowed: true,
60
+ matchKey: senderId,
61
+ matchSource: "id"
62
+ };
63
+ return { allowed: false };
64
+ }
65
+ function resolveFeishuGroupConfig(params) {
66
+ const groups = params.cfg?.groups ?? {};
67
+ const wildcard = groups["*"];
68
+ const groupId = params.groupId?.trim();
69
+ if (!groupId) return;
70
+ const direct = groups[groupId];
71
+ if (direct) return direct;
72
+ const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
73
+ const matchKey = Object.keys(groups).find((key) => normalizeOptionalLowercaseString(key) === lowered);
74
+ if (matchKey) return groups[matchKey];
75
+ return wildcard;
76
+ }
77
+ function hasExplicitFeishuGroupConfig(params) {
78
+ const groups = params.cfg?.groups ?? {};
79
+ const groupId = params.groupId?.trim();
80
+ if (!groupId) return false;
81
+ if (Object.prototype.hasOwnProperty.call(groups, groupId) && groupId !== "*") return true;
82
+ const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
83
+ return Object.keys(groups).some((key) => key !== "*" && normalizeOptionalLowercaseString(key) === lowered);
84
+ }
85
+ function resolveFeishuGroupToolPolicy(params) {
86
+ const cfg = params.cfg.channels?.feishu;
87
+ if (!cfg) return;
88
+ return resolveFeishuGroupConfig({
89
+ cfg,
90
+ groupId: params.groupId
91
+ })?.tools;
92
+ }
93
+ function isFeishuGroupAllowed(params) {
94
+ return evaluateSenderGroupAccessForPolicy({
95
+ groupPolicy: params.groupPolicy === "allowall" ? "open" : params.groupPolicy,
96
+ groupAllowFrom: params.allowFrom.map((entry) => String(entry)),
97
+ senderId: params.senderId,
98
+ isSenderAllowed: () => resolveFeishuAllowlistMatch(params).allowed
99
+ }).allowed;
100
+ }
101
+ function resolveFeishuReplyPolicy(params) {
102
+ if (params.isDirectMessage) return { requireMention: false };
103
+ const feishuCfg = params.cfg.channels?.feishu;
104
+ const resolvedCfg = resolveMergedAccountConfig({
105
+ channelConfig: feishuCfg,
106
+ accounts: feishuCfg?.accounts,
107
+ accountId: normalizeAccountId(params.accountId),
108
+ normalizeAccountId,
109
+ omitKeys: ["defaultAccount"]
110
+ });
111
+ const groupRequireMention = resolveFeishuGroupConfig({
112
+ cfg: resolvedCfg,
113
+ groupId: params.groupId
114
+ })?.requireMention;
115
+ return { requireMention: typeof groupRequireMention === "boolean" ? groupRequireMention : typeof resolvedCfg.requireMention === "boolean" ? resolvedCfg.requireMention : params.groupPolicy !== "open" };
116
+ }
117
+ //#endregion
118
+ export { resolveFeishuGroupToolPolicy as a, resolveFeishuGroupConfig as i, isFeishuGroupAllowed as n, resolveFeishuReplyPolicy as o, resolveFeishuAllowlistMatch as r, hasExplicitFeishuGroupConfig as t };
@@ -0,0 +1,149 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-DUslC3ob.js";
2
+ import { r as createFeishuClient } from "./client-DBVoQL5w.js";
3
+ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
4
+ //#region extensions/feishu/src/async.ts
5
+ const RACE_TIMEOUT = Symbol("race-timeout");
6
+ const RACE_ABORT = Symbol("race-abort");
7
+ async function raceWithTimeoutAndAbort(promise, options = {}) {
8
+ if (options.abortSignal?.aborted) return { status: "aborted" };
9
+ if (options.timeoutMs === void 0 && !options.abortSignal) return {
10
+ status: "resolved",
11
+ value: await promise
12
+ };
13
+ let timeoutHandle;
14
+ let abortHandler;
15
+ const contenders = [promise];
16
+ if (options.timeoutMs !== void 0) contenders.push(new Promise((resolve) => {
17
+ timeoutHandle = setTimeout(() => resolve(RACE_TIMEOUT), options.timeoutMs);
18
+ }));
19
+ if (options.abortSignal) contenders.push(new Promise((resolve) => {
20
+ abortHandler = () => resolve(RACE_ABORT);
21
+ options.abortSignal?.addEventListener("abort", abortHandler, { once: true });
22
+ }));
23
+ try {
24
+ const result = await Promise.race(contenders);
25
+ if (result === RACE_TIMEOUT) return { status: "timeout" };
26
+ if (result === RACE_ABORT) return { status: "aborted" };
27
+ return {
28
+ status: "resolved",
29
+ value: result
30
+ };
31
+ } finally {
32
+ if (timeoutHandle) clearTimeout(timeoutHandle);
33
+ if (abortHandler) options.abortSignal?.removeEventListener("abort", abortHandler);
34
+ }
35
+ }
36
+ function waitForAbortableDelay(delayMs, abortSignal) {
37
+ if (abortSignal?.aborted) return Promise.resolve(false);
38
+ return new Promise((resolve) => {
39
+ let settled = false;
40
+ let timer;
41
+ let handleAbort;
42
+ const finish = (value) => {
43
+ if (settled) return;
44
+ settled = true;
45
+ if (timer) clearTimeout(timer);
46
+ if (handleAbort) abortSignal?.removeEventListener("abort", handleAbort);
47
+ resolve(value);
48
+ };
49
+ handleAbort = () => {
50
+ finish(false);
51
+ };
52
+ abortSignal?.addEventListener("abort", handleAbort, { once: true });
53
+ if (abortSignal?.aborted) {
54
+ finish(false);
55
+ return;
56
+ }
57
+ timer = setTimeout(() => finish(true), delayMs);
58
+ timer.unref?.();
59
+ });
60
+ }
61
+ //#endregion
62
+ //#region extensions/feishu/src/probe.ts
63
+ var probe_exports = /* @__PURE__ */ __exportAll({
64
+ FEISHU_PROBE_REQUEST_TIMEOUT_MS: () => FEISHU_PROBE_REQUEST_TIMEOUT_MS,
65
+ probeFeishu: () => probeFeishu
66
+ });
67
+ /** Cache probe results to reduce repeated health-check calls.
68
+ * Gateway health checks call probeFeishu() every minute; without caching this
69
+ * burns ~43,200 calls/month, easily exceeding Feishu's free-tier quota.
70
+ * Successful bot info is effectively static, while failures are cached briefly
71
+ * to avoid hammering the API during transient outages. */
72
+ const probeCache = /* @__PURE__ */ new Map();
73
+ const PROBE_SUCCESS_TTL_MS = 600 * 1e3;
74
+ const PROBE_ERROR_TTL_MS = 60 * 1e3;
75
+ const MAX_PROBE_CACHE_SIZE = 64;
76
+ const FEISHU_PROBE_REQUEST_TIMEOUT_MS = 1e4;
77
+ function setCachedProbeResult(cacheKey, result, ttlMs) {
78
+ probeCache.set(cacheKey, {
79
+ result,
80
+ expiresAt: Date.now() + ttlMs
81
+ });
82
+ if (probeCache.size > MAX_PROBE_CACHE_SIZE) {
83
+ const oldest = probeCache.keys().next().value;
84
+ if (oldest !== void 0) probeCache.delete(oldest);
85
+ }
86
+ return result;
87
+ }
88
+ async function probeFeishu(creds, options = {}) {
89
+ if (!creds?.appId || !creds?.appSecret) return {
90
+ ok: false,
91
+ error: "missing credentials (appId, appSecret)"
92
+ };
93
+ if (options.abortSignal?.aborted) return {
94
+ ok: false,
95
+ appId: creds.appId,
96
+ error: "probe aborted"
97
+ };
98
+ const timeoutMs = options.timeoutMs ?? 1e4;
99
+ const cacheKey = creds.accountId ?? `${creds.appId}:${creds.appSecret.slice(0, 8)}`;
100
+ const cached = probeCache.get(cacheKey);
101
+ if (cached && cached.expiresAt > Date.now()) return cached.result;
102
+ try {
103
+ const responseResult = await raceWithTimeoutAndAbort(createFeishuClient(creds).request({
104
+ method: "POST",
105
+ url: "/open-apis/bot/v1/openclaw_bot/ping",
106
+ data: { needBotInfo: true },
107
+ timeout: timeoutMs
108
+ }), {
109
+ timeoutMs,
110
+ abortSignal: options.abortSignal
111
+ });
112
+ if (responseResult.status === "aborted") return {
113
+ ok: false,
114
+ appId: creds.appId,
115
+ error: "probe aborted"
116
+ };
117
+ if (responseResult.status === "timeout") return setCachedProbeResult(cacheKey, {
118
+ ok: false,
119
+ appId: creds.appId,
120
+ error: `probe timed out after ${timeoutMs}ms`
121
+ }, PROBE_ERROR_TTL_MS);
122
+ const response = responseResult.value;
123
+ if (options.abortSignal?.aborted) return {
124
+ ok: false,
125
+ appId: creds.appId,
126
+ error: "probe aborted"
127
+ };
128
+ if (response.code !== 0) return setCachedProbeResult(cacheKey, {
129
+ ok: false,
130
+ appId: creds.appId,
131
+ error: `API error: ${response.msg || `code ${response.code}`}`
132
+ }, PROBE_ERROR_TTL_MS);
133
+ const botInfo = response.data?.pingBotInfo;
134
+ return setCachedProbeResult(cacheKey, {
135
+ ok: true,
136
+ appId: creds.appId,
137
+ botName: botInfo?.botName,
138
+ botOpenId: botInfo?.botID
139
+ }, PROBE_SUCCESS_TTL_MS);
140
+ } catch (err) {
141
+ return setCachedProbeResult(cacheKey, {
142
+ ok: false,
143
+ appId: creds.appId,
144
+ error: formatErrorMessage(err)
145
+ }, PROBE_ERROR_TTL_MS);
146
+ }
147
+ }
148
+ //#endregion
149
+ export { waitForAbortableDelay as i, probe_exports as n, raceWithTimeoutAndAbort as r, probeFeishu as t };
@@ -0,0 +1,14 @@
1
+ import "node:module";
2
+ //#region \0rolldown/runtime.js
3
+ var __defProp = Object.defineProperty;
4
+ var __exportAll = (all, no_symbols) => {
5
+ let target = {};
6
+ for (var name in all) __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
11
+ return target;
12
+ };
13
+ //#endregion
14
+ export { __exportAll as t };
@@ -0,0 +1,8 @@
1
+ import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
2
+ //#region extensions/feishu/src/runtime.ts
3
+ const { setRuntime: setFeishuRuntime, getRuntime: getFeishuRuntime } = createPluginRuntimeStore({
4
+ pluginId: "feishu",
5
+ errorMessage: "Feishu runtime not initialized"
6
+ });
7
+ //#endregion
8
+ export { setFeishuRuntime as n, getFeishuRuntime as t };
@@ -0,0 +1,14 @@
1
+ import { n as setFeishuRuntime } from "./runtime-CG0DuRCy.js";
2
+ import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
3
+ import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
4
+ import { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";
5
+ import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
6
+ import { DEFAULT_ACCOUNT_ID, buildChannelConfigSchema, createActionGate, createDedupeCache } from "openclaw/plugin-sdk/core";
7
+ import { buildAgentMediaPayload } from "openclaw/plugin-sdk/agent-media-payload";
8
+ import { createReplyPrefixContext } from "openclaw/plugin-sdk/channel-reply-pipeline";
9
+ import { evaluateSupplementalContextVisibility, filterSupplementalContextItems, resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
10
+ import { loadSessionStore, resolveSessionStoreEntry } from "openclaw/plugin-sdk/session-store-runtime";
11
+ import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
12
+ import { createPersistentDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
13
+ import { isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText } from "openclaw/plugin-sdk/webhook-ingress";
14
+ export { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE, buildAgentMediaPayload, buildChannelConfigSchema, buildProbeChannelStatusSummary, chunkTextForOutbound, createActionGate, createChannelPairingController, createDedupeCache, createDefaultChannelRuntimeState, createPersistentDedupe, createReplyPrefixContext, evaluateSupplementalContextVisibility, filterSupplementalContextItems, isRequestBodyLimitError, loadSessionStore, normalizeAgentId, readJsonFileWithFallback, readRequestBodyWithLimit, requestBodyErrorToText, resolveChannelContextVisibilityMode, resolveSessionStoreEntry, setFeishuRuntime };
@@ -0,0 +1,119 @@
1
+ import { collectConditionalChannelFieldAssignments, collectSimpleChannelFieldAssignments, getChannelSurface, hasOwnProperty, normalizeSecretStringValue } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
2
+ //#region extensions/feishu/src/secret-contract.ts
3
+ const secretTargetRegistryEntries = [
4
+ {
5
+ id: "channels.feishu.accounts.*.appSecret",
6
+ targetType: "channels.feishu.accounts.*.appSecret",
7
+ configFile: "openclaw.json",
8
+ pathPattern: "channels.feishu.accounts.*.appSecret",
9
+ secretShape: "secret_input",
10
+ expectedResolvedValue: "string",
11
+ includeInPlan: true,
12
+ includeInConfigure: true,
13
+ includeInAudit: true
14
+ },
15
+ {
16
+ id: "channels.feishu.accounts.*.encryptKey",
17
+ targetType: "channels.feishu.accounts.*.encryptKey",
18
+ configFile: "openclaw.json",
19
+ pathPattern: "channels.feishu.accounts.*.encryptKey",
20
+ secretShape: "secret_input",
21
+ expectedResolvedValue: "string",
22
+ includeInPlan: true,
23
+ includeInConfigure: true,
24
+ includeInAudit: true
25
+ },
26
+ {
27
+ id: "channels.feishu.accounts.*.verificationToken",
28
+ targetType: "channels.feishu.accounts.*.verificationToken",
29
+ configFile: "openclaw.json",
30
+ pathPattern: "channels.feishu.accounts.*.verificationToken",
31
+ secretShape: "secret_input",
32
+ expectedResolvedValue: "string",
33
+ includeInPlan: true,
34
+ includeInConfigure: true,
35
+ includeInAudit: true
36
+ },
37
+ {
38
+ id: "channels.feishu.appSecret",
39
+ targetType: "channels.feishu.appSecret",
40
+ configFile: "openclaw.json",
41
+ pathPattern: "channels.feishu.appSecret",
42
+ secretShape: "secret_input",
43
+ expectedResolvedValue: "string",
44
+ includeInPlan: true,
45
+ includeInConfigure: true,
46
+ includeInAudit: true
47
+ },
48
+ {
49
+ id: "channels.feishu.encryptKey",
50
+ targetType: "channels.feishu.encryptKey",
51
+ configFile: "openclaw.json",
52
+ pathPattern: "channels.feishu.encryptKey",
53
+ secretShape: "secret_input",
54
+ expectedResolvedValue: "string",
55
+ includeInPlan: true,
56
+ includeInConfigure: true,
57
+ includeInAudit: true
58
+ },
59
+ {
60
+ id: "channels.feishu.verificationToken",
61
+ targetType: "channels.feishu.verificationToken",
62
+ configFile: "openclaw.json",
63
+ pathPattern: "channels.feishu.verificationToken",
64
+ secretShape: "secret_input",
65
+ expectedResolvedValue: "string",
66
+ includeInPlan: true,
67
+ includeInConfigure: true,
68
+ includeInAudit: true
69
+ }
70
+ ];
71
+ function collectRuntimeConfigAssignments(params) {
72
+ const resolved = getChannelSurface(params.config, "feishu");
73
+ if (!resolved) return;
74
+ const { channel: feishu, surface } = resolved;
75
+ collectSimpleChannelFieldAssignments({
76
+ channelKey: "feishu",
77
+ field: "appSecret",
78
+ channel: feishu,
79
+ surface,
80
+ defaults: params.defaults,
81
+ context: params.context,
82
+ topInactiveReason: "no enabled account inherits this top-level Feishu appSecret.",
83
+ accountInactiveReason: "Feishu account is disabled."
84
+ });
85
+ const baseConnectionMode = normalizeSecretStringValue(feishu.connectionMode) === "webhook" ? "webhook" : "websocket";
86
+ const resolveAccountMode = (account) => hasOwnProperty(account, "connectionMode") ? normalizeSecretStringValue(account.connectionMode) : baseConnectionMode;
87
+ collectConditionalChannelFieldAssignments({
88
+ channelKey: "feishu",
89
+ field: "encryptKey",
90
+ channel: feishu,
91
+ surface,
92
+ defaults: params.defaults,
93
+ context: params.context,
94
+ topLevelActiveWithoutAccounts: baseConnectionMode === "webhook",
95
+ topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "encryptKey") && resolveAccountMode(account) === "webhook",
96
+ accountActive: ({ account, enabled }) => enabled && resolveAccountMode(account) === "webhook",
97
+ topInactiveReason: "no enabled Feishu webhook-mode surface inherits this top-level encryptKey.",
98
+ accountInactiveReason: "Feishu account is disabled or not running in webhook mode."
99
+ });
100
+ collectConditionalChannelFieldAssignments({
101
+ channelKey: "feishu",
102
+ field: "verificationToken",
103
+ channel: feishu,
104
+ surface,
105
+ defaults: params.defaults,
106
+ context: params.context,
107
+ topLevelActiveWithoutAccounts: baseConnectionMode === "webhook",
108
+ topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "verificationToken") && resolveAccountMode(account) === "webhook",
109
+ accountActive: ({ account, enabled }) => enabled && resolveAccountMode(account) === "webhook",
110
+ topInactiveReason: "no enabled Feishu webhook-mode surface inherits this top-level verificationToken.",
111
+ accountInactiveReason: "Feishu account is disabled or not running in webhook mode."
112
+ });
113
+ }
114
+ const channelSecrets = {
115
+ secretTargetRegistryEntries,
116
+ collectRuntimeConfigAssignments
117
+ };
118
+ //#endregion
119
+ export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
@@ -0,0 +1,2 @@
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-Dm4Z_zQN.js";
2
+ export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -0,0 +1,11 @@
1
+ import "./security-audit-shared-ByuMx9cJ.js";
2
+ //#region extensions/feishu/src/message-action-contract.ts
3
+ const messageActionTargetAliases = {
4
+ read: { aliases: ["messageId"] },
5
+ pin: { aliases: ["messageId"] },
6
+ unpin: { aliases: ["messageId"] },
7
+ "list-pins": { aliases: ["chatId"] },
8
+ "channel-info": { aliases: ["chatId"] }
9
+ };
10
+ //#endregion
11
+ export { messageActionTargetAliases as t };
@@ -0,0 +1,38 @@
1
+ import { hasConfiguredSecretInput } from "openclaw/plugin-sdk/secret-input";
2
+ //#region extensions/feishu/src/security-audit-shared.ts
3
+ function asRecord(value) {
4
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
5
+ }
6
+ function hasNonEmptyString(value) {
7
+ return typeof value === "string" && value.trim().length > 0;
8
+ }
9
+ function isFeishuDocToolEnabled(cfg) {
10
+ const feishu = asRecord(asRecord(cfg.channels)?.feishu);
11
+ if (!feishu || feishu.enabled === false) return false;
12
+ const baseTools = asRecord(feishu.tools);
13
+ const baseDocEnabled = baseTools?.doc !== false;
14
+ const baseAppId = hasNonEmptyString(feishu.appId);
15
+ const baseAppSecret = hasConfiguredSecretInput(feishu.appSecret, cfg.secrets?.defaults);
16
+ const baseConfigured = baseAppId && baseAppSecret;
17
+ const accounts = asRecord(feishu.accounts);
18
+ if (!accounts || Object.keys(accounts).length === 0) return baseDocEnabled && baseConfigured;
19
+ for (const accountValue of Object.values(accounts)) {
20
+ const account = asRecord(accountValue) ?? {};
21
+ if (account.enabled === false) continue;
22
+ if (!((asRecord(account.tools) ?? baseTools)?.doc !== false)) continue;
23
+ if ((hasNonEmptyString(account.appId) || baseAppId) && (hasConfiguredSecretInput(account.appSecret, cfg.secrets?.defaults) || baseAppSecret)) return true;
24
+ }
25
+ return false;
26
+ }
27
+ function collectFeishuSecurityAuditFindings(params) {
28
+ if (!isFeishuDocToolEnabled(params.cfg)) return [];
29
+ return [{
30
+ checkId: "channels.feishu.doc_owner_open_id",
31
+ severity: "warn",
32
+ title: "Feishu doc create can grant requester permissions",
33
+ detail: "channels.feishu tools include \"doc\"; feishu_doc action \"create\" can grant document access to the trusted requesting Feishu user.",
34
+ remediation: "Disable channels.feishu.tools.doc when not needed, and restrict tool access for untrusted prompts."
35
+ }];
36
+ }
37
+ //#endregion
38
+ export { collectFeishuSecurityAuditFindings as t };
@@ -0,0 +1,2 @@
1
+ import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-ByuMx9cJ.js";
2
+ export { collectFeishuSecurityAuditFindings };