@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
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { SettingsDeclaration } from "@/settings/define-settings";
|
|
2
|
+
|
|
3
|
+
/** Rank of an item no hint places: after every ranked one. */
|
|
4
|
+
const UNRANKED = Number.MAX_SAFE_INTEGER;
|
|
5
|
+
|
|
6
|
+
/** One place on a settings screen: a field of its own, or a group with its fields in order. */
|
|
7
|
+
type DisplayEntry =
|
|
8
|
+
| { readonly kind: "field"; readonly key: string }
|
|
9
|
+
| { readonly kind: "group"; readonly id: string; readonly fields: readonly string[] };
|
|
10
|
+
|
|
11
|
+
/** The display order of a declaration. */
|
|
12
|
+
export interface DisplayOrder {
|
|
13
|
+
/** Every declared group, fields or not, ranked. */
|
|
14
|
+
readonly groups: readonly string[];
|
|
15
|
+
/** The screen's places, top to bottom: ungrouped fields and groups holding fields. */
|
|
16
|
+
readonly entries: readonly DisplayEntry[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** An item and the keys it sorts by, compared left to right. */
|
|
20
|
+
interface Ranked<T> {
|
|
21
|
+
readonly item: T;
|
|
22
|
+
readonly keys: readonly number[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The order every surface shows a declaration in.
|
|
27
|
+
*
|
|
28
|
+
* - Groups rank by their position in `ui.groupOrder` (unlisted ones after
|
|
29
|
+
* listed ones), then by their own `order` (none after any), then by where
|
|
30
|
+
* they stand in declared order: at their first field, or after every field
|
|
31
|
+
* for a group with no field, in declaration order.
|
|
32
|
+
* - Fields rank within their group, and ungrouped fields among themselves,
|
|
33
|
+
* by `ui.order` (none after any), then by declaration order.
|
|
34
|
+
* - On screen, each place is kept by its kind: a group stands where a group's
|
|
35
|
+
* first field is declared and an ungrouped field where an ungrouped field
|
|
36
|
+
* is declared, then the ranked groups fill the group places and the ranked
|
|
37
|
+
* ungrouped fields the field places. With no hint this is declared order.
|
|
38
|
+
*
|
|
39
|
+
* @param declaration - the module's settings declaration; left untouched.
|
|
40
|
+
* @returns every declared group ranked, and the screen's places in order.
|
|
41
|
+
*/
|
|
42
|
+
export function displayOrder(declaration: SettingsDeclaration): DisplayOrder {
|
|
43
|
+
const fieldKeys = Object.keys(declaration.fields);
|
|
44
|
+
const slots: ("field" | "group")[] = [];
|
|
45
|
+
const firstField = new Map<string, number>();
|
|
46
|
+
const members = new Map<string, Ranked<string>[]>();
|
|
47
|
+
const loose: Ranked<string>[] = [];
|
|
48
|
+
fieldKeys.forEach((key, index) => {
|
|
49
|
+
const ui = declaration.fields[key]?.ui;
|
|
50
|
+
const ranked: Ranked<string> = { item: key, keys: [ui?.order ?? UNRANKED, index] };
|
|
51
|
+
const groupId = ui?.group;
|
|
52
|
+
if (groupId === undefined) {
|
|
53
|
+
slots.push("field");
|
|
54
|
+
loose.push(ranked);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!firstField.has(groupId)) {
|
|
58
|
+
firstField.set(groupId, index);
|
|
59
|
+
slots.push("group");
|
|
60
|
+
}
|
|
61
|
+
members.set(groupId, [...(members.get(groupId) ?? []), ranked]);
|
|
62
|
+
});
|
|
63
|
+
const groups = rankedGroups({ declaration, firstField, fieldCount: fieldKeys.length });
|
|
64
|
+
const filledGroups = groups.filter((id) => members.has(id));
|
|
65
|
+
const fields = sortedItems(loose);
|
|
66
|
+
let nextGroup = 0;
|
|
67
|
+
let nextField = 0;
|
|
68
|
+
const entries = slots.map((slot): DisplayEntry => {
|
|
69
|
+
switch (slot) {
|
|
70
|
+
case "field": {
|
|
71
|
+
const key = fields[nextField] ?? "";
|
|
72
|
+
nextField += 1;
|
|
73
|
+
return { kind: "field", key };
|
|
74
|
+
}
|
|
75
|
+
case "group": {
|
|
76
|
+
const id = filledGroups[nextGroup] ?? "";
|
|
77
|
+
nextGroup += 1;
|
|
78
|
+
return { kind: "group", id, fields: sortedItems(members.get(id) ?? []) };
|
|
79
|
+
}
|
|
80
|
+
default:
|
|
81
|
+
return unhandledSlot(slot);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return { groups, entries };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Every declared group id, ranked. */
|
|
88
|
+
function rankedGroups(params: {
|
|
89
|
+
declaration: SettingsDeclaration;
|
|
90
|
+
firstField: ReadonlyMap<string, number>;
|
|
91
|
+
fieldCount: number;
|
|
92
|
+
}): string[] {
|
|
93
|
+
const { declaration, firstField, fieldCount } = params;
|
|
94
|
+
const groupOrder = declaration.ui?.groupOrder ?? [];
|
|
95
|
+
const ranked = Object.entries(declaration.groups ?? {}).map(
|
|
96
|
+
([id, group], index): Ranked<string> => {
|
|
97
|
+
const position = groupOrder.indexOf(id);
|
|
98
|
+
return {
|
|
99
|
+
item: id,
|
|
100
|
+
keys: [
|
|
101
|
+
position === -1 ? UNRANKED : position,
|
|
102
|
+
group.order ?? UNRANKED,
|
|
103
|
+
firstField.get(id) ?? fieldCount + index,
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
return sortedItems(ranked);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** The items sorted by their keys, on a copy. */
|
|
112
|
+
function sortedItems<T>(ranked: readonly Ranked<T>[]): T[] {
|
|
113
|
+
return [...ranked].sort(compareRanked).map((entry) => entry.item);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function compareRanked<T>(left: Ranked<T>, right: Ranked<T>): number {
|
|
117
|
+
for (const [index, key] of left.keys.entries()) {
|
|
118
|
+
const other = right.keys[index] ?? UNRANKED;
|
|
119
|
+
if (key !== other) {
|
|
120
|
+
return key < other ? -1 : 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function unhandledSlot(slot: never): never {
|
|
127
|
+
throw new Error(`Unhandled display slot: ${String(slot)}`);
|
|
128
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DynamicSuggestions, FieldSpec } from "@/settings/fields/field";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The server-side search a field declares, if any: only an integer or text
|
|
5
|
+
* field can declare one, as its `suggest` (static choices are not a search).
|
|
6
|
+
*
|
|
7
|
+
* @param spec - the field's kind and constraints.
|
|
8
|
+
* @returns the search, or `undefined` when the field has none.
|
|
9
|
+
*/
|
|
10
|
+
export function fieldSearch(spec: FieldSpec): DynamicSuggestions<unknown> | undefined {
|
|
11
|
+
if (spec.kind !== "integer" && spec.kind !== "text") {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const { suggest } = spec;
|
|
15
|
+
return suggest === undefined || "choices" in suggest ? undefined : suggest;
|
|
16
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BoundsOptions,
|
|
3
|
+
ChannelOptions,
|
|
4
|
+
EnumOptions,
|
|
5
|
+
Field,
|
|
6
|
+
FieldOptions,
|
|
7
|
+
FieldSpec,
|
|
8
|
+
IntegerOptions,
|
|
9
|
+
ListOptions,
|
|
10
|
+
SecretField,
|
|
11
|
+
SecretOptions,
|
|
12
|
+
TextOptions,
|
|
13
|
+
TogglesOptions,
|
|
14
|
+
ToggleValues,
|
|
15
|
+
} from "@/settings/fields/field";
|
|
16
|
+
|
|
17
|
+
/** Options that make a field always have a value. */
|
|
18
|
+
type Defined<T> = { readonly default: T };
|
|
19
|
+
|
|
20
|
+
/** A builder whose result is `"defined"` when defaulted. */
|
|
21
|
+
export interface FieldBuilder<T, X> {
|
|
22
|
+
(options: X & FieldOptions<T> & Defined<T>): Field<T, "defined">;
|
|
23
|
+
(options?: X & FieldOptions<T>): Field<T, "optional">;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The field builders of {@link field}. */
|
|
27
|
+
export interface FieldBuilders {
|
|
28
|
+
readonly channel: FieldBuilder<string, ChannelOptions>;
|
|
29
|
+
readonly role: FieldBuilder<string, unknown>;
|
|
30
|
+
readonly user: FieldBuilder<string, unknown>;
|
|
31
|
+
/**
|
|
32
|
+
* Stored as `#rrggbb`; accepts hex codes and the base colour names, never the
|
|
33
|
+
* aliases a bot registers for its Discord inputs.
|
|
34
|
+
*/
|
|
35
|
+
readonly color: FieldBuilder<string, unknown>;
|
|
36
|
+
/** Stored as whole seconds; accepts `"15m"`, `"1h30m"`… Bounds are in seconds. */
|
|
37
|
+
readonly duration: FieldBuilder<number, BoundsOptions>;
|
|
38
|
+
enum<const V extends string>(
|
|
39
|
+
options: EnumOptions<V> & FieldOptions<NoInfer<V>> & Defined<NoInfer<V>>,
|
|
40
|
+
): Field<V, "defined">;
|
|
41
|
+
enum<const V extends string>(
|
|
42
|
+
options: EnumOptions<V> & FieldOptions<NoInfer<V>>,
|
|
43
|
+
): Field<V, "optional">;
|
|
44
|
+
readonly integer: FieldBuilder<number, IntegerOptions>;
|
|
45
|
+
readonly number: FieldBuilder<number, BoundsOptions>;
|
|
46
|
+
readonly text: FieldBuilder<string, TextOptions>;
|
|
47
|
+
readonly boolean: FieldBuilder<boolean, unknown>;
|
|
48
|
+
secret(options?: SecretOptions): SecretField<"optional">;
|
|
49
|
+
list<T>(
|
|
50
|
+
item: Field<T>,
|
|
51
|
+
options: ListOptions & FieldOptions<readonly T[]> & Defined<readonly T[]>,
|
|
52
|
+
): Field<readonly T[], "defined">;
|
|
53
|
+
list<T>(
|
|
54
|
+
item: Field<T>,
|
|
55
|
+
options?: ListOptions & FieldOptions<readonly T[]>,
|
|
56
|
+
): Field<readonly T[], "optional">;
|
|
57
|
+
/** A boolean per key, e.g. enabled modules; not allowed as a list item. */
|
|
58
|
+
toggles<const K extends string>(options: TogglesOptions<K>): Field<ToggleValues<K>, "defined">;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Assemble a field from its constraints and common options. The presence is
|
|
63
|
+
* `never` here: the builder overloads narrow it from the options.
|
|
64
|
+
*/
|
|
65
|
+
function createField<T>(spec: FieldSpec, options: FieldOptions<T>): Field<T, never> {
|
|
66
|
+
return { ...options, spec, required: options.required ?? false };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function channelField(options: ChannelOptions & FieldOptions<string> = {}): Field<string, never> {
|
|
70
|
+
const { types, ...common } = options;
|
|
71
|
+
return createField({ kind: "channel", types }, common);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function roleField(options: FieldOptions<string> = {}): Field<string, never> {
|
|
75
|
+
return createField({ kind: "role" }, options);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function userField(options: FieldOptions<string> = {}): Field<string, never> {
|
|
79
|
+
return createField({ kind: "user" }, options);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function colorField(options: FieldOptions<string> = {}): Field<string, never> {
|
|
83
|
+
return createField({ kind: "color" }, options);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function durationField(options: BoundsOptions & FieldOptions<number> = {}): Field<number, never> {
|
|
87
|
+
const { min, max, ...common } = options;
|
|
88
|
+
return createField({ kind: "duration", min, max }, common);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function enumField<V extends string>(options: EnumOptions<V> & FieldOptions<V>): Field<V, never> {
|
|
92
|
+
const { choices, ...common } = options;
|
|
93
|
+
return createField({ kind: "enum", choices }, common);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function integerField(options: IntegerOptions & FieldOptions<number> = {}): Field<number, never> {
|
|
97
|
+
const { min, max, suggest, ...common } = options;
|
|
98
|
+
return createField({ kind: "integer", min, max, suggest }, common);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function numberField(options: BoundsOptions & FieldOptions<number> = {}): Field<number, never> {
|
|
102
|
+
const { min, max, ...common } = options;
|
|
103
|
+
return createField({ kind: "number", min, max }, common);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function textField(options: TextOptions & FieldOptions<string> = {}): Field<string, never> {
|
|
107
|
+
const { minLength, maxLength, suggest, ...common } = options;
|
|
108
|
+
return createField({ kind: "text", minLength, maxLength, suggest }, common);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function booleanField(options: FieldOptions<boolean> = {}): Field<boolean, never> {
|
|
112
|
+
return createField({ kind: "boolean" }, options);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function secretField(options: SecretOptions = {}): SecretField<"optional"> {
|
|
116
|
+
return { ...options, spec: { kind: "secret" }, required: options.required ?? false };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function listField<T>(
|
|
120
|
+
item: Field<T>,
|
|
121
|
+
options: ListOptions & FieldOptions<readonly T[]> = {},
|
|
122
|
+
): Field<readonly T[], never> {
|
|
123
|
+
const { minItems, maxItems, ...common } = options;
|
|
124
|
+
return createField({ kind: "list", item, minItems, maxItems }, common);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The declared keys all start `false`, then `default` sets its own; a key
|
|
129
|
+
* `default` names but `keys` lacks is kept, so the default fails its own field
|
|
130
|
+
* when the declaration is checked.
|
|
131
|
+
*/
|
|
132
|
+
function togglesField<K extends string>(
|
|
133
|
+
options: TogglesOptions<K>,
|
|
134
|
+
): Field<ToggleValues<K>, "defined"> {
|
|
135
|
+
const { keys, keyLabels, default: defaults, ...common } = options;
|
|
136
|
+
const off = Object.fromEntries(keys.map((key) => [key, false])) as Record<K, boolean>;
|
|
137
|
+
return createField(
|
|
138
|
+
{ kind: "toggles", keys, keyLabels },
|
|
139
|
+
{ ...common, default: { ...off, ...defaults } },
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Builders for every setting kind. Channel, role and user values are
|
|
145
|
+
* snowflake strings; texts in the options are catalog keys.
|
|
146
|
+
*/
|
|
147
|
+
export const field: FieldBuilders = {
|
|
148
|
+
channel: channelField,
|
|
149
|
+
role: roleField,
|
|
150
|
+
user: userField,
|
|
151
|
+
color: colorField,
|
|
152
|
+
duration: durationField,
|
|
153
|
+
enum: enumField,
|
|
154
|
+
integer: integerField,
|
|
155
|
+
number: numberField,
|
|
156
|
+
text: textField,
|
|
157
|
+
boolean: booleanField,
|
|
158
|
+
secret: secretField,
|
|
159
|
+
list: listField,
|
|
160
|
+
toggles: togglesField,
|
|
161
|
+
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type { Choice } from "@/settings/choice";
|
|
2
|
+
import type { ChannelKind } from "@/settings/ports/guild-directory";
|
|
3
|
+
|
|
4
|
+
/** Discord's hard limits that a declaration must stay within. */
|
|
5
|
+
export const FIELD_LIMITS = {
|
|
6
|
+
/** Longest text a Discord text input accepts. */
|
|
7
|
+
textMaxLength: 4000,
|
|
8
|
+
/** Most items a list field may hold (one select menu). */
|
|
9
|
+
listMaxItems: 25,
|
|
10
|
+
/** Most static choices an enum or a suggestion list may declare (one select menu). */
|
|
11
|
+
staticChoices: 25,
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
/** Kinds a list field may hold. */
|
|
15
|
+
export const LIST_ITEM_KINDS: readonly FieldKind[] = [
|
|
16
|
+
"channel",
|
|
17
|
+
"role",
|
|
18
|
+
"user",
|
|
19
|
+
"enum",
|
|
20
|
+
"integer",
|
|
21
|
+
"text",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Whether a field always has a value (`"defined"`: it has a default) or may be
|
|
26
|
+
* unset (`"optional"`: no default, even when required, since a guild may not
|
|
27
|
+
* have configured it yet). Drives the value type of {@link SettingsValues}.
|
|
28
|
+
*/
|
|
29
|
+
export type FieldPresence = "defined" | "optional";
|
|
30
|
+
|
|
31
|
+
declare const presence: unique symbol;
|
|
32
|
+
|
|
33
|
+
/** One labelled static choice: the stored value and the catalog key of its label. */
|
|
34
|
+
export interface FieldChoice<V> {
|
|
35
|
+
readonly value: V;
|
|
36
|
+
readonly label: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** What a suggestion search knows about the request. */
|
|
40
|
+
export interface SuggestionContext {
|
|
41
|
+
readonly guildId: string;
|
|
42
|
+
readonly userId: string;
|
|
43
|
+
readonly locale: string;
|
|
44
|
+
/** The other values currently entered, possibly unsaved. */
|
|
45
|
+
readonly values: Readonly<Record<string, unknown>>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A fixed list of suggested values (1 to 25). */
|
|
49
|
+
export interface StaticSuggestions<T> {
|
|
50
|
+
readonly choices: readonly FieldChoice<T>[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A server-side search. `strict` rejects values the search does not know. */
|
|
54
|
+
export interface DynamicSuggestions<T> {
|
|
55
|
+
resolve(query: string, ctx: SuggestionContext): Promise<readonly Choice[]>;
|
|
56
|
+
label?(value: T, ctx: SuggestionContext): Promise<string | undefined>;
|
|
57
|
+
readonly strict?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Suggestions offered while a value is typed. */
|
|
61
|
+
export type Suggestions<T> = StaticSuggestions<T> | DynamicSuggestions<T>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Presentation hints (FR-020). They describe meaning, not layout; surfaces may
|
|
65
|
+
* ignore them.
|
|
66
|
+
*/
|
|
67
|
+
export interface FieldUi<T = unknown> {
|
|
68
|
+
/** Id of a group declared on the module. */
|
|
69
|
+
readonly group?: string;
|
|
70
|
+
readonly order?: number;
|
|
71
|
+
/** Preferred control, e.g. `"slider"`. */
|
|
72
|
+
readonly hint?: string;
|
|
73
|
+
readonly advanced?: boolean;
|
|
74
|
+
readonly examples?: readonly T[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Options shared by every field kind. Texts are catalog keys. */
|
|
78
|
+
export interface FieldOptions<T> {
|
|
79
|
+
/** Required on a module's fields; a list item needs none. */
|
|
80
|
+
readonly label?: string;
|
|
81
|
+
readonly description?: string;
|
|
82
|
+
readonly placeholder?: string;
|
|
83
|
+
readonly unit?: string;
|
|
84
|
+
/** Unset until an administrator sets it, unless it has a default. */
|
|
85
|
+
readonly required?: boolean;
|
|
86
|
+
readonly default?: T;
|
|
87
|
+
readonly ui?: FieldUi<T>;
|
|
88
|
+
/** Opaque access declaration: stored, never enforced here (FR-032). */
|
|
89
|
+
readonly access?: unknown;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Kind-specific constraints of a field. */
|
|
93
|
+
export type FieldSpec =
|
|
94
|
+
| { readonly kind: "channel"; readonly types?: readonly ChannelKind[] }
|
|
95
|
+
| { readonly kind: "role" }
|
|
96
|
+
| { readonly kind: "user" }
|
|
97
|
+
| { readonly kind: "color" }
|
|
98
|
+
| { readonly kind: "duration"; readonly min?: number; readonly max?: number }
|
|
99
|
+
| { readonly kind: "enum"; readonly choices: readonly FieldChoice<string>[] }
|
|
100
|
+
| {
|
|
101
|
+
readonly kind: "integer";
|
|
102
|
+
readonly min?: number;
|
|
103
|
+
readonly max?: number;
|
|
104
|
+
readonly suggest?: Suggestions<number>;
|
|
105
|
+
}
|
|
106
|
+
| { readonly kind: "number"; readonly min?: number; readonly max?: number }
|
|
107
|
+
| {
|
|
108
|
+
readonly kind: "text";
|
|
109
|
+
readonly minLength?: number;
|
|
110
|
+
readonly maxLength?: number;
|
|
111
|
+
readonly suggest?: Suggestions<string>;
|
|
112
|
+
}
|
|
113
|
+
| { readonly kind: "boolean" }
|
|
114
|
+
| { readonly kind: "secret" }
|
|
115
|
+
| {
|
|
116
|
+
readonly kind: "list";
|
|
117
|
+
readonly item: AnyField;
|
|
118
|
+
readonly minItems?: number;
|
|
119
|
+
readonly maxItems?: number;
|
|
120
|
+
}
|
|
121
|
+
| {
|
|
122
|
+
readonly kind: "toggles";
|
|
123
|
+
readonly keys: readonly string[];
|
|
124
|
+
/** Catalog key of each key's label, by key. */
|
|
125
|
+
readonly keyLabels?: Readonly<Partial<Record<string, string>>>;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/** Every field kind. */
|
|
129
|
+
export type FieldKind = FieldSpec["kind"];
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A declared setting: its kind and constraints, its hints and its value type
|
|
133
|
+
* `T`. Built by the `field` builders; the validation schema behind it stays internal.
|
|
134
|
+
*/
|
|
135
|
+
export interface Field<T, P extends FieldPresence = FieldPresence> {
|
|
136
|
+
readonly spec: FieldSpec;
|
|
137
|
+
readonly label?: string;
|
|
138
|
+
readonly description?: string;
|
|
139
|
+
readonly placeholder?: string;
|
|
140
|
+
readonly unit?: string;
|
|
141
|
+
readonly required: boolean;
|
|
142
|
+
readonly default?: T;
|
|
143
|
+
readonly ui?: FieldUi<T>;
|
|
144
|
+
readonly access?: unknown;
|
|
145
|
+
/** Type-level only: never set at runtime. */
|
|
146
|
+
readonly [presence]?: P;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Any field, whatever its value type. */
|
|
150
|
+
export type AnyField = Field<unknown>;
|
|
151
|
+
|
|
152
|
+
/** A secret field: readable by module logic, write-only for surfaces. */
|
|
153
|
+
export type SecretField<P extends FieldPresence = FieldPresence> = Field<string, P> & {
|
|
154
|
+
readonly spec: { readonly kind: "secret" };
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/** Kind-specific options of a channel field. */
|
|
158
|
+
export type ChannelOptions = { readonly types?: readonly ChannelKind[] };
|
|
159
|
+
/** Inclusive numeric bounds of a duration, integer or number field. */
|
|
160
|
+
export type BoundsOptions = { readonly min?: number; readonly max?: number };
|
|
161
|
+
/** Kind-specific options of an integer field. */
|
|
162
|
+
export type IntegerOptions = BoundsOptions & { readonly suggest?: Suggestions<number> };
|
|
163
|
+
/** Kind-specific options of a text field. */
|
|
164
|
+
export type TextOptions = {
|
|
165
|
+
readonly minLength?: number;
|
|
166
|
+
readonly maxLength?: number;
|
|
167
|
+
readonly suggest?: Suggestions<string>;
|
|
168
|
+
};
|
|
169
|
+
/** Kind-specific options of a list field. */
|
|
170
|
+
export type ListOptions = { readonly minItems?: number; readonly maxItems?: number };
|
|
171
|
+
/** Kind-specific options of an enum field. */
|
|
172
|
+
export type EnumOptions<V> = { readonly choices: readonly FieldChoice<V>[] };
|
|
173
|
+
|
|
174
|
+
/** The value of a toggles field: one boolean per declared key. */
|
|
175
|
+
export type ToggleValues<K extends string> = Readonly<Record<K, boolean>>;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Options of a toggles field. `default` sets some keys; every other key
|
|
179
|
+
* defaults to `false`, so the field always has a value. `keyLabels` are
|
|
180
|
+
* catalog keys.
|
|
181
|
+
*/
|
|
182
|
+
export type TogglesOptions<K extends string> = Omit<
|
|
183
|
+
FieldOptions<ToggleValues<K>>,
|
|
184
|
+
"default" | "required"
|
|
185
|
+
> & {
|
|
186
|
+
readonly keys: readonly K[];
|
|
187
|
+
readonly keyLabels?: Readonly<Partial<Record<K, string>>>;
|
|
188
|
+
readonly default?: Readonly<Partial<Record<K, boolean>>>;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/** Options of a secret: no default, no examples. */
|
|
192
|
+
export type SecretOptions = Omit<FieldOptions<string>, "default" | "ui"> & {
|
|
193
|
+
readonly ui?: Omit<FieldUi, "examples">;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* The compile-time guard closing every `switch` on a field kind: a new kind
|
|
198
|
+
* left unhandled makes the call a type error instead of a silent fallthrough.
|
|
199
|
+
*
|
|
200
|
+
* @throws Error when reached at runtime, which only a spec built outside the
|
|
201
|
+
* type system can cause.
|
|
202
|
+
*/
|
|
203
|
+
export function unhandledFieldKind(spec: never): never {
|
|
204
|
+
throw new Error(`Unhandled field kind: ${(spec as FieldSpec).kind}`);
|
|
205
|
+
}
|