@azurioh/discord-kernel 0.1.0 → 1.0.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/README.md +318 -1
- package/dist/authz/require-level-guard.d.ts +1 -1
- package/dist/authz/require-level-guard.d.ts.map +1 -1
- package/dist/color.d.ts +42 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +130 -0
- package/dist/color.js.map +1 -0
- package/dist/discord/command/all-required.d.ts +8 -0
- package/dist/discord/command/all-required.d.ts.map +1 -0
- package/dist/discord/command/all-required.js +12 -0
- package/dist/discord/command/all-required.js.map +1 -0
- package/dist/discord/command/autocomplete-dispatcher.d.ts.map +1 -1
- package/dist/discord/command/autocomplete-dispatcher.js +2 -1
- package/dist/discord/command/autocomplete-dispatcher.js.map +1 -1
- package/dist/discord/command/autocomplete-limits.d.ts +3 -0
- package/dist/discord/command/autocomplete-limits.d.ts.map +1 -0
- package/dist/discord/command/autocomplete-limits.js +6 -0
- package/dist/discord/command/autocomplete-limits.js.map +1 -0
- package/dist/discord/command/autocomplete.d.ts +6 -1
- package/dist/discord/command/autocomplete.d.ts.map +1 -1
- package/dist/discord/command/autocomplete.js +6 -6
- package/dist/discord/command/autocomplete.js.map +1 -1
- package/dist/discord/command/command-responders.d.ts +26 -0
- package/dist/discord/command/command-responders.d.ts.map +1 -0
- package/dist/discord/command/command-responders.js +16 -0
- package/dist/discord/command/command-responders.js.map +1 -0
- package/dist/discord/command/context.d.ts +8 -17
- package/dist/discord/command/context.d.ts.map +1 -1
- package/dist/discord/command/context.js +8 -37
- package/dist/discord/command/context.js.map +1 -1
- package/dist/discord/command/cooldown-guard.d.ts +1 -1
- package/dist/discord/command/cooldown-guard.d.ts.map +1 -1
- package/dist/discord/command/create-command.d.ts +1 -8
- package/dist/discord/command/create-command.d.ts.map +1 -1
- package/dist/discord/command/create-command.js +17 -65
- package/dist/discord/command/create-command.js.map +1 -1
- package/dist/discord/command/create-context-menu-command.d.ts +3 -9
- package/dist/discord/command/create-context-menu-command.d.ts.map +1 -1
- package/dist/discord/command/create-context-menu-command.js +14 -65
- package/dist/discord/command/create-context-menu-command.js.map +1 -1
- package/dist/discord/command/errors.d.ts +1 -1
- package/dist/discord/command/errors.d.ts.map +1 -1
- package/dist/discord/command/errors.js +2 -2
- package/dist/discord/command/errors.js.map +1 -1
- package/dist/discord/command/guard.d.ts +15 -8
- package/dist/discord/command/guard.d.ts.map +1 -1
- package/dist/discord/command/guard.js +4 -4
- package/dist/discord/command/guard.js.map +1 -1
- package/dist/discord/command/options.d.ts +1 -10
- package/dist/discord/command/options.d.ts.map +1 -1
- package/dist/discord/command/options.js +127 -320
- package/dist/discord/command/options.js.map +1 -1
- package/dist/discord/command/passes-guard.d.ts +14 -0
- package/dist/discord/command/passes-guard.d.ts.map +1 -0
- package/dist/discord/command/passes-guard.js +27 -0
- package/dist/discord/command/passes-guard.js.map +1 -0
- package/dist/discord/command/permission-guard.d.ts +1 -1
- package/dist/discord/command/permission-guard.d.ts.map +1 -1
- package/dist/discord/command/render-command-failure.d.ts +23 -0
- package/dist/discord/command/render-command-failure.d.ts.map +1 -0
- package/dist/discord/command/render-command-failure.js +40 -0
- package/dist/discord/command/render-command-failure.js.map +1 -0
- package/dist/discord/command/route-key.d.ts +8 -0
- package/dist/discord/command/route-key.d.ts.map +1 -0
- package/dist/discord/command/route-key.js +13 -0
- package/dist/discord/command/route-key.js.map +1 -0
- package/dist/discord/command/router.d.ts +32 -7
- package/dist/discord/command/router.d.ts.map +1 -1
- package/dist/discord/command/router.js +48 -10
- package/dist/discord/command/router.js.map +1 -1
- package/dist/discord/command/send-embed.d.ts +14 -0
- package/dist/discord/command/send-embed.d.ts.map +1 -0
- package/dist/discord/command/send-embed.js +37 -0
- package/dist/discord/command/send-embed.js.map +1 -0
- package/dist/discord/command/types.d.ts +7 -1
- package/dist/discord/command/types.d.ts.map +1 -1
- package/dist/discord/components/component-access.d.ts +12 -0
- package/dist/discord/components/component-access.d.ts.map +1 -0
- package/dist/discord/components/component-access.js +21 -0
- package/dist/discord/components/component-access.js.map +1 -0
- package/dist/discord/components/component-router.d.ts +37 -15
- package/dist/discord/components/component-router.d.ts.map +1 -1
- package/dist/discord/components/component-router.js +44 -32
- package/dist/discord/components/component-router.js.map +1 -1
- package/dist/discord/components/interactive-message/index.d.ts +3 -1
- package/dist/discord/components/interactive-message/index.d.ts.map +1 -1
- package/dist/discord/components/interactive-message/index.js +5 -3
- package/dist/discord/components/interactive-message/index.js.map +1 -1
- package/dist/discord/components/interactive-message/interactive-message-collector.d.ts +3 -28
- package/dist/discord/components/interactive-message/interactive-message-collector.d.ts.map +1 -1
- package/dist/discord/components/interactive-message/interactive-message-collector.js +6 -53
- package/dist/discord/components/interactive-message/interactive-message-collector.js.map +1 -1
- package/dist/discord/components/interactive-message/message-edit-options.d.ts +18 -0
- package/dist/discord/components/interactive-message/message-edit-options.d.ts.map +1 -0
- package/dist/discord/components/interactive-message/message-edit-options.js +40 -0
- package/dist/discord/components/interactive-message/message-edit-options.js.map +1 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.d.ts +2 -1
- package/dist/discord/components/interactive-message/mount-interactive-message.d.ts.map +1 -1
- package/dist/discord/components/interactive-message/mount-interactive-message.js +4 -2
- package/dist/discord/components/interactive-message/mount-interactive-message.js.map +1 -1
- package/dist/discord/components/interactive-message/state-store.d.ts +12 -0
- package/dist/discord/components/interactive-message/state-store.d.ts.map +1 -0
- package/dist/discord/components/interactive-message/state-store.js +14 -0
- package/dist/discord/components/interactive-message/state-store.js.map +1 -0
- package/dist/discord/components/paginator/mount-paginator.js +7 -5
- package/dist/discord/components/paginator/mount-paginator.js.map +1 -1
- package/dist/discord/components/paginator/paginator-view.d.ts +1 -1
- package/dist/discord/components/paginator/paginator-view.d.ts.map +1 -1
- package/dist/discord/components/persistent-paginator.d.ts +1 -1
- package/dist/discord/components/persistent-paginator.d.ts.map +1 -1
- package/dist/discord/components/persistent-paginator.js +6 -6
- package/dist/discord/components/persistent-paginator.js.map +1 -1
- package/dist/discord/components/settings-editor/from-declaration-controls.d.ts +67 -0
- package/dist/discord/components/settings-editor/from-declaration-controls.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-controls.js +245 -0
- package/dist/discord/components/settings-editor/from-declaration-controls.js.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-display.d.ts +23 -0
- package/dist/discord/components/settings-editor/from-declaration-display.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-display.js +114 -0
- package/dist/discord/components/settings-editor/from-declaration-display.js.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-layout.d.ts +33 -0
- package/dist/discord/components/settings-editor/from-declaration-layout.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-layout.js +178 -0
- package/dist/discord/components/settings-editor/from-declaration-layout.js.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-search.d.ts +27 -0
- package/dist/discord/components/settings-editor/from-declaration-search.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-search.js +58 -0
- package/dist/discord/components/settings-editor/from-declaration-search.js.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-stored.d.ts +21 -0
- package/dist/discord/components/settings-editor/from-declaration-stored.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-stored.js +37 -0
- package/dist/discord/components/settings-editor/from-declaration-stored.js.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-subject.d.ts +32 -0
- package/dist/discord/components/settings-editor/from-declaration-subject.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-subject.js +65 -0
- package/dist/discord/components/settings-editor/from-declaration-subject.js.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-values.d.ts +57 -0
- package/dist/discord/components/settings-editor/from-declaration-values.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration-values.js +187 -0
- package/dist/discord/components/settings-editor/from-declaration-values.js.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration.d.ts +39 -0
- package/dist/discord/components/settings-editor/from-declaration.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/from-declaration.js +132 -0
- package/dist/discord/components/settings-editor/from-declaration.js.map +1 -0
- package/dist/discord/components/settings-editor/index.d.ts +3 -1
- package/dist/discord/components/settings-editor/index.d.ts.map +1 -1
- package/dist/discord/components/settings-editor/index.js +6 -3
- package/dist/discord/components/settings-editor/index.js.map +1 -1
- package/dist/discord/components/settings-editor/mount-settings-editor.d.ts +16 -2
- package/dist/discord/components/settings-editor/mount-settings-editor.d.ts.map +1 -1
- package/dist/discord/components/settings-editor/mount-settings-editor.js +14 -10
- package/dist/discord/components/settings-editor/mount-settings-editor.js.map +1 -1
- package/dist/discord/components/settings-editor/navigation.d.ts +20 -0
- package/dist/discord/components/settings-editor/navigation.d.ts.map +1 -1
- package/dist/discord/components/settings-editor/navigation.js +22 -0
- package/dist/discord/components/settings-editor/navigation.js.map +1 -1
- package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts +4 -3
- package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts.map +1 -1
- package/dist/discord/components/settings-editor/settings-editor-card.view.js +60 -34
- package/dist/discord/components/settings-editor/settings-editor-card.view.js.map +1 -1
- package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts +2 -1
- package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts.map +1 -1
- package/dist/discord/components/settings-editor/settings-editor-field-modal.js +48 -72
- package/dist/discord/components/settings-editor/settings-editor-field-modal.js.map +1 -1
- package/dist/discord/components/settings-editor/settings-editor-field-values.d.ts +6 -0
- package/dist/discord/components/settings-editor/settings-editor-field-values.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-field-values.js +13 -0
- package/dist/discord/components/settings-editor/settings-editor-field-values.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.d.ts +6 -5
- package/dist/discord/components/settings-editor/settings-editor-fields.d.ts.map +1 -1
- package/dist/discord/components/settings-editor/settings-editor-fields.js +0 -10
- package/dist/discord/components/settings-editor/settings-editor-fields.js.map +1 -1
- package/dist/discord/components/settings-editor/settings-editor.view.d.ts +3 -2
- package/dist/discord/components/settings-editor/settings-editor.view.d.ts.map +1 -1
- package/dist/discord/components/settings-editor/settings-editor.view.js +4 -21
- package/dist/discord/components/settings-editor/settings-editor.view.js.map +1 -1
- package/dist/discord/events/event-guild-id.d.ts +10 -0
- package/dist/discord/events/event-guild-id.d.ts.map +1 -0
- package/dist/discord/events/event-guild-id.js +37 -0
- package/dist/discord/events/event-guild-id.js.map +1 -0
- package/dist/discord/events/event-router.d.ts +17 -3
- package/dist/discord/events/event-router.d.ts.map +1 -1
- package/dist/discord/events/event-router.js +33 -9
- package/dist/discord/events/event-router.js.map +1 -1
- package/dist/discord/i18n.d.ts +17 -2
- package/dist/discord/i18n.d.ts.map +1 -1
- package/dist/discord/i18n.js +43 -6
- package/dist/discord/i18n.js.map +1 -1
- package/dist/discord/interaction/interaction-locale.d.ts +14 -0
- package/dist/discord/interaction/interaction-locale.d.ts.map +1 -0
- package/dist/discord/interaction/interaction-locale.js +12 -0
- package/dist/discord/interaction/interaction-locale.js.map +1 -0
- package/dist/discord/interaction/locale-resolver.d.ts +27 -0
- package/dist/discord/interaction/locale-resolver.d.ts.map +1 -0
- package/dist/discord/interaction/locale-resolver.js +3 -0
- package/dist/discord/interaction/locale-resolver.js.map +1 -0
- package/dist/discord/interaction/modal.d.ts.map +1 -1
- package/dist/discord/interaction/modal.js +5 -40
- package/dist/discord/interaction/modal.js.map +1 -1
- package/dist/discord/interaction/reply-locale.d.ts +18 -0
- package/dist/discord/interaction/reply-locale.d.ts.map +1 -0
- package/dist/discord/interaction/reply-locale.js +25 -0
- package/dist/discord/interaction/reply-locale.js.map +1 -0
- package/dist/discord/interaction/select-bounds.d.ts +19 -0
- package/dist/discord/interaction/select-bounds.d.ts.map +1 -0
- package/dist/discord/interaction/select-bounds.js +17 -0
- package/dist/discord/interaction/select-bounds.js.map +1 -0
- package/dist/discord/interaction/select-menu.d.ts.map +1 -1
- package/dist/discord/interaction/select-menu.js +2 -9
- package/dist/discord/interaction/select-menu.js.map +1 -1
- package/dist/discord/placeholder-registry.d.ts +1 -1
- package/dist/discord/placeholder-registry.d.ts.map +1 -1
- package/dist/discord/presenter.d.ts +1 -1
- package/dist/discord/presenter.d.ts.map +1 -1
- package/dist/discord/settings/discord-guild-directory.d.ts +28 -0
- package/dist/discord/settings/discord-guild-directory.d.ts.map +1 -0
- package/dist/discord/settings/discord-guild-directory.js +171 -0
- package/dist/discord/settings/discord-guild-directory.js.map +1 -0
- package/dist/discord/settings/guild-locale-resolver.d.ts +25 -0
- package/dist/discord/settings/guild-locale-resolver.d.ts.map +1 -0
- package/dist/discord/settings/guild-locale-resolver.js +33 -0
- package/dist/discord/settings/guild-locale-resolver.js.map +1 -0
- package/dist/discord/settings/is-module-disabled.d.ts +16 -0
- package/dist/discord/settings/is-module-disabled.d.ts.map +1 -0
- package/dist/discord/settings/is-module-disabled.js +20 -0
- package/dist/discord/settings/is-module-disabled.js.map +1 -0
- package/dist/discord/settings/module-disabled-embed.d.ts +13 -0
- package/dist/discord/settings/module-disabled-embed.d.ts.map +1 -0
- package/dist/discord/settings/module-disabled-embed.js +16 -0
- package/dist/discord/settings/module-disabled-embed.js.map +1 -0
- package/dist/discord/settings/require-configured.d.ts +26 -0
- package/dist/discord/settings/require-configured.d.ts.map +1 -0
- package/dist/discord/settings/require-configured.js +62 -0
- package/dist/discord/settings/require-configured.js.map +1 -0
- package/dist/discord/ui/color-aliases.d.ts +31 -0
- package/dist/discord/ui/color-aliases.d.ts.map +1 -0
- package/dist/discord/ui/color-aliases.js +66 -0
- package/dist/discord/ui/color-aliases.js.map +1 -0
- package/dist/discord/ui/color-input.d.ts +5 -32
- package/dist/discord/ui/color-input.d.ts.map +1 -1
- package/dist/discord/ui/color-input.js +8 -157
- package/dist/discord/ui/color-input.js.map +1 -1
- package/dist/discord/ui/colors.d.ts +0 -2
- package/dist/discord/ui/colors.d.ts.map +1 -1
- package/dist/discord/ui/colors.js +4 -5
- package/dist/discord/ui/colors.js.map +1 -1
- package/dist/discord/ui/embed.d.ts.map +1 -1
- package/dist/discord/ui/embed.js +3 -8
- package/dist/discord/ui/embed.js.map +1 -1
- package/dist/discord/ui/truncate-text.d.ts +11 -0
- package/dist/discord/ui/truncate-text.d.ts.map +1 -0
- package/dist/discord/ui/truncate-text.js +19 -0
- package/dist/discord/ui/truncate-text.js.map +1 -0
- package/dist/errors/error-message.d.ts +9 -0
- package/dist/errors/error-message.d.ts.map +1 -0
- package/dist/errors/error-message.js +14 -0
- package/dist/errors/error-message.js.map +1 -0
- package/dist/i18n/business-message.d.ts +1 -1
- package/dist/i18n/business-message.d.ts.map +1 -1
- package/dist/i18n/catalog.d.ts +9 -0
- package/dist/i18n/catalog.d.ts.map +1 -1
- package/dist/i18n/catalog.js +4 -0
- package/dist/i18n/catalog.js.map +1 -1
- package/dist/i18n/locale.d.ts +2 -0
- package/dist/i18n/locale.d.ts.map +1 -1
- package/dist/i18n/locale.js +3 -1
- package/dist/i18n/locale.js.map +1 -1
- package/dist/i18n/translator.d.ts +2 -0
- package/dist/i18n/translator.d.ts.map +1 -1
- package/dist/i18n/translator.js.map +1 -1
- package/dist/module/module.d.ts +15 -1
- package/dist/module/module.d.ts.map +1 -1
- package/dist/resilience/retry.js +2 -2
- package/dist/resilience/retry.js.map +1 -1
- package/dist/scheduler/scheduler.d.ts.map +1 -1
- package/dist/scheduler/scheduler.js +2 -4
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/settings/cache.d.ts +29 -0
- package/dist/settings/cache.d.ts.map +1 -0
- package/dist/settings/cache.js +47 -0
- package/dist/settings/cache.js.map +1 -0
- package/dist/settings/choice.d.ts +10 -0
- package/dist/settings/choice.d.ts.map +1 -0
- package/dist/settings/choice.js +3 -0
- package/dist/settings/choice.js.map +1 -0
- package/dist/settings/decode-stored.d.ts +20 -0
- package/dist/settings/decode-stored.d.ts.map +1 -0
- package/dist/settings/decode-stored.js +35 -0
- package/dist/settings/decode-stored.js.map +1 -0
- package/dist/settings/define-settings.d.ts +52 -0
- package/dist/settings/define-settings.d.ts.map +1 -0
- package/dist/settings/define-settings.js +141 -0
- package/dist/settings/define-settings.js.map +1 -0
- package/dist/settings/describe-field.d.ts +19 -0
- package/dist/settings/describe-field.d.ts.map +1 -0
- package/dist/settings/describe-field.js +131 -0
- package/dist/settings/describe-field.js.map +1 -0
- package/dist/settings/describe.d.ts +27 -0
- package/dist/settings/describe.d.ts.map +1 -0
- package/dist/settings/describe.js +62 -0
- package/dist/settings/describe.js.map +1 -0
- package/dist/settings/duration.d.ts +16 -0
- package/dist/settings/duration.d.ts.map +1 -0
- package/dist/settings/duration.js +56 -0
- package/dist/settings/duration.js.map +1 -0
- package/dist/settings/field-order.d.ts +37 -0
- package/dist/settings/field-order.d.ts.map +1 -0
- package/dist/settings/field-order.js +100 -0
- package/dist/settings/field-order.js.map +1 -0
- package/dist/settings/field-search.d.ts +10 -0
- package/dist/settings/field-search.d.ts.map +1 -0
- package/dist/settings/field-search.js +18 -0
- package/dist/settings/field-search.js.map +1 -0
- package/dist/settings/fields/builders.d.ts +41 -0
- package/dist/settings/fields/builders.d.ts.map +1 -0
- package/dist/settings/fields/builders.js +83 -0
- package/dist/settings/fields/builders.js.map +1 -0
- package/dist/settings/fields/field.d.ts +199 -0
- package/dist/settings/fields/field.d.ts.map +1 -0
- package/dist/settings/fields/field.js +33 -0
- package/dist/settings/fields/field.js.map +1 -0
- package/dist/settings/fields/zod-schema.d.ts +67 -0
- package/dist/settings/fields/zod-schema.d.ts.map +1 -0
- package/dist/settings/fields/zod-schema.js +281 -0
- package/dist/settings/fields/zod-schema.js.map +1 -0
- package/dist/settings/in-memory/in-memory-guild-directory.d.ts +24 -0
- package/dist/settings/in-memory/in-memory-guild-directory.d.ts.map +1 -0
- package/dist/settings/in-memory/in-memory-guild-directory.js +42 -0
- package/dist/settings/in-memory/in-memory-guild-directory.js.map +1 -0
- package/dist/settings/in-memory/in-memory-settings-store.d.ts +8 -0
- package/dist/settings/in-memory/in-memory-settings-store.d.ts.map +1 -0
- package/dist/settings/in-memory/in-memory-settings-store.js +43 -0
- package/dist/settings/in-memory/in-memory-settings-store.js.map +1 -0
- package/dist/settings/in-memory/in-process-notifier.d.ts +9 -0
- package/dist/settings/in-memory/in-process-notifier.d.ts.map +1 -0
- package/dist/settings/in-memory/in-process-notifier.js +32 -0
- package/dist/settings/in-memory/in-process-notifier.js.map +1 -0
- package/dist/settings/index.d.ts +22 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +31 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/settings/is-plain-object.d.ts +6 -0
- package/dist/settings/is-plain-object.d.ts.map +1 -0
- package/dist/settings/is-plain-object.js +15 -0
- package/dist/settings/is-plain-object.js.map +1 -0
- package/dist/settings/messages.d.ts +61 -0
- package/dist/settings/messages.d.ts.map +1 -0
- package/dist/settings/messages.js +155 -0
- package/dist/settings/messages.js.map +1 -0
- package/dist/settings/migrate.d.ts +35 -0
- package/dist/settings/migrate.d.ts.map +1 -0
- package/dist/settings/migrate.js +42 -0
- package/dist/settings/migrate.js.map +1 -0
- package/dist/settings/ports/guild-directory.d.ts +61 -0
- package/dist/settings/ports/guild-directory.d.ts.map +1 -0
- package/dist/settings/ports/guild-directory.js +3 -0
- package/dist/settings/ports/guild-directory.js.map +1 -0
- package/dist/settings/ports/settings-changed-notifier.d.ts +20 -0
- package/dist/settings/ports/settings-changed-notifier.d.ts.map +1 -0
- package/dist/settings/ports/settings-changed-notifier.js +3 -0
- package/dist/settings/ports/settings-changed-notifier.js.map +1 -0
- package/dist/settings/ports/settings-store.d.ts +76 -0
- package/dist/settings/ports/settings-store.d.ts.map +1 -0
- package/dist/settings/ports/settings-store.js +3 -0
- package/dist/settings/ports/settings-store.js.map +1 -0
- package/dist/settings/registry.d.ts +31 -0
- package/dist/settings/registry.d.ts.map +1 -0
- package/dist/settings/registry.js +102 -0
- package/dist/settings/registry.js.map +1 -0
- package/dist/settings/settings-declaration-error.d.ts +13 -0
- package/dist/settings/settings-declaration-error.d.ts.map +1 -0
- package/dist/settings/settings-declaration-error.js +22 -0
- package/dist/settings/settings-declaration-error.js.map +1 -0
- package/dist/settings/settings-service.d.ts +148 -0
- package/dist/settings/settings-service.d.ts.map +1 -0
- package/dist/settings/settings-service.js +279 -0
- package/dist/settings/settings-service.js.map +1 -0
- package/dist/settings/settings-validation-error.d.ts +23 -0
- package/dist/settings/settings-validation-error.d.ts.map +1 -0
- package/dist/settings/settings-validation-error.js +17 -0
- package/dist/settings/settings-validation-error.js.map +1 -0
- package/dist/settings/status.d.ts +16 -0
- package/dist/settings/status.d.ts.map +1 -0
- package/dist/settings/status.js +18 -0
- package/dist/settings/status.js.map +1 -0
- package/dist/settings/suggest.d.ts +77 -0
- package/dist/settings/suggest.d.ts.map +1 -0
- package/dist/settings/suggest.js +192 -0
- package/dist/settings/suggest.js.map +1 -0
- package/dist/settings/system/kernel-settings.d.ts +43 -0
- package/dist/settings/system/kernel-settings.d.ts.map +1 -0
- package/dist/settings/system/kernel-settings.js +53 -0
- package/dist/settings/system/kernel-settings.js.map +1 -0
- package/dist/settings/system/module-gate.d.ts +31 -0
- package/dist/settings/system/module-gate.d.ts.map +1 -0
- package/dist/settings/system/module-gate.js +34 -0
- package/dist/settings/system/module-gate.js.map +1 -0
- package/dist/settings/testing/index.d.ts +2 -0
- package/dist/settings/testing/index.d.ts.map +1 -0
- package/dist/settings/testing/index.js +6 -0
- package/dist/settings/testing/index.js.map +1 -0
- package/dist/settings/testing/settings-store-contract.d.ts +29 -0
- package/dist/settings/testing/settings-store-contract.d.ts.map +1 -0
- package/dist/settings/testing/settings-store-contract.js +192 -0
- package/dist/settings/testing/settings-store-contract.js.map +1 -0
- package/dist/settings/timed-search.d.ts +26 -0
- package/dist/settings/timed-search.d.ts.map +1 -0
- package/dist/settings/timed-search.js +48 -0
- package/dist/settings/timed-search.js.map +1 -0
- package/dist/settings/types.d.ts +37 -0
- package/dist/settings/types.d.ts.map +1 -0
- package/dist/settings/types.js +3 -0
- package/dist/settings/types.js.map +1 -0
- package/dist/settings/validate.d.ts +55 -0
- package/dist/settings/validate.d.ts.map +1 -0
- package/dist/settings/validate.js +196 -0
- package/dist/settings/validate.js.map +1 -0
- package/package.json +463 -88
- package/src/authz/require-level-guard.ts +1 -1
- package/src/color.ts +134 -0
- package/src/discord/command/all-required.ts +12 -0
- package/src/discord/command/autocomplete-dispatcher.ts +2 -1
- package/src/discord/command/autocomplete-limits.ts +2 -0
- package/src/discord/command/autocomplete.ts +8 -7
- package/src/discord/command/command-responders.ts +39 -0
- package/src/discord/command/context.ts +14 -54
- package/src/discord/command/cooldown-guard.ts +1 -1
- package/src/discord/command/create-command.ts +19 -94
- package/src/discord/command/create-context-menu-command.ts +19 -97
- package/src/discord/command/errors.ts +1 -1
- package/src/discord/command/guard.ts +24 -12
- package/src/discord/command/options.ts +202 -412
- package/src/discord/command/passes-guard.ts +37 -0
- package/src/discord/command/permission-guard.ts +1 -1
- package/src/discord/command/render-command-failure.ts +71 -0
- package/src/discord/command/route-key.ts +9 -0
- package/src/discord/command/router.ts +73 -12
- package/src/discord/command/send-embed.ts +42 -0
- package/src/discord/command/types.ts +7 -1
- package/src/discord/components/component-access.ts +20 -0
- package/src/discord/components/component-router.ts +73 -36
- package/src/discord/components/interactive-message/index.ts +5 -3
- package/src/discord/components/interactive-message/interactive-message-collector.ts +4 -68
- package/src/discord/components/interactive-message/message-edit-options.ts +47 -0
- package/src/discord/components/interactive-message/mount-interactive-message.ts +5 -3
- package/src/discord/components/interactive-message/state-store.ts +20 -0
- package/src/discord/components/paginator/mount-paginator.ts +3 -3
- package/src/discord/components/paginator/paginator-view.ts +1 -1
- package/src/discord/components/persistent-paginator.ts +8 -9
- package/src/discord/components/settings-editor/from-declaration-controls.ts +371 -0
- package/src/discord/components/settings-editor/from-declaration-display.ts +155 -0
- package/src/discord/components/settings-editor/from-declaration-layout.ts +247 -0
- package/src/discord/components/settings-editor/from-declaration-search.ts +77 -0
- package/src/discord/components/settings-editor/from-declaration-stored.ts +39 -0
- package/src/discord/components/settings-editor/from-declaration-subject.ts +110 -0
- package/src/discord/components/settings-editor/from-declaration-values.ts +240 -0
- package/src/discord/components/settings-editor/from-declaration.ts +218 -0
- package/src/discord/components/settings-editor/index.ts +5 -2
- package/src/discord/components/settings-editor/mount-settings-editor.ts +28 -10
- package/src/discord/components/settings-editor/navigation.ts +41 -0
- package/src/discord/components/settings-editor/settings-editor-card.view.ts +79 -36
- package/src/discord/components/settings-editor/settings-editor-field-modal.ts +76 -68
- package/src/discord/components/settings-editor/settings-editor-field-values.ts +11 -0
- package/src/discord/components/settings-editor/settings-editor-fields.ts +6 -11
- package/src/discord/components/settings-editor/settings-editor.view.ts +11 -24
- package/src/discord/events/event-guild-id.ts +35 -0
- package/src/discord/events/event-router.ts +46 -13
- package/src/discord/i18n.ts +47 -8
- package/src/discord/interaction/interaction-locale.ts +19 -0
- package/src/discord/interaction/locale-resolver.ts +28 -0
- package/src/discord/interaction/modal.ts +5 -40
- package/src/discord/interaction/reply-locale.ts +35 -0
- package/src/discord/interaction/select-bounds.ts +33 -0
- package/src/discord/interaction/select-menu.ts +2 -9
- package/src/discord/placeholder-registry.ts +1 -1
- package/src/discord/presenter.ts +1 -1
- package/src/discord/settings/discord-guild-directory.ts +214 -0
- package/src/discord/settings/guild-locale-resolver.ts +38 -0
- package/src/discord/settings/is-module-disabled.ts +22 -0
- package/src/discord/settings/module-disabled-embed.ts +19 -0
- package/src/discord/settings/require-configured.ts +68 -0
- package/src/discord/ui/color-aliases.ts +70 -0
- package/src/discord/ui/color-input.ts +8 -173
- package/src/discord/ui/colors.ts +2 -3
- package/src/discord/ui/embed.ts +3 -9
- package/src/discord/ui/truncate-text.ts +15 -0
- package/src/errors/error-message.ts +10 -0
- package/src/i18n/business-message.ts +1 -1
- package/src/i18n/catalog.ts +14 -0
- package/src/i18n/locale.ts +3 -0
- package/src/i18n/translator.ts +3 -0
- package/src/module/module.ts +15 -1
- package/src/resilience/retry.ts +1 -1
- package/src/scheduler/scheduler.ts +2 -5
- package/src/settings/cache.ts +70 -0
- package/src/settings/choice.ts +9 -0
- package/src/settings/decode-stored.ts +40 -0
- package/src/settings/define-settings.ts +214 -0
- package/src/settings/describe-field.ts +155 -0
- package/src/settings/describe.ts +90 -0
- package/src/settings/duration.ts +54 -0
- package/src/settings/field-order.ts +128 -0
- package/src/settings/field-search.ts +16 -0
- package/src/settings/fields/builders.ts +161 -0
- package/src/settings/fields/field.ts +205 -0
- package/src/settings/fields/zod-schema.ts +300 -0
- package/src/settings/in-memory/in-memory-guild-directory.ts +69 -0
- package/src/settings/in-memory/in-memory-settings-store.ts +46 -0
- package/src/settings/in-memory/in-process-notifier.ts +40 -0
- package/src/settings/index.ts +72 -0
- package/src/settings/is-plain-object.ts +11 -0
- package/src/settings/messages.ts +161 -0
- package/src/settings/migrate.ts +58 -0
- package/src/settings/ports/guild-directory.ts +48 -0
- package/src/settings/ports/settings-changed-notifier.ts +20 -0
- package/src/settings/ports/settings-store.ts +74 -0
- package/src/settings/registry.ts +137 -0
- package/src/settings/settings-declaration-error.ts +16 -0
- package/src/settings/settings-service.ts +535 -0
- package/src/settings/settings-validation-error.ts +41 -0
- package/src/settings/status.ts +25 -0
- package/src/settings/suggest.ts +267 -0
- package/src/settings/system/kernel-settings.ts +74 -0
- package/src/settings/system/module-gate.ts +49 -0
- package/src/settings/testing/index.ts +7 -0
- package/src/settings/testing/settings-store-contract.ts +278 -0
- package/src/settings/timed-search.ts +56 -0
- package/src/settings/types.ts +42 -0
- package/src/settings/validate.ts +298 -0
package/src/color.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generic web colours, at the value the name carries everywhere else — an
|
|
3
|
+
* administrator typing `orange` gets the orange they would get in CSS, not a
|
|
4
|
+
* shade this module invented.
|
|
5
|
+
*/
|
|
6
|
+
const RED = "#ff0000";
|
|
7
|
+
const BLUE = "#0000ff";
|
|
8
|
+
const GREEN = "#008000";
|
|
9
|
+
const YELLOW = "#ffff00";
|
|
10
|
+
const ORANGE = "#ffa500";
|
|
11
|
+
const PURPLE = "#800080";
|
|
12
|
+
const PINK = "#ffc0cb";
|
|
13
|
+
const WHITE = "#ffffff";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Discord's own brand colour. Kept with the base names rather than in the
|
|
17
|
+
* Discord ring so a `blurple` setting means the same colour on every surface,
|
|
18
|
+
* and so embeds fall back to it when a bot declares no palette.
|
|
19
|
+
*/
|
|
20
|
+
export const DISCORD_BLURPLE = "#5865f2";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Not `#000000`: Discord reads a zero colour as "no colour set" and renders the
|
|
24
|
+
* default grey bar instead, so pure black is the one value an administrator
|
|
25
|
+
* could ask for and never see. One step off zero reads as black.
|
|
26
|
+
*/
|
|
27
|
+
const BLACK = "#010101";
|
|
28
|
+
|
|
29
|
+
const GREY = "#808080";
|
|
30
|
+
const CYAN = "#00ffff";
|
|
31
|
+
const BROWN = "#a52a2a";
|
|
32
|
+
const SILVER = "#c0c0c0";
|
|
33
|
+
const TURQUOISE = "#40e0d0";
|
|
34
|
+
const MAGENTA = "#ff00ff";
|
|
35
|
+
const NAVY = "#000080";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Colour names an administrator may type instead of a hex code, French and
|
|
39
|
+
* English side by side.
|
|
40
|
+
*
|
|
41
|
+
* This table is **input vocabulary, not display text**. Nothing in it is ever
|
|
42
|
+
* shown to anyone, and its keys must never be translated at runtime: a catalog
|
|
43
|
+
* lookup resolves against the reply locale, which would make `rouge` stop
|
|
44
|
+
* working the moment an admin's Discord is set to English — the opposite of the
|
|
45
|
+
* point. Both spellings are accepted from everyone, always, which only a flat
|
|
46
|
+
* table can promise.
|
|
47
|
+
*
|
|
48
|
+
* Fixed on purpose: a value stored from one of these names must mean the same
|
|
49
|
+
* colour in every bot. Names a bot adds for its own inputs live with those
|
|
50
|
+
* inputs, not here.
|
|
51
|
+
*/
|
|
52
|
+
export const BASE_COLOR_NAMES: Readonly<Record<string, string>> = {
|
|
53
|
+
red: RED,
|
|
54
|
+
rouge: RED,
|
|
55
|
+
blue: BLUE,
|
|
56
|
+
bleu: BLUE,
|
|
57
|
+
green: GREEN,
|
|
58
|
+
vert: GREEN,
|
|
59
|
+
yellow: YELLOW,
|
|
60
|
+
jaune: YELLOW,
|
|
61
|
+
orange: ORANGE,
|
|
62
|
+
purple: PURPLE,
|
|
63
|
+
// French for purple, not the CSS `violet` (a pale pink): an admin typing it
|
|
64
|
+
// here is asking for the colour the word means in their own language.
|
|
65
|
+
violet: PURPLE,
|
|
66
|
+
pink: PINK,
|
|
67
|
+
rose: PINK,
|
|
68
|
+
white: WHITE,
|
|
69
|
+
blanc: WHITE,
|
|
70
|
+
black: BLACK,
|
|
71
|
+
noir: BLACK,
|
|
72
|
+
grey: GREY,
|
|
73
|
+
gray: GREY,
|
|
74
|
+
gris: GREY,
|
|
75
|
+
cyan: CYAN,
|
|
76
|
+
brown: BROWN,
|
|
77
|
+
marron: BROWN,
|
|
78
|
+
silver: SILVER,
|
|
79
|
+
argent: SILVER,
|
|
80
|
+
argenté: SILVER,
|
|
81
|
+
turquoise: TURQUOISE,
|
|
82
|
+
magenta: MAGENTA,
|
|
83
|
+
navy: NAVY,
|
|
84
|
+
marine: NAVY,
|
|
85
|
+
blurple: DISCORD_BLURPLE,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Accents must not be a trap: `dore` and `doré` are the same request, and an
|
|
90
|
+
* administrator has no way of knowing which one a table happened to spell.
|
|
91
|
+
* Case and surrounding whitespace are folded for the same reason.
|
|
92
|
+
*/
|
|
93
|
+
export function normalizeColorName(raw: string): string {
|
|
94
|
+
return raw
|
|
95
|
+
.trim()
|
|
96
|
+
.toLowerCase()
|
|
97
|
+
.normalize("NFD")
|
|
98
|
+
.replace(/\p{Diacritic}/gu, "");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Index a name → `#rrggbb` table by {@link normalizeColorName}, so lookups fold case and accents. */
|
|
102
|
+
export function indexColorNames(names: Readonly<Record<string, string>>): Map<string, string> {
|
|
103
|
+
return new Map(Object.entries(names).map(([name, hex]) => [normalizeColorName(name), hex]));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const BASE_COLORS_BY_NORMALIZED_NAME: ReadonlyMap<string, string> =
|
|
107
|
+
indexColorNames(BASE_COLOR_NAMES);
|
|
108
|
+
|
|
109
|
+
/** `#RGB` and `#RRGGBB`, with or without the leading hash. */
|
|
110
|
+
const HEX_COLOR_PATTERN = /^#?(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Normalize a hexadecimal colour code to `#rrggbb`, `null` when the input is
|
|
114
|
+
* not one. Surrounding whitespace is ignored.
|
|
115
|
+
*/
|
|
116
|
+
export function parseHexColor(raw: string): string | null {
|
|
117
|
+
const value = raw.trim();
|
|
118
|
+
if (!HEX_COLOR_PATTERN.test(value)) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const digits = value.replace("#", "").toLowerCase();
|
|
122
|
+
const expanded =
|
|
123
|
+
digits.length === 3 ? [...digits].map((digit) => `${digit}${digit}`).join("") : digits;
|
|
124
|
+
return `#${expanded}`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Normalize a colour to `#rrggbb`, from a hexadecimal code or from one of the
|
|
129
|
+
* {@link BASE_COLOR_NAMES}. `null` for anything else: the refusal belongs to
|
|
130
|
+
* whichever caller asked, so this only reports that it could not read the value.
|
|
131
|
+
*/
|
|
132
|
+
export function parseColor(raw: string): string | null {
|
|
133
|
+
return BASE_COLORS_BY_NORMALIZED_NAME.get(normalizeColorName(raw)) ?? parseHexColor(raw);
|
|
134
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Option, Options } from "@/discord/command/options";
|
|
2
|
+
|
|
3
|
+
type AsRequired<O> = O extends Option<infer V, boolean> ? Option<V, true> : never;
|
|
4
|
+
|
|
5
|
+
/** Turn every option in a record into its required variant. */
|
|
6
|
+
export function allRequired<O extends Options>(fields: O): { [K in keyof O]: AsRequired<O[K]> } {
|
|
7
|
+
const out = {} as { [K in keyof O]: AsRequired<O[K]> };
|
|
8
|
+
for (const [key, option] of Object.entries(fields)) {
|
|
9
|
+
out[key as keyof O] = option.required() as AsRequired<O[keyof O]>;
|
|
10
|
+
}
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Interaction } from "discord.js";
|
|
2
2
|
import type { SlashCommand } from "@/discord/command/types";
|
|
3
3
|
import type { InteractionDispatcher } from "@/discord/interaction/interaction-router";
|
|
4
|
+
import { errorMessage } from "@/errors/error-message";
|
|
4
5
|
import type { Logger } from "@/logger";
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -44,7 +45,7 @@ export class AutocompleteDispatcher implements InteractionDispatcher {
|
|
|
44
45
|
this.logger.error(
|
|
45
46
|
{
|
|
46
47
|
command: interaction.commandName,
|
|
47
|
-
err:
|
|
48
|
+
err: errorMessage(error),
|
|
48
49
|
},
|
|
49
50
|
"Autocomplete handler failed",
|
|
50
51
|
);
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { AutocompleteInteraction } from "discord.js";
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
2
|
+
import { MAX_AUTOCOMPLETE_CHOICES } from "@/discord/command/autocomplete-limits";
|
|
3
|
+
import type { CompiledSubcommand } from "@/discord/command/create-command";
|
|
4
|
+
import type { Options } from "@/discord/command/options";
|
|
5
|
+
import { routeKey } from "@/discord/command/route-key";
|
|
6
|
+
import type { Choice } from "@/settings/choice";
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Serving option autocomplete. Kept beside the DSL because resolving *which*
|
|
@@ -8,9 +11,6 @@ import type { Choice, Options } from "@/discord/command/options";
|
|
|
8
11
|
* dispatcher only decides that an interaction is an autocomplete request.
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
|
-
/** Discord refuses more than this many suggestions in one response. */
|
|
12
|
-
const MAX_CHOICES = 25;
|
|
13
|
-
|
|
14
14
|
/**
|
|
15
15
|
* Answer a focused option's autocomplete request.
|
|
16
16
|
*
|
|
@@ -47,12 +47,13 @@ export async function respondWithSuggestions(
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Discord rejects the whole response when it carries more than
|
|
50
|
+
* Discord rejects the whole response when it carries more than
|
|
51
|
+
* {@link MAX_AUTOCOMPLETE_CHOICES} choices, so a
|
|
51
52
|
* resolver returning more is trimmed rather than failing outright — a partial
|
|
52
53
|
* list is still useful to the user typing.
|
|
53
54
|
*/
|
|
54
55
|
function truncate(choices: readonly Choice[]): Choice[] {
|
|
55
|
-
return choices.slice(0,
|
|
56
|
+
return choices.slice(0, MAX_AUTOCOMPLETE_CHOICES);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
/**
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CommandInteraction } from "discord.js";
|
|
2
|
+
import { sendEmbed } from "@/discord/command/send-embed";
|
|
3
|
+
import type { Presenter } from "@/discord/presenter";
|
|
4
|
+
import type { Locale } from "@/i18n/locale";
|
|
5
|
+
import type { TranslationParams, Translator } from "@/i18n/translator";
|
|
6
|
+
import type { Logger } from "@/logger";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* What every command handler's context offers, whatever kind of command it
|
|
10
|
+
* serves: the reply language, a translate helper bound to it, and responders
|
|
11
|
+
* that route through the injected {@link Presenter}.
|
|
12
|
+
*/
|
|
13
|
+
export interface CommandResponders {
|
|
14
|
+
/** Reply language: user's client locale → guild locale → configured default. */
|
|
15
|
+
readonly locale: Locale;
|
|
16
|
+
/** Translate a catalog key for this interaction's locale. */
|
|
17
|
+
t(key: string, params?: TranslationParams): string;
|
|
18
|
+
confirm(message: string): Promise<void>;
|
|
19
|
+
error(message: string): Promise<void>;
|
|
20
|
+
deny(message: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Bind the shared responders to one interaction, its locale and its visibility. */
|
|
24
|
+
export function createCommandResponders(
|
|
25
|
+
interaction: CommandInteraction,
|
|
26
|
+
locale: Locale,
|
|
27
|
+
ephemeral: boolean,
|
|
28
|
+
deps: { readonly presenter: Presenter; readonly logger: Logger; readonly translator: Translator },
|
|
29
|
+
): CommandResponders {
|
|
30
|
+
const { presenter, logger, translator } = deps;
|
|
31
|
+
return {
|
|
32
|
+
locale,
|
|
33
|
+
t: (key, params) => translator.translate(locale, key, params),
|
|
34
|
+
confirm: (message) =>
|
|
35
|
+
sendEmbed(interaction, presenter.confirmation(message, locale), ephemeral, logger),
|
|
36
|
+
error: (message) => sendEmbed(interaction, presenter.error(message, locale), ephemeral, logger),
|
|
37
|
+
deny: (message) => sendEmbed(interaction, presenter.denial(message, locale), ephemeral, logger),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ChatInputCommandInteraction, EmbedBuilder } from "discord.js";
|
|
2
|
+
import {
|
|
3
|
+
type CommandResponders,
|
|
4
|
+
createCommandResponders,
|
|
5
|
+
} from "@/discord/command/command-responders";
|
|
2
6
|
import type { Options, Values } from "@/discord/command/options";
|
|
7
|
+
import { sendEmbed } from "@/discord/command/send-embed";
|
|
8
|
+
import { interactionLocale } from "@/discord/interaction/interaction-locale";
|
|
3
9
|
import type { Presenter } from "@/discord/presenter";
|
|
4
|
-
import {
|
|
10
|
+
import type { Locale } from "@/i18n/locale";
|
|
11
|
+
import type { Translator } from "@/i18n/translator";
|
|
5
12
|
import type { Logger } from "@/logger";
|
|
6
13
|
|
|
7
14
|
/**
|
|
@@ -10,55 +17,16 @@ import type { Logger } from "@/logger";
|
|
|
10
17
|
* translate helper bound to it, and convenience responders that route through
|
|
11
18
|
* the injected {@link Presenter}.
|
|
12
19
|
*/
|
|
13
|
-
export interface Context<O extends Options> {
|
|
20
|
+
export interface Context<O extends Options> extends CommandResponders {
|
|
14
21
|
readonly interaction: ChatInputCommandInteraction;
|
|
15
22
|
readonly options: Values<O>;
|
|
16
|
-
/** Reply language: user's client locale → guild locale → configured default. */
|
|
17
|
-
readonly locale: Locale;
|
|
18
|
-
/** Translate a catalog key for this interaction's locale. */
|
|
19
|
-
t(key: string, params?: TranslationParams): string;
|
|
20
23
|
reply(embed: EmbedBuilder): Promise<void>;
|
|
21
|
-
confirm(message: string): Promise<void>;
|
|
22
|
-
error(message: string): Promise<void>;
|
|
23
|
-
deny(message: string): Promise<void>;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* must not escape a handler and reach the client's unhandled `error` event,
|
|
30
|
-
* which would crash the process. Visibility on a deferred interaction is fixed
|
|
31
|
-
* at deferReply time, so editReply carries no flags.
|
|
27
|
+
* @param locale - the reply language the pipeline already resolved (through
|
|
28
|
+
* the bot's `LocaleResolver`); omitted, the interaction's own locales are used.
|
|
32
29
|
*/
|
|
33
|
-
export async function sendEmbed(
|
|
34
|
-
interaction: ChatInputCommandInteraction,
|
|
35
|
-
embed: EmbedBuilder,
|
|
36
|
-
ephemeral: boolean,
|
|
37
|
-
logger: Logger,
|
|
38
|
-
): Promise<void> {
|
|
39
|
-
const flags = ephemeral ? MessageFlags.Ephemeral : undefined;
|
|
40
|
-
try {
|
|
41
|
-
if (interaction.deferred) {
|
|
42
|
-
await interaction.editReply({ embeds: [embed] });
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (interaction.replied) {
|
|
46
|
-
await interaction.followUp({ embeds: [embed], flags });
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
await interaction.reply({ embeds: [embed], flags });
|
|
50
|
-
} catch (error) {
|
|
51
|
-
logger.error(
|
|
52
|
-
{
|
|
53
|
-
commandName: interaction.commandName,
|
|
54
|
-
interactionId: interaction.id,
|
|
55
|
-
err: error instanceof Error ? error.message : String(error),
|
|
56
|
-
},
|
|
57
|
-
"Failed to deliver interaction response",
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
30
|
export function createContext<O extends Options>(
|
|
63
31
|
interaction: ChatInputCommandInteraction,
|
|
64
32
|
options: Values<O>,
|
|
@@ -66,20 +34,12 @@ export function createContext<O extends Options>(
|
|
|
66
34
|
presenter: Presenter,
|
|
67
35
|
logger: Logger,
|
|
68
36
|
translator: Translator,
|
|
37
|
+
locale: Locale = interactionLocale(interaction, translator),
|
|
69
38
|
): Context<O> {
|
|
70
|
-
const locale = resolveLocale(
|
|
71
|
-
[interaction.locale, interaction.guildLocale],
|
|
72
|
-
translator.defaultLocale,
|
|
73
|
-
);
|
|
74
39
|
return {
|
|
40
|
+
...createCommandResponders(interaction, locale, ephemeral, { presenter, logger, translator }),
|
|
75
41
|
interaction,
|
|
76
42
|
options,
|
|
77
|
-
locale,
|
|
78
|
-
t: (key, params) => translator.translate(locale, key, params),
|
|
79
43
|
reply: (embed) => sendEmbed(interaction, embed, ephemeral, logger),
|
|
80
|
-
confirm: (message) =>
|
|
81
|
-
sendEmbed(interaction, presenter.confirmation(message, locale), ephemeral, logger),
|
|
82
|
-
error: (message) => sendEmbed(interaction, presenter.error(message, locale), ephemeral, logger),
|
|
83
|
-
deny: (message) => sendEmbed(interaction, presenter.denial(message, locale), ephemeral, logger),
|
|
84
44
|
};
|
|
85
45
|
}
|
|
@@ -2,7 +2,7 @@ import type { CommandInteraction } from "discord.js";
|
|
|
2
2
|
import { type Clock, systemClock } from "@/clock";
|
|
3
3
|
import type { Guard, GuardResult } from "@/discord/command/guard";
|
|
4
4
|
import { CORE_MESSAGES } from "@/discord/i18n";
|
|
5
|
-
import type { LocalizedText } from "@/i18n";
|
|
5
|
+
import type { LocalizedText } from "@/i18n/translator";
|
|
6
6
|
|
|
7
7
|
const ALLOW: GuardResult = { ok: true };
|
|
8
8
|
const MILLISECONDS_PER_SECOND = 1000;
|
|
@@ -7,14 +7,17 @@ import {
|
|
|
7
7
|
type SlashCommandSubcommandBuilder,
|
|
8
8
|
} from "discord.js";
|
|
9
9
|
import { resolveRouteOptions, respondWithSuggestions } from "@/discord/command/autocomplete";
|
|
10
|
-
import { type Context, createContext
|
|
10
|
+
import { type Context, createContext } from "@/discord/command/context";
|
|
11
11
|
import type { Guard } from "@/discord/command/guard";
|
|
12
12
|
import type { Options, Values } from "@/discord/command/options";
|
|
13
|
+
import { passesGuard } from "@/discord/command/passes-guard";
|
|
14
|
+
import { renderCommandFailure } from "@/discord/command/render-command-failure";
|
|
15
|
+
import { routeKey } from "@/discord/command/route-key";
|
|
13
16
|
import type { CommandRuntime, SlashCommand } from "@/discord/command/types";
|
|
14
17
|
import { CORE_MESSAGES } from "@/discord/i18n";
|
|
18
|
+
import { replyLocale } from "@/discord/interaction/reply-locale";
|
|
15
19
|
import { type PermissionBit, resolvePermissions } from "@/discord/permissions";
|
|
16
|
-
import {
|
|
17
|
-
import { type Locale, type LocalizedText, resolveLocale } from "@/i18n";
|
|
20
|
+
import type { LocalizedText } from "@/i18n/translator";
|
|
18
21
|
|
|
19
22
|
export interface SubcommandDef<O extends Options> {
|
|
20
23
|
description: string;
|
|
@@ -117,27 +120,6 @@ interface SubcommandContainer {
|
|
|
117
120
|
): unknown;
|
|
118
121
|
}
|
|
119
122
|
|
|
120
|
-
/** Resolve the reply locale for an interaction handled outside `createContext`. */
|
|
121
|
-
function interactionLocale(
|
|
122
|
-
interaction: ChatInputCommandInteraction,
|
|
123
|
-
runtime: CommandRuntime,
|
|
124
|
-
): Locale {
|
|
125
|
-
return resolveLocale(
|
|
126
|
-
[interaction.locale, interaction.guildLocale],
|
|
127
|
-
runtime.translator.defaultLocale,
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* The key a subcommand is stored and looked up under. Exported because dispatch
|
|
133
|
-
* and autocomplete must agree on it: if they ever built it differently, an
|
|
134
|
-
* autocomplete inside a group would silently resolve to no options instead of
|
|
135
|
-
* failing loudly.
|
|
136
|
-
*/
|
|
137
|
-
export function routeKey(group: string | null, name: string): string {
|
|
138
|
-
return group ? `${group}/${name}` : name;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
123
|
/**
|
|
142
124
|
* The root-level settings, split out of {@link CommandDef} so applying them does
|
|
143
125
|
* not drag the option generic `O` along (a `CommandDef<O>` is not assignable to
|
|
@@ -211,29 +193,6 @@ function ephemeralReplyOptions(ephemeral: boolean): { flags?: MessageFlags.Ephem
|
|
|
211
193
|
return {};
|
|
212
194
|
}
|
|
213
195
|
|
|
214
|
-
/** Run a guard if present; reply with a denial and return `false` when it fails. */
|
|
215
|
-
async function passesGuard(
|
|
216
|
-
interaction: ChatInputCommandInteraction,
|
|
217
|
-
guard: Guard | undefined,
|
|
218
|
-
runtime: CommandRuntime,
|
|
219
|
-
): Promise<boolean> {
|
|
220
|
-
if (!guard) {
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
const result = await guard.check(interaction);
|
|
224
|
-
if (!result.ok) {
|
|
225
|
-
const locale = interactionLocale(interaction, runtime);
|
|
226
|
-
await interaction.reply({
|
|
227
|
-
embeds: [
|
|
228
|
-
runtime.presenter.denial(runtime.translator.resolve(locale, result.message), locale),
|
|
229
|
-
],
|
|
230
|
-
flags: MessageFlags.Ephemeral,
|
|
231
|
-
});
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
return true;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
196
|
/** Read options, optionally defer, build the context and invoke the handler. */
|
|
238
197
|
async function executeRoute(
|
|
239
198
|
interaction: ChatInputCommandInteraction,
|
|
@@ -254,10 +213,21 @@ async function executeRoute(
|
|
|
254
213
|
presenter,
|
|
255
214
|
logger,
|
|
256
215
|
translator,
|
|
216
|
+
await replyLocale(interaction, runtime),
|
|
257
217
|
);
|
|
258
218
|
await route.invoke(ctx);
|
|
259
219
|
} catch (error) {
|
|
260
|
-
await
|
|
220
|
+
await renderCommandFailure(
|
|
221
|
+
interaction,
|
|
222
|
+
{
|
|
223
|
+
error,
|
|
224
|
+
ephemeral: route.ephemeral,
|
|
225
|
+
fallbackError: route.fallbackError,
|
|
226
|
+
logFields: { subcommand: label },
|
|
227
|
+
logMessage: "Command handler failed",
|
|
228
|
+
},
|
|
229
|
+
runtime,
|
|
230
|
+
);
|
|
261
231
|
}
|
|
262
232
|
}
|
|
263
233
|
|
|
@@ -284,7 +254,7 @@ async function dispatchGrouped(
|
|
|
284
254
|
const route = routes.get(label);
|
|
285
255
|
|
|
286
256
|
if (!route) {
|
|
287
|
-
const locale =
|
|
257
|
+
const locale = await replyLocale(interaction, runtime);
|
|
288
258
|
await interaction.reply({
|
|
289
259
|
embeds: [
|
|
290
260
|
runtime.presenter.error(
|
|
@@ -303,51 +273,6 @@ async function dispatchGrouped(
|
|
|
303
273
|
await executeRoute(interaction, route, label, runtime);
|
|
304
274
|
}
|
|
305
275
|
|
|
306
|
-
async function renderError(
|
|
307
|
-
interaction: ChatInputCommandInteraction,
|
|
308
|
-
route: CompiledSubcommand,
|
|
309
|
-
label: string,
|
|
310
|
-
error: unknown,
|
|
311
|
-
runtime: CommandRuntime,
|
|
312
|
-
): Promise<void> {
|
|
313
|
-
const { presenter, logger, translator } = runtime;
|
|
314
|
-
const locale = interactionLocale(interaction, runtime);
|
|
315
|
-
if (error instanceof BusinessError) {
|
|
316
|
-
const text = error.translation
|
|
317
|
-
? translator.translate(locale, error.translation.key, error.translation.params)
|
|
318
|
-
: error.message;
|
|
319
|
-
const embed =
|
|
320
|
-
error.severity === "warning"
|
|
321
|
-
? presenter.warning(text, locale)
|
|
322
|
-
: presenter.error(text, locale);
|
|
323
|
-
await sendEmbed(interaction, embed, route.ephemeral, logger);
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
const ref = createIncidentRef();
|
|
328
|
-
logger.error(
|
|
329
|
-
{
|
|
330
|
-
command: interaction.commandName,
|
|
331
|
-
subcommand: label,
|
|
332
|
-
userId: interaction.user.id,
|
|
333
|
-
ref,
|
|
334
|
-
err: error instanceof Error ? error.message : String(error),
|
|
335
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
336
|
-
},
|
|
337
|
-
"Command handler failed",
|
|
338
|
-
);
|
|
339
|
-
await sendEmbed(
|
|
340
|
-
interaction,
|
|
341
|
-
presenter.systemError(
|
|
342
|
-
translator.resolve(locale, route.fallbackError ?? { key: CORE_MESSAGES.genericError }),
|
|
343
|
-
ref,
|
|
344
|
-
locale,
|
|
345
|
-
),
|
|
346
|
-
route.ephemeral,
|
|
347
|
-
logger,
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
276
|
/**
|
|
352
277
|
* Build a {@link SlashCommand} from a declarative definition: it produces the
|
|
353
278
|
* discord.js builder *and* the routing/guard/error pipeline. The runtime
|
|
@@ -2,21 +2,24 @@ import {
|
|
|
2
2
|
ApplicationCommandType,
|
|
3
3
|
ContextMenuCommandBuilder,
|
|
4
4
|
type ContextMenuCommandInteraction,
|
|
5
|
-
type EmbedBuilder,
|
|
6
5
|
InteractionContextType,
|
|
7
6
|
type LocalizationMap,
|
|
8
7
|
type Message,
|
|
9
8
|
MessageFlags,
|
|
10
9
|
type User,
|
|
11
10
|
} from "discord.js";
|
|
11
|
+
import {
|
|
12
|
+
type CommandResponders,
|
|
13
|
+
createCommandResponders,
|
|
14
|
+
} from "@/discord/command/command-responders";
|
|
12
15
|
import { ContextMenuTargetError } from "@/discord/command/errors";
|
|
13
16
|
import type { Guard } from "@/discord/command/guard";
|
|
17
|
+
import { passesGuard } from "@/discord/command/passes-guard";
|
|
18
|
+
import { renderCommandFailure } from "@/discord/command/render-command-failure";
|
|
14
19
|
import type { CommandRuntime, ContextMenuCommand } from "@/discord/command/types";
|
|
15
|
-
import {
|
|
20
|
+
import { replyLocale } from "@/discord/interaction/reply-locale";
|
|
16
21
|
import { type PermissionBit, resolvePermissions } from "@/discord/permissions";
|
|
17
|
-
import {
|
|
18
|
-
import { type Locale, type LocalizedText, resolveLocale, type TranslationParams } from "@/i18n";
|
|
19
|
-
import type { Logger } from "@/logger";
|
|
22
|
+
import type { LocalizedText } from "@/i18n/translator";
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Context-menu commands: the entries a user reaches by right-clicking a member
|
|
@@ -35,17 +38,10 @@ export interface ContextMenuTarget {
|
|
|
35
38
|
readonly message: Message;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
export interface ContextMenuContext<K extends keyof ContextMenuTarget> {
|
|
41
|
+
export interface ContextMenuContext<K extends keyof ContextMenuTarget> extends CommandResponders {
|
|
39
42
|
readonly interaction: ContextMenuCommandInteraction;
|
|
40
43
|
/** The right-clicked member or message. */
|
|
41
44
|
readonly target: ContextMenuTarget[K];
|
|
42
|
-
/** Reply language: user's client locale → guild locale → configured default. */
|
|
43
|
-
readonly locale: Locale;
|
|
44
|
-
/** Translate a catalog key for this interaction's locale. */
|
|
45
|
-
t(key: string, params?: TranslationParams): string;
|
|
46
|
-
confirm(message: string): Promise<void>;
|
|
47
|
-
error(message: string): Promise<void>;
|
|
48
|
-
deny(message: string): Promise<void>;
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
export interface ContextMenuCommandDef<K extends keyof ContextMenuTarget> {
|
|
@@ -124,104 +120,30 @@ async function dispatch<K extends keyof ContextMenuTarget>(
|
|
|
124
120
|
ephemeral: boolean,
|
|
125
121
|
runtime: CommandRuntime,
|
|
126
122
|
): Promise<void> {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
[interaction.locale, interaction.guildLocale],
|
|
130
|
-
translator.defaultLocale,
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
if (def.guard) {
|
|
134
|
-
const result = await def.guard.check(interaction);
|
|
135
|
-
if (!result.ok) {
|
|
136
|
-
await interaction.reply({
|
|
137
|
-
embeds: [presenter.denial(translator.resolve(locale, result.message), locale)],
|
|
138
|
-
flags: MessageFlags.Ephemeral,
|
|
139
|
-
});
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
123
|
+
if (!(await passesGuard(interaction, def.guard, runtime))) {
|
|
124
|
+
return;
|
|
142
125
|
}
|
|
126
|
+
const locale = await replyLocale(interaction, runtime);
|
|
143
127
|
|
|
144
128
|
try {
|
|
145
129
|
if (def.defer) {
|
|
146
130
|
await interaction.deferReply(ephemeral ? { flags: MessageFlags.Ephemeral } : {});
|
|
147
131
|
}
|
|
148
132
|
await def.handler({
|
|
133
|
+
...createCommandResponders(interaction, locale, ephemeral, runtime),
|
|
149
134
|
interaction,
|
|
150
135
|
target: resolveTarget(interaction, def.target),
|
|
151
|
-
locale,
|
|
152
|
-
t: (key, params) => translator.translate(locale, key, params),
|
|
153
|
-
confirm: (message) =>
|
|
154
|
-
send(interaction, presenter.confirmation(message, locale), ephemeral, logger),
|
|
155
|
-
error: (message) => send(interaction, presenter.error(message, locale), ephemeral, logger),
|
|
156
|
-
deny: (message) => send(interaction, presenter.denial(message, locale), ephemeral, logger),
|
|
157
136
|
});
|
|
158
137
|
} catch (error) {
|
|
159
|
-
|
|
160
|
-
const text = error.translation
|
|
161
|
-
? translator.translate(locale, error.translation.key, error.translation.params)
|
|
162
|
-
: error.message;
|
|
163
|
-
const embed =
|
|
164
|
-
error.severity === "warning"
|
|
165
|
-
? presenter.warning(text, locale)
|
|
166
|
-
: presenter.error(text, locale);
|
|
167
|
-
await send(interaction, embed, ephemeral, logger);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const ref = createIncidentRef();
|
|
171
|
-
logger.error(
|
|
172
|
-
{
|
|
173
|
-
command: interaction.commandName,
|
|
174
|
-
userId: interaction.user.id,
|
|
175
|
-
ref,
|
|
176
|
-
err: error instanceof Error ? error.message : String(error),
|
|
177
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
178
|
-
},
|
|
179
|
-
"Context menu handler failed",
|
|
180
|
-
);
|
|
181
|
-
await send(
|
|
138
|
+
await renderCommandFailure(
|
|
182
139
|
interaction,
|
|
183
|
-
presenter.systemError(
|
|
184
|
-
translator.resolve(locale, def.fallbackError ?? { key: CORE_MESSAGES.genericError }),
|
|
185
|
-
ref,
|
|
186
|
-
locale,
|
|
187
|
-
),
|
|
188
|
-
ephemeral,
|
|
189
|
-
logger,
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Deliver an embed whatever the interaction's lifecycle state, and never throw:
|
|
196
|
-
* a failed delivery (e.g. an expired interaction) must not escape into the
|
|
197
|
-
* client's unhandled `error` event. Mirrors the command pipeline's `sendEmbed`,
|
|
198
|
-
* which is typed for chat-input interactions only.
|
|
199
|
-
*/
|
|
200
|
-
async function send(
|
|
201
|
-
interaction: ContextMenuCommandInteraction,
|
|
202
|
-
embed: EmbedBuilder,
|
|
203
|
-
ephemeral: boolean,
|
|
204
|
-
logger: Logger,
|
|
205
|
-
): Promise<void> {
|
|
206
|
-
const flags = ephemeral ? MessageFlags.Ephemeral : undefined;
|
|
207
|
-
try {
|
|
208
|
-
if (interaction.deferred) {
|
|
209
|
-
await interaction.editReply({ embeds: [embed] });
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
if (interaction.replied) {
|
|
213
|
-
await interaction.followUp({ embeds: [embed], flags });
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
await interaction.reply({ embeds: [embed], flags });
|
|
217
|
-
} catch (error) {
|
|
218
|
-
logger.error(
|
|
219
140
|
{
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
141
|
+
error,
|
|
142
|
+
ephemeral,
|
|
143
|
+
fallbackError: def.fallbackError,
|
|
144
|
+
logMessage: "Context menu handler failed",
|
|
223
145
|
},
|
|
224
|
-
|
|
146
|
+
runtime,
|
|
225
147
|
);
|
|
226
148
|
}
|
|
227
149
|
}
|