@seedcord/gateway 0.0.1 → 0.1.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/index.cjs +4023 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2528 -2
- package/dist/index.mjs +3914 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +94 -52
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":";;;;AACA,MAAa"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["EventMetadataKey","GatedMetadataKey","InteractionRoutes","ApplicationCommandType","ComponentDefsKey","InteractionRouteKeys","InteractionMetadataKey","SeedcordTypeError","SeedcordErrorCode","SeedcordError","MiddlewareMetadataKey","Silence","Role","TextChannel","GuildMember","GateNotice","Notice","NoticeCard","PermissionFlagsBits","Role","GuildMember","Guild","NotInGuild","Logger","SeedcordError","SeedcordErrorCode","Logger","SlashCommandBuilder","TextChannel","DiscordAPIError","RESTJSONErrorCodes","Guild","Logger","SeedcordError","SeedcordErrorCode","Role","PermissionFlagsBits","DiscordAPIError","RESTJSONErrorCodes","Guild","DiscordAPIError","RESTJSONErrorCodes","DiscordAPIError","RESTJSONErrorCodes","RESTJSONErrorCodes","MessageFlags","Logger","MessageFlags","DiscordAPIError","CustomId","RowComponent","ButtonBuilder","ButtonStyle","BuilderComponent","TextDisplayBuilder","ComponentType","StrictEventEmitter","SeedcordError","SeedcordErrorCode","Logger","SeedcordError","SeedcordErrorCode","SeedcordError","SeedcordErrorCode","ComponentDefsKey","SeedcordError","SeedcordErrorCode","SeedcordError","SeedcordErrorCode","SeedcordError","SeedcordErrorCode","ButtonBuilder","PAGE_MAX","ButtonStyle","SeedcordRangeError","SeedcordErrorCode","SeedcordTypeError","ActionRowBuilder","BuilderComponent","TextDisplayBuilder","SeedcordRangeError","SeedcordErrorCode","Logger","SubscribeMetadataKey","ContextMenuCommandBuilder","ApplicationCommandType","SlashCommandBuilder","Logger","Collection","SeedcordError","SeedcordErrorCode","Envapter","BuilderComponent","CommandMetadataKey","SlashCommandBuilder","Message","GuildMember","User","GuildMember","logger","Logger","crypto","Notice","Fault","DiscordAPIError","logger","Logger","Silence","DiscordAPIError","Notice","Logger","SeedcordError","SeedcordErrorCode","Envapter","MiddlewareMetadataKey","EventMetadataKey","MessageFlags","Logger","Silence","DiscordAPIError","Notice","Logger","InteractionRoutes","SeedcordError","SeedcordErrorCode","Envapter","InteractionRouteKeys","MiddlewareMetadataKey","InteractionMetadataKey","Events","Logger","Client","ShutdownPhase","Logger","Envapter","AttachmentBuilder","BuilderComponent","SeparatorSpacingSize","webhookUrlValidator","SeedcordError","SeedcordErrorCode","WebhookClient","BuilderComponent","SeedcordError","SeedcordErrorCode","WebhookClient","BuilderComponent","DiscordAPIError","SnowflakeUtil","Logger","Envapter","SubscribeMetadataKey","SeedcordBrand","packageVersion","SeedcordError","SeedcordErrorCode","CoordinatedShutdown","CoordinatedStartup","MemoryRateLimiter","HealthCheck","Envapter","StartupPhase"],"sources":["../src/bot/decorators/Events.ts","../src/bot/decorators/Gated.ts","../src/miscellaneous/areRoutes.ts","../src/bot/decorators/Interactions.ts","../src/bot/decorators/Middlewares.ts","../src/bot/gates/catalog/IgnoreBots.ts","../src/bot/notices/utils.ts","../src/bot/notices/index.ts","../src/bot/gates/catalog/Nsfw.ts","../src/bot/utilities/permissions/checkPermissions.ts","../src/bot/gates/catalog/permissions.ts","../src/bot/injectors/EmojiInjector.ts","../src/bot/injectors/CommandMentionInjector.ts","../src/bot/utilities/channels/fetchText.ts","../src/bot/utilities/permissions/checkBotPermissions.ts","../src/bot/utilities/roles/getBotRole.ts","../src/bot/utilities/permissions/hasPermsToAssign.ts","../src/bot/utilities/roles/fetchRole.ts","../src/bot/utilities/users/fetchGuildMember.ts","../src/bot/utilities/users/fetchManyGuildMembers.ts","../src/bot/utilities/users/fetchUser.ts","../src/bot/utilities/users/fetchManyUsers.ts","../src/bot/utilities/users/updateMemberRoles.ts","../src/bot/harmlessApiCodes.ts","../src/miscellaneous/flagsFor.ts","../src/bot/ReplySender.ts","../src/bot/confirm/reserved.ts","../src/bot/confirm/getConfirmation.ts","../src/hmr/devChannel.ts","../src/interfaces/Plugin.ts","../src/handlers/BaseHandler.ts","../src/handlers/interaction/InteractionMiddleware.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/controls.ts","../src/pagination/render.ts","../src/pagination/Paginator.ts","../src/pagination/sources.ts","../src/subscribers/Subscriber.ts","../src/subscribers/decorators/Subscribe.ts","../src/subscribers/bases/WebhookLog.ts","../src/hmr/HmrModuleHandler.ts","../src/bot/utilities/miscellaneous/contextMenuLeaves.ts","../src/bot/utilities/miscellaneous/slashRouteLeaves.ts","../src/bot/controllers/CommandRegistry.ts","../src/miscellaneous/deriveEventActor.ts","../src/bot/gates/runGates.ts","../src/miscellaneous/FaultThrottle.ts","../src/miscellaneous/extractErrorResponse.ts","../src/bot/handleEventFault.ts","../src/bot/controllers/EventDispatcher.ts","../src/bot/defaults/UnhandledEvent.ts","../src/bot/handleInteractionFault.ts","../src/bot/controllers/InteractionDispatcher.ts","../src/bot/Bot.ts","../src/hmr/HmrManager.ts","../src/subscribers/bases/webhookHelpers.ts","../src/subscribers/default/HandledException.ts","../src/subscribers/default/UnknownException.ts","../src/subscribers/Bus.ts","../src/version.ts","../src/Seedcord.ts"],"sourcesContent":["import { EventMetadataKey } from '@seedcord/core/internal';\n\nimport type { ValidNonInteractionKeys } from '@handlers/BaseHandler';\nimport type { EventHandler } from '@handlers/event';\nimport type { EventFrequency } from '@miscellaneous/types';\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","/**\n * Checks if the provided value is an array of strings.\n *\n * @internal\n */\nexport function areRoutes(routes: unknown): routes is string[] {\n return Array.isArray(routes) && routes.every((r) => typeof r === 'string');\n}\n","import {\n ComponentDefsKey,\n InteractionMetadataKey,\n InteractionRouteKeys,\n InteractionRoutes\n} from '@seedcord/core/internal';\nimport { ApplicationCommandType } from 'discord.js';\n\nimport { areRoutes } from '@miscellaneous/areRoutes';\n\nimport type { BaseHandler, Repliables } from '@handlers/BaseHandler';\nimport type { HandlerConstructor } from '@handlers/constructors';\nimport type { AutocompleteHandler } from '@handlers/interaction/AutocompleteHandler';\nimport type { ContextMenuHandler } from '@handlers/interaction/ContextMenuHandler';\nimport type { InteractionHandler } from '@handlers/interaction/InteractionHandler';\nimport type { SlashHandler } from '@handlers/interaction/SlashHandler';\nimport type { MessageContextMenuRegistry, SlashOptionRegistry, UserContextMenuRegistry } from '@seedcord/core';\nimport type { HasComponentDefs, AnyCustomId } from '@seedcord/core/internal';\nimport type {\n AutocompleteInteraction,\n ButtonInteraction,\n CacheType,\n ChannelSelectMenuInteraction,\n MentionableSelectMenuInteraction,\n ModalSubmitInteraction,\n RoleSelectMenuInteraction,\n StringSelectMenuInteraction,\n UserSelectMenuInteraction\n} from 'discord.js';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Types of select menus supported for routing\n */\nexport enum SelectMenuKind {\n String = 'string',\n User = 'user',\n Role = 'role',\n Channel = 'channel',\n Mentionable = 'mentionable'\n}\n\n/** @internal */\ntype HandlerEventType<TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> =\n InstanceType<TCtor> extends InteractionHandler<infer TEvent> ? TEvent : never;\n\n/**\n * Compile-time assertion that the required event type(s) `TRequired` are included in the handler event union.\n *\n * @internal\n */\ntype AssertHandles<TRequired, TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> =\n Extract<HandlerEventType<TCtor>, TRequired> extends never\n ? Constructor<['Handler event generic must include', TRequired]>\n : TCtor;\n\n/**\n * The slash route(s) a handler serves, read off its `SlashHandler` generic.\n *\n * @internal\n */\ntype SlashRouteOf<TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> =\n InstanceType<TCtor> extends SlashHandler<infer Route, CacheType> ? Route : never;\n\n/**\n * On a route/generic mismatch, resolves to a non-constructor type so applying the decorator is a TS1238.\n *\n * @internal\n */\ntype AssertSlashRoute<Route extends string, TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> = [\n Route\n] extends [SlashRouteOf<TCtor>]\n ? [SlashRouteOf<TCtor>] extends [Route]\n ? TCtor\n : Constructor<['SlashHandler declares a route the SlashRoute decorator does not list', SlashRouteOf<TCtor>]>\n : Constructor<['SlashRoute does not match the SlashHandler generic', Route]>;\n\n/**\n * Routes one or more slash commands to a {@link SlashHandler}.\n *\n * Pass the same route string(s) as the handler's generic. A single command reads `this.options`, several\n * commands branch with `this.match`. The decorator routes and the generic must match exactly, so listing\n * fewer or more than the handler declares is a compile error. Subcommands use a slash path.\n *\n * @param routes - The route string(s) this handler serves, e.g. `'ban'`, `'ban', 'kick'`, or `'demo/setup'`.\n * @decorator\n * @example\n * ```ts\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * const target = this.options.getUser('target');\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * \\@SlashRoute('ban', 'kick')\n * class ModerationHandler extends SlashHandler<'ban' | 'kick'> {\n * async execute() {\n * await this.match({ ban: (o) => o.getUser('target'), kick: (o) => o.getUser('member') });\n * }\n * }\n * ```\n */\nexport function SlashRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends new (...args: any[]) => InteractionHandler<Repliables>>(\n constructor: AssertSlashRoute<Route, TCtor>\n ): void {\n // justified: AssertSlashRoute has already narrowed the ctor, this erases it to the metadata-store shape.\n storeMetadata(InteractionRoutes.Slash, routes, constructor as HandlerConstructor);\n };\n}\n\n/**\n * Routes button interactions to handler classes.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Passing different definitions to the decorator and the generic is a compile error. Routing\n * matches the stable prefix, so a wire minted from an older shape still reaches the handler, where\n * reading this.params throws StaleCustomId and the controller boundary turns it into a reply.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n */\nexport function ButtonRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends new (...args: any[]) => InteractionHandler<Repliables> & HasComponentDefs<Defs>>(\n constructor: AssertHandles<ButtonInteraction, TCtor>\n ): void {\n // justified: AssertHandles has already narrowed the ctor, this erases it to the metadata-store shape.\n storeComponentRoute(InteractionRoutes.Button, defs, constructor as HandlerConstructor);\n };\n}\n\n/**\n * Routes modal submissions to handler classes.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Passing different definitions to the decorator and the generic is a compile error. Routing\n * matches the stable prefix, so an older-shape wire still reaches the handler and throws StaleCustomId\n * on read, the same as a button route.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n */\nexport function ModalRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends new (...args: any[]) => InteractionHandler<Repliables> & HasComponentDefs<Defs>>(\n constructor: AssertHandles<ModalSubmitInteraction, TCtor>\n ): void {\n // justified: AssertHandles has already narrowed the ctor, this erases it to the metadata-store shape.\n storeComponentRoute(InteractionRoutes.Modal, defs, constructor as HandlerConstructor);\n };\n}\n\n/** The context-menu command names valid for a kind, read off the matching registry. @internal */\ntype NamesFor<Kind extends ApplicationCommandType.User | ApplicationCommandType.Message> =\n Kind extends ApplicationCommandType.User ? keyof UserContextMenuRegistry : keyof MessageContextMenuRegistry;\n\n/**\n * The context-menu kind a handler serves, read off its event's `commandType` discriminant. Direct\n * inference from the `ContextMenuHandler` generic widens the kind to the whole union because the handler's\n * conditional members blur it, so this uses the event literal to keep it narrow.\n *\n * @internal\n */\ntype ContextMenuKindOf<TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> =\n InstanceType<TCtor> extends ContextMenuHandler<infer Kind, CacheType>\n ? [Kind] extends [ApplicationCommandType.User | ApplicationCommandType.Message]\n ? HandlerEventType<TCtor> extends { commandType: infer K }\n ? Extract<K, ApplicationCommandType.User | ApplicationCommandType.Message>\n : never\n : never\n : never;\n\n/**\n * On a kind mismatch between the decorator and the handler generic, resolves to a non-constructor type so\n * applying the decorator is a TS1238. Cross-checks both directions, mirroring {@link AssertSlashRoute}.\n *\n * @internal\n */\ntype AssertContextMenuRoute<\n Kind extends ApplicationCommandType.User | ApplicationCommandType.Message,\n TCtor extends new (...args: any[]) => InteractionHandler<Repliables>\n> = [Kind] extends [ContextMenuKindOf<TCtor>]\n ? [ContextMenuKindOf<TCtor>] extends [Kind]\n ? TCtor\n : Constructor<\n [\n 'ContextMenuHandler declares a kind the ContextMenuRoute decorator does not match',\n ContextMenuKindOf<TCtor>\n ]\n >\n : Constructor<['ContextMenuRoute does not match the ContextMenuHandler generic', Kind]>;\n\n/**\n * Routes one or more context-menu commands to a {@link ContextMenuHandler}.\n *\n * Pass the kind (`ApplicationCommandType.User` or `ApplicationCommandType.Message`) and the command name(s),\n * each checked against that kind's registry, so a typo is a compile error. The same kind must sit on the\n * handler's generic, cross-checked both directions. Context menus carry no options, so a multi-name handler\n * reads `this.target` uniformly with no branch.\n *\n * @param kind - The context-menu kind, `ApplicationCommandType.User` or `ApplicationCommandType.Message`.\n * @param names - The command name(s) this handler serves, keyed off the matching registry.\n * @decorator\n * @example\n * ```ts\n * \\@ContextMenuRoute(ApplicationCommandType.User, 'View Profile')\n * class ViewProfile extends ContextMenuHandler<ApplicationCommandType.User> {\n * async execute() {\n * const user = this.target;\n * }\n * }\n * ```\n */\nexport function ContextMenuRoute<const Kind extends ApplicationCommandType.User | ApplicationCommandType.Message>(\n kind: Kind,\n ...names: NamesFor<Kind>[]\n) {\n return function <TCtor extends new (...args: any[]) => InteractionHandler<Repliables>>(\n constructor: AssertContextMenuRoute<Kind, TCtor>\n ): void {\n const routeType =\n kind === ApplicationCommandType.User\n ? InteractionRoutes.UserContextMenu\n : InteractionRoutes.MessageContextMenu;\n // justified: AssertContextMenuRoute has already narrowed the ctor, this erases it to the metadata-store shape.\n storeMetadata(routeType, names, constructor as HandlerConstructor);\n };\n}\n\n/**\n * The command route(s) an autocomplete handler serves, read off its `AutocompleteHandler` generic.\n *\n * @internal\n */\ntype AutocompleteRouteOf<TCtor extends new (...args: any[]) => BaseHandler<AutocompleteInteraction<CacheType>>> =\n InstanceType<TCtor> extends AutocompleteHandler<infer Route, CacheType> ? Route : never;\n\n/**\n * On a route/generic mismatch, resolves to a non-constructor type so applying the decorator is a TS1238.\n *\n * @internal\n */\ntype AssertAutocompleteRoute<\n Route extends keyof SlashOptionRegistry,\n TCtor extends new (...args: any[]) => BaseHandler<AutocompleteInteraction<CacheType>>\n> = [Route] extends [AutocompleteRouteOf<TCtor>]\n ? [AutocompleteRouteOf<TCtor>] extends [Route]\n ? TCtor\n : Constructor<\n [\n 'AutocompleteHandler declares a command the AutocompleteRoute decorator does not list',\n AutocompleteRouteOf<TCtor>\n ]\n >\n : Constructor<['AutocompleteRoute does not match the AutocompleteHandler generic', Route]>;\n\n/**\n * Routes one or more commands' autocomplete to an {@link AutocompleteHandler}.\n *\n * Pass the same command route string(s) as the handler's generic. One command branches with `this.match`\n * over its autocompletable fields, several commands share one handler whose arms span every command's\n * fields. The decorator routes and the generic must match exactly, so listing fewer or more than the\n * handler declares is a compile error.\n *\n * @param routes - The command route string(s) this handler serves, e.g. `'search'` or `'search', 'find'`.\n * @decorator\n * @example\n * ```ts\n * \\@AutocompleteRoute('search')\n * class SearchAutocomplete extends AutocompleteHandler<'search'> {\n * async execute() {\n * await this.match({ query: (value, respond) => respond([{ name: value, value }]) });\n * }\n * }\n * ```\n */\nexport function AutocompleteRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends new (...args: any[]) => BaseHandler<AutocompleteInteraction<CacheType>>>(\n constructor: AssertAutocompleteRoute<Route, TCtor>\n ): void {\n // justified: AssertAutocompleteRoute has already narrowed the ctor, this erases it to the metadata-store shape.\n storeMetadata(InteractionRoutes.Autocomplete, routes, constructor as HandlerConstructor);\n };\n}\n\n/** @internal */\nexport type 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 * Routes select menu interactions to handler classes.\n *\n * Pass the select kind and the {@link CustomId} definition(s) this handler decodes. The handler's\n * generic must list the same definitions, and its second generic argument must be the matching select\n * interaction type, or it is a compile error.\n *\n * @param type - Select menu kind from {@link SelectMenuKind}.\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n *\n * @example\n * ```typescript\n * \\@SelectMenuRoute(SelectMenuKind.User, AssignId)\n * class AssignSelect extends SelectMenuHandler<SelectMenuKind.User, [typeof AssignId]> {\n * // handles user select menus minted from AssignId\n * }\n * ```\n */\nexport function SelectMenuRoute<SelectMenu extends SelectMenuKind, const Defs extends readonly AnyCustomId[]>(\n type: SelectMenu,\n ...defs: Defs\n) {\n return function <TCtor extends new (...args: any[]) => InteractionHandler<Repliables> & HasComponentDefs<Defs>>(\n constructor: AssertHandles<SelectMenuInteractionFor<SelectMenu>, TCtor>\n ): void {\n const routeMap = {\n [SelectMenuKind.String]: InteractionRoutes.StringMenu,\n [SelectMenuKind.User]: InteractionRoutes.UserMenu,\n [SelectMenuKind.Role]: InteractionRoutes.RoleMenu,\n [SelectMenuKind.Channel]: InteractionRoutes.ChannelMenu,\n [SelectMenuKind.Mentionable]: InteractionRoutes.MentionableMenu\n };\n\n // justified: AssertHandles has already narrowed the ctor, this erases it to the metadata-store shape.\n storeComponentRoute(routeMap[type], defs, constructor as HandlerConstructor);\n };\n}\n\n// store each definition's stable prefix as a routing key for the controller, and the full defs array on\n// the constructor so the handler base can decode against them.\nfunction storeComponentRoute(\n route: InteractionRoutes,\n defs: readonly AnyCustomId[],\n constructor: HandlerConstructor\n): void {\n storeMetadata(\n route,\n defs.map((def) => def.prefix),\n constructor\n );\n Reflect.defineMetadata(ComponentDefsKey, defs, constructor);\n}\n\nfunction storeMetadata(\n route: InteractionRoutes,\n routes: string | string[],\n constructor: Constructor<InteractionHandler<Repliables> | AutocompleteHandler<keyof SlashOptionRegistry, CacheType>>\n): void {\n const key = InteractionRouteKeys[route];\n const savedRoutes: unknown = Reflect.getMetadata(key, constructor);\n const existing: string[] = areRoutes(savedRoutes) ? savedRoutes : [];\n\n const toStore = Array.isArray(routes) ? routes : [routes];\n Reflect.defineMetadata(key, [...existing, ...toStore], constructor);\n Reflect.defineMetadata(InteractionMetadataKey, true, constructor);\n}\n","import { MiddlewareMetadataKey } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\n\nimport type { Repliables, ValidNonInteractionKeys } from '@handlers/BaseHandler';\nimport type { EventMiddleware } from '@handlers/event';\nimport type { InteractionMiddleware } from '@handlers/interaction';\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 { GuildMember, Role, TextChannel } from 'discord.js';\n\nimport type { Guild } from 'discord.js';\n\n/** Whose permissions a check ran against, used to mention and label the subject in a refusal. */\nexport type PermSubject = Role | TextChannel | Guild | GuildMember;\n\nexport function mentionFor(subject: PermSubject): string {\n if (subject instanceof Role) return `<@&${subject.id}>`;\n if (subject instanceof TextChannel) return `<#${subject.id}>`;\n if (subject instanceof GuildMember) return `<@${subject.id}>`;\n return `\\`${subject.name}\\``;\n}\n\nexport function labelFor(subject: PermSubject): string {\n if (subject instanceof Role) return 'role';\n if (subject instanceof TextChannel) return 'channel';\n if (subject instanceof GuildMember) return 'member';\n return 'guild';\n}\n","import { Notice } from '@seedcord/core';\nimport { GateNotice, NoticeCard } from '@seedcord/core/internal';\n\nimport { labelFor, mentionFor } from './utils';\n\nimport type { PermSubject } from './utils';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { Role } from 'discord.js';\n\nexport { NeedsAny, NotAllowed, NotInDm, NotInGuild, NotOwner, OnCooldown } from '@seedcord/core/internal';\n\n// ----- catalog gate refusals -----\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 MissingRole extends GateNotice {\n public constructor(\n message: string | undefined,\n public readonly role: Role | null\n ) {\n super(message ?? (role ? `You need the ${role.name} role to use this.` : 'You do not have the required role.'));\n }\n}\n\n// ----- permission refusals -----\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\nexport class MissingPermissions extends Notice {\n public constructor(\n message: string,\n public where: PermSubject,\n public missingPerms: string[]\n ) {\n super(message);\n }\n\n public render(): ReplyResponse {\n const bullets = this.missingPerms.map((perm) => `• ${perm}`).join('\\n');\n const card = new NoticeCard(\n `The ${labelFor(this.where)} ${mentionFor(this.where)} is missing the following permission entries:\\n\\n${bullets}`\n );\n return { components: [card.component] };\n }\n}\n\nexport class HasDangerousPermissions extends Notice {\n public constructor(\n message: string,\n public target: PermSubject,\n public dangerousPerms: string[]\n ) {\n super(message);\n }\n\n public render(): ReplyResponse {\n const bullets = this.dangerousPerms.map((perm) => `• ${perm}`).join('\\n');\n const card = new NoticeCard(\n `The ${labelFor(this.target)} ${mentionFor(this.target)} has the following permission entries that must not be enabled:\\n\\n${bullets}`\n );\n return { components: [card.component] };\n }\n}\n\n// ----- utility refusals -----\n\nexport class UserNotFound extends Notice {\n public constructor(public readonly userArg: string) {\n super(`User not found: ${userArg}`);\n }\n\n public render(): ReplyResponse {\n const card = new NoticeCard(\n `User probably doesn't exist or was deleted.\\n` +\n `**User Argument:** \\`${this.userArg}\\`\\n` +\n `Please check the user ID and try again. Only pass valid user IDs as the argument.`,\n 'User Not Found'\n );\n return { components: [card.component] };\n }\n}\n\nexport class UserNotInGuild extends Notice {\n public constructor(message = 'User is not in the guild.') {\n super(message);\n }\n\n public render(): ReplyResponse {\n return { components: [new NoticeCard(this.message).component] };\n }\n}\n\nexport class RoleDoesNotExist extends Notice {\n public constructor(\n message: string,\n public roleId: string\n ) {\n super(message);\n }\n\n public render(): ReplyResponse {\n return { components: [new NoticeCard(`The role with ID \\`${this.roleId}\\` does not exist.`).component] };\n }\n}\n\nexport class CouldNotFindChannel extends Notice {\n public constructor(\n message: string,\n public readonly channelId: string\n ) {\n super(message);\n }\n\n public render(): ReplyResponse {\n const card = new NoticeCard(\n `Could not find channel with ID \\`${this.channelId}\\`. It could also be that the channel is not a text channel.`\n );\n return { components: [card.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 { NonModalInteraction } from '@handlers/BaseHandler';\nimport type { Gate, GateNoticeOptions } from '@seedcord/core';\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 { prettify } from '@seedcord/utils';\nimport { Guild, GuildMember, PermissionFlagsBits, Role } from 'discord.js';\n\nimport { HasDangerousPermissions, MissingPermissions } from '@bot/notices';\n\nimport type { PermSubject } from '@bot/notices/utils';\nimport type { Notice } from '@seedcord/core';\nimport type { Nullable } from '@seedcord/types';\nimport type { PermissionsBitField, TextChannel } from 'discord.js';\n\n/**\n * Map of permission bits to their prettified human readable names.\n */\nexport const PermissionNames = new Map<bigint, string>(\n Object.entries(PermissionFlagsBits).map(([key, bit]) => [bit, prettify(key)])\n);\n\n/**\n * Array of permission bits for permission validation.\n * Import any of the predefined sets or pass a custom bigint[].\n */\nexport type BotPermissionScope = readonly bigint[];\n\n/**\n * Optional custom error constructors for {@link CheckPermissionOptions}.\n */\nexport interface PermissionErrorCtors {\n /* Error thrown when required permissions are missing */\n missing?: new (message: string, where: PermSubject, missingPerms: string[]) => Notice;\n /* Error thrown when dangerous permissions are present */\n dangerous?: new (message: string, target: PermSubject, dangerousPerms: string[]) => Notice;\n}\n\n/**\n * Options for {@link checkPermissions}.\n *\n * @see {@link PermissionErrorCtors}\n */\nexport interface CheckPermissionOptions extends PermissionErrorCtors {\n /** Role or member whose permissions will be checked */\n for: Role | GuildMember;\n /** Context where permissions apply, guild or channel */\n in: Guild | TextChannel;\n /** Permission bits to validate */\n scope: BotPermissionScope;\n /** When true, ensure target does not have the given permissions */\n inverse?: boolean;\n}\n\n/**\n * Checks permissions for a {@link Role} or a {@link GuildMember} in a {@link Guild}. Refuses when a\n * permission in `scope` is missing, or with `inverse` when one is present.\n *\n * @param target - Role or member to check\n * @param ctx - Guild context\n * @param scope - Permission bits to validate\n * @param inverse - Whether to ensure absence of the given permissions\n * @param errors - Optional custom error constructors\n *\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * // Check if a role has ManageMessages and KickMembers permissions in a guild\n * checkPermissions(role, guild, [\n * PermissionFlagsBits.ManageMessages,\n * PermissionFlagsBits.KickMembers\n * ]);\n * ```\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * // Ensure a member does NOT have Administrator permission in a guild and show custom errors\n * checkPermissions(member, guild, [\n * PermissionFlagsBits.Administrator\n * ], true, {\n * missing: CustomMissingPermissionsError,\n * dangerous: CustomDangerousPermissionsError\n * });\n * ```\n */\nexport function checkPermissions(\n target: Role | GuildMember,\n ctx: Guild,\n scope: BotPermissionScope,\n inverse?: boolean,\n errors?: PermissionErrorCtors\n): void;\n\n/**\n * Checks permissions for a {@link Role} or a {@link GuildMember} in a {@link TextChannel}. Refuses when a\n * permission in `scope` is missing, or with `inverse` when one is present.\n *\n * @param target - Role or member to check\n * @param ctx - Channel context\n * @param scope - Permission bits to validate\n * @param inverse - Whether to ensure absence of the given permissions\n * @param errors - Optional custom error constructors\n *\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * // Check if a role has SendMessages and ViewChannel permissions in a text channel\n * checkPermissions(role, textChannel, [\n * PermissionFlagsBits.SendMessages,\n * PermissionFlagsBits.ViewChannel\n * ]);\n * ```\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * // Ensure a member does NOT have ManageChannels permission in a text channel and show custom errors\n * checkPermissions(member, textChannel, [\n * PermissionFlagsBits.ManageChannels\n * ], true, {\n * missing: CustomMissingPermissionsError,\n * dangerous: CustomDangerousPermissionsError\n * });\n * ```\n */\nexport function checkPermissions(\n target: Role | GuildMember,\n // eslint-disable-next-line @typescript-eslint/unified-signatures\n ctx: TextChannel,\n scope: BotPermissionScope,\n inverse?: boolean,\n errors?: PermissionErrorCtors\n): void;\n\n/**\n * Checks permissions using an options object. Refuses when a permission in {@link CheckPermissionOptions.scope} is missing,\n * or with `options.inverse` when one is present.\n *\n * @param options - Complete options for the check\n *\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * // Check permissions using an options object\n * checkPermissions({\n * for: member,\n * in: textChannel,\n * scope: [\n * PermissionFlagsBits.SendMessages,\n * PermissionFlagsBits.ViewChannel\n * ]\n * });\n * ```\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkPermissions } from '@seedcord/gateway';\n *\n * // Ensure a role does NOT have BanMembers permission in a guild using an options object\n * checkPermissions({\n * for: role,\n * in: guild,\n * scope: [\n * PermissionFlagsBits.BanMembers\n * ],\n * inverse: true,\n * missing: CustomMissingPermissionsError,\n * dangerous: CustomDangerousPermissionsError\n * });\n * ```\n */\nexport function checkPermissions(options: CheckPermissionOptions): void;\n\nexport function checkPermissions(\n a: Role | GuildMember | CheckPermissionOptions,\n b?: Guild | TextChannel,\n c?: BotPermissionScope,\n d?: boolean,\n e?: PermissionErrorCtors\n): void {\n const opts: CheckPermissionOptions =\n a instanceof Role || a instanceof GuildMember\n ? {\n for: a,\n in: b as Guild | TextChannel,\n scope: c as BotPermissionScope,\n inverse: d ?? false,\n ...e\n }\n : a;\n\n const { for: pFor, in: pIn, scope, inverse = false, missing: missingCtor, dangerous: dangerousCtor } = opts;\n\n const Missing = missingCtor ?? MissingPermissions;\n const Dangerous = dangerousCtor ?? HasDangerousPermissions;\n\n const perms: Nullable<Readonly<PermissionsBitField>> =\n pIn instanceof Guild ? pFor.permissions : pIn.permissionsFor(pFor, true);\n\n const names = (bits: readonly bigint[]): string[] => bits.map((bit) => PermissionNames.get(bit) ?? String(bit));\n\n const present = scope.filter((bit) => perms.has(bit, true));\n const presentNames = names(present);\n\n if (inverse) {\n if (present.length > 0) {\n const base =\n `${pFor instanceof Role ? 'Role' : 'Member'}` +\n ` has dangerous permissions in this` +\n ` ${pIn instanceof Guild ? 'guild' : 'channel'}`;\n throw new Dangerous(base, pFor, presentNames);\n }\n return;\n }\n\n const missingBits = scope.filter((bit) => !perms.has(bit, true));\n if (missingBits.length > 0) {\n // name the entity that lacks the permission, matching the inverse branch, not the guild it was checked in\n throw new Missing('Missing Any/All/No Permissions', pFor, names(missingBits));\n }\n}\n","import { defineGate } from '@seedcord/core';\nimport { pickNotice } from '@seedcord/core/internal';\n\nimport { MissingRole, NotInGuild } from '@bot/notices';\nimport { checkPermissions } from '@bUtilities/permissions/checkPermissions';\n\nimport type { InteractionGateContext } from '../Gate';\nimport type { BotPermissionScope, PermissionErrorCtors } from '@bUtilities/permissions/checkPermissions';\nimport type { NonModalInteraction } from '@handlers/BaseHandler';\nimport type { Gate, GateNoticeOptions } from '@seedcord/core';\n\n// shown to a caller who is in a guild but whose member the cache could not resolve\nconst UNCACHED_MEMBER = 'Your server member data could not be resolved. Try again.';\n\n/**\n * Options for {@link RequirePermissions} and {@link RequireBotPermissions}, one override per refusal the gate\n * can show.\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import type { Guild, GuildMember, Role, TextChannel } from 'discord.js';\n *\n * // `missing` is a Notice ctor: (message, where, missingPerms)\n * class MissingPermsNotice extends Notice {\n * public constructor(message: string, where: Role | TextChannel | Guild | GuildMember, missing: string[]) {\n * super(`${message} (${missing.join(', ')})`);\n * }\n * }\n *\n * RequirePermissions([PermissionFlagsBits.BanMembers], { missing: MissingPermsNotice });\n * ```\n */\nexport interface RequirePermissionsOptions {\n /** Reword or replace the refusal shown outside a guild. */\n notInGuild?: GateNoticeOptions;\n /** Replace the missing-permissions refusal with a ctor that receives the where and the missing perm names. */\n missing?: PermissionErrorCtors['missing'];\n}\n\n/**\n * Options for {@link RequireRole}, one override per refusal the gate can show.\n */\nexport interface RequireRoleOptions {\n /** Reword or replace the refusal shown outside a guild. */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when the caller lacks the role. */\n missingRole?: GateNoticeOptions;\n}\n\n/**\n * Requires the caller to hold every permission in `scope`, via `checkPermissions`. Refuses outside a guild.\n *\n * Interaction-only and excludes ModalSubmit, since a modal lacks a reliable cached caller member.\n *\n * @param scope - The permission flag bits the caller must all hold.\n * @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-permissions one with `missing`.\n *\n * @see {@link Gated}\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers]))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * const target = this.options.getUser('target');\n * }\n * }\n * ```\n */\nexport function RequirePermissions(\n scope: BotPermissionScope,\n options?: RequirePermissionsOptions\n): Gate<InteractionGateContext<NonModalInteraction>, 'RequirePermissions'> {\n return defineGate('RequirePermissions', (ctx: InteractionGateContext<NonModalInteraction>) => {\n if (!ctx.guild) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message));\n if (!ctx.member) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message ?? UNCACHED_MEMBER));\n checkPermissions(\n ctx.member,\n ctx.guild,\n scope,\n false,\n options?.missing ? { missing: options.missing } : undefined\n );\n });\n}\n\n/**\n * Requires the bot to hold every permission in `scope`, via `checkPermissions`. Refuses outside a guild.\n *\n * It reads the bot's own member, so it attaches to modal handlers as well.\n *\n * @param scope - The permission flag bits the bot must all hold.\n * @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-permissions one with `missing`.\n *\n * @see {@link Gated}\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(RequireBotPermissions([PermissionFlagsBits.BanMembers]))\n * \\@ModalRoute(MyModalId)\n * class MyModalHandler extends ModalHandler<[typeof MyModalId]> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireBotPermissions(\n scope: BotPermissionScope,\n options?: RequirePermissionsOptions\n): Gate<InteractionGateContext, 'RequireBotPermissions'> {\n return defineGate('RequireBotPermissions', (ctx: InteractionGateContext) => {\n const botMember = ctx.guild?.members.me;\n if (!ctx.guild || !botMember) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message));\n checkPermissions(\n botMember,\n ctx.guild,\n scope,\n false,\n options?.missing ? { missing: options.missing } : undefined\n );\n });\n}\n\n/**\n * Requires the caller to have `roleId`, read from the member's role cache. Refuses outside a guild first, then\n * when the role is missing.\n *\n * Interaction-only and excludes ModalSubmit.\n *\n * @param roleId - The role snowflake the caller must hold, read from the member's role cache.\n * @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.\n *\n * @see {@link Gated}\n *\n * @example\n * ```ts\n * \\@Gated(RequireRole('123456789012345678'))\n * \\@SlashRoute('vip')\n * class VipHandler extends SlashHandler<'vip'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireRole(\n roleId: string,\n options?: RequireRoleOptions\n): Gate<InteractionGateContext<NonModalInteraction>, 'RequireRole'> {\n return defineGate('RequireRole', (ctx: InteractionGateContext<NonModalInteraction>) => {\n if (!ctx.guild) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message));\n if (!ctx.member) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message ?? UNCACHED_MEMBER));\n if (ctx.member.roles.cache.has(roleId)) return;\n const role = ctx.guild.roles.cache.get(roleId) ?? null;\n throw pickNotice(options?.missingRole, (message) => new MissingRole(message, role));\n });\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/services';\nimport chalk from 'chalk';\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: Record<string, SavedEmojiType> = {};\n\nfunction isEmojiTuple(v: unknown): v is readonly [string, string] {\n return Array.isArray(v) && v.length === 2 && typeof v[0] === 'string' && typeof v[1] === 'string';\n}\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 * Global emoji mappings object\n *\n * @see {@link EmojiMap}\n */\nexport const Emojis = emojiStorage as InjectedEmojiMap;\n\n/**\n * Loads and injects emojis based on bot configuration.\n *\n * For emojis injected from specific guilds, ensure that the Guilds intent is provided in client options.\n *\n * @internal\n */\nexport class EmojiInjector {\n private readonly logger = new Logger('Emojis');\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(chalk.bold.yellow('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 for (const key of Object.keys(emojiStorage)) Reflect.deleteProperty(emojiStorage, key);\n }\n}\n","import { SlashCommandBuilder } from '@discordjs/builders';\nimport { Logger } from '@seedcord/services';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\nimport { chatInputApplicationCommandMention } from 'discord.js';\n\nimport type { DeployResult } from '@bControllers/CommandRegistry';\nimport type { Core } from '@interfaces/Core';\nimport type { SlashOptionRegistry } from '@seedcord/core';\nimport type { ApplicationCommand, Snowflake } from 'discord.js';\n\nconst mentionStorage: Record<string, string> = {};\n\n/** Each registered slash route mapped to its mention string. */\nexport type InjectedMentionMap = {\n [K in keyof SlashOptionRegistry]: string;\n};\n\n/**\n * Ready-to-send command mention strings, keyed by {@link SlashOptionRegistry}.\n *\n * A value is a clickable `</name:id>` when the command's id resolved from the deploy, otherwise the plain\n * `/name` text. Populated by {@link CommandMentionInjector} after each deploy.\n */\nexport const CommandMentions = mentionStorage as InjectedMentionMap;\n\nconst MULTI_GUILD = Symbol('seedcord:commandmentions:multi-guild');\n\n/**\n * Turns each deployed slash route into a clickable command mention exposed through {@link CommandMentions}.\n *\n * Consumes the ids {@link DeployResult} carries, so it runs after a deploy rather than resolving from a name\n * cache (discord.js offers none for command ids). A global command is clickable everywhere by its app-wide id.\n * A guild command deployed to one guild is clickable by that guild's id. A command deployed to two or more\n * guilds mints a different id per guild, so one accessor key cannot resolve it, and it falls back to plain\n * `/name` text with one warn. On a non-owning shard a guild command also falls back to plain text.\n *\n * @internal\n */\nexport class CommandMentionInjector {\n private readonly logger = new Logger('CommandMentions');\n\n constructor(private readonly core: Core) {}\n\n public inject(deploy: DeployResult): void {\n this.clear();\n\n const globalIds = this.indexByName(deploy.global);\n const guildIds = this.indexGuilds(deploy.guilds);\n const warned = new Set<string>();\n let clickable = 0;\n\n for (const command of this.allSlashBuilders()) {\n const id = this.resolveId(command.name, globalIds, guildIds, warned);\n for (const leaf of routeLeavesOf(command.toJSON())) {\n mentionStorage[leaf.route] = id ? this.toMention(leaf.route, id) : this.toPlain(leaf.route);\n if (id) clickable++;\n }\n }\n\n this.logger.utils.summary('Linked mentions', {\n clickable,\n plain: Object.keys(mentionStorage).length - clickable\n });\n }\n\n private allSlashBuilders(): SlashCommandBuilder[] {\n const registry = this.core.bot.commands;\n if (!registry) return [];\n // a guild command in N guilds is the same builder pushed once per guild, so dedupe by reference\n const all = [...registry.globalCommands, ...registry.guildCommands.values()].flat();\n const slash = all.filter((command): command is SlashCommandBuilder => command instanceof SlashCommandBuilder);\n return [...new Set(slash)];\n }\n\n private indexByName(collection: Map<Snowflake, ApplicationCommand>): Map<string, Snowflake> {\n const map = new Map<string, Snowflake>();\n for (const command of collection.values()) map.set(command.name, command.id);\n return map;\n }\n\n private indexGuilds(\n guilds: Map<Snowflake, Map<Snowflake, ApplicationCommand>>\n ): Map<string, Snowflake | typeof MULTI_GUILD> {\n const map = new Map<string, Snowflake | typeof MULTI_GUILD>();\n for (const collection of guilds.values()) {\n for (const command of collection.values()) {\n const existing = map.get(command.name);\n if (existing === undefined) map.set(command.name, command.id);\n else if (existing !== command.id) map.set(command.name, MULTI_GUILD);\n }\n }\n return map;\n }\n\n private resolveId(\n name: string,\n globalIds: Map<string, Snowflake>,\n guildIds: Map<string, Snowflake | typeof MULTI_GUILD>,\n warned: Set<string>\n ): Snowflake | undefined {\n const global = globalIds.get(name);\n if (global) return global;\n\n const guild = guildIds.get(name);\n if (guild === undefined) return undefined;\n if (guild === MULTI_GUILD) {\n if (!warned.has(name)) {\n this.logger.warn(`${name} is deployed to multiple guilds, falling back to plain text (not clickable).`);\n warned.add(name);\n }\n return undefined;\n }\n return guild;\n }\n\n // buildSlashRoute puts the GROUP in the middle slot, matching the 4-arg (name, group, sub, id) overload order\n private toMention(route: string, id: Snowflake): string {\n const [name, middle, sub] = route.split('/');\n if (name && middle && sub) return chatInputApplicationCommandMention(name, middle, sub, id);\n if (name && middle) return chatInputApplicationCommandMention(name, middle, id);\n return chatInputApplicationCommandMention(name ?? route, id);\n }\n\n private toPlain(route: string): string {\n return `/${route.replaceAll('/', ' ')}`;\n }\n\n private clear(): void {\n for (const key of Object.keys(mentionStorage)) Reflect.deleteProperty(mentionStorage, key);\n }\n}\n","import { DiscordAPIError, RESTJSONErrorCodes, TextChannel } from 'discord.js';\n\nimport { CouldNotFindChannel } from '@bot/notices';\n\nimport type { Nullable } from '@seedcord/types';\nimport type { Channel, Client, TextChannelResolvable } from 'discord.js';\n\n/**\n * Fetches and validates a text channel. Refuses when the channel doesn't exist or isn't a text channel.\n *\n * @param client - The Discord client instance\n * @param channelId - Channel ID or TextChannel instance\n * @returns Promise resolving to the text channel\n */\nexport async function fetchText(client: Client, channelId: TextChannelResolvable): Promise<TextChannel> {\n if (channelId instanceof TextChannel) {\n return channelId;\n }\n\n let channel: Nullable<Channel> = client.channels.cache.get(channelId);\n\n if (!channel) {\n try {\n channel = await client.channels.fetch(channelId);\n } catch (err) {\n if (err instanceof DiscordAPIError && err.code === RESTJSONErrorCodes.UnknownChannel) {\n throw new CouldNotFindChannel('Channel not found or not a text channel', channelId);\n }\n\n throw err;\n }\n }\n\n if (channel?.isTextBased()) {\n return channel as TextChannel;\n }\n\n throw new CouldNotFindChannel('Channel not found or not a text channel', channelId);\n}\n","import { Logger } from '@seedcord/services';\nimport { Guild } from 'discord.js';\n\nimport { MissingPermissions } from '@bot/notices';\n\nimport { checkPermissions, PermissionNames } from './checkPermissions';\n\nimport type { BotPermissionScope, PermissionErrorCtors } from './checkPermissions';\nimport type { TextChannel } from 'discord.js';\n\n/**\n * Checks if the bot has required permissions in a {@link Guild} or {@link TextChannel}. Refuses when a\n * required permission is missing.\n *\n * @param target - Guild or text channel to check in\n * @param scope - Permission bits to validate\n * @param inverse - Whether to check for absence of the given permissions\n * @param errors - Optional custom error constructors\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n * import { checkBotPermissions } from '@seedcord/gateway';\n *\n * // Check if the bot has SendMessages and ViewChannel permissions in a text channel\n * checkBotPermissions(textChannel, [\n * PermissionFlagsBits.SendMessages,\n * PermissionFlagsBits.ViewChannel\n * ]);\n * ```\n */\nexport function checkBotPermissions(\n target: Guild | TextChannel,\n scope: BotPermissionScope,\n inverse = false,\n errors?: PermissionErrorCtors\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?.missing ?? MissingPermissions;\n throw new Missing('Missing Permissions', target, 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');\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?.missing ?? MissingPermissions;\n throw new Missing('Missing Permissions', target, names);\n }\n\n checkPermissions(me, target, scope, inverse, errors);\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { Guild, Role } from 'discord.js';\n\n/**\n * Gets the bot's managed role in a guild.\n *\n * @param guild - The guild to get the bot role from\n * @returns The bot's managed role in the guild\n * @throws A **SeedcordError** if the client user is unavailable or if the bot role is missing\n */\nexport function getBotRole(guild: Guild): Role {\n const botRole = guild.roles.botRoleFor(guild.client.user);\n\n if (!botRole) {\n throw new SeedcordError(SeedcordErrorCode.CoreBotRoleMissing, [guild.id]);\n }\n\n return botRole;\n}\n","import { PermissionFlagsBits, Role, type Guild, type GuildMember, type TextChannel } from 'discord.js';\n\nimport { CannotAssignBotRole, MissingPermissions, RoleHigherThanMe } from '@bot/notices';\n\nimport { checkBotPermissions } from './checkBotPermissions';\nimport { getBotRole } from '../roles/getBotRole';\n\nimport type { Notice } from '@seedcord/core';\n\n/**\n * Optional custom error constructors for {@link HasPermsToAssignOptions}.\n */\nexport interface AssignRoleErrorCtors {\n /** Custom error for role higher than bot */\n higher?: new (message: string, role: Role, botRole: Role) => Notice;\n /** Custom error for managed role assignment */\n managed?: new (message: string) => Notice;\n /** Custom error for missing Manage Roles permission */\n missing?: new (message: string, where: Role | TextChannel | Guild | GuildMember, missingPerms: string[]) => Notice;\n}\n\n/**\n * Options for {@link hasPermsToAssign}.\n */\nexport interface HasPermsToAssignOptions {\n /** Target role to validate for assignment */\n targetRole: Role;\n /** Optional custom error constructors */\n errors?: AssignRoleErrorCtors;\n}\n\n/**\n * Validates if 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 *\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 * errors: {\n * higher: CustomHigherError,\n * managed: CustomManagedError,\n * missing: CustomMissingPermissionsError\n * }\n * });\n * ```\n */\nexport function hasPermsToAssign(roleOrOptions: Role | HasPermsToAssignOptions): void {\n const { targetRole, errors } =\n roleOrOptions instanceof Role ? { targetRole: roleOrOptions, errors: undefined } : roleOrOptions;\n\n const HigherErr = errors?.higher ?? RoleHigherThanMe;\n const ManagedErr = errors?.managed ?? CannotAssignBotRole;\n const Missing = errors?.missing ?? MissingPermissions;\n\n const botRole = getBotRole(targetRole.guild);\n\n if (targetRole.comparePositionTo(botRole) >= 0) {\n throw new HigherErr('Role is higher than me', targetRole, botRole);\n }\n\n if (targetRole.managed) {\n throw new ManagedErr(`Cannot assign managed role ${targetRole.name}`);\n }\n\n checkBotPermissions(targetRole.guild, [PermissionFlagsBits.ManageRoles], false, { missing: Missing });\n}\n","import { DiscordAPIError, Guild, RESTJSONErrorCodes } from 'discord.js';\n\nimport { RoleDoesNotExist } from '@bot/notices';\n\nimport type { Nullable } from '@seedcord/types';\nimport type { Client, Role } from 'discord.js';\n\nfunction isUnknownRole(err: unknown): boolean {\n return err instanceof DiscordAPIError && err.code === RESTJSONErrorCodes.UnknownRole;\n}\n\nasync function fetchRoleInGuild(guild: Guild, roleId: string): Promise<Nullable<Role>> {\n const cached = guild.roles.cache.get(roleId);\n if (cached) return cached;\n\n try {\n return await guild.roles.fetch(roleId);\n } catch (err) {\n if (isUnknownRole(err)) {\n throw new RoleDoesNotExist('Role not found in specified guild', roleId);\n }\n\n throw err;\n }\n}\n\nasync function scanGuildsForRole(client: Client, roleId: string): Promise<Nullable<Role>> {\n const cached = client.guilds.cache.map((guild) => guild.roles.cache.get(roleId)).find(Boolean);\n if (cached) return cached;\n\n for (const guild of client.guilds.cache.values()) {\n try {\n const role = await guild.roles.fetch(roleId);\n if (role) return role;\n } catch (err) {\n // A role id is unique to one guild, so \"unknown role\" just means \"not this one\"; keep\n // scanning. Surface anything else (rate limits, permissions, outages).\n if (isUnknownRole(err)) continue;\n\n throw err;\n }\n }\n\n return null;\n}\n\n/**\n * Fetches a role by ID from a client or guild. Refuses when the role doesn't exist.\n *\n * @param clientOrGuild - Discord client or guild instance\n * @param roleId - The role ID to fetch\n * @returns Promise resolving to the role\n */\nexport async function fetchRole(clientOrGuild: Client | Guild, roleId: string): Promise<Role> {\n if (!roleId) {\n throw new RoleDoesNotExist('Role ID is null or undefined', roleId);\n }\n\n const role =\n clientOrGuild instanceof Guild\n ? await fetchRoleInGuild(clientOrGuild, roleId)\n : await scanGuildsForRole(clientOrGuild, roleId);\n\n if (!role) {\n throw new RoleDoesNotExist('Role not found', roleId);\n }\n\n return role;\n}\n","import { DiscordAPIError, RESTJSONErrorCodes } from 'discord.js';\n\nimport { UserNotInGuild } from '@bot/notices';\n\nimport type { Guild, GuildMember } from 'discord.js';\n\n/**\n * Fetches a guild member by user ID. Refuses when the user is not in the guild.\n *\n * @param guild - The guild to fetch the member from\n * @param userId - The Discord user ID\n * @returns Promise resolving to the guild member\n */\nexport async function fetchGuildMember(guild: Guild, userId: string): Promise<GuildMember> {\n let user = guild.members.cache.get(userId);\n user ??= await guild.members.fetch(userId).catch((err) => {\n if (err instanceof DiscordAPIError && err.code === RESTJSONErrorCodes.UnknownMember) {\n throw new UserNotInGuild(`User with ID ${userId} not found in guild`);\n }\n\n throw err;\n });\n\n return user;\n}\n","import { fetchGuildMember } from './fetchGuildMember';\n\nimport type { Guild, GuildMember } from 'discord.js';\n\n/**\n * Fetches multiple guild members by user IDs.\n *\n * @param guild - The guild to fetch members from\n * @param userIds - Array of Discord user IDs\n * @returns Promise resolving to array of successfully fetched members\n */\nexport async function fetchManyGuildMembers(guild: Guild, userIds: string[]): Promise<GuildMember[]> {\n const results = await Promise.allSettled(userIds.map((userId) => fetchGuildMember(guild, userId)));\n\n return results\n .filter((result): result is PromiseFulfilledResult<GuildMember> => result.status === 'fulfilled')\n .map((result) => result.value);\n}\n","import { DiscordAPIError, RESTJSONErrorCodes } from 'discord.js';\n\nimport { UserNotFound } from '@bot/notices';\n\nimport type { Notice } from '@seedcord/core';\nimport type { Client, User } from 'discord.js';\n\n/**\n * Options for {@link fetchUser}.\n */\nexport interface FetchUserOptions {\n /** Notice shown when the user does not exist, defaulting to the standard user-not-found notice. */\n throwAs?: new (userArg: string) => Notice;\n}\n\n/**\n * Fetches a Discord user by ID. Refuses when the user doesn't exist, with `options.throwAs` or the default.\n *\n * @param client - The Discord client instance\n * @param userId - The Discord user ID\n * @param options - Optional overrides, including the {@link FetchUserOptions.throwAs} notice\n * @returns Promise resolving to the user\n */\nexport async function fetchUser(client: Client, userId: string, options?: FetchUserOptions): Promise<User> {\n const Throw = options?.throwAs ?? UserNotFound;\n\n let user = client.users.cache.get(userId);\n user ??= await client.users.fetch(userId).catch((err) => {\n if (err instanceof DiscordAPIError && err.code === RESTJSONErrorCodes.UnknownUser) {\n throw new Throw(userId);\n }\n\n throw err;\n });\n\n return user;\n}\n","import { fetchUser } from './fetchUser';\n\nimport type { FetchUserOptions } from './fetchUser';\nimport type { Client, User } from 'discord.js';\n\n/**\n * Fetches multiple Discord users by IDs.\n *\n * @param client - The Discord client instance\n * @param userIds - Array of Discord user IDs\n * @param options - Optional overrides threaded to each {@link fetchUser} call\n * @returns Promise resolving to array of successfully fetched users\n */\nexport async function fetchManyUsers(client: Client, userIds: string[], options?: FetchUserOptions): Promise<User[]> {\n const results = await Promise.allSettled(userIds.map((userId) => fetchUser(client, userId, options)));\n\n return results\n .filter((result): result is PromiseFulfilledResult<User> => result.status === 'fulfilled')\n .map((result) => result.value);\n}\n","import type { Snowflake, GuildMember } from 'discord.js';\n\n/**\n * Updates a guild member's roles by adding and removing specified roles.\n *\n * @param rolesToAdd - Array of role IDs to add to the member\n * @param rolesToRemove - Array of role IDs to remove from the member\n * @param member - The guild member to update\n * @returns Promise that resolves when roles are updated\n */\nexport async function updateMemberRoles(\n rolesToAdd: Snowflake[],\n rolesToRemove: Snowflake[],\n member: GuildMember\n): Promise<void> {\n const current = new Set(member.roles.cache.map((r) => r.id));\n const toAdd = new Set(rolesToAdd);\n const toRemove = new Set(rolesToRemove);\n const updated = current.union(toAdd).difference(toRemove);\n\n await member.roles.set([...updated]);\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. There is nothing to show the user and no bug to report. The controller boundary drops them on\n * the original throw, and {@link ReplySender} drops them on its own send.\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 { MessageFlags } from 'discord.js';\n\n/**\n * Builds the `flags` bitfield for a framework reply. Every framework reply is ComponentsV2, so the\n * IsComponentsV2 flag is always set.\n *\n * @param ephemeral - Whether the reply is ephemeral.\n * @returns The OR'd `MessageFlags` value as a plain number.\n *\n * @internal\n */\nexport function flagsFor(ephemeral: boolean): number {\n let flags = MessageFlags.IsComponentsV2;\n if (ephemeral) flags |= MessageFlags.Ephemeral;\n return flags;\n}\n","import { Logger } from '@seedcord/services';\nimport { DiscordAPIError, MessageFlags } from 'discord.js';\n\nimport { HARMLESS_API_CODES } from '@bot/harmlessApiCodes';\nimport { flagsFor } from '@miscellaneous/flagsFor';\n\nimport type { Repliables } from '@handlers/BaseHandler';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { InteractionReplyOptions, Message, WebhookMessageEditOptions } from 'discord.js';\n\n/**\n * Sends a {@link ReplyResponse} to an interaction, picking reply, editReply, or followUp from the live\n * acknowledgement state. Logs and drops its own send failures so a dead token never escapes into the\n * controller.\n */\nexport class ReplySender {\n private readonly logger = new Logger('ReplySender');\n\n public constructor(private readonly interaction: Repliables) {}\n\n /**\n * Sends the reply and returns the sent message so a caller can attach a collector to it. Never throws,\n * a failed send is logged and dropped and resolves to `undefined`.\n *\n * @param response - The ComponentsV2 reply to show.\n * @param ephemeral - Whether the reply is ephemeral. {@default `true`}\n * @returns The sent {@link Message}, or `undefined` when the send was swallowed.\n */\n public async send(response: ReplyResponse, ephemeral = true): Promise<Message | undefined> {\n try {\n return await this.dispatch(response, ephemeral);\n } catch (error) {\n this.logSwallowed('send', error);\n return undefined;\n }\n }\n\n /**\n * Edits an already-sent message to a new {@link ReplyResponse}. Used to swap a confirmation prompt for\n * its outcome. Never throws, a failed edit is logged and dropped.\n *\n * @param message - The message to edit (the handle a prior {@link send} returned).\n * @param response - The reply to replace it with.\n */\n public async edit(message: Message, response: ReplyResponse): Promise<void> {\n try {\n await this.interaction.webhook.editMessage(message, this.editBody(response));\n } catch (error) {\n this.logSwallowed('edit', error);\n }\n }\n\n private async dispatch(response: ReplyResponse, ephemeral: boolean): Promise<Message> {\n if (this.interaction.replied) {\n return await this.interaction.followUp(this.replyOptions(response, ephemeral));\n }\n\n if (this.interaction.deferred) {\n // ephemeral is null only after deferUpdate, where @original is the live source message, so follow\n // up to avoid overwriting it. deferReply set ephemeral to a boolean over a throwaway placeholder,\n // so editReply upgrades it in place.\n if (this.interaction.ephemeral === null) {\n return await this.interaction.followUp(this.replyOptions(response, ephemeral));\n }\n return await this.interaction.editReply(this.editBody(response));\n }\n\n await this.interaction.reply(this.replyOptions(response, ephemeral));\n // reply() resolves to an InteractionResponse, fetchReply() is the message the collector attaches to.\n return await this.interaction.fetchReply();\n }\n\n private replyOptions(response: ReplyResponse, ephemeral: boolean): InteractionReplyOptions {\n return {\n components: response.components,\n flags: flagsFor(ephemeral),\n ...(response.allowedMentions && { allowedMentions: response.allowedMentions }),\n ...(response.files && { files: response.files })\n };\n }\n\n private editBody(response: ReplyResponse): WebhookMessageEditOptions {\n return {\n components: response.components,\n flags: MessageFlags.IsComponentsV2,\n ...(response.allowedMentions && { allowedMentions: response.allowedMentions }),\n ...(response.files && { files: response.files })\n };\n }\n\n private logSwallowed(action: string, error: unknown): void {\n if (error instanceof DiscordAPIError && HARMLESS_API_CODES.has(error.code)) {\n this.logger.debug(`reply ${action} hit harmless code ${error.code}`);\n return;\n }\n this.logger.error(`reply ${action} failed`, error);\n }\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 { ReplySender } from '@bot/ReplySender';\n\nimport { CONFIRM_DEF } from './reserved';\n\nimport type { NonModalInteraction, Repliables } from '@handlers/BaseHandler';\nimport type { ReplyResponse } from '@seedcord/types';\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 mint the ids once.\nconst CONFIRM_IDS = {\n confirm: CONFIRM_DEF.encode({ choice: 'confirm' }),\n cancel: CONFIRM_DEF.encode({ choice: 'cancel' })\n};\n\n/** A confirm outcome to show, the reply itself or a factory for it. */\ntype Outcome = ReplyResponse | (() => Promisable<ReplyResponse>);\n\n// the prompt a confirmation shows, a string convenience form or a factory that gets the two minted ids.\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, a clean \"no decision\", not an error.\n return null;\n }\n}\n\n// settle the prompt for an outcome, edit it to the author's reply, or remove it when no hook was given.\nasync function settle(\n sender: ReplySender,\n interaction: Repliables,\n message: Message,\n outcome: Outcome | undefined\n): Promise<void> {\n if (outcome === undefined) {\n // deleteReply routes through the interaction webhook, so it removes an ephemeral prompt where a\n // plain message.delete() cannot.\n await interaction.deleteReply(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. Never throws, a swallowed send resolves to `false`. Not usable from a\n * {@link ModalHandler}, the `interaction` parameter excludes a modal submit at compile time.\n *\n * @param interaction - The repliable interaction to prompt on, `this.event` 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.event, `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 interaction: 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`. Never throws. Not usable from a {@link ModalHandler}.\n *\n * @param interaction - The repliable interaction to prompt on, `this.event` 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 kit `BuilderComponent`/`RowComponent` wrappers, not raw discord.js builders.\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, deliver\n * a result after confirming with a fresh `interaction.followUp(...)`, the prompt is already gone.\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.event,\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 interaction: NonModalInteraction,\n prompt: (ids: { confirm: string; cancel: string }) => Promisable<ReplyResponse>,\n options?: ConfirmOptions\n): Promise<boolean>;\nexport async function getConfirmation(\n interaction: 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 sender = new ReplySender(interaction);\n const message = await sender.send(response, ephemeral);\n // a swallowed send means the prompt never showed, so there is nothing to settle, collect, or run.\n if (!message) return false;\n\n const winner = await collectChoice(message, interaction.user.id, timeoutMs);\n if (!winner) {\n await settle(sender, interaction, message, options?.onTimeout);\n return false;\n }\n\n await winner.deferUpdate().catch(() => undefined);\n const confirmed = winner.customId === CONFIRM_IDS.confirm;\n await settle(sender, interaction, message, confirmed ? options?.onConfirm : options?.onCancel);\n return confirmed;\n}\n","import type { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\n// the dev wire, held in a module-private singleton. NEVER export this from hmr/index.ts. the seedcord\n// package exposes only \".\", so an unbarreled singleton stays unreachable by user and plugin code at runtime.\nlet channel: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined;\n\nexport function setDevChannel(next: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined): void {\n channel = next;\n}\n\nexport function getDevChannel(): DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined {\n return channel;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { StrictEventEmitter } from '@seedcord/services';\n\nimport { getDevChannel } from '@hmr/devChannel';\n\nimport type { Core } from './Core';\nimport type {\n SENoEvents,\n CoordinatedShutdown,\n CoordinatedStartup,\n Logger,\n StartupPhase,\n SEEventMapLike\n} from '@seedcord/services';\nimport type { Tail } from '@seedcord/types';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types/internal';\n\n/** Interface for objects that can be initialized asynchronously */\nexport interface Initializeable {\n init(): Promise<void>;\n}\n\n/**\n * Base class for Seedcord plugins\n *\n * Extend this class to create plugins that integrate with the Seedcord lifecycle.\n * Plugins have access to the core instance and must implement initialization logic.\n */\nexport abstract class Plugin<TPluginEvents extends SEEventMapLike<TPluginEvents> = SENoEvents>\n extends StrictEventEmitter<TPluginEvents>\n implements Initializeable, HmrAware\n{\n /** Logger instance for this plugin. */\n public abstract logger: Logger;\n\n public name: string = this.constructor.name;\n\n constructor(protected pluggable: Core) {\n super();\n }\n\n /**\n * Initialize the plugin.\n * @virtual\n */\n abstract init(): Promise<void>;\n\n /**\n * Reloads plugin state on an HMR update. The base implementation is a no-op, override it in your plugin.\n * @virtual\n */\n public onHmr(_event: HmrUpdateEvent): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.\n * @param patterns - Glob patterns relative to the project root\n */\n protected registerCriticalFiles(patterns: string[]): void {\n getDevChannel()?.send('seedcord:register-critical-files', { patterns });\n }\n\n /** @internal */\n override setMaxListeners(n: number): this {\n return super.setMaxListeners(n);\n }\n\n /** @internal */\n override removeListener<TEventKey extends Extract<keyof TPluginEvents, string | symbol>>(\n event: TEventKey,\n listener: (...args: TPluginEvents[TEventKey]) => void\n ): this {\n return super.removeListener(event, listener);\n }\n\n /** @internal */\n override removeAllListeners(eventName?: string | symbol): this {\n return super.removeAllListeners(eventName);\n }\n}\n\n/**\n * Constructor type for plugins that can accept additional arguments after Core\n * @typeParam TPlugin - The plugin type being constructed\n *\n * @internal\n */\nexport type PluginCtor<TPlugin extends Plugin = Plugin> = new (core: Core, ...args: any[]) => TPlugin;\n\n/**\n * Extracts the argument types for a plugin constructor (excluding the Core parameter)\n * @typeParam Ctor - The plugin constructor to extract arguments from\n *\n * @internal\n */\nexport type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;\n\n/**\n * Base class for objects that can have plugins attached.\n *\n * Provides plugin attachment capabilities and lifecycle management. Plugins are attached during\n * configuration and initialized during startup. Not constructed directly, the host is a {@link Seedcord}.\n */\nexport class Pluggable<\n TPluggableEvents extends SEEventMapLike<TPluggableEvents> = SENoEvents\n> extends StrictEventEmitter<TPluggableEvents> {\n protected isInitialized = false;\n protected readonly shutdown: CoordinatedShutdown;\n protected readonly startup: CoordinatedStartup;\n protected readonly plugins: Plugin[] = [];\n\n private static readonly PLUGIN_INIT_TIMEOUT_MS = 15_000;\n\n constructor(shutdown: CoordinatedShutdown, startup: CoordinatedStartup) {\n super();\n this.shutdown = shutdown;\n this.startup = startup;\n }\n\n /** @internal */\n protected async init(): Promise<this> {\n if (this.isInitialized) return this;\n\n await this.startup.run();\n this.isInitialized = true;\n\n return this;\n }\n\n /**\n * Attaches a plugin to this instance\n *\n * Plugins provide external functionality and are initialized during the specified startup phase.\n * The plugin instance becomes available as a property in `core` wherever it's available.\n *\n * Make sure to augment the {@link Core} interface with the plugin type to ensure TypeScript recognizes it and provides intellisense.\n *\n * @typeParam Key - The property name for accessing the plugin\n * @typeParam Ctor - The plugin constructor type\n * @param key - Property name to access the plugin instance\n * @param Plugin - Plugin constructor class\n * @param startupPhase - When during startup to initialize this plugin ({@link StartupPhase})\n * @param args - Additional arguments to pass to the plugin constructor\n * @returns This instance with the plugin attached as a typed property\n * @throws A **SeedcordError** When called after initialization or if key already exists\n * @example\n * ```typescript\n * seedcord.attach('db', Mongo, StartupPhase.Configuration, { uri: 'mongodb://...', name: 'seedcord', dir: ... })\n * ```\n */\n public attach<Key extends string, Ctor extends PluginCtor>(\n this: this,\n key: Key,\n Plugin: Ctor,\n startupPhase: StartupPhase,\n ...args: PluginArgs<Ctor>\n ): this & Record<Key, InstanceType<Ctor>> {\n if (this.isInitialized) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);\n }\n if (key in this) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n }\n\n // `Core` is augmented by consumer declaration merging, so `this` only satisfies the augmented type\n // after every plugin attaches, which is what attach() does. The host is always a Core at runtime.\n // eslint-disable-next-line no-restricted-syntax -- forced by the declaration-merging note above\n const instance = new Plugin(this as unknown as Core, ...args);\n this.plugins.push(instance);\n\n const entry = {\n [key]: instance\n } as Record<Key, InstanceType<Ctor>>;\n\n this.startup.addTask(\n startupPhase,\n `Plugin:${key}`,\n async () => {\n instance.logger.utils.initialization(key, 'start');\n await instance.init();\n instance.logger.utils.initialization(key, 'end');\n },\n Pluggable.PLUGIN_INIT_TIMEOUT_MS\n );\n\n return Object.assign(this, entry);\n }\n\n /** @internal */\n override setMaxListeners(n: number): this {\n return super.setMaxListeners(n);\n }\n\n /** @internal */\n override removeListener<TEventKey extends Extract<keyof TPluggableEvents, string | symbol>>(\n event: TEventKey,\n listener: (...args: TPluggableEvents[TEventKey]) => void\n ): this {\n return super.removeListener(event, listener);\n }\n\n /** @internal */\n override removeAllListeners(eventName?: string | symbol): this {\n return super.removeAllListeners(eventName);\n }\n}\n","import { Logger } from '@seedcord/services';\n\nimport type { Core } from '@interfaces/Core';\nimport type {\n AnySelectMenuInteraction,\n AutocompleteInteraction,\n ButtonInteraction,\n ChatInputCommandInteraction,\n ClientEvents,\n ContextMenuCommandInteraction,\n Events,\n ModalSubmitInteraction\n} from 'discord.js';\n\nexport type ValidInteractionTypes =\n | ChatInputCommandInteraction\n | ButtonInteraction\n | ModalSubmitInteraction\n | AutocompleteInteraction\n | AnySelectMenuInteraction\n | ContextMenuCommandInteraction;\n\nexport type ValidNonInteractionKeys = Exclude<keyof ClientEvents, Events.InteractionCreate>;\n\nexport type ValidEventTypes = ValidInteractionTypes | ClientEvents[ValidNonInteractionKeys];\n\nexport type Repliables = Exclude<ValidInteractionTypes, AutocompleteInteraction>;\n\nexport type NonModalInteraction = Exclude<Repliables, ModalSubmitInteraction>;\n\n/** @internal */\nexport interface Handler {\n execute(): Promise<void>;\n}\n\n/**\n * Base class for a Discord event or interaction handler. Don't register handlers directly, use the more specific handler subclasses.\n */\nexport abstract class BaseHandler<ValidEvent extends ValidEventTypes> implements Handler {\n protected readonly event: ValidEvent;\n protected readonly logger: Logger;\n\n protected constructor(\n event: ValidEvent,\n public readonly core: Core\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name);\n }\n\n /**\n * Holds the main logic of your handler. The dispatcher calls it after the handler's gates pass, so a\n * gate that refuses stops `execute()` from running.\n */\n abstract execute(): Promise<void>;\n\n /** @internal */\n public getEvent(): ValidEvent {\n return this.event;\n }\n}\n","import { BaseHandler } from '@handlers/BaseHandler';\n\nimport type { Handler, Repliables } from '@handlers/BaseHandler';\nimport type { Core } from '@interfaces/Core';\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>\n extends BaseHandler<Repliable>\n implements Handler\n{\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);\n }\n}\n","import { BaseHandler } from '@handlers/BaseHandler';\n\nimport type { Handler, Repliables } from '@handlers/BaseHandler';\nimport type { Core } from '@interfaces/Core';\n\n/**\n * Shared base the typed interaction handlers extend.\n *\n * Not a public entry point. You should be using {@link SlashHandler}, {@link ButtonHandler}, {@link ModalHandler},\n * or {@link SelectMenuHandler} instead. This class only carries the repliable-event plumbing those bases share,\n * so DO NOT use it directly.\n *\n * @typeParam Repliable - The interaction type this handler processes\n */\nexport abstract class InteractionHandler<Repliable extends Repliables>\n extends BaseHandler<Repliable>\n implements Handler\n{\n // keep this ctor. it gives typeof InteractionHandler a public construct signature that HandlerConstructor\n // needs, and dropping it (inheriting BaseHandler's protected ctor) collapses HandlerConstructor to never.\n constructor(event: Repliable, core: Core) {\n super(event, core);\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 /**\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. A single-route handler reads `this.options` directly instead, match buys nothing there.\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 = (arms as Record<string, (options: SlashOptions<Route, Cache>) => Promisable<Ret>>)[route];\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 {\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\ntype ContextMenuKind = ApplicationCommandType.User | ApplicationCommandType.Message;\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 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 { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { BaseHandler } from '@handlers/BaseHandler';\n\nimport type { Handler } from '@handlers/BaseHandler';\nimport type { AutocompleteOptions } from '@inputs/AutocompleteOptions';\nimport type { Core } from '@interfaces/Core';\nimport type { SlashOptionRegistry } from '@seedcord/core';\nimport type { ApplicationCommandOptionChoiceData, AutocompleteInteraction, CacheType } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\ntype Row<Route extends keyof SlashOptionRegistry> = SlashOptionRegistry[Route];\n\n// distributes over a union Route so a multi-command handler sees the union of every command's autocompletable\n// fields. keyof a union row would intersect to only the names common to all commands instead.\ntype AutocompletableNames<Route extends keyof SlashOptionRegistry> = Route extends unknown\n ? {\n [Name in keyof Row<Route>]: Row<Route>[Name] extends { autocomplete: true } ? Name : never;\n }[keyof Row<Route>]\n : never;\n\n// the registry entry for one field name, gathered across every registered command that declares it.\ntype EntryFor<Route extends keyof SlashOptionRegistry, Name extends PropertyKey> = Route extends unknown\n ? Name extends keyof Row<Route>\n ? Row<Route>[Name]\n : never\n : never;\n\n// the choice value Discord expects for an autocompletable option, string for a string option and number for\n// an integer or number option. distributes over a mixed-kind union to widen to string | number.\ntype ChoiceValueOf<Entry> = Entry extends { kind: 'string' }\n ? string\n : Entry extends { kind: 'integer' | 'number' }\n ? number\n : never;\n\n/** The focused option. `value` is the raw partial Discord delivers mid-type, always a string regardless of kind. */\ninterface FocusedField<Route extends keyof SlashOptionRegistry> {\n name: AutocompletableNames<Route>;\n value: string;\n}\n\n/** One arm per autocompletable field, `value` is the focused partial, `respond` is pinned to the field's choice type. */\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<Route extends keyof SlashOptionRegistry, Cache extends CacheType = 'cached'>\n extends BaseHandler<AutocompleteInteraction<Cache>>\n implements Handler\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) {\n super(event, core);\n }\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 private decodedFocused?: { name: string; value: string };\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 fixes the autocompletable names, a focused field outside that set fails the match lookup.\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` pinned to that field's choice value type. 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.event.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 = (arms as Record<string, Arm>)[name];\n if (!arm) throw new SeedcordError(SeedcordErrorCode.AutocompleteMatchArmMissing, [name]);\n return await arm(value, respond);\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. Read the focused field from `this.focused`, not here.\n */\n protected get options(): AutocompleteOptions<Route> {\n // the autocomplete resolver already carries these getters, AutocompleteOptions is its registry-typed view.\n return this.event.options as AutocompleteOptions<Route>;\n }\n}\n","import 'reflect-metadata';\n\nimport { decodeFor, ComponentDefsKey } 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 { AnyCustomId, DecodedParams, HasComponentDefs } 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// params for a single-route handler. a multi-route handler must use match(), so its params is never.\ntype SingleParams<Defs extends readonly AnyCustomId[]> = Defs extends readonly [infer One extends AnyCustomId]\n ? DecodedParams<One['shape']>\n : never;\n\n// one arm per route, keyed by prefix, each receiving that route's decoded params.\ntype MatchArms<Defs extends readonly AnyCustomId[], Ret> = {\n [Def in Defs[number] as Def['prefix']]: (params: DecodedParams<Def['shape']>) => Promisable<Ret>;\n};\n\n/**\n * Shared base the customId-routed component handlers extend.\n *\n * Not a public entry point. You should be using {@link ButtonHandler}, {@link SelectMenuHandler}, or\n * {@link ModalHandler} instead. This class only carries the customId decode and route-matching plumbing\n * those bases share, so DO NOT use it directly.\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 only, never set at runtime. a route decorator types its argument against this so passing\n // different defs to the decorator and the generic fails to compile.\n /** @internal */\n declare readonly __componentDefs?: Defs;\n\n // the definitions the route decorator stored, read off the concrete handler class.\n private get registeredDefs(): readonly AnyCustomId[] {\n const defs = Reflect.getMetadata(ComponentDefsKey, this.constructor) as readonly AnyCustomId[] | undefined;\n if (!defs) throw new SeedcordError(SeedcordErrorCode.CustomIdHandlerRouteMissing, [this.constructor.name]);\n return defs;\n }\n\n private decoded?: { prefix: string; params: Record<string, unknown> };\n\n private get route(): { prefix: string; params: Record<string, unknown> } {\n if (this.decoded) return this.decoded;\n // justified, decodeFor returns runtime values and the generic Defs fixes their decoded types.\n const decoded = decodeFor(this.registeredDefs, this.event.customId) as {\n prefix: string;\n params: Record<string, unknown>;\n };\n this.decoded = decoded;\n return 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 must cover every registered def, a missing prefix or an unknown key is a\n * compile error. Decoding runs before any arm, so a stale or corrupt wire throws before an arm body executes.\n *\n * @param arms - One handler 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.event.reply(`approved <@${userId}>`),\n * reject: ({ userId }) => this.event.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 const arm = (arms as Record<string, (params: Record<string, unknown>) => Promisable<Ret>>)[prefix];\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. Passing different\n * definitions to the decorator 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.event.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","import { ComponentHandler } from './ComponentHandler';\n\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`.\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.event.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","import { ComponentHandler } from './ComponentHandler';\n\nimport type { SelectMenuInteractionFor, SelectMenuKind } from '@bDecorators/Interactions';\nimport type { AnyCustomId } from '@seedcord/core/internal';\nimport type { CacheType } from 'discord.js';\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.\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.event.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","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { BaseHandler } from '@handlers/BaseHandler';\n\nimport type { SingleEventPayload } from './payload';\nimport type { Handler, ValidNonInteractionKeys } from '@handlers/BaseHandler';\nimport type { Core } from '@interfaces/Core';\nimport type { ClientEvents } from 'discord.js';\nimport type { Promisable } from 'type-fest';\n\n// one arm per registered event, keyed by event name, receiving that event's payload as named params. spread,\n// not a single tuple, so the discord.js tuple labels surface as parameter names in editor signature help, e.g.\n// messageUpdate gives (oldMessage, newMessage).\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<Names extends ValidNonInteractionKeys>\n extends BaseHandler<ClientEvents[Names]>\n implements Handler\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);\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 '@handlers/BaseHandler';\n\nimport type { SingleEventPayload } from './payload';\nimport type { Handler, ValidNonInteractionKeys } from '@handlers/BaseHandler';\nimport type { Core } from '@interfaces/Core';\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<in out EventName extends ValidNonInteractionKeys = ValidNonInteractionKeys>\n extends BaseHandler<ClientEvents[EventName]>\n implements Handler\n{\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);\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 { ActionRowBuilder, ButtonBuilder } from '@discordjs/builders';\nimport { PAGE_MAX, type PageCursor } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { ButtonStyle } from 'discord.js';\n\nimport type { PageView } from '@seedcord/core';\nimport type { APIMessageComponentEmoji } from 'discord.js';\n\n/** The five built-in nav controls. */\nexport type ControlKey = 'first' | 'prev' | 'indicator' | 'next' | 'last';\n\n// the button styles with a custom_id. Link and Premium have none, so they would un-route a control.\ntype CustomIdStyle = ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success | ButtonStyle.Danger;\n\n/** Cosmetic overrides for a control button. `style` excludes Link and Premium, which would un-route it. */\nexport interface ControlCosmetics {\n label?: string;\n style?: CustomIdStyle;\n emoji?: APIMessageComponentEmoji;\n}\n\n/** The controls passed to `render`. Each accessor returns a fresh builder stamped with its target page. */\nexport interface PaginatorControls {\n /**\n * A fresh `ButtonBuilder` for one control, already stamped with its target page and disabled-at-bounds\n * state. Call only cosmetic setters on it, a `setCustomId` or `setStyle(Link)` un-routes it.\n */\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder;\n /**\n * Assemble an action row of the chosen controls, in order. Throws on an empty set, more than five\n * controls, or a duplicate.\n */\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder>;\n}\n\nconst DEFAULT_LABEL: Record<ControlKey, string> = {\n first: 'First',\n prev: 'Prev',\n indicator: '',\n next: 'Next',\n last: 'Last'\n};\n\n// a distinct slot per control keeps two controls with the same target page from sharing an id, within\n// the cursor's SLOT_MAX (0-4).\nconst CONTROL_SLOT: Record<ControlKey, number> = {\n first: 0,\n prev: 1,\n indicator: 2,\n next: 3,\n last: 4\n};\n\nconst MAX_BUTTONS_PER_ROW = 5;\n\nexport class Controls implements PaginatorControls {\n constructor(\n private readonly cursor: PageCursor<string>,\n private readonly view: PageView<unknown>\n ) {}\n\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder {\n const { target, disabled } = this.navState(key);\n\n // an emoji with no explicit label makes an icon-only button. the indicator always shows its page text.\n const defaultLabel = key === 'indicator' ? this.indicatorText() : DEFAULT_LABEL[key];\n const label = cosmetics?.label ?? (key === 'indicator' || !cosmetics?.emoji ? defaultLabel : undefined);\n\n const button = new ButtonBuilder()\n // clamp to the cursor's [0, PAGE_MAX] bound, an enormous list could push last/next past it and encode throws.\n .setCustomId(this.cursor.encode({ page: Math.min(Math.max(0, target), PAGE_MAX), slot: CONTROL_SLOT[key] }))\n .setStyle(cosmetics?.style ?? ButtonStyle.Secondary)\n .setDisabled(disabled);\n if (label !== undefined) button.setLabel(label);\n if (cosmetics?.emoji) button.setEmoji(cosmetics.emoji);\n return button;\n }\n\n private navState(key: ControlKey): { target: number; disabled: boolean } {\n const { page, totalPages, hasPrev, hasNext } = this.view;\n const knownTotal = totalPages !== undefined;\n const target = {\n first: 0,\n prev: page - 1,\n indicator: page,\n next: page + 1,\n last: knownTotal ? totalPages - 1 : page\n }[key];\n // past PAGE_MAX the encoded page would clamp to a wrong one, so next and last are disabled.\n const disabled = {\n first: !hasPrev,\n prev: !hasPrev,\n indicator: true,\n next: !hasNext || page + 1 > PAGE_MAX,\n last: !hasNext || !knownTotal || totalPages - 1 > PAGE_MAX\n }[key];\n return { target, disabled };\n }\n\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder> {\n if (keys.length === 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationEmptyControls);\n }\n if (keys.length > MAX_BUTTONS_PER_ROW) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationTooManyControls, [keys.length]);\n }\n // repeating a control reuses its slot and page, so the custom_ids collide and Discord rejects the message.\n const seen = new Set<ControlKey>();\n for (const key of keys) {\n if (seen.has(key)) throw new SeedcordTypeError(SeedcordErrorCode.PaginationDuplicateControls, [key]);\n seen.add(key);\n }\n return new ActionRowBuilder<ButtonBuilder>().addComponents(keys.map((key) => this.button(key)));\n }\n\n private indicatorText(): string {\n const { page, totalPages } = this.view;\n return totalPages === undefined ? `Page ${page + 1}` : `Page ${page + 1} of ${totalPages}`;\n }\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\nimport { BuilderComponent } from '@seedcord/core';\n\nimport { Controls } from './controls';\n\nimport type { ControlKey, PaginatorControls } from './controls';\nimport type { ButtonBuilder, ActionRowBuilder } from '@discordjs/builders';\nimport type { PageView } from '@seedcord/core';\nimport type { PageCursor } from '@seedcord/core/internal';\nimport type { ReplyResponse, V2Component } from '@seedcord/types';\n\n/** What `renderItem` returns for one item, a text line or a section. */\nexport type ItemRender<Item> = (item: Item, index: number) => string | BuilderComponent<'section'>;\n\n/** What the V2 reply can be built from. Each arm is normalized into a {@link ReplyResponse}. */\ntype Renderable = string | V2Component[] | ReplyResponse;\n\n/** A full-page render override, handed the page data and the controls factory. */\nexport type PageRender<Item> = (view: PageView<Item>, controls: PaginatorControls) => Renderable;\n\n// subclassed because BuilderComponent.instance is protected, so the assembly has to happen inside.\nclass PageContainer<Item> extends BuilderComponent<'container'> {\n constructor(view: PageView<Item>, renderItem: ItemRender<Item>, controlRow: ActionRowBuilder<ButtonBuilder>) {\n super('container');\n const base = view.page * view.perPage;\n let lines: string[] = [];\n const flush = (): void => {\n if (lines.length === 0) return;\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(lines.join('\\n')));\n lines = [];\n };\n view.items.forEach((item, offset) => {\n const rendered = renderItem(item, base + offset);\n if (typeof rendered === 'string') {\n lines.push(rendered);\n return;\n }\n flush();\n this.instance.addSectionComponents(rendered.component);\n });\n flush();\n this.instance.addActionRowComponents(controlRow);\n }\n}\n\nfunction toReplyResponse(renderable: Renderable): ReplyResponse {\n if (typeof renderable === 'string') return { components: [new TextDisplayBuilder().setContent(renderable)] };\n if (Array.isArray(renderable)) return { components: renderable };\n return renderable;\n}\n\nconst ARRAY_KEYS: ControlKey[] = ['first', 'prev', 'indicator', 'next', 'last'];\nconst CURSOR_KEYS: ControlKey[] = ['prev', 'indicator', 'next'];\n\n/**\n * Build a page's V2 reply. A `render` override builds the whole tree, otherwise the default container lists\n * the items and appends the controls (all five for a known total, prev/indicator/next for a cursor source).\n */\nexport function renderPage<Item>(\n view: PageView<Item>,\n cursor: PageCursor<string>,\n config: { renderItem?: ItemRender<Item>; render?: PageRender<Item> }\n): ReplyResponse {\n const controls = new Controls(cursor, view);\n if (config.render) return toReplyResponse(config.render(view, controls));\n\n const renderItem = config.renderItem ?? String;\n const row = controls.row(...(view.totalPages === undefined ? CURSOR_KEYS : ARRAY_KEYS));\n return { components: [new PageContainer(view, renderItem, row).component] };\n}\n","import { pageCursor } from '@seedcord/core/internal';\n\nimport { ReplySender } from '@bot/ReplySender';\nimport { ButtonHandler } from '@handlers/interaction/components';\n\nimport { renderPage } from './render';\n\nimport type { PageContext } from './PageContext';\nimport type { ItemRender, PageRender } from './render';\nimport type { PageSource } from './sources';\nimport type { Repliables } from '@handlers/BaseHandler';\nimport type { Core } from '@interfaces/Core';\nimport type { PageCursor } from '@seedcord/core/internal';\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { ButtonInteraction, Message } from 'discord.js';\n\ninterface PaginatorConfig<Item, Prefix extends string> {\n /** The route prefix used to build the page cursor on the nav buttons. */\n prefix: Prefix;\n /** Where the page data comes from. */\n source: PageSource<Item>;\n /** Render one item, `index` is its absolute position across pages. Ignored when `render` is set. */\n renderItem?: ItemRender<Item>;\n /** Take over the whole page tree. Receives the page data and the controls factory. */\n render?: PageRender<Item>;\n /** Whether the first page is ephemeral. {@default false} */\n ephemeral?: boolean;\n}\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 && { 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> {\n /** The page cursor, pass it to your `@ButtonRoute`. */\n public readonly cursor: PageCursor<Prefix>;\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 private readonly config: PaginatorConfig<Item, Prefix>;\n\n constructor(config: PaginatorConfig<Item, Prefix>) {\n this.cursor = pageCursor(config.prefix);\n this.config = 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.event.deferUpdate();\n const response = await loadPage(contextOf(this.event, this.core), this.params.page);\n await new ReplySender(this.event).edit(this.event.message, response);\n }\n };\n }\n\n /** Render page 0 and send it, picking reply or followUp from the interaction's state. */\n async start(interaction: Repliables, core?: Core): Promise<Message | undefined> {\n const response = await this.page(contextOf(interaction, core), 0);\n return new ReplySender(interaction).send(response, this.config.ephemeral ?? false);\n }\n\n /** Render a page as a {@link ReplyResponse}. To post it elsewhere, add `flags: MessageFlags.IsComponentsV2`. */\n async page(ctx: PageContext, n: number): Promise<ReplyResponse> {\n const view = await this.config.source.page(ctx, n);\n return renderPage(view, this.cursor, this.config);\n }\n}\n","import { paginate } from '@seedcord/core';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport type { PageContext } from './PageContext';\nimport type { PageView } from '@seedcord/core';\nimport type { Promisable } from 'type-fest';\n\nconst DEFAULT_PER_PAGE = 10;\n\n/**\n * The one method a paginator calls on a source, once per click. Implement it to supply a custom source.\n *\n * @typeParam Item - The item type the source pages over.\n */\nexport interface PageSource<Item> {\n page(ctx: PageContext, n: number): Promise<PageView<Item>>;\n}\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 via {@link paginate}, so the real total is known (a real last button, \"Page X of Y\"). Cache inside\n * your loader if the load is expensive.\n *\n * @typeParam Item - The item type, inferred from the loader's return.\n */\nexport class ArraySource<Item> implements PageSource<Item> {\n private readonly perPage: number;\n\n constructor(\n private readonly load: (ctx: PageContext) => Promisable<readonly Item[]>,\n opts?: { perPage?: number }\n ) {\n this.perPage = opts?.perPage ?? DEFAULT_PER_PAGE;\n if (!Number.isSafeInteger(this.perPage) || this.perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [this.perPage]);\n }\n }\n\n async page(ctx: PageContext, n: number): Promise<PageView<Item>> {\n return paginate(await this.load(ctx), n, this.perPage);\n }\n}\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> implements PageSource<Item> {\n private readonly perPage: number;\n\n constructor(\n private readonly fetch: (\n ctx: PageContext,\n page: number,\n perPage: number\n ) => Promisable<{ items: readonly Item[]; hasNext: boolean }>,\n opts?: { perPage?: number }\n ) {\n this.perPage = opts?.perPage ?? DEFAULT_PER_PAGE;\n if (!Number.isSafeInteger(this.perPage) || this.perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [this.perPage]);\n }\n }\n\n async page(ctx: PageContext, n: number): Promise<PageView<Item>> {\n const page = Math.max(0, Math.trunc(n));\n const { items, hasNext } = await this.fetch(ctx, page, this.perPage);\n return { items: [...items], page, perPage: this.perPage, hasPrev: page > 0, hasNext };\n }\n}\n","import { Logger } from '@seedcord/services';\n\nimport type { SubscriptionKey, AllSubscriptions } from './types/Subscriptions';\nimport type { Core } from '@interfaces/Core';\n\n/**\n * Abstract base class for handling application subscribers.\n *\n * Provides type-safe access to subscribers data and the core framework instance.\n * Extend this class to create custom subscriber handlers.\n *\n * @typeParam KeyOfSubscribers - The specific subscriber type this handler processes\n */\nexport abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey> {\n protected readonly logger: Logger;\n\n /**\n * Instantiates the subscriber with event data and core.\n *\n * @param data - The subscriber event data\n * @param core - The core framework instance\n */\n constructor(\n protected readonly data: AllSubscriptions[KeyOfSubscribers],\n protected readonly core: Core\n ) {\n this.logger = new Logger(this.constructor.name);\n }\n\n /**\n * Executes the subscriber handler logic.\n */\n abstract execute(): Promise<void>;\n}\n","import { SubscribeMetadataKey } from '@seedcord/core/internal';\n\nimport type { Subscriber } from '../Subscriber';\nimport type { SubscriptionKey } from '../types/Subscriptions';\nimport type { EventFrequency } from '@miscellaneous/types';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Options accepted by the `@Subscribe` decorator.\n */\nexport interface SubscribeOptions {\n /**\n * Frequency: `'once'` or `'on'`.\n *\n * @defaultValue `'on'`\n */\n readonly frequency?: EventFrequency | undefined;\n}\n\n/** @internal */\nexport interface SubscribeMetadataEntry {\n readonly subscriber: SubscriptionKey;\n readonly frequency?: EventFrequency | undefined;\n}\n\n/**\n * Registers a subscriber handler class with a specific subscriber event.\n *\n * Associates the decorated class with a subscriber event type for automatic\n * registration and execution when the subscriber is emitted.\n *\n * @typeParam TSubscriber - The subscriber event name to register for\n * @param subscriber - The subscriber event name to register for\n * @param options - Options to configure the subscriber handler registration.\n * @decorator\n * @example\n * ```typescript\n * \\@Subscribe('userJoin')\n * class WelcomeHandler extends Subscriber<'userJoin'> {\n * async execute() {\n * // Handle user join event\n * }\n * }\n * ```\n * @example\n * ```ts\n * \\@Subscribe('userJoin', { frequency: 'once' })\n * // or\n * \\@Subscribe('userJoin')\n * ```\n */\nexport function Subscribe<TSubscriber extends SubscriptionKey>(subscriber: TSubscriber, options?: SubscribeOptions) {\n return function <HandlerCtor extends Constructor<Subscriber<TSubscriber>>>(constructor: HandlerCtor): void {\n const meta: SubscribeMetadataEntry = {\n subscriber,\n frequency: options?.frequency\n };\n\n Reflect.defineMetadata(SubscribeMetadataKey, meta, constructor);\n };\n}\n","import { Subscriber } from '../Subscriber';\n\nimport type { SubscriptionKey, AllSubscriptions } from '../types/Subscriptions';\nimport type { Core } from '@interfaces/Core';\nimport type { WebhookClient } from 'discord.js';\n\n/**\n * Abstract webhook logging handler for subscriber events.\n *\n * Extends Subscriber to provide webhook-based logging capabilities.\n * Implementations must define the webhook client to send messages to by implementing the webhook property.\n *\n * @typeParam KeyOfSubscribers - The specific subscriber type this handler processes\n */\nexport abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey> extends Subscriber<KeyOfSubscribers> {\n /** The Discord webhook client for sending log messages */\n abstract webhook: WebhookClient;\n\n constructor(data: AllSubscriptions[KeyOfSubscribers], core: Core) {\n super(data, core);\n }\n}\n","import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { formatFilePath } from '@seedcord/utils';\nimport chalk from 'chalk';\n\nimport type { Logger } from '@seedcord/services';\nimport type { HmrUpdateEvent } from '@seedcord/types/internal';\n\ninterface HmrStore<THandler, TMiddleware, TArtifacts> {\n fileToHandlers: Map<string, Set<THandler>>;\n fileToMiddlewares: Map<string, Set<TMiddleware>>;\n handlerArtifacts: Map<THandler, TArtifacts>;\n}\n\n/**\n * Options for configuring the HmrModuleHandler.\n *\n * This is only useful during development.\n */\ninterface HmrModuleHandlerOptions<THandler, TMiddleware = void, TArtifacts = unknown> {\n /** Directory containing handler modules. */\n handlersDir: string;\n /** Directory containing middleware modules. Optional because not all setups use middleware. */\n middlewaresDir?: string;\n /** Function to determine if a value is a handler module of type THandler. */\n isHandler: (val: unknown) => val is THandler;\n /** Function to determine if a value is a middleware module of type TMiddleware. Optional because not all setups use middleware. */\n isMiddleware?: (val: unknown) => val is TMiddleware;\n /** Function to register a handler module. */\n registerHandler: (handler: THandler, file: string) => void;\n /** Function to register a middleware module. Optional because not all setups use middleware. */\n registerMiddleware?: (middleware: TMiddleware, file: string) => void;\n /** Function to unregister a handler module. */\n unregisterHandler: (handler: THandler, artifacts?: TArtifacts) => void;\n /** Function to unregister a middleware module. Optional because not all setups use middleware. */\n unregisterMiddleware?: (middleware: TMiddleware) => void;\n /** Function to extract artifacts from a handler to be stored across hmr cache invalidations. */\n getArtifacts?: (handler: THandler) => TArtifacts;\n /** Logger instance for logging HMR activities.*/\n logger: Logger;\n}\n\n/**\n * Reloads THandler and optional TMiddleware modules on HMR updates.\n *\n * You can either implement a custom `onHmr()` method in your class by extending `HmrAware`, or if it's a plugin, override the existing `onHmr()` with fully custom logic. Or, use this class's `handle()` method inside your `onHmr()` to get standard HMR handling for your modules based on the provided options you give to the constructor.\n *\n * This is only useful during development.\n */\nexport class HmrModuleHandler<THandler, TMiddleware = void, TArtifacts = unknown> {\n private readonly store: HmrStore<THandler, TMiddleware, TArtifacts>;\n private readonly options: HmrModuleHandlerOptions<THandler, TMiddleware, TArtifacts>;\n\n constructor(options: HmrModuleHandlerOptions<THandler, TMiddleware, TArtifacts>) {\n // spread into a new object so scoping the logger to the hmr channel leaves the caller's options unchanged.\n this.options = { ...options, logger: options.logger.inChannel('hmr') };\n\n // the Maps survive a leaf reload by ordinary object lifetime, the Seedcord singleton is never\n // reconstructed and a reload re-imports only the changed file, so no import.meta.hot.data stash is needed\n this.store = {\n fileToHandlers: new Map(),\n fileToMiddlewares: new Map(),\n handlerArtifacts: new Map()\n };\n }\n\n /**\n * Handles an HMR update event by reloading affected modules based on the event details and config. It receives an {@link HmrUpdateEvent}, then checks the type of update.\n *\n * - If it's a deletion, it unloads the module.\n * - If it's an update/creation, it checks if the file is tracked, unloads it if so, then reloads the file if it is in the handlers or middlewares directory and is a valid handler/middleware.\n */\n public async handle(event: HmrUpdateEvent): Promise<void> {\n const { file, affectedModules, type } = event;\n const { logger, handlersDir, middlewaresDir } = this.options;\n\n if (type === 'delete' || type === 'deleteDir') {\n this.unload(file);\n return;\n }\n\n if (type === 'update' && !existsSync(file)) {\n if (this.isTracked(file)) {\n logger.info(`Received update for non-existent file: ${formatFilePath(file)}, treating as delete`);\n this.unload(file);\n }\n return;\n }\n\n const rollbackEnabled = event.rollback ?? true;\n const filesToReload = affectedModules && affectedModules.length > 0 ? affectedModules : [file];\n const absHandlersDir = resolve(process.cwd(), handlersDir);\n const absMiddlewaresDir = middlewaresDir ? resolve(process.cwd(), middlewaresDir) : null;\n\n for (const fileToReload of filesToReload) {\n const isHandler = fileToReload.startsWith(absHandlersDir);\n const isMiddleware = absMiddlewaresDir ? fileToReload.startsWith(absMiddlewaresDir) : false;\n\n if (!isHandler && !isMiddleware) {\n continue;\n }\n\n await this.reloadWithRollback(fileToReload, rollbackEnabled);\n }\n }\n\n private async reloadWithRollback(file: string, rollbackEnabled: boolean): Promise<void> {\n const { logger } = this.options;\n const snapshot = this.snapshotUnits(file);\n this.unload(file);\n\n const reloaded = await this.reloadFile(file);\n if (reloaded) return;\n\n // drop any partial registration the failed reload left, so the file ends in a clean state\n this.unload(file);\n if (!rollbackEnabled) return;\n\n // restore the last-good units, a typo keeps them live until the next good save\n this.restoreUnits(file, snapshot);\n logger.warn(`${chalk.yellow.bold('Rolled back')} ${chalk.gray(formatFilePath(file))} to the last-good version`);\n }\n\n /**\n * Tracks a handler module as being loaded from a specific file.\n * @param file - The file path the handler was loaded from.\n * @param handler - The handler module instance.\n */\n public trackHandler(file: string, handler: THandler): void {\n let set = this.store.fileToHandlers.get(file);\n if (!set) {\n set = new Set();\n this.store.fileToHandlers.set(file, set);\n }\n set.add(handler);\n\n if (this.options.getArtifacts) {\n const artifacts = this.options.getArtifacts(handler);\n this.store.handlerArtifacts.set(handler, artifacts);\n }\n }\n\n /**\n * Tracks a middleware module as being loaded from a specific file.\n * @param file - The file path the middleware was loaded from.\n * @param middleware - The middleware module instance.\n */\n public trackMiddleware(file: string, middleware: TMiddleware): void {\n let set = this.store.fileToMiddlewares.get(file);\n if (!set) {\n set = new Set();\n this.store.fileToMiddlewares.set(file, set);\n }\n set.add(middleware);\n }\n\n private isTracked(file: string): boolean {\n return this.store.fileToHandlers.has(file) || this.store.fileToMiddlewares.has(file);\n }\n\n private unload(file: string): void {\n const { logger } = this.options;\n const handlers = this.store.fileToHandlers.get(file);\n if (handlers) {\n for (const handler of handlers) {\n const artifacts = this.store.handlerArtifacts.get(handler);\n this.options.unregisterHandler(handler, artifacts);\n this.store.handlerArtifacts.delete(handler);\n const name = (handler as { name?: string }).name ?? 'Handler';\n logger.info(\n `${chalk.red.bold('Unloaded')} ${chalk.cyan.bold(name)} from ${chalk.gray(formatFilePath(file))}`\n );\n }\n this.store.fileToHandlers.delete(file);\n }\n\n const middlewares = this.store.fileToMiddlewares.get(file);\n if (middlewares) {\n for (const middleware of middlewares) {\n this.options.unregisterMiddleware?.(middleware);\n const name = (middleware as { name?: string }).name ?? 'Middleware';\n logger.info(\n `${chalk.red.bold('Unloaded')} ${chalk.cyan.bold(name)} from ${chalk.gray(formatFilePath(file))}`\n );\n }\n this.store.fileToMiddlewares.delete(file);\n }\n }\n\n private async reloadFile(file: string): Promise<boolean> {\n const { logger, isHandler, isMiddleware, registerHandler, registerMiddleware } = this.options;\n\n if (!existsSync(file)) {\n logger.info(`File does not exist, skipping reload: ${formatFilePath(file)}`);\n return false;\n }\n\n try {\n let fileUrl = pathToFileURL(file).href;\n // vitest has no real vite server managing the module graph, so bust the import cache manually.\n if (process.env.VITEST === 'true') fileUrl += `?update=${Date.now()}`;\n\n const imported = (await import(fileUrl)) as Record<string, unknown>;\n\n for (const val of Object.values(imported)) {\n if (isHandler(val)) {\n registerHandler(val, file);\n this.trackHandler(file, val);\n const name = (val as { name?: string }).name ?? 'Handler';\n logger.info(\n `${chalk.blue.bold('Reloaded')} ${chalk.cyan.bold(name)} from ${chalk.gray(formatFilePath(file))}`\n );\n } else if (isMiddleware && registerMiddleware && isMiddleware(val)) {\n registerMiddleware(val, file);\n this.trackMiddleware(file, val);\n const name = (val as { name?: string }).name ?? 'Middleware';\n logger.info(\n `${chalk.blue.bold('Reloaded')} ${chalk.cyan.bold(name)} from ${chalk.gray(formatFilePath(file))}`\n );\n }\n }\n\n return true;\n } catch (error) {\n logger.error(`Failed to reload file: ${file}`, error);\n return false;\n }\n }\n\n // units are class objects, so restoring re-registers the same classes and a db plugin's connection is untouched\n private snapshotUnits(file: string): { handlers: THandler[]; middlewares: TMiddleware[] } {\n return {\n handlers: [...(this.store.fileToHandlers.get(file) ?? [])],\n middlewares: [...(this.store.fileToMiddlewares.get(file) ?? [])]\n };\n }\n\n private restoreUnits(file: string, snapshot: { handlers: THandler[]; middlewares: TMiddleware[] }): void {\n for (const handler of snapshot.handlers) {\n this.options.registerHandler(handler, file);\n this.trackHandler(file, handler);\n }\n\n if (this.options.registerMiddleware) {\n for (const middleware of snapshot.middlewares) {\n this.options.registerMiddleware(middleware, file);\n this.trackMiddleware(file, middleware);\n }\n }\n }\n}\n","import { ContextMenuCommandBuilder } from '@discordjs/builders';\nimport { ApplicationCommandType } from 'discord.js';\n\nimport type { SlashCommandBuilder } from '@discordjs/builders';\n\n/** The registered context-menu command names, split by kind, deduplicated. @internal */\nexport interface ContextMenuLeaves {\n readonly user: Set<string>;\n readonly message: Set<string>;\n}\n\n/**\n * Collects the names of every registered context-menu command across a set of command builders, split into a\n * user set and a message set. The same builder may appear more than once (a guild command is pushed once per\n * guild), and slash commands carry no context-menu name, so both collapse here. The split mirrors the\n * controller's two name-keyed maps, so the boot guard checks each name against its own kind.\n *\n * @internal\n */\nexport function contextMenuLeaves(\n commands: Iterable<SlashCommandBuilder | ContextMenuCommandBuilder>\n): ContextMenuLeaves {\n const user = new Set<string>();\n const message = new Set<string>();\n for (const command of commands) {\n if (!(command instanceof ContextMenuCommandBuilder)) continue;\n if (command.type === ApplicationCommandType.User) user.add(command.name);\n else message.add(command.name);\n }\n return { user, message };\n}\n","import { SlashCommandBuilder } from '@discordjs/builders';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\n\nimport type { ContextMenuCommandBuilder } from '@discordjs/builders';\n\n/**\n * Collects the route keys of every executable slash leaf across a set of command builders, deduplicated. The\n * same builder may appear more than once (a guild command is pushed once per guild), and context-menu\n * commands carry no slash route, so both collapse here. Route keys come from the same {@link routeLeavesOf}\n * that `seedcord codegen` reads, so the boot-time check compares against the generated registry's keys.\n *\n * @internal\n */\nexport function slashRouteLeaves(commands: Iterable<SlashCommandBuilder | ContextMenuCommandBuilder>): Set<string> {\n const leaves = new Set<string>();\n for (const command of commands) {\n if (!(command instanceof SlashCommandBuilder)) continue;\n for (const leaf of routeLeavesOf(command.toJSON())) leaves.add(leaf.route);\n }\n return leaves;\n}\n","import { resolve } from 'node:path';\n\nimport { SlashCommandBuilder } from '@discordjs/builders';\nimport { BuilderComponent } from '@seedcord/core';\nimport { CommandMetadataKey } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/services';\nimport { formatFilePath, traverseDirectory } from '@seedcord/utils';\nimport chalk from 'chalk';\nimport { Collection } from 'discord.js';\nimport { Envapter } from 'envapt';\n\nimport { contextMenuLeaves } from '@bUtilities/miscellaneous/contextMenuLeaves';\nimport { slashRouteLeaves } from '@bUtilities/miscellaneous/slashRouteLeaves';\nimport { getDevChannel } from '@hmr/devChannel';\nimport { HmrModuleHandler } from '@hmr/HmrModuleHandler';\n\nimport type { ContextMenuLeaves } from '@bUtilities/miscellaneous/contextMenuLeaves';\nimport type { ContextMenuCommandBuilder } from '@discordjs/builders';\nimport type { Core } from '@interfaces/Core';\nimport type { Initializeable } from '@interfaces/Plugin';\nimport type { CommandMeta } from '@seedcord/core/internal';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types/internal';\nimport type { ApplicationCommand, Snowflake } from 'discord.js';\n\ntype CommandCtor = new () => BuilderComponent<'command' | 'context_menu'>;\n\n/** The command collections Discord returns from each scope's deploy, keyed by command id. */\nexport interface DeployResult {\n global: Collection<Snowflake, ApplicationCommand>;\n guilds: Collection<Snowflake, Collection<Snowflake, ApplicationCommand>>;\n}\n\ninterface CommandArtifact {\n name: string;\n scope: 'global' | 'guild';\n guilds?: string[];\n}\n\n/**\n * Manages Discord application command registration and deployment.\n *\n * Scans command directories, builds command structures, and registers both global and guild-scoped commands\n * to Discord's API. Accessed via `core.bot.commands`. Do not construct it directly.\n */\nexport class CommandRegistry implements Initializeable, HmrAware {\n public readonly name = 'Commands';\n private readonly logger = new Logger('Commands');\n private isInitialised = false;\n\n public readonly globalCommands: (SlashCommandBuilder | ContextMenuCommandBuilder)[] = [];\n public readonly guildCommands = new Collection<string, (SlashCommandBuilder | ContextMenuCommandBuilder)[]>();\n\n private readonly ctorToCommand = new Map<CommandCtor, CommandArtifact>();\n private readonly hmrHandler?: HmrModuleHandler<CommandCtor, void, CommandArtifact | undefined>;\n private readonly pendingEvents = new Map<string, HmrUpdateEvent>();\n\n public constructor(\n private readonly core: Core,\n private readonly onDeployed?: (result: DeployResult) => void\n ) {\n const commandsDir = this.core.config.bot.commands.path;\n if (!commandsDir) {\n throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, ['CommandRegistry', 'commands']);\n }\n\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n this.hmrHandler = new HmrModuleHandler<CommandCtor, void, CommandArtifact | undefined>({\n handlersDir: commandsDir,\n isHandler: this.isCommandClass.bind(this),\n registerHandler: this.registerCommand.bind(this),\n unregisterHandler: this.unregisterCommand.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n\n private getArtifacts(ctor: CommandCtor): CommandArtifact | undefined {\n return this.ctorToCommand.get(ctor);\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialised) return;\n this.isInitialised = true;\n\n const commandsDir = this.core.config.bot.commands.path;\n if (!commandsDir) return;\n\n this.logger.info(chalk.bold(commandsDir));\n\n await this.loadCommands(commandsDir);\n\n this.logger.utils.summary('Loaded commands', {\n global: this.globalCommands.length,\n 'guild groups': this.guildCommands.size\n });\n\n getDevChannel()?.on('seedcord:refresh-commands', (data) => {\n void this.refresh(data.shouldRefresh);\n });\n }\n\n /** @internal */\n public async refresh(shouldRefresh = true): Promise<void> {\n if (!shouldRefresh) {\n this.logger.info(chalk.italic('Command refresh cancelled.'));\n this.pendingEvents.clear();\n return;\n }\n\n this.logger.info(chalk.italic('Refreshing commands...'));\n for (const event of this.pendingEvents.values()) {\n await this.hmrHandler?.handle(event);\n }\n this.pendingEvents.clear();\n await this.setCommands();\n }\n\n /** @internal */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n const commandsDir = this.core.config.bot.commands.path;\n if (commandsDir && event.file.startsWith(resolve(process.cwd(), commandsDir))) {\n this.pendingEvents.delete(event.file);\n this.pendingEvents.set(event.file, event);\n getDevChannel()?.send('seedcord:commands-update-prompt', {\n files: [...this.pendingEvents.keys()].map((f) => formatFilePath(f))\n });\n } else {\n await this.hmrHandler?.handle(event);\n }\n }\n\n private async loadCommands(dir: string): Promise<void> {\n await traverseDirectory(\n dir,\n (fullPath, rel, mod) => {\n for (const exported of Object.values(mod))\n if (this.isCommandClass(exported)) {\n this.registerCommand(exported, rel);\n this.hmrHandler?.trackHandler(fullPath, exported);\n }\n },\n this.logger\n );\n }\n\n private isCommandClass(obj: unknown): obj is CommandCtor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof BuilderComponent && Reflect.hasMetadata(CommandMetadataKey, obj);\n }\n\n private registerCommand(ctor: CommandCtor, rel: string): void {\n const meta = Reflect.getMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n\n if (!meta) return;\n\n const instance = new ctor();\n const comp = instance.component;\n\n const commandType = comp instanceof SlashCommandBuilder ? 'slash command' : 'context menu command';\n\n if (meta.scope === 'global') {\n this.globalCommands.push(comp);\n this.logger.utils.registration(ctor.name, rel);\n this.logger.utils.item(`Global ${commandType}: ${chalk.bold.cyan(comp.name)}`);\n } else {\n for (const g of meta.guilds) {\n const arr = this.guildCommands.get(g) ?? [];\n arr.push(comp);\n this.guildCommands.set(g, arr);\n }\n this.logger.utils.registration(ctor.name, rel);\n this.logger.utils.item(\n `Guild ${commandType}: ${chalk.bold.cyan(comp.name)} for ${chalk.magenta.bold(meta.guilds.length)} guild(s)`\n );\n }\n this.ctorToCommand.set(ctor, {\n name: comp.name,\n scope: meta.scope,\n ...(meta.scope === 'guild' && { guilds: meta.guilds })\n });\n }\n\n private unregisterCommand(ctor: CommandCtor, artifacts?: CommandArtifact): void {\n const info = artifacts ?? this.ctorToCommand.get(ctor);\n if (!info) return;\n\n if (info.scope === 'global') {\n const idx = this.globalCommands.findIndex((c) => c.name === info.name);\n if (idx !== -1) this.globalCommands.splice(idx, 1);\n } else {\n for (const g of info.guilds ?? []) {\n const arr = this.guildCommands.get(g);\n if (arr) {\n const idx = arr.findIndex((c) => c.name === info.name);\n if (idx !== -1) arr.splice(idx, 1);\n }\n }\n }\n this.ctorToCommand.delete(ctor);\n }\n\n /** @internal */\n public async setCommands(): Promise<DeployResult> {\n const result: DeployResult = { global: new Collection(), guilds: new Collection() };\n\n if (this.globalCommands.length > 0) {\n const deployed = await this.core.bot.client.application?.commands.set(this.globalCommands);\n if (deployed) result.global = deployed;\n const tag = this.globalCommands.length === 1 ? 'command' : 'commands';\n this.logger.utils.summary('Configured global', {\n [tag]: this.globalCommands.length\n });\n this.logger.utils.item(`${this.globalCommands.map((command) => chalk.bold.cyan(command.name)).join(', ')}`);\n }\n\n for (const [guildId, commands] of this.guildCommands.entries()) {\n const guild = this.core.bot.client.guilds.cache.get(guildId);\n if (!guild) {\n this.logger.warn(`Guild with ID ${guildId} not found, skipping command registration.`);\n continue;\n }\n\n const deployed = await guild.commands.set(commands);\n result.guilds.set(guildId, deployed);\n const tag = commands.length === 1 ? 'command' : 'commands';\n this.logger.utils.summary(`Configured commands for ${chalk.bold.yellow(guild.name)}`, {\n [tag]: commands.length\n });\n this.logger.utils.item(`${commands.map((command) => chalk.bold.cyan(command.name)).join(', ')}`);\n }\n\n this.onDeployed?.(result);\n return result;\n }\n\n /** The deduplicated slash route keys across every global and guild command. @internal */\n public routeLeaves(): Set<string> {\n return slashRouteLeaves([...this.globalCommands, ...this.guildCommands.values()].flat());\n }\n\n /** The registered context-menu command names, split by kind, across every global and guild command. @internal */\n public contextMenuLeaves(): ContextMenuLeaves {\n return contextMenuLeaves([...this.globalCommands, ...this.guildCommands.values()].flat());\n }\n}\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 { Repliables, ValidNonInteractionKeys } from '@handlers/BaseHandler';\nimport type { Core } from '@interfaces/Core';\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 };\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 };\n}\n","/**\n * Drops duplicate fault reports inside a fixed window so a recurring fault (a database outage on a\n * hot path) reports once per window instead of flooding the webhook. Keyed on a structural string, so\n * the map stays small, and a stale entry is evicted on the next read of its key.\n *\n * @internal\n */\nexport class FaultThrottle {\n private readonly lastReportedAt = new Map<string, number>();\n\n constructor(\n private readonly windowMs = 60_000,\n private readonly now: () => number = () => Date.now()\n ) {}\n\n /** Evicts the entry for this key if it has aged out, so the map never holds stale keys forever. */\n public shouldReport(key: string): boolean {\n const last = this.lastReportedAt.get(key);\n if (last === undefined) return true;\n if (this.now() - last < this.windowMs) return false;\n\n this.lastReportedAt.delete(key);\n return true;\n }\n\n public markReported(key: string): void {\n this.lastReportedAt.set(key, this.now());\n }\n\n public clear(): void {\n this.lastReportedAt.clear();\n }\n}\n","import * as crypto from 'node:crypto';\n\nimport { Notice, Fault } from '@seedcord/core';\nimport { prefixOf } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/services';\nimport { DiscordAPIError } from 'discord.js';\n\nimport { slashRouteOf } from '@bot/utilities/miscellaneous/slashRouteOf';\nimport { FaultThrottle } from '@miscellaneous/FaultThrottle';\n\nimport type { Repliables } from '@handlers/BaseHandler';\nimport type { Core } from '@interfaces/Core';\nimport type { RenderContext, ReplyResponse, Nullable } from '@seedcord/types';\nimport type { EventFaultSource, InteractionFaultSource } from '@subscribers/types/Subscriptions';\nimport type { Guild, User } from 'discord.js';\nimport type { UUID } from 'node:crypto';\n\nconst logger = new Logger('ErrorsHandling');\n\n/**\n * The single throttle for every fault publish, so a recurring fault reports once per window across both\n * the interaction and event paths. Exported so tests reset it between cases.\n *\n * @internal\n */\nexport const faultThrottle = new FaultThrottle();\n\n/**\n * A fault that came from a client event. The event boundary derives the actor and channel best-effort.\n *\n * @internal\n */\ninterface EventOrigin {\n name: string;\n handler: string;\n args: unknown;\n channelId: string | null;\n}\n\n/**\n * Where an error came from. `interaction` sets the interaction `handledException` source, `event` sets\n * the event source. guild/user back the `unknownException` payload on every path.\n *\n * @internal\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\n/** @internal */\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 *\n * @internal\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// the throttle protocol both report paths share: report once per window per key, stamp only on a report\nfunction withThrottle(origin: ErrorOrigin, error: Error, publish: () => void): void {\n const key = faultKey(origin, error);\n if (!faultThrottle.shouldReport(key)) {\n logger.info(`throttled duplicate fault ${key}`);\n return;\n }\n publish();\n faultThrottle.markReported(key);\n}\n\nfunction reportFault(denial: Notice, core: Core, origin: ErrorOrigin, uuid: UUID): void {\n withThrottle(origin, denial, () => {\n logger.error(`${denial.name}: ${uuid}`, denial);\n\n if (origin.interaction) {\n core.bus.publish('handledException', { denial, uuid, source: buildInteractionSource(origin.interaction) });\n } else if (origin.event) {\n core.bus.publish('handledException', { denial, uuid, source: buildEventSource(origin.event, origin) });\n } else {\n // autocomplete has no reply target and no typed source, so report through unknownException\n core.bus.publish('unknownException', {\n uuid,\n error: denial,\n guild: origin.guild,\n user: origin.user,\n metadata: metadataFor(origin)\n });\n }\n });\n}\n\nfunction reportRawFault(error: Error, core: Core, origin: ErrorOrigin, uuid: UUID): void {\n withThrottle(origin, error, () => {\n const showStack = core.config.errors?.errorStack ?? false;\n if (showStack) logger.error(uuid, error);\n else logger.error(`${uuid} | ${error.message}`);\n\n core.bus.publish('unknownException', {\n uuid,\n error,\n guild: origin.guild,\n user: origin.user,\n metadata: metadataFor(origin)\n });\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 // || not ??, an empty prefix (a too-short routeKey) must fall back to the full wire\n return prefixOf(interaction.customId) || interaction.customId;\n }\n return 'interaction';\n}\n\nfunction buildInteractionSource(interaction: Repliables): InteractionFaultSource {\n // the full slash route (with subcommand) so two subcommands of one parent do not share a key\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 { Logger } from '@seedcord/services';\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');\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) logger.debug(`Silence: ${caught.reason}`);\n return;\n }\n if (!Error.isError(caught)) throw 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 (caught instanceof DiscordAPIError && ignore.has(caught.code)) {\n logger.debug(`swallowed api code ${caught.code}`);\n return;\n }\n\n // a non-reporting denial has no reply target on an event, so it stops quietly\n if (caught instanceof Notice && !caught.report) return;\n\n const actor = deriveEventActor(args);\n extractErrorResponse(caught, core, {\n event: { name: eventName, handler: handlerName, args, channelId: actor.channelId },\n guild: actor.guild,\n user: actor.user\n });\n}\n","import { EventMetadataKey, MiddlewareMetadataKey, runHandlerGates } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/services';\nimport { hasKeys, traverseDirectory } from '@seedcord/utils';\nimport chalk from 'chalk';\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';\nimport { HmrModuleHandler } from '@hmr/HmrModuleHandler';\nimport { areRoutes } from '@miscellaneous/areRoutes';\n\nimport type { RegisterEventMetadataEntry } from '@bDecorators/Events';\nimport type { MiddlewareMetadata } from '@bDecorators/Middlewares';\nimport type { ValidNonInteractionKeys } from '@handlers/BaseHandler';\nimport type { EventHandlerConstructor, EventMiddlewareConstructor } from '@handlers/constructors';\nimport type { Core } from '@interfaces/Core';\nimport type { Initializeable } from '@interfaces/Plugin';\nimport type { EventFrequency } from '@miscellaneous/types';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types/internal';\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, registers handlers with Discord client events,\n * and coordinates event execution through the handler system. Does not handle interactions.\n * Multiple handlers can point to one event.\n *\n * @internal\n */\nexport class EventDispatcher implements Initializeable, HmrAware {\n private readonly logger = new Logger('Events');\n private isInitialized = false;\n\n public readonly name = 'Events';\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 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 this.logger.info(chalk.bold(handlersDir));\n\n const middlewareDir = hasKeys(this.core.config.bot.events, ['middlewares'])\n ? this.core.config.bot.events.middlewares\n : undefined;\n if (middlewareDir) {\n this.logger.info(`${chalk.bold(middlewareDir)} ${chalk.gray('(middlewares)')}`);\n await this.loadMiddlewares(middlewareDir);\n }\n\n await this.loadHandlers(handlersDir);\n this.attachToClient();\n\n this.logger.info(`${chalk.bold.green('Loaded event handlers:')}`);\n const eventList: string[] = [`${chalk.magenta.bold(this.middlewares.length)} middlewares`];\n this.eventMap.forEach((handlers, eventName) => {\n eventList.push(`${chalk.magenta.bold(handlers.length)} ${eventName}`);\n });\n this.logger.utils.list(eventList);\n }\n\n private async loadHandlers(dir: string): Promise<void> {\n await traverseDirectory(\n dir,\n (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 this.logger\n );\n }\n\n private async loadMiddlewares(dir: string): Promise<void> {\n await traverseDirectory(\n dir,\n (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 this.logger\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 this.logger.utils.registration(\n `${middlewareCtor.name} ${chalk.gray(`(${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 // return false so a throw in middleware 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 handler registered post-init (HMR) introduces an event type 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 this.logger.utils.registration(handlerClass.name, relativePath);\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 ${chalk.bold.green(eventName)} to the client with ${chalk.gray(handlerEntries?.length ?? 0)} handler(s)`\n );\n\n this.core.bot.client.on(eventName, (...args: ClientEvents[typeof eventName]) => {\n this.core.bot.emit('any:event', eventName, ...args);\n void (async () => {\n await this.processEvent(eventName, args).catch((err: Error) => {\n this.logger.error(`[${chalk.bold.red('UNHANDLED ERROR AT ROOT')}] ${err.name}`, err.stack);\n this.core.bot.emit('error:unhandled:event', err);\n });\n })();\n });\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 // Return before 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 ${chalk.bold.green(eventName)} with ${chalk.gray(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 { MessageFlags } from 'discord.js';\n\nimport { InteractionHandler } from '@handlers/interaction/InteractionHandler';\n\nimport type { Repliables } from '@handlers/BaseHandler';\n\n/**\n * Default handler for unhandled interactions. A reply failure here rides the controller boundary as a\n * raw fault, so it needs no decorator of its own.\n *\n * @internal\n */\nexport class UnhandledEvent extends InteractionHandler<Repliables> {\n async execute(): Promise<void> {\n await this.event.reply({\n content: `Feature not implemented yet.`,\n flags: MessageFlags.Ephemeral\n });\n }\n}\n","import { Notice, Silence } from '@seedcord/core';\nimport { Logger } from '@seedcord/services';\nimport { DiscordAPIError } from 'discord.js';\n\nimport { ReplySender } from '@bot/ReplySender';\nimport { slashRouteOf } from '@bUtilities/miscellaneous/slashRouteOf';\nimport { extractErrorResponse } from '@miscellaneous/extractErrorResponse';\n\nimport type { ValidInteractionTypes } from '@handlers/BaseHandler';\nimport type { Core } from '@interfaces/Core';\n\nconst logger = new Logger('InteractionBoundary');\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, building a {@link ReplySender} lazily so it reads the live\n * acknowledgement state at catch time.\n *\n * @internal\n */\nexport async function handleInteractionFault(\n caught: unknown,\n interaction: ValidInteractionTypes,\n core: Core\n): Promise<void> {\n if (caught instanceof Silence) {\n if (caught.reason !== undefined) logger.debug(`Silence: ${caught.reason}`);\n return;\n }\n if (!Error.isError(caught)) throw caught;\n\n // empty by default, so every api code from the handler's own work reports. the reply sender swallows\n // the harmless reply-token codes on its own send regardless, see HARMLESS_API_CODES.\n const ignore = new Set<number | string>(core.config.errors?.ignoreApiCodes ?? []);\n if (caught instanceof DiscordAPIError && ignore.has(caught.code)) {\n logger.debug(`swallowed api code ${caught.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(caught, core, {\n guild: interaction.guild,\n user: interaction.user,\n metadata: interaction,\n route: slashRouteOf(interaction)\n });\n return;\n }\n\n const { response } = extractErrorResponse(caught, core, {\n interaction,\n guild: interaction.guild,\n user: interaction.user,\n metadata: interaction\n });\n await new ReplySender(interaction).send(response, caught instanceof Notice ? caught.ephemeral : true);\n}\n","/* eslint-disable max-lines -- one handler method per interaction type keeps the router in one file */\nimport {\n InteractionMetadataKey,\n InteractionRouteKeys,\n InteractionRoutes,\n MiddlewareMetadataKey,\n prefixOf,\n runHandlerGates\n} from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/services';\nimport { formatFilePath, hasKeys, traverseDirectory } from '@seedcord/utils';\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 { UnhandledEvent } 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 { HmrModuleHandler } from '@hmr/HmrModuleHandler';\nimport { areRoutes } from '@miscellaneous/areRoutes';\n\nimport type { MiddlewareMetadata } from '@bDecorators/Middlewares';\nimport type { ContextMenuLeaves } from '@bUtilities/miscellaneous/contextMenuLeaves';\nimport type { Repliables, ValidInteractionTypes } from '@handlers/BaseHandler';\nimport type { HandlerConstructor, InteractionMiddlewareConstructor } from '@handlers/constructors';\nimport type { Core } from '@interfaces/Core';\nimport type { Initializeable } from '@interfaces/Plugin';\nimport type { CustomIdMatcher } from '@seedcord/types';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types/internal';\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\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');\n private isInitialized = false;\n\n public readonly name: string = 'Interactions';\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 private readonly keysToIgnore = new Set<CustomIdMatcher>();\n private readonly middlewares: RegisteredMiddleware[] = [];\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 ignore them here or the global\n // router double-acks 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 /**\n * Warns for each command route with no registered `@SlashRoute` handler, which would fall through to\n * UnhandledEvent at runtime. A bot may route commands outside the registry, so this does not throw.\n *\n * @internal\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 ${chalk.bold.cyan(route)} has no registered ${chalk.bold('@SlashRoute')} handler.`\n );\n }\n }\n }\n\n /**\n * Warns for each context-menu command with no matching handler, which would fall through to UnhandledEvent\n * at runtime. Checked per kind since a user and a message command can share a name.\n *\n * @internal\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 ${chalk.bold.cyan(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 ${chalk.bold.cyan(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 // Already checked in constructor\n if (!handlersDir) return;\n\n this.logger.info(chalk.bold(handlersDir));\n\n const middlewareDir = hasKeys(this.core.config.bot.interactions, ['middlewares'])\n ? this.core.config.bot.interactions.middlewares\n : undefined;\n if (middlewareDir) {\n this.logger.info(`${chalk.bold(middlewareDir)} ${chalk.gray('(middlewares)')}`);\n await this.loadMiddlewares(middlewareDir);\n }\n\n await this.loadHandlers(handlersDir);\n this.attachToClient();\n\n this.logger.info(`${chalk.bold.green('Loaded interaction handlers:')}`);\n this.logger.utils.list([\n `${chalk.magenta.bold(this.middlewares.length)} middlewares`,\n `${chalk.magenta.bold(this.slashMap.size)} slash commands`,\n `${chalk.magenta.bold(this.buttonMap.size)} buttons`,\n `${chalk.magenta.bold(this.modalMap.size)} modals`,\n `${chalk.magenta.bold(this.stringSelectMap.size)} string selects`,\n `${chalk.magenta.bold(this.userSelectMap.size)} user selects`,\n `${chalk.magenta.bold(this.roleSelectMap.size)} role selects`,\n `${chalk.magenta.bold(this.channelSelectMap.size)} channel selects`,\n `${chalk.magenta.bold(this.mentionableSelectMap.size)} mentionable selects`,\n `${chalk.magenta.bold(this.messageContextMenuMap.size)} message context menus`,\n `${chalk.magenta.bold(this.userContextMenuMap.size)} user context menus`,\n `${chalk.magenta.bold(this.autocompleteMap.size)} autocomplete`\n ]);\n }\n\n private async loadHandlers(dir: string): Promise<void> {\n await traverseDirectory(\n dir,\n (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 this.logger\n );\n }\n\n private async loadMiddlewares(dir: string): Promise<void> {\n await traverseDirectory(\n dir,\n (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 this.logger\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 silently overwrite the first, so this throws to surface it\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 this.logger.utils.registration(\n `${middlewareCtor.name} ${chalk.gray(`(${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 // 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), so this throws\n if (existing && existing !== handlerClass) {\n throw new SeedcordError(SeedcordErrorCode.InteractionDuplicateRoute, [\n route,\n existing.name,\n handlerClass.name\n ]);\n }\n writes.push([map, route]);\n }\n\n this.logger.utils.registration(handlerClass.name, formatFilePath(relativePath));\n }\n\n for (const [map, route] of writes) map.set(route, handlerClass);\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 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 this.core.bot.emit('any:interaction', interaction);\n this.handleInteraction(interaction).catch((err: Error) => {\n this.logger.error(`[${chalk.bold.red('UNHANDLED ERROR AT ROOT')}] ${err.name}`, err.stack);\n this.core.bot.emit('error:unhandled:interaction', err);\n });\n });\n }\n\n private async handleCustomIdInteraction<TInteraction extends Interaction & { customId: string }>(\n interaction: TInteraction,\n getMap: () => Map<string, HandlerConstructor>,\n interactionType: string\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 if (!prefix) return this.logger.warn(`${interactionType} has invalid customId: ${interaction.customId}`);\n\n await this.processInteraction(\n interaction,\n () => prefix,\n (key) => getMap().get(key)\n );\n }\n\n private async processInteraction<TInteraction extends Interaction>(\n interaction: TInteraction,\n extractKey: (i: TInteraction) => string,\n getHandler: (key: string) => HandlerConstructor | undefined\n ): Promise<void> {\n const key = extractKey(interaction);\n\n try {\n if (!interaction.isAutocomplete()) {\n for (const { ctor } of this.middlewares) {\n const middleware = new ctor(interaction as Repliables, this.core);\n await middleware.execute();\n }\n }\n\n let HandlerCtor = getHandler(key);\n if (!HandlerCtor) {\n this.logger.warn(`No handler found for key ${chalk.bold.cyan(key)}. Falling back to UnhandledEvent.`);\n HandlerCtor = UnhandledEvent;\n }\n\n this.logger.debug(`Processing ${chalk.bold.green(key)} with ${chalk.gray(HandlerCtor.name)}`);\n // @ts-expect-error TS can't infer the type of interaction here\n const handler = new HandlerCtor(interaction as Repliables, this.core);\n // autocomplete has no reply target, @Gated rejects it at compile time, this is the runtime backstop\n if (!interaction.isAutocomplete()) {\n await runHandlerGates(HandlerCtor, interactionGateContext(interaction as Repliables, this.core));\n }\n await handler.execute();\n } catch (caught) {\n await handleInteractionFault(caught, interaction as ValidInteractionTypes, this.core);\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 () => route,\n (key) => this.slashMap.get(key)\n );\n }\n\n private async handleButton(interaction: ButtonInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, () => this.buttonMap, 'Button');\n }\n\n private async handleModal(interaction: ModalSubmitInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, () => this.modalMap, 'Modal');\n }\n\n private async handleStringSelectMenu(interaction: StringSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, () => this.stringSelectMap, 'String select menu');\n }\n\n private async handleUserSelectMenu(interaction: UserSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, () => this.userSelectMap, 'User select menu');\n }\n\n private async handleRoleSelectMenu(interaction: RoleSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, () => this.roleSelectMap, 'Role select menu');\n }\n\n private async handleChannelSelectMenu(interaction: ChannelSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, () => this.channelSelectMap, 'Channel select menu');\n }\n\n private async handleMentionableSelectMenu(interaction: MentionableSelectMenuInteraction): Promise<void> {\n await this.handleCustomIdInteraction(interaction, () => this.mentionableSelectMap, 'Mentionable select menu');\n }\n\n private async handleMessageContextMenu(interaction: MessageContextMenuCommandInteraction): Promise<void> {\n await this.processInteraction(\n interaction,\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 () => 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\n if (!this.autocompleteMap.has(route)) {\n this.logger.warn(`No autocomplete handler for ${chalk.bold.cyan(route)}.`);\n await interaction.respond([]);\n return;\n }\n\n await this.processInteraction(\n interaction,\n () => route,\n (key) => this.autocompleteMap.get(key)\n );\n }\n}\n","import { validateDiscordToken } from '@seedcord/errors/internal';\nimport { Logger, ShutdownPhase } from '@seedcord/services';\nimport chalk from 'chalk';\nimport { Client, ClientEvents, Interaction } from 'discord.js';\nimport { Envapt } from 'envapt';\n\nimport { CommandRegistry } from '@bControllers/CommandRegistry';\nimport { EventDispatcher } from '@bControllers/EventDispatcher';\nimport { InteractionDispatcher } from '@bControllers/InteractionDispatcher';\nimport { Plugin } from '@interfaces/Plugin';\n\nimport { CommandMentionInjector, CommandMentions } from './injectors/CommandMentionInjector';\nimport { EmojiInjector, Emojis } from './injectors/EmojiInjector';\n\nimport type { InjectedMentionMap } from './injectors/CommandMentionInjector';\nimport type { InjectedEmojiMap } from './injectors/EmojiInjector';\nimport type { Core } from '@interfaces/Core';\nimport type { HmrUpdateEvent } from '@seedcord/types/internal';\n\n/**\n * Types of events emitted by the {@link Core.bot} instance.\n */\nexport interface BotEvents {\n /** Emitted when an unhandled interaction error occurs */\n 'error:unhandled:interaction': [error: Error];\n /** Emitted when an unhandled event error occurs */\n 'error:unhandled:event': [error: Error];\n /** Emitted for any event */\n 'any:event': { [K in keyof ClientEvents]: [K, ...ClientEvents[K]] }[keyof ClientEvents];\n /** Emitted for any interaction */\n 'any:interaction': [interaction: Interaction];\n}\n\n/**\n * Discord bot implementation that manages client and controllers\n *\n * Don't instantiate this class directly. Use `core.bot` instead.\n */\nexport class Bot extends Plugin<BotEvents> {\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');\n private isInitialized = false;\n\n private readonly _client: Client;\n private readonly interactions?: InteractionDispatcher;\n private readonly events?: EventDispatcher;\n public readonly commands?: CommandRegistry;\n private readonly emojiInjector: EmojiInjector;\n public readonly emojis: InjectedEmojiMap = Emojis;\n public readonly mentions: InjectedMentionMap = CommandMentions;\n\n /** @internal For use in dev mode */\n public override 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.commands) await this.commands.onHmr(event);\n }\n\n /** @internal */\n constructor(core: Core) {\n super(core);\n\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 if (core.config.bot.commands.path) {\n const mentionInjector = new CommandMentionInjector(core);\n this.commands = new CommandRegistry(core, (result) => {\n mentionInjector.inject(result);\n });\n }\n\n this.emojiInjector = new EmojiInjector(core);\n\n const BOT_SHUTDOWN_TIMEOUT = 2000;\n core.shutdown.addTask(\n ShutdownPhase.DiscordCleanup,\n 'stop-bot',\n async () => await this.stop(),\n BOT_SHUTDOWN_TIMEOUT\n );\n }\n\n /**\n * Initializes Discord client and all controllers\n * @internal\n */\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.commands) {\n await this.commands.init();\n await this.commands.setCommands();\n this.interactions?.warnUnhandledRoutes(this.commands.routeLeaves());\n this.interactions?.warnUnhandledContextMenuRoutes(this.commands.contextMenuLeaves());\n }\n }\n\n /**\n * Stops the bot and cleans up connections\n * @internal\n */\n public async stop(): Promise<void> {\n this._client.removeAllListeners();\n\n await this.logout();\n }\n\n /**\n * Logs the bot into Discord using the configured token\n */\n private async login(token: string): Promise<Bot> {\n await this._client.login(token);\n this.logger.info(`Logged in as ${chalk.bold.magenta(this._client.user?.username)}!`);\n return this;\n }\n\n /**\n * Logs out and destroys the Discord client connection\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 /**\n * Emits a Discord event with its argument tuple. The overloads enforce the key/args correlation\n * at compile time only; at runtime this forwards straight to the underlying EventEmitter.\n *\n * @internal\n */\n override emit<TKey extends keyof ClientEvents>(\n event: 'any:event',\n name: TKey,\n ...args: ClientEvents[TKey]\n ): boolean;\n\n /** @internal */\n override emit<TEventKey extends keyof BotEvents>(event: TEventKey, ...args: BotEvents[TEventKey]): boolean;\n\n override emit(event: string, ...args: unknown[]): boolean {\n // justified, runtime emit forwards to the base emitter; TS cannot correlate the overload generics across super.emit.\n return super.emit(event as never, ...(args as never));\n }\n}\n","import { Logger } from '@seedcord/services';\nimport { wrapHot } from '@seedcord/types/internal';\nimport { formatFilePath } from '@seedcord/utils';\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\n\nimport { getDevChannel, setDevChannel } from './devChannel';\n\nimport type { HmrAware, HmrUpdateEvent, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\nexport class HmrManager {\n private readonly logger = new Logger('HMR', { channel: 'hmr' });\n private readonly listeners = new Set<HmrAware>();\n\n constructor() {}\n\n /** @internal */\n public init(): void {\n if (!import.meta.hot) return;\n // the one raw `import.meta.hot` read in the framework, captured into the dev-channel singleton\n // so every other framework site reads it through getDevChannel\n setDevChannel(wrapHot<SeedcordFrameworkEvents, SeedcordCliEvents>(import.meta.hot));\n\n if (Envapter.isDevelopment || Envapter.isTest) {\n this.logger.info('Enabled');\n\n getDevChannel()?.on('seedcord:hmr', (payload) => {\n const affected = payload.affectedModules?.length ?? 0;\n this.logger.info(`${chalk.bold('1')} module changed, ${chalk.bold(affected)} affected modules`);\n\n if (payload.affectedModules) {\n this.logger.utils.list(\n payload.affectedModules.map((mod) => formatFilePath(mod)),\n 'Affected modules: '\n );\n }\n\n void this.handleUpdate(payload);\n });\n }\n }\n\n /** @internal */\n public register(listener: HmrAware): void {\n this.listeners.add(listener);\n }\n\n /** @internal */\n public unregister(listener: HmrAware): void {\n this.listeners.delete(listener);\n }\n\n private async handleUpdate(event: HmrUpdateEvent): Promise<void> {\n const promises = [...this.listeners].map(async (listener) => {\n try {\n await listener.onHmr(event);\n } catch (error) {\n this.logger.error(`Error handling HMR update in ${chalk.bold(listener.name)}: `, error);\n }\n });\n\n await Promise.all(promises);\n }\n}\n","import { BuilderComponent } from '@seedcord/core';\nimport { filterCirculars } from '@seedcord/utils';\nimport { AttachmentBuilder, SeparatorSpacingSize } from 'discord.js';\n\nconst DISCORD_WEBHOOK_REGEX = new RegExp(\n String.raw`^https?:\\/\\/(?:canary\\.|ptb\\.)?discord(?:app)?\\.com\\/api\\/webhooks\\/\\d+\\/[\\w$-]+$`\n);\n\n/**\n * Whether a string is a well-formed Discord webhook URL.\n *\n * @internal\n */\nexport function isDiscordWebhookUrl(value: string): boolean {\n return URL.canParse(value) && DISCORD_WEBHOOK_REGEX.test(value);\n}\n\n/**\n * Serializes a value to a JSON attachment, made circular-safe first.\n *\n * @internal\n */\nexport function jsonAttachment(name: string, description: string, data: unknown): AttachmentBuilder {\n const content = filterCirculars(data);\n return new AttachmentBuilder(Buffer.from(JSON.stringify(content, undefined, 2), 'utf8'), { name, description });\n}\n\n/**\n * The small divider the default webhook reporters place between sections.\n *\n * @internal\n */\nexport class WebhookSeparator extends BuilderComponent<'separator'> {\n constructor() {\n super('separator');\n this.instance.setSpacing(SeparatorSpacingSize.Small).setDivider(true);\n }\n}\n","import { BuilderComponent } from '@seedcord/core';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { WebhookClient } from 'discord.js';\nimport { Envapt } from 'envapt';\n\nimport { flagsFor } from '@miscellaneous/flagsFor';\n\nimport { isDiscordWebhookUrl, jsonAttachment, WebhookSeparator } from '../bases/webhookHelpers';\nimport { WebhookLog } from '../bases/WebhookLog';\nimport { Subscribe } from '../decorators/Subscribe';\n\nimport type { AllSubscriptions, FaultSource } from '../types/Subscriptions';\nimport type { Notice } from '@seedcord/core';\n\nfunction webhookUrlValidator(raw: unknown): string {\n if (raw !== null && typeof raw !== 'string') {\n throw new SeedcordError(SeedcordErrorCode.ConfigHandledExceptionWebhookInvalid);\n }\n\n const value = raw?.trim() ?? '';\n if (value === '') {\n throw new SeedcordError(SeedcordErrorCode.ConfigHandledExceptionWebhookMissing);\n }\n\n if (!isDiscordWebhookUrl(value)) {\n throw new SeedcordError(SeedcordErrorCode.ConfigHandledExceptionWebhookInvalid);\n }\n\n return value;\n}\n\n/**\n * Default subscriber that delivers a reported `Notice` (`report: true`) to a webhook with the denial,\n * the fault source, the threaded uuid, the cause stack, and the raw source as a JSON attachment. The\n * controller boundary throttles identical faults before they reach the bus.\n *\n * Requires the HANDLED_EXCEPTION_WEBHOOK_URL environment variable, the same rule UNKNOWN_EXCEPTION_WEBHOOK_URL enforces.\n *\n * @throws A **SeedcordError** if HANDLED_EXCEPTION_WEBHOOK_URL is not set or is invalid\n */\n@Subscribe('handledException')\nexport class HandledException extends WebhookLog<'handledException'> {\n @Envapt('HANDLED_EXCEPTION_WEBHOOK_URL', {\n converter: (raw) => webhookUrlValidator(raw)\n })\n declare static readonly handledExceptionWebhookUrl: string;\n\n webhook = new WebhookClient({\n url: HandledException.handledExceptionWebhookUrl\n });\n\n async execute(): Promise<void> {\n const { source } = this.data;\n\n try {\n await this.webhook.send({\n flags: flagsFor(false),\n withComponents: true,\n username: 'Handled Exception',\n components: [new HandledExceptionContainer(this.data).component],\n files: [jsonAttachment('source.json', 'The raw source the fault came from', source.raw)]\n });\n } catch (error) {\n this.logger.error('Failed to send handled exception webhook', error);\n }\n }\n}\n\nclass HandledExceptionContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['handledException']) {\n super('container');\n\n const { denial, uuid, source } = data;\n\n this.instance\n .addTextDisplayComponents((text) => text.setContent(faultSummary(denial, source)))\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(`### UUID \\`${uuid}\\`\\n\\`\\`\\`${causeStack(denial)}\\`\\`\\``)\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Source'))\n .addFileComponents((file) => file.setURL('attachment://source.json'));\n }\n}\n\n/**\n * The summary block of a fault report, narrowed per source kind so an interaction fault shows its\n * command and customId while an event fault shows its event name and handler.\n *\n * @internal\n */\nexport function faultSummary(denial: Notice, source: FaultSource): string {\n const head = `### A handled fault was reported: \\`${denial.name}\\`\\n**Message:** ${denial.message}\\n`;\n if (source.kind === 'event') {\n return (\n `${head}**Event:** ${source.eventName}\\n` +\n `**Handler:** ${source.handler}\\n` +\n `**User ID:** \\`${source.userId ?? 'n/a'}\\`\\n` +\n `**Guild ID:** \\`${source.guildId ?? 'n/a'}\\`\\n` +\n `**Channel ID:** \\`${source.channelId ?? 'n/a'}\\``\n );\n }\n return (\n `${head}**Kind:** ${source.interactionKind}\\n` +\n `**Command:** ${source.command ?? 'n/a'}\\n` +\n `**CustomId:** ${source.customId ?? 'n/a'}\\n` +\n `**User ID:** \\`${source.userId}\\`\\n` +\n `**Guild ID:** \\`${source.guildId ?? 'n/a'}\\`\\n` +\n `**Channel ID:** \\`${source.channelId ?? 'n/a'}\\`\\n` +\n `**Interaction ID:** \\`${source.interactionId}\\``\n );\n}\n\n/**\n * The text shown for a denial's cause in the report. Tolerates a non-serializable cause (a bigint or a\n * circular object) so building the report never throws.\n *\n * @internal\n */\nexport function causeStack(denial: Notice): string {\n const { cause } = denial;\n if (Error.isError(cause)) return cause.stack ?? cause.message;\n if (typeof cause === 'string') return cause;\n if (typeof cause === 'bigint' || typeof cause === 'symbol' || typeof cause === 'function') return cause.toString();\n if (cause !== undefined) {\n try {\n return JSON.stringify(cause);\n } catch {\n return '[unserializable cause]';\n }\n }\n return denial.stack ?? 'No cause recorded.';\n}\n","import { BuilderComponent } from '@seedcord/core';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { WebhookClient, DiscordAPIError, SnowflakeUtil } from 'discord.js';\nimport { Envapt } from 'envapt';\n\nimport { flagsFor } from '@miscellaneous/flagsFor';\n\nimport { isDiscordWebhookUrl, jsonAttachment, WebhookSeparator } from '../bases/webhookHelpers';\nimport { WebhookLog } from '../bases/WebhookLog';\nimport { Subscribe } from '../decorators/Subscribe';\n\nimport type { AllSubscriptions } from '../types/Subscriptions';\n\nfunction webhookUrlValidator(raw: unknown): string {\n if (raw !== null && typeof raw !== 'string') {\n throw new SeedcordError(SeedcordErrorCode.ConfigUnknownExceptionWebhookInvalid);\n }\n\n const value = raw?.trim() ?? '';\n if (value === '') {\n throw new SeedcordError(SeedcordErrorCode.ConfigUnknownExceptionWebhookMissing);\n }\n\n if (!isDiscordWebhookUrl(value)) {\n throw new SeedcordError(SeedcordErrorCode.ConfigUnknownExceptionWebhookInvalid);\n }\n\n return value;\n}\n\n/**\n * Default subscriber to log unhandled exceptions via webhook. It provides basic information about the error:\n * - Error stack trace\n * - Guild ID and name (if applicable)\n * - User ID and username (if applicable)\n * - A unique UUID for tracking\n * - Timestamps comparing interaction time and error log time (if applicable)\n * - Metadata associated with the error (if provided)\n *\n * Developers need to set the UNKNOWN_EXCEPTION_WEBHOOK_URL environment variable in their .env file otherwise this subscriber will throw an error during initialization.\n *\n * @throws A **SeedcordError** if UNKNOWN_EXCEPTION_WEBHOOK_URL is not set or is invalid\n */\n@Subscribe('unknownException')\nexport class UnknownException extends WebhookLog<'unknownException'> {\n @Envapt('UNKNOWN_EXCEPTION_WEBHOOK_URL', {\n converter: (raw) => webhookUrlValidator(raw)\n })\n declare static readonly unknownExceptionWebhookUrl: string;\n\n webhook = new WebhookClient({\n url: UnknownException.unknownExceptionWebhookUrl\n });\n\n async execute(): Promise<void> {\n const { metadata } = this.data;\n const metadataFile = metadata\n ? jsonAttachment('metadata.json', 'Metadata associated with the error', metadata)\n : null;\n\n try {\n await this.webhook.send({\n flags: flagsFor(false),\n withComponents: true,\n username: 'Unknown Exception',\n components: [new UnhandledErrorContainer(this.data).component],\n files: metadataFile ? [metadataFile] : []\n });\n } catch (error) {\n this.logger.error('Failed to send unknown exception webhook', error);\n }\n }\n}\n\nclass UnhandledErrorContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['unknownException']) {\n super('container');\n\n const { uuid, error, guild, user, metadata } = data;\n\n this.instance\n .addTextDisplayComponents((text) =>\n text.setContent(\n `### An unknown exception was thrown\\n` +\n `**Guild ID:** \\`${guild?.id ?? 'Not used in a guild'}\\`\\n` +\n `**Guild Name:** ${guild?.name ?? 'Not used in a guild'}\\n` +\n `**User ID:** \\`${user?.id ?? 'Missing user info'}\\`\\n` +\n `**Username:** ${user?.username ?? 'Missing user info'}\\n`\n )\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent(`### UUID \\`${uuid}\\`\\n\\`\\`\\`${error.stack}\\`\\`\\``));\n\n this.addTimestampsIfAvailable(error);\n this.addMetadataIfAvailable(metadata);\n }\n\n private addTimestampsIfAvailable(error: Error): void {\n if (!(error instanceof DiscordAPIError)) return;\n\n const now = Date.now();\n\n // Extract the snowflake ID from `/interactions/{ID}/`\n const snowflake = error.url.match(/\\/interactions\\/(\\d+)\\//)?.[1];\n if (!snowflake) return undefined;\n\n const interactionTs = Number(SnowflakeUtil.deconstruct(snowflake).timestamp);\n\n const diff = now - interactionTs;\n const seconds = Math.floor(diff / 1000);\n const millis = diff % 1000;\n\n this.instance\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(\n `### Timestamps\\n` +\n `- **\\`Interaction sent\\` :** ${new Date(interactionTs).toISOString()} (${interactionTs})\\n` +\n `- **\\`Error logged \\` :** ${new Date(now).toISOString()} (${now})\\n` +\n `- **\\`Offset \\` :** ${seconds}s ${millis}ms`\n )\n );\n }\n\n private addMetadataIfAvailable(metadata: unknown): void {\n if (!metadata) return;\n\n this.instance\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Metadata'))\n .addFileComponents((file) => file.setURL('attachment://metadata.json'));\n }\n}\n","import { SubscribeMetadataKey } from '@seedcord/core/internal';\nimport { Logger } from '@seedcord/services';\nimport { traverseDirectory } from '@seedcord/utils';\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\n\nimport { HmrModuleHandler } from '@hmr/HmrModuleHandler';\nimport { Plugin } from '@interfaces/Plugin';\n\nimport { HandledException } from './default/HandledException';\nimport { UnknownException } from './default/UnknownException';\nimport { Subscriber } from './Subscriber';\n\nimport type { SubscribeMetadataEntry } from './decorators/Subscribe';\nimport type { AllSubscriptions, SubscriptionKey, SubscriptionTuples } from './types/Subscriptions';\nimport type { Core } from '@interfaces/Core';\nimport type { EventFrequency } from '@miscellaneous/types';\nimport type { HmrUpdateEvent } from '@seedcord/types/internal';\n\n// `data: never` so a concrete subscriber (which takes one subscription's payload) is assignable here\n// for storage. The per-key map restores the precise payload type at dispatch.\ntype SubscriberConstructor = new (data: never, core: Core) => Subscriber<SubscriptionKey>;\ninterface RegisteredSubscriberHandlerEntry {\n ctor: SubscriberConstructor;\n frequency: EventFrequency;\n}\n\ntype SubscriberArtifact = SubscriptionKey[];\n\n/**\n * Manages application subscribers and event handling\n *\n * Provides a centralized system for registering and executing custom subscribers\n * throughout the application lifecycle. Bus subscribers are loaded from configured directories\n * and can be triggered programmatically or by framework events. Accessed via `core.bus`. Do not\n * construct it directly.\n */\nexport class Bus extends Plugin<SubscriptionTuples> {\n public readonly logger = new Logger('Subscribers');\n /** @internal */\n public override readonly name = 'Subscribers';\n private isInitialized = false;\n private readonly subscribersMap = new Map<SubscriptionKey, RegisteredSubscriberHandlerEntry[]>();\n private readonly executedOnceHandlers = new Set<SubscriberConstructor>();\n private readonly hmrHandler?: HmrModuleHandler<SubscriberConstructor, void, SubscriberArtifact>;\n\n constructor(protected core: Core) {\n super(core);\n\n if (this.core.config.subscribers.path) {\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n this.hmrHandler = new HmrModuleHandler({\n handlersDir: this.core.config.subscribers.path,\n isHandler: this.isSubscriber.bind(this),\n registerHandler: this.registerSubscriber.bind(this),\n unregisterHandler: this.unregisterSubscriber.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n }\n\n private getArtifacts(ctor: SubscriberConstructor): SubscriberArtifact {\n const meta = Reflect.getMetadata(SubscribeMetadataKey, ctor) as SubscribeMetadataEntry;\n return [meta.subscriber];\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialized) return;\n\n this.isInitialized = true;\n\n this.registerSubscriber(UnknownException);\n this.registerSubscriber(HandledException);\n\n // require both webhook urls at boot so a missing one stops the boot, never silently dropping fault\n // reports when the first exception fires.\n Envapter.require('UNKNOWN_EXCEPTION_WEBHOOK_URL', 'HANDLED_EXCEPTION_WEBHOOK_URL');\n\n const subscribersDir = this.core.config.subscribers.path;\n if (subscribersDir) {\n this.logger.info(chalk.bold(subscribersDir));\n await this.loadSubscribers(subscribersDir);\n const totalSubscribers = [...this.subscribersMap.values()].reduce(\n (acc, handlers) => acc + handlers.length,\n 0\n );\n this.logger.utils.list([`${chalk.bold.magenta(totalSubscribers)} subscribers`], chalk.bold.green('Loaded'));\n }\n }\n\n /** @internal For use in dev mode */\n public override async onHmr(event: HmrUpdateEvent): Promise<void> {\n if (this.hmrHandler) {\n await this.hmrHandler.handle(event);\n }\n }\n\n private async loadSubscribers(dir: string): Promise<void> {\n await traverseDirectory(\n dir,\n (fullPath, relativePath, imported) => {\n for (const exportName of Object.keys(imported)) {\n const val = imported[exportName];\n if (this.isSubscriber(val)) {\n this.registerSubscriber(val);\n this.hmrHandler?.trackHandler(fullPath, val);\n this.logger.utils.registration(val.name, relativePath);\n }\n }\n },\n this.logger\n );\n }\n\n private registerSubscriber(handler: SubscriberConstructor): void {\n const options = Reflect.getMetadata(SubscribeMetadataKey, handler) as SubscribeMetadataEntry;\n\n let handlers = this.subscribersMap.get(options.subscriber);\n if (!handlers) {\n handlers = [];\n this.subscribersMap.set(options.subscriber, handlers);\n }\n handlers.push({ ctor: handler, frequency: options.frequency ?? 'on' });\n }\n\n private unregisterSubscriber(handler: SubscriberConstructor, artifacts?: SubscriberArtifact): void {\n const subscribers = artifacts ?? [...this.subscribersMap.keys()];\n for (const subscriber of subscribers) {\n const handlers = this.subscribersMap.get(subscriber);\n if (!handlers) continue;\n const index = handlers.findIndex((entry) => entry.ctor === handler);\n if (index !== -1) {\n handlers.splice(index, 1);\n }\n }\n // spent follows the ctor identity, so leaving executedOnceHandlers alone keeps a rollback-restored subscriber spent\n }\n\n private isSubscriber(obj: unknown): obj is SubscriberConstructor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof Subscriber && Reflect.hasMetadata(SubscribeMetadataKey, obj);\n }\n\n /**\n * Publishes an event to its subscribers and native listeners.\n *\n * Fire-and-forget, so subscriber handlers run asynchronously and this returns before they\n * complete, and callers must not assume side effects have landed. Errors thrown by a subscriber\n * are caught and logged, never surfaced here. A `'once'` subscriber is marked as executed when\n * it starts (even if it throws), so it never runs twice.\n *\n * @param event - The subscription key to publish\n * @param data - Payload passed to each subscriber\n * @returns Whether the underlying emitter had native listeners for the event\n */\n public publish<KeyOfSubscribers extends SubscriptionKey>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n void this.processSubscriber(event, data);\n // justified: a generic key can't reduce SubscriptionTuples[K], but data is this event's payload by the signature\n return super.emit(event, ...([data] as SubscriptionTuples[KeyOfSubscribers]));\n }\n\n private async processSubscriber<KeyOfSubscribers extends SubscriptionKey>(\n subscriberName: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): Promise<void> {\n const handlers = this.subscribersMap.get(subscriberName);\n if (!handlers) return;\n\n for (const entry of handlers) {\n if (entry.frequency === 'once' && this.executedOnceHandlers.has(entry.ctor)) {\n continue;\n }\n\n try {\n // Mark before awaiting so a re-entrant publish of the same event can't run a\n // 'once' subscriber twice while the first invocation is still pending.\n if (entry.frequency === 'once') {\n this.executedOnceHandlers.add(entry.ctor);\n }\n\n // the map keys each subscriber to one subscription, so data matches this ctor's payload arm\n const Ctor = entry.ctor as new (\n data: AllSubscriptions[KeyOfSubscribers],\n core: Core\n ) => Subscriber<KeyOfSubscribers>;\n const instance = new Ctor(data, this.core);\n await instance.execute();\n } catch (err) {\n this.logger.error(`Error in subscriber ${String(subscriberName)} handler ${entry.ctor.name}:`, err);\n }\n }\n }\n}\n","/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n","import { setBotColor } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { MemoryRateLimiter } from '@seedcord/rate-limiter';\nimport { HealthCheck, CoordinatedShutdown, CoordinatedStartup, StartupPhase } from '@seedcord/services';\nimport { SeedcordBrand } from '@seedcord/types/internal';\nimport { Envapter } from 'envapt';\n\nimport { Bot } from './bot/Bot';\nimport { HmrManager } from './hmr/HmrManager';\nimport { Pluggable } from './interfaces/Plugin';\nimport { Bus } from './subscribers/Bus';\nimport { version as packageVersion } from './version';\n\nimport type { GatewayConfig } from './interfaces/Config';\nimport type { Core } from './interfaces/Core';\nimport type { IRateLimiter } from '@seedcord/types';\n\n/**\n * Main Seedcord bot framework class\n *\n * Primary entry point for creating Discord bots with Seedcord.\n * Manages component lifecycle and provides plugin support.\n */\nexport class Seedcord extends Pluggable implements Core {\n // These 3 variables are used by the CLI\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 static isInstantiated = false;\n\n /** @see {@link CoordinatedShutdown} */\n public override readonly shutdown: CoordinatedShutdown;\n\n /** @see {@link CoordinatedStartup} */\n public override readonly startup: CoordinatedStartup;\n\n /** @see {@link Bus} */\n public readonly bus: Bus;\n\n /** @see {@link Bot} */\n public readonly bot: Bot;\n\n /** @see {@link IRateLimiter} */\n public readonly rateLimiter: IRateLimiter;\n\n /** @see {@link HealthCheck} */\n private readonly healthCheck: HealthCheck;\n\n /** @see {@link HmrManager} */\n private readonly hmrManager: HmrManager;\n\n /**\n * Creates a new Seedcord instance\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 if (Seedcord.isInstantiated) {\n throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);\n }\n\n Seedcord.isInstantiated = true;\n\n const shutdown = new CoordinatedShutdown(config.shutdownEnabled);\n const startup = new CoordinatedStartup();\n\n super(shutdown, startup);\n\n setBotColor(config.botColor);\n\n this.shutdown = shutdown;\n this.startup = startup;\n\n this.hmrManager = new HmrManager();\n this.hmrManager.init();\n this.bus = new Bus(this);\n this.bot = new Bot(this);\n this.rateLimiter = new MemoryRateLimiter();\n this.healthCheck = new HealthCheck(this.shutdown, config.healthCheck);\n\n this.registerStartupTasks();\n }\n\n /** @internal */\n // @ts-expect-error called only by tests, so the source build sees it as unused\n private static reset(): void {\n Seedcord.isInstantiated = false;\n }\n\n /**\n * Registers default startup tasks\n * @internal\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.bus.init();\n this.bus.logger.utils.initialization('Subscribers', 'end');\n });\n\n this.startup.addTask(StartupPhase.Instantiation, '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 this.startup.addTask(StartupPhase.Ready, 'Health Check', async () => {\n this.healthCheck.logger.utils.initialization('HealthCheck', 'start');\n await this.healthCheck.init();\n this.healthCheck.logger.utils.initialization('HealthCheck', 'end');\n });\n }\n\n /**\n * Starts the bot and runs all initialization tasks\n *\n * @returns This Seedcord instance when fully initialized\n */\n public async start(): Promise<this> {\n await super.init();\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.bus);\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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"}
|