@azurioh/discord-kernel 0.1.0
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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/authz/authorizer.d.ts +45 -0
- package/dist/authz/authorizer.d.ts.map +1 -0
- package/dist/authz/authorizer.js +31 -0
- package/dist/authz/authorizer.js.map +1 -0
- package/dist/authz/require-level-guard.d.ts +23 -0
- package/dist/authz/require-level-guard.d.ts.map +1 -0
- package/dist/authz/require-level-guard.js +37 -0
- package/dist/authz/require-level-guard.js.map +1 -0
- package/dist/clock.d.ts +13 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +13 -0
- package/dist/clock.js.map +1 -0
- package/dist/concurrency/keyed-queue.d.ts +18 -0
- package/dist/concurrency/keyed-queue.d.ts.map +1 -0
- package/dist/concurrency/keyed-queue.js +37 -0
- package/dist/concurrency/keyed-queue.js.map +1 -0
- package/dist/concurrency/run-with-concurrency.d.ts +15 -0
- package/dist/concurrency/run-with-concurrency.d.ts.map +1 -0
- package/dist/concurrency/run-with-concurrency.js +40 -0
- package/dist/concurrency/run-with-concurrency.js.map +1 -0
- package/dist/config/env.d.ts +17 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +49 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/errors.d.ts +14 -0
- package/dist/config/errors.d.ts.map +1 -0
- package/dist/config/errors.js +25 -0
- package/dist/config/errors.js.map +1 -0
- package/dist/datetime.d.ts +34 -0
- package/dist/datetime.d.ts.map +1 -0
- package/dist/datetime.js +188 -0
- package/dist/datetime.js.map +1 -0
- package/dist/discord/api-errors.d.ts +20 -0
- package/dist/discord/api-errors.d.ts.map +1 -0
- package/dist/discord/api-errors.js +90 -0
- package/dist/discord/api-errors.js.map +1 -0
- package/dist/discord/channel-exporter.d.ts +42 -0
- package/dist/discord/channel-exporter.d.ts.map +1 -0
- package/dist/discord/channel-exporter.js +3 -0
- package/dist/discord/channel-exporter.js.map +1 -0
- package/dist/discord/command/autocomplete-dispatcher.d.ts +26 -0
- package/dist/discord/command/autocomplete-dispatcher.d.ts.map +1 -0
- package/dist/discord/command/autocomplete-dispatcher.js +41 -0
- package/dist/discord/command/autocomplete-dispatcher.js.map +1 -0
- package/dist/discord/command/autocomplete.d.ts +18 -0
- package/dist/discord/command/autocomplete.d.ts.map +1 -0
- package/dist/discord/command/autocomplete.js +65 -0
- package/dist/discord/command/autocomplete.js.map +1 -0
- package/dist/discord/command/context.d.ts +33 -0
- package/dist/discord/command/context.d.ts.map +1 -0
- package/dist/discord/command/context.js +48 -0
- package/dist/discord/command/context.js.map +1 -0
- package/dist/discord/command/cooldown-guard.d.ts +25 -0
- package/dist/discord/command/cooldown-guard.d.ts.map +1 -0
- package/dist/discord/command/cooldown-guard.js +60 -0
- package/dist/discord/command/cooldown-guard.js.map +1 -0
- package/dist/discord/command/create-command.d.ts +100 -0
- package/dist/discord/command/create-command.d.ts.map +1 -0
- package/dist/discord/command/create-command.js +245 -0
- package/dist/discord/command/create-command.js.map +1 -0
- package/dist/discord/command/create-context-menu-command.d.ts +51 -0
- package/dist/discord/command/create-context-menu-command.d.ts.map +1 -0
- package/dist/discord/command/create-context-menu-command.js +128 -0
- package/dist/discord/command/create-context-menu-command.js.map +1 -0
- package/dist/discord/command/errors.d.ts +19 -0
- package/dist/discord/command/errors.d.ts.map +1 -0
- package/dist/discord/command/errors.js +27 -0
- package/dist/discord/command/errors.js.map +1 -0
- package/dist/discord/command/guard.d.ts +30 -0
- package/dist/discord/command/guard.d.ts.map +1 -0
- package/dist/discord/command/guard.js +34 -0
- package/dist/discord/command/guard.js.map +1 -0
- package/dist/discord/command/localization.d.ts +9 -0
- package/dist/discord/command/localization.d.ts.map +1 -0
- package/dist/discord/command/localization.js +13 -0
- package/dist/discord/command/localization.js.map +1 -0
- package/dist/discord/command/options.d.ts +113 -0
- package/dist/discord/command/options.d.ts.map +1 -0
- package/dist/discord/command/options.js +509 -0
- package/dist/discord/command/options.js.map +1 -0
- package/dist/discord/command/permission-guard.d.ts +21 -0
- package/dist/discord/command/permission-guard.d.ts.map +1 -0
- package/dist/discord/command/permission-guard.js +69 -0
- package/dist/discord/command/permission-guard.js.map +1 -0
- package/dist/discord/command/router.d.ts +48 -0
- package/dist/discord/command/router.d.ts.map +1 -0
- package/dist/discord/command/router.js +118 -0
- package/dist/discord/command/router.js.map +1 -0
- package/dist/discord/command/types.d.ts +51 -0
- package/dist/discord/command/types.d.ts.map +1 -0
- package/dist/discord/command/types.js +3 -0
- package/dist/discord/command/types.js.map +1 -0
- package/dist/discord/components/component-router.d.ts +116 -0
- package/dist/discord/components/component-router.d.ts.map +1 -0
- package/dist/discord/components/component-router.js +123 -0
- package/dist/discord/components/component-router.js.map +1 -0
- package/dist/discord/components/interactive-message/index.d.ts +3 -0
- package/dist/discord/components/interactive-message/index.d.ts.map +1 -0
- package/dist/discord/components/interactive-message/index.js +11 -0
- package/dist/discord/components/interactive-message/index.js.map +1 -0
- package/dist/discord/components/interactive-message/interactive-message-collector.d.ts +195 -0
- package/dist/discord/components/interactive-message/interactive-message-collector.d.ts.map +1 -0
- package/dist/discord/components/interactive-message/interactive-message-collector.js +151 -0
- package/dist/discord/components/interactive-message/interactive-message-collector.js.map +1 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.d.ts +30 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.d.ts.map +1 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.js +44 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.js.map +1 -0
- package/dist/discord/components/paginator/index.d.ts +5 -0
- package/dist/discord/components/paginator/index.d.ts.map +1 -0
- package/dist/discord/components/paginator/index.js +15 -0
- package/dist/discord/components/paginator/index.js.map +1 -0
- package/dist/discord/components/paginator/mount-paginator.d.ts +25 -0
- package/dist/discord/components/paginator/mount-paginator.d.ts.map +1 -0
- package/dist/discord/components/paginator/mount-paginator.js +41 -0
- package/dist/discord/components/paginator/mount-paginator.js.map +1 -0
- package/dist/discord/components/paginator/page-state.d.ts +21 -0
- package/dist/discord/components/paginator/page-state.d.ts.map +1 -0
- package/dist/discord/components/paginator/page-state.js +44 -0
- package/dist/discord/components/paginator/page-state.js.map +1 -0
- package/dist/discord/components/paginator/paginator-buttons.d.ts +17 -0
- package/dist/discord/components/paginator/paginator-buttons.d.ts.map +1 -0
- package/dist/discord/components/paginator/paginator-buttons.js +45 -0
- package/dist/discord/components/paginator/paginator-buttons.js.map +1 -0
- package/dist/discord/components/paginator/paginator-view.d.ts +26 -0
- package/dist/discord/components/paginator/paginator-view.d.ts.map +1 -0
- package/dist/discord/components/paginator/paginator-view.js +28 -0
- package/dist/discord/components/paginator/paginator-view.js.map +1 -0
- package/dist/discord/components/persistent-paginator.d.ts +47 -0
- package/dist/discord/components/persistent-paginator.d.ts.map +1 -0
- package/dist/discord/components/persistent-paginator.js +137 -0
- package/dist/discord/components/persistent-paginator.js.map +1 -0
- package/dist/discord/components/settings-editor/index.d.ts +7 -0
- package/dist/discord/components/settings-editor/index.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/index.js +22 -0
- package/dist/discord/components/settings-editor/index.js.map +1 -0
- package/dist/discord/components/settings-editor/mount-settings-editor.d.ts +140 -0
- package/dist/discord/components/settings-editor/mount-settings-editor.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/mount-settings-editor.js +344 -0
- package/dist/discord/components/settings-editor/mount-settings-editor.js.map +1 -0
- package/dist/discord/components/settings-editor/navigation.d.ts +49 -0
- package/dist/discord/components/settings-editor/navigation.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/navigation.js +39 -0
- package/dist/discord/components/settings-editor/navigation.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts +56 -0
- package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-card.view.js +284 -0
- package/dist/discord/components/settings-editor/settings-editor-card.view.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts +69 -0
- package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-field-modal.js +353 -0
- package/dist/discord/components/settings-editor/settings-editor-field-modal.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.d.ts +216 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.js +66 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor.view.d.ts +303 -0
- package/dist/discord/components/settings-editor/settings-editor.view.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor.view.js +316 -0
- package/dist/discord/components/settings-editor/settings-editor.view.js.map +1 -0
- package/dist/discord/events/create-event.d.ts +5 -0
- package/dist/discord/events/create-event.d.ts.map +1 -0
- package/dist/discord/events/create-event.js +8 -0
- package/dist/discord/events/create-event.js.map +1 -0
- package/dist/discord/events/event-router.d.ts +16 -0
- package/dist/discord/events/event-router.d.ts.map +1 -0
- package/dist/discord/events/event-router.js +51 -0
- package/dist/discord/events/event-router.js.map +1 -0
- package/dist/discord/events/types.d.ts +16 -0
- package/dist/discord/events/types.d.ts.map +1 -0
- package/dist/discord/events/types.js +3 -0
- package/dist/discord/events/types.js.map +1 -0
- package/dist/discord/i18n.d.ts +58 -0
- package/dist/discord/i18n.d.ts.map +1 -0
- package/dist/discord/i18n.js +173 -0
- package/dist/discord/i18n.js.map +1 -0
- package/dist/discord/interaction/button.d.ts +39 -0
- package/dist/discord/interaction/button.d.ts.map +1 -0
- package/dist/discord/interaction/button.js +36 -0
- package/dist/discord/interaction/button.js.map +1 -0
- package/dist/discord/interaction/interaction-router.d.ts +21 -0
- package/dist/discord/interaction/interaction-router.d.ts.map +1 -0
- package/dist/discord/interaction/interaction-router.js +24 -0
- package/dist/discord/interaction/interaction-router.js.map +1 -0
- package/dist/discord/interaction/modal.d.ts +171 -0
- package/dist/discord/interaction/modal.d.ts.map +1 -0
- package/dist/discord/interaction/modal.js +264 -0
- package/dist/discord/interaction/modal.js.map +1 -0
- package/dist/discord/interaction/select-menu.d.ts +104 -0
- package/dist/discord/interaction/select-menu.d.ts.map +1 -0
- package/dist/discord/interaction/select-menu.js +126 -0
- package/dist/discord/interaction/select-menu.js.map +1 -0
- package/dist/discord/permissions.d.ts +32 -0
- package/dist/discord/permissions.d.ts.map +1 -0
- package/dist/discord/permissions.js +40 -0
- package/dist/discord/permissions.js.map +1 -0
- package/dist/discord/placeholder-registry-errors.d.ts +10 -0
- package/dist/discord/placeholder-registry-errors.d.ts.map +1 -0
- package/dist/discord/placeholder-registry-errors.js +18 -0
- package/dist/discord/placeholder-registry-errors.js.map +1 -0
- package/dist/discord/placeholder-registry.d.ts +53 -0
- package/dist/discord/placeholder-registry.d.ts.map +1 -0
- package/dist/discord/placeholder-registry.js +52 -0
- package/dist/discord/placeholder-registry.js.map +1 -0
- package/dist/discord/presenter.d.ts +26 -0
- package/dist/discord/presenter.d.ts.map +1 -0
- package/dist/discord/presenter.js +3 -0
- package/dist/discord/presenter.js.map +1 -0
- package/dist/discord/ui/card.d.ts +114 -0
- package/dist/discord/ui/card.d.ts.map +1 -0
- package/dist/discord/ui/card.js +162 -0
- package/dist/discord/ui/card.js.map +1 -0
- package/dist/discord/ui/color-input-errors.d.ts +12 -0
- package/dist/discord/ui/color-input-errors.d.ts.map +1 -0
- package/dist/discord/ui/color-input-errors.js +21 -0
- package/dist/discord/ui/color-input-errors.js.map +1 -0
- package/dist/discord/ui/color-input.d.ts +37 -0
- package/dist/discord/ui/color-input.d.ts.map +1 -0
- package/dist/discord/ui/color-input.js +166 -0
- package/dist/discord/ui/color-input.js.map +1 -0
- package/dist/discord/ui/colors.d.ts +44 -0
- package/dist/discord/ui/colors.d.ts.map +1 -0
- package/dist/discord/ui/colors.js +45 -0
- package/dist/discord/ui/colors.js.map +1 -0
- package/dist/discord/ui/embed.d.ts +16 -0
- package/dist/discord/ui/embed.d.ts.map +1 -0
- package/dist/discord/ui/embed.js +53 -0
- package/dist/discord/ui/embed.js.map +1 -0
- package/dist/discord/ui/message-attachments.d.ts +40 -0
- package/dist/discord/ui/message-attachments.d.ts.map +1 -0
- package/dist/discord/ui/message-attachments.js +27 -0
- package/dist/discord/ui/message-attachments.js.map +1 -0
- package/dist/errors/business-error.d.ts +41 -0
- package/dist/errors/business-error.d.ts.map +1 -0
- package/dist/errors/business-error.js +39 -0
- package/dist/errors/business-error.js.map +1 -0
- package/dist/errors/describe-error.d.ts +29 -0
- package/dist/errors/describe-error.d.ts.map +1 -0
- package/dist/errors/describe-error.js +49 -0
- package/dist/errors/describe-error.js.map +1 -0
- package/dist/errors/incident-ref.d.ts +7 -0
- package/dist/errors/incident-ref.d.ts.map +1 -0
- package/dist/errors/incident-ref.js +13 -0
- package/dist/errors/incident-ref.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +15 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/i18n/business-message.d.ts +14 -0
- package/dist/i18n/business-message.d.ts.map +1 -0
- package/dist/i18n/business-message.js +19 -0
- package/dist/i18n/business-message.js.map +1 -0
- package/dist/i18n/catalog.d.ts +27 -0
- package/dist/i18n/catalog.d.ts.map +1 -0
- package/dist/i18n/catalog.js +25 -0
- package/dist/i18n/catalog.js.map +1 -0
- package/dist/i18n/errors.d.ts +10 -0
- package/dist/i18n/errors.d.ts.map +1 -0
- package/dist/i18n/errors.js +18 -0
- package/dist/i18n/errors.js.map +1 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +16 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/locale.d.ts +22 -0
- package/dist/i18n/locale.d.ts.map +1 -0
- package/dist/i18n/locale.js +40 -0
- package/dist/i18n/locale.js.map +1 -0
- package/dist/i18n/translator.d.ts +35 -0
- package/dist/i18n/translator.d.ts.map +1 -0
- package/dist/i18n/translator.js +40 -0
- package/dist/i18n/translator.js.map +1 -0
- package/dist/logger.d.ts +28 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +3 -0
- package/dist/logger.js.map +1 -0
- package/dist/module/module.d.ts +42 -0
- package/dist/module/module.d.ts.map +1 -0
- package/dist/module/module.js +3 -0
- package/dist/module/module.js.map +1 -0
- package/dist/persistence/database.d.ts +24 -0
- package/dist/persistence/database.d.ts.map +1 -0
- package/dist/persistence/database.js +3 -0
- package/dist/persistence/database.js.map +1 -0
- package/dist/resilience/retry.d.ts +36 -0
- package/dist/resilience/retry.d.ts.map +1 -0
- package/dist/resilience/retry.js +78 -0
- package/dist/resilience/retry.js.map +1 -0
- package/dist/scheduler/errors.d.ts +25 -0
- package/dist/scheduler/errors.d.ts.map +1 -0
- package/dist/scheduler/errors.js +45 -0
- package/dist/scheduler/errors.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +68 -0
- package/dist/scheduler/scheduler.d.ts.map +1 -0
- package/dist/scheduler/scheduler.js +162 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/package.json +89 -0
- package/src/authz/authorizer.ts +76 -0
- package/src/authz/require-level-guard.ts +42 -0
- package/src/clock.ts +18 -0
- package/src/concurrency/keyed-queue.ts +50 -0
- package/src/concurrency/run-with-concurrency.ts +44 -0
- package/src/config/env.ts +58 -0
- package/src/config/errors.ts +21 -0
- package/src/datetime.ts +221 -0
- package/src/discord/api-errors.ts +91 -0
- package/src/discord/channel-exporter.ts +48 -0
- package/src/discord/command/autocomplete-dispatcher.ts +54 -0
- package/src/discord/command/autocomplete.ts +76 -0
- package/src/discord/command/context.ts +85 -0
- package/src/discord/command/cooldown-guard.ts +81 -0
- package/src/discord/command/create-command.ts +431 -0
- package/src/discord/command/create-context-menu-command.ts +227 -0
- package/src/discord/command/errors.ts +22 -0
- package/src/discord/command/guard.ts +54 -0
- package/src/discord/command/localization.ts +11 -0
- package/src/discord/command/options.ts +847 -0
- package/src/discord/command/permission-guard.ts +74 -0
- package/src/discord/command/router.ts +142 -0
- package/src/discord/command/types.ts +52 -0
- package/src/discord/components/component-router.ts +213 -0
- package/src/discord/components/interactive-message/index.ts +18 -0
- package/src/discord/components/interactive-message/interactive-message-collector.ts +374 -0
- package/src/discord/components/interactive-message/mount-interactive-message.ts +71 -0
- package/src/discord/components/paginator/index.ts +17 -0
- package/src/discord/components/paginator/mount-paginator.ts +69 -0
- package/src/discord/components/paginator/page-state.ts +45 -0
- package/src/discord/components/paginator/paginator-buttons.ts +60 -0
- package/src/discord/components/paginator/paginator-view.ts +61 -0
- package/src/discord/components/persistent-paginator.ts +197 -0
- package/src/discord/components/settings-editor/index.ts +41 -0
- package/src/discord/components/settings-editor/mount-settings-editor.ts +646 -0
- package/src/discord/components/settings-editor/navigation.ts +67 -0
- package/src/discord/components/settings-editor/settings-editor-card.view.ts +344 -0
- package/src/discord/components/settings-editor/settings-editor-field-modal.ts +538 -0
- package/src/discord/components/settings-editor/settings-editor-fields.ts +290 -0
- package/src/discord/components/settings-editor/settings-editor.view.ts +654 -0
- package/src/discord/events/create-event.ts +7 -0
- package/src/discord/events/event-router.ts +53 -0
- package/src/discord/events/types.ts +17 -0
- package/src/discord/i18n.ts +173 -0
- package/src/discord/interaction/button.ts +75 -0
- package/src/discord/interaction/interaction-router.ts +28 -0
- package/src/discord/interaction/modal.ts +505 -0
- package/src/discord/interaction/select-menu.ts +246 -0
- package/src/discord/permissions.ts +57 -0
- package/src/discord/placeholder-registry-errors.ts +11 -0
- package/src/discord/placeholder-registry.ts +77 -0
- package/src/discord/presenter.ts +26 -0
- package/src/discord/ui/card.ts +303 -0
- package/src/discord/ui/color-input-errors.ts +17 -0
- package/src/discord/ui/color-input.ts +179 -0
- package/src/discord/ui/colors.ts +58 -0
- package/src/discord/ui/embed.ts +64 -0
- package/src/discord/ui/message-attachments.ts +57 -0
- package/src/errors/business-error.ts +49 -0
- package/src/errors/describe-error.ts +73 -0
- package/src/errors/incident-ref.ts +10 -0
- package/src/errors/index.ts +12 -0
- package/src/i18n/business-message.ts +23 -0
- package/src/i18n/catalog.ts +41 -0
- package/src/i18n/errors.ts +11 -0
- package/src/i18n/index.ts +11 -0
- package/src/i18n/locale.ts +41 -0
- package/src/i18n/translator.ts +78 -0
- package/src/logger.ts +28 -0
- package/src/module/module.ts +42 -0
- package/src/persistence/database.ts +23 -0
- package/src/resilience/retry.ts +102 -0
- package/src/scheduler/errors.ts +40 -0
- package/src/scheduler/scheduler.ts +248 -0
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Attachment,
|
|
3
|
+
ChannelSelectMenuBuilder,
|
|
4
|
+
type ChannelType,
|
|
5
|
+
CheckboxBuilder,
|
|
6
|
+
FileUploadBuilder,
|
|
7
|
+
LabelBuilder,
|
|
8
|
+
ModalBuilder,
|
|
9
|
+
type ModalSubmitInteraction,
|
|
10
|
+
RoleSelectMenuBuilder,
|
|
11
|
+
StringSelectMenuBuilder,
|
|
12
|
+
StringSelectMenuOptionBuilder,
|
|
13
|
+
TextInputBuilder,
|
|
14
|
+
TextInputStyle,
|
|
15
|
+
UserSelectMenuBuilder,
|
|
16
|
+
} from "discord.js";
|
|
17
|
+
|
|
18
|
+
export type TextFieldStyleName = "short" | "paragraph";
|
|
19
|
+
|
|
20
|
+
const TEXT_FIELD_STYLES: Record<TextFieldStyleName, TextInputStyle> = {
|
|
21
|
+
short: TextInputStyle.Short,
|
|
22
|
+
paragraph: TextInputStyle.Paragraph,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Separates a modal's static id from the dynamic state appended for routing. */
|
|
26
|
+
const CUSTOM_ID_SEPARATOR = ":";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A single text field. `required` defaults to Discord's own default (`true`); set
|
|
30
|
+
* it to `false` to make {@link Modal.read} return `null` when left empty.
|
|
31
|
+
*/
|
|
32
|
+
export interface TextFieldDef {
|
|
33
|
+
kind?: "text";
|
|
34
|
+
label: string;
|
|
35
|
+
/** Helper text rendered under the label. */
|
|
36
|
+
description?: string;
|
|
37
|
+
style?: TextFieldStyleName;
|
|
38
|
+
required?: boolean;
|
|
39
|
+
minLength?: number;
|
|
40
|
+
maxLength?: number;
|
|
41
|
+
placeholder?: string;
|
|
42
|
+
/** Prefilled content, e.g. when editing an existing value. */
|
|
43
|
+
value?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** A single checkbox field — always optional from Discord's own perspective. */
|
|
47
|
+
export interface CheckboxFieldDef {
|
|
48
|
+
kind: "checkbox";
|
|
49
|
+
label: string;
|
|
50
|
+
/** Helper text rendered under the label. */
|
|
51
|
+
description?: string;
|
|
52
|
+
/** Pre-ticked state. Defaults to unticked. */
|
|
53
|
+
default?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A single file upload. `required` defaults to Discord's own default (`true`);
|
|
58
|
+
* set it to `false` to make {@link Modal.read} return `null` when nothing was
|
|
59
|
+
* uploaded.
|
|
60
|
+
*/
|
|
61
|
+
export interface FileFieldDef {
|
|
62
|
+
kind: "file";
|
|
63
|
+
label: string;
|
|
64
|
+
/** Helper text rendered under the label. */
|
|
65
|
+
description?: string;
|
|
66
|
+
required?: boolean;
|
|
67
|
+
/** How many files may be uploaded at once. Discord's own default is one of each. */
|
|
68
|
+
minValues?: number;
|
|
69
|
+
maxValues?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** One choice offered by a {@link SelectFieldDef}. */
|
|
73
|
+
export interface SelectFieldOption {
|
|
74
|
+
label: string;
|
|
75
|
+
value: string;
|
|
76
|
+
description?: string;
|
|
77
|
+
default?: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A single string select menu. `required` defaults to Discord's own default
|
|
82
|
+
* (`true`); set it to `false` to make {@link Modal.read} return `null` when
|
|
83
|
+
* nothing was picked.
|
|
84
|
+
*/
|
|
85
|
+
export interface SelectFieldDef {
|
|
86
|
+
kind: "select";
|
|
87
|
+
label: string;
|
|
88
|
+
/** Helper text rendered under the label. */
|
|
89
|
+
description?: string;
|
|
90
|
+
options: readonly SelectFieldOption[];
|
|
91
|
+
placeholder?: string;
|
|
92
|
+
required?: boolean;
|
|
93
|
+
minValues?: number;
|
|
94
|
+
maxValues?: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* A single role select menu. `required` defaults to Discord's own default
|
|
99
|
+
* (`true`); set it to `false` to make {@link Modal.read} return `null` when
|
|
100
|
+
* nothing was picked.
|
|
101
|
+
*/
|
|
102
|
+
export interface RoleFieldDef {
|
|
103
|
+
kind: "role";
|
|
104
|
+
label: string;
|
|
105
|
+
/** Helper text rendered under the label. */
|
|
106
|
+
description?: string;
|
|
107
|
+
defaultRoleIds?: readonly string[];
|
|
108
|
+
placeholder?: string;
|
|
109
|
+
required?: boolean;
|
|
110
|
+
minValues?: number;
|
|
111
|
+
maxValues?: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A single user select menu. `required` defaults to Discord's own default
|
|
116
|
+
* (`true`); set it to `false` to make {@link Modal.read} return `null` when
|
|
117
|
+
* nothing was picked.
|
|
118
|
+
*/
|
|
119
|
+
export interface UserFieldDef {
|
|
120
|
+
kind: "user";
|
|
121
|
+
label: string;
|
|
122
|
+
/** Helper text rendered under the label. */
|
|
123
|
+
description?: string;
|
|
124
|
+
defaultUserIds?: readonly string[];
|
|
125
|
+
placeholder?: string;
|
|
126
|
+
required?: boolean;
|
|
127
|
+
minValues?: number;
|
|
128
|
+
maxValues?: number;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A single channel select menu. `required` defaults to Discord's own default
|
|
133
|
+
* (`true`); set it to `false` to make {@link Modal.read} return `null` when
|
|
134
|
+
* nothing was picked.
|
|
135
|
+
*/
|
|
136
|
+
export interface ChannelFieldDef {
|
|
137
|
+
kind: "channel";
|
|
138
|
+
label: string;
|
|
139
|
+
/** Helper text rendered under the label. */
|
|
140
|
+
description?: string;
|
|
141
|
+
defaultChannelIds?: readonly string[];
|
|
142
|
+
/** Restricts which channel kinds may be picked, e.g. to categories only. */
|
|
143
|
+
channelTypes?: readonly ChannelType[];
|
|
144
|
+
placeholder?: string;
|
|
145
|
+
required?: boolean;
|
|
146
|
+
minValues?: number;
|
|
147
|
+
maxValues?: number;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export type FieldDef =
|
|
151
|
+
| TextFieldDef
|
|
152
|
+
| CheckboxFieldDef
|
|
153
|
+
| FileFieldDef
|
|
154
|
+
| SelectFieldDef
|
|
155
|
+
| RoleFieldDef
|
|
156
|
+
| UserFieldDef
|
|
157
|
+
| ChannelFieldDef;
|
|
158
|
+
|
|
159
|
+
/** Field declarations keyed by custom id — the same key `read` returns values under. */
|
|
160
|
+
export type ModalFields = Record<string, FieldDef>;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Submitted values, keyed like the declaration. A checkbox field always resolves
|
|
164
|
+
* to a `boolean`; an optional text, file, select, role, user or channel field
|
|
165
|
+
* widens to `| null` so a caller cannot forget the empty case. A file field's
|
|
166
|
+
* uploads come back as a list because the field itself may allow several, and
|
|
167
|
+
* so do a select/role/user/channel field's picks, as the identifiers chosen.
|
|
168
|
+
* This only resolves correctly because `createModal` infers its fields as
|
|
169
|
+
* `const`.
|
|
170
|
+
*/
|
|
171
|
+
export type ModalValues<F extends ModalFields> = {
|
|
172
|
+
[K in keyof F]: F[K] extends CheckboxFieldDef
|
|
173
|
+
? boolean
|
|
174
|
+
: F[K] extends FileFieldDef
|
|
175
|
+
? F[K]["required"] extends false
|
|
176
|
+
? readonly Attachment[] | null
|
|
177
|
+
: readonly Attachment[]
|
|
178
|
+
: F[K] extends SelectFieldDef | RoleFieldDef | UserFieldDef | ChannelFieldDef
|
|
179
|
+
? F[K]["required"] extends false
|
|
180
|
+
? readonly string[] | null
|
|
181
|
+
: readonly string[]
|
|
182
|
+
: F[K] extends TextFieldDef
|
|
183
|
+
? F[K]["required"] extends false
|
|
184
|
+
? string | null
|
|
185
|
+
: string
|
|
186
|
+
: never;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export interface ModalDef<F extends ModalFields> {
|
|
190
|
+
id: string;
|
|
191
|
+
title: string;
|
|
192
|
+
/**
|
|
193
|
+
* Text shown above the fields, via a Text Display component — a legend whose
|
|
194
|
+
* content is not one of the fields themselves. Counts toward the same
|
|
195
|
+
* five-component budget `fields` does: Discord's own modal object carries
|
|
196
|
+
* "between 1 and 5 (inclusive) components", label and text display alike.
|
|
197
|
+
*/
|
|
198
|
+
legend?: string;
|
|
199
|
+
fields: F;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Compiled modal: it knows how to render itself (`build`) and how to decode what
|
|
204
|
+
* came back (`read`) — the same construction/behaviour pairing as a compiled
|
|
205
|
+
* {@link import("@/discord/interaction/button").Button}. Without it a module
|
|
206
|
+
* has to hand-roll raw discord.js builders, which the template forbids everywhere
|
|
207
|
+
* else in the DSL.
|
|
208
|
+
*/
|
|
209
|
+
export interface Modal<F extends ModalFields> {
|
|
210
|
+
readonly id: string;
|
|
211
|
+
/**
|
|
212
|
+
* Build the modal to show. `state` is appended after a colon so the persistent
|
|
213
|
+
* {@link import("@/discord/components/component-router").ComponentRouter}
|
|
214
|
+
* still routes it to the handler registered under `id`.
|
|
215
|
+
*/
|
|
216
|
+
build(state?: string): ModalBuilder;
|
|
217
|
+
read(interaction: ModalSubmitInteraction): ModalValues<F>;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function createTextInput(name: string, field: TextFieldDef): TextInputBuilder {
|
|
221
|
+
const input = new TextInputBuilder()
|
|
222
|
+
.setCustomId(name)
|
|
223
|
+
.setStyle(TEXT_FIELD_STYLES[field.style ?? "short"])
|
|
224
|
+
.setRequired(field.required ?? true);
|
|
225
|
+
if (field.minLength !== undefined) {
|
|
226
|
+
input.setMinLength(field.minLength);
|
|
227
|
+
}
|
|
228
|
+
if (field.maxLength !== undefined) {
|
|
229
|
+
input.setMaxLength(field.maxLength);
|
|
230
|
+
}
|
|
231
|
+
if (field.placeholder !== undefined) {
|
|
232
|
+
input.setPlaceholder(field.placeholder);
|
|
233
|
+
}
|
|
234
|
+
if (field.value !== undefined) {
|
|
235
|
+
input.setValue(field.value);
|
|
236
|
+
}
|
|
237
|
+
return input;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function createFileUpload(name: string, field: FileFieldDef): FileUploadBuilder {
|
|
241
|
+
const upload = new FileUploadBuilder().setCustomId(name).setRequired(field.required ?? true);
|
|
242
|
+
if (field.minValues !== undefined) {
|
|
243
|
+
upload.setMinValues(field.minValues);
|
|
244
|
+
}
|
|
245
|
+
if (field.maxValues !== undefined) {
|
|
246
|
+
upload.setMaxValues(field.maxValues);
|
|
247
|
+
}
|
|
248
|
+
return upload;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function createSelectOption(option: SelectFieldOption): StringSelectMenuOptionBuilder {
|
|
252
|
+
const built = new StringSelectMenuOptionBuilder()
|
|
253
|
+
.setLabel(option.label)
|
|
254
|
+
.setValue(option.value)
|
|
255
|
+
.setDefault(option.default ?? false);
|
|
256
|
+
if (option.description !== undefined) {
|
|
257
|
+
built.setDescription(option.description);
|
|
258
|
+
}
|
|
259
|
+
return built;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function createStringSelect(name: string, field: SelectFieldDef): StringSelectMenuBuilder {
|
|
263
|
+
const select = new StringSelectMenuBuilder()
|
|
264
|
+
.setCustomId(name)
|
|
265
|
+
.setRequired(field.required ?? true)
|
|
266
|
+
.addOptions(field.options.map(createSelectOption));
|
|
267
|
+
if (field.placeholder !== undefined) {
|
|
268
|
+
select.setPlaceholder(field.placeholder);
|
|
269
|
+
}
|
|
270
|
+
if (field.minValues !== undefined) {
|
|
271
|
+
select.setMinValues(field.minValues);
|
|
272
|
+
}
|
|
273
|
+
if (field.maxValues !== undefined) {
|
|
274
|
+
select.setMaxValues(field.maxValues);
|
|
275
|
+
}
|
|
276
|
+
return select;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function createRoleSelect(name: string, field: RoleFieldDef): RoleSelectMenuBuilder {
|
|
280
|
+
const select = new RoleSelectMenuBuilder().setCustomId(name).setRequired(field.required ?? true);
|
|
281
|
+
if (field.defaultRoleIds !== undefined) {
|
|
282
|
+
select.setDefaultRoles(...field.defaultRoleIds);
|
|
283
|
+
}
|
|
284
|
+
if (field.placeholder !== undefined) {
|
|
285
|
+
select.setPlaceholder(field.placeholder);
|
|
286
|
+
}
|
|
287
|
+
if (field.minValues !== undefined) {
|
|
288
|
+
select.setMinValues(field.minValues);
|
|
289
|
+
}
|
|
290
|
+
if (field.maxValues !== undefined) {
|
|
291
|
+
select.setMaxValues(field.maxValues);
|
|
292
|
+
}
|
|
293
|
+
return select;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function createUserSelect(name: string, field: UserFieldDef): UserSelectMenuBuilder {
|
|
297
|
+
const select = new UserSelectMenuBuilder().setCustomId(name).setRequired(field.required ?? true);
|
|
298
|
+
if (field.defaultUserIds !== undefined) {
|
|
299
|
+
select.setDefaultUsers(...field.defaultUserIds);
|
|
300
|
+
}
|
|
301
|
+
if (field.placeholder !== undefined) {
|
|
302
|
+
select.setPlaceholder(field.placeholder);
|
|
303
|
+
}
|
|
304
|
+
if (field.minValues !== undefined) {
|
|
305
|
+
select.setMinValues(field.minValues);
|
|
306
|
+
}
|
|
307
|
+
if (field.maxValues !== undefined) {
|
|
308
|
+
select.setMaxValues(field.maxValues);
|
|
309
|
+
}
|
|
310
|
+
return select;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function createChannelSelect(name: string, field: ChannelFieldDef): ChannelSelectMenuBuilder {
|
|
314
|
+
const select = new ChannelSelectMenuBuilder()
|
|
315
|
+
.setCustomId(name)
|
|
316
|
+
.setRequired(field.required ?? true);
|
|
317
|
+
if (field.channelTypes !== undefined) {
|
|
318
|
+
select.setChannelTypes(...field.channelTypes);
|
|
319
|
+
}
|
|
320
|
+
if (field.defaultChannelIds !== undefined) {
|
|
321
|
+
select.setDefaultChannels(...field.defaultChannelIds);
|
|
322
|
+
}
|
|
323
|
+
if (field.placeholder !== undefined) {
|
|
324
|
+
select.setPlaceholder(field.placeholder);
|
|
325
|
+
}
|
|
326
|
+
if (field.minValues !== undefined) {
|
|
327
|
+
select.setMinValues(field.minValues);
|
|
328
|
+
}
|
|
329
|
+
if (field.maxValues !== undefined) {
|
|
330
|
+
select.setMaxValues(field.maxValues);
|
|
331
|
+
}
|
|
332
|
+
return select;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function createLabel(name: string, field: FieldDef): LabelBuilder {
|
|
336
|
+
const label = new LabelBuilder().setLabel(field.label);
|
|
337
|
+
if (field.description !== undefined) {
|
|
338
|
+
label.setDescription(field.description);
|
|
339
|
+
}
|
|
340
|
+
if (field.kind === "checkbox") {
|
|
341
|
+
return label.setCheckboxComponent(
|
|
342
|
+
new CheckboxBuilder().setCustomId(name).setDefault(field.default ?? false),
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
if (field.kind === "file") {
|
|
346
|
+
return label.setFileUploadComponent(createFileUpload(name, field));
|
|
347
|
+
}
|
|
348
|
+
if (field.kind === "select") {
|
|
349
|
+
return label.setStringSelectMenuComponent(createStringSelect(name, field));
|
|
350
|
+
}
|
|
351
|
+
if (field.kind === "role") {
|
|
352
|
+
return label.setRoleSelectMenuComponent(createRoleSelect(name, field));
|
|
353
|
+
}
|
|
354
|
+
if (field.kind === "user") {
|
|
355
|
+
return label.setUserSelectMenuComponent(createUserSelect(name, field));
|
|
356
|
+
}
|
|
357
|
+
if (field.kind === "channel") {
|
|
358
|
+
return label.setChannelSelectMenuComponent(createChannelSelect(name, field));
|
|
359
|
+
}
|
|
360
|
+
return label.setTextInputComponent(createTextInput(name, field));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* An optional field left blank comes back as an empty string (or not at all when
|
|
365
|
+
* Discord omits it), two shapes for the same "nothing entered" outcome — collapse
|
|
366
|
+
* both to `null` so callers branch once.
|
|
367
|
+
*/
|
|
368
|
+
function readOptionalField(interaction: ModalSubmitInteraction, name: string): string | null {
|
|
369
|
+
if (!interaction.fields.fields.has(name)) {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
const value = interaction.fields.getTextInputValue(name);
|
|
373
|
+
return value.length > 0 ? value : null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* The same "nothing entered" collapsing for an upload: an optional file field
|
|
378
|
+
* left alone comes back absent, or present with no attachment at all.
|
|
379
|
+
*/
|
|
380
|
+
function readOptionalFiles(
|
|
381
|
+
interaction: ModalSubmitInteraction,
|
|
382
|
+
name: string,
|
|
383
|
+
): readonly Attachment[] | null {
|
|
384
|
+
if (!interaction.fields.fields.has(name)) {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
const uploaded = interaction.fields.getUploadedFiles(name);
|
|
388
|
+
if (uploaded === null || uploaded.size === 0) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
return [...uploaded.values()];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* The same "nothing entered" collapsing for a string select: an optional select
|
|
396
|
+
* field left alone comes back absent, or present with no option chosen.
|
|
397
|
+
*/
|
|
398
|
+
function readOptionalSelectValues(
|
|
399
|
+
interaction: ModalSubmitInteraction,
|
|
400
|
+
name: string,
|
|
401
|
+
): readonly string[] | null {
|
|
402
|
+
if (!interaction.fields.fields.has(name)) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
const values = interaction.fields.getStringSelectValues(name);
|
|
406
|
+
return values.length > 0 ? values : null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* The same "nothing entered" collapsing for a role/user/channel select: an
|
|
411
|
+
* optional field left alone comes back absent, or present with an empty (or
|
|
412
|
+
* `null`) selection. The identifiers are returned as the keys of the
|
|
413
|
+
* `Collection` the underlying getter resolves.
|
|
414
|
+
*/
|
|
415
|
+
function readOptionalIds(
|
|
416
|
+
interaction: ModalSubmitInteraction,
|
|
417
|
+
name: string,
|
|
418
|
+
getSelected: (
|
|
419
|
+
interaction: ModalSubmitInteraction,
|
|
420
|
+
name: string,
|
|
421
|
+
) => ReadonlyMap<string, unknown> | null,
|
|
422
|
+
): readonly string[] | null {
|
|
423
|
+
if (!interaction.fields.fields.has(name)) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
const selected = getSelected(interaction, name);
|
|
427
|
+
if (selected === null || selected.size === 0) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
return [...selected.keys()];
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Declare a modal: a title, a custom id and typed fields (text, checkbox,
|
|
435
|
+
* file, select, role, user or channel).
|
|
436
|
+
*
|
|
437
|
+
* Discord caps a modal at five components, so keep `fields` — plus one more if
|
|
438
|
+
* `legend` is set — within that budget. The `const` type parameter is what
|
|
439
|
+
* preserves each field's literal `kind`/`required`, and therefore the shape of
|
|
440
|
+
* the values `read` returns.
|
|
441
|
+
*/
|
|
442
|
+
export function createModal<const F extends ModalFields>(def: ModalDef<F>): Modal<F> {
|
|
443
|
+
const entries = Object.entries(def.fields) as [keyof F & string, FieldDef][];
|
|
444
|
+
|
|
445
|
+
return {
|
|
446
|
+
id: def.id,
|
|
447
|
+
build(state) {
|
|
448
|
+
const customId = state === undefined ? def.id : `${def.id}${CUSTOM_ID_SEPARATOR}${state}`;
|
|
449
|
+
const modal = new ModalBuilder().setCustomId(customId).setTitle(def.title);
|
|
450
|
+
if (def.legend !== undefined) {
|
|
451
|
+
modal.addTextDisplayComponents((textDisplay) =>
|
|
452
|
+
textDisplay.setContent(def.legend as string),
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
return modal.addLabelComponents(...entries.map(([name, field]) => createLabel(name, field)));
|
|
456
|
+
},
|
|
457
|
+
read(interaction) {
|
|
458
|
+
const values = {} as Record<
|
|
459
|
+
string,
|
|
460
|
+
string | null | boolean | readonly Attachment[] | readonly string[]
|
|
461
|
+
>;
|
|
462
|
+
for (const [name, field] of entries) {
|
|
463
|
+
if (field.kind === "checkbox") {
|
|
464
|
+
values[name] = interaction.fields.getCheckbox(name);
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
const isRequired = field.required ?? true;
|
|
468
|
+
if (field.kind === "file") {
|
|
469
|
+
values[name] = isRequired
|
|
470
|
+
? [...interaction.fields.getUploadedFiles(name, true).values()]
|
|
471
|
+
: readOptionalFiles(interaction, name);
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
if (field.kind === "select") {
|
|
475
|
+
values[name] = isRequired
|
|
476
|
+
? interaction.fields.getStringSelectValues(name)
|
|
477
|
+
: readOptionalSelectValues(interaction, name);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
if (field.kind === "role") {
|
|
481
|
+
values[name] = isRequired
|
|
482
|
+
? [...interaction.fields.getSelectedRoles(name, true).keys()]
|
|
483
|
+
: readOptionalIds(interaction, name, (i, n) => i.fields.getSelectedRoles(n, false));
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (field.kind === "user") {
|
|
487
|
+
values[name] = isRequired
|
|
488
|
+
? [...interaction.fields.getSelectedUsers(name, true).keys()]
|
|
489
|
+
: readOptionalIds(interaction, name, (i, n) => i.fields.getSelectedUsers(n, false));
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if (field.kind === "channel") {
|
|
493
|
+
values[name] = isRequired
|
|
494
|
+
? [...interaction.fields.getSelectedChannels(name, true).keys()]
|
|
495
|
+
: readOptionalIds(interaction, name, (i, n) => i.fields.getSelectedChannels(n, false));
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
values[name] = isRequired
|
|
499
|
+
? interaction.fields.getTextInputValue(name)
|
|
500
|
+
: readOptionalField(interaction, name);
|
|
501
|
+
}
|
|
502
|
+
return values as ModalValues<F>;
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
}
|