@openclaw/discord 2026.9.1-beta.1 → 2026.9.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 (165) hide show
  1. package/dist/account-inspect-BY-ve3yH.js +45 -0
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-CfQ-vSyf.js → accounts-CwJQoLjM.js} +89 -45
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{activities-api-q-9PaaHH.js → activities-api-CTcGq3Hf.js} +30 -17
  6. package/dist/activities-api.js +1 -1
  7. package/dist/{allow-list-BDMimASD.js → allow-list-DBTtR2dz.js} +13 -35
  8. package/dist/{api-DNVbJyEy.js → api-BfmEP6wp.js} +6 -5
  9. package/dist/api.js +18 -18
  10. package/dist/{approval-handler.runtime-B7qhK3fR.js → approval-handler.runtime-DUSe5fyH.js} +19 -12
  11. package/dist/{audit-CBEv_ERu.js → audit-DpPfwoJM.js} +8 -7
  12. package/dist/{channel-Dx1tMTfx.js → channel-BHajPgwR.js} +29 -23
  13. package/dist/{channel-actions.runtime-CLWWu9nC.js → channel-actions.runtime-DS8pXo0S.js} +38 -38
  14. package/dist/channel-config-api.js +1 -1
  15. package/dist/channel-plugin-api.js +1 -1
  16. package/dist/{channel.setup-DOzXS2Pk.js → channel.setup-BWmMe1tT.js} +18 -18
  17. package/dist/command-owners-D78sAoOz.js +10 -0
  18. package/dist/{components-B9V5o361.js → components-BimX47Mq.js} +111 -149
  19. package/dist/{config-schema-BR13IAx6.js → config-schema-B797-Spt.js} +19 -12
  20. package/dist/{conversation-binding-route-DJYrY2TQ.js → conversation-binding-route-DuR5NGIx.js} +1 -1
  21. package/dist/{directory-config-BK6eqekJ.js → directory-config-CD2v2Szs.js} +2 -2
  22. package/dist/directory-contract-api.js +1 -1
  23. package/dist/{directory-live-DSAJSrJk.js → directory-live-DaJzWJ2N.js} +4 -4
  24. package/dist/{doctor-Cm7Y1pJ2.js → doctor-D4HH1inA.js} +9 -6
  25. package/dist/{doctor-contract-DsWvKIXF.js → doctor-contract-Co5vRCZ6.js} +9 -6
  26. package/dist/doctor-contract-api.js +31 -28
  27. package/dist/{handle-action.guild-admin-BdwCRHmm.js → handle-action.guild-admin-4We6wWQU.js} +6 -3
  28. package/dist/index.js +1 -1
  29. package/dist/ingress-identity-XNmW-mZS.js +60 -0
  30. package/dist/{message-handler-BXpWZyni.js → message-handler-DhgBabyU.js} +61 -70
  31. package/dist/{message-handler.preflight-Ba5LAY_X.js → message-handler.preflight-oZ7dQCd0.js} +41 -101
  32. package/dist/{message-handler.process-3HEzmemS.js → message-handler.process-BzCYf1pa.js} +82 -108
  33. package/dist/{message-text-aiwO5R2F.js → message-text-DK4NnBg-.js} +11 -6
  34. package/dist/{outbound-adapter-BE4jSq2d.js → outbound-adapter-CtggmGh9.js} +52 -67
  35. package/dist/{outbound-components-oLpg8Qzb.js → outbound-components-Dn8SJWMS.js} +5 -4
  36. package/dist/{outbound-session-route-Cg15ZFJd.js → outbound-session-route-Q_HEusBQ.js} +57 -15
  37. package/dist/{owner-access-UlYi9t0M.js → owner-access-Cp8r6Ipf.js} +9 -7
  38. package/dist/{pluralkit-Tiyl70dx.js → pluralkit-BY75YcK0.js} +2 -2
  39. package/dist/{probe-n6ZXxK8V.js → probe-3ovFAp3b.js} +3 -3
  40. package/dist/{probe.runtime-CN4bdPfZ.js → probe.runtime-BckHn3cJ.js} +1 -1
  41. package/dist/{provider-session.runtime-B9xe-Qaf.js → provider-session.runtime-BL2lHBH7.js} +3 -3
  42. package/dist/{provider-B11xwilq.js → provider-uKmmrDM4.js} +299 -136
  43. package/dist/provider.runtime-C-IkWF2w.js +2 -0
  44. package/dist/{realtime-session.runtime-CU8IQUS-.js → realtime-session.runtime-CGYm1t_0.js} +798 -448
  45. package/dist/{resolve-allowlist-common-BLoYaxEG.js → resolve-allowlist-common-sKIKy-cF.js} +3 -3
  46. package/dist/{resolve-channels-C2sT_n67.js → resolve-channels-CoiMlWy0.js} +4 -4
  47. package/dist/{resolve-users-CzpjLwjy.js → resolve-users-DJpiokfW.js} +5 -4
  48. package/dist/{retry-Cv4jCU5Z.js → retry-DQt1zDgH.js} +356 -214
  49. package/dist/{retry-after-DdLPmPoa.js → retry-after-BrLjLUJi.js} +2 -1
  50. package/dist/{runtime-CY4PRMF-.js → runtime-BHsdEdr5.js} +2 -2
  51. package/dist/{runtime-BHrTlFkf.js → runtime-Ghtfh5ZA.js} +151 -109
  52. package/dist/runtime-api.js +20 -20
  53. package/dist/{secret-config-contract-B3i6WxV5.js → secret-config-contract-DFu9hfU8.js} +14 -6
  54. package/dist/secret-contract-api.js +1 -1
  55. package/dist/{security-audit-BfJhAXZp.js → security-audit-DKfK-iPY.js} +10 -11
  56. package/dist/security-audit-contract-api.js +1 -1
  57. package/dist/{security-audit.runtime-BVKF9VtY.js → security-audit.runtime-sKZyKgpx.js} +1 -1
  58. package/dist/{send-C49MFF9j.js → send-CZeWKUiA.js} +132 -100
  59. package/dist/{send.components-DKKAw5VX.js → send.components-BG5IDABj.js} +21 -15
  60. package/dist/{send.outbound-zam0TrZx.js → send.outbound-DHuFUL6W.js} +42 -63
  61. package/dist/{send.shared-JjljcV4O.js → send.shared-B0n_fWzu.js} +77 -149
  62. package/dist/{sender-identity-BJtfyise.js → sender-identity-B8Ncfi63.js} +1 -1
  63. package/dist/setup-plugin-api.js +1 -1
  64. package/dist/{shared-_5EcP4jW.js → shared-C3dKun_X.js} +24 -15
  65. package/dist/{subagent-hooks-DQzvOptn.js → subagent-hooks-ZoQXEI1E.js} +2 -2
  66. package/dist/subagent-hooks-api.js +1 -1
  67. package/dist/{system-events-C7yxaHWP.js → system-events-DFF_awl7.js} +2 -2
  68. package/dist/{target-resolver-vxIh6O3-.js → target-resolver-DLtHDwMK.js} +6 -5
  69. package/dist/targets-BObRyaKX.js +3 -0
  70. package/dist/{thread-bindings-DW5F9vat.js → thread-bindings-DKvsNjQR.js} +7 -6
  71. package/dist/{thread-bindings.manager-ByOtwjo_.js → thread-bindings.manager-pbbRT5gb.js} +38 -29
  72. package/dist/{thread-bindings.session-updates-CJb-BpPL.js → thread-bindings.session-updates-t6jeFB1-.js} +3 -2
  73. package/dist/{thread-bindings.state-D8OMdk4O.js → thread-bindings.state-DtgOqsbX.js} +34 -1
  74. package/dist/{threading-agH1T_6s.js → threading-BCx49X-6.js} +8 -6
  75. package/dist/{timeouts-B9cy6RvQ.js → timeouts-D86uWLt_.js} +1 -1
  76. package/dist/{transcripts-source-BR11iHA4.js → transcripts-source-Dc6Nnli5.js} +55 -7
  77. package/dist/transcripts-source-api.js +1 -1
  78. package/dist/{typing-Dc_YMY2e.js → typing-CuopV-Hi.js} +2 -2
  79. package/dist/{voice-runtime-DIeaa8fJ.js → voice-runtime-BQnILUbG.js} +492 -105
  80. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/README.md +1 -1
  81. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/conforms.d.ts +2 -0
  82. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/package.json +3 -3
  83. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubArray.d.ts +2 -0
  84. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubObject.d.ts +2 -0
  85. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubString.d.ts +2 -0
  86. package/node_modules/@discordjs/voice/node_modules/@types/node/README.md +1 -1
  87. package/node_modules/@discordjs/voice/node_modules/@types/node/buffer.buffer.d.ts +5 -5
  88. package/node_modules/@discordjs/voice/node_modules/@types/node/crypto.d.ts +2 -2
  89. package/node_modules/@discordjs/voice/node_modules/@types/node/http.d.ts +16 -0
  90. package/node_modules/@discordjs/voice/node_modules/@types/node/http2.d.ts +10 -2
  91. package/node_modules/@discordjs/voice/node_modules/@types/node/package.json +2 -2
  92. package/node_modules/@discordjs/voice/node_modules/@types/node/process.d.ts +52 -0
  93. package/node_modules/@discordjs/voice/node_modules/@types/node/quic.d.ts +210 -28
  94. package/node_modules/@discordjs/voice/node_modules/@types/node/sqlite.d.ts +6 -2
  95. package/node_modules/@discordjs/voice/node_modules/@types/node/test.d.ts +36 -0
  96. package/node_modules/typebox/build/format/email.mjs +1 -1
  97. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  98. package/node_modules/typebox/build/format/json_pointer.d.mts +2 -2
  99. package/node_modules/typebox/build/format/json_pointer.mjs +2 -2
  100. package/node_modules/typebox/build/format/json_pointer_uri_fragment.d.mts +2 -2
  101. package/node_modules/typebox/build/format/json_pointer_uri_fragment.mjs +2 -2
  102. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  103. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  104. package/node_modules/typebox/build/system/memory/assign.mjs +2 -1
  105. package/node_modules/typebox/build/system/memory/create.mjs +3 -4
  106. package/node_modules/typebox/build/system/memory/discard.mjs +2 -2
  107. package/node_modules/typebox/build/system/memory/freeze.d.mts +4 -0
  108. package/node_modules/typebox/build/system/memory/freeze.mjs +6 -0
  109. package/node_modules/typebox/build/system/memory/update.mjs +3 -2
  110. package/node_modules/typebox/package.json +1 -1
  111. package/node_modules/undici/docs/docs/api/Client.md +4 -0
  112. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +3 -2
  113. package/node_modules/undici/docs/docs/api/EventSource.md +4 -0
  114. package/node_modules/undici/docs/docs/api/Interceptors.md +7 -3
  115. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +7 -1
  116. package/node_modules/undici/lib/cache/memory-cache-store.js +2 -2
  117. package/node_modules/undici/lib/core/symbols.js +2 -0
  118. package/node_modules/undici/lib/dispatcher/agent.js +7 -2
  119. package/node_modules/undici/lib/dispatcher/balanced-pool.js +7 -4
  120. package/node_modules/undici/lib/dispatcher/client-h1.js +12 -4
  121. package/node_modules/undici/lib/dispatcher/client-h2.js +43 -3
  122. package/node_modules/undici/lib/dispatcher/client.js +3 -2
  123. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +13 -1
  124. package/node_modules/undici/lib/dispatcher/dispatcher.js +15 -1
  125. package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +3 -0
  126. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +10 -3
  127. package/node_modules/undici/lib/dispatcher/proxy-agent.js +18 -1
  128. package/node_modules/undici/lib/dispatcher/retry-agent.js +3 -0
  129. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +1 -1
  130. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +91 -21
  131. package/node_modules/undici/lib/handler/cache-handler.js +29 -5
  132. package/node_modules/undici/lib/handler/decorator-handler.js +7 -1
  133. package/node_modules/undici/lib/handler/deduplication-handler.js +12 -6
  134. package/node_modules/undici/lib/handler/redirect-handler.js +21 -4
  135. package/node_modules/undici/lib/handler/retry-handler.js +148 -30
  136. package/node_modules/undici/lib/interceptor/cache.js +65 -12
  137. package/node_modules/undici/lib/interceptor/decompress.js +115 -13
  138. package/node_modules/undici/lib/interceptor/deduplicate.js +5 -4
  139. package/node_modules/undici/lib/interceptor/dns.js +7 -0
  140. package/node_modules/undici/lib/interceptor/dump.js +10 -23
  141. package/node_modules/undici/lib/mock/mock-agent.js +13 -1
  142. package/node_modules/undici/lib/mock/mock-utils.js +11 -10
  143. package/node_modules/undici/lib/util/cache.js +45 -3
  144. package/node_modules/undici/lib/web/cookies/parse.js +150 -147
  145. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +28 -1
  146. package/node_modules/undici/lib/web/eventsource/eventsource.js +13 -3
  147. package/node_modules/undici/lib/web/fetch/index.js +6 -0
  148. package/node_modules/undici/lib/web/fetch/request.js +2 -3
  149. package/node_modules/undici/lib/web/fetch/util.js +6 -1
  150. package/node_modules/undici/lib/web/webidl/index.js +3 -3
  151. package/node_modules/undici/lib/web/websocket/connection.js +1 -1
  152. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +5 -0
  153. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -10
  154. package/node_modules/undici/package.json +3 -3
  155. package/node_modules/undici/types/client.d.ts +10 -0
  156. package/node_modules/undici/types/interceptors.d.ts +2 -0
  157. package/node_modules/undici/types/mock-agent.d.ts +11 -10
  158. package/node_modules/undici/types/socks5-proxy-agent.d.ts +2 -0
  159. package/openclaw.plugin.json +15 -8
  160. package/package.json +7 -6
  161. package/skills/discord/SKILL.md +1 -1
  162. package/dist/account-inspect-BDfKyuvL.js +0 -89
  163. package/dist/provider.runtime-DiYaHvOz.js +0 -2
  164. package/dist/sdk-runtime-4geQHtXc.js +0 -338
  165. package/dist/targets-CtTKvntJ.js +0 -3
@@ -3,7 +3,7 @@ import { collectNestedChannelFieldAssignments, collectSimpleChannelFieldAssignme
3
3
  import { collectNestedChannelTtsAssignments } from "openclaw/plugin-sdk/channel-secret-tts-runtime";
4
4
  //#region extensions/discord/src/secret-config-contract.ts
5
5
  function createVoiceProviderSecretTarget(params) {
6
- const path = `${params.scope === "account" ? "channels.discord.accounts.*" : "channels.discord"}.voice.${params.capability}.providers.*.apiKey`;
6
+ const path = `${params.scope === "account" ? "channels.discord.accounts.*" : "channels.discord"}.voice.${params.providerPath}.providers.*.apiKey`;
7
7
  return {
8
8
  id: path,
9
9
  targetType: path,
@@ -14,7 +14,7 @@ function createVoiceProviderSecretTarget(params) {
14
14
  includeInPlan: true,
15
15
  includeInConfigure: true,
16
16
  includeInAudit: true,
17
- providerIdPathSegmentIndex: params.scope === "account" ? 7 : 5
17
+ providerIdPathSegmentIndex: path.split(".").length - 2
18
18
  };
19
19
  }
20
20
  function discordRealtimeVoiceSecretOwnerId(accountId, providerId) {
@@ -47,11 +47,15 @@ const secretTargetRegistryEntries = [
47
47
  includeInAudit: true
48
48
  },
49
49
  createVoiceProviderSecretTarget({
50
- capability: "realtime",
50
+ providerPath: "realtime",
51
51
  scope: "account"
52
52
  }),
53
53
  createVoiceProviderSecretTarget({
54
- capability: "tts",
54
+ providerPath: "tts",
55
+ scope: "account"
56
+ }),
57
+ createVoiceProviderSecretTarget({
58
+ providerPath: "tts.personas.*",
55
59
  scope: "account"
56
60
  }),
57
61
  {
@@ -77,11 +81,15 @@ const secretTargetRegistryEntries = [
77
81
  includeInAudit: true
78
82
  },
79
83
  createVoiceProviderSecretTarget({
80
- capability: "realtime",
84
+ providerPath: "realtime",
85
+ scope: "channel"
86
+ }),
87
+ createVoiceProviderSecretTarget({
88
+ providerPath: "tts",
81
89
  scope: "channel"
82
90
  }),
83
91
  createVoiceProviderSecretTarget({
84
- capability: "tts",
92
+ providerPath: "tts.personas.*",
85
93
  scope: "channel"
86
94
  })
87
95
  ];
@@ -1,2 +1,2 @@
1
- import { r as secretTargetRegistryEntries, t as collectRuntimeConfigAssignments } from "./secret-config-contract-B3i6WxV5.js";
1
+ import { r as secretTargetRegistryEntries, t as collectRuntimeConfigAssignments } from "./secret-config-contract-DFu9hfU8.js";
2
2
  export { collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -32,12 +32,8 @@ function listBroadMemberTargetPaths(params) {
32
32
  }
33
33
  function addDiscordNameBasedEntries(params) {
34
34
  if (!Array.isArray(params.values)) return;
35
- for (const value of params.values) {
36
- if (!isDiscordMutableAllowEntry(String(value))) continue;
37
- const text = normalizeOptionalString(String(value)) ?? "";
38
- if (!text) continue;
39
- params.target.add(`${params.source}:${text}`);
40
- }
35
+ const entries = new Set(params.values.map((value) => String(value).trim()).filter(isDiscordMutableAllowEntry));
36
+ if (entries.size > 0) params.target.set(params.source, entries.size);
41
37
  }
42
38
  async function collectDiscordSecurityAuditFindings(params) {
43
39
  const findings = [];
@@ -45,7 +41,7 @@ async function collectDiscordSecurityAuditFindings(params) {
45
41
  const accountId = normalizeOptionalString(params.accountId) ?? params.account.accountId ?? "default";
46
42
  const dangerousNameMatchingEnabled = isDangerousNameMatchingEnabled(discordCfg);
47
43
  const storeAllowFrom = await readChannelAllowFromStore("discord", process.env, accountId).catch(() => []);
48
- const discordNameBasedAllowEntries = /* @__PURE__ */ new Set();
44
+ const discordNameBasedAllowEntries = /* @__PURE__ */ new Map();
49
45
  const discordPathPrefix = params.orderedAccountIds.length > 1 || params.hasExplicitAccountPath ? `channels.discord.accounts.${accountId}` : "channels.discord";
50
46
  if ((discordCfg.groupPolicy ?? params.cfg.channels?.defaults?.groupPolicy ?? "allowlist") === "allowlist") {
51
47
  const broadMemberPaths = listBroadMemberTargetPaths({
@@ -73,7 +69,7 @@ async function collectDiscordSecurityAuditFindings(params) {
73
69
  addDiscordNameBasedEntries({
74
70
  target: discordNameBasedAllowEntries,
75
71
  values: storeAllowFrom,
76
- source: "~/.openclaw/credentials/discord-allowFrom.json"
72
+ source: "Discord pairing store"
77
73
  });
78
74
  const guildEntries = discordCfg.guilds ?? {};
79
75
  for (const [guildKey, guildValue] of Object.entries(guildEntries)) {
@@ -96,13 +92,16 @@ async function collectDiscordSecurityAuditFindings(params) {
96
92
  }
97
93
  }
98
94
  if (discordNameBasedAllowEntries.size > 0) {
99
- const examples = Array.from(discordNameBasedAllowEntries).slice(0, 5);
100
- const more = discordNameBasedAllowEntries.size > examples.length ? ` (+${discordNameBasedAllowEntries.size - examples.length} more)` : "";
95
+ const counts = Array.from(discordNameBasedAllowEntries);
96
+ const entryCount = counts.reduce((total, [, count]) => total + count, 0);
97
+ const sources = counts.slice(0, 5).map(([source, count]) => `${source} (${count})`);
98
+ const more = counts.length > sources.length ? ` (+${counts.length - sources.length} more sources)` : "";
99
+ const summary = `Found ${entryCount} name/tag entries: ${sources.join(", ")}${more}.`;
101
100
  findings.push({
102
101
  checkId: "channels.discord.allowFrom.name_based_entries",
103
102
  severity: dangerousNameMatchingEnabled ? "info" : "warn",
104
103
  title: dangerousNameMatchingEnabled ? "Discord allowlist uses break-glass name/tag matching" : "Discord allowlist contains name or tag entries",
105
- detail: dangerousNameMatchingEnabled ? `Discord name/tag allowlist matching is explicitly enabled via dangerouslyAllowNameMatching. This mutable-identity mode is operator-selected break-glass behavior and out-of-scope for vulnerability reports by itself. Found: ${examples.join(", ")}${more}.` : `Discord name/tag allowlist matching uses normalized slugs and can collide across users. Found: ${examples.join(", ")}${more}.`,
104
+ detail: dangerousNameMatchingEnabled ? "Discord name/tag allowlist matching is explicitly enabled via dangerouslyAllowNameMatching. This mutable-identity mode is operator-selected break-glass behavior and out-of-scope for vulnerability reports by itself. " + summary : "Discord name/tag allowlist matching uses normalized slugs and can collide across users. " + summary,
106
105
  remediation: dangerousNameMatchingEnabled ? "Prefer stable Discord IDs (or <@id>/user:<id>/pk:<id>), then disable dangerouslyAllowNameMatching." : "Prefer stable Discord IDs (or <@id>/user:<id>/pk:<id>) in channels.discord.allowFrom and channels.discord.guilds.*.users, or explicitly opt in with dangerouslyAllowNameMatching=true if you accept the risk."
107
106
  });
108
107
  }
@@ -1,2 +1,2 @@
1
- import { t as collectDiscordSecurityAuditFindings } from "./security-audit-BfJhAXZp.js";
1
+ import { t as collectDiscordSecurityAuditFindings } from "./security-audit-DKfK-iPY.js";
2
2
  export { collectDiscordSecurityAuditFindings };
@@ -1,2 +1,2 @@
1
- import { t as collectDiscordSecurityAuditFindings } from "./security-audit-BfJhAXZp.js";
1
+ import { t as collectDiscordSecurityAuditFindings } from "./security-audit-DKfK-iPY.js";
2
2
  export { collectDiscordSecurityAuditFindings };
@@ -1,8 +1,8 @@
1
- import { $t as listGuildRoles, At as getChannel, B as readRetryAfter, Bt as addGuildMemberRole, Ct as listMessageReactionUsers, Dt as deleteChannelMessage, Et as deleteChannel, F as DiscordError, Ft as listChannelPins, Gt as createGuildSticker, Ht as createGuildChannel, I as RateLimitError, It as pinChannelMessage, Jt as getGuildMember, Kt as deleteChannelPermission, L as isUnknownDiscordVoiceStateError, Lt as searchGuildMessages, Nt as listChannelArchivedThreads, Ot as editChannel, Pt as listChannelMessages, Qt as listGuildEmojis, R as readDiscordCode, Rt as sendChannelTyping, St as deleteOwnMessageReaction, Tt as createThread, Ut as createGuildEmoji, Vt as createGuildBan, Wt as createGuildScheduledEvent, Xt as listGuildActiveThreads, Yt as getGuildVoiceState, Zt as listGuildChannels, an as timeoutGuildMember, c as createDiscordSendResult, en as listGuildScheduledEvents, i as recordDiscordMessageCreateAmbiguity, in as removeGuildMemberRole, jt as getChannelMessage, kt as editChannelMessage, n as createDiscordRetryRunner, nn as putChannelPermission, on as __exportAll, qt as getGuild, rn as removeGuildMember, t as classifyDiscordDeliveryFailure, tn as moveGuildChannels, xt as createOwnMessageReaction, z as readDiscordMessage, zt as unpinChannelMessage } from "./retry-Cv4jCU5Z.js";
2
- import { t as parseDiscordRetryAfterBodySeconds } from "./retry-after-DdLPmPoa.js";
3
- import { C as hasAllGuildPermissionsDiscord, I as resolveDiscordClientAccountContext, K as parseAndResolveChannelRecipient, L as resolveDiscordRest, M as resolveDiscordSuppressEmbeds, N as createDiscordClient, O as createDiscordMessageNonce, R as DISCORD_REST_TIMEOUT_MS, S as fetchMemberGuildPermissionsDiscord, T as hasAnyGuildPermissionDiscord, _ as DiscordSendError, b as canViewDiscordGuildChannel, g as DISCORD_MAX_STICKER_BYTES, h as DISCORD_MAX_EVENT_COVER_BYTES, i as formatReactionEmoji, k as resolveDiscordMessageFlags, l as resolveChannelId, m as DISCORD_MAX_EMOJI_BYTES, n as buildDiscordTextChunks, o as normalizeEmojiName, p as sendDiscordText, r as buildReactionIdentifier, s as normalizeReactionEmoji, t as buildDiscordSendError, v as canManageGuildMemberRoleDiscord, w as hasAnyChannelPermissionDiscord, x as fetchChannelPermissionsDiscord, y as canManageGuildRoleDiscord } from "./send.shared-JjljcV4O.js";
4
- import { n as sendPollDiscord, o as rewriteDiscordKnownMentions, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-zam0TrZx.js";
5
- import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS } from "./timeouts-B9cy6RvQ.js";
1
+ import { $t as listGuildEmojis, At as editChannelMessage, B as readDiscordMessage, Bt as unpinChannelMessage, Ct as deleteOwnMessageReaction, Dt as deleteChannel, Et as createThread, Ft as listChannelMessages, Gt as createGuildScheduledEvent, Ht as createGuildBan, I as DiscordError, It as listChannelPins, Jt as getGuild, Kt as createGuildSticker, L as RateLimitError, Lt as pinChannelMessage, Mt as getChannelMessage, Ot as deleteChannelMessage, Pt as listChannelArchivedThreads, Qt as listGuildChannels, R as isUnknownDiscordVoiceStateError, Rt as searchGuildMessages, St as createOwnMessageReaction, Ut as createGuildChannel, V as readRetryAfter, Vt as addGuildMemberRole, Wt as createGuildEmoji, Xt as getGuildVoiceState, Yt as getGuildMember, Zt as listGuildActiveThreads, a as recordDiscordMessageCreateAmbiguity, an as removeGuildMemberRole, c as createDiscordSendReceiptFromResults, en as listGuildRoles, in as removeGuildMember, jt as getChannel, kt as editChannel, l as createDiscordSendResult, n as classifyDiscordDeliveryFailure, nn as moveGuildChannels, o as chunkDiscordTextWithMode, on as timeoutGuildMember, qt as deleteChannelPermission, r as createDiscordRetryRunner, rn as putChannelPermission, sn as __exportAll, tn as listGuildScheduledEvents, wt as listMessageReactionUsers, z as readDiscordCode, zt as sendChannelTyping } from "./retry-DQt1zDgH.js";
2
+ import { t as parseDiscordRetryAfterBodySeconds } from "./retry-after-BrLjLUJi.js";
3
+ import { C as hasAllGuildPermissionsDiscord, I as resolveDiscordClientAccountContext, K as parseAndResolveChannelRecipient, L as resolveDiscordRest, M as resolveDiscordSuppressEmbeds, N as createDiscordClient, O as createDiscordMessageNonce, R as DISCORD_REST_TIMEOUT_MS, S as fetchMemberGuildPermissionsDiscord, T as hasAnyGuildPermissionDiscord, _ as DiscordSendError, b as canViewDiscordGuildChannel, g as DISCORD_MAX_STICKER_BYTES, h as DISCORD_MAX_EVENT_COVER_BYTES, i as formatReactionEmoji, k as resolveDiscordMessageFlags, l as resolveChannelId, m as DISCORD_MAX_EMOJI_BYTES, n as buildDiscordTextChunks, o as normalizeEmojiName, p as sendDiscordText, r as buildReactionIdentifier, s as normalizeReactionEmoji, t as buildDiscordSendError, v as canManageGuildMemberRoleDiscord, w as hasAnyChannelPermissionDiscord, x as fetchChannelPermissionsDiscord, y as canManageGuildRoleDiscord } from "./send.shared-B0n_fWzu.js";
4
+ import { n as sendPollDiscord, o as rewriteDiscordKnownMentions, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-DHuFUL6W.js";
5
+ import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS } from "./timeouts-D86uWLt_.js";
6
6
  import fs from "node:fs/promises";
7
7
  import { ChannelType } from "discord-api-types/v10";
8
8
  import crypto from "node:crypto";
@@ -55,7 +55,8 @@ async function editChannelDiscord(payload, opts) {
55
55
  return await editChannel(rest, payload.channelId, { body });
56
56
  }
57
57
  async function deleteChannelDiscord(channelId, opts) {
58
- await deleteChannel(resolveDiscordRest(opts), channelId);
58
+ const rest = resolveDiscordRest(opts);
59
+ await deleteChannel(rest, channelId);
59
60
  return {
60
61
  ok: true,
61
62
  channelId
@@ -80,13 +81,15 @@ async function setChannelPermissionDiscord(payload, opts) {
80
81
  return { ok: true };
81
82
  }
82
83
  async function removeChannelPermissionDiscord(channelId, targetId, opts) {
83
- await deleteChannelPermission(resolveDiscordRest(opts), channelId, targetId);
84
+ const rest = resolveDiscordRest(opts);
85
+ await deleteChannelPermission(rest, channelId, targetId);
84
86
  return { ok: true };
85
87
  }
86
88
  //#endregion
87
89
  //#region extensions/discord/src/send.emojis-stickers.ts
88
90
  async function listGuildEmojisDiscord(guildId, opts) {
89
- return await listGuildEmojis(resolveDiscordRest(opts), guildId);
91
+ const rest = resolveDiscordRest(opts);
92
+ return await listGuildEmojis(rest, guildId);
90
93
  }
91
94
  async function uploadEmojiDiscord(payload, opts) {
92
95
  const rest = resolveDiscordRest(opts);
@@ -133,27 +136,34 @@ async function uploadStickerDiscord(payload, opts) {
133
136
  //#endregion
134
137
  //#region extensions/discord/src/send.guild.ts
135
138
  async function fetchMemberInfoDiscord(guildId, userId, opts) {
136
- return await getGuildMember(resolveDiscordRest(opts), guildId, userId);
139
+ const rest = resolveDiscordRest(opts);
140
+ return await getGuildMember(rest, guildId, userId);
137
141
  }
138
142
  async function fetchRoleInfoDiscord(guildId, opts) {
139
- return await listGuildRoles(resolveDiscordRest(opts), guildId);
143
+ const rest = resolveDiscordRest(opts);
144
+ return await listGuildRoles(rest, guildId);
140
145
  }
141
146
  async function addRoleDiscord(payload, opts) {
142
- await addGuildMemberRole(resolveDiscordRest(opts), payload.guildId, payload.userId, payload.roleId);
147
+ const rest = resolveDiscordRest(opts);
148
+ await addGuildMemberRole(rest, payload.guildId, payload.userId, payload.roleId);
143
149
  return { ok: true };
144
150
  }
145
151
  async function removeRoleDiscord(payload, opts) {
146
- await removeGuildMemberRole(resolveDiscordRest(opts), payload.guildId, payload.userId, payload.roleId);
152
+ const rest = resolveDiscordRest(opts);
153
+ await removeGuildMemberRole(rest, payload.guildId, payload.userId, payload.roleId);
147
154
  return { ok: true };
148
155
  }
149
156
  async function fetchChannelInfoDiscord(channelId, opts) {
150
- return await getChannel(resolveDiscordRest(opts), channelId);
157
+ const rest = resolveDiscordRest(opts);
158
+ return await getChannel(rest, channelId);
151
159
  }
152
160
  async function fetchGuildInfoDiscord(guildId, opts) {
153
- return await getGuild(resolveDiscordRest(opts), guildId);
161
+ const rest = resolveDiscordRest(opts);
162
+ return await getGuild(rest, guildId);
154
163
  }
155
164
  async function listGuildChannelsDiscord(guildId, opts) {
156
- return await listGuildChannels(resolveDiscordRest(opts), guildId);
165
+ const rest = resolveDiscordRest(opts);
166
+ return await listGuildChannels(rest, guildId);
157
167
  }
158
168
  async function fetchVoiceStatusDiscord(guildId, userId, opts) {
159
169
  const rest = resolveDiscordRest(opts);
@@ -172,7 +182,8 @@ async function fetchVoiceStatusDiscord(guildId, userId, opts) {
172
182
  }
173
183
  }
174
184
  async function listScheduledEventsDiscord(guildId, opts) {
175
- return await listGuildScheduledEvents(resolveDiscordRest(opts), guildId);
185
+ const rest = resolveDiscordRest(opts);
186
+ return await listGuildScheduledEvents(rest, guildId);
176
187
  }
177
188
  const ALLOWED_EVENT_COVER_TYPES = /* @__PURE__ */ new Set([
178
189
  "image/png",
@@ -187,13 +198,15 @@ async function resolveEventCoverImage(imageUrl, opts) {
187
198
  return `data:${contentType};base64,${media.buffer.toString("base64")}`;
188
199
  }
189
200
  async function createScheduledEventDiscord(guildId, payload, opts) {
190
- return await createGuildScheduledEvent(resolveDiscordRest(opts), guildId, payload);
201
+ const rest = resolveDiscordRest(opts);
202
+ return await createGuildScheduledEvent(rest, guildId, payload);
191
203
  }
192
204
  async function timeoutMemberDiscord(payload, opts) {
193
205
  const rest = resolveDiscordRest(opts);
194
206
  let until = payload.until;
195
207
  if (!until && payload.durationMinutes) {
196
- until = timestampMsToIsoString(resolveExpiresAtMsFromDurationMs(payload.durationMinutes * 60 * 1e3));
208
+ const ms = payload.durationMinutes * 60 * 1e3;
209
+ until = timestampMsToIsoString(resolveExpiresAtMsFromDurationMs(ms));
197
210
  if (!until) throw new Error("Discord timeout duration is outside the supported Date range");
198
211
  }
199
212
  return await timeoutGuildMember(rest, payload.guildId, payload.userId, {
@@ -202,7 +215,8 @@ async function timeoutMemberDiscord(payload, opts) {
202
215
  });
203
216
  }
204
217
  async function kickMemberDiscord(payload, opts) {
205
- await removeGuildMember(resolveDiscordRest(opts), payload.guildId, payload.userId, { headers: payload.reason ? { "X-Audit-Log-Reason": encodeURIComponent(payload.reason) } : void 0 });
218
+ const rest = resolveDiscordRest(opts);
219
+ await removeGuildMember(rest, payload.guildId, payload.userId, { headers: payload.reason ? { "X-Audit-Log-Reason": encodeURIComponent(payload.reason) } : void 0 });
206
220
  return { ok: true };
207
221
  }
208
222
  async function banMemberDiscord(payload, opts) {
@@ -265,28 +279,34 @@ async function readMessagesDiscord(channelId, query, opts) {
265
279
  return assertDiscordResponseArray(await listChannelMessages(rest, channelId, params), "message read");
266
280
  }
267
281
  async function fetchMessageDiscord(channelId, messageId, opts) {
268
- return await getChannelMessage(resolveDiscordRest(opts), channelId, messageId);
282
+ const rest = resolveDiscordRest(opts);
283
+ return await getChannelMessage(rest, channelId, messageId);
269
284
  }
270
285
  async function editMessageDiscord(channelId, messageId, payload, opts) {
271
- return await editChannelMessage(resolveDiscordRest(opts), channelId, messageId, { body: {
286
+ const rest = resolveDiscordRest(opts);
287
+ return await editChannelMessage(rest, channelId, messageId, { body: {
272
288
  content: payload.content,
273
289
  ...payload.flags !== void 0 ? { flags: payload.flags } : {}
274
290
  } });
275
291
  }
276
292
  async function deleteMessageDiscord(channelId, messageId, opts) {
277
- await deleteChannelMessage(resolveDiscordRest(opts), channelId, messageId);
293
+ const rest = resolveDiscordRest(opts);
294
+ await deleteChannelMessage(rest, channelId, messageId);
278
295
  return { ok: true };
279
296
  }
280
297
  async function pinMessageDiscord(channelId, messageId, opts) {
281
- await pinChannelMessage(resolveDiscordRest(opts), channelId, messageId);
298
+ const rest = resolveDiscordRest(opts);
299
+ await pinChannelMessage(rest, channelId, messageId);
282
300
  return { ok: true };
283
301
  }
284
302
  async function unpinMessageDiscord(channelId, messageId, opts) {
285
- await unpinChannelMessage(resolveDiscordRest(opts), channelId, messageId);
303
+ const rest = resolveDiscordRest(opts);
304
+ await unpinChannelMessage(rest, channelId, messageId);
286
305
  return { ok: true };
287
306
  }
288
307
  async function listPinsDiscord(channelId, opts) {
289
- return await listChannelPins(resolveDiscordRest(opts), channelId);
308
+ const rest = resolveDiscordRest(opts);
309
+ return await listChannelPins(rest, channelId);
290
310
  }
291
311
  async function createThreadDiscord(channelId, payload, opts) {
292
312
  const { rest, request } = createDiscordClient(opts);
@@ -299,7 +319,8 @@ async function createThreadDiscord(channelId, payload, opts) {
299
319
  const archiveDuration = payload.autoArchiveMinutes ?? resolveDefaultThreadAutoArchiveDuration(channel);
300
320
  if (archiveDuration !== void 0) body.auto_archive_duration = archiveDuration;
301
321
  const isForumLike = channel?.type === ChannelType.GuildForum || channel?.type === ChannelType.GuildMedia;
302
- const initialMessageChunks = buildDiscordTextChunks(isForumLike ? payload.content?.trim() ? payload.content : payload.name : payload.content?.trim() ? payload.content : "", { maxLinesPerMessage: DISCORD_THREAD_TRANSPORT_ONLY_MAX_LINES });
322
+ const initialMessageContent = isForumLike ? payload.content?.trim() ? payload.content : payload.name : payload.content?.trim() ? payload.content : "";
323
+ const initialMessageChunks = buildDiscordTextChunks(initialMessageContent, { maxLinesPerMessage: DISCORD_THREAD_TRANSPORT_ONLY_MAX_LINES });
303
324
  if (isForumLike) {
304
325
  body.message = { content: initialMessageChunks[0] ?? payload.name };
305
326
  if (payload.appliedTags?.length) body.applied_tags = payload.appliedTags;
@@ -381,14 +402,8 @@ async function searchMessagesDiscord(query, opts) {
381
402
  }
382
403
  //#endregion
383
404
  //#region extensions/discord/src/send.webhook.ts
384
- const DISCORD_WEBHOOK_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
405
+ const DISCORD_WEBHOOK_ERROR_BODY_LIMIT_BYTES = 8192;
385
406
  const DISCORD_WEBHOOK_TIMEOUT_MS = DISCORD_REST_TIMEOUT_MS;
386
- function resolveWebhookExecutionUrl(params) {
387
- const baseUrl = new URL(`https://discord.com/api/v10/webhooks/${encodeURIComponent(params.webhookId)}/${encodeURIComponent(params.webhookToken)}`);
388
- baseUrl.searchParams.set("wait", params.wait === false ? "false" : "true");
389
- if (params.threadId !== void 0 && params.threadId !== null && params.threadId !== "") baseUrl.searchParams.set("thread_id", String(params.threadId));
390
- return baseUrl.toString();
391
- }
392
407
  function coerceWebhookErrorBody(raw) {
393
408
  if (!raw) return;
394
409
  try {
@@ -439,62 +454,73 @@ async function sendWebhookMessageDiscord(text, opts) {
439
454
  conversationId: threadConversationId,
440
455
  sourceId: webhookId
441
456
  });
442
- const url = resolveWebhookExecutionUrl({
443
- webhookId,
444
- webhookToken,
445
- threadId: opts.threadId,
446
- wait: opts.wait
447
- });
457
+ const url = new URL(`https://discord.com/api/v10/webhooks/${encodeURIComponent(webhookId)}/${encodeURIComponent(webhookToken)}`);
458
+ url.searchParams.set("wait", opts.wait === false ? "false" : "true");
459
+ if (opts.threadId != null && opts.threadId !== "") url.searchParams.set("thread_id", String(opts.threadId));
448
460
  const deadline = buildTimeoutAbortSignal({
449
461
  timeoutMs: DISCORD_WEBHOOK_TIMEOUT_MS,
450
462
  operation: "discord.webhook.send"
451
463
  });
452
464
  const request = createDiscordRetryRunner({ signal: deadline.signal });
465
+ const chunks = chunkDiscordTextWithMode(rewrittenText, { maxLines: Number.MAX_SAFE_INTEGER });
466
+ const results = [];
453
467
  try {
454
- const response = await request(async () => {
455
- await opts.onPlatformSendDispatch?.();
456
- const attemptResponse = await (proxyFetch ?? fetch)(url, {
457
- method: "POST",
458
- headers: { "content-type": "application/json" },
459
- body: JSON.stringify({
460
- content: rewrittenText,
461
- username: normalizeOptionalString(opts.username),
462
- avatar_url: normalizeOptionalString(opts.avatarUrl),
463
- ...flags ? { flags } : {},
464
- ...messageReference ? { message_reference: messageReference } : {}
465
- }),
466
- signal: deadline.signal
468
+ for (const content of chunks.length ? chunks : [""]) {
469
+ const response = await request(async () => {
470
+ await opts.onPlatformSendDispatch?.();
471
+ opts.assertPlatformSendAuthorized?.();
472
+ const attemptResponse = await (proxyFetch ?? fetch)(url.toString(), {
473
+ method: "POST",
474
+ headers: { "content-type": "application/json" },
475
+ body: JSON.stringify({
476
+ content,
477
+ username: normalizeOptionalString(opts.username),
478
+ avatar_url: normalizeOptionalString(opts.avatarUrl),
479
+ ...flags ? { flags } : {},
480
+ ...messageReference ? { message_reference: messageReference } : {}
481
+ }),
482
+ signal: deadline.signal
483
+ });
484
+ if (!attemptResponse.ok) await throwWebhookResponseError(attemptResponse, deadline.signal);
485
+ return attemptResponse;
486
+ }, "webhook", { safety: "non-idempotent-create" });
487
+ const payload = response.status === 204 ? {} : await readProviderJsonResponse(response, "Discord webhook send").catch(() => {
488
+ throwIfWebhookDeadlineExpired(deadline.signal);
489
+ return {};
467
490
  });
468
- if (!attemptResponse.ok) await throwWebhookResponseError(attemptResponse, deadline.signal);
469
- return attemptResponse;
470
- }, "webhook", { safety: "non-idempotent-create" });
471
- const payload = response.status === 204 ? {} : await readProviderJsonResponse(response, "Discord webhook send").catch(() => {
472
- throwIfWebhookDeadlineExpired(deadline.signal);
473
- return {};
474
- });
475
- try {
476
- recordChannelActivity({
491
+ try {
492
+ recordChannelActivity({
493
+ channel: "discord",
494
+ accountId: account.accountId,
495
+ direction: "outbound"
496
+ });
497
+ } catch {}
498
+ const result = createDiscordSendResult({
499
+ result: payload,
500
+ fallbackChannelId: opts.threadId ? String(opts.threadId) : "",
501
+ kind: "text",
502
+ ...opts.threadId != null ? { threadId: opts.threadId } : {},
503
+ ...replyTo ? { replyToId: replyTo } : {}
504
+ });
505
+ const resultConversationId = result.channelId.trim();
506
+ if (result.messageId && resultConversationId) recordOutboundMessageIdentity({
477
507
  channel: "discord",
478
508
  accountId: account.accountId,
479
- direction: "outbound"
509
+ conversationId: resultConversationId,
510
+ messageId: result.messageId,
511
+ sourceId: webhookId
480
512
  });
481
- } catch {}
482
- const result = createDiscordSendResult({
483
- result: payload,
484
- fallbackChannelId: opts.threadId ? String(opts.threadId) : "",
485
- kind: "text",
486
- ...opts.threadId != null ? { threadId: opts.threadId } : {},
487
- ...replyTo ? { replyToId: replyTo } : {}
488
- });
489
- const resultConversationId = result.channelId.trim();
490
- if (result.messageId !== "unknown" && resultConversationId) recordOutboundMessageIdentity({
491
- channel: "discord",
492
- accountId: account.accountId,
493
- conversationId: resultConversationId,
494
- messageId: result.messageId,
495
- sourceId: webhookId
496
- });
497
- return result;
513
+ results.push(result);
514
+ await opts.onDeliveryResult?.(result);
515
+ }
516
+ const last = expectDefined(results.at(-1), "Discord webhook delivery result");
517
+ return results.length === 1 ? last : {
518
+ ...last,
519
+ receipt: createDiscordSendReceiptFromResults({ results })
520
+ };
521
+ } catch (error) {
522
+ if (results.length) recordDiscordMessageCreateAmbiguity(error);
523
+ throw error;
498
524
  } finally {
499
525
  deadline.cleanup();
500
526
  }
@@ -515,7 +541,7 @@ async function sendWebhookMessageDiscord(text, opts) {
515
541
  const DISCORD_VOICE_MESSAGE_FLAG = 8192;
516
542
  const WAVEFORM_SAMPLES = 256;
517
543
  const DISCORD_OPUS_SAMPLE_RATE_HZ = 48e3;
518
- const DISCORD_VOICE_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
544
+ const DISCORD_VOICE_ERROR_BODY_LIMIT_BYTES = 8192;
519
545
  const DISCORD_VOICE_UPLOAD_SSRF_POLICY = {
520
546
  allowRfc2544BenchmarkRange: true,
521
547
  allowIpv6UniqueLocalRange: true
@@ -539,7 +565,7 @@ function createRateLimitError(response, body) {
539
565
  */
540
566
  async function getAudioDuration(filePath) {
541
567
  try {
542
- const duration = parseStrictFiniteNumber(await runFfprobe([
568
+ const stdout = await runFfprobe([
543
569
  "-v",
544
570
  "error",
545
571
  "-show_entries",
@@ -547,7 +573,8 @@ async function getAudioDuration(filePath) {
547
573
  "-of",
548
574
  "csv=p=0",
549
575
  filePath
550
- ]));
576
+ ]);
577
+ const duration = parseStrictFiniteNumber(stdout);
551
578
  if (duration === void 0) throw new Error("Could not parse duration");
552
579
  return Math.round(duration * 100) / 100;
553
580
  } catch (err) {
@@ -635,7 +662,7 @@ async function ensureOggOpus(filePath) {
635
662
  const trimmed = filePath.trim();
636
663
  if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) throw new Error(`Voice message conversion requires a local file path; received a URL/protocol source: ${trimmed}`);
637
664
  if (normalizeLowercaseStringOrEmpty(path.extname(filePath)) === ".ogg") try {
638
- const { codec, sampleRateHz } = parseFfprobeCodecAndSampleRate(await runFfprobe([
665
+ const stdout = await runFfprobe([
639
666
  "-v",
640
667
  "error",
641
668
  "-select_streams",
@@ -645,7 +672,8 @@ async function ensureOggOpus(filePath) {
645
672
  "-of",
646
673
  "csv=p=0",
647
674
  filePath
648
- ]));
675
+ ]);
676
+ const { codec, sampleRateHz } = parseFfprobeCodecAndSampleRate(stdout);
649
677
  if (codec === "opus" && sampleRateHz === DISCORD_OPUS_SAMPLE_RATE_HZ) return {
650
678
  path: filePath,
651
679
  cleanup: false
@@ -708,20 +736,22 @@ async function createVoiceRequestError(response, fallbackMessage) {
708
736
  return new DiscordError(response, parsed ?? { message: fallbackMessage });
709
737
  }
710
738
  async function requestVoiceUploadUrl(params) {
711
- const { response: res, release } = await fetchWithSsrFGuard({
712
- url: `${params.rest.options?.baseUrl ?? "https://discord.com/api"}/channels/${params.channelId}/attachments`,
713
- init: {
714
- method: "POST",
715
- headers: {
716
- Authorization: `Bot ${params.botToken}`,
717
- "Content-Type": "application/json"
718
- },
719
- body: JSON.stringify({ files: [{
720
- filename: params.filename,
721
- file_size: params.fileSize,
722
- id: "0"
723
- }] })
739
+ const url = `${params.rest.options?.baseUrl ?? "https://discord.com/api"}/channels/${params.channelId}/attachments`;
740
+ const uploadUrlInit = {
741
+ method: "POST",
742
+ headers: {
743
+ Authorization: `Bot ${params.botToken}`,
744
+ "Content-Type": "application/json"
724
745
  },
746
+ body: JSON.stringify({ files: [{
747
+ filename: params.filename,
748
+ file_size: params.fileSize,
749
+ id: "0"
750
+ }] })
751
+ };
752
+ const { response: res, release } = await fetchWithSsrFGuard({
753
+ url,
754
+ init: uploadUrlInit,
725
755
  timeoutMs: params.rest.options.timeout,
726
756
  policy: DISCORD_VOICE_UPLOAD_SSRF_POLICY,
727
757
  auditContext: "discord.voice.upload-url"
@@ -760,7 +790,7 @@ async function uploadVoiceAttachment(params) {
760
790
  * 2. Upload the OGG file to the provided URL
761
791
  * 3. Send the message with flag 8192 and attachment metadata
762
792
  */
763
- async function sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, replyTo, request, silent, token, onPlatformSendDispatch) {
793
+ async function sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, replyTo, request, silent, token, onPlatformSendDispatch, assertPlatformSendAuthorized) {
764
794
  const filename = "voice-message.ogg";
765
795
  const fileSize = audioBuffer.byteLength;
766
796
  const botToken = token;
@@ -801,6 +831,7 @@ async function sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, r
801
831
  try {
802
832
  return await request(async () => {
803
833
  await onPlatformSendDispatch?.();
834
+ assertPlatformSendAuthorized?.();
804
835
  try {
805
836
  return await rest.post(`/channels/${channelId}/messages`, { body: messagePayload });
806
837
  } catch (error) {
@@ -872,7 +903,7 @@ async function sendVoiceMessageDiscord(to, audioPath, opts) {
872
903
  oggCleanup = ogg.cleanup;
873
904
  const metadata = await getVoiceMessageMetadata(oggPath);
874
905
  const audioBuffer = await fs.readFile(oggPath);
875
- const result = await sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, opts.reply?.messageId, request, opts.silent, token, opts.onPlatformSendDispatch);
906
+ const result = await sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, opts.reply?.messageId, request, opts.silent, token, opts.onPlatformSendDispatch, opts.assertPlatformSendAuthorized);
876
907
  recordChannelActivity({
877
908
  channel: "discord",
878
909
  accountId: accountInfo.accountId,
@@ -896,7 +927,8 @@ async function sendVoiceMessageDiscord(to, audioPath, opts) {
896
927
  //#endregion
897
928
  //#region extensions/discord/src/send.typing.ts
898
929
  async function sendTypingDiscord(channelId, opts) {
899
- await sendChannelTyping(resolveDiscordRest(opts), channelId);
930
+ const rest = resolveDiscordRest(opts);
931
+ await sendChannelTyping(rest, channelId);
900
932
  return {
901
933
  ok: true,
902
934
  channelId