@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.
- package/account-inspect-api.ts +6 -0
- package/action-runtime-api.ts +1 -0
- package/api.ts +132 -0
- package/channel-config-api.ts +1 -0
- package/channel-plugin-api.ts +3 -0
- package/config-api.ts +4 -0
- package/configured-state.ts +6 -0
- package/contract-api.ts +21 -0
- package/directory-contract-api.ts +4 -0
- package/doctor-contract-api.ts +1 -0
- package/index.test.ts +13 -0
- package/index.ts +18 -13
- package/openclaw.plugin.json +3326 -1
- package/package.json +68 -2
- package/runtime-api.actions.ts +15 -0
- package/runtime-api.lookup.ts +22 -0
- package/runtime-api.monitor.ts +50 -0
- package/runtime-api.send.ts +79 -0
- package/runtime-api.threads.ts +30 -0
- package/runtime-api.ts +180 -0
- package/runtime-setter-api.ts +3 -0
- package/secret-contract-api.ts +4 -0
- package/security-audit-contract-api.ts +1 -0
- package/security-contract-api.ts +4 -0
- package/session-key-api.ts +1 -0
- package/setup-entry.ts +9 -0
- package/setup-plugin-api.ts +3 -0
- package/src/account-inspect.test.ts +126 -0
- package/src/account-inspect.ts +132 -0
- package/src/accounts.test.ts +247 -0
- package/src/accounts.ts +196 -0
- package/src/actions/handle-action.guild-admin.ts +411 -0
- package/src/actions/handle-action.test.ts +306 -0
- package/src/actions/handle-action.ts +372 -0
- package/src/actions/runtime.guild.ts +446 -0
- package/src/actions/runtime.messaging.messages.ts +205 -0
- package/src/actions/runtime.messaging.reactions.ts +67 -0
- package/src/actions/runtime.messaging.runtime.ts +69 -0
- package/src/actions/runtime.messaging.send.ts +248 -0
- package/src/actions/runtime.messaging.shared.ts +97 -0
- package/src/actions/runtime.messaging.ts +37 -0
- package/src/actions/runtime.moderation-shared.ts +48 -0
- package/src/actions/runtime.moderation.authz.test.ts +151 -0
- package/src/actions/runtime.moderation.ts +116 -0
- package/src/actions/runtime.presence.test.ts +160 -0
- package/src/actions/runtime.presence.ts +117 -0
- package/src/actions/runtime.shared.ts +83 -0
- package/src/actions/runtime.test.ts +1087 -0
- package/src/actions/runtime.ts +87 -0
- package/src/api-barrel.test.ts +80 -0
- package/src/api.test.ts +130 -0
- package/src/api.ts +169 -0
- package/src/approval-handler.runtime.test.ts +41 -0
- package/src/approval-handler.runtime.ts +632 -0
- package/src/approval-native.test.ts +330 -0
- package/src/approval-native.ts +219 -0
- package/src/approval-runtime.ts +14 -0
- package/src/approval-shared.ts +53 -0
- package/src/audit-core.ts +141 -0
- package/src/audit.test.ts +145 -0
- package/src/audit.ts +32 -0
- package/src/channel-actions.contract.test.ts +45 -0
- package/src/channel-actions.runtime.ts +1 -0
- package/src/channel-actions.test.ts +275 -0
- package/src/channel-actions.ts +203 -0
- package/src/channel-api.ts +29 -0
- package/src/channel.conversation.ts +159 -0
- package/src/channel.loaders.ts +47 -0
- package/src/channel.runtime.ts +1 -0
- package/src/channel.setup.ts +12 -0
- package/src/channel.test.ts +547 -12
- package/src/channel.ts +597 -430
- package/src/chunk.test.ts +157 -0
- package/src/chunk.ts +321 -0
- package/src/client.proxy.test.ts +176 -0
- package/src/client.test.ts +76 -0
- package/src/client.ts +132 -0
- package/src/component-custom-id.ts +72 -0
- package/src/components-registry.ts +356 -0
- package/src/components.builders.ts +409 -0
- package/src/components.modal.ts +124 -0
- package/src/components.parse.ts +407 -0
- package/src/components.test.ts +312 -0
- package/src/components.ts +54 -0
- package/src/components.types.ts +187 -0
- package/src/config-schema.test.ts +325 -0
- package/src/config-schema.ts +6 -0
- package/src/config-ui-hints.ts +249 -0
- package/src/conversation-identity.ts +58 -0
- package/src/delivery-retry.ts +56 -0
- package/src/directory-cache.ts +116 -0
- package/src/directory-config.ts +58 -0
- package/src/directory-contract.test.ts +129 -0
- package/src/directory-live.test.ts +126 -0
- package/src/directory-live.ts +135 -0
- package/src/doctor-contract.ts +477 -0
- package/src/doctor-shared.ts +5 -0
- package/src/doctor.test.ts +405 -0
- package/src/doctor.ts +340 -0
- package/src/draft-chunking.test.ts +64 -0
- package/src/draft-chunking.ts +43 -0
- package/src/draft-stream.test.ts +159 -0
- package/src/draft-stream.ts +154 -0
- package/src/error-body.ts +38 -0
- package/src/exec-approvals.test.ts +88 -0
- package/src/exec-approvals.ts +110 -0
- package/src/gateway-logging.test.ts +98 -0
- package/src/gateway-logging.ts +67 -0
- package/src/group-policy.ts +113 -0
- package/src/guilds.ts +29 -0
- package/src/inbound-context.contract.test.ts +11 -0
- package/src/interactive-dispatch.ts +104 -0
- package/src/internal/api.commands.ts +51 -0
- package/src/internal/api.guild.ts +164 -0
- package/src/internal/api.interactions.ts +53 -0
- package/src/internal/api.messages.ts +113 -0
- package/src/internal/api.reactions.ts +38 -0
- package/src/internal/api.test.ts +262 -0
- package/src/internal/api.ts +61 -0
- package/src/internal/api.users.ts +19 -0
- package/src/internal/api.webhooks.ts +13 -0
- package/src/internal/client.test.ts +408 -0
- package/src/internal/client.ts +308 -0
- package/src/internal/command-deploy.ts +237 -0
- package/src/internal/commands.ts +188 -0
- package/src/internal/components.base.ts +65 -0
- package/src/internal/components.message.ts +279 -0
- package/src/internal/components.modal.ts +95 -0
- package/src/internal/components.ts +31 -0
- package/src/internal/discord.ts +11 -0
- package/src/internal/embeds.ts +35 -0
- package/src/internal/entity-cache.ts +98 -0
- package/src/internal/event-queue.ts +162 -0
- package/src/internal/gateway-close-codes.ts +25 -0
- package/src/internal/gateway-dispatch.ts +96 -0
- package/src/internal/gateway-identify-limiter.ts +26 -0
- package/src/internal/gateway-lifecycle.ts +61 -0
- package/src/internal/gateway-rate-limit.ts +104 -0
- package/src/internal/gateway.test.ts +603 -0
- package/src/internal/gateway.ts +476 -0
- package/src/internal/interaction-dispatch.test.ts +148 -0
- package/src/internal/interaction-dispatch.ts +162 -0
- package/src/internal/interaction-options.ts +98 -0
- package/src/internal/interaction-response.ts +53 -0
- package/src/internal/interactions.test.ts +325 -0
- package/src/internal/interactions.ts +378 -0
- package/src/internal/listeners.ts +85 -0
- package/src/internal/live-smoke.live.test.ts +26 -0
- package/src/internal/modal-fields.ts +95 -0
- package/src/internal/payload.ts +69 -0
- package/src/internal/rest-body.ts +115 -0
- package/src/internal/rest-errors.ts +88 -0
- package/src/internal/rest-routes.ts +50 -0
- package/src/internal/rest-scheduler.ts +557 -0
- package/src/internal/rest.test.ts +673 -0
- package/src/internal/rest.ts +322 -0
- package/src/internal/schemas.ts +36 -0
- package/src/internal/structures.test.ts +43 -0
- package/src/internal/structures.ts +280 -0
- package/src/internal/test-builders.test-support.ts +163 -0
- package/src/internal/voice.ts +49 -0
- package/src/media-detection.ts +28 -0
- package/src/mentions.test.ts +111 -0
- package/src/mentions.ts +147 -0
- package/src/monitor/access-groups.ts +55 -0
- package/src/monitor/ack-reactions.ts +70 -0
- package/src/monitor/acp-bind-here.integration.test.ts +211 -0
- package/src/monitor/agent-components-auth.ts +7 -0
- package/src/monitor/agent-components-context.ts +154 -0
- package/src/monitor/agent-components-data.ts +224 -0
- package/src/monitor/agent-components-dm-auth.ts +221 -0
- package/src/monitor/agent-components-guild-auth.ts +322 -0
- package/src/monitor/agent-components-helpers.runtime.ts +5 -0
- package/src/monitor/agent-components-helpers.ts +34 -0
- package/src/monitor/agent-components-reply.ts +10 -0
- package/src/monitor/agent-components.deps.runtime.ts +2 -0
- package/src/monitor/agent-components.dispatch.ts +366 -0
- package/src/monitor/agent-components.handlers.ts +303 -0
- package/src/monitor/agent-components.modal.ts +160 -0
- package/src/monitor/agent-components.plugin-interactive.ts +187 -0
- package/src/monitor/agent-components.runtime.ts +14 -0
- package/src/monitor/agent-components.system-controls.ts +211 -0
- package/src/monitor/agent-components.ts +70 -0
- package/src/monitor/agent-components.types.ts +58 -0
- package/src/monitor/agent-components.wildcard-controls.ts +168 -0
- package/src/monitor/agent-components.wildcard.test.ts +71 -0
- package/src/monitor/allow-list.test.ts +14 -0
- package/src/monitor/allow-list.ts +633 -0
- package/src/monitor/auto-presence.test.ts +156 -0
- package/src/monitor/auto-presence.ts +356 -0
- package/src/monitor/channel-access.test.ts +99 -0
- package/src/monitor/channel-access.ts +102 -0
- package/src/monitor/commands.test.ts +24 -0
- package/src/monitor/commands.ts +9 -0
- package/src/monitor/dm-command-auth.test.ts +197 -0
- package/src/monitor/dm-command-auth.ts +158 -0
- package/src/monitor/dm-command-decision.test.ts +113 -0
- package/src/monitor/dm-command-decision.ts +49 -0
- package/src/monitor/exec-approvals.test.ts +226 -0
- package/src/monitor/exec-approvals.ts +158 -0
- package/src/monitor/format.ts +45 -0
- package/src/monitor/gateway-handle.ts +34 -0
- package/src/monitor/gateway-metadata.test.ts +29 -0
- package/src/monitor/gateway-metadata.ts +298 -0
- package/src/monitor/gateway-plugin.test.ts +297 -0
- package/src/monitor/gateway-plugin.ts +294 -0
- package/src/monitor/gateway-registry.ts +37 -0
- package/src/monitor/gateway-supervisor.test.ts +150 -0
- package/src/monitor/gateway-supervisor.ts +206 -0
- package/src/monitor/inbound-context.test-helpers.ts +37 -0
- package/src/monitor/inbound-context.test.ts +106 -0
- package/src/monitor/inbound-context.ts +103 -0
- package/src/monitor/inbound-dedupe.ts +79 -0
- package/src/monitor/inbound-job.test.ts +203 -0
- package/src/monitor/inbound-job.ts +118 -0
- package/src/monitor/listeners.queue.ts +91 -0
- package/src/monitor/listeners.reactions.ts +610 -0
- package/src/monitor/listeners.test.ts +200 -0
- package/src/monitor/listeners.ts +150 -0
- package/src/monitor/message-channel-info.ts +96 -0
- package/src/monitor/message-forwarded.ts +107 -0
- package/src/monitor/message-handler.batch-gate.test.ts +22 -0
- package/src/monitor/message-handler.batch-gate.ts +19 -0
- package/src/monitor/message-handler.bot-self-filter.test.ts +68 -0
- package/src/monitor/message-handler.context.ts +406 -0
- package/src/monitor/message-handler.dm-preflight.ts +123 -0
- package/src/monitor/message-handler.draft-preview.ts +246 -0
- package/src/monitor/message-handler.hydration.test.ts +80 -0
- package/src/monitor/message-handler.hydration.ts +198 -0
- package/src/monitor/message-handler.inbound-context.test.ts +59 -0
- package/src/monitor/message-handler.module-test-helpers.ts +31 -0
- package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
- package/src/monitor/message-handler.preflight-channel-context.test.ts +18 -0
- package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
- package/src/monitor/message-handler.preflight-context.ts +54 -0
- package/src/monitor/message-handler.preflight-helpers.ts +164 -0
- package/src/monitor/message-handler.preflight-history.ts +23 -0
- package/src/monitor/message-handler.preflight-logging.ts +36 -0
- package/src/monitor/message-handler.preflight-pluralkit.ts +26 -0
- package/src/monitor/message-handler.preflight-runtime.ts +28 -0
- package/src/monitor/message-handler.preflight-thread.ts +49 -0
- package/src/monitor/message-handler.preflight.acp-bindings.test.ts +369 -0
- package/src/monitor/message-handler.preflight.test-helpers.ts +111 -0
- package/src/monitor/message-handler.preflight.test.ts +1623 -0
- package/src/monitor/message-handler.preflight.ts +679 -0
- package/src/monitor/message-handler.preflight.types.ts +110 -0
- package/src/monitor/message-handler.process.test.ts +1369 -0
- package/src/monitor/message-handler.process.ts +686 -0
- package/src/monitor/message-handler.queue.test.ts +496 -0
- package/src/monitor/message-handler.routing-preflight.ts +112 -0
- package/src/monitor/message-handler.test-harness.ts +99 -0
- package/src/monitor/message-handler.test-helpers.ts +75 -0
- package/src/monitor/message-handler.ts +274 -0
- package/src/monitor/message-media.ts +509 -0
- package/src/monitor/message-run-queue.ts +101 -0
- package/src/monitor/message-text.ts +171 -0
- package/src/monitor/message-utils.test.ts +1157 -0
- package/src/monitor/message-utils.ts +32 -0
- package/src/monitor/model-picker-preferences.test.ts +67 -0
- package/src/monitor/model-picker-preferences.ts +184 -0
- package/src/monitor/model-picker.state.ts +364 -0
- package/src/monitor/model-picker.test-utils.ts +26 -0
- package/src/monitor/model-picker.test.ts +794 -0
- package/src/monitor/model-picker.ts +38 -0
- package/src/monitor/model-picker.view.ts +695 -0
- package/src/monitor/monitor.agent-components.test.ts +375 -0
- package/src/monitor/monitor.test.ts +849 -0
- package/src/monitor/monitor.threading-utils.test.ts +598 -0
- package/src/monitor/native-command-agent-reply.ts +125 -0
- package/src/monitor/native-command-arg-ui.ts +233 -0
- package/src/monitor/native-command-auth.ts +308 -0
- package/src/monitor/native-command-bypass.ts +13 -0
- package/src/monitor/native-command-context.test.ts +98 -0
- package/src/monitor/native-command-context.ts +103 -0
- package/src/monitor/native-command-dispatch.ts +35 -0
- package/src/monitor/native-command-model-picker-apply.ts +177 -0
- package/src/monitor/native-command-model-picker-interaction.ts +461 -0
- package/src/monitor/native-command-model-picker-ui.ts +368 -0
- package/src/monitor/native-command-reply.test.ts +68 -0
- package/src/monitor/native-command-reply.ts +185 -0
- package/src/monitor/native-command-route.ts +91 -0
- package/src/monitor/native-command-status.ts +76 -0
- package/src/monitor/native-command-ui.ts +26 -0
- package/src/monitor/native-command-ui.types.ts +20 -0
- package/src/monitor/native-command.args.ts +45 -0
- package/src/monitor/native-command.command-arg.test.ts +99 -0
- package/src/monitor/native-command.commands-allowfrom.test.ts +490 -0
- package/src/monitor/native-command.model-picker.test.ts +767 -0
- package/src/monitor/native-command.options.test.ts +369 -0
- package/src/monitor/native-command.options.ts +153 -0
- package/src/monitor/native-command.plugin-dispatch.test.ts +961 -0
- package/src/monitor/native-command.runtime.ts +50 -0
- package/src/monitor/native-command.status-direct.test.ts +272 -0
- package/src/monitor/native-command.test-helpers.ts +64 -0
- package/src/monitor/native-command.think-autocomplete.test.ts +416 -0
- package/src/monitor/native-command.ts +700 -0
- package/src/monitor/native-command.types.ts +9 -0
- package/src/monitor/native-interaction-channel-context.ts +50 -0
- package/src/monitor/preflight-audio.runtime.ts +9 -0
- package/src/monitor/preflight-audio.test.ts +157 -0
- package/src/monitor/preflight-audio.ts +130 -0
- package/src/monitor/presence-cache.ts +61 -0
- package/src/monitor/presence.test.ts +44 -0
- package/src/monitor/presence.ts +50 -0
- package/src/monitor/provider-session.runtime.ts +12 -0
- package/src/monitor/provider.acp.ts +89 -0
- package/src/monitor/provider.allowlist.test.ts +149 -0
- package/src/monitor/provider.allowlist.ts +394 -0
- package/src/monitor/provider.cleanup.ts +41 -0
- package/src/monitor/provider.commands.ts +129 -0
- package/src/monitor/provider.config-log.ts +45 -0
- package/src/monitor/provider.deploy-errors.ts +362 -0
- package/src/monitor/provider.deploy.ts +221 -0
- package/src/monitor/provider.interactions.ts +160 -0
- package/src/monitor/provider.lifecycle.test.ts +713 -0
- package/src/monitor/provider.lifecycle.ts +552 -0
- package/src/monitor/provider.proxy.test.ts +745 -0
- package/src/monitor/provider.rest-proxy.test.ts +121 -0
- package/src/monitor/provider.runtime.ts +1 -0
- package/src/monitor/provider.skill-dedupe.test.ts +42 -0
- package/src/monitor/provider.startup-log.ts +32 -0
- package/src/monitor/provider.startup.test.ts +426 -0
- package/src/monitor/provider.startup.ts +323 -0
- package/src/monitor/provider.test.ts +1111 -0
- package/src/monitor/provider.ts +713 -0
- package/src/monitor/reply-context.ts +64 -0
- package/src/monitor/reply-delivery.test.ts +244 -0
- package/src/monitor/reply-delivery.ts +203 -0
- package/src/monitor/rest-fetch.ts +43 -0
- package/src/monitor/route-resolution.test.ts +204 -0
- package/src/monitor/route-resolution.ts +140 -0
- package/src/monitor/sender-identity.ts +81 -0
- package/src/monitor/startup-status.test.ts +30 -0
- package/src/monitor/startup-status.ts +10 -0
- package/src/monitor/status.ts +22 -0
- package/src/monitor/system-events.ts +55 -0
- package/src/monitor/thread-bindings.config.ts +35 -0
- package/src/monitor/thread-bindings.discord-api.test.ts +229 -0
- package/src/monitor/thread-bindings.discord-api.ts +310 -0
- package/src/monitor/thread-bindings.lifecycle.test.ts +1871 -0
- package/src/monitor/thread-bindings.lifecycle.ts +354 -0
- package/src/monitor/thread-bindings.manager.ts +553 -0
- package/src/monitor/thread-bindings.messages.ts +6 -0
- package/src/monitor/thread-bindings.persona.test.ts +34 -0
- package/src/monitor/thread-bindings.persona.ts +25 -0
- package/src/monitor/thread-bindings.session-adapter.ts +229 -0
- package/src/monitor/thread-bindings.session-shared.ts +59 -0
- package/src/monitor/thread-bindings.session-updates.ts +35 -0
- package/src/monitor/thread-bindings.shared-state.test.ts +36 -0
- package/src/monitor/thread-bindings.state.ts +540 -0
- package/src/monitor/thread-bindings.ts +48 -0
- package/src/monitor/thread-bindings.types.ts +83 -0
- package/src/monitor/thread-channel-context.ts +112 -0
- package/src/monitor/thread-session-close.test.ts +180 -0
- package/src/monitor/thread-session-close.ts +63 -0
- package/src/monitor/thread-title.generate.test.ts +197 -0
- package/src/monitor/thread-title.test.ts +31 -0
- package/src/monitor/thread-title.ts +181 -0
- package/src/monitor/threading.auto-thread.test.ts +327 -0
- package/src/monitor/threading.auto-thread.ts +287 -0
- package/src/monitor/threading.cache.ts +45 -0
- package/src/monitor/threading.parent-info.test.ts +156 -0
- package/src/monitor/threading.starter.test.ts +260 -0
- package/src/monitor/threading.starter.ts +287 -0
- package/src/monitor/threading.ts +20 -0
- package/src/monitor/threading.types.ts +102 -0
- package/src/monitor/timeouts.ts +84 -0
- package/src/monitor/typing.test.ts +42 -0
- package/src/monitor/typing.ts +17 -0
- package/src/monitor.gateway.test.ts +187 -0
- package/src/monitor.gateway.ts +75 -0
- package/src/monitor.test.ts +1397 -0
- package/src/monitor.ts +28 -0
- package/src/normalize.test.ts +56 -0
- package/src/normalize.ts +86 -0
- package/src/outbound-adapter.interactive-order.test.ts +64 -0
- package/src/outbound-adapter.test-harness.ts +207 -0
- package/src/outbound-adapter.test.ts +696 -0
- package/src/outbound-adapter.ts +291 -0
- package/src/outbound-approval.ts +29 -0
- package/src/outbound-components.ts +81 -0
- package/src/outbound-payload.contract.test.ts +38 -0
- package/src/outbound-payload.ts +134 -0
- package/src/outbound-send-context.ts +92 -0
- package/src/outbound-session-route.test.ts +34 -0
- package/src/outbound-session-route.ts +72 -0
- package/src/pluralkit.test.ts +67 -0
- package/src/pluralkit.ts +58 -0
- package/src/preview-streaming.ts +32 -0
- package/src/probe.intents.test.ts +94 -0
- package/src/probe.parse-token.test.ts +43 -0
- package/src/probe.runtime.ts +1 -0
- package/src/probe.ts +237 -0
- package/src/proxy-fetch.ts +92 -0
- package/src/proxy-request-client.test.ts +78 -0
- package/src/proxy-request-client.ts +21 -0
- package/src/recipient-resolution.ts +39 -0
- package/src/resolve-allowlist-common.test.ts +36 -0
- package/src/resolve-allowlist-common.ts +39 -0
- package/src/resolve-channels.test.ts +340 -0
- package/src/resolve-channels.ts +369 -0
- package/src/resolve-users.test.ts +222 -0
- package/src/resolve-users.ts +184 -0
- package/src/retry.test.ts +83 -0
- package/src/retry.ts +98 -0
- package/src/runtime-api.ts +64 -0
- package/src/runtime.ts +22 -5
- package/src/secret-config-contract.ts +140 -0
- package/src/security-audit.runtime.ts +1 -0
- package/src/security-audit.test.ts +246 -0
- package/src/security-audit.ts +208 -0
- package/src/security-contract.ts +47 -0
- package/src/security-doctor.test.ts +25 -0
- package/src/security-doctor.ts +20 -0
- package/src/security.ts +60 -0
- package/src/send-target-parsing.ts +14 -0
- package/src/send.channels.ts +139 -0
- package/src/send.components.test.ts +275 -0
- package/src/send.components.ts +381 -0
- package/src/send.creates-thread.test.ts +643 -0
- package/src/send.emojis-stickers.ts +57 -0
- package/src/send.guild.ts +170 -0
- package/src/send.message-request.ts +97 -0
- package/src/send.messages.test.ts +53 -0
- package/src/send.messages.ts +225 -0
- package/src/send.outbound.ts +413 -0
- package/src/send.permissions.authz.test.ts +188 -0
- package/src/send.permissions.ts +283 -0
- package/src/send.reactions.ts +155 -0
- package/src/send.sends-basic-channel-messages.test.ts +941 -0
- package/src/send.shared.ts +447 -0
- package/src/send.test-harness.ts +56 -0
- package/src/send.ts +82 -0
- package/src/send.types.ts +188 -0
- package/src/send.typing.test.ts +41 -0
- package/src/send.typing.ts +9 -0
- package/src/send.voice.ts +134 -0
- package/src/send.webhook-activity.test.ts +105 -0
- package/src/send.webhook.proxy.test.ts +191 -0
- package/src/send.webhook.ts +133 -0
- package/src/session-contract.ts +3 -0
- package/src/session-key-normalization.test.ts +44 -0
- package/src/session-key-normalization.ts +47 -0
- package/src/setup-account-state.test.ts +91 -0
- package/src/setup-account-state.ts +144 -0
- package/src/setup-adapter.ts +12 -0
- package/src/setup-core.ts +212 -0
- package/src/setup-runtime-helpers.ts +10 -0
- package/src/setup-surface.test.ts +137 -0
- package/src/setup-surface.ts +129 -0
- package/src/shared-interactive.test.ts +153 -0
- package/src/shared-interactive.ts +124 -0
- package/src/shared.test.ts +165 -0
- package/src/shared.ts +190 -0
- package/src/status-issues.test.ts +70 -0
- package/src/status-issues.ts +169 -0
- package/src/subagent-hooks.test.ts +130 -81
- package/src/subagent-hooks.ts +184 -122
- package/src/target-parsing.ts +53 -0
- package/src/target-resolver.ts +129 -0
- package/src/targets.test.ts +367 -0
- package/src/targets.ts +12 -0
- package/src/test-http-helpers.ts +10 -0
- package/src/test-support/component-runtime.ts +190 -0
- package/src/test-support/config.ts +7 -0
- package/src/test-support/configured-binding-runtime.ts +29 -0
- package/src/test-support/partial-channel.ts +26 -0
- package/src/test-support/provider.test-support.ts +545 -0
- package/src/token.test.ts +107 -0
- package/src/token.ts +60 -0
- package/src/ui-colors.ts +27 -0
- package/src/ui.ts +20 -0
- package/src/voice/access.test.ts +217 -0
- package/src/voice/access.ts +124 -0
- package/src/voice/audio.ts +173 -0
- package/src/voice/capture-state.test.ts +48 -0
- package/src/voice/capture-state.ts +120 -0
- package/src/voice/command.test.ts +164 -0
- package/src/voice/command.ts +283 -0
- package/src/voice/config.ts +8 -0
- package/src/voice/manager.e2e.test.ts +928 -0
- package/src/voice/manager.ready-listener.test.ts +37 -0
- package/src/voice/manager.runtime.ts +11 -0
- package/src/voice/manager.ts +691 -0
- package/src/voice/prompt.test.ts +16 -0
- package/src/voice/prompt.ts +17 -0
- package/src/voice/receive-recovery.test.ts +79 -0
- package/src/voice/receive-recovery.ts +159 -0
- package/src/voice/sanitize.test.ts +34 -0
- package/src/voice/sanitize.ts +32 -0
- package/src/voice/sdk-runtime.ts +14 -0
- package/src/voice/segment.ts +156 -0
- package/src/voice/session.ts +50 -0
- package/src/voice/speaker-context.ts +127 -0
- package/src/voice/tts.ts +125 -0
- package/src/voice-message.test.ts +234 -0
- package/src/voice-message.ts +444 -0
- package/subagent-hooks-api.ts +27 -0
- package/test-api.ts +4 -0
- package/thread-binding-api.ts +1 -0
- package/timeouts.ts +6 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ComponentType,
|
|
3
|
+
InteractionResponseType,
|
|
4
|
+
InteractionType,
|
|
5
|
+
type APIApplicationCommandInteraction,
|
|
6
|
+
type APIApplicationCommandInteractionDataOption,
|
|
7
|
+
type APIChannel,
|
|
8
|
+
type APIInteraction,
|
|
9
|
+
type APIInteractionDataResolvedChannel,
|
|
10
|
+
type APIMessage,
|
|
11
|
+
type APIMessageComponentInteraction,
|
|
12
|
+
type APIModalSubmitInteraction,
|
|
13
|
+
type APIUser,
|
|
14
|
+
} from "discord-api-types/v10";
|
|
15
|
+
import {
|
|
16
|
+
createInteractionCallback,
|
|
17
|
+
createWebhookMessage,
|
|
18
|
+
deleteWebhookMessage,
|
|
19
|
+
editWebhookMessage,
|
|
20
|
+
getWebhookMessage,
|
|
21
|
+
} from "./api.js";
|
|
22
|
+
import { OptionsHandler } from "./interaction-options.js";
|
|
23
|
+
import {
|
|
24
|
+
InteractionResponseController,
|
|
25
|
+
needsComponentsV2Query,
|
|
26
|
+
type InteractionResponseState,
|
|
27
|
+
} from "./interaction-response.js";
|
|
28
|
+
import { extractModalFields, ModalFields } from "./modal-fields.js";
|
|
29
|
+
import { serializePayload, type MessagePayload } from "./payload.js";
|
|
30
|
+
import { assertDiscordInteractionPayload } from "./schemas.js";
|
|
31
|
+
import {
|
|
32
|
+
channelFactory,
|
|
33
|
+
Guild,
|
|
34
|
+
Message,
|
|
35
|
+
User,
|
|
36
|
+
type DiscordChannel,
|
|
37
|
+
type StructureClient,
|
|
38
|
+
} from "./structures.js";
|
|
39
|
+
|
|
40
|
+
export { OptionsHandler } from "./interaction-options.js";
|
|
41
|
+
export { ModalFields } from "./modal-fields.js";
|
|
42
|
+
|
|
43
|
+
type InteractionClient = StructureClient & {
|
|
44
|
+
options: { clientId: string };
|
|
45
|
+
componentHandler: {
|
|
46
|
+
waitForMessageComponent(
|
|
47
|
+
message: Message,
|
|
48
|
+
timeoutMs: number,
|
|
49
|
+
): Promise<
|
|
50
|
+
| { success: true; customId: string; message: Message; values?: string[] }
|
|
51
|
+
| { success: false; message: Message; reason: "timed out" }
|
|
52
|
+
>;
|
|
53
|
+
};
|
|
54
|
+
fetchChannel(id: string): Promise<DiscordChannel>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type Modal = {
|
|
58
|
+
serialize: () => unknown;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
type ComponentData = Record<string, unknown>;
|
|
62
|
+
|
|
63
|
+
export type RawInteraction = APIInteraction & {
|
|
64
|
+
token: string;
|
|
65
|
+
member?: { user?: APIUser; roles?: string[] };
|
|
66
|
+
guild_id?: string;
|
|
67
|
+
channel_id?: string;
|
|
68
|
+
channel?: unknown;
|
|
69
|
+
data?: {
|
|
70
|
+
custom_id?: string;
|
|
71
|
+
component_type?: number;
|
|
72
|
+
values?: string[];
|
|
73
|
+
components?: unknown[];
|
|
74
|
+
options?: APIApplicationCommandInteractionDataOption[];
|
|
75
|
+
resolved?: {
|
|
76
|
+
channels?: Record<string, APIInteractionDataResolvedChannel>;
|
|
77
|
+
roles?: Record<string, { id: string; name?: string }>;
|
|
78
|
+
users?: Record<string, { id: string; username?: string; discriminator?: string }>;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
message?: unknown;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
type CommandRawInteraction = APIApplicationCommandInteraction & RawInteraction;
|
|
85
|
+
type MessageComponentRawInteraction = APIMessageComponentInteraction & RawInteraction;
|
|
86
|
+
type ModalSubmitRawInteraction = APIModalSubmitInteraction & RawInteraction;
|
|
87
|
+
|
|
88
|
+
function toCommandRawInteraction(rawData: RawInteraction): CommandRawInteraction {
|
|
89
|
+
return rawData as CommandRawInteraction;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function toMessageComponentRawInteraction(rawData: RawInteraction): MessageComponentRawInteraction {
|
|
93
|
+
return rawData as MessageComponentRawInteraction;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function toModalSubmitRawInteraction(rawData: RawInteraction): ModalSubmitRawInteraction {
|
|
97
|
+
return rawData as ModalSubmitRawInteraction;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function readInteractionUser(rawData: RawInteraction, client: InteractionClient): User | null {
|
|
101
|
+
const directUser = "user" in rawData ? rawData.user : undefined;
|
|
102
|
+
if (directUser && typeof directUser === "object" && "id" in directUser) {
|
|
103
|
+
return new User(client, directUser);
|
|
104
|
+
}
|
|
105
|
+
const memberUser = rawData.member?.user;
|
|
106
|
+
if (memberUser && typeof memberUser === "object" && typeof memberUser.id === "string") {
|
|
107
|
+
const user = { ...memberUser } as APIUser;
|
|
108
|
+
if (typeof user.username !== "string") {
|
|
109
|
+
user.username = "";
|
|
110
|
+
}
|
|
111
|
+
return new User(client, user);
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export class BaseInteraction {
|
|
117
|
+
readonly id: string;
|
|
118
|
+
readonly token: string;
|
|
119
|
+
readonly user: User | null;
|
|
120
|
+
readonly userId: string;
|
|
121
|
+
readonly guild: Guild | null;
|
|
122
|
+
readonly channel: DiscordChannel | null;
|
|
123
|
+
message: Message | null = null;
|
|
124
|
+
private readonly response = new InteractionResponseController();
|
|
125
|
+
|
|
126
|
+
constructor(
|
|
127
|
+
public client: InteractionClient,
|
|
128
|
+
public rawData: RawInteraction,
|
|
129
|
+
) {
|
|
130
|
+
this.id = rawData.id;
|
|
131
|
+
this.token = rawData.token;
|
|
132
|
+
this.user = readInteractionUser(rawData, client);
|
|
133
|
+
this.userId = this.user?.id ?? "";
|
|
134
|
+
this.guild = rawData.guild_id ? new Guild<true>(client, rawData.guild_id) : null;
|
|
135
|
+
this.channel =
|
|
136
|
+
"channel" in rawData && rawData.channel
|
|
137
|
+
? channelFactory(client, rawData.channel as APIChannel)
|
|
138
|
+
: null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
get acknowledged(): boolean {
|
|
142
|
+
return this.response.acknowledged;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
get responseState(): InteractionResponseState {
|
|
146
|
+
return this.response.state;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
set responseState(nextState: InteractionResponseState) {
|
|
150
|
+
this.response.state = nextState;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
protected async callback(type: InteractionResponseType, data?: unknown) {
|
|
154
|
+
this.response.recordCallback(type);
|
|
155
|
+
return await createInteractionCallback(
|
|
156
|
+
this.client.rest,
|
|
157
|
+
this.id,
|
|
158
|
+
this.token,
|
|
159
|
+
data === undefined ? { type } : { type, data },
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async reply(payload: MessagePayload): Promise<unknown> {
|
|
164
|
+
const action = this.response.nextReplyAction();
|
|
165
|
+
if (action === "edit") {
|
|
166
|
+
return await this.editReply(payload);
|
|
167
|
+
}
|
|
168
|
+
if (action === "follow-up") {
|
|
169
|
+
return await this.followUp(payload);
|
|
170
|
+
}
|
|
171
|
+
return await this.callback(
|
|
172
|
+
InteractionResponseType.ChannelMessageWithSource,
|
|
173
|
+
serializePayload(payload),
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async defer(options?: { ephemeral?: boolean }): Promise<unknown> {
|
|
178
|
+
return await this.callback(
|
|
179
|
+
InteractionResponseType.DeferredChannelMessageWithSource,
|
|
180
|
+
options?.ephemeral ? { flags: 64 } : undefined,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async acknowledge(): Promise<unknown> {
|
|
185
|
+
return await this.defer();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async editReply(payload: MessagePayload): Promise<unknown> {
|
|
189
|
+
const body = serializePayload(payload);
|
|
190
|
+
const query = needsComponentsV2Query(body) ? { with_components: true } : undefined;
|
|
191
|
+
const result = query
|
|
192
|
+
? await editWebhookMessage(
|
|
193
|
+
this.client.rest,
|
|
194
|
+
this.client.options.clientId,
|
|
195
|
+
this.token,
|
|
196
|
+
"@original",
|
|
197
|
+
{ body },
|
|
198
|
+
query,
|
|
199
|
+
)
|
|
200
|
+
: await editWebhookMessage(
|
|
201
|
+
this.client.rest,
|
|
202
|
+
this.client.options.clientId,
|
|
203
|
+
this.token,
|
|
204
|
+
"@original",
|
|
205
|
+
{ body },
|
|
206
|
+
);
|
|
207
|
+
this.response.recordReplyEdit();
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async deleteReply(): Promise<unknown> {
|
|
212
|
+
return await deleteWebhookMessage(
|
|
213
|
+
this.client.rest,
|
|
214
|
+
this.client.options.clientId,
|
|
215
|
+
this.token,
|
|
216
|
+
"@original",
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async fetchReply(): Promise<unknown> {
|
|
221
|
+
return await getWebhookMessage(
|
|
222
|
+
this.client.rest,
|
|
223
|
+
this.client.options.clientId,
|
|
224
|
+
this.token,
|
|
225
|
+
"@original",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async replyAndWaitForComponent(payload: MessagePayload, timeoutMs = 300_000) {
|
|
230
|
+
const result = await this.reply(payload);
|
|
231
|
+
const rawMessage = isRawMessage(result) ? result : await this.fetchReply();
|
|
232
|
+
if (!isRawMessage(rawMessage)) {
|
|
233
|
+
throw new Error("Discord interaction reply did not return a message");
|
|
234
|
+
}
|
|
235
|
+
const message = new Message(this.client, rawMessage as APIMessage);
|
|
236
|
+
return await this.client.componentHandler.waitForMessageComponent(message, timeoutMs);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async followUp(payload: MessagePayload): Promise<unknown> {
|
|
240
|
+
const body = serializePayload(payload);
|
|
241
|
+
return await createWebhookMessage(
|
|
242
|
+
this.client.rest,
|
|
243
|
+
this.client.options.clientId,
|
|
244
|
+
this.token,
|
|
245
|
+
{ body },
|
|
246
|
+
needsComponentsV2Query(body) ? { with_components: true } : undefined,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export class CommandInteraction extends BaseInteraction {
|
|
252
|
+
readonly options: OptionsHandler;
|
|
253
|
+
constructor(
|
|
254
|
+
client: InteractionClient,
|
|
255
|
+
rawData: APIApplicationCommandInteraction & RawInteraction,
|
|
256
|
+
) {
|
|
257
|
+
super(client, rawData);
|
|
258
|
+
this.options = new OptionsHandler(
|
|
259
|
+
rawData.data.options,
|
|
260
|
+
client,
|
|
261
|
+
rawData.data.resolved?.channels,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export class AutocompleteInteraction extends CommandInteraction {
|
|
267
|
+
async respond(choices: Array<{ name: string; value: string | number }>): Promise<unknown> {
|
|
268
|
+
return await this.callback(InteractionResponseType.ApplicationCommandAutocompleteResult, {
|
|
269
|
+
choices,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export class BaseComponentInteraction extends BaseInteraction {
|
|
275
|
+
readonly values: string[];
|
|
276
|
+
|
|
277
|
+
constructor(client: InteractionClient, rawData: APIMessageComponentInteraction & RawInteraction) {
|
|
278
|
+
super(client, rawData);
|
|
279
|
+
this.message =
|
|
280
|
+
rawData.message && typeof rawData.message === "object"
|
|
281
|
+
? new Message(client, rawData.message)
|
|
282
|
+
: null;
|
|
283
|
+
this.values = Array.isArray(rawData.data.values) ? rawData.data.values.map(String) : [];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async update(payload: MessagePayload): Promise<unknown> {
|
|
287
|
+
return await this.callback(InteractionResponseType.UpdateMessage, serializePayload(payload));
|
|
288
|
+
}
|
|
289
|
+
async acknowledge(): Promise<unknown> {
|
|
290
|
+
return await this.callback(InteractionResponseType.DeferredMessageUpdate);
|
|
291
|
+
}
|
|
292
|
+
async showModal(modal: Modal): Promise<unknown> {
|
|
293
|
+
return await this.callback(InteractionResponseType.Modal, modal.serialize());
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async editAndWaitForComponent(
|
|
297
|
+
payload: MessagePayload,
|
|
298
|
+
message: Message | null = this.message,
|
|
299
|
+
timeoutMs = 300_000,
|
|
300
|
+
) {
|
|
301
|
+
if (!message) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
const editedMessage = await message.edit(payload);
|
|
305
|
+
return await this.client.componentHandler.waitForMessageComponent(editedMessage, timeoutMs);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export class ButtonInteraction extends BaseComponentInteraction {}
|
|
310
|
+
export class StringSelectMenuInteraction extends BaseComponentInteraction {}
|
|
311
|
+
export class UserSelectMenuInteraction extends BaseComponentInteraction {}
|
|
312
|
+
export class RoleSelectMenuInteraction extends BaseComponentInteraction {}
|
|
313
|
+
export class MentionableSelectMenuInteraction extends BaseComponentInteraction {}
|
|
314
|
+
export class ChannelSelectMenuInteraction extends BaseComponentInteraction {}
|
|
315
|
+
|
|
316
|
+
export class ModalInteraction extends BaseInteraction {
|
|
317
|
+
readonly fields: ModalFields;
|
|
318
|
+
constructor(client: InteractionClient, rawData: APIModalSubmitInteraction & RawInteraction) {
|
|
319
|
+
super(client, rawData);
|
|
320
|
+
this.fields = new ModalFields(
|
|
321
|
+
extractModalFields(rawData.data.components ?? []),
|
|
322
|
+
rawData.data.resolved,
|
|
323
|
+
client,
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
async acknowledge(): Promise<unknown> {
|
|
327
|
+
return await this.callback(InteractionResponseType.DeferredMessageUpdate);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function createInteraction(client: InteractionClient, rawData: RawInteraction) {
|
|
332
|
+
assertDiscordInteractionPayload(rawData);
|
|
333
|
+
if (rawData.type === InteractionType.ApplicationCommandAutocomplete) {
|
|
334
|
+
return new AutocompleteInteraction(client, toCommandRawInteraction(rawData));
|
|
335
|
+
}
|
|
336
|
+
if (rawData.type === InteractionType.ApplicationCommand) {
|
|
337
|
+
return new CommandInteraction(client, toCommandRawInteraction(rawData));
|
|
338
|
+
}
|
|
339
|
+
if (rawData.type === InteractionType.ModalSubmit) {
|
|
340
|
+
return new ModalInteraction(client, toModalSubmitRawInteraction(rawData));
|
|
341
|
+
}
|
|
342
|
+
if (rawData.type === InteractionType.MessageComponent) {
|
|
343
|
+
const componentRawData = toMessageComponentRawInteraction(rawData);
|
|
344
|
+
switch (rawData.data?.component_type) {
|
|
345
|
+
case ComponentType.Button:
|
|
346
|
+
return new ButtonInteraction(client, componentRawData);
|
|
347
|
+
case ComponentType.StringSelect:
|
|
348
|
+
return new StringSelectMenuInteraction(client, componentRawData);
|
|
349
|
+
case ComponentType.UserSelect:
|
|
350
|
+
return new UserSelectMenuInteraction(client, componentRawData);
|
|
351
|
+
case ComponentType.RoleSelect:
|
|
352
|
+
return new RoleSelectMenuInteraction(client, componentRawData);
|
|
353
|
+
case ComponentType.MentionableSelect:
|
|
354
|
+
return new MentionableSelectMenuInteraction(client, componentRawData);
|
|
355
|
+
case ComponentType.ChannelSelect:
|
|
356
|
+
return new ChannelSelectMenuInteraction(client, componentRawData);
|
|
357
|
+
default:
|
|
358
|
+
return new BaseComponentInteraction(client, componentRawData);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return new BaseInteraction(client, rawData);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function parseComponentInteractionData(
|
|
365
|
+
component: { customIdParser: (id: string) => { data: ComponentData } },
|
|
366
|
+
customId: string,
|
|
367
|
+
): ComponentData {
|
|
368
|
+
return component.customIdParser(customId).data;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function isRawMessage(value: unknown): value is { id: string; channel_id: string } {
|
|
372
|
+
return (
|
|
373
|
+
Boolean(value) &&
|
|
374
|
+
typeof value === "object" &&
|
|
375
|
+
typeof (value as { id?: unknown }).id === "string" &&
|
|
376
|
+
typeof (value as { channel_id?: unknown }).channel_id === "string"
|
|
377
|
+
);
|
|
378
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GatewayDispatchEvents,
|
|
3
|
+
type APIMessage,
|
|
4
|
+
type APIReaction,
|
|
5
|
+
type GatewayPresenceUpdateDispatchData,
|
|
6
|
+
type GatewayThreadUpdateDispatchData,
|
|
7
|
+
} from "discord-api-types/v10";
|
|
8
|
+
import type { Client } from "./client.js";
|
|
9
|
+
import { Guild, Message, User } from "./structures.js";
|
|
10
|
+
|
|
11
|
+
export type DiscordMessageDispatchData = {
|
|
12
|
+
id?: string;
|
|
13
|
+
channel_id: string;
|
|
14
|
+
channelId?: string;
|
|
15
|
+
guild_id?: string;
|
|
16
|
+
message: Message;
|
|
17
|
+
author: User | null;
|
|
18
|
+
member?: { roles?: string[]; nick?: string | null; nickname?: string | null };
|
|
19
|
+
rawMember?: { roles?: string[]; nick?: string | null; nickname?: string | null };
|
|
20
|
+
guild?: Guild | null;
|
|
21
|
+
channel?: unknown;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type DiscordReactionDispatchData = {
|
|
25
|
+
user_id?: string;
|
|
26
|
+
channel_id: string;
|
|
27
|
+
message_id: string;
|
|
28
|
+
guild_id?: string;
|
|
29
|
+
emoji: APIReaction["emoji"];
|
|
30
|
+
burst?: boolean;
|
|
31
|
+
type?: number;
|
|
32
|
+
user: User;
|
|
33
|
+
rawMember?: { roles?: string[] };
|
|
34
|
+
guild?: Guild | null;
|
|
35
|
+
message: Message<true> | { fetch(): Promise<{ author?: User | null }> };
|
|
36
|
+
rawMessage?: APIMessage;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export abstract class BaseListener {
|
|
40
|
+
abstract readonly type: string;
|
|
41
|
+
abstract handle(data: unknown, client: Client): Promise<void> | void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export abstract class ReadyListener extends BaseListener {
|
|
45
|
+
readonly type = GatewayDispatchEvents.Ready;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export abstract class ResumedListener extends BaseListener {
|
|
49
|
+
readonly type = GatewayDispatchEvents.Resumed;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export abstract class MessageCreateListener extends BaseListener {
|
|
53
|
+
readonly type = GatewayDispatchEvents.MessageCreate;
|
|
54
|
+
abstract override handle(data: DiscordMessageDispatchData, client: Client): Promise<void> | void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export abstract class InteractionCreateListener extends BaseListener {
|
|
58
|
+
readonly type = GatewayDispatchEvents.InteractionCreate;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export abstract class MessageReactionAddListener extends BaseListener {
|
|
62
|
+
readonly type = GatewayDispatchEvents.MessageReactionAdd;
|
|
63
|
+
abstract override handle(data: DiscordReactionDispatchData, client: Client): Promise<void> | void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export abstract class MessageReactionRemoveListener extends BaseListener {
|
|
67
|
+
readonly type = GatewayDispatchEvents.MessageReactionRemove;
|
|
68
|
+
abstract override handle(data: DiscordReactionDispatchData, client: Client): Promise<void> | void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export abstract class PresenceUpdateListener extends BaseListener {
|
|
72
|
+
readonly type = GatewayDispatchEvents.PresenceUpdate;
|
|
73
|
+
abstract override handle(
|
|
74
|
+
data: GatewayPresenceUpdateDispatchData,
|
|
75
|
+
client: Client,
|
|
76
|
+
): Promise<void> | void;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export abstract class ThreadUpdateListener extends BaseListener {
|
|
80
|
+
readonly type = GatewayDispatchEvents.ThreadUpdate;
|
|
81
|
+
abstract override handle(
|
|
82
|
+
data: GatewayThreadUpdateDispatchData,
|
|
83
|
+
client: Client,
|
|
84
|
+
): Promise<void> | void;
|
|
85
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Routes } from "discord-api-types/v10";
|
|
2
|
+
import { isLiveTestEnabled } from "openclaw/plugin-sdk/test-env";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { parseApplicationIdFromToken } from "../probe.js";
|
|
5
|
+
import { RequestClient } from "./rest.js";
|
|
6
|
+
|
|
7
|
+
const TOKEN = process.env.DISCORD_BOT_TOKEN ?? "";
|
|
8
|
+
const LIVE = isLiveTestEnabled(["DISCORD_LIVE_TEST"]) && TOKEN.length > 0;
|
|
9
|
+
const describeLive = LIVE ? describe : describe.skip;
|
|
10
|
+
|
|
11
|
+
describeLive("discord live smoke", () => {
|
|
12
|
+
it("resolves bot identity and gateway metadata", async () => {
|
|
13
|
+
const rest = new RequestClient(TOKEN, { queueRequests: false, timeout: 15_000 });
|
|
14
|
+
|
|
15
|
+
const me = (await rest.get(Routes.user("@me"))) as { id?: string; bot?: boolean };
|
|
16
|
+
expect(me.bot).toBe(true);
|
|
17
|
+
expect(me.id).toBe(parseApplicationIdFromToken(TOKEN));
|
|
18
|
+
|
|
19
|
+
const gateway = (await rest.get(Routes.gatewayBot())) as {
|
|
20
|
+
url?: string;
|
|
21
|
+
session_start_limit?: { max_concurrency?: number };
|
|
22
|
+
};
|
|
23
|
+
expect(gateway.url).toMatch(/^wss:\/\//);
|
|
24
|
+
expect(gateway.session_start_limit?.max_concurrency).toBeGreaterThan(0);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { type APIRole, type APIUser } from "discord-api-types/v10";
|
|
2
|
+
import { Role, User, type StructureClient } from "./structures.js";
|
|
3
|
+
|
|
4
|
+
type ModalResolvedData = {
|
|
5
|
+
roles?: Record<string, { id: string; name?: string }>;
|
|
6
|
+
users?: Record<string, { id: string; username?: string; discriminator?: string }>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function extractModalFields(components: unknown[]): Record<string, string | string[]> {
|
|
10
|
+
const out: Record<string, string | string[]> = {};
|
|
11
|
+
for (const component of flattenModalComponents(components)) {
|
|
12
|
+
const raw = component as { custom_id?: unknown; value?: unknown; values?: unknown };
|
|
13
|
+
if (typeof raw.custom_id !== "string") {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (Array.isArray(raw.values)) {
|
|
17
|
+
out[raw.custom_id] = raw.values.map(String);
|
|
18
|
+
} else if (
|
|
19
|
+
typeof raw.value === "string" ||
|
|
20
|
+
typeof raw.value === "number" ||
|
|
21
|
+
typeof raw.value === "boolean"
|
|
22
|
+
) {
|
|
23
|
+
out[raw.custom_id] = String(raw.value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function flattenModalComponents(components: unknown[]): unknown[] {
|
|
30
|
+
const out: unknown[] = [];
|
|
31
|
+
for (const entry of components) {
|
|
32
|
+
if (!entry || typeof entry !== "object") {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const component = entry as { component?: unknown; components?: unknown[] };
|
|
36
|
+
if (component.component && typeof component.component === "object") {
|
|
37
|
+
out.push(component.component);
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(component.components)) {
|
|
40
|
+
out.push(...flattenModalComponents(component.components));
|
|
41
|
+
}
|
|
42
|
+
out.push(entry);
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class ModalFields {
|
|
48
|
+
constructor(
|
|
49
|
+
private values: Record<string, string | string[]>,
|
|
50
|
+
private resolved?: ModalResolvedData,
|
|
51
|
+
private client?: StructureClient,
|
|
52
|
+
) {}
|
|
53
|
+
|
|
54
|
+
private value(id: string, required: boolean): string | string[] | undefined {
|
|
55
|
+
const value = this.values[id];
|
|
56
|
+
if (required && (value === undefined || (Array.isArray(value) && value.length === 0))) {
|
|
57
|
+
throw new Error(`Missing required modal field ${id}`);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getText(id: string, required = false): string | null {
|
|
63
|
+
const value = this.value(id, required);
|
|
64
|
+
return typeof value === "string" ? value : null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getStringSelect(id: string, required = false): string[] {
|
|
68
|
+
const value = this.value(id, required);
|
|
69
|
+
if (Array.isArray(value)) {
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
return typeof value === "string" ? [value] : [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getRoleSelect(id: string, required = false): Role[] {
|
|
76
|
+
const values = this.getStringSelect(id, required);
|
|
77
|
+
return values.map((roleId) => {
|
|
78
|
+
const raw = this.resolved?.roles?.[roleId];
|
|
79
|
+
return raw
|
|
80
|
+
? new Role(this.client!, { id: roleId, name: raw.name ?? "" } as APIRole)
|
|
81
|
+
: new Role<true>(this.client!, roleId);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getUserSelect(id: string, required = false): User[] {
|
|
86
|
+
const values = this.getStringSelect(id, required);
|
|
87
|
+
return values.map((userId) => {
|
|
88
|
+
const raw = this.resolved?.users?.[userId];
|
|
89
|
+
return new User(this.client!, {
|
|
90
|
+
id: userId,
|
|
91
|
+
username: raw?.username ?? "",
|
|
92
|
+
} as APIUser);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { MessageFlags, type APIEmbed } from "discord-api-types/v10";
|
|
2
|
+
import { Embed } from "./embeds.js";
|
|
3
|
+
|
|
4
|
+
export type MessagePayloadFile = {
|
|
5
|
+
name: string;
|
|
6
|
+
data: Blob | Uint8Array | ArrayBuffer;
|
|
7
|
+
description?: string;
|
|
8
|
+
duration_secs?: number;
|
|
9
|
+
waveform?: string;
|
|
10
|
+
};
|
|
11
|
+
export type MessagePayloadObject = {
|
|
12
|
+
content?: string;
|
|
13
|
+
embeds?: Array<APIEmbed | Embed>;
|
|
14
|
+
components?: TopLevelComponents[];
|
|
15
|
+
allowedMentions?: unknown;
|
|
16
|
+
allowed_mentions?: unknown;
|
|
17
|
+
flags?: number;
|
|
18
|
+
tts?: boolean;
|
|
19
|
+
files?: MessagePayloadFile[];
|
|
20
|
+
poll?: unknown;
|
|
21
|
+
ephemeral?: boolean;
|
|
22
|
+
stickers?: [string, string, string] | [string, string] | [string];
|
|
23
|
+
};
|
|
24
|
+
export type MessagePayload = string | MessagePayloadObject;
|
|
25
|
+
export type TopLevelComponents = {
|
|
26
|
+
isV2?: boolean;
|
|
27
|
+
serialize: () => unknown;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function clean<T extends Record<string, unknown>>(value: T): T {
|
|
31
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined)) as T;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function serializeAnyComponent(component: { serialize: () => unknown }): unknown {
|
|
35
|
+
return component.serialize();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function payloadHasV2Components(payload: MessagePayloadObject): boolean {
|
|
39
|
+
return Boolean(payload.components?.some((component) => component.isV2));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalizePayloadFlags(payload: MessagePayloadObject): number | undefined {
|
|
43
|
+
const flags = payload.ephemeral ? (payload.flags ?? 0) | MessageFlags.Ephemeral : payload.flags;
|
|
44
|
+
if (!payloadHasV2Components(payload)) {
|
|
45
|
+
return flags;
|
|
46
|
+
}
|
|
47
|
+
if (payload.content || payload.embeds?.length) {
|
|
48
|
+
throw new Error("Discord Components V2 payloads cannot include content or embeds");
|
|
49
|
+
}
|
|
50
|
+
return (flags ?? 0) | MessageFlags.IsComponentsV2;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function serializePayload(payload: MessagePayload) {
|
|
54
|
+
if (typeof payload === "string") {
|
|
55
|
+
return { content: payload };
|
|
56
|
+
}
|
|
57
|
+
const flags = normalizePayloadFlags(payload);
|
|
58
|
+
return clean({
|
|
59
|
+
content: payload.content,
|
|
60
|
+
embeds: payload.embeds?.map((entry) => ("serialize" in entry ? entry.serialize() : entry)),
|
|
61
|
+
components: payload.components?.map((entry) => serializeAnyComponent(entry)),
|
|
62
|
+
allowed_mentions: payload.allowed_mentions ?? payload.allowedMentions,
|
|
63
|
+
flags,
|
|
64
|
+
tts: payload.tts,
|
|
65
|
+
files: payload.files,
|
|
66
|
+
poll: payload.poll,
|
|
67
|
+
sticker_ids: payload.stickers,
|
|
68
|
+
});
|
|
69
|
+
}
|