@openclaw/discord 2026.7.1-beta.1 → 2026.7.1-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 (46) hide show
  1. package/dist/action-runtime-api.js +1 -1
  2. package/dist/api.js +6 -6
  3. package/dist/{approval-handler.runtime-DzoY4ufU.js → approval-handler.runtime-Cg7CuLSc.js} +2 -2
  4. package/dist/{audit-BXGKCgbA.js → audit-BCVhE9Oe.js} +2 -2
  5. package/dist/{channel-Da36gsaP.js → channel-CfngVOjW.js} +11 -31
  6. package/dist/{channel-actions-CamohoDF.js → channel-actions-DJ_i4v9b.js} +2 -5
  7. package/dist/{channel-actions.runtime-C1y4B9J0.js → channel-actions.runtime-BDW12z0o.js} +2 -2
  8. package/dist/channel-plugin-api.js +1 -1
  9. package/dist/{channel.setup-KhiBHeGT.js → channel.setup-BYZ78cmU.js} +1 -1
  10. package/dist/{conversation-identity-BEsyd7A1.js → conversation-identity-CnYbx3sO.js} +1 -1
  11. package/dist/{doctor-D3ngpo-Y.js → doctor-CKIw8urm.js} +1 -1
  12. package/dist/{handle-action.guild-admin-zmPNo8TF.js → handle-action.guild-admin-CHMDXefq.js} +2 -2
  13. package/dist/{manager.runtime-TLLuQzsA.js → manager.runtime-BkMOU8kh.js} +2 -2
  14. package/dist/{message-handler-ClZrgeka.js → message-handler-B2cEpj5S.js} +6 -13
  15. package/dist/{message-handler.preflight-CjnHwEwP.js → message-handler.preflight-B93Az6zg.js} +14 -40
  16. package/dist/{message-handler.process-OruF8JFV.js → message-handler.process-CW5mMw4o.js} +12 -19
  17. package/dist/{message-utils-C_tYBSAu.js → message-utils-Dy9KeClm.js} +1 -1
  18. package/dist/{outbound-adapter-B0iwUl6c.js → outbound-adapter-n_qRwyHZ.js} +6 -18
  19. package/dist/{preflight-audio-ClWbnQto.js → preflight-audio-DecwnhEA.js} +2 -5
  20. package/dist/{provider-CChQJujf.js → provider-BuTO6czP.js} +16 -35
  21. package/dist/{provider-session.runtime-Dy71XetI.js → provider-session.runtime-DmBTGaQX.js} +3 -3
  22. package/dist/provider.runtime-CqZpKOCE.js +2 -0
  23. package/dist/{runtime-C-fNslbg.js → runtime-DaaaVvJm.js} +325 -297
  24. package/dist/runtime-api.actions.js +2 -2
  25. package/dist/runtime-api.js +14 -14
  26. package/dist/runtime-api.lookup.js +1 -1
  27. package/dist/runtime-api.monitor-ChuqOjHq.js +6 -0
  28. package/dist/runtime-api.monitor.js +4 -4
  29. package/dist/runtime-api.send.js +4 -4
  30. package/dist/runtime-api.threads.js +3 -3
  31. package/dist/{send-BYTToRY1.js → send-B_yfprXu.js} +2 -2
  32. package/dist/{send.components-Cmv2qMB5.js → send.components-C2psXc7A.js} +2 -2
  33. package/dist/{send.outbound-BqvRMxXy.js → send.outbound-BPcCF1v2.js} +1 -1
  34. package/dist/{send.shared-YLGCAMjV.js → send.shared-CUTfqvXx.js} +2 -13
  35. package/dist/session-binding-contract-api.js +1 -1
  36. package/dist/setup-plugin-api.js +1 -1
  37. package/dist/{shared-D11J9bXI.js → shared-AnStShZr.js} +3 -10
  38. package/dist/{subagent-hooks-cE_tFGCX.js → subagent-hooks-DkO-jpvh.js} +1 -1
  39. package/dist/subagent-hooks-api.js +2 -5
  40. package/dist/{thread-bindings-C1yhwdOw.js → thread-bindings-BuXtcLSp.js} +2 -2
  41. package/dist/{thread-bindings.discord-api-XBJmlLaf.js → thread-bindings.discord-api-CetgvIbE.js} +3 -3
  42. package/dist/{thread-bindings.manager-BdFs0ot7.js → thread-bindings.manager-B7AHjU4s.js} +2 -2
  43. package/npm-shrinkwrap.json +3 -3
  44. package/package.json +4 -4
  45. package/dist/provider.runtime-BiOSsG0m.js +0 -2
  46. package/dist/runtime-api.monitor-CN1_mmYY.js +0 -6
@@ -1,17 +1,57 @@
1
1
  import { Ut as resolveDiscordChannelId } from "./send.receipt-CK162xD0.js";
2
2
  import { a as mergeDiscordAccountConfig, o as resolveDefaultDiscordAccountId, t as createDiscordActionGate } from "./accounts-P19jm1lf.js";
3
3
  import { d as readDiscordComponentSpec } from "./components-CBPNJhVP.js";
4
- import { _ as withNormalizedTimestamp, c as jsonResult, d as readNonNegativeIntegerParam, f as readPositiveIntegerParam, g as resolvePollMaxSelections, h as readStringParam, l as parseAvailableTags, m as readStringArrayParam, p as readReactionParams, r as sendDiscordComponentMessage, s as assertMediaNotDataUrl, u as readBooleanParam } from "./send.components-Cmv2qMB5.js";
4
+ import { _ as withNormalizedTimestamp, c as jsonResult, d as readNonNegativeIntegerParam, f as readPositiveIntegerParam, g as resolvePollMaxSelections, h as readStringParam, l as parseAvailableTags, m as readStringArrayParam, p as readReactionParams, r as sendDiscordComponentMessage, s as assertMediaNotDataUrl, u as readBooleanParam } from "./send.components-C2psXc7A.js";
5
5
  import { n as getGateway, o as getPresence } from "./gateway-registry-DPxmW0Db.js";
6
- import { E as canManageGuildRoleDiscord, L as createDiscordRuntimeAccountContext, M as hasAnyGuildPermissionDiscord, N as isThreadChannelType$1, O as fetchChannelPermissionsDiscord, T as canManageGuildMemberRoleDiscord, d as resolveDiscordTargetChannelId, j as hasAnyChannelPermissionDiscord } from "./send.shared-YLGCAMjV.js";
6
+ import { E as canManageGuildRoleDiscord, L as createDiscordRuntimeAccountContext, M as hasAnyGuildPermissionDiscord, N as isThreadChannelType$1, O as fetchChannelPermissionsDiscord, T as canManageGuildMemberRoleDiscord, d as resolveDiscordTargetChannelId, j as hasAnyChannelPermissionDiscord } from "./send.shared-CUTfqvXx.js";
7
7
  import { a as normalizeDiscordSlug, c as resolveDiscordChannelConfigWithFallback, n as isDiscordGroupAllowedByPolicy } from "./allow-list-C-MqM-B_.js";
8
- import { A as listScheduledEventsDiscord, B as moveChannelDiscord, C as fetchChannelInfoDiscord, D as fetchVoiceStatusDiscord, E as fetchRoleInfoDiscord, F as uploadEmojiDiscord, H as setChannelPermissionDiscord, I as uploadStickerDiscord, L as createChannelDiscord, M as resolveEventCoverImage, N as timeoutMemberDiscord, O as kickMemberDiscord, P as listGuildEmojisDiscord, R as deleteChannelDiscord, S as createScheduledEventDiscord, T as fetchMemberInfoDiscord, V as removeChannelPermissionDiscord, _ as readMessagesDiscord, a as removeReactionDiscord, b as addRoleDiscord, d as deleteMessageDiscord, f as editMessageDiscord, g as pinMessageDiscord, h as listThreadsDiscord, i as removeOwnReactionsDiscord, j as removeRoleDiscord, k as listGuildChannelsDiscord, l as DiscordThreadInitialMessageError, m as listPinsDiscord, n as fetchReactionsDiscord, p as fetchMessageDiscord, r as reactMessageDiscord, s as sendVoiceMessageDiscord, u as createThreadDiscord, v as searchMessagesDiscord, w as fetchGuildInfoDiscord, x as banMemberDiscord, y as unpinMessageDiscord, z as editChannelDiscord } from "./send-BYTToRY1.js";
9
- import { n as sendPollDiscord, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-BqvRMxXy.js";
8
+ import { A as listScheduledEventsDiscord, B as moveChannelDiscord, C as fetchChannelInfoDiscord, D as fetchVoiceStatusDiscord, E as fetchRoleInfoDiscord, F as uploadEmojiDiscord, H as setChannelPermissionDiscord, I as uploadStickerDiscord, L as createChannelDiscord, M as resolveEventCoverImage, N as timeoutMemberDiscord, O as kickMemberDiscord, P as listGuildEmojisDiscord, R as deleteChannelDiscord, S as createScheduledEventDiscord, T as fetchMemberInfoDiscord, V as removeChannelPermissionDiscord, _ as readMessagesDiscord, a as removeReactionDiscord, b as addRoleDiscord, d as deleteMessageDiscord, f as editMessageDiscord, g as pinMessageDiscord, h as listThreadsDiscord, i as removeOwnReactionsDiscord, j as removeRoleDiscord, k as listGuildChannelsDiscord, l as DiscordThreadInitialMessageError, m as listPinsDiscord, n as fetchReactionsDiscord, p as fetchMessageDiscord, r as reactMessageDiscord, s as sendVoiceMessageDiscord, u as createThreadDiscord, v as searchMessagesDiscord, w as fetchGuildInfoDiscord, x as banMemberDiscord, y as unpinMessageDiscord, z as editChannelDiscord } from "./send-B_yfprXu.js";
9
+ import { n as sendPollDiscord, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-BPcCF1v2.js";
10
10
  import "./targets-BA7gf0K0.js";
11
11
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
12
12
  import { ChannelType, PermissionFlagsBits } from "discord-api-types/v10";
13
13
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
14
14
  import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
15
+ //#region extensions/discord/src/actions/runtime.messaging.runtime.ts
16
+ const discordMessagingActionRuntime = {
17
+ createThreadDiscord,
18
+ deleteMessageDiscord,
19
+ editChannelDiscord,
20
+ editMessageDiscord,
21
+ fetchChannelInfoDiscord,
22
+ fetchGuildInfoDiscord,
23
+ fetchChannelPermissionsDiscord,
24
+ fetchMessageDiscord,
25
+ fetchReactionsDiscord,
26
+ listPinsDiscord,
27
+ listThreadsDiscord,
28
+ pinMessageDiscord,
29
+ reactMessageDiscord,
30
+ readDiscordComponentSpec,
31
+ readMessagesDiscord,
32
+ removeOwnReactionsDiscord,
33
+ removeReactionDiscord,
34
+ resolveDiscordReactionTargetChannelId,
35
+ resolveDiscordChannelId,
36
+ searchMessagesDiscord,
37
+ sendDiscordComponentMessage,
38
+ sendMessageDiscord,
39
+ sendPollDiscord,
40
+ sendStickerDiscord,
41
+ sendVoiceMessageDiscord,
42
+ unpinMessageDiscord
43
+ };
44
+ async function resolveDiscordReactionTargetChannelId(params) {
45
+ try {
46
+ return resolveDiscordChannelId(params.target);
47
+ } catch {
48
+ return (await resolveDiscordTargetChannelId(params.target, {
49
+ cfg: params.cfg,
50
+ accountId: params.accountId
51
+ })).channelId;
52
+ }
53
+ }
54
+ //#endregion
15
55
  //#region extensions/discord/src/actions/runtime.shared.ts
16
56
  function readDiscordParentIdParam(params) {
17
57
  if (params.clearParent === true) return null;
@@ -66,6 +106,239 @@ function readDiscordChannelMoveParams(params) {
66
106
  };
67
107
  }
68
108
  //#endregion
109
+ //#region extensions/discord/src/actions/runtime.messaging.shared.ts
110
+ function hasDiscordGuildEntries(guilds) {
111
+ return Boolean(guilds && Object.keys(guilds).length > 0);
112
+ }
113
+ function allowsAllDiscordGuildChannels(channels) {
114
+ const wildcard = channels?.["*"];
115
+ if (!wildcard || wildcard.enabled === false) return false;
116
+ return Object.values(channels ?? {}).every((entry) => entry?.enabled !== false);
117
+ }
118
+ function resolveDiscordActionGuildEntry(params) {
119
+ const guildId = params.guildId?.trim();
120
+ if (!params.guilds) return null;
121
+ if (guildId && params.guilds[guildId]) return {
122
+ ...params.guilds[guildId],
123
+ id: guildId
124
+ };
125
+ if (guildId) {
126
+ const byConfiguredId = Object.values(params.guilds).find((guild) => guild?.id === guildId);
127
+ if (byConfiguredId) return {
128
+ ...byConfiguredId,
129
+ id: guildId
130
+ };
131
+ }
132
+ const guildSlug = params.guildName ? normalizeDiscordSlug(params.guildName) : "";
133
+ if (guildSlug) {
134
+ const bySlug = params.guilds[guildSlug] ?? Object.values(params.guilds).find((guild) => guild?.slug === guildSlug);
135
+ if (bySlug) return {
136
+ ...bySlug,
137
+ id: guildId,
138
+ slug: guildSlug || bySlug.slug
139
+ };
140
+ }
141
+ if (params.includeWildcard === false) return null;
142
+ const wildcard = params.guilds["*"];
143
+ return wildcard ? {
144
+ ...wildcard,
145
+ id: guildId
146
+ } : null;
147
+ }
148
+ function readDiscordChannelStringField(value, ...keys) {
149
+ if (!value || typeof value !== "object") return;
150
+ const record = value;
151
+ for (const key of keys) {
152
+ const candidate = record[key];
153
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
154
+ }
155
+ }
156
+ function readDiscordChannelType(value) {
157
+ if (!value || typeof value !== "object") return;
158
+ const type = value.type;
159
+ return typeof type === "number" ? type : void 0;
160
+ }
161
+ function isDiscordThreadChannel(value) {
162
+ const type = readDiscordChannelType(value);
163
+ return type === 10 || type === 11 || type === 12;
164
+ }
165
+ function isDiscordReadTargetAllowedInGuild(params) {
166
+ if (resolveDiscordChannelConfigWithFallback({
167
+ guildInfo: params.guildInfo,
168
+ channelId: params.target.channelId,
169
+ channelName: params.target.channelName,
170
+ channelSlug: params.target.channelSlug,
171
+ parentId: params.target.parentId,
172
+ parentName: params.target.parentName,
173
+ parentSlug: params.target.parentSlug,
174
+ scope: params.target.scope
175
+ })?.allowed === false) return false;
176
+ return isDiscordGroupAllowedByPolicy({
177
+ groupPolicy: params.groupPolicy,
178
+ guildAllowlisted: Boolean(params.guildInfo),
179
+ channelAllowlistConfigured: hasDiscordGuildEntries(params.guildInfo?.channels),
180
+ channelAllowed: true
181
+ });
182
+ }
183
+ function isDiscordReadTargetExplicitlyAllowedById(params) {
184
+ const channelEntry = params.guildInfo?.channels?.[params.target.channelId];
185
+ if (!channelEntry || channelEntry.enabled === false) return false;
186
+ return isDiscordGroupAllowedByPolicy({
187
+ groupPolicy: params.groupPolicy,
188
+ guildAllowlisted: Boolean(params.guildInfo),
189
+ channelAllowlistConfigured: true,
190
+ channelAllowed: true
191
+ });
192
+ }
193
+ function createDiscordMessagingActionContext(params) {
194
+ const accountId = readStringParam(params.input, "accountId");
195
+ const cfgOptions = { cfg: params.cfg };
196
+ const accountConfig = mergeDiscordAccountConfig(params.cfg, accountId ?? resolveDefaultDiscordAccountId(params.cfg));
197
+ const guilds = accountConfig.guilds;
198
+ const hasGuildEntries = Object.keys(guilds ?? {}).length > 0;
199
+ const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({
200
+ providerConfigPresent: params.cfg.channels?.discord !== void 0,
201
+ groupPolicy: accountConfig.groupPolicy,
202
+ defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
203
+ });
204
+ const withOpts = (extra) => createDiscordActionOptions({
205
+ cfg: params.cfg,
206
+ accountId,
207
+ extra
208
+ });
209
+ const resolvedReactionAccountId = accountId ?? resolveDefaultDiscordAccountId(params.cfg);
210
+ const reactionRuntimeOptions = resolvedReactionAccountId ? createDiscordRuntimeAccountContext({
211
+ cfg: params.cfg,
212
+ accountId: resolvedReactionAccountId
213
+ }) : cfgOptions;
214
+ const guildNameById = /* @__PURE__ */ new Map();
215
+ const resolveGuildName = async (guildId) => {
216
+ if (guildNameById.has(guildId)) return guildNameById.get(guildId) ?? null;
217
+ try {
218
+ const guildName = readDiscordChannelStringField(await discordMessagingActionRuntime.fetchGuildInfoDiscord(guildId, withOpts()), "name") ?? null;
219
+ guildNameById.set(guildId, guildName);
220
+ return guildName;
221
+ } catch {
222
+ guildNameById.set(guildId, null);
223
+ return null;
224
+ }
225
+ };
226
+ const resolveReadGuildEntry = async (guildId) => {
227
+ const direct = resolveDiscordActionGuildEntry({
228
+ guilds,
229
+ guildId,
230
+ includeWildcard: false
231
+ });
232
+ if (direct || !guildId) return direct;
233
+ const named = resolveDiscordActionGuildEntry({
234
+ guilds,
235
+ guildId,
236
+ guildName: await resolveGuildName(guildId) ?? void 0,
237
+ includeWildcard: false
238
+ });
239
+ if (named) return named;
240
+ return resolveDiscordActionGuildEntry({
241
+ guilds,
242
+ guildId
243
+ });
244
+ };
245
+ const resolveReadTargetContext = async (channelId) => {
246
+ const fallback = {
247
+ channelId,
248
+ channelSlug: normalizeDiscordSlug(channelId) || channelId
249
+ };
250
+ let channelInfo;
251
+ try {
252
+ channelInfo = await discordMessagingActionRuntime.fetchChannelInfoDiscord(channelId, withOpts());
253
+ } catch {
254
+ return fallback;
255
+ }
256
+ const channelName = readDiscordChannelStringField(channelInfo, "name");
257
+ const target = {
258
+ channelId,
259
+ channelSlug: channelName ? normalizeDiscordSlug(channelName) : fallback.channelSlug
260
+ };
261
+ const targetGuildId = readDiscordChannelStringField(channelInfo, "guild_id", "guildId");
262
+ if (targetGuildId) target.guildId = targetGuildId;
263
+ if (channelName) target.channelName = channelName;
264
+ if (!isDiscordThreadChannel(channelInfo)) return target;
265
+ target.scope = "thread";
266
+ target.parentId = readDiscordChannelStringField(channelInfo, "parent_id", "parentId");
267
+ if (!target.parentId) return target;
268
+ try {
269
+ const parentName = readDiscordChannelStringField(await discordMessagingActionRuntime.fetchChannelInfoDiscord(target.parentId, withOpts()), "name");
270
+ if (parentName) {
271
+ target.parentName = parentName;
272
+ target.parentSlug = normalizeDiscordSlug(parentName);
273
+ }
274
+ } catch {}
275
+ return target;
276
+ };
277
+ return {
278
+ action: params.action,
279
+ params: params.input,
280
+ isActionEnabled: params.isActionEnabled,
281
+ cfg: params.cfg,
282
+ options: params.options,
283
+ accountId,
284
+ resolveChannelId: () => discordMessagingActionRuntime.resolveDiscordChannelId(readStringParam(params.input, "channelId", { required: true })),
285
+ assertReadTargetAllowed: async ({ guildId, channelId }) => {
286
+ const targetChannelId = discordMessagingActionRuntime.resolveDiscordChannelId(channelId);
287
+ if (!hasGuildEntries && groupPolicy !== "disabled" && groupPolicy !== "allowlist") return;
288
+ const target = await resolveReadTargetContext(targetChannelId);
289
+ if (guildId) {
290
+ if (target.guildId && target.guildId !== guildId) throw new Error("Discord read target channel is not allowed.");
291
+ if (!isDiscordReadTargetAllowedInGuild({
292
+ groupPolicy,
293
+ guildInfo: await resolveReadGuildEntry(guildId),
294
+ target
295
+ })) throw new Error("Discord read target channel is not allowed.");
296
+ return;
297
+ }
298
+ if (target.guildId) {
299
+ if (!isDiscordReadTargetAllowedInGuild({
300
+ groupPolicy,
301
+ guildInfo: await resolveReadGuildEntry(target.guildId),
302
+ target
303
+ })) throw new Error("Discord read target channel is not allowed.");
304
+ return;
305
+ }
306
+ if (!Object.values(guilds ?? {}).some((guildInfo) => isDiscordReadTargetExplicitlyAllowedById({
307
+ groupPolicy,
308
+ guildInfo: guildInfo ?? null,
309
+ target
310
+ }))) throw new Error("Discord read target channel is not allowed.");
311
+ },
312
+ assertGuildReadTargetAllowed: async ({ guildId, channelTargetRequiredMessage }) => {
313
+ const guildInfo = await resolveReadGuildEntry(guildId);
314
+ if (!isDiscordGroupAllowedByPolicy({
315
+ groupPolicy,
316
+ guildAllowlisted: Boolean(guildInfo),
317
+ channelAllowlistConfigured: false,
318
+ channelAllowed: true
319
+ })) throw new Error("Discord read target channel is not allowed.");
320
+ if (hasDiscordGuildEntries(guildInfo?.channels) && !allowsAllDiscordGuildChannels(guildInfo.channels)) throw new Error(channelTargetRequiredMessage ?? "Discord message search requires channelId or channelIds so each read target can be authorized.");
321
+ },
322
+ resolveReactionChannelId: async () => {
323
+ const target = readStringParam(params.input, "channelId") ?? readStringParam(params.input, "to", { required: true });
324
+ return await discordMessagingActionRuntime.resolveDiscordReactionTargetChannelId({
325
+ target,
326
+ cfg: params.cfg,
327
+ accountId: resolvedReactionAccountId
328
+ });
329
+ },
330
+ withOpts,
331
+ withReactionRuntimeOptions: (extra) => ({
332
+ ...reactionRuntimeOptions ?? cfgOptions,
333
+ ...extra
334
+ }),
335
+ normalizeMessage: (message) => {
336
+ if (!message || typeof message !== "object") return message;
337
+ return withNormalizedTimestamp(message, message.timestamp);
338
+ }
339
+ };
340
+ }
341
+ //#endregion
69
342
  //#region extensions/discord/src/actions/runtime.guild.ts
70
343
  const discordGuildActionRuntime = {
71
344
  addRoleDiscord,
@@ -245,15 +518,29 @@ async function handleDiscordGuildAction(action, params, isActionEnabled, cfg, op
245
518
  accountId,
246
519
  cfg
247
520
  });
521
+ const readTargetGate = createDiscordMessagingActionContext({
522
+ action,
523
+ input: params,
524
+ isActionEnabled,
525
+ cfg,
526
+ options
527
+ });
248
528
  const withOpts = (extra) => createDiscordActionOptions({
249
529
  cfg,
250
530
  accountId,
251
531
  extra
252
532
  });
533
+ const assertGuildMetadataReadAllowed = async (guildId) => {
534
+ await readTargetGate.assertGuildReadTargetAllowed({
535
+ guildId,
536
+ channelTargetRequiredMessage: "Discord guild metadata reads require a wildcard channel allowlist for this guild."
537
+ });
538
+ };
253
539
  switch (action) {
254
540
  case "memberInfo": {
255
541
  if (!isActionEnabled("memberInfo")) throw new Error("Discord member info is disabled.");
256
542
  const guildId = readStringParam(params, "guildId", { required: true });
543
+ await assertGuildMetadataReadAllowed(guildId);
257
544
  const userId = readStringParam(params, "userId", { required: true });
258
545
  const effectiveAccountId = accountId ?? resolveDefaultDiscordAccountId(cfg);
259
546
  const member = await discordGuildActionRuntime.fetchMemberInfoDiscord(guildId, userId, createDiscordActionOptions({
@@ -275,6 +562,7 @@ async function handleDiscordGuildAction(action, params, isActionEnabled, cfg, op
275
562
  case "roleInfo": {
276
563
  if (!isActionEnabled("roleInfo")) throw new Error("Discord role info is disabled.");
277
564
  const guildId = readStringParam(params, "guildId", { required: true });
565
+ await assertGuildMetadataReadAllowed(guildId);
278
566
  return jsonResult({
279
567
  ok: true,
280
568
  roles: await discordGuildActionRuntime.fetchRoleInfoDiscord(guildId, withOpts())
@@ -283,6 +571,7 @@ async function handleDiscordGuildAction(action, params, isActionEnabled, cfg, op
283
571
  case "emojiList": {
284
572
  if (!isActionEnabled("reactions")) throw new Error("Discord reactions are disabled.");
285
573
  const guildId = readStringParam(params, "guildId", { required: true });
574
+ await assertGuildMetadataReadAllowed(guildId);
286
575
  return jsonResult({
287
576
  ok: true,
288
577
  emojis: await discordGuildActionRuntime.listGuildEmojisDiscord(guildId, withOpts())
@@ -343,6 +632,7 @@ async function handleDiscordGuildAction(action, params, isActionEnabled, cfg, op
343
632
  case "channelInfo": {
344
633
  if (!isActionEnabled("channelInfo")) throw new Error("Discord channel info is disabled.");
345
634
  const channelId = readStringParam(params, "channelId", { required: true });
635
+ await readTargetGate.assertReadTargetAllowed({ channelId });
346
636
  return jsonResult({
347
637
  ok: true,
348
638
  channel: await discordGuildActionRuntime.fetchChannelInfoDiscord(channelId, withOpts())
@@ -351,6 +641,7 @@ async function handleDiscordGuildAction(action, params, isActionEnabled, cfg, op
351
641
  case "channelList": {
352
642
  if (!isActionEnabled("channelInfo")) throw new Error("Discord channel info is disabled.");
353
643
  const guildId = readStringParam(params, "guildId", { required: true });
644
+ await assertGuildMetadataReadAllowed(guildId);
354
645
  return jsonResult({
355
646
  ok: true,
356
647
  channels: await discordGuildActionRuntime.listGuildChannelsDiscord(guildId, withOpts())
@@ -359,6 +650,7 @@ async function handleDiscordGuildAction(action, params, isActionEnabled, cfg, op
359
650
  case "voiceStatus": {
360
651
  if (!isActionEnabled("voiceStatus")) throw new Error("Discord voice status is disabled.");
361
652
  const guildId = readStringParam(params, "guildId", { required: true });
653
+ await assertGuildMetadataReadAllowed(guildId);
362
654
  const userId = readStringParam(params, "userId", { required: true });
363
655
  return jsonResult({
364
656
  ok: true,
@@ -368,6 +660,7 @@ async function handleDiscordGuildAction(action, params, isActionEnabled, cfg, op
368
660
  case "eventList": {
369
661
  if (!isActionEnabled("events")) throw new Error("Discord events are disabled.");
370
662
  const guildId = readStringParam(params, "guildId", { required: true });
663
+ await assertGuildMetadataReadAllowed(guildId);
371
664
  return jsonResult({
372
665
  ok: true,
373
666
  events: await discordGuildActionRuntime.listScheduledEventsDiscord(guildId, withOpts())
@@ -459,66 +752,26 @@ async function handleDiscordGuildAction(action, params, isActionEnabled, cfg, op
459
752
  }
460
753
  case "channelPermissionSet": {
461
754
  if (!isActionEnabled("channels")) throw new Error("Discord channel management is disabled.");
462
- const { channelId, targetId } = readChannelPermissionTarget(params);
463
- const targetType = readStringParam(params, "targetType", { required: true }) === "member" ? 1 : 0;
464
- const allow = readStringParam(params, "allow");
465
- const deny = readStringParam(params, "deny");
466
- await discordGuildActionRuntime.setChannelPermissionDiscord({
467
- channelId,
468
- targetId,
469
- targetType,
470
- allow: allow ?? void 0,
471
- deny: deny ?? void 0
472
- }, withOpts());
473
- return jsonResult({ ok: true });
474
- }
475
- case "channelPermissionRemove": {
476
- if (!isActionEnabled("channels")) throw new Error("Discord channel management is disabled.");
477
- const { channelId, targetId } = readChannelPermissionTarget(params);
478
- await discordGuildActionRuntime.removeChannelPermissionDiscord(channelId, targetId, withOpts());
479
- return jsonResult({ ok: true });
480
- }
481
- default: throw new Error(`Unknown action: ${action}`);
482
- }
483
- }
484
- //#endregion
485
- //#region extensions/discord/src/actions/runtime.messaging.runtime.ts
486
- const discordMessagingActionRuntime = {
487
- createThreadDiscord,
488
- deleteMessageDiscord,
489
- editChannelDiscord,
490
- editMessageDiscord,
491
- fetchChannelInfoDiscord,
492
- fetchGuildInfoDiscord,
493
- fetchChannelPermissionsDiscord,
494
- fetchMessageDiscord,
495
- fetchReactionsDiscord,
496
- listPinsDiscord,
497
- listThreadsDiscord,
498
- pinMessageDiscord,
499
- reactMessageDiscord,
500
- readDiscordComponentSpec,
501
- readMessagesDiscord,
502
- removeOwnReactionsDiscord,
503
- removeReactionDiscord,
504
- resolveDiscordReactionTargetChannelId,
505
- resolveDiscordChannelId,
506
- searchMessagesDiscord,
507
- sendDiscordComponentMessage,
508
- sendMessageDiscord,
509
- sendPollDiscord,
510
- sendStickerDiscord,
511
- sendVoiceMessageDiscord,
512
- unpinMessageDiscord
513
- };
514
- async function resolveDiscordReactionTargetChannelId(params) {
515
- try {
516
- return resolveDiscordChannelId(params.target);
517
- } catch {
518
- return (await resolveDiscordTargetChannelId(params.target, {
519
- cfg: params.cfg,
520
- accountId: params.accountId
521
- })).channelId;
755
+ const { channelId, targetId } = readChannelPermissionTarget(params);
756
+ const targetType = readStringParam(params, "targetType", { required: true }) === "member" ? 1 : 0;
757
+ const allow = readStringParam(params, "allow");
758
+ const deny = readStringParam(params, "deny");
759
+ await discordGuildActionRuntime.setChannelPermissionDiscord({
760
+ channelId,
761
+ targetId,
762
+ targetType,
763
+ allow: allow ?? void 0,
764
+ deny: deny ?? void 0
765
+ }, withOpts());
766
+ return jsonResult({ ok: true });
767
+ }
768
+ case "channelPermissionRemove": {
769
+ if (!isActionEnabled("channels")) throw new Error("Discord channel management is disabled.");
770
+ const { channelId, targetId } = readChannelPermissionTarget(params);
771
+ await discordGuildActionRuntime.removeChannelPermissionDiscord(channelId, targetId, withOpts());
772
+ return jsonResult({ ok: true });
773
+ }
774
+ default: throw new Error(`Unknown action: ${action}`);
522
775
  }
523
776
  }
524
777
  //#endregion
@@ -965,6 +1218,14 @@ async function handleDiscordMessageSendAction(ctx) {
965
1218
  const includeArchived = readBooleanParam(ctx.params, "includeArchived");
966
1219
  const before = readStringParam(ctx.params, "before");
967
1220
  const limit = readPositiveIntegerParam(ctx.params, "limit");
1221
+ if (channelId && includeArchived === true) await ctx.assertReadTargetAllowed({
1222
+ guildId,
1223
+ channelId
1224
+ });
1225
+ else await ctx.assertGuildReadTargetAllowed({
1226
+ guildId,
1227
+ channelTargetRequiredMessage: "Discord active thread lists require a wildcard channel allowlist so each read target can be authorized."
1228
+ });
968
1229
  return jsonResult(normalizeDiscordThreadListActionResult({
969
1230
  value: await discordMessagingActionRuntime.listThreadsDiscord({
970
1231
  guildId,
@@ -1001,239 +1262,6 @@ async function handleDiscordMessageSendAction(ctx) {
1001
1262
  }
1002
1263
  }
1003
1264
  //#endregion
1004
- //#region extensions/discord/src/actions/runtime.messaging.shared.ts
1005
- function hasDiscordGuildEntries(guilds) {
1006
- return Boolean(guilds && Object.keys(guilds).length > 0);
1007
- }
1008
- function allowsAllDiscordGuildChannels(channels) {
1009
- const wildcard = channels?.["*"];
1010
- if (!wildcard || wildcard.enabled === false) return false;
1011
- return Object.values(channels ?? {}).every((entry) => entry?.enabled !== false);
1012
- }
1013
- function resolveDiscordActionGuildEntry(params) {
1014
- const guildId = params.guildId?.trim();
1015
- if (!params.guilds) return null;
1016
- if (guildId && params.guilds[guildId]) return {
1017
- ...params.guilds[guildId],
1018
- id: guildId
1019
- };
1020
- if (guildId) {
1021
- const byConfiguredId = Object.values(params.guilds).find((guild) => guild?.id === guildId);
1022
- if (byConfiguredId) return {
1023
- ...byConfiguredId,
1024
- id: guildId
1025
- };
1026
- }
1027
- const guildSlug = params.guildName ? normalizeDiscordSlug(params.guildName) : "";
1028
- if (guildSlug) {
1029
- const bySlug = params.guilds[guildSlug] ?? Object.values(params.guilds).find((guild) => guild?.slug === guildSlug);
1030
- if (bySlug) return {
1031
- ...bySlug,
1032
- id: guildId,
1033
- slug: guildSlug || bySlug.slug
1034
- };
1035
- }
1036
- if (params.includeWildcard === false) return null;
1037
- const wildcard = params.guilds["*"];
1038
- return wildcard ? {
1039
- ...wildcard,
1040
- id: guildId
1041
- } : null;
1042
- }
1043
- function readDiscordChannelStringField(value, ...keys) {
1044
- if (!value || typeof value !== "object") return;
1045
- const record = value;
1046
- for (const key of keys) {
1047
- const candidate = record[key];
1048
- if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1049
- }
1050
- }
1051
- function readDiscordChannelType(value) {
1052
- if (!value || typeof value !== "object") return;
1053
- const type = value.type;
1054
- return typeof type === "number" ? type : void 0;
1055
- }
1056
- function isDiscordThreadChannel(value) {
1057
- const type = readDiscordChannelType(value);
1058
- return type === 10 || type === 11 || type === 12;
1059
- }
1060
- function isDiscordReadTargetAllowedInGuild(params) {
1061
- if (resolveDiscordChannelConfigWithFallback({
1062
- guildInfo: params.guildInfo,
1063
- channelId: params.target.channelId,
1064
- channelName: params.target.channelName,
1065
- channelSlug: params.target.channelSlug,
1066
- parentId: params.target.parentId,
1067
- parentName: params.target.parentName,
1068
- parentSlug: params.target.parentSlug,
1069
- scope: params.target.scope
1070
- })?.allowed === false) return false;
1071
- return isDiscordGroupAllowedByPolicy({
1072
- groupPolicy: params.groupPolicy,
1073
- guildAllowlisted: Boolean(params.guildInfo),
1074
- channelAllowlistConfigured: hasDiscordGuildEntries(params.guildInfo?.channels),
1075
- channelAllowed: true
1076
- });
1077
- }
1078
- function isDiscordReadTargetExplicitlyAllowedById(params) {
1079
- const channelEntry = params.guildInfo?.channels?.[params.target.channelId];
1080
- if (!channelEntry || channelEntry.enabled === false) return false;
1081
- return isDiscordGroupAllowedByPolicy({
1082
- groupPolicy: params.groupPolicy,
1083
- guildAllowlisted: Boolean(params.guildInfo),
1084
- channelAllowlistConfigured: true,
1085
- channelAllowed: true
1086
- });
1087
- }
1088
- function createDiscordMessagingActionContext(params) {
1089
- const accountId = readStringParam(params.input, "accountId");
1090
- const cfgOptions = { cfg: params.cfg };
1091
- const accountConfig = mergeDiscordAccountConfig(params.cfg, accountId ?? resolveDefaultDiscordAccountId(params.cfg));
1092
- const guilds = accountConfig.guilds;
1093
- const hasGuildEntries = Object.keys(guilds ?? {}).length > 0;
1094
- const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({
1095
- providerConfigPresent: params.cfg.channels?.discord !== void 0,
1096
- groupPolicy: accountConfig.groupPolicy,
1097
- defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
1098
- });
1099
- const withOpts = (extra) => createDiscordActionOptions({
1100
- cfg: params.cfg,
1101
- accountId,
1102
- extra
1103
- });
1104
- const resolvedReactionAccountId = accountId ?? resolveDefaultDiscordAccountId(params.cfg);
1105
- const reactionRuntimeOptions = resolvedReactionAccountId ? createDiscordRuntimeAccountContext({
1106
- cfg: params.cfg,
1107
- accountId: resolvedReactionAccountId
1108
- }) : cfgOptions;
1109
- const guildNameById = /* @__PURE__ */ new Map();
1110
- const resolveGuildName = async (guildId) => {
1111
- if (guildNameById.has(guildId)) return guildNameById.get(guildId) ?? null;
1112
- try {
1113
- const guildName = readDiscordChannelStringField(await discordMessagingActionRuntime.fetchGuildInfoDiscord(guildId, withOpts()), "name") ?? null;
1114
- guildNameById.set(guildId, guildName);
1115
- return guildName;
1116
- } catch {
1117
- guildNameById.set(guildId, null);
1118
- return null;
1119
- }
1120
- };
1121
- const resolveReadGuildEntry = async (guildId) => {
1122
- const direct = resolveDiscordActionGuildEntry({
1123
- guilds,
1124
- guildId,
1125
- includeWildcard: false
1126
- });
1127
- if (direct || !guildId) return direct;
1128
- const named = resolveDiscordActionGuildEntry({
1129
- guilds,
1130
- guildId,
1131
- guildName: await resolveGuildName(guildId) ?? void 0,
1132
- includeWildcard: false
1133
- });
1134
- if (named) return named;
1135
- return resolveDiscordActionGuildEntry({
1136
- guilds,
1137
- guildId
1138
- });
1139
- };
1140
- const resolveReadTargetContext = async (channelId) => {
1141
- const fallback = {
1142
- channelId,
1143
- channelSlug: normalizeDiscordSlug(channelId) || channelId
1144
- };
1145
- let channelInfo;
1146
- try {
1147
- channelInfo = await discordMessagingActionRuntime.fetchChannelInfoDiscord(channelId, withOpts());
1148
- } catch {
1149
- return fallback;
1150
- }
1151
- const channelName = readDiscordChannelStringField(channelInfo, "name");
1152
- const target = {
1153
- channelId,
1154
- channelSlug: channelName ? normalizeDiscordSlug(channelName) : fallback.channelSlug
1155
- };
1156
- const targetGuildId = readDiscordChannelStringField(channelInfo, "guild_id", "guildId");
1157
- if (targetGuildId) target.guildId = targetGuildId;
1158
- if (channelName) target.channelName = channelName;
1159
- if (!isDiscordThreadChannel(channelInfo)) return target;
1160
- target.scope = "thread";
1161
- target.parentId = readDiscordChannelStringField(channelInfo, "parent_id", "parentId");
1162
- if (!target.parentId) return target;
1163
- try {
1164
- const parentName = readDiscordChannelStringField(await discordMessagingActionRuntime.fetchChannelInfoDiscord(target.parentId, withOpts()), "name");
1165
- if (parentName) {
1166
- target.parentName = parentName;
1167
- target.parentSlug = normalizeDiscordSlug(parentName);
1168
- }
1169
- } catch {}
1170
- return target;
1171
- };
1172
- return {
1173
- action: params.action,
1174
- params: params.input,
1175
- isActionEnabled: params.isActionEnabled,
1176
- cfg: params.cfg,
1177
- options: params.options,
1178
- accountId,
1179
- resolveChannelId: () => discordMessagingActionRuntime.resolveDiscordChannelId(readStringParam(params.input, "channelId", { required: true })),
1180
- assertReadTargetAllowed: async ({ guildId, channelId }) => {
1181
- const targetChannelId = discordMessagingActionRuntime.resolveDiscordChannelId(channelId);
1182
- if (!hasGuildEntries && groupPolicy !== "disabled" && groupPolicy !== "allowlist") return;
1183
- const target = await resolveReadTargetContext(targetChannelId);
1184
- if (guildId) {
1185
- if (target.guildId && target.guildId !== guildId) throw new Error("Discord read target channel is not allowed.");
1186
- if (!isDiscordReadTargetAllowedInGuild({
1187
- groupPolicy,
1188
- guildInfo: await resolveReadGuildEntry(guildId),
1189
- target
1190
- })) throw new Error("Discord read target channel is not allowed.");
1191
- return;
1192
- }
1193
- if (target.guildId) {
1194
- if (!isDiscordReadTargetAllowedInGuild({
1195
- groupPolicy,
1196
- guildInfo: await resolveReadGuildEntry(target.guildId),
1197
- target
1198
- })) throw new Error("Discord read target channel is not allowed.");
1199
- return;
1200
- }
1201
- if (!Object.values(guilds ?? {}).some((guildInfo) => isDiscordReadTargetExplicitlyAllowedById({
1202
- groupPolicy,
1203
- guildInfo: guildInfo ?? null,
1204
- target
1205
- }))) throw new Error("Discord read target channel is not allowed.");
1206
- },
1207
- assertGuildReadTargetAllowed: async ({ guildId }) => {
1208
- const guildInfo = await resolveReadGuildEntry(guildId);
1209
- if (!isDiscordGroupAllowedByPolicy({
1210
- groupPolicy,
1211
- guildAllowlisted: Boolean(guildInfo),
1212
- channelAllowlistConfigured: false,
1213
- channelAllowed: true
1214
- })) throw new Error("Discord read target channel is not allowed.");
1215
- if (hasDiscordGuildEntries(guildInfo?.channels) && !allowsAllDiscordGuildChannels(guildInfo.channels)) throw new Error("Discord message search requires channelId or channelIds so each read target can be authorized.");
1216
- },
1217
- resolveReactionChannelId: async () => {
1218
- const target = readStringParam(params.input, "channelId") ?? readStringParam(params.input, "to", { required: true });
1219
- return await discordMessagingActionRuntime.resolveDiscordReactionTargetChannelId({
1220
- target,
1221
- cfg: params.cfg,
1222
- accountId: resolvedReactionAccountId
1223
- });
1224
- },
1225
- withOpts,
1226
- withReactionRuntimeOptions: (extra) => ({
1227
- ...reactionRuntimeOptions ?? cfgOptions,
1228
- ...extra
1229
- }),
1230
- normalizeMessage: (message) => {
1231
- if (!message || typeof message !== "object") return message;
1232
- return withNormalizedTimestamp(message, message.timestamp);
1233
- }
1234
- };
1235
- }
1236
- //#endregion
1237
1265
  //#region extensions/discord/src/actions/runtime.messaging.ts
1238
1266
  async function handleDiscordMessagingAction(action, params, isActionEnabled, cfg, options) {
1239
1267
  if (!cfg) throw new Error("Discord messaging actions require a resolved runtime config.");