@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
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ActionRowBuilder,
|
|
3
3
|
AnySelectMenuInteraction,
|
|
4
|
-
Attachment,
|
|
5
4
|
ButtonInteraction,
|
|
6
5
|
ChatInputCommandInteraction,
|
|
7
6
|
CollectedMessageInteraction,
|
|
@@ -11,10 +10,12 @@ import type {
|
|
|
11
10
|
MessageActionRowComponentBuilder,
|
|
12
11
|
MessageMentionOptions,
|
|
13
12
|
} from "discord.js";
|
|
13
|
+
import { toMessageEditOptions } from "@/discord/components/interactive-message/message-edit-options";
|
|
14
|
+
import type { StateStore } from "@/discord/components/interactive-message/state-store";
|
|
14
15
|
import type { Button, ComponentContext } from "@/discord/interaction/button";
|
|
15
16
|
import type { Card } from "@/discord/ui/card";
|
|
16
|
-
import {
|
|
17
|
-
import { describeError } from "@/errors";
|
|
17
|
+
import type { MessageFile } from "@/discord/ui/message-attachments";
|
|
18
|
+
import { describeError } from "@/errors/describe-error";
|
|
18
19
|
import type { Logger } from "@/logger";
|
|
19
20
|
|
|
20
21
|
/** How long an interactive message stays live without a click. */
|
|
@@ -90,71 +91,6 @@ export type InteractiveMessagePayload<S = never> =
|
|
|
90
91
|
components?: never;
|
|
91
92
|
});
|
|
92
93
|
|
|
93
|
-
/**
|
|
94
|
-
* The payload as discord.js takes it on an edit, given what the message already
|
|
95
|
-
* carries: a file already up there under a wanted name is kept rather than
|
|
96
|
-
* uploaded a second time, so an unrelated re-render neither drops nor re-sends
|
|
97
|
-
* it.
|
|
98
|
-
*
|
|
99
|
-
* A payload stating no files touches neither field, leaving the message's own
|
|
100
|
-
* attachments alone.
|
|
101
|
-
*
|
|
102
|
-
* `state` is only read for a `"card"` payload — it is what `Card.apply` needs
|
|
103
|
-
* to render the container — and is otherwise unused. No caller building an
|
|
104
|
-
* `"embeds"` payload has ever had to pass it, and still does not: it is the
|
|
105
|
-
* third, optional parameter existing two-argument calls already omit.
|
|
106
|
-
*/
|
|
107
|
-
export function toMessageEditOptions<S>(
|
|
108
|
-
payload: InteractiveMessagePayload<S>,
|
|
109
|
-
existing: readonly Attachment[],
|
|
110
|
-
state?: S,
|
|
111
|
-
): InteractionUpdateOptions {
|
|
112
|
-
const { files, allowedMentions } = payload;
|
|
113
|
-
const mentions = allowedMentions === undefined ? {} : { allowedMentions };
|
|
114
|
-
const attachments = files === undefined ? {} : planMessageAttachments(existing, files);
|
|
115
|
-
|
|
116
|
-
if (payload.layout === "card") {
|
|
117
|
-
if (state === undefined) {
|
|
118
|
-
// Only reachable once a caller actually builds a `"card"` payload
|
|
119
|
-
// without threading the state its `Card` needs — a programming error
|
|
120
|
-
// in that caller, not something a member's click can trigger.
|
|
121
|
-
throw new Error(
|
|
122
|
-
'toMessageEditOptions: a "card" layout payload needs the state its Card was ' +
|
|
123
|
-
"declared over to call Card.apply, and none was given.",
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
components: [payload.card.apply(state, false), ...(payload.controls ?? [])],
|
|
128
|
-
...mentions,
|
|
129
|
-
...attachments,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const { embeds, components } = payload;
|
|
134
|
-
return { embeds, components, ...mentions, ...attachments };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* The single mutable cell shared by the view and the collector. Kept explicit
|
|
139
|
-
* rather than captured as a closure variable so the two always read the same
|
|
140
|
-
* reference.
|
|
141
|
-
*/
|
|
142
|
-
export interface StateStore<S> {
|
|
143
|
-
read(): S;
|
|
144
|
-
write(next: S): void;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/** Hold a state the collector can advance in place. */
|
|
148
|
-
export function createStateStore<S>(initial: S): StateStore<S> {
|
|
149
|
-
let state = initial;
|
|
150
|
-
return {
|
|
151
|
-
read: () => state,
|
|
152
|
-
write: (next) => {
|
|
153
|
-
state = next;
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
94
|
/**
|
|
159
95
|
* What {@link InteractiveView.disabledControls} hands back: enough of a payload
|
|
160
96
|
* to neutralise the message's controls in place, in whichever layout the view
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Attachment, InteractionUpdateOptions } from "discord.js";
|
|
2
|
+
import type { InteractiveMessagePayload } from "@/discord/components/interactive-message/interactive-message-collector";
|
|
3
|
+
import { planMessageAttachments } from "@/discord/ui/message-attachments";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The payload as discord.js takes it on an edit, given what the message already
|
|
7
|
+
* carries: a file already up there under a wanted name is kept rather than
|
|
8
|
+
* uploaded a second time, so an unrelated re-render neither drops nor re-sends
|
|
9
|
+
* it.
|
|
10
|
+
*
|
|
11
|
+
* A payload stating no files touches neither field, leaving the message's own
|
|
12
|
+
* attachments alone.
|
|
13
|
+
*
|
|
14
|
+
* `state` is only read for a `"card"` payload — it is what `Card.apply` needs
|
|
15
|
+
* to render the container — and is otherwise unused. No caller building an
|
|
16
|
+
* `"embeds"` payload has ever had to pass it, and still does not: it is the
|
|
17
|
+
* third, optional parameter existing two-argument calls already omit.
|
|
18
|
+
*/
|
|
19
|
+
export function toMessageEditOptions<S>(
|
|
20
|
+
payload: InteractiveMessagePayload<S>,
|
|
21
|
+
existing: readonly Attachment[],
|
|
22
|
+
state?: S,
|
|
23
|
+
): InteractionUpdateOptions {
|
|
24
|
+
const { files, allowedMentions } = payload;
|
|
25
|
+
const mentions = allowedMentions === undefined ? {} : { allowedMentions };
|
|
26
|
+
const attachments = files === undefined ? {} : planMessageAttachments(existing, files);
|
|
27
|
+
|
|
28
|
+
if (payload.layout === "card") {
|
|
29
|
+
if (state === undefined) {
|
|
30
|
+
// Only reachable once a caller actually builds a `"card"` payload
|
|
31
|
+
// without threading the state its `Card` needs — a programming error
|
|
32
|
+
// in that caller, not something a member's click can trigger.
|
|
33
|
+
throw new Error(
|
|
34
|
+
'toMessageEditOptions: a "card" layout payload needs the state its Card was ' +
|
|
35
|
+
"declared over to call Card.apply, and none was given.",
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
components: [payload.card.apply(state, false), ...(payload.controls ?? [])],
|
|
40
|
+
...mentions,
|
|
41
|
+
...attachments,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { embeds, components } = payload;
|
|
46
|
+
return { embeds, components, ...mentions, ...attachments };
|
|
47
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { type ChatInputCommandInteraction, MessageFlags } from "discord.js";
|
|
2
2
|
import {
|
|
3
3
|
COLLECTOR_IDLE_MS,
|
|
4
|
-
createStateStore,
|
|
5
4
|
type InteractiveMessageHandle,
|
|
6
5
|
type InteractiveSelect,
|
|
7
6
|
type InteractiveView,
|
|
8
7
|
mountInteractiveMessageCollector,
|
|
9
|
-
type StateStore,
|
|
10
|
-
toMessageEditOptions,
|
|
11
8
|
} from "@/discord/components/interactive-message/interactive-message-collector";
|
|
9
|
+
import { toMessageEditOptions } from "@/discord/components/interactive-message/message-edit-options";
|
|
10
|
+
import {
|
|
11
|
+
createStateStore,
|
|
12
|
+
type StateStore,
|
|
13
|
+
} from "@/discord/components/interactive-message/state-store";
|
|
12
14
|
import type { Button } from "@/discord/interaction/button";
|
|
13
15
|
import type { Logger } from "@/logger";
|
|
14
16
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single mutable cell shared by the view and the collector. Kept explicit
|
|
3
|
+
* rather than captured as a closure variable so the two always read the same
|
|
4
|
+
* reference.
|
|
5
|
+
*/
|
|
6
|
+
export interface StateStore<S> {
|
|
7
|
+
read(): S;
|
|
8
|
+
write(next: S): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Hold a state the collector can advance in place. */
|
|
12
|
+
export function createStateStore<S>(initial: S): StateStore<S> {
|
|
13
|
+
let state = initial;
|
|
14
|
+
return {
|
|
15
|
+
read: () => state,
|
|
16
|
+
write: (next) => {
|
|
17
|
+
state = next;
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ChatInputCommandInteraction } from "discord.js";
|
|
2
2
|
import {
|
|
3
3
|
COLLECTOR_IDLE_MS,
|
|
4
|
-
createStateStore,
|
|
5
4
|
mountInteractiveMessageCollector,
|
|
6
|
-
|
|
7
|
-
} from "@/discord/components/interactive-message";
|
|
5
|
+
} from "@/discord/components/interactive-message/interactive-message-collector";
|
|
6
|
+
import { toMessageEditOptions } from "@/discord/components/interactive-message/message-edit-options";
|
|
7
|
+
import { createStateStore } from "@/discord/components/interactive-message/state-store";
|
|
8
8
|
import { createPageState, pageCount } from "@/discord/components/paginator/page-state";
|
|
9
9
|
import {
|
|
10
10
|
createPaginatorButtons,
|
|
@@ -2,7 +2,7 @@ import type { ActionRowBuilder, ButtonBuilder, EmbedBuilder } from "discord.js";
|
|
|
2
2
|
import type {
|
|
3
3
|
InteractiveMessagePayload,
|
|
4
4
|
InteractiveView,
|
|
5
|
-
} from "@/discord/components/interactive-message";
|
|
5
|
+
} from "@/discord/components/interactive-message/interactive-message-collector";
|
|
6
6
|
import { type PageState, selectPageItems } from "@/discord/components/paginator/page-state";
|
|
7
7
|
import { type Button, createActionRow } from "@/discord/interaction/button";
|
|
8
8
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { ActionRowBuilder, ButtonBuilder, EmbedBuilder } from "discord.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
type RoutableInteraction,
|
|
2
|
+
import { openToAnyone } from "@/discord/components/component-access";
|
|
3
|
+
import type {
|
|
4
|
+
ComponentHandler,
|
|
5
|
+
ComponentRuntime,
|
|
6
|
+
RoutableInteraction,
|
|
8
7
|
} from "@/discord/components/component-router";
|
|
9
|
-
import { toMessageEditOptions } from "@/discord/components/interactive-message";
|
|
8
|
+
import { toMessageEditOptions } from "@/discord/components/interactive-message/message-edit-options";
|
|
10
9
|
import {
|
|
11
10
|
clampPage,
|
|
12
11
|
isFirstPage,
|
|
@@ -186,12 +185,12 @@ export function createPersistentPaginator(
|
|
|
186
185
|
return {
|
|
187
186
|
customId,
|
|
188
187
|
render: (page = FIRST_PAGE) => loadPage(page),
|
|
189
|
-
handler:
|
|
188
|
+
handler: {
|
|
190
189
|
customId,
|
|
191
190
|
// Navigation only re-renders what the message already showed to
|
|
192
191
|
// whoever can see the channel; it grants no access of its own.
|
|
193
192
|
authorize: openToAnyone("paging a message reveals nothing its reader could not already see"),
|
|
194
193
|
handle: handleClick,
|
|
195
|
-
}
|
|
194
|
+
},
|
|
196
195
|
};
|
|
197
196
|
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import type { ChannelType } from "discord.js";
|
|
2
|
+
import { MAX_SELECT_OPTIONS } from "@/discord/components/settings-editor/settings-editor.view";
|
|
3
|
+
import {
|
|
4
|
+
MAX_MODAL_INPUT_LENGTH,
|
|
5
|
+
type SettingsEditorChoice,
|
|
6
|
+
type SettingsEditorGroupField,
|
|
7
|
+
} from "@/discord/components/settings-editor/settings-editor-fields";
|
|
8
|
+
import { SETTINGS_EDITOR_MESSAGES } from "@/discord/i18n";
|
|
9
|
+
import { CHANNEL_TYPE_BY_KIND } from "@/discord/settings/discord-guild-directory";
|
|
10
|
+
import type { SettingsDeclaration } from "@/settings/define-settings";
|
|
11
|
+
import { fieldSearch } from "@/settings/field-search";
|
|
12
|
+
import {
|
|
13
|
+
type AnyField,
|
|
14
|
+
FIELD_LIMITS,
|
|
15
|
+
type FieldSpec,
|
|
16
|
+
unhandledFieldKind,
|
|
17
|
+
} from "@/settings/fields/field";
|
|
18
|
+
import { SETTINGS_MESSAGES } from "@/settings/messages";
|
|
19
|
+
import type { ChannelKind } from "@/settings/ports/guild-directory";
|
|
20
|
+
import { SettingsDeclarationError } from "@/settings/settings-declaration-error";
|
|
21
|
+
|
|
22
|
+
/** One editable entry of the screen: a typed box or a picker, never a level or a group. */
|
|
23
|
+
type ControlEntry = SettingsEditorGroupField<string>["fields"][number];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* How a control's value moves between the stored settings and the screen:
|
|
27
|
+
* - `text`: a string typed as is (text, colour);
|
|
28
|
+
* - `number`: a number typed as its decimal text (integer, number);
|
|
29
|
+
* - `duration`: whole seconds typed as `1h30m`;
|
|
30
|
+
* - `secret`: typed, prefilled with whether it is set, never with its value;
|
|
31
|
+
* - `lines`: a list of integers or texts typed one item per line;
|
|
32
|
+
* - `boolean`: picked from a yes/no choice;
|
|
33
|
+
* - `single`: one picked id or enum value;
|
|
34
|
+
* - `many`: a list of picked ids or enum values;
|
|
35
|
+
* - `toggles`: the keys of one toggles select that are on (`keys` are that
|
|
36
|
+
* select's own, at most {@link MAX_SELECT_OPTIONS});
|
|
37
|
+
* - `search`: one value picked from a search's first results, a number for
|
|
38
|
+
* an integer field;
|
|
39
|
+
* - `other`: the free entry beside a non-strict search's select, typed, a
|
|
40
|
+
* number for an integer field; it opens empty and wins over the pick.
|
|
41
|
+
*/
|
|
42
|
+
export type ControlShape =
|
|
43
|
+
| { readonly kind: "text" | "number" | "duration" | "secret" | "boolean" | "single" | "many" }
|
|
44
|
+
| { readonly kind: "lines"; readonly numeric: boolean }
|
|
45
|
+
| { readonly kind: "toggles"; readonly keys: readonly string[] }
|
|
46
|
+
| { readonly kind: "search"; readonly numeric: boolean }
|
|
47
|
+
| { readonly kind: "other"; readonly numeric: boolean };
|
|
48
|
+
|
|
49
|
+
/** One control of the screen and the declared field it edits. */
|
|
50
|
+
export interface DeclarationControl {
|
|
51
|
+
readonly entry: ControlEntry;
|
|
52
|
+
/** Key of the declared field; a toggles field split over several selects shares it. */
|
|
53
|
+
readonly fieldKey: string;
|
|
54
|
+
/** Id of the declared group the field belongs to, if any. */
|
|
55
|
+
readonly groupId: string | undefined;
|
|
56
|
+
readonly shape: ControlShape;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type TogglesSpec = Extract<FieldSpec, { readonly kind: "toggles" }>;
|
|
60
|
+
|
|
61
|
+
/** Separates a split toggles field's key from the number of its select. */
|
|
62
|
+
const CHUNK_SEPARATOR = "#";
|
|
63
|
+
|
|
64
|
+
/** Key suffix of the free entry beside a non-strict searchable field's select. */
|
|
65
|
+
export const OTHER_VALUE_SUFFIX = "#other";
|
|
66
|
+
|
|
67
|
+
/** The options each searchable field's select offers, by field key: its search's first results. */
|
|
68
|
+
export type SearchOptions = ReadonlyMap<string, readonly SettingsEditorChoice[]>;
|
|
69
|
+
|
|
70
|
+
/** What every entry of one declared field states, whatever its control. */
|
|
71
|
+
interface EntryBase {
|
|
72
|
+
readonly key: string;
|
|
73
|
+
readonly labelKey: string;
|
|
74
|
+
readonly hintKey: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The controls of a declaration, in declared order: one per field, except a
|
|
79
|
+
* toggles field with more keys than a select offers, which gets one control
|
|
80
|
+
* per chunk of at most {@link MAX_SELECT_OPTIONS} keys, and a non-strict
|
|
81
|
+
* searchable field, which gets its select then a free entry (FR-026a). A
|
|
82
|
+
* searchable field whose search offered nothing is typed like any other.
|
|
83
|
+
*
|
|
84
|
+
* @param declaration - the module's settings declaration.
|
|
85
|
+
* @param searchOptions - what each searchable field's select offers.
|
|
86
|
+
* @returns every control of the screen.
|
|
87
|
+
* @throws SettingsDeclarationError when a list holds an item kind lists cannot
|
|
88
|
+
* hold, which only a declaration built without `defineSettings` can do.
|
|
89
|
+
*/
|
|
90
|
+
export function declarationControls(
|
|
91
|
+
declaration: SettingsDeclaration,
|
|
92
|
+
searchOptions: SearchOptions,
|
|
93
|
+
): DeclarationControl[] {
|
|
94
|
+
return Object.entries(declaration.fields).flatMap(([fieldKey, declared]) =>
|
|
95
|
+
fieldControls({
|
|
96
|
+
declarationId: declaration.id,
|
|
97
|
+
fieldKey,
|
|
98
|
+
declared,
|
|
99
|
+
options: searchOptions.get(fieldKey) ?? [],
|
|
100
|
+
}),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Whether a control is the free entry beside a non-strict search's select. */
|
|
105
|
+
export function isFreeEntry(control: DeclarationControl): boolean {
|
|
106
|
+
return control.shape.kind === "other";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function fieldControls(params: {
|
|
110
|
+
declarationId: string;
|
|
111
|
+
fieldKey: string;
|
|
112
|
+
declared: AnyField;
|
|
113
|
+
options: readonly SettingsEditorChoice[];
|
|
114
|
+
}): DeclarationControl[] {
|
|
115
|
+
const { fieldKey, declared, options } = params;
|
|
116
|
+
const groupId = declared.ui?.group;
|
|
117
|
+
const base: EntryBase = {
|
|
118
|
+
key: fieldKey,
|
|
119
|
+
labelKey: declared.label ?? fieldKey,
|
|
120
|
+
hintKey: declared.description ?? SETTINGS_EDITOR_MESSAGES.entryHint,
|
|
121
|
+
};
|
|
122
|
+
const { spec } = declared;
|
|
123
|
+
if (spec.kind === "toggles") {
|
|
124
|
+
return togglesControls({ base, groupId, spec });
|
|
125
|
+
}
|
|
126
|
+
const search = fieldSearch(spec);
|
|
127
|
+
if (search !== undefined && options.length > 0) {
|
|
128
|
+
const numeric = spec.kind === "integer";
|
|
129
|
+
const select: DeclarationControl = {
|
|
130
|
+
entry: { ...base, kind: "choice", minValues: 0, maxValues: 1, choices: options },
|
|
131
|
+
fieldKey,
|
|
132
|
+
groupId,
|
|
133
|
+
shape: { kind: "search", numeric },
|
|
134
|
+
};
|
|
135
|
+
if (search.strict === true) {
|
|
136
|
+
return [select];
|
|
137
|
+
}
|
|
138
|
+
const free = typedEntry({
|
|
139
|
+
base: {
|
|
140
|
+
key: `${fieldKey}${OTHER_VALUE_SUFFIX}`,
|
|
141
|
+
labelKey: SETTINGS_EDITOR_MESSAGES.otherValue,
|
|
142
|
+
hintKey: SETTINGS_EDITOR_MESSAGES.entryHint,
|
|
143
|
+
},
|
|
144
|
+
declared,
|
|
145
|
+
style: "short",
|
|
146
|
+
maxLength: spec.kind === "text" ? spec.maxLength : undefined,
|
|
147
|
+
});
|
|
148
|
+
const helper = { helperKey: SETTINGS_EDITOR_MESSAGES.otherValueHelper };
|
|
149
|
+
return [
|
|
150
|
+
select,
|
|
151
|
+
{ entry: { ...free, ...helper }, fieldKey, groupId, shape: { kind: "other", numeric } },
|
|
152
|
+
];
|
|
153
|
+
}
|
|
154
|
+
const single = singleControl({ ...params, base, spec });
|
|
155
|
+
return [{ ...single, fieldKey, groupId }];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** The entry and shape of a field that is not a toggles field. */
|
|
159
|
+
function singleControl(params: {
|
|
160
|
+
declarationId: string;
|
|
161
|
+
fieldKey: string;
|
|
162
|
+
declared: AnyField;
|
|
163
|
+
base: EntryBase;
|
|
164
|
+
spec: Exclude<FieldSpec, TogglesSpec>;
|
|
165
|
+
}): Pick<DeclarationControl, "entry" | "shape"> {
|
|
166
|
+
const { base, spec, declared } = params;
|
|
167
|
+
switch (spec.kind) {
|
|
168
|
+
case "text":
|
|
169
|
+
return {
|
|
170
|
+
entry: typedEntry({
|
|
171
|
+
base,
|
|
172
|
+
declared,
|
|
173
|
+
style: "paragraph",
|
|
174
|
+
maxLength: spec.maxLength ?? FIELD_LIMITS.textMaxLength,
|
|
175
|
+
}),
|
|
176
|
+
shape: { kind: "text" },
|
|
177
|
+
};
|
|
178
|
+
case "color":
|
|
179
|
+
return { entry: typedEntry({ base, declared, style: "short" }), shape: { kind: "text" } };
|
|
180
|
+
case "integer":
|
|
181
|
+
case "number":
|
|
182
|
+
return { entry: typedEntry({ base, declared, style: "short" }), shape: { kind: "number" } };
|
|
183
|
+
case "duration":
|
|
184
|
+
return { entry: typedEntry({ base, declared, style: "short" }), shape: { kind: "duration" } };
|
|
185
|
+
case "secret":
|
|
186
|
+
return { entry: typedEntry({ base, declared, style: "short" }), shape: { kind: "secret" } };
|
|
187
|
+
case "boolean":
|
|
188
|
+
return {
|
|
189
|
+
entry: { ...base, kind: "choice", minValues: 0, maxValues: 1, choices: BOOLEAN_CHOICES },
|
|
190
|
+
shape: { kind: "boolean" },
|
|
191
|
+
};
|
|
192
|
+
case "enum":
|
|
193
|
+
case "channel":
|
|
194
|
+
case "role":
|
|
195
|
+
case "user":
|
|
196
|
+
return {
|
|
197
|
+
entry: pickerEntry({ base, spec, bounds: { minValues: 0, maxValues: 1 } }),
|
|
198
|
+
shape: { kind: "single" },
|
|
199
|
+
};
|
|
200
|
+
case "list":
|
|
201
|
+
return listControl({ ...params, spec });
|
|
202
|
+
default:
|
|
203
|
+
return unhandledFieldKind(spec);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** The two options of a yes/no field, stored as `"true"` and `"false"`. */
|
|
208
|
+
const BOOLEAN_CHOICES: readonly SettingsEditorChoice[] = [
|
|
209
|
+
{ value: String(true), labelKey: SETTINGS_MESSAGES.booleanTrue },
|
|
210
|
+
{ value: String(false), labelKey: SETTINGS_MESSAGES.booleanFalse },
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
function typedEntry(params: {
|
|
214
|
+
base: EntryBase;
|
|
215
|
+
declared: AnyField;
|
|
216
|
+
style: "short" | "paragraph";
|
|
217
|
+
maxLength?: number;
|
|
218
|
+
}): ControlEntry {
|
|
219
|
+
const { base, declared, style } = params;
|
|
220
|
+
const placeholder =
|
|
221
|
+
declared.placeholder === undefined ? {} : { placeholderKey: declared.placeholder };
|
|
222
|
+
return {
|
|
223
|
+
...base,
|
|
224
|
+
kind: "text",
|
|
225
|
+
style,
|
|
226
|
+
maxLength: params.maxLength ?? MAX_MODAL_INPUT_LENGTH,
|
|
227
|
+
...placeholder,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** How many values a picker takes. */
|
|
232
|
+
interface PickerBounds {
|
|
233
|
+
readonly minValues: number;
|
|
234
|
+
readonly maxValues: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** The spec of a value picked from a list: a channel, a role, a member or an enum value. */
|
|
238
|
+
type PickableSpec = Extract<FieldSpec, { readonly kind: "enum" | "channel" | "role" | "user" }>;
|
|
239
|
+
|
|
240
|
+
function isPickable(spec: FieldSpec): spec is PickableSpec {
|
|
241
|
+
return (
|
|
242
|
+
spec.kind === "enum" || spec.kind === "channel" || spec.kind === "role" || spec.kind === "user"
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** A picker for one channel, role, user or enum value, or a list of them. */
|
|
247
|
+
function pickerEntry(params: {
|
|
248
|
+
base: EntryBase;
|
|
249
|
+
spec: PickableSpec;
|
|
250
|
+
bounds: PickerBounds;
|
|
251
|
+
}): ControlEntry {
|
|
252
|
+
const { base, spec, bounds } = params;
|
|
253
|
+
switch (spec.kind) {
|
|
254
|
+
case "enum":
|
|
255
|
+
return {
|
|
256
|
+
...base,
|
|
257
|
+
...bounds,
|
|
258
|
+
kind: "choice",
|
|
259
|
+
choices: spec.choices.map((choice) => ({ value: choice.value, labelKey: choice.label })),
|
|
260
|
+
};
|
|
261
|
+
case "channel":
|
|
262
|
+
return { ...base, ...bounds, ...channelPicker(spec.types) };
|
|
263
|
+
case "role":
|
|
264
|
+
case "user":
|
|
265
|
+
return { ...base, ...bounds, kind: spec.kind };
|
|
266
|
+
default:
|
|
267
|
+
return unhandledFieldKind(spec);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Every guild channel type, for a channel field that restricts none. */
|
|
272
|
+
const EVERY_CHANNEL_TYPE: readonly ChannelType[] = Object.values(CHANNEL_TYPE_BY_KIND);
|
|
273
|
+
|
|
274
|
+
/** A category picker when the field takes categories only, a channel picker otherwise. */
|
|
275
|
+
function channelPicker(
|
|
276
|
+
types: readonly ChannelKind[] | undefined,
|
|
277
|
+
):
|
|
278
|
+
| { readonly kind: "category" }
|
|
279
|
+
| { readonly kind: "channel"; readonly channelTypes: readonly ChannelType[] } {
|
|
280
|
+
if (types !== undefined && types.length > 0 && types.every(isCategory)) {
|
|
281
|
+
return { kind: "category" };
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
kind: "channel",
|
|
285
|
+
channelTypes: types === undefined ? EVERY_CHANNEL_TYPE : types.map(toChannelType),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function isCategory(kind: ChannelKind): boolean {
|
|
290
|
+
return kind === "category";
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function toChannelType(kind: ChannelKind): ChannelType {
|
|
294
|
+
return CHANNEL_TYPE_BY_KIND[kind];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* A list of pickable items becomes a picker bounded by the list's sizes; a
|
|
299
|
+
* list of integers or texts, which no picker offers, a box taking one item
|
|
300
|
+
* per line.
|
|
301
|
+
*/
|
|
302
|
+
function listControl(params: {
|
|
303
|
+
declarationId: string;
|
|
304
|
+
fieldKey: string;
|
|
305
|
+
declared: AnyField;
|
|
306
|
+
base: EntryBase;
|
|
307
|
+
spec: Extract<FieldSpec, { readonly kind: "list" }>;
|
|
308
|
+
}): Pick<DeclarationControl, "entry" | "shape"> {
|
|
309
|
+
const { base, spec, declared } = params;
|
|
310
|
+
const itemKind = spec.item.spec.kind;
|
|
311
|
+
if (itemKind === "integer" || itemKind === "text") {
|
|
312
|
+
return {
|
|
313
|
+
entry: typedEntry({ base, declared, style: "paragraph" }),
|
|
314
|
+
shape: { kind: "lines", numeric: itemKind === "integer" },
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
const itemSpec = spec.item.spec;
|
|
318
|
+
if (!isPickable(itemSpec)) {
|
|
319
|
+
throw new SettingsDeclarationError(
|
|
320
|
+
params.declarationId,
|
|
321
|
+
`field "${params.fieldKey}" is a list of ${itemKind}, which lists cannot hold`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
const bounds: PickerBounds = {
|
|
325
|
+
minValues: spec.minItems ?? 0,
|
|
326
|
+
maxValues: spec.maxItems ?? FIELD_LIMITS.listMaxItems,
|
|
327
|
+
};
|
|
328
|
+
return { entry: pickerEntry({ base, spec: itemSpec, bounds }), shape: { kind: "many" } };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* A toggles field as selects of at most {@link MAX_SELECT_OPTIONS} keys each,
|
|
333
|
+
* every key labelled with its `keyLabels` entry. A single select keeps the
|
|
334
|
+
* field's key; split ones number theirs.
|
|
335
|
+
*/
|
|
336
|
+
function togglesControls(params: {
|
|
337
|
+
base: EntryBase;
|
|
338
|
+
groupId: string | undefined;
|
|
339
|
+
spec: TogglesSpec;
|
|
340
|
+
}): DeclarationControl[] {
|
|
341
|
+
const { base, groupId, spec } = params;
|
|
342
|
+
const chunks = chunked(spec.keys, MAX_SELECT_OPTIONS);
|
|
343
|
+
return chunks.map((keys, index) => ({
|
|
344
|
+
entry: {
|
|
345
|
+
...base,
|
|
346
|
+
key: chunks.length === 1 ? base.key : `${base.key}${CHUNK_SEPARATOR}${index + 1}`,
|
|
347
|
+
kind: "choice",
|
|
348
|
+
minValues: 0,
|
|
349
|
+
maxValues: keys.length,
|
|
350
|
+
choices: keys.map((key) => ({ value: key, labelKey: spec.keyLabels?.[key] ?? key })),
|
|
351
|
+
},
|
|
352
|
+
fieldKey: base.key,
|
|
353
|
+
groupId,
|
|
354
|
+
shape: { kind: "toggles", keys },
|
|
355
|
+
}));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* `items` in consecutive chunks of at most `size`, in order.
|
|
360
|
+
*
|
|
361
|
+
* @param items - the items to split.
|
|
362
|
+
* @param size - the most items one chunk holds.
|
|
363
|
+
* @returns the chunks; none for no items.
|
|
364
|
+
*/
|
|
365
|
+
function chunked<T>(items: readonly T[], size: number): T[][] {
|
|
366
|
+
const chunks: T[][] = [];
|
|
367
|
+
for (let start = 0; start < items.length; start += size) {
|
|
368
|
+
chunks.push(items.slice(start, start + size));
|
|
369
|
+
}
|
|
370
|
+
return chunks;
|
|
371
|
+
}
|