@kodelyth/discord 2026.5.39 → 2026.5.42

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 (639) hide show
  1. package/account-inspect-api.ts +6 -0
  2. package/action-runtime-api.ts +1 -0
  3. package/api.ts +130 -0
  4. package/channel-config-api.ts +1 -0
  5. package/channel-plugin-api.ts +3 -0
  6. package/config-api.ts +4 -0
  7. package/configured-state.ts +6 -0
  8. package/contract-api.ts +21 -0
  9. package/directory-contract-api.ts +4 -0
  10. package/dist/account-inspect-Dqw-enky.js +81 -0
  11. package/dist/account-inspect-api.js +10 -0
  12. package/dist/accounts-B7OBFePq.js +224 -0
  13. package/dist/action-runtime-api.js +2 -0
  14. package/dist/agent-components.runtime-DVY_1VB4.js +4 -0
  15. package/dist/allow-list-B0s7evD7.js +354 -0
  16. package/dist/api-CXAcv9nZ.js +130 -0
  17. package/dist/api.js +23 -0
  18. package/dist/approval-handler.runtime-B9xUAF3n.js +426 -0
  19. package/dist/audit-DoiK49WO.js +24 -0
  20. package/dist/audit-core-BGrq3G7r.js +105 -0
  21. package/dist/channel-U_aeoFwW.js +795 -0
  22. package/dist/channel-actions-BxEBnEuv.js +173 -0
  23. package/dist/channel-actions.runtime-CPtpH-yl.js +263 -0
  24. package/dist/channel-api-BfjklLby.js +21 -0
  25. package/dist/channel-config-api.js +2 -0
  26. package/dist/channel-plugin-api.js +2 -0
  27. package/dist/channel.setup-BUSC0apv.js +337 -0
  28. package/dist/components-luonoe13.js +909 -0
  29. package/dist/config-api-DSYGqaLQ.js +2 -0
  30. package/dist/config-schema-DIqJBGwC.js +357 -0
  31. package/dist/configured-state.js +6 -0
  32. package/dist/contract-api.js +8 -0
  33. package/dist/conversation-identity-DXAm0_Mk.js +270 -0
  34. package/dist/directory-config-CYbuMmPS.js +49 -0
  35. package/dist/directory-contract-api.js +2 -0
  36. package/dist/directory-live-DX4dLRpJ.js +159 -0
  37. package/dist/doctor-bbKSvGVD.js +244 -0
  38. package/dist/doctor-contract-Btjt6NJD.js +383 -0
  39. package/dist/doctor-contract-api.js +2 -0
  40. package/dist/gateway-registry-BKSpa4GB.js +74 -0
  41. package/dist/handle-action.guild-admin-B5BArS2n.js +286 -0
  42. package/dist/inbound-context-WAOqhGlT.js +48 -0
  43. package/dist/inbound-event-delivery-C-1Ji3WP.js +65 -0
  44. package/dist/index.js +26 -0
  45. package/dist/manager.runtime-DXHynKE4.js +2356 -0
  46. package/dist/message-handler-mXzc3tA_.js +381 -0
  47. package/dist/message-handler.preflight-BPD1a347.js +1113 -0
  48. package/dist/message-handler.process-GUa3aV8z.js +1438 -0
  49. package/dist/message-utils-dUbem16p.js +549 -0
  50. package/dist/outbound-adapter-C18OAc1y.js +536 -0
  51. package/dist/pluralkit-D1Q2x0w5.js +22 -0
  52. package/dist/preflight-audio-CZtpWcIm.js +72 -0
  53. package/dist/preflight-audio.runtime-Brx_0_xW.js +7 -0
  54. package/dist/preview-streaming-D_slNIiO.js +8 -0
  55. package/dist/probe-D--Ca4JF.js +139 -0
  56. package/dist/probe.runtime-DQBchZzv.js +2 -0
  57. package/dist/provider-B2-31CIT.js +9565 -0
  58. package/dist/provider-session.runtime-BwzzSsrH.js +6 -0
  59. package/dist/provider.runtime-CP3oHLls.js +2 -0
  60. package/dist/resolve-allowlist-common-CqxPLcJO.js +34 -0
  61. package/dist/resolve-channels-0LX4pUbB.js +265 -0
  62. package/dist/resolve-users-CztOv0Qs.js +120 -0
  63. package/dist/runtime-DUaw66V_.js +1073 -0
  64. package/dist/runtime-api.actions.js +3 -0
  65. package/dist/runtime-api.js +30 -0
  66. package/dist/runtime-api.lookup.js +7 -0
  67. package/dist/runtime-api.monitor-CvVKvEXW.js +5 -0
  68. package/dist/runtime-api.monitor.js +8 -0
  69. package/dist/runtime-api.send.js +6 -0
  70. package/dist/runtime-api.threads.js +6 -0
  71. package/dist/runtime-fC6f4UF2.js +8 -0
  72. package/dist/runtime-setter-api.js +2 -0
  73. package/dist/secret-config-contract-B6WW5V88.js +115 -0
  74. package/dist/secret-contract-api.js +2 -0
  75. package/dist/security-audit-CnyIQKz6.js +120 -0
  76. package/dist/security-audit-contract-api.js +2 -0
  77. package/dist/security-audit.runtime-CQSkjNLu.js +2 -0
  78. package/dist/security-contract-DLvYOgLM.js +26 -0
  79. package/dist/security-contract-api.js +2 -0
  80. package/dist/security-doctor-DepqtNCI.js +18 -0
  81. package/dist/send-DCtPCHGk.js +881 -0
  82. package/dist/send.components-Bcgxvm52.js +474 -0
  83. package/dist/send.outbound-S9t0UuHc.js +330 -0
  84. package/dist/send.receipt-CDn3GBWC.js +3119 -0
  85. package/dist/send.shared-D4iBnAmn.js +669 -0
  86. package/dist/sender-identity-CxCe3_1a.js +43 -0
  87. package/dist/session-contract-Dwhw3RTY.js +6 -0
  88. package/dist/session-key-api.js +2 -0
  89. package/dist/session-key-normalization-CP8dPUid.js +23 -0
  90. package/dist/setup-entry.js +11 -0
  91. package/dist/setup-plugin-api.js +2 -0
  92. package/dist/shared-AIlvuZXt.js +171 -0
  93. package/dist/subagent-hooks-8bK-mgiU.js +120 -0
  94. package/dist/subagent-hooks-api.js +22 -0
  95. package/dist/system-events-Ba1TklaL.js +34 -0
  96. package/dist/target-resolver-BrtFQtoK.js +82 -0
  97. package/dist/targets-DWLLZE2l.js +3 -0
  98. package/dist/test-api.js +45 -0
  99. package/dist/thread-binding-api.js +4 -0
  100. package/dist/thread-bindings-9aKRmZv0.js +255 -0
  101. package/dist/thread-bindings.discord-api-ssGH5wc2.js +244 -0
  102. package/dist/thread-bindings.manager-0YBHGemk.js +534 -0
  103. package/dist/thread-bindings.session-updates-DJZGIwaU.js +54 -0
  104. package/dist/thread-bindings.state-eTFl-PqJ.js +318 -0
  105. package/dist/timeouts-CEwuGaWT.js +52 -0
  106. package/dist/timeouts.js +2 -0
  107. package/dist/typing-BmJKRpCS.js +14 -0
  108. package/doctor-contract-api.ts +1 -0
  109. package/index.test.ts +13 -0
  110. package/index.ts +24 -0
  111. package/klaw.plugin.json +2 -3822
  112. package/package.json +4 -4
  113. package/runtime-api.actions.ts +15 -0
  114. package/runtime-api.lookup.ts +22 -0
  115. package/runtime-api.monitor.ts +50 -0
  116. package/runtime-api.send.ts +79 -0
  117. package/runtime-api.threads.ts +31 -0
  118. package/runtime-api.ts +181 -0
  119. package/runtime-setter-api.ts +3 -0
  120. package/secret-contract-api.ts +4 -0
  121. package/security-audit-contract-api.ts +1 -0
  122. package/security-contract-api.ts +4 -0
  123. package/session-key-api.ts +1 -0
  124. package/setup-entry.ts +9 -0
  125. package/setup-plugin-api.ts +3 -0
  126. package/src/account-inspect.test.ts +126 -0
  127. package/src/account-inspect.ts +128 -0
  128. package/src/accounts.test.ts +381 -0
  129. package/src/accounts.ts +205 -0
  130. package/src/actions/handle-action.guild-admin.ts +421 -0
  131. package/src/actions/handle-action.test.ts +480 -0
  132. package/src/actions/handle-action.ts +402 -0
  133. package/src/actions/runtime.guild.ts +446 -0
  134. package/src/actions/runtime.messaging.messages.ts +226 -0
  135. package/src/actions/runtime.messaging.reactions.ts +67 -0
  136. package/src/actions/runtime.messaging.runtime.ts +73 -0
  137. package/src/actions/runtime.messaging.send.ts +336 -0
  138. package/src/actions/runtime.messaging.shared.ts +97 -0
  139. package/src/actions/runtime.messaging.ts +37 -0
  140. package/src/actions/runtime.moderation-shared.ts +48 -0
  141. package/src/actions/runtime.moderation.authz.test.ts +151 -0
  142. package/src/actions/runtime.moderation.ts +116 -0
  143. package/src/actions/runtime.presence.test.ts +165 -0
  144. package/src/actions/runtime.presence.ts +117 -0
  145. package/src/actions/runtime.shared.ts +86 -0
  146. package/src/actions/runtime.test.ts +1337 -0
  147. package/src/actions/runtime.ts +87 -0
  148. package/src/api-barrel.test.ts +78 -0
  149. package/src/api.test.ts +152 -0
  150. package/src/api.ts +215 -0
  151. package/src/approval-handler.runtime.test.ts +41 -0
  152. package/src/approval-handler.runtime.ts +633 -0
  153. package/src/approval-native.test.ts +330 -0
  154. package/src/approval-native.ts +219 -0
  155. package/src/approval-runtime.ts +14 -0
  156. package/src/approval-shared.ts +50 -0
  157. package/src/audit-core.ts +178 -0
  158. package/src/audit.test.ts +204 -0
  159. package/src/audit.ts +32 -0
  160. package/src/channel-actions.contract.test.ts +45 -0
  161. package/src/channel-actions.runtime.ts +1 -0
  162. package/src/channel-actions.test.ts +504 -0
  163. package/src/channel-actions.ts +254 -0
  164. package/src/channel-api.ts +29 -0
  165. package/src/channel.conversation.ts +159 -0
  166. package/src/channel.loaders.ts +50 -0
  167. package/src/channel.message-adapter.test.ts +230 -0
  168. package/src/channel.runtime.ts +1 -0
  169. package/src/channel.setup.ts +12 -0
  170. package/src/channel.test.ts +828 -0
  171. package/src/channel.ts +728 -0
  172. package/src/chunk.test.ts +170 -0
  173. package/src/chunk.ts +321 -0
  174. package/src/client.proxy.test.ts +177 -0
  175. package/src/client.test.ts +83 -0
  176. package/src/client.ts +143 -0
  177. package/src/component-custom-id.ts +72 -0
  178. package/src/components-registry.ts +356 -0
  179. package/src/components.builders.ts +409 -0
  180. package/src/components.modal.ts +124 -0
  181. package/src/components.parse.ts +407 -0
  182. package/src/components.test.ts +345 -0
  183. package/src/components.ts +54 -0
  184. package/src/components.types.ts +187 -0
  185. package/src/config-schema.test.ts +439 -0
  186. package/src/config-schema.ts +6 -0
  187. package/src/config-ui-hints.ts +354 -0
  188. package/src/conversation-identity.ts +58 -0
  189. package/src/delivery-retry.ts +52 -0
  190. package/src/directory-cache.ts +116 -0
  191. package/src/directory-config.ts +58 -0
  192. package/src/directory-contract.test.ts +129 -0
  193. package/src/directory-live.test.ts +141 -0
  194. package/src/directory-live.ts +135 -0
  195. package/src/doctor-contract.ts +477 -0
  196. package/src/doctor-shared.ts +5 -0
  197. package/src/doctor.test.ts +393 -0
  198. package/src/doctor.ts +340 -0
  199. package/src/draft-chunking.test.ts +64 -0
  200. package/src/draft-chunking.ts +43 -0
  201. package/src/draft-stream.test.ts +193 -0
  202. package/src/draft-stream.ts +162 -0
  203. package/src/durable-delivery.test.ts +103 -0
  204. package/src/error-body.ts +38 -0
  205. package/src/exec-approvals.test.ts +88 -0
  206. package/src/exec-approvals.ts +110 -0
  207. package/src/gateway-logging.test.ts +98 -0
  208. package/src/gateway-logging.ts +67 -0
  209. package/src/group-policy.ts +113 -0
  210. package/src/guilds.ts +29 -0
  211. package/src/inbound-context.contract.test.ts +11 -0
  212. package/src/inbound-event-delivery.ts +135 -0
  213. package/src/interactive-dispatch.ts +104 -0
  214. package/src/internal/api.commands.ts +51 -0
  215. package/src/internal/api.guild.ts +164 -0
  216. package/src/internal/api.interactions.ts +53 -0
  217. package/src/internal/api.messages.ts +113 -0
  218. package/src/internal/api.reactions.ts +38 -0
  219. package/src/internal/api.test.ts +260 -0
  220. package/src/internal/api.ts +61 -0
  221. package/src/internal/api.users.ts +19 -0
  222. package/src/internal/api.webhooks.ts +13 -0
  223. package/src/internal/client.test.ts +472 -0
  224. package/src/internal/client.ts +310 -0
  225. package/src/internal/command-deploy.test.ts +197 -0
  226. package/src/internal/command-deploy.ts +352 -0
  227. package/src/internal/commands.ts +188 -0
  228. package/src/internal/components.base.ts +65 -0
  229. package/src/internal/components.message.ts +279 -0
  230. package/src/internal/components.modal.ts +95 -0
  231. package/src/internal/components.ts +31 -0
  232. package/src/internal/discord.ts +11 -0
  233. package/src/internal/embeds.ts +35 -0
  234. package/src/internal/entity-cache.ts +98 -0
  235. package/src/internal/event-queue.ts +185 -0
  236. package/src/internal/gateway-close-codes.ts +25 -0
  237. package/src/internal/gateway-dispatch.ts +96 -0
  238. package/src/internal/gateway-identify-limiter.ts +26 -0
  239. package/src/internal/gateway-lifecycle.test.ts +114 -0
  240. package/src/internal/gateway-lifecycle.ts +75 -0
  241. package/src/internal/gateway-rate-limit.ts +104 -0
  242. package/src/internal/gateway.test.ts +676 -0
  243. package/src/internal/gateway.ts +479 -0
  244. package/src/internal/interaction-dispatch.test.ts +148 -0
  245. package/src/internal/interaction-dispatch.ts +162 -0
  246. package/src/internal/interaction-options.ts +98 -0
  247. package/src/internal/interaction-response.ts +53 -0
  248. package/src/internal/interactions.test.ts +329 -0
  249. package/src/internal/interactions.ts +378 -0
  250. package/src/internal/listeners.ts +91 -0
  251. package/src/internal/live-smoke.live.test.ts +26 -0
  252. package/src/internal/modal-fields.ts +95 -0
  253. package/src/internal/payload.ts +69 -0
  254. package/src/internal/rest-body.ts +115 -0
  255. package/src/internal/rest-errors.ts +88 -0
  256. package/src/internal/rest-routes.ts +50 -0
  257. package/src/internal/rest-scheduler.ts +557 -0
  258. package/src/internal/rest.test.ts +681 -0
  259. package/src/internal/rest.ts +322 -0
  260. package/src/internal/schemas.ts +36 -0
  261. package/src/internal/structures.test.ts +43 -0
  262. package/src/internal/structures.ts +280 -0
  263. package/src/internal/test-builders.test-support.ts +167 -0
  264. package/src/internal/voice.ts +49 -0
  265. package/src/media-detection.ts +28 -0
  266. package/src/mentions.test.ts +111 -0
  267. package/src/mentions.ts +147 -0
  268. package/src/monitor/ack-reactions.ts +70 -0
  269. package/src/monitor/acp-bind-here.integration.test.ts +219 -0
  270. package/src/monitor/agent-components-auth.ts +7 -0
  271. package/src/monitor/agent-components-context.ts +154 -0
  272. package/src/monitor/agent-components-data.ts +224 -0
  273. package/src/monitor/agent-components-dm-auth.ts +177 -0
  274. package/src/monitor/agent-components-guild-auth.ts +322 -0
  275. package/src/monitor/agent-components-helpers.runtime.ts +3 -0
  276. package/src/monitor/agent-components-helpers.ts +34 -0
  277. package/src/monitor/agent-components-reply.ts +10 -0
  278. package/src/monitor/agent-components.deps.runtime.ts +2 -0
  279. package/src/monitor/agent-components.dispatch.ts +359 -0
  280. package/src/monitor/agent-components.handlers.ts +303 -0
  281. package/src/monitor/agent-components.modal.ts +160 -0
  282. package/src/monitor/agent-components.plugin-interactive.ts +187 -0
  283. package/src/monitor/agent-components.runtime.ts +14 -0
  284. package/src/monitor/agent-components.system-controls.ts +215 -0
  285. package/src/monitor/agent-components.ts +70 -0
  286. package/src/monitor/agent-components.types.ts +58 -0
  287. package/src/monitor/agent-components.wildcard-controls.ts +171 -0
  288. package/src/monitor/agent-components.wildcard.test.ts +71 -0
  289. package/src/monitor/allow-list.test.ts +14 -0
  290. package/src/monitor/allow-list.ts +631 -0
  291. package/src/monitor/auto-presence.test.ts +184 -0
  292. package/src/monitor/auto-presence.ts +356 -0
  293. package/src/monitor/channel-access.test.ts +113 -0
  294. package/src/monitor/channel-access.ts +102 -0
  295. package/src/monitor/commands.test.ts +24 -0
  296. package/src/monitor/commands.ts +9 -0
  297. package/src/monitor/dm-command-auth.test.ts +274 -0
  298. package/src/monitor/dm-command-auth.ts +259 -0
  299. package/src/monitor/dm-command-decision.test.ts +108 -0
  300. package/src/monitor/dm-command-decision.ts +49 -0
  301. package/src/monitor/exec-approvals.test.ts +225 -0
  302. package/src/monitor/exec-approvals.ts +158 -0
  303. package/src/monitor/format.ts +45 -0
  304. package/src/monitor/gateway-handle.ts +33 -0
  305. package/src/monitor/gateway-metadata.test.ts +29 -0
  306. package/src/monitor/gateway-metadata.ts +298 -0
  307. package/src/monitor/gateway-plugin.test.ts +320 -0
  308. package/src/monitor/gateway-plugin.ts +302 -0
  309. package/src/monitor/gateway-registry.ts +37 -0
  310. package/src/monitor/gateway-supervisor.test.ts +157 -0
  311. package/src/monitor/gateway-supervisor.ts +206 -0
  312. package/src/monitor/inbound-context.test-helpers.ts +37 -0
  313. package/src/monitor/inbound-context.test.ts +112 -0
  314. package/src/monitor/inbound-context.ts +95 -0
  315. package/src/monitor/inbound-dedupe.ts +79 -0
  316. package/src/monitor/inbound-job.test.ts +216 -0
  317. package/src/monitor/inbound-job.ts +118 -0
  318. package/src/monitor/listeners.queue.ts +91 -0
  319. package/src/monitor/listeners.reactions.ts +594 -0
  320. package/src/monitor/listeners.test.ts +209 -0
  321. package/src/monitor/listeners.ts +150 -0
  322. package/src/monitor/message-channel-info.ts +96 -0
  323. package/src/monitor/message-forwarded.ts +114 -0
  324. package/src/monitor/message-handler.batch-gate.test.ts +22 -0
  325. package/src/monitor/message-handler.batch-gate.ts +19 -0
  326. package/src/monitor/message-handler.bot-self-filter.test.ts +68 -0
  327. package/src/monitor/message-handler.context.ts +492 -0
  328. package/src/monitor/message-handler.dm-preflight.ts +119 -0
  329. package/src/monitor/message-handler.draft-preview.ts +426 -0
  330. package/src/monitor/message-handler.hydration.test.ts +80 -0
  331. package/src/monitor/message-handler.hydration.ts +198 -0
  332. package/src/monitor/message-handler.inbound-context.test.ts +61 -0
  333. package/src/monitor/message-handler.module-test-helpers.ts +31 -0
  334. package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
  335. package/src/monitor/message-handler.preflight-channel-context.test.ts +18 -0
  336. package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
  337. package/src/monitor/message-handler.preflight-context.ts +54 -0
  338. package/src/monitor/message-handler.preflight-helpers.ts +164 -0
  339. package/src/monitor/message-handler.preflight-history.ts +23 -0
  340. package/src/monitor/message-handler.preflight-logging.ts +36 -0
  341. package/src/monitor/message-handler.preflight-pluralkit.ts +26 -0
  342. package/src/monitor/message-handler.preflight-runtime.ts +28 -0
  343. package/src/monitor/message-handler.preflight-thread.ts +49 -0
  344. package/src/monitor/message-handler.preflight.acp-bindings.test.ts +371 -0
  345. package/src/monitor/message-handler.preflight.test-helpers.ts +114 -0
  346. package/src/monitor/message-handler.preflight.test.ts +2255 -0
  347. package/src/monitor/message-handler.preflight.ts +822 -0
  348. package/src/monitor/message-handler.preflight.types.ts +115 -0
  349. package/src/monitor/message-handler.process.test.ts +2520 -0
  350. package/src/monitor/message-handler.process.ts +1027 -0
  351. package/src/monitor/message-handler.queue.test.ts +680 -0
  352. package/src/monitor/message-handler.routing-preflight.ts +112 -0
  353. package/src/monitor/message-handler.test-harness.ts +99 -0
  354. package/src/monitor/message-handler.test-helpers.ts +75 -0
  355. package/src/monitor/message-handler.ts +309 -0
  356. package/src/monitor/message-media.ts +536 -0
  357. package/src/monitor/message-run-queue.ts +101 -0
  358. package/src/monitor/message-text.ts +171 -0
  359. package/src/monitor/message-utils.test.ts +1234 -0
  360. package/src/monitor/message-utils.ts +34 -0
  361. package/src/monitor/model-picker-preferences.test.ts +67 -0
  362. package/src/monitor/model-picker-preferences.ts +184 -0
  363. package/src/monitor/model-picker.state.ts +364 -0
  364. package/src/monitor/model-picker.test-utils.ts +26 -0
  365. package/src/monitor/model-picker.test.ts +869 -0
  366. package/src/monitor/model-picker.ts +38 -0
  367. package/src/monitor/model-picker.view.ts +722 -0
  368. package/src/monitor/monitor.agent-components.test.ts +410 -0
  369. package/src/monitor/monitor.test.ts +919 -0
  370. package/src/monitor/monitor.threading-utils.test.ts +614 -0
  371. package/src/monitor/native-command-agent-reply.ts +125 -0
  372. package/src/monitor/native-command-arg-ui.ts +233 -0
  373. package/src/monitor/native-command-auth.ts +309 -0
  374. package/src/monitor/native-command-bypass.ts +13 -0
  375. package/src/monitor/native-command-context.test.ts +105 -0
  376. package/src/monitor/native-command-context.ts +109 -0
  377. package/src/monitor/native-command-dispatch.ts +35 -0
  378. package/src/monitor/native-command-model-picker-apply.ts +209 -0
  379. package/src/monitor/native-command-model-picker-interaction.ts +516 -0
  380. package/src/monitor/native-command-model-picker-ui.ts +357 -0
  381. package/src/monitor/native-command-reply.test.ts +68 -0
  382. package/src/monitor/native-command-reply.ts +185 -0
  383. package/src/monitor/native-command-route.ts +91 -0
  384. package/src/monitor/native-command-status.ts +76 -0
  385. package/src/monitor/native-command-ui.ts +26 -0
  386. package/src/monitor/native-command-ui.types.ts +20 -0
  387. package/src/monitor/native-command.args.ts +45 -0
  388. package/src/monitor/native-command.command-arg.test.ts +108 -0
  389. package/src/monitor/native-command.commands-allowfrom.test.ts +504 -0
  390. package/src/monitor/native-command.model-picker.test.ts +930 -0
  391. package/src/monitor/native-command.options.test.ts +379 -0
  392. package/src/monitor/native-command.options.ts +153 -0
  393. package/src/monitor/native-command.plugin-dispatch.test.ts +1212 -0
  394. package/src/monitor/native-command.runtime.ts +51 -0
  395. package/src/monitor/native-command.status-direct.test.ts +278 -0
  396. package/src/monitor/native-command.test-helpers.ts +64 -0
  397. package/src/monitor/native-command.think-autocomplete.test.ts +411 -0
  398. package/src/monitor/native-command.ts +747 -0
  399. package/src/monitor/native-command.types.ts +9 -0
  400. package/src/monitor/native-interaction-channel-context.ts +50 -0
  401. package/src/monitor/preflight-audio.runtime.ts +9 -0
  402. package/src/monitor/preflight-audio.test.ts +157 -0
  403. package/src/monitor/preflight-audio.ts +130 -0
  404. package/src/monitor/presence-cache.ts +61 -0
  405. package/src/monitor/presence.test.ts +61 -0
  406. package/src/monitor/presence.ts +50 -0
  407. package/src/monitor/provider-session.runtime.ts +12 -0
  408. package/src/monitor/provider.acp.ts +89 -0
  409. package/src/monitor/provider.allowlist.test.ts +217 -0
  410. package/src/monitor/provider.allowlist.ts +398 -0
  411. package/src/monitor/provider.cleanup.ts +41 -0
  412. package/src/monitor/provider.commands.ts +129 -0
  413. package/src/monitor/provider.config-log.ts +45 -0
  414. package/src/monitor/provider.deploy-errors.ts +362 -0
  415. package/src/monitor/provider.deploy.ts +221 -0
  416. package/src/monitor/provider.interactions.ts +160 -0
  417. package/src/monitor/provider.lifecycle.test.ts +734 -0
  418. package/src/monitor/provider.lifecycle.ts +562 -0
  419. package/src/monitor/provider.proxy.test.ts +804 -0
  420. package/src/monitor/provider.rest-proxy.test.ts +389 -0
  421. package/src/monitor/provider.runtime.ts +1 -0
  422. package/src/monitor/provider.skill-dedupe.test.ts +42 -0
  423. package/src/monitor/provider.startup-log.ts +32 -0
  424. package/src/monitor/provider.startup.test.ts +440 -0
  425. package/src/monitor/provider.startup.ts +323 -0
  426. package/src/monitor/provider.test.ts +1173 -0
  427. package/src/monitor/provider.ts +688 -0
  428. package/src/monitor/reply-context.ts +64 -0
  429. package/src/monitor/reply-delivery.test.ts +474 -0
  430. package/src/monitor/reply-delivery.ts +212 -0
  431. package/src/monitor/reply-safety.ts +96 -0
  432. package/src/monitor/rest-fetch.ts +94 -0
  433. package/src/monitor/route-resolution.test.ts +209 -0
  434. package/src/monitor/route-resolution.ts +140 -0
  435. package/src/monitor/sender-identity.ts +81 -0
  436. package/src/monitor/startup-status.test.ts +30 -0
  437. package/src/monitor/startup-status.ts +10 -0
  438. package/src/monitor/status.ts +22 -0
  439. package/src/monitor/system-events.ts +55 -0
  440. package/src/monitor/thread-bindings.config.ts +35 -0
  441. package/src/monitor/thread-bindings.discord-api.test.ts +250 -0
  442. package/src/monitor/thread-bindings.discord-api.ts +310 -0
  443. package/src/monitor/thread-bindings.lifecycle.test.ts +1994 -0
  444. package/src/monitor/thread-bindings.lifecycle.ts +354 -0
  445. package/src/monitor/thread-bindings.manager.ts +551 -0
  446. package/src/monitor/thread-bindings.messages.ts +6 -0
  447. package/src/monitor/thread-bindings.persona.test.ts +34 -0
  448. package/src/monitor/thread-bindings.persona.ts +25 -0
  449. package/src/monitor/thread-bindings.session-adapter.ts +229 -0
  450. package/src/monitor/thread-bindings.session-shared.ts +59 -0
  451. package/src/monitor/thread-bindings.session-updates.ts +35 -0
  452. package/src/monitor/thread-bindings.shared-state.test.ts +39 -0
  453. package/src/monitor/thread-bindings.state.ts +540 -0
  454. package/src/monitor/thread-bindings.ts +48 -0
  455. package/src/monitor/thread-bindings.types.ts +83 -0
  456. package/src/monitor/thread-channel-context.ts +112 -0
  457. package/src/monitor/thread-session-close.test.ts +180 -0
  458. package/src/monitor/thread-session-close.ts +63 -0
  459. package/src/monitor/thread-title.generate.test.ts +209 -0
  460. package/src/monitor/thread-title.test.ts +31 -0
  461. package/src/monitor/thread-title.ts +181 -0
  462. package/src/monitor/threading.auto-thread.test.ts +330 -0
  463. package/src/monitor/threading.auto-thread.ts +287 -0
  464. package/src/monitor/threading.cache.ts +45 -0
  465. package/src/monitor/threading.parent-info.test.ts +156 -0
  466. package/src/monitor/threading.starter.test.ts +279 -0
  467. package/src/monitor/threading.starter.ts +288 -0
  468. package/src/monitor/threading.ts +20 -0
  469. package/src/monitor/threading.types.ts +102 -0
  470. package/src/monitor/timeouts.ts +84 -0
  471. package/src/monitor/typing.test.ts +42 -0
  472. package/src/monitor/typing.ts +17 -0
  473. package/src/monitor.gateway.test.ts +187 -0
  474. package/src/monitor.gateway.ts +75 -0
  475. package/src/monitor.test.ts +1416 -0
  476. package/src/monitor.ts +28 -0
  477. package/src/network-config.test.ts +92 -0
  478. package/src/network-config.ts +79 -0
  479. package/src/normalize.test.ts +56 -0
  480. package/src/normalize.ts +86 -0
  481. package/src/outbound-adapter.interactive-order.test.ts +82 -0
  482. package/src/outbound-adapter.test-harness.ts +207 -0
  483. package/src/outbound-adapter.test.ts +804 -0
  484. package/src/outbound-adapter.ts +326 -0
  485. package/src/outbound-approval.ts +29 -0
  486. package/src/outbound-components.ts +86 -0
  487. package/src/outbound-payload.contract.test.ts +49 -0
  488. package/src/outbound-payload.ts +208 -0
  489. package/src/outbound-send-context.ts +89 -0
  490. package/src/outbound-session-route.test.ts +42 -0
  491. package/src/outbound-session-route.ts +72 -0
  492. package/src/pluralkit.test.ts +67 -0
  493. package/src/pluralkit.ts +58 -0
  494. package/src/preview-streaming.ts +18 -0
  495. package/src/probe.intents.test.ts +94 -0
  496. package/src/probe.parse-token.test.ts +43 -0
  497. package/src/probe.runtime.ts +1 -0
  498. package/src/probe.ts +237 -0
  499. package/src/proxy-fetch.ts +92 -0
  500. package/src/proxy-request-client.test.ts +100 -0
  501. package/src/proxy-request-client.ts +21 -0
  502. package/src/recipient-resolution.ts +39 -0
  503. package/src/resolve-allowlist-common.test.ts +40 -0
  504. package/src/resolve-allowlist-common.ts +39 -0
  505. package/src/resolve-channels.test.ts +341 -0
  506. package/src/resolve-channels.ts +369 -0
  507. package/src/resolve-users.test.ts +243 -0
  508. package/src/resolve-users.ts +184 -0
  509. package/src/retry.test.ts +83 -0
  510. package/src/retry.ts +98 -0
  511. package/src/runtime-api.ts +61 -0
  512. package/src/runtime-config.ts +16 -0
  513. package/src/runtime.ts +23 -0
  514. package/src/secret-config-contract.ts +140 -0
  515. package/src/security-audit.runtime.ts +1 -0
  516. package/src/security-audit.test.ts +245 -0
  517. package/src/security-audit.ts +208 -0
  518. package/src/security-contract.ts +47 -0
  519. package/src/security-doctor.test.ts +25 -0
  520. package/src/security-doctor.ts +20 -0
  521. package/src/security.ts +60 -0
  522. package/src/send-target-parsing.ts +14 -0
  523. package/src/send.channels.ts +139 -0
  524. package/src/send.components.test.ts +330 -0
  525. package/src/send.components.ts +391 -0
  526. package/src/send.creates-thread.test.ts +681 -0
  527. package/src/send.emojis-stickers.ts +57 -0
  528. package/src/send.guild.ts +170 -0
  529. package/src/send.message-request.ts +112 -0
  530. package/src/send.messages.test.ts +59 -0
  531. package/src/send.messages.ts +229 -0
  532. package/src/send.outbound.ts +459 -0
  533. package/src/send.permissions.authz.test.ts +190 -0
  534. package/src/send.permissions.ts +283 -0
  535. package/src/send.reactions.ts +155 -0
  536. package/src/send.receipt.ts +69 -0
  537. package/src/send.sends-basic-channel-messages.test.ts +1068 -0
  538. package/src/send.shared.ts +469 -0
  539. package/src/send.test-harness.ts +56 -0
  540. package/src/send.ts +82 -0
  541. package/src/send.types.ts +191 -0
  542. package/src/send.typing.test.ts +41 -0
  543. package/src/send.typing.ts +9 -0
  544. package/src/send.voice.ts +136 -0
  545. package/src/send.webhook-activity.test.ts +152 -0
  546. package/src/send.webhook.proxy.test.ts +210 -0
  547. package/src/send.webhook.ts +137 -0
  548. package/src/session-contract.ts +3 -0
  549. package/src/session-key-normalization.test.ts +44 -0
  550. package/src/session-key-normalization.ts +47 -0
  551. package/src/setup-account-state.test.ts +113 -0
  552. package/src/setup-account-state.ts +141 -0
  553. package/src/setup-adapter.ts +14 -0
  554. package/src/setup-core.ts +215 -0
  555. package/src/setup-runtime-helpers.ts +10 -0
  556. package/src/setup-surface.test.ts +137 -0
  557. package/src/setup-surface.ts +132 -0
  558. package/src/shared-interactive.test.ts +153 -0
  559. package/src/shared-interactive.ts +161 -0
  560. package/src/shared.test.ts +186 -0
  561. package/src/shared.ts +197 -0
  562. package/src/status-issues.test.ts +97 -0
  563. package/src/status-issues.ts +198 -0
  564. package/src/subagent-hooks.test.ts +465 -0
  565. package/src/subagent-hooks.ts +232 -0
  566. package/src/target-parsing.ts +70 -0
  567. package/src/target-resolver.ts +129 -0
  568. package/src/targets.test.ts +393 -0
  569. package/src/targets.ts +12 -0
  570. package/src/test-http-helpers.ts +10 -0
  571. package/src/test-support/component-runtime.ts +194 -0
  572. package/src/test-support/config.ts +7 -0
  573. package/src/test-support/configured-binding-runtime.ts +29 -0
  574. package/src/test-support/partial-channel.ts +26 -0
  575. package/src/test-support/provider.test-support.ts +547 -0
  576. package/src/token.test.ts +174 -0
  577. package/src/token.ts +107 -0
  578. package/src/ui-colors.ts +27 -0
  579. package/src/ui.ts +20 -0
  580. package/src/voice/access.test.ts +288 -0
  581. package/src/voice/access.ts +126 -0
  582. package/src/voice/audio.test.ts +47 -0
  583. package/src/voice/audio.ts +249 -0
  584. package/src/voice/capture-state.test.ts +48 -0
  585. package/src/voice/capture-state.ts +120 -0
  586. package/src/voice/command.test.ts +170 -0
  587. package/src/voice/command.ts +284 -0
  588. package/src/voice/config.ts +8 -0
  589. package/src/voice/ingress.ts +164 -0
  590. package/src/voice/manager.e2e.test.ts +3286 -0
  591. package/src/voice/manager.ready-listener.test.ts +54 -0
  592. package/src/voice/manager.runtime.ts +14 -0
  593. package/src/voice/manager.ts +1155 -0
  594. package/src/voice/prompt.test.ts +30 -0
  595. package/src/voice/prompt.ts +22 -0
  596. package/src/voice/realtime.ts +1370 -0
  597. package/src/voice/receive-recovery.test.ts +81 -0
  598. package/src/voice/receive-recovery.ts +159 -0
  599. package/src/voice/sanitize.test.ts +34 -0
  600. package/src/voice/sanitize.ts +29 -0
  601. package/src/voice/sdk-runtime.ts +14 -0
  602. package/src/voice/segment.ts +160 -0
  603. package/src/voice/session.ts +81 -0
  604. package/src/voice/speaker-context.ts +127 -0
  605. package/src/voice/tts.ts +151 -0
  606. package/src/voice-message.test.ts +376 -0
  607. package/src/voice-message.ts +474 -0
  608. package/subagent-hooks-api.ts +27 -0
  609. package/test-api.ts +4 -0
  610. package/thread-binding-api.ts +1 -0
  611. package/timeouts.ts +6 -0
  612. package/tsconfig.json +16 -0
  613. package/account-inspect-api.js +0 -7
  614. package/action-runtime-api.js +0 -7
  615. package/api.js +0 -7
  616. package/channel-config-api.js +0 -7
  617. package/channel-plugin-api.js +0 -7
  618. package/configured-state.js +0 -7
  619. package/contract-api.js +0 -7
  620. package/directory-contract-api.js +0 -7
  621. package/doctor-contract-api.js +0 -7
  622. package/index.js +0 -7
  623. package/runtime-api.actions.js +0 -7
  624. package/runtime-api.js +0 -7
  625. package/runtime-api.lookup.js +0 -7
  626. package/runtime-api.monitor.js +0 -7
  627. package/runtime-api.send.js +0 -7
  628. package/runtime-api.threads.js +0 -7
  629. package/runtime-setter-api.js +0 -7
  630. package/secret-contract-api.js +0 -7
  631. package/security-audit-contract-api.js +0 -7
  632. package/security-contract-api.js +0 -7
  633. package/session-key-api.js +0 -7
  634. package/setup-entry.js +0 -7
  635. package/setup-plugin-api.js +0 -7
  636. package/subagent-hooks-api.js +0 -7
  637. package/test-api.js +0 -7
  638. package/thread-binding-api.js +0 -7
  639. package/timeouts.js +0 -7
@@ -0,0 +1,3119 @@
1
+ import "node:module";
2
+ import { buildMessagingTarget, parseMentionPrefixOrAtUserTarget, requireTargetKind } from "klaw/plugin-sdk/messaging-targets";
3
+ import { ApplicationCommandOptionType, ApplicationCommandType, ButtonStyle, ComponentType, GatewayDispatchEvents, InteractionContextType, InteractionResponseType, InteractionType, MessageFlags, Routes, TextInputStyle } from "discord-api-types/v10";
4
+ import { createHash, randomBytes } from "node:crypto";
5
+ import path from "node:path";
6
+ import { privateFileStore } from "klaw/plugin-sdk/security-runtime";
7
+ import { Type } from "typebox";
8
+ import { Check } from "typebox/value";
9
+ import { inspect } from "node:util";
10
+ import { chunkMarkdownTextWithMode } from "klaw/plugin-sdk/reply-chunking";
11
+ import { createMessageReceiptFromOutboundResults } from "klaw/plugin-sdk/channel-message";
12
+ //#region \0rolldown/runtime.js
13
+ var __defProp = Object.defineProperty;
14
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
15
+ var __getOwnPropNames = Object.getOwnPropertyNames;
16
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
17
+ var __exportAll = (all, no_symbols) => {
18
+ let target = {};
19
+ for (var name in all) __defProp(target, name, {
20
+ get: all[name],
21
+ enumerable: true
22
+ });
23
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
24
+ return target;
25
+ };
26
+ var __copyProps = (to, from, except, desc) => {
27
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
28
+ key = keys[i];
29
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
30
+ get: ((k) => from[k]).bind(null, key),
31
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
32
+ });
33
+ }
34
+ return to;
35
+ };
36
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
37
+ //#endregion
38
+ //#region extensions/discord/src/target-parsing.ts
39
+ function parseDiscordTarget(raw, options = {}) {
40
+ const trimmed = raw.trim();
41
+ if (!trimmed) return;
42
+ const providerPrefixedTarget = parseDiscordProviderPrefixedTarget(trimmed);
43
+ if (providerPrefixedTarget) return providerPrefixedTarget;
44
+ const userTarget = parseMentionPrefixOrAtUserTarget({
45
+ raw: trimmed,
46
+ mentionPattern: /^<@!?(\d+)>$/,
47
+ prefixes: [
48
+ {
49
+ prefix: "user:",
50
+ kind: "user"
51
+ },
52
+ {
53
+ prefix: "channel:",
54
+ kind: "channel"
55
+ },
56
+ {
57
+ prefix: "discord:",
58
+ kind: "user"
59
+ }
60
+ ],
61
+ atUserPattern: /^\d+$/,
62
+ atUserErrorMessage: "Discord DMs require a user id (use user:<id> or a <@id> mention)"
63
+ });
64
+ if (userTarget) return userTarget;
65
+ if (/^\d+$/.test(trimmed)) {
66
+ if (options.defaultKind) return buildMessagingTarget(options.defaultKind, trimmed, trimmed);
67
+ throw new Error(options.ambiguousMessage ?? `Ambiguous Discord recipient "${trimmed}". For DMs use "user:${trimmed}" or "<@${trimmed}>"; for channels use "channel:${trimmed}".`);
68
+ }
69
+ return buildMessagingTarget("channel", trimmed, trimmed);
70
+ }
71
+ function parseDiscordProviderPrefixedTarget(raw) {
72
+ const match = /^discord:(channel|user):(.+)$/i.exec(raw);
73
+ if (!match) return;
74
+ const kind = match[1]?.toLowerCase();
75
+ const id = match[2]?.trim();
76
+ if (!kind || !id) return;
77
+ return buildMessagingTarget(kind, id, `${kind}:${id}`);
78
+ }
79
+ function resolveDiscordChannelId(raw) {
80
+ return requireTargetKind({
81
+ platform: "Discord",
82
+ target: parseDiscordTarget(raw, { defaultKind: "channel" }),
83
+ kind: "channel"
84
+ });
85
+ }
86
+ //#endregion
87
+ //#region extensions/discord/src/internal/api.commands.ts
88
+ async function listApplicationCommands(rest, clientId) {
89
+ return await rest.get(Routes.applicationCommands(clientId));
90
+ }
91
+ async function createApplicationCommand(rest, clientId, body) {
92
+ return await rest.post(Routes.applicationCommands(clientId), { body });
93
+ }
94
+ async function editApplicationCommand(rest, clientId, commandId, body) {
95
+ return await rest.patch(Routes.applicationCommand(clientId, commandId), { body });
96
+ }
97
+ async function deleteApplicationCommand(rest, clientId, commandId) {
98
+ await rest.delete(Routes.applicationCommand(clientId, commandId));
99
+ }
100
+ async function overwriteApplicationCommands(rest, clientId, body) {
101
+ await rest.put(Routes.applicationCommands(clientId), { body });
102
+ }
103
+ async function overwriteGuildApplicationCommands(rest, clientId, guildId, body) {
104
+ await rest.put(Routes.applicationGuildCommands(clientId, guildId), { body });
105
+ }
106
+ //#endregion
107
+ //#region extensions/discord/src/internal/api.guild.ts
108
+ async function getGuild(rest, guildId) {
109
+ return await rest.get(Routes.guild(guildId));
110
+ }
111
+ async function createGuildChannel(rest, guildId, data) {
112
+ return await rest.post(Routes.guildChannels(guildId), data);
113
+ }
114
+ async function moveGuildChannels(rest, guildId, data) {
115
+ await rest.patch(Routes.guildChannels(guildId), data);
116
+ }
117
+ async function getGuildMember(rest, guildId, userId) {
118
+ return await rest.get(Routes.guildMember(guildId, userId));
119
+ }
120
+ async function listGuildRoles(rest, guildId) {
121
+ return await rest.get(Routes.guildRoles(guildId));
122
+ }
123
+ async function listGuildChannels(rest, guildId) {
124
+ return await rest.get(Routes.guildChannels(guildId));
125
+ }
126
+ async function putChannelPermission(rest, channelId, targetId, data) {
127
+ await rest.put(Routes.channelPermission(channelId, targetId), data);
128
+ }
129
+ async function deleteChannelPermission(rest, channelId, targetId) {
130
+ await rest.delete(Routes.channelPermission(channelId, targetId));
131
+ }
132
+ async function listGuildActiveThreads(rest, guildId) {
133
+ return await rest.get(Routes.guildActiveThreads(guildId));
134
+ }
135
+ async function getGuildVoiceState(rest, guildId, userId) {
136
+ return await rest.get(Routes.guildVoiceState(guildId, userId));
137
+ }
138
+ async function listGuildScheduledEvents(rest, guildId) {
139
+ return await rest.get(Routes.guildScheduledEvents(guildId));
140
+ }
141
+ async function createGuildScheduledEvent(rest, guildId, body) {
142
+ return await rest.post(Routes.guildScheduledEvents(guildId), { body });
143
+ }
144
+ async function timeoutGuildMember(rest, guildId, userId, data) {
145
+ return await rest.patch(Routes.guildMember(guildId, userId), data);
146
+ }
147
+ async function addGuildMemberRole(rest, guildId, userId, roleId) {
148
+ await rest.put(Routes.guildMemberRole(guildId, userId, roleId));
149
+ }
150
+ async function removeGuildMemberRole(rest, guildId, userId, roleId) {
151
+ await rest.delete(Routes.guildMemberRole(guildId, userId, roleId));
152
+ }
153
+ async function removeGuildMember(rest, guildId, userId, data) {
154
+ await rest.delete(Routes.guildMember(guildId, userId), data);
155
+ }
156
+ async function createGuildBan(rest, guildId, userId, data) {
157
+ await rest.put(Routes.guildBan(guildId, userId), data);
158
+ }
159
+ async function listGuildEmojis(rest, guildId) {
160
+ return await rest.get(Routes.guildEmojis(guildId));
161
+ }
162
+ async function createGuildEmoji(rest, guildId, data) {
163
+ return await rest.post(Routes.guildEmojis(guildId), data);
164
+ }
165
+ async function createGuildSticker(rest, guildId, data) {
166
+ return await rest.post(Routes.guildStickers(guildId), data);
167
+ }
168
+ //#endregion
169
+ //#region extensions/discord/src/internal/api.interactions.ts
170
+ async function createInteractionCallback(rest, interactionId, token, body) {
171
+ return await rest.post(Routes.interactionCallback(interactionId, token), { body });
172
+ }
173
+ async function editWebhookMessage(rest, applicationId, token, messageId, data, query) {
174
+ return query ? await rest.patch(Routes.webhookMessage(applicationId, token, messageId), data, query) : await rest.patch(Routes.webhookMessage(applicationId, token, messageId), data);
175
+ }
176
+ async function deleteWebhookMessage(rest, applicationId, token, messageId) {
177
+ return await rest.delete(Routes.webhookMessage(applicationId, token, messageId));
178
+ }
179
+ async function getWebhookMessage(rest, applicationId, token, messageId) {
180
+ return await rest.get(Routes.webhookMessage(applicationId, token, messageId));
181
+ }
182
+ async function createWebhookMessage(rest, applicationId, token, data, query) {
183
+ return await rest.post(Routes.webhook(applicationId, token), data, query);
184
+ }
185
+ //#endregion
186
+ //#region extensions/discord/src/internal/api.messages.ts
187
+ async function getChannel(rest, channelId) {
188
+ return await rest.get(Routes.channel(channelId));
189
+ }
190
+ async function editChannel(rest, channelId, data) {
191
+ return await rest.patch(Routes.channel(channelId), data);
192
+ }
193
+ async function deleteChannel(rest, channelId) {
194
+ await rest.delete(Routes.channel(channelId));
195
+ }
196
+ async function listChannelMessages(rest, channelId, query) {
197
+ return await rest.get(Routes.channelMessages(channelId), query);
198
+ }
199
+ async function getChannelMessage(rest, channelId, messageId) {
200
+ return await rest.get(Routes.channelMessage(channelId, messageId));
201
+ }
202
+ async function createChannelMessage(rest, channelId, data) {
203
+ return await rest.post(Routes.channelMessages(channelId), data);
204
+ }
205
+ async function editChannelMessage(rest, channelId, messageId, data) {
206
+ return await rest.patch(Routes.channelMessage(channelId, messageId), data);
207
+ }
208
+ async function deleteChannelMessage(rest, channelId, messageId) {
209
+ await rest.delete(Routes.channelMessage(channelId, messageId));
210
+ }
211
+ async function pinChannelMessage(rest, channelId, messageId) {
212
+ await rest.put(Routes.channelPin(channelId, messageId));
213
+ }
214
+ async function unpinChannelMessage(rest, channelId, messageId) {
215
+ await rest.delete(Routes.channelPin(channelId, messageId));
216
+ }
217
+ async function listChannelPins(rest, channelId) {
218
+ return await rest.get(Routes.channelPins(channelId));
219
+ }
220
+ async function sendChannelTyping(rest, channelId) {
221
+ await rest.post(Routes.channelTyping(channelId));
222
+ }
223
+ async function createThread(rest, channelId, data, messageId) {
224
+ const route = messageId ? Routes.threads(channelId, messageId) : Routes.threads(channelId);
225
+ return await rest.post(route, data);
226
+ }
227
+ async function listChannelArchivedThreads(rest, channelId, query) {
228
+ return await rest.get(Routes.channelThreads(channelId, "public"), query);
229
+ }
230
+ async function searchGuildMessages(rest, guildId, params) {
231
+ return await rest.get(`/guilds/${guildId}/messages/search?${params.toString()}`);
232
+ }
233
+ //#endregion
234
+ //#region extensions/discord/src/internal/api.reactions.ts
235
+ async function createOwnMessageReaction(rest, channelId, messageId, encodedEmoji) {
236
+ await rest.put(Routes.channelMessageOwnReaction(channelId, messageId, encodedEmoji));
237
+ }
238
+ async function deleteOwnMessageReaction(rest, channelId, messageId, encodedEmoji) {
239
+ await rest.delete(Routes.channelMessageOwnReaction(channelId, messageId, encodedEmoji));
240
+ }
241
+ async function listMessageReactionUsers(rest, channelId, messageId, encodedEmoji, query) {
242
+ return await rest.get(Routes.channelMessageReaction(channelId, messageId, encodedEmoji), query);
243
+ }
244
+ //#endregion
245
+ //#region extensions/discord/src/internal/api.users.ts
246
+ async function getCurrentUser(rest) {
247
+ return await rest.get(Routes.user("@me"));
248
+ }
249
+ async function getUser(rest, userId) {
250
+ return await rest.get(Routes.user(userId));
251
+ }
252
+ async function createUserDmChannel(rest, recipientId) {
253
+ return await rest.post(Routes.userChannels(), { body: { recipient_id: recipientId } });
254
+ }
255
+ //#endregion
256
+ //#region extensions/discord/src/internal/api.webhooks.ts
257
+ async function createChannelWebhook(rest, channelId, data) {
258
+ return await rest.post(Routes.channelWebhooks(channelId), data);
259
+ }
260
+ //#endregion
261
+ //#region extensions/discord/src/internal/command-deploy.ts
262
+ var DiscordCommandDeployer = class {
263
+ constructor(params) {
264
+ this.params = params;
265
+ this.hashes = /* @__PURE__ */ new Map();
266
+ this.hashesLoaded = false;
267
+ }
268
+ async getCommands() {
269
+ return await listApplicationCommands(this.rest, this.params.clientId);
270
+ }
271
+ async deploy(options = {}) {
272
+ const commands = this.params.commands.filter((command) => command.name !== "*");
273
+ const serializedGlobal = commands.filter((command) => !command.guildIds).map((command) => command.serialize());
274
+ for (const [guildId, entries] of groupGuildCommands(commands)) await this.putCommandSetIfChanged(`guild:${guildId}`, entries, async () => {
275
+ await overwriteGuildApplicationCommands(this.rest, this.params.clientId, guildId, entries);
276
+ }, options);
277
+ if (this.params.devGuilds?.length) {
278
+ for (const guildId of this.params.devGuilds) {
279
+ const entries = commands.map((command) => command.serialize());
280
+ await this.putCommandSetIfChanged(`dev-guild:${guildId}`, entries, async () => {
281
+ await overwriteGuildApplicationCommands(this.rest, this.params.clientId, guildId, entries);
282
+ }, options);
283
+ }
284
+ return {
285
+ mode: options.mode ?? "reconcile",
286
+ usedDevGuilds: true
287
+ };
288
+ }
289
+ if (options.mode !== "overwrite") {
290
+ await this.putCommandSetIfChanged("global:reconcile", serializedGlobal, async () => {
291
+ await this.reconcileGlobalCommands(serializedGlobal);
292
+ }, options);
293
+ return {
294
+ mode: "reconcile",
295
+ usedDevGuilds: false
296
+ };
297
+ }
298
+ await this.putCommandSetIfChanged("global:overwrite", serializedGlobal, async () => {
299
+ await overwriteApplicationCommands(this.rest, this.params.clientId, serializedGlobal);
300
+ }, options);
301
+ return {
302
+ mode: "overwrite",
303
+ usedDevGuilds: false
304
+ };
305
+ }
306
+ async reconcileGlobalCommands(desired) {
307
+ const existing = await this.getCommands();
308
+ const existingByKey = new Map(existing.map((command) => [stableCommandKey(command), command]));
309
+ const desiredKeys = /* @__PURE__ */ new Set();
310
+ for (const command of desired) {
311
+ const key = stableCommandKey(command);
312
+ desiredKeys.add(key);
313
+ const current = existingByKey.get(key);
314
+ if (!current) {
315
+ await createApplicationCommand(this.rest, this.params.clientId, command);
316
+ continue;
317
+ }
318
+ if (!commandsEqual(current, command)) await editApplicationCommand(this.rest, this.params.clientId, current.id, command);
319
+ }
320
+ for (const command of existing) if (!desiredKeys.has(stableCommandKey(command))) await deleteApplicationCommand(this.rest, this.params.clientId, command.id);
321
+ }
322
+ async putCommandSetIfChanged(key, commands, deploy, options) {
323
+ const hash = stableCommandSetHash(commands);
324
+ await this.loadPersistedHashes();
325
+ if (!options.force && this.hashes.get(key) === hash) return;
326
+ await deploy();
327
+ this.hashes.set(key, hash);
328
+ await this.persistHashes();
329
+ }
330
+ async loadPersistedHashes() {
331
+ if (this.hashesLoaded) return;
332
+ this.hashesLoaded = true;
333
+ const storePath = this.params.hashStorePath;
334
+ if (!storePath) return;
335
+ try {
336
+ const parsed = await privateFileStore(path.dirname(storePath)).readJsonIfExists(path.basename(storePath));
337
+ if (!parsed?.hashes || typeof parsed.hashes !== "object") return;
338
+ for (const [key, value] of Object.entries(parsed.hashes)) if (typeof value === "string" && key.trim() && value.trim()) this.hashes.set(key, value);
339
+ } catch {}
340
+ }
341
+ async persistHashes() {
342
+ const storePath = this.params.hashStorePath;
343
+ if (!storePath) return;
344
+ try {
345
+ await privateFileStore(path.dirname(storePath)).writeJson(path.basename(storePath), {
346
+ version: 1,
347
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
348
+ hashes: Object.fromEntries([...this.hashes.entries()].toSorted(([left], [right]) => left.localeCompare(right)))
349
+ }, { trailingNewline: true });
350
+ } catch {}
351
+ }
352
+ get rest() {
353
+ return this.params.rest();
354
+ }
355
+ };
356
+ function groupGuildCommands(commands) {
357
+ const guildCommands = /* @__PURE__ */ new Map();
358
+ for (const command of commands.filter((entry) => entry.guildIds)) for (const guildId of command.guildIds ?? []) {
359
+ const entries = guildCommands.get(guildId) ?? [];
360
+ entries.push(command.serialize());
361
+ guildCommands.set(guildId, entries);
362
+ }
363
+ return guildCommands;
364
+ }
365
+ function stableCommandKey(command) {
366
+ return `${command.type ?? ApplicationCommandType.ChatInput}:${command.name}`;
367
+ }
368
+ function comparableCommand(value) {
369
+ if (!value || typeof value !== "object") return value;
370
+ const omit = new Set([
371
+ "application_id",
372
+ "description_localized",
373
+ "dm_permission",
374
+ "guild_id",
375
+ "id",
376
+ "name_localized",
377
+ "nsfw",
378
+ "version",
379
+ "default_permission"
380
+ ]);
381
+ return stableComparableObject(Object.fromEntries(Object.entries(value).filter(([key, entry]) => !omit.has(key) && entry !== void 0)));
382
+ }
383
+ const unorderedCommandArrayFields = new Set([
384
+ "channel_types",
385
+ "contexts",
386
+ "integration_types"
387
+ ]);
388
+ const optionComparisonOmittedFields = new Set([
389
+ "contexts",
390
+ "default_member_permissions",
391
+ "description_localized",
392
+ "integration_types",
393
+ "name_localized"
394
+ ]);
395
+ const nullableLocalizationFields = new Set(["description_localizations", "name_localizations"]);
396
+ function stableComparableObject(value, path = []) {
397
+ if (Array.isArray(value)) {
398
+ const normalized = value.map((entry) => stableComparableObject(entry, path));
399
+ const key = path.at(-1);
400
+ if (key && unorderedCommandArrayFields.has(key) && normalized.every((entry) => typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean")) return normalized.toSorted((left, right) => String(left).localeCompare(String(right)));
401
+ return normalized;
402
+ }
403
+ if (!value || typeof value !== "object") return value;
404
+ return Object.fromEntries(Object.entries(value).filter(([key, entry]) => {
405
+ if (entry === void 0) return false;
406
+ if (entry === null && nullableLocalizationFields.has(key)) return false;
407
+ if (path.includes("options") && optionComparisonOmittedFields.has(key)) return false;
408
+ if ((key === "required" || key === "autocomplete") && entry === false) return false;
409
+ return true;
410
+ }).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => [key, shouldNormalizeDescriptionValue(path, key, entry) ? normalizeDescriptionForComparison(entry) : stableComparableObject(entry, [...path, key])]));
411
+ }
412
+ function shouldNormalizeDescriptionValue(path, key, entry) {
413
+ return typeof entry === "string" && (key === "description" || path.at(-1) === "description_localizations");
414
+ }
415
+ /**
416
+ * Normalize a Discord command description for equality comparison.
417
+ *
418
+ * Discord's server-side storage performs two transformations that our local
419
+ * desired descriptors do not:
420
+ *
421
+ * 1. Consecutive whitespace (including `\n`) is collapsed to a single space.
422
+ * 2. Whitespace between two CJK (Chinese, Japanese, Korean) characters is
423
+ * removed entirely. So a local description `"第一行。\n第二行。"` is stored
424
+ * as `"第一行。第二行。"` on Discord and returned without the `\n`.
425
+ *
426
+ * Without this normalization every startup for any CJK-heavy deployment reads
427
+ * back Discord's collapsed form, computes a diff against the local `\n`-form,
428
+ * decides the command needs updating, and issues a `PATCH`. Under the global
429
+ * per-application rate limit this quickly produces 429 bursts and some
430
+ * commands silently fail to register (see the Discord deploy 429 reports).
431
+ *
432
+ * Applying the same transformation to both sides before comparison makes the
433
+ * equality check match Discord's storage semantics and prevents spurious
434
+ * reconcile writes on every startup.
435
+ */
436
+ function normalizeDescriptionForComparison(description) {
437
+ const collapsed = description.replace(/\s+/g, " ");
438
+ const cjkBoundaryWhitespace = /([\u3000-\u303F\u4E00-\u9FFF\uFF00-\uFFEF])\s+([\u3000-\u303F\u4E00-\u9FFF\uFF00-\uFFEF])/g;
439
+ return collapsed.replace(cjkBoundaryWhitespace, "$1$2").replace(cjkBoundaryWhitespace, "$1$2").trim();
440
+ }
441
+ function commandsEqual(a, b) {
442
+ return JSON.stringify(comparableCommand(a)) === JSON.stringify(comparableCommand(b));
443
+ }
444
+ function stableCommandSetHash(commands) {
445
+ const stable = commands.map((command) => stableComparableObject(command)).toSorted((a, b) => stableCommandKey(a).localeCompare(stableCommandKey(b)));
446
+ return createHash("sha256").update(JSON.stringify(stable)).digest("hex");
447
+ }
448
+ //#endregion
449
+ //#region extensions/discord/src/internal/components.base.ts
450
+ function parseCustomId(id) {
451
+ const [rawKey, ...parts] = id.split(";");
452
+ const [keyPart, firstValue] = rawKey.split("=");
453
+ const key = keyPart.includes(":") ? keyPart.split(":")[0] : keyPart;
454
+ const data = {};
455
+ const entries = firstValue === void 0 ? parts : [rawKey.slice(key.length + 1), ...parts];
456
+ for (const entry of entries) {
457
+ const index = entry.indexOf("=");
458
+ if (index < 0) continue;
459
+ const name = entry.slice(0, index).replace(/^[^:]+:/, "");
460
+ const raw = entry.slice(index + 1);
461
+ data[name] = raw === "true" ? true : raw === "false" ? false : raw;
462
+ }
463
+ return {
464
+ key,
465
+ data
466
+ };
467
+ }
468
+ function clean$3(value) {
469
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
470
+ }
471
+ function colorToNumber(value) {
472
+ if (typeof value === "number") return value;
473
+ if (typeof value === "string" && /^#?[0-9a-f]{6}$/i.test(value)) return Number.parseInt(value.replace(/^#/, ""), 16);
474
+ }
475
+ var BaseComponent = class {
476
+ constructor() {
477
+ this.isV2 = false;
478
+ }
479
+ };
480
+ var BaseMessageInteractiveComponent = class extends BaseComponent {
481
+ constructor(..._args) {
482
+ super(..._args);
483
+ this.isV2 = false;
484
+ this.defer = false;
485
+ this.ephemeral = false;
486
+ this.customIdParser = parseCustomId;
487
+ }
488
+ run(_interaction, _data) {}
489
+ };
490
+ var BaseModalComponent = class extends BaseComponent {};
491
+ //#endregion
492
+ //#region extensions/discord/src/internal/components.message.ts
493
+ var BaseButton = class extends BaseMessageInteractiveComponent {
494
+ constructor(..._args) {
495
+ super(..._args);
496
+ this.type = ComponentType.Button;
497
+ this.style = ButtonStyle.Primary;
498
+ this.disabled = false;
499
+ }
500
+ };
501
+ var Button = class extends BaseButton {
502
+ serialize() {
503
+ return clean$3({
504
+ type: this.type,
505
+ style: this.style,
506
+ custom_id: this.customId,
507
+ label: this.label,
508
+ emoji: this.emoji,
509
+ disabled: this.disabled || void 0
510
+ });
511
+ }
512
+ };
513
+ var LinkButton = class extends BaseButton {
514
+ constructor(..._args2) {
515
+ super(..._args2);
516
+ this.customId = "";
517
+ this.style = ButtonStyle.Link;
518
+ }
519
+ async run() {
520
+ throw new Error("Link buttons do not run handlers");
521
+ }
522
+ serialize() {
523
+ return clean$3({
524
+ type: this.type,
525
+ style: this.style,
526
+ label: this.label,
527
+ emoji: this.emoji,
528
+ disabled: this.disabled || void 0,
529
+ url: this.url
530
+ });
531
+ }
532
+ };
533
+ var AnySelectMenu = class extends BaseMessageInteractiveComponent {
534
+ constructor(..._args3) {
535
+ super(..._args3);
536
+ this.disabled = false;
537
+ }
538
+ serialize() {
539
+ return clean$3({
540
+ ...this.serializeOptions(),
541
+ custom_id: this.customId,
542
+ placeholder: this.placeholder,
543
+ min_values: this.minValues,
544
+ max_values: this.maxValues,
545
+ disabled: this.disabled || void 0,
546
+ required: this.required
547
+ });
548
+ }
549
+ };
550
+ var StringSelectMenu = class extends AnySelectMenu {
551
+ constructor(..._args4) {
552
+ super(..._args4);
553
+ this.type = ComponentType.StringSelect;
554
+ }
555
+ serializeOptions() {
556
+ return {
557
+ type: this.type,
558
+ options: this.options
559
+ };
560
+ }
561
+ };
562
+ var UserSelectMenu = class extends AnySelectMenu {
563
+ constructor(..._args5) {
564
+ super(..._args5);
565
+ this.type = ComponentType.UserSelect;
566
+ }
567
+ serializeOptions() {
568
+ return {
569
+ type: this.type,
570
+ default_values: this.defaultValues
571
+ };
572
+ }
573
+ };
574
+ var RoleSelectMenu = class extends AnySelectMenu {
575
+ constructor(..._args6) {
576
+ super(..._args6);
577
+ this.type = ComponentType.RoleSelect;
578
+ }
579
+ serializeOptions() {
580
+ return {
581
+ type: this.type,
582
+ default_values: this.defaultValues
583
+ };
584
+ }
585
+ };
586
+ var MentionableSelectMenu = class extends AnySelectMenu {
587
+ constructor(..._args7) {
588
+ super(..._args7);
589
+ this.type = ComponentType.MentionableSelect;
590
+ }
591
+ serializeOptions() {
592
+ return {
593
+ type: this.type,
594
+ default_values: this.defaultValues
595
+ };
596
+ }
597
+ };
598
+ var ChannelSelectMenu = class extends AnySelectMenu {
599
+ constructor(..._args8) {
600
+ super(..._args8);
601
+ this.type = ComponentType.ChannelSelect;
602
+ }
603
+ serializeOptions() {
604
+ return {
605
+ type: this.type,
606
+ default_values: this.defaultValues,
607
+ channel_types: this.channelTypes
608
+ };
609
+ }
610
+ };
611
+ var Row = class extends BaseComponent {
612
+ constructor(components = []) {
613
+ super();
614
+ this.type = ComponentType.ActionRow;
615
+ this.isV2 = false;
616
+ this.components = components;
617
+ }
618
+ addComponent(component) {
619
+ this.components.push(component);
620
+ }
621
+ removeComponent(component) {
622
+ this.components = this.components.filter((entry) => entry !== component);
623
+ }
624
+ removeAllComponents() {
625
+ this.components = [];
626
+ }
627
+ serialize() {
628
+ return {
629
+ type: this.type,
630
+ components: this.components.map((entry) => entry.serialize())
631
+ };
632
+ }
633
+ };
634
+ var TextDisplay = class extends BaseComponent {
635
+ constructor(content) {
636
+ super();
637
+ this.content = content;
638
+ this.type = ComponentType.TextDisplay;
639
+ this.isV2 = true;
640
+ }
641
+ serialize() {
642
+ return clean$3({
643
+ type: this.type,
644
+ content: this.content
645
+ });
646
+ }
647
+ };
648
+ var Separator = class extends BaseComponent {
649
+ constructor(options) {
650
+ super();
651
+ this.type = ComponentType.Separator;
652
+ this.isV2 = true;
653
+ this.divider = true;
654
+ this.spacing = "small";
655
+ this.spacing = options?.spacing ?? this.spacing;
656
+ this.divider = options?.divider ?? this.divider;
657
+ }
658
+ serialize() {
659
+ return clean$3({
660
+ type: this.type,
661
+ divider: this.divider,
662
+ spacing: this.spacing === "large" ? 2 : this.spacing === "small" ? 1 : this.spacing
663
+ });
664
+ }
665
+ };
666
+ var Thumbnail = class extends BaseComponent {
667
+ constructor(url) {
668
+ super();
669
+ this.url = url;
670
+ this.type = ComponentType.Thumbnail;
671
+ this.isV2 = true;
672
+ }
673
+ serialize() {
674
+ return clean$3({
675
+ type: this.type,
676
+ media: this.url ? { url: this.url } : void 0
677
+ });
678
+ }
679
+ };
680
+ var Section = class extends BaseComponent {
681
+ constructor(components = [], accessory) {
682
+ super();
683
+ this.components = components;
684
+ this.accessory = accessory;
685
+ this.type = ComponentType.Section;
686
+ this.isV2 = true;
687
+ }
688
+ serialize() {
689
+ return clean$3({
690
+ type: this.type,
691
+ components: this.components.map((entry) => entry.serialize()),
692
+ accessory: this.accessory?.serialize()
693
+ });
694
+ }
695
+ };
696
+ var MediaGallery = class extends BaseComponent {
697
+ constructor(items = []) {
698
+ super();
699
+ this.items = items;
700
+ this.type = ComponentType.MediaGallery;
701
+ this.isV2 = true;
702
+ }
703
+ serialize() {
704
+ return {
705
+ type: this.type,
706
+ items: this.items.map((entry) => ({
707
+ media: { url: entry.url },
708
+ description: entry.description,
709
+ spoiler: entry.spoiler
710
+ }))
711
+ };
712
+ }
713
+ };
714
+ var File = class extends BaseComponent {
715
+ constructor(file, spoiler = false) {
716
+ super();
717
+ this.file = file;
718
+ this.spoiler = spoiler;
719
+ this.type = ComponentType.File;
720
+ this.isV2 = true;
721
+ }
722
+ serialize() {
723
+ return clean$3({
724
+ type: this.type,
725
+ file: this.file ? { url: this.file } : void 0,
726
+ spoiler: this.spoiler || void 0
727
+ });
728
+ }
729
+ };
730
+ var Container = class extends BaseComponent {
731
+ constructor(components = [], options) {
732
+ super();
733
+ this.type = ComponentType.Container;
734
+ this.isV2 = true;
735
+ this.spoiler = false;
736
+ this.components = components;
737
+ this.accentColor = options?.accentColor;
738
+ this.spoiler = options?.spoiler ?? false;
739
+ }
740
+ serialize() {
741
+ return clean$3({
742
+ type: this.type,
743
+ components: this.components.map((entry) => entry.serialize()),
744
+ accent_color: colorToNumber(this.accentColor),
745
+ spoiler: this.spoiler || void 0
746
+ });
747
+ }
748
+ };
749
+ //#endregion
750
+ //#region extensions/discord/src/internal/components.modal.ts
751
+ var TextInput = class extends BaseModalComponent {
752
+ constructor(..._args) {
753
+ super(..._args);
754
+ this.type = ComponentType.TextInput;
755
+ this.customIdParser = parseCustomId;
756
+ this.style = TextInputStyle.Short;
757
+ }
758
+ serialize() {
759
+ return clean$3({
760
+ type: this.type,
761
+ custom_id: this.customId,
762
+ style: this.style,
763
+ min_length: this.minLength,
764
+ max_length: this.maxLength,
765
+ required: this.required,
766
+ value: this.value,
767
+ placeholder: this.placeholder
768
+ });
769
+ }
770
+ };
771
+ var CheckboxGroup = class extends BaseModalComponent {
772
+ constructor(..._args2) {
773
+ super(..._args2);
774
+ this.type = 22;
775
+ this.options = [];
776
+ }
777
+ serialize() {
778
+ return clean$3({
779
+ type: this.type,
780
+ custom_id: this.customId,
781
+ options: this.options,
782
+ required: this.required,
783
+ min_values: this.minValues,
784
+ max_values: this.maxValues
785
+ });
786
+ }
787
+ };
788
+ var RadioGroup = class extends BaseModalComponent {
789
+ constructor(..._args3) {
790
+ super(..._args3);
791
+ this.type = 21;
792
+ this.options = [];
793
+ }
794
+ serialize() {
795
+ return clean$3({
796
+ type: this.type,
797
+ custom_id: this.customId,
798
+ options: this.options,
799
+ required: this.required,
800
+ min_values: this.minValues,
801
+ max_values: this.maxValues
802
+ });
803
+ }
804
+ };
805
+ var Label = class extends BaseModalComponent {
806
+ constructor(component) {
807
+ super();
808
+ this.component = component;
809
+ this.type = ComponentType.Label;
810
+ this.customId = "";
811
+ }
812
+ serialize() {
813
+ return clean$3({
814
+ type: this.type,
815
+ label: this.label,
816
+ description: this.description,
817
+ component: this.component?.serialize()
818
+ });
819
+ }
820
+ };
821
+ var Modal = class {
822
+ constructor() {
823
+ this.components = [];
824
+ this.customIdParser = parseCustomId;
825
+ }
826
+ serialize() {
827
+ return {
828
+ title: this.title,
829
+ custom_id: this.customId,
830
+ components: this.components.map((entry) => entry.serialize())
831
+ };
832
+ }
833
+ };
834
+ //#endregion
835
+ //#region extensions/discord/src/internal/payload.ts
836
+ function clean$2(value) {
837
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
838
+ }
839
+ function serializeAnyComponent(component) {
840
+ return component.serialize();
841
+ }
842
+ function payloadHasV2Components(payload) {
843
+ return Boolean(payload.components?.some((component) => component.isV2));
844
+ }
845
+ function normalizePayloadFlags(payload) {
846
+ const flags = payload.ephemeral ? (payload.flags ?? 0) | MessageFlags.Ephemeral : payload.flags;
847
+ if (!payloadHasV2Components(payload)) return flags;
848
+ if (payload.content || payload.embeds?.length) throw new Error("Discord Components V2 payloads cannot include content or embeds");
849
+ return (flags ?? 0) | MessageFlags.IsComponentsV2;
850
+ }
851
+ function serializePayload(payload) {
852
+ if (typeof payload === "string") return { content: payload };
853
+ const flags = normalizePayloadFlags(payload);
854
+ return clean$2({
855
+ content: payload.content,
856
+ embeds: payload.embeds?.map((entry) => "serialize" in entry ? entry.serialize() : entry),
857
+ components: payload.components?.map((entry) => serializeAnyComponent(entry)),
858
+ allowed_mentions: payload.allowed_mentions ?? payload.allowedMentions,
859
+ flags,
860
+ tts: payload.tts,
861
+ files: payload.files,
862
+ poll: payload.poll,
863
+ sticker_ids: payload.stickers
864
+ });
865
+ }
866
+ //#endregion
867
+ //#region extensions/discord/src/internal/structures.ts
868
+ var Base = class {
869
+ constructor(client) {
870
+ this.client = client;
871
+ }
872
+ };
873
+ var User = class extends Base {
874
+ constructor(client, rawDataOrId) {
875
+ super(client);
876
+ this.rawDataValue = typeof rawDataOrId === "string" ? null : rawDataOrId;
877
+ this.id = typeof rawDataOrId === "string" ? rawDataOrId : rawDataOrId.id;
878
+ }
879
+ get rawData() {
880
+ if (!this.rawDataValue) throw new Error("Partial Discord user has no raw data");
881
+ return this.rawDataValue;
882
+ }
883
+ get partial() {
884
+ return this.rawDataValue === null;
885
+ }
886
+ get username() {
887
+ return this.rawDataValue?.username ?? "";
888
+ }
889
+ get globalName() {
890
+ return this.rawDataValue?.global_name;
891
+ }
892
+ get discriminator() {
893
+ return this.rawDataValue?.discriminator;
894
+ }
895
+ get bot() {
896
+ return this.rawDataValue?.bot;
897
+ }
898
+ get avatar() {
899
+ return this.rawDataValue?.avatar;
900
+ }
901
+ get avatarUrl() {
902
+ return this.avatar ? `https://cdn.discordapp.com/avatars/${this.id}/${this.avatar}.png` : null;
903
+ }
904
+ toString() {
905
+ return `<@${this.id}>`;
906
+ }
907
+ async fetch() {
908
+ return this.client.fetchUser(this.id);
909
+ }
910
+ async createDm() {
911
+ return await createUserDmChannel(this.client.rest, this.id);
912
+ }
913
+ async send(data) {
914
+ const dm = await this.createDm();
915
+ const message = await createChannelMessage(this.client.rest, dm.id, { body: serializePayload(data) });
916
+ return new Message(this.client, message);
917
+ }
918
+ };
919
+ var Role = class extends Base {
920
+ constructor(client, rawDataOrId) {
921
+ super(client);
922
+ this.rawDataValue = typeof rawDataOrId === "string" ? null : rawDataOrId;
923
+ this.id = typeof rawDataOrId === "string" ? rawDataOrId : rawDataOrId.id;
924
+ }
925
+ get name() {
926
+ return this.rawDataValue?.name ?? "";
927
+ }
928
+ };
929
+ var Guild = class extends Base {
930
+ constructor(client, rawDataOrId) {
931
+ super(client);
932
+ this.rawDataValue = typeof rawDataOrId === "string" ? null : rawDataOrId;
933
+ this.id = typeof rawDataOrId === "string" ? rawDataOrId : rawDataOrId.id;
934
+ }
935
+ get name() {
936
+ return this.rawDataValue?.name ?? "";
937
+ }
938
+ };
939
+ var GuildMember = class extends Base {
940
+ constructor(client, rawData) {
941
+ super(client);
942
+ this.rawData = rawData;
943
+ }
944
+ get user() {
945
+ return this.rawData.user ? new User(this.client, this.rawData.user) : null;
946
+ }
947
+ get roles() {
948
+ return this.rawData.roles ?? [];
949
+ }
950
+ get nickname() {
951
+ return this.rawData.nick ?? void 0;
952
+ }
953
+ };
954
+ var Message = class Message extends Base {
955
+ constructor(client, rawDataOrIds) {
956
+ super(client);
957
+ this.rawDataValue = typeof rawDataOrIds === "string" || !("author" in rawDataOrIds) ? null : rawDataOrIds;
958
+ this.id = typeof rawDataOrIds === "string" ? rawDataOrIds : rawDataOrIds.id;
959
+ this.channelId = typeof rawDataOrIds === "string" ? "" : "channel_id" in rawDataOrIds ? rawDataOrIds.channel_id : rawDataOrIds.channelId ?? "";
960
+ }
961
+ get rawData() {
962
+ if (!this.rawDataValue) throw new Error("Partial Discord message has no raw data");
963
+ return this.rawDataValue;
964
+ }
965
+ get partial() {
966
+ return this.rawDataValue === null;
967
+ }
968
+ get message() {
969
+ return this;
970
+ }
971
+ get channel_id() {
972
+ return this.channelId;
973
+ }
974
+ get guild_id() {
975
+ return this.rawDataValue?.guild_id;
976
+ }
977
+ get guild() {
978
+ return this.guild_id ? new Guild(this.client, this.guild_id) : null;
979
+ }
980
+ get webhookId() {
981
+ return this.webhook_id;
982
+ }
983
+ get webhook_id() {
984
+ return this.rawDataValue?.webhook_id ?? null;
985
+ }
986
+ get member() {
987
+ const member = this.rawDataValue?.member;
988
+ return member ? new GuildMember(this.client, member) : null;
989
+ }
990
+ get rawMember() {
991
+ return this.rawDataValue?.member;
992
+ }
993
+ get content() {
994
+ return this.rawDataValue?.content ?? "";
995
+ }
996
+ get author() {
997
+ return this.rawDataValue?.author ? new User(this.client, this.rawDataValue.author) : null;
998
+ }
999
+ get embeds() {
1000
+ return this.rawDataValue?.embeds ?? [];
1001
+ }
1002
+ get attachments() {
1003
+ return this.rawDataValue?.attachments ?? [];
1004
+ }
1005
+ get stickers() {
1006
+ return this.rawDataValue?.sticker_items ?? [];
1007
+ }
1008
+ get mentionedUsers() {
1009
+ return (this.rawDataValue?.mentions ?? []).map((user) => new User(this.client, user));
1010
+ }
1011
+ get mentionedRoles() {
1012
+ return this.rawDataValue?.mention_roles ?? [];
1013
+ }
1014
+ get mentionedEveryone() {
1015
+ return this.rawDataValue?.mention_everyone ?? false;
1016
+ }
1017
+ get timestamp() {
1018
+ return this.rawDataValue?.timestamp;
1019
+ }
1020
+ get type() {
1021
+ return this.rawDataValue?.type;
1022
+ }
1023
+ get messageReference() {
1024
+ return this.rawDataValue?.message_reference;
1025
+ }
1026
+ get referencedMessage() {
1027
+ return this.rawDataValue?.referenced_message ? new Message(this.client, this.rawDataValue.referenced_message) : null;
1028
+ }
1029
+ get thread() {
1030
+ return this.rawDataValue?.thread ? channelFactory(this.client, this.rawDataValue.thread) : null;
1031
+ }
1032
+ async fetch() {
1033
+ const raw = await getChannelMessage(this.client.rest, this.channelId, this.id);
1034
+ return new Message(this.client, raw);
1035
+ }
1036
+ async delete() {
1037
+ await deleteChannelMessage(this.client.rest, this.channelId, this.id);
1038
+ }
1039
+ async edit(data) {
1040
+ const raw = await editChannelMessage(this.client.rest, this.channelId, this.id, { body: serializePayload(data) });
1041
+ return new Message(this.client, raw);
1042
+ }
1043
+ async reply(data) {
1044
+ const raw = await createChannelMessage(this.client.rest, this.channelId, { body: {
1045
+ ...serializePayload(data),
1046
+ message_reference: {
1047
+ message_id: this.id,
1048
+ fail_if_not_exists: false
1049
+ }
1050
+ } });
1051
+ return new Message(this.client, raw);
1052
+ }
1053
+ async pin() {
1054
+ await pinChannelMessage(this.client.rest, this.channelId, this.id);
1055
+ }
1056
+ async unpin() {
1057
+ await unpinChannelMessage(this.client.rest, this.channelId, this.id);
1058
+ }
1059
+ };
1060
+ function channelFactory(clientForTest, channelData, _partial) {
1061
+ return {
1062
+ ...channelData,
1063
+ rawData: channelData,
1064
+ guildId: "guild_id" in channelData ? channelData.guild_id : void 0,
1065
+ guild: "guild_id" in channelData && typeof channelData.guild_id === "string" ? new Guild(clientForTest, channelData.guild_id) : void 0,
1066
+ parentId: "parent_id" in channelData ? channelData.parent_id : void 0,
1067
+ ownerId: "owner_id" in channelData ? channelData.owner_id : void 0
1068
+ };
1069
+ }
1070
+ //#endregion
1071
+ //#region extensions/discord/src/internal/entity-cache.ts
1072
+ const DEFAULT_REST_CACHE_TTL_MS = 3e4;
1073
+ var DiscordEntityCache = class {
1074
+ constructor(params) {
1075
+ this.params = params;
1076
+ this.entries = /* @__PURE__ */ new Map();
1077
+ }
1078
+ async fetchUser(id) {
1079
+ return await this.fetchCached(`user:${id}`, async () => {
1080
+ const raw = await getUser(this.rest, id);
1081
+ return new User(this.params.client, raw);
1082
+ });
1083
+ }
1084
+ async fetchChannel(id) {
1085
+ return await this.fetchCached(`channel:${id}`, async () => {
1086
+ const raw = await getChannel(this.rest, id);
1087
+ return channelFactory(this.params.client, raw);
1088
+ });
1089
+ }
1090
+ async fetchGuild(id) {
1091
+ return await this.fetchCached(`guild:${id}`, async () => {
1092
+ const raw = await getGuild(this.rest, id);
1093
+ return new Guild(this.params.client, raw);
1094
+ });
1095
+ }
1096
+ async fetchMember(guildId, userId) {
1097
+ return await this.fetchCached(`member:${guildId}:${userId}`, async () => {
1098
+ const raw = await getGuildMember(this.rest, guildId, userId);
1099
+ return new GuildMember(this.params.client, raw);
1100
+ });
1101
+ }
1102
+ invalidateForGatewayEvent(type, data) {
1103
+ const raw = data && typeof data === "object" ? data : {};
1104
+ const channelUpdate = GatewayDispatchEvents.ChannelUpdate;
1105
+ const channelDelete = GatewayDispatchEvents.ChannelDelete;
1106
+ const guildUpdate = GatewayDispatchEvents.GuildUpdate;
1107
+ const guildMemberUpdate = GatewayDispatchEvents.GuildMemberUpdate;
1108
+ if (type === channelUpdate || type === channelDelete) this.deleteId("channel", raw.id);
1109
+ if (type === guildUpdate) this.deleteId("guild", raw.id);
1110
+ if (type === guildMemberUpdate) {
1111
+ const guildId = raw.guild_id;
1112
+ const user = raw.user && typeof raw.user === "object" ? raw.user : {};
1113
+ if (typeof guildId === "string" && typeof user.id === "string") {
1114
+ this.entries.delete(`member:${guildId}:${user.id}`);
1115
+ this.entries.delete(`user:${user.id}`);
1116
+ }
1117
+ }
1118
+ }
1119
+ deleteId(prefix, id) {
1120
+ if (typeof id === "string") this.entries.delete(`${prefix}:${id}`);
1121
+ }
1122
+ async fetchCached(key, fetcher) {
1123
+ const ttl = this.params.ttlMs ?? DEFAULT_REST_CACHE_TTL_MS;
1124
+ if (ttl > 0) {
1125
+ const cached = this.entries.get(key);
1126
+ if (cached && cached.expiresAt > Date.now()) return cached.value;
1127
+ }
1128
+ const value = await fetcher();
1129
+ if (ttl > 0) this.entries.set(key, {
1130
+ expiresAt: Date.now() + ttl,
1131
+ value
1132
+ });
1133
+ return value;
1134
+ }
1135
+ get rest() {
1136
+ return typeof this.params.rest === "function" ? this.params.rest() : this.params.rest;
1137
+ }
1138
+ };
1139
+ //#endregion
1140
+ //#region extensions/discord/src/internal/event-queue.ts
1141
+ const DEFAULT_MAX_QUEUE_SIZE = 1e4;
1142
+ const DEFAULT_MAX_CONCURRENCY = 50;
1143
+ const DEFAULT_LISTENER_TIMEOUT_MS = 12e4;
1144
+ const DEFAULT_SLOW_LISTENER_THRESHOLD_MS = 3e4;
1145
+ var DiscordEventQueue = class {
1146
+ constructor(options = {}) {
1147
+ this.queue = [];
1148
+ this.queueHead = 0;
1149
+ this.processing = 0;
1150
+ this.processedCount = 0;
1151
+ this.droppedCount = 0;
1152
+ this.timeoutCount = 0;
1153
+ this.options = {
1154
+ maxQueueSize: normalizePositiveInteger(options.maxQueueSize, DEFAULT_MAX_QUEUE_SIZE),
1155
+ maxConcurrency: normalizePositiveInteger(options.maxConcurrency, DEFAULT_MAX_CONCURRENCY),
1156
+ listenerTimeout: normalizePositiveInteger(options.listenerTimeout, DEFAULT_LISTENER_TIMEOUT_MS),
1157
+ slowListenerThreshold: normalizePositiveInteger(options.slowListenerThreshold, DEFAULT_SLOW_LISTENER_THRESHOLD_MS)
1158
+ };
1159
+ }
1160
+ enqueue(params) {
1161
+ if (this.pendingQueueSize >= this.options.maxQueueSize) {
1162
+ this.droppedCount += 1;
1163
+ return Promise.reject(/* @__PURE__ */ new Error(`Discord event queue is full for ${params.eventType}; maxQueueSize=${this.options.maxQueueSize}`));
1164
+ }
1165
+ return new Promise((resolve, reject) => {
1166
+ this.queue.push({
1167
+ ...params,
1168
+ resolve,
1169
+ reject
1170
+ });
1171
+ this.processNext();
1172
+ });
1173
+ }
1174
+ getMetrics() {
1175
+ return {
1176
+ queueSize: this.pendingQueueSize,
1177
+ processing: this.processing,
1178
+ processed: this.processedCount,
1179
+ dropped: this.droppedCount,
1180
+ timeouts: this.timeoutCount,
1181
+ maxQueueSize: this.options.maxQueueSize,
1182
+ maxConcurrency: this.options.maxConcurrency
1183
+ };
1184
+ }
1185
+ get pendingQueueSize() {
1186
+ return Math.max(0, this.queue.length - this.queueHead);
1187
+ }
1188
+ takeNextJob() {
1189
+ if (this.queueHead >= this.queue.length) {
1190
+ this.queue.length = 0;
1191
+ this.queueHead = 0;
1192
+ return;
1193
+ }
1194
+ const job = this.queue[this.queueHead];
1195
+ this.queueHead += 1;
1196
+ if (this.queueHead >= this.queue.length) {
1197
+ this.queue.length = 0;
1198
+ this.queueHead = 0;
1199
+ } else if (this.queueHead > 256 && this.queueHead * 2 > this.queue.length) {
1200
+ this.queue.splice(0, this.queueHead);
1201
+ this.queueHead = 0;
1202
+ }
1203
+ return job;
1204
+ }
1205
+ processNext() {
1206
+ while (this.processing < this.options.maxConcurrency && this.pendingQueueSize > 0) {
1207
+ const job = this.takeNextJob();
1208
+ if (!job) return;
1209
+ this.processing += 1;
1210
+ this.runJob(job).then(job.resolve, job.reject).finally(() => {
1211
+ this.processing -= 1;
1212
+ this.processedCount += 1;
1213
+ this.processNext();
1214
+ });
1215
+ }
1216
+ }
1217
+ async runJob(job) {
1218
+ const startedAt = Date.now();
1219
+ try {
1220
+ await this.runWithTimeout(job);
1221
+ this.logSlowListener(job, Date.now() - startedAt);
1222
+ } catch (error) {
1223
+ if (isListenerTimeoutError(error)) {
1224
+ this.timeoutCount += 1;
1225
+ console.error(`[EventQueue] Listener ${job.listenerName} timed out after ${this.options.listenerTimeout}ms for event ${job.eventType}`);
1226
+ return;
1227
+ }
1228
+ console.error(`[EventQueue] Listener ${job.listenerName} failed for event ${job.eventType}:`, error);
1229
+ }
1230
+ }
1231
+ async runWithTimeout(job) {
1232
+ let timeout;
1233
+ try {
1234
+ await Promise.race([job.run(), new Promise((_, reject) => {
1235
+ timeout = setTimeout(() => {
1236
+ reject(createListenerTimeoutError(this.options.listenerTimeout));
1237
+ }, this.options.listenerTimeout);
1238
+ timeout.unref?.();
1239
+ })]);
1240
+ } finally {
1241
+ if (timeout) clearTimeout(timeout);
1242
+ }
1243
+ }
1244
+ logSlowListener(job, durationMs) {
1245
+ if (durationMs < this.options.slowListenerThreshold) return;
1246
+ console.warn(`[EventQueue] Slow listener detected: ${job.listenerName} took ${durationMs}ms for event ${job.eventType}`);
1247
+ }
1248
+ };
1249
+ function normalizePositiveInteger(value, fallback) {
1250
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return fallback;
1251
+ return Math.max(1, Math.floor(value));
1252
+ }
1253
+ function createListenerTimeoutError(timeoutMs) {
1254
+ const error = /* @__PURE__ */ new Error(`Listener timeout after ${timeoutMs}ms`);
1255
+ error.name = "DiscordEventQueueListenerTimeoutError";
1256
+ return error;
1257
+ }
1258
+ function isListenerTimeoutError(error) {
1259
+ return error instanceof Error && error.name === "DiscordEventQueueListenerTimeoutError";
1260
+ }
1261
+ //#endregion
1262
+ //#region extensions/discord/src/internal/commands.ts
1263
+ function clean$1(value) {
1264
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
1265
+ }
1266
+ function resolveConditionalCommandOption(value, interaction) {
1267
+ return typeof value === "function" ? value(interaction) : value;
1268
+ }
1269
+ async function deferCommandInteractionIfNeeded(command, interaction) {
1270
+ if (!resolveConditionalCommandOption(command.defer, interaction)) return;
1271
+ await interaction.defer({ ephemeral: resolveConditionalCommandOption(command.ephemeral, interaction) });
1272
+ }
1273
+ function readRawCommandOptions(interaction) {
1274
+ const options = interaction.rawData.data?.options;
1275
+ return Array.isArray(options) ? options : [];
1276
+ }
1277
+ function findSelectedSubcommand(subcommands, interaction) {
1278
+ const subcommandName = readRawCommandOptions(interaction).find((option) => option.type === ApplicationCommandOptionType.Subcommand)?.name;
1279
+ return typeof subcommandName === "string" ? subcommands.find((command) => command.name === subcommandName) : void 0;
1280
+ }
1281
+ function findCommandOption(options, name) {
1282
+ if (!name) return;
1283
+ return options?.find((option) => option.name === name);
1284
+ }
1285
+ function hasCommandOptions(command) {
1286
+ return "options" in command;
1287
+ }
1288
+ function resolveFocusedCommandOptionAutocompleteHandler(command, interaction) {
1289
+ const focusedName = interaction.options.getFocused()?.name;
1290
+ const autocomplete = findCommandOption("subcommands" in command && Array.isArray(command.subcommands) ? findSelectedSubcommand(command.subcommands, interaction)?.options : hasCommandOptions(command) ? command.options : void 0, focusedName)?.autocomplete;
1291
+ return typeof autocomplete === "function" ? autocomplete : void 0;
1292
+ }
1293
+ var BaseCommand = class {
1294
+ constructor() {
1295
+ this.defer = false;
1296
+ this.ephemeral = false;
1297
+ this.integrationTypes = [0, 1];
1298
+ this.contexts = [
1299
+ InteractionContextType.Guild,
1300
+ InteractionContextType.BotDM,
1301
+ InteractionContextType.PrivateChannel
1302
+ ];
1303
+ }
1304
+ serialize() {
1305
+ return clean$1({
1306
+ name: this.name,
1307
+ name_localizations: this.nameLocalizations,
1308
+ description: this.type === ApplicationCommandType.ChatInput ? this.description ?? "" : void 0,
1309
+ description_localizations: this.descriptionLocalizations,
1310
+ type: this.type,
1311
+ options: this.serializeOptions(),
1312
+ integration_types: this.integrationTypes,
1313
+ contexts: this.contexts,
1314
+ default_member_permissions: Array.isArray(this.permission) ? this.permission.reduce((sum, entry) => sum | entry, 0n).toString() : this.permission ? this.permission.toString() : null
1315
+ });
1316
+ }
1317
+ };
1318
+ var Command = class extends BaseCommand {
1319
+ constructor(..._args) {
1320
+ super(..._args);
1321
+ this.type = ApplicationCommandType.ChatInput;
1322
+ }
1323
+ async autocomplete(interaction) {
1324
+ throw new Error(`The ${interaction.rawData?.data?.name ?? this.name} command does not support autocomplete`);
1325
+ }
1326
+ async preCheck(interaction) {
1327
+ return Boolean(interaction) || true;
1328
+ }
1329
+ serializeOptions() {
1330
+ return this.options?.map((option) => {
1331
+ if (typeof option.autocomplete === "function") {
1332
+ const { autocomplete: _autocomplete, ...rest } = option;
1333
+ return {
1334
+ ...rest,
1335
+ autocomplete: true
1336
+ };
1337
+ }
1338
+ return option;
1339
+ });
1340
+ }
1341
+ };
1342
+ var CommandWithSubcommands = class extends BaseCommand {
1343
+ constructor(..._args2) {
1344
+ super(..._args2);
1345
+ this.type = ApplicationCommandType.ChatInput;
1346
+ }
1347
+ async run(interaction) {
1348
+ const subcommand = findSelectedSubcommand(this.subcommands, interaction);
1349
+ if (!subcommand) {
1350
+ const subcommandName = readRawCommandOptions(interaction).find((option) => option.type === ApplicationCommandOptionType.Subcommand)?.name;
1351
+ throw new Error(`Unknown Discord subcommand: ${typeof subcommandName === "string" ? subcommandName : "<missing>"}`);
1352
+ }
1353
+ await deferCommandInteractionIfNeeded(subcommand, interaction);
1354
+ return await subcommand.run(interaction);
1355
+ }
1356
+ serializeOptions() {
1357
+ return this.subcommands.map((command) => clean$1({
1358
+ name: command.name,
1359
+ name_localizations: command.nameLocalizations,
1360
+ description: command.description ?? "",
1361
+ description_localizations: command.descriptionLocalizations,
1362
+ type: ApplicationCommandOptionType.Subcommand,
1363
+ options: command.serializeOptions()
1364
+ }));
1365
+ }
1366
+ };
1367
+ //#endregion
1368
+ //#region extensions/discord/src/internal/interaction-options.ts
1369
+ function readFocusedOption(options) {
1370
+ for (const option of options ?? []) {
1371
+ if ("focused" in option && option.focused) return option;
1372
+ const child = readFocusedOption(readChildOptions(option));
1373
+ if (child) return child;
1374
+ }
1375
+ }
1376
+ function findOption(options, name) {
1377
+ for (const option of options ?? []) {
1378
+ if (option.name === name) return option;
1379
+ const child = findOption(readChildOptions(option), name);
1380
+ if (child) return child;
1381
+ }
1382
+ }
1383
+ function readChildOptions(option) {
1384
+ if (!("options" in option) || !Array.isArray(option.options)) return;
1385
+ return option.options;
1386
+ }
1387
+ var OptionsHandler = class {
1388
+ constructor(rawOptions, client, resolvedChannels) {
1389
+ this.rawOptions = rawOptions;
1390
+ this.client = client;
1391
+ this.resolvedChannels = resolvedChannels;
1392
+ }
1393
+ getString(name) {
1394
+ const option = findOption(this.rawOptions, name);
1395
+ const value = option && "value" in option ? option.value : void 0;
1396
+ return typeof value === "string" ? value : null;
1397
+ }
1398
+ getNumber(name) {
1399
+ const option = findOption(this.rawOptions, name);
1400
+ const value = option && "value" in option ? option.value : void 0;
1401
+ return typeof value === "number" ? value : null;
1402
+ }
1403
+ getBoolean(name) {
1404
+ const option = findOption(this.rawOptions, name);
1405
+ const value = option && "value" in option ? option.value : void 0;
1406
+ return typeof value === "boolean" ? value : null;
1407
+ }
1408
+ async getChannel(name, required = false) {
1409
+ const option = findOption(this.rawOptions, name);
1410
+ const value = option && "value" in option ? option.value : void 0;
1411
+ const id = typeof value === "string" ? value : void 0;
1412
+ const resolved = id ? this.resolvedChannels?.[id] : void 0;
1413
+ if (resolved) return channelFactory(this.client, resolved);
1414
+ if (id) return await this.client.fetchChannel(id);
1415
+ if (required) throw new Error(`Missing required channel option ${name}`);
1416
+ return null;
1417
+ }
1418
+ getFocused() {
1419
+ return readFocusedOption(this.rawOptions);
1420
+ }
1421
+ };
1422
+ //#endregion
1423
+ //#region extensions/discord/src/internal/interaction-response.ts
1424
+ var InteractionResponseController = class {
1425
+ constructor() {
1426
+ this.state = "unacknowledged";
1427
+ }
1428
+ get acknowledged() {
1429
+ return this.state !== "unacknowledged";
1430
+ }
1431
+ recordCallback(type) {
1432
+ if (type === InteractionResponseType.DeferredChannelMessageWithSource) {
1433
+ this.state = "deferred";
1434
+ return;
1435
+ }
1436
+ if (type === InteractionResponseType.DeferredMessageUpdate) {
1437
+ this.state = "deferred-update";
1438
+ return;
1439
+ }
1440
+ this.state = "replied";
1441
+ }
1442
+ nextReplyAction() {
1443
+ if (this.state === "deferred" || this.state === "deferred-update") return "edit";
1444
+ if (this.state === "unacknowledged") return "initial";
1445
+ return "follow-up";
1446
+ }
1447
+ recordReplyEdit() {
1448
+ this.state = "replied";
1449
+ }
1450
+ };
1451
+ function needsComponentsV2Query(body) {
1452
+ return body !== null && typeof body === "object" && "flags" in body && typeof body.flags === "number" && (body.flags & MessageFlags.IsComponentsV2) !== 0;
1453
+ }
1454
+ //#endregion
1455
+ //#region extensions/discord/src/internal/modal-fields.ts
1456
+ function extractModalFields(components) {
1457
+ const out = {};
1458
+ for (const component of flattenModalComponents(components)) {
1459
+ const raw = component;
1460
+ if (typeof raw.custom_id !== "string") continue;
1461
+ if (Array.isArray(raw.values)) out[raw.custom_id] = raw.values.map(String);
1462
+ else if (typeof raw.value === "string" || typeof raw.value === "number" || typeof raw.value === "boolean") out[raw.custom_id] = String(raw.value);
1463
+ }
1464
+ return out;
1465
+ }
1466
+ function flattenModalComponents(components) {
1467
+ const out = [];
1468
+ for (const entry of components) {
1469
+ if (!entry || typeof entry !== "object") continue;
1470
+ const component = entry;
1471
+ if (component.component && typeof component.component === "object") out.push(component.component);
1472
+ if (Array.isArray(component.components)) out.push(...flattenModalComponents(component.components));
1473
+ out.push(entry);
1474
+ }
1475
+ return out;
1476
+ }
1477
+ var ModalFields = class {
1478
+ constructor(values, resolved, client) {
1479
+ this.values = values;
1480
+ this.resolved = resolved;
1481
+ this.client = client;
1482
+ }
1483
+ value(id, required) {
1484
+ const value = this.values[id];
1485
+ if (required && (value === void 0 || Array.isArray(value) && value.length === 0)) throw new Error(`Missing required modal field ${id}`);
1486
+ return value;
1487
+ }
1488
+ getText(id, required = false) {
1489
+ const value = this.value(id, required);
1490
+ return typeof value === "string" ? value : null;
1491
+ }
1492
+ getStringSelect(id, required = false) {
1493
+ const value = this.value(id, required);
1494
+ if (Array.isArray(value)) return value;
1495
+ return typeof value === "string" ? [value] : [];
1496
+ }
1497
+ getRoleSelect(id, required = false) {
1498
+ return this.getStringSelect(id, required).map((roleId) => {
1499
+ const raw = this.resolved?.roles?.[roleId];
1500
+ return raw ? new Role(this.client, {
1501
+ id: roleId,
1502
+ name: raw.name ?? ""
1503
+ }) : new Role(this.client, roleId);
1504
+ });
1505
+ }
1506
+ getUserSelect(id, required = false) {
1507
+ return this.getStringSelect(id, required).map((userId) => {
1508
+ const raw = this.resolved?.users?.[userId];
1509
+ return new User(this.client, {
1510
+ id: userId,
1511
+ username: raw?.username ?? ""
1512
+ });
1513
+ });
1514
+ }
1515
+ };
1516
+ //#endregion
1517
+ //#region extensions/discord/src/internal/schemas.ts
1518
+ const discordInteractionPayloadSchema = Type.Object({
1519
+ id: Type.String({ minLength: 1 }),
1520
+ token: Type.String({ minLength: 1 }),
1521
+ type: Type.Number()
1522
+ }, { additionalProperties: true });
1523
+ const discordRateLimitBodySchema = Type.Object({
1524
+ message: Type.Optional(Type.String()),
1525
+ retry_after: Type.Optional(Type.Union([Type.Number(), Type.String()])),
1526
+ global: Type.Optional(Type.Boolean()),
1527
+ code: Type.Optional(Type.Union([Type.Number(), Type.String()]))
1528
+ }, { additionalProperties: true });
1529
+ function assertDiscordInteractionPayload(value) {
1530
+ if (!Check(discordInteractionPayloadSchema, value)) throw new Error("Invalid Discord interaction payload");
1531
+ }
1532
+ function isDiscordRateLimitBody(value) {
1533
+ return Check(discordRateLimitBodySchema, value);
1534
+ }
1535
+ //#endregion
1536
+ //#region extensions/discord/src/internal/interactions.ts
1537
+ function toCommandRawInteraction(rawData) {
1538
+ return rawData;
1539
+ }
1540
+ function toMessageComponentRawInteraction(rawData) {
1541
+ return rawData;
1542
+ }
1543
+ function toModalSubmitRawInteraction(rawData) {
1544
+ return rawData;
1545
+ }
1546
+ function readInteractionUser(rawData, client) {
1547
+ const directUser = "user" in rawData ? rawData.user : void 0;
1548
+ if (directUser && typeof directUser === "object" && "id" in directUser) return new User(client, directUser);
1549
+ const memberUser = rawData.member?.user;
1550
+ if (memberUser && typeof memberUser === "object" && typeof memberUser.id === "string") {
1551
+ const user = { ...memberUser };
1552
+ if (typeof user.username !== "string") user.username = "";
1553
+ return new User(client, user);
1554
+ }
1555
+ return null;
1556
+ }
1557
+ var BaseInteraction = class {
1558
+ constructor(client, rawData) {
1559
+ this.client = client;
1560
+ this.rawData = rawData;
1561
+ this.message = null;
1562
+ this.response = new InteractionResponseController();
1563
+ this.id = rawData.id;
1564
+ this.token = rawData.token;
1565
+ this.user = readInteractionUser(rawData, client);
1566
+ this.userId = this.user?.id ?? "";
1567
+ this.guild = rawData.guild_id ? new Guild(client, rawData.guild_id) : null;
1568
+ this.channel = "channel" in rawData && rawData.channel ? channelFactory(client, rawData.channel) : null;
1569
+ }
1570
+ get acknowledged() {
1571
+ return this.response.acknowledged;
1572
+ }
1573
+ get responseState() {
1574
+ return this.response.state;
1575
+ }
1576
+ set responseState(nextState) {
1577
+ this.response.state = nextState;
1578
+ }
1579
+ async callback(type, data) {
1580
+ this.response.recordCallback(type);
1581
+ return await createInteractionCallback(this.client.rest, this.id, this.token, data === void 0 ? { type } : {
1582
+ type,
1583
+ data
1584
+ });
1585
+ }
1586
+ async reply(payload) {
1587
+ const action = this.response.nextReplyAction();
1588
+ if (action === "edit") return await this.editReply(payload);
1589
+ if (action === "follow-up") return await this.followUp(payload);
1590
+ return await this.callback(InteractionResponseType.ChannelMessageWithSource, serializePayload(payload));
1591
+ }
1592
+ async defer(options) {
1593
+ return await this.callback(InteractionResponseType.DeferredChannelMessageWithSource, options?.ephemeral ? { flags: 64 } : void 0);
1594
+ }
1595
+ async acknowledge() {
1596
+ return await this.defer();
1597
+ }
1598
+ async editReply(payload) {
1599
+ const body = serializePayload(payload);
1600
+ const query = needsComponentsV2Query(body) ? { with_components: true } : void 0;
1601
+ const result = query ? await editWebhookMessage(this.client.rest, this.client.options.clientId, this.token, "@original", { body }, query) : await editWebhookMessage(this.client.rest, this.client.options.clientId, this.token, "@original", { body });
1602
+ this.response.recordReplyEdit();
1603
+ return result;
1604
+ }
1605
+ async deleteReply() {
1606
+ return await deleteWebhookMessage(this.client.rest, this.client.options.clientId, this.token, "@original");
1607
+ }
1608
+ async fetchReply() {
1609
+ return await getWebhookMessage(this.client.rest, this.client.options.clientId, this.token, "@original");
1610
+ }
1611
+ async replyAndWaitForComponent(payload, timeoutMs = 3e5) {
1612
+ const result = await this.reply(payload);
1613
+ const rawMessage = isRawMessage(result) ? result : await this.fetchReply();
1614
+ if (!isRawMessage(rawMessage)) throw new Error("Discord interaction reply did not return a message");
1615
+ const message = new Message(this.client, rawMessage);
1616
+ return await this.client.componentHandler.waitForMessageComponent(message, timeoutMs);
1617
+ }
1618
+ async followUp(payload) {
1619
+ const body = serializePayload(payload);
1620
+ return await createWebhookMessage(this.client.rest, this.client.options.clientId, this.token, { body }, needsComponentsV2Query(body) ? { with_components: true } : void 0);
1621
+ }
1622
+ };
1623
+ var CommandInteraction = class extends BaseInteraction {
1624
+ constructor(client, rawData) {
1625
+ super(client, rawData);
1626
+ this.options = new OptionsHandler(rawData.data.options, client, rawData.data.resolved?.channels);
1627
+ }
1628
+ };
1629
+ var AutocompleteInteraction = class extends CommandInteraction {
1630
+ async respond(choices) {
1631
+ return await this.callback(InteractionResponseType.ApplicationCommandAutocompleteResult, { choices });
1632
+ }
1633
+ };
1634
+ var BaseComponentInteraction = class extends BaseInteraction {
1635
+ constructor(client, rawData) {
1636
+ super(client, rawData);
1637
+ this.message = rawData.message && typeof rawData.message === "object" ? new Message(client, rawData.message) : null;
1638
+ this.values = Array.isArray(rawData.data.values) ? rawData.data.values.map(String) : [];
1639
+ }
1640
+ async update(payload) {
1641
+ return await this.callback(InteractionResponseType.UpdateMessage, serializePayload(payload));
1642
+ }
1643
+ async acknowledge() {
1644
+ return await this.callback(InteractionResponseType.DeferredMessageUpdate);
1645
+ }
1646
+ async showModal(modal) {
1647
+ return await this.callback(InteractionResponseType.Modal, modal.serialize());
1648
+ }
1649
+ async editAndWaitForComponent(payload, message = this.message, timeoutMs = 3e5) {
1650
+ if (!message) return null;
1651
+ const editedMessage = await message.edit(payload);
1652
+ return await this.client.componentHandler.waitForMessageComponent(editedMessage, timeoutMs);
1653
+ }
1654
+ };
1655
+ var ButtonInteraction = class extends BaseComponentInteraction {};
1656
+ var StringSelectMenuInteraction = class extends BaseComponentInteraction {};
1657
+ var UserSelectMenuInteraction = class extends BaseComponentInteraction {};
1658
+ var RoleSelectMenuInteraction = class extends BaseComponentInteraction {};
1659
+ var MentionableSelectMenuInteraction = class extends BaseComponentInteraction {};
1660
+ var ChannelSelectMenuInteraction = class extends BaseComponentInteraction {};
1661
+ var ModalInteraction = class extends BaseInteraction {
1662
+ constructor(client, rawData) {
1663
+ super(client, rawData);
1664
+ this.fields = new ModalFields(extractModalFields(rawData.data.components ?? []), rawData.data.resolved, client);
1665
+ }
1666
+ async acknowledge() {
1667
+ return await this.callback(InteractionResponseType.DeferredMessageUpdate);
1668
+ }
1669
+ };
1670
+ function createInteraction(client, rawData) {
1671
+ assertDiscordInteractionPayload(rawData);
1672
+ if (rawData.type === InteractionType.ApplicationCommandAutocomplete) return new AutocompleteInteraction(client, toCommandRawInteraction(rawData));
1673
+ if (rawData.type === InteractionType.ApplicationCommand) return new CommandInteraction(client, toCommandRawInteraction(rawData));
1674
+ if (rawData.type === InteractionType.ModalSubmit) return new ModalInteraction(client, toModalSubmitRawInteraction(rawData));
1675
+ if (rawData.type === InteractionType.MessageComponent) {
1676
+ const componentRawData = toMessageComponentRawInteraction(rawData);
1677
+ switch (rawData.data?.component_type) {
1678
+ case ComponentType.Button: return new ButtonInteraction(client, componentRawData);
1679
+ case ComponentType.StringSelect: return new StringSelectMenuInteraction(client, componentRawData);
1680
+ case ComponentType.UserSelect: return new UserSelectMenuInteraction(client, componentRawData);
1681
+ case ComponentType.RoleSelect: return new RoleSelectMenuInteraction(client, componentRawData);
1682
+ case ComponentType.MentionableSelect: return new MentionableSelectMenuInteraction(client, componentRawData);
1683
+ case ComponentType.ChannelSelect: return new ChannelSelectMenuInteraction(client, componentRawData);
1684
+ default: return new BaseComponentInteraction(client, componentRawData);
1685
+ }
1686
+ }
1687
+ return new BaseInteraction(client, rawData);
1688
+ }
1689
+ function parseComponentInteractionData(component, customId) {
1690
+ return component.customIdParser(customId).data;
1691
+ }
1692
+ function isRawMessage(value) {
1693
+ return Boolean(value) && typeof value === "object" && typeof value.id === "string" && typeof value.channel_id === "string";
1694
+ }
1695
+ //#endregion
1696
+ //#region extensions/discord/src/internal/interaction-dispatch.ts
1697
+ async function dispatchInteraction(client, rawData) {
1698
+ const interaction = createInteraction(client, rawData);
1699
+ if (rawData.type === InteractionType.ApplicationCommandAutocomplete) {
1700
+ const command = client.commands.find((entry) => entry.name === readInteractionName(rawData));
1701
+ if (!command) return;
1702
+ const autocompleteInteraction = interaction;
1703
+ const optionAutocomplete = resolveFocusedCommandOptionAutocompleteHandler(command, autocompleteInteraction);
1704
+ if (optionAutocomplete) {
1705
+ await optionAutocomplete(autocompleteInteraction);
1706
+ return;
1707
+ }
1708
+ if ("autocomplete" in command) await command.autocomplete(autocompleteInteraction);
1709
+ return;
1710
+ }
1711
+ if (rawData.type === InteractionType.ApplicationCommand) {
1712
+ const command = client.commands.find((entry) => entry.name === readInteractionName(rawData));
1713
+ if (command && "run" in command) {
1714
+ await deferCommandInteractionIfNeeded(command, interaction);
1715
+ await command.run(interaction);
1716
+ }
1717
+ return;
1718
+ }
1719
+ if (rawData.type === InteractionType.MessageComponent) {
1720
+ const customId = readCustomId(rawData);
1721
+ if (!customId) return;
1722
+ const componentInteraction = interaction;
1723
+ if (client.componentHandler.resolveOneOffComponent({
1724
+ channelId: readMessageChannelId(rawData),
1725
+ customId,
1726
+ messageId: readMessageId(rawData),
1727
+ values: readComponentValues(rawData)
1728
+ })) {
1729
+ await componentInteraction.acknowledge();
1730
+ return;
1731
+ }
1732
+ const component = client.componentHandler.resolve(customId, { componentType: rawData.data?.component_type });
1733
+ if (component) {
1734
+ await deferComponentInteractionIfNeeded(component, componentInteraction);
1735
+ await component.run(componentInteraction, parseComponentInteractionData(component, customId));
1736
+ }
1737
+ return;
1738
+ }
1739
+ if (rawData.type === InteractionType.ModalSubmit) {
1740
+ const customId = readCustomId(rawData);
1741
+ if (!customId) return;
1742
+ const modal = client.modalHandler.resolve(customId);
1743
+ if (modal) await modal.run(interaction, modal.customIdParser(customId).data);
1744
+ }
1745
+ }
1746
+ function resolveConditionalComponentOption(value, interaction) {
1747
+ return typeof value === "function" ? value(interaction) : value;
1748
+ }
1749
+ async function deferComponentInteractionIfNeeded(component, interaction) {
1750
+ if (!resolveConditionalComponentOption(component.defer, interaction)) return;
1751
+ if (resolveConditionalComponentOption(component.ephemeral, interaction)) {
1752
+ await interaction.defer({ ephemeral: true });
1753
+ return;
1754
+ }
1755
+ await interaction.acknowledge();
1756
+ }
1757
+ function readInteractionName(rawData) {
1758
+ return rawData.data?.name;
1759
+ }
1760
+ function readCustomId(rawData) {
1761
+ return rawData.data?.custom_id;
1762
+ }
1763
+ function readComponentValues(rawData) {
1764
+ const values = rawData.data?.values;
1765
+ return Array.isArray(values) ? values.map(String) : void 0;
1766
+ }
1767
+ function readMessageId(rawData) {
1768
+ const messageId = rawData.message?.id;
1769
+ return typeof messageId === "string" ? messageId : void 0;
1770
+ }
1771
+ function readMessageChannelId(rawData) {
1772
+ const channelId = rawData.message?.channel_id;
1773
+ return typeof channelId === "string" ? channelId : void 0;
1774
+ }
1775
+ //#endregion
1776
+ //#region extensions/discord/src/internal/rest-body.ts
1777
+ function serializeRequestBody(data, headers) {
1778
+ if (data?.headers) for (const [key, value] of Object.entries(data.headers)) headers.set(key, value);
1779
+ if (data?.body == null) return;
1780
+ if (typeof data.body === "object") {
1781
+ const bodyObject = data.body;
1782
+ const topLevelFiles = Array.isArray(bodyObject.files) ? bodyObject.files : void 0;
1783
+ const nestedData = bodyObject.data && typeof bodyObject.data === "object" ? bodyObject.data : void 0;
1784
+ const nestedFiles = nestedData && Array.isArray(nestedData.files) ? nestedData.files : void 0;
1785
+ const files = topLevelFiles ?? nestedFiles;
1786
+ const filesContainer = topLevelFiles ? bodyObject : nestedFiles ? nestedData : void 0;
1787
+ if (files?.length && filesContainer) {
1788
+ if (data.multipartStyle === "form") {
1789
+ const formData = new FormData();
1790
+ for (const [key, value] of Object.entries(filesContainer)) {
1791
+ if (key === "files" || value === void 0 || value === null) continue;
1792
+ formData.append(key, typeof value === "string" ? value : JSON.stringify(value));
1793
+ }
1794
+ for (const file of files) {
1795
+ const item = file;
1796
+ const name = typeof item.name === "string" && item.name ? item.name : "file";
1797
+ const blob = item.data instanceof Blob ? item.data : new Blob([item.data], { type: typeof item.contentType === "string" ? item.contentType : void 0 });
1798
+ formData.append(typeof item.fieldName === "string" && item.fieldName ? item.fieldName : "file", blob, name);
1799
+ }
1800
+ return formData;
1801
+ }
1802
+ const payloadJson = topLevelFiles ? { ...bodyObject } : {
1803
+ ...bodyObject,
1804
+ data: { ...nestedData }
1805
+ };
1806
+ const payloadFilesContainer = topLevelFiles ? payloadJson : payloadJson.data ?? {};
1807
+ const formData = new FormData();
1808
+ const existingAttachments = Array.isArray(payloadFilesContainer.attachments) ? [...payloadFilesContainer.attachments] : [];
1809
+ const uploaded = files.map((file, index) => {
1810
+ const item = file;
1811
+ const name = typeof item.name === "string" && item.name ? item.name : `file-${index}`;
1812
+ const blob = item.data instanceof Blob ? item.data : new Blob([item.data], { type: typeof item.contentType === "string" ? item.contentType : void 0 });
1813
+ const id = existingAttachments.length + index;
1814
+ formData.append(`files[${id}]`, blob, name);
1815
+ const attachment = {
1816
+ id,
1817
+ filename: name
1818
+ };
1819
+ if (typeof item.description === "string") attachment.description = item.description;
1820
+ if (typeof item.duration_secs === "number") attachment.duration_secs = item.duration_secs;
1821
+ if (typeof item.waveform === "string") attachment.waveform = item.waveform;
1822
+ return attachment;
1823
+ });
1824
+ payloadFilesContainer.attachments = [...existingAttachments, ...uploaded];
1825
+ delete payloadFilesContainer.files;
1826
+ formData.append("payload_json", JSON.stringify(payloadJson));
1827
+ return formData;
1828
+ }
1829
+ }
1830
+ if (!data.rawBody) headers.set("Content-Type", "application/json");
1831
+ return data.rawBody ? data.body : JSON.stringify(data.body);
1832
+ }
1833
+ //#endregion
1834
+ //#region extensions/discord/src/internal/rest-errors.ts
1835
+ function readDiscordCode(body) {
1836
+ const value = body && typeof body === "object" && "code" in body ? body.code : void 0;
1837
+ if (typeof value === "number" && Number.isFinite(value)) return value;
1838
+ if (typeof value === "string" && /^\d+$/.test(value)) return Number(value);
1839
+ }
1840
+ function readDiscordMessage(body, fallback) {
1841
+ const value = body && typeof body === "object" && "message" in body ? body.message : void 0;
1842
+ return typeof value === "string" && value.trim() ? value : fallback;
1843
+ }
1844
+ function readRetryAfterHeader(value, now = Date.now()) {
1845
+ if (!value) return;
1846
+ const seconds = Number(value);
1847
+ if (Number.isFinite(seconds)) return seconds;
1848
+ const retryAt = Date.parse(value);
1849
+ return Number.isFinite(retryAt) ? (retryAt - now) / 1e3 : void 0;
1850
+ }
1851
+ function coerceRetryAfterSeconds(value) {
1852
+ if (typeof value !== "number" && typeof value !== "string") return;
1853
+ const seconds = typeof value === "number" ? value : Number(value);
1854
+ return Number.isFinite(seconds) && seconds >= 0 ? Math.max(0, seconds) : void 0;
1855
+ }
1856
+ function readRetryAfter(body, response, fallbackSeconds = 0) {
1857
+ return coerceRetryAfterSeconds(body && typeof body === "object" && "retry_after" in body ? body.retry_after : void 0) ?? coerceRetryAfterSeconds(readRetryAfterHeader(response.headers.get("Retry-After"))) ?? fallbackSeconds;
1858
+ }
1859
+ var DiscordError = class extends Error {
1860
+ constructor(response, body) {
1861
+ super(readDiscordMessage(body, `Discord API request failed (${response.status})`));
1862
+ this.name = "DiscordError";
1863
+ this.status = response.status;
1864
+ this.statusCode = response.status;
1865
+ this.rawBody = body;
1866
+ this.rawError = body;
1867
+ this.discordCode = readDiscordCode(body);
1868
+ }
1869
+ };
1870
+ var RateLimitError = class extends DiscordError {
1871
+ constructor(response, body) {
1872
+ super(response, body);
1873
+ this.name = "RateLimitError";
1874
+ this.retryAfter = readRetryAfter(body, response, 1);
1875
+ this.scope = body.global ? "global" : response.headers.get("X-RateLimit-Scope");
1876
+ this.bucket = response.headers.get("X-RateLimit-Bucket");
1877
+ }
1878
+ };
1879
+ //#endregion
1880
+ //#region extensions/discord/src/internal/rest-routes.ts
1881
+ function createRouteKey(method, path) {
1882
+ return `${method.toUpperCase()} ${path.split("?")[0] ?? path}`;
1883
+ }
1884
+ function readTopLevelRouteKey(path) {
1885
+ const [pathname = path] = path.split("?");
1886
+ const [first, id, token] = pathname.replace(/^\/+/, "").split("/");
1887
+ if (!first || !id) return pathname;
1888
+ if (first === "channels" || first === "guilds" || first === "webhooks") return first === "webhooks" && token ? `${first}/${id}/${token}` : `${first}/${id}`;
1889
+ return first;
1890
+ }
1891
+ function createBucketKey(bucket, path) {
1892
+ return `${bucket}:${readTopLevelRouteKey(path)}`;
1893
+ }
1894
+ function readHeaderNumber(headers, name) {
1895
+ const value = headers.get(name);
1896
+ if (!value) return;
1897
+ const parsed = Number(value);
1898
+ return Number.isFinite(parsed) ? parsed : void 0;
1899
+ }
1900
+ function readResetAt(response) {
1901
+ const resetAfter = readHeaderNumber(response.headers, "X-RateLimit-Reset-After");
1902
+ if (resetAfter !== void 0) return Date.now() + Math.max(0, resetAfter * 1e3);
1903
+ const reset = readHeaderNumber(response.headers, "X-RateLimit-Reset");
1904
+ return reset !== void 0 ? reset * 1e3 : void 0;
1905
+ }
1906
+ function appendQuery(path, query) {
1907
+ if (!query || Object.keys(query).length === 0) return path;
1908
+ const search = new URLSearchParams();
1909
+ for (const [key, value] of Object.entries(query)) search.set(key, String(value));
1910
+ return `${path}?${search.toString()}`;
1911
+ }
1912
+ //#endregion
1913
+ //#region extensions/discord/src/internal/rest-scheduler.ts
1914
+ const INVALID_REQUEST_WINDOW_MS = 10 * 6e4;
1915
+ const requestPriorities = [
1916
+ "critical",
1917
+ "standard",
1918
+ "background"
1919
+ ];
1920
+ function createLaneQueues() {
1921
+ return {
1922
+ critical: [],
1923
+ standard: [],
1924
+ background: []
1925
+ };
1926
+ }
1927
+ function countPending(bucket) {
1928
+ return requestPriorities.reduce((count, lane) => count + bucket.pending[lane].length, 0);
1929
+ }
1930
+ var RestScheduler = class {
1931
+ constructor(options, executor) {
1932
+ this.options = options;
1933
+ this.executor = executor;
1934
+ this.activeWorkers = 0;
1935
+ this.buckets = /* @__PURE__ */ new Map();
1936
+ this.globalRateLimitUntil = 0;
1937
+ this.invalidRequestTimestamps = [];
1938
+ this.laneCursor = 0;
1939
+ this.laneDropped = {
1940
+ critical: 0,
1941
+ standard: 0,
1942
+ background: 0
1943
+ };
1944
+ this.queuedByLane = {
1945
+ critical: 0,
1946
+ standard: 0,
1947
+ background: 0
1948
+ };
1949
+ this.queueGeneration = 0;
1950
+ this.queuedRequests = 0;
1951
+ this.routeBuckets = /* @__PURE__ */ new Map();
1952
+ this.laneSchedule = this.buildLaneSchedule(options.lanes);
1953
+ }
1954
+ enqueue(params) {
1955
+ if (this.queuedRequests >= this.options.maxQueueSize) throw new Error("Discord request queue is full");
1956
+ const laneOptions = this.options.lanes[params.priority];
1957
+ if (this.queuedByLane[params.priority] >= laneOptions.maxQueueSize) {
1958
+ this.laneDropped[params.priority] += 1;
1959
+ throw new Error(`Discord ${params.priority} request queue is full (${this.queuedByLane[params.priority]} / ${laneOptions.maxQueueSize})`);
1960
+ }
1961
+ const routeKey = createRouteKey(params.method, params.path);
1962
+ const bucket = this.getBucket(this.routeBuckets.get(routeKey) ?? routeKey);
1963
+ return new Promise((resolve, reject) => {
1964
+ this.queuedRequests += 1;
1965
+ this.queuedByLane[params.priority] += 1;
1966
+ bucket.pending[params.priority].push({
1967
+ ...params,
1968
+ enqueuedAt: Date.now(),
1969
+ generation: this.queueGeneration,
1970
+ routeKey,
1971
+ retryCount: 0,
1972
+ resolve,
1973
+ reject
1974
+ });
1975
+ this.drainQueues();
1976
+ });
1977
+ }
1978
+ recordResponse(routeKey, path, response, parsed) {
1979
+ this.updateRateLimitState(routeKey, path, response, parsed);
1980
+ this.recordInvalidRequest(routeKey, path, response);
1981
+ }
1982
+ clearQueue() {
1983
+ this.queueGeneration += 1;
1984
+ if (this.drainTimer) {
1985
+ clearTimeout(this.drainTimer);
1986
+ this.drainTimer = void 0;
1987
+ }
1988
+ this.rejectPending(/* @__PURE__ */ new Error("Discord request queue cleared"));
1989
+ }
1990
+ abortPending() {
1991
+ this.queueGeneration += 1;
1992
+ this.rejectPending(new DOMException("Aborted", "AbortError"));
1993
+ }
1994
+ get queueSize() {
1995
+ return this.queuedRequests;
1996
+ }
1997
+ getMetrics() {
1998
+ this.pruneInvalidRequests();
1999
+ return {
2000
+ globalRateLimitUntil: this.globalRateLimitUntil,
2001
+ activeBuckets: this.buckets.size,
2002
+ routeBucketMappings: this.routeBuckets.size,
2003
+ buckets: Array.from(this.buckets.entries()).map(([key, bucket]) => ({
2004
+ key,
2005
+ active: bucket.active,
2006
+ bucket: bucket.bucket,
2007
+ invalidRequests: bucket.invalidRequests,
2008
+ pending: countPending(bucket),
2009
+ pendingByLane: Object.fromEntries(requestPriorities.map((lane) => [lane, bucket.pending[lane].length])),
2010
+ rateLimitHits: bucket.rateLimitHits,
2011
+ remaining: bucket.remaining,
2012
+ resetAt: bucket.resetAt,
2013
+ routeKeyCount: bucket.routeKeys.size
2014
+ })),
2015
+ invalidRequestCount: this.invalidRequestTimestamps.length,
2016
+ invalidRequestCountByStatus: this.invalidRequestTimestamps.reduce((counts, entry) => {
2017
+ counts[entry.status] = (counts[entry.status] ?? 0) + 1;
2018
+ return counts;
2019
+ }, {}),
2020
+ queueSize: this.queueSize,
2021
+ queueSizeByLane: { ...this.queuedByLane },
2022
+ droppedByLane: { ...this.laneDropped },
2023
+ oldestQueuedByLane: Object.fromEntries(requestPriorities.map((lane) => [lane, this.getOldestQueuedAge(lane)])),
2024
+ activeWorkers: this.activeWorkers,
2025
+ maxConcurrentWorkers: this.maxConcurrentWorkers
2026
+ };
2027
+ }
2028
+ get maxConcurrentWorkers() {
2029
+ return Math.max(1, Math.floor(this.options.maxConcurrency));
2030
+ }
2031
+ get maxRateLimitRetries() {
2032
+ return Math.max(0, Math.floor(this.options.maxRateLimitRetries));
2033
+ }
2034
+ getBucket(key) {
2035
+ const existing = this.buckets.get(key);
2036
+ if (existing) return existing;
2037
+ const bucket = {
2038
+ active: 0,
2039
+ invalidRequests: 0,
2040
+ pending: createLaneQueues(),
2041
+ rateLimitHits: 0,
2042
+ resetAt: 0,
2043
+ routeKeys: new Set([key])
2044
+ };
2045
+ this.buckets.set(key, bucket);
2046
+ return bucket;
2047
+ }
2048
+ hasBucketReference(key) {
2049
+ for (const bucketKey of this.routeBuckets.values()) if (bucketKey === key) return true;
2050
+ return false;
2051
+ }
2052
+ isBucketRateLimited(bucket, now = Date.now()) {
2053
+ return bucket.remaining === 0 && bucket.resetAt > now;
2054
+ }
2055
+ pruneRouteMapping(routeKey) {
2056
+ const bucketKey = this.routeBuckets.get(routeKey);
2057
+ if (!bucketKey) return;
2058
+ this.routeBuckets.delete(routeKey);
2059
+ this.buckets.get(bucketKey)?.routeKeys.delete(routeKey);
2060
+ }
2061
+ pruneIdleRouteMappings(bucketKey, bucket, now = Date.now()) {
2062
+ if (bucket.active > 0 || countPending(bucket) > 0 || this.isBucketRateLimited(bucket, now)) return;
2063
+ for (const routeKey of Array.from(bucket.routeKeys)) if (this.routeBuckets.get(routeKey) === bucketKey) this.pruneRouteMapping(routeKey);
2064
+ }
2065
+ shouldPruneIdleBucket(key) {
2066
+ return this.routeBuckets.get(key) !== key && !this.hasBucketReference(key);
2067
+ }
2068
+ bindRouteToBucket(routeKey, bucketKey) {
2069
+ const target = this.getBucket(bucketKey);
2070
+ target.routeKeys.add(routeKey);
2071
+ this.routeBuckets.set(routeKey, bucketKey);
2072
+ const routeBucket = this.buckets.get(routeKey);
2073
+ if (routeBucket && routeBucket !== target) {
2074
+ for (const lane of requestPriorities) {
2075
+ target.pending[lane].push(...routeBucket.pending[lane]);
2076
+ routeBucket.pending[lane] = [];
2077
+ }
2078
+ if (routeBucket.active === 0) this.buckets.delete(routeKey);
2079
+ }
2080
+ return target;
2081
+ }
2082
+ updateRateLimitState(routeKey, path, response, parsed) {
2083
+ const bucketHeader = response.headers.get("X-RateLimit-Bucket");
2084
+ const bucket = bucketHeader ? this.bindRouteToBucket(routeKey, createBucketKey(bucketHeader, path)) : this.getBucket(this.routeBuckets.get(routeKey) ?? routeKey);
2085
+ bucket.bucket = bucketHeader ?? bucket.bucket;
2086
+ const limit = readHeaderNumber(response.headers, "X-RateLimit-Limit");
2087
+ if (limit !== void 0) bucket.limit = limit;
2088
+ const remaining = readHeaderNumber(response.headers, "X-RateLimit-Remaining");
2089
+ if (remaining !== void 0) bucket.remaining = remaining;
2090
+ const resetAt = readResetAt(response);
2091
+ if (resetAt !== void 0) bucket.resetAt = resetAt;
2092
+ if (response.status !== 429) return;
2093
+ bucket.rateLimitHits += 1;
2094
+ const retryAfterMs = Math.max(0, readRetryAfter(parsed, response, 1) * 1e3);
2095
+ const retryAt = Date.now() + retryAfterMs;
2096
+ if (response.headers.get("X-RateLimit-Global") === "true" || isGlobalRateLimit(parsed)) {
2097
+ this.globalRateLimitUntil = Math.max(this.globalRateLimitUntil, retryAt);
2098
+ return;
2099
+ }
2100
+ bucket.remaining = 0;
2101
+ bucket.resetAt = Math.max(bucket.resetAt, retryAt);
2102
+ }
2103
+ recordInvalidRequest(routeKey, path, response) {
2104
+ if (response.status !== 401 && response.status !== 403 && response.status !== 429) return;
2105
+ if (response.status === 429 && response.headers.get("X-RateLimit-Scope") === "shared") return;
2106
+ const now = Date.now();
2107
+ this.invalidRequestTimestamps.push({
2108
+ at: now,
2109
+ status: response.status
2110
+ });
2111
+ this.pruneInvalidRequests(now);
2112
+ const bucketHeader = response.headers.get("X-RateLimit-Bucket");
2113
+ const bucketKey = bucketHeader ? createBucketKey(bucketHeader, path) : this.routeBuckets.get(routeKey) ?? routeKey;
2114
+ const bucket = this.buckets.get(bucketKey);
2115
+ if (bucket) bucket.invalidRequests += 1;
2116
+ }
2117
+ pruneInvalidRequests(now = Date.now()) {
2118
+ const cutoff = now - INVALID_REQUEST_WINDOW_MS;
2119
+ while (this.invalidRequestTimestamps.length > 0 && (this.invalidRequestTimestamps[0]?.at ?? 0) <= cutoff) this.invalidRequestTimestamps.shift();
2120
+ }
2121
+ getBucketWaitMs(bucket, now) {
2122
+ if (bucket.remaining === 0 && bucket.resetAt > now) return bucket.resetAt - now;
2123
+ if (bucket.remaining === 0 && bucket.resetAt <= now) bucket.remaining = bucket.limit;
2124
+ return 0;
2125
+ }
2126
+ scheduleDrain(delayMs = 0) {
2127
+ if (this.drainTimer) return;
2128
+ this.drainTimer = setTimeout(() => {
2129
+ this.drainTimer = void 0;
2130
+ this.drainQueues();
2131
+ }, Math.max(0, delayMs));
2132
+ this.drainTimer.unref?.();
2133
+ }
2134
+ drainQueues() {
2135
+ let nextDelayMs = Number.POSITIVE_INFINITY;
2136
+ while (this.activeWorkers < this.maxConcurrentWorkers) {
2137
+ const next = this.takeNextQueuedRequest();
2138
+ if (!next.queued) {
2139
+ if (next.waitMs !== void 0) nextDelayMs = Math.min(nextDelayMs, next.waitMs);
2140
+ break;
2141
+ }
2142
+ const { bucket, queued } = next;
2143
+ if (bucket.remaining !== void 0 && bucket.remaining > 0) bucket.remaining -= 1;
2144
+ bucket.active += 1;
2145
+ this.activeWorkers += 1;
2146
+ this.runQueuedRequest(queued, bucket);
2147
+ }
2148
+ if (Number.isFinite(nextDelayMs)) this.scheduleDrain(nextDelayMs);
2149
+ }
2150
+ takeNextQueuedRequest() {
2151
+ const now = Date.now();
2152
+ if (this.globalRateLimitUntil > now) return { waitMs: this.globalRateLimitUntil - now };
2153
+ this.pruneIdleBuckets(now);
2154
+ let nextDelayMs;
2155
+ const buckets = Array.from(this.buckets.values()).filter((bucket) => countPending(bucket) > 0);
2156
+ if (buckets.length === 0) return {};
2157
+ for (let laneOffset = 0; laneOffset < this.laneSchedule.length; laneOffset += 1) {
2158
+ const lane = this.laneSchedule[(this.laneCursor + laneOffset) % this.laneSchedule.length];
2159
+ if (!lane || this.queuedByLane[lane] <= 0) continue;
2160
+ for (const bucket of buckets) {
2161
+ const queue = bucket.pending[lane];
2162
+ this.dropStaleHeadRequests(queue, lane, now);
2163
+ if (queue.length === 0) continue;
2164
+ if (bucket.active > 0) continue;
2165
+ const waitMs = this.getBucketWaitMs(bucket, now);
2166
+ if (waitMs > 0) {
2167
+ nextDelayMs = Math.min(nextDelayMs ?? waitMs, waitMs);
2168
+ continue;
2169
+ }
2170
+ const queued = queue.shift();
2171
+ if (!queued) continue;
2172
+ this.queuedByLane[lane] = Math.max(0, this.queuedByLane[lane] - 1);
2173
+ this.laneCursor = (this.laneCursor + laneOffset + 1) % this.laneSchedule.length;
2174
+ return {
2175
+ bucket,
2176
+ queued
2177
+ };
2178
+ }
2179
+ }
2180
+ return { waitMs: nextDelayMs };
2181
+ }
2182
+ dropStaleHeadRequests(queue, lane, now) {
2183
+ if (lane !== "background") return;
2184
+ const staleAfterMs = this.options.lanes[lane].staleAfterMs;
2185
+ if (!staleAfterMs || staleAfterMs <= 0) return;
2186
+ while (queue.length > 0 && now - (queue[0]?.enqueuedAt ?? now) > staleAfterMs) {
2187
+ const stale = queue.shift();
2188
+ if (!stale) continue;
2189
+ this.queuedRequests = Math.max(0, this.queuedRequests - 1);
2190
+ this.queuedByLane[lane] = Math.max(0, this.queuedByLane[lane] - 1);
2191
+ this.laneDropped[lane] += 1;
2192
+ stale.reject(/* @__PURE__ */ new Error(`Dropped stale ${lane} request after ${now - stale.enqueuedAt}ms`));
2193
+ }
2194
+ }
2195
+ pruneIdleBuckets(now = Date.now()) {
2196
+ for (const [key, bucket] of this.buckets) {
2197
+ if (bucket.active !== 0 || countPending(bucket) > 0) continue;
2198
+ if (this.isBucketRateLimited(bucket, now)) continue;
2199
+ this.pruneIdleRouteMappings(key, bucket, now);
2200
+ if (this.shouldPruneIdleBucket(key)) this.buckets.delete(key);
2201
+ }
2202
+ }
2203
+ async runQueuedRequest(queued, bucket) {
2204
+ let requeued = false;
2205
+ try {
2206
+ queued.resolve(await this.executor(queued));
2207
+ } catch (error) {
2208
+ if (error instanceof RateLimitError && this.requeueRateLimitedRequest(queued)) {
2209
+ requeued = true;
2210
+ return;
2211
+ }
2212
+ queued.reject(error);
2213
+ } finally {
2214
+ bucket.active = Math.max(0, bucket.active - 1);
2215
+ this.activeWorkers = Math.max(0, this.activeWorkers - 1);
2216
+ if (!requeued) this.queuedRequests = Math.max(0, this.queuedRequests - 1);
2217
+ if (bucket.active === 0 && countPending(bucket) === 0) {
2218
+ for (const routeKey of bucket.routeKeys) if (this.routeBuckets.get(routeKey) === routeKey) this.routeBuckets.delete(routeKey);
2219
+ }
2220
+ this.drainQueues();
2221
+ }
2222
+ }
2223
+ requeueRateLimitedRequest(queued) {
2224
+ if (queued.generation !== this.queueGeneration || queued.retryCount >= this.maxRateLimitRetries) return false;
2225
+ const bucketKey = this.routeBuckets.get(queued.routeKey) ?? queued.routeKey;
2226
+ this.getBucket(bucketKey).pending[queued.priority].push({
2227
+ ...queued,
2228
+ enqueuedAt: Date.now(),
2229
+ retryCount: queued.retryCount + 1
2230
+ });
2231
+ this.queuedByLane[queued.priority] += 1;
2232
+ return true;
2233
+ }
2234
+ rejectPending(error) {
2235
+ for (const bucket of this.buckets.values()) for (const lane of requestPriorities) for (const queued of bucket.pending[lane].splice(0)) {
2236
+ queued.reject(error);
2237
+ this.queuedRequests = Math.max(0, this.queuedRequests - 1);
2238
+ this.queuedByLane[lane] = Math.max(0, this.queuedByLane[lane] - 1);
2239
+ }
2240
+ }
2241
+ buildLaneSchedule(lanes) {
2242
+ const schedule = [];
2243
+ for (const lane of requestPriorities) {
2244
+ const weight = Math.max(1, Math.floor(lanes[lane].weight));
2245
+ for (let i = 0; i < weight; i += 1) schedule.push(lane);
2246
+ }
2247
+ return schedule.length > 0 ? schedule : [...requestPriorities];
2248
+ }
2249
+ getOldestQueuedAge(lane) {
2250
+ const now = Date.now();
2251
+ let oldest = 0;
2252
+ for (const bucket of this.buckets.values()) {
2253
+ const queued = bucket.pending[lane][0];
2254
+ if (!queued) continue;
2255
+ oldest = Math.max(oldest, now - queued.enqueuedAt);
2256
+ }
2257
+ return oldest;
2258
+ }
2259
+ };
2260
+ function isGlobalRateLimit(parsed) {
2261
+ return parsed && typeof parsed === "object" && "global" in parsed ? Boolean(parsed.global) : false;
2262
+ }
2263
+ //#endregion
2264
+ //#region extensions/discord/src/internal/rest.ts
2265
+ const defaultOptions = {
2266
+ tokenHeader: "Bot",
2267
+ baseUrl: "https://discord.com/api",
2268
+ apiVersion: 10,
2269
+ userAgent: "Klaw Discord",
2270
+ timeout: 15e3,
2271
+ queueRequests: true,
2272
+ maxQueueSize: 1e3,
2273
+ runtimeProfile: "persistent"
2274
+ };
2275
+ const DEFAULT_MAX_CONCURRENT_WORKERS = 4;
2276
+ const defaultLaneOptions = {
2277
+ critical: { weight: 6 },
2278
+ standard: { weight: 3 },
2279
+ background: {
2280
+ staleAfterMs: 2e4,
2281
+ weight: 1
2282
+ }
2283
+ };
2284
+ function coerceResponseBody(raw) {
2285
+ if (!raw) return;
2286
+ try {
2287
+ return JSON.parse(raw);
2288
+ } catch {
2289
+ return raw;
2290
+ }
2291
+ }
2292
+ function escapeMultipartQuotedValue(value) {
2293
+ return value.replace(/["\r\n]/g, (ch) => ch === "\"" ? "%22" : ch === "\r" ? "%0D" : "%0A");
2294
+ }
2295
+ async function formDataToMultipartBody(body, headers) {
2296
+ const boundary = `----klaw-discord-${randomBytes(12).toString("hex")}`;
2297
+ headers.set("Content-Type", `multipart/form-data; boundary=${boundary}`);
2298
+ const chunks = [];
2299
+ const push = (value) => {
2300
+ chunks.push(typeof value === "string" ? Buffer.from(value) : value);
2301
+ };
2302
+ for (const [key, value] of body.entries()) {
2303
+ push(`--${boundary}\r\n`);
2304
+ const escapedKey = escapeMultipartQuotedValue(key);
2305
+ if (typeof value === "string") {
2306
+ push(`Content-Disposition: form-data; name="${escapedKey}"\r\n\r\n`);
2307
+ push(value);
2308
+ push("\r\n");
2309
+ continue;
2310
+ }
2311
+ const filename = value.name;
2312
+ push(`Content-Disposition: form-data; name="${escapedKey}"; filename="${escapeMultipartQuotedValue(typeof filename === "string" && filename.length > 0 ? filename : "blob")}"\r\n`);
2313
+ if (value.type) push(`Content-Type: ${value.type}\r\n`);
2314
+ push("\r\n");
2315
+ push(Buffer.from(await value.arrayBuffer()));
2316
+ push("\r\n");
2317
+ }
2318
+ push(`--${boundary}--\r\n`);
2319
+ return Buffer.concat(chunks);
2320
+ }
2321
+ async function normalizeFetchBody(body, headers) {
2322
+ if (body instanceof FormData) return await formDataToMultipartBody(body, headers);
2323
+ return body;
2324
+ }
2325
+ var RequestClient = class {
2326
+ constructor(token, options) {
2327
+ this.requestControllers = /* @__PURE__ */ new Set();
2328
+ this.token = token.replace(/^Bot\s+/i, "");
2329
+ this.customFetch = options?.fetch;
2330
+ this.options = {
2331
+ ...defaultOptions,
2332
+ ...options
2333
+ };
2334
+ this.scheduler = new RestScheduler({
2335
+ lanes: normalizeSchedulerLanes(this.options.maxQueueSize ?? defaultOptions.maxQueueSize, this.options.scheduler?.lanes),
2336
+ maxConcurrency: this.options.scheduler?.maxConcurrency ?? DEFAULT_MAX_CONCURRENT_WORKERS,
2337
+ maxQueueSize: this.options.maxQueueSize ?? defaultOptions.maxQueueSize,
2338
+ maxRateLimitRetries: this.options.scheduler?.maxRateLimitRetries ?? 3
2339
+ }, async (request) => await this.executeRequest(request.method, request.path, {
2340
+ data: request.data,
2341
+ query: request.query
2342
+ }, request.routeKey));
2343
+ }
2344
+ async get(path, query) {
2345
+ return await this.request("GET", path, { query });
2346
+ }
2347
+ async post(path, data, query) {
2348
+ return await this.request("POST", path, {
2349
+ data,
2350
+ query
2351
+ });
2352
+ }
2353
+ async patch(path, data, query) {
2354
+ return await this.request("PATCH", path, {
2355
+ data,
2356
+ query
2357
+ });
2358
+ }
2359
+ async put(path, data, query) {
2360
+ return await this.request("PUT", path, {
2361
+ data,
2362
+ query
2363
+ });
2364
+ }
2365
+ async delete(path, data, query) {
2366
+ return await this.request("DELETE", path, {
2367
+ data,
2368
+ query
2369
+ });
2370
+ }
2371
+ async request(method, path, params) {
2372
+ const routeKey = createRouteKey(method, path);
2373
+ if (!this.options.queueRequests) return await this.executeRequest(method, path, params, routeKey);
2374
+ return await this.scheduler.enqueue({
2375
+ method,
2376
+ path,
2377
+ priority: getRequestPriority(method, path),
2378
+ ...params
2379
+ });
2380
+ }
2381
+ async executeRequest(method, path, params, routeKey = createRouteKey(method, path)) {
2382
+ const url = `${this.options.baseUrl}/v${this.options.apiVersion}${appendQuery(path, params.query)}`;
2383
+ const headers = new Headers({ "User-Agent": this.options.userAgent ?? defaultOptions.userAgent });
2384
+ if (this.token !== "webhook") headers.set("Authorization", `${this.options.tokenHeader ?? "Bot"} ${this.token}`);
2385
+ const body = serializeRequestBody(params.data, headers);
2386
+ const controller = new AbortController();
2387
+ const timeout = setTimeout(() => controller.abort(), this.options.timeout ?? 15e3);
2388
+ timeout.unref?.();
2389
+ this.requestControllers.add(controller);
2390
+ try {
2391
+ const response = await (this.customFetch ?? fetch)(url, {
2392
+ method,
2393
+ headers,
2394
+ body: await normalizeFetchBody(body, headers),
2395
+ signal: controller.signal
2396
+ });
2397
+ const parsed = coerceResponseBody(await response.text());
2398
+ this.scheduler.recordResponse(routeKey, path, response, parsed);
2399
+ if (response.status === 204) return;
2400
+ if (response.status === 429) {
2401
+ const rateLimitBody = isDiscordRateLimitBody(parsed) ? parsed : void 0;
2402
+ throw new RateLimitError(response, {
2403
+ message: readDiscordMessage(rateLimitBody, "Rate limited"),
2404
+ retry_after: readRetryAfter(rateLimitBody, response, 1),
2405
+ code: readDiscordCode(rateLimitBody),
2406
+ global: Boolean(rateLimitBody?.global)
2407
+ });
2408
+ }
2409
+ if (!response.ok) throw new DiscordError(response, parsed);
2410
+ return parsed;
2411
+ } catch (error) {
2412
+ if (error instanceof DOMException && error.name === "AbortError") throw error;
2413
+ if (error instanceof Error) throw error;
2414
+ throw new Error(`Discord request failed: ${inspect(error)}`, { cause: error });
2415
+ } finally {
2416
+ clearTimeout(timeout);
2417
+ this.requestControllers.delete(controller);
2418
+ }
2419
+ }
2420
+ clearQueue() {
2421
+ this.scheduler.clearQueue();
2422
+ }
2423
+ get queueSize() {
2424
+ return this.scheduler.queueSize;
2425
+ }
2426
+ getSchedulerMetrics() {
2427
+ return this.scheduler.getMetrics();
2428
+ }
2429
+ abortAllRequests() {
2430
+ this.scheduler.abortPending();
2431
+ for (const controller of this.requestControllers) controller.abort();
2432
+ this.requestControllers.clear();
2433
+ }
2434
+ };
2435
+ function normalizeSchedulerLanes(maxQueueSize, lanes) {
2436
+ const fallbackMaxQueueSize = Math.max(1, Math.floor(maxQueueSize));
2437
+ return {
2438
+ critical: normalizeSchedulerLane("critical", fallbackMaxQueueSize, lanes?.critical),
2439
+ standard: normalizeSchedulerLane("standard", fallbackMaxQueueSize, lanes?.standard),
2440
+ background: normalizeSchedulerLane("background", fallbackMaxQueueSize, lanes?.background)
2441
+ };
2442
+ }
2443
+ function normalizeSchedulerLane(lane, maxQueueSize, options) {
2444
+ const defaults = defaultLaneOptions[lane];
2445
+ return {
2446
+ maxQueueSize: options?.maxQueueSize !== void 0 ? Math.max(1, Math.floor(options.maxQueueSize)) : maxQueueSize,
2447
+ staleAfterMs: options?.staleAfterMs !== void 0 ? Math.max(0, Math.floor(options.staleAfterMs)) : defaults.staleAfterMs,
2448
+ weight: options?.weight !== void 0 ? Math.max(1, Math.floor(options.weight)) : defaults.weight
2449
+ };
2450
+ }
2451
+ function getRequestPriority(method, path) {
2452
+ const normalizedMethod = method.toUpperCase();
2453
+ const normalizedPath = path.toLowerCase();
2454
+ if (/^\/interactions\/\d+\/[^/]+\/callback$/.test(normalizedPath)) return "critical";
2455
+ return normalizedMethod === "GET" ? "background" : "standard";
2456
+ }
2457
+ //#endregion
2458
+ //#region extensions/discord/src/internal/client.ts
2459
+ var Plugin = class {};
2460
+ var ComponentRegistry = class {
2461
+ constructor() {
2462
+ this.entries = /* @__PURE__ */ new Map();
2463
+ this.oneOffComponents = /* @__PURE__ */ new Map();
2464
+ this.wildcardEntries = [];
2465
+ }
2466
+ register(entry) {
2467
+ const key = parseRegistryKey(entry.customId, entry.customIdParser);
2468
+ if (key === "*") {
2469
+ if (!this.wildcardEntries.includes(entry)) this.wildcardEntries.push(entry);
2470
+ return;
2471
+ }
2472
+ const entries = this.entries.get(key) ?? [];
2473
+ if (!entries.includes(entry)) {
2474
+ entries.push(entry);
2475
+ this.entries.set(key, entries);
2476
+ }
2477
+ }
2478
+ resolve(customId, options) {
2479
+ for (const entries of this.entries.values()) {
2480
+ const match = entries.find((entry) => {
2481
+ if (options?.componentType !== void 0 && entry.type !== options.componentType) return false;
2482
+ const parser = entry.customIdParser ?? parseCustomId;
2483
+ return parseRegistryKey(entry.customId, parser) === parseRegistryKey(customId, parser);
2484
+ });
2485
+ if (match) return match;
2486
+ }
2487
+ return this.wildcardEntries.find((entry) => {
2488
+ if (options?.componentType !== void 0 && entry.type !== options.componentType) return false;
2489
+ return true;
2490
+ });
2491
+ }
2492
+ waitForMessageComponent(message, timeoutMs) {
2493
+ const key = createOneOffComponentKey(message.id, message.channelId);
2494
+ return new Promise((resolve) => {
2495
+ const existing = this.oneOffComponents.get(key);
2496
+ if (existing) {
2497
+ clearTimeout(existing.timer);
2498
+ existing.resolve({
2499
+ success: false,
2500
+ message,
2501
+ reason: "timed out"
2502
+ });
2503
+ }
2504
+ const timer = setTimeout(() => {
2505
+ this.oneOffComponents.delete(key);
2506
+ resolve({
2507
+ success: false,
2508
+ message,
2509
+ reason: "timed out"
2510
+ });
2511
+ }, Math.max(0, timeoutMs));
2512
+ timer.unref?.();
2513
+ this.oneOffComponents.set(key, {
2514
+ message,
2515
+ timer,
2516
+ resolve
2517
+ });
2518
+ });
2519
+ }
2520
+ resolveOneOffComponent(params) {
2521
+ if (!params.messageId || !params.channelId) return false;
2522
+ const entry = this.oneOffComponents.get(createOneOffComponentKey(params.messageId, params.channelId));
2523
+ if (!entry) return false;
2524
+ clearTimeout(entry.timer);
2525
+ this.oneOffComponents.delete(createOneOffComponentKey(params.messageId, params.channelId));
2526
+ entry.resolve({
2527
+ success: true,
2528
+ customId: params.customId,
2529
+ message: entry.message,
2530
+ values: params.values
2531
+ });
2532
+ return true;
2533
+ }
2534
+ };
2535
+ function parseRegistryKey(customId, parser = parseCustomId) {
2536
+ return parser(customId).key;
2537
+ }
2538
+ function createOneOffComponentKey(messageId, channelId) {
2539
+ return `${messageId}:${channelId}`;
2540
+ }
2541
+ var Client = class {
2542
+ constructor(options, handlers, plugins = []) {
2543
+ this.routes = [];
2544
+ this.plugins = [];
2545
+ this.componentHandler = new ComponentRegistry();
2546
+ this.modalHandler = new ComponentRegistry();
2547
+ if (!options.clientId) throw new Error("Missing Discord application ID");
2548
+ if (!options.token) throw new Error("Missing Discord bot token");
2549
+ this.options = {
2550
+ ...options,
2551
+ baseUrl: options.baseUrl.replace(/\/+$/, "")
2552
+ };
2553
+ this.commands = handlers.commands ?? [];
2554
+ this.listeners = handlers.listeners ?? [];
2555
+ this.rest = new RequestClient(options.token, options.requestOptions);
2556
+ this.eventQueue = this.options.eventQueue ? new DiscordEventQueue(this.options.eventQueue) : void 0;
2557
+ this.entityCache = new DiscordEntityCache({
2558
+ client: this,
2559
+ rest: () => this.rest,
2560
+ ttlMs: this.options.restCacheTtlMs
2561
+ });
2562
+ this.commandDeployer = new DiscordCommandDeployer({
2563
+ clientId: this.options.clientId,
2564
+ commands: this.commands,
2565
+ devGuilds: this.options.devGuilds,
2566
+ hashStorePath: this.options.commandDeployHashStorePath,
2567
+ rest: () => this.rest
2568
+ });
2569
+ for (const component of handlers.components ?? []) this.componentHandler.register(component);
2570
+ for (const command of this.commands) for (const component of command.components ?? []) this.componentHandler.register(component);
2571
+ for (const modal of handlers.modals ?? []) this.modalHandler.register(modal);
2572
+ for (const plugin of plugins) {
2573
+ plugin.registerClient?.(this);
2574
+ plugin.registerRoutes?.(this);
2575
+ this.plugins.push({
2576
+ id: plugin.id,
2577
+ plugin
2578
+ });
2579
+ }
2580
+ }
2581
+ getPlugin(id) {
2582
+ return this.plugins.find((entry) => entry.id === id)?.plugin;
2583
+ }
2584
+ registerListener(listener) {
2585
+ if (!this.listeners.includes(listener)) this.listeners.push(listener);
2586
+ return listener;
2587
+ }
2588
+ unregisterListener(listener) {
2589
+ const index = this.listeners.indexOf(listener);
2590
+ if (index < 0) return false;
2591
+ this.listeners.splice(index, 1);
2592
+ return true;
2593
+ }
2594
+ getRuntimeMetrics() {
2595
+ return {
2596
+ request: this.rest.getSchedulerMetrics(),
2597
+ eventQueue: this.eventQueue?.getMetrics()
2598
+ };
2599
+ }
2600
+ async fetchUser(id) {
2601
+ return await this.entityCache.fetchUser(id);
2602
+ }
2603
+ async fetchChannel(id) {
2604
+ return await this.entityCache.fetchChannel(id);
2605
+ }
2606
+ async fetchGuild(id) {
2607
+ return await this.entityCache.fetchGuild(id);
2608
+ }
2609
+ async fetchMember(guildId, userId) {
2610
+ return await this.entityCache.fetchMember(guildId, userId);
2611
+ }
2612
+ async getDiscordCommands() {
2613
+ return await this.commandDeployer.getCommands();
2614
+ }
2615
+ async deployCommands(options = {}) {
2616
+ return await this.commandDeployer.deploy(options);
2617
+ }
2618
+ async reconcileCommands() {
2619
+ return await this.deployCommands({ mode: "reconcile" });
2620
+ }
2621
+ async handleInteraction(rawData, _ctx) {
2622
+ await dispatchInteraction(this, rawData);
2623
+ }
2624
+ async dispatchGatewayEvent(type, data) {
2625
+ this.entityCache.invalidateForGatewayEvent(type, data);
2626
+ const listeners = this.listeners.filter((entry) => entry.type === type);
2627
+ if (!this.eventQueue) {
2628
+ for (const listener of listeners) await listener.handle(data, this);
2629
+ return;
2630
+ }
2631
+ await Promise.all(listeners.map((listener) => this.eventQueue.enqueue({
2632
+ eventType: type,
2633
+ listenerName: listener.constructor.name || "AnonymousListener",
2634
+ run: async () => {
2635
+ await listener.handle(data, this);
2636
+ }
2637
+ })));
2638
+ }
2639
+ };
2640
+ //#endregion
2641
+ //#region extensions/discord/src/internal/embeds.ts
2642
+ function clean(value) {
2643
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
2644
+ }
2645
+ var Embed = class {
2646
+ constructor(embed) {
2647
+ Object.assign(this, embed);
2648
+ }
2649
+ serialize() {
2650
+ return clean({
2651
+ title: this.title,
2652
+ description: this.description,
2653
+ url: this.url,
2654
+ timestamp: this.timestamp,
2655
+ color: this.color,
2656
+ footer: this.footer,
2657
+ image: typeof this.image === "string" ? { url: this.image } : this.image,
2658
+ thumbnail: typeof this.thumbnail === "string" ? { url: this.thumbnail } : this.thumbnail,
2659
+ author: this.author,
2660
+ fields: this.fields
2661
+ });
2662
+ }
2663
+ };
2664
+ //#endregion
2665
+ //#region extensions/discord/src/internal/listeners.ts
2666
+ var BaseListener = class {};
2667
+ var ReadyListener = class extends BaseListener {
2668
+ constructor(..._args) {
2669
+ super(..._args);
2670
+ this.type = GatewayDispatchEvents.Ready;
2671
+ }
2672
+ };
2673
+ var ResumedListener = class extends BaseListener {
2674
+ constructor(..._args2) {
2675
+ super(..._args2);
2676
+ this.type = GatewayDispatchEvents.Resumed;
2677
+ }
2678
+ };
2679
+ var MessageCreateListener = class extends BaseListener {
2680
+ constructor(..._args3) {
2681
+ super(..._args3);
2682
+ this.type = GatewayDispatchEvents.MessageCreate;
2683
+ }
2684
+ };
2685
+ var InteractionCreateListener = class extends BaseListener {
2686
+ constructor(..._args4) {
2687
+ super(..._args4);
2688
+ this.type = GatewayDispatchEvents.InteractionCreate;
2689
+ }
2690
+ };
2691
+ var MessageReactionAddListener = class extends BaseListener {
2692
+ constructor(..._args5) {
2693
+ super(..._args5);
2694
+ this.type = GatewayDispatchEvents.MessageReactionAdd;
2695
+ }
2696
+ };
2697
+ var MessageReactionRemoveListener = class extends BaseListener {
2698
+ constructor(..._args6) {
2699
+ super(..._args6);
2700
+ this.type = GatewayDispatchEvents.MessageReactionRemove;
2701
+ }
2702
+ };
2703
+ var PresenceUpdateListener = class extends BaseListener {
2704
+ constructor(..._args7) {
2705
+ super(..._args7);
2706
+ this.type = GatewayDispatchEvents.PresenceUpdate;
2707
+ }
2708
+ };
2709
+ var VoiceStateUpdateListener = class extends BaseListener {
2710
+ constructor(..._args8) {
2711
+ super(..._args8);
2712
+ this.type = GatewayDispatchEvents.VoiceStateUpdate;
2713
+ }
2714
+ };
2715
+ var ThreadUpdateListener = class extends BaseListener {
2716
+ constructor(..._args9) {
2717
+ super(..._args9);
2718
+ this.type = GatewayDispatchEvents.ThreadUpdate;
2719
+ }
2720
+ };
2721
+ //#endregion
2722
+ //#region extensions/discord/src/internal/discord.ts
2723
+ var discord_exports = /* @__PURE__ */ __exportAll({
2724
+ AnySelectMenu: () => AnySelectMenu,
2725
+ AutocompleteInteraction: () => AutocompleteInteraction,
2726
+ Base: () => Base,
2727
+ BaseCommand: () => BaseCommand,
2728
+ BaseComponent: () => BaseComponent,
2729
+ BaseComponentInteraction: () => BaseComponentInteraction,
2730
+ BaseInteraction: () => BaseInteraction,
2731
+ BaseListener: () => BaseListener,
2732
+ BaseMessageInteractiveComponent: () => BaseMessageInteractiveComponent,
2733
+ BaseModalComponent: () => BaseModalComponent,
2734
+ Button: () => Button,
2735
+ ButtonInteraction: () => ButtonInteraction,
2736
+ ChannelSelectMenu: () => ChannelSelectMenu,
2737
+ ChannelSelectMenuInteraction: () => ChannelSelectMenuInteraction,
2738
+ CheckboxGroup: () => CheckboxGroup,
2739
+ Client: () => Client,
2740
+ Command: () => Command,
2741
+ CommandInteraction: () => CommandInteraction,
2742
+ CommandWithSubcommands: () => CommandWithSubcommands,
2743
+ ComponentRegistry: () => ComponentRegistry,
2744
+ Container: () => Container,
2745
+ DiscordError: () => DiscordError,
2746
+ Embed: () => Embed,
2747
+ File: () => File,
2748
+ Guild: () => Guild,
2749
+ GuildMember: () => GuildMember,
2750
+ InteractionCreateListener: () => InteractionCreateListener,
2751
+ Label: () => Label,
2752
+ LinkButton: () => LinkButton,
2753
+ MediaGallery: () => MediaGallery,
2754
+ MentionableSelectMenu: () => MentionableSelectMenu,
2755
+ MentionableSelectMenuInteraction: () => MentionableSelectMenuInteraction,
2756
+ Message: () => Message,
2757
+ MessageCreateListener: () => MessageCreateListener,
2758
+ MessageReactionAddListener: () => MessageReactionAddListener,
2759
+ MessageReactionRemoveListener: () => MessageReactionRemoveListener,
2760
+ Modal: () => Modal,
2761
+ ModalFields: () => ModalFields,
2762
+ ModalInteraction: () => ModalInteraction,
2763
+ OptionsHandler: () => OptionsHandler,
2764
+ Plugin: () => Plugin,
2765
+ PresenceUpdateListener: () => PresenceUpdateListener,
2766
+ RadioGroup: () => RadioGroup,
2767
+ RateLimitError: () => RateLimitError,
2768
+ ReadyListener: () => ReadyListener,
2769
+ RequestClient: () => RequestClient,
2770
+ ResumedListener: () => ResumedListener,
2771
+ Role: () => Role,
2772
+ RoleSelectMenu: () => RoleSelectMenu,
2773
+ RoleSelectMenuInteraction: () => RoleSelectMenuInteraction,
2774
+ Row: () => Row,
2775
+ Section: () => Section,
2776
+ Separator: () => Separator,
2777
+ StringSelectMenu: () => StringSelectMenu,
2778
+ StringSelectMenuInteraction: () => StringSelectMenuInteraction,
2779
+ TextDisplay: () => TextDisplay,
2780
+ TextInput: () => TextInput,
2781
+ ThreadUpdateListener: () => ThreadUpdateListener,
2782
+ Thumbnail: () => Thumbnail,
2783
+ User: () => User,
2784
+ UserSelectMenu: () => UserSelectMenu,
2785
+ UserSelectMenuInteraction: () => UserSelectMenuInteraction,
2786
+ VoiceStateUpdateListener: () => VoiceStateUpdateListener,
2787
+ addGuildMemberRole: () => addGuildMemberRole,
2788
+ channelFactory: () => channelFactory,
2789
+ clean: () => clean$3,
2790
+ colorToNumber: () => colorToNumber,
2791
+ createApplicationCommand: () => createApplicationCommand,
2792
+ createChannelMessage: () => createChannelMessage,
2793
+ createChannelWebhook: () => createChannelWebhook,
2794
+ createGuildBan: () => createGuildBan,
2795
+ createGuildChannel: () => createGuildChannel,
2796
+ createGuildEmoji: () => createGuildEmoji,
2797
+ createGuildScheduledEvent: () => createGuildScheduledEvent,
2798
+ createGuildSticker: () => createGuildSticker,
2799
+ createInteraction: () => createInteraction,
2800
+ createInteractionCallback: () => createInteractionCallback,
2801
+ createOwnMessageReaction: () => createOwnMessageReaction,
2802
+ createThread: () => createThread,
2803
+ createUserDmChannel: () => createUserDmChannel,
2804
+ createWebhookMessage: () => createWebhookMessage,
2805
+ deferCommandInteractionIfNeeded: () => deferCommandInteractionIfNeeded,
2806
+ deleteApplicationCommand: () => deleteApplicationCommand,
2807
+ deleteChannel: () => deleteChannel,
2808
+ deleteChannelMessage: () => deleteChannelMessage,
2809
+ deleteChannelPermission: () => deleteChannelPermission,
2810
+ deleteOwnMessageReaction: () => deleteOwnMessageReaction,
2811
+ deleteWebhookMessage: () => deleteWebhookMessage,
2812
+ editApplicationCommand: () => editApplicationCommand,
2813
+ editChannel: () => editChannel,
2814
+ editChannelMessage: () => editChannelMessage,
2815
+ editWebhookMessage: () => editWebhookMessage,
2816
+ getChannel: () => getChannel,
2817
+ getChannelMessage: () => getChannelMessage,
2818
+ getCurrentUser: () => getCurrentUser,
2819
+ getGuild: () => getGuild,
2820
+ getGuildMember: () => getGuildMember,
2821
+ getGuildVoiceState: () => getGuildVoiceState,
2822
+ getUser: () => getUser,
2823
+ getWebhookMessage: () => getWebhookMessage,
2824
+ listApplicationCommands: () => listApplicationCommands,
2825
+ listChannelArchivedThreads: () => listChannelArchivedThreads,
2826
+ listChannelMessages: () => listChannelMessages,
2827
+ listChannelPins: () => listChannelPins,
2828
+ listGuildActiveThreads: () => listGuildActiveThreads,
2829
+ listGuildChannels: () => listGuildChannels,
2830
+ listGuildEmojis: () => listGuildEmojis,
2831
+ listGuildRoles: () => listGuildRoles,
2832
+ listGuildScheduledEvents: () => listGuildScheduledEvents,
2833
+ listMessageReactionUsers: () => listMessageReactionUsers,
2834
+ moveGuildChannels: () => moveGuildChannels,
2835
+ overwriteApplicationCommands: () => overwriteApplicationCommands,
2836
+ overwriteGuildApplicationCommands: () => overwriteGuildApplicationCommands,
2837
+ parseComponentInteractionData: () => parseComponentInteractionData,
2838
+ parseCustomId: () => parseCustomId,
2839
+ pinChannelMessage: () => pinChannelMessage,
2840
+ putChannelPermission: () => putChannelPermission,
2841
+ removeGuildMember: () => removeGuildMember,
2842
+ removeGuildMemberRole: () => removeGuildMemberRole,
2843
+ resolveFocusedCommandOptionAutocompleteHandler: () => resolveFocusedCommandOptionAutocompleteHandler,
2844
+ searchGuildMessages: () => searchGuildMessages,
2845
+ sendChannelTyping: () => sendChannelTyping,
2846
+ serializePayload: () => serializePayload,
2847
+ timeoutGuildMember: () => timeoutGuildMember,
2848
+ unpinChannelMessage: () => unpinChannelMessage
2849
+ });
2850
+ import * as import_discord_api_types_v10 from "discord-api-types/v10";
2851
+ __reExport(discord_exports, import_discord_api_types_v10);
2852
+ //#endregion
2853
+ //#region extensions/discord/src/chunk.ts
2854
+ const DEFAULT_MAX_CHARS = 2e3;
2855
+ const DEFAULT_MAX_LINES = 17;
2856
+ const FENCE_RE = /^( {0,3})(`{3,}|~{3,})(.*)$/;
2857
+ const CJK_PUNCTUATION_BREAK_AFTER_RE = /[、。,.!?;:)]}〉》」』】〕〗〙]/u;
2858
+ function countLines(text) {
2859
+ if (!text) return 0;
2860
+ return text.split("\n").length;
2861
+ }
2862
+ function parseFenceLine(line) {
2863
+ const match = line.match(FENCE_RE);
2864
+ if (!match) return null;
2865
+ const indent = match[1] ?? "";
2866
+ const marker = match[2] ?? "";
2867
+ return {
2868
+ indent,
2869
+ markerChar: marker[0] ?? "`",
2870
+ markerLen: marker.length,
2871
+ openLine: line
2872
+ };
2873
+ }
2874
+ function closeFenceLine(openFence) {
2875
+ return `${openFence.indent}${openFence.markerChar.repeat(openFence.markerLen)}`;
2876
+ }
2877
+ function closeFenceIfNeeded(text, openFence) {
2878
+ if (!openFence) return text;
2879
+ const closeLine = closeFenceLine(openFence);
2880
+ if (!text) return closeLine;
2881
+ if (!text.endsWith("\n")) return `${text}\n${closeLine}`;
2882
+ return `${text}${closeLine}`;
2883
+ }
2884
+ function isHighSurrogate(code) {
2885
+ return code >= 55296 && code <= 56319;
2886
+ }
2887
+ function isLowSurrogate(code) {
2888
+ return code >= 56320 && code <= 57343;
2889
+ }
2890
+ function clampToCodePointBoundary(text, index) {
2891
+ const boundary = Math.min(Math.max(0, index), text.length);
2892
+ if (boundary <= 0 || boundary >= text.length) return boundary;
2893
+ const previous = text.charCodeAt(boundary - 1);
2894
+ const next = text.charCodeAt(boundary);
2895
+ if (isHighSurrogate(previous) && isLowSurrogate(next)) return boundary > 1 ? boundary - 1 : boundary + 1;
2896
+ return boundary;
2897
+ }
2898
+ function findWhitespaceBreak(window) {
2899
+ for (let i = window.length - 1; i >= 0; i--) if (/\s/.test(window[i])) return i;
2900
+ return -1;
2901
+ }
2902
+ function findCjkPunctuationBreak(window) {
2903
+ for (let end = window.length; end > 0;) {
2904
+ const start = isLowSurrogate(window.charCodeAt(end - 1)) && end > 1 ? end - 2 : end - 1;
2905
+ const char = window.slice(start, end);
2906
+ if (start > 0 && CJK_PUNCTUATION_BREAK_AFTER_RE.test(char)) return end;
2907
+ end = start;
2908
+ }
2909
+ return -1;
2910
+ }
2911
+ function splitLongLine(line, maxChars, opts) {
2912
+ const limit = Math.max(1, Math.floor(maxChars));
2913
+ if (line.length <= limit) return [line];
2914
+ const out = [];
2915
+ let remaining = line;
2916
+ while (remaining.length > limit) {
2917
+ if (opts.preserveWhitespace) {
2918
+ const breakIdx = clampToCodePointBoundary(remaining, limit);
2919
+ out.push(remaining.slice(0, breakIdx));
2920
+ remaining = remaining.slice(breakIdx);
2921
+ continue;
2922
+ }
2923
+ const window = remaining.slice(0, limit);
2924
+ let breakIdx = findWhitespaceBreak(window);
2925
+ if (breakIdx <= 0) breakIdx = findCjkPunctuationBreak(window);
2926
+ if (breakIdx <= 0) breakIdx = clampToCodePointBoundary(remaining, limit);
2927
+ out.push(remaining.slice(0, breakIdx));
2928
+ remaining = remaining.slice(breakIdx);
2929
+ }
2930
+ if (remaining.length) out.push(remaining);
2931
+ return out;
2932
+ }
2933
+ /**
2934
+ * Chunks outbound Discord text by both character count and (soft) line count,
2935
+ * while keeping fenced code blocks balanced across chunks.
2936
+ */
2937
+ function chunkDiscordText(text, opts = {}) {
2938
+ const maxChars = Math.max(1, Math.floor(opts.maxChars ?? DEFAULT_MAX_CHARS));
2939
+ const maxLines = Math.max(1, Math.floor(opts.maxLines ?? DEFAULT_MAX_LINES));
2940
+ const body = text ?? "";
2941
+ if (!body) return [];
2942
+ if (body.length <= maxChars && countLines(body) <= maxLines) return [body];
2943
+ const lines = body.split("\n");
2944
+ const chunks = [];
2945
+ let current = "";
2946
+ let currentLines = 0;
2947
+ let openFence = null;
2948
+ const flush = () => {
2949
+ if (!current) return;
2950
+ const payload = closeFenceIfNeeded(current, openFence);
2951
+ if (payload.trim().length) chunks.push(payload);
2952
+ current = "";
2953
+ currentLines = 0;
2954
+ if (openFence) {
2955
+ current = openFence.openLine;
2956
+ currentLines = 1;
2957
+ }
2958
+ };
2959
+ for (const originalLine of lines) {
2960
+ const fenceInfo = parseFenceLine(originalLine);
2961
+ const wasInsideFence = openFence !== null;
2962
+ let nextOpenFence = openFence;
2963
+ if (fenceInfo) {
2964
+ if (!openFence) nextOpenFence = fenceInfo;
2965
+ else if (openFence.markerChar === fenceInfo.markerChar && fenceInfo.markerLen >= openFence.markerLen) nextOpenFence = null;
2966
+ }
2967
+ const reserveChars = nextOpenFence ? closeFenceLine(nextOpenFence).length + 1 : 0;
2968
+ const reserveLines = nextOpenFence ? 1 : 0;
2969
+ const effectiveMaxChars = maxChars - reserveChars;
2970
+ const effectiveMaxLines = maxLines - reserveLines;
2971
+ const charLimit = effectiveMaxChars > 0 ? effectiveMaxChars : maxChars;
2972
+ const lineLimit = effectiveMaxLines > 0 ? effectiveMaxLines : maxLines;
2973
+ const prefixLen = current.length > 0 ? current.length + 1 : 0;
2974
+ const segments = splitLongLine(originalLine, Math.max(1, charLimit - prefixLen), { preserveWhitespace: wasInsideFence });
2975
+ for (let segIndex = 0; segIndex < segments.length; segIndex++) {
2976
+ const segment = segments[segIndex];
2977
+ const isLineContinuation = segIndex > 0;
2978
+ const addition = `${isLineContinuation ? "" : current.length > 0 ? "\n" : ""}${segment}`;
2979
+ const nextLen = current.length + addition.length;
2980
+ const nextLines = currentLines + (isLineContinuation ? 0 : 1);
2981
+ if ((nextLen > charLimit || nextLines > lineLimit) && current.length > 0) flush();
2982
+ if (current.length > 0) {
2983
+ current += addition;
2984
+ if (!isLineContinuation) currentLines += 1;
2985
+ } else {
2986
+ current = segment;
2987
+ currentLines = 1;
2988
+ }
2989
+ }
2990
+ openFence = nextOpenFence;
2991
+ }
2992
+ if (current.length) {
2993
+ const payload = closeFenceIfNeeded(current, openFence);
2994
+ if (payload.trim().length) chunks.push(payload);
2995
+ }
2996
+ return rebalanceReasoningItalics(text, chunks);
2997
+ }
2998
+ function chunkDiscordTextWithMode(text, opts) {
2999
+ if ((opts.chunkMode ?? "length") !== "newline") return chunkDiscordText(text, opts);
3000
+ const lineChunks = chunkMarkdownTextWithMode(text, Math.max(1, Math.floor(opts.maxChars ?? DEFAULT_MAX_CHARS)), "newline");
3001
+ const chunks = [];
3002
+ for (const line of lineChunks) {
3003
+ const nested = chunkDiscordText(line, opts);
3004
+ if (!nested.length && line) {
3005
+ chunks.push(line);
3006
+ continue;
3007
+ }
3008
+ chunks.push(...nested);
3009
+ }
3010
+ return chunks;
3011
+ }
3012
+ function rebalanceReasoningItalics(source, chunks) {
3013
+ if (chunks.length <= 1) return chunks;
3014
+ if (!(/^(?:Reasoning:|Thinking\.{0,3})\n+_/u.test(source) && source.trimEnd().endsWith("_"))) return chunks;
3015
+ const adjusted = [...chunks];
3016
+ for (let i = 0; i < adjusted.length; i++) {
3017
+ const isLast = i === adjusted.length - 1;
3018
+ const current = adjusted[i];
3019
+ if (!current.trimEnd().endsWith("_")) adjusted[i] = `${current}_`;
3020
+ if (isLast) break;
3021
+ const next = adjusted[i + 1];
3022
+ const leadingWhitespaceLen = next.length - next.trimStart().length;
3023
+ const leadingWhitespace = next.slice(0, leadingWhitespaceLen);
3024
+ const nextBody = next.slice(leadingWhitespaceLen);
3025
+ if (!nextBody.startsWith("_")) adjusted[i + 1] = `${leadingWhitespace}_${nextBody}`;
3026
+ }
3027
+ return adjusted;
3028
+ }
3029
+ //#endregion
3030
+ //#region extensions/discord/src/normalize.ts
3031
+ function normalizeDiscordMessagingTarget(raw) {
3032
+ return parseDiscordTarget(raw, { defaultKind: "channel" })?.normalized;
3033
+ }
3034
+ /**
3035
+ * Normalize a Discord outbound target for delivery. Bare numeric IDs are
3036
+ * prefixed with "channel:" to avoid the ambiguous-target error in
3037
+ * parseDiscordTarget, unless the ID is explicitly configured as an allowed DM
3038
+ * sender. All other formats pass through unchanged.
3039
+ */
3040
+ function normalizeDiscordOutboundTarget(to, allowFrom) {
3041
+ const trimmed = to?.trim();
3042
+ if (!trimmed) return {
3043
+ ok: false,
3044
+ error: /* @__PURE__ */ new Error("Discord recipient is required. Use \"channel:<id>\" for channels or \"user:<id>\" for DMs.")
3045
+ };
3046
+ if (/^\d+$/.test(trimmed)) {
3047
+ if (allowFromContainsDiscordUserId(allowFrom, trimmed)) return {
3048
+ ok: true,
3049
+ to: `user:${trimmed}`
3050
+ };
3051
+ return {
3052
+ ok: true,
3053
+ to: `channel:${trimmed}`
3054
+ };
3055
+ }
3056
+ return {
3057
+ ok: true,
3058
+ to: trimmed
3059
+ };
3060
+ }
3061
+ function allowFromContainsDiscordUserId(allowFrom, userId) {
3062
+ const normalizedUserId = userId.trim();
3063
+ if (!normalizedUserId) return false;
3064
+ return (allowFrom ?? []).some((entry) => normalizeAllowFromDiscordUserId(entry) === normalizedUserId);
3065
+ }
3066
+ function normalizeAllowFromDiscordUserId(entry) {
3067
+ const trimmed = entry.trim().toLowerCase();
3068
+ if (!trimmed || trimmed === "*") return;
3069
+ const mentionMatch = /^<@!?(\d+)>$/.exec(trimmed);
3070
+ if (mentionMatch) return mentionMatch[1];
3071
+ const prefixedMatch = /^(?:discord:)?user:(\d+)$/.exec(trimmed);
3072
+ if (prefixedMatch) return prefixedMatch[1];
3073
+ const discordMatch = /^discord:(\d+)$/.exec(trimmed);
3074
+ if (discordMatch) return discordMatch[1];
3075
+ return /^\d+$/.test(trimmed) ? trimmed : void 0;
3076
+ }
3077
+ function looksLikeDiscordTargetId(raw) {
3078
+ const trimmed = raw.trim();
3079
+ if (!trimmed) return false;
3080
+ if (/^<@!?\d+>$/.test(trimmed)) return true;
3081
+ if (/^(user|channel|discord):/i.test(trimmed)) return true;
3082
+ if (/^\d{6,}$/.test(trimmed)) return true;
3083
+ return false;
3084
+ }
3085
+ //#endregion
3086
+ //#region extensions/discord/src/send.receipt.ts
3087
+ function createDiscordSendReceipt(params) {
3088
+ return createMessageReceiptFromOutboundResults({
3089
+ results: params.platformMessageIds.map((messageId) => messageId.trim()).filter((messageId) => messageId && messageId !== "unknown").map((messageId) => {
3090
+ const result = {
3091
+ channel: "discord",
3092
+ messageId
3093
+ };
3094
+ if (params.channelId) result.channelId = params.channelId;
3095
+ return result;
3096
+ }),
3097
+ kind: params.kind,
3098
+ threadId: params.threadId,
3099
+ replyToId: params.replyToId
3100
+ });
3101
+ }
3102
+ function createDiscordSendResult(params) {
3103
+ const messageId = params.result.id || "unknown";
3104
+ const channelId = params.result.channel_id ?? params.fallbackChannelId;
3105
+ const receiptParams = {
3106
+ platformMessageIds: params.result.platformMessageIds?.length ? params.result.platformMessageIds : [messageId],
3107
+ channelId,
3108
+ kind: params.kind
3109
+ };
3110
+ if (params.threadId != null) receiptParams.threadId = String(params.threadId);
3111
+ if (params.replyToId) receiptParams.replyToId = params.replyToId;
3112
+ return {
3113
+ messageId,
3114
+ channelId,
3115
+ receipt: createDiscordSendReceipt(receiptParams)
3116
+ };
3117
+ }
3118
+ //#endregion
3119
+ export { BaseMessageInteractiveComponent as $, Message as A, getGuildMember as At, Container as B, removeGuildMemberRole as Bt, RateLimitError as C, createGuildBan as Ct, Command as D, createGuildSticker as Dt, readRetryAfter as E, createGuildScheduledEvent as Et, Modal as F, listGuildRoles as Ft, RoleSelectMenu as G, LinkButton as H, parseDiscordTarget as Ht, RadioGroup as I, listGuildScheduledEvents as It, Separator as J, Row as K, TextInput as L, moveGuildChannels as Lt, serializePayload as M, listGuildActiveThreads as Mt, CheckboxGroup as N, listGuildChannels as Nt, CommandWithSubcommands as O, deleteChannelPermission as Ot, Label as P, listGuildEmojis as Pt, UserSelectMenu as Q, Button as R, putChannelPermission as Rt, DiscordError as S, addGuildMemberRole as St, readDiscordMessage as T, createGuildEmoji as Tt, MediaGallery as U, resolveDiscordChannelId as Ut, File as V, timeoutGuildMember as Vt, MentionableSelectMenu as W, __exportAll as Wt, TextDisplay as X, StringSelectMenu as Y, Thumbnail as Z, VoiceStateUpdateListener as _, listChannelPins as _t, normalizeDiscordMessagingTarget as a, deleteOwnMessageReaction as at, Plugin as b, sendChannelTyping as bt, discord_exports as c, createThread as ct, MessageReactionAddListener as d, editChannel as dt, parseCustomId as et, MessageReactionRemoveListener as f, editChannelMessage as ft, ThreadUpdateListener as g, listChannelMessages as gt, ResumedListener as h, listChannelArchivedThreads as ht, looksLikeDiscordTargetId as i, createOwnMessageReaction as it, User as j, getGuildVoiceState as jt, Guild as k, getGuild as kt, InteractionCreateListener as l, deleteChannel as lt, ReadyListener as m, getChannelMessage as mt, createDiscordSendResult as n, createUserDmChannel as nt, normalizeDiscordOutboundTarget as o, listMessageReactionUsers as ot, PresenceUpdateListener as p, getChannel as pt, Section as q, allowFromContainsDiscordUserId as r, getCurrentUser as rt, chunkDiscordTextWithMode as s, createChannelMessage as st, createDiscordSendReceipt as t, createChannelWebhook as tt, MessageCreateListener as u, deleteChannelMessage as ut, Embed as v, pinChannelMessage as vt, readDiscordCode as w, createGuildChannel as wt, RequestClient as x, unpinChannelMessage as xt, Client as y, searchGuildMessages as yt, ChannelSelectMenu as z, removeGuildMember as zt };