@seedcord/gateway 0.1.0 → 0.1.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["BaseHandler","CoreBaseHandler","BaseHandler","CoreRepliableHandler","BaseHandler","BaseHandler","BaseHandler","BaseArraySource","BaseCursorSource","CoreSubscriber","CoreWebhookLog","CorePlugin","logger","logger","packageVersion"],"sources":["../src/logger-bootstrap.ts","../src/bot/decorators/Events.ts","../src/bot/decorators/Gated.ts","../src/bot/decorators/Middlewares.ts","../src/bot/gates/catalog/IgnoreBots.ts","../src/bot/notices/index.ts","../src/bot/gates/catalog/Nsfw.ts","../src/bot/injectors/EmojiInjector.ts","../src/bot/notices/utils.ts","../src/bot/utilities/permissions/checkPermissions.ts","../src/bot/utilities/permissions/checkBotPermissions.ts","../src/bot/utilities/permissions/hasPermsToAssign.ts","../src/bot/confirm/reserved.ts","../src/bot/confirm/getConfirmation.ts","../src/handlers/BaseHandler.ts","../src/handlers/interaction/InteractionMiddleware.ts","../src/bot/ReplySender.ts","../src/handlers/RepliableHandler.ts","../src/handlers/interaction/InteractionHandler.ts","../src/bot/utilities/miscellaneous/slashRouteOf.ts","../src/handlers/interaction/SlashHandler.ts","../src/handlers/interaction/ContextMenuHandler.ts","../src/handlers/interaction/AutocompleteHandler.ts","../src/handlers/interaction/components/ComponentHandler.ts","../src/handlers/interaction/components/ButtonHandler.ts","../src/handlers/interaction/components/ModalHandler.ts","../src/handlers/interaction/components/SelectMenuHandler.ts","../src/handlers/event/EventHandler.ts","../src/handlers/event/EventMiddleware.ts","../src/pagination/Paginator.ts","../src/pagination/sources.ts","../src/subscribers/index.ts","../src/plugin.ts","../src/miscellaneous/deriveEventActor.ts","../src/bot/gates/runGates.ts","../src/miscellaneous/extractErrorResponse.ts","../src/bot/handleEventFault.ts","../src/bot/controllers/EventDispatcher.ts","../src/bot/defaults/UnhandledRepliable.ts","../src/bot/defaults/UnhandledAutocomplete.ts","../src/bot/harmlessApiCodes.ts","../src/bot/handleInteractionFault.ts","../src/bot/controllers/InteractionDispatcher.ts","../src/bot/Bot.ts","../src/version.ts","../src/Seedcord.ts"],"sourcesContent":["import { installNodeDefaults } from '@seedcord/logger/node';\n\n// the gateway runs on node so install the winston sinks before any logging\ninstallNodeDefaults();\n","import { EventMetadataKey } from '@seedcord/core/internal';\n\nimport type { EventHandler } from '@handlers/event';\nimport type { EventFrequency } from '@seedcord/types';\nimport type { ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\nimport type { Constructor } from 'type-fest';\n\n/** Options accepted by the event registration decorator. */\nexport interface RegisterEventOptions {\n /**\n * Frequency: 'once' or 'on'.\n *\n * @defaultValue `'on'`\n */\n readonly frequency?: EventFrequency | undefined;\n}\n\n/** @internal */\nexport interface RegisterEventMetadataEntry<EventKey extends keyof ClientEvents> {\n readonly event: EventKey;\n readonly frequency: EventFrequency;\n}\n\n/** Tuple describing a single event and optional options. */\nexport type EventSpec<EventKey extends ValidNonInteractionKeys> = readonly [\n event: EventKey,\n options?: RegisterEventOptions\n];\n\n/**\n * Registers an event handler class with one or more Discord.js events.\n *\n * Associates the decorated class with the provided Discord client events for automatic registration and execution when those events are emitted.\n *\n * Supply any number of event tuples. Each tuple can include per event options.\n *\n * @typeParam EventKey - Union of Discord.js ClientEvents keys to register for\n * @param defs - One or more tuples of [event, options]\n * @decorator\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate])\n * class MessageHandler extends EventHandler<Events.MessageCreate> {\n * async execute() {\n * // Handle message creation\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])\n * class MessageHandler extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {\n * async execute() {\n * // Handle message creation or update\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate, { frequency: 'once' }], [Events.MessageUpdate])\n * class OneTimeMessageHandler extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {\n * async execute() {\n * // Handle only the first message creation, and message update normally\n * }\n * }\n * ```\n */\nexport function RegisterEvent<const Defs extends readonly EventSpec<ValidNonInteractionKeys>[]>(...defs: Defs) {\n type EventKey = Defs[number][0];\n\n // EventHandler is invariant in its Names generic (match puts Names in the arms, a contravariant position), so\n // this single constraint rejects a handler whose generic and decorator list different events, both directions.\n return function <HandlerCtor extends Constructor<EventHandler<EventKey>>>(constructor: HandlerCtor): void {\n const saved = Reflect.getMetadata(EventMetadataKey, constructor) as\n | RegisterEventMetadataEntry<EventKey>[]\n | undefined;\n const existing = saved ?? [];\n\n const entries = defs.map<RegisterEventMetadataEntry<EventKey>>(([event, options]) => ({\n event,\n frequency: options?.frequency ?? 'on'\n }));\n\n Reflect.defineMetadata(EventMetadataKey, [...existing, ...entries], constructor);\n };\n}\n","import { GatedMetadataKey } from '@seedcord/core/internal';\n\nimport type { AnyHandlerCtor, FitAll } from '@bot/gates/matching';\nimport type { Gate, GateContextBase } from '@seedcord/core';\nimport type { NonEmptyTuple } from 'type-fest';\n\n/**\n * Attaches gates to a handler. The gates run before `execute`, and a gate refusing stops the handler with\n * the reply or drop the gate threw. Multiple gates are ANDed, so each must pass. A gate that requires a\n * context the handler does not provide (a button gate on a slash handler, an interaction gate on an event\n * handler) is a compile error at this line, and the error names the gate and the handler kind. Place it\n * above the route decorator.\n *\n * Combine gates with {@link and} or {@link or} to build a single gate from multiple arms.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(GuildOnly(), RequirePermissions([PermissionFlagsBits.Administrator]))\n * \\@SlashRoute('maintenance')\n * class Maintenance extends SlashHandler<'maintenance'> {\n * async execute() {\n * // both gates passed, so this runs in a guild with an admin caller\n * }\n * }\n * ```\n *\n * @typeParam Gates - The non-empty tuple of gates to run, in order, against the handler's context.\n * @typeParam TCtor - The decorated handler's constructor, checked against every gate's required context.\n * @param gates - One or more gates to attach, each ANDed so the handler runs only when all pass.\n * @param ctor - The handler class being decorated, rejected at compile time when a gate needs a context it lacks.\n *\n * @see {@link defineGate}\n * @see {@link defineEffectGate}\n * @decorator\n */\nexport function Gated<const Gates extends NonEmptyTuple<Gate<GateContextBase>>>(...gates: Gates) {\n // mismatch resolves to the error tuple, so the class fails to assign and TS names the gate\n return function <TCtor extends AnyHandlerCtor>(\n ctor: FitAll<TCtor, Gates> extends Gates ? TCtor : FitAll<TCtor, Gates>\n ): void {\n const existing = (Reflect.getMetadata(GatedMetadataKey, ctor) as readonly Gate[] | undefined) ?? [];\n Reflect.defineMetadata(GatedMetadataKey, [...existing, ...gates], ctor);\n };\n}\n","import { MiddlewareMetadataKey } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\n\nimport type { EventMiddleware } from '@handlers/event';\nimport type { InteractionMiddleware } from '@handlers/interaction';\nimport type { Repliables, ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Middleware types supported by Seedcord\n */\nexport enum MiddlewareType {\n Interaction = 'interaction',\n Event = 'event'\n}\n\n/**\n * Additional middleware registration options\n *\n * @typeParam MType - The type of middleware being registered\n */\nexport interface MiddlewareOptions<\n MType extends MiddlewareType,\n Events extends readonly ValidNonInteractionKeys[] = readonly ValidNonInteractionKeys[]\n> {\n /**\n * Restrict event middleware execution to specific Discord client events. The middleware's `EventMiddleware`\n * generic must list the same events, or applying the decorator is a compile error.\n */\n readonly events?: MType extends MiddlewareType.Event ? Events : never;\n}\n\n/** @internal */\nexport interface MiddlewareMetadata {\n priority: number;\n type: MiddlewareType;\n events?: readonly ValidNonInteractionKeys[];\n}\n\n/**\n * Decorator used to register middleware with priority ordering. The lower the priority number, the earlier it runs.\n *\n * Interaction middleware cannot specify event filters.\n *\n * @param type - Middleware kind from {@link MiddlewareType}\n * @param priority - Ordering value where lower runs earlier. {@default `0` }\n * @param options - Additional registration options\n *\n * @decorator\n *\n * @example\n * ```ts\n * \\@Middleware(MiddlewareType.Event, 10, { events: [Events.MessageCreate, Events.MessageUpdate] })\n * class MyEventMiddleware extends EventMiddleware {}\n * ```\n * @throws A **SeedcordTypeError** If priority is not a finite number\n * @throws A **SeedcordError** If interaction middleware specifies event filters\n */\nexport function Middleware<MType extends MiddlewareType, const Events extends readonly ValidNonInteractionKeys[] = []>(\n type: MType,\n priority = 0,\n options: MiddlewareOptions<MType, Events> = {}\n) {\n return (\n ctor: MType extends MiddlewareType.Interaction\n ? Constructor<InteractionMiddleware<Repliables>>\n : Events extends readonly []\n ? Constructor<EventMiddleware<ValidNonInteractionKeys>>\n : Constructor<EventMiddleware<Events[number]>>\n ): void => {\n const normalizedPriority = Number(priority);\n if (!Number.isFinite(normalizedPriority)) {\n throw new SeedcordTypeError(SeedcordErrorCode.DecoratorInvalidMiddlewarePriority);\n }\n\n if (type === MiddlewareType.Interaction && Array.isArray(options.events) && options.events.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorInteractionEventFilter);\n }\n\n const metadata: MiddlewareMetadata = {\n priority: normalizedPriority,\n type,\n // an empty array means catchall, only store a real filter\n ...(options.events && options.events.length > 0 && { events: options.events })\n };\n\n Reflect.defineMetadata(MiddlewareMetadataKey, metadata, ctor);\n };\n}\n","import { defineGate, Silence } from '@seedcord/core';\n\nimport type { EventGateContext } from '../Gate';\n\n/**\n * Drops a client event whose actor is a bot, with a {@link Silence} so nothing is replied. Event-only, because a\n * Silence on an interaction would leave Discord's failed-interaction state. It rejects an interaction handler at\n * the decorator line. Takes no options, so attach it directly without calling it.\n *\n * @see {@link Gated}\n *\n * @example\n * ```ts\n * import { Events } from 'discord.js';\n *\n * \\@Gated(IgnoreBots)\n * class OnMessage extends EventHandler<Events.MessageCreate> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport const IgnoreBots = defineGate('IgnoreBots', (ctx: EventGateContext) => {\n if (ctx.user?.bot) throw new Silence('actor is a bot');\n});\n","import { Notice } from '@seedcord/core';\nimport { GateNotice, NoticeCard } from '@seedcord/core/internal';\n\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { Role } from 'discord.js';\n\nexport class NotNsfw extends GateNotice {\n public constructor(message = 'This can only be used in an age-restricted channel.') {\n super(message);\n }\n}\n\nexport class RoleHigherThanMe extends Notice {\n public constructor(\n message: string,\n public role: Role,\n public botRole: Role\n ) {\n super(message);\n }\n\n public render(): ReplyResponse {\n const card = new NoticeCard(\n `I cannot assign a role that is higher than me.\\n\\n` +\n `The role <@&${this.role.id}> is higher than my role <@&${this.botRole.id}> in the hierarchy.`\n );\n return { components: [card.component] };\n }\n}\n\nexport class CannotAssignBotRole extends Notice {\n public constructor(message = 'I cannot assign a managed role.') {\n super(message);\n }\n\n public render(): ReplyResponse {\n return { components: [new NoticeCard('I cannot assign a managed role.').component] };\n }\n}\n","import { defineGate } from '@seedcord/core';\nimport { pickNotice } from '@seedcord/core/internal';\n\nimport { NotNsfw } from '@bot/notices';\n\nimport type { InteractionGateContext } from '../Gate';\nimport type { Gate, GateNoticeOptions } from '@seedcord/core';\nimport type { NonModalInteraction } from '@src/handlers/interactionTypes';\n\n// a thread carries no nsfw flag of its own, so it inherits the parent channel's\nfunction channelIsNsfw(channel: InteractionGateContext['interaction']['channel']): boolean {\n if (!channel) return false;\n if (channel.isThread()) return channel.parent?.nsfw ?? false;\n return 'nsfw' in channel ? channel.nsfw : false;\n}\n\n/**\n * Requires an age-restricted channel, else refuses. Pass {@link GateNoticeOptions} to reword or replace the refusal.\n *\n * A thread inherits its parent channel's nsfw flag. ModalSubmit has no reliable channel, so it is excluded.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see {@link Gated}\n *\n * @example\n * ```ts\n * \\@Gated(Nsfw())\n * \\@SlashRoute('nsfwcmd')\n * class NsfwHandler extends SlashHandler<'nsfwcmd'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function Nsfw(options?: GateNoticeOptions): Gate<InteractionGateContext<NonModalInteraction>, 'Nsfw'> {\n return defineGate('Nsfw', (ctx: InteractionGateContext<NonModalInteraction>) => {\n if (channelIsNsfw(ctx.interaction.channel)) return;\n throw pickNotice(options, (message) => new NotNsfw(message));\n });\n}\n","import { accessorStore, clearStore, guardedAccessor, isEmojiTuple } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\n\nimport type { Core } from '@interfaces/Core';\nimport type { EmojiMap } from '@seedcord/types';\nimport type { ApplicationEmoji, GuildEmoji } from 'discord.js';\n\ntype SavedEmojiType = GuildEmoji | ApplicationEmoji;\n\nconst emojiStorage = accessorStore<SavedEmojiType>();\n\n/**\n * The global {@link Emojis} accessor type. Each key resolves to its precise class, `GuildEmoji` for a `'guild'`\n * tag and `ApplicationEmoji` for an `'application'` tag, the tags `seedcord codegen` writes into {@link EmojiMap}.\n */\nexport type InjectedEmojiMap = {\n [K in keyof EmojiMap]: EmojiMap[K] extends 'guild' ? GuildEmoji : ApplicationEmoji;\n};\n\n/**\n * The bot's resolved emojis, keyed by {@link EmojiMap}. Filled by {@link EmojiInjector} during startup.\n * A read before that throws.\n */\nexport const Emojis = guardedAccessor('Emojis', emojiStorage) as InjectedEmojiMap;\n\n/**\n * Loads and injects emojis based on bot configuration. A guild emoji requires the Guilds intent in the client\n * options.\n *\n * @internal\n */\nexport class EmojiInjector {\n private readonly logger = new Logger('Emojis', { channel: 'bot' });\n\n constructor(private readonly core: Core) {}\n\n public async init(): Promise<void> {\n this.clearEmojis();\n\n if (!this.core.config.bot.emojis || Object.keys(this.core.config.bot.emojis).length === 0) {\n this.logger.debug('No emojis configured, skipping emoji injection.');\n return;\n }\n\n const configEmojis = this.core.config.bot.emojis;\n await this.core.bot.client.application?.emojis.fetch();\n\n const failures: string[] = [];\n const fetchedGuilds = new Set<string>();\n for (const [key, value] of Object.entries(configEmojis)) {\n if (isEmojiTuple(value)) {\n await this.resolveTuple(key, value, failures, fetchedGuilds);\n } else if (typeof value === 'string') {\n this.resolveString(key, value, failures);\n } else {\n failures.push(` - \"${key}\" has an invalid value (expected a name or [name, guildId])`);\n }\n }\n\n // surface every unresolved emoji at once so the user fixes the whole config in one pass\n if (failures.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.ConfigEmojiUnresolved, [failures.length, failures.join('\\n')]);\n }\n\n this.logger.utils.summary('Loaded emojis', { emojis: Object.keys(emojiStorage).length });\n }\n\n private async resolveTuple(\n key: string,\n value: readonly [string, string],\n failures: string[],\n fetchedGuilds: Set<string>\n ): Promise<void> {\n const [emojiName, guildId] = value;\n\n const guild = this.core.bot.client.guilds.cache.get(guildId);\n if (!guild) {\n failures.push(\n ` - \"${emojiName}\" for \"${key}\" targets guild ${guildId}, which is not available (check the Guilds intent)`\n );\n return;\n }\n\n if (!fetchedGuilds.has(guildId)) {\n await guild.emojis.fetch();\n fetchedGuilds.add(guildId);\n }\n const guildEmoji = guild.emojis.cache.find((e) => e.name === emojiName);\n if (!guildEmoji) {\n failures.push(` - \"${emojiName}\" for \"${key}\" was not found in guild ${guildId}`);\n return;\n }\n\n emojiStorage[key] = guildEmoji;\n }\n\n private resolveString(key: string, emojiName: string, failures: string[]): void {\n const appEmoji = this.core.bot.client.application?.emojis.cache.find((e) => e.name === emojiName);\n if (!appEmoji) {\n failures.push(` - \"${emojiName}\" for \"${key}\" was not found among the application emojis`);\n return;\n }\n\n emojiStorage[key] = appEmoji;\n }\n\n private clearEmojis(): void {\n clearStore(emojiStorage);\n }\n}\n","import { Role } from 'discord.js';\n\nimport type { GuildMember } from 'discord.js';\n\n// whose permissions a check ran against, mentioned as the refusal subject\ntype PermSubject = Role | GuildMember;\n\nexport function mentionFor(subject: PermSubject): string {\n if (subject instanceof Role) return `<@&${subject.id}>`;\n return `<@${subject.id}>`;\n}\n","import { assertPermissions } from '@seedcord/core';\nimport { Guild, GuildMember, Role } from 'discord.js';\n\nimport { mentionFor } from '@bot/notices/utils';\n\nimport type { PermissionNoticeOverrides, PermissionScope } from '@seedcord/core';\nimport type { TextChannel } from 'discord.js';\n\n/** Options for {@link checkPermissions}. */\nexport interface CheckPermissionOptions extends PermissionNoticeOverrides {\n /** The role or member to check. */\n for: Role | GuildMember;\n /** A guild reads the base bits from roles, a text channel reads the overwrite-resolved set. */\n in: Guild | TextChannel;\n /** The permission flag bits to check. */\n scope: PermissionScope;\n /** Refuse when the target holds a scope bit. */\n inverse?: boolean;\n}\n\n/**\n * Checks a {@link Role} or a {@link GuildMember} against the base permission bits in a {@link Guild},\n * before channel overwrites. Refuses when a permission in `scope` is missing, or with `inverse` when one\n * is present.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * checkPermissions(role, guild, [PermissionFlagsBits.ManageMessages, PermissionFlagsBits.KickMembers]);\n * ```\n *\n * @example\n * ```ts\n * // refuse when the member holds Administrator, and replace the refusal\n * checkPermissions(member, guild, [PermissionFlagsBits.Administrator], true, {\n * dangerousNotice: CustomDangerousNotice\n * });\n * ```\n */\nexport function checkPermissions(\n target: Role | GuildMember,\n ctx: Guild,\n scope: PermissionScope,\n inverse?: boolean,\n errors?: PermissionNoticeOverrides\n): void;\n\n/**\n * Checks a {@link Role} or a {@link GuildMember} against the overwrite-resolved set in a\n * {@link TextChannel}. Refuses when a permission in `scope` is missing, or with `inverse` when one is\n * present.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * checkPermissions(role, textChannel, [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]);\n * ```\n */\nexport function checkPermissions(\n target: Role | GuildMember,\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- the guild and channel forms resolve different bits, documented separately\n ctx: TextChannel,\n scope: PermissionScope,\n inverse?: boolean,\n errors?: PermissionNoticeOverrides\n): void;\n\n/**\n * Checks permissions with an options object. Refuses when a permission in\n * {@link CheckPermissionOptions.scope} is missing, or with `options.inverse` when one is present.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * checkPermissions({\n * for: member,\n * in: textChannel,\n * scope: [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]\n * });\n * ```\n */\nexport function checkPermissions(options: CheckPermissionOptions): void;\n\nexport function checkPermissions(\n a: Role | GuildMember | CheckPermissionOptions,\n b?: Guild | TextChannel,\n c?: PermissionScope,\n d?: boolean,\n e?: PermissionNoticeOverrides\n): void {\n const opts: CheckPermissionOptions =\n a instanceof Role || a instanceof GuildMember\n ? // justified: the positional overloads always supply b and c, the implementation signature widens them to | undefined\n {\n for: a,\n in: b as Guild | TextChannel,\n scope: c as PermissionScope,\n inverse: d ?? false,\n ...e\n }\n : a;\n\n const { for: pFor, in: pIn, scope, inverse = false, missingNotice, dangerousNotice } = opts;\n\n const perms = pIn instanceof Guild ? pFor.permissions : pIn.permissionsFor(pFor, true);\n\n assertPermissions({\n subject: mentionFor(pFor),\n permissions: perms.bitfield,\n scope,\n inverse,\n ...(missingNotice && { missingNotice }),\n ...(dangerousNotice && { dangerousNotice })\n });\n}\n","import { MissingPermissions, PermissionNames } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/logger';\nimport { Guild } from 'discord.js';\n\nimport { checkPermissions } from './checkPermissions';\n\nimport type { PermissionNoticeOverrides, PermissionScope } from '@seedcord/core';\nimport type { TextChannel } from 'discord.js';\n\n/**\n * Checks the bot's own permissions in a {@link Guild} or {@link TextChannel}. Refuses when a permission in\n * `scope` is missing, or with `inverse` when one is present. When the bot member is uncached, the refusal\n * reports every permission in `scope` as missing.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkBotPermissions } from '@seedcord/gateway';\n *\n * checkBotPermissions(textChannel, [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]);\n * ```\n */\nexport function checkBotPermissions(\n target: Guild | TextChannel,\n scope: PermissionScope,\n inverse = false,\n errors?: PermissionNoticeOverrides\n): void {\n if (target instanceof Guild) {\n const me = target.members.me;\n if (!me) {\n const names = scope.map((bit) => PermissionNames.get(bit) ?? String(bit));\n const Missing = errors?.missingNotice ?? MissingPermissions;\n throw new Missing(undefined, 'The bot', names);\n }\n checkPermissions(me, target, scope, inverse, errors);\n return;\n }\n\n const me = target.guild.members.me;\n\n if (!me) {\n const logger = new Logger('checkBotPermissions', { channel: 'errors' });\n logger.warn(\n `Bot member is unavailable in guild ${target.guild.id} while checking permissions in channel ${target.id}`\n );\n const names = scope.map((bit) => PermissionNames.get(bit) ?? String(bit));\n const Missing = errors?.missingNotice ?? MissingPermissions;\n throw new Missing(undefined, 'The bot', names);\n }\n\n checkPermissions(me, target, scope, inverse, errors);\n}\n","import { MissingPermissions } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { PermissionFlagsBits, Role } from 'discord.js';\n\nimport { CannotAssignBotRole, RoleHigherThanMe } from '@bot/notices';\n\nimport { checkBotPermissions } from './checkBotPermissions';\n\nimport type { Notice } from '@seedcord/core';\nimport type { Guild } from 'discord.js';\n\n/**\n * Optional custom error constructors for {@link HasPermsToAssignOptions}.\n */\nexport interface AssignRoleNoticeOverrides {\n higherNotice?: new (message: string, role: Role, botRole: Role) => Notice;\n managedNotice?: new (message: string) => Notice;\n missingNotice?: new (message: string | undefined, subject: string, missingPerms: readonly string[]) => Notice;\n}\n\n/**\n * Options for {@link hasPermsToAssign}.\n */\nexport interface HasPermsToAssignOptions {\n targetRole: Role;\n noticeOverrides?: AssignRoleNoticeOverrides;\n}\n\n// botRoleFor searches the guild's role cache, so a cold cache returns null\nfunction botRoleOf(guild: Guild): Role {\n const botRole = guild.roles.botRoleFor(guild.client.user);\n if (!botRole) throw new SeedcordError(SeedcordErrorCode.CoreBotRoleMissing, [guild.id]);\n return botRole;\n}\n\n/**\n * Validates that the bot can assign a target role. Refuses when the target role is above the bot's, is managed, or the bot lacks Manage Roles.\n *\n * @param roleOrOptions - Target role or complete options for the check\n * @throws A `Notice` on refusal, or a `SeedcordError` when the bot has no role in the guild's role cache.\n *\n * @example\n * ```ts\n * import { hasPermsToAssign } from '@seedcord/gateway';\n *\n * // Check if the bot can assign a specific role\n * hasPermsToAssign(role);\n *\n * // Check with custom error handling\n * hasPermsToAssign({\n * targetRole: role,\n * noticeOverrides: {\n * higherNotice: CustomHigherNotice,\n * managedNotice: CustomManagedNotice,\n * missingNotice: CustomMissingPermissionsNotice\n * }\n * });\n * ```\n */\nexport function hasPermsToAssign(roleOrOptions: Role | HasPermsToAssignOptions): void {\n const { targetRole, noticeOverrides: errors } =\n roleOrOptions instanceof Role\n ? {\n targetRole: roleOrOptions,\n noticeOverrides: undefined\n }\n : roleOrOptions;\n\n const HigherNotice = errors?.higherNotice ?? RoleHigherThanMe;\n const ManagedNotice = errors?.managedNotice ?? CannotAssignBotRole;\n const MissingNotice = errors?.missingNotice ?? MissingPermissions;\n\n const botRole = botRoleOf(targetRole.guild);\n\n if (targetRole.comparePositionTo(botRole) >= 0) {\n throw new HigherNotice('Role is higher than me', targetRole, botRole);\n }\n\n if (targetRole.managed) {\n throw new ManagedNotice(`Cannot assign managed role ${targetRole.name}`);\n }\n\n checkBotPermissions(targetRole.guild, [PermissionFlagsBits.ManageRoles], false, { missingNotice: MissingNotice });\n}\n","import { CustomId } from '@seedcord/core';\n\nconst RESERVED_CONFIRM_PREFIX = '__seedcord_confirm';\n\n/**\n * The reserved confirm/cancel codec. It has no route, so the dispatcher ignores its clicks and only the\n * in-process collector reads them. Do not mint a real component from it.\n *\n * @internal\n */\nexport const CONFIRM_DEF = new CustomId(RESERVED_CONFIRM_PREFIX).oneOf('choice', ['confirm', 'cancel']);\n","import { ButtonBuilder, TextDisplayBuilder } from '@discordjs/builders';\nimport { BuilderComponent, RowComponent } from '@seedcord/core';\nimport { ButtonStyle, ComponentType } from 'discord.js';\n\nimport { CONFIRM_DEF } from './reserved';\n\nimport type { ReplySender } from '@bot/ReplySender';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { NonModalInteraction } from '@src/handlers/interactionTypes';\nimport type { RepliableHandler } from '@src/handlers/RepliableHandler';\nimport type { ButtonInteraction, Message } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n// the reserved def's shape and choices never change, so encode the ids once\nconst CONFIRM_IDS = {\n confirm: CONFIRM_DEF.encode({ choice: 'confirm' }),\n cancel: CONFIRM_DEF.encode({ choice: 'cancel' })\n};\n\ntype Outcome = ReplyResponse | (() => Promisable<ReplyResponse>);\n\ntype ConfirmPrompt = string | ((ids: { confirm: string; cancel: string }) => Promisable<ReplyResponse>);\n\n/** Options shared by both confirmation forms. */\nexport interface ConfirmOptions {\n /**\n * Whether the prompt is ephemeral. Only the invoking user can act on it either way, a non-invoker's\n * click is ignored.\n *\n * @defaultValue `true`\n */\n ephemeral?: boolean;\n /**\n * Milliseconds to wait for a click before the prompt is settled and the result resolves to `false`.\n *\n * @defaultValue `30_000`\n */\n timeoutMs?: number;\n /** Shown in place of the prompt when the user confirms. Absent removes the prompt. */\n onConfirm?: Outcome;\n /** Shown in place of the prompt when the user cancels. Absent removes the prompt. */\n onCancel?: Outcome;\n /** Shown in place of the prompt when the prompt times out. Absent removes the prompt. */\n onTimeout?: Outcome;\n}\n\n/** Options for the string-prompt form, adding the built-in Confirm/Cancel buttons' labels and style. */\nexport interface DefaultConfirmOptions extends ConfirmOptions {\n /**\n * Confirm-button label.\n *\n * @defaultValue `'Confirm'`\n */\n confirmLabel?: string;\n /**\n * Cancel-button label.\n *\n * @defaultValue `'Cancel'`\n */\n cancelLabel?: string;\n /**\n * Confirm-button style.\n *\n * @defaultValue {@link ButtonStyle.Danger}\n */\n confirmStyle?: ButtonStyle;\n}\n\nclass ConfirmButtons extends RowComponent<'button'> {\n constructor(options: DefaultConfirmOptions | undefined) {\n super('button');\n this.instance.addComponents(\n new ButtonBuilder()\n .setCustomId(CONFIRM_IDS.confirm)\n .setLabel(options?.confirmLabel ?? 'Confirm')\n .setStyle(options?.confirmStyle ?? ButtonStyle.Danger),\n new ButtonBuilder()\n .setCustomId(CONFIRM_IDS.cancel)\n .setLabel(options?.cancelLabel ?? 'Cancel')\n .setStyle(ButtonStyle.Secondary)\n );\n }\n}\n\nclass ConfirmPromptCard extends BuilderComponent<'container'> {\n constructor(text: string, options: DefaultConfirmOptions | undefined) {\n super('container');\n this.instance\n .addTextDisplayComponents(new TextDisplayBuilder().setContent(text))\n .addActionRowComponents(new ConfirmButtons(options).component);\n }\n}\n\nfunction defaultPrompt(text: string, options: DefaultConfirmOptions | undefined): ReplyResponse {\n return { components: [new ConfirmPromptCard(text, options).component] };\n}\n\nasync function collectChoice(message: Message, userId: string, timeoutMs: number): Promise<ButtonInteraction | null> {\n try {\n return await message.awaitMessageComponent({\n componentType: ComponentType.Button,\n time: timeoutMs,\n filter: (click) => click.user.id === userId && CONFIRM_DEF.owns(click.customId)\n });\n } catch {\n // awaitMessageComponent rejects on timeout, which resolves to no decision here\n return null;\n }\n}\n\nasync function settle(sender: ReplySender, message: Message, outcome: Outcome | undefined): Promise<void> {\n if (outcome === undefined) {\n // routes through the interaction webhook, so it removes an ephemeral prompt where a plain\n // message.delete() cannot\n await sender.delete(message).catch(() => undefined);\n return;\n }\n await sender.edit(message, typeof outcome === 'function' ? await outcome() : outcome);\n}\n\n/**\n * Shows a confirm/cancel prompt with built-in Confirm and Cancel buttons and resolves to `true` only if the\n * invoking user clicks confirm. A cancel click or a timeout resolves to `false`. Gate the action behind it\n * with an early return. A failed prompt send throws into the fault boundary. A {@link ModalHandler} is\n * excluded at compile time.\n *\n * @param handler - The handler to prompt from, `this` inside a non-modal handler.\n * @param prompt - The message shown above the Confirm and Cancel buttons.\n * @param options - Ephemeral flag, timeout, the built-in buttons' labels and style, and the optional\n * `onConfirm`/`onCancel`/`onTimeout` outcome replies that edit the prompt in place.\n * @returns `true` if confirmed, `false` on cancel or timeout.\n *\n * @example\n * ```ts\n * import { getConfirmation } from '@seedcord/gateway';\n *\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * const target = this.options.getUser('target', true);\n * if (!(await getConfirmation(this, `Ban ${target.tag}? This cannot be undone.`))) return;\n * await this.event.guild?.members.ban(target.id);\n * }\n * }\n * ```\n */\nexport function getConfirmation(\n handler: RepliableHandler<NonModalInteraction>,\n prompt: string,\n options?: DefaultConfirmOptions\n): Promise<boolean>;\n/**\n * Shows a confirm/cancel prompt you build yourself and resolves to `true` only if the invoking user clicks\n * confirm. The factory receives the two minted button ids. Set them on your own buttons. A cancel click or a\n * timeout resolves to `false`. A failed prompt send throws into the fault boundary. A {@link ModalHandler} is\n * excluded at compile time.\n *\n * @param handler - The handler to prompt from, `this` inside a non-modal handler.\n * @param prompt - A factory given the minted `{ confirm, cancel }` ids that returns the reply to show. Build\n * it with the `BuilderComponent` and `RowComponent` wrappers.\n * @param options - Ephemeral flag, timeout, and the optional `onConfirm`/`onCancel`/`onTimeout` outcome\n * replies that edit the prompt in place.\n * @returns `true` if confirmed, `false` on cancel or timeout.\n *\n * @remarks\n * The prompt is collected in-process, so it does not survive a bot restart. Without an outcome hook the\n * prompt is gone once the user confirms, so deliver the result with a fresh `this.followUp(...)`.\n *\n * @example\n * ```ts\n * import { ButtonBuilder, TextDisplayBuilder } from '@discordjs/builders';\n * import { ButtonStyle } from 'discord.js';\n * import { BuilderComponent, RowComponent, getConfirmation } from '@seedcord/gateway';\n *\n * class BanPrompt extends BuilderComponent<'container'> {\n * constructor(text: string) {\n * super('container');\n * this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(text));\n * }\n * }\n *\n * class ConfirmRow extends RowComponent<'button'> {\n * constructor(ids: { confirm: string; cancel: string }) {\n * super('button');\n * const buttons = [\n * [ids.confirm, 'Ban', ButtonStyle.Danger],\n * [ids.cancel, 'Cancel', ButtonStyle.Secondary]\n * ] as const;\n * this.instance.addComponents(\n * ...buttons.map(([id, label, style]) => new ButtonBuilder().setCustomId(id).setLabel(label).setStyle(style))\n * );\n * }\n * }\n *\n * const target = this.options.getUser('target', true);\n * const confirmed = await getConfirmation(\n * this,\n * (ids) => ({ components: [new BanPrompt(`Ban ${target.tag}?`).component, new ConfirmRow(ids).component] }),\n * { onConfirm: { components: [new BanPrompt(`Banned ${target.tag}.`).component] } }\n * );\n * if (!confirmed) return;\n * ```\n */\nexport function getConfirmation(\n handler: RepliableHandler<NonModalInteraction>,\n prompt: (ids: { confirm: string; cancel: string }) => Promisable<ReplyResponse>,\n options?: ConfirmOptions\n): Promise<boolean>;\nexport async function getConfirmation(\n handler: RepliableHandler<NonModalInteraction>,\n prompt: ConfirmPrompt,\n options?: DefaultConfirmOptions\n): Promise<boolean> {\n const { ephemeral = true, timeoutMs = DEFAULT_TIMEOUT_MS } = options ?? {};\n\n const response = typeof prompt === 'string' ? defaultPrompt(prompt, options) : await prompt(CONFIRM_IDS);\n const interaction = handler.getEvent();\n const sender = handler.getSender();\n const message = await sender.send(response, { ephemeral });\n\n const winner = await collectChoice(message, interaction.user.id, timeoutMs);\n if (!winner) {\n await settle(sender, message, options?.onTimeout);\n return false;\n }\n\n // discord can expire the 3s ack window between the filter firing and this ack\n await winner.deferUpdate().catch(() => undefined);\n const confirmed = winner.customId === CONFIRM_IDS.confirm;\n await settle(sender, message, confirmed ? options?.onConfirm : options?.onCancel);\n return confirmed;\n}\n","import { BaseHandler as CoreBaseHandler } from '@seedcord/core';\n\nimport type { Core } from '../interfaces';\nimport type { ValidEventTypes } from './interactionTypes';\n\n/**\n * The gateway base, fixes the core base's `TCore` to the gateway {@link Core} and adds the `getEvent`\n * gate hook.\n */\nexport abstract class BaseHandler<ValidEvent extends ValidEventTypes> extends CoreBaseHandler<ValidEvent, Core> {\n /** @internal */\n public getEvent(): ValidEvent {\n return this.event;\n }\n}\n","import { BaseHandler } from '@src/handlers/BaseHandler';\n\nimport type { Core } from '@interfaces/Core';\nimport type { Repliables } from '@src/handlers/interactionTypes';\n\n/**\n * Base class for interaction middleware\n *\n * Middleware runs before interaction handlers and can modify behavior or block execution.\n * Unlike handlers, middleware should not send responses directly.\n *\n * @typeParam Repliable - The interaction type this middleware processes\n */\nexport abstract class InteractionMiddleware<Repliable extends Repliables> extends BaseHandler<Repliable> {\n // keep this ctor. it gives typeof InteractionMiddleware a public construct signature that\n // InteractionMiddlewareConstructor needs, and dropping it collapses that type to never.\n constructor(event: Repliable, core: Core) {\n super(event, core, undefined, 'interactions');\n }\n}\n","import { BaseReplySender, deferFlags, sendFlags } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { MessageFlags } from 'discord.js';\n\nimport type { GatewayFile, GatewayReplyResponse } from '@interfaces/ReplyResponse';\nimport type { Bus } from '@seedcord/core';\nimport type { AckState } from '@seedcord/core/internal';\nimport type { DeferOpts, ReplyFile, SendOpts } from '@seedcord/types';\nimport type { Repliables } from '@src/handlers/interactionTypes';\nimport type {\n APIModalInteractionResponseCallbackData,\n InteractionCallbackResponse,\n InteractionReplyOptions,\n InteractionUpdateOptions,\n MessageComponentInteraction,\n ModalMessageModalSubmitInteraction,\n Message,\n WebhookMessageEditOptions\n} from 'discord.js';\n\n// the two djs kinds carrying a source message, so update / deferUpdate have a target\ntype SourceInteraction = MessageComponentInteraction | ModalMessageModalSubmitInteraction;\n\n/** The created message a gateway reply resolves to. */\nexport type SentMessage = Message;\n\nfunction isReplyFile(file: ReplyFile | GatewayFile): file is ReplyFile {\n return typeof file === 'object' && 'data' in file && ArrayBuffer.isView(file.data);\n}\n\n// discord.js rejects a plain Uint8Array, so convert the bytes to a Buffer\nfunction toDjsFile(file: ReplyFile | GatewayFile): GatewayFile {\n if (!isReplyFile(file)) return file;\n return {\n attachment: Buffer.from(file.data),\n name: file.name,\n ...(file.description !== undefined && { description: file.description }),\n ...(file.title !== undefined && { title: file.title })\n };\n}\n\n// djs flips `replied` on editReply, so per-call derivation would break repeated update() and post-edit\n// send() parity\nfunction seedState(interaction: Repliables): AckState {\n if (interaction.deferred && interaction.ephemeral === null) return 'deferred-update';\n if (interaction.replied) return 'replied';\n if (interaction.deferred) return 'deferred-reply';\n return 'unacked';\n}\n\n/**\n * Writes interaction responses through the discord.js interaction. Construction is internal to the repliable\n * handler bases and the dispatcher.\n */\nexport class ReplySender extends BaseReplySender<SentMessage, GatewayFile> {\n public constructor(\n private readonly interaction: Repliables,\n routeId: string,\n bus?: Bus\n ) {\n super(routeId, seedState(interaction), bus && { bus, interactionId: interaction.id });\n }\n\n protected async writeReply(\n response: GatewayReplyResponse | string,\n opts?: SendOpts\n ): Promise<SentMessage | undefined> {\n const result = await this.interaction.reply({\n ...this.replyOptions(response, sendFlags(opts)),\n withResponse: true\n });\n return this.createdMessage(result);\n }\n\n protected async writeDefer(opts?: DeferOpts): Promise<void> {\n await this.interaction.deferReply({ flags: deferFlags(opts) });\n }\n\n protected async writeDeferUpdate(): Promise<void> {\n await this.sourceInteraction('deferUpdate').deferUpdate();\n }\n\n protected async writeUpdate(response: GatewayReplyResponse | string): Promise<SentMessage | undefined> {\n const source = this.sourceInteraction('update');\n const result = await source.update({ ...this.updateOptions(response), withResponse: true });\n return this.createdMessage(result);\n }\n\n protected async writeFollowUp(response: GatewayReplyResponse | string, opts?: SendOpts): Promise<SentMessage> {\n return await this.interaction.followUp(this.replyOptions(response, sendFlags(opts)));\n }\n\n protected async writeEditOriginal(response: GatewayReplyResponse | string): Promise<SentMessage> {\n return await this.interaction.editReply(this.editOptions(response));\n }\n\n protected async writeEditTarget(targetId: string, response: GatewayReplyResponse | string): Promise<SentMessage> {\n return await this.interaction.webhook.editMessage(targetId, this.editOptions(response));\n }\n\n protected async writeDeleteOriginal(): Promise<void> {\n await this.interaction.deleteReply();\n }\n\n protected async writeDeleteTarget(targetId: string): Promise<void> {\n await this.interaction.deleteReply(targetId);\n }\n\n protected async writeModal(data: APIModalInteractionResponseCallbackData): Promise<void> {\n const { interaction } = this;\n // unreachable after guardModalSource, the throw re-narrows the union for showModal\n if (interaction.isModalSubmit()) this.rejectModalSubmit();\n await interaction.showModal(data);\n }\n\n protected override guardModalSource(): void {\n // runtime backstop for direct sender callers, which a compile-time gate on the bases cannot cover\n if (this.interaction.isModalSubmit()) this.rejectModalSubmit();\n }\n\n private rejectModalSubmit(): never {\n throw new SeedcordError(SeedcordErrorCode.ReplyIllegalAckState, [\n 'showModal',\n 'this interaction is a modal submit',\n 'A modal cannot open another modal.',\n this.routeId\n ]);\n }\n\n // only component and message-opened-modal kinds carry a source message\n private sourceInteraction(method: 'update' | 'deferUpdate'): SourceInteraction {\n const { interaction } = this;\n if (interaction.isMessageComponent()) return interaction;\n if (interaction.isModalSubmit() && interaction.isFromMessage()) return interaction;\n throw new SeedcordError(SeedcordErrorCode.ReplyUpdateWithoutSource, [method, this.routeId]);\n }\n\n private replyOptions(response: GatewayReplyResponse | string, flags: number): InteractionReplyOptions {\n const reply = this.serialize(response);\n return {\n components: reply.components,\n flags,\n ...(reply.allowedMentions && { allowedMentions: reply.allowedMentions }),\n ...(reply.files && { files: reply.files.map(toDjsFile) })\n };\n }\n\n private editOptions(response: GatewayReplyResponse | string): WebhookMessageEditOptions {\n const reply = this.serialize(response);\n return {\n components: reply.components,\n flags: MessageFlags.IsComponentsV2,\n ...(reply.allowedMentions && { allowedMentions: reply.allowedMentions }),\n ...(reply.files && { files: reply.files.map(toDjsFile) })\n };\n }\n\n private updateOptions(response: GatewayReplyResponse | string): InteractionUpdateOptions {\n const reply = this.serialize(response);\n return {\n components: reply.components,\n flags: MessageFlags.IsComponentsV2,\n ...(reply.allowedMentions && { allowedMentions: reply.allowedMentions }),\n ...(reply.files && { files: reply.files.map(toDjsFile) })\n };\n }\n\n private createdMessage(result: InteractionCallbackResponse): SentMessage | undefined {\n return result.resource?.message ?? undefined;\n }\n}\n","import { RepliableHandler as CoreRepliableHandler } from '@seedcord/core';\n\nimport { ReplySender } from '@bot/ReplySender';\n\nimport type { Repliables } from './interactionTypes';\nimport type { SentMessage } from '@bot/ReplySender';\nimport type { Core } from '@interfaces/Core';\nimport type { GatewayFile } from '@interfaces/ReplyResponse';\n\n/**\n * Shared base the repliable interaction handlers extend.\n *\n * Not a public entry point. Extend {@link SlashHandler}, {@link ButtonHandler}, {@link ModalHandler},\n * {@link SelectMenuHandler}, or {@link ContextMenuHandler} instead. This class binds the core reply base\n * to the gateway sender.\n *\n * @typeParam Event - The repliable interaction type this handler processes\n */\nexport abstract class RepliableHandler<Event extends Repliables> extends CoreRepliableHandler<\n Event,\n Core,\n SentMessage,\n GatewayFile,\n ReplySender\n> {\n // this chain skips gateway BaseHandler, the only class that defines getEvent, so it re-declares here\n /** @internal */\n public getEvent(): Event {\n return this.event;\n }\n\n protected buildSender(event: Event, core: Core, routeId: string): ReplySender {\n return new ReplySender(event, routeId, core.bus);\n }\n}\n","import { RepliableHandler } from '@handlers/RepliableHandler';\n\nimport type { Core } from '@interfaces/Core';\nimport type { DispatchContext } from '@seedcord/core';\nimport type { ModalLike } from '@seedcord/core/internal';\nimport type { NonModalInteraction, Repliables } from '@src/handlers/interactionTypes';\n\n/**\n * Shared base the typed interaction handlers extend.\n *\n * Not a public entry point. Extend {@link SlashHandler}, {@link ButtonHandler}, {@link ModalHandler},\n * or {@link SelectMenuHandler} instead. This class adds `showModal` on top of the reply members those bases\n * share.\n *\n * @typeParam Repliable - The interaction type this handler processes\n */\nexport abstract class InteractionHandler<Repliable extends Repliables> extends RepliableHandler<Repliable> {\n // keep this ctor. it gives typeof InteractionHandler a public construct signature that HandlerConstructor\n // needs, and dropping it (inheriting RepliableHandler's protected ctor) collapses HandlerConstructor to never.\n constructor(event: Repliable, core: Core, dispatch?: DispatchContext) {\n super(event, core, dispatch);\n }\n\n /**\n * Open a modal. Must be the initial response to this interaction. The modal kind rejects this call at\n * compile time (Discord forbids a modal in response to a modal).\n */\n protected showModal(this: InteractionHandler<NonModalInteraction>, modal: ModalLike): Promise<void> {\n return this.sender.showModal(modal);\n }\n}\n","import { buildSlashRoute } from '@seedcord/utils/internal';\n\nimport type { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js';\n\n/**\n * Computes the dispatch route for a chat-input or autocomplete interaction. The controller and\n * `seedcord codegen` both assemble route keys through the same {@link buildSlashRoute}, so a dispatched\n * interaction and a generated registry key always match.\n *\n * @internal\n */\nexport function slashRouteOf(interaction: ChatInputCommandInteraction | AutocompleteInteraction): string {\n const group = interaction.options.getSubcommandGroup(false) ?? undefined;\n const subcommand = interaction.options.getSubcommand(false) ?? undefined;\n return buildSlashRoute(interaction.commandName, subcommand, group);\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { SlashOptions } from '@inputs/SlashOptions';\nimport type { SlashOptionRegistry } from '@seedcord/core';\nimport type { CacheType, ChatInputCommandInteraction } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\n// one arm per command this handler is registered for, keyed by route, each receiving that route's typed options.\ntype SlashMatchArms<Route extends keyof SlashOptionRegistry, Cache extends CacheType, Ret> = {\n [Key in Route]: (options: SlashOptions<Key, Cache>) => Promisable<Ret>;\n};\n\n/**\n * Base class for a chat-input (slash) command handler.\n *\n * Pass the route from the generated registry as the generic, the same string as `@SlashRoute`, then read\n * `this.options` for a single command or `this.match` for several. Command authoring stays plain\n * discord.js, `seedcord codegen` reads its `toJSON()` to type these options.\n *\n * @typeParam Route - One or more route keys from {@link SlashOptionRegistry}, e.g. `'ban'` or `'ban' | 'kick'`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * const target = this.options.getUser('target'); // User\n * const reason = this.options.getString('reason'); // string | null\n * }\n * }\n * ```\n */\nexport abstract class SlashHandler<\n Route extends keyof SlashOptionRegistry,\n Cache extends CacheType = 'cached'\n> extends InteractionHandler<ChatInputCommandInteraction<Cache>> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __slashRoute?: Route;\n\n /**\n * The typed options for this command's route. Required options drop the null, choices narrow to their\n * literal union, and only the getters for kinds this command actually uses appear. Use `this.event.options`\n * directly for anything outside this view, such as narrowing a channel option by type.\n */\n protected get options(): SlashOptions<Route, Cache> {\n // the djs resolver already carries every getter, SlashOptions is its stricter registry-typed view.\n return this.event.options as SlashOptions<Route, Cache>;\n }\n\n /**\n * Run the arm for whichever command fired. Use this only when the handler is registered for several\n * routes.\n *\n * Provide one arm per registered route, keyed by its route string, and each arm receives that route's\n * own narrowed options. The arms must cover every route in the generic, a missing route or an unknown\n * key is a compile error.\n *\n * @param arms - One handler per registered route, keyed by route string.\n * @returns The result of the arm that ran.\n *\n * @example\n * ```ts\n * \\@SlashRoute('ban', 'kick')\n * class ModHandler extends SlashHandler<'ban' | 'kick'> {\n * async execute() {\n * await this.match({\n * ban: (options) => this.event.guild?.members.ban(options.getUser('target', true).id),\n * kick: (options) => this.event.guild?.members.kick(options.getUser('member', true).id)\n * });\n * }\n * }\n * ```\n */\n protected async match<Ret>(arms: SlashMatchArms<Route, Cache, Ret>): Promise<Ret> {\n const route = slashRouteOf(this.event);\n // justified: SlashMatchArms is keyed by Route literals, the Record cast indexes it with the runtime route string.\n const arm = Object.hasOwn(arms, route)\n ? (arms as Record<string, (options: SlashOptions<Route, Cache>) => Promisable<Ret>>)[route]\n : undefined;\n if (!arm) throw new SeedcordError(SeedcordErrorCode.SlashMatchArmMissing, [route]);\n return await arm(this.options);\n }\n}\n","import { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { ContextMenuKind } from '@seedcord/core';\nimport type {\n APIInteractionGuildMember,\n ApplicationCommandType,\n BooleanCache,\n CacheType,\n CacheTypeReducer,\n GuildMember,\n Message,\n MessageContextMenuCommandInteraction,\n User,\n UserContextMenuCommandInteraction\n} from 'discord.js';\n\n// the interaction class for each kind, so this.event carries the right targetUser/targetMessage members.\ntype InteractionFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User\n ? UserContextMenuCommandInteraction<Cache>\n : MessageContextMenuCommandInteraction<Cache>;\n\n// the right-clicked entity, a User for a user menu and a Message for a message menu.\ntype TargetFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User\n ? User\n : Message<BooleanCache<Cache>>;\n\n// the invoking member, present only on user menus where Discord resolves it alongside the target user.\ntype TargetMemberFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User\n ? CacheTypeReducer<Cache, GuildMember, APIInteractionGuildMember> | null\n : never;\n\n/**\n * Base class for a context-menu command handler (right-click a user or a message).\n *\n * Pass the kind from `discord.js`'s {@link ApplicationCommandType} as the generic, the same value as\n * `@ContextMenuRoute`. Read the right-clicked entity from `this.target`, a `User` for a user menu and a\n * `Message` for a message menu. Context menus carry no options, so a handler registered for several names\n * reads `this.target` uniformly with no per-name branch.\n *\n * @typeParam Kind - `ApplicationCommandType.User` or `ApplicationCommandType.Message`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@ContextMenuRoute(ApplicationCommandType.Message, 'Report Message')\n * class ReportMessage extends ContextMenuHandler<ApplicationCommandType.Message> {\n * async execute() {\n * const message = this.target;\n * }\n * }\n * ```\n */\nexport abstract class ContextMenuHandler<\n Kind extends ContextMenuKind,\n Cache extends CacheType = 'cached'\n> extends InteractionHandler<InteractionFor<Kind, Cache>> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __ctxKind?: Kind;\n\n protected get target(): TargetFor<Kind, Cache> {\n // justified: the Kind generic decides which interaction member is live, both narrow to TargetFor.\n const event = this.event;\n const target = 'targetUser' in event ? event.targetUser : event.targetMessage;\n return target as TargetFor<Kind, Cache>;\n }\n\n /**\n * The invoking guild member, resolved only on user menus. Reading it on a message menu is a compile\n * error since the type is `never` there.\n */\n protected get targetMember(): TargetMemberFor<Kind, Cache> {\n // justified: only the User-kind event carries targetMember, the Message-kind read is unreachable per the type.\n return (this.event as UserContextMenuCommandInteraction<Cache>).targetMember as TargetMemberFor<Kind, Cache>;\n }\n}\n","import { reportedWrite } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { BaseHandler } from '@src/handlers/BaseHandler';\n\nimport type { Core } from '@interfaces/Core';\nimport type { AutocompleteOptions, DispatchContext, SlashOptionRegistry } from '@seedcord/core';\nimport type { AutocompletableNames, ChoiceValueOf, EntryFor, FocusedField } from '@seedcord/core/internal';\nimport type { ApplicationCommandOptionChoiceData, AutocompleteInteraction, CacheType } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\ntype FocusedArms<Route extends keyof SlashOptionRegistry, Ret> = {\n [Name in AutocompletableNames<Route>]: (\n value: string,\n respond: (\n choices: readonly ApplicationCommandOptionChoiceData<ChoiceValueOf<EntryFor<Route, Name>>>[]\n ) => Promise<void>\n ) => Promisable<Ret>;\n};\n\n/**\n * Base class for a Discord autocomplete handler.\n *\n * Pass the command route(s) from the generated registry as the generic, the same string(s) as\n * `@AutocompleteRoute`. Branch on the focused field with `this.match`, read already-entered sibling options\n * with `this.options`, and find which command fired with `this.route`.\n *\n * @typeParam Route - One or more route keys from {@link SlashOptionRegistry}, e.g. `'search'` or `'search' | 'find'`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@AutocompleteRoute('search')\n * class SearchAutocomplete extends AutocompleteHandler<'search'> {\n * async execute() {\n * await this.match({\n * query: (value, respond) => respond([{ name: value, value }])\n * });\n * }\n * }\n * ```\n */\nexport abstract class AutocompleteHandler<\n Route extends keyof SlashOptionRegistry,\n Cache extends CacheType = 'cached'\n> extends BaseHandler<AutocompleteInteraction<Cache>> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __autocompleteRoute?: Route;\n\n // keep this ctor. it gives typeof AutocompleteHandler a public construct signature that HandlerConstructor\n // needs, and dropping it (inheriting BaseHandler's protected ctor) collapses HandlerConstructor to never.\n constructor(event: AutocompleteInteraction<Cache>, core: Core, dispatch?: DispatchContext) {\n super(event, core, dispatch, 'interactions');\n }\n\n private decodedFocused?: { name: string; value: string };\n\n /**\n * The focused option for this interaction. `value` is always the raw partial string the user is typing,\n * even for an integer or number option, so coerce it yourself when you need a number.\n */\n protected get focused(): FocusedField<Route> {\n if (this.decodedFocused) return this.decodedFocused as FocusedField<Route>;\n const raw = this.event.options.getFocused(true);\n const focused = { name: raw.name, value: raw.value };\n this.decodedFocused = focused;\n // the registry constrains the names, a focused field outside the set has no arm.\n return focused as FocusedField<Route>;\n }\n\n /**\n * Run the arm for the focused field. An autocomplete always dispatches by which field is focused, so\n * match is how you read it. There is no single-field shortcut the way slash/component handlers have one.\n *\n * Provide one arm per autocompletable field across the registered commands, keyed by field name. Each\n * arm receives the focused partial value and a `respond` typed to that field's choice value. The\n * arms must cover every autocompletable field, a missing field or an unknown key is a compile error. A\n * focused field with no arm, only reachable from a stale-deployed command, throws at runtime.\n *\n * @param arms - One handler per autocompletable field, keyed by field name.\n * @returns The result of the arm that ran.\n *\n * @example\n * ```ts\n * \\@AutocompleteRoute('search')\n * class SearchAutocomplete extends AutocompleteHandler<'search'> {\n * async execute() {\n * await this.match({\n * query: (value, respond) => respond(titles(value).map((s) => ({ name: s, value: s }))),\n * tag: (value, respond) => respond(tags(value).map((s) => ({ name: s, value: s })))\n * });\n * }\n * }\n * ```\n */\n protected async match<Ret>(arms: FocusedArms<Route, Ret>): Promise<Ret> {\n const { name, value } = this.focused;\n const respond = (choices: readonly ApplicationCommandOptionChoiceData[]): Promise<void> =>\n this.respond(choices);\n // justified: FocusedArms is keyed by field literals, the Record cast indexes it with the runtime field name.\n type Arm = (\n value: string,\n respond: (choices: readonly ApplicationCommandOptionChoiceData[]) => Promise<void>\n ) => Promisable<Ret>;\n const arm = Object.hasOwn(arms, name) ? (arms as Record<string, Arm>)[name] : undefined;\n if (!arm) throw new SeedcordError(SeedcordErrorCode.AutocompleteMatchArmMissing, [name]);\n return await arm(value, respond);\n }\n\n /** Send autocomplete suggestions, callback type 8. Prefer {@link match}, which restricts each field's choices to its declared type. */\n protected async respond(choices: readonly ApplicationCommandOptionChoiceData[]): Promise<void> {\n // a hand-built handler outside a dispatch carries no route id\n const routeId = this.dispatch?.routeId ?? 'autocomplete';\n await reportedWrite({ bus: this.core.bus, interactionId: this.event.id }, routeId, 'respond', () =>\n // eslint-disable-next-line @seedcord/no-raw-interaction-acks -- this is the base respond and calls djs directly\n this.event.respond(choices)\n );\n }\n\n /** The firing command route, for a field whose completion differs per registered command. */\n protected get route(): Route {\n return slashRouteOf(this.event) as Route;\n }\n\n /**\n * The already-entered options on this command, restricted to the kinds Discord resolves during autocomplete\n * (string, integer, number, boolean) with every read nullable, since a sibling is partial while the user\n * types the focused field. The focused field is on `this.focused`.\n */\n protected get options(): AutocompleteOptions<Route> {\n // the djs resolver exposes these getters, AutocompleteOptions is the registry-typed view over it.\n return this.event.options as AutocompleteOptions<Route>;\n }\n}\n","import { decodeComponentRoute } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { SentMessage } from '@bot/ReplySender';\nimport type { GatewayReplyResponse } from '@interfaces/ReplyResponse';\nimport type {\n AnyCustomId,\n DecodedComponentRoute,\n HasComponentDefs,\n MatchArms,\n SingleParams\n} from '@seedcord/core/internal';\nimport type { AnySelectMenuInteraction, ButtonInteraction, ModalSubmitInteraction } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\ntype ComponentInteraction = ButtonInteraction | ModalSubmitInteraction | AnySelectMenuInteraction;\n\n/**\n * Shared base the customId-routed component handlers extend.\n *\n * Not a public entry point. Extend {@link ButtonHandler}, {@link SelectMenuHandler}, or {@link ModalHandler}\n * instead. This class defines the customId decode and the route matching those bases share.\n *\n * @typeParam Event - The component interaction type this handler processes\n * @typeParam Defs - The customId route definitions registered on the concrete handler\n */\nexport abstract class ComponentHandler<Event extends ComponentInteraction, Defs extends readonly AnyCustomId[]>\n extends InteractionHandler<Event>\n implements HasComponentDefs<Defs>\n{\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __componentDefs?: Defs;\n\n /** Rewrite the source message this component interaction came from. */\n protected update(response: GatewayReplyResponse | string): Promise<SentMessage> {\n return this.sender.update(response);\n }\n\n /** Acknowledge the component without changing the source message. */\n protected deferUpdate(): Promise<void> {\n return this.sender.deferUpdate();\n }\n\n private decoded?: DecodedComponentRoute;\n\n private get route(): DecodedComponentRoute {\n this.decoded ??= decodeComponentRoute(this.constructor, this.event.customId);\n return this.decoded;\n }\n\n /**\n * The decoded params of the single route this handler is registered for.\n *\n * Reading this decodes `this.event.customId` once (cached after the first read) and throws\n * `StaleCustomId` or `InvalidCustomId` when the wire no longer matches the current shape, which the\n * controller boundary turns into a reply. On a handler registered for several routes this is\n * `never`, so use {@link match} instead.\n */\n protected get params(): SingleParams<Defs> {\n return this.route.params as SingleParams<Defs>;\n }\n\n /**\n * Run the arm for whichever route the component was minted from. Use this only when the handler is\n * registered for several routes. A single-route handler reads `this.params` directly. On a multi-route\n * handler `this.params` is `never`, so match is the only way to read the decoded params.\n *\n * Provide one arm per registered route, keyed by its prefix, and each arm receives that route's own\n * decoded params. The arms cover every registered route prefix, checked at compile time, and a prefix\n * unmatched at runtime throws `CustomIdMatchArmMissing`. Decoding runs before any arm, so a stale or\n * corrupt wire throws before an arm body executes.\n *\n * @param arms - One callback per registered route, keyed by prefix.\n * @returns The result of the arm that ran.\n *\n * @example\n * ```ts\n * \\@ButtonRoute(Approve, Reject)\n * class ReviewButtons extends ButtonHandler<[typeof Approve, typeof Reject]> {\n * async execute() {\n * await this.match({\n * approve: ({ userId }) => this.reply(`approved <@${userId}>`),\n * reject: ({ userId }) => this.reply(`rejected <@${userId}>`)\n * });\n * }\n * }\n * ```\n */\n protected async match<Ret>(arms: MatchArms<Defs, Ret>): Promise<Ret> {\n const { prefix, params } = this.route;\n // justified: MatchArms is keyed by prefix literals, so the Record cast indexes it with the runtime prefix\n const arm = Object.hasOwn(arms, prefix)\n ? (arms as Record<string, (params: Record<string, unknown>) => Promisable<Ret>>)[prefix]\n : undefined;\n if (!arm) throw new SeedcordError(SeedcordErrorCode.CustomIdMatchArmMissing, [prefix]);\n return await arm(params);\n }\n}\n","import { ComponentHandler } from './ComponentHandler';\n\nimport type { AnyCustomId } from '@seedcord/core/internal';\nimport type { ButtonInteraction, CacheType } from 'discord.js';\n\n/**\n * Base class for a button interaction handler.\n *\n * Register the customId definitions this handler decodes with `@ButtonRoute`, list the same ones in the\n * generic, then read `this.params` for a single route or `this.match` for several. Reply through the handler\n * members, or rewrite the source message with `this.update`. Passing different definitions to the decorator\n * and the generic is a compile error.\n *\n * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof ApproveId]`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@ButtonRoute(ApproveId)\n * class ApproveButton extends ButtonHandler<[typeof ApproveId]> {\n * async execute() {\n * const { userId } = this.params;\n * await this.reply(`approved <@${userId}>`);\n * }\n * }\n * ```\n */\nexport abstract class ButtonHandler<\n Defs extends readonly AnyCustomId[],\n Cache extends CacheType = 'cached'\n> extends ComponentHandler<ButtonInteraction<Cache>, Defs> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __component?: 'button';\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { ComponentHandler } from './ComponentHandler';\n\nimport type { SentMessage } from '@bot/ReplySender';\nimport type { GatewayReplyResponse } from '@interfaces/ReplyResponse';\nimport type { AnyCustomId } from '@seedcord/core/internal';\nimport type { CacheType, ModalSubmitInteraction } from 'discord.js';\n\n/**\n * Base class for a modal submit handler.\n *\n * Register the customId definitions this handler decodes with `@ModalRoute`, list the same ones in the\n * generic, then read `this.params` for a single route or `this.match` for several. Read the submitted\n * inputs from `this.event.fields`, and reply through the handler members. Discord forbids opening a modal in\n * response to a modal, so `showModal` fails compilation on this kind.\n *\n * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof ConfigId]`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@ModalRoute(ConfigId)\n * class ConfigModal extends ModalHandler<[typeof ConfigId]> {\n * async execute() {\n * const { guildId } = this.params;\n * const name = this.event.fields.getTextInputValue('name');\n * await this.reply(`saved ${name} for ${guildId}`);\n * }\n * }\n * ```\n */\nexport abstract class ModalHandler<\n Defs extends readonly AnyCustomId[],\n Cache extends CacheType = 'cached'\n> extends ComponentHandler<ModalSubmitInteraction<Cache>, Defs> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __component?: 'modal';\n\n /** Rewrite the message this modal was opened from. Throws when a command opened the modal. */\n protected override update(response: GatewayReplyResponse | string): Promise<SentMessage> {\n this.ensureSourceMessage('update');\n return super.update(response);\n }\n\n /** Acknowledge the submit without changing the source message. Throws when a command opened the modal. */\n protected override deferUpdate(): Promise<void> {\n this.ensureSourceMessage('deferUpdate');\n return super.deferUpdate();\n }\n\n // discord omits the message when a command opened the modal, so update and deferUpdate have no target\n private ensureSourceMessage(method: string): void {\n if (this.event.isFromMessage()) return;\n throw new SeedcordError(SeedcordErrorCode.ReplyUpdateWithoutSource, [method, this.routeId]);\n }\n}\n","import { ComponentHandler } from './ComponentHandler';\n\nimport type { SelectMenuKind } from '@seedcord/core';\nimport type { AnyCustomId } from '@seedcord/core/internal';\nimport type {\n CacheType,\n ChannelSelectMenuInteraction,\n MentionableSelectMenuInteraction,\n RoleSelectMenuInteraction,\n StringSelectMenuInteraction,\n UserSelectMenuInteraction\n} from 'discord.js';\n\ntype SelectMenuInteractionFor<\n SelectMenu extends SelectMenuKind,\n Cache extends CacheType = CacheType\n> = SelectMenu extends SelectMenuKind.String\n ? StringSelectMenuInteraction<Cache>\n : SelectMenu extends SelectMenuKind.User\n ? UserSelectMenuInteraction<Cache>\n : SelectMenu extends SelectMenuKind.Role\n ? RoleSelectMenuInteraction<Cache>\n : SelectMenu extends SelectMenuKind.Channel\n ? ChannelSelectMenuInteraction<Cache>\n : SelectMenu extends SelectMenuKind.Mentionable\n ? MentionableSelectMenuInteraction<Cache>\n : never;\n\n/**\n * Base class for a select menu handler.\n *\n * Pass the select kind first and the customId definitions second, the same order as `@SelectMenuRoute`,\n * so `this.event` and `this.event.values` are narrowed to that kind. Read `this.params` for a single\n * route or `this.match` for several, and reply through the handler members or rewrite the source message\n * with `this.update`.\n *\n * @typeParam Kind - The select kind from {@link SelectMenuKind}, e.g. `SelectMenuKind.User`.\n * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof AssignId]`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@SelectMenuRoute(SelectMenuKind.User, AssignId)\n * class AssignSelect extends SelectMenuHandler<SelectMenuKind.User, [typeof AssignId]> {\n * async execute() {\n * const { roleId } = this.params;\n * await this.reply(`assigning ${this.event.values.length} member(s) to <@&${roleId}>`);\n * }\n * }\n * ```\n */\nexport abstract class SelectMenuHandler<\n Kind extends SelectMenuKind,\n Defs extends readonly AnyCustomId[],\n Cache extends CacheType = 'cached'\n> extends ComponentHandler<SelectMenuInteractionFor<Kind, Cache>, Defs> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __component?: Kind;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { BaseHandler } from '@src/handlers/BaseHandler';\n\nimport type { SingleEventPayload } from './payload';\nimport type { Core } from '@interfaces/Core';\nimport type { ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\n// spread so the discord.js tuple labels surface as parameter names in editor signature help, e.g.\n// messageUpdate gives (oldMessage, newMessage). a single tuple param would lose the labels.\ntype EventMatchArms<Names extends ValidNonInteractionKeys, Ret> = {\n [Name in Names]: (...args: ClientEvents[Name]) => Promisable<Ret>;\n};\n\n/**\n * Base class for a Discord client event handler.\n *\n * Pass the event name(s) as the generic, the same one(s) as `@RegisterEvent`. A single-event handler reads\n * `this.event` (the payload tuple) directly. A handler registered for several events branches with `this.match`,\n * keyed by event name, since the union of payload tuples is not directly readable.\n *\n * @typeParam Names - One or more `ClientEvents` keys, e.g. `Events.MessageCreate` or `Events.MessageCreate | Events.MessageUpdate`.\n *\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])\n * class PingPong extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {\n * async execute() {\n * await this.match({\n * [Events.MessageCreate]: (message) => message.reply('pong'),\n * [Events.MessageUpdate]: (_oldMessage, edited) => edited.reply('pong')\n * });\n * }\n * }\n * ```\n */\nexport abstract class EventHandler<in out Names extends ValidNonInteractionKeys> extends BaseHandler<\n ClientEvents[Names]\n> {\n // the fired event name, threaded by the controller. undefined when constructed directly, e.g. in a test.\n private readonly firedEvent: Names | undefined;\n\n constructor(event: ClientEvents[Names], core: Core, eventName?: Names) {\n super(event, core, undefined, 'events');\n this.firedEvent = eventName;\n }\n\n // a concrete tuple for one event, never for several, so reading it on a multi-event handler is a compile error\n declare protected readonly event: SingleEventPayload<Names>;\n\n /**\n * Run the arm for whichever event fired. Use this only when the handler is registered for several\n * events. A single-event handler reads `this.event` directly. On a multi-event handler `this.event` is\n * `never`, so match is the only way to read the payload.\n *\n * Provide one arm per registered event, keyed by its name, and each arm receives that event's own\n * payload tuple. The arms must cover every event in the generic, a missing event or an unknown key is a\n * compile error.\n *\n * @param arms - One handler per registered event, keyed by event name.\n * @returns The result of the arm that ran.\n *\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])\n * class MessageWatcher extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {\n * async execute() {\n * await this.match({\n * [Events.MessageCreate]: (message) => this.scan(message),\n * [Events.MessageUpdate]: (_old, updated) => this.scan(updated)\n * });\n * }\n * }\n * ```\n */\n protected async match<Ret>(arms: EventMatchArms<Names, Ret>): Promise<Ret> {\n const name = this.firedEvent;\n if (name === undefined) throw new SeedcordError(SeedcordErrorCode.EventMatchArmMissing, ['<no event>']);\n // justified: each arm takes its own payload tuple, so no single param type unifies the arms in a cast. read\n // the arm as unknown keyed by the runtime event name, then narrow to a function before calling it.\n const arm = (arms as Record<string, unknown>)[name];\n if (typeof arm !== 'function') throw new SeedcordError(SeedcordErrorCode.EventMatchArmMissing, [name]);\n // getEvent() carries the real payload tuple, this.event is narrowed to never for the multi-event view.\n // spread it so the arm receives the same named params its type declares.\n return await (arm as (...args: unknown[]) => Promisable<Ret>)(...this.getEvent());\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { BaseHandler } from '@src/handlers/BaseHandler';\n\nimport type { SingleEventPayload } from './payload';\nimport type { Core } from '@interfaces/Core';\nimport type { ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\n\n/**\n * Base class for Discord event middleware.\n *\n * Middleware runs before event handlers and can stop the event by throwing a `Silence`. Unlike `EventHandler`, it\n * runs the SAME for every event it is registered for, so it has no `match`. Specify a single event in the\n * generic and `{ events }` to read `this.event` fully typed. Span several events (or omit `{ events }` for a\n * catchall) and `this.event` narrows to `never`, read `this.eventName` and do work that does not depend on the\n * payload shape. A middleware that needs each event's payload is written one event per class.\n *\n * @typeParam EventName - One or more `ClientEvents` keys. Defaults to every event (catchall).\n */\nexport abstract class EventMiddleware<\n in out EventName extends ValidNonInteractionKeys = ValidNonInteractionKeys\n> extends BaseHandler<ClientEvents[EventName]> {\n // the fired event name, threaded by the controller. undefined when constructed directly, e.g. in a test.\n private readonly firedEvent: EventName | undefined;\n\n constructor(event: ClientEvents[EventName], core: Core, eventName?: EventName) {\n super(event, core, undefined, 'events');\n this.firedEvent = eventName;\n }\n\n // a concrete tuple for one event, never for several or a catchall, so reading the payload on a multi-event\n // middleware is a compile error. branch on this.eventName and do payload-shape-independent work instead.\n declare protected readonly event: SingleEventPayload<EventName>;\n\n /**\n * The event that fired this middleware. Read it on a catchall or multi-event middleware, where `this.event`\n * is `never`, to do work that does not depend on the payload shape. A single-event middleware reads\n * `this.event` directly and does not need this.\n */\n protected get eventName(): EventName {\n if (this.firedEvent === undefined) throw new SeedcordError(SeedcordErrorCode.EventMiddlewareNameUnavailable);\n return this.firedEvent;\n }\n}\n","import { PaginatorBase } from '@seedcord/core';\n\nimport { ButtonHandler } from '@handlers/interaction/components';\n\nimport type { PageContext } from './PageContext';\nimport type { RepliableHandler } from '@handlers/RepliableHandler';\nimport type { Core } from '@interfaces/Core';\nimport type { PaginatorConfig } from '@seedcord/core';\nimport type { PageCursor } from '@seedcord/core/internal';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { Repliables } from '@src/handlers/interactionTypes';\nimport type { ButtonInteraction, Message } from 'discord.js';\n\n// `& { execute }` concretizes the abstract execute so the empty `extends Bans.Handler {}` stays concrete\n// (no TS2515) and a concrete Nav assigns with no cast.\ntype PaginatorHandlerCtor<Prefix extends string> = new (\n event: ButtonInteraction<'cached'>,\n core: Core\n) => ButtonHandler<[PageCursor<Prefix>]> & { execute(): Promise<void> };\n\nfunction contextOf(interaction: Repliables, core: Core): PageContext {\n return { interaction, user: interaction.user, guild: interaction.guild, core };\n}\n\n/**\n * A restart-proof paginator. Each nav button's customId encodes its full target page, so clicks are\n * idempotent and survive a restart. A persistent `@ButtonRoute` on `Handler` dispatches the clicks.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `config.prefix`.\n *\n * @example\n * ```ts\n * export const Bans = new Paginator({\n * prefix: 'bans',\n * source: new ArraySource((ctx) => ctx.guild.bans.fetch().then((b) => [...b.values()]), { perPage: 10 }),\n * renderItem: (ban) => ban.user.tag\n * });\n *\n * \\@ButtonRoute(Bans.cursor)\n * export class BansNav extends Bans.Handler {}\n * ```\n */\nexport class Paginator<Item, const Prefix extends string> extends PaginatorBase<Item, Prefix, PageContext> {\n /** The nav handler base. Extend it with an empty body and decorate it, `@ButtonRoute(p.cursor)`. */\n public readonly Handler: PaginatorHandlerCtor<Prefix>;\n\n constructor(config: PaginatorConfig<Item, Prefix, PageContext>) {\n super(config);\n\n // an arrow captures the paginator lexically so Nav.execute can reach it without aliasing `this`.\n const loadPage = (ctx: PageContext, n: number): Promise<ReplyResponse> => this.page(ctx, n);\n this.Handler = class Nav extends ButtonHandler<[PageCursor<Prefix>]> {\n async execute(): Promise<void> {\n await this.deferUpdate();\n const response = await loadPage(contextOf(this.event, this.core), this.params.page);\n // deferUpdate seeds the sender deferred-update, so update PATCHes @original\n await this.update(response);\n }\n };\n }\n\n /**\n * Render page 0 and send it through the handler's sender, which picks reply, edit, or followUp from its\n * ack state.\n *\n * @param handler - The handler starting the paginator, normally `this`.\n */\n async start(handler: RepliableHandler<Repliables>): Promise<Message> {\n const interaction = handler.getEvent();\n const response = await this.page(contextOf(interaction, handler.core), 0);\n return handler.getSender().send(response, { ephemeral: this.config.ephemeral ?? false });\n }\n}\n","import { ArraySource as BaseArraySource, CursorSource as BaseCursorSource } from '@seedcord/core';\n\nimport type { PageContext } from './PageContext';\n\n/**\n * A source for a bounded list you can load whole. It loads the full list on every click, then slices the\n * page, so the real total is known (a real last button, \"Page X of Y\"). Cache inside your loader if the\n * load is expensive.\n *\n * @typeParam Item - The item type, inferred from the loader's return.\n */\nexport class ArraySource<Item> extends BaseArraySource<Item, PageContext> {}\n\n/**\n * A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).\n * The fetcher receives the page index and the page size and reports whether a next page exists. A cursor\n * source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator\n * reads \"Page X\".\n *\n * @typeParam Item - The item type, inferred from the fetcher's slice.\n */\nexport class CursorSource<Item> extends BaseCursorSource<Item, PageContext> {}\n","import { Subscriber as CoreSubscriber, WebhookLog as CoreWebhookLog } from '@seedcord/core';\n\nimport type { Core } from '@interfaces/Core';\nimport type { SubscriptionKey } from '@seedcord/core';\n\n/**\n * Base class for a gateway subscriber, binding `this.core` to the gateway {@link Core}.\n *\n * @typeParam KeyOfSubscribers - The subscription key this handler receives\n */\nexport abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey> extends CoreSubscriber<\n KeyOfSubscribers,\n Core\n> {}\n\n/**\n * Base class for a gateway subscriber that delivers its event to a Discord webhook, binding\n * `this.core` to the gateway {@link Core}.\n *\n * @typeParam KeyOfSubscribers - The subscription key this reporter receives\n */\nexport abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey> extends CoreWebhookLog<\n KeyOfSubscribers,\n Core\n> {}\n","import { Plugin as CorePlugin } from '@seedcord/core/plugin';\n\nimport type { Core } from '@interfaces/Core';\nimport type { PluginOptions } from '@seedcord/core/plugin';\nimport type { TypedOmit } from '@seedcord/types';\n\n/** The options a gateway plugin declares, narrowed to the transports this base serves. */\nexport type GatewayPluginOptions = TypedOmit<PluginOptions, 'transport'> & { transport?: 'gateway' | 'any' };\n\n/**\n * Base class for a gateway plugin, binding `this.core` to the gateway {@link Core}.\n *\n * A plugin that runs on either transport extends the base from `@seedcord/core/plugin`, whose\n * `this.core` is typed to the shared members only.\n *\n * @typeParam Opts - The transport and runtime the plugin declares.\n */\nexport abstract class Plugin<Opts extends GatewayPluginOptions = {}> extends CorePlugin<Opts, Core> {}\n\nexport type { PluginLifecycleSpec, PluginOptions } from '@seedcord/core/plugin';\n","import { GuildMember, Message, User } from 'discord.js';\n\nimport type { Guild } from 'discord.js';\n\nexport interface EventActor {\n guild: Guild | null;\n member: GuildMember | null;\n user: User | null;\n channelId: string | null;\n}\n\n// the actor sits in a different arg per event, so scan the tuple for the common carriers, best-effort\nexport function deriveEventActor(args: unknown): EventActor {\n const tuple = Array.isArray(args) ? (args as unknown[]) : [args];\n for (const arg of tuple) {\n if (arg instanceof Message) {\n return { guild: arg.guild, member: arg.member, user: arg.author, channelId: arg.channelId };\n }\n if (arg instanceof GuildMember) return { guild: arg.guild, member: arg, user: arg.user, channelId: null };\n if (arg instanceof User) return { guild: null, member: null, user: arg, channelId: null };\n }\n return { guild: null, member: null, user: null, channelId: null };\n}\n","import { GuildMember } from 'discord.js';\n\nimport { deriveEventActor } from '@miscellaneous/deriveEventActor';\n\nimport type { EventGateContext, InteractionGateContext } from './Gate';\nimport type { Core } from '@interfaces/Core';\nimport type { Repliables, ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\n\nexport function interactionGateContext(interaction: Repliables, core: Core): InteractionGateContext {\n const rawMember = interaction.member;\n // an uncached member still arrives as the raw payload shape, whose roles are already ids. the cache\n // additionally carries the everyone role (id equals the guild id), which the raw payload never does,\n // so it is filtered out for one shape across cache states\n const memberRoleIds =\n rawMember instanceof GuildMember\n ? [...rawMember.roles.cache.keys()].filter((id) => id !== interaction.guildId)\n : (rawMember?.roles ?? []);\n\n return {\n kind: 'interaction',\n interaction,\n core,\n user: interaction.user,\n guild: interaction.guild,\n member: rawMember instanceof GuildMember ? rawMember : null,\n userId: interaction.user.id,\n guildId: interaction.guildId,\n channelId: interaction.channelId,\n memberRoleIds,\n memberPermissions: interaction.memberPermissions?.bitfield ?? null,\n // djs types appPermissions non-null on interactions, a ?. here would trip no-unnecessary-condition\n appPermissions: interaction.appPermissions.bitfield,\n memberGuildPermissions: rawMember instanceof GuildMember ? rawMember.permissions.bitfield : null,\n appGuildPermissions: interaction.guild?.members.me?.permissions.bitfield ?? null,\n routeId: null // runHandlerGates sets routeId from the handler metadata before the gates run\n };\n}\n\nexport function eventGateContext(\n eventName: ValidNonInteractionKeys,\n args: ClientEvents[ValidNonInteractionKeys],\n core: Core\n): EventGateContext {\n const actor = deriveEventActor(args);\n return {\n kind: 'event',\n core,\n eventName,\n payload: args,\n user: actor.user,\n guild: actor.guild,\n member: actor.member,\n userId: actor.user?.id ?? null,\n guildId: actor.guild?.id ?? null,\n channelId: actor.channelId,\n // the cache carries the everyone role (id equals the guild id), filtered out to match the interaction shape\n memberRoleIds: actor.member ? [...actor.member.roles.cache.keys()].filter((id) => id !== actor.guild?.id) : [],\n memberPermissions: actor.member?.permissions.bitfield ?? null,\n appPermissions: null,\n memberGuildPermissions: actor.member?.permissions.bitfield ?? null,\n appGuildPermissions: actor.guild?.members.me?.permissions.bitfield ?? null,\n routeId: null // runHandlerGates sets routeId from the handler metadata before the gates run\n };\n}\n","import * as crypto from 'node:crypto';\n\nimport { Notice, Fault } from '@seedcord/core';\nimport { prefixOf, PublishDefault, FaultThrottle } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/logger';\nimport { DiscordAPIError } from 'discord.js';\n\nimport { slashRouteOf } from '@bot/utilities/miscellaneous/slashRouteOf';\n\nimport type { Core } from '@interfaces/Core';\nimport type { FaultSource, SubscriptionData } from '@seedcord/core';\nimport type { RenderContext, ReplyResponse, Nullable } from '@seedcord/types';\nimport type { Repliables } from '@src/handlers/interactionTypes';\nimport type { Guild, User } from 'discord.js';\nimport type { UUID } from 'node:crypto';\n\ntype InteractionFaultSource = Extract<FaultSource, { kind: 'interaction' }>;\ntype EventFaultSource = Extract<FaultSource, { kind: 'event' }>;\n\nconst logger = new Logger('ErrorsHandling', { channel: 'errors' });\n\ninterface EventOrigin {\n name: string;\n handler: string;\n args: unknown;\n channelId: string | null;\n}\n\nexport interface ErrorOrigin {\n interaction?: Repliables;\n event?: EventOrigin;\n /** The route, for the throttle key when there is no repliable interaction or event (autocomplete). */\n route?: string;\n guild: Nullable<Guild>;\n user: Nullable<User>;\n metadata?: unknown;\n}\n\nexport interface ExtractedErrorResponse {\n uuid: UUID;\n response: ReplyResponse;\n}\n\n/**\n * Processes an error into a user-facing reply and routes its report.\n *\n * A {@link Notice} always renders its own reply. A reporting denial (`report: true`) additionally\n * publishes `handledException` on the interaction path. A raw, non-denial throw publishes\n * `unknownException` and renders the configured `defaultError` (or a generic {@link Fault}). One uuid is\n * threaded into both the reply and the bus payload.\n */\nexport function extractErrorResponse(error: Error, core: Core, origin: ErrorOrigin): ExtractedErrorResponse {\n const uuid = crypto.randomUUID();\n const developerUsername = core.config.notifications?.developerUsername;\n const ctx: RenderContext = developerUsername === undefined ? { uuid } : { uuid, developerUsername };\n\n if (error instanceof Notice) {\n if (error.report) reportFault(error, core, origin, uuid);\n return { uuid, response: error.render(ctx) };\n }\n\n reportRawFault(error, core, origin, uuid);\n\n const override = core.config.errors?.defaultError;\n const response = override ? new override(uuid).render(ctx) : new Fault().render(ctx);\n\n return { uuid, response };\n}\n\n// stamp only after a publish, so a throttled fault stays reportable next window\nfunction withThrottle(core: Core, origin: ErrorOrigin, error: Error, publish: () => void): void {\n const throttle = FaultThrottle.for(core);\n const key = faultKey(origin, error);\n if (!throttle.shouldReport(key)) {\n logger.debug(`throttled duplicate fault ${key}`);\n return;\n }\n publish();\n throttle.markReported(key);\n}\n\nfunction reportFault(denial: Notice, core: Core, origin: ErrorOrigin, uuid: UUID): void {\n // outside the throttle, so the uuid on the user's card always resolves to a log line\n logger.error(`${denial.name}: ${uuid}`, denial);\n\n withThrottle(core, origin, denial, () => {\n if (origin.interaction) {\n core.bus[PublishDefault]('handledException', {\n denial,\n uuid,\n source: buildInteractionSource(origin.interaction)\n });\n } else if (origin.event) {\n core.bus[PublishDefault]('handledException', {\n denial,\n uuid,\n source: buildEventSource(origin.event, origin)\n });\n } else {\n // autocomplete has no reply target and no typed source, so report through unknownException\n core.bus[PublishDefault]('unknownException', {\n uuid,\n error: denial,\n ...scalarActors(origin),\n metadata: metadataFor(origin)\n });\n }\n });\n}\n\nfunction causeLine(error: Error): string {\n const { cause } = error;\n if (!Error.isError(cause)) return '';\n const [first] = cause.message.split('\\n');\n return `\\ncaused by ${cause.name}: ${first ?? cause.message}`;\n}\n\nfunction reportRawFault(error: Error, core: Core, origin: ErrorOrigin, uuid: UUID): void {\n const showStack = core.config.errors?.errorStack ?? false;\n // outside the throttle, so the uuid on the user's card always resolves to a log line\n if (showStack) logger.error(uuid, error);\n else logger.error(`${uuid} | ${error.message}${causeLine(error)}`);\n\n withThrottle(core, origin, error, () => {\n core.bus[PublishDefault]('unknownException', {\n uuid,\n error,\n ...scalarActors(origin),\n metadata: metadataFor(origin)\n });\n });\n}\n\n// the bus payload must stay djs-free, so map to plain scalars\nfunction scalarActors(origin: ErrorOrigin): Pick<SubscriptionData<'unknownException'>, 'guild' | 'user'> {\n return {\n guild: origin.guild ? { id: origin.guild.id, name: origin.guild.name } : undefined,\n user: origin.user ? { id: origin.user.id, username: origin.user.username } : undefined\n };\n}\n\nfunction metadataFor(origin: ErrorOrigin): unknown {\n if (origin.event) return { eventName: origin.event.name, handler: origin.event.handler, args: origin.event.args };\n return origin.metadata;\n}\n\nfunction buildEventSource(event: EventOrigin, origin: ErrorOrigin): EventFaultSource {\n return {\n kind: 'event',\n eventName: event.name,\n handler: event.handler,\n userId: origin.user?.id ?? null,\n guildId: origin.guild?.id ?? null,\n channelId: event.channelId,\n raw: event.args\n };\n}\n\n// the stable route plus the error name, so a parameterized component or a flooding event collapses to one key\nfunction faultKey(origin: ErrorOrigin, error: Error): string {\n const name =\n error instanceof Notice\n ? error.name\n : error instanceof DiscordAPIError\n ? String(error.code)\n : error.constructor.name;\n if (origin.event) return `${origin.event.name}:${origin.event.handler}:${name}`;\n if (origin.interaction) return `${interactionRoute(origin.interaction)}:${name}`;\n // autocomplete, namespaced so it never collides with a same-named slash command\n if (origin.route) return `autocomplete:${origin.route}:${name}`;\n return `autocomplete:${name}`;\n}\n\nfunction interactionRoute(interaction: Repliables): string {\n if (interaction.isChatInputCommand()) return slashRouteOf(interaction);\n if (interaction.isContextMenuCommand()) return interaction.commandName;\n if (interaction.isButton() || interaction.isAnySelectMenu() || interaction.isModalSubmit()) {\n // || so an empty prefix (a too-short routeKey) falls back to the full wire\n return prefixOf(interaction.customId) || interaction.customId;\n }\n return 'interaction';\n}\n\nfunction buildInteractionSource(interaction: Repliables): InteractionFaultSource {\n const command = interaction.isChatInputCommand()\n ? slashRouteOf(interaction)\n : interaction.isContextMenuCommand()\n ? interaction.commandName\n : null;\n const customId =\n interaction.isButton() || interaction.isAnySelectMenu() || interaction.isModalSubmit()\n ? interaction.customId\n : null;\n\n return {\n kind: 'interaction',\n interactionKind: interactionKind(interaction),\n command,\n customId,\n userId: interaction.user.id,\n guildId: interaction.guildId,\n channelId: interaction.channelId,\n interactionId: interaction.id,\n raw: interaction\n };\n}\n\nfunction interactionKind(interaction: Repliables): InteractionFaultSource['interactionKind'] {\n if (interaction.isChatInputCommand()) return 'slash';\n if (interaction.isContextMenuCommand()) return 'context-menu';\n if (interaction.isButton()) return 'button';\n if (interaction.isAnySelectMenu()) return 'select';\n return 'modal';\n}\n","import { Notice, Silence } from '@seedcord/core';\nimport { asError } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/logger';\nimport { DiscordAPIError } from 'discord.js';\n\nimport { deriveEventActor } from '@miscellaneous/deriveEventActor';\nimport { extractErrorResponse } from '@miscellaneous/extractErrorResponse';\n\nimport type { Core } from '@interfaces/Core';\n\nconst logger = new Logger('EventBoundary', { channel: 'errors' });\n\n/**\n * The event controller boundary. Reports a throw from an event handler and never replies, since a\n * generic event has no reply target. A {@link Silence} or a non-reporting {@link Notice} stops quietly, a\n * reporting denial or a raw error publishes a fault with a best-effort actor derived from the args.\n *\n * @internal\n */\nexport function handleEventFault(\n caught: unknown,\n eventName: string,\n handlerName: string,\n args: unknown,\n core: Core\n): void {\n if (caught instanceof Silence) {\n if (caught.reason !== undefined && (core.config.errors?.logSilences ?? true)) {\n logger.debug(`Silence: ${caught.reason}`);\n }\n return;\n }\n const error = asError(caught);\n\n // empty by default, so a dead resource on an event reports (throttled) until the dev confirms it is\n // an expected dead end and adds the code here. a swallowed code still debug-logs.\n const ignore = new Set<number | string>(core.config.errors?.ignoreEventApiCodes ?? []);\n if (error instanceof DiscordAPIError && ignore.has(error.code)) {\n logger.debug(`swallowed api code ${error.code}`);\n return;\n }\n\n // a non-reporting denial has no reply target on an event, so it stops quietly\n if (error instanceof Notice && !error.report) return;\n\n const actor = deriveEventActor(args);\n extractErrorResponse(error, core, {\n event: { name: eventName, handler: handlerName, args, channelId: actor.channelId },\n guild: actor.guild,\n user: actor.user\n });\n}\n","import { HmrModuleHandler } from '@seedcord/core/hmr';\nimport {\n areRoutes,\n asError,\n EventMetadataKey,\n MiddlewareMetadataKey,\n PublishDefault,\n runHandlerGates\n} from '@seedcord/core/internal';\nimport { settleWithin } from '@seedcord/core/node/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger, paint } from '@seedcord/logger';\nimport { formatFilePath, hasKeys } from '@seedcord/utils';\nimport { traverseDirectory } from '@seedcord/utils/node';\nimport { Envapter } from 'envapt';\n\nimport { MiddlewareType } from '@bDecorators/Middlewares';\nimport { eventGateContext } from '@bot/gates/runGates';\nimport { handleEventFault } from '@bot/handleEventFault';\nimport { EventHandler, EventMiddleware } from '@handlers/event';\n\nimport type { RegisterEventMetadataEntry } from '@bDecorators/Events';\nimport type { MiddlewareMetadata } from '@bDecorators/Middlewares';\nimport type { EventHandlerConstructor, EventMiddlewareConstructor } from '@handlers/constructors';\nimport type { Core } from '@interfaces/Core';\nimport type { Initializeable, SubscriptionData } from '@seedcord/core';\nimport type { EventFrequency, HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\n\ninterface RegisteredEventMiddleware {\n readonly ctor: EventMiddlewareConstructor;\n readonly priority: number;\n readonly events?: readonly ValidNonInteractionKeys[];\n}\n\ninterface RegisteredEventHandlerEntry {\n readonly ctor: EventHandlerConstructor;\n readonly frequency: EventFrequency;\n}\n\ntype EventArtifact = string;\n\n/**\n * Scans event handler directories, attaches one client listener per registered event, and runs the\n * handlers for each fire. Interactions route through InteractionDispatcher. Multiple handlers can\n * point to one event.\n *\n * @internal\n */\nexport class EventDispatcher implements Initializeable, HmrAware {\n private readonly logger = new Logger('Events', { channel: 'events' });\n private isInitialized = false;\n\n private readonly eventMap = new Map<keyof ClientEvents, RegisteredEventHandlerEntry[]>();\n private readonly middlewares: RegisteredEventMiddleware[] = [];\n private readonly executedOnceHandlers = new Set<EventHandlerConstructor>();\n private readonly attachedEvents = new Set<keyof ClientEvents>();\n\n private readonly inFlight = new Set<Promise<void>>();\n private draining = false;\n\n // batched during bulk load, hmr registrations log inline\n private loading = false;\n private readonly loadedHandlers: { name: string; from: string }[] = [];\n private readonly loadedMiddlewares: { name: string; from: string }[] = [];\n\n private readonly hmrHandler?: HmrModuleHandler<\n EventHandlerConstructor,\n EventMiddlewareConstructor,\n EventArtifact[]\n >;\n\n public constructor(protected core: Core) {\n const eventsDir = this.core.config.bot.events.path;\n if (!eventsDir) {\n // unreachable today, guards against a path regression\n throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, ['EventDispatcher', 'events']);\n }\n\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n\n this.hmrHandler = new HmrModuleHandler({\n handlersDir: eventsDir,\n ...(hasKeys(this.core.config.bot.events, ['middlewares']) && {\n middlewaresDir: this.core.config.bot.events.middlewares\n }),\n isHandler: this.isEventHandlerClass.bind(this),\n isMiddleware: this.isMiddlewareClass.bind(this),\n registerHandler: this.registerHandler.bind(this),\n registerMiddleware: this.registerMiddleware.bind(this),\n unregisterHandler: this.unregisterHandler.bind(this),\n unregisterMiddleware: this.unregisterMiddleware.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n\n private getArtifacts(ctor: EventHandlerConstructor): EventArtifact[] {\n const events: EventArtifact[] = [];\n for (const [event, handlers] of this.eventMap.entries()) {\n if (handlers.some((h) => h.ctor === ctor)) events.push(event);\n }\n return events;\n }\n\n public async init(): Promise<void> {\n if (this.isInitialized) {\n return;\n }\n this.isInitialized = true;\n\n const handlersDir = this.core.config.bot.events.path;\n if (!handlersDir) {\n return;\n }\n\n const middlewareDir = hasKeys(this.core.config.bot.events, ['middlewares'])\n ? this.core.config.bot.events.middlewares\n : undefined;\n\n this.loading = true;\n this.loadedHandlers.length = 0;\n this.loadedMiddlewares.length = 0;\n try {\n if (middlewareDir) await this.loadMiddlewares(middlewareDir);\n await this.loadHandlers(handlersDir);\n } finally {\n this.loading = false;\n }\n\n this.attachToClient();\n this.reportLoad();\n }\n\n private reportLoad(): void {\n const { utils } = this.logger;\n\n utils.summary('Loaded', {\n 'event handlers': this.loadedHandlers.length,\n middlewares: this.loadedMiddlewares.length\n });\n\n if (this.loadedMiddlewares.length > 0) {\n utils.block('Loaded event middlewares', utils.entries(this.loadedMiddlewares));\n }\n\n const perEvent: Record<string, number> = {};\n for (const [event, handlers] of this.eventMap) perEvent[event] = handlers.length;\n\n utils.block('Loaded event handlers', [...utils.entries(this.loadedHandlers), ...utils.counts(perEvent)]);\n }\n\n private async loadHandlers(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const val of Object.values(imported)) {\n if (!this.isEventHandlerClass(val)) continue;\n this.registerHandler(val, relativePath);\n this.hmrHandler?.trackHandler(fullPath, val);\n }\n });\n }\n\n private async loadMiddlewares(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const val of Object.values(imported)) {\n if (!this.isMiddlewareClass(val)) continue;\n\n this.registerMiddleware(val, relativePath);\n this.hmrHandler?.trackMiddleware(fullPath, val);\n }\n });\n }\n\n /** @internal For use in dev mode */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n await this.hmrHandler?.handle(event);\n }\n\n private unregisterHandler(handlerClass: EventHandlerConstructor, artifacts?: EventArtifact[]): void {\n const events = artifacts ?? [...this.eventMap.keys()];\n for (const event of events) {\n const handlers = this.eventMap.get(event as keyof ClientEvents);\n if (!handlers) continue;\n const index = handlers.findIndex((h) => h.ctor === handlerClass);\n if (index !== -1) {\n handlers.splice(index, 1);\n if (handlers.length === 0) {\n this.eventMap.delete(event as keyof ClientEvents);\n }\n }\n }\n // spent follows the ctor identity, so leaving executedOnceHandlers alone keeps a rollback-restored ctor spent\n }\n\n private unregisterMiddleware(middlewareCtor: EventMiddlewareConstructor): void {\n const index = this.middlewares.findIndex((entry) => entry.ctor === middlewareCtor);\n if (index !== -1) {\n this.middlewares.splice(index, 1);\n }\n }\n\n private registerMiddleware(middlewareCtor: EventMiddlewareConstructor, relativePath: string): void {\n const metadata = Reflect.getMetadata(MiddlewareMetadataKey, middlewareCtor) as MiddlewareMetadata | undefined;\n if (metadata?.type !== MiddlewareType.Event) return;\n\n const alreadyRegistered = this.middlewares.some((entry) => entry.ctor === middlewareCtor);\n if (alreadyRegistered) return;\n\n this.middlewares.push({\n ctor: middlewareCtor,\n priority: metadata.priority,\n ...(metadata.events && { events: metadata.events })\n });\n this.middlewares.sort((a, b) => a.priority - b.priority);\n\n if (this.loading) {\n this.loadedMiddlewares.push({\n name: `${middlewareCtor.name} (${metadata.priority})`,\n from: formatFilePath(relativePath)\n });\n return;\n }\n\n this.logger.utils.registration(\n `${middlewareCtor.name} ${paint.mute(`(${metadata.priority})`)}`,\n relativePath,\n 'event middleware'\n );\n }\n\n private async runMiddlewares<KeyOfEvents extends keyof ClientEvents>(\n eventName: KeyOfEvents,\n args: ClientEvents[KeyOfEvents]\n ): Promise<boolean> {\n for (const { ctor, events } of this.middlewares) {\n if (events && !events.includes(eventName)) continue;\n\n try {\n const middleware = new ctor(args, this.core, eventName); // event name so a catchall/multi middleware can read this.eventName\n await middleware.execute();\n } catch (caught) {\n // a middleware throw stops the event for downstream handlers\n handleEventFault(caught, String(eventName), ctor.name, args, this.core);\n return false;\n }\n }\n\n return true;\n }\n\n private isEventHandlerClass(obj: unknown): obj is EventHandlerConstructor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof EventHandler && Reflect.hasMetadata(EventMetadataKey, obj);\n }\n\n private isMiddlewareClass(obj: unknown): obj is EventMiddlewareConstructor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof EventMiddleware && Reflect.hasMetadata(MiddlewareMetadataKey, obj);\n }\n\n private registerHandler(handlerClass: EventHandlerConstructor, relativePath: string): void {\n const raw = Reflect.getMetadata(EventMetadataKey, handlerClass) as unknown;\n\n const register = (key: keyof ClientEvents, frequency: EventFrequency): void => {\n let handlers = this.eventMap.get(key);\n if (!handlers) {\n handlers = [];\n this.eventMap.set(key, handlers);\n }\n\n handlers.push({\n ctor: handlerClass,\n frequency\n });\n\n // a post-init (hmr) registration can add an event with no client listener yet\n if (this.isInitialized && !this.attachedEvents.has(key)) {\n this.attachListener(key);\n }\n };\n\n if (Array.isArray(raw)) {\n for (const entry of raw as RegisterEventMetadataEntry<keyof ClientEvents>[]) {\n register(entry.event, entry.frequency);\n }\n } else {\n const names = areRoutes(raw) ? raw : typeof raw === 'string' ? [raw] : [];\n\n for (const name of names) {\n register(name as keyof ClientEvents, 'on');\n }\n }\n\n const from = formatFilePath(relativePath);\n if (this.loading) this.loadedHandlers.push({ name: handlerClass.name, from });\n else this.logger.utils.registration(handlerClass.name, from);\n }\n\n private attachToClient(): void {\n for (const [eventName] of this.eventMap) {\n this.attachListener(eventName);\n }\n }\n\n private attachListener(eventName: keyof ClientEvents): void {\n if (this.attachedEvents.has(eventName)) return;\n this.attachedEvents.add(eventName);\n\n const handlerEntries = this.eventMap.get(eventName);\n this.logger.debug(\n `Attaching ${paint.mint.bold(eventName)} to the client with ${paint.mute(handlerEntries?.length ?? 0)} handler(s)`\n );\n\n this.core.bot.client.on(eventName, (...args: ClientEvents[typeof eventName]) => {\n if (this.draining) return;\n // justified: the per-event tuple erases across the generic key, args matches eventName here\n this.core.bus[PublishDefault]('anyEvent', { name: eventName, args } as SubscriptionData<'anyEvent'>);\n const run = this.processEvent(eventName, args).catch((caught: unknown) => {\n const error = asError(caught);\n this.logger.error(`[${paint.coral.bold('UNHANDLED ERROR AT ROOT')}] ${error.name}`, error.stack);\n this.core.bus[PublishDefault]('unhandledEventError', { error });\n });\n this.inFlight.add(run);\n void run.finally(() => this.inFlight.delete(run));\n });\n }\n\n public stopAccepting(): void {\n this.draining = true;\n }\n\n public drain(timeoutMs: number): Promise<void> {\n return settleWithin(Promise.allSettled(this.inFlight), timeoutMs);\n }\n\n private async processEvent<KeyOfEvents extends keyof ClientEvents>(\n eventName: KeyOfEvents,\n args: ClientEvents[KeyOfEvents]\n ): Promise<void> {\n const handlerEntries = this.eventMap.get(eventName);\n if (!handlerEntries || handlerEntries.length === 0) return;\n\n const handlersToExecute = handlerEntries.filter(\n (entry) => entry.frequency !== 'once' || !this.executedOnceHandlers.has(entry.ctor)\n );\n\n // avoid running middlewares when every handler is a spent 'once'\n if (handlersToExecute.length === 0) return;\n\n const shouldContinue = await this.runMiddlewares(eventName, args);\n if (!shouldContinue) return;\n\n for (const entry of handlersToExecute) {\n // mark a 'once' handler spent before running so a rethrow can't re-fire it. the has() re-check\n // closes the window where a concurrent fire claimed it during the runMiddlewares await\n if (entry.frequency === 'once') {\n if (this.executedOnceHandlers.has(entry.ctor)) continue;\n this.executedOnceHandlers.add(entry.ctor);\n }\n\n await this.processHandler(eventName, entry.ctor, args);\n }\n }\n\n private async processHandler<KeyOfEvents extends keyof ClientEvents>(\n eventName: KeyOfEvents,\n ctor: EventHandlerConstructor,\n args: ClientEvents[KeyOfEvents]\n ): Promise<void> {\n try {\n this.logger.debug(`Processing ${paint.mint.bold(eventName)} with ${paint.mute(ctor.name)}`);\n const handler = new ctor(args, this.core, eventName); // event name so match can route by it\n const eventCtx = eventGateContext(eventName, args, this.core);\n await runHandlerGates(ctor, eventCtx);\n await handler.execute();\n } catch (caught) {\n handleEventFault(caught, String(eventName), ctor.name, args, this.core);\n }\n }\n}\n","import { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { Repliables } from '@src/handlers/interactionTypes';\n\n/**\n * @internal Default handler for unhandled repliable interactions.\n */\nexport class UnhandledRepliable extends InteractionHandler<Repliables> {\n async execute(): Promise<void> {\n await this.reply('Feature not implemented yet.');\n }\n}\n","import { AutocompleteHandler } from '@handlers/interaction/AutocompleteHandler';\n\nimport type { SlashOptionRegistry } from '@seedcord/core';\nimport type { CacheType } from 'discord.js';\n\n/**\n * @internal Default handler for an autocomplete with no registered handler.\n */\n// eslint-disable-next-line @seedcord/interaction-handler-missing-route -- the dispatcher's autocomplete fallback, never registered\nexport class UnhandledAutocomplete extends AutocompleteHandler<keyof SlashOptionRegistry, CacheType> {\n async execute(): Promise<void> {\n await this.respond([]);\n }\n}\n","import { RESTJSONErrorCodes } from 'discord.js';\n\n/**\n * Discord API error codes that mean a dead end on an interaction, a dead token, a double ack, or a gone\n * message. Nothing to show the user and no bug to report, so the boundary's fault-card send drops them.\n *\n * @internal\n */\nexport const HARMLESS_API_CODES: ReadonlySet<number | string> = new Set([\n RESTJSONErrorCodes.UnknownInteraction,\n RESTJSONErrorCodes.InteractionHasAlreadyBeenAcknowledged,\n RESTJSONErrorCodes.UnknownMessage\n]);\n","import { Notice, Silence } from '@seedcord/core';\nimport { asError, reportedWrite } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/logger';\nimport { DiscordAPIError } from 'discord.js';\n\nimport { ReplySender } from '@bot/ReplySender';\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { extractErrorResponse } from '@miscellaneous/extractErrorResponse';\n\nimport { HARMLESS_API_CODES } from './harmlessApiCodes';\n\nimport type { Core } from '@interfaces/Core';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { ValidInteractionTypes } from '@src/handlers/interactionTypes';\nimport type { AutocompleteInteraction } from 'discord.js';\n\nconst logger = new Logger('InteractionBoundary', { channel: 'errors' });\n\n/**\n * The interaction controller boundary. Sorts a throw from any handler-lifecycle phase into the right\n * user reply plus the right bus event. When a handler is built its sender is passed in, so the boundary\n * sends from the current ack state. A middleware or pre-construction throw arrives with no sender, so the\n * boundary builds one from the interaction flags.\n *\n * @internal\n */\nexport async function handleInteractionFault(\n caught: unknown,\n interaction: ValidInteractionTypes,\n core: Core,\n routeId: string,\n sender?: ReplySender\n): Promise<void> {\n if (caught instanceof Silence) {\n if (caught.reason !== undefined && (core.config.errors?.logSilences ?? true)) {\n logger.debug(`Silence: ${caught.reason}`);\n }\n return;\n }\n const error = asError(caught);\n\n // empty by default, so every api code from the handler's own work reports\n const ignore = new Set<number | string>(core.config.errors?.ignoreApiCodes ?? []);\n if (error instanceof DiscordAPIError && ignore.has(error.code)) {\n logger.debug(`swallowed api code ${error.code}`);\n return;\n }\n\n // autocomplete has no reply target, so report through extractErrorResponse and build no sender\n if (interaction.isAutocomplete()) {\n extractErrorResponse(error, core, {\n guild: interaction.guild,\n user: interaction.user,\n metadata: interaction,\n route: slashRouteOf(interaction)\n });\n // empty choices are the only legal response, and they clear the client's loading spinner\n await sendEmptyChoices(interaction, core, routeId);\n return;\n }\n\n const { response } = extractErrorResponse(error, core, {\n interaction,\n guild: interaction.guild,\n user: interaction.user,\n metadata: interaction\n });\n const liveSender = sender ?? new ReplySender(interaction, routeId, core.bus);\n await sendGuarded(liveSender, response, error instanceof Notice ? error.ephemeral : true);\n}\n\n// reports like any other write, so a faulted autocomplete still shows its discord round trip\nasync function sendEmptyChoices(interaction: AutocompleteInteraction, core: Core, routeId: string): Promise<void> {\n const telemetry = { bus: core.bus, interactionId: interaction.id };\n try {\n await reportedWrite(telemetry, routeId, 'respond', () => interaction.respond([]));\n } catch (error) {\n logger.debug(`autocomplete empty-choices send failed: ${String(error)}`);\n }\n}\n\n// the boundary's own send drops the harmless reply-token codes so a dead token never escapes it\nasync function sendGuarded(sender: ReplySender, response: ReplyResponse, ephemeral: boolean): Promise<void> {\n try {\n await sender.send(response, { ephemeral });\n } catch (error) {\n if (error instanceof DiscordAPIError && HARMLESS_API_CODES.has(error.code)) {\n logger.debug(`reply send hit harmless code ${error.code}`);\n return;\n }\n logger.error('reply send failed', error);\n }\n}\n","/* eslint-disable max-lines -- one handler method per interaction type keeps the router in one file */\nimport { DispatchContext } from '@seedcord/core';\nimport { HmrModuleHandler } from '@seedcord/core/hmr';\nimport {\n InteractionMetadataKey,\n InteractionRouteKeys,\n InteractionRoutes,\n asError,\n dispatchedPayload,\n outcomeFor,\n queuedMsFor,\n MiddlewareMetadataKey,\n prefixOf,\n PublishDefault,\n routeIdOf,\n runHandlerGates,\n slowGateMonitor,\n areRoutes\n} from '@seedcord/core/internal';\nimport { settleWithin } from '@seedcord/core/node/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger, paint } from '@seedcord/logger';\nimport { formatFilePath, hasKeys } from '@seedcord/utils';\nimport { traverseDirectory } from '@seedcord/utils/node';\nimport chalk from 'chalk';\nimport { Events } from 'discord.js';\nimport { Envapter } from 'envapt';\n\nimport { MiddlewareType } from '@bDecorators/Middlewares';\nimport { CONFIRM_DEF } from '@bot/confirm/reserved';\nimport { UnhandledAutocomplete, UnhandledRepliable } from '@bot/defaults';\nimport { interactionGateContext } from '@bot/gates/runGates';\nimport { handleInteractionFault } from '@bot/handleInteractionFault';\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { AutocompleteHandler, InteractionMiddleware } from '@handlers/interaction';\nimport { InteractionHandler } from '@handlers/interaction/InteractionHandler';\nimport { RepliableHandler } from '@handlers/RepliableHandler';\n\nimport type { MiddlewareMetadata } from '@bDecorators/Middlewares';\nimport type { ReplySender } from '@bot/ReplySender';\nimport type { HandlerConstructor, InteractionMiddlewareConstructor } from '@handlers/constructors';\nimport type { Core } from '@interfaces/Core';\nimport type { DispatchOutcome, Initializeable } from '@seedcord/core';\nimport type { ContextMenuLeaves } from '@seedcord/core/internal';\nimport type { CustomIdMatcher, HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { Repliables, ValidInteractionTypes } from '@src/handlers/interactionTypes';\nimport type {\n AutocompleteInteraction,\n ButtonInteraction,\n ChannelSelectMenuInteraction,\n ChatInputCommandInteraction,\n Interaction,\n MentionableSelectMenuInteraction,\n MessageContextMenuCommandInteraction,\n ModalSubmitInteraction,\n RoleSelectMenuInteraction,\n StringSelectMenuInteraction,\n UserContextMenuCommandInteraction,\n UserSelectMenuInteraction\n} from 'discord.js';\n\ninterface InteractionArtifact {\n routeType: InteractionRoutes;\n routes: string[];\n}\n\ninterface RegisteredMiddleware {\n readonly ctor: InteractionMiddlewareConstructor;\n readonly priority: number;\n}\n\ninterface DispatchedHandler {\n execute(): Promise<void>;\n}\n\n/**\n * Scans handler directories, routes each interaction to its registered handler, and runs the handler.\n * One handler per interaction.\n *\n * @internal\n */\nexport class InteractionDispatcher implements Initializeable, HmrAware {\n private readonly logger = new Logger('Interactions', { channel: 'interactions' });\n private isInitialized = false;\n\n private readonly slashMap = new Map<string, HandlerConstructor>();\n private readonly buttonMap = new Map<string, HandlerConstructor>();\n private readonly modalMap = new Map<string, HandlerConstructor>();\n private readonly stringSelectMap = new Map<string, HandlerConstructor>();\n private readonly userSelectMap = new Map<string, HandlerConstructor>();\n private readonly roleSelectMap = new Map<string, HandlerConstructor>();\n private readonly channelSelectMap = new Map<string, HandlerConstructor>();\n private readonly mentionableSelectMap = new Map<string, HandlerConstructor>();\n private readonly messageContextMenuMap = new Map<string, HandlerConstructor>();\n private readonly userContextMenuMap = new Map<string, HandlerConstructor>();\n private readonly autocompleteMap = new Map<string, HandlerConstructor>();\n\n // the duplicate-route error reports the file the existing class came from. A stale hmr artifact list can\n // leave a class in a route map after its entry here is gone, hence the fallback at the read site\n private readonly handlerFiles = new Map<HandlerConstructor, string>();\n\n private readonly keysToIgnore = new Set<CustomIdMatcher>();\n private readonly middlewares: RegisteredMiddleware[] = [];\n\n private readonly inFlight = new Set<Promise<void>>();\n private draining = false;\n\n // batched during bulk load, hmr registrations log inline\n private loading = false;\n private readonly loadedHandlers: { name: string; from: string }[] = [];\n private readonly loadedMiddlewares: { name: string; from: string }[] = [];\n\n private readonly hmrHandler?: HmrModuleHandler<\n HandlerConstructor,\n InteractionMiddlewareConstructor,\n InteractionArtifact[]\n >;\n\n private readonly routeTypes: [InteractionRoutes, Map<string, HandlerConstructor>][] = [\n [InteractionRoutes.Slash, this.slashMap],\n [InteractionRoutes.Button, this.buttonMap],\n [InteractionRoutes.Modal, this.modalMap],\n [InteractionRoutes.StringMenu, this.stringSelectMap],\n [InteractionRoutes.UserMenu, this.userSelectMap],\n [InteractionRoutes.RoleMenu, this.roleSelectMap],\n [InteractionRoutes.ChannelMenu, this.channelSelectMap],\n [InteractionRoutes.MentionableMenu, this.mentionableSelectMap],\n [InteractionRoutes.MessageContextMenu, this.messageContextMenuMap],\n [InteractionRoutes.UserContextMenu, this.userContextMenuMap],\n [InteractionRoutes.Autocomplete, this.autocompleteMap]\n ];\n\n constructor(protected core: Core) {\n const ignoredKeysFromConfig = hasKeys(this.core.config.bot.interactions, ['ignoreCustomIds'])\n ? this.core.config.bot.interactions.ignoreCustomIds\n : undefined;\n if (ignoredKeysFromConfig) {\n for (const ignoredKey of ignoredKeysFromConfig) this.keysToIgnore.add(ignoredKey);\n }\n\n // the in-process getConfirmation() collector consumes these clicks, so the global router would double-ack them\n this.keysToIgnore.add(CONFIRM_DEF);\n\n const interactionsDir = this.core.config.bot.interactions.path;\n if (!interactionsDir) {\n // unreachable today, guards against a path regression\n throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, [\n 'InteractionDispatcher',\n 'interactions'\n ]);\n }\n\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n this.hmrHandler = new HmrModuleHandler({\n handlersDir: interactionsDir,\n ...(hasKeys(this.core.config.bot.interactions, ['middlewares']) &&\n this.core.config.bot.interactions.middlewares && {\n middlewaresDir: this.core.config.bot.interactions.middlewares\n }),\n isHandler: this.isHandlerClass.bind(this),\n isMiddleware: this.isMiddlewareClass.bind(this),\n registerHandler: this.registerHandler.bind(this),\n registerMiddleware: this.registerMiddleware.bind(this),\n unregisterHandler: this.unregisterHandler.bind(this),\n unregisterMiddleware: this.unregisterMiddleware.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n\n public warnUnhandledRoutes(commandLeaves: Iterable<string>): void {\n for (const route of commandLeaves) {\n if (!this.slashMap.has(route)) {\n this.logger.warn(\n `Slash route ${paint.sky.bold(route)} has no registered ${chalk.bold('@SlashRoute')} handler.`\n );\n }\n }\n }\n\n public warnUnhandledContextMenuRoutes(leaves: ContextMenuLeaves): void {\n for (const name of leaves.user) {\n if (!this.userContextMenuMap.has(name)) {\n this.logger.warn(\n `User context menu ${paint.sky.bold(name)} has no registered ${chalk.bold('@ContextMenuRoute')} handler.`\n );\n }\n }\n for (const name of leaves.message) {\n if (!this.messageContextMenuMap.has(name)) {\n this.logger.warn(\n `Message context menu ${paint.sky.bold(name)} has no registered ${chalk.bold('@ContextMenuRoute')} handler.`\n );\n }\n }\n }\n\n private getArtifacts(handlerClass: HandlerConstructor): InteractionArtifact[] {\n const artifacts: InteractionArtifact[] = [];\n for (const [routeType] of this.routeTypes) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[routeType], handlerClass);\n if (areRoutes(meta)) artifacts.push({ routeType, routes: meta });\n }\n return artifacts;\n }\n\n public async init(): Promise<void> {\n if (this.isInitialized) return;\n\n this.isInitialized = true;\n\n const handlersDir = this.core.config.bot.interactions.path;\n // unreachable, the constructor throws when the path is unset\n if (!handlersDir) return;\n\n const middlewareDir = hasKeys(this.core.config.bot.interactions, ['middlewares'])\n ? this.core.config.bot.interactions.middlewares\n : undefined;\n\n this.loading = true;\n this.loadedHandlers.length = 0;\n this.loadedMiddlewares.length = 0;\n try {\n if (middlewareDir) await this.loadMiddlewares(middlewareDir);\n await this.loadHandlers(handlersDir);\n } finally {\n this.loading = false;\n }\n\n this.attachToClient();\n this.reportLoad();\n }\n\n private reportLoad(): void {\n const { utils } = this.logger;\n\n utils.summary('Loaded', {\n 'interaction handlers': this.loadedHandlers.length,\n middlewares: this.loadedMiddlewares.length\n });\n\n if (this.loadedMiddlewares.length > 0) {\n utils.block('Loaded middlewares', utils.entries(this.loadedMiddlewares));\n }\n\n utils.block('Loaded interaction handlers', [\n ...utils.entries(this.loadedHandlers),\n ...utils.counts({\n slash: this.slashMap.size,\n buttons: this.buttonMap.size,\n modals: this.modalMap.size,\n 'string selects': this.stringSelectMap.size,\n 'user selects': this.userSelectMap.size,\n 'role selects': this.roleSelectMap.size,\n 'channel selects': this.channelSelectMap.size,\n 'mentionable selects': this.mentionableSelectMap.size,\n 'message menus': this.messageContextMenuMap.size,\n 'user menus': this.userContextMenuMap.size,\n autocomplete: this.autocompleteMap.size\n })\n ]);\n }\n\n private async loadHandlers(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const val of Object.values(imported)) {\n if (!this.isHandlerClass(val)) continue;\n this.registerHandler(val, relativePath);\n this.hmrHandler?.trackHandler(fullPath, val);\n }\n });\n }\n\n private async loadMiddlewares(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const val of Object.values(imported)) {\n if (!this.isMiddlewareClass(val)) continue;\n\n this.registerMiddleware(val, relativePath);\n this.hmrHandler?.trackMiddleware(fullPath, val);\n }\n });\n }\n\n private registerMiddleware(middlewareCtor: InteractionMiddlewareConstructor, relativePath: string): void {\n const metadata = Reflect.getMetadata(MiddlewareMetadataKey, middlewareCtor) as MiddlewareMetadata | undefined;\n if (metadata?.type !== MiddlewareType.Interaction) return;\n\n // same class re-registered (double import or an HMR re-scan) is idempotent, matching event middleware\n if (this.middlewares.some((entry) => entry.ctor === middlewareCtor)) return;\n\n // a different class sharing the name would run alongside the first\n if (this.middlewares.some((entry) => entry.ctor.name === middlewareCtor.name)) {\n throw new SeedcordError(SeedcordErrorCode.InteractionDuplicateMiddleware, [middlewareCtor.name]);\n }\n\n this.middlewares.push({ ctor: middlewareCtor, priority: metadata.priority });\n this.middlewares.sort((a, b) => a.priority - b.priority);\n\n if (this.loading) {\n this.loadedMiddlewares.push({\n name: `${middlewareCtor.name} (${metadata.priority})`,\n from: formatFilePath(relativePath)\n });\n return;\n }\n\n this.logger.utils.registration(\n `${middlewareCtor.name} ${paint.mute(`(${metadata.priority})`)}`,\n relativePath,\n 'middleware'\n );\n }\n\n private isHandlerClass(obj: unknown): obj is HandlerConstructor {\n if (typeof obj !== 'function') return false;\n return (\n (obj.prototype instanceof InteractionHandler && Reflect.hasMetadata(InteractionMetadataKey, obj)) ||\n (obj.prototype instanceof AutocompleteHandler && Reflect.hasMetadata(InteractionMetadataKey, obj))\n );\n }\n\n private isMiddlewareClass(obj: unknown): obj is InteractionMiddlewareConstructor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof InteractionMiddleware && Reflect.hasMetadata(MiddlewareMetadataKey, obj);\n }\n\n private registerHandler(handlerClass: HandlerConstructor, relativePath: string): void {\n const from = formatFilePath(relativePath);\n // a partial registration would orphan routes and break hmr rollback\n const writes: [Map<string, HandlerConstructor>, string][] = [];\n\n for (const [routeType, map] of this.routeTypes) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[routeType], handlerClass);\n if (!areRoutes(meta)) continue;\n\n for (const route of meta) {\n const existing = map.get(route);\n // a different class on the same route would silently shadow (last write wins)\n if (existing && existing !== handlerClass) {\n throw new SeedcordError(SeedcordErrorCode.InteractionDuplicateRoute, [\n `${routeType}:${route}`,\n `${existing.name} (${this.handlerFiles.get(existing) ?? 'unknown file'})`,\n `${handlerClass.name} (${from})`\n ]);\n }\n writes.push([map, route]);\n }\n }\n\n if (writes.length === 0) return;\n for (const [map, route] of writes) map.set(route, handlerClass);\n this.handlerFiles.set(handlerClass, from);\n\n if (this.loading) this.loadedHandlers.push({ name: handlerClass.name, from });\n else this.logger.utils.registration(handlerClass.name, from);\n }\n\n /** @internal For use in dev mode */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n await this.hmrHandler?.handle(event);\n }\n\n private unregisterHandler(handlerClass: HandlerConstructor, artifacts?: InteractionArtifact[]): void {\n this.handlerFiles.delete(handlerClass);\n if (artifacts) {\n for (const { routeType, routes } of artifacts) {\n const map = this.routeTypes.find(([type]) => type === routeType)?.[1];\n if (map) {\n routes.forEach((route) => map.delete(route));\n }\n }\n return;\n }\n\n for (const [routeType, map] of this.routeTypes) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[routeType], handlerClass);\n if (!areRoutes(meta)) continue;\n\n const routes = meta;\n routes.forEach((route) => map.delete(route));\n }\n }\n\n private unregisterMiddleware(middlewareCtor: InteractionMiddlewareConstructor): void {\n const index = this.middlewares.findIndex((entry) => entry.ctor === middlewareCtor);\n if (index !== -1) {\n this.middlewares.splice(index, 1);\n }\n }\n\n private attachToClient(): void {\n this.core.bot.client.on(Events.InteractionCreate, (interaction) => {\n if (this.draining) return;\n this.core.bus[PublishDefault]('anyInteraction', { interaction });\n const run = this.handleInteraction(interaction).catch((caught: unknown) => {\n const error = asError(caught);\n this.logger.error(`[${paint.coral.bold('UNHANDLED ERROR AT ROOT')}] ${error.name}`, error.stack);\n this.core.bus[PublishDefault]('unhandledInteractionError', { error });\n });\n this.inFlight.add(run);\n void run.finally(() => this.inFlight.delete(run));\n });\n }\n\n public stopAccepting(): void {\n this.draining = true;\n }\n\n public drain(timeoutMs: number): Promise<void> {\n return settleWithin(Promise.allSettled(this.inFlight), timeoutMs);\n }\n\n private async handleCustomIdInteraction<TInteraction extends Interaction & { customId: string }>(\n interaction: TInteraction,\n kind: InteractionRoutes,\n getMap: () => Map<string, HandlerConstructor>\n ): Promise<void> {\n if ([...this.keysToIgnore].some((matcher) => matcher.owns(interaction.customId))) return;\n\n // route by the stable prefix (the routeKey minus its shape hash) so an older-shape wire still\n // reaches its handler, where reading this.params throws StaleCustomId and the boundary replies.\n // an empty prefix matches no route, so the unhandled default replies to it the way http does\n const prefix = prefixOf(interaction.customId);\n if (!prefix)\n this.logger.warn(`${paint.sky.bold(kind)} has invalid customId: ${paint.mute(interaction.customId)}`);\n\n await this.processInteraction(\n interaction,\n kind,\n () => prefix,\n (key) => getMap().get(key)\n );\n }\n\n private async processInteraction<TInteraction extends Interaction>(\n interaction: TInteraction,\n kind: InteractionRoutes,\n extractKey: (i: TInteraction) => string,\n getHandler: (key: string) => HandlerConstructor | undefined,\n fallback: HandlerConstructor = UnhandledRepliable\n ): Promise<void> {\n const key = extractKey(interaction);\n const startedAt = performance.now();\n // read here, since a read at publish time would count the handler run into the queue too\n const queuedMs = queuedMsFor(interaction.id);\n const matched = getHandler(key);\n\n // the handler's own routeId replaces this once the dispatch context is built, and the closure\n // below reads whichever one is current when it publishes. an empty key means a customId\n // seedcord never minted, since a minted routeKey always outlives its 3-char hash\n let routeId = `${kind}:${key || 'unrouted'}`;\n // the key fires once per dispatch, and a throw from the boundary itself reaches the catch below\n // after the refusal already reported\n let reported = false;\n const report = (outcome: DispatchOutcome): void => {\n if (reported) return;\n reported = true;\n this.core.bus[PublishDefault](\n 'interactionDispatched',\n dispatchedPayload({\n routeId,\n interactionId: interaction.id,\n kind,\n outcome,\n startedAt,\n fallback: !matched,\n queuedMs\n })\n );\n };\n\n // declared outside the try so the fault boundary replies through the handler's exact ack state\n let sender: ReplySender | undefined;\n try {\n if (!interaction.isAutocomplete()) await this.runMiddlewares(interaction as Repliables);\n\n const HandlerCtor = matched ?? fallback;\n const dispatch = new DispatchContext(routeIdOf(HandlerCtor) ?? routeId);\n routeId = dispatch.routeId ?? routeId;\n const handler = this.buildHandler(HandlerCtor, interaction as Repliables, dispatch, key, !matched);\n if (handler instanceof RepliableHandler) sender = handler.getSender();\n // autocomplete has no reply target, @Gated rejects it at compile time, this is the runtime backstop\n const refusal = interaction.isAutocomplete()\n ? null\n : await this.gateRefusal(HandlerCtor, interaction as Repliables, dispatch.routeId);\n if (refusal) {\n await this.answer(refusal.caught, interaction as ValidInteractionTypes, routeId, sender, report);\n return;\n }\n await handler.execute();\n report('handled');\n } catch (caught) {\n await this.answer(caught, interaction as ValidInteractionTypes, routeId, sender, report);\n }\n }\n\n // reports in a finally, so a throw from the boundary still publishes\n private async answer(\n caught: unknown,\n interaction: ValidInteractionTypes,\n routeId: string,\n sender: ReplySender | undefined,\n report: (outcome: DispatchOutcome) => void\n ): Promise<void> {\n try {\n await handleInteractionFault(caught, interaction, this.core, routeId, sender);\n } finally {\n report(outcomeFor(caught));\n }\n }\n\n private buildHandler(\n HandlerCtor: HandlerConstructor,\n interaction: Repliables,\n dispatch: DispatchContext,\n key: string,\n isFallback: boolean\n ): DispatchedHandler {\n if (isFallback) {\n this.logger.warn(`No handler found for key ${paint.sky.bold(key)}. Falling back to ${HandlerCtor.name}.`);\n }\n this.logger.debug(`Processing ${paint.mint.bold(key)} with ${paint.mute(HandlerCtor.name)}`);\n // @ts-expect-error TS can't infer the type of interaction here\n return new HandlerCtor(interaction, this.core, dispatch);\n }\n\n private async runMiddlewares(interaction: Repliables): Promise<void> {\n for (const { ctor } of this.middlewares) {\n const middleware = new ctor(interaction, this.core);\n await middleware.execute();\n }\n }\n\n // null when the gates passed. the caller answers the refusal, so one code path reports and replies\n private async gateRefusal(\n HandlerCtor: HandlerConstructor,\n interaction: Repliables,\n routeId: string | null\n ): Promise<{ caught: unknown } | null> {\n const monitor = slowGateMonitor();\n try {\n await runHandlerGates(\n HandlerCtor,\n interactionGateContext(interaction, this.core),\n routeId ?? undefined,\n monitor?.observe\n );\n return null;\n } catch (caught) {\n return { caught };\n } finally {\n // a refusing gate ate budget too, report either way\n monitor?.report(routeId);\n }\n }\n\n private async handleInteraction(interaction: Interaction): Promise<void> {\n switch (true) {\n case interaction.isChatInputCommand(): {\n await this.handleSlashCommand(interaction);\n break;\n }\n case interaction.isButton(): {\n await this.handleButton(interaction);\n break;\n }\n case interaction.isModalSubmit(): {\n await this.handleModal(interaction);\n break;\n }\n case interaction.isStringSelectMenu(): {\n await this.handleStringSelectMenu(interaction);\n break;\n }\n case interaction.isUserSelectMenu(): {\n await this.handleUserSelectMenu(interaction);\n break;\n }\n case interaction.isRoleSelectMenu(): {\n await this.handleRoleSelectMenu(interaction);\n break;\n }\n case interaction.isChannelSelectMenu(): {\n await this.handleChannelSelectMenu(interaction);\n break;\n }\n case interaction.isMentionableSelectMenu(): {\n await this.handleMentionableSelectMenu(interaction);\n break;\n }\n case interaction.isMessageContextMenuCommand(): {\n await this.handleMessageContextMenu(interaction);\n break;\n }\n case interaction.isUserContextMenuCommand(): {\n await this.handleUserContextMenu(interaction);\n break;\n }\n case interaction.isAutocomplete(): {\n await this.handleAutocomplete(interaction);\n break;\n }\n default: {\n this.logger.warn(`Unhandled interaction type: ${interaction.type}`);\n break;\n }\n }\n }\n\n private async handleSlashCommand(interaction: ChatInputCommandInteraction): Promise<void> {\n const route = slashRouteOf(interaction);\n await this.processInteraction(\n interaction,\n InteractionRoutes.Slash,\n () => route,\n (key) => this.slashMap.get(key)\n );\n }\n\n private async handleButton(interaction: ButtonInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.Button, () => this.buttonMap);\n }\n\n private async handleModal(interaction: ModalSubmitInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.Modal, () => this.modalMap);\n }\n\n private async handleStringSelectMenu(interaction: StringSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.StringMenu, () => this.stringSelectMap);\n }\n\n private async handleUserSelectMenu(interaction: UserSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.UserMenu, () => this.userSelectMap);\n }\n\n private async handleRoleSelectMenu(interaction: RoleSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.RoleMenu, () => this.roleSelectMap);\n }\n\n private async handleChannelSelectMenu(interaction: ChannelSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.ChannelMenu, () => this.channelSelectMap);\n }\n\n private async handleMentionableSelectMenu(interaction: MentionableSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(\n interaction,\n InteractionRoutes.MentionableMenu,\n () => this.mentionableSelectMap\n );\n }\n\n private async handleMessageContextMenu(interaction: MessageContextMenuCommandInteraction): Promise<void> {\n await this.processInteraction(\n interaction,\n InteractionRoutes.MessageContextMenu,\n () => interaction.commandName,\n (key) => this.messageContextMenuMap.get(key)\n );\n }\n\n private async handleUserContextMenu(interaction: UserContextMenuCommandInteraction): Promise<void> {\n await this.processInteraction(\n interaction,\n InteractionRoutes.UserContextMenu,\n () => interaction.commandName,\n (key) => this.userContextMenuMap.get(key)\n );\n }\n\n private async handleAutocomplete(interaction: AutocompleteInteraction): Promise<void> {\n const route = slashRouteOf(interaction);\n await this.processInteraction(\n interaction,\n InteractionRoutes.Autocomplete,\n () => route,\n (key) => this.autocompleteMap.get(key),\n UnhandledAutocomplete\n );\n }\n}\n","import { CommandInjector } from '@seedcord/core/internal';\nimport { CommandRegistry, ShutdownPhase } from '@seedcord/core/node/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, validateDiscordToken } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\nimport chalk from 'chalk';\nimport { Client, Events } from 'discord.js';\nimport { Envapt } from 'envapt/legacy';\n\nimport { EventDispatcher } from '@bControllers/EventDispatcher';\nimport { InteractionDispatcher } from '@bControllers/InteractionDispatcher';\n\nimport { EmojiInjector } from './injectors/EmojiInjector';\n\nimport type { Core } from '@interfaces/Core';\nimport type { Initializeable } from '@seedcord/core';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\n\nconst DISPATCH_DRAIN_TIMEOUT_MS = 5000;\n// headroom so each dispatcher's own timer settles before the outer task timeout fires\nconst DRAIN_HEADROOM_MS = 1000;\nconst DRAIN_TASK_TIMEOUT_MS = DISPATCH_DRAIN_TIMEOUT_MS + DRAIN_HEADROOM_MS;\nconst UNBIND_TIMEOUT_MS = 2000;\nconst LOGOUT_TIMEOUT_MS = 2000;\n\n/**\n * The Discord client and its controllers. Access it through `core.bot`.\n */\nexport class Bot implements Initializeable, HmrAware {\n @Envapt<string>('DISCORD_BOT_TOKEN', {\n converter: (raw) => validateDiscordToken(raw)\n })\n declare public readonly botToken: string;\n\n /** @internal */\n public readonly logger = new Logger('Bot', { channel: 'bot' });\n private isInitialized = false;\n\n private readonly _client: Client;\n private readonly interactions?: InteractionDispatcher;\n private readonly events?: EventDispatcher;\n private readonly emojiInjector: EmojiInjector;\n private readonly commandRegistry?: CommandRegistry;\n\n /** @internal */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n if (this.interactions) await this.interactions.onHmr(event);\n if (this.events) await this.events.onHmr(event);\n if (this.commandRegistry) await this.commandRegistry.onHmr(event);\n }\n\n /** @internal */\n constructor(core: Core) {\n this._client = new Client(core.config.bot.clientOptions);\n\n if (core.config.bot.interactions.path) {\n this.interactions = new InteractionDispatcher(core);\n }\n if (core.config.bot.events.path) {\n this.events = new EventDispatcher(core);\n }\n\n const commandsDir = core.config.bot.commands.path;\n if (commandsDir) {\n const injector = new CommandInjector();\n // onDeployed only fires at deploy time, so registry is assigned by then\n const registry: CommandRegistry = new CommandRegistry({\n dir: commandsDir,\n // core.rest is this same object, assigned only after this constructor returns\n rest: this._client.rest,\n applicationId: () => this.applicationId(),\n onDeployed: (result) => {\n injector.inject(result, registry.allCommands());\n }\n });\n this.commandRegistry = registry;\n }\n\n this.emojiInjector = new EmojiInjector(core);\n\n this.registerShutdownTasks(core);\n }\n\n private applicationId(): string {\n const { application } = this._client;\n if (!application) throw new SeedcordError(SeedcordErrorCode.CoreApplicationUnavailable);\n return application.id;\n }\n\n private registerShutdownTasks(core: Core): void {\n core.shutdown.addTask(\n ShutdownPhase.Unbind,\n 'stop-dispatch',\n () => {\n this.stopAccepting();\n return Promise.resolve();\n },\n UNBIND_TIMEOUT_MS\n );\n core.shutdown.addTask(ShutdownPhase.Drain, 'drain-dispatch', () => this.drain(), DRAIN_TASK_TIMEOUT_MS);\n core.shutdown.addTask(ShutdownPhase.Logout, 'stop-bot', async () => await this.stop(), LOGOUT_TIMEOUT_MS);\n }\n\n private stopAccepting(): void {\n this.interactions?.stopAccepting();\n this.events?.stopAccepting();\n }\n\n private async drain(): Promise<void> {\n // allSettled so a rejecting drain does not abort the other dispatcher's drain\n await Promise.allSettled([\n this.interactions?.drain(DISPATCH_DRAIN_TIMEOUT_MS),\n this.events?.drain(DISPATCH_DRAIN_TIMEOUT_MS)\n ]);\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialized) {\n return;\n }\n this.isInitialized = true;\n\n const token = this.botToken;\n\n if (this.interactions) await this.interactions.init();\n if (this.events) await this.events.init();\n\n await this.login(token);\n\n await this.emojiInjector.init();\n\n if (this.commandRegistry) {\n await this.commandRegistry.init();\n await this.commandRegistry.setCommands();\n this.interactions?.warnUnhandledRoutes(this.commandRegistry.routeLeaves());\n this.interactions?.warnUnhandledContextMenuRoutes(this.commandRegistry.contextMenuLeaves());\n }\n }\n\n /** @internal */\n public async stop(): Promise<void> {\n this._client.removeAllListeners();\n\n await this.logout();\n }\n\n private async login(token: string): Promise<Bot> {\n const ready: PromiseWithResolvers<void> = Promise.withResolvers();\n this._client.once(Events.ClientReady, () => ready.resolve());\n void this._client.login(token);\n await ready.promise;\n this.logger.info(`Logged in as ${chalk.bold.magenta(this._client.user?.username)}!`);\n return this;\n }\n\n private async logout(): Promise<void> {\n await this._client.destroy();\n this.logger.info(chalk.bold.red('Logged out of Discord!'));\n }\n\n public get client(): Client {\n return this._client;\n }\n}\n","/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n","import { Bus } from '@seedcord/core';\nimport { HmrManager, setBotColor } from '@seedcord/core/internal';\nimport {\n HealthCheck,\n CoordinatedShutdown,\n CoordinatedStartup,\n StartupPhase,\n Pluggable,\n SubscriberLoader\n} from '@seedcord/core/node/internal';\nimport { LoggerChannelRegistry } from '@seedcord/logger';\nimport { installNodeDefaults } from '@seedcord/logger/node';\nimport { MemoryRateLimiter } from '@seedcord/rate-limiter';\nimport { SeedcordBrand } from '@seedcord/types/internal';\nimport { Envapter } from 'envapt';\n\nimport { Bot } from './bot/Bot';\nimport { version as packageVersion } from './version';\n\nimport type { GatewayConfig } from './interfaces/Config';\nimport type { Core } from './interfaces/Core';\nimport type { REST } from '@discordjs/rest';\nimport type { IRateLimiter } from '@seedcord/types';\nimport type { SeedcordInstance } from '@seedcord/types/internal';\n\n/**\n * The gateway bot host. Opens a discord.js gateway session, discovers handlers, and runs\n * coordinated startup and shutdown. Attach plugins with `attach()`.\n */\nexport class Seedcord extends Pluggable<'gateway', 'server'> implements Core, SeedcordInstance {\n // the CLI reads these to detect and augment the instance\n /** @internal */\n public readonly [SeedcordBrand] = true;\n /** @internal */\n public readonly augmentTarget = '@seedcord/gateway';\n /** @internal */\n public readonly version: string = packageVersion;\n\n private readonly healthCheck?: HealthCheck | undefined;\n private readonly hmrManager: HmrManager;\n\n /** @see {@link Bus} */\n public readonly bus: Bus;\n\n private readonly subscribers: SubscriberLoader;\n\n /** @see {@link Bot} */\n public readonly bot: Bot;\n\n /** The discord.js client's REST client. Its token is set during the Login phase. */\n public readonly rest: REST;\n\n /** @see {@link IRateLimiter} */\n public readonly rateLimiter: IRateLimiter;\n\n /**\n * @param config - Bot configuration including paths and Discord client options\n * @throws A **SeedcordError** When attempting to create multiple instances (singleton)\n */\n constructor(public readonly config: GatewayConfig) {\n super(new CoordinatedShutdown(), new CoordinatedStartup());\n\n installNodeDefaults(config.logger);\n setBotColor(config.botColor);\n\n this.hmrManager = new HmrManager();\n this.hmrManager.init();\n this.bus = new Bus(this);\n this.subscribers = new SubscriberLoader(this.bus, config.subscribers.path);\n this.bot = new Bot(this);\n this.rest = this.bot.client.rest;\n this.rateLimiter = config.store ?? new MemoryRateLimiter();\n this.healthCheck = HealthCheck.fromOption(this.shutdown, config.healthCheck);\n\n this.registerStartupTasks();\n }\n\n /** The bot's discord username, populated after login. */\n public get username(): string | undefined {\n return this.bot.client.user?.username;\n }\n\n protected static override reset(): void {\n super.reset();\n LoggerChannelRegistry.instance.reset();\n }\n\n private registerStartupTasks(): void {\n if (Envapter.isDevelopment || Envapter.isTest) this.registerHmrAwareModules();\n\n this.startup.addTask(StartupPhase.Configuration, 'bus-initialization', async () => {\n this.bus.logger.utils.initialization('Subscribers', 'start');\n await this.subscribers.init();\n this.bus.logger.utils.initialization('Subscribers', 'end');\n });\n\n this.startup.addTask(StartupPhase.Login, 'bot-initialization', async () => {\n this.bot.logger.utils.initialization('Bot', 'start');\n await this.bot.init();\n this.bot.logger.utils.initialization('Bot', 'end');\n });\n\n const { healthCheck } = this;\n if (healthCheck) {\n this.startup.addTask(StartupPhase.Ready, 'health-check', async () => {\n healthCheck.logger.utils.initialization('HealthCheck', 'start');\n await healthCheck.init();\n healthCheck.logger.utils.initialization('HealthCheck', 'end');\n });\n }\n }\n\n /**\n * Starts the bot and runs all initialization tasks\n *\n * @returns This Seedcord instance when initialized\n */\n public async start(): Promise<this> {\n try {\n await super.init();\n } catch (caught) {\n // shutdown releases any resource opened before the failure, then rethrow\n await this.shutdown.run(1, false);\n Seedcord.reset();\n throw caught;\n }\n return this;\n }\n\n private registerHmrAwareModules(): void {\n this.startup.addTask(StartupPhase.Configuration, 'hmr-registration', async () => {\n this.hmrManager.register(this.bot);\n this.hmrManager.register(this.subscribers);\n for (const plugin of this.plugins) {\n this.hmrManager.register(plugin);\n }\n await Promise.resolve();\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["BaseHandler","CoreBaseHandler","BaseHandler","CoreRepliableHandler","BaseHandler","BaseHandler","BaseHandler","BaseArraySource","BaseCursorSource","CoreSubscriber","CoreWebhookLog","CorePlugin","logger","logger","packageVersion"],"sources":["../src/logger-bootstrap.ts","../src/bot/decorators/Events.ts","../src/bot/decorators/Gated.ts","../src/bot/decorators/Middlewares.ts","../src/bot/gates/catalog/IgnoreBots.ts","../src/bot/notices/index.ts","../src/bot/gates/catalog/Nsfw.ts","../src/bot/injectors/EmojiInjector.ts","../src/bot/notices/utils.ts","../src/bot/utilities/permissions/checkPermissions.ts","../src/bot/utilities/permissions/checkBotPermissions.ts","../src/bot/utilities/permissions/hasPermsToAssign.ts","../src/bot/confirm/reserved.ts","../src/bot/confirm/getConfirmation.ts","../src/handlers/BaseHandler.ts","../src/handlers/interaction/InteractionMiddleware.ts","../src/bot/ReplySender.ts","../src/handlers/RepliableHandler.ts","../src/handlers/interaction/InteractionHandler.ts","../src/bot/utilities/miscellaneous/slashRouteOf.ts","../src/handlers/interaction/SlashHandler.ts","../src/handlers/interaction/ContextMenuHandler.ts","../src/handlers/interaction/AutocompleteHandler.ts","../src/handlers/interaction/components/ComponentHandler.ts","../src/handlers/interaction/components/ButtonHandler.ts","../src/handlers/interaction/components/ModalHandler.ts","../src/handlers/interaction/components/SelectMenuHandler.ts","../src/handlers/event/EventHandler.ts","../src/handlers/event/EventMiddleware.ts","../src/pagination/Paginator.ts","../src/pagination/sources.ts","../src/subscribers/index.ts","../src/plugin.ts","../src/miscellaneous/deriveEventActor.ts","../src/bot/gates/runGates.ts","../src/miscellaneous/extractErrorResponse.ts","../src/bot/handleEventFault.ts","../src/bot/controllers/EventDispatcher.ts","../src/bot/defaults/UnhandledRepliable.ts","../src/bot/defaults/UnhandledAutocomplete.ts","../src/bot/harmlessApiCodes.ts","../src/bot/handleInteractionFault.ts","../src/bot/controllers/InteractionDispatcher.ts","../src/bot/Bot.ts","../src/version.ts","../src/Seedcord.ts"],"sourcesContent":["import { installNodeDefaults } from '@seedcord/logger/node';\n\n// the gateway runs on node so install the winston sinks before any logging\ninstallNodeDefaults();\n","import { EventMetadataKey } from '@seedcord/core/internal';\n\nimport type { EventHandler } from '@handlers/event';\nimport type { EventFrequency } from '@seedcord/types';\nimport type { ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\nimport type { Constructor } from 'type-fest';\n\n/** Options accepted by the event registration decorator. */\nexport interface RegisterEventOptions {\n /**\n * Frequency: 'once' or 'on'.\n *\n * @defaultValue `'on'`\n */\n readonly frequency?: EventFrequency | undefined;\n}\n\n/** @internal */\nexport interface RegisterEventMetadataEntry<EventKey extends keyof ClientEvents> {\n readonly event: EventKey;\n readonly frequency: EventFrequency;\n}\n\n/** Tuple describing a single event and optional options. */\nexport type EventSpec<EventKey extends ValidNonInteractionKeys> = readonly [\n event: EventKey,\n options?: RegisterEventOptions\n];\n\n/**\n * Registers an event handler class with one or more Discord.js events.\n *\n * Associates the decorated class with the provided Discord client events for automatic registration and execution when those events are emitted.\n *\n * Supply any number of event tuples. Each tuple can include per event options.\n *\n * @typeParam EventKey - Union of Discord.js ClientEvents keys to register for\n * @param defs - One or more tuples of [event, options]\n * @decorator\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate])\n * class MessageHandler extends EventHandler<Events.MessageCreate> {\n * async execute() {\n * // Handle message creation\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])\n * class MessageHandler extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {\n * async execute() {\n * // Handle message creation or update\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate, { frequency: 'once' }], [Events.MessageUpdate])\n * class OneTimeMessageHandler extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {\n * async execute() {\n * // Handle only the first message creation, and message update normally\n * }\n * }\n * ```\n */\nexport function RegisterEvent<const Defs extends readonly EventSpec<ValidNonInteractionKeys>[]>(...defs: Defs) {\n type EventKey = Defs[number][0];\n\n // EventHandler is invariant in its Names generic (match puts Names in the arms, a contravariant position), so\n // this single constraint rejects a handler whose generic and decorator list different events, both directions.\n return function <HandlerCtor extends Constructor<EventHandler<EventKey>>>(constructor: HandlerCtor): void {\n const saved = Reflect.getMetadata(EventMetadataKey, constructor) as\n RegisterEventMetadataEntry<EventKey>[] | undefined;\n const existing = saved ?? [];\n\n const entries = defs.map<RegisterEventMetadataEntry<EventKey>>(([event, options]) => ({\n event,\n frequency: options?.frequency ?? 'on'\n }));\n\n Reflect.defineMetadata(EventMetadataKey, [...existing, ...entries], constructor);\n };\n}\n","import { GatedMetadataKey } from '@seedcord/core/internal';\n\nimport type { AnyHandlerCtor, FitAll } from '@bot/gates/matching';\nimport type { Gate, GateContextBase } from '@seedcord/core';\nimport type { NonEmptyTuple } from 'type-fest';\n\n/**\n * Attaches gates to a handler. The gates run before `execute`, and a gate refusing stops the handler with\n * the reply or drop the gate threw. Multiple gates are ANDed, so each must pass. A gate that requires a\n * context the handler does not provide (a button gate on a slash handler, an interaction gate on an event\n * handler) is a compile error at this line, and the error names the gate and the handler kind. Place it\n * above the route decorator.\n *\n * Combine gates with {@link and} or {@link or} to build a single gate from multiple arms.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(GuildOnly(), RequirePermissions([PermissionFlagsBits.Administrator]))\n * \\@SlashRoute('maintenance')\n * class Maintenance extends SlashHandler<'maintenance'> {\n * async execute() {\n * // both gates passed, so this runs in a guild with an admin caller\n * }\n * }\n * ```\n *\n * @typeParam Gates - The non-empty tuple of gates to run, in order, against the handler's context.\n * @typeParam TCtor - The decorated handler's constructor, checked against every gate's required context.\n * @param gates - One or more gates to attach, each ANDed so the handler runs only when all pass.\n * @param ctor - The handler class being decorated, rejected at compile time when a gate needs a context it lacks.\n *\n * @see {@link defineGate}\n * @see {@link defineEffectGate}\n * @decorator\n */\nexport function Gated<const Gates extends NonEmptyTuple<Gate<GateContextBase>>>(...gates: Gates) {\n // mismatch resolves to the error tuple, so the class fails to assign and TS names the gate\n return function <TCtor extends AnyHandlerCtor>(\n ctor: FitAll<TCtor, Gates> extends Gates ? TCtor : FitAll<TCtor, Gates>\n ): void {\n const existing = (Reflect.getMetadata(GatedMetadataKey, ctor) as readonly Gate[] | undefined) ?? [];\n Reflect.defineMetadata(GatedMetadataKey, [...existing, ...gates], ctor);\n };\n}\n","import { MiddlewareMetadataKey } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\n\nimport type { EventMiddleware } from '@handlers/event';\nimport type { InteractionMiddleware } from '@handlers/interaction';\nimport type { Repliables, ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Middleware types supported by Seedcord\n */\nexport enum MiddlewareType {\n Interaction = 'interaction',\n Event = 'event'\n}\n\n/**\n * Additional middleware registration options\n *\n * @typeParam MType - The type of middleware being registered\n */\nexport interface MiddlewareOptions<\n MType extends MiddlewareType,\n Events extends readonly ValidNonInteractionKeys[] = readonly ValidNonInteractionKeys[]\n> {\n /**\n * Restrict event middleware execution to specific Discord client events. The middleware's `EventMiddleware`\n * generic must list the same events, or applying the decorator is a compile error.\n */\n readonly events?: MType extends MiddlewareType.Event ? Events : never;\n}\n\n/** @internal */\nexport interface MiddlewareMetadata {\n priority: number;\n type: MiddlewareType;\n events?: readonly ValidNonInteractionKeys[];\n}\n\n/**\n * Decorator used to register middleware with priority ordering. The lower the priority number, the earlier it runs.\n *\n * Interaction middleware cannot specify event filters.\n *\n * @param type - Middleware kind from {@link MiddlewareType}\n * @param priority - Ordering value where lower runs earlier. {@default `0` }\n * @param options - Additional registration options\n *\n * @decorator\n *\n * @example\n * ```ts\n * \\@Middleware(MiddlewareType.Event, 10, { events: [Events.MessageCreate, Events.MessageUpdate] })\n * class MyEventMiddleware extends EventMiddleware {}\n * ```\n * @throws A **SeedcordTypeError** If priority is not a finite number\n * @throws A **SeedcordError** If interaction middleware specifies event filters\n */\nexport function Middleware<MType extends MiddlewareType, const Events extends readonly ValidNonInteractionKeys[] = []>(\n type: MType,\n priority = 0,\n options: MiddlewareOptions<MType, Events> = {}\n) {\n return (\n ctor: MType extends MiddlewareType.Interaction\n ? Constructor<InteractionMiddleware<Repliables>>\n : Events extends readonly []\n ? Constructor<EventMiddleware<ValidNonInteractionKeys>>\n : Constructor<EventMiddleware<Events[number]>>\n ): void => {\n const normalizedPriority = Number(priority);\n if (!Number.isFinite(normalizedPriority)) {\n throw new SeedcordTypeError(SeedcordErrorCode.DecoratorInvalidMiddlewarePriority);\n }\n\n if (type === MiddlewareType.Interaction && Array.isArray(options.events) && options.events.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorInteractionEventFilter);\n }\n\n const metadata: MiddlewareMetadata = {\n priority: normalizedPriority,\n type,\n // an empty array means catchall, only store a real filter\n ...(options.events && options.events.length > 0 && { events: options.events })\n };\n\n Reflect.defineMetadata(MiddlewareMetadataKey, metadata, ctor);\n };\n}\n","import { defineGate, Silence } from '@seedcord/core';\n\nimport type { EventGateContext } from '../Gate';\n\n/**\n * Drops a client event whose actor is a bot, with a {@link Silence} so nothing is replied. Event-only, because a\n * Silence on an interaction would leave Discord's failed-interaction state. It rejects an interaction handler at\n * the decorator line. Takes no options, so attach it directly without calling it.\n *\n * @see {@link Gated}\n *\n * @example\n * ```ts\n * import { Events } from 'discord.js';\n *\n * \\@Gated(IgnoreBots)\n * class OnMessage extends EventHandler<Events.MessageCreate> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport const IgnoreBots = defineGate('IgnoreBots', (ctx: EventGateContext) => {\n if (ctx.user?.bot) throw new Silence('actor is a bot');\n});\n","import { Notice } from '@seedcord/core';\nimport { GateNotice, NoticeCard } from '@seedcord/core/internal';\n\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { Role } from 'discord.js';\n\nexport class NotNsfw extends GateNotice {\n public constructor(message = 'This can only be used in an age-restricted channel.') {\n super(message);\n }\n}\n\nexport class RoleHigherThanMe extends Notice {\n public constructor(\n message: string,\n public role: Role,\n public botRole: Role\n ) {\n super(message);\n }\n\n public render(): ReplyResponse {\n const card = new NoticeCard(\n `I cannot assign a role that is higher than me.\\n\\n` +\n `The role <@&${this.role.id}> is higher than my role <@&${this.botRole.id}> in the hierarchy.`\n );\n return { components: [card.component] };\n }\n}\n\nexport class CannotAssignBotRole extends Notice {\n public constructor(message = 'I cannot assign a managed role.') {\n super(message);\n }\n\n public render(): ReplyResponse {\n return { components: [new NoticeCard('I cannot assign a managed role.').component] };\n }\n}\n","import { defineGate } from '@seedcord/core';\nimport { pickNotice } from '@seedcord/core/internal';\n\nimport { NotNsfw } from '@bot/notices';\n\nimport type { InteractionGateContext } from '../Gate';\nimport type { Gate, GateNoticeOptions } from '@seedcord/core';\nimport type { NonModalInteraction } from '@src/handlers/interactionTypes';\n\n// a thread carries no nsfw flag of its own, so it inherits the parent channel's\nfunction channelIsNsfw(channel: InteractionGateContext['interaction']['channel']): boolean {\n if (!channel) return false;\n if (channel.isThread()) return channel.parent?.nsfw ?? false;\n return 'nsfw' in channel ? channel.nsfw : false;\n}\n\n/**\n * Requires an age-restricted channel, else refuses. Pass {@link GateNoticeOptions} to reword or replace the refusal.\n *\n * A thread inherits its parent channel's nsfw flag. ModalSubmit has no reliable channel, so it is excluded.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see {@link Gated}\n *\n * @example\n * ```ts\n * \\@Gated(Nsfw())\n * \\@SlashRoute('nsfwcmd')\n * class NsfwHandler extends SlashHandler<'nsfwcmd'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function Nsfw(options?: GateNoticeOptions): Gate<InteractionGateContext<NonModalInteraction>, 'Nsfw'> {\n return defineGate('Nsfw', (ctx: InteractionGateContext<NonModalInteraction>) => {\n if (channelIsNsfw(ctx.interaction.channel)) return;\n throw pickNotice(options, (message) => new NotNsfw(message));\n });\n}\n","import { accessorStore, clearStore, guardedAccessor, isEmojiTuple } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\n\nimport type { Core } from '@interfaces/Core';\nimport type { EmojiMap } from '@seedcord/types';\nimport type { ApplicationEmoji, GuildEmoji } from 'discord.js';\n\ntype SavedEmojiType = GuildEmoji | ApplicationEmoji;\n\nconst emojiStorage = accessorStore<SavedEmojiType>();\n\n/**\n * The global {@link Emojis} accessor type. Each key resolves to its precise class, `GuildEmoji` for a `'guild'`\n * tag and `ApplicationEmoji` for an `'application'` tag, the tags `seedcord codegen` writes into {@link EmojiMap}.\n */\nexport type InjectedEmojiMap = {\n [K in keyof EmojiMap]: EmojiMap[K] extends 'guild' ? GuildEmoji : ApplicationEmoji;\n};\n\n/**\n * The bot's resolved emojis, keyed by {@link EmojiMap}. Filled by {@link EmojiInjector} during startup.\n * A read before that throws.\n */\nexport const Emojis = guardedAccessor('Emojis', emojiStorage) as InjectedEmojiMap;\n\n/**\n * Loads and injects emojis based on bot configuration. A guild emoji requires the Guilds intent in the client\n * options.\n *\n * @internal\n */\nexport class EmojiInjector {\n private readonly logger = new Logger('Emojis', { channel: 'bot' });\n\n constructor(private readonly core: Core) {}\n\n public async init(): Promise<void> {\n this.clearEmojis();\n\n if (!this.core.config.bot.emojis || Object.keys(this.core.config.bot.emojis).length === 0) {\n this.logger.debug('No emojis configured, skipping emoji injection.');\n return;\n }\n\n const configEmojis = this.core.config.bot.emojis;\n await this.core.bot.client.application?.emojis.fetch();\n\n const failures: string[] = [];\n const fetchedGuilds = new Set<string>();\n for (const [key, value] of Object.entries(configEmojis)) {\n if (isEmojiTuple(value)) {\n await this.resolveTuple(key, value, failures, fetchedGuilds);\n } else if (typeof value === 'string') {\n this.resolveString(key, value, failures);\n } else {\n failures.push(` - \"${key}\" has an invalid value (expected a name or [name, guildId])`);\n }\n }\n\n // surface every unresolved emoji at once so the user fixes the whole config in one pass\n if (failures.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.ConfigEmojiUnresolved, [failures.length, failures.join('\\n')]);\n }\n\n this.logger.utils.summary('Loaded emojis', { emojis: Object.keys(emojiStorage).length });\n }\n\n private async resolveTuple(\n key: string,\n value: readonly [string, string],\n failures: string[],\n fetchedGuilds: Set<string>\n ): Promise<void> {\n const [emojiName, guildId] = value;\n\n const guild = this.core.bot.client.guilds.cache.get(guildId);\n if (!guild) {\n failures.push(\n ` - \"${emojiName}\" for \"${key}\" targets guild ${guildId}, which is not available (check the Guilds intent)`\n );\n return;\n }\n\n if (!fetchedGuilds.has(guildId)) {\n await guild.emojis.fetch();\n fetchedGuilds.add(guildId);\n }\n const guildEmoji = guild.emojis.cache.find((e) => e.name === emojiName);\n if (!guildEmoji) {\n failures.push(` - \"${emojiName}\" for \"${key}\" was not found in guild ${guildId}`);\n return;\n }\n\n emojiStorage[key] = guildEmoji;\n }\n\n private resolveString(key: string, emojiName: string, failures: string[]): void {\n const appEmoji = this.core.bot.client.application?.emojis.cache.find((e) => e.name === emojiName);\n if (!appEmoji) {\n failures.push(` - \"${emojiName}\" for \"${key}\" was not found among the application emojis`);\n return;\n }\n\n emojiStorage[key] = appEmoji;\n }\n\n private clearEmojis(): void {\n clearStore(emojiStorage);\n }\n}\n","import { Role } from 'discord.js';\n\nimport type { GuildMember } from 'discord.js';\n\n// whose permissions a check ran against, mentioned as the refusal subject\ntype PermSubject = Role | GuildMember;\n\nexport function mentionFor(subject: PermSubject): string {\n if (subject instanceof Role) return `<@&${subject.id}>`;\n return `<@${subject.id}>`;\n}\n","import { assertPermissions } from '@seedcord/core';\nimport { Guild, GuildMember, Role } from 'discord.js';\n\nimport { mentionFor } from '@bot/notices/utils';\n\nimport type { PermissionNoticeOverrides, PermissionScope } from '@seedcord/core';\nimport type { TextChannel } from 'discord.js';\n\n/** Options for {@link checkPermissions}. */\nexport interface CheckPermissionOptions extends PermissionNoticeOverrides {\n /** The role or member to check. */\n for: Role | GuildMember;\n /** A guild reads the base bits from roles, a text channel reads the overwrite-resolved set. */\n in: Guild | TextChannel;\n /** The permission flag bits to check. */\n scope: PermissionScope;\n /** Refuse when the target holds a scope bit. */\n inverse?: boolean;\n}\n\n/**\n * Checks a {@link Role} or a {@link GuildMember} against the base permission bits in a {@link Guild},\n * before channel overwrites. Refuses when a permission in `scope` is missing, or with `inverse` when one\n * is present.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * checkPermissions(role, guild, [PermissionFlagsBits.ManageMessages, PermissionFlagsBits.KickMembers]);\n * ```\n *\n * @example\n * ```ts\n * // refuse when the member holds Administrator, and replace the refusal\n * checkPermissions(member, guild, [PermissionFlagsBits.Administrator], true, {\n * dangerousNotice: CustomDangerousNotice\n * });\n * ```\n */\nexport function checkPermissions(\n target: Role | GuildMember,\n ctx: Guild,\n scope: PermissionScope,\n inverse?: boolean,\n errors?: PermissionNoticeOverrides\n): void;\n\n/**\n * Checks a {@link Role} or a {@link GuildMember} against the overwrite-resolved set in a\n * {@link TextChannel}. Refuses when a permission in `scope` is missing, or with `inverse` when one is\n * present.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * checkPermissions(role, textChannel, [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]);\n * ```\n */\nexport function checkPermissions(\n target: Role | GuildMember,\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- the guild and channel forms resolve different bits, documented separately\n ctx: TextChannel,\n scope: PermissionScope,\n inverse?: boolean,\n errors?: PermissionNoticeOverrides\n): void;\n\n/**\n * Checks permissions with an options object. Refuses when a permission in\n * {@link CheckPermissionOptions.scope} is missing, or with `options.inverse` when one is present.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * checkPermissions({\n * for: member,\n * in: textChannel,\n * scope: [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]\n * });\n * ```\n */\nexport function checkPermissions(options: CheckPermissionOptions): void;\n\nexport function checkPermissions(\n a: Role | GuildMember | CheckPermissionOptions,\n b?: Guild | TextChannel,\n c?: PermissionScope,\n d?: boolean,\n e?: PermissionNoticeOverrides\n): void {\n const opts: CheckPermissionOptions =\n a instanceof Role || a instanceof GuildMember\n ? // justified: the positional overloads always supply b and c, the implementation signature widens them to | undefined\n {\n for: a,\n in: b as Guild | TextChannel,\n scope: c as PermissionScope,\n inverse: d ?? false,\n ...e\n }\n : a;\n\n const { for: pFor, in: pIn, scope, inverse = false, missingNotice, dangerousNotice } = opts;\n\n const perms = pIn instanceof Guild ? pFor.permissions : pIn.permissionsFor(pFor, true);\n\n assertPermissions({\n subject: mentionFor(pFor),\n permissions: perms.bitfield,\n scope,\n inverse,\n ...(missingNotice && { missingNotice }),\n ...(dangerousNotice && { dangerousNotice })\n });\n}\n","import { MissingPermissions, PermissionNames } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/logger';\nimport { Guild } from 'discord.js';\n\nimport { checkPermissions } from './checkPermissions';\n\nimport type { PermissionNoticeOverrides, PermissionScope } from '@seedcord/core';\nimport type { TextChannel } from 'discord.js';\n\n/**\n * Checks the bot's own permissions in a {@link Guild} or {@link TextChannel}. Refuses when a permission in\n * `scope` is missing, or with `inverse` when one is present. When the bot member is uncached, the refusal\n * reports every permission in `scope` as missing.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkBotPermissions } from '@seedcord/gateway';\n *\n * checkBotPermissions(textChannel, [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]);\n * ```\n */\nexport function checkBotPermissions(\n target: Guild | TextChannel,\n scope: PermissionScope,\n inverse = false,\n errors?: PermissionNoticeOverrides\n): void {\n if (target instanceof Guild) {\n const me = target.members.me;\n if (!me) {\n const names = scope.map((bit) => PermissionNames.get(bit) ?? String(bit));\n const Missing = errors?.missingNotice ?? MissingPermissions;\n throw new Missing(undefined, 'The bot', names);\n }\n checkPermissions(me, target, scope, inverse, errors);\n return;\n }\n\n const me = target.guild.members.me;\n\n if (!me) {\n const logger = new Logger('checkBotPermissions', { channel: 'errors' });\n logger.warn(\n `Bot member is unavailable in guild ${target.guild.id} while checking permissions in channel ${target.id}`\n );\n const names = scope.map((bit) => PermissionNames.get(bit) ?? String(bit));\n const Missing = errors?.missingNotice ?? MissingPermissions;\n throw new Missing(undefined, 'The bot', names);\n }\n\n checkPermissions(me, target, scope, inverse, errors);\n}\n","import { MissingPermissions } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { PermissionFlagsBits, Role } from 'discord.js';\n\nimport { CannotAssignBotRole, RoleHigherThanMe } from '@bot/notices';\n\nimport { checkBotPermissions } from './checkBotPermissions';\n\nimport type { Notice } from '@seedcord/core';\nimport type { Guild } from 'discord.js';\n\n/**\n * Optional custom error constructors for {@link HasPermsToAssignOptions}.\n */\nexport interface AssignRoleNoticeOverrides {\n higherNotice?: new (message: string, role: Role, botRole: Role) => Notice;\n managedNotice?: new (message: string) => Notice;\n missingNotice?: new (message: string | undefined, subject: string, missingPerms: readonly string[]) => Notice;\n}\n\n/**\n * Options for {@link hasPermsToAssign}.\n */\nexport interface HasPermsToAssignOptions {\n targetRole: Role;\n noticeOverrides?: AssignRoleNoticeOverrides;\n}\n\n// botRoleFor searches the guild's role cache, so a cold cache returns null\nfunction botRoleOf(guild: Guild): Role {\n const botRole = guild.roles.botRoleFor(guild.client.user);\n if (!botRole) throw new SeedcordError(SeedcordErrorCode.CoreBotRoleMissing, [guild.id]);\n return botRole;\n}\n\n/**\n * Validates that the bot can assign a target role. Refuses when the target role is above the bot's, is managed, or the bot lacks Manage Roles.\n *\n * @param roleOrOptions - Target role or complete options for the check\n * @throws A `Notice` on refusal, or a `SeedcordError` when the bot has no role in the guild's role cache.\n *\n * @example\n * ```ts\n * import { hasPermsToAssign } from '@seedcord/gateway';\n *\n * // Check if the bot can assign a specific role\n * hasPermsToAssign(role);\n *\n * // Check with custom error handling\n * hasPermsToAssign({\n * targetRole: role,\n * noticeOverrides: {\n * higherNotice: CustomHigherNotice,\n * managedNotice: CustomManagedNotice,\n * missingNotice: CustomMissingPermissionsNotice\n * }\n * });\n * ```\n */\nexport function hasPermsToAssign(roleOrOptions: Role | HasPermsToAssignOptions): void {\n const { targetRole, noticeOverrides: errors } =\n roleOrOptions instanceof Role\n ? {\n targetRole: roleOrOptions,\n noticeOverrides: undefined\n }\n : roleOrOptions;\n\n const HigherNotice = errors?.higherNotice ?? RoleHigherThanMe;\n const ManagedNotice = errors?.managedNotice ?? CannotAssignBotRole;\n const MissingNotice = errors?.missingNotice ?? MissingPermissions;\n\n const botRole = botRoleOf(targetRole.guild);\n\n if (targetRole.comparePositionTo(botRole) >= 0) {\n throw new HigherNotice('Role is higher than me', targetRole, botRole);\n }\n\n if (targetRole.managed) {\n throw new ManagedNotice(`Cannot assign managed role ${targetRole.name}`);\n }\n\n checkBotPermissions(targetRole.guild, [PermissionFlagsBits.ManageRoles], false, { missingNotice: MissingNotice });\n}\n","import { CustomId } from '@seedcord/core';\n\nconst RESERVED_CONFIRM_PREFIX = '__seedcord_confirm';\n\n/**\n * The reserved confirm/cancel codec. It has no route, so the dispatcher ignores its clicks and only the\n * in-process collector reads them. Do not mint a real component from it.\n *\n * @internal\n */\nexport const CONFIRM_DEF = new CustomId(RESERVED_CONFIRM_PREFIX).oneOf('choice', ['confirm', 'cancel']);\n","import { ButtonBuilder, TextDisplayBuilder } from '@discordjs/builders';\nimport { BuilderComponent, RowComponent } from '@seedcord/core';\nimport { ButtonStyle, ComponentType } from 'discord.js';\n\nimport { CONFIRM_DEF } from './reserved';\n\nimport type { ReplySender } from '@bot/ReplySender';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { NonModalInteraction } from '@src/handlers/interactionTypes';\nimport type { RepliableHandler } from '@src/handlers/RepliableHandler';\nimport type { ButtonInteraction, Message } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n// the reserved def's shape and choices never change, so encode the ids once\nconst CONFIRM_IDS = {\n confirm: CONFIRM_DEF.encode({ choice: 'confirm' }),\n cancel: CONFIRM_DEF.encode({ choice: 'cancel' })\n};\n\ntype Outcome = ReplyResponse | (() => Promisable<ReplyResponse>);\n\ntype ConfirmPrompt = string | ((ids: { confirm: string; cancel: string }) => Promisable<ReplyResponse>);\n\n/** Options shared by both confirmation forms. */\nexport interface ConfirmOptions {\n /**\n * Whether the prompt is ephemeral. Only the invoking user can act on it either way, a non-invoker's\n * click is ignored.\n *\n * @defaultValue `true`\n */\n ephemeral?: boolean;\n /**\n * Milliseconds to wait for a click before the prompt is settled and the result resolves to `false`.\n *\n * @defaultValue `30_000`\n */\n timeoutMs?: number;\n /** Shown in place of the prompt when the user confirms. Absent removes the prompt. */\n onConfirm?: Outcome;\n /** Shown in place of the prompt when the user cancels. Absent removes the prompt. */\n onCancel?: Outcome;\n /** Shown in place of the prompt when the prompt times out. Absent removes the prompt. */\n onTimeout?: Outcome;\n}\n\n/** Options for the string-prompt form, adding the built-in Confirm/Cancel buttons' labels and style. */\nexport interface DefaultConfirmOptions extends ConfirmOptions {\n /**\n * Confirm-button label.\n *\n * @defaultValue `'Confirm'`\n */\n confirmLabel?: string;\n /**\n * Cancel-button label.\n *\n * @defaultValue `'Cancel'`\n */\n cancelLabel?: string;\n /**\n * Confirm-button style.\n *\n * @defaultValue {@link ButtonStyle.Danger}\n */\n confirmStyle?: ButtonStyle;\n}\n\nclass ConfirmButtons extends RowComponent<'button'> {\n constructor(options: DefaultConfirmOptions | undefined) {\n super('button');\n this.instance.addComponents(\n new ButtonBuilder()\n .setCustomId(CONFIRM_IDS.confirm)\n .setLabel(options?.confirmLabel ?? 'Confirm')\n .setStyle(options?.confirmStyle ?? ButtonStyle.Danger),\n new ButtonBuilder()\n .setCustomId(CONFIRM_IDS.cancel)\n .setLabel(options?.cancelLabel ?? 'Cancel')\n .setStyle(ButtonStyle.Secondary)\n );\n }\n}\n\nclass ConfirmPromptCard extends BuilderComponent<'container'> {\n constructor(text: string, options: DefaultConfirmOptions | undefined) {\n super('container');\n this.instance\n .addTextDisplayComponents(new TextDisplayBuilder().setContent(text))\n .addActionRowComponents(new ConfirmButtons(options).component);\n }\n}\n\nfunction defaultPrompt(text: string, options: DefaultConfirmOptions | undefined): ReplyResponse {\n return { components: [new ConfirmPromptCard(text, options).component] };\n}\n\nasync function collectChoice(message: Message, userId: string, timeoutMs: number): Promise<ButtonInteraction | null> {\n try {\n return await message.awaitMessageComponent({\n componentType: ComponentType.Button,\n time: timeoutMs,\n filter: (click) => click.user.id === userId && CONFIRM_DEF.owns(click.customId)\n });\n } catch {\n // awaitMessageComponent rejects on timeout, which resolves to no decision here\n return null;\n }\n}\n\nasync function settle(sender: ReplySender, message: Message, outcome: Outcome | undefined): Promise<void> {\n if (outcome === undefined) {\n // routes through the interaction webhook, so it removes an ephemeral prompt where a plain\n // message.delete() cannot\n await sender.delete(message).catch(() => undefined);\n return;\n }\n await sender.edit(message, typeof outcome === 'function' ? await outcome() : outcome);\n}\n\n/**\n * Shows a confirm/cancel prompt with built-in Confirm and Cancel buttons and resolves to `true` only if the\n * invoking user clicks confirm. A cancel click or a timeout resolves to `false`. Gate the action behind it\n * with an early return. A failed prompt send throws into the fault boundary. A {@link ModalHandler} is\n * excluded at compile time.\n *\n * @param handler - The handler to prompt from, `this` inside a non-modal handler.\n * @param prompt - The message shown above the Confirm and Cancel buttons.\n * @param options - Ephemeral flag, timeout, the built-in buttons' labels and style, and the optional\n * `onConfirm`/`onCancel`/`onTimeout` outcome replies that edit the prompt in place.\n * @returns `true` if confirmed, `false` on cancel or timeout.\n *\n * @example\n * ```ts\n * import { getConfirmation } from '@seedcord/gateway';\n *\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * const target = this.options.getUser('target', true);\n * if (!(await getConfirmation(this, `Ban ${target.tag}? This cannot be undone.`))) return;\n * await this.event.guild?.members.ban(target.id);\n * }\n * }\n * ```\n */\nexport function getConfirmation(\n handler: RepliableHandler<NonModalInteraction>,\n prompt: string,\n options?: DefaultConfirmOptions\n): Promise<boolean>;\n/**\n * Shows a confirm/cancel prompt you build yourself and resolves to `true` only if the invoking user clicks\n * confirm. The factory receives the two minted button ids. Set them on your own buttons. A cancel click or a\n * timeout resolves to `false`. A failed prompt send throws into the fault boundary. A {@link ModalHandler} is\n * excluded at compile time.\n *\n * @param handler - The handler to prompt from, `this` inside a non-modal handler.\n * @param prompt - A factory given the minted `{ confirm, cancel }` ids that returns the reply to show. Build\n * it with the `BuilderComponent` and `RowComponent` wrappers.\n * @param options - Ephemeral flag, timeout, and the optional `onConfirm`/`onCancel`/`onTimeout` outcome\n * replies that edit the prompt in place.\n * @returns `true` if confirmed, `false` on cancel or timeout.\n *\n * @remarks\n * The prompt is collected in-process, so it does not survive a bot restart. Without an outcome hook the\n * prompt is gone once the user confirms, so deliver the result with a fresh `this.followUp(...)`.\n *\n * @example\n * ```ts\n * import { ButtonBuilder, TextDisplayBuilder } from '@discordjs/builders';\n * import { ButtonStyle } from 'discord.js';\n * import { BuilderComponent, RowComponent, getConfirmation } from '@seedcord/gateway';\n *\n * class BanPrompt extends BuilderComponent<'container'> {\n * constructor(text: string) {\n * super('container');\n * this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(text));\n * }\n * }\n *\n * class ConfirmRow extends RowComponent<'button'> {\n * constructor(ids: { confirm: string; cancel: string }) {\n * super('button');\n * const buttons = [\n * [ids.confirm, 'Ban', ButtonStyle.Danger],\n * [ids.cancel, 'Cancel', ButtonStyle.Secondary]\n * ] as const;\n * this.instance.addComponents(\n * ...buttons.map(([id, label, style]) => new ButtonBuilder().setCustomId(id).setLabel(label).setStyle(style))\n * );\n * }\n * }\n *\n * const target = this.options.getUser('target', true);\n * const confirmed = await getConfirmation(\n * this,\n * (ids) => ({ components: [new BanPrompt(`Ban ${target.tag}?`).component, new ConfirmRow(ids).component] }),\n * { onConfirm: { components: [new BanPrompt(`Banned ${target.tag}.`).component] } }\n * );\n * if (!confirmed) return;\n * ```\n */\nexport function getConfirmation(\n handler: RepliableHandler<NonModalInteraction>,\n prompt: (ids: { confirm: string; cancel: string }) => Promisable<ReplyResponse>,\n options?: ConfirmOptions\n): Promise<boolean>;\nexport async function getConfirmation(\n handler: RepliableHandler<NonModalInteraction>,\n prompt: ConfirmPrompt,\n options?: DefaultConfirmOptions\n): Promise<boolean> {\n const { ephemeral = true, timeoutMs = DEFAULT_TIMEOUT_MS } = options ?? {};\n\n const response = typeof prompt === 'string' ? defaultPrompt(prompt, options) : await prompt(CONFIRM_IDS);\n const interaction = handler.getEvent();\n const sender = handler.getSender();\n const message = await sender.send(response, { ephemeral });\n\n const winner = await collectChoice(message, interaction.user.id, timeoutMs);\n if (!winner) {\n await settle(sender, message, options?.onTimeout);\n return false;\n }\n\n // discord can expire the 3s ack window between the filter firing and this ack\n await winner.deferUpdate().catch(() => undefined);\n const confirmed = winner.customId === CONFIRM_IDS.confirm;\n await settle(sender, message, confirmed ? options?.onConfirm : options?.onCancel);\n return confirmed;\n}\n","import { BaseHandler as CoreBaseHandler } from '@seedcord/core';\n\nimport type { Core } from '../interfaces';\nimport type { ValidEventTypes } from './interactionTypes';\n\n/**\n * The gateway base, fixes the core base's `TCore` to the gateway {@link Core} and adds the `getEvent`\n * gate hook.\n */\nexport abstract class BaseHandler<ValidEvent extends ValidEventTypes> extends CoreBaseHandler<ValidEvent, Core> {\n /** @internal */\n public getEvent(): ValidEvent {\n return this.event;\n }\n}\n","import { BaseHandler } from '@src/handlers/BaseHandler';\n\nimport type { Core } from '@interfaces/Core';\nimport type { Repliables } from '@src/handlers/interactionTypes';\n\n/**\n * Base class for interaction middleware\n *\n * Middleware runs before interaction handlers and can modify behavior or block execution.\n * Unlike handlers, middleware should not send responses directly.\n *\n * @typeParam Repliable - The interaction type this middleware processes\n */\nexport abstract class InteractionMiddleware<Repliable extends Repliables> extends BaseHandler<Repliable> {\n // keep this ctor. it gives typeof InteractionMiddleware a public construct signature that\n // InteractionMiddlewareConstructor needs, and dropping it collapses that type to never.\n constructor(event: Repliable, core: Core) {\n super(event, core, undefined, 'interactions');\n }\n}\n","import { BaseReplySender, deferFlags, sendFlags } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { MessageFlags } from 'discord.js';\n\nimport type { GatewayFile, GatewayReplyResponse } from '@interfaces/ReplyResponse';\nimport type { Bus } from '@seedcord/core';\nimport type { AckState } from '@seedcord/core/internal';\nimport type { DeferOpts, ReplyFile, SendOpts } from '@seedcord/types';\nimport type { Repliables } from '@src/handlers/interactionTypes';\nimport type {\n APIModalInteractionResponseCallbackData,\n InteractionCallbackResponse,\n InteractionReplyOptions,\n InteractionUpdateOptions,\n MessageComponentInteraction,\n ModalMessageModalSubmitInteraction,\n Message,\n WebhookMessageEditOptions\n} from 'discord.js';\n\n// the two djs kinds carrying a source message, so update / deferUpdate have a target\ntype SourceInteraction = MessageComponentInteraction | ModalMessageModalSubmitInteraction;\n\n/** The created message a gateway reply resolves to. */\nexport type SentMessage = Message;\n\nfunction isReplyFile(file: ReplyFile | GatewayFile): file is ReplyFile {\n return typeof file === 'object' && 'data' in file && ArrayBuffer.isView(file.data);\n}\n\n// discord.js rejects a plain Uint8Array, so convert the bytes to a Buffer\nfunction toDjsFile(file: ReplyFile | GatewayFile): GatewayFile {\n if (!isReplyFile(file)) return file;\n return {\n attachment: Buffer.from(file.data),\n name: file.name,\n ...(file.description !== undefined && { description: file.description }),\n ...(file.title !== undefined && { title: file.title })\n };\n}\n\n// djs flips `replied` on editReply, so per-call derivation would break repeated update() and post-edit\n// send() parity\nfunction seedState(interaction: Repliables): AckState {\n if (interaction.deferred && interaction.ephemeral === null) return 'deferred-update';\n if (interaction.replied) return 'replied';\n if (interaction.deferred) return 'deferred-reply';\n return 'unacked';\n}\n\n/**\n * Writes interaction responses through the discord.js interaction. Construction is internal to the repliable\n * handler bases and the dispatcher.\n */\nexport class ReplySender extends BaseReplySender<SentMessage, GatewayFile> {\n public constructor(\n private readonly interaction: Repliables,\n routeId: string,\n bus: Bus\n ) {\n super(routeId, { bus, interactionId: interaction.id }, seedState(interaction));\n }\n\n protected async writeReply(\n response: GatewayReplyResponse | string,\n opts?: SendOpts\n ): Promise<SentMessage | undefined> {\n const result = await this.interaction.reply({\n ...this.replyOptions(response, sendFlags(opts)),\n withResponse: true\n });\n return this.createdMessage(result);\n }\n\n protected async writeDefer(opts?: DeferOpts): Promise<void> {\n await this.interaction.deferReply({ flags: deferFlags(opts) });\n }\n\n protected async writeDeferUpdate(): Promise<void> {\n await this.sourceInteraction('deferUpdate').deferUpdate();\n }\n\n protected async writeUpdate(response: GatewayReplyResponse | string): Promise<SentMessage | undefined> {\n const source = this.sourceInteraction('update');\n const result = await source.update({ ...this.updateOptions(response), withResponse: true });\n return this.createdMessage(result);\n }\n\n protected async writeFollowUp(response: GatewayReplyResponse | string, opts?: SendOpts): Promise<SentMessage> {\n return await this.interaction.followUp(this.replyOptions(response, sendFlags(opts)));\n }\n\n protected async writeEditOriginal(response: GatewayReplyResponse | string): Promise<SentMessage> {\n return await this.interaction.editReply(this.editOptions(response));\n }\n\n protected async writeEditTarget(targetId: string, response: GatewayReplyResponse | string): Promise<SentMessage> {\n return await this.interaction.webhook.editMessage(targetId, this.editOptions(response));\n }\n\n protected async writeDeleteOriginal(): Promise<void> {\n await this.interaction.deleteReply();\n }\n\n protected async writeDeleteTarget(targetId: string): Promise<void> {\n await this.interaction.deleteReply(targetId);\n }\n\n protected async writeModal(data: APIModalInteractionResponseCallbackData): Promise<void> {\n const { interaction } = this;\n // unreachable after guardModalSource, the throw re-narrows the union for showModal\n if (interaction.isModalSubmit()) this.rejectModalSubmit();\n await interaction.showModal(data);\n }\n\n protected override guardModalSource(): void {\n // runtime backstop for direct sender callers, which a compile-time gate on the bases cannot cover\n if (this.interaction.isModalSubmit()) this.rejectModalSubmit();\n }\n\n private rejectModalSubmit(): never {\n throw new SeedcordError(SeedcordErrorCode.ReplyIllegalAckState, [\n 'showModal',\n 'this interaction is a modal submit',\n 'A modal cannot open another modal.',\n this.routeId\n ]);\n }\n\n // only component and message-opened-modal kinds carry a source message\n private sourceInteraction(method: 'update' | 'deferUpdate'): SourceInteraction {\n const { interaction } = this;\n if (interaction.isMessageComponent()) return interaction;\n if (interaction.isModalSubmit() && interaction.isFromMessage()) return interaction;\n throw new SeedcordError(SeedcordErrorCode.ReplyUpdateWithoutSource, [method, this.routeId]);\n }\n\n private replyOptions(response: GatewayReplyResponse | string, flags: number): InteractionReplyOptions {\n const reply = this.serialize(response);\n return {\n components: reply.components,\n flags,\n ...(reply.allowedMentions && { allowedMentions: reply.allowedMentions }),\n ...(reply.files && { files: reply.files.map(toDjsFile) })\n };\n }\n\n private editOptions(response: GatewayReplyResponse | string): WebhookMessageEditOptions {\n const reply = this.serialize(response);\n return {\n components: reply.components,\n flags: MessageFlags.IsComponentsV2,\n ...(reply.allowedMentions && { allowedMentions: reply.allowedMentions }),\n ...(reply.files && { files: reply.files.map(toDjsFile) })\n };\n }\n\n private updateOptions(response: GatewayReplyResponse | string): InteractionUpdateOptions {\n const reply = this.serialize(response);\n return {\n components: reply.components,\n flags: MessageFlags.IsComponentsV2,\n ...(reply.allowedMentions && { allowedMentions: reply.allowedMentions }),\n ...(reply.files && { files: reply.files.map(toDjsFile) })\n };\n }\n\n private createdMessage(result: InteractionCallbackResponse): SentMessage | undefined {\n return result.resource?.message ?? undefined;\n }\n}\n","import { RepliableHandler as CoreRepliableHandler } from '@seedcord/core';\n\nimport { ReplySender } from '@bot/ReplySender';\n\nimport type { Repliables } from './interactionTypes';\nimport type { SentMessage } from '@bot/ReplySender';\nimport type { Core } from '@interfaces/Core';\nimport type { GatewayFile } from '@interfaces/ReplyResponse';\n\n/**\n * Shared base the repliable interaction handlers extend.\n *\n * Not a public entry point. Extend {@link SlashHandler}, {@link ButtonHandler}, {@link ModalHandler},\n * {@link SelectMenuHandler}, or {@link ContextMenuHandler} instead. This class binds the core reply base\n * to the gateway sender.\n *\n * @typeParam Event - The repliable interaction type this handler processes\n */\nexport abstract class RepliableHandler<Event extends Repliables> extends CoreRepliableHandler<\n Event,\n Core,\n SentMessage,\n GatewayFile,\n ReplySender\n> {\n // this chain skips gateway BaseHandler, the only class that defines getEvent, so it re-declares here\n /** @internal */\n public getEvent(): Event {\n return this.event;\n }\n\n protected buildSender(event: Event, core: Core, routeId: string): ReplySender {\n return new ReplySender(event, routeId, core.bus);\n }\n}\n","import { RepliableHandler } from '@handlers/RepliableHandler';\n\nimport type { Core } from '@interfaces/Core';\nimport type { DispatchContext } from '@seedcord/core';\nimport type { ModalLike } from '@seedcord/core/internal';\nimport type { NonModalInteraction, Repliables } from '@src/handlers/interactionTypes';\n\n/**\n * Shared base the typed interaction handlers extend.\n *\n * Not a public entry point. Extend {@link SlashHandler}, {@link ButtonHandler}, {@link ModalHandler},\n * or {@link SelectMenuHandler} instead. This class adds `showModal` on top of the reply members those bases\n * share.\n *\n * @typeParam Repliable - The interaction type this handler processes\n */\nexport abstract class InteractionHandler<Repliable extends Repliables> extends RepliableHandler<Repliable> {\n // keep this ctor. it gives typeof InteractionHandler a public construct signature that HandlerConstructor\n // needs, and dropping it (inheriting RepliableHandler's protected ctor) collapses HandlerConstructor to never.\n constructor(event: Repliable, core: Core, dispatch?: DispatchContext) {\n super(event, core, dispatch);\n }\n\n /**\n * Open a modal. Must be the initial response to this interaction. The modal kind rejects this call at\n * compile time (Discord forbids a modal in response to a modal).\n */\n protected showModal(this: InteractionHandler<NonModalInteraction>, modal: ModalLike): Promise<void> {\n return this.sender.showModal(modal);\n }\n}\n","import { buildSlashRoute } from '@seedcord/utils/internal';\n\nimport type { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js';\n\n/**\n * Computes the dispatch route for a chat-input or autocomplete interaction. The controller and\n * `seedcord codegen` both assemble route keys through the same {@link buildSlashRoute}, so a dispatched\n * interaction and a generated registry key always match.\n *\n * @internal\n */\nexport function slashRouteOf(interaction: ChatInputCommandInteraction | AutocompleteInteraction): string {\n const group = interaction.options.getSubcommandGroup(false) ?? undefined;\n const subcommand = interaction.options.getSubcommand(false) ?? undefined;\n return buildSlashRoute(interaction.commandName, subcommand, group);\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { SlashOptions } from '@inputs/SlashOptions';\nimport type { SlashOptionRegistry } from '@seedcord/core';\nimport type { CacheType, ChatInputCommandInteraction } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\n// one arm per command this handler is registered for, keyed by route, each receiving that route's typed options.\ntype SlashMatchArms<Route extends keyof SlashOptionRegistry, Cache extends CacheType, Ret> = {\n [Key in Route]: (options: SlashOptions<Key, Cache>) => Promisable<Ret>;\n};\n\n/**\n * Base class for a chat-input (slash) command handler.\n *\n * Pass the route from the generated registry as the generic, the same string as `@SlashRoute`, then read\n * `this.options` for a single command or `this.match` for several. Command authoring stays plain\n * discord.js, `seedcord codegen` reads its `toJSON()` to type these options.\n *\n * @typeParam Route - One or more route keys from {@link SlashOptionRegistry}, e.g. `'ban'` or `'ban' | 'kick'`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * const target = this.options.getUser('target'); // User\n * const reason = this.options.getString('reason'); // string | null\n * }\n * }\n * ```\n */\nexport abstract class SlashHandler<\n Route extends keyof SlashOptionRegistry,\n Cache extends CacheType = 'cached'\n> extends InteractionHandler<ChatInputCommandInteraction<Cache>> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __slashRoute?: Route;\n\n /**\n * The typed options for this command's route. Required options drop the null, choices narrow to their\n * literal union, and only the getters for kinds this command actually uses appear. Use `this.event.options`\n * directly for anything outside this view, such as narrowing a channel option by type.\n */\n protected get options(): SlashOptions<Route, Cache> {\n // the djs resolver already carries every getter, SlashOptions is its stricter registry-typed view.\n return this.event.options as SlashOptions<Route, Cache>;\n }\n\n /**\n * Run the arm for whichever command fired. Use this only when the handler is registered for several\n * routes.\n *\n * Provide one arm per registered route, keyed by its route string, and each arm receives that route's\n * own narrowed options. The arms must cover every route in the generic, a missing route or an unknown\n * key is a compile error.\n *\n * @param arms - One handler per registered route, keyed by route string.\n * @returns The result of the arm that ran.\n *\n * @example\n * ```ts\n * \\@SlashRoute('ban', 'kick')\n * class ModHandler extends SlashHandler<'ban' | 'kick'> {\n * async execute() {\n * await this.match({\n * ban: (options) => this.event.guild?.members.ban(options.getUser('target', true).id),\n * kick: (options) => this.event.guild?.members.kick(options.getUser('member', true).id)\n * });\n * }\n * }\n * ```\n */\n protected async match<Ret>(arms: SlashMatchArms<Route, Cache, Ret>): Promise<Ret> {\n const route = slashRouteOf(this.event);\n // justified: SlashMatchArms is keyed by Route literals, the Record cast indexes it with the runtime route string.\n const arm = Object.hasOwn(arms, route)\n ? (arms as Record<string, (options: SlashOptions<Route, Cache>) => Promisable<Ret>>)[route]\n : undefined;\n if (!arm) throw new SeedcordError(SeedcordErrorCode.SlashMatchArmMissing, [route]);\n return await arm(this.options);\n }\n}\n","import { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { ContextMenuKind } from '@seedcord/core';\nimport type {\n APIInteractionGuildMember,\n ApplicationCommandType,\n BooleanCache,\n CacheType,\n CacheTypeReducer,\n GuildMember,\n Message,\n MessageContextMenuCommandInteraction,\n User,\n UserContextMenuCommandInteraction\n} from 'discord.js';\n\n// the interaction class for each kind, so this.event carries the right targetUser/targetMessage members.\ntype InteractionFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User\n ? UserContextMenuCommandInteraction<Cache>\n : MessageContextMenuCommandInteraction<Cache>;\n\n// the right-clicked entity, a User for a user menu and a Message for a message menu.\ntype TargetFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User\n ? User\n : Message<BooleanCache<Cache>>;\n\n// the invoking member, present only on user menus where Discord resolves it alongside the target user.\ntype TargetMemberFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User\n ? CacheTypeReducer<Cache, GuildMember, APIInteractionGuildMember> | null\n : never;\n\n/**\n * Base class for a context-menu command handler (right-click a user or a message).\n *\n * Pass the kind from `discord.js`'s {@link ApplicationCommandType} as the generic, the same value as\n * `@ContextMenuRoute`. Read the right-clicked entity from `this.target`, a `User` for a user menu and a\n * `Message` for a message menu. Context menus carry no options, so a handler registered for several names\n * reads `this.target` uniformly with no per-name branch.\n *\n * @typeParam Kind - `ApplicationCommandType.User` or `ApplicationCommandType.Message`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@ContextMenuRoute(ApplicationCommandType.Message, 'Report Message')\n * class ReportMessage extends ContextMenuHandler<ApplicationCommandType.Message> {\n * async execute() {\n * const message = this.target;\n * }\n * }\n * ```\n */\nexport abstract class ContextMenuHandler<\n Kind extends ContextMenuKind,\n Cache extends CacheType = 'cached'\n> extends InteractionHandler<InteractionFor<Kind, Cache>> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __ctxKind?: Kind;\n\n protected get target(): TargetFor<Kind, Cache> {\n // justified: the Kind generic decides which interaction member is live, both narrow to TargetFor.\n const event = this.event;\n const target = 'targetUser' in event ? event.targetUser : event.targetMessage;\n return target as TargetFor<Kind, Cache>;\n }\n\n /**\n * The invoking guild member, resolved only on user menus. Reading it on a message menu is a compile\n * error since the type is `never` there.\n */\n protected get targetMember(): TargetMemberFor<Kind, Cache> {\n // justified: only the User-kind event carries targetMember, the Message-kind read is unreachable per the type.\n return (this.event as UserContextMenuCommandInteraction<Cache>).targetMember as TargetMemberFor<Kind, Cache>;\n }\n}\n","import { reportedWrite } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { BaseHandler } from '@src/handlers/BaseHandler';\n\nimport type { Core } from '@interfaces/Core';\nimport type { AutocompleteOptions, DispatchContext, SlashOptionRegistry } from '@seedcord/core';\nimport type { AutocompletableNames, ChoiceValueOf, EntryFor, FocusedField } from '@seedcord/core/internal';\nimport type { ApplicationCommandOptionChoiceData, AutocompleteInteraction, CacheType } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\ntype FocusedArms<Route extends keyof SlashOptionRegistry, Ret> = {\n [Name in AutocompletableNames<Route>]: (\n value: string,\n respond: (\n choices: readonly ApplicationCommandOptionChoiceData<ChoiceValueOf<EntryFor<Route, Name>>>[]\n ) => Promise<void>\n ) => Promisable<Ret>;\n};\n\n/**\n * Base class for a Discord autocomplete handler.\n *\n * Pass the command route(s) from the generated registry as the generic, the same string(s) as\n * `@AutocompleteRoute`. Branch on the focused field with `this.match`, read already-entered sibling options\n * with `this.options`, and find which command fired with `this.route`.\n *\n * @typeParam Route - One or more route keys from {@link SlashOptionRegistry}, e.g. `'search'` or `'search' | 'find'`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@AutocompleteRoute('search')\n * class SearchAutocomplete extends AutocompleteHandler<'search'> {\n * async execute() {\n * await this.match({\n * query: (value, respond) => respond([{ name: value, value }])\n * });\n * }\n * }\n * ```\n */\nexport abstract class AutocompleteHandler<\n Route extends keyof SlashOptionRegistry,\n Cache extends CacheType = 'cached'\n> extends BaseHandler<AutocompleteInteraction<Cache>> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __autocompleteRoute?: Route;\n\n // keep this ctor. it gives typeof AutocompleteHandler a public construct signature that HandlerConstructor\n // needs, and dropping it (inheriting BaseHandler's protected ctor) collapses HandlerConstructor to never.\n constructor(event: AutocompleteInteraction<Cache>, core: Core, dispatch?: DispatchContext) {\n super(event, core, dispatch, 'interactions');\n }\n\n private decodedFocused?: { name: string; value: string };\n\n /**\n * The focused option for this interaction. `value` is always the raw partial string the user is typing,\n * even for an integer or number option, so coerce it yourself when you need a number.\n */\n protected get focused(): FocusedField<Route> {\n if (this.decodedFocused) return this.decodedFocused as FocusedField<Route>;\n const raw = this.event.options.getFocused(true);\n const focused = { name: raw.name, value: raw.value };\n this.decodedFocused = focused;\n // the registry constrains the names, a focused field outside the set has no arm.\n return focused as FocusedField<Route>;\n }\n\n /**\n * Run the arm for the focused field. An autocomplete always dispatches by which field is focused, so\n * match is how you read it. There is no single-field shortcut the way slash/component handlers have one.\n *\n * Provide one arm per autocompletable field across the registered commands, keyed by field name. Each\n * arm receives the focused partial value and a `respond` typed to that field's choice value. The\n * arms must cover every autocompletable field, a missing field or an unknown key is a compile error. A\n * focused field with no arm, only reachable from a stale-deployed command, throws at runtime.\n *\n * @param arms - One handler per autocompletable field, keyed by field name.\n * @returns The result of the arm that ran.\n *\n * @example\n * ```ts\n * \\@AutocompleteRoute('search')\n * class SearchAutocomplete extends AutocompleteHandler<'search'> {\n * async execute() {\n * await this.match({\n * query: (value, respond) => respond(titles(value).map((s) => ({ name: s, value: s }))),\n * tag: (value, respond) => respond(tags(value).map((s) => ({ name: s, value: s })))\n * });\n * }\n * }\n * ```\n */\n protected async match<Ret>(arms: FocusedArms<Route, Ret>): Promise<Ret> {\n const { name, value } = this.focused;\n const respond = (choices: readonly ApplicationCommandOptionChoiceData[]): Promise<void> =>\n this.respond(choices);\n // justified: FocusedArms is keyed by field literals, the Record cast indexes it with the runtime field name.\n type Arm = (\n value: string,\n respond: (choices: readonly ApplicationCommandOptionChoiceData[]) => Promise<void>\n ) => Promisable<Ret>;\n const arm = Object.hasOwn(arms, name) ? (arms as Record<string, Arm>)[name] : undefined;\n if (!arm) throw new SeedcordError(SeedcordErrorCode.AutocompleteMatchArmMissing, [name]);\n return await arm(value, respond);\n }\n\n /** Send autocomplete suggestions, callback type 8. Prefer {@link match}, which restricts each field's choices to its declared type. */\n protected async respond(choices: readonly ApplicationCommandOptionChoiceData[]): Promise<void> {\n // a hand-built handler outside a dispatch carries no route id\n const routeId = this.dispatch?.routeId ?? 'autocomplete';\n await reportedWrite({ bus: this.core.bus, interactionId: this.event.id }, routeId, 'respond', () =>\n // eslint-disable-next-line @seedcord/no-raw-interaction-acks -- this is the base respond and calls djs directly\n this.event.respond(choices)\n );\n }\n\n /** The firing command route, for a field whose completion differs per registered command. */\n protected get route(): Route {\n return slashRouteOf(this.event) as Route;\n }\n\n /**\n * The already-entered options on this command, restricted to the kinds Discord resolves during autocomplete\n * (string, integer, number, boolean) with every read nullable, since a sibling is partial while the user\n * types the focused field. The focused field is on `this.focused`.\n */\n protected get options(): AutocompleteOptions<Route> {\n // the djs resolver exposes these getters, AutocompleteOptions is the registry-typed view over it.\n return this.event.options as AutocompleteOptions<Route>;\n }\n}\n","import { decodeComponentRoute } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { SentMessage } from '@bot/ReplySender';\nimport type { GatewayReplyResponse } from '@interfaces/ReplyResponse';\nimport type {\n AnyCustomId,\n DecodedComponentRoute,\n HasComponentDefs,\n MatchArms,\n SingleParams\n} from '@seedcord/core/internal';\nimport type { AnySelectMenuInteraction, ButtonInteraction, ModalSubmitInteraction } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\ntype ComponentInteraction = ButtonInteraction | ModalSubmitInteraction | AnySelectMenuInteraction;\n\n/**\n * Shared base the customId-routed component handlers extend.\n *\n * Not a public entry point. Extend {@link ButtonHandler}, {@link SelectMenuHandler}, or {@link ModalHandler}\n * instead. This class defines the customId decode and the route matching those bases share.\n *\n * @typeParam Event - The component interaction type this handler processes\n * @typeParam Defs - The customId route definitions registered on the concrete handler\n */\nexport abstract class ComponentHandler<Event extends ComponentInteraction, Defs extends readonly AnyCustomId[]>\n extends InteractionHandler<Event>\n implements HasComponentDefs<Defs>\n{\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __componentDefs?: Defs;\n\n /** Rewrite the source message this component interaction came from. */\n protected update(response: GatewayReplyResponse | string): Promise<SentMessage> {\n return this.sender.update(response);\n }\n\n /** Acknowledge the component without changing the source message. */\n protected deferUpdate(): Promise<void> {\n return this.sender.deferUpdate();\n }\n\n private decoded?: DecodedComponentRoute;\n\n private get route(): DecodedComponentRoute {\n this.decoded ??= decodeComponentRoute(this.constructor, this.event.customId);\n return this.decoded;\n }\n\n /**\n * The decoded params of the single route this handler is registered for.\n *\n * Reading this decodes `this.event.customId` once (cached after the first read) and throws\n * `StaleCustomId` or `InvalidCustomId` when the wire no longer matches the current shape, which the\n * controller boundary turns into a reply. On a handler registered for several routes this is\n * `never`, so use {@link match} instead.\n */\n protected get params(): SingleParams<Defs> {\n return this.route.params as SingleParams<Defs>;\n }\n\n /**\n * Run the arm for whichever route the component was minted from. Use this only when the handler is\n * registered for several routes. A single-route handler reads `this.params` directly. On a multi-route\n * handler `this.params` is `never`, so match is the only way to read the decoded params.\n *\n * Provide one arm per registered route, keyed by its prefix, and each arm receives that route's own\n * decoded params. The arms cover every registered route prefix, checked at compile time, and a prefix\n * unmatched at runtime throws `CustomIdMatchArmMissing`. Decoding runs before any arm, so a stale or\n * corrupt wire throws before an arm body executes.\n *\n * @param arms - One callback per registered route, keyed by prefix.\n * @returns The result of the arm that ran.\n *\n * @example\n * ```ts\n * \\@ButtonRoute(Approve, Reject)\n * class ReviewButtons extends ButtonHandler<[typeof Approve, typeof Reject]> {\n * async execute() {\n * await this.match({\n * approve: ({ userId }) => this.reply(`approved <@${userId}>`),\n * reject: ({ userId }) => this.reply(`rejected <@${userId}>`)\n * });\n * }\n * }\n * ```\n */\n protected async match<Ret>(arms: MatchArms<Defs, Ret>): Promise<Ret> {\n const { prefix, params } = this.route;\n // justified: MatchArms is keyed by prefix literals, so the Record cast indexes it with the runtime prefix\n const arm = Object.hasOwn(arms, prefix)\n ? (arms as Record<string, (params: Record<string, unknown>) => Promisable<Ret>>)[prefix]\n : undefined;\n if (!arm) throw new SeedcordError(SeedcordErrorCode.CustomIdMatchArmMissing, [prefix]);\n return await arm(params);\n }\n}\n","import { ComponentHandler } from './ComponentHandler';\n\nimport type { AnyCustomId } from '@seedcord/core/internal';\nimport type { ButtonInteraction, CacheType } from 'discord.js';\n\n/**\n * Base class for a button interaction handler.\n *\n * Register the customId definitions this handler decodes with `@ButtonRoute`, list the same ones in the\n * generic, then read `this.params` for a single route or `this.match` for several. Reply through the handler\n * members, or rewrite the source message with `this.update`. Passing different definitions to the decorator\n * and the generic is a compile error.\n *\n * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof ApproveId]`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@ButtonRoute(ApproveId)\n * class ApproveButton extends ButtonHandler<[typeof ApproveId]> {\n * async execute() {\n * const { userId } = this.params;\n * await this.reply(`approved <@${userId}>`);\n * }\n * }\n * ```\n */\nexport abstract class ButtonHandler<\n Defs extends readonly AnyCustomId[],\n Cache extends CacheType = 'cached'\n> extends ComponentHandler<ButtonInteraction<Cache>, Defs> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __component?: 'button';\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { ComponentHandler } from './ComponentHandler';\n\nimport type { SentMessage } from '@bot/ReplySender';\nimport type { GatewayReplyResponse } from '@interfaces/ReplyResponse';\nimport type { AnyCustomId } from '@seedcord/core/internal';\nimport type { CacheType, ModalSubmitInteraction } from 'discord.js';\n\n/**\n * Base class for a modal submit handler.\n *\n * Register the customId definitions this handler decodes with `@ModalRoute`, list the same ones in the\n * generic, then read `this.params` for a single route or `this.match` for several. Read the submitted\n * inputs from `this.event.fields`, and reply through the handler members. Discord forbids opening a modal in\n * response to a modal, so `showModal` fails compilation on this kind.\n *\n * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof ConfigId]`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@ModalRoute(ConfigId)\n * class ConfigModal extends ModalHandler<[typeof ConfigId]> {\n * async execute() {\n * const { guildId } = this.params;\n * const name = this.event.fields.getTextInputValue('name');\n * await this.reply(`saved ${name} for ${guildId}`);\n * }\n * }\n * ```\n */\nexport abstract class ModalHandler<\n Defs extends readonly AnyCustomId[],\n Cache extends CacheType = 'cached'\n> extends ComponentHandler<ModalSubmitInteraction<Cache>, Defs> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __component?: 'modal';\n\n /** Rewrite the message this modal was opened from. Throws when a command opened the modal. */\n protected override update(response: GatewayReplyResponse | string): Promise<SentMessage> {\n this.ensureSourceMessage('update');\n return super.update(response);\n }\n\n /** Acknowledge the submit without changing the source message. Throws when a command opened the modal. */\n protected override deferUpdate(): Promise<void> {\n this.ensureSourceMessage('deferUpdate');\n return super.deferUpdate();\n }\n\n // discord omits the message when a command opened the modal, so update and deferUpdate have no target\n private ensureSourceMessage(method: string): void {\n if (this.event.isFromMessage()) return;\n throw new SeedcordError(SeedcordErrorCode.ReplyUpdateWithoutSource, [method, this.routeId]);\n }\n}\n","import { ComponentHandler } from './ComponentHandler';\n\nimport type { SelectMenuKind } from '@seedcord/core';\nimport type { AnyCustomId } from '@seedcord/core/internal';\nimport type {\n CacheType,\n ChannelSelectMenuInteraction,\n MentionableSelectMenuInteraction,\n RoleSelectMenuInteraction,\n StringSelectMenuInteraction,\n UserSelectMenuInteraction\n} from 'discord.js';\n\ntype SelectMenuInteractionFor<\n SelectMenu extends SelectMenuKind,\n Cache extends CacheType = CacheType\n> = SelectMenu extends SelectMenuKind.String\n ? StringSelectMenuInteraction<Cache>\n : SelectMenu extends SelectMenuKind.User\n ? UserSelectMenuInteraction<Cache>\n : SelectMenu extends SelectMenuKind.Role\n ? RoleSelectMenuInteraction<Cache>\n : SelectMenu extends SelectMenuKind.Channel\n ? ChannelSelectMenuInteraction<Cache>\n : SelectMenu extends SelectMenuKind.Mentionable\n ? MentionableSelectMenuInteraction<Cache>\n : never;\n\n/**\n * Base class for a select menu handler.\n *\n * Pass the select kind first and the customId definitions second, the same order as `@SelectMenuRoute`,\n * so `this.event` and `this.event.values` are narrowed to that kind. Read `this.params` for a single\n * route or `this.match` for several, and reply through the handler members or rewrite the source message\n * with `this.update`.\n *\n * @typeParam Kind - The select kind from {@link SelectMenuKind}, e.g. `SelectMenuKind.User`.\n * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof AssignId]`.\n * @typeParam Cache - The interaction cache state, `'cached'` by default.\n *\n * @example\n * ```ts\n * \\@SelectMenuRoute(SelectMenuKind.User, AssignId)\n * class AssignSelect extends SelectMenuHandler<SelectMenuKind.User, [typeof AssignId]> {\n * async execute() {\n * const { roleId } = this.params;\n * await this.reply(`assigning ${this.event.values.length} member(s) to <@&${roleId}>`);\n * }\n * }\n * ```\n */\nexport abstract class SelectMenuHandler<\n Kind extends SelectMenuKind,\n Defs extends readonly AnyCustomId[],\n Cache extends CacheType = 'cached'\n> extends ComponentHandler<SelectMenuInteractionFor<Kind, Cache>, Defs> {\n // phantom, never set at runtime.\n /** @internal */\n declare readonly __component?: Kind;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { BaseHandler } from '@src/handlers/BaseHandler';\n\nimport type { SingleEventPayload } from './payload';\nimport type { Core } from '@interfaces/Core';\nimport type { ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\n// spread so the discord.js tuple labels surface as parameter names in editor signature help, e.g.\n// messageUpdate gives (oldMessage, newMessage). a single tuple param would lose the labels.\ntype EventMatchArms<Names extends ValidNonInteractionKeys, Ret> = {\n [Name in Names]: (...args: ClientEvents[Name]) => Promisable<Ret>;\n};\n\n/**\n * Base class for a Discord client event handler.\n *\n * Pass the event name(s) as the generic, the same one(s) as `@RegisterEvent`. A single-event handler reads\n * `this.event` (the payload tuple) directly. A handler registered for several events branches with `this.match`,\n * keyed by event name, since the union of payload tuples is not directly readable.\n *\n * @typeParam Names - One or more `ClientEvents` keys, e.g. `Events.MessageCreate` or `Events.MessageCreate | Events.MessageUpdate`.\n *\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])\n * class PingPong extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {\n * async execute() {\n * await this.match({\n * [Events.MessageCreate]: (message) => message.reply('pong'),\n * [Events.MessageUpdate]: (_oldMessage, edited) => edited.reply('pong')\n * });\n * }\n * }\n * ```\n */\nexport abstract class EventHandler<in out Names extends ValidNonInteractionKeys> extends BaseHandler<\n ClientEvents[Names]\n> {\n // the fired event name, threaded by the controller. undefined when constructed directly, e.g. in a test.\n private readonly firedEvent: Names | undefined;\n\n constructor(event: ClientEvents[Names], core: Core, eventName?: Names) {\n super(event, core, undefined, 'events');\n this.firedEvent = eventName;\n }\n\n // a concrete tuple for one event, never for several, so reading it on a multi-event handler is a compile error\n declare protected readonly event: SingleEventPayload<Names>;\n\n /**\n * Run the arm for whichever event fired. Use this only when the handler is registered for several\n * events. A single-event handler reads `this.event` directly. On a multi-event handler `this.event` is\n * `never`, so match is the only way to read the payload.\n *\n * Provide one arm per registered event, keyed by its name, and each arm receives that event's own\n * payload tuple. The arms must cover every event in the generic, a missing event or an unknown key is a\n * compile error.\n *\n * @param arms - One handler per registered event, keyed by event name.\n * @returns The result of the arm that ran.\n *\n * @example\n * ```ts\n * \\@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])\n * class MessageWatcher extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {\n * async execute() {\n * await this.match({\n * [Events.MessageCreate]: (message) => this.scan(message),\n * [Events.MessageUpdate]: (_old, updated) => this.scan(updated)\n * });\n * }\n * }\n * ```\n */\n protected async match<Ret>(arms: EventMatchArms<Names, Ret>): Promise<Ret> {\n const name = this.firedEvent;\n if (name === undefined) throw new SeedcordError(SeedcordErrorCode.EventMatchArmMissing, ['<no event>']);\n // justified: each arm takes its own payload tuple, so no single param type unifies the arms in a cast. read\n // the arm as unknown keyed by the runtime event name, then narrow to a function before calling it.\n const arm = (arms as Record<string, unknown>)[name];\n if (typeof arm !== 'function') throw new SeedcordError(SeedcordErrorCode.EventMatchArmMissing, [name]);\n // getEvent() carries the real payload tuple, this.event is narrowed to never for the multi-event view.\n // spread it so the arm receives the same named params its type declares.\n return await (arm as (...args: unknown[]) => Promisable<Ret>)(...this.getEvent());\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { BaseHandler } from '@src/handlers/BaseHandler';\n\nimport type { SingleEventPayload } from './payload';\nimport type { Core } from '@interfaces/Core';\nimport type { ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\n\n/**\n * Base class for Discord event middleware.\n *\n * Middleware runs before event handlers and can stop the event by throwing a `Silence`. Unlike `EventHandler`, it\n * runs the SAME for every event it is registered for, so it has no `match`. Specify a single event in the\n * generic and `{ events }` to read `this.event` fully typed. Span several events (or omit `{ events }` for a\n * catchall) and `this.event` narrows to `never`, read `this.eventName` and do work that does not depend on the\n * payload shape. A middleware that needs each event's payload is written one event per class.\n *\n * @typeParam EventName - One or more `ClientEvents` keys. Defaults to every event (catchall).\n */\nexport abstract class EventMiddleware<\n in out EventName extends ValidNonInteractionKeys = ValidNonInteractionKeys\n> extends BaseHandler<ClientEvents[EventName]> {\n // the fired event name, threaded by the controller. undefined when constructed directly, e.g. in a test.\n private readonly firedEvent: EventName | undefined;\n\n constructor(event: ClientEvents[EventName], core: Core, eventName?: EventName) {\n super(event, core, undefined, 'events');\n this.firedEvent = eventName;\n }\n\n // a concrete tuple for one event, never for several or a catchall, so reading the payload on a multi-event\n // middleware is a compile error. branch on this.eventName and do payload-shape-independent work instead.\n declare protected readonly event: SingleEventPayload<EventName>;\n\n /**\n * The event that fired this middleware. Read it on a catchall or multi-event middleware, where `this.event`\n * is `never`, to do work that does not depend on the payload shape. A single-event middleware reads\n * `this.event` directly and does not need this.\n */\n protected get eventName(): EventName {\n if (this.firedEvent === undefined) throw new SeedcordError(SeedcordErrorCode.EventMiddlewareNameUnavailable);\n return this.firedEvent;\n }\n}\n","import { PaginatorBase } from '@seedcord/core';\n\nimport { ButtonHandler } from '@handlers/interaction/components';\n\nimport type { PageContext } from './PageContext';\nimport type { RepliableHandler } from '@handlers/RepliableHandler';\nimport type { Core } from '@interfaces/Core';\nimport type { PaginatorConfig } from '@seedcord/core';\nimport type { PageCursor } from '@seedcord/core/internal';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { Repliables } from '@src/handlers/interactionTypes';\nimport type { ButtonInteraction, Message } from 'discord.js';\n\n// `& { execute }` concretizes the abstract execute so the empty `extends Bans.Handler {}` stays concrete\n// (no TS2515) and a concrete Nav assigns with no cast.\ntype PaginatorHandlerCtor<Prefix extends string> = new (\n event: ButtonInteraction<'cached'>,\n core: Core\n) => ButtonHandler<[PageCursor<Prefix>]> & { execute(): Promise<void> };\n\nfunction contextOf(interaction: Repliables, core: Core): PageContext {\n return { interaction, user: interaction.user, guild: interaction.guild, core };\n}\n\n/**\n * A restart-proof paginator. Each nav button's customId encodes its full target page, so clicks are\n * idempotent and survive a restart. A persistent `@ButtonRoute` on `Handler` dispatches the clicks.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `config.prefix`.\n *\n * @example\n * ```ts\n * export const Bans = new Paginator({\n * prefix: 'bans',\n * source: new ArraySource((ctx) => ctx.guild.bans.fetch().then((b) => [...b.values()]), { perPage: 10 }),\n * renderItem: (ban) => ban.user.tag\n * });\n *\n * \\@ButtonRoute(Bans.cursor)\n * export class BansNav extends Bans.Handler {}\n * ```\n */\nexport class Paginator<Item, const Prefix extends string> extends PaginatorBase<Item, Prefix, PageContext> {\n /** The nav handler base. Extend it with an empty body and decorate it, `@ButtonRoute(p.cursor)`. */\n public readonly Handler: PaginatorHandlerCtor<Prefix>;\n\n constructor(config: PaginatorConfig<Item, Prefix, PageContext>) {\n super(config);\n\n // an arrow captures the paginator lexically so Nav.execute can reach it without aliasing `this`.\n const loadPage = (ctx: PageContext, n: number): Promise<ReplyResponse> => this.page(ctx, n);\n this.Handler = class Nav extends ButtonHandler<[PageCursor<Prefix>]> {\n async execute(): Promise<void> {\n await this.deferUpdate();\n const response = await loadPage(contextOf(this.event, this.core), this.params.page);\n // deferUpdate seeds the sender deferred-update, so update PATCHes @original\n await this.update(response);\n }\n };\n }\n\n /**\n * Render page 0 and send it through the handler's sender, which picks reply, edit, or followUp from its\n * ack state.\n *\n * @param handler - The handler starting the paginator, normally `this`.\n */\n async start(handler: RepliableHandler<Repliables>): Promise<Message> {\n const interaction = handler.getEvent();\n const response = await this.page(contextOf(interaction, handler.core), 0);\n return handler.getSender().send(response, { ephemeral: this.config.ephemeral ?? false });\n }\n}\n","import { ArraySource as BaseArraySource, CursorSource as BaseCursorSource } from '@seedcord/core';\n\nimport type { PageContext } from './PageContext';\n\n/**\n * A source for a bounded list you can load whole. It loads the full list on every click, then slices the\n * page, so the real total is known (a real last button, \"Page X of Y\"). Cache inside your loader if the\n * load is expensive.\n *\n * @typeParam Item - The item type, inferred from the loader's return.\n */\nexport class ArraySource<Item> extends BaseArraySource<Item, PageContext> {}\n\n/**\n * A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).\n * The fetcher receives the page index and the page size and reports whether a next page exists. A cursor\n * source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator\n * reads \"Page X\".\n *\n * @typeParam Item - The item type, inferred from the fetcher's slice.\n */\nexport class CursorSource<Item> extends BaseCursorSource<Item, PageContext> {}\n","import { Subscriber as CoreSubscriber, WebhookLog as CoreWebhookLog } from '@seedcord/core';\n\nimport type { Core } from '@interfaces/Core';\nimport type { SubscriptionKey } from '@seedcord/core';\n\n/**\n * Base class for a gateway subscriber, binding `this.core` to the gateway {@link Core}.\n *\n * @typeParam KeyOfSubscribers - The subscription key this handler receives\n */\nexport abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey> extends CoreSubscriber<\n KeyOfSubscribers,\n Core\n> {}\n\n/**\n * Base class for a gateway subscriber that delivers its event to a Discord webhook, binding\n * `this.core` to the gateway {@link Core}.\n *\n * @typeParam KeyOfSubscribers - The subscription key this reporter receives\n */\nexport abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey> extends CoreWebhookLog<\n KeyOfSubscribers,\n Core\n> {}\n","import { Plugin as CorePlugin } from '@seedcord/core/plugin';\n\nimport type { Core } from '@interfaces/Core';\nimport type { PluginOptions } from '@seedcord/core/plugin';\nimport type { TypedOmit } from '@seedcord/types';\n\n/** The options a gateway plugin declares, narrowed to the transports this base serves. */\nexport type GatewayPluginOptions = TypedOmit<PluginOptions, 'transport'> & { transport?: 'gateway' | 'any' };\n\n/**\n * Base class for a gateway plugin, binding `this.core` to the gateway {@link Core}.\n *\n * A plugin that runs on either transport extends the base from `@seedcord/core/plugin`, whose\n * `this.core` is typed to the shared members only.\n *\n * @typeParam Opts - The transport and runtime the plugin declares.\n */\nexport abstract class Plugin<Opts extends GatewayPluginOptions = {}> extends CorePlugin<Opts, Core> {}\n\nexport type { PluginLifecycleSpec, PluginOptions } from '@seedcord/core/plugin';\n","import { GuildMember, Message, User } from 'discord.js';\n\nimport type { Guild } from 'discord.js';\n\nexport interface EventActor {\n guild: Guild | null;\n member: GuildMember | null;\n user: User | null;\n channelId: string | null;\n}\n\n// the actor sits in a different arg per event, so scan the tuple for the common carriers, best-effort\nexport function deriveEventActor(args: unknown): EventActor {\n const tuple = Array.isArray(args) ? (args as unknown[]) : [args];\n for (const arg of tuple) {\n if (arg instanceof Message) {\n return { guild: arg.guild, member: arg.member, user: arg.author, channelId: arg.channelId };\n }\n if (arg instanceof GuildMember) return { guild: arg.guild, member: arg, user: arg.user, channelId: null };\n if (arg instanceof User) return { guild: null, member: null, user: arg, channelId: null };\n }\n return { guild: null, member: null, user: null, channelId: null };\n}\n","import { GuildMember } from 'discord.js';\n\nimport { deriveEventActor } from '@miscellaneous/deriveEventActor';\n\nimport type { EventGateContext, InteractionGateContext } from './Gate';\nimport type { Core } from '@interfaces/Core';\nimport type { Repliables, ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\n\nexport function interactionGateContext(interaction: Repliables, core: Core): InteractionGateContext {\n const rawMember = interaction.member;\n // an uncached member still arrives as the raw payload shape, whose roles are already ids. the cache\n // additionally carries the everyone role (id equals the guild id), which the raw payload never does,\n // so it is filtered out for one shape across cache states\n const memberRoleIds =\n rawMember instanceof GuildMember\n ? [...rawMember.roles.cache.keys()].filter((id) => id !== interaction.guildId)\n : (rawMember?.roles ?? []);\n\n return {\n kind: 'interaction',\n interaction,\n core,\n user: interaction.user,\n guild: interaction.guild,\n member: rawMember instanceof GuildMember ? rawMember : null,\n userId: interaction.user.id,\n guildId: interaction.guildId,\n channelId: interaction.channelId,\n memberRoleIds,\n memberPermissions: interaction.memberPermissions?.bitfield ?? null,\n // djs types appPermissions non-null on interactions, a ?. here would trip no-unnecessary-condition\n appPermissions: interaction.appPermissions.bitfield,\n memberGuildPermissions: rawMember instanceof GuildMember ? rawMember.permissions.bitfield : null,\n appGuildPermissions: interaction.guild?.members.me?.permissions.bitfield ?? null,\n routeId: null // runHandlerGates sets routeId from the handler metadata before the gates run\n };\n}\n\nexport function eventGateContext(\n eventName: ValidNonInteractionKeys,\n args: ClientEvents[ValidNonInteractionKeys],\n core: Core\n): EventGateContext {\n const actor = deriveEventActor(args);\n return {\n kind: 'event',\n core,\n eventName,\n payload: args,\n user: actor.user,\n guild: actor.guild,\n member: actor.member,\n userId: actor.user?.id ?? null,\n guildId: actor.guild?.id ?? null,\n channelId: actor.channelId,\n // the cache carries the everyone role (id equals the guild id), filtered out to match the interaction shape\n memberRoleIds: actor.member ? [...actor.member.roles.cache.keys()].filter((id) => id !== actor.guild?.id) : [],\n memberPermissions: actor.member?.permissions.bitfield ?? null,\n appPermissions: null,\n memberGuildPermissions: actor.member?.permissions.bitfield ?? null,\n appGuildPermissions: actor.guild?.members.me?.permissions.bitfield ?? null,\n routeId: null // runHandlerGates sets routeId from the handler metadata before the gates run\n };\n}\n","import * as crypto from 'node:crypto';\n\nimport { Notice, Fault } from '@seedcord/core';\nimport { prefixOf, PublishDefault, FaultThrottle } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/logger';\nimport { DiscordAPIError } from 'discord.js';\n\nimport { slashRouteOf } from '@bot/utilities/miscellaneous/slashRouteOf';\n\nimport type { Core } from '@interfaces/Core';\nimport type { FaultSource, SubscriptionData } from '@seedcord/core';\nimport type { RenderContext, ReplyResponse, Nullable } from '@seedcord/types';\nimport type { Repliables } from '@src/handlers/interactionTypes';\nimport type { Guild, User } from 'discord.js';\nimport type { UUID } from 'node:crypto';\n\ntype InteractionFaultSource = Extract<FaultSource, { kind: 'interaction' }>;\ntype EventFaultSource = Extract<FaultSource, { kind: 'event' }>;\n\nconst logger = new Logger('ErrorsHandling', { channel: 'errors' });\n\ninterface EventOrigin {\n name: string;\n handler: string;\n args: unknown;\n channelId: string | null;\n}\n\nexport interface ErrorOrigin {\n interaction?: Repliables;\n event?: EventOrigin;\n /** The route, for the throttle key when there is no repliable interaction or event (autocomplete). */\n route?: string;\n guild: Nullable<Guild>;\n user: Nullable<User>;\n metadata?: unknown;\n}\n\nexport interface ExtractedErrorResponse {\n uuid: UUID;\n response: ReplyResponse;\n}\n\n/**\n * Processes an error into a user-facing reply and routes its report.\n *\n * A {@link Notice} always renders its own reply. A reporting denial (`report: true`) additionally\n * publishes `handledException` on the interaction path. A raw, non-denial throw publishes\n * `unknownException` and renders the configured `defaultError` (or a generic {@link Fault}). One uuid is\n * threaded into both the reply and the bus payload.\n */\nexport function extractErrorResponse(error: Error, core: Core, origin: ErrorOrigin): ExtractedErrorResponse {\n const uuid = crypto.randomUUID();\n const developerUsername = core.config.notifications?.developerUsername;\n const ctx: RenderContext = developerUsername === undefined ? { uuid } : { uuid, developerUsername };\n\n if (error instanceof Notice) {\n if (error.report) reportFault(error, core, origin, uuid);\n return { uuid, response: error.render(ctx) };\n }\n\n reportRawFault(error, core, origin, uuid);\n\n const override = core.config.errors?.defaultError;\n const response = override ? new override(uuid).render(ctx) : new Fault().render(ctx);\n\n return { uuid, response };\n}\n\n// stamp only after a publish, so a throttled fault stays reportable next window\nfunction withThrottle(core: Core, origin: ErrorOrigin, error: Error, publish: () => void): void {\n const throttle = FaultThrottle.for(core);\n const key = faultKey(origin, error);\n if (!throttle.shouldReport(key)) {\n logger.debug(`throttled duplicate fault ${key}`);\n return;\n }\n publish();\n throttle.markReported(key);\n}\n\nfunction reportFault(denial: Notice, core: Core, origin: ErrorOrigin, uuid: UUID): void {\n // outside the throttle, so the uuid on the user's card always resolves to a log line\n logger.error(`${denial.name}: ${uuid}`, denial);\n\n withThrottle(core, origin, denial, () => {\n if (origin.interaction) {\n core.bus[PublishDefault]('handledException', {\n denial,\n uuid,\n source: buildInteractionSource(origin.interaction)\n });\n } else if (origin.event) {\n core.bus[PublishDefault]('handledException', {\n denial,\n uuid,\n source: buildEventSource(origin.event, origin)\n });\n } else {\n // autocomplete has no reply target and no typed source, so report through unknownException\n core.bus[PublishDefault]('unknownException', {\n uuid,\n error: denial,\n ...scalarActors(origin),\n metadata: metadataFor(origin)\n });\n }\n });\n}\n\nfunction causeLine(error: Error): string {\n const { cause } = error;\n if (!Error.isError(cause)) return '';\n const [first] = cause.message.split('\\n');\n return `\\ncaused by ${cause.name}: ${first ?? cause.message}`;\n}\n\nfunction reportRawFault(error: Error, core: Core, origin: ErrorOrigin, uuid: UUID): void {\n const showStack = core.config.errors?.errorStack ?? false;\n // outside the throttle, so the uuid on the user's card always resolves to a log line\n if (showStack) logger.error(uuid, error);\n else logger.error(`${uuid} | ${error.message}${causeLine(error)}`);\n\n withThrottle(core, origin, error, () => {\n core.bus[PublishDefault]('unknownException', {\n uuid,\n error,\n ...scalarActors(origin),\n metadata: metadataFor(origin)\n });\n });\n}\n\n// the bus payload must stay djs-free, so map to plain scalars\nfunction scalarActors(origin: ErrorOrigin): Pick<SubscriptionData<'unknownException'>, 'guild' | 'user'> {\n return {\n guild: origin.guild ? { id: origin.guild.id, name: origin.guild.name } : undefined,\n user: origin.user ? { id: origin.user.id, username: origin.user.username } : undefined\n };\n}\n\nfunction metadataFor(origin: ErrorOrigin): unknown {\n if (origin.event) return { eventName: origin.event.name, handler: origin.event.handler, args: origin.event.args };\n return origin.metadata;\n}\n\nfunction buildEventSource(event: EventOrigin, origin: ErrorOrigin): EventFaultSource {\n return {\n kind: 'event',\n eventName: event.name,\n handler: event.handler,\n userId: origin.user?.id ?? null,\n guildId: origin.guild?.id ?? null,\n channelId: event.channelId,\n raw: event.args\n };\n}\n\n// the stable route plus the error name, so a parameterized component or a flooding event collapses to one key\nfunction faultKey(origin: ErrorOrigin, error: Error): string {\n const name =\n error instanceof Notice\n ? error.name\n : error instanceof DiscordAPIError\n ? String(error.code)\n : error.constructor.name;\n if (origin.event) return `${origin.event.name}:${origin.event.handler}:${name}`;\n if (origin.interaction) return `${interactionRoute(origin.interaction)}:${name}`;\n // autocomplete, namespaced so it never collides with a same-named slash command\n if (origin.route) return `autocomplete:${origin.route}:${name}`;\n return `autocomplete:${name}`;\n}\n\nfunction interactionRoute(interaction: Repliables): string {\n if (interaction.isChatInputCommand()) return slashRouteOf(interaction);\n if (interaction.isContextMenuCommand()) return interaction.commandName;\n if (interaction.isButton() || interaction.isAnySelectMenu() || interaction.isModalSubmit()) {\n // || so an empty prefix (a too-short routeKey) falls back to the full wire\n return prefixOf(interaction.customId) || interaction.customId;\n }\n return 'interaction';\n}\n\nfunction buildInteractionSource(interaction: Repliables): InteractionFaultSource {\n const command = interaction.isChatInputCommand()\n ? slashRouteOf(interaction)\n : interaction.isContextMenuCommand()\n ? interaction.commandName\n : null;\n const customId =\n interaction.isButton() || interaction.isAnySelectMenu() || interaction.isModalSubmit()\n ? interaction.customId\n : null;\n\n return {\n kind: 'interaction',\n interactionKind: interactionKind(interaction),\n command,\n customId,\n userId: interaction.user.id,\n guildId: interaction.guildId,\n channelId: interaction.channelId,\n interactionId: interaction.id,\n raw: interaction\n };\n}\n\nfunction interactionKind(interaction: Repliables): InteractionFaultSource['interactionKind'] {\n if (interaction.isChatInputCommand()) return 'slash';\n if (interaction.isContextMenuCommand()) return 'context-menu';\n if (interaction.isButton()) return 'button';\n if (interaction.isAnySelectMenu()) return 'select';\n return 'modal';\n}\n","import { Notice, Silence } from '@seedcord/core';\nimport { asError } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/logger';\nimport { DiscordAPIError } from 'discord.js';\n\nimport { deriveEventActor } from '@miscellaneous/deriveEventActor';\nimport { extractErrorResponse } from '@miscellaneous/extractErrorResponse';\n\nimport type { Core } from '@interfaces/Core';\n\nconst logger = new Logger('Faults', { channel: 'errors' });\n\n/**\n * The event controller boundary. Reports a throw from an event handler and never replies, since a\n * generic event has no reply target. A {@link Silence} or a non-reporting {@link Notice} stops quietly, a\n * reporting denial or a raw error publishes a fault with a best-effort actor derived from the args.\n *\n * @internal\n */\nexport function handleEventFault(\n caught: unknown,\n eventName: string,\n handlerName: string,\n args: unknown,\n core: Core\n): void {\n if (caught instanceof Silence) {\n if (caught.reason !== undefined && (core.config.errors?.logSilences ?? true)) {\n logger.debug(`Silence: ${caught.reason}`);\n }\n return;\n }\n const error = asError(caught);\n\n // empty by default, so a dead resource on an event reports (throttled) until the dev confirms it is\n // an expected dead end and adds the code here. a swallowed code still debug-logs.\n const ignore = new Set<number | string>(core.config.errors?.ignoreEventApiCodes ?? []);\n if (error instanceof DiscordAPIError && ignore.has(error.code)) {\n logger.debug(`swallowed api code ${error.code}`);\n return;\n }\n\n // a non-reporting denial has no reply target on an event, so it stops quietly\n if (error instanceof Notice && !error.report) return;\n\n const actor = deriveEventActor(args);\n extractErrorResponse(error, core, {\n event: { name: eventName, handler: handlerName, args, channelId: actor.channelId },\n guild: actor.guild,\n user: actor.user\n });\n}\n","import { HmrModuleHandler } from '@seedcord/core/hmr';\nimport {\n areRoutes,\n asError,\n EventMetadataKey,\n MiddlewareMetadataKey,\n PublishDefault,\n runHandlerGates\n} from '@seedcord/core/internal';\nimport { settleWithin } from '@seedcord/core/node/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger, paint } from '@seedcord/logger';\nimport { formatFilePath, hasKeys } from '@seedcord/utils';\nimport { traverseDirectory } from '@seedcord/utils/node';\nimport { Envapter } from 'envapt';\n\nimport { MiddlewareType } from '@bDecorators/Middlewares';\nimport { eventGateContext } from '@bot/gates/runGates';\nimport { handleEventFault } from '@bot/handleEventFault';\nimport { EventHandler, EventMiddleware } from '@handlers/event';\n\nimport type { RegisterEventMetadataEntry } from '@bDecorators/Events';\nimport type { MiddlewareMetadata } from '@bDecorators/Middlewares';\nimport type { EventHandlerConstructor, EventMiddlewareConstructor } from '@handlers/constructors';\nimport type { Core } from '@interfaces/Core';\nimport type { Initializeable, SubscriptionData } from '@seedcord/core';\nimport type { EventFrequency, HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { ValidNonInteractionKeys } from '@src/handlers/interactionTypes';\nimport type { ClientEvents } from 'discord.js';\n\ninterface RegisteredEventMiddleware {\n readonly ctor: EventMiddlewareConstructor;\n readonly priority: number;\n readonly events?: readonly ValidNonInteractionKeys[];\n}\n\ninterface RegisteredEventHandlerEntry {\n readonly ctor: EventHandlerConstructor;\n readonly frequency: EventFrequency;\n}\n\ntype EventArtifact = string;\n\n/**\n * Scans event handler directories, attaches one client listener per registered event, and runs the\n * handlers for each fire. Interactions route through InteractionDispatcher. Multiple handlers can\n * point to one event.\n *\n * @internal\n */\nexport class EventDispatcher implements Initializeable, HmrAware {\n private readonly logger = new Logger('Events', { channel: 'events' });\n private isInitialized = false;\n\n private readonly eventMap = new Map<keyof ClientEvents, RegisteredEventHandlerEntry[]>();\n private readonly middlewares: RegisteredEventMiddleware[] = [];\n private readonly executedOnceHandlers = new Set<EventHandlerConstructor>();\n private readonly attachedEvents = new Set<keyof ClientEvents>();\n\n private readonly inFlight = new Set<Promise<void>>();\n private draining = false;\n\n // batched during bulk load. A reload reports on the hmr channel instead\n private loading = false;\n private readonly loadedHandlers: { name: string; from: string }[] = [];\n private readonly loadedMiddlewares: { name: string; from: string }[] = [];\n\n private readonly hmrHandler?: HmrModuleHandler<\n EventHandlerConstructor,\n EventMiddlewareConstructor,\n EventArtifact[]\n >;\n\n public constructor(protected core: Core) {\n const eventsDir = this.core.config.bot.events.path;\n if (!eventsDir) {\n // unreachable today, guards against a path regression\n throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, ['EventDispatcher', 'events']);\n }\n\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n\n this.hmrHandler = new HmrModuleHandler({\n handlersDir: eventsDir,\n ...(hasKeys(this.core.config.bot.events, ['middlewares']) && {\n middlewaresDir: this.core.config.bot.events.middlewares\n }),\n isHandler: this.isEventHandlerClass.bind(this),\n isMiddleware: this.isMiddlewareClass.bind(this),\n registerHandler: this.registerHandler.bind(this),\n registerMiddleware: this.registerMiddleware.bind(this),\n unregisterHandler: this.unregisterHandler.bind(this),\n unregisterMiddleware: this.unregisterMiddleware.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n\n private getArtifacts(ctor: EventHandlerConstructor): EventArtifact[] {\n const events: EventArtifact[] = [];\n for (const [event, handlers] of this.eventMap.entries()) {\n if (handlers.some((h) => h.ctor === ctor)) events.push(event);\n }\n return events;\n }\n\n public async init(): Promise<void> {\n if (this.isInitialized) {\n return;\n }\n this.isInitialized = true;\n\n const handlersDir = this.core.config.bot.events.path;\n if (!handlersDir) {\n return;\n }\n\n const middlewareDir = hasKeys(this.core.config.bot.events, ['middlewares'])\n ? this.core.config.bot.events.middlewares\n : undefined;\n\n this.loading = true;\n this.loadedHandlers.length = 0;\n this.loadedMiddlewares.length = 0;\n try {\n if (middlewareDir) await this.loadMiddlewares(middlewareDir);\n await this.loadHandlers(handlersDir);\n } finally {\n this.loading = false;\n }\n\n this.attachToClient();\n this.reportLoad();\n }\n\n private reportLoad(): void {\n const { utils } = this.logger;\n\n utils.summary(\n 'Loaded',\n { 'event handlers': this.loadedHandlers.length, middlewares: this.loadedMiddlewares.length },\n 'debug'\n );\n\n if (this.loadedMiddlewares.length > 0) {\n utils.block('Loaded event middlewares', utils.entries(this.loadedMiddlewares), 'debug');\n }\n\n const perEvent: Record<string, number> = {};\n for (const [event, handlers] of this.eventMap) perEvent[event] = handlers.length;\n\n utils.block(\n 'Loaded event handlers',\n [...utils.entries(this.loadedHandlers), ...utils.counts(perEvent)],\n 'debug'\n );\n }\n\n private async loadHandlers(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const val of Object.values(imported)) {\n if (!this.isEventHandlerClass(val)) continue;\n this.registerHandler(val, relativePath);\n this.hmrHandler?.trackHandler(fullPath, val);\n }\n });\n }\n\n private async loadMiddlewares(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const val of Object.values(imported)) {\n if (!this.isMiddlewareClass(val)) continue;\n\n this.registerMiddleware(val, relativePath);\n this.hmrHandler?.trackMiddleware(fullPath, val);\n }\n });\n }\n\n /** @internal For use in dev mode */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n await this.hmrHandler?.handle(event);\n }\n\n private unregisterHandler(handlerClass: EventHandlerConstructor, artifacts?: EventArtifact[]): void {\n const events = artifacts ?? [...this.eventMap.keys()];\n for (const event of events) {\n const handlers = this.eventMap.get(event as keyof ClientEvents);\n if (!handlers) continue;\n const index = handlers.findIndex((h) => h.ctor === handlerClass);\n if (index !== -1) {\n handlers.splice(index, 1);\n if (handlers.length === 0) {\n this.eventMap.delete(event as keyof ClientEvents);\n }\n }\n }\n // spent follows the ctor identity, so leaving executedOnceHandlers alone keeps a rollback-restored ctor spent\n }\n\n private unregisterMiddleware(middlewareCtor: EventMiddlewareConstructor): void {\n const index = this.middlewares.findIndex((entry) => entry.ctor === middlewareCtor);\n if (index !== -1) {\n this.middlewares.splice(index, 1);\n }\n }\n\n private registerMiddleware(middlewareCtor: EventMiddlewareConstructor, relativePath: string): void {\n const metadata = Reflect.getMetadata(MiddlewareMetadataKey, middlewareCtor) as MiddlewareMetadata | undefined;\n if (metadata?.type !== MiddlewareType.Event) return;\n\n const alreadyRegistered = this.middlewares.some((entry) => entry.ctor === middlewareCtor);\n if (alreadyRegistered) return;\n\n this.middlewares.push({\n ctor: middlewareCtor,\n priority: metadata.priority,\n ...(metadata.events && { events: metadata.events })\n });\n this.middlewares.sort((a, b) => a.priority - b.priority);\n\n if (this.loading) {\n this.loadedMiddlewares.push({\n name: `${middlewareCtor.name} (${metadata.priority})`,\n from: formatFilePath(relativePath)\n });\n }\n }\n\n private async runMiddlewares<KeyOfEvents extends keyof ClientEvents>(\n eventName: KeyOfEvents,\n args: ClientEvents[KeyOfEvents]\n ): Promise<boolean> {\n for (const { ctor, events } of this.middlewares) {\n if (events && !events.includes(eventName)) continue;\n\n try {\n const middleware = new ctor(args, this.core, eventName); // event name so a catchall/multi middleware can read this.eventName\n await middleware.execute();\n } catch (caught) {\n // a middleware throw stops the event for downstream handlers\n handleEventFault(caught, String(eventName), ctor.name, args, this.core);\n return false;\n }\n }\n\n return true;\n }\n\n private isEventHandlerClass(obj: unknown): obj is EventHandlerConstructor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof EventHandler && Reflect.hasMetadata(EventMetadataKey, obj);\n }\n\n private isMiddlewareClass(obj: unknown): obj is EventMiddlewareConstructor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof EventMiddleware && Reflect.hasMetadata(MiddlewareMetadataKey, obj);\n }\n\n private registerHandler(handlerClass: EventHandlerConstructor, relativePath: string): void {\n const raw = Reflect.getMetadata(EventMetadataKey, handlerClass) as unknown;\n\n const register = (key: keyof ClientEvents, frequency: EventFrequency): void => {\n let handlers = this.eventMap.get(key);\n if (!handlers) {\n handlers = [];\n this.eventMap.set(key, handlers);\n }\n\n handlers.push({\n ctor: handlerClass,\n frequency\n });\n\n // a post-init (hmr) registration can add an event with no client listener yet\n if (this.isInitialized && !this.attachedEvents.has(key)) {\n this.attachListener(key);\n }\n };\n\n if (Array.isArray(raw)) {\n for (const entry of raw as RegisterEventMetadataEntry<keyof ClientEvents>[]) {\n register(entry.event, entry.frequency);\n }\n } else {\n const names = areRoutes(raw) ? raw : typeof raw === 'string' ? [raw] : [];\n\n for (const name of names) {\n register(name as keyof ClientEvents, 'on');\n }\n }\n\n const from = formatFilePath(relativePath);\n if (this.loading) this.loadedHandlers.push({ name: handlerClass.name, from });\n }\n\n private attachToClient(): void {\n for (const [eventName] of this.eventMap) {\n this.attachListener(eventName);\n }\n }\n\n private attachListener(eventName: keyof ClientEvents): void {\n if (this.attachedEvents.has(eventName)) return;\n this.attachedEvents.add(eventName);\n\n const handlerEntries = this.eventMap.get(eventName);\n this.logger.debug(\n `Attaching ${paint.mint.bold(eventName)} to the client with ${paint.mute(handlerEntries?.length ?? 0)} handler(s)`\n );\n\n this.core.bot.client.on(eventName, (...args: ClientEvents[typeof eventName]) => {\n if (this.draining) return;\n // justified: the per-event tuple erases across the generic key, args matches eventName here\n this.core.bus[PublishDefault]('anyEvent', { name: eventName, args } as SubscriptionData<'anyEvent'>);\n const run = this.processEvent(eventName, args).catch((caught: unknown) => {\n const error = asError(caught);\n this.logger.error(`[${paint.coral.bold('UNHANDLED ERROR AT ROOT')}] ${error.name}`, error.stack);\n this.core.bus[PublishDefault]('unhandledEventError', { error });\n });\n this.inFlight.add(run);\n void run.finally(() => this.inFlight.delete(run));\n });\n }\n\n public stopAccepting(): void {\n this.draining = true;\n }\n\n public drain(timeoutMs: number): Promise<void> {\n return settleWithin(Promise.allSettled(this.inFlight), timeoutMs);\n }\n\n private async processEvent<KeyOfEvents extends keyof ClientEvents>(\n eventName: KeyOfEvents,\n args: ClientEvents[KeyOfEvents]\n ): Promise<void> {\n const handlerEntries = this.eventMap.get(eventName);\n if (!handlerEntries || handlerEntries.length === 0) return;\n\n const handlersToExecute = handlerEntries.filter(\n (entry) => entry.frequency !== 'once' || !this.executedOnceHandlers.has(entry.ctor)\n );\n\n // avoid running middlewares when every handler is a spent 'once'\n if (handlersToExecute.length === 0) return;\n\n const shouldContinue = await this.runMiddlewares(eventName, args);\n if (!shouldContinue) return;\n\n for (const entry of handlersToExecute) {\n // marked spent before running so a rethrow can't re-fire it\n if (entry.frequency === 'once') {\n // a concurrent fire could have claimed it during the runMiddlewares await\n if (this.executedOnceHandlers.has(entry.ctor)) continue;\n this.executedOnceHandlers.add(entry.ctor);\n }\n\n await this.processHandler(eventName, entry.ctor, args);\n }\n }\n\n private async processHandler<KeyOfEvents extends keyof ClientEvents>(\n eventName: KeyOfEvents,\n ctor: EventHandlerConstructor,\n args: ClientEvents[KeyOfEvents]\n ): Promise<void> {\n try {\n this.logger.debug(`Processing ${paint.mint.bold(eventName)} with ${paint.mute(ctor.name)}`);\n const handler = new ctor(args, this.core, eventName); // event name so match can route by it\n const eventCtx = eventGateContext(eventName, args, this.core);\n await runHandlerGates(ctor, eventCtx);\n await handler.execute();\n } catch (caught) {\n handleEventFault(caught, String(eventName), ctor.name, args, this.core);\n }\n }\n}\n","import { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { Repliables } from '@src/handlers/interactionTypes';\n\n/**\n * @internal Default handler for unhandled repliable interactions.\n */\nexport class UnhandledRepliable extends InteractionHandler<Repliables> {\n async execute(): Promise<void> {\n await this.reply('Feature not implemented yet.');\n }\n}\n","import { AutocompleteHandler } from '@handlers/interaction/AutocompleteHandler';\n\nimport type { SlashOptionRegistry } from '@seedcord/core';\nimport type { CacheType } from 'discord.js';\n\n/**\n * @internal Default handler for an autocomplete with no registered handler.\n */\n// eslint-disable-next-line @seedcord/interaction-handler-missing-route -- the dispatcher's autocomplete fallback, never registered\nexport class UnhandledAutocomplete extends AutocompleteHandler<keyof SlashOptionRegistry, CacheType> {\n async execute(): Promise<void> {\n await this.respond([]);\n }\n}\n","import { RESTJSONErrorCodes } from 'discord.js';\n\n/**\n * Discord API error codes that mean a dead end on an interaction, a dead token, a double ack, or a gone\n * message. Nothing to show the user and no bug to report, so the boundary's fault-card send drops them.\n *\n * @internal\n */\nexport const HARMLESS_API_CODES: ReadonlySet<number | string> = new Set([\n RESTJSONErrorCodes.UnknownInteraction,\n RESTJSONErrorCodes.InteractionHasAlreadyBeenAcknowledged,\n RESTJSONErrorCodes.UnknownMessage\n]);\n","import { Notice, Silence } from '@seedcord/core';\nimport { asError, reportedWrite } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/logger';\nimport { DiscordAPIError } from 'discord.js';\n\nimport { ReplySender } from '@bot/ReplySender';\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { extractErrorResponse } from '@miscellaneous/extractErrorResponse';\n\nimport { HARMLESS_API_CODES } from './harmlessApiCodes';\n\nimport type { Core } from '@interfaces/Core';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { ValidInteractionTypes } from '@src/handlers/interactionTypes';\nimport type { AutocompleteInteraction } from 'discord.js';\n\nconst logger = new Logger('Faults', { channel: 'errors' });\n\n/**\n * The interaction controller boundary. Sorts a throw from any handler-lifecycle phase into the right\n * user reply plus the right bus event. When a handler is built its sender is passed in, so the boundary\n * sends from the current ack state. A middleware or pre-construction throw arrives with no sender, so the\n * boundary builds one from the interaction flags.\n *\n * @internal\n */\nexport async function handleInteractionFault(\n caught: unknown,\n interaction: ValidInteractionTypes,\n core: Core,\n routeId: string,\n sender?: ReplySender\n): Promise<void> {\n if (caught instanceof Silence) {\n if (caught.reason !== undefined && (core.config.errors?.logSilences ?? true)) {\n logger.debug(`Silence: ${caught.reason}`);\n }\n return;\n }\n const error = asError(caught);\n\n // empty by default, so every api code from the handler's own work reports\n const ignore = new Set<number | string>(core.config.errors?.ignoreApiCodes ?? []);\n if (error instanceof DiscordAPIError && ignore.has(error.code)) {\n logger.debug(`swallowed api code ${error.code}`);\n return;\n }\n\n // autocomplete has no reply target, so report through extractErrorResponse and build no sender\n if (interaction.isAutocomplete()) {\n extractErrorResponse(error, core, {\n guild: interaction.guild,\n user: interaction.user,\n metadata: interaction,\n route: slashRouteOf(interaction)\n });\n // empty choices are the only legal response, and they clear the client's loading spinner\n await sendEmptyChoices(interaction, core, routeId);\n return;\n }\n\n const { response } = extractErrorResponse(error, core, {\n interaction,\n guild: interaction.guild,\n user: interaction.user,\n metadata: interaction\n });\n const liveSender = sender ?? new ReplySender(interaction, routeId, core.bus);\n await sendGuarded(liveSender, response, error instanceof Notice ? error.ephemeral : true);\n}\n\n// reports like any other write, so a faulted autocomplete still shows its discord round trip\nasync function sendEmptyChoices(interaction: AutocompleteInteraction, core: Core, routeId: string): Promise<void> {\n const telemetry = { bus: core.bus, interactionId: interaction.id };\n try {\n await reportedWrite(telemetry, routeId, 'respond', () => interaction.respond([]));\n } catch (error) {\n logger.debug(`autocomplete empty-choices send failed: ${String(error)}`);\n }\n}\n\n// the boundary's own send drops the harmless reply-token codes so a dead token never escapes it\nasync function sendGuarded(sender: ReplySender, response: ReplyResponse, ephemeral: boolean): Promise<void> {\n try {\n await sender.send(response, { ephemeral });\n } catch (error) {\n if (error instanceof DiscordAPIError && HARMLESS_API_CODES.has(error.code)) {\n logger.debug(`reply send hit harmless code ${error.code}`);\n return;\n }\n logger.error('reply send failed', error);\n }\n}\n","/* eslint-disable max-lines -- one handler method per interaction type keeps the router in one file */\nimport { DispatchContext } from '@seedcord/core';\nimport { HmrModuleHandler } from '@seedcord/core/hmr';\nimport {\n InteractionMetadataKey,\n InteractionRouteKeys,\n InteractionRoutes,\n asError,\n outcomeFor,\n queuedMsFor,\n reportDispatch,\n MiddlewareMetadataKey,\n prefixOf,\n PublishDefault,\n routeIdOf,\n runHandlerGates,\n slowGateMonitor,\n areRoutes\n} from '@seedcord/core/internal';\nimport { settleWithin } from '@seedcord/core/node/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger, paint } from '@seedcord/logger';\nimport { formatFilePath, hasKeys } from '@seedcord/utils';\nimport { traverseDirectory } from '@seedcord/utils/node';\nimport chalk from 'chalk';\nimport { Events } from 'discord.js';\nimport { Envapter } from 'envapt';\n\nimport { MiddlewareType } from '@bDecorators/Middlewares';\nimport { CONFIRM_DEF } from '@bot/confirm/reserved';\nimport { UnhandledAutocomplete, UnhandledRepliable } from '@bot/defaults';\nimport { interactionGateContext } from '@bot/gates/runGates';\nimport { handleInteractionFault } from '@bot/handleInteractionFault';\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { AutocompleteHandler, InteractionMiddleware } from '@handlers/interaction';\nimport { InteractionHandler } from '@handlers/interaction/InteractionHandler';\nimport { RepliableHandler } from '@handlers/RepliableHandler';\n\nimport type { MiddlewareMetadata } from '@bDecorators/Middlewares';\nimport type { ReplySender } from '@bot/ReplySender';\nimport type { HandlerConstructor, InteractionMiddlewareConstructor } from '@handlers/constructors';\nimport type { Core } from '@interfaces/Core';\nimport type { DispatchOutcome, Initializeable } from '@seedcord/core';\nimport type { ContextMenuLeaves } from '@seedcord/core/internal';\nimport type { CustomIdMatcher, HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { Repliables, ValidInteractionTypes } from '@src/handlers/interactionTypes';\nimport type {\n AutocompleteInteraction,\n ButtonInteraction,\n ChannelSelectMenuInteraction,\n ChatInputCommandInteraction,\n Interaction,\n MentionableSelectMenuInteraction,\n MessageContextMenuCommandInteraction,\n ModalSubmitInteraction,\n RoleSelectMenuInteraction,\n StringSelectMenuInteraction,\n UserContextMenuCommandInteraction,\n UserSelectMenuInteraction\n} from 'discord.js';\n\ninterface InteractionArtifact {\n routeType: InteractionRoutes;\n routes: string[];\n}\n\ninterface RegisteredMiddleware {\n readonly ctor: InteractionMiddlewareConstructor;\n readonly priority: number;\n}\n\ninterface DispatchedHandler {\n execute(): Promise<void>;\n}\n\n/**\n * Scans handler directories, routes each interaction to its registered handler, and runs the handler.\n * One handler per interaction.\n *\n * @internal\n */\nexport class InteractionDispatcher implements Initializeable, HmrAware {\n private readonly logger = new Logger('Interactions', { channel: 'interactions' });\n private isInitialized = false;\n\n private readonly slashMap = new Map<string, HandlerConstructor>();\n private readonly buttonMap = new Map<string, HandlerConstructor>();\n private readonly modalMap = new Map<string, HandlerConstructor>();\n private readonly stringSelectMap = new Map<string, HandlerConstructor>();\n private readonly userSelectMap = new Map<string, HandlerConstructor>();\n private readonly roleSelectMap = new Map<string, HandlerConstructor>();\n private readonly channelSelectMap = new Map<string, HandlerConstructor>();\n private readonly mentionableSelectMap = new Map<string, HandlerConstructor>();\n private readonly messageContextMenuMap = new Map<string, HandlerConstructor>();\n private readonly userContextMenuMap = new Map<string, HandlerConstructor>();\n private readonly autocompleteMap = new Map<string, HandlerConstructor>();\n\n // the duplicate-route error reports the file the existing class came from\n private readonly handlerFiles = new Map<HandlerConstructor, string>();\n\n private readonly keysToIgnore = new Set<CustomIdMatcher>();\n private readonly middlewares: RegisteredMiddleware[] = [];\n\n private readonly inFlight = new Set<Promise<void>>();\n private draining = false;\n\n // batched during bulk load. A reload reports on the hmr channel instead\n private loading = false;\n private readonly loadedHandlers: { name: string; from: string }[] = [];\n private readonly loadedMiddlewares: { name: string; from: string }[] = [];\n\n private readonly hmrHandler?: HmrModuleHandler<\n HandlerConstructor,\n InteractionMiddlewareConstructor,\n InteractionArtifact[]\n >;\n\n private readonly routeTypes: [InteractionRoutes, Map<string, HandlerConstructor>][] = [\n [InteractionRoutes.Slash, this.slashMap],\n [InteractionRoutes.Button, this.buttonMap],\n [InteractionRoutes.Modal, this.modalMap],\n [InteractionRoutes.StringMenu, this.stringSelectMap],\n [InteractionRoutes.UserMenu, this.userSelectMap],\n [InteractionRoutes.RoleMenu, this.roleSelectMap],\n [InteractionRoutes.ChannelMenu, this.channelSelectMap],\n [InteractionRoutes.MentionableMenu, this.mentionableSelectMap],\n [InteractionRoutes.MessageContextMenu, this.messageContextMenuMap],\n [InteractionRoutes.UserContextMenu, this.userContextMenuMap],\n [InteractionRoutes.Autocomplete, this.autocompleteMap]\n ];\n\n constructor(protected core: Core) {\n const ignoredKeysFromConfig = hasKeys(this.core.config.bot.interactions, ['ignoreCustomIds'])\n ? this.core.config.bot.interactions.ignoreCustomIds\n : undefined;\n if (ignoredKeysFromConfig) {\n for (const ignoredKey of ignoredKeysFromConfig) this.keysToIgnore.add(ignoredKey);\n }\n\n // the in-process getConfirmation() collector consumes these clicks, so the global router would double-ack them\n this.keysToIgnore.add(CONFIRM_DEF);\n\n const interactionsDir = this.core.config.bot.interactions.path;\n if (!interactionsDir) {\n // unreachable today, guards against a path regression\n throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, [\n 'InteractionDispatcher',\n 'interactions'\n ]);\n }\n\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n this.hmrHandler = new HmrModuleHandler({\n handlersDir: interactionsDir,\n ...(hasKeys(this.core.config.bot.interactions, ['middlewares']) &&\n this.core.config.bot.interactions.middlewares && {\n middlewaresDir: this.core.config.bot.interactions.middlewares\n }),\n isHandler: this.isHandlerClass.bind(this),\n isMiddleware: this.isMiddlewareClass.bind(this),\n registerHandler: this.registerHandler.bind(this),\n registerMiddleware: this.registerMiddleware.bind(this),\n unregisterHandler: this.unregisterHandler.bind(this),\n unregisterMiddleware: this.unregisterMiddleware.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n\n public warnUnhandledRoutes(commandLeaves: Iterable<string>): void {\n for (const route of commandLeaves) {\n if (!this.slashMap.has(route)) {\n this.logger.warn(\n `Slash route ${paint.sky.bold(route)} has no registered ${chalk.bold('@SlashRoute')} handler.`\n );\n }\n }\n }\n\n public warnUnhandledContextMenuRoutes(leaves: ContextMenuLeaves): void {\n for (const name of leaves.user) {\n if (!this.userContextMenuMap.has(name)) {\n this.logger.warn(\n `User context menu ${paint.sky.bold(name)} has no registered ${chalk.bold('@ContextMenuRoute')} handler.`\n );\n }\n }\n for (const name of leaves.message) {\n if (!this.messageContextMenuMap.has(name)) {\n this.logger.warn(\n `Message context menu ${paint.sky.bold(name)} has no registered ${chalk.bold('@ContextMenuRoute')} handler.`\n );\n }\n }\n }\n\n private getArtifacts(handlerClass: HandlerConstructor): InteractionArtifact[] {\n const artifacts: InteractionArtifact[] = [];\n for (const [routeType] of this.routeTypes) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[routeType], handlerClass);\n if (areRoutes(meta)) artifacts.push({ routeType, routes: meta });\n }\n return artifacts;\n }\n\n public async init(): Promise<void> {\n if (this.isInitialized) return;\n\n this.isInitialized = true;\n\n const handlersDir = this.core.config.bot.interactions.path;\n // unreachable, the constructor throws when the path is unset\n if (!handlersDir) return;\n\n const middlewareDir = hasKeys(this.core.config.bot.interactions, ['middlewares'])\n ? this.core.config.bot.interactions.middlewares\n : undefined;\n\n this.loading = true;\n this.loadedHandlers.length = 0;\n this.loadedMiddlewares.length = 0;\n try {\n if (middlewareDir) await this.loadMiddlewares(middlewareDir);\n await this.loadHandlers(handlersDir);\n } finally {\n this.loading = false;\n }\n\n this.attachToClient();\n this.reportLoad();\n }\n\n private reportLoad(): void {\n const { utils } = this.logger;\n\n utils.summary(\n 'Loaded',\n { 'interaction handlers': this.loadedHandlers.length, middlewares: this.loadedMiddlewares.length },\n 'debug'\n );\n\n if (this.loadedMiddlewares.length > 0) {\n utils.block('Loaded middlewares', utils.entries(this.loadedMiddlewares), 'debug');\n }\n\n utils.block(\n 'Loaded interaction handlers',\n [\n ...utils.entries(this.loadedHandlers),\n ...utils.counts({\n slash: this.slashMap.size,\n buttons: this.buttonMap.size,\n modals: this.modalMap.size,\n 'string selects': this.stringSelectMap.size,\n 'user selects': this.userSelectMap.size,\n 'role selects': this.roleSelectMap.size,\n 'channel selects': this.channelSelectMap.size,\n 'mentionable selects': this.mentionableSelectMap.size,\n 'message menus': this.messageContextMenuMap.size,\n 'user menus': this.userContextMenuMap.size,\n autocomplete: this.autocompleteMap.size\n })\n ],\n 'debug'\n );\n }\n\n private async loadHandlers(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const val of Object.values(imported)) {\n if (!this.isHandlerClass(val)) continue;\n this.registerHandler(val, relativePath);\n this.hmrHandler?.trackHandler(fullPath, val);\n }\n });\n }\n\n private async loadMiddlewares(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const val of Object.values(imported)) {\n if (!this.isMiddlewareClass(val)) continue;\n\n this.registerMiddleware(val, relativePath);\n this.hmrHandler?.trackMiddleware(fullPath, val);\n }\n });\n }\n\n private registerMiddleware(middlewareCtor: InteractionMiddlewareConstructor, relativePath: string): void {\n const metadata = Reflect.getMetadata(MiddlewareMetadataKey, middlewareCtor) as MiddlewareMetadata | undefined;\n if (metadata?.type !== MiddlewareType.Interaction) return;\n\n // same class re-registered (double import or an HMR re-scan) is idempotent, matching event middleware\n if (this.middlewares.some((entry) => entry.ctor === middlewareCtor)) return;\n\n // a different class sharing the name would run alongside the first\n if (this.middlewares.some((entry) => entry.ctor.name === middlewareCtor.name)) {\n throw new SeedcordError(SeedcordErrorCode.InteractionDuplicateMiddleware, [middlewareCtor.name]);\n }\n\n this.middlewares.push({ ctor: middlewareCtor, priority: metadata.priority });\n this.middlewares.sort((a, b) => a.priority - b.priority);\n\n if (this.loading) {\n this.loadedMiddlewares.push({\n name: `${middlewareCtor.name} (${metadata.priority})`,\n from: formatFilePath(relativePath)\n });\n }\n }\n\n private isHandlerClass(obj: unknown): obj is HandlerConstructor {\n if (typeof obj !== 'function') return false;\n return (\n (obj.prototype instanceof InteractionHandler && Reflect.hasMetadata(InteractionMetadataKey, obj)) ||\n (obj.prototype instanceof AutocompleteHandler && Reflect.hasMetadata(InteractionMetadataKey, obj))\n );\n }\n\n private isMiddlewareClass(obj: unknown): obj is InteractionMiddlewareConstructor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof InteractionMiddleware && Reflect.hasMetadata(MiddlewareMetadataKey, obj);\n }\n\n private registerHandler(handlerClass: HandlerConstructor, relativePath: string): void {\n const from = formatFilePath(relativePath);\n // a partial registration would orphan routes and break hmr rollback\n const writes: [Map<string, HandlerConstructor>, string][] = [];\n\n for (const [routeType, map] of this.routeTypes) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[routeType], handlerClass);\n if (!areRoutes(meta)) continue;\n\n for (const route of meta) {\n const existing = map.get(route);\n // a different class on the same route would silently shadow (last write wins)\n if (existing && existing !== handlerClass) {\n throw new SeedcordError(SeedcordErrorCode.InteractionDuplicateRoute, [\n `${routeType}:${route}`,\n // a stale hmr artifact list can leave a class in a route map after its entry here is gone\n `${existing.name} (${this.handlerFiles.get(existing) ?? 'unknown file'})`,\n `${handlerClass.name} (${from})`\n ]);\n }\n writes.push([map, route]);\n }\n }\n\n if (writes.length === 0) return;\n for (const [map, route] of writes) map.set(route, handlerClass);\n this.handlerFiles.set(handlerClass, from);\n\n if (this.loading) this.loadedHandlers.push({ name: handlerClass.name, from });\n }\n\n /** @internal For use in dev mode */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n await this.hmrHandler?.handle(event);\n }\n\n private unregisterHandler(handlerClass: HandlerConstructor, artifacts?: InteractionArtifact[]): void {\n this.handlerFiles.delete(handlerClass);\n if (artifacts) {\n for (const { routeType, routes } of artifacts) {\n const map = this.routeTypes.find(([type]) => type === routeType)?.[1];\n if (map) {\n routes.forEach((route) => map.delete(route));\n }\n }\n return;\n }\n\n for (const [routeType, map] of this.routeTypes) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[routeType], handlerClass);\n if (!areRoutes(meta)) continue;\n\n const routes = meta;\n routes.forEach((route) => map.delete(route));\n }\n }\n\n private unregisterMiddleware(middlewareCtor: InteractionMiddlewareConstructor): void {\n const index = this.middlewares.findIndex((entry) => entry.ctor === middlewareCtor);\n if (index !== -1) {\n this.middlewares.splice(index, 1);\n }\n }\n\n private attachToClient(): void {\n this.core.bot.client.on(Events.InteractionCreate, (interaction) => {\n if (this.draining) return;\n this.core.bus[PublishDefault]('anyInteraction', { interaction });\n const run = this.handleInteraction(interaction).catch((caught: unknown) => {\n const error = asError(caught);\n this.logger.error(`[${paint.coral.bold('UNHANDLED ERROR AT ROOT')}] ${error.name}`, error.stack);\n this.core.bus[PublishDefault]('unhandledInteractionError', { error });\n });\n this.inFlight.add(run);\n void run.finally(() => this.inFlight.delete(run));\n });\n }\n\n public stopAccepting(): void {\n this.draining = true;\n }\n\n public drain(timeoutMs: number): Promise<void> {\n return settleWithin(Promise.allSettled(this.inFlight), timeoutMs);\n }\n\n private async handleCustomIdInteraction<TInteraction extends Interaction & { customId: string }>(\n interaction: TInteraction,\n kind: InteractionRoutes,\n getMap: () => Map<string, HandlerConstructor>\n ): Promise<void> {\n if ([...this.keysToIgnore].some((matcher) => matcher.owns(interaction.customId))) return;\n\n // route by the stable prefix (the routeKey minus its shape hash) so an older-shape wire still\n // reaches its handler, where reading this.params throws StaleCustomId and the boundary replies\n const prefix = prefixOf(interaction.customId);\n // an empty prefix matches no route, so the unhandled default replies to it the way http does\n if (!prefix)\n this.logger.warn(`${paint.sky.bold(kind)} has invalid customId: ${paint.mute(interaction.customId)}`);\n\n await this.processInteraction(\n interaction,\n kind,\n () => prefix,\n (key) => getMap().get(key)\n );\n }\n\n private async processInteraction<TInteraction extends Interaction>(\n interaction: TInteraction,\n kind: InteractionRoutes,\n extractKey: (i: TInteraction) => string,\n getHandler: (key: string) => HandlerConstructor | undefined,\n fallback: HandlerConstructor = UnhandledRepliable\n ): Promise<void> {\n const key = extractKey(interaction);\n const startedAt = performance.now();\n // read here, since a read at publish time would count the handler run into the queue too\n const queuedMs = queuedMsFor(interaction.id);\n const matched = getHandler(key);\n\n // the handler's own routeId replaces this once the dispatch context is built, and the closure\n // below reads whichever one is current when it publishes. an empty key means a customId\n // seedcord never minted, since a minted routeKey always outlives its 3-char hash\n let routeId = `${kind}:${key || 'unrouted'}`;\n // one report per dispatch, since a throw while answering a refusal reaches the catch and answers again\n let reported = false;\n const report = (outcome: DispatchOutcome): void => {\n if (reported) return;\n reported = true;\n reportDispatch(this.core.bus, {\n routeId,\n interactionId: interaction.id,\n kind,\n outcome,\n startedAt,\n fallback: !matched,\n queuedMs\n });\n };\n\n // declared outside the try so the fault boundary replies through the handler's exact ack state\n let sender: ReplySender | undefined;\n try {\n if (!interaction.isAutocomplete()) await this.runMiddlewares(interaction as Repliables);\n\n const HandlerCtor = matched ?? fallback;\n const dispatch = new DispatchContext(routeIdOf(HandlerCtor) ?? routeId);\n routeId = dispatch.routeId ?? routeId;\n const handler = this.buildHandler(HandlerCtor, interaction as Repliables, dispatch, key, !matched);\n if (handler instanceof RepliableHandler) sender = handler.getSender();\n // @Gated rejects autocomplete at compile time, since it has no reply target. This is the runtime backstop\n const refusal = interaction.isAutocomplete()\n ? null\n : await this.gateRefusal(HandlerCtor, interaction as Repliables, dispatch.routeId);\n if (refusal) {\n await this.answer(refusal.caught, interaction as ValidInteractionTypes, routeId, sender, report);\n return;\n }\n await handler.execute();\n report('handled');\n } catch (caught) {\n await this.answer(caught, interaction as ValidInteractionTypes, routeId, sender, report);\n }\n }\n\n // reports in a finally, so a throw from the boundary still publishes\n private async answer(\n caught: unknown,\n interaction: ValidInteractionTypes,\n routeId: string,\n sender: ReplySender | undefined,\n report: (outcome: DispatchOutcome) => void\n ): Promise<void> {\n try {\n await handleInteractionFault(caught, interaction, this.core, routeId, sender);\n } finally {\n report(outcomeFor(caught));\n }\n }\n\n private buildHandler(\n HandlerCtor: HandlerConstructor,\n interaction: Repliables,\n dispatch: DispatchContext,\n key: string,\n isFallback: boolean\n ): DispatchedHandler {\n if (isFallback) {\n this.logger.warn(`No handler found for key ${paint.sky.bold(key)}. Falling back to ${HandlerCtor.name}.`);\n }\n this.logger.debug(`Processing ${paint.mint.bold(key)} with ${paint.mute(HandlerCtor.name)}`);\n // @ts-expect-error TS can't infer the type of interaction here\n return new HandlerCtor(interaction, this.core, dispatch);\n }\n\n private async runMiddlewares(interaction: Repliables): Promise<void> {\n for (const { ctor } of this.middlewares) {\n const middleware = new ctor(interaction, this.core);\n await middleware.execute();\n }\n }\n\n // null when the gates passed. the caller answers the refusal, so one code path reports and replies\n private async gateRefusal(\n HandlerCtor: HandlerConstructor,\n interaction: Repliables,\n routeId: string | null\n ): Promise<{ caught: unknown } | null> {\n const monitor = slowGateMonitor();\n try {\n await runHandlerGates(\n HandlerCtor,\n interactionGateContext(interaction, this.core),\n routeId ?? undefined,\n monitor?.observe\n );\n return null;\n } catch (caught) {\n return { caught };\n } finally {\n // a refusing gate spent budget too\n monitor?.report(routeId);\n }\n }\n\n private async handleInteraction(interaction: Interaction): Promise<void> {\n switch (true) {\n case interaction.isChatInputCommand(): {\n await this.handleSlashCommand(interaction);\n break;\n }\n case interaction.isButton(): {\n await this.handleButton(interaction);\n break;\n }\n case interaction.isModalSubmit(): {\n await this.handleModal(interaction);\n break;\n }\n case interaction.isStringSelectMenu(): {\n await this.handleStringSelectMenu(interaction);\n break;\n }\n case interaction.isUserSelectMenu(): {\n await this.handleUserSelectMenu(interaction);\n break;\n }\n case interaction.isRoleSelectMenu(): {\n await this.handleRoleSelectMenu(interaction);\n break;\n }\n case interaction.isChannelSelectMenu(): {\n await this.handleChannelSelectMenu(interaction);\n break;\n }\n case interaction.isMentionableSelectMenu(): {\n await this.handleMentionableSelectMenu(interaction);\n break;\n }\n case interaction.isMessageContextMenuCommand(): {\n await this.handleMessageContextMenu(interaction);\n break;\n }\n case interaction.isUserContextMenuCommand(): {\n await this.handleUserContextMenu(interaction);\n break;\n }\n case interaction.isAutocomplete(): {\n await this.handleAutocomplete(interaction);\n break;\n }\n default: {\n this.logger.warn(`Unhandled interaction type: ${interaction.type}`);\n break;\n }\n }\n }\n\n private async handleSlashCommand(interaction: ChatInputCommandInteraction): Promise<void> {\n const route = slashRouteOf(interaction);\n await this.processInteraction(\n interaction,\n InteractionRoutes.Slash,\n () => route,\n (key) => this.slashMap.get(key)\n );\n }\n\n private async handleButton(interaction: ButtonInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.Button, () => this.buttonMap);\n }\n\n private async handleModal(interaction: ModalSubmitInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.Modal, () => this.modalMap);\n }\n\n private async handleStringSelectMenu(interaction: StringSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.StringMenu, () => this.stringSelectMap);\n }\n\n private async handleUserSelectMenu(interaction: UserSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.UserMenu, () => this.userSelectMap);\n }\n\n private async handleRoleSelectMenu(interaction: RoleSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.RoleMenu, () => this.roleSelectMap);\n }\n\n private async handleChannelSelectMenu(interaction: ChannelSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, InteractionRoutes.ChannelMenu, () => this.channelSelectMap);\n }\n\n private async handleMentionableSelectMenu(interaction: MentionableSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(\n interaction,\n InteractionRoutes.MentionableMenu,\n () => this.mentionableSelectMap\n );\n }\n\n private async handleMessageContextMenu(interaction: MessageContextMenuCommandInteraction): Promise<void> {\n await this.processInteraction(\n interaction,\n InteractionRoutes.MessageContextMenu,\n () => interaction.commandName,\n (key) => this.messageContextMenuMap.get(key)\n );\n }\n\n private async handleUserContextMenu(interaction: UserContextMenuCommandInteraction): Promise<void> {\n await this.processInteraction(\n interaction,\n InteractionRoutes.UserContextMenu,\n () => interaction.commandName,\n (key) => this.userContextMenuMap.get(key)\n );\n }\n\n private async handleAutocomplete(interaction: AutocompleteInteraction): Promise<void> {\n const route = slashRouteOf(interaction);\n await this.processInteraction(\n interaction,\n InteractionRoutes.Autocomplete,\n () => route,\n (key) => this.autocompleteMap.get(key),\n UnhandledAutocomplete\n );\n }\n}\n","import { CommandInjector } from '@seedcord/core/internal';\nimport { CommandRegistry, ShutdownPhase } from '@seedcord/core/node/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, validateDiscordToken } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\nimport chalk from 'chalk';\nimport { Client, Events } from 'discord.js';\nimport { Envapt } from 'envapt/legacy';\n\nimport { EventDispatcher } from '@bControllers/EventDispatcher';\nimport { InteractionDispatcher } from '@bControllers/InteractionDispatcher';\n\nimport { EmojiInjector } from './injectors/EmojiInjector';\n\nimport type { Core } from '@interfaces/Core';\nimport type { Initializeable } from '@seedcord/core';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\n\nconst DISPATCH_DRAIN_TIMEOUT_MS = 5000;\n// headroom so each dispatcher's own timer settles before the outer task timeout fires\nconst DRAIN_HEADROOM_MS = 1000;\nconst DRAIN_TASK_TIMEOUT_MS = DISPATCH_DRAIN_TIMEOUT_MS + DRAIN_HEADROOM_MS;\nconst UNBIND_TIMEOUT_MS = 2000;\nconst LOGOUT_TIMEOUT_MS = 2000;\n\n/**\n * The Discord client and its controllers. Access it through `core.bot`.\n */\nexport class Bot implements Initializeable, HmrAware {\n @Envapt<string>('DISCORD_BOT_TOKEN', {\n converter: (raw) => validateDiscordToken(raw)\n })\n declare public readonly botToken: string;\n\n /** @internal */\n public readonly logger = new Logger('Bot', { channel: 'bot' });\n private isInitialized = false;\n\n private readonly _client: Client;\n private readonly interactions?: InteractionDispatcher;\n private readonly events?: EventDispatcher;\n private readonly emojiInjector: EmojiInjector;\n private readonly commandRegistry?: CommandRegistry;\n\n /** @internal */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n if (this.interactions) await this.interactions.onHmr(event);\n if (this.events) await this.events.onHmr(event);\n if (this.commandRegistry) await this.commandRegistry.onHmr(event);\n }\n\n /** @internal */\n constructor(core: Core) {\n this._client = new Client(core.config.bot.clientOptions);\n\n if (core.config.bot.interactions.path) {\n this.interactions = new InteractionDispatcher(core);\n }\n if (core.config.bot.events.path) {\n this.events = new EventDispatcher(core);\n }\n\n const commandsDir = core.config.bot.commands.path;\n if (commandsDir) {\n const injector = new CommandInjector();\n // onDeployed only fires at deploy time, so registry is assigned by then\n const registry: CommandRegistry = new CommandRegistry({\n dir: commandsDir,\n // core.rest is this same object, assigned only after this constructor returns\n rest: this._client.rest,\n applicationId: () => this.applicationId(),\n onDeployed: (result) => {\n injector.inject(result, registry.allCommands());\n }\n });\n this.commandRegistry = registry;\n }\n\n this.emojiInjector = new EmojiInjector(core);\n\n this.registerShutdownTasks(core);\n }\n\n private applicationId(): string {\n const { application } = this._client;\n if (!application) throw new SeedcordError(SeedcordErrorCode.CoreApplicationUnavailable);\n return application.id;\n }\n\n private registerShutdownTasks(core: Core): void {\n core.shutdown.addTask(\n ShutdownPhase.Unbind,\n 'stop-dispatch',\n () => {\n this.stopAccepting();\n return Promise.resolve();\n },\n UNBIND_TIMEOUT_MS\n );\n core.shutdown.addTask(ShutdownPhase.Drain, 'drain-dispatch', () => this.drain(), DRAIN_TASK_TIMEOUT_MS);\n core.shutdown.addTask(ShutdownPhase.Logout, 'stop-bot', async () => await this.stop(), LOGOUT_TIMEOUT_MS);\n }\n\n private stopAccepting(): void {\n this.interactions?.stopAccepting();\n this.events?.stopAccepting();\n }\n\n private async drain(): Promise<void> {\n // allSettled so a rejecting drain does not abort the other dispatcher's drain\n await Promise.allSettled([\n this.interactions?.drain(DISPATCH_DRAIN_TIMEOUT_MS),\n this.events?.drain(DISPATCH_DRAIN_TIMEOUT_MS)\n ]);\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialized) {\n return;\n }\n this.isInitialized = true;\n\n const token = this.botToken;\n\n if (this.interactions) await this.interactions.init();\n if (this.events) await this.events.init();\n\n await this.login(token);\n\n await this.emojiInjector.init();\n\n if (this.commandRegistry) {\n await this.commandRegistry.init();\n await this.commandRegistry.setCommands();\n this.interactions?.warnUnhandledRoutes(this.commandRegistry.routeLeaves());\n this.interactions?.warnUnhandledContextMenuRoutes(this.commandRegistry.contextMenuLeaves());\n }\n }\n\n /** @internal */\n public async stop(): Promise<void> {\n this._client.removeAllListeners();\n\n await this.logout();\n }\n\n private async login(token: string): Promise<Bot> {\n const ready: PromiseWithResolvers<void> = Promise.withResolvers();\n this._client.once(Events.ClientReady, () => ready.resolve());\n void this._client.login(token);\n await ready.promise;\n this.logger.info(`Logged in as ${chalk.bold.magenta(this._client.user?.username)}!`);\n return this;\n }\n\n private async logout(): Promise<void> {\n await this._client.destroy();\n this.logger.info(chalk.bold.red('Logged out of Discord!'));\n }\n\n public get client(): Client {\n return this._client;\n }\n}\n","/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n","import { Bus } from '@seedcord/core';\nimport { HmrManager, setBotColor } from '@seedcord/core/internal';\nimport {\n HealthCheck,\n CoordinatedShutdown,\n CoordinatedStartup,\n StartupPhase,\n Pluggable,\n SubscriberLoader\n} from '@seedcord/core/node/internal';\nimport { LoggerChannelRegistry } from '@seedcord/logger';\nimport { installNodeDefaults } from '@seedcord/logger/node';\nimport { MemoryRateLimiter } from '@seedcord/rate-limiter';\nimport { SeedcordBrand } from '@seedcord/types/internal';\nimport { Envapter } from 'envapt';\n\nimport { Bot } from './bot/Bot';\nimport { version as packageVersion } from './version';\n\nimport type { GatewayConfig } from './interfaces/Config';\nimport type { Core } from './interfaces/Core';\nimport type { REST } from '@discordjs/rest';\nimport type { IRateLimiter } from '@seedcord/types';\nimport type { SeedcordInstance } from '@seedcord/types/internal';\n\n/**\n * The gateway bot host. Opens a discord.js gateway session, discovers handlers, and runs\n * coordinated startup and shutdown. Attach plugins with `attach()`.\n */\nexport class Seedcord extends Pluggable<'gateway', 'server'> implements Core, SeedcordInstance {\n // the CLI reads these to detect and augment the instance\n /** @internal */\n public readonly [SeedcordBrand] = true;\n /** @internal */\n public readonly augmentTarget = '@seedcord/gateway';\n /** @internal */\n public readonly version: string = packageVersion;\n\n private readonly healthCheck?: HealthCheck | undefined;\n private readonly hmrManager: HmrManager;\n\n /** @see {@link Bus} */\n public readonly bus: Bus;\n\n private readonly subscribers: SubscriberLoader;\n\n /** @see {@link Bot} */\n public readonly bot: Bot;\n\n /** The discord.js client's REST client. Its token is set during the Login phase. */\n public readonly rest: REST;\n\n /** @see {@link IRateLimiter} */\n public readonly rateLimiter: IRateLimiter;\n\n /**\n * @param config - Bot configuration including paths and Discord client options\n * @throws A **SeedcordError** When attempting to create multiple instances (singleton)\n */\n constructor(public readonly config: GatewayConfig) {\n super(new CoordinatedShutdown(), new CoordinatedStartup());\n\n installNodeDefaults(config.logger);\n setBotColor(config.botColor);\n\n this.hmrManager = new HmrManager();\n this.hmrManager.init();\n this.bus = new Bus(this);\n this.subscribers = new SubscriberLoader(this.bus, config.subscribers.path);\n this.bot = new Bot(this);\n this.rest = this.bot.client.rest;\n this.rateLimiter = config.store ?? new MemoryRateLimiter();\n this.healthCheck = HealthCheck.fromOption(this.shutdown, config.healthCheck);\n\n this.registerStartupTasks();\n }\n\n /** The bot's discord username, populated after login. */\n public get username(): string | undefined {\n return this.bot.client.user?.username;\n }\n\n protected static override reset(): void {\n super.reset();\n // reset() would drop the dev TUI's log sink\n LoggerChannelRegistry.instance.configure({});\n }\n\n private registerStartupTasks(): void {\n if (Envapter.isDevelopment || Envapter.isTest) this.registerHmrAwareModules();\n\n this.startup.addTask(StartupPhase.Configuration, 'bus-initialization', async () => {\n this.bus.logger.utils.initialization('Subscribers', 'start');\n await this.subscribers.init();\n this.bus.logger.utils.initialization('Subscribers', 'end');\n });\n\n this.startup.addTask(StartupPhase.Login, 'bot-initialization', async () => {\n this.bot.logger.utils.initialization('Bot', 'start');\n await this.bot.init();\n this.bot.logger.utils.initialization('Bot', 'end');\n });\n\n const { healthCheck } = this;\n if (healthCheck) {\n this.startup.addTask(StartupPhase.Ready, 'health-check', async () => {\n healthCheck.logger.utils.initialization('HealthCheck', 'start');\n await healthCheck.init();\n healthCheck.logger.utils.initialization('HealthCheck', 'end');\n });\n }\n }\n\n /**\n * Starts the bot and runs all initialization tasks\n *\n * @returns This Seedcord instance when initialized\n */\n public async start(): Promise<this> {\n try {\n await super.init();\n } catch (caught) {\n // shutdown releases any resource opened before the failure, then rethrow\n await this.shutdown.run(1, false);\n Seedcord.reset();\n throw caught;\n }\n return this;\n }\n\n private registerHmrAwareModules(): void {\n this.startup.addTask(StartupPhase.Configuration, 'hmr-registration', async () => {\n this.hmrManager.register(this.bot);\n this.hmrManager.register(this.subscribers);\n for (const plugin of this.plugins) {\n this.hmrManager.register(plugin);\n }\n await Promise.resolve();\n });\n }\n}\n"],"mappings":"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"}