@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/README.md
CHANGED
|
@@ -51,6 +51,300 @@ import { type Catalog, createTranslator } from "@azurioh/discord-kernel/i18n";
|
|
|
51
51
|
- **A palette.** Embeds render in Discord's blurple until you say otherwise, so a
|
|
52
52
|
bot never starts out wearing someone else's identity.
|
|
53
53
|
|
|
54
|
+
## Module settings
|
|
55
|
+
|
|
56
|
+
A module declares its per-guild settings once. The kernel then validates,
|
|
57
|
+
stores, caches and reads them, and builds the Discord settings screen, the
|
|
58
|
+
autocomplete suggestions and a JSON Schema for other surfaces (a web
|
|
59
|
+
dashboard) from that single declaration. Everything lives behind two entry
|
|
60
|
+
points: `@azurioh/discord-kernel/settings` and, for tests,
|
|
61
|
+
`@azurioh/discord-kernel/settings/testing`.
|
|
62
|
+
|
|
63
|
+
### Declaring settings
|
|
64
|
+
|
|
65
|
+
Every text is a catalog key (with an English source), never a literal:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { defineSettings, field } from "@azurioh/discord-kernel/settings";
|
|
69
|
+
|
|
70
|
+
export const tickets = defineSettings({
|
|
71
|
+
id: "tickets",
|
|
72
|
+
version: 1,
|
|
73
|
+
labels: { title: "tickets.settings.title" },
|
|
74
|
+
groups: { routing: { label: "tickets.settings.routing" } },
|
|
75
|
+
fields: {
|
|
76
|
+
channel: field.channel({ label: "tickets.channel", types: ["text"], required: true, ui: { group: "routing" } }),
|
|
77
|
+
staffRole: field.role({ label: "tickets.staff-role", ui: { group: "routing" } }),
|
|
78
|
+
maxOpen: field.integer({ label: "tickets.max-open", min: 1, max: 10, default: 3 }),
|
|
79
|
+
cooldown: field.duration({ label: "tickets.cooldown", default: 300 }), // seconds, typed as `5m`
|
|
80
|
+
mode: field.enum({
|
|
81
|
+
label: "tickets.mode",
|
|
82
|
+
choices: [
|
|
83
|
+
{ value: "open", label: "tickets.mode.open" },
|
|
84
|
+
{ value: "closed", label: "tickets.mode.closed" },
|
|
85
|
+
],
|
|
86
|
+
default: "open",
|
|
87
|
+
}),
|
|
88
|
+
apiKey: field.secret({ label: "tickets.api-key" }),
|
|
89
|
+
pingRoles: field.list(field.role(), { label: "tickets.ping-roles", maxItems: 5, default: [] }),
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Field kinds: `text`, `integer`, `number`, `boolean`, `enum`, `color`,
|
|
95
|
+
`duration`, `channel`, `role`, `user`, `secret`, `list` and `toggles`. Give the
|
|
96
|
+
declarations to a `BotModule` (`settings: [tickets]`), then build the registry
|
|
97
|
+
and the service once, in the composition root:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { createDiscordGuildDirectory } from "@azurioh/discord-kernel/discord/settings/discord-guild-directory";
|
|
101
|
+
import {
|
|
102
|
+
createInProcessNotifier,
|
|
103
|
+
createSettingsRegistry,
|
|
104
|
+
createSettingsService,
|
|
105
|
+
SETTINGS_CATALOG,
|
|
106
|
+
} from "@azurioh/discord-kernel/settings";
|
|
107
|
+
|
|
108
|
+
translations.register(SETTINGS_CATALOG); // with CORE_CATALOG and every module's catalog
|
|
109
|
+
const registry = createSettingsRegistry({
|
|
110
|
+
declarations: modules.flatMap((module) => module.settings ?? []),
|
|
111
|
+
translations, // a key without an English source fails the boot, as does a duplicate id
|
|
112
|
+
modules, // builds the module toggles, see "System settings"
|
|
113
|
+
});
|
|
114
|
+
const settings = createSettingsService({
|
|
115
|
+
registry,
|
|
116
|
+
store, // your SettingsStore adapter, see "Storage adapters"
|
|
117
|
+
guilds: createDiscordGuildDirectory(client),
|
|
118
|
+
notifier: createInProcessNotifier(logger),
|
|
119
|
+
translator,
|
|
120
|
+
clock: systemClock,
|
|
121
|
+
logger,
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Reading and writing
|
|
126
|
+
|
|
127
|
+
Values are typed from the declaration: a required field or a field with a
|
|
128
|
+
default is never `undefined`, a mistyped key fails to compile.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const values = await settings.get(tickets, guildId); // cached; defaults for unset fields
|
|
132
|
+
values.maxOpen; // number
|
|
133
|
+
values.staffRole; // string | undefined
|
|
134
|
+
|
|
135
|
+
const ctx = { guildId, userId, locale }; // who writes, where, in which language
|
|
136
|
+
await settings.validate(tickets, guildId, { maxOpen: 50 }, ctx); // { ok: false, issues: [{ field: "maxOpen", code: "max", ... }] }
|
|
137
|
+
await settings.set(tickets, guildId, { maxOpen: 5, staffRole: null }, ctx); // null unsets a field
|
|
138
|
+
await settings.reset(tickets, guildId, ["maxOpen"], ctx); // or "all"
|
|
139
|
+
const { missing } = await settings.status(tickets, guildId); // required fields left unset
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`set` stores nothing unless every submitted field is valid, and throws a
|
|
143
|
+
`SettingsValidationError` listing all the issues. Two writers holding the same
|
|
144
|
+
`expectedRevision` cannot both win: the second gets a `ConflictError`. Every
|
|
145
|
+
write invalidates the cache and emits a `settings.changed` event through the
|
|
146
|
+
notifier. Module logic reads secrets with `get`; surfaces use `getForSurface`,
|
|
147
|
+
where a secret is only `{ isSet }`.
|
|
148
|
+
|
|
149
|
+
### The Discord settings screen
|
|
150
|
+
|
|
151
|
+
`settingsEditorFromDeclaration` turns a declaration into the options of
|
|
152
|
+
`mountSettingsEditor`: one control per field kind, groups split into modals of
|
|
153
|
+
at most 5 inputs, nested levels so a card never exceeds Discord's component
|
|
154
|
+
budget, and every save sent through `service.set`, so the screen accepts and
|
|
155
|
+
refuses exactly what the service does.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import {
|
|
159
|
+
editorComponentIds,
|
|
160
|
+
mountSettingsEditor,
|
|
161
|
+
settingsEditorFromDeclaration,
|
|
162
|
+
} from "@azurioh/discord-kernel/discord/components/settings-editor";
|
|
163
|
+
|
|
164
|
+
const adapted = await settingsEditorFromDeclaration(tickets, settings, {
|
|
165
|
+
guildId,
|
|
166
|
+
userId,
|
|
167
|
+
locale: ctx.locale,
|
|
168
|
+
translator,
|
|
169
|
+
});
|
|
170
|
+
await mountSettingsEditor(ctx.interaction, {
|
|
171
|
+
...adapted,
|
|
172
|
+
ids: editorComponentIds("tickets-settings"),
|
|
173
|
+
chrome, // your title and colours
|
|
174
|
+
translator,
|
|
175
|
+
locale: ctx.locale,
|
|
176
|
+
clock: systemClock,
|
|
177
|
+
logger,
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Describing settings for other surfaces
|
|
182
|
+
|
|
183
|
+
`settings.describe(declaration, locale)` returns a JSON Schema (draft 2020-12)
|
|
184
|
+
with every label and description translated (English for an unsupported
|
|
185
|
+
locale), and kernel hints (kind, group, order, secret) under `x-kernel`. A
|
|
186
|
+
secret's value is never in it. A web dashboard renders its form from this and
|
|
187
|
+
writes through the same `set`.
|
|
188
|
+
|
|
189
|
+
### Suggestions and strict fields
|
|
190
|
+
|
|
191
|
+
A field can offer suggestions, static or searched:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
timezone: field.text({
|
|
195
|
+
label: "tickets.timezone",
|
|
196
|
+
suggest: { resolve: searchTimezones, label: timezoneLabel, strict: true },
|
|
197
|
+
}),
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`settings.suggest(declaration, key, query, { ...ctx, values })` returns at most
|
|
201
|
+
25 `Choice`s in the command autocomplete's own format, so one search serves
|
|
202
|
+
`/config set` and the settings screen (where a searchable field becomes a
|
|
203
|
+
select). Channel, role and user fields search the guild without any code. A
|
|
204
|
+
search slower than 2.5 s (`SUGGESTION_TIMEOUT_MS`) or failing yields nothing
|
|
205
|
+
and is logged. `settings.label(...)` gives a stored value's readable name. A
|
|
206
|
+
**strict** field accepts only a value its search knows; anything else is an
|
|
207
|
+
`unknownChoice` issue.
|
|
208
|
+
|
|
209
|
+
### System settings: module toggles and guild language
|
|
210
|
+
|
|
211
|
+
The kernel declares its own settings like any module (`registry.kernel`): which
|
|
212
|
+
modules are enabled on the guild (`defaultEnabled` on a `BotModule`, `true`
|
|
213
|
+
unless said otherwise) and the bot's language there. Pass a `ModuleGate` to the
|
|
214
|
+
routers and each gated handler is skipped on a guild that disabled its module,
|
|
215
|
+
with a translated reply for commands and components:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import { createModuleGate } from "@azurioh/discord-kernel/settings";
|
|
219
|
+
|
|
220
|
+
const gate = createModuleGate({ service: settings, registry, logger });
|
|
221
|
+
const commands = new CommandRouter({ presenter, logger, translator, gate, localeResolver });
|
|
222
|
+
const components = new ComponentRouter({ presenter, logger, translator, gate, localeResolver });
|
|
223
|
+
const events = new EventRouter(logger, gate);
|
|
224
|
+
commands.registerAll(module.commands ?? [], module.name); // no name: never gated
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Scheduled jobs call `gate.isEnabled(moduleName, guildId)` themselves. The guild
|
|
228
|
+
language reaches every reply through the `LocaleResolver` port, described in
|
|
229
|
+
[Per-guild values](#per-guild-values).
|
|
230
|
+
|
|
231
|
+
### Blocking a command until its module is configured
|
|
232
|
+
|
|
233
|
+
`requireConfigured(declaration, service)` is a guard for a command or a
|
|
234
|
+
component handler. It denies while a required field is unset, and lets the call
|
|
235
|
+
through as soon as it is set, without a restart. Members with *Manage Server*
|
|
236
|
+
also read which settings are missing.
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import { requireConfigured } from "@azurioh/discord-kernel/discord/settings/require-configured";
|
|
240
|
+
|
|
241
|
+
createCommand({ name: "ticket", guard: requireConfigured(tickets, settings), handler });
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Evolving module settings
|
|
245
|
+
|
|
246
|
+
Adding a field needs nothing: guilds configured before read its default.
|
|
247
|
+
Removing one needs nothing either: its stored value is ignored and dropped on
|
|
248
|
+
the next write. To reshape stored values (rename a key, change a unit), raise
|
|
249
|
+
the declaration's `version` and give it a `migrate`:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
export const warnings = defineSettings({
|
|
253
|
+
id: "warnings",
|
|
254
|
+
version: 2, // was 1: `maxWarnings` became `warnLimit`
|
|
255
|
+
migrate: (fromVersion, raw) => {
|
|
256
|
+
if (fromVersion !== 1) throw new Error(`no migration from version ${fromVersion}`);
|
|
257
|
+
const { maxWarnings, ...rest } = raw as Record<string, unknown>;
|
|
258
|
+
return maxWarnings === undefined ? rest : { ...rest, warnLimit: maxWarnings };
|
|
259
|
+
},
|
|
260
|
+
labels: { title: "warnings.title" },
|
|
261
|
+
fields: { warnLimit: field.integer({ label: "warnings.limit", min: 1, max: 10, default: 3 }) },
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Migration is lazy: the first read of a guild's older record runs `migrate`,
|
|
266
|
+
validates the result like any stored value, and writes it back once under the
|
|
267
|
+
new version (a concurrent reader on another shard loses the compare-and-set and
|
|
268
|
+
simply reads the migrated record). `set` and `reset` migrate first too. Rules for
|
|
269
|
+
`migrate`:
|
|
270
|
+
|
|
271
|
+
- **Pure.** It receives a copy of the stored values and returns the new ones;
|
|
272
|
+
no I/O, no clock, no randomness.
|
|
273
|
+
- **Every older version.** A guild may skip releases, so `fromVersion` can be
|
|
274
|
+
any version below the current one. Chain the steps (v1 → v2 → v3) or throw
|
|
275
|
+
for a version you no longer support.
|
|
276
|
+
- **Failures are safe.** When it throws or its result fails validation, nothing
|
|
277
|
+
is written, the error is logged with the guild, module and versions, and the
|
|
278
|
+
guild reads defaults for the fields it cannot read. A record written by a
|
|
279
|
+
newer version (after a rollback) is read but never overwritten.
|
|
280
|
+
|
|
281
|
+
### Storage adapters
|
|
282
|
+
|
|
283
|
+
Settings persistence is hexagonal: the kernel declares the `SettingsStore` port
|
|
284
|
+
and never imports a database driver. Each database sits behind an adapter your
|
|
285
|
+
bot owns, and the composition root picks one at boot.
|
|
286
|
+
|
|
287
|
+
```mermaid
|
|
288
|
+
flowchart LR
|
|
289
|
+
service["SettingsService (kernel)"] --> port(["SettingsStore port"])
|
|
290
|
+
port -.implemented by.-> memory["createInMemorySettingsStore (kernel, tests)"]
|
|
291
|
+
port -.implemented by.-> json["JSON file adapter (your bot)"]
|
|
292
|
+
port -.implemented by.-> sql["SQLite / Postgres adapter (your bot)"]
|
|
293
|
+
port -.implemented by.-> other["MongoDB / Redis adapter (your bot)"]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
The port has three methods: `read`, `write` and `delete`. It stores one
|
|
297
|
+
`StoredSettings` record per `(guildId, moduleId)`, and every field of a record
|
|
298
|
+
is JSON-serialisable. An adapter must honour these guarantees:
|
|
299
|
+
|
|
300
|
+
| Guarantee | Meaning |
|
|
301
|
+
| --------- | ------- |
|
|
302
|
+
| A missing record reads as `null` | `read` returns `null` until the first write and after a delete |
|
|
303
|
+
| Atomic compare-and-set | `write` lands only if the stored revision equals `expectedRevision` (`null` means no record yet), checked and applied in one atomic step, so of two writers holding the same revision exactly one wins |
|
|
304
|
+
| Conflicts change nothing | A mismatch throws the kernel's `ConflictError` and leaves the stored record as it was. Any other failure is thrown as it is, never as a conflict |
|
|
305
|
+
| Isolation | One `(guildId, moduleId)` never reads, overwrites or deletes another |
|
|
306
|
+
| Idempotent delete | Deleting a missing record succeeds |
|
|
307
|
+
| Independent copies | The store keeps no reference to the record it was given and hands out none it keeps |
|
|
308
|
+
| Faithful round-trip | `read` returns a record equal to the one written (JSON values, `updatedBy` absent stays absent) |
|
|
309
|
+
|
|
310
|
+
#### Writing an adapter for any database
|
|
311
|
+
|
|
312
|
+
The only hard part is the compare-and-set. Use the native primitive that checks
|
|
313
|
+
and writes in one step, never a read followed by a write:
|
|
314
|
+
|
|
315
|
+
- **SQL (Postgres, MySQL, SQLite):** a table keyed `(guild_id, module_id)`. A create
|
|
316
|
+
is `INSERT ... ON CONFLICT DO NOTHING` and an update is
|
|
317
|
+
`UPDATE ... WHERE guild_id = ? AND module_id = ? AND revision = ?`. Zero affected
|
|
318
|
+
rows means `ConflictError`. The sandbox bot's `src/shared/settings/sqlite/` is a
|
|
319
|
+
worked example.
|
|
320
|
+
- **MongoDB:** one document per key with a unique index on `{ guildId, moduleId }`.
|
|
321
|
+
An update is `findOneAndUpdate({ guildId, moduleId, revision: expected }, { $set: record })`,
|
|
322
|
+
where no match means a conflict. A create is `insertOne`, where a duplicate-key error
|
|
323
|
+
(code 11000) means a conflict.
|
|
324
|
+
- **Redis:** one key per record. Either `WATCH key`, `GET`, compare, then
|
|
325
|
+
`MULTI`/`SET`/`EXEC`, where a nil `EXEC` means a conflict, or a Lua script that
|
|
326
|
+
compares the stored revision and sets the key atomically.
|
|
327
|
+
|
|
328
|
+
Then prove the adapter with the contract suite. It is runner-agnostic: pass it
|
|
329
|
+
your runner's `describe`, `it` and `expect`, and a factory that returns an empty store:
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
// tests/postgres-settings-store.test.ts
|
|
333
|
+
import { runSettingsStoreContract } from "@azurioh/discord-kernel/settings/testing";
|
|
334
|
+
import { afterAll, describe, expect, it } from "vitest";
|
|
335
|
+
import { createPostgresSettingsStore } from "../src/postgres-settings-store";
|
|
336
|
+
import { createTestDatabase } from "./support/test-database";
|
|
337
|
+
|
|
338
|
+
const database = await createTestDatabase(); // one fresh schema per run
|
|
339
|
+
afterAll(() => database.drop());
|
|
340
|
+
|
|
341
|
+
runSettingsStoreContract(() => createPostgresSettingsStore(database.freshTable()), { describe, it, expect });
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Every guarantee in the table has a case in the suite, including two concurrent
|
|
345
|
+
writers with the same revision. The kernel's own `createInMemorySettingsStore`
|
|
346
|
+
passes the same suite and is the store to use in tests.
|
|
347
|
+
|
|
54
348
|
## Making it yours
|
|
55
349
|
|
|
56
350
|
Two things are global by nature — a bot has one look, decided once — and are set
|
|
@@ -58,7 +352,7 @@ from the composition root before any module is constructed:
|
|
|
58
352
|
|
|
59
353
|
```ts
|
|
60
354
|
import { configureEmbedColors } from "@azurioh/discord-kernel/discord/ui/colors";
|
|
61
|
-
import { registerColorAliases } from "@azurioh/discord-kernel/discord/ui/color-
|
|
355
|
+
import { registerColorAliases } from "@azurioh/discord-kernel/discord/ui/color-aliases";
|
|
62
356
|
|
|
63
357
|
configureEmbedColors({ brand: 0xf3c909 });
|
|
64
358
|
registerColorAliases({ gold: "#f3c909", or: "#f3c909" });
|
|
@@ -67,6 +361,29 @@ registerColorAliases({ gold: "#f3c909", or: "#f3c909" });
|
|
|
67
361
|
Everything else is injected: your modules are factories receiving a container
|
|
68
362
|
you define, so nothing in the kernel is reachable as a singleton.
|
|
69
363
|
|
|
364
|
+
## Per-guild values
|
|
365
|
+
|
|
366
|
+
A value the kernel uses when it answers an interaction is read through a
|
|
367
|
+
resolver port, per guild, never from a global. The bot passes a default
|
|
368
|
+
implementation built from its own configuration, and any module can replace it
|
|
369
|
+
with its own. Today that value is the reply language:
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
import { createGuildLocaleResolver } from "@azurioh/discord-kernel/discord/settings/guild-locale-resolver";
|
|
373
|
+
|
|
374
|
+
// Member locale → guild language setting → guild Discord locale → translator default.
|
|
375
|
+
const localeResolver = createGuildLocaleResolver({ service: settings, registry, translator });
|
|
376
|
+
const commands = new CommandRouter({ presenter, logger, translator, localeResolver });
|
|
377
|
+
const components = new ComponentRouter({ presenter, logger, translator, localeResolver });
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Any object implementing `LocaleResolver`
|
|
381
|
+
(`@azurioh/discord-kernel/discord/interaction/locale-resolver`) fits:
|
|
382
|
+
`{ resolve({ locale, guildLocale, guildId }) => Promise<Locale> }`. Without one,
|
|
383
|
+
the routers keep the interaction's own locales, so a bot without settings is
|
|
384
|
+
unaffected. A resolver that throws is logged and the interaction's own locales
|
|
385
|
+
are used.
|
|
386
|
+
|
|
70
387
|
## Requirements
|
|
71
388
|
|
|
72
389
|
Node 22.12+, discord.js 14.27+, TypeScript 5.9. The published build is
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BaseInteraction } from "discord.js";
|
|
2
2
|
import type { Authorizer, PermissionLevel } from "../authz/authorizer";
|
|
3
3
|
import type { Guard } from "../discord/command/guard";
|
|
4
|
-
import type { LocalizedText } from "../i18n";
|
|
4
|
+
import type { LocalizedText } from "../i18n/translator";
|
|
5
5
|
/**
|
|
6
6
|
* Role IDs held by the interacting member, resolved without a network call:
|
|
7
7
|
* `interaction.member.roles` is either the cached `GuildMemberRoleManager` (a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"require-level-guard.d.ts","sourceRoot":"","sources":["../../src/authz/require-level-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"require-level-guard.d.ts","sourceRoot":"","sources":["../../src/authz/require-level-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,eAAe,GAAG,MAAM,EAAE,CAOpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,aAAa,GACxB,KAAK,CAOP"}
|
package/dist/color.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discord's own brand colour. Kept with the base names rather than in the
|
|
3
|
+
* Discord ring so a `blurple` setting means the same colour on every surface,
|
|
4
|
+
* and so embeds fall back to it when a bot declares no palette.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DISCORD_BLURPLE = "#5865f2";
|
|
7
|
+
/**
|
|
8
|
+
* Colour names an administrator may type instead of a hex code, French and
|
|
9
|
+
* English side by side.
|
|
10
|
+
*
|
|
11
|
+
* This table is **input vocabulary, not display text**. Nothing in it is ever
|
|
12
|
+
* shown to anyone, and its keys must never be translated at runtime: a catalog
|
|
13
|
+
* lookup resolves against the reply locale, which would make `rouge` stop
|
|
14
|
+
* working the moment an admin's Discord is set to English — the opposite of the
|
|
15
|
+
* point. Both spellings are accepted from everyone, always, which only a flat
|
|
16
|
+
* table can promise.
|
|
17
|
+
*
|
|
18
|
+
* Fixed on purpose: a value stored from one of these names must mean the same
|
|
19
|
+
* colour in every bot. Names a bot adds for its own inputs live with those
|
|
20
|
+
* inputs, not here.
|
|
21
|
+
*/
|
|
22
|
+
export declare const BASE_COLOR_NAMES: Readonly<Record<string, string>>;
|
|
23
|
+
/**
|
|
24
|
+
* Accents must not be a trap: `dore` and `doré` are the same request, and an
|
|
25
|
+
* administrator has no way of knowing which one a table happened to spell.
|
|
26
|
+
* Case and surrounding whitespace are folded for the same reason.
|
|
27
|
+
*/
|
|
28
|
+
export declare function normalizeColorName(raw: string): string;
|
|
29
|
+
/** Index a name → `#rrggbb` table by {@link normalizeColorName}, so lookups fold case and accents. */
|
|
30
|
+
export declare function indexColorNames(names: Readonly<Record<string, string>>): Map<string, string>;
|
|
31
|
+
/**
|
|
32
|
+
* Normalize a hexadecimal colour code to `#rrggbb`, `null` when the input is
|
|
33
|
+
* not one. Surrounding whitespace is ignored.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseHexColor(raw: string): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* Normalize a colour to `#rrggbb`, from a hexadecimal code or from one of the
|
|
38
|
+
* {@link BASE_COLOR_NAMES}. `null` for anything else: the refusal belongs to
|
|
39
|
+
* whichever caller asked, so this only reports that it could not read the value.
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseColor(raw: string): string | null;
|
|
42
|
+
//# sourceMappingURL=color.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,eAAO,MAAM,eAAe,YAAY,CAAC;AAiBzC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkC7D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMtD;AAED,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAE5F;AAQD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASxD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAErD"}
|
package/dist/color.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BASE_COLOR_NAMES = exports.DISCORD_BLURPLE = void 0;
|
|
4
|
+
exports.normalizeColorName = normalizeColorName;
|
|
5
|
+
exports.indexColorNames = indexColorNames;
|
|
6
|
+
exports.parseHexColor = parseHexColor;
|
|
7
|
+
exports.parseColor = parseColor;
|
|
8
|
+
/**
|
|
9
|
+
* The generic web colours, at the value the name carries everywhere else — an
|
|
10
|
+
* administrator typing `orange` gets the orange they would get in CSS, not a
|
|
11
|
+
* shade this module invented.
|
|
12
|
+
*/
|
|
13
|
+
const RED = "#ff0000";
|
|
14
|
+
const BLUE = "#0000ff";
|
|
15
|
+
const GREEN = "#008000";
|
|
16
|
+
const YELLOW = "#ffff00";
|
|
17
|
+
const ORANGE = "#ffa500";
|
|
18
|
+
const PURPLE = "#800080";
|
|
19
|
+
const PINK = "#ffc0cb";
|
|
20
|
+
const WHITE = "#ffffff";
|
|
21
|
+
/**
|
|
22
|
+
* Discord's own brand colour. Kept with the base names rather than in the
|
|
23
|
+
* Discord ring so a `blurple` setting means the same colour on every surface,
|
|
24
|
+
* and so embeds fall back to it when a bot declares no palette.
|
|
25
|
+
*/
|
|
26
|
+
exports.DISCORD_BLURPLE = "#5865f2";
|
|
27
|
+
/**
|
|
28
|
+
* Not `#000000`: Discord reads a zero colour as "no colour set" and renders the
|
|
29
|
+
* default grey bar instead, so pure black is the one value an administrator
|
|
30
|
+
* could ask for and never see. One step off zero reads as black.
|
|
31
|
+
*/
|
|
32
|
+
const BLACK = "#010101";
|
|
33
|
+
const GREY = "#808080";
|
|
34
|
+
const CYAN = "#00ffff";
|
|
35
|
+
const BROWN = "#a52a2a";
|
|
36
|
+
const SILVER = "#c0c0c0";
|
|
37
|
+
const TURQUOISE = "#40e0d0";
|
|
38
|
+
const MAGENTA = "#ff00ff";
|
|
39
|
+
const NAVY = "#000080";
|
|
40
|
+
/**
|
|
41
|
+
* Colour names an administrator may type instead of a hex code, French and
|
|
42
|
+
* English side by side.
|
|
43
|
+
*
|
|
44
|
+
* This table is **input vocabulary, not display text**. Nothing in it is ever
|
|
45
|
+
* shown to anyone, and its keys must never be translated at runtime: a catalog
|
|
46
|
+
* lookup resolves against the reply locale, which would make `rouge` stop
|
|
47
|
+
* working the moment an admin's Discord is set to English — the opposite of the
|
|
48
|
+
* point. Both spellings are accepted from everyone, always, which only a flat
|
|
49
|
+
* table can promise.
|
|
50
|
+
*
|
|
51
|
+
* Fixed on purpose: a value stored from one of these names must mean the same
|
|
52
|
+
* colour in every bot. Names a bot adds for its own inputs live with those
|
|
53
|
+
* inputs, not here.
|
|
54
|
+
*/
|
|
55
|
+
exports.BASE_COLOR_NAMES = {
|
|
56
|
+
red: RED,
|
|
57
|
+
rouge: RED,
|
|
58
|
+
blue: BLUE,
|
|
59
|
+
bleu: BLUE,
|
|
60
|
+
green: GREEN,
|
|
61
|
+
vert: GREEN,
|
|
62
|
+
yellow: YELLOW,
|
|
63
|
+
jaune: YELLOW,
|
|
64
|
+
orange: ORANGE,
|
|
65
|
+
purple: PURPLE,
|
|
66
|
+
// French for purple, not the CSS `violet` (a pale pink): an admin typing it
|
|
67
|
+
// here is asking for the colour the word means in their own language.
|
|
68
|
+
violet: PURPLE,
|
|
69
|
+
pink: PINK,
|
|
70
|
+
rose: PINK,
|
|
71
|
+
white: WHITE,
|
|
72
|
+
blanc: WHITE,
|
|
73
|
+
black: BLACK,
|
|
74
|
+
noir: BLACK,
|
|
75
|
+
grey: GREY,
|
|
76
|
+
gray: GREY,
|
|
77
|
+
gris: GREY,
|
|
78
|
+
cyan: CYAN,
|
|
79
|
+
brown: BROWN,
|
|
80
|
+
marron: BROWN,
|
|
81
|
+
silver: SILVER,
|
|
82
|
+
argent: SILVER,
|
|
83
|
+
argenté: SILVER,
|
|
84
|
+
turquoise: TURQUOISE,
|
|
85
|
+
magenta: MAGENTA,
|
|
86
|
+
navy: NAVY,
|
|
87
|
+
marine: NAVY,
|
|
88
|
+
blurple: exports.DISCORD_BLURPLE,
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Accents must not be a trap: `dore` and `doré` are the same request, and an
|
|
92
|
+
* administrator has no way of knowing which one a table happened to spell.
|
|
93
|
+
* Case and surrounding whitespace are folded for the same reason.
|
|
94
|
+
*/
|
|
95
|
+
function normalizeColorName(raw) {
|
|
96
|
+
return raw
|
|
97
|
+
.trim()
|
|
98
|
+
.toLowerCase()
|
|
99
|
+
.normalize("NFD")
|
|
100
|
+
.replace(/\p{Diacritic}/gu, "");
|
|
101
|
+
}
|
|
102
|
+
/** Index a name → `#rrggbb` table by {@link normalizeColorName}, so lookups fold case and accents. */
|
|
103
|
+
function indexColorNames(names) {
|
|
104
|
+
return new Map(Object.entries(names).map(([name, hex]) => [normalizeColorName(name), hex]));
|
|
105
|
+
}
|
|
106
|
+
const BASE_COLORS_BY_NORMALIZED_NAME = indexColorNames(exports.BASE_COLOR_NAMES);
|
|
107
|
+
/** `#RGB` and `#RRGGBB`, with or without the leading hash. */
|
|
108
|
+
const HEX_COLOR_PATTERN = /^#?(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
109
|
+
/**
|
|
110
|
+
* Normalize a hexadecimal colour code to `#rrggbb`, `null` when the input is
|
|
111
|
+
* not one. Surrounding whitespace is ignored.
|
|
112
|
+
*/
|
|
113
|
+
function parseHexColor(raw) {
|
|
114
|
+
const value = raw.trim();
|
|
115
|
+
if (!HEX_COLOR_PATTERN.test(value)) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const digits = value.replace("#", "").toLowerCase();
|
|
119
|
+
const expanded = digits.length === 3 ? [...digits].map((digit) => `${digit}${digit}`).join("") : digits;
|
|
120
|
+
return `#${expanded}`;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Normalize a colour to `#rrggbb`, from a hexadecimal code or from one of the
|
|
124
|
+
* {@link BASE_COLOR_NAMES}. `null` for anything else: the refusal belongs to
|
|
125
|
+
* whichever caller asked, so this only reports that it could not read the value.
|
|
126
|
+
*/
|
|
127
|
+
function parseColor(raw) {
|
|
128
|
+
return BASE_COLORS_BY_NORMALIZED_NAME.get(normalizeColorName(raw)) ?? parseHexColor(raw);
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=color.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.js","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":";;;AA4FA,gDAMC;AAGD,0CAEC;AAYD,sCASC;AAOD,gCAEC;AArID;;;;GAIG;AACH,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,KAAK,GAAG,SAAS,CAAC;AACxB,MAAM,MAAM,GAAG,SAAS,CAAC;AACzB,MAAM,MAAM,GAAG,SAAS,CAAC;AACzB,MAAM,MAAM,GAAG,SAAS,CAAC;AACzB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB;;;;GAIG;AACU,QAAA,eAAe,GAAG,SAAS,CAAC;AAEzC;;;;GAIG;AACH,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,KAAK,GAAG,SAAS,CAAC;AACxB,MAAM,MAAM,GAAG,SAAS,CAAC;AACzB,MAAM,SAAS,GAAG,SAAS,CAAC;AAC5B,MAAM,OAAO,GAAG,SAAS,CAAC;AAC1B,MAAM,IAAI,GAAG,SAAS,CAAC;AAEvB;;;;;;;;;;;;;;GAcG;AACU,QAAA,gBAAgB,GAAqC;IACjE,GAAG,EAAE,GAAG;IACR,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,KAAK;IACX,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,4EAA4E;IAC5E,sEAAsE;IACtE,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,MAAM;IACf,SAAS,EAAE,SAAS;IACpB,OAAO,EAAE,OAAO;IAChB,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,uBAAe;CACxB,CAAC;AAEF;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,GAAW;IAC7C,OAAO,GAAG;SACR,IAAI,EAAE;SACN,WAAW,EAAE;SACb,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,sGAAsG;AACtG,SAAgB,eAAe,CAAC,KAAuC;IACtE,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,8BAA8B,GACnC,eAAe,CAAC,wBAAgB,CAAC,CAAC;AAEnC,8DAA8D;AAC9D,MAAM,iBAAiB,GAAG,kCAAkC,CAAC;AAE7D;;;GAGG;AACH,SAAgB,aAAa,CAAC,GAAW;IACxC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACzB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,QAAQ,GACb,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACxF,OAAO,IAAI,QAAQ,EAAE,CAAC;AACvB,CAAC;AAED;;;;GAIG;AACH,SAAgB,UAAU,CAAC,GAAW;IACrC,OAAO,8BAA8B,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;AAC1F,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Option, Options } from "../../discord/command/options";
|
|
2
|
+
type AsRequired<O> = O extends Option<infer V, boolean> ? Option<V, true> : never;
|
|
3
|
+
/** Turn every option in a record into its required variant. */
|
|
4
|
+
export declare function allRequired<O extends Options>(fields: O): {
|
|
5
|
+
[K in keyof O]: AsRequired<O[K]>;
|
|
6
|
+
};
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=all-required.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"all-required.d.ts","sourceRoot":"","sources":["../../../src/discord/command/all-required.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEjE,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;AAElF,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,CAAC,SAAS,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAM9F"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.allRequired = allRequired;
|
|
4
|
+
/** Turn every option in a record into its required variant. */
|
|
5
|
+
function allRequired(fields) {
|
|
6
|
+
const out = {};
|
|
7
|
+
for (const [key, option] of Object.entries(fields)) {
|
|
8
|
+
out[key] = option.required();
|
|
9
|
+
}
|
|
10
|
+
return out;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=all-required.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"all-required.js","sourceRoot":"","sources":["../../../src/discord/command/all-required.ts"],"names":[],"mappings":";;AAKA,kCAMC;AAPD,+DAA+D;AAC/D,SAAgB,WAAW,CAAoB,MAAS;IACvD,MAAM,GAAG,GAAG,EAA0C,CAAC;IACvD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpD,GAAG,CAAC,GAAc,CAAC,GAAG,MAAM,CAAC,QAAQ,EAA4B,CAAC;IACnE,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocomplete-dispatcher.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"autocomplete-dispatcher.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEtF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC7B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;CAC5C;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,qBAAqB;IAElE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,MAAM;IAGhC,+DAA+D;IACzD,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CA0BxD"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AutocompleteDispatcher = void 0;
|
|
4
|
+
const error_message_1 = require("../../errors/error-message");
|
|
4
5
|
/**
|
|
5
6
|
* Answers option autocomplete requests. It is an {@link InteractionDispatcher}
|
|
6
7
|
* aggregated by the shared {@link InteractionRouter}, never a second
|
|
@@ -31,7 +32,7 @@ class AutocompleteDispatcher {
|
|
|
31
32
|
catch (error) {
|
|
32
33
|
this.logger.error({
|
|
33
34
|
command: interaction.commandName,
|
|
34
|
-
err:
|
|
35
|
+
err: (0, error_message_1.errorMessage)(error),
|
|
35
36
|
}, "Autocomplete handler failed");
|
|
36
37
|
}
|
|
37
38
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocomplete-dispatcher.js","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-dispatcher.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"autocomplete-dispatcher.js","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-dispatcher.ts"],"names":[],"mappings":";;;AAGA,0DAAsD;AAatD;;;;GAIG;AACH,MAAa,sBAAsB;IAEhB;IACA;IAFlB,YACkB,QAAuB,EACvB,MAAc;QADd,aAAQ,GAAR,QAAQ,CAAe;QACvB,WAAM,GAAN,MAAM,CAAQ;IAC7B,CAAC;IAEJ,+DAA+D;IAC/D,KAAK,CAAC,MAAM,CAAC,WAAwB;QACpC,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAC3D,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAC;QACd,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,mEAAmE;QACnE,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAChB;gBACC,OAAO,EAAE,WAAW,CAAC,WAAW;gBAChC,GAAG,EAAE,IAAA,4BAAY,EAAC,KAAK,CAAC;aACxB,EACD,6BAA6B,CAC7B,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAjCD,wDAiCC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autocomplete-limits.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-limits.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,KAAK,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_AUTOCOMPLETE_CHOICES = void 0;
|
|
4
|
+
/** Discord refuses an autocomplete response carrying more than this many choices. */
|
|
5
|
+
exports.MAX_AUTOCOMPLETE_CHOICES = 25;
|
|
6
|
+
//# sourceMappingURL=autocomplete-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autocomplete-limits.js","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-limits.ts"],"names":[],"mappings":";;;AAAA,qFAAqF;AACxE,QAAA,wBAAwB,GAAG,EAAE,CAAC"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { AutocompleteInteraction } from "discord.js";
|
|
2
|
-
import {
|
|
2
|
+
import type { CompiledSubcommand } from "../../discord/command/create-command";
|
|
3
3
|
import type { Options } from "../../discord/command/options";
|
|
4
|
+
/**
|
|
5
|
+
* Serving option autocomplete. Kept beside the DSL because resolving *which*
|
|
6
|
+
* option is focused needs the same route table `createCommand` builds — the
|
|
7
|
+
* dispatcher only decides that an interaction is an autocomplete request.
|
|
8
|
+
*/
|
|
4
9
|
/**
|
|
5
10
|
* Answer a focused option's autocomplete request.
|
|
6
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocomplete.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"autocomplete.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAIzD;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,uBAAuB,EACpC,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC,CAsBf;AAYD;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,WAAW,EAAE,uBAAuB,EACpC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACvC,WAAW,EAAE,OAAO,GAAG,IAAI,GACzB,OAAO,CAUT"}
|