@openclaw/discord 2026.7.2-beta.7 → 2026.8.1-beta.3

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 (114) hide show
  1. package/dist/{account-inspect-SXiCBCgP.js → account-inspect-D5xmUpnj.js} +49 -43
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/accounts-DNl-oCEw.js +371 -0
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{active-turn-thread-route-MlKWp8RD.js → active-turn-thread-route-fmHl1HNd.js} +9 -11
  6. package/dist/{activities-api-DTKsuDxf.js → activities-api-KCBAmWxD.js} +133 -175
  7. package/dist/activities-api.js +1 -1
  8. package/dist/{allow-list-DzKrtfah.js → allow-list-BDMimASD.js} +2 -3
  9. package/dist/{api-DnrK9gML.js → api-DNVbJyEy.js} +7 -2
  10. package/dist/api.js +18 -18
  11. package/dist/{approval-handler.runtime-HymvFTYn.js → approval-handler.runtime-B12RCYr8.js} +6 -6
  12. package/dist/{approval-message-safety-DEyKVsAw.js → approval-message-safety-XGFPbDoI.js} +89 -3
  13. package/dist/{audit-CjsrabP8.js → audit-Yc7eZDd6.js} +5 -5
  14. package/dist/{channel-actions-uXFTJX3o.js → channel-actions-Dr2QI8Bf.js} +11 -7
  15. package/dist/{channel-actions.runtime-CIYU90sl.js → channel-actions.runtime-CODTvo7c.js} +99 -97
  16. package/dist/{channel-vKa-76xY.js → channel-cXYzGc4L.js} +102 -104
  17. package/dist/channel-config-api.js +1 -1
  18. package/dist/channel-plugin-api.js +1 -1
  19. package/dist/{channel.setup-CmcwZ_qd.js → channel.setup-CSiwnMgs.js} +16 -54
  20. package/dist/{outbound-session-route-H-HoyH5U.js → components-ezGKo_Yh.js} +69 -142
  21. package/dist/{config-schema-WHRQcY19.js → config-schema-DC5kDtQ5.js} +42 -11
  22. package/dist/conversation-binding-route-D6rCQ5S0.js +43 -0
  23. package/dist/{directory-config-D_LojtCe.js → directory-config-XyCfoqLg.js} +2 -2
  24. package/dist/directory-contract-api.js +1 -1
  25. package/dist/{directory-live-Bw5Ephzv.js → directory-live-Df0NbFJB.js} +7 -4
  26. package/dist/{doctor-Bc4S1qyd.js → doctor-DYY31GrO.js} +34 -13
  27. package/dist/{doctor-contract-CCFMIDk9.js → doctor-contract-DsWvKIXF.js} +2 -3
  28. package/dist/doctor-contract-api.js +147 -2
  29. package/dist/{handle-action.guild-admin-D6VRRW-C.js → handle-action.guild-admin-6Tvvinsa.js} +4 -7
  30. package/dist/{inbound-event-delivery-CEPlt2uz.js → inbound-event-delivery-De2qxTrP.js} +4 -25
  31. package/dist/index.js +5 -4
  32. package/dist/{message-handler-CeiSulIw.js → message-handler-B61q5MOF.js} +118 -33
  33. package/dist/{message-handler.preflight-DibgQFf2.js → message-handler.preflight-Bzg_Hawz.js} +75 -61
  34. package/dist/{message-handler.process-Dnc_oz9y.js → message-handler.process--4_712Ec.js} +236 -296
  35. package/dist/{message-utils-BgTwT_q7.js → message-utils-BXLLnFl6.js} +34 -35
  36. package/dist/{model-picker-preference-primitives-D25pnCOu.js → model-picker-preference-primitives-BHT1LkR_.js} +3 -3
  37. package/dist/{outbound-adapter-DtE-i2OJ.js → outbound-adapter-DxHTOqiN.js} +157 -68
  38. package/dist/{outbound-components-C7GVyfPh.js → outbound-components-B2PL0ooH.js} +3 -3
  39. package/dist/owner-access-Bg41VzAf.js +107 -0
  40. package/dist/{pluralkit-CD4B11JB.js → pluralkit-dUl4v1X3.js} +1 -1
  41. package/dist/{preflight-audio-BjnQZ5yS.js → preflight-audio-DrnqFA8U.js} +22 -28
  42. package/dist/{probe-BeWKhjqX.js → probe-BTdtVRwU.js} +37 -13
  43. package/dist/probe.runtime-Dq5-PRKT.js +2 -0
  44. package/dist/{provider-DfQJX3z5.js → provider-DlK_ynqt.js} +1131 -2021
  45. package/dist/{provider-session.runtime-Bo88k0pV.js → provider-session.runtime-CvvphHvs.js} +3 -3
  46. package/dist/provider.runtime-CzKGRiAF.js +2 -0
  47. package/dist/realtime-session.runtime-ysbMG8v7.js +1351 -0
  48. package/dist/{resolve-allowlist-common-DHERApxi.js → resolve-allowlist-common-DIVXbD1P.js} +3 -3
  49. package/dist/{resolve-channels-BjepAj8b.js → resolve-channels-CGeUoIqb.js} +4 -4
  50. package/dist/{resolve-users-Bc28htgt.js → resolve-users-BtKxLUZv.js} +3 -3
  51. package/dist/{chunk-DX4jpFQP.js → retry-DNsVTeTo.js} +308 -131
  52. package/dist/{runtime-BmW_j_hl.js → runtime-CQovMsH3.js} +12 -15
  53. package/dist/{runtime-_aRC6V2s.js → runtime-D71_VFLr.js} +49 -58
  54. package/dist/runtime-api.actions.js +2 -2
  55. package/dist/runtime-api.js +23 -23
  56. package/dist/runtime-api.lookup.js +5 -5
  57. package/dist/runtime-api.monitor-CzeTYF32.js +6 -0
  58. package/dist/runtime-api.monitor.js +6 -5
  59. package/dist/runtime-api.send.js +6 -6
  60. package/dist/runtime-api.threads.js +5 -6
  61. package/dist/sdk-runtime-37OU6_Yh.js +369 -0
  62. package/dist/{secret-config-contract-B1akrlyY.js → secret-config-contract-B3i6WxV5.js} +53 -25
  63. package/dist/secret-contract-api.js +1 -1
  64. package/dist/security-audit-contract-api.js +1 -1
  65. package/dist/{security-audit.runtime-CPN0xFYz.js → security-audit.runtime-BVKF9VtY.js} +1 -1
  66. package/dist/{send-CdkZ6zeW.js → send-rQIffSYu.js} +180 -91
  67. package/dist/{send.components-5uqwkjgE.js → send.components-ChK1wS7w.js} +32 -46
  68. package/dist/{send.outbound-D-80Ej-t.js → send.outbound-HIkgji_7.js} +57 -34
  69. package/dist/{send.reactions-CtlmGd_o.js → send.reactions-gmJ6yFPo.js} +14 -21
  70. package/dist/{send.receipt-CuwRrpFz.js → send.receipt-Cnhoautb.js} +29 -1
  71. package/dist/{send.shared-jpvAG_u6.js → send.shared-B3fpaLWJ.js} +112 -181
  72. package/dist/{sender-identity-mG_zsdox.js → sender-identity-BJtfyise.js} +1 -1
  73. package/dist/setup-entry.js +0 -5
  74. package/dist/setup-plugin-api.js +1 -1
  75. package/dist/{shared-CXF1tup1.js → shared-CaAaoksy.js} +27 -23
  76. package/dist/subagent-hooks-CNT2ZJTJ.js +49 -0
  77. package/dist/subagent-hooks-api.js +2 -6
  78. package/dist/subagent-progress-FPLqBY1s.js +110 -0
  79. package/dist/{system-events-DdUqf91B.js → system-events-Nuwoq_au.js} +2 -2
  80. package/dist/{target-resolver-C3s_2m0t.js → target-resolver-DIXShHaZ.js} +3 -3
  81. package/dist/targets-B2pf49zc.js +3 -0
  82. package/dist/{thread-bindings-C-M-ly7P.js → thread-bindings-VlymUnbz.js} +29 -28
  83. package/dist/{thread-bindings.manager-DYvSlrva.js → thread-bindings.manager-CngsgErq.js} +258 -29
  84. package/dist/{thread-bindings.session-updates-DAIlp7Px.js → thread-bindings.session-updates-CJb-BpPL.js} +1 -1
  85. package/dist/{thread-bindings.state-Cgi5uRn-.js → thread-bindings.state-D8OMdk4O.js} +3 -16
  86. package/dist/threading-DU6pgeGm.js +456 -0
  87. package/dist/transcripts-source-DeIMNbRh.js +265 -0
  88. package/dist/transcripts-source-api.js +7 -2
  89. package/dist/{typing--Mzo2kM7.js → typing-oLiS5Z13.js} +1 -1
  90. package/dist/voice-runtime-CjNFaynA.js +2549 -0
  91. package/openclaw.plugin.json +215 -25
  92. package/package.json +15 -11
  93. package/skills/discord/SKILL.md +22 -115
  94. package/dist/accounts-DJTf1LtA.js +0 -219
  95. package/dist/channel-api-CAJ0wMoV.js +0 -21
  96. package/dist/legacy-state-migrations-api.js +0 -138
  97. package/dist/manager.runtime-Bjav3pfC.js +0 -3655
  98. package/dist/preflight-audio.runtime-CoCXMM8r.js +0 -7
  99. package/dist/probe.runtime-DqFGFMbZ.js +0 -2
  100. package/dist/provider.runtime-Cy7XZmyh.js +0 -2
  101. package/dist/runtime-api.monitor-CCRubd3-.js +0 -5
  102. package/dist/session-binding-contract-api.js +0 -2
  103. package/dist/subagent-hooks-Dxy7Fmnq.js +0 -120
  104. package/dist/subagent-progress-DI3sYLLo.js +0 -664
  105. package/dist/targets-Dv_RN7vT.js +0 -3
  106. package/dist/thread-bindings.discord-api-BoDNqamb.js +0 -246
  107. package/dist/transcripts-source-DIKGsTGT.js +0 -123
  108. package/node_modules/p-map/index.d.ts +0 -155
  109. package/node_modules/p-map/index.js +0 -285
  110. package/node_modules/p-map/license +0 -9
  111. package/node_modules/p-map/package.json +0 -57
  112. package/node_modules/p-map/readme.md +0 -190
  113. package/dist/{audit-core-xwjIczO0.js → audit-core-BCX8UeFH.js} +1 -1
  114. package/dist/{security-audit-jGnJF__m.js → security-audit-BfJhAXZp.js} +1 -1
@@ -1,11 +1,11 @@
1
- import { A as readDiscordMessage, At as createGuildBan, Bt as listGuildChannels, Ct as listChannelMessages, D as RateLimitError, E as DiscordError, Et as searchGuildMessages, Ft as deleteChannelPermission, Gt as putChannelPermission, Ht as listGuildRoles, It as getGuild, Jt as timeoutGuildMember, Kt as removeGuildMember, Lt as getGuildMember, Mt as createGuildEmoji, Nt as createGuildScheduledEvent, O as isUnknownDiscordVoiceStateError, Ot as unpinChannelMessage, Pt as createGuildSticker, Rt as getGuildVoiceState, St as listChannelArchivedThreads, Tt as pinChannelMessage, Ut as listGuildScheduledEvents, Vt as listGuildEmojis, Wt as moveGuildChannels, Yt as __exportAll, _t as editChannel, bt as getChannelMessage, gt as deleteChannelMessage, ht as deleteChannel, j as readRetryAfter, jt as createGuildChannel, k as readDiscordCode, kt as addGuildMemberRole, mt as createThread, pt as createChannelMessage, qt as removeGuildMemberRole, vt as editChannelMessage, wt as listChannelPins, yt as getChannel, zt as listGuildActiveThreads } from "./chunk-DX4jpFQP.js";
2
- import { s as resolveDiscordAccount } from "./accounts-DJTf1LtA.js";
3
- import { A as hasAllGuildPermissionsDiscord, C as DISCORD_MAX_STICKER_BYTES, D as canViewDiscordGuildChannel, E as canManageGuildRoleDiscord, L as resolveDiscordClientAccountContext, M as hasAnyGuildPermissionDiscord, O as fetchChannelPermissionsDiscord, P as createDiscordClient, R as resolveDiscordRest, S as DISCORD_MAX_EVENT_COVER_BYTES, T as canManageGuildMemberRoleDiscord, W as parseAndResolveChannelRecipient, g as createDiscordMessageNonce, j as hasAnyChannelPermissionDiscord, k as fetchMemberGuildPermissionsDiscord, l as resolveChannelId, o as normalizeEmojiName, t as buildDiscordSendError, w as DiscordSendError, x as DISCORD_MAX_EMOJI_BYTES, z as DISCORD_REST_TIMEOUT_MS } from "./send.shared-jpvAG_u6.js";
4
- import { n as sendPollDiscord, o as rewriteDiscordKnownMentions, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-D-80Ej-t.js";
5
- import { n as createDiscordSendResult } from "./send.receipt-CuwRrpFz.js";
1
+ import { $t as timeoutGuildMember, A as RateLimitError, At as pinChannelMessage, Bt as deleteChannelPermission, Ct as editChannelMessage, Dt as listChannelArchivedThreads, Ft as createGuildBan, Gt as listGuildChannels, Ht as getGuildMember, It as createGuildChannel, Jt as listGuildScheduledEvents, Kt as listGuildEmojis, Lt as createGuildEmoji, M as readDiscordCode, Mt as sendChannelTyping, N as readDiscordMessage, Nt as unpinChannelMessage, Ot as listChannelMessages, P as readRetryAfter, Pt as addGuildMemberRole, Qt as removeGuildMemberRole, Rt as createGuildScheduledEvent, St as editChannel, Tt as getChannelMessage, Ut as getGuildVoiceState, Vt as getGuild, Wt as listGuildActiveThreads, Xt as putChannelPermission, Yt as moveGuildChannels, Zt as removeGuildMember, bt as deleteChannel, en as __exportAll, i as recordDiscordMessageCreateAmbiguity, j as isUnknownDiscordVoiceStateError, jt as searchGuildMessages, k as DiscordError, kt as listChannelPins, n as createDiscordRetryRunner, qt as listGuildRoles, t as classifyDiscordDeliveryFailure, wt as getChannel, xt as deleteChannelMessage, yt as createThread, zt as createGuildSticker } from "./retry-DNsVTeTo.js";
2
+ import { t as parseDiscordRetryAfterBodySeconds } from "./retry-after-DdLPmPoa.js";
3
+ import { c as resolveDiscordAccount } from "./accounts-DNl-oCEw.js";
4
+ import { A as resolveDiscordMessageFlags, C as hasAllGuildPermissionsDiscord, L as resolveDiscordClientAccountContext, N as resolveDiscordSuppressEmbeds, P as createDiscordClient, R as resolveDiscordRest, S as fetchMemberGuildPermissionsDiscord, T as hasAnyGuildPermissionDiscord, _ as DiscordSendError, b as canViewDiscordGuildChannel, g as DISCORD_MAX_STICKER_BYTES, h as DISCORD_MAX_EVENT_COVER_BYTES, k as createDiscordMessageNonce, l as resolveChannelId, m as DISCORD_MAX_EMOJI_BYTES, n as buildDiscordTextChunks, o as normalizeEmojiName, p as sendDiscordText, q as parseAndResolveChannelRecipient, t as buildDiscordSendError, v as canManageGuildMemberRoleDiscord, w as hasAnyChannelPermissionDiscord, x as fetchChannelPermissionsDiscord, y as canManageGuildRoleDiscord, z as DISCORD_REST_TIMEOUT_MS } from "./send.shared-B3fpaLWJ.js";
5
+ import { n as sendPollDiscord, o as rewriteDiscordKnownMentions, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-HIkgji_7.js";
6
+ import { r as createDiscordSendResult } from "./send.receipt-Cnhoautb.js";
6
7
  import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS } from "./timeouts-B9cy6RvQ.js";
7
- import { a as sendTypingDiscord, i as removeReactionDiscord, n as reactMessageDiscord, r as removeOwnReactionsDiscord, t as fetchReactionsDiscord } from "./send.reactions-CtlmGd_o.js";
8
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
8
+ import { i as removeReactionDiscord, n as reactMessageDiscord, r as removeOwnReactionsDiscord, t as fetchReactionsDiscord } from "./send.reactions-gmJ6yFPo.js";
9
9
  import fs from "node:fs/promises";
10
10
  import { ChannelType } from "discord-api-types/v10";
11
11
  import crypto from "node:crypto";
@@ -14,15 +14,16 @@ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
14
14
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
15
15
  import { readProviderJsonResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
16
16
  import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
17
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
17
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
18
18
  import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
19
19
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
20
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
20
21
  import { recordOutboundMessageIdentity } from "openclaw/plugin-sdk/channel-outbound";
21
- import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS, extensionForMime, maxBytesForKind, parseFfprobeCodecAndSampleRate, runFfmpeg, runFfprobe, unlinkIfExists } from "openclaw/plugin-sdk/media-runtime";
22
+ import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS, buildOutboundMediaLoadOptions, extensionForMime, maxBytesForKind, parseFfprobeCodecAndSampleRate, runFfmpeg, runFfprobe, unlinkIfExists } from "openclaw/plugin-sdk/media-runtime";
22
23
  import { loadWebMediaRaw } from "openclaw/plugin-sdk/web-media";
23
24
  import { buildTimeoutAbortSignal } from "openclaw/plugin-sdk/extension-shared";
24
25
  import path from "node:path";
25
- import { resolvePreferredOpenClawTmpDir, tempWorkspace } from "openclaw/plugin-sdk/temp-path";
26
+ import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
26
27
  import { writeExternalFileWithinRoot } from "openclaw/plugin-sdk/security-runtime";
27
28
  //#region extensions/discord/src/send.channels.ts
28
29
  async function createChannelDiscord(payload, opts) {
@@ -218,8 +219,11 @@ async function banMemberDiscord(payload, opts) {
218
219
  }
219
220
  //#endregion
220
221
  //#region extensions/discord/src/send.messages.ts
221
- function formatDiscordThreadInitialMessageError(error) {
222
- return error instanceof Error ? error.message : String(error);
222
+ const DISCORD_THREAD_TRANSPORT_ONLY_MAX_LINES = Number.MAX_SAFE_INTEGER;
223
+ function resolveDiscordThreadStarterMessageId(thread) {
224
+ const starterMessage = "message" in thread ? thread.message : void 0;
225
+ if (starterMessage && typeof starterMessage === "object" && "id" in starterMessage && typeof starterMessage.id === "string") return starterMessage.id;
226
+ return thread.id;
223
227
  }
224
228
  function assertDiscordResponseArray(value, label) {
225
229
  if (!Array.isArray(value)) throw new Error(`Unexpected Discord response for ${label}: expected array.`);
@@ -233,12 +237,22 @@ function resolveDefaultThreadAutoArchiveDuration(channel) {
233
237
  if (!channel || !("default_auto_archive_duration" in channel)) return;
234
238
  return channel.default_auto_archive_duration;
235
239
  }
240
+ function describeDiscordThreadInitialMessageFailure(delivery) {
241
+ if (delivery?.failedChunkDelivery === "unknown") return delivery.deliveredChunkCount > 0 ? "Discord thread was created, but delivery of the remaining initial content could not be confirmed" : "Discord thread was created, but initial message delivery could not be confirmed";
242
+ return delivery && delivery.deliveredChunkCount > 0 ? "Discord thread was created, but its initial content was only partially delivered" : "Discord thread was created, but sending the initial message failed";
243
+ }
236
244
  var DiscordThreadInitialMessageError = class extends Error {
237
- constructor(thread, error) {
238
- const initialMessageError = formatDiscordThreadInitialMessageError(error);
239
- super(`Discord thread was created, but sending the initial message failed: ${initialMessageError}`);
245
+ constructor(thread, error, initialMessageDelivery) {
246
+ const initialMessageError = formatErrorMessage(error);
247
+ const initialMessageWarning = describeDiscordThreadInitialMessageFailure(initialMessageDelivery);
248
+ super(`${initialMessageWarning}: ${initialMessageError}`, { cause: error });
240
249
  this.name = "DiscordThreadInitialMessageError";
250
+ this.initialMessageDelivery = initialMessageDelivery ? {
251
+ ...initialMessageDelivery,
252
+ deliveredMessageIds: [...initialMessageDelivery.deliveredMessageIds]
253
+ } : void 0;
241
254
  this.initialMessageError = initialMessageError;
255
+ this.initialMessageWarning = initialMessageWarning;
242
256
  this.thread = thread;
243
257
  }
244
258
  };
@@ -278,7 +292,7 @@ async function listPinsDiscord(channelId, opts) {
278
292
  return await listChannelPins(resolveDiscordRest(opts), channelId);
279
293
  }
280
294
  async function createThreadDiscord(channelId, payload, opts) {
281
- const rest = resolveDiscordRest(opts);
295
+ const { rest, request } = createDiscordClient(opts);
282
296
  const body = { name: payload.name };
283
297
  if (!payload.messageId && payload.type !== void 0) body.type = payload.type;
284
298
  let channel;
@@ -288,16 +302,52 @@ async function createThreadDiscord(channelId, payload, opts) {
288
302
  const archiveDuration = payload.autoArchiveMinutes ?? resolveDefaultThreadAutoArchiveDuration(channel);
289
303
  if (archiveDuration !== void 0) body.auto_archive_duration = archiveDuration;
290
304
  const isForumLike = channel?.type === ChannelType.GuildForum || channel?.type === ChannelType.GuildMedia;
305
+ const initialMessageChunks = buildDiscordTextChunks(isForumLike ? payload.content?.trim() ? payload.content : payload.name : payload.content?.trim() ? payload.content : "", { maxLinesPerMessage: DISCORD_THREAD_TRANSPORT_ONLY_MAX_LINES });
291
306
  if (isForumLike) {
292
- body.message = { content: payload.content?.trim() ? payload.content : payload.name };
307
+ body.message = { content: initialMessageChunks[0] ?? payload.name };
293
308
  if (payload.appliedTags?.length) body.applied_tags = payload.appliedTags;
294
309
  }
295
310
  if (!payload.messageId && !isForumLike && body.type === void 0) body.type = ChannelType.PublicThread;
296
311
  const thread = await createThread(rest, channelId, { body }, payload.messageId);
297
- if (!isForumLike && payload.content?.trim() && "id" in thread) try {
298
- await createChannelMessage(rest, thread.id, { body: { content: payload.content } });
299
- } catch (error) {
300
- throw new DiscordThreadInitialMessageError(thread, error);
312
+ const followupChunks = isForumLike ? initialMessageChunks.slice(1) : initialMessageChunks;
313
+ if (followupChunks.length && "id" in thread) {
314
+ const deliveredMessageIds = isForumLike ? [resolveDiscordThreadStarterMessageId(thread)] : [];
315
+ let deliveredChunkCount = isForumLike ? 1 : 0;
316
+ const firstFollowupChunkIndex = isForumLike ? 1 : 0;
317
+ for (const [followupIndex, content] of followupChunks.entries()) {
318
+ let chunkMayHaveDelivered = false;
319
+ const trackedRequest = (fn, label, options) => request(async () => {
320
+ try {
321
+ return await fn();
322
+ } catch (error) {
323
+ chunkMayHaveDelivered ||= classifyDiscordDeliveryFailure(error) === "ambiguous";
324
+ throw error;
325
+ }
326
+ }, label, options);
327
+ try {
328
+ const result = await sendDiscordText({
329
+ rest,
330
+ request: trackedRequest,
331
+ channelId: thread.id,
332
+ text: content,
333
+ maxLinesPerMessage: DISCORD_THREAD_TRANSPORT_ONLY_MAX_LINES
334
+ });
335
+ deliveredMessageIds.push(...result.platformMessageIds);
336
+ deliveredChunkCount += 1;
337
+ } catch (error) {
338
+ const finalFailure = classifyDiscordDeliveryFailure(error);
339
+ const failedChunkDelivery = chunkMayHaveDelivered || finalFailure === "ambiguous" || finalFailure === "unknown" ? "unknown" : "not_delivered";
340
+ if (failedChunkDelivery === "unknown") recordDiscordMessageCreateAmbiguity(error);
341
+ throw new DiscordThreadInitialMessageError(thread, error, {
342
+ starterMessageDelivered: isForumLike,
343
+ deliveredChunkCount,
344
+ deliveredMessageIds,
345
+ failedChunkDelivery,
346
+ failedChunkIndex: firstFollowupChunkIndex + followupIndex,
347
+ totalChunkCount: initialMessageChunks.length
348
+ });
349
+ }
350
+ }
301
351
  }
302
352
  return thread;
303
353
  }
@@ -322,7 +372,15 @@ async function searchMessagesDiscord(query, opts) {
322
372
  const limit = Math.min(Math.max(Math.floor(query.limit), 1), 25);
323
373
  params.set("limit", String(limit));
324
374
  }
325
- return assertDiscordResponseObject(await searchGuildMessages(rest, query.guildId, params), "message search");
375
+ const result = assertDiscordResponseObject(await searchGuildMessages(rest, query.guildId, params), "message search");
376
+ if (result.code === 11e4) {
377
+ const message = typeof result.message === "string" && result.message.trim() ? result.message.trim() : "Discord search index is not yet available";
378
+ const retryAfter = parseDiscordRetryAfterBodySeconds(result.retry_after);
379
+ const retryHint = retryAfter === void 0 ? "" : ` (retry after ${retryAfter}s)`;
380
+ throw new Error(`Discord message search unavailable: ${message}${retryHint}`);
381
+ }
382
+ if (!Array.isArray(result.messages)) throw new Error("Unexpected Discord response for message search: expected messages array.");
383
+ return result;
326
384
  }
327
385
  //#endregion
328
386
  //#region extensions/discord/src/send.webhook.ts
@@ -376,6 +434,7 @@ async function sendWebhookMessageDiscord(text, opts) {
376
434
  accountId: account.accountId,
377
435
  mentionAliases: account.config.mentionAliases
378
436
  });
437
+ const flags = resolveDiscordMessageFlags({ suppressEmbeds: resolveDiscordSuppressEmbeds({ configured: account.config.suppressEmbeds }) });
379
438
  const threadConversationId = opts.threadId == null ? "" : String(opts.threadId).trim();
380
439
  if (threadConversationId) recordOutboundMessageIdentity({
381
440
  channel: "discord",
@@ -393,19 +452,25 @@ async function sendWebhookMessageDiscord(text, opts) {
393
452
  timeoutMs: DISCORD_WEBHOOK_TIMEOUT_MS,
394
453
  operation: "discord.webhook.send"
395
454
  });
455
+ const request = createDiscordRetryRunner({ signal: deadline.signal });
396
456
  try {
397
- const response = await (proxyFetch ?? fetch)(url, {
398
- method: "POST",
399
- headers: { "content-type": "application/json" },
400
- body: JSON.stringify({
401
- content: rewrittenText,
402
- username: normalizeOptionalString(opts.username),
403
- avatar_url: normalizeOptionalString(opts.avatarUrl),
404
- ...messageReference ? { message_reference: messageReference } : {}
405
- }),
406
- signal: deadline.signal
407
- });
408
- if (!response.ok) await throwWebhookResponseError(response, deadline.signal);
457
+ const response = await request(async () => {
458
+ await opts.onPlatformSendDispatch?.();
459
+ const attemptResponse = await (proxyFetch ?? fetch)(url, {
460
+ method: "POST",
461
+ headers: { "content-type": "application/json" },
462
+ body: JSON.stringify({
463
+ content: rewrittenText,
464
+ username: normalizeOptionalString(opts.username),
465
+ avatar_url: normalizeOptionalString(opts.avatarUrl),
466
+ ...flags ? { flags } : {},
467
+ ...messageReference ? { message_reference: messageReference } : {}
468
+ }),
469
+ signal: deadline.signal
470
+ });
471
+ if (!attemptResponse.ok) await throwWebhookResponseError(attemptResponse, deadline.signal);
472
+ return attemptResponse;
473
+ }, "webhook", { safety: "non-idempotent-create" });
409
474
  const payload = response.status === 204 ? {} : await readProviderJsonResponse(response, "Discord webhook send").catch(() => {
410
475
  throwIfWebhookDeadlineExpired(deadline.signal);
411
476
  return {};
@@ -469,8 +534,8 @@ async function runFfmpegToOutput(params) {
469
534
  }
470
535
  });
471
536
  }
472
- function createRateLimitError(response, body, request) {
473
- return new RateLimitError(response, body, request ?? new Request("https://discord.com/api/v10/channels/voice/messages", { method: "POST" }));
537
+ function createRateLimitError(response, body) {
538
+ return new RateLimitError(response, body);
474
539
  }
475
540
  /**
476
541
  * Get audio duration using ffprobe
@@ -735,7 +800,20 @@ async function sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, r
735
800
  message_id: replyTo,
736
801
  fail_if_not_exists: false
737
802
  };
738
- return await request(() => rest.post(`/channels/${channelId}/messages`, { body: messagePayload }), "voice-message", { safety: "nonce-protected-create" });
803
+ let messageCreateMayHaveCommitted = false;
804
+ try {
805
+ return await request(async () => {
806
+ try {
807
+ return await rest.post(`/channels/${channelId}/messages`, { body: messagePayload });
808
+ } catch (error) {
809
+ messageCreateMayHaveCommitted ||= classifyDiscordDeliveryFailure(error) === "ambiguous";
810
+ throw error;
811
+ }
812
+ }, "voice-message", { safety: "nonce-protected-create" });
813
+ } catch (error) {
814
+ if (messageCreateMayHaveCommitted) recordDiscordMessageCreateAmbiguity(error);
815
+ throw error;
816
+ }
739
817
  }
740
818
  //#endregion
741
819
  //#region extensions/discord/src/send.voice.ts
@@ -747,19 +825,20 @@ function toDiscordSendResult(result, fallbackChannelId, reply) {
747
825
  reply
748
826
  });
749
827
  }
750
- async function materializeVoiceMessageInput(mediaUrl) {
751
- const media = await loadWebMediaRaw(mediaUrl, maxBytesForKind("audio"));
828
+ async function withMaterializedVoiceMessageInput(mediaUrl, opts, run) {
829
+ const media = await loadWebMediaRaw(mediaUrl, buildOutboundMediaLoadOptions({
830
+ maxBytes: maxBytesForKind("audio"),
831
+ mediaAccess: opts.mediaAccess,
832
+ mediaLocalRoots: opts.mediaLocalRoots,
833
+ mediaReadFile: opts.mediaReadFile
834
+ }));
752
835
  const extFromName = media.fileName ? path.extname(media.fileName) : "";
753
836
  const extFromMime = media.contentType ? extensionForMime(media.contentType) : "";
754
837
  const ext = extFromName || extFromMime || ".bin";
755
- const workspace = await tempWorkspace({
838
+ return await withTempWorkspace({
756
839
  rootDir: resolvePreferredOpenClawTmpDir(),
757
840
  prefix: "voice-src-"
758
- });
759
- return {
760
- filePath: await workspace.write(`input${ext}`, media.buffer),
761
- cleanup: () => workspace.cleanup().then(() => void 0)
762
- };
841
+ }, async (workspace) => await run(await workspace.write(`input${ext}`, media.buffer)));
763
842
  }
764
843
  /**
765
844
  * Send a voice message to Discord.
@@ -772,52 +851,62 @@ async function materializeVoiceMessageInput(mediaUrl) {
772
851
  * @param opts - Send options
773
852
  */
774
853
  async function sendVoiceMessageDiscord(to, audioPath, opts) {
775
- const { filePath: localInputPath, cleanup: cleanupLocalInput } = await materializeVoiceMessageInput(audioPath);
776
- let oggPath = null;
777
- let oggCleanup = false;
778
- let token;
779
- let rest;
780
- let channelId;
781
854
  const cfg = requireRuntimeConfig(opts.cfg, "Discord voice send");
782
- try {
783
- const accountInfo = resolveDiscordAccount({
784
- cfg,
785
- accountId: opts.accountId
786
- });
787
- const client = createDiscordClient({
788
- ...opts,
789
- cfg
790
- });
791
- token = client.token;
792
- rest = client.rest;
793
- const request = client.request;
794
- const recipient = await parseAndResolveChannelRecipient(to, cfg, opts.accountId);
795
- channelId = (await resolveChannelId(rest, recipient, request)).channelId;
796
- const ogg = await ensureOggOpus(localInputPath);
797
- oggPath = ogg.path;
798
- oggCleanup = ogg.cleanup;
799
- const metadata = await getVoiceMessageMetadata(oggPath);
800
- const audioBuffer = await fs.readFile(oggPath);
801
- const result = await sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, opts.reply?.messageId, request, opts.silent, token);
802
- recordChannelActivity({
803
- channel: "discord",
804
- accountId: accountInfo.accountId,
805
- direction: "outbound"
806
- });
807
- return toDiscordSendResult(result, channelId, opts.reply);
808
- } catch (err) {
809
- if (channelId && rest && token) throw await buildDiscordSendError(err, {
810
- channelId,
811
- cfg,
812
- rest,
813
- token,
814
- hasMedia: true
815
- });
816
- throw err;
817
- } finally {
818
- await unlinkIfExists(oggCleanup ? oggPath : null);
819
- await cleanupLocalInput();
820
- }
855
+ return await withMaterializedVoiceMessageInput(audioPath, opts, async (localInputPath) => {
856
+ let oggPath = null;
857
+ let oggCleanup = false;
858
+ let token;
859
+ let rest;
860
+ let channelId;
861
+ try {
862
+ const accountInfo = resolveDiscordAccount({
863
+ cfg,
864
+ accountId: opts.accountId
865
+ });
866
+ const client = createDiscordClient({
867
+ ...opts,
868
+ cfg
869
+ });
870
+ token = client.token;
871
+ rest = client.rest;
872
+ const request = client.request;
873
+ const recipient = await parseAndResolveChannelRecipient(to, cfg, opts.accountId);
874
+ channelId = (await resolveChannelId(rest, recipient, request)).channelId;
875
+ const ogg = await ensureOggOpus(localInputPath);
876
+ oggPath = ogg.path;
877
+ oggCleanup = ogg.cleanup;
878
+ const metadata = await getVoiceMessageMetadata(oggPath);
879
+ const audioBuffer = await fs.readFile(oggPath);
880
+ await opts.onPlatformSendDispatch?.();
881
+ const result = await sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, opts.reply?.messageId, request, opts.silent, token);
882
+ recordChannelActivity({
883
+ channel: "discord",
884
+ accountId: accountInfo.accountId,
885
+ direction: "outbound"
886
+ });
887
+ return toDiscordSendResult(result, channelId, opts.reply);
888
+ } catch (err) {
889
+ if (channelId && rest && token) throw await buildDiscordSendError(err, {
890
+ channelId,
891
+ cfg,
892
+ rest,
893
+ token,
894
+ hasMedia: true
895
+ });
896
+ throw err;
897
+ } finally {
898
+ await unlinkIfExists(oggCleanup ? oggPath : null);
899
+ }
900
+ });
901
+ }
902
+ //#endregion
903
+ //#region extensions/discord/src/send.typing.ts
904
+ async function sendTypingDiscord(channelId, opts) {
905
+ await sendChannelTyping(resolveDiscordRest(opts), channelId);
906
+ return {
907
+ ok: true,
908
+ channelId
909
+ };
821
910
  }
822
911
  //#endregion
823
912
  //#region extensions/discord/src/send.ts
@@ -877,4 +966,4 @@ var send_exports = /* @__PURE__ */ __exportAll({
877
966
  uploadStickerDiscord: () => uploadStickerDiscord
878
967
  });
879
968
  //#endregion
880
- export { uploadEmojiDiscord as A, kickMemberDiscord as C, resolveEventCoverImage as D, removeRoleDiscord as E, moveChannelDiscord as F, removeChannelPermissionDiscord as I, setChannelPermissionDiscord as L, createChannelDiscord as M, deleteChannelDiscord as N, timeoutMemberDiscord as O, editChannelDiscord as P, fetchVoiceStatusDiscord as S, listScheduledEventsDiscord as T, createScheduledEventDiscord as _, createThreadDiscord as a, fetchMemberInfoDiscord as b, fetchMessageDiscord as c, pinMessageDiscord as d, readMessagesDiscord as f, banMemberDiscord as g, addRoleDiscord as h, DiscordThreadInitialMessageError as i, uploadStickerDiscord as j, listGuildEmojisDiscord as k, listPinsDiscord as l, unpinMessageDiscord as m, sendVoiceMessageDiscord as n, deleteMessageDiscord as o, searchMessagesDiscord as p, sendWebhookMessageDiscord as r, editMessageDiscord as s, send_exports as t, listThreadsDiscord as u, fetchChannelInfoDiscord as v, listGuildChannelsDiscord as w, fetchRoleInfoDiscord as x, fetchGuildInfoDiscord as y };
969
+ export { listGuildEmojisDiscord as A, fetchVoiceStatusDiscord as C, removeRoleDiscord as D, listScheduledEventsDiscord as E, editChannelDiscord as F, moveChannelDiscord as I, removeChannelPermissionDiscord as L, uploadStickerDiscord as M, createChannelDiscord as N, resolveEventCoverImage as O, deleteChannelDiscord as P, setChannelPermissionDiscord as R, fetchRoleInfoDiscord as S, listGuildChannelsDiscord as T, banMemberDiscord as _, DiscordThreadInitialMessageError as a, fetchGuildInfoDiscord as b, editMessageDiscord as c, listThreadsDiscord as d, pinMessageDiscord as f, addRoleDiscord as g, unpinMessageDiscord as h, sendWebhookMessageDiscord as i, uploadEmojiDiscord as j, timeoutMemberDiscord as k, fetchMessageDiscord as l, searchMessagesDiscord as m, sendTypingDiscord as n, createThreadDiscord as o, readMessagesDiscord as p, sendVoiceMessageDiscord as r, deleteMessageDiscord as s, send_exports as t, listPinsDiscord as u, createScheduledEventDiscord as v, kickMemberDiscord as w, fetchMemberInfoDiscord as x, fetchChannelInfoDiscord as y };
@@ -1,44 +1,32 @@
1
- import { L as serializePayload, Yt as __exportAll, pt as createChannelMessage, vt as editChannelMessage } from "./chunk-DX4jpFQP.js";
2
- import { s as resolveDiscordAccount } from "./accounts-DJTf1LtA.js";
3
- import { f as buildDiscordComponentMessage, g as resolveDiscordComponentAttachmentName, p as buildDiscordComponentMessageFlags } from "./outbound-session-route-H-HoyH5U.js";
4
- import { P as createDiscordClient, W as parseAndResolveChannelRecipient, b as stripUndefinedFields, g as createDiscordMessageNonce, l as resolveChannelId, m as SUPPRESS_NOTIFICATIONS_FLAG, t as buildDiscordSendError, u as resolveDiscordChannel } from "./send.shared-jpvAG_u6.js";
1
+ import { Ct as editChannelMessage, V as serializePayload, en as __exportAll, vt as createChannelMessage } from "./retry-DNsVTeTo.js";
2
+ import { d as buildDiscordComponentMessage, f as buildDiscordComponentMessageFlags, h as resolveDiscordComponentAttachmentName } from "./components-ezGKo_Yh.js";
3
+ import { c as resolveDiscordAccount, y as loadOutboundMediaFromUrl } from "./accounts-DNl-oCEw.js";
5
4
  import { n as getOptionalDiscordRuntime } from "./runtime-DgnVQ7zW.js";
6
- import "./config-schema-WHRQcY19.js";
7
- import "./channel-api-CAJ0wMoV.js";
8
- import { t as sendMessageDiscord } from "./send.outbound-D-80Ej-t.js";
9
- import { n as createDiscordSendResult } from "./send.receipt-CuwRrpFz.js";
10
- import "openclaw/plugin-sdk/account-helpers";
11
- import "openclaw/plugin-sdk/account-id";
12
- import "openclaw/plugin-sdk/channel-config-helpers";
13
- import "openclaw/plugin-sdk/routing";
14
- import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
15
- import "openclaw/plugin-sdk/secret-input";
5
+ import { D as SUPPRESS_NOTIFICATIONS_FLAG, P as createDiscordClient, k as createDiscordMessageNonce, l as resolveChannelId, q as parseAndResolveChannelRecipient, t as buildDiscordSendError, u as resolveDiscordChannel } from "./send.shared-B3fpaLWJ.js";
6
+ import { t as sendMessageDiscord } from "./send.outbound-HIkgji_7.js";
7
+ import { r as createDiscordSendResult } from "./send.receipt-Cnhoautb.js";
16
8
  import { ChannelType } from "discord-api-types/v10";
17
9
  import { asDateTimestampMs, isFutureDateTimestampMs, resolveDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
18
- import { assertMediaNotDataUrl, jsonResult as jsonResult$1, parseAvailableTags, readNonNegativeIntegerParam, readPositiveIntegerParam, readReactionParams, readStringArrayParam, readStringParam as readStringParam$1, resolvePollMaxSelections, withNormalizedTimestamp } from "openclaw/plugin-sdk/channel-actions";
10
+ import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
19
11
  import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
12
+ import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
20
13
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
21
- import { resolveGlobalMap } from "openclaw/plugin-sdk/global-singleton";
22
- import "openclaw/plugin-sdk/channel-status";
23
- import "openclaw/plugin-sdk/channel-config-schema";
24
- import { readBooleanParam as readBooleanParam$1 } from "openclaw/plugin-sdk/boolean-param";
25
- import "openclaw/plugin-sdk/channel-plugin-common";
26
- import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
14
+ import { createPluginStateErrorReporter } from "openclaw/plugin-sdk/plugin-state-runtime";
15
+ import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
27
16
  //#region extensions/discord/src/components-registry-state.ts
28
- const discordComponentRegistryState = {
29
- componentEntries: resolveGlobalMap(Symbol.for("openclaw.discord.componentEntries")),
30
- modalEntries: resolveGlobalMap(Symbol.for("openclaw.discord.modalEntries")),
17
+ const discordComponentRegistryState = resolveGlobalSingleton(Symbol.for("openclaw.discord.componentRegistryState"), () => ({
18
+ componentEntries: /* @__PURE__ */ new Map(),
19
+ modalEntries: /* @__PURE__ */ new Map(),
31
20
  persistentComponentStore: void 0,
32
21
  persistentModalStore: void 0,
33
- persistentRegistryDisabled: false,
34
- reset() {
35
- this.componentEntries.clear();
36
- this.modalEntries.clear();
37
- this.persistentComponentStore = void 0;
38
- this.persistentModalStore = void 0;
39
- this.persistentRegistryDisabled = false;
40
- }
41
- };
22
+ persistentRegistryDisabled: false
23
+ }), (state) => {
24
+ state.componentEntries.clear();
25
+ state.modalEntries.clear();
26
+ state.persistentComponentStore = void 0;
27
+ state.persistentModalStore = void 0;
28
+ state.persistentRegistryDisabled = false;
29
+ });
42
30
  //#endregion
43
31
  //#region extensions/discord/src/components-registry.ts
44
32
  const DEFAULT_COMPONENT_TTL_MS = 1800 * 1e3;
@@ -52,14 +40,6 @@ function getComponentEntries() {
52
40
  function getModalEntries() {
53
41
  return discordComponentRegistryState.modalEntries;
54
42
  }
55
- function reportPersistentComponentRegistryError(error) {
56
- try {
57
- getOptionalDiscordRuntime()?.logging.getChildLogger({
58
- plugin: "discord",
59
- feature: "component-registry-state"
60
- }).warn("Discord persistent component registry state failed", formatRegistryError(error));
61
- } catch {}
62
- }
63
43
  function formatRegistryError(error) {
64
44
  if (!(error instanceof Error)) return { error: formatRegistryErrorValue(error) };
65
45
  const details = {
@@ -77,6 +57,7 @@ function formatRegistryError(error) {
77
57
  } else if (cause !== void 0) details.errorCause = formatRegistryErrorValue(cause);
78
58
  return details;
79
59
  }
60
+ const reportPersistentComponentRegistryError = createPluginStateErrorReporter(getOptionalDiscordRuntime, "discord", "component-registry-state", "Discord persistent component registry state failed", formatRegistryError);
80
61
  function formatRegistryErrorValue(value) {
81
62
  if (typeof value === "string") return value;
82
63
  if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") return String(value);
@@ -381,11 +362,14 @@ async function buildDiscordComponentPayload(params) {
381
362
  mediaLocalRoots: params.opts.mediaLocalRoots,
382
363
  mediaReadFile: params.opts.mediaReadFile
383
364
  });
384
- resolvedFileName = params.opts.filename?.trim() || media.fileName || "upload";
365
+ const filenameOverride = params.opts.filename?.trim();
366
+ const explicitAttachmentName = extractComponentAttachmentNames(spec)[0];
367
+ resolvedFileName = filenameOverride || media.fileName || explicitAttachmentName || `upload${extensionForMime(media.contentType) ?? ""}`;
385
368
  spec = withImplicitComponentAttachmentBlock(spec, resolvedFileName);
386
369
  files = [{
387
370
  data: media.buffer,
388
- name: resolvedFileName
371
+ name: resolvedFileName,
372
+ contentType: media.contentType
389
373
  }];
390
374
  }
391
375
  const uniqueAttachmentNames = uniqueStrings(extractComponentAttachmentNames(spec));
@@ -402,7 +386,7 @@ async function buildDiscordComponentPayload(params) {
402
386
  const flags = buildDiscordComponentMessageFlags(buildResult.components);
403
387
  const finalFlags = params.opts.silent ? (flags ?? 0) | SUPPRESS_NOTIFICATIONS_FLAG : flags ?? void 0;
404
388
  return {
405
- body: stripUndefinedFields({
389
+ body: {
406
390
  ...serializePayload({
407
391
  components: buildResult.components,
408
392
  allowed_mentions: params.opts.allowedMentions,
@@ -410,7 +394,7 @@ async function buildDiscordComponentPayload(params) {
410
394
  ...files ? { files } : {}
411
395
  }),
412
396
  ...messageReference ? { message_reference: messageReference } : {}
413
- }),
397
+ },
414
398
  buildResult
415
399
  };
416
400
  }
@@ -433,6 +417,7 @@ async function sendDiscordComponentMessage(to, spec, opts) {
433
417
  tableMode: opts.tableMode,
434
418
  chunkMode: opts.chunkMode,
435
419
  onDeliveryResult: opts.onDeliveryResult,
420
+ onPlatformSendDispatch: opts.onPlatformSendDispatch,
436
421
  ...opts.suppressEmbeds === void 0 ? {} : { suppressEmbeds: opts.suppressEmbeds }
437
422
  });
438
423
  const cfg = requireRuntimeConfig(opts.cfg, "Discord component send");
@@ -459,6 +444,7 @@ async function sendDiscordComponentMessage(to, spec, opts) {
459
444
  };
460
445
  let result;
461
446
  try {
447
+ await opts.onPlatformSendDispatch?.();
462
448
  result = await request(() => createChannelMessage(rest, channelId, { body }), "components", { safety: "nonce-protected-create" });
463
449
  } catch (err) {
464
450
  throw await buildDiscordSendError(err, {
@@ -537,4 +523,4 @@ async function editDiscordComponentMessage(to, messageId, spec, opts) {
537
523
  });
538
524
  }
539
525
  //#endregion
540
- export { resolveDiscordModalEntryWithPersistence as _, assertMediaNotDataUrl as a, readBooleanParam$1 as c, readReactionParams as d, readStringArrayParam as f, resolveDiscordComponentEntryWithPersistence as g, withNormalizedTimestamp as h, send_components_exports as i, readNonNegativeIntegerParam as l, resolvePollMaxSelections as m, registerBuiltDiscordComponentMessage as n, jsonResult$1 as o, readStringParam$1 as p, sendDiscordComponentMessage as r, parseAvailableTags as s, editDiscordComponentMessage as t, readPositiveIntegerParam as u };
526
+ export { resolveDiscordComponentEntryWithPersistence as a, send_components_exports as i, registerBuiltDiscordComponentMessage as n, resolveDiscordModalEntryWithPersistence as o, sendDiscordComponentMessage as r, editDiscordComponentMessage as t };