@openclaw/discord 2026.3.13 → 2026.5.2-beta.1

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 (502) hide show
  1. package/account-inspect-api.ts +6 -0
  2. package/action-runtime-api.ts +1 -0
  3. package/api.ts +132 -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/doctor-contract-api.ts +1 -0
  11. package/index.test.ts +13 -0
  12. package/index.ts +18 -13
  13. package/openclaw.plugin.json +3326 -1
  14. package/package.json +68 -2
  15. package/runtime-api.actions.ts +15 -0
  16. package/runtime-api.lookup.ts +22 -0
  17. package/runtime-api.monitor.ts +50 -0
  18. package/runtime-api.send.ts +79 -0
  19. package/runtime-api.threads.ts +30 -0
  20. package/runtime-api.ts +180 -0
  21. package/runtime-setter-api.ts +3 -0
  22. package/secret-contract-api.ts +4 -0
  23. package/security-audit-contract-api.ts +1 -0
  24. package/security-contract-api.ts +4 -0
  25. package/session-key-api.ts +1 -0
  26. package/setup-entry.ts +9 -0
  27. package/setup-plugin-api.ts +3 -0
  28. package/src/account-inspect.test.ts +126 -0
  29. package/src/account-inspect.ts +132 -0
  30. package/src/accounts.test.ts +247 -0
  31. package/src/accounts.ts +196 -0
  32. package/src/actions/handle-action.guild-admin.ts +411 -0
  33. package/src/actions/handle-action.test.ts +306 -0
  34. package/src/actions/handle-action.ts +372 -0
  35. package/src/actions/runtime.guild.ts +446 -0
  36. package/src/actions/runtime.messaging.messages.ts +205 -0
  37. package/src/actions/runtime.messaging.reactions.ts +67 -0
  38. package/src/actions/runtime.messaging.runtime.ts +69 -0
  39. package/src/actions/runtime.messaging.send.ts +248 -0
  40. package/src/actions/runtime.messaging.shared.ts +97 -0
  41. package/src/actions/runtime.messaging.ts +37 -0
  42. package/src/actions/runtime.moderation-shared.ts +48 -0
  43. package/src/actions/runtime.moderation.authz.test.ts +151 -0
  44. package/src/actions/runtime.moderation.ts +116 -0
  45. package/src/actions/runtime.presence.test.ts +160 -0
  46. package/src/actions/runtime.presence.ts +117 -0
  47. package/src/actions/runtime.shared.ts +83 -0
  48. package/src/actions/runtime.test.ts +1087 -0
  49. package/src/actions/runtime.ts +87 -0
  50. package/src/api-barrel.test.ts +80 -0
  51. package/src/api.test.ts +130 -0
  52. package/src/api.ts +169 -0
  53. package/src/approval-handler.runtime.test.ts +41 -0
  54. package/src/approval-handler.runtime.ts +632 -0
  55. package/src/approval-native.test.ts +330 -0
  56. package/src/approval-native.ts +219 -0
  57. package/src/approval-runtime.ts +14 -0
  58. package/src/approval-shared.ts +53 -0
  59. package/src/audit-core.ts +141 -0
  60. package/src/audit.test.ts +145 -0
  61. package/src/audit.ts +32 -0
  62. package/src/channel-actions.contract.test.ts +45 -0
  63. package/src/channel-actions.runtime.ts +1 -0
  64. package/src/channel-actions.test.ts +275 -0
  65. package/src/channel-actions.ts +203 -0
  66. package/src/channel-api.ts +29 -0
  67. package/src/channel.conversation.ts +159 -0
  68. package/src/channel.loaders.ts +47 -0
  69. package/src/channel.runtime.ts +1 -0
  70. package/src/channel.setup.ts +12 -0
  71. package/src/channel.test.ts +547 -12
  72. package/src/channel.ts +597 -430
  73. package/src/chunk.test.ts +157 -0
  74. package/src/chunk.ts +321 -0
  75. package/src/client.proxy.test.ts +176 -0
  76. package/src/client.test.ts +76 -0
  77. package/src/client.ts +132 -0
  78. package/src/component-custom-id.ts +72 -0
  79. package/src/components-registry.ts +356 -0
  80. package/src/components.builders.ts +409 -0
  81. package/src/components.modal.ts +124 -0
  82. package/src/components.parse.ts +407 -0
  83. package/src/components.test.ts +312 -0
  84. package/src/components.ts +54 -0
  85. package/src/components.types.ts +187 -0
  86. package/src/config-schema.test.ts +325 -0
  87. package/src/config-schema.ts +6 -0
  88. package/src/config-ui-hints.ts +249 -0
  89. package/src/conversation-identity.ts +58 -0
  90. package/src/delivery-retry.ts +56 -0
  91. package/src/directory-cache.ts +116 -0
  92. package/src/directory-config.ts +58 -0
  93. package/src/directory-contract.test.ts +129 -0
  94. package/src/directory-live.test.ts +126 -0
  95. package/src/directory-live.ts +135 -0
  96. package/src/doctor-contract.ts +477 -0
  97. package/src/doctor-shared.ts +5 -0
  98. package/src/doctor.test.ts +405 -0
  99. package/src/doctor.ts +340 -0
  100. package/src/draft-chunking.test.ts +64 -0
  101. package/src/draft-chunking.ts +43 -0
  102. package/src/draft-stream.test.ts +159 -0
  103. package/src/draft-stream.ts +154 -0
  104. package/src/error-body.ts +38 -0
  105. package/src/exec-approvals.test.ts +88 -0
  106. package/src/exec-approvals.ts +110 -0
  107. package/src/gateway-logging.test.ts +98 -0
  108. package/src/gateway-logging.ts +67 -0
  109. package/src/group-policy.ts +113 -0
  110. package/src/guilds.ts +29 -0
  111. package/src/inbound-context.contract.test.ts +11 -0
  112. package/src/interactive-dispatch.ts +104 -0
  113. package/src/internal/api.commands.ts +51 -0
  114. package/src/internal/api.guild.ts +164 -0
  115. package/src/internal/api.interactions.ts +53 -0
  116. package/src/internal/api.messages.ts +113 -0
  117. package/src/internal/api.reactions.ts +38 -0
  118. package/src/internal/api.test.ts +262 -0
  119. package/src/internal/api.ts +61 -0
  120. package/src/internal/api.users.ts +19 -0
  121. package/src/internal/api.webhooks.ts +13 -0
  122. package/src/internal/client.test.ts +408 -0
  123. package/src/internal/client.ts +308 -0
  124. package/src/internal/command-deploy.ts +237 -0
  125. package/src/internal/commands.ts +188 -0
  126. package/src/internal/components.base.ts +65 -0
  127. package/src/internal/components.message.ts +279 -0
  128. package/src/internal/components.modal.ts +95 -0
  129. package/src/internal/components.ts +31 -0
  130. package/src/internal/discord.ts +11 -0
  131. package/src/internal/embeds.ts +35 -0
  132. package/src/internal/entity-cache.ts +98 -0
  133. package/src/internal/event-queue.ts +162 -0
  134. package/src/internal/gateway-close-codes.ts +25 -0
  135. package/src/internal/gateway-dispatch.ts +96 -0
  136. package/src/internal/gateway-identify-limiter.ts +26 -0
  137. package/src/internal/gateway-lifecycle.ts +61 -0
  138. package/src/internal/gateway-rate-limit.ts +104 -0
  139. package/src/internal/gateway.test.ts +603 -0
  140. package/src/internal/gateway.ts +476 -0
  141. package/src/internal/interaction-dispatch.test.ts +148 -0
  142. package/src/internal/interaction-dispatch.ts +162 -0
  143. package/src/internal/interaction-options.ts +98 -0
  144. package/src/internal/interaction-response.ts +53 -0
  145. package/src/internal/interactions.test.ts +325 -0
  146. package/src/internal/interactions.ts +378 -0
  147. package/src/internal/listeners.ts +85 -0
  148. package/src/internal/live-smoke.live.test.ts +26 -0
  149. package/src/internal/modal-fields.ts +95 -0
  150. package/src/internal/payload.ts +69 -0
  151. package/src/internal/rest-body.ts +115 -0
  152. package/src/internal/rest-errors.ts +88 -0
  153. package/src/internal/rest-routes.ts +50 -0
  154. package/src/internal/rest-scheduler.ts +557 -0
  155. package/src/internal/rest.test.ts +673 -0
  156. package/src/internal/rest.ts +322 -0
  157. package/src/internal/schemas.ts +36 -0
  158. package/src/internal/structures.test.ts +43 -0
  159. package/src/internal/structures.ts +280 -0
  160. package/src/internal/test-builders.test-support.ts +163 -0
  161. package/src/internal/voice.ts +49 -0
  162. package/src/media-detection.ts +28 -0
  163. package/src/mentions.test.ts +111 -0
  164. package/src/mentions.ts +147 -0
  165. package/src/monitor/access-groups.ts +55 -0
  166. package/src/monitor/ack-reactions.ts +70 -0
  167. package/src/monitor/acp-bind-here.integration.test.ts +211 -0
  168. package/src/monitor/agent-components-auth.ts +7 -0
  169. package/src/monitor/agent-components-context.ts +154 -0
  170. package/src/monitor/agent-components-data.ts +224 -0
  171. package/src/monitor/agent-components-dm-auth.ts +221 -0
  172. package/src/monitor/agent-components-guild-auth.ts +322 -0
  173. package/src/monitor/agent-components-helpers.runtime.ts +5 -0
  174. package/src/monitor/agent-components-helpers.ts +34 -0
  175. package/src/monitor/agent-components-reply.ts +10 -0
  176. package/src/monitor/agent-components.deps.runtime.ts +2 -0
  177. package/src/monitor/agent-components.dispatch.ts +366 -0
  178. package/src/monitor/agent-components.handlers.ts +303 -0
  179. package/src/monitor/agent-components.modal.ts +160 -0
  180. package/src/monitor/agent-components.plugin-interactive.ts +187 -0
  181. package/src/monitor/agent-components.runtime.ts +14 -0
  182. package/src/monitor/agent-components.system-controls.ts +211 -0
  183. package/src/monitor/agent-components.ts +70 -0
  184. package/src/monitor/agent-components.types.ts +58 -0
  185. package/src/monitor/agent-components.wildcard-controls.ts +168 -0
  186. package/src/monitor/agent-components.wildcard.test.ts +71 -0
  187. package/src/monitor/allow-list.test.ts +14 -0
  188. package/src/monitor/allow-list.ts +633 -0
  189. package/src/monitor/auto-presence.test.ts +156 -0
  190. package/src/monitor/auto-presence.ts +356 -0
  191. package/src/monitor/channel-access.test.ts +99 -0
  192. package/src/monitor/channel-access.ts +102 -0
  193. package/src/monitor/commands.test.ts +24 -0
  194. package/src/monitor/commands.ts +9 -0
  195. package/src/monitor/dm-command-auth.test.ts +197 -0
  196. package/src/monitor/dm-command-auth.ts +158 -0
  197. package/src/monitor/dm-command-decision.test.ts +113 -0
  198. package/src/monitor/dm-command-decision.ts +49 -0
  199. package/src/monitor/exec-approvals.test.ts +226 -0
  200. package/src/monitor/exec-approvals.ts +158 -0
  201. package/src/monitor/format.ts +45 -0
  202. package/src/monitor/gateway-handle.ts +34 -0
  203. package/src/monitor/gateway-metadata.test.ts +29 -0
  204. package/src/monitor/gateway-metadata.ts +298 -0
  205. package/src/monitor/gateway-plugin.test.ts +297 -0
  206. package/src/monitor/gateway-plugin.ts +294 -0
  207. package/src/monitor/gateway-registry.ts +37 -0
  208. package/src/monitor/gateway-supervisor.test.ts +150 -0
  209. package/src/monitor/gateway-supervisor.ts +206 -0
  210. package/src/monitor/inbound-context.test-helpers.ts +37 -0
  211. package/src/monitor/inbound-context.test.ts +106 -0
  212. package/src/monitor/inbound-context.ts +103 -0
  213. package/src/monitor/inbound-dedupe.ts +79 -0
  214. package/src/monitor/inbound-job.test.ts +203 -0
  215. package/src/monitor/inbound-job.ts +118 -0
  216. package/src/monitor/listeners.queue.ts +91 -0
  217. package/src/monitor/listeners.reactions.ts +610 -0
  218. package/src/monitor/listeners.test.ts +200 -0
  219. package/src/monitor/listeners.ts +150 -0
  220. package/src/monitor/message-channel-info.ts +96 -0
  221. package/src/monitor/message-forwarded.ts +107 -0
  222. package/src/monitor/message-handler.batch-gate.test.ts +22 -0
  223. package/src/monitor/message-handler.batch-gate.ts +19 -0
  224. package/src/monitor/message-handler.bot-self-filter.test.ts +68 -0
  225. package/src/monitor/message-handler.context.ts +406 -0
  226. package/src/monitor/message-handler.dm-preflight.ts +123 -0
  227. package/src/monitor/message-handler.draft-preview.ts +246 -0
  228. package/src/monitor/message-handler.hydration.test.ts +80 -0
  229. package/src/monitor/message-handler.hydration.ts +198 -0
  230. package/src/monitor/message-handler.inbound-context.test.ts +59 -0
  231. package/src/monitor/message-handler.module-test-helpers.ts +31 -0
  232. package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
  233. package/src/monitor/message-handler.preflight-channel-context.test.ts +18 -0
  234. package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
  235. package/src/monitor/message-handler.preflight-context.ts +54 -0
  236. package/src/monitor/message-handler.preflight-helpers.ts +164 -0
  237. package/src/monitor/message-handler.preflight-history.ts +23 -0
  238. package/src/monitor/message-handler.preflight-logging.ts +36 -0
  239. package/src/monitor/message-handler.preflight-pluralkit.ts +26 -0
  240. package/src/monitor/message-handler.preflight-runtime.ts +28 -0
  241. package/src/monitor/message-handler.preflight-thread.ts +49 -0
  242. package/src/monitor/message-handler.preflight.acp-bindings.test.ts +369 -0
  243. package/src/monitor/message-handler.preflight.test-helpers.ts +111 -0
  244. package/src/monitor/message-handler.preflight.test.ts +1623 -0
  245. package/src/monitor/message-handler.preflight.ts +679 -0
  246. package/src/monitor/message-handler.preflight.types.ts +110 -0
  247. package/src/monitor/message-handler.process.test.ts +1369 -0
  248. package/src/monitor/message-handler.process.ts +686 -0
  249. package/src/monitor/message-handler.queue.test.ts +496 -0
  250. package/src/monitor/message-handler.routing-preflight.ts +112 -0
  251. package/src/monitor/message-handler.test-harness.ts +99 -0
  252. package/src/monitor/message-handler.test-helpers.ts +75 -0
  253. package/src/monitor/message-handler.ts +274 -0
  254. package/src/monitor/message-media.ts +509 -0
  255. package/src/monitor/message-run-queue.ts +101 -0
  256. package/src/monitor/message-text.ts +171 -0
  257. package/src/monitor/message-utils.test.ts +1157 -0
  258. package/src/monitor/message-utils.ts +32 -0
  259. package/src/monitor/model-picker-preferences.test.ts +67 -0
  260. package/src/monitor/model-picker-preferences.ts +184 -0
  261. package/src/monitor/model-picker.state.ts +364 -0
  262. package/src/monitor/model-picker.test-utils.ts +26 -0
  263. package/src/monitor/model-picker.test.ts +794 -0
  264. package/src/monitor/model-picker.ts +38 -0
  265. package/src/monitor/model-picker.view.ts +695 -0
  266. package/src/monitor/monitor.agent-components.test.ts +375 -0
  267. package/src/monitor/monitor.test.ts +849 -0
  268. package/src/monitor/monitor.threading-utils.test.ts +598 -0
  269. package/src/monitor/native-command-agent-reply.ts +125 -0
  270. package/src/monitor/native-command-arg-ui.ts +233 -0
  271. package/src/monitor/native-command-auth.ts +308 -0
  272. package/src/monitor/native-command-bypass.ts +13 -0
  273. package/src/monitor/native-command-context.test.ts +98 -0
  274. package/src/monitor/native-command-context.ts +103 -0
  275. package/src/monitor/native-command-dispatch.ts +35 -0
  276. package/src/monitor/native-command-model-picker-apply.ts +177 -0
  277. package/src/monitor/native-command-model-picker-interaction.ts +461 -0
  278. package/src/monitor/native-command-model-picker-ui.ts +368 -0
  279. package/src/monitor/native-command-reply.test.ts +68 -0
  280. package/src/monitor/native-command-reply.ts +185 -0
  281. package/src/monitor/native-command-route.ts +91 -0
  282. package/src/monitor/native-command-status.ts +76 -0
  283. package/src/monitor/native-command-ui.ts +26 -0
  284. package/src/monitor/native-command-ui.types.ts +20 -0
  285. package/src/monitor/native-command.args.ts +45 -0
  286. package/src/monitor/native-command.command-arg.test.ts +99 -0
  287. package/src/monitor/native-command.commands-allowfrom.test.ts +490 -0
  288. package/src/monitor/native-command.model-picker.test.ts +767 -0
  289. package/src/monitor/native-command.options.test.ts +369 -0
  290. package/src/monitor/native-command.options.ts +153 -0
  291. package/src/monitor/native-command.plugin-dispatch.test.ts +961 -0
  292. package/src/monitor/native-command.runtime.ts +50 -0
  293. package/src/monitor/native-command.status-direct.test.ts +272 -0
  294. package/src/monitor/native-command.test-helpers.ts +64 -0
  295. package/src/monitor/native-command.think-autocomplete.test.ts +416 -0
  296. package/src/monitor/native-command.ts +700 -0
  297. package/src/monitor/native-command.types.ts +9 -0
  298. package/src/monitor/native-interaction-channel-context.ts +50 -0
  299. package/src/monitor/preflight-audio.runtime.ts +9 -0
  300. package/src/monitor/preflight-audio.test.ts +157 -0
  301. package/src/monitor/preflight-audio.ts +130 -0
  302. package/src/monitor/presence-cache.ts +61 -0
  303. package/src/monitor/presence.test.ts +44 -0
  304. package/src/monitor/presence.ts +50 -0
  305. package/src/monitor/provider-session.runtime.ts +12 -0
  306. package/src/monitor/provider.acp.ts +89 -0
  307. package/src/monitor/provider.allowlist.test.ts +149 -0
  308. package/src/monitor/provider.allowlist.ts +394 -0
  309. package/src/monitor/provider.cleanup.ts +41 -0
  310. package/src/monitor/provider.commands.ts +129 -0
  311. package/src/monitor/provider.config-log.ts +45 -0
  312. package/src/monitor/provider.deploy-errors.ts +362 -0
  313. package/src/monitor/provider.deploy.ts +221 -0
  314. package/src/monitor/provider.interactions.ts +160 -0
  315. package/src/monitor/provider.lifecycle.test.ts +713 -0
  316. package/src/monitor/provider.lifecycle.ts +552 -0
  317. package/src/monitor/provider.proxy.test.ts +745 -0
  318. package/src/monitor/provider.rest-proxy.test.ts +121 -0
  319. package/src/monitor/provider.runtime.ts +1 -0
  320. package/src/monitor/provider.skill-dedupe.test.ts +42 -0
  321. package/src/monitor/provider.startup-log.ts +32 -0
  322. package/src/monitor/provider.startup.test.ts +426 -0
  323. package/src/monitor/provider.startup.ts +323 -0
  324. package/src/monitor/provider.test.ts +1111 -0
  325. package/src/monitor/provider.ts +713 -0
  326. package/src/monitor/reply-context.ts +64 -0
  327. package/src/monitor/reply-delivery.test.ts +244 -0
  328. package/src/monitor/reply-delivery.ts +203 -0
  329. package/src/monitor/rest-fetch.ts +43 -0
  330. package/src/monitor/route-resolution.test.ts +204 -0
  331. package/src/monitor/route-resolution.ts +140 -0
  332. package/src/monitor/sender-identity.ts +81 -0
  333. package/src/monitor/startup-status.test.ts +30 -0
  334. package/src/monitor/startup-status.ts +10 -0
  335. package/src/monitor/status.ts +22 -0
  336. package/src/monitor/system-events.ts +55 -0
  337. package/src/monitor/thread-bindings.config.ts +35 -0
  338. package/src/monitor/thread-bindings.discord-api.test.ts +229 -0
  339. package/src/monitor/thread-bindings.discord-api.ts +310 -0
  340. package/src/monitor/thread-bindings.lifecycle.test.ts +1871 -0
  341. package/src/monitor/thread-bindings.lifecycle.ts +354 -0
  342. package/src/monitor/thread-bindings.manager.ts +553 -0
  343. package/src/monitor/thread-bindings.messages.ts +6 -0
  344. package/src/monitor/thread-bindings.persona.test.ts +34 -0
  345. package/src/monitor/thread-bindings.persona.ts +25 -0
  346. package/src/monitor/thread-bindings.session-adapter.ts +229 -0
  347. package/src/monitor/thread-bindings.session-shared.ts +59 -0
  348. package/src/monitor/thread-bindings.session-updates.ts +35 -0
  349. package/src/monitor/thread-bindings.shared-state.test.ts +36 -0
  350. package/src/monitor/thread-bindings.state.ts +540 -0
  351. package/src/monitor/thread-bindings.ts +48 -0
  352. package/src/monitor/thread-bindings.types.ts +83 -0
  353. package/src/monitor/thread-channel-context.ts +112 -0
  354. package/src/monitor/thread-session-close.test.ts +180 -0
  355. package/src/monitor/thread-session-close.ts +63 -0
  356. package/src/monitor/thread-title.generate.test.ts +197 -0
  357. package/src/monitor/thread-title.test.ts +31 -0
  358. package/src/monitor/thread-title.ts +181 -0
  359. package/src/monitor/threading.auto-thread.test.ts +327 -0
  360. package/src/monitor/threading.auto-thread.ts +287 -0
  361. package/src/monitor/threading.cache.ts +45 -0
  362. package/src/monitor/threading.parent-info.test.ts +156 -0
  363. package/src/monitor/threading.starter.test.ts +260 -0
  364. package/src/monitor/threading.starter.ts +287 -0
  365. package/src/monitor/threading.ts +20 -0
  366. package/src/monitor/threading.types.ts +102 -0
  367. package/src/monitor/timeouts.ts +84 -0
  368. package/src/monitor/typing.test.ts +42 -0
  369. package/src/monitor/typing.ts +17 -0
  370. package/src/monitor.gateway.test.ts +187 -0
  371. package/src/monitor.gateway.ts +75 -0
  372. package/src/monitor.test.ts +1397 -0
  373. package/src/monitor.ts +28 -0
  374. package/src/normalize.test.ts +56 -0
  375. package/src/normalize.ts +86 -0
  376. package/src/outbound-adapter.interactive-order.test.ts +64 -0
  377. package/src/outbound-adapter.test-harness.ts +207 -0
  378. package/src/outbound-adapter.test.ts +696 -0
  379. package/src/outbound-adapter.ts +291 -0
  380. package/src/outbound-approval.ts +29 -0
  381. package/src/outbound-components.ts +81 -0
  382. package/src/outbound-payload.contract.test.ts +38 -0
  383. package/src/outbound-payload.ts +134 -0
  384. package/src/outbound-send-context.ts +92 -0
  385. package/src/outbound-session-route.test.ts +34 -0
  386. package/src/outbound-session-route.ts +72 -0
  387. package/src/pluralkit.test.ts +67 -0
  388. package/src/pluralkit.ts +58 -0
  389. package/src/preview-streaming.ts +32 -0
  390. package/src/probe.intents.test.ts +94 -0
  391. package/src/probe.parse-token.test.ts +43 -0
  392. package/src/probe.runtime.ts +1 -0
  393. package/src/probe.ts +237 -0
  394. package/src/proxy-fetch.ts +92 -0
  395. package/src/proxy-request-client.test.ts +78 -0
  396. package/src/proxy-request-client.ts +21 -0
  397. package/src/recipient-resolution.ts +39 -0
  398. package/src/resolve-allowlist-common.test.ts +36 -0
  399. package/src/resolve-allowlist-common.ts +39 -0
  400. package/src/resolve-channels.test.ts +340 -0
  401. package/src/resolve-channels.ts +369 -0
  402. package/src/resolve-users.test.ts +222 -0
  403. package/src/resolve-users.ts +184 -0
  404. package/src/retry.test.ts +83 -0
  405. package/src/retry.ts +98 -0
  406. package/src/runtime-api.ts +64 -0
  407. package/src/runtime.ts +22 -5
  408. package/src/secret-config-contract.ts +140 -0
  409. package/src/security-audit.runtime.ts +1 -0
  410. package/src/security-audit.test.ts +246 -0
  411. package/src/security-audit.ts +208 -0
  412. package/src/security-contract.ts +47 -0
  413. package/src/security-doctor.test.ts +25 -0
  414. package/src/security-doctor.ts +20 -0
  415. package/src/security.ts +60 -0
  416. package/src/send-target-parsing.ts +14 -0
  417. package/src/send.channels.ts +139 -0
  418. package/src/send.components.test.ts +275 -0
  419. package/src/send.components.ts +381 -0
  420. package/src/send.creates-thread.test.ts +643 -0
  421. package/src/send.emojis-stickers.ts +57 -0
  422. package/src/send.guild.ts +170 -0
  423. package/src/send.message-request.ts +97 -0
  424. package/src/send.messages.test.ts +53 -0
  425. package/src/send.messages.ts +225 -0
  426. package/src/send.outbound.ts +413 -0
  427. package/src/send.permissions.authz.test.ts +188 -0
  428. package/src/send.permissions.ts +283 -0
  429. package/src/send.reactions.ts +155 -0
  430. package/src/send.sends-basic-channel-messages.test.ts +941 -0
  431. package/src/send.shared.ts +447 -0
  432. package/src/send.test-harness.ts +56 -0
  433. package/src/send.ts +82 -0
  434. package/src/send.types.ts +188 -0
  435. package/src/send.typing.test.ts +41 -0
  436. package/src/send.typing.ts +9 -0
  437. package/src/send.voice.ts +134 -0
  438. package/src/send.webhook-activity.test.ts +105 -0
  439. package/src/send.webhook.proxy.test.ts +191 -0
  440. package/src/send.webhook.ts +133 -0
  441. package/src/session-contract.ts +3 -0
  442. package/src/session-key-normalization.test.ts +44 -0
  443. package/src/session-key-normalization.ts +47 -0
  444. package/src/setup-account-state.test.ts +91 -0
  445. package/src/setup-account-state.ts +144 -0
  446. package/src/setup-adapter.ts +12 -0
  447. package/src/setup-core.ts +212 -0
  448. package/src/setup-runtime-helpers.ts +10 -0
  449. package/src/setup-surface.test.ts +137 -0
  450. package/src/setup-surface.ts +129 -0
  451. package/src/shared-interactive.test.ts +153 -0
  452. package/src/shared-interactive.ts +124 -0
  453. package/src/shared.test.ts +165 -0
  454. package/src/shared.ts +190 -0
  455. package/src/status-issues.test.ts +70 -0
  456. package/src/status-issues.ts +169 -0
  457. package/src/subagent-hooks.test.ts +130 -81
  458. package/src/subagent-hooks.ts +184 -122
  459. package/src/target-parsing.ts +53 -0
  460. package/src/target-resolver.ts +129 -0
  461. package/src/targets.test.ts +367 -0
  462. package/src/targets.ts +12 -0
  463. package/src/test-http-helpers.ts +10 -0
  464. package/src/test-support/component-runtime.ts +190 -0
  465. package/src/test-support/config.ts +7 -0
  466. package/src/test-support/configured-binding-runtime.ts +29 -0
  467. package/src/test-support/partial-channel.ts +26 -0
  468. package/src/test-support/provider.test-support.ts +545 -0
  469. package/src/token.test.ts +107 -0
  470. package/src/token.ts +60 -0
  471. package/src/ui-colors.ts +27 -0
  472. package/src/ui.ts +20 -0
  473. package/src/voice/access.test.ts +217 -0
  474. package/src/voice/access.ts +124 -0
  475. package/src/voice/audio.ts +173 -0
  476. package/src/voice/capture-state.test.ts +48 -0
  477. package/src/voice/capture-state.ts +120 -0
  478. package/src/voice/command.test.ts +164 -0
  479. package/src/voice/command.ts +283 -0
  480. package/src/voice/config.ts +8 -0
  481. package/src/voice/manager.e2e.test.ts +928 -0
  482. package/src/voice/manager.ready-listener.test.ts +37 -0
  483. package/src/voice/manager.runtime.ts +11 -0
  484. package/src/voice/manager.ts +691 -0
  485. package/src/voice/prompt.test.ts +16 -0
  486. package/src/voice/prompt.ts +17 -0
  487. package/src/voice/receive-recovery.test.ts +79 -0
  488. package/src/voice/receive-recovery.ts +159 -0
  489. package/src/voice/sanitize.test.ts +34 -0
  490. package/src/voice/sanitize.ts +32 -0
  491. package/src/voice/sdk-runtime.ts +14 -0
  492. package/src/voice/segment.ts +156 -0
  493. package/src/voice/session.ts +50 -0
  494. package/src/voice/speaker-context.ts +127 -0
  495. package/src/voice/tts.ts +125 -0
  496. package/src/voice-message.test.ts +234 -0
  497. package/src/voice-message.ts +444 -0
  498. package/subagent-hooks-api.ts +27 -0
  499. package/test-api.ts +4 -0
  500. package/thread-binding-api.ts +1 -0
  501. package/timeouts.ts +6 -0
  502. package/tsconfig.json +16 -0
@@ -0,0 +1,76 @@
1
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
2
+ import { describe, expect, it } from "vitest";
3
+ import { createDiscordRestClient } from "./client.js";
4
+ import type { RequestClient } from "./internal/discord.js";
5
+
6
+ describe("createDiscordRestClient", () => {
7
+ const fakeRest = {} as RequestClient;
8
+
9
+ it("uses explicit token without resolving config token SecretRefs", () => {
10
+ const cfg = {
11
+ channels: {
12
+ discord: {
13
+ token: {
14
+ source: "exec",
15
+ provider: "vault",
16
+ id: "discord/bot-token",
17
+ },
18
+ },
19
+ },
20
+ } as OpenClawConfig;
21
+
22
+ const result = createDiscordRestClient({ cfg, token: "Bot explicit-token", rest: fakeRest });
23
+
24
+ expect(result.token).toBe("explicit-token");
25
+ expect(result.rest).toBe(fakeRest);
26
+ expect(result.account.accountId).toBe("default");
27
+ });
28
+
29
+ it("keeps account retry config when explicit token is provided", () => {
30
+ const cfg = {
31
+ channels: {
32
+ discord: {
33
+ accounts: {
34
+ ops: {
35
+ token: {
36
+ source: "exec",
37
+ provider: "vault",
38
+ id: "discord/ops-token",
39
+ },
40
+ retry: {
41
+ attempts: 7,
42
+ },
43
+ },
44
+ },
45
+ },
46
+ },
47
+ } as OpenClawConfig;
48
+
49
+ const result = createDiscordRestClient({
50
+ cfg,
51
+ accountId: "ops",
52
+ token: "Bot explicit-account-token",
53
+ rest: fakeRest,
54
+ });
55
+
56
+ expect(result.token).toBe("explicit-account-token");
57
+ expect(result.account.accountId).toBe("ops");
58
+ expect(result.account.config.retry).toMatchObject({ attempts: 7 });
59
+ });
60
+
61
+ it("still throws when no explicit token is provided and config token is unresolved", () => {
62
+ const cfg = {
63
+ channels: {
64
+ discord: {
65
+ token: {
66
+ source: "file",
67
+ provider: "default",
68
+ id: "/discord/token",
69
+ },
70
+ },
71
+ },
72
+ } as OpenClawConfig;
73
+
74
+ expect(() => createDiscordRestClient({ cfg, rest: fakeRest })).toThrow(/unresolved SecretRef/i);
75
+ });
76
+ });
package/src/client.ts ADDED
@@ -0,0 +1,132 @@
1
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
2
+ import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
3
+ import type { RetryConfig, RetryRunner } from "openclaw/plugin-sdk/retry-runtime";
4
+ import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
5
+ import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
6
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
7
+ import {
8
+ mergeDiscordAccountConfig,
9
+ resolveDiscordAccount,
10
+ type ResolvedDiscordAccount,
11
+ } from "./accounts.js";
12
+ import { RequestClient } from "./internal/discord.js";
13
+ import { resolveDiscordProxyFetchForAccount } from "./proxy-fetch.js";
14
+ import { createDiscordRequestClient } from "./proxy-request-client.js";
15
+ import { createDiscordRetryRunner } from "./retry.js";
16
+ import type { DiscordRuntimeAccountContext } from "./send.types.js";
17
+ import { normalizeDiscordToken } from "./token.js";
18
+
19
+ export type DiscordClientOpts = {
20
+ cfg: OpenClawConfig;
21
+ token?: string;
22
+ accountId?: string;
23
+ rest?: RequestClient;
24
+ retry?: RetryConfig;
25
+ verbose?: boolean;
26
+ };
27
+
28
+ export function createDiscordRuntimeAccountContext(params: {
29
+ cfg: OpenClawConfig;
30
+ accountId: string;
31
+ }): DiscordRuntimeAccountContext {
32
+ return {
33
+ cfg: params.cfg,
34
+ accountId: normalizeAccountId(params.accountId),
35
+ };
36
+ }
37
+
38
+ export function resolveDiscordClientAccountContext(
39
+ opts: Pick<DiscordClientOpts, "cfg" | "accountId">,
40
+ runtime?: Pick<RuntimeEnv, "error">,
41
+ ) {
42
+ const resolvedCfg = requireRuntimeConfig(opts.cfg, "Discord client");
43
+ const account = resolveAccountWithoutToken({
44
+ cfg: resolvedCfg,
45
+ accountId: opts.accountId,
46
+ });
47
+ return {
48
+ cfg: resolvedCfg,
49
+ account,
50
+ proxyFetch: resolveDiscordProxyFetchForAccount(account, resolvedCfg, runtime),
51
+ };
52
+ }
53
+
54
+ function resolveToken(params: { accountId: string; fallbackToken?: string }) {
55
+ const fallback = normalizeDiscordToken(params.fallbackToken, "channels.discord.token");
56
+ if (!fallback) {
57
+ throw new Error(
58
+ `Discord bot token missing for account "${params.accountId}" (set discord.accounts.${params.accountId}.token or DISCORD_BOT_TOKEN for default).`,
59
+ );
60
+ }
61
+ return fallback;
62
+ }
63
+
64
+ function resolveRest(
65
+ token: string,
66
+ account: ResolvedDiscordAccount,
67
+ cfg: OpenClawConfig,
68
+ rest?: RequestClient,
69
+ proxyFetch?: typeof fetch,
70
+ ) {
71
+ if (rest) {
72
+ return rest;
73
+ }
74
+ const resolvedProxyFetch = proxyFetch ?? resolveDiscordProxyFetchForAccount(account, cfg);
75
+ return createDiscordRequestClient(
76
+ token,
77
+ resolvedProxyFetch ? { fetch: resolvedProxyFetch } : undefined,
78
+ );
79
+ }
80
+
81
+ function resolveAccountWithoutToken(params: {
82
+ cfg: OpenClawConfig;
83
+ accountId?: string;
84
+ }): ResolvedDiscordAccount {
85
+ const accountId = normalizeAccountId(params.accountId);
86
+ const merged = mergeDiscordAccountConfig(params.cfg, accountId);
87
+ const baseEnabled = params.cfg.channels?.discord?.enabled !== false;
88
+ const accountEnabled = merged.enabled !== false;
89
+ return {
90
+ accountId,
91
+ enabled: baseEnabled && accountEnabled,
92
+ name: normalizeOptionalString(merged.name),
93
+ token: "",
94
+ tokenSource: "none",
95
+ config: merged,
96
+ };
97
+ }
98
+
99
+ export function createDiscordRestClient(opts: DiscordClientOpts) {
100
+ const explicitToken = normalizeDiscordToken(opts.token, "channels.discord.token");
101
+ const proxyContext = resolveDiscordClientAccountContext(opts);
102
+ const resolvedCfg = proxyContext.cfg;
103
+ const account = explicitToken
104
+ ? proxyContext.account
105
+ : resolveDiscordAccount({ cfg: resolvedCfg, accountId: opts.accountId });
106
+ const token =
107
+ explicitToken ??
108
+ resolveToken({
109
+ accountId: account.accountId,
110
+ fallbackToken: account.token,
111
+ });
112
+ const rest = resolveRest(token, account, resolvedCfg, opts.rest, proxyContext.proxyFetch);
113
+ return { token, rest, account };
114
+ }
115
+
116
+ export function createDiscordClient(opts: DiscordClientOpts): {
117
+ token: string;
118
+ rest: RequestClient;
119
+ request: RetryRunner;
120
+ } {
121
+ const { token, rest, account } = createDiscordRestClient(opts);
122
+ const request = createDiscordRetryRunner({
123
+ retry: opts.retry,
124
+ configRetry: account.config.retry,
125
+ verbose: opts.verbose,
126
+ });
127
+ return { token, rest, request };
128
+ }
129
+
130
+ export function resolveDiscordRest(opts: DiscordClientOpts) {
131
+ return createDiscordRestClient(opts).rest;
132
+ }
@@ -0,0 +1,72 @@
1
+ import { parseCustomId, type ComponentParserResult } from "./internal/discord.js";
2
+
3
+ export const DISCORD_COMPONENT_CUSTOM_ID_KEY = "occomp";
4
+ export const DISCORD_MODAL_CUSTOM_ID_KEY = "ocmodal";
5
+
6
+ export function buildDiscordComponentCustomId(params: {
7
+ componentId: string;
8
+ modalId?: string;
9
+ }): string {
10
+ const base = `${DISCORD_COMPONENT_CUSTOM_ID_KEY}:cid=${params.componentId}`;
11
+ return params.modalId ? `${base};mid=${params.modalId}` : base;
12
+ }
13
+
14
+ export function buildDiscordModalCustomId(modalId: string): string {
15
+ return `${DISCORD_MODAL_CUSTOM_ID_KEY}:mid=${modalId}`;
16
+ }
17
+
18
+ export function parseDiscordComponentCustomId(
19
+ id: string,
20
+ ): { componentId: string; modalId?: string } | null {
21
+ const parsed = parseCustomId(id);
22
+ if (parsed.key !== DISCORD_COMPONENT_CUSTOM_ID_KEY) {
23
+ return null;
24
+ }
25
+ const componentId = parsed.data.cid;
26
+ if (typeof componentId !== "string" || !componentId.trim()) {
27
+ return null;
28
+ }
29
+ const modalId = parsed.data.mid;
30
+ return {
31
+ componentId,
32
+ modalId: typeof modalId === "string" && modalId.trim() ? modalId : undefined,
33
+ };
34
+ }
35
+
36
+ export function parseDiscordModalCustomId(id: string): string | null {
37
+ const parsed = parseCustomId(id);
38
+ if (parsed.key !== DISCORD_MODAL_CUSTOM_ID_KEY) {
39
+ return null;
40
+ }
41
+ const modalId = parsed.data.mid;
42
+ if (typeof modalId !== "string" || !modalId.trim()) {
43
+ return null;
44
+ }
45
+ return modalId;
46
+ }
47
+
48
+ function isDiscordComponentWildcardRegistrationId(id: string): boolean {
49
+ return /^__openclaw_discord_component_[a-z_]+_wildcard__$/.test(id);
50
+ }
51
+
52
+ export function parseDiscordComponentCustomIdForInteraction(id: string): ComponentParserResult {
53
+ if (id === "*" || isDiscordComponentWildcardRegistrationId(id)) {
54
+ return { key: "*", data: {} };
55
+ }
56
+ const parsed = parseCustomId(id);
57
+ if (parsed.key !== DISCORD_COMPONENT_CUSTOM_ID_KEY) {
58
+ return parsed;
59
+ }
60
+ return { key: "*", data: parsed.data };
61
+ }
62
+
63
+ export function parseDiscordModalCustomIdForInteraction(id: string): ComponentParserResult {
64
+ if (id === "*" || isDiscordComponentWildcardRegistrationId(id)) {
65
+ return { key: "*", data: {} };
66
+ }
67
+ const parsed = parseCustomId(id);
68
+ if (parsed.key !== DISCORD_MODAL_CUSTOM_ID_KEY) {
69
+ return parsed;
70
+ }
71
+ return { key: "*", data: parsed.data };
72
+ }
@@ -0,0 +1,356 @@
1
+ import { resolveGlobalMap } from "openclaw/plugin-sdk/global-singleton";
2
+ import type { DiscordComponentEntry, DiscordModalEntry } from "./components.js";
3
+ import { getOptionalDiscordRuntime } from "./runtime.js";
4
+
5
+ const DEFAULT_COMPONENT_TTL_MS = 30 * 60 * 1000;
6
+ const PERSISTENT_COMPONENT_NAMESPACE = "discord.components";
7
+ const PERSISTENT_MODAL_NAMESPACE = "discord.modals";
8
+ const PERSISTENT_COMPONENT_MAX_ENTRIES = 500;
9
+ const PERSISTENT_MODAL_MAX_ENTRIES = 500;
10
+ const DISCORD_COMPONENT_ENTRIES_KEY = Symbol.for("openclaw.discord.componentEntries");
11
+ const DISCORD_MODAL_ENTRIES_KEY = Symbol.for("openclaw.discord.modalEntries");
12
+
13
+ type PersistedDiscordRegistryEntry<T extends { id: string }> = {
14
+ version: 1;
15
+ entry: T;
16
+ };
17
+
18
+ type DiscordPersistentStore<T> = {
19
+ register(key: string, value: T, opts?: { ttlMs?: number }): Promise<void>;
20
+ lookup(key: string): Promise<T | undefined>;
21
+ consume(key: string): Promise<T | undefined>;
22
+ delete(key: string): Promise<boolean>;
23
+ };
24
+
25
+ type DiscordRegistryStore<T extends { id: string }> = DiscordPersistentStore<
26
+ PersistedDiscordRegistryEntry<T>
27
+ >;
28
+
29
+ let componentEntries: Map<string, DiscordComponentEntry> | undefined;
30
+ let modalEntries: Map<string, DiscordModalEntry> | undefined;
31
+ let persistentComponentStore: DiscordRegistryStore<DiscordComponentEntry> | undefined;
32
+ let persistentModalStore: DiscordRegistryStore<DiscordModalEntry> | undefined;
33
+ let persistentRegistryDisabled = false;
34
+
35
+ function getComponentEntries(): Map<string, DiscordComponentEntry> {
36
+ componentEntries ??= resolveGlobalMap<string, DiscordComponentEntry>(
37
+ DISCORD_COMPONENT_ENTRIES_KEY,
38
+ );
39
+ return componentEntries;
40
+ }
41
+
42
+ function getModalEntries(): Map<string, DiscordModalEntry> {
43
+ modalEntries ??= resolveGlobalMap<string, DiscordModalEntry>(DISCORD_MODAL_ENTRIES_KEY);
44
+ return modalEntries;
45
+ }
46
+
47
+ function reportPersistentComponentRegistryError(error: unknown): void {
48
+ try {
49
+ getOptionalDiscordRuntime()
50
+ ?.logging.getChildLogger({ plugin: "discord", feature: "component-registry-state" })
51
+ .warn("Discord persistent component registry state failed", { error: String(error) });
52
+ } catch {
53
+ // Best effort only: persistent state must never break Discord interactions.
54
+ }
55
+ }
56
+
57
+ function disablePersistentComponentRegistry(error: unknown): void {
58
+ persistentRegistryDisabled = true;
59
+ persistentComponentStore = undefined;
60
+ persistentModalStore = undefined;
61
+ reportPersistentComponentRegistryError(error);
62
+ }
63
+
64
+ function getPersistentComponentStore(): DiscordRegistryStore<DiscordComponentEntry> | undefined {
65
+ if (persistentRegistryDisabled) {
66
+ return undefined;
67
+ }
68
+ if (persistentComponentStore) {
69
+ return persistentComponentStore;
70
+ }
71
+ const runtime = getOptionalDiscordRuntime();
72
+ if (!runtime) {
73
+ return undefined;
74
+ }
75
+ try {
76
+ persistentComponentStore = runtime.state.openKeyedStore<
77
+ PersistedDiscordRegistryEntry<DiscordComponentEntry>
78
+ >({
79
+ namespace: PERSISTENT_COMPONENT_NAMESPACE,
80
+ maxEntries: PERSISTENT_COMPONENT_MAX_ENTRIES,
81
+ defaultTtlMs: DEFAULT_COMPONENT_TTL_MS,
82
+ });
83
+ return persistentComponentStore;
84
+ } catch (error) {
85
+ disablePersistentComponentRegistry(error);
86
+ return undefined;
87
+ }
88
+ }
89
+
90
+ function getPersistentModalStore(): DiscordRegistryStore<DiscordModalEntry> | undefined {
91
+ if (persistentRegistryDisabled) {
92
+ return undefined;
93
+ }
94
+ if (persistentModalStore) {
95
+ return persistentModalStore;
96
+ }
97
+ const runtime = getOptionalDiscordRuntime();
98
+ if (!runtime) {
99
+ return undefined;
100
+ }
101
+ try {
102
+ persistentModalStore = runtime.state.openKeyedStore<
103
+ PersistedDiscordRegistryEntry<DiscordModalEntry>
104
+ >({
105
+ namespace: PERSISTENT_MODAL_NAMESPACE,
106
+ maxEntries: PERSISTENT_MODAL_MAX_ENTRIES,
107
+ defaultTtlMs: DEFAULT_COMPONENT_TTL_MS,
108
+ });
109
+ return persistentModalStore;
110
+ } catch (error) {
111
+ disablePersistentComponentRegistry(error);
112
+ return undefined;
113
+ }
114
+ }
115
+
116
+ function isExpired(entry: { expiresAt?: number }, now: number) {
117
+ return typeof entry.expiresAt === "number" && entry.expiresAt <= now;
118
+ }
119
+
120
+ function normalizeEntryTimestamps<T extends { createdAt?: number; expiresAt?: number }>(
121
+ entry: T,
122
+ now: number,
123
+ ttlMs: number,
124
+ ): T {
125
+ const createdAt = entry.createdAt ?? now;
126
+ const expiresAt = entry.expiresAt ?? createdAt + ttlMs;
127
+ return { ...entry, createdAt, expiresAt };
128
+ }
129
+
130
+ function registerEntries<
131
+ T extends { id: string; messageId?: string; createdAt?: number; expiresAt?: number },
132
+ >(
133
+ entries: T[],
134
+ store: Map<string, T>,
135
+ params: { now: number; ttlMs: number; messageId?: string },
136
+ ): T[] {
137
+ const normalizedEntries: T[] = [];
138
+ for (const entry of entries) {
139
+ const normalized = normalizeEntryTimestamps(
140
+ { ...entry, messageId: params.messageId ?? entry.messageId },
141
+ params.now,
142
+ params.ttlMs,
143
+ );
144
+ store.set(entry.id, normalized);
145
+ normalizedEntries.push(normalized);
146
+ }
147
+ return normalizedEntries;
148
+ }
149
+
150
+ function resolveEntry<T extends { expiresAt?: number }>(
151
+ store: Map<string, T>,
152
+ params: { id: string; consume?: boolean },
153
+ ): T | null {
154
+ const entry = store.get(params.id);
155
+ if (!entry) {
156
+ return null;
157
+ }
158
+ const now = Date.now();
159
+ if (isExpired(entry, now)) {
160
+ store.delete(params.id);
161
+ return null;
162
+ }
163
+ if (params.consume !== false) {
164
+ store.delete(params.id);
165
+ }
166
+ return entry;
167
+ }
168
+
169
+ function readPersistedRegistryEntry<T extends { id: string }>(
170
+ persisted: PersistedDiscordRegistryEntry<T> | undefined,
171
+ ): T | null {
172
+ if (persisted?.version !== 1 || typeof persisted.entry?.id !== "string") {
173
+ return null;
174
+ }
175
+ return persisted.entry;
176
+ }
177
+
178
+ function registerPersistentRegistryEntries<T extends { id: string }>(params: {
179
+ entries: T[];
180
+ ttlMs: number;
181
+ openStore: () => DiscordRegistryStore<T> | undefined;
182
+ }): void {
183
+ if (params.entries.length === 0) {
184
+ return;
185
+ }
186
+ const store = params.openStore();
187
+ if (!store) {
188
+ return;
189
+ }
190
+ for (const entry of params.entries) {
191
+ void store
192
+ .register(entry.id, { version: 1, entry }, { ttlMs: params.ttlMs })
193
+ .catch(disablePersistentComponentRegistry);
194
+ }
195
+ }
196
+
197
+ function registerPersistentEntries(params: {
198
+ entries: DiscordComponentEntry[];
199
+ modals: DiscordModalEntry[];
200
+ ttlMs: number;
201
+ }): void {
202
+ registerPersistentRegistryEntries({
203
+ entries: params.entries,
204
+ ttlMs: params.ttlMs,
205
+ openStore: getPersistentComponentStore,
206
+ });
207
+ registerPersistentRegistryEntries({
208
+ entries: params.modals,
209
+ ttlMs: params.ttlMs,
210
+ openStore: getPersistentModalStore,
211
+ });
212
+ }
213
+
214
+ function deletePersistentEntry<T extends { id: string }>(params: {
215
+ id: string;
216
+ openStore: () => DiscordRegistryStore<T> | undefined;
217
+ }): void {
218
+ const store = params.openStore();
219
+ if (!store) {
220
+ return;
221
+ }
222
+ void store.delete(params.id).catch(disablePersistentComponentRegistry);
223
+ }
224
+
225
+ function resolveComponentConsumptionIds(entry: DiscordComponentEntry): string[] {
226
+ if (!entry.consumptionGroupId) {
227
+ return [entry.id];
228
+ }
229
+ const ids = entry.consumptionGroupEntryIds?.filter((id) => typeof id === "string" && id) ?? [];
230
+ return ids.length > 0 ? Array.from(new Set(ids)) : [entry.id];
231
+ }
232
+
233
+ function deleteComponentConsumptionGroup(entry: DiscordComponentEntry): void {
234
+ const store = getComponentEntries();
235
+ for (const id of resolveComponentConsumptionIds(entry)) {
236
+ store.delete(id);
237
+ }
238
+ }
239
+
240
+ function deletePersistentComponentConsumptionGroup(entry: DiscordComponentEntry): void {
241
+ const store = getPersistentComponentStore();
242
+ if (!store) {
243
+ return;
244
+ }
245
+ for (const id of resolveComponentConsumptionIds(entry)) {
246
+ void store.delete(id).catch(disablePersistentComponentRegistry);
247
+ }
248
+ }
249
+
250
+ async function resolvePersistentRegistryEntry<T extends { id: string }>(params: {
251
+ id: string;
252
+ consume?: boolean;
253
+ openStore: () => DiscordRegistryStore<T> | undefined;
254
+ }): Promise<T | null> {
255
+ const store = params.openStore();
256
+ if (!store) {
257
+ return null;
258
+ }
259
+ try {
260
+ const value =
261
+ params.consume === false ? await store.lookup(params.id) : await store.consume(params.id);
262
+ return readPersistedRegistryEntry(value);
263
+ } catch (error) {
264
+ disablePersistentComponentRegistry(error);
265
+ return null;
266
+ }
267
+ }
268
+
269
+ export function registerDiscordComponentEntries(params: {
270
+ entries: DiscordComponentEntry[];
271
+ modals: DiscordModalEntry[];
272
+ ttlMs?: number;
273
+ messageId?: string;
274
+ }): void {
275
+ const now = Date.now();
276
+ const ttlMs = params.ttlMs ?? DEFAULT_COMPONENT_TTL_MS;
277
+ const normalizedEntries = registerEntries(params.entries, getComponentEntries(), {
278
+ now,
279
+ ttlMs,
280
+ messageId: params.messageId,
281
+ });
282
+ const normalizedModals = registerEntries(params.modals, getModalEntries(), {
283
+ now,
284
+ ttlMs,
285
+ messageId: params.messageId,
286
+ });
287
+ registerPersistentEntries({
288
+ entries: normalizedEntries,
289
+ modals: normalizedModals,
290
+ ttlMs,
291
+ });
292
+ }
293
+
294
+ export function resolveDiscordComponentEntry(params: {
295
+ id: string;
296
+ consume?: boolean;
297
+ }): DiscordComponentEntry | null {
298
+ const entry = resolveEntry(getComponentEntries(), params);
299
+ if (entry && params.consume !== false) {
300
+ deleteComponentConsumptionGroup(entry);
301
+ }
302
+ return entry;
303
+ }
304
+
305
+ export async function resolveDiscordComponentEntryWithPersistence(params: {
306
+ id: string;
307
+ consume?: boolean;
308
+ }): Promise<DiscordComponentEntry | null> {
309
+ const inMemory = resolveDiscordComponentEntry(params);
310
+ if (inMemory) {
311
+ if (params.consume !== false) {
312
+ deletePersistentComponentConsumptionGroup(inMemory);
313
+ }
314
+ return inMemory;
315
+ }
316
+ const persisted = await resolvePersistentRegistryEntry({
317
+ ...params,
318
+ openStore: getPersistentComponentStore,
319
+ });
320
+ if (persisted && params.consume !== false) {
321
+ deletePersistentComponentConsumptionGroup(persisted);
322
+ }
323
+ return persisted;
324
+ }
325
+
326
+ export function resolveDiscordModalEntry(params: {
327
+ id: string;
328
+ consume?: boolean;
329
+ }): DiscordModalEntry | null {
330
+ return resolveEntry(getModalEntries(), params);
331
+ }
332
+
333
+ export async function resolveDiscordModalEntryWithPersistence(params: {
334
+ id: string;
335
+ consume?: boolean;
336
+ }): Promise<DiscordModalEntry | null> {
337
+ const inMemory = resolveDiscordModalEntry(params);
338
+ if (inMemory) {
339
+ if (params.consume !== false) {
340
+ deletePersistentEntry({ ...params, openStore: getPersistentModalStore });
341
+ }
342
+ return inMemory;
343
+ }
344
+ return await resolvePersistentRegistryEntry({
345
+ ...params,
346
+ openStore: getPersistentModalStore,
347
+ });
348
+ }
349
+
350
+ export function clearDiscordComponentEntries(): void {
351
+ getComponentEntries().clear();
352
+ getModalEntries().clear();
353
+ persistentComponentStore = undefined;
354
+ persistentModalStore = undefined;
355
+ persistentRegistryDisabled = false;
356
+ }