@openclaw/discord 2026.6.11 → 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 (66) hide show
  1. package/dist/action-runtime-api.js +1 -1
  2. package/dist/{api-4GFMoWu0.js → api-CJvEMuA6.js} +9 -2
  3. package/dist/api.js +14 -14
  4. package/dist/{approval-handler.runtime-SsFtZQA6.js → approval-handler.runtime-Cg7CuLSc.js} +3 -3
  5. package/dist/{audit-CAnmyf2A.js → audit-BCVhE9Oe.js} +3 -3
  6. package/dist/{channel-YA7AbYP3.js → channel-CfngVOjW.js} +17 -37
  7. package/dist/{channel-actions-BJ3n5Z1l.js → channel-actions-DJ_i4v9b.js} +3 -6
  8. package/dist/{channel-actions.runtime-D2QTRgZ9.js → channel-actions.runtime-BDW12z0o.js} +5 -5
  9. package/dist/channel-plugin-api.js +1 -1
  10. package/dist/{channel.setup-B1zDEAR7.js → channel.setup-BYZ78cmU.js} +3 -3
  11. package/dist/{components-Dm4c_ce6.js → components-CBPNJhVP.js} +1 -1
  12. package/dist/{conversation-identity-DZ0BD7xO.js → conversation-identity-CnYbx3sO.js} +2 -2
  13. package/dist/{directory-config-BK1OhHa3.js → directory-config-CouAqvDj.js} +1 -1
  14. package/dist/directory-contract-api.js +1 -1
  15. package/dist/{directory-live-DP3CmwGf.js → directory-live-C8lwwDJo.js} +2 -2
  16. package/dist/{doctor-D3ngpo-Y.js → doctor-CKIw8urm.js} +1 -1
  17. package/dist/{handle-action.guild-admin-B2cOoU2D.js → handle-action.guild-admin-CHMDXefq.js} +2 -2
  18. package/dist/index.js +1 -1
  19. package/dist/{manager.runtime-CPHxr9B3.js → manager.runtime-BkMOU8kh.js} +4 -4
  20. package/dist/{message-handler-CKaTgBIV.js → message-handler-B2cEpj5S.js} +11 -15
  21. package/dist/{message-handler.preflight--eAiaewz.js → message-handler.preflight-B93Az6zg.js} +15 -41
  22. package/dist/{message-handler.process-PhKAmrEd.js → message-handler.process-CW5mMw4o.js} +204 -33
  23. package/dist/{message-utils-O1vK3kPu.js → message-utils-Dy9KeClm.js} +1 -1
  24. package/dist/{outbound-adapter-fO_7hbTh.js → outbound-adapter-n_qRwyHZ.js} +17 -23
  25. package/dist/{pluralkit-B3MzPaPU.js → pluralkit-DaWTJTmF.js} +3 -3
  26. package/dist/{preflight-audio-ClWbnQto.js → preflight-audio-DecwnhEA.js} +2 -5
  27. package/dist/{probe-CxnDikWm.js → probe-Bkf8mJlj.js} +3 -2
  28. package/dist/{probe.runtime-DLFkSDVB.js → probe.runtime-3Rerer9g.js} +1 -1
  29. package/dist/{provider-BJaJ20MY.js → provider-BuTO6czP.js} +68 -60
  30. package/dist/{provider-session.runtime-D6xc-60s.js → provider-session.runtime-DmBTGaQX.js} +3 -3
  31. package/dist/provider.runtime-CqZpKOCE.js +2 -0
  32. package/dist/{resolve-allowlist-common-BDpBb8dF.js → resolve-allowlist-common-BDNoAQll.js} +1 -1
  33. package/dist/{resolve-channels-iJIjYfRw.js → resolve-channels-C_rAwrkj.js} +3 -3
  34. package/dist/{resolve-users-_fv1mm1f.js → resolve-users-Cz1tkemy.js} +3 -3
  35. package/dist/{runtime-ywXByivr.js → runtime-DaaaVvJm.js} +330 -303
  36. package/dist/runtime-api.actions.js +2 -2
  37. package/dist/runtime-api.js +19 -19
  38. package/dist/runtime-api.lookup.js +5 -5
  39. package/dist/runtime-api.monitor-ChuqOjHq.js +6 -0
  40. package/dist/runtime-api.monitor.js +4 -4
  41. package/dist/runtime-api.send.js +5 -5
  42. package/dist/runtime-api.threads.js +3 -3
  43. package/dist/{send-Dc5uQX5H.js → send-B_yfprXu.js} +18 -9
  44. package/dist/{send.components-D4bl20xr.js → send.components-C2psXc7A.js} +4 -4
  45. package/dist/{send.outbound-5axvwLkl.js → send.outbound-BPcCF1v2.js} +5 -4
  46. package/dist/{send.receipt-B21MspvT.js → send.receipt-CK162xD0.js} +28 -1
  47. package/dist/{send.shared-9082A2sO.js → send.shared-CUTfqvXx.js} +4 -15
  48. package/dist/session-binding-contract-api.js +1 -1
  49. package/dist/setup-plugin-api.js +1 -1
  50. package/dist/{shared-D11J9bXI.js → shared-AnStShZr.js} +3 -10
  51. package/dist/{subagent-hooks-NTv6B4up.js → subagent-hooks-DkO-jpvh.js} +2 -2
  52. package/dist/subagent-hooks-api.js +2 -5
  53. package/dist/{system-events-BzaI1WpN.js → system-events-XRYuwB2n.js} +1 -1
  54. package/dist/{target-resolver-agnOrtOU.js → target-resolver-DYufMbXm.js} +2 -2
  55. package/dist/targets-BA7gf0K0.js +3 -0
  56. package/dist/{thread-bindings-DNitaHVh.js → thread-bindings-BuXtcLSp.js} +4 -4
  57. package/dist/{thread-bindings.discord-api-CjYNuvZa.js → thread-bindings.discord-api-CetgvIbE.js} +4 -4
  58. package/dist/{thread-bindings.manager-PZvJ4TJx.js → thread-bindings.manager-B7AHjU4s.js} +3 -3
  59. package/dist/{transcripts-source-Bi8N6h5X.js → transcripts-source-DW6d1eCL.js} +1 -1
  60. package/dist/transcripts-source-api.js +1 -1
  61. package/dist/{typing-BdRqXUN3.js → typing-BMQEI8OW.js} +1 -1
  62. package/npm-shrinkwrap.json +3 -3
  63. package/package.json +4 -4
  64. package/dist/provider.runtime-jNlHxUSW.js +0 -2
  65. package/dist/runtime-api.monitor-Bb5AaRzg.js +0 -6
  66. package/dist/targets-ClUPljCU.js +0 -3
@@ -1,17 +1,57 @@
1
- import { Ut as resolveDiscordChannelId } from "./send.receipt-B21MspvT.js";
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
- import { d as readDiscordComponentSpec } from "./components-Dm4c_ce6.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-D4bl20xr.js";
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-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-9082A2sO.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-Dc5uQX5H.js";
9
- import { n as sendPollDiscord, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-5axvwLkl.js";
10
- import "./targets-ClUPljCU.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
+ 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
@@ -678,13 +931,12 @@ async function handleDiscordMessageManagementAction(ctx) {
678
931
  ok: true,
679
932
  results
680
933
  });
681
- const resultsRecord = results;
682
- const messages = resultsRecord.messages;
934
+ const messages = results.messages;
683
935
  const normalizedMessages = Array.isArray(messages) ? messages.map((group) => Array.isArray(group) ? group.map((msg) => ctx.normalizeMessage(msg)) : group) : messages;
684
936
  return jsonResult({
685
937
  ok: true,
686
938
  results: {
687
- ...resultsRecord,
939
+ ...results,
688
940
  messages: normalizedMessages
689
941
  }
690
942
  });
@@ -966,6 +1218,14 @@ async function handleDiscordMessageSendAction(ctx) {
966
1218
  const includeArchived = readBooleanParam(ctx.params, "includeArchived");
967
1219
  const before = readStringParam(ctx.params, "before");
968
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
+ });
969
1229
  return jsonResult(normalizeDiscordThreadListActionResult({
970
1230
  value: await discordMessagingActionRuntime.listThreadsDiscord({
971
1231
  guildId,
@@ -1002,239 +1262,6 @@ async function handleDiscordMessageSendAction(ctx) {
1002
1262
  }
1003
1263
  }
1004
1264
  //#endregion
1005
- //#region extensions/discord/src/actions/runtime.messaging.shared.ts
1006
- function hasDiscordGuildEntries(guilds) {
1007
- return Boolean(guilds && Object.keys(guilds).length > 0);
1008
- }
1009
- function allowsAllDiscordGuildChannels(channels) {
1010
- const wildcard = channels?.["*"];
1011
- if (!wildcard || wildcard.enabled === false) return false;
1012
- return Object.values(channels ?? {}).every((entry) => entry?.enabled !== false);
1013
- }
1014
- function resolveDiscordActionGuildEntry(params) {
1015
- const guildId = params.guildId?.trim();
1016
- if (!params.guilds) return null;
1017
- if (guildId && params.guilds[guildId]) return {
1018
- ...params.guilds[guildId],
1019
- id: guildId
1020
- };
1021
- if (guildId) {
1022
- const byConfiguredId = Object.values(params.guilds).find((guild) => guild?.id === guildId);
1023
- if (byConfiguredId) return {
1024
- ...byConfiguredId,
1025
- id: guildId
1026
- };
1027
- }
1028
- const guildSlug = params.guildName ? normalizeDiscordSlug(params.guildName) : "";
1029
- if (guildSlug) {
1030
- const bySlug = params.guilds[guildSlug] ?? Object.values(params.guilds).find((guild) => guild?.slug === guildSlug);
1031
- if (bySlug) return {
1032
- ...bySlug,
1033
- id: guildId,
1034
- slug: guildSlug || bySlug.slug
1035
- };
1036
- }
1037
- if (params.includeWildcard === false) return null;
1038
- const wildcard = params.guilds["*"];
1039
- return wildcard ? {
1040
- ...wildcard,
1041
- id: guildId
1042
- } : null;
1043
- }
1044
- function readDiscordChannelStringField(value, ...keys) {
1045
- if (!value || typeof value !== "object") return;
1046
- const record = value;
1047
- for (const key of keys) {
1048
- const candidate = record[key];
1049
- if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1050
- }
1051
- }
1052
- function readDiscordChannelType(value) {
1053
- if (!value || typeof value !== "object") return;
1054
- const type = value.type;
1055
- return typeof type === "number" ? type : void 0;
1056
- }
1057
- function isDiscordThreadChannel(value) {
1058
- const type = readDiscordChannelType(value);
1059
- return type === 10 || type === 11 || type === 12;
1060
- }
1061
- function isDiscordReadTargetAllowedInGuild(params) {
1062
- if (resolveDiscordChannelConfigWithFallback({
1063
- guildInfo: params.guildInfo,
1064
- channelId: params.target.channelId,
1065
- channelName: params.target.channelName,
1066
- channelSlug: params.target.channelSlug,
1067
- parentId: params.target.parentId,
1068
- parentName: params.target.parentName,
1069
- parentSlug: params.target.parentSlug,
1070
- scope: params.target.scope
1071
- })?.allowed === false) return false;
1072
- return isDiscordGroupAllowedByPolicy({
1073
- groupPolicy: params.groupPolicy,
1074
- guildAllowlisted: Boolean(params.guildInfo),
1075
- channelAllowlistConfigured: hasDiscordGuildEntries(params.guildInfo?.channels),
1076
- channelAllowed: true
1077
- });
1078
- }
1079
- function isDiscordReadTargetExplicitlyAllowedById(params) {
1080
- const channelEntry = params.guildInfo?.channels?.[params.target.channelId];
1081
- if (!channelEntry || channelEntry.enabled === false) return false;
1082
- return isDiscordGroupAllowedByPolicy({
1083
- groupPolicy: params.groupPolicy,
1084
- guildAllowlisted: Boolean(params.guildInfo),
1085
- channelAllowlistConfigured: true,
1086
- channelAllowed: true
1087
- });
1088
- }
1089
- function createDiscordMessagingActionContext(params) {
1090
- const accountId = readStringParam(params.input, "accountId");
1091
- const cfgOptions = { cfg: params.cfg };
1092
- const accountConfig = mergeDiscordAccountConfig(params.cfg, accountId ?? resolveDefaultDiscordAccountId(params.cfg));
1093
- const guilds = accountConfig.guilds;
1094
- const hasGuildEntries = Object.keys(guilds ?? {}).length > 0;
1095
- const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({
1096
- providerConfigPresent: params.cfg.channels?.discord !== void 0,
1097
- groupPolicy: accountConfig.groupPolicy,
1098
- defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
1099
- });
1100
- const withOpts = (extra) => createDiscordActionOptions({
1101
- cfg: params.cfg,
1102
- accountId,
1103
- extra
1104
- });
1105
- const resolvedReactionAccountId = accountId ?? resolveDefaultDiscordAccountId(params.cfg);
1106
- const reactionRuntimeOptions = resolvedReactionAccountId ? createDiscordRuntimeAccountContext({
1107
- cfg: params.cfg,
1108
- accountId: resolvedReactionAccountId
1109
- }) : cfgOptions;
1110
- const guildNameById = /* @__PURE__ */ new Map();
1111
- const resolveGuildName = async (guildId) => {
1112
- if (guildNameById.has(guildId)) return guildNameById.get(guildId) ?? null;
1113
- try {
1114
- const guildName = readDiscordChannelStringField(await discordMessagingActionRuntime.fetchGuildInfoDiscord(guildId, withOpts()), "name") ?? null;
1115
- guildNameById.set(guildId, guildName);
1116
- return guildName;
1117
- } catch {
1118
- guildNameById.set(guildId, null);
1119
- return null;
1120
- }
1121
- };
1122
- const resolveReadGuildEntry = async (guildId) => {
1123
- const direct = resolveDiscordActionGuildEntry({
1124
- guilds,
1125
- guildId,
1126
- includeWildcard: false
1127
- });
1128
- if (direct || !guildId) return direct;
1129
- const named = resolveDiscordActionGuildEntry({
1130
- guilds,
1131
- guildId,
1132
- guildName: await resolveGuildName(guildId) ?? void 0,
1133
- includeWildcard: false
1134
- });
1135
- if (named) return named;
1136
- return resolveDiscordActionGuildEntry({
1137
- guilds,
1138
- guildId
1139
- });
1140
- };
1141
- const resolveReadTargetContext = async (channelId) => {
1142
- const fallback = {
1143
- channelId,
1144
- channelSlug: normalizeDiscordSlug(channelId) || channelId
1145
- };
1146
- let channelInfo;
1147
- try {
1148
- channelInfo = await discordMessagingActionRuntime.fetchChannelInfoDiscord(channelId, withOpts());
1149
- } catch {
1150
- return fallback;
1151
- }
1152
- const channelName = readDiscordChannelStringField(channelInfo, "name");
1153
- const target = {
1154
- channelId,
1155
- channelSlug: channelName ? normalizeDiscordSlug(channelName) : fallback.channelSlug
1156
- };
1157
- const targetGuildId = readDiscordChannelStringField(channelInfo, "guild_id", "guildId");
1158
- if (targetGuildId) target.guildId = targetGuildId;
1159
- if (channelName) target.channelName = channelName;
1160
- if (!isDiscordThreadChannel(channelInfo)) return target;
1161
- target.scope = "thread";
1162
- target.parentId = readDiscordChannelStringField(channelInfo, "parent_id", "parentId");
1163
- if (!target.parentId) return target;
1164
- try {
1165
- const parentName = readDiscordChannelStringField(await discordMessagingActionRuntime.fetchChannelInfoDiscord(target.parentId, withOpts()), "name");
1166
- if (parentName) {
1167
- target.parentName = parentName;
1168
- target.parentSlug = normalizeDiscordSlug(parentName);
1169
- }
1170
- } catch {}
1171
- return target;
1172
- };
1173
- return {
1174
- action: params.action,
1175
- params: params.input,
1176
- isActionEnabled: params.isActionEnabled,
1177
- cfg: params.cfg,
1178
- options: params.options,
1179
- accountId,
1180
- resolveChannelId: () => discordMessagingActionRuntime.resolveDiscordChannelId(readStringParam(params.input, "channelId", { required: true })),
1181
- assertReadTargetAllowed: async ({ guildId, channelId }) => {
1182
- const targetChannelId = discordMessagingActionRuntime.resolveDiscordChannelId(channelId);
1183
- if (!hasGuildEntries && groupPolicy !== "disabled" && groupPolicy !== "allowlist") return;
1184
- const target = await resolveReadTargetContext(targetChannelId);
1185
- if (guildId) {
1186
- if (target.guildId && target.guildId !== guildId) throw new Error("Discord read target channel is not allowed.");
1187
- if (!isDiscordReadTargetAllowedInGuild({
1188
- groupPolicy,
1189
- guildInfo: await resolveReadGuildEntry(guildId),
1190
- target
1191
- })) throw new Error("Discord read target channel is not allowed.");
1192
- return;
1193
- }
1194
- if (target.guildId) {
1195
- if (!isDiscordReadTargetAllowedInGuild({
1196
- groupPolicy,
1197
- guildInfo: await resolveReadGuildEntry(target.guildId),
1198
- target
1199
- })) throw new Error("Discord read target channel is not allowed.");
1200
- return;
1201
- }
1202
- if (!Object.values(guilds ?? {}).some((guildInfo) => isDiscordReadTargetExplicitlyAllowedById({
1203
- groupPolicy,
1204
- guildInfo: guildInfo ?? null,
1205
- target
1206
- }))) throw new Error("Discord read target channel is not allowed.");
1207
- },
1208
- assertGuildReadTargetAllowed: async ({ guildId }) => {
1209
- const guildInfo = await resolveReadGuildEntry(guildId);
1210
- if (!isDiscordGroupAllowedByPolicy({
1211
- groupPolicy,
1212
- guildAllowlisted: Boolean(guildInfo),
1213
- channelAllowlistConfigured: false,
1214
- channelAllowed: true
1215
- })) throw new Error("Discord read target channel is not allowed.");
1216
- if (hasDiscordGuildEntries(guildInfo?.channels) && !allowsAllDiscordGuildChannels(guildInfo.channels)) throw new Error("Discord message search requires channelId or channelIds so each read target can be authorized.");
1217
- },
1218
- resolveReactionChannelId: async () => {
1219
- const target = readStringParam(params.input, "channelId") ?? readStringParam(params.input, "to", { required: true });
1220
- return await discordMessagingActionRuntime.resolveDiscordReactionTargetChannelId({
1221
- target,
1222
- cfg: params.cfg,
1223
- accountId: resolvedReactionAccountId
1224
- });
1225
- },
1226
- withOpts,
1227
- withReactionRuntimeOptions: (extra) => ({
1228
- ...reactionRuntimeOptions ?? cfgOptions,
1229
- ...extra
1230
- }),
1231
- normalizeMessage: (message) => {
1232
- if (!message || typeof message !== "object") return message;
1233
- return withNormalizedTimestamp(message, message.timestamp);
1234
- }
1235
- };
1236
- }
1237
- //#endregion
1238
1265
  //#region extensions/discord/src/actions/runtime.messaging.ts
1239
1266
  async function handleDiscordMessagingAction(action, params, isActionEnabled, cfg, options) {
1240
1267
  if (!cfg) throw new Error("Discord messaging actions require a resolved runtime config.");