@azurioh/discord-kernel 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/authz/authorizer.d.ts +45 -0
- package/dist/authz/authorizer.d.ts.map +1 -0
- package/dist/authz/authorizer.js +31 -0
- package/dist/authz/authorizer.js.map +1 -0
- package/dist/authz/require-level-guard.d.ts +23 -0
- package/dist/authz/require-level-guard.d.ts.map +1 -0
- package/dist/authz/require-level-guard.js +37 -0
- package/dist/authz/require-level-guard.js.map +1 -0
- package/dist/clock.d.ts +13 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +13 -0
- package/dist/clock.js.map +1 -0
- package/dist/concurrency/keyed-queue.d.ts +18 -0
- package/dist/concurrency/keyed-queue.d.ts.map +1 -0
- package/dist/concurrency/keyed-queue.js +37 -0
- package/dist/concurrency/keyed-queue.js.map +1 -0
- package/dist/concurrency/run-with-concurrency.d.ts +15 -0
- package/dist/concurrency/run-with-concurrency.d.ts.map +1 -0
- package/dist/concurrency/run-with-concurrency.js +40 -0
- package/dist/concurrency/run-with-concurrency.js.map +1 -0
- package/dist/config/env.d.ts +17 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +49 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/errors.d.ts +14 -0
- package/dist/config/errors.d.ts.map +1 -0
- package/dist/config/errors.js +25 -0
- package/dist/config/errors.js.map +1 -0
- package/dist/datetime.d.ts +34 -0
- package/dist/datetime.d.ts.map +1 -0
- package/dist/datetime.js +188 -0
- package/dist/datetime.js.map +1 -0
- package/dist/discord/api-errors.d.ts +20 -0
- package/dist/discord/api-errors.d.ts.map +1 -0
- package/dist/discord/api-errors.js +90 -0
- package/dist/discord/api-errors.js.map +1 -0
- package/dist/discord/channel-exporter.d.ts +42 -0
- package/dist/discord/channel-exporter.d.ts.map +1 -0
- package/dist/discord/channel-exporter.js +3 -0
- package/dist/discord/channel-exporter.js.map +1 -0
- package/dist/discord/command/autocomplete-dispatcher.d.ts +26 -0
- package/dist/discord/command/autocomplete-dispatcher.d.ts.map +1 -0
- package/dist/discord/command/autocomplete-dispatcher.js +41 -0
- package/dist/discord/command/autocomplete-dispatcher.js.map +1 -0
- package/dist/discord/command/autocomplete.d.ts +18 -0
- package/dist/discord/command/autocomplete.d.ts.map +1 -0
- package/dist/discord/command/autocomplete.js +65 -0
- package/dist/discord/command/autocomplete.js.map +1 -0
- package/dist/discord/command/context.d.ts +33 -0
- package/dist/discord/command/context.d.ts.map +1 -0
- package/dist/discord/command/context.js +48 -0
- package/dist/discord/command/context.js.map +1 -0
- package/dist/discord/command/cooldown-guard.d.ts +25 -0
- package/dist/discord/command/cooldown-guard.d.ts.map +1 -0
- package/dist/discord/command/cooldown-guard.js +60 -0
- package/dist/discord/command/cooldown-guard.js.map +1 -0
- package/dist/discord/command/create-command.d.ts +100 -0
- package/dist/discord/command/create-command.d.ts.map +1 -0
- package/dist/discord/command/create-command.js +245 -0
- package/dist/discord/command/create-command.js.map +1 -0
- package/dist/discord/command/create-context-menu-command.d.ts +51 -0
- package/dist/discord/command/create-context-menu-command.d.ts.map +1 -0
- package/dist/discord/command/create-context-menu-command.js +128 -0
- package/dist/discord/command/create-context-menu-command.js.map +1 -0
- package/dist/discord/command/errors.d.ts +19 -0
- package/dist/discord/command/errors.d.ts.map +1 -0
- package/dist/discord/command/errors.js +27 -0
- package/dist/discord/command/errors.js.map +1 -0
- package/dist/discord/command/guard.d.ts +30 -0
- package/dist/discord/command/guard.d.ts.map +1 -0
- package/dist/discord/command/guard.js +34 -0
- package/dist/discord/command/guard.js.map +1 -0
- package/dist/discord/command/localization.d.ts +9 -0
- package/dist/discord/command/localization.d.ts.map +1 -0
- package/dist/discord/command/localization.js +13 -0
- package/dist/discord/command/localization.js.map +1 -0
- package/dist/discord/command/options.d.ts +113 -0
- package/dist/discord/command/options.d.ts.map +1 -0
- package/dist/discord/command/options.js +509 -0
- package/dist/discord/command/options.js.map +1 -0
- package/dist/discord/command/permission-guard.d.ts +21 -0
- package/dist/discord/command/permission-guard.d.ts.map +1 -0
- package/dist/discord/command/permission-guard.js +69 -0
- package/dist/discord/command/permission-guard.js.map +1 -0
- package/dist/discord/command/router.d.ts +48 -0
- package/dist/discord/command/router.d.ts.map +1 -0
- package/dist/discord/command/router.js +118 -0
- package/dist/discord/command/router.js.map +1 -0
- package/dist/discord/command/types.d.ts +51 -0
- package/dist/discord/command/types.d.ts.map +1 -0
- package/dist/discord/command/types.js +3 -0
- package/dist/discord/command/types.js.map +1 -0
- package/dist/discord/components/component-router.d.ts +116 -0
- package/dist/discord/components/component-router.d.ts.map +1 -0
- package/dist/discord/components/component-router.js +123 -0
- package/dist/discord/components/component-router.js.map +1 -0
- package/dist/discord/components/interactive-message/index.d.ts +3 -0
- package/dist/discord/components/interactive-message/index.d.ts.map +1 -0
- package/dist/discord/components/interactive-message/index.js +11 -0
- package/dist/discord/components/interactive-message/index.js.map +1 -0
- package/dist/discord/components/interactive-message/interactive-message-collector.d.ts +195 -0
- package/dist/discord/components/interactive-message/interactive-message-collector.d.ts.map +1 -0
- package/dist/discord/components/interactive-message/interactive-message-collector.js +151 -0
- package/dist/discord/components/interactive-message/interactive-message-collector.js.map +1 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.d.ts +30 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.d.ts.map +1 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.js +44 -0
- package/dist/discord/components/interactive-message/mount-interactive-message.js.map +1 -0
- package/dist/discord/components/paginator/index.d.ts +5 -0
- package/dist/discord/components/paginator/index.d.ts.map +1 -0
- package/dist/discord/components/paginator/index.js +15 -0
- package/dist/discord/components/paginator/index.js.map +1 -0
- package/dist/discord/components/paginator/mount-paginator.d.ts +25 -0
- package/dist/discord/components/paginator/mount-paginator.d.ts.map +1 -0
- package/dist/discord/components/paginator/mount-paginator.js +41 -0
- package/dist/discord/components/paginator/mount-paginator.js.map +1 -0
- package/dist/discord/components/paginator/page-state.d.ts +21 -0
- package/dist/discord/components/paginator/page-state.d.ts.map +1 -0
- package/dist/discord/components/paginator/page-state.js +44 -0
- package/dist/discord/components/paginator/page-state.js.map +1 -0
- package/dist/discord/components/paginator/paginator-buttons.d.ts +17 -0
- package/dist/discord/components/paginator/paginator-buttons.d.ts.map +1 -0
- package/dist/discord/components/paginator/paginator-buttons.js +45 -0
- package/dist/discord/components/paginator/paginator-buttons.js.map +1 -0
- package/dist/discord/components/paginator/paginator-view.d.ts +26 -0
- package/dist/discord/components/paginator/paginator-view.d.ts.map +1 -0
- package/dist/discord/components/paginator/paginator-view.js +28 -0
- package/dist/discord/components/paginator/paginator-view.js.map +1 -0
- package/dist/discord/components/persistent-paginator.d.ts +47 -0
- package/dist/discord/components/persistent-paginator.d.ts.map +1 -0
- package/dist/discord/components/persistent-paginator.js +137 -0
- package/dist/discord/components/persistent-paginator.js.map +1 -0
- package/dist/discord/components/settings-editor/index.d.ts +7 -0
- package/dist/discord/components/settings-editor/index.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/index.js +22 -0
- package/dist/discord/components/settings-editor/index.js.map +1 -0
- package/dist/discord/components/settings-editor/mount-settings-editor.d.ts +140 -0
- package/dist/discord/components/settings-editor/mount-settings-editor.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/mount-settings-editor.js +344 -0
- package/dist/discord/components/settings-editor/mount-settings-editor.js.map +1 -0
- package/dist/discord/components/settings-editor/navigation.d.ts +49 -0
- package/dist/discord/components/settings-editor/navigation.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/navigation.js +39 -0
- package/dist/discord/components/settings-editor/navigation.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts +56 -0
- package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-card.view.js +284 -0
- package/dist/discord/components/settings-editor/settings-editor-card.view.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts +69 -0
- package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-field-modal.js +353 -0
- package/dist/discord/components/settings-editor/settings-editor-field-modal.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.d.ts +216 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.js +66 -0
- package/dist/discord/components/settings-editor/settings-editor-fields.js.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor.view.d.ts +303 -0
- package/dist/discord/components/settings-editor/settings-editor.view.d.ts.map +1 -0
- package/dist/discord/components/settings-editor/settings-editor.view.js +316 -0
- package/dist/discord/components/settings-editor/settings-editor.view.js.map +1 -0
- package/dist/discord/events/create-event.d.ts +5 -0
- package/dist/discord/events/create-event.d.ts.map +1 -0
- package/dist/discord/events/create-event.js +8 -0
- package/dist/discord/events/create-event.js.map +1 -0
- package/dist/discord/events/event-router.d.ts +16 -0
- package/dist/discord/events/event-router.d.ts.map +1 -0
- package/dist/discord/events/event-router.js +51 -0
- package/dist/discord/events/event-router.js.map +1 -0
- package/dist/discord/events/types.d.ts +16 -0
- package/dist/discord/events/types.d.ts.map +1 -0
- package/dist/discord/events/types.js +3 -0
- package/dist/discord/events/types.js.map +1 -0
- package/dist/discord/i18n.d.ts +58 -0
- package/dist/discord/i18n.d.ts.map +1 -0
- package/dist/discord/i18n.js +173 -0
- package/dist/discord/i18n.js.map +1 -0
- package/dist/discord/interaction/button.d.ts +39 -0
- package/dist/discord/interaction/button.d.ts.map +1 -0
- package/dist/discord/interaction/button.js +36 -0
- package/dist/discord/interaction/button.js.map +1 -0
- package/dist/discord/interaction/interaction-router.d.ts +21 -0
- package/dist/discord/interaction/interaction-router.d.ts.map +1 -0
- package/dist/discord/interaction/interaction-router.js +24 -0
- package/dist/discord/interaction/interaction-router.js.map +1 -0
- package/dist/discord/interaction/modal.d.ts +171 -0
- package/dist/discord/interaction/modal.d.ts.map +1 -0
- package/dist/discord/interaction/modal.js +264 -0
- package/dist/discord/interaction/modal.js.map +1 -0
- package/dist/discord/interaction/select-menu.d.ts +104 -0
- package/dist/discord/interaction/select-menu.d.ts.map +1 -0
- package/dist/discord/interaction/select-menu.js +126 -0
- package/dist/discord/interaction/select-menu.js.map +1 -0
- package/dist/discord/permissions.d.ts +32 -0
- package/dist/discord/permissions.d.ts.map +1 -0
- package/dist/discord/permissions.js +40 -0
- package/dist/discord/permissions.js.map +1 -0
- package/dist/discord/placeholder-registry-errors.d.ts +10 -0
- package/dist/discord/placeholder-registry-errors.d.ts.map +1 -0
- package/dist/discord/placeholder-registry-errors.js +18 -0
- package/dist/discord/placeholder-registry-errors.js.map +1 -0
- package/dist/discord/placeholder-registry.d.ts +53 -0
- package/dist/discord/placeholder-registry.d.ts.map +1 -0
- package/dist/discord/placeholder-registry.js +52 -0
- package/dist/discord/placeholder-registry.js.map +1 -0
- package/dist/discord/presenter.d.ts +26 -0
- package/dist/discord/presenter.d.ts.map +1 -0
- package/dist/discord/presenter.js +3 -0
- package/dist/discord/presenter.js.map +1 -0
- package/dist/discord/ui/card.d.ts +114 -0
- package/dist/discord/ui/card.d.ts.map +1 -0
- package/dist/discord/ui/card.js +162 -0
- package/dist/discord/ui/card.js.map +1 -0
- package/dist/discord/ui/color-input-errors.d.ts +12 -0
- package/dist/discord/ui/color-input-errors.d.ts.map +1 -0
- package/dist/discord/ui/color-input-errors.js +21 -0
- package/dist/discord/ui/color-input-errors.js.map +1 -0
- package/dist/discord/ui/color-input.d.ts +37 -0
- package/dist/discord/ui/color-input.d.ts.map +1 -0
- package/dist/discord/ui/color-input.js +166 -0
- package/dist/discord/ui/color-input.js.map +1 -0
- package/dist/discord/ui/colors.d.ts +44 -0
- package/dist/discord/ui/colors.d.ts.map +1 -0
- package/dist/discord/ui/colors.js +45 -0
- package/dist/discord/ui/colors.js.map +1 -0
- package/dist/discord/ui/embed.d.ts +16 -0
- package/dist/discord/ui/embed.d.ts.map +1 -0
- package/dist/discord/ui/embed.js +53 -0
- package/dist/discord/ui/embed.js.map +1 -0
- package/dist/discord/ui/message-attachments.d.ts +40 -0
- package/dist/discord/ui/message-attachments.d.ts.map +1 -0
- package/dist/discord/ui/message-attachments.js +27 -0
- package/dist/discord/ui/message-attachments.js.map +1 -0
- package/dist/errors/business-error.d.ts +41 -0
- package/dist/errors/business-error.d.ts.map +1 -0
- package/dist/errors/business-error.js +39 -0
- package/dist/errors/business-error.js.map +1 -0
- package/dist/errors/describe-error.d.ts +29 -0
- package/dist/errors/describe-error.d.ts.map +1 -0
- package/dist/errors/describe-error.js +49 -0
- package/dist/errors/describe-error.js.map +1 -0
- package/dist/errors/incident-ref.d.ts +7 -0
- package/dist/errors/incident-ref.d.ts.map +1 -0
- package/dist/errors/incident-ref.js +13 -0
- package/dist/errors/incident-ref.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +15 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/i18n/business-message.d.ts +14 -0
- package/dist/i18n/business-message.d.ts.map +1 -0
- package/dist/i18n/business-message.js +19 -0
- package/dist/i18n/business-message.js.map +1 -0
- package/dist/i18n/catalog.d.ts +27 -0
- package/dist/i18n/catalog.d.ts.map +1 -0
- package/dist/i18n/catalog.js +25 -0
- package/dist/i18n/catalog.js.map +1 -0
- package/dist/i18n/errors.d.ts +10 -0
- package/dist/i18n/errors.d.ts.map +1 -0
- package/dist/i18n/errors.js +18 -0
- package/dist/i18n/errors.js.map +1 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +16 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/locale.d.ts +22 -0
- package/dist/i18n/locale.d.ts.map +1 -0
- package/dist/i18n/locale.js +40 -0
- package/dist/i18n/locale.js.map +1 -0
- package/dist/i18n/translator.d.ts +35 -0
- package/dist/i18n/translator.d.ts.map +1 -0
- package/dist/i18n/translator.js +40 -0
- package/dist/i18n/translator.js.map +1 -0
- package/dist/logger.d.ts +28 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +3 -0
- package/dist/logger.js.map +1 -0
- package/dist/module/module.d.ts +42 -0
- package/dist/module/module.d.ts.map +1 -0
- package/dist/module/module.js +3 -0
- package/dist/module/module.js.map +1 -0
- package/dist/persistence/database.d.ts +24 -0
- package/dist/persistence/database.d.ts.map +1 -0
- package/dist/persistence/database.js +3 -0
- package/dist/persistence/database.js.map +1 -0
- package/dist/resilience/retry.d.ts +36 -0
- package/dist/resilience/retry.d.ts.map +1 -0
- package/dist/resilience/retry.js +78 -0
- package/dist/resilience/retry.js.map +1 -0
- package/dist/scheduler/errors.d.ts +25 -0
- package/dist/scheduler/errors.d.ts.map +1 -0
- package/dist/scheduler/errors.js +45 -0
- package/dist/scheduler/errors.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +68 -0
- package/dist/scheduler/scheduler.d.ts.map +1 -0
- package/dist/scheduler/scheduler.js +162 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/package.json +89 -0
- package/src/authz/authorizer.ts +76 -0
- package/src/authz/require-level-guard.ts +42 -0
- package/src/clock.ts +18 -0
- package/src/concurrency/keyed-queue.ts +50 -0
- package/src/concurrency/run-with-concurrency.ts +44 -0
- package/src/config/env.ts +58 -0
- package/src/config/errors.ts +21 -0
- package/src/datetime.ts +221 -0
- package/src/discord/api-errors.ts +91 -0
- package/src/discord/channel-exporter.ts +48 -0
- package/src/discord/command/autocomplete-dispatcher.ts +54 -0
- package/src/discord/command/autocomplete.ts +76 -0
- package/src/discord/command/context.ts +85 -0
- package/src/discord/command/cooldown-guard.ts +81 -0
- package/src/discord/command/create-command.ts +431 -0
- package/src/discord/command/create-context-menu-command.ts +227 -0
- package/src/discord/command/errors.ts +22 -0
- package/src/discord/command/guard.ts +54 -0
- package/src/discord/command/localization.ts +11 -0
- package/src/discord/command/options.ts +847 -0
- package/src/discord/command/permission-guard.ts +74 -0
- package/src/discord/command/router.ts +142 -0
- package/src/discord/command/types.ts +52 -0
- package/src/discord/components/component-router.ts +213 -0
- package/src/discord/components/interactive-message/index.ts +18 -0
- package/src/discord/components/interactive-message/interactive-message-collector.ts +374 -0
- package/src/discord/components/interactive-message/mount-interactive-message.ts +71 -0
- package/src/discord/components/paginator/index.ts +17 -0
- package/src/discord/components/paginator/mount-paginator.ts +69 -0
- package/src/discord/components/paginator/page-state.ts +45 -0
- package/src/discord/components/paginator/paginator-buttons.ts +60 -0
- package/src/discord/components/paginator/paginator-view.ts +61 -0
- package/src/discord/components/persistent-paginator.ts +197 -0
- package/src/discord/components/settings-editor/index.ts +41 -0
- package/src/discord/components/settings-editor/mount-settings-editor.ts +646 -0
- package/src/discord/components/settings-editor/navigation.ts +67 -0
- package/src/discord/components/settings-editor/settings-editor-card.view.ts +344 -0
- package/src/discord/components/settings-editor/settings-editor-field-modal.ts +538 -0
- package/src/discord/components/settings-editor/settings-editor-fields.ts +290 -0
- package/src/discord/components/settings-editor/settings-editor.view.ts +654 -0
- package/src/discord/events/create-event.ts +7 -0
- package/src/discord/events/event-router.ts +53 -0
- package/src/discord/events/types.ts +17 -0
- package/src/discord/i18n.ts +173 -0
- package/src/discord/interaction/button.ts +75 -0
- package/src/discord/interaction/interaction-router.ts +28 -0
- package/src/discord/interaction/modal.ts +505 -0
- package/src/discord/interaction/select-menu.ts +246 -0
- package/src/discord/permissions.ts +57 -0
- package/src/discord/placeholder-registry-errors.ts +11 -0
- package/src/discord/placeholder-registry.ts +77 -0
- package/src/discord/presenter.ts +26 -0
- package/src/discord/ui/card.ts +303 -0
- package/src/discord/ui/color-input-errors.ts +17 -0
- package/src/discord/ui/color-input.ts +179 -0
- package/src/discord/ui/colors.ts +58 -0
- package/src/discord/ui/embed.ts +64 -0
- package/src/discord/ui/message-attachments.ts +57 -0
- package/src/errors/business-error.ts +49 -0
- package/src/errors/describe-error.ts +73 -0
- package/src/errors/incident-ref.ts +10 -0
- package/src/errors/index.ts +12 -0
- package/src/i18n/business-message.ts +23 -0
- package/src/i18n/catalog.ts +41 -0
- package/src/i18n/errors.ts +11 -0
- package/src/i18n/index.ts +11 -0
- package/src/i18n/locale.ts +41 -0
- package/src/i18n/translator.ts +78 -0
- package/src/logger.ts +28 -0
- package/src/module/module.ts +42 -0
- package/src/persistence/database.ts +23 -0
- package/src/resilience/retry.ts +102 -0
- package/src/scheduler/errors.ts +40 -0
- package/src/scheduler/scheduler.ts +248 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_CARD_TEXT_CHARACTERS = exports.MAX_CARD_COMPONENTS = void 0;
|
|
4
|
+
exports.createCard = createCard;
|
|
5
|
+
const discord_js_1 = require("discord.js");
|
|
6
|
+
const button_1 = require("../../discord/interaction/button");
|
|
7
|
+
/** Discord refuses a message carrying more components than this, container included. */
|
|
8
|
+
exports.MAX_CARD_COMPONENTS = 40;
|
|
9
|
+
/** Discord's cap on the characters carried by every `TextDisplay` in a message, summed. */
|
|
10
|
+
exports.MAX_CARD_TEXT_CHARACTERS = 4000;
|
|
11
|
+
/**
|
|
12
|
+
* The text an `entry` block renders, whether it ends up alone in a
|
|
13
|
+
* `TextDisplay` or riding along inside a `Section`.
|
|
14
|
+
*
|
|
15
|
+
* Composed as one `TextDisplay` — the title in bold, then each line on its
|
|
16
|
+
* own row — rather than one `TextDisplay` per line: a `Section` holds at
|
|
17
|
+
* most three text children, so a title plus more than two lines would
|
|
18
|
+
* already be out of room, and a single block reads as one paragraph instead
|
|
19
|
+
* of a list of unrelated fragments.
|
|
20
|
+
*/
|
|
21
|
+
function entryContent(block) {
|
|
22
|
+
const lines = block.lines ?? [];
|
|
23
|
+
return lines.length === 0 ? `**${block.title}**` : `**${block.title}**\n${lines.join("\n")}`;
|
|
24
|
+
}
|
|
25
|
+
/** How many characters of the 4000-character `TextDisplay` budget a block spends. */
|
|
26
|
+
function textCharacters(block) {
|
|
27
|
+
if (block.kind === "text") {
|
|
28
|
+
return block.content.length;
|
|
29
|
+
}
|
|
30
|
+
if (block.kind === "entry") {
|
|
31
|
+
return entryContent(block).length;
|
|
32
|
+
}
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
/** How many components a block compiles to, container itself excluded. */
|
|
36
|
+
function componentCount(block) {
|
|
37
|
+
switch (block.kind) {
|
|
38
|
+
case "text":
|
|
39
|
+
return 1;
|
|
40
|
+
case "entry":
|
|
41
|
+
// No accessory: one `TextDisplay`. Either accessory: the `Section`
|
|
42
|
+
// itself, its one `TextDisplay` child, and the accessory — three.
|
|
43
|
+
return block.action !== undefined || block.thumbnail !== undefined ? 3 : 1;
|
|
44
|
+
case "controls":
|
|
45
|
+
// The `ActionRow` plus every button it carries.
|
|
46
|
+
return 1 + block.buttons.length;
|
|
47
|
+
case "select":
|
|
48
|
+
// The `ActionRow` plus the menu itself.
|
|
49
|
+
return 2;
|
|
50
|
+
case "separator":
|
|
51
|
+
return 1;
|
|
52
|
+
case "gallery":
|
|
53
|
+
// Discord counts the gallery as one component; its items are data on
|
|
54
|
+
// it, not components of their own, the same way an embed's fields
|
|
55
|
+
// are not counted individually.
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Refuse a card Discord would refuse, naming what is over budget and by how
|
|
61
|
+
* much — the pattern `settings-editor.view.ts` (`assertFits`) already uses
|
|
62
|
+
* for a select menu's option cap. Checked once, at `createCard`, rather than
|
|
63
|
+
* at `apply()`: the block list does not vary with state, so failing here
|
|
64
|
+
* names the declaration instead of surfacing as a rejected message at
|
|
65
|
+
* whichever render happens to trip it first.
|
|
66
|
+
*/
|
|
67
|
+
function assertFitsBudget(blocks) {
|
|
68
|
+
// +1 for the container itself, which is a component in its own right.
|
|
69
|
+
const totalComponents = 1 + blocks.reduce((sum, block) => sum + componentCount(block), 0);
|
|
70
|
+
const totalCharacters = blocks.reduce((sum, block) => sum + textCharacters(block), 0);
|
|
71
|
+
const problems = [];
|
|
72
|
+
if (totalComponents > exports.MAX_CARD_COMPONENTS) {
|
|
73
|
+
problems.push(`${totalComponents} components (container included), Discord allows ${exports.MAX_CARD_COMPONENTS} — ${totalComponents - exports.MAX_CARD_COMPONENTS} over`);
|
|
74
|
+
}
|
|
75
|
+
if (totalCharacters > exports.MAX_CARD_TEXT_CHARACTERS) {
|
|
76
|
+
problems.push(`${totalCharacters} characters across its text, Discord allows ${exports.MAX_CARD_TEXT_CHARACTERS} — ${totalCharacters - exports.MAX_CARD_TEXT_CHARACTERS} over`);
|
|
77
|
+
}
|
|
78
|
+
if (problems.length > 0) {
|
|
79
|
+
throw new Error(`Card exceeds Discord's budget: ${problems.join("; ")}.`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Render one `entry` block: a `Section` with an accessory, or a bare `TextDisplay`. */
|
|
83
|
+
function applyEntry(container, block, state, forceDisabled) {
|
|
84
|
+
const text = new discord_js_1.TextDisplayBuilder().setContent(entryContent(block));
|
|
85
|
+
if (block.action !== undefined) {
|
|
86
|
+
container.addSectionComponents(new discord_js_1.SectionBuilder()
|
|
87
|
+
.addTextDisplayComponents(text)
|
|
88
|
+
.setButtonAccessory(block.action.apply(state, forceDisabled)));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (block.thumbnail !== undefined) {
|
|
92
|
+
container.addSectionComponents(new discord_js_1.SectionBuilder()
|
|
93
|
+
.addTextDisplayComponents(text)
|
|
94
|
+
.setThumbnailAccessory(new discord_js_1.ThumbnailBuilder().setURL(block.thumbnail)));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
container.addTextDisplayComponents(text);
|
|
98
|
+
}
|
|
99
|
+
/** Render one block onto the container being built, for the given state. */
|
|
100
|
+
function applyBlock(container, block, state, forceDisabled) {
|
|
101
|
+
switch (block.kind) {
|
|
102
|
+
case "text":
|
|
103
|
+
container.addTextDisplayComponents(new discord_js_1.TextDisplayBuilder().setContent(block.content));
|
|
104
|
+
return;
|
|
105
|
+
case "entry":
|
|
106
|
+
applyEntry(container, block, state, forceDisabled);
|
|
107
|
+
return;
|
|
108
|
+
case "controls":
|
|
109
|
+
container.addActionRowComponents((0, button_1.createActionRow)([...block.buttons], state, { disableAll: forceDisabled }));
|
|
110
|
+
return;
|
|
111
|
+
case "select":
|
|
112
|
+
container.addActionRowComponents(new discord_js_1.ActionRowBuilder().addComponents(block.menu.apply(forceDisabled)));
|
|
113
|
+
return;
|
|
114
|
+
case "separator": {
|
|
115
|
+
const separator = new discord_js_1.SeparatorBuilder();
|
|
116
|
+
if (block.spacing !== undefined) {
|
|
117
|
+
separator.setSpacing(block.spacing === "large" ? discord_js_1.SeparatorSpacingSize.Large : discord_js_1.SeparatorSpacingSize.Small);
|
|
118
|
+
}
|
|
119
|
+
if (block.divider !== undefined) {
|
|
120
|
+
separator.setDivider(block.divider);
|
|
121
|
+
}
|
|
122
|
+
container.addSeparatorComponents(separator);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
case "gallery":
|
|
126
|
+
container.addMediaGalleryComponents(new discord_js_1.MediaGalleryBuilder().addItems(...block.images.map((image) => {
|
|
127
|
+
const item = new discord_js_1.MediaGalleryItemBuilder().setURL(image.url);
|
|
128
|
+
if (image.description !== undefined) {
|
|
129
|
+
item.setDescription(image.description);
|
|
130
|
+
}
|
|
131
|
+
if (image.spoiler !== undefined) {
|
|
132
|
+
item.setSpoiler(image.spoiler);
|
|
133
|
+
}
|
|
134
|
+
return item;
|
|
135
|
+
})));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Declare a card: a definition compiling to a `ContainerBuilder`, the
|
|
141
|
+
* Components V2 analogue of an embed. Follows the same split as
|
|
142
|
+
* `createButton`/`createModal`/`createStringSelect` — data in, a compiled
|
|
143
|
+
* value with an `apply` out — so a caller never touches a V2 builder
|
|
144
|
+
* directly.
|
|
145
|
+
*/
|
|
146
|
+
function createCard(def) {
|
|
147
|
+
const blocks = def.blocks.filter((block) => block !== null);
|
|
148
|
+
assertFitsBudget(blocks);
|
|
149
|
+
return {
|
|
150
|
+
apply(state, forceDisabled = false) {
|
|
151
|
+
const container = new discord_js_1.ContainerBuilder();
|
|
152
|
+
if (def.accent !== undefined) {
|
|
153
|
+
container.setAccentColor(def.accent);
|
|
154
|
+
}
|
|
155
|
+
for (const block of blocks) {
|
|
156
|
+
applyBlock(container, block, state, forceDisabled);
|
|
157
|
+
}
|
|
158
|
+
return container;
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.js","sourceRoot":"","sources":["../../../src/discord/ui/card.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bot registered a colour name longer than the field an administrator types
|
|
3
|
+
* it into. Raised while the composition root registers its aliases at boot —
|
|
4
|
+
* the alternative is a name Discord silently truncates, which then never
|
|
5
|
+
* resolves and looks like the parser rejecting a colour it actually knows.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ColorAliasTooLongError extends Error {
|
|
8
|
+
readonly alias: string;
|
|
9
|
+
readonly maxLength: number;
|
|
10
|
+
constructor(alias: string, maxLength: number);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=color-input-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-input-errors.d.ts","sourceRoot":"","sources":["../../../src/discord/ui/color-input-errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAE/C,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM;gBADjB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM;CAO3B"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ColorAliasTooLongError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A bot registered a colour name longer than the field an administrator types
|
|
6
|
+
* it into. Raised while the composition root registers its aliases at boot —
|
|
7
|
+
* the alternative is a name Discord silently truncates, which then never
|
|
8
|
+
* resolves and looks like the parser rejecting a colour it actually knows.
|
|
9
|
+
*/
|
|
10
|
+
class ColorAliasTooLongError extends Error {
|
|
11
|
+
alias;
|
|
12
|
+
maxLength;
|
|
13
|
+
constructor(alias, maxLength) {
|
|
14
|
+
super(`Colour alias "${alias}" is ${alias.length} characters, over the ${maxLength} the input field accepts`);
|
|
15
|
+
this.alias = alias;
|
|
16
|
+
this.maxLength = maxLength;
|
|
17
|
+
this.name = "ColorAliasTooLongError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.ColorAliasTooLongError = ColorAliasTooLongError;
|
|
21
|
+
//# sourceMappingURL=color-input-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-input-errors.js","sourceRoot":"","sources":["../../../src/discord/ui/color-input-errors.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,MAAa,sBAAuB,SAAQ,KAAK;IAEtC;IACA;IAFV,YACU,KAAa,EACb,SAAiB;QAE1B,KAAK,CACJ,iBAAiB,KAAK,QAAQ,KAAK,CAAC,MAAM,yBAAyB,SAAS,0BAA0B,CACtG,CAAC;QALO,UAAK,GAAL,KAAK,CAAQ;QACb,cAAS,GAAT,SAAS,CAAQ;QAK1B,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACtC,CAAC;CACD;AAVD,wDAUC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every name a lookup answers to: the kernel's own, plus whatever the bot
|
|
3
|
+
* registered. Exposed for inspection — a screen listing the colours it accepts
|
|
4
|
+
* reads this — never for mutation, which goes through
|
|
5
|
+
* {@link registerColorAliases} so the length check cannot be skipped.
|
|
6
|
+
*/
|
|
7
|
+
export declare const COLOR_ALIASES: Readonly<Record<string, string>>;
|
|
8
|
+
/**
|
|
9
|
+
* What a colour input field may hold.
|
|
10
|
+
*
|
|
11
|
+
* Derived from the built-in table rather than written down, so adding a longer
|
|
12
|
+
* name here cannot leave the field silently truncating it at the client — and
|
|
13
|
+
* fixed rather than recomputed on registration, because field definitions read
|
|
14
|
+
* it once at module load, long before a bot registers anything.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAX_COLOR_INPUT_LENGTH: number;
|
|
17
|
+
/**
|
|
18
|
+
* Teach the parser the colours this bot calls by name — its brand gold, its
|
|
19
|
+
* team colours — from the composition root, before any module is constructed.
|
|
20
|
+
*
|
|
21
|
+
* A name over {@link MAX_COLOR_INPUT_LENGTH} is refused rather than accepted:
|
|
22
|
+
* the input field is already sized, so registering a longer name would let an
|
|
23
|
+
* administrator type a colour the client cuts short, which then reads as the
|
|
24
|
+
* parser rejecting a name it actually knows.
|
|
25
|
+
*
|
|
26
|
+
* @throws ColorAliasTooLongError when a name cannot fit the input field.
|
|
27
|
+
*/
|
|
28
|
+
export declare function registerColorAliases(aliases: Readonly<Record<string, string>>): void;
|
|
29
|
+
/**
|
|
30
|
+
* Normalize a colour input to `#RRGGBB`, from a hexadecimal code or from one of
|
|
31
|
+
* the names in {@link COLOR_ALIASES} — an administrator picking a colour should
|
|
32
|
+
* not have to look a hex code up. `null` for anything that is neither: the
|
|
33
|
+
* refusal an administrator reads belongs to whichever screen asked, so core
|
|
34
|
+
* reports that it could not read the value and leaves the wording to the caller.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseColorInput(raw: string): string | null;
|
|
37
|
+
//# sourceMappingURL=color-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-input.d.ts","sourceRoot":"","sources":["../../../src/discord/ui/color-input.ts"],"names":[],"mappings":"AAgGA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAE1D,CAAC;AAcF;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,QAGlC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAWpF;AAKD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAa1D"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_COLOR_INPUT_LENGTH = exports.COLOR_ALIASES = void 0;
|
|
4
|
+
exports.registerColorAliases = registerColorAliases;
|
|
5
|
+
exports.parseColorInput = parseColorInput;
|
|
6
|
+
const color_input_errors_1 = require("../../discord/ui/color-input-errors");
|
|
7
|
+
const colors_1 = require("../../discord/ui/colors");
|
|
8
|
+
/**
|
|
9
|
+
* The generic web colours, at the value the name carries everywhere else — an
|
|
10
|
+
* administrator typing `orange` gets the orange they would get in CSS, not a
|
|
11
|
+
* shade this module invented.
|
|
12
|
+
*/
|
|
13
|
+
const RED = "#ff0000";
|
|
14
|
+
const BLUE = "#0000ff";
|
|
15
|
+
const GREEN = "#008000";
|
|
16
|
+
const YELLOW = "#ffff00";
|
|
17
|
+
const ORANGE = "#ffa500";
|
|
18
|
+
const PURPLE = "#800080";
|
|
19
|
+
const PINK = "#ffc0cb";
|
|
20
|
+
const WHITE = "#ffffff";
|
|
21
|
+
/**
|
|
22
|
+
* Not `#000000`: Discord reads a zero colour as "no colour set" and renders the
|
|
23
|
+
* default grey bar instead, so pure black is the one value an administrator
|
|
24
|
+
* could ask for and never see. One step off zero reads as black.
|
|
25
|
+
*/
|
|
26
|
+
const BLACK = "#010101";
|
|
27
|
+
const GREY = "#808080";
|
|
28
|
+
const CYAN = "#00ffff";
|
|
29
|
+
const BROWN = "#a52a2a";
|
|
30
|
+
const SILVER = "#c0c0c0";
|
|
31
|
+
const TURQUOISE = "#40e0d0";
|
|
32
|
+
const MAGENTA = "#ff00ff";
|
|
33
|
+
const NAVY = "#000080";
|
|
34
|
+
/**
|
|
35
|
+
* Colour names an administrator may type instead of a hex code, French and
|
|
36
|
+
* English side by side.
|
|
37
|
+
*
|
|
38
|
+
* This table is **input vocabulary, not display text**. Nothing in it is ever
|
|
39
|
+
* shown to anyone, and its keys must never be translated at runtime: a catalog
|
|
40
|
+
* lookup resolves against the reply locale, which would make `rouge` stop
|
|
41
|
+
* working the moment an admin's Discord is set to English — the opposite of the
|
|
42
|
+
* point. Both spellings are accepted from everyone, always, which only a flat
|
|
43
|
+
* table can promise.
|
|
44
|
+
*
|
|
45
|
+
* These are the names the kernel ships. A bot adds its own — the colour it
|
|
46
|
+
* calls by its brand's name — through {@link registerColorAliases}, which is
|
|
47
|
+
* also why this table is not the one lookups read: {@link COLOR_ALIASES} is.
|
|
48
|
+
*/
|
|
49
|
+
const BUILT_IN_COLOR_ALIASES = {
|
|
50
|
+
red: RED,
|
|
51
|
+
rouge: RED,
|
|
52
|
+
blue: BLUE,
|
|
53
|
+
bleu: BLUE,
|
|
54
|
+
green: GREEN,
|
|
55
|
+
vert: GREEN,
|
|
56
|
+
yellow: YELLOW,
|
|
57
|
+
jaune: YELLOW,
|
|
58
|
+
orange: ORANGE,
|
|
59
|
+
purple: PURPLE,
|
|
60
|
+
// French for purple, not the CSS `violet` (a pale pink): an admin typing it
|
|
61
|
+
// here is asking for the colour the word means in their own language.
|
|
62
|
+
violet: PURPLE,
|
|
63
|
+
pink: PINK,
|
|
64
|
+
rose: PINK,
|
|
65
|
+
white: WHITE,
|
|
66
|
+
blanc: WHITE,
|
|
67
|
+
black: BLACK,
|
|
68
|
+
noir: BLACK,
|
|
69
|
+
grey: GREY,
|
|
70
|
+
gray: GREY,
|
|
71
|
+
gris: GREY,
|
|
72
|
+
cyan: CYAN,
|
|
73
|
+
brown: BROWN,
|
|
74
|
+
marron: BROWN,
|
|
75
|
+
silver: SILVER,
|
|
76
|
+
argent: SILVER,
|
|
77
|
+
argenté: SILVER,
|
|
78
|
+
turquoise: TURQUOISE,
|
|
79
|
+
magenta: MAGENTA,
|
|
80
|
+
navy: NAVY,
|
|
81
|
+
marine: NAVY,
|
|
82
|
+
blurple: colors_1.DISCORD_BLURPLE,
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Accents must not be a trap: `dore` and `doré` are the same request, and an
|
|
86
|
+
* administrator has no way of knowing which one this file happened to spell.
|
|
87
|
+
* Case and surrounding whitespace are folded for the same reason.
|
|
88
|
+
*/
|
|
89
|
+
function normalizeColorName(raw) {
|
|
90
|
+
return raw
|
|
91
|
+
.trim()
|
|
92
|
+
.toLowerCase()
|
|
93
|
+
.normalize("NFD")
|
|
94
|
+
.replace(/\p{Diacritic}/gu, "");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Every name a lookup answers to: the kernel's own, plus whatever the bot
|
|
98
|
+
* registered. Exposed for inspection — a screen listing the colours it accepts
|
|
99
|
+
* reads this — never for mutation, which goes through
|
|
100
|
+
* {@link registerColorAliases} so the length check cannot be skipped.
|
|
101
|
+
*/
|
|
102
|
+
exports.COLOR_ALIASES = {
|
|
103
|
+
...BUILT_IN_COLOR_ALIASES,
|
|
104
|
+
};
|
|
105
|
+
const COLORS_BY_NORMALIZED_NAME = new Map(Object.entries(exports.COLOR_ALIASES).map(([name, hex]) => [normalizeColorName(name), hex]));
|
|
106
|
+
/** The `#rrggbb` a recognised colour name stands for, `null` for anything else. */
|
|
107
|
+
function resolveNamedColor(raw) {
|
|
108
|
+
return COLORS_BY_NORMALIZED_NAME.get(normalizeColorName(raw)) ?? null;
|
|
109
|
+
}
|
|
110
|
+
/** `#RRGGBB` — the longest hexadecimal form the parser accepts. */
|
|
111
|
+
const HEX_INPUT_LENGTH = 7;
|
|
112
|
+
/**
|
|
113
|
+
* What a colour input field may hold.
|
|
114
|
+
*
|
|
115
|
+
* Derived from the built-in table rather than written down, so adding a longer
|
|
116
|
+
* name here cannot leave the field silently truncating it at the client — and
|
|
117
|
+
* fixed rather than recomputed on registration, because field definitions read
|
|
118
|
+
* it once at module load, long before a bot registers anything.
|
|
119
|
+
*/
|
|
120
|
+
exports.MAX_COLOR_INPUT_LENGTH = Math.max(HEX_INPUT_LENGTH, ...Object.keys(BUILT_IN_COLOR_ALIASES).map((name) => name.length));
|
|
121
|
+
/**
|
|
122
|
+
* Teach the parser the colours this bot calls by name — its brand gold, its
|
|
123
|
+
* team colours — from the composition root, before any module is constructed.
|
|
124
|
+
*
|
|
125
|
+
* A name over {@link MAX_COLOR_INPUT_LENGTH} is refused rather than accepted:
|
|
126
|
+
* the input field is already sized, so registering a longer name would let an
|
|
127
|
+
* administrator type a colour the client cuts short, which then reads as the
|
|
128
|
+
* parser rejecting a name it actually knows.
|
|
129
|
+
*
|
|
130
|
+
* @throws ColorAliasTooLongError when a name cannot fit the input field.
|
|
131
|
+
*/
|
|
132
|
+
function registerColorAliases(aliases) {
|
|
133
|
+
for (const [name, hex] of Object.entries(aliases)) {
|
|
134
|
+
if (name.length > exports.MAX_COLOR_INPUT_LENGTH) {
|
|
135
|
+
throw new color_input_errors_1.ColorAliasTooLongError(name, exports.MAX_COLOR_INPUT_LENGTH);
|
|
136
|
+
}
|
|
137
|
+
// Both views are written: the table is what a screen lists, the map is what
|
|
138
|
+
// a lookup reads, and a name present in one but not the other would be a
|
|
139
|
+
// colour the bot advertises and refuses.
|
|
140
|
+
exports.COLOR_ALIASES[name] = hex;
|
|
141
|
+
COLORS_BY_NORMALIZED_NAME.set(normalizeColorName(name), hex);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Discord accepts `#RGB` and `#RRGGBB`, with or without the leading hash. */
|
|
145
|
+
const HEX_COLOR_PATTERN = /^#?(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
146
|
+
/**
|
|
147
|
+
* Normalize a colour input to `#RRGGBB`, from a hexadecimal code or from one of
|
|
148
|
+
* the names in {@link COLOR_ALIASES} — an administrator picking a colour should
|
|
149
|
+
* not have to look a hex code up. `null` for anything that is neither: the
|
|
150
|
+
* refusal an administrator reads belongs to whichever screen asked, so core
|
|
151
|
+
* reports that it could not read the value and leaves the wording to the caller.
|
|
152
|
+
*/
|
|
153
|
+
function parseColorInput(raw) {
|
|
154
|
+
const value = raw.trim();
|
|
155
|
+
const named = resolveNamedColor(value);
|
|
156
|
+
if (named !== null) {
|
|
157
|
+
return named;
|
|
158
|
+
}
|
|
159
|
+
if (!HEX_COLOR_PATTERN.test(value)) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const digits = value.replace("#", "").toLowerCase();
|
|
163
|
+
const expanded = digits.length === 3 ? [...digits].map((digit) => `${digit}${digit}`).join("") : digits;
|
|
164
|
+
return `#${expanded}`;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=color-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-input.js","sourceRoot":"","sources":["../../../src/discord/ui/color-input.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The five roles an embed colour can play. A bot restyles by supplying its own
|
|
3
|
+
* values for these, never by adding a sixth: a role the kernel does not know is
|
|
4
|
+
* a module's own constant, not a theme entry.
|
|
5
|
+
*/
|
|
6
|
+
export interface EmbedColors {
|
|
7
|
+
success: number;
|
|
8
|
+
warning: number;
|
|
9
|
+
danger: number;
|
|
10
|
+
/** The bot's own identity, for embeds that should not read as Discord's. */
|
|
11
|
+
brand: number;
|
|
12
|
+
/** Neutral informational embeds — listings, recaps, previews. */
|
|
13
|
+
neutral: number;
|
|
14
|
+
}
|
|
15
|
+
/** Convert a `#rrggbb` string to the integer discord.js wants for `setColor`. */
|
|
16
|
+
export declare function toDiscordColor(hex: string): number;
|
|
17
|
+
/** Discord's own brand colour, the fallback for a bot that declares no palette. */
|
|
18
|
+
export declare const DISCORD_BLURPLE = "#5865f2";
|
|
19
|
+
/**
|
|
20
|
+
* What every embed renders as until the composition root says otherwise. Kept
|
|
21
|
+
* deliberately unbranded: a kernel that shipped one bot's colours would make
|
|
22
|
+
* every other bot start out wearing them.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DEFAULT_EMBED_COLORS: Readonly<EmbedColors>;
|
|
25
|
+
/**
|
|
26
|
+
* The live palette every embed reads, in the kernel and in the modules alike.
|
|
27
|
+
*
|
|
28
|
+
* This is the one piece of module-level state the kernel keeps, and it is a
|
|
29
|
+
* deliberate exception to "DI, no singletons". A colour is read deep inside pure
|
|
30
|
+
* view functions that build an embed from a value object — threading a theme
|
|
31
|
+
* through every one of them would put a parameter nobody reasons about on the
|
|
32
|
+
* whole rendering surface, to express something that is global by nature: a bot
|
|
33
|
+
* has one palette, decided once, for its entire run.
|
|
34
|
+
*
|
|
35
|
+
* Read it, never copy it: destructuring at module load captures the defaults
|
|
36
|
+
* before {@link configureEmbedColors} has run.
|
|
37
|
+
*/
|
|
38
|
+
export declare const EMBED_COLORS: EmbedColors;
|
|
39
|
+
/**
|
|
40
|
+
* Replace some or all of the palette. Call it from the composition root, before
|
|
41
|
+
* any module is constructed — after that, an embed may already have rendered.
|
|
42
|
+
*/
|
|
43
|
+
export declare function configureEmbedColors(overrides: Partial<EmbedColors>): void;
|
|
44
|
+
//# sourceMappingURL=colors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../../../src/discord/ui/colors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,mFAAmF;AACnF,eAAO,MAAM,eAAe,YAAY,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,WAAW,CAMtD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,EAAE,WAAyC,CAAC;AAErE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAE1E"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EMBED_COLORS = exports.DEFAULT_EMBED_COLORS = exports.DISCORD_BLURPLE = void 0;
|
|
4
|
+
exports.toDiscordColor = toDiscordColor;
|
|
5
|
+
exports.configureEmbedColors = configureEmbedColors;
|
|
6
|
+
/** Convert a `#rrggbb` string to the integer discord.js wants for `setColor`. */
|
|
7
|
+
function toDiscordColor(hex) {
|
|
8
|
+
return Number.parseInt(hex.slice(1), 16);
|
|
9
|
+
}
|
|
10
|
+
/** Discord's own brand colour, the fallback for a bot that declares no palette. */
|
|
11
|
+
exports.DISCORD_BLURPLE = "#5865f2";
|
|
12
|
+
/**
|
|
13
|
+
* What every embed renders as until the composition root says otherwise. Kept
|
|
14
|
+
* deliberately unbranded: a kernel that shipped one bot's colours would make
|
|
15
|
+
* every other bot start out wearing them.
|
|
16
|
+
*/
|
|
17
|
+
exports.DEFAULT_EMBED_COLORS = {
|
|
18
|
+
success: toDiscordColor("#22c55e"),
|
|
19
|
+
warning: toDiscordColor("#e67e22"),
|
|
20
|
+
danger: toDiscordColor("#ef4444"),
|
|
21
|
+
brand: toDiscordColor(exports.DISCORD_BLURPLE),
|
|
22
|
+
neutral: toDiscordColor(exports.DISCORD_BLURPLE),
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The live palette every embed reads, in the kernel and in the modules alike.
|
|
26
|
+
*
|
|
27
|
+
* This is the one piece of module-level state the kernel keeps, and it is a
|
|
28
|
+
* deliberate exception to "DI, no singletons". A colour is read deep inside pure
|
|
29
|
+
* view functions that build an embed from a value object — threading a theme
|
|
30
|
+
* through every one of them would put a parameter nobody reasons about on the
|
|
31
|
+
* whole rendering surface, to express something that is global by nature: a bot
|
|
32
|
+
* has one palette, decided once, for its entire run.
|
|
33
|
+
*
|
|
34
|
+
* Read it, never copy it: destructuring at module load captures the defaults
|
|
35
|
+
* before {@link configureEmbedColors} has run.
|
|
36
|
+
*/
|
|
37
|
+
exports.EMBED_COLORS = { ...exports.DEFAULT_EMBED_COLORS };
|
|
38
|
+
/**
|
|
39
|
+
* Replace some or all of the palette. Call it from the composition root, before
|
|
40
|
+
* any module is constructed — after that, an embed may already have rendered.
|
|
41
|
+
*/
|
|
42
|
+
function configureEmbedColors(overrides) {
|
|
43
|
+
Object.assign(exports.EMBED_COLORS, overrides);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=colors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colors.js","sourceRoot":"","sources":["../../../src/discord/ui/colors.ts"],"names":[],"mappings":";;;AAgBA,wCAEC;AAqCD,oDAEC;AA1CD,iFAAiF;AACjF,SAAgB,cAAc,CAAC,GAAW;IACzC,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,mFAAmF;AACtE,QAAA,eAAe,GAAG,SAAS,CAAC;AAEzC;;;;GAIG;AACU,QAAA,oBAAoB,GAA0B;IAC1D,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC;IAClC,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC;IAClC,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC;IACjC,KAAK,EAAE,cAAc,CAAC,uBAAe,CAAC;IACtC,OAAO,EAAE,cAAc,CAAC,uBAAe,CAAC;CACxC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACU,QAAA,YAAY,GAAgB,EAAE,GAAG,4BAAoB,EAAE,CAAC;AAErE;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,SAA+B;IACnE,MAAM,CAAC,MAAM,CAAC,oBAAY,EAAE,SAAS,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EmbedBuilder } from "discord.js";
|
|
2
|
+
/** A single embed field. */
|
|
3
|
+
export interface EmbedField {
|
|
4
|
+
name: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Add fields to an embed while respecting Discord's size limits. Truncates
|
|
9
|
+
* over-long names/values, stops before exceeding the 25-field or 6000-character
|
|
10
|
+
* caps, and appends an overflow footer when some fields were dropped — so the
|
|
11
|
+
* embed can always be sent (no `MAX_EMBED_SIZE_EXCEEDED` rejection).
|
|
12
|
+
*/
|
|
13
|
+
export declare function appendBoundedFields(embed: EmbedBuilder, fields: EmbedField[], overflowFooter: (hiddenCount: number) => string): void;
|
|
14
|
+
/** Build a plain titled embed. */
|
|
15
|
+
export declare function buildEmbed(title: string, description: string): EmbedBuilder;
|
|
16
|
+
//# sourceMappingURL=embed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../../../src/discord/ui/embed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAa1C,4BAA4B;AAC5B,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,UAAU,EAAE,EACpB,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,GAC7C,IAAI,CAsBN;AASD,kCAAkC;AAClC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,CAE3E"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.appendBoundedFields = appendBoundedFields;
|
|
4
|
+
exports.buildEmbed = buildEmbed;
|
|
5
|
+
const discord_js_1 = require("discord.js");
|
|
6
|
+
/** Discord hard limit on the number of fields per embed. */
|
|
7
|
+
const MAX_EMBED_FIELDS = 25;
|
|
8
|
+
/** Discord hard limit on a field name length. */
|
|
9
|
+
const MAX_FIELD_NAME = 256;
|
|
10
|
+
/** Discord hard limit on a field value length. */
|
|
11
|
+
const MAX_FIELD_VALUE = 1024;
|
|
12
|
+
/** Discord hard limit on the total character count of an embed. */
|
|
13
|
+
const MAX_EMBED_TOTAL = 6000;
|
|
14
|
+
/** Headroom kept free for footer/title so the total stays under the limit. */
|
|
15
|
+
const EMBED_TOTAL_SAFETY_MARGIN = 256;
|
|
16
|
+
/**
|
|
17
|
+
* Add fields to an embed while respecting Discord's size limits. Truncates
|
|
18
|
+
* over-long names/values, stops before exceeding the 25-field or 6000-character
|
|
19
|
+
* caps, and appends an overflow footer when some fields were dropped — so the
|
|
20
|
+
* embed can always be sent (no `MAX_EMBED_SIZE_EXCEEDED` rejection).
|
|
21
|
+
*/
|
|
22
|
+
function appendBoundedFields(embed, fields, overflowFooter) {
|
|
23
|
+
let usedChars = (embed.data.title?.length ?? 0) + (embed.data.description?.length ?? 0);
|
|
24
|
+
let shown = 0;
|
|
25
|
+
for (const field of fields) {
|
|
26
|
+
if (shown >= MAX_EMBED_FIELDS) {
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
const name = truncate(field.name, MAX_FIELD_NAME);
|
|
30
|
+
const value = truncate(field.value, MAX_FIELD_VALUE);
|
|
31
|
+
if (usedChars + name.length + value.length > MAX_EMBED_TOTAL - EMBED_TOTAL_SAFETY_MARGIN) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
embed.addFields({ name, value });
|
|
35
|
+
usedChars += name.length + value.length;
|
|
36
|
+
shown += 1;
|
|
37
|
+
}
|
|
38
|
+
const hidden = fields.length - shown;
|
|
39
|
+
if (hidden > 0) {
|
|
40
|
+
embed.setFooter({ text: overflowFooter(hidden) });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function truncate(text, max) {
|
|
44
|
+
if (text.length <= max) {
|
|
45
|
+
return text;
|
|
46
|
+
}
|
|
47
|
+
return `${text.slice(0, max - 1)}…`;
|
|
48
|
+
}
|
|
49
|
+
/** Build a plain titled embed. */
|
|
50
|
+
function buildEmbed(title, description) {
|
|
51
|
+
return new discord_js_1.EmbedBuilder().setTitle(title).setDescription(description);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=embed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed.js","sourceRoot":"","sources":["../../../src/discord/ui/embed.ts"],"names":[],"mappings":";;AAyBA,kDA0BC;AAUD,gCAEC;AA/DD,2CAA0C;AAE1C,4DAA4D;AAC5D,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,iDAAiD;AACjD,MAAM,cAAc,GAAG,GAAG,CAAC;AAC3B,kDAAkD;AAClD,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,mEAAmE;AACnE,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,8EAA8E;AAC9E,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAQtC;;;;;GAKG;AACH,SAAgB,mBAAmB,CAClC,KAAmB,EACnB,MAAoB,EACpB,cAA+C;IAE/C,IAAI,SAAS,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC;IACxF,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,KAAK,IAAI,gBAAgB,EAAE,CAAC;YAC/B,MAAM;QACP,CAAC;QACD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QACrD,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,eAAe,GAAG,yBAAyB,EAAE,CAAC;YAC1F,MAAM;QACP,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjC,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QACxC,KAAK,IAAI,CAAC,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACrC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAChB,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;AACF,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY,EAAE,GAAW;IAC1C,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AACrC,CAAC;AAED,kCAAkC;AAClC,SAAgB,UAAU,CAAC,KAAa,EAAE,WAAmB;IAC5D,OAAO,IAAI,yBAAY,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Attachment } from "discord.js";
|
|
2
|
+
/**
|
|
3
|
+
* A file a message carries: the bytes, and the name an embed resolves an
|
|
4
|
+
* `attachment://` reference on.
|
|
5
|
+
*
|
|
6
|
+
* `Uint8Array` rather than `Buffer` so a caller can produce one without
|
|
7
|
+
* reaching for a Node-specific type; the conversion happens here, at the edge
|
|
8
|
+
* that hands it to discord.js.
|
|
9
|
+
*/
|
|
10
|
+
export interface MessageFile {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly bytes: Uint8Array;
|
|
13
|
+
}
|
|
14
|
+
/** A file as discord.js takes it on a send or an edit. */
|
|
15
|
+
export interface MessageUpload {
|
|
16
|
+
readonly attachment: Buffer;
|
|
17
|
+
readonly name: string;
|
|
18
|
+
}
|
|
19
|
+
/** What an edit has to state for a message to end up carrying exactly what was asked. */
|
|
20
|
+
export interface PlannedAttachments {
|
|
21
|
+
readonly attachments: Attachment[];
|
|
22
|
+
readonly files: MessageUpload[];
|
|
23
|
+
}
|
|
24
|
+
export declare function toMessageUpload(file: MessageFile): MessageUpload;
|
|
25
|
+
/**
|
|
26
|
+
* Split what a message should carry into what is already up there and what has
|
|
27
|
+
* to be uploaded.
|
|
28
|
+
*
|
|
29
|
+
* Discord reads an edit's `attachments` field as the complete set the message
|
|
30
|
+
* keeps — so `attachments: []` strips whatever it was published with, and
|
|
31
|
+
* re-sending the bytes to hold on to a file would upload the same one again on
|
|
32
|
+
* every unrelated re-render. Existing attachments are matched by name because
|
|
33
|
+
* that is what an embed resolves `attachment://` on, so a file already up there
|
|
34
|
+
* under the wanted name is the very one to keep.
|
|
35
|
+
*
|
|
36
|
+
* A caller carrying no files of its own never reaches this: it states neither
|
|
37
|
+
* field, and Discord leaves the message's own alone.
|
|
38
|
+
*/
|
|
39
|
+
export declare function planMessageAttachments(existing: readonly Attachment[], wanted: readonly MessageFile[]): PlannedAttachments;
|
|
40
|
+
//# sourceMappingURL=message-attachments.d.ts.map
|