@openclaw/discord 2026.10.2 → 2026.10.5-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 (246) hide show
  1. package/dist/.setup/account-inspect-8cCu6uPG.mjs +31 -0
  2. package/dist/.setup/{accounts-HE9-mj1L.mjs → accounts-ljrzXBJi.mjs} +47 -45
  3. package/dist/.setup/{allow-list-vxkG9_JD.mjs → allow-list-B_ToXtew.mjs} +34 -101
  4. package/dist/.setup/{api-DlNUkDqj.mjs → api-CtmE1OUN.mjs} +25 -31
  5. package/dist/.setup/{approval-handler.runtime-DmnEa54W.mjs → approval-handler.runtime-D7FoZSn0.mjs} +30 -53
  6. package/dist/.setup/{approval-message-updates-B0jdSqOj.mjs → approval-message-updates-CIGByUcE.mjs} +2 -2
  7. package/dist/.setup/{audit-BpikUwN_.mjs → audit-zSawfbsN.mjs} +5 -8
  8. package/dist/.setup/{channel-Dr-AUnGt.mjs → channel-DI7DMzu0.mjs} +136 -215
  9. package/dist/.setup/{channel-access-BRp3Y-rF.mjs → channel-access-DasWY_OV.mjs} +6 -7
  10. package/dist/.setup/{channel.setup-BmNvkidb.mjs → channel.setup-DdFVN1mr.mjs} +35 -64
  11. package/dist/.setup/{components-DLJR0xU-.mjs → components-HN9052L1.mjs} +123 -146
  12. package/dist/.setup/{config-schema-BQWfnSCx.mjs → config-schema-_uBILpQf.mjs} +7 -3
  13. package/dist/.setup/{conversation-binding-route-DicJC1Lj.mjs → conversation-binding-route-DTjCBx-O.mjs} +1 -1
  14. package/dist/.setup/{directory-config-gqsdcplU.mjs → directory-config-3iVub-3m.mjs} +1 -1
  15. package/dist/.setup/{directory-live-Bipr0eUJ.mjs → directory-live-DLygQVtW.mjs} +18 -22
  16. package/dist/.setup/{discord-9gysrhzp.mjs → discord-BGqgx-yd.mjs} +686 -854
  17. package/dist/.setup/{doctor-B2bskDcF.mjs → doctor-DSrNJ7m2.mjs} +36 -47
  18. package/dist/.setup/{doctor-contract-Bg3NPAMw.mjs → doctor-contract-Bwv8EuQ_.mjs} +7 -16
  19. package/dist/.setup/{handle-action-UmkjXBfo.mjs → handle-action-CXH1h1tq.mjs} +25 -38
  20. package/dist/.setup/{handle-action.guild-admin-CB4sc9VV.mjs → handle-action.guild-admin-CHKW6PIs.mjs} +25 -31
  21. package/dist/.setup/{live-policy-config-VxexfRKo.mjs → live-policy-config-BPoB3eQi.mjs} +1 -1
  22. package/dist/.setup/{message-handler-BK69A-NB.mjs → message-handler-Ii_etru1.mjs} +9 -14
  23. package/dist/.setup/{message-handler.preflight-DFpsh90H.mjs → message-handler.preflight-C7YuSRl_.mjs} +79 -128
  24. package/dist/.setup/{message-handler.preflight-pluralkit-BXGGVmpe.mjs → message-handler.preflight-pluralkit-C3iAG--b.mjs} +6 -6
  25. package/dist/.setup/{message-handler.process-TKoqcqIP.mjs → message-handler.process-ClgWYH6o.mjs} +234 -206
  26. package/dist/.setup/{outbound-adapter-D4wRAb5S.mjs → outbound-adapter-D8OOIuKn.mjs} +73 -112
  27. package/dist/.setup/{outbound-session-route-BvBH4LC6.mjs → outbound-session-route-B0Hpwn3Q.mjs} +57 -115
  28. package/dist/.setup/output-activity-uBpMSX75.mjs +11 -0
  29. package/dist/.setup/{pluralkit-a6_NLfH9.mjs → pluralkit-B64dfq_j.mjs} +3 -1
  30. package/dist/.setup/{preflight-audio-DHGIHEpv.mjs → preflight-audio-wWgsZG5F.mjs} +1 -5
  31. package/dist/.setup/{presence-cache-Dg3_dADn.mjs → presence-cache-DCeTsL73.mjs} +3 -6
  32. package/dist/.setup/{probe-BwSKpnZf.mjs → probe-D3P1x4aN.mjs} +10 -18
  33. package/dist/.setup/{provider-YP8gN9_o.mjs → provider-D9EzOfG8.mjs} +2990 -3903
  34. package/dist/.setup/{provider-session.runtime-D1gkPxHT.mjs → provider-session.runtime-CsnRvddI.mjs} +5 -5
  35. package/dist/.setup/provider.runtime-BQVcM7Pg.mjs +2 -0
  36. package/dist/.setup/{realtime-session.runtime-BKUQBy1u.mjs → realtime-session.runtime-CxGBk8H-.mjs} +69 -98
  37. package/dist/.setup/{receive-recovery-DgkX7Qvi.mjs → receive-recovery-eVmK2_hl.mjs} +2 -12
  38. package/dist/.setup/resolve-allowlist-common-DNSsUQRF.mjs +66 -0
  39. package/dist/.setup/resolve-channels-UdT38DzU.mjs +173 -0
  40. package/dist/.setup/{resolve-users-DNrwvunm.mjs → resolve-users-DnCsrXZ_.mjs} +12 -41
  41. package/dist/.setup/{runtime-CESTexGn.mjs → runtime-CRTkKU1G.mjs} +202 -313
  42. package/dist/.setup/{runtime-DPcmPST9.mjs → runtime-DPm3gZXk.mjs} +2 -2
  43. package/dist/.setup/{secret-config-contract-uOE2J7yM.mjs → secret-config-contract-CIsH7R3B.mjs} +9 -18
  44. package/dist/.setup/{security-audit-D42cp5N7.mjs → security-audit-BFT84Uny.mjs} +1 -2
  45. package/dist/.setup/security-contract-DNyyjTZZ.mjs +19 -0
  46. package/dist/.setup/{send-CJk3VP5q.mjs → send-DbILKgcm.mjs} +184 -241
  47. package/dist/.setup/{send.components-dPljuV24.mjs → send.components-FxOS3CeP.mjs} +47 -63
  48. package/dist/.setup/{send.outbound-rOboMO_6.mjs → send.outbound-_jx4Xpd3.mjs} +178 -202
  49. package/dist/.setup/{send.receipt-DVOg2Oaw.mjs → send.receipt-BAlzXd8e.mjs} +33 -109
  50. package/dist/.setup/{send.shared-C4CN24D9.mjs → send.shared-CjQ4jbMA.mjs} +97 -153
  51. package/dist/.setup/{sender-identity-AHpUNr72.mjs → sender-identity-BNBvGt1l.mjs} +1 -1
  52. package/dist/.setup/setup-plugin-api-xfOFmxHP.mjs +3 -0
  53. package/dist/.setup/{shared-BoBnM5kM.mjs → shared-CestGDpq.mjs} +30 -20
  54. package/dist/.setup/{subagent-hooks-HH8Uy9cx.mjs → subagent-hooks-CME7dSGf.mjs} +5 -10
  55. package/dist/.setup/{system-events-Cwxaww8i.mjs → system-events-BwwSDCw4.mjs} +2 -2
  56. package/dist/.setup/target-parsing-C-HyNxcE.mjs +48 -0
  57. package/dist/.setup/{target-resolver-CSFoPQ12.mjs → target-resolver-Bse8fuTi.mjs} +11 -27
  58. package/dist/.setup/targets-DZJjkzwv.mjs +3 -0
  59. package/dist/.setup/{thread-bindings-DjQCkmsd.mjs → thread-bindings-0hPTSK14.mjs} +61 -52
  60. package/dist/.setup/{thread-bindings.manager-D2-GYZ5s.mjs → thread-bindings.manager-CdNa6UIs.mjs} +138 -211
  61. package/dist/.setup/{thread-bindings.session-updates-Bu_CGr_O.mjs → thread-bindings.session-updates-DGSljVf6.mjs} +60 -99
  62. package/dist/.setup/threading-BKe3E3tp.mjs +246 -0
  63. package/dist/.setup/{timeouts-pun7VJ02.mjs → timeouts-CuNARfyw.mjs} +10 -18
  64. package/dist/.setup/{transcripts-source-CaZQnGRH.mjs → transcripts-source-0qQYVu2H.mjs} +50 -368
  65. package/dist/.setup/{voice-runtime-DDymtIw8.mjs → voice-runtime-QlZJ4sHv.mjs} +166 -322
  66. package/dist/account-inspect-api.js +1 -1
  67. package/dist/action-runtime-api.js +1 -1
  68. package/dist/activities-api.js +77 -120
  69. package/dist/api.js +19 -18
  70. package/dist/channel-config-api.js +1 -1
  71. package/dist/channel-plugin-api.js +1 -1
  72. package/dist/directory-contract-api.js +1 -1
  73. package/dist/doctor-contract-api.js +1 -1
  74. package/dist/runtime-api.js +21 -20
  75. package/dist/secret-contract-api.js +1 -1
  76. package/dist/security-audit-contract-api.js +1 -1
  77. package/dist/security-contract-api.js +1 -1
  78. package/dist/setup-entry.js +1 -1
  79. package/dist/setup-plugin-api.js +1 -1
  80. package/dist/src/voice/audio-worker.runtime.js +38 -57
  81. package/dist/subagent-hooks-api.js +1 -1
  82. package/dist/transcripts-source-api.js +1 -1
  83. package/node_modules/@types/node/README.md +1 -1
  84. package/node_modules/@types/node/crypto.d.ts +2 -2
  85. package/node_modules/@types/node/dgram.d.ts +1 -1
  86. package/node_modules/@types/node/package.json +2 -2
  87. package/node_modules/@types/node/zlib.d.ts +6 -0
  88. package/node_modules/@types/ws/README.md +1 -1
  89. package/node_modules/@types/ws/index.d.mts +4 -0
  90. package/node_modules/@types/ws/index.d.ts +4 -0
  91. package/node_modules/@types/ws/package.json +3 -3
  92. package/node_modules/discord-api-types/_generated_/rest/v10/interfaces.d.ts +21 -0
  93. package/node_modules/discord-api-types/_generated_/rest/v10/interfaces.d.ts.map +1 -1
  94. package/node_modules/discord-api-types/_generated_/rest/v9/interfaces.d.ts +21 -0
  95. package/node_modules/discord-api-types/_generated_/rest/v9/interfaces.d.ts.map +1 -1
  96. package/node_modules/discord-api-types/globals.d.ts +6 -0
  97. package/node_modules/discord-api-types/globals.d.ts.map +1 -1
  98. package/node_modules/discord-api-types/globals.js +6 -0
  99. package/node_modules/discord-api-types/globals.js.map +1 -1
  100. package/node_modules/discord-api-types/package.json +3 -3
  101. package/node_modules/discord-api-types/payloads/index.mjs +1 -0
  102. package/node_modules/discord-api-types/payloads/v10/applicationIdentityProfile.d.ts +207 -0
  103. package/node_modules/discord-api-types/payloads/v10/applicationIdentityProfile.d.ts.map +1 -0
  104. package/node_modules/discord-api-types/payloads/v10/applicationIdentityProfile.js +25 -0
  105. package/node_modules/discord-api-types/payloads/v10/applicationIdentityProfile.js.map +1 -0
  106. package/node_modules/discord-api-types/payloads/v10/autoModeration.d.ts +1 -1
  107. package/node_modules/discord-api-types/payloads/v10/autoModeration.d.ts.map +1 -1
  108. package/node_modules/discord-api-types/payloads/v10/guild.d.ts +27 -23
  109. package/node_modules/discord-api-types/payloads/v10/guild.d.ts.map +1 -1
  110. package/node_modules/discord-api-types/payloads/v10/guild.js +26 -22
  111. package/node_modules/discord-api-types/payloads/v10/guild.js.map +1 -1
  112. package/node_modules/discord-api-types/payloads/v10/index.d.ts +1 -0
  113. package/node_modules/discord-api-types/payloads/v10/index.d.ts.map +1 -1
  114. package/node_modules/discord-api-types/payloads/v10/index.js +1 -0
  115. package/node_modules/discord-api-types/payloads/v10/index.js.map +1 -1
  116. package/node_modules/discord-api-types/payloads/v10/index.mjs +1 -0
  117. package/node_modules/discord-api-types/payloads/v9/applicationIdentityProfile.d.ts +207 -0
  118. package/node_modules/discord-api-types/payloads/v9/applicationIdentityProfile.d.ts.map +1 -0
  119. package/node_modules/discord-api-types/payloads/v9/applicationIdentityProfile.js +25 -0
  120. package/node_modules/discord-api-types/payloads/v9/applicationIdentityProfile.js.map +1 -0
  121. package/node_modules/discord-api-types/payloads/v9/autoModeration.d.ts +1 -1
  122. package/node_modules/discord-api-types/payloads/v9/autoModeration.d.ts.map +1 -1
  123. package/node_modules/discord-api-types/payloads/v9/guild.d.ts +27 -23
  124. package/node_modules/discord-api-types/payloads/v9/guild.d.ts.map +1 -1
  125. package/node_modules/discord-api-types/payloads/v9/guild.js +26 -22
  126. package/node_modules/discord-api-types/payloads/v9/guild.js.map +1 -1
  127. package/node_modules/discord-api-types/payloads/v9/index.d.ts +1 -0
  128. package/node_modules/discord-api-types/payloads/v9/index.d.ts.map +1 -1
  129. package/node_modules/discord-api-types/payloads/v9/index.js +1 -0
  130. package/node_modules/discord-api-types/payloads/v9/index.js.map +1 -1
  131. package/node_modules/discord-api-types/payloads/v9/index.mjs +1 -0
  132. package/node_modules/discord-api-types/rest/common.d.ts +2 -0
  133. package/node_modules/discord-api-types/rest/common.d.ts.map +1 -1
  134. package/node_modules/discord-api-types/rest/common.js +2 -0
  135. package/node_modules/discord-api-types/rest/common.js.map +1 -1
  136. package/node_modules/discord-api-types/rest/v10/applicationIdentityProfile.d.ts +70 -0
  137. package/node_modules/discord-api-types/rest/v10/applicationIdentityProfile.d.ts.map +1 -0
  138. package/node_modules/discord-api-types/rest/v10/applicationIdentityProfile.js +3 -0
  139. package/node_modules/discord-api-types/rest/v10/applicationIdentityProfile.js.map +1 -0
  140. package/node_modules/discord-api-types/rest/v10/index.d.ts +1 -0
  141. package/node_modules/discord-api-types/rest/v10/index.d.ts.map +1 -1
  142. package/node_modules/discord-api-types/rest/v10/index.js +29 -0
  143. package/node_modules/discord-api-types/rest/v10/index.js.map +1 -1
  144. package/node_modules/discord-api-types/rest/v10/interactions.d.ts +4 -2
  145. package/node_modules/discord-api-types/rest/v10/interactions.d.ts.map +1 -1
  146. package/node_modules/discord-api-types/rest/v10/user.d.ts +2 -2
  147. package/node_modules/discord-api-types/rest/v10/user.d.ts.map +1 -1
  148. package/node_modules/discord-api-types/rest/v9/applicationIdentityProfile.d.ts +70 -0
  149. package/node_modules/discord-api-types/rest/v9/applicationIdentityProfile.d.ts.map +1 -0
  150. package/node_modules/discord-api-types/rest/v9/applicationIdentityProfile.js +3 -0
  151. package/node_modules/discord-api-types/rest/v9/applicationIdentityProfile.js.map +1 -0
  152. package/node_modules/discord-api-types/rest/v9/index.d.ts +1 -0
  153. package/node_modules/discord-api-types/rest/v9/index.d.ts.map +1 -1
  154. package/node_modules/discord-api-types/rest/v9/index.js +29 -0
  155. package/node_modules/discord-api-types/rest/v9/index.js.map +1 -1
  156. package/node_modules/discord-api-types/rest/v9/interactions.d.ts +4 -2
  157. package/node_modules/discord-api-types/rest/v9/interactions.d.ts.map +1 -1
  158. package/node_modules/discord-api-types/rest/v9/user.d.ts +2 -2
  159. package/node_modules/discord-api-types/rest/v9/user.d.ts.map +1 -1
  160. package/node_modules/discord-api-types/v10.mjs +1 -0
  161. package/node_modules/discord-api-types/v9.mjs +1 -0
  162. package/node_modules/micromark/dev/lib/compile.d.ts.map +1 -1
  163. package/node_modules/micromark/dev/lib/compile.js +14 -4
  164. package/node_modules/micromark/dev/lib/create-tokenizer.d.ts.map +1 -1
  165. package/node_modules/micromark/dev/lib/create-tokenizer.js +7 -6
  166. package/node_modules/micromark/dev/lib/initialize/document.js +25 -21
  167. package/node_modules/micromark/dev/lib/initialize/text.d.ts.map +1 -1
  168. package/node_modules/micromark/dev/lib/initialize/text.js +10 -6
  169. package/node_modules/micromark/dev/lib/preprocess.d.ts.map +1 -1
  170. package/node_modules/micromark/dev/lib/preprocess.js +19 -21
  171. package/node_modules/micromark/lib/compile.d.ts.map +1 -1
  172. package/node_modules/micromark/lib/compile.js +37 -29
  173. package/node_modules/micromark/lib/create-tokenizer.d.ts.map +1 -1
  174. package/node_modules/micromark/lib/create-tokenizer.js +37 -35
  175. package/node_modules/micromark/lib/initialize/document.js +21 -13
  176. package/node_modules/micromark/lib/initialize/text.d.ts.map +1 -1
  177. package/node_modules/micromark/lib/initialize/text.js +7 -3
  178. package/node_modules/micromark/lib/preprocess.d.ts.map +1 -1
  179. package/node_modules/micromark/lib/preprocess.js +16 -19
  180. package/node_modules/micromark/package.json +2 -15
  181. package/node_modules/micromark-core-commonmark/dev/lib/attention.js +18 -24
  182. package/node_modules/micromark-core-commonmark/dev/lib/code-fenced.d.ts.map +1 -1
  183. package/node_modules/micromark-core-commonmark/dev/lib/code-fenced.js +1 -43
  184. package/node_modules/micromark-core-commonmark/dev/lib/code-indented.js +19 -43
  185. package/node_modules/micromark-core-commonmark/dev/lib/heading-atx.js +2 -6
  186. package/node_modules/micromark-core-commonmark/dev/lib/html-flow.d.ts.map +1 -1
  187. package/node_modules/micromark-core-commonmark/dev/lib/html-flow.js +2 -53
  188. package/node_modules/micromark-core-commonmark/dev/lib/label-end.js +14 -12
  189. package/node_modules/micromark-core-commonmark/dev/lib/label-start-image.d.ts.map +1 -1
  190. package/node_modules/micromark-core-commonmark/dev/lib/label-start-image.js +14 -5
  191. package/node_modules/micromark-core-commonmark/dev/lib/label-start-link.d.ts.map +1 -1
  192. package/node_modules/micromark-core-commonmark/dev/lib/label-start-link.js +14 -5
  193. package/node_modules/micromark-core-commonmark/dev/lib/partial-non-lazy-continuation.d.ts +4 -0
  194. package/node_modules/micromark-core-commonmark/dev/lib/partial-non-lazy-continuation.d.ts.map +1 -0
  195. package/node_modules/micromark-core-commonmark/dev/lib/partial-non-lazy-continuation.js +67 -0
  196. package/node_modules/micromark-core-commonmark/dev/lib/setext-underline.d.ts.map +1 -1
  197. package/node_modules/micromark-core-commonmark/dev/lib/setext-underline.js +8 -5
  198. package/node_modules/micromark-core-commonmark/lib/attention.js +14 -24
  199. package/node_modules/micromark-core-commonmark/lib/code-fenced.d.ts.map +1 -1
  200. package/node_modules/micromark-core-commonmark/lib/code-fenced.js +1 -39
  201. package/node_modules/micromark-core-commonmark/lib/code-indented.js +11 -29
  202. package/node_modules/micromark-core-commonmark/lib/heading-atx.js +2 -6
  203. package/node_modules/micromark-core-commonmark/lib/html-flow.d.ts.map +1 -1
  204. package/node_modules/micromark-core-commonmark/lib/html-flow.js +2 -51
  205. package/node_modules/micromark-core-commonmark/lib/label-end.js +11 -10
  206. package/node_modules/micromark-core-commonmark/lib/label-start-image.d.ts.map +1 -1
  207. package/node_modules/micromark-core-commonmark/lib/label-start-image.js +11 -3
  208. package/node_modules/micromark-core-commonmark/lib/label-start-link.d.ts.map +1 -1
  209. package/node_modules/micromark-core-commonmark/lib/label-start-link.js +11 -3
  210. package/node_modules/micromark-core-commonmark/lib/partial-non-lazy-continuation.d.ts +4 -0
  211. package/node_modules/micromark-core-commonmark/lib/partial-non-lazy-continuation.d.ts.map +1 -0
  212. package/node_modules/micromark-core-commonmark/lib/partial-non-lazy-continuation.js +61 -0
  213. package/node_modules/micromark-core-commonmark/lib/setext-underline.d.ts.map +1 -1
  214. package/node_modules/micromark-core-commonmark/lib/setext-underline.js +7 -5
  215. package/node_modules/micromark-core-commonmark/package.json +4 -16
  216. package/node_modules/micromark-factory-space/dev/index.d.ts +24 -1
  217. package/node_modules/micromark-factory-space/dev/index.d.ts.map +1 -1
  218. package/node_modules/micromark-factory-space/dev/index.js +58 -3
  219. package/node_modules/micromark-factory-space/index.d.ts +24 -1
  220. package/node_modules/micromark-factory-space/index.d.ts.map +1 -1
  221. package/node_modules/micromark-factory-space/index.js +55 -3
  222. package/node_modules/micromark-factory-space/package.json +1 -10
  223. package/node_modules/micromark-factory-space/readme.md +25 -25
  224. package/node_modules/micromark-util-edit-map/dev/index.d.ts +78 -0
  225. package/node_modules/micromark-util-edit-map/dev/index.d.ts.map +1 -0
  226. package/node_modules/micromark-util-edit-map/dev/index.js +237 -0
  227. package/node_modules/micromark-util-edit-map/index.d.ts +78 -0
  228. package/node_modules/micromark-util-edit-map/index.d.ts.map +1 -0
  229. package/node_modules/micromark-util-edit-map/index.js +225 -0
  230. package/node_modules/micromark-util-edit-map/license +22 -0
  231. package/node_modules/micromark-util-edit-map/package.json +48 -0
  232. package/node_modules/micromark-util-edit-map/readme.md +234 -0
  233. package/node_modules/micromark-util-types/index.d.ts +6 -3
  234. package/node_modules/micromark-util-types/package.json +2 -36
  235. package/node_modules/ws/lib/websocket.js +17 -3
  236. package/node_modules/ws/package.json +1 -1
  237. package/openclaw.plugin.json +3 -6
  238. package/package.json +7 -12
  239. package/dist/.setup/account-inspect-DsER5ILV.mjs +0 -45
  240. package/dist/.setup/provider.runtime-CZ51OIgD.mjs +0 -2
  241. package/dist/.setup/resolve-allowlist-common-BUyU3C-T.mjs +0 -27
  242. package/dist/.setup/resolve-channels-DA6QlhZN.mjs +0 -246
  243. package/dist/.setup/security-contract-DSHk7I2w.mjs +0 -26
  244. package/dist/.setup/setup-plugin-api-BVlCz3fm.mjs +0 -3
  245. package/dist/.setup/targets-bqXQENmX.mjs +0 -3
  246. package/dist/control-ui/2afbdab1d3aa65a789d8a3eba666f4b1ec5df07073538fe30d6cf32093a1fb2d/index.js +0 -1
@@ -1,15 +1,15 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.mjs";
2
- import { D as getDiscordEndpointRuntime, O as resolveDiscordEndpointAttachmentGuard, T as parseDiscordRetryAfterBodySeconds } from "./allow-list-vxkG9_JD.mjs";
3
- import { C as hasAnyChannelPermissionDiscord, D as createDiscordMessageNonce, I as resolveDiscordClientAccountContext, L as resolveDiscordRest, M as parseAndResolveChannelRecipient, N as createDiscordClient, O as resolveDiscordMessageFlags, R as DISCORD_REST_TIMEOUT_MS, S as hasAllGuildPermissionsDiscord, _ as canManageGuildMemberRoleDiscord, a as normalizeEmojiName, b as fetchChannelPermissionsDiscord, c as resolveChannelId, f as sendDiscordText, g as DiscordSendError, h as DISCORD_MAX_STICKER_BYTES, j as resolveDiscordSuppressEmbeds, m as DISCORD_MAX_EVENT_COVER_BYTES, n as buildDiscordTextChunks, o as normalizeReactionEmoji, p as DISCORD_MAX_EMOJI_BYTES, r as buildReactionIdentifier, t as buildDiscordSendError, v as canManageGuildRoleDiscord, w as hasAnyGuildPermissionDiscord, x as fetchMemberGuildPermissionsDiscord, y as canViewDiscordGuildChannel } from "./send.shared-C4CN24D9.mjs";
4
- import { C as withDiscordRequestAuthority, S as readRetryAfter, _ as DiscordError, _t as getGuildVoiceState, at as deleteOwnMessageReaction, b as readDiscordCode, ct as deleteChannelMessage, dt as getChannelMessage, gt as getGuildMember, ht as getGuild, it as createOwnMessageReaction, lt as editChannelMessage, mt as unpinChannelMessage, ot as listMessageReactionUsers, pt as pinChannelMessage, st as createThread, ut as getChannel, v as RateLimitError, vt as listGuildEmojis, x as readDiscordMessage, y as isUnknownDiscordVoiceStateError, yt as stripUndefinedFields } from "./discord-9gysrhzp.mjs";
5
- import { _ as createDiscordRetryRunner, a as createReusableDiscordReplyReference, b as chunkDiscordTextWithMode, g as classifyDiscordDeliveryFailure, n as createDiscordSendReceiptFromResults, o as resolveDiscordReplyMessageId, r as createDiscordSendResult, y as recordDiscordMessageCreateAmbiguity } from "./send.receipt-DVOg2Oaw.mjs";
6
- import { o as parseDiscordHttpErrorBody } from "./api-DlNUkDqj.mjs";
7
- import { i as prepareDiscordOutboundText, n as sendPollDiscord, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-rOboMO_6.mjs";
8
- import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS } from "./timeouts-pun7VJ02.mjs";
2
+ import { D as getDiscordEndpointRuntime, O as resolveDiscordEndpointAttachmentGuard, T as parseDiscordRetryAfterBodySeconds } from "./allow-list-B_ToXtew.mjs";
3
+ import { C as hasAnyChannelPermissionDiscord, D as createDiscordMessageNonce, I as resolveDiscordClientAccountContext, L as resolveDiscordRest, M as parseAndResolveChannelRecipient, N as createDiscordClient, O as resolveDiscordMessageFlags, R as DISCORD_REST_TIMEOUT_MS, S as hasAllGuildPermissionsDiscord, _ as canManageGuildMemberRoleDiscord, a as normalizeEmojiName, b as fetchChannelPermissionsDiscord, c as resolveChannelId, d as sendDiscordChunks, g as DiscordSendError, h as DISCORD_MAX_STICKER_BYTES, j as resolveDiscordSuppressEmbeds, m as DISCORD_MAX_EVENT_COVER_BYTES, n as buildDiscordTextChunks, o as normalizeReactionEmoji, p as DISCORD_MAX_EMOJI_BYTES, r as buildReactionIdentifier, t as buildDiscordSendError, v as canManageGuildRoleDiscord, w as hasAnyGuildPermissionDiscord, x as fetchMemberGuildPermissionsDiscord, y as canViewDiscordGuildChannel } from "./send.shared-CjQ4jbMA.mjs";
4
+ import { B as readDiscordCode, H as readRetryAfter, L as DiscordError, R as RateLimitError, V as readDiscordMessage, W as withDiscordRequestAuthority, _t as getGuildMember, at as deleteOwnMessageReaction, bt as stripUndefinedFields, ct as createThread, dt as getChannel, ft as getChannelMessage, gt as getGuild, ht as unpinChannelMessage, it as createOwnMessageReaction, lt as deleteChannelMessage, mt as pinChannelMessage, ot as listMessageReactionUsers, ut as editChannelMessage, vt as getGuildVoiceState, yt as listGuildEmojis, z as isUnknownDiscordVoiceStateError } from "./discord-BGqgx-yd.mjs";
5
+ import { _ as recordDiscordMessageCreateAmbiguity, a as createReusableDiscordReplyReference, h as createDiscordRetryRunner, m as classifyDiscordDeliveryFailure, n as createDiscordSendReceiptFromResults, o as resolveDiscordReplyMessageId, r as createDiscordSendResult, v as chunkDiscordTextWithMode } from "./send.receipt-BAlzXd8e.mjs";
6
+ import { o as parseDiscordHttpErrorBody } from "./api-CtmE1OUN.mjs";
7
+ import { i as prepareDiscordOutboundText, n as sendPollDiscord, r as sendStickerDiscord, t as sendMessageDiscord } from "./send.outbound-_jx4Xpd3.mjs";
8
+ import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS } from "./timeouts-CuNARfyw.mjs";
9
9
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
10
10
  import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
11
11
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
12
- import { ChannelType, Routes } from "discord-api-types/v10";
12
+ import { ChannelType, MessageFlags, Routes } from "discord-api-types/v10";
13
13
  import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS, buildOutboundMediaLoadOptions, extensionForMime, maxBytesForKind, parseFfprobeCodecAndSampleRate, runFfmpeg, runFfprobe, unlinkIfExists } from "openclaw/plugin-sdk/media-runtime";
14
14
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
15
15
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
@@ -92,25 +92,33 @@ async function removeChannelPermissionDiscord(channelId, targetId, opts) {
92
92
  }
93
93
  //#endregion
94
94
  //#region extensions/discord/src/send.emojis-stickers.ts
95
+ const DISCORD_IMAGE_UPLOAD_TYPES = [
96
+ "image/png",
97
+ "image/jpeg",
98
+ "image/jpg",
99
+ "image/gif"
100
+ ];
101
+ async function loadDiscordMediaForUpload(mediaUrl, opts, maxBytes, contentTypes, invalidType) {
102
+ const media = await loadWebMediaRaw(mediaUrl, buildOutboundMediaLoadOptions({
103
+ maxBytes,
104
+ mediaAccess: opts?.mediaAccess,
105
+ mediaLocalRoots: opts?.mediaLocalRoots,
106
+ mediaReadFile: opts?.mediaReadFile
107
+ }));
108
+ const contentType = normalizeOptionalLowercaseString(media.contentType);
109
+ if (!contentType || !contentTypes.includes(contentType)) throw new Error(invalidType(contentType));
110
+ return {
111
+ media,
112
+ contentType
113
+ };
114
+ }
95
115
  async function listGuildEmojisDiscord(guildId, opts) {
96
116
  const rest = resolveDiscordRest(opts);
97
117
  return await listGuildEmojis(rest, guildId);
98
118
  }
99
119
  async function uploadEmojiDiscord(payload, opts) {
100
120
  const rest = resolveDiscordRest(opts);
101
- const media = await loadWebMediaRaw(payload.mediaUrl, buildOutboundMediaLoadOptions({
102
- maxBytes: DISCORD_MAX_EMOJI_BYTES,
103
- mediaAccess: opts.mediaAccess,
104
- mediaLocalRoots: opts.mediaLocalRoots,
105
- mediaReadFile: opts.mediaReadFile
106
- }));
107
- const contentType = normalizeOptionalLowercaseString(media.contentType);
108
- if (!contentType || ![
109
- "image/png",
110
- "image/jpeg",
111
- "image/jpg",
112
- "image/gif"
113
- ].includes(contentType)) throw new Error("Discord emoji uploads require a PNG, JPG, or GIF image");
121
+ const { media, contentType } = await loadDiscordMediaForUpload(payload.mediaUrl, opts, DISCORD_MAX_EMOJI_BYTES, DISCORD_IMAGE_UPLOAD_TYPES, () => "Discord emoji uploads require a PNG, JPG, or GIF image");
114
122
  const image = `data:${contentType};base64,${media.buffer.toString("base64")}`;
115
123
  const roleIds = normalizeStringEntries(payload.roleIds ?? []);
116
124
  return await rest.post(Routes.guildEmojis(payload.guildId), { body: {
@@ -121,18 +129,11 @@ async function uploadEmojiDiscord(payload, opts) {
121
129
  }
122
130
  async function uploadStickerDiscord(payload, opts) {
123
131
  const rest = resolveDiscordRest(opts);
124
- const media = await loadWebMediaRaw(payload.mediaUrl, buildOutboundMediaLoadOptions({
125
- maxBytes: DISCORD_MAX_STICKER_BYTES,
126
- mediaAccess: opts.mediaAccess,
127
- mediaLocalRoots: opts.mediaLocalRoots,
128
- mediaReadFile: opts.mediaReadFile
129
- }));
130
- const contentType = normalizeOptionalLowercaseString(media.contentType);
131
- if (!contentType || ![
132
+ const { media, contentType } = await loadDiscordMediaForUpload(payload.mediaUrl, opts, DISCORD_MAX_STICKER_BYTES, [
132
133
  "image/png",
133
134
  "image/apng",
134
135
  "application/json"
135
- ].includes(contentType)) throw new Error("Discord sticker uploads require a PNG, APNG, or Lottie JSON file");
136
+ ], () => "Discord sticker uploads require a PNG, APNG, or Lottie JSON file");
136
137
  return await rest.post(Routes.guildStickers(payload.guildId), {
137
138
  multipartStyle: "form",
138
139
  body: {
@@ -150,32 +151,32 @@ async function uploadStickerDiscord(payload, opts) {
150
151
  }
151
152
  //#endregion
152
153
  //#region extensions/discord/src/send.guild.ts
153
- async function fetchMemberInfoDiscord(guildId, userId, opts) {
154
- const rest = resolveDiscordRest(opts);
155
- return await getGuildMember(rest, guildId, userId);
154
+ function readDiscordResource(read) {
155
+ return async (id, opts) => await read(resolveDiscordRest(opts), id);
156
156
  }
157
- async function fetchRoleInfoDiscord(guildId, opts) {
158
- return await resolveDiscordRest(opts).get(Routes.guildRoles(guildId));
159
- }
160
- async function addRoleDiscord(payload, opts) {
161
- await resolveDiscordRest(opts).put(Routes.guildMemberRole(payload.guildId, payload.userId, payload.roleId));
162
- return { ok: true };
163
- }
164
- async function removeRoleDiscord(payload, opts) {
165
- await resolveDiscordRest(opts).delete(Routes.guildMemberRole(payload.guildId, payload.userId, payload.roleId));
166
- return { ok: true };
167
- }
168
- async function fetchChannelInfoDiscord(channelId, opts) {
169
- const rest = resolveDiscordRest(opts);
170
- return await getChannel(rest, channelId);
157
+ function auditReasonHeaders(reason) {
158
+ return reason ? { "X-Audit-Log-Reason": encodeURIComponent(reason) } : void 0;
171
159
  }
172
- async function fetchGuildInfoDiscord(guildId, opts) {
160
+ async function fetchMemberInfoDiscord(guildId, userId, opts) {
173
161
  const rest = resolveDiscordRest(opts);
174
- return await getGuild(rest, guildId);
162
+ return await getGuildMember(rest, guildId, userId);
175
163
  }
176
- async function listGuildChannelsDiscord(guildId, opts) {
177
- return await resolveDiscordRest(opts).get(Routes.guildChannels(guildId));
164
+ const fetchRoleInfoDiscord = readDiscordResource(async (rest, guildId) => {
165
+ return await rest.get(Routes.guildRoles(guildId));
166
+ });
167
+ function roleMutation(method) {
168
+ return async (payload, opts) => {
169
+ await resolveDiscordRest(opts)[method](Routes.guildMemberRole(payload.guildId, payload.userId, payload.roleId));
170
+ return { ok: true };
171
+ };
178
172
  }
173
+ const addRoleDiscord = roleMutation("put");
174
+ const removeRoleDiscord = roleMutation("delete");
175
+ const fetchChannelInfoDiscord = readDiscordResource(getChannel);
176
+ const fetchGuildInfoDiscord = readDiscordResource(getGuild);
177
+ const listGuildChannelsDiscord = readDiscordResource(async (rest, guildId) => {
178
+ return await rest.get(Routes.guildChannels(guildId));
179
+ });
179
180
  async function fetchVoiceStatusDiscord(guildId, userId, opts) {
180
181
  const rest = resolveDiscordRest(opts);
181
182
  try {
@@ -192,24 +193,11 @@ async function fetchVoiceStatusDiscord(guildId, userId, opts) {
192
193
  };
193
194
  }
194
195
  }
195
- async function listScheduledEventsDiscord(guildId, opts) {
196
- return await resolveDiscordRest(opts).get(Routes.guildScheduledEvents(guildId));
197
- }
198
- const ALLOWED_EVENT_COVER_TYPES = /* @__PURE__ */ new Set([
199
- "image/png",
200
- "image/jpeg",
201
- "image/jpg",
202
- "image/gif"
203
- ]);
196
+ const listScheduledEventsDiscord = readDiscordResource(async (rest, guildId) => {
197
+ return await rest.get(Routes.guildScheduledEvents(guildId));
198
+ });
204
199
  async function resolveEventCoverImage(imageUrl, opts) {
205
- const media = await loadWebMediaRaw(imageUrl, buildOutboundMediaLoadOptions({
206
- maxBytes: DISCORD_MAX_EVENT_COVER_BYTES,
207
- mediaAccess: opts?.mediaAccess,
208
- mediaLocalRoots: opts?.mediaLocalRoots,
209
- mediaReadFile: opts?.mediaReadFile
210
- }));
211
- const contentType = normalizeOptionalLowercaseString(media.contentType);
212
- if (!contentType || !ALLOWED_EVENT_COVER_TYPES.has(contentType)) throw new Error(`Discord event cover images must be PNG, JPG, or GIF (got ${contentType ?? "unknown"})`);
200
+ const { media, contentType } = await loadDiscordMediaForUpload(imageUrl, opts, DISCORD_MAX_EVENT_COVER_BYTES, DISCORD_IMAGE_UPLOAD_TYPES, (actualType) => `Discord event cover images must be PNG, JPG, or GIF (got ${actualType ?? "unknown"})`);
213
201
  return `data:${contentType};base64,${media.buffer.toString("base64")}`;
214
202
  }
215
203
  async function createScheduledEventDiscord(guildId, payload, opts) {
@@ -225,11 +213,11 @@ async function timeoutMemberDiscord(payload, opts) {
225
213
  }
226
214
  return await rest.patch(Routes.guildMember(payload.guildId, payload.userId), {
227
215
  body: { communication_disabled_until: until ?? null },
228
- headers: payload.reason ? { "X-Audit-Log-Reason": encodeURIComponent(payload.reason) } : void 0
216
+ headers: auditReasonHeaders(payload.reason)
229
217
  });
230
218
  }
231
219
  async function kickMemberDiscord(payload, opts) {
232
- await resolveDiscordRest(opts).delete(Routes.guildMember(payload.guildId, payload.userId), { headers: payload.reason ? { "X-Audit-Log-Reason": encodeURIComponent(payload.reason) } : void 0 });
220
+ await resolveDiscordRest(opts).delete(Routes.guildMember(payload.guildId, payload.userId), { headers: auditReasonHeaders(payload.reason) });
233
221
  return { ok: true };
234
222
  }
235
223
  async function banMemberDiscord(payload, opts) {
@@ -237,7 +225,7 @@ async function banMemberDiscord(payload, opts) {
237
225
  const deleteMessageDays = typeof payload.deleteMessageDays === "number" && Number.isFinite(payload.deleteMessageDays) ? Math.min(Math.max(Math.floor(payload.deleteMessageDays), 0), 7) : void 0;
238
226
  await rest.put(Routes.guildBan(payload.guildId, payload.userId), {
239
227
  body: deleteMessageDays !== void 0 ? { delete_message_days: deleteMessageDays } : void 0,
240
- headers: payload.reason ? { "X-Audit-Log-Reason": encodeURIComponent(payload.reason) } : void 0
228
+ headers: auditReasonHeaders(payload.reason)
241
229
  });
242
230
  return { ok: true };
243
231
  }
@@ -257,10 +245,6 @@ function assertDiscordResponseObject(value, label) {
257
245
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`Unexpected Discord response for ${label}: expected object.`);
258
246
  return value;
259
247
  }
260
- function resolveDefaultThreadAutoArchiveDuration(channel) {
261
- if (!channel || !("default_auto_archive_duration" in channel)) return;
262
- return channel.default_auto_archive_duration;
263
- }
264
248
  function describeDiscordThreadInitialMessageFailure(delivery) {
265
249
  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";
266
250
  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";
@@ -286,9 +270,14 @@ async function readMessagesDiscord(channelId, query, opts) {
286
270
  const limit = typeof messageQuery.limit === "number" && Number.isFinite(messageQuery.limit) ? Math.min(Math.max(Math.floor(messageQuery.limit), 1), 100) : void 0;
287
271
  const params = {};
288
272
  if (limit) params.limit = limit;
289
- if (messageQuery.before) params.before = messageQuery.before;
290
- if (messageQuery.after) params.after = messageQuery.after;
291
- if (messageQuery.around) params.around = messageQuery.around;
273
+ for (const key of [
274
+ "before",
275
+ "after",
276
+ "around"
277
+ ]) {
278
+ const value = messageQuery[key];
279
+ if (value) params[key] = value;
280
+ }
292
281
  return assertDiscordResponseArray(await rest.get(Routes.channelMessages(channelId), params), "message read");
293
282
  }
294
283
  async function fetchMessageDiscord(channelId, messageId, opts) {
@@ -303,21 +292,15 @@ async function editMessageDiscord(channelId, messageId, payload, opts) {
303
292
  ...payload.allowedMentions ? { allowed_mentions: payload.allowedMentions } : {}
304
293
  } });
305
294
  }
306
- async function deleteMessageDiscord(channelId, messageId, opts) {
307
- const rest = resolveDiscordRest(opts);
308
- await deleteChannelMessage(rest, channelId, messageId);
309
- return { ok: true };
310
- }
311
- async function pinMessageDiscord(channelId, messageId, opts) {
312
- const rest = resolveDiscordRest(opts);
313
- await pinChannelMessage(rest, channelId, messageId);
314
- return { ok: true };
315
- }
316
- async function unpinMessageDiscord(channelId, messageId, opts) {
317
- const rest = resolveDiscordRest(opts);
318
- await unpinChannelMessage(rest, channelId, messageId);
319
- return { ok: true };
295
+ function messageMutation(operation) {
296
+ return async (channelId, messageId, opts) => {
297
+ await operation(resolveDiscordRest(opts), channelId, messageId);
298
+ return { ok: true };
299
+ };
320
300
  }
301
+ const deleteMessageDiscord = messageMutation(deleteChannelMessage);
302
+ const pinMessageDiscord = messageMutation(pinChannelMessage);
303
+ const unpinMessageDiscord = messageMutation(unpinChannelMessage);
321
304
  async function listPinsDiscord(channelId, opts) {
322
305
  return await resolveDiscordRest(opts).get(Routes.channelPins(channelId));
323
306
  }
@@ -327,10 +310,8 @@ async function createThreadDiscord(channelId, payload, opts) {
327
310
  const body = { name: payload.name };
328
311
  if (!payload.messageId && payload.type !== void 0) body.type = payload.type;
329
312
  let channel;
330
- if (!payload.messageId) try {
331
- channel = await getChannel(rest, channelId);
332
- } catch {}
333
- const archiveDuration = payload.autoArchiveMinutes ?? resolveDefaultThreadAutoArchiveDuration(channel);
313
+ if (!payload.messageId) channel = await getChannel(rest, channelId).catch(() => void 0);
314
+ const archiveDuration = payload.autoArchiveMinutes ?? (channel && "default_auto_archive_duration" in channel ? channel.default_auto_archive_duration : void 0);
334
315
  if (archiveDuration !== void 0) body.auto_archive_duration = archiveDuration;
335
316
  const isForumLike = channel?.type === ChannelType.GuildForum || channel?.type === ChannelType.GuildMedia;
336
317
  const initialMessageContent = payload.content?.trim() ? payload.content : isForumLike ? payload.name : "";
@@ -360,7 +341,7 @@ async function createThreadDiscord(channelId, payload, opts) {
360
341
  }
361
342
  }, label, options);
362
343
  try {
363
- const result = await sendDiscordText({
344
+ const result = await sendDiscordChunks({
364
345
  rest,
365
346
  request: trackedRequest,
366
347
  channelId: thread.id,
@@ -554,7 +535,6 @@ async function sendWebhookMessageDiscord(text, opts) {
554
535
  }
555
536
  //#endregion
556
537
  //#region extensions/discord/src/voice-message.ts
557
- const DISCORD_VOICE_MESSAGE_FLAG = 8192;
558
538
  const WAVEFORM_SAMPLES = 256;
559
539
  const DISCORD_OPUS_SAMPLE_RATE_HZ = 48e3;
560
540
  const DISCORD_VOICE_ERROR_BODY_LIMIT_BYTES = 8192;
@@ -562,14 +542,25 @@ const DISCORD_VOICE_UPLOAD_SSRF_POLICY = {
562
542
  allowRfc2544BenchmarkRange: true,
563
543
  allowIpv6UniqueLocalRange: true
564
544
  };
565
- async function runFfmpegToOutput(params) {
566
- const rootDir = path.dirname(params.outputPath);
545
+ async function runFfmpegToOutput(inputPath, outputPath, outputArgs) {
546
+ const rootDir = path.dirname(outputPath);
567
547
  await fs.mkdir(rootDir, { recursive: true });
568
548
  await writeExternalFileWithinRoot({
569
549
  rootDir,
570
- path: path.basename(params.outputPath),
550
+ path: path.basename(outputPath),
571
551
  write: async (tempPath) => {
572
- await runFfmpeg(params.buildArgs(tempPath));
552
+ await runFfmpeg([
553
+ "-y",
554
+ "-i",
555
+ inputPath,
556
+ "-vn",
557
+ "-sn",
558
+ "-dn",
559
+ "-t",
560
+ String(MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS),
561
+ ...outputArgs,
562
+ tempPath
563
+ ]);
573
564
  }
574
565
  });
575
566
  }
@@ -592,51 +583,29 @@ async function getAudioDuration(filePath) {
592
583
  throw new Error(`Failed to get audio duration: ${errMessage}`, { cause: err });
593
584
  }
594
585
  }
595
- async function generateWaveform(filePath) {
596
- try {
597
- return await generateWaveformFromPcm(filePath);
598
- } catch {
599
- return generatePlaceholderWaveform();
600
- }
601
- }
602
586
  async function generateWaveformFromPcm(filePath) {
603
587
  const tempDir = resolvePreferredOpenClawTmpDir();
604
588
  const tempPcm = path.join(tempDir, `waveform-${crypto.randomUUID()}.raw`);
605
589
  try {
606
- await runFfmpegToOutput({
607
- outputPath: tempPcm,
608
- buildArgs: (outputPath) => [
609
- "-y",
610
- "-i",
611
- filePath,
612
- "-vn",
613
- "-sn",
614
- "-dn",
615
- "-t",
616
- String(MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS),
617
- "-f",
618
- "s16le",
619
- "-acodec",
620
- "pcm_s16le",
621
- "-ac",
622
- "1",
623
- "-ar",
624
- "8000",
625
- outputPath
626
- ]
627
- });
590
+ await runFfmpegToOutput(filePath, tempPcm, [
591
+ "-f",
592
+ "s16le",
593
+ "-acodec",
594
+ "pcm_s16le",
595
+ "-ac",
596
+ "1",
597
+ "-ar",
598
+ "8000"
599
+ ]);
628
600
  const pcmData = await fs.readFile(tempPcm);
629
601
  const samples = new Int16Array(pcmData.buffer, pcmData.byteOffset, pcmData.byteLength / 2);
630
602
  const step = Math.max(1, Math.floor(samples.length / WAVEFORM_SAMPLES));
631
603
  const waveform = Buffer.alloc(WAVEFORM_SAMPLES);
632
604
  for (let i = 0; i < WAVEFORM_SAMPLES && i * step < samples.length; i++) {
633
605
  let sum = 0;
634
- let count = 0;
635
- for (let j = 0; j < step && i * step + j < samples.length; j++) {
636
- sum += Math.abs(expectDefined(samples.at(i * step + j), "bounded PCM waveform sample"));
637
- count++;
638
- }
639
- const avg = count > 0 ? sum / count : 0;
606
+ const count = Math.min(step, samples.length - i * step);
607
+ for (let j = 0; j < count; j++) sum += Math.abs(expectDefined(samples.at(i * step + j), "bounded PCM waveform sample"));
608
+ const avg = sum / count;
640
609
  const normalized = Math.min(255, Math.round(avg / 32767 * 255));
641
610
  waveform[i] = normalized;
642
611
  }
@@ -680,28 +649,16 @@ async function ensureOggOpus(filePath) {
680
649
  } catch {}
681
650
  const tempDir = resolvePreferredOpenClawTmpDir();
682
651
  const outputPath = path.join(tempDir, `voice-${crypto.randomUUID()}.ogg`);
683
- await runFfmpegToOutput({
684
- outputPath,
685
- buildArgs: (tempPath) => [
686
- "-y",
687
- "-i",
688
- filePath,
689
- "-vn",
690
- "-sn",
691
- "-dn",
692
- "-t",
693
- String(MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS),
694
- "-ar",
695
- String(DISCORD_OPUS_SAMPLE_RATE_HZ),
696
- "-c:a",
697
- "libopus",
698
- "-b:a",
699
- "64k",
700
- "-f",
701
- "ogg",
702
- tempPath
703
- ]
704
- });
652
+ await runFfmpegToOutput(filePath, outputPath, [
653
+ "-ar",
654
+ String(DISCORD_OPUS_SAMPLE_RATE_HZ),
655
+ "-c:a",
656
+ "libopus",
657
+ "-b:a",
658
+ "64k",
659
+ "-f",
660
+ "ogg"
661
+ ]);
705
662
  return {
706
663
  path: outputPath,
707
664
  cleanup: true
@@ -711,7 +668,7 @@ async function ensureOggOpus(filePath) {
711
668
  * Wait for waveform cleanup before callers can release the audio input.
712
669
  */
713
670
  async function getVoiceMessageMetadata(filePath) {
714
- const waveform = generateWaveform(filePath);
671
+ const waveform = generateWaveformFromPcm(filePath).catch(generatePlaceholderWaveform);
715
672
  try {
716
673
  return {
717
674
  durationSecs: await getAudioDuration(filePath),
@@ -794,14 +751,13 @@ async function sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, r
794
751
  const filename = "voice-message.ogg";
795
752
  const fileSize = audioBuffer.byteLength;
796
753
  const endpointRuntime = getDiscordEndpointRuntime() ?? null;
797
- const botToken = token;
798
- if (!botToken) throw new Error("Discord bot token is required for voice message upload");
754
+ if (!token) throw new Error("Discord bot token is required for voice message upload");
799
755
  const { upload_filename } = await request(async () => {
800
756
  const uploadUrlResponse = await requestVoiceUploadUrl({
801
757
  rest,
802
758
  endpointRuntime,
803
759
  channelId,
804
- botToken,
760
+ botToken: token,
805
761
  filename,
806
762
  fileSize
807
763
  });
@@ -815,7 +771,7 @@ async function sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, r
815
771
  return attachment;
816
772
  }, "voice-upload");
817
773
  const messagePayload = {
818
- flags: silent ? 12288 : DISCORD_VOICE_MESSAGE_FLAG,
774
+ flags: MessageFlags.IsVoiceMessage | (silent ? MessageFlags.SuppressNotifications : 0),
819
775
  nonce: createDiscordMessageNonce(),
820
776
  enforce_nonce: true,
821
777
  attachments: [{
@@ -849,73 +805,63 @@ async function sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, r
849
805
  }
850
806
  //#endregion
851
807
  //#region extensions/discord/src/send.voice.ts
852
- async function withMaterializedVoiceMessageInput(mediaUrl, opts, run) {
853
- const media = await loadWebMediaRaw(mediaUrl, buildOutboundMediaLoadOptions({
854
- maxBytes: maxBytesForKind("audio"),
855
- mediaAccess: opts.mediaAccess,
856
- mediaLocalRoots: opts.mediaLocalRoots,
857
- mediaReadFile: opts.mediaReadFile
858
- }));
859
- const extFromName = media.fileName ? path.extname(media.fileName) : "";
860
- const extFromMime = media.contentType ? extensionForMime(media.contentType) : "";
861
- const ext = extFromName || extFromMime || ".bin";
862
- return await withTempWorkspace({
863
- rootDir: resolvePreferredOpenClawTmpDir(),
864
- prefix: "voice-src-"
865
- }, async (workspace) => await run(await workspace.write(`input${ext}`, media.buffer)));
866
- }
867
808
  /** Discord voice messages require OGG/Opus audio with a waveform and cannot include text. */
868
809
  async function sendVoiceMessageDiscord(to, audioPath, opts) {
869
- return await withDiscordRequestAuthority(opts.assertPlatformSendAuthorized, () => sendVoiceMessageDiscordInternal(to, audioPath, opts));
870
- }
871
- async function sendVoiceMessageDiscordInternal(to, audioPath, opts) {
872
- const cfg = requireRuntimeConfig(opts.cfg, "Discord voice send");
873
- return await withMaterializedVoiceMessageInput(audioPath, opts, async (localInputPath) => {
874
- let oggPath = null;
875
- let oggCleanup = false;
876
- let token;
877
- let rest;
878
- let channelId;
879
- try {
880
- const client = createDiscordClient({
881
- ...opts,
882
- cfg
883
- });
884
- token = client.token;
885
- rest = client.rest;
886
- const request = client.request;
887
- const accountInfo = client.account;
888
- const recipient = await parseAndResolveChannelRecipient(to, cfg, accountInfo.accountId);
889
- channelId = (await resolveChannelId(rest, recipient, request)).channelId;
890
- const ogg = await ensureOggOpus(localInputPath);
891
- oggPath = ogg.path;
892
- oggCleanup = ogg.cleanup;
893
- const metadata = await getVoiceMessageMetadata(oggPath);
894
- const audioBuffer = await fs.readFile(oggPath);
895
- const result = await sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, opts.reply?.messageId, request, opts.silent, token, opts.onPlatformSendDispatch, opts.assertPlatformSendAuthorized);
896
- recordChannelActivity({
897
- channel: "discord",
898
- accountId: accountInfo.accountId,
899
- direction: "outbound"
900
- });
901
- return createDiscordSendResult({
902
- result,
903
- fallbackChannelId: channelId,
904
- kind: "voice",
905
- reply: opts.reply
906
- });
907
- } catch (err) {
908
- if (channelId && rest && token) throw await buildDiscordSendError(err, {
909
- channelId,
910
- cfg,
911
- rest,
912
- token,
913
- hasMedia: true
914
- });
915
- throw err;
916
- } finally {
917
- await unlinkIfExists(oggCleanup ? oggPath : null);
918
- }
810
+ return await withDiscordRequestAuthority(opts.assertPlatformSendAuthorized, async () => {
811
+ const cfg = requireRuntimeConfig(opts.cfg, "Discord voice send");
812
+ const media = await loadWebMediaRaw(audioPath, buildOutboundMediaLoadOptions({
813
+ maxBytes: maxBytesForKind("audio"),
814
+ mediaAccess: opts.mediaAccess,
815
+ mediaLocalRoots: opts.mediaLocalRoots,
816
+ mediaReadFile: opts.mediaReadFile
817
+ }));
818
+ const extFromName = media.fileName ? path.extname(media.fileName) : "";
819
+ const extFromMime = media.contentType ? extensionForMime(media.contentType) : "";
820
+ const ext = extFromName || extFromMime || ".bin";
821
+ return await withTempWorkspace({
822
+ rootDir: resolvePreferredOpenClawTmpDir(),
823
+ prefix: "voice-src-"
824
+ }, async (workspace) => {
825
+ const localInputPath = await workspace.write(`input${ext}`, media.buffer);
826
+ let ogg;
827
+ let client;
828
+ let channelId;
829
+ try {
830
+ client = createDiscordClient({
831
+ ...opts,
832
+ cfg
833
+ });
834
+ const { token, rest, request, account: accountInfo } = client;
835
+ const recipient = await parseAndResolveChannelRecipient(to, cfg, accountInfo.accountId);
836
+ channelId = (await resolveChannelId(rest, recipient, request)).channelId;
837
+ ogg = await ensureOggOpus(localInputPath);
838
+ const metadata = await getVoiceMessageMetadata(ogg.path);
839
+ const audioBuffer = await fs.readFile(ogg.path);
840
+ const result = await sendDiscordVoiceMessage(rest, channelId, audioBuffer, metadata, opts.reply?.messageId, request, opts.silent, token, opts.onPlatformSendDispatch, opts.assertPlatformSendAuthorized);
841
+ recordChannelActivity({
842
+ channel: "discord",
843
+ accountId: accountInfo.accountId,
844
+ direction: "outbound"
845
+ });
846
+ return createDiscordSendResult({
847
+ result,
848
+ fallbackChannelId: channelId,
849
+ kind: "voice",
850
+ reply: opts.reply
851
+ });
852
+ } catch (err) {
853
+ if (channelId && client?.rest && client.token) throw await buildDiscordSendError(err, {
854
+ channelId,
855
+ cfg,
856
+ rest: client.rest,
857
+ token: client.token,
858
+ hasMedia: true
859
+ });
860
+ throw err;
861
+ } finally {
862
+ await unlinkIfExists(ogg?.cleanup ? ogg.path : null);
863
+ }
864
+ });
919
865
  });
920
866
  }
921
867
  //#endregion
@@ -937,18 +883,16 @@ function resolveDiscordReactionClient(opts) {
937
883
  cfg
938
884
  });
939
885
  }
940
- async function reactMessageDiscord(channelId, messageId, emoji, opts) {
941
- const { rest, request } = resolveDiscordReactionClient(opts);
942
- const encoded = normalizeReactionEmoji(emoji);
943
- await request(() => createOwnMessageReaction(rest, channelId, messageId, encoded), "react");
944
- return { ok: true };
945
- }
946
- async function removeReactionDiscord(channelId, messageId, emoji, opts) {
947
- const { rest, request } = resolveDiscordReactionClient(opts);
948
- const encoded = normalizeReactionEmoji(emoji);
949
- await request(() => deleteOwnMessageReaction(rest, channelId, messageId, encoded), "reaction-remove");
950
- return { ok: true };
886
+ function reactionMutation(operation, label) {
887
+ return async (channelId, messageId, emoji, opts) => {
888
+ const { rest, request } = resolveDiscordReactionClient(opts);
889
+ const encoded = normalizeReactionEmoji(emoji);
890
+ await request(() => operation(rest, channelId, messageId, encoded), label);
891
+ return { ok: true };
892
+ };
951
893
  }
894
+ const reactMessageDiscord = reactionMutation(createOwnMessageReaction, "react");
895
+ const removeReactionDiscord = reactionMutation(deleteOwnMessageReaction, "reaction-remove");
952
896
  async function removeOwnReactionsDiscord(channelId, messageId, opts) {
953
897
  const { rest, request } = resolveDiscordReactionClient(opts);
954
898
  const message = await request(() => getChannelMessage(rest, channelId, messageId), "reaction-list");
@@ -971,7 +915,6 @@ async function removeOwnReactionsDiscord(channelId, messageId, opts) {
971
915
  async function fetchReactionsDiscord(channelId, messageId, opts) {
972
916
  const { rest, request } = resolveDiscordReactionClient(opts);
973
917
  const reactions = (await request(() => getChannelMessage(rest, channelId, messageId), "reaction-list")).reactions ?? [];
974
- if (reactions.length === 0) return [];
975
918
  const limit = typeof opts.limit === "number" && Number.isFinite(opts.limit) ? Math.min(Math.max(Math.floor(opts.limit), 1), 100) : 100;
976
919
  const summaries = [];
977
920
  for (const reaction of reactions) {