@seedcord/core 0.1.0-next.5 → 0.1.0-next.6
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/dist/{AutocompleteOptions-eB87SZ4a.d.mts → AutocompleteOptions-eKhIe6Qt.d.mts} +9 -16
- package/dist/Plugin-C2-VHrsX.cjs +114 -0
- package/dist/Plugin-C2-VHrsX.cjs.map +1 -0
- package/dist/Plugin-CNyRKDHT.d.mts +226 -0
- package/dist/Plugin-PcdPjAzc.mjs +97 -0
- package/dist/Plugin-PcdPjAzc.mjs.map +1 -0
- package/dist/devChannel-CQU7hq7Q.mjs +14 -0
- package/dist/devChannel-CQU7hq7Q.mjs.map +1 -0
- package/dist/devChannel-CoCmAVDx.cjs +26 -0
- package/dist/devChannel-CoCmAVDx.cjs.map +1 -0
- package/dist/index.cjs +5 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +4 -3
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.cjs +7 -17
- package/dist/internal.index.cjs.map +1 -1
- package/dist/internal.index.d.mts +3 -2
- package/dist/internal.index.mjs +4 -15
- package/dist/internal.index.mjs.map +1 -1
- package/dist/node-internal.index.cjs +645 -0
- package/dist/node-internal.index.cjs.map +1 -0
- package/dist/node-internal.index.d.cts +1 -0
- package/dist/{node.index.d.mts → node-internal.index.d.mts} +104 -143
- package/dist/node-internal.index.mjs +636 -0
- package/dist/node-internal.index.mjs.map +1 -0
- package/dist/{permissions-DQL5ViZn.cjs → permissions-DSW_EZfN.cjs} +19 -1
- package/dist/{permissions-DQL5ViZn.cjs.map → permissions-DSW_EZfN.cjs.map} +1 -1
- package/dist/{permissions-SokZLJMj.mjs → permissions-RVCBhL2n.mjs} +14 -2
- package/dist/{permissions-SokZLJMj.mjs.map → permissions-RVCBhL2n.mjs.map} +1 -1
- package/dist/phases-BfpAG6w3.mjs +31 -0
- package/dist/phases-BfpAG6w3.mjs.map +1 -0
- package/dist/phases-C_BGNyVo.cjs +43 -0
- package/dist/phases-C_BGNyVo.cjs.map +1 -0
- package/dist/plugin.index.cjs +4 -0
- package/dist/plugin.index.d.cts +1 -0
- package/dist/plugin.index.d.mts +3 -0
- package/dist/plugin.index.mjs +3 -0
- package/package.json +24 -13
- package/dist/node.index.cjs +0 -521
- package/dist/node.index.cjs.map +0 -1
- package/dist/node.index.d.cts +0 -1
- package/dist/node.index.mjs +0 -513
- package/dist/node.index.mjs.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["CommandMetadataKey","SeedcordError","SeedcordErrorCode","contextMenuRouteOf","selectMenuRouteOf","Logger","Notice","NoticeCard","defineGate","runCheck","markCommits","Notice","NeedsAny","NotAllowed","defineGate","pickNotice","NotOwner","NotInGuild","NotInDm","SeedcordTypeError","SeedcordErrorCode","defineEffectGate","OnCooldown","SeedcordRangeError","SeedcordErrorCode"],"sources":["../src/decorators/Command.ts","../src/decorators/routes.ts","../src/dispatch/DispatchContext.ts","../src/handlers/BaseHandler.ts","../src/handlers/RepliableHandler.ts","../src/stops/Fault.ts","../src/gates/combinators.ts","../src/gates/catalog/access.ts","../src/gates/catalog/Cooldown.ts","../src/stops/Silence.ts","../src/pagination/paginate.ts","../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { CommandMetadataKey } from '@src/metadataKeys';\n\nimport type { BuilderComponent } from '@components/Component';\nimport type { Constructor } from 'type-fest';\n\ntype CommandCtor = Constructor<BuilderComponent<'command' | 'context_menu'>>;\n\ninterface GlobalMeta {\n scope: 'global';\n}\n\ninterface GuildMeta {\n scope: 'guild';\n guilds: string[];\n}\n\nexport type CommandMeta = GlobalMeta | GuildMeta;\n\ntype CommandScope = CommandMeta['scope'];\n\n/**\n * Attaches deployment metadata so the framework registers this command globally or in specific guilds.\n *\n * @param scope - Must be 'global' for global registration\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('global')\n * class PingCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'global'): (ctor: CommandCtor) => void;\n\n/**\n * Registers a command for specific guild deployment.\n *\n * @param scope - Must be 'guild' for guild-specific registration\n * @param guilds - Array of guild IDs where the command should be registered\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('guild', ['123456789'])\n * class AdminCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'guild', guilds: string[]): (ctor: CommandCtor) => void;\n\nexport function RegisterCommand(scope: CommandScope, guilds: string[] = []) {\n return (ctor: CommandCtor): void => {\n const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n if (existingMeta) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [\n ctor.name,\n existingMeta.scope,\n scope\n ]);\n }\n\n if (scope === 'global' && guilds.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);\n }\n\n if (scope === 'guild' && (!Array.isArray(guilds) || guilds.length === 0)) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);\n }\n\n const meta: GlobalMeta | GuildMeta = scope === 'global' ? { scope } : { scope, guilds };\n Reflect.defineMetadata(CommandMetadataKey, meta, ctor);\n };\n}\n","import {\n contextMenuRouteOf,\n selectMenuRouteOf,\n storeComponentRoute,\n storeInteractionRoute\n} from '@decorators/interactionRoutes';\nimport { InteractionRoutes } from '@src/metadataKeys';\n\nimport type { AnyCustomId } from '@customId/CustomId';\nimport type { SelectMenuKind } from '@decorators/interactionRoutes';\nimport type { MessageContextMenuRegistry, UserContextMenuRegistry } from '@registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '@registries/SlashOptionRegistry';\nimport type { ApplicationCommandType } from 'discord-api-types/v10';\nimport type { Constructor } from 'type-fest';\n\ntype ContextMenuKind = ApplicationCommandType.User | ApplicationCommandType.Message;\n\ntype ComponentBrand = 'button' | 'modal' | SelectMenuKind;\n\n// phantom brands keep the decorators off transport-specific classes\ntype AnyHandlerCtor = new (...args: any[]) => unknown;\n\ntype SlashRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __slashRoute?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype AutocompleteRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __autocompleteRoute?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype ContextMenuKindOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __ctxKind?: infer Kind extends ContextMenuKind;\n }\n ? Kind\n : never;\n\ntype ComponentOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __component?: infer Brand extends ComponentBrand;\n }\n ? Brand\n : never;\n\ntype DefsOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __componentDefs?: infer Defs extends readonly AnyCustomId[];\n }\n ? Defs\n : never;\n\ntype AssertSlashRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n SlashRouteOf<TCtor>\n]\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\ntype AssertAutocompleteRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n AutocompleteRouteOf<TCtor>\n]\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\ntype AssertContextMenuRoute<Kind extends ContextMenuKind, TCtor extends AnyHandlerCtor> = [Kind] extends [\n ContextMenuKindOf<TCtor>\n]\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// one assignability direction for the defs, a bidirectional check would reject const-inferred readonly tuples\ntype AssertComponentRoute<\n Brand extends ComponentBrand,\n Defs extends readonly AnyCustomId[],\n TCtor extends AnyHandlerCtor\n> = [ComponentOf<TCtor>] extends [Brand]\n ? [Brand] extends [ComponentOf<TCtor>]\n ? [DefsOf<TCtor>] extends [Defs]\n ? TCtor\n : Constructor<['the customId definitions do not match the handler generic', DefsOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>;\n\ntype NamesFor<Kind extends ContextMenuKind> = Kind extends ApplicationCommandType.User\n ? keyof UserContextMenuRegistry\n : keyof MessageContextMenuRegistry;\n\n/**\n * Routes one or more slash commands to a `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 */\nexport function SlashRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertSlashRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Slash, routes, constructor);\n };\n}\n\n/**\n * Routes one or more commands' autocomplete to an `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 AnyHandlerCtor>(constructor: AssertAutocompleteRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Autocomplete, routes, constructor);\n };\n}\n\n/**\n * Routes one or more context-menu commands to a `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 handler's generic must\n * declare the same kind, cross-checked both directions. Context menus carry no options, so a multi-name\n * handler 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 ContextMenuKind>(kind: Kind, ...names: NamesFor<Kind>[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertContextMenuRoute<Kind, TCtor>): void {\n storeInteractionRoute(contextMenuRouteOf(kind), names, constructor);\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 AnyHandlerCtor>(constructor: AssertComponentRoute<'button', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Button, defs, constructor);\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 AnyHandlerCtor>(constructor: AssertComponentRoute<'modal', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Modal, defs, constructor);\n };\n}\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 kind and definitions, 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 * ```\n */\nexport function SelectMenuRoute<const Kind extends SelectMenuKind, const Defs extends readonly AnyCustomId[]>(\n type: Kind,\n ...defs: Defs\n) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<Kind, Defs, TCtor>): void {\n storeComponentRoute(selectMenuRouteOf(type), defs, constructor);\n };\n}\n","/**\n * The per-dispatch bag. Any code can merge fields into it by declaration merging, the\n * same pattern as {@link SlashOptionRegistry}. It stays empty until one does, so `keyof DispatchState` is\n * `never` and the bag is inert.\n */\nexport interface DispatchState {}\n\n/**\n * A typed bag allocated once per interaction dispatch and handed to the handler. The middleware and i18n\n * work reads and writes it through {@link DispatchState}. Today the bag is empty, so it only carries the\n * dispatched `routeId`.\n */\nexport class DispatchContext {\n private readonly state: Partial<DispatchState> = {};\n\n constructor(public readonly routeId: string | null) {}\n\n set<Key extends keyof DispatchState>(key: Key, value: DispatchState[Key]): void {\n this.state[key] = value;\n }\n\n get<Key extends keyof DispatchState>(key: Key): DispatchState[Key] | undefined {\n return this.state[key];\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { DispatchContext } from '@src/dispatch/DispatchContext';\n\n/**\n * Base class every transport handler extends. Don't register handlers directly, use the more specific\n * handler subclasses.\n *\n * @typeParam Event - The event or interaction this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class BaseHandler<Event, TCore extends CoreBase> {\n protected readonly event: Event;\n protected readonly logger: Logger;\n // absent on event handlers\n protected readonly dispatch?: DispatchContext | undefined;\n\n protected constructor(\n event: Event,\n public readonly core: TCore,\n dispatch?: DispatchContext\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name);\n this.dispatch = dispatch;\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","import { BaseHandler } from './BaseHandler';\n\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { BaseReplySender } from '@reply/BaseReplySender';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { DispatchContext } from '@src/dispatch/DispatchContext';\n\n/**\n * Shared base the repliable handlers on both transports extend. Defines the reply members over the sender\n * the transport builds.\n *\n * @typeParam Event - The repliable interaction type this handler processes\n * @typeParam TCore - The transport's Core\n * @typeParam TMessage - The transport's created-message lens\n * @typeParam TSender - The transport's reply sender\n */\nexport abstract class RepliableHandler<\n Event,\n TCore extends CoreBase,\n TMessage extends { id: string },\n TSender extends BaseReplySender<TMessage>\n> extends BaseHandler<Event, TCore> {\n protected readonly sender: TSender;\n protected readonly routeId: string;\n\n protected constructor(event: Event, core: TCore, dispatch?: DispatchContext) {\n super(event, core, dispatch);\n this.routeId = dispatch?.routeId ?? this.constructor.name;\n // runs inside the ctor, an override builds from its arguments only, subclass fields are not initialized yet\n this.sender = this.buildSender(event, core, this.routeId);\n }\n\n protected abstract buildSender(event: Event, core: TCore, routeId: string): TSender;\n\n /** @internal The dispatcher's fault boundary replies through the live ack state. */\n public getSender(): TSender {\n return this.sender;\n }\n\n /** Send the initial response, exactly once. */\n protected reply(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.reply(response, opts);\n }\n\n /** Show a \"thinking\" placeholder, then fill it later with {@link edit}. */\n protected defer(opts?: DeferOpts): Promise<void> {\n return this.sender.defer(opts);\n }\n\n /** Send a new message once the interaction is acknowledged. */\n protected followUp(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.followUp(response, opts);\n }\n\n /** Rewrite the initial reply or deferred placeholder. The targeted form rewrites a message a prior send returned. */\n protected edit(response: ReplyResponse | string): Promise<TMessage>;\n protected edit(target: TMessage, response: ReplyResponse | string): Promise<TMessage>;\n protected edit(\n targetOrResponse: TMessage | ReplyResponse | string,\n maybeResponse?: ReplyResponse | string\n ): Promise<TMessage> {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n if (maybeResponse === undefined) return this.sender.edit(targetOrResponse as ReplyResponse | string);\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n return this.sender.edit(targetOrResponse as TMessage, maybeResponse);\n }\n\n /** Routes to reply, followUp, or edit based on the current ack state. */\n protected send(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.send(response, opts);\n }\n\n /** Delete the initial reply or deferred placeholder. Pass a target to delete a message a prior send returned. */\n protected delete(target?: TMessage): Promise<void> {\n return target === undefined ? this.sender.delete() : this.sender.delete(target);\n }\n}\n","import { Notice } from './Notice';\nimport { NoticeCard } from './NoticeCard';\n\nimport type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * A generic fault you throw after catching an error you do not have a specific message for.\n *\n * The user sees a fixed generic reply with the tracking uuid, never the cause. `report` defaults to\n * `true`, so the framework logs it and publishes it to the `handledException` bus. Pass `report: false`\n * to show the generic reply without the bus publish. The original error is stored as the standard\n * `cause`, so the real stack reaches the webhook. For a fault the user should see a real message,\n * subclass {@link Notice} and write your own `render` instead.\n *\n * The framework also renders this for an unhandled throw, where it points the user at\n * `ctx.developerUsername`.\n *\n * @example\n * ```ts\n * import { Fault } from '@seedcord/gateway';\n *\n * try {\n * await db.write(record);\n * } catch (cause) {\n * // user sees the generic reply with the uuid, the real error rides along as cause for the webhook\n * throw new Fault({ cause });\n *\n * // pass report: false to show the same reply without publishing to the handledException bus\n * // throw new Fault({ cause, report: false });\n * }\n * ```\n */\nexport class Fault extends Notice {\n public constructor(options?: { cause?: unknown; report?: boolean }) {\n super('A fault occurred', options?.cause === undefined ? undefined : { cause: options.cause });\n this.report = options?.report ?? true;\n }\n\n public render(ctx: RenderContext): ReplyResponse {\n const contact = ctx.developerUsername ?? 'the developer';\n const card = new NoticeCard(\n `Something went wrong. Please reach out to ${contact} with a way to reproduce the error and the following:\\n### UUID: \\`${ctx.uuid}\\``,\n 'Error'\n );\n return { components: [card.component] };\n }\n}\n","import { NeedsAny, NotAllowed } from '@notices/index';\nimport { Fault } from '@stops/Fault';\nimport { Notice } from '@stops/Notice';\n\nimport { markCommits, rollbackCommits, runCheck } from './effects';\nimport { defineGate } from './Gate';\n\nimport type { Gate, GateContextBase, RequiredOf } from './Gate';\nimport type { IntersectRequired, JoinNames, TwoOrMore } from './matching';\n\n/**\n * Runs each gate in order and refuses on the first refusal. Takes two or more arms. The required\n * context is the intersection of the arms, so an event-only and an interaction-only gate cannot be\n * combined.\n *\n * @typeParam Gates - The tuple of two or more gate arms, run left to right.\n * @param gates - The gate arms to run in order, all refused on the first refusal.\n *\n * @see {@link or}\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(and(GuildOnly(), RequirePermissions([PermissionFlagsBits.BanMembers])))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function and<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<IntersectRequired<Gates> & GateContextBase, JoinNames<Gates, ' & '>>;\nexport function and(...gates: readonly Gate<GateContextBase>[]): Gate<GateContextBase> {\n return defineGate(gates.map((gate) => gate.name).join(' & '), async (ctx) => {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n });\n}\n\n// the caller-supplied refusal when every or arm refuses, replacing the default list or neutral refusal\ninterface OrOptions {\n fail: Notice | ((ctx: GateContextBase) => Notice);\n}\n\n// a gate has a check method, the options object does not\nfunction isOrOptions(arg: Gate<GateContextBase> | OrOptions): arg is OrOptions {\n return !('check' in arg);\n}\n\n/**\n * Runs each gate in order and passes on the first arm that passes. Takes two or more arms. The\n * required context is the union of the arms, so a handler that matches any one arm fits. When every\n * arm refuses it throws the trailing {@link OrOptions} `fail` if given, else an auto list of the\n * arms derived from the summary field, else a default refusal. The trailing options object does not\n * count as an arm.\n *\n * @typeParam Gates - The tuple of two or more gate arms, tried left to right.\n * @param gates - The gate arms to try in order, with an optional trailing {@link OrOptions} object.\n *\n * @see {@link and}\n *\n * @example\n * ```ts\n * \\@Gated(or(OwnerOnly(), RequireRole('123456789012345678')))\n * \\@SlashRoute('admin')\n * class AdminHandler extends SlashHandler<'admin'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\n/**\n * @example\n * ```ts\n * // custom refusal when every arm refuses\n * or(OwnerOnly(), RequireRole('123456789012345678'), { fail: new NotAllowedNotice() });\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...args: [...Gates, OrOptions]\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\nexport function or(...args: readonly (Gate<GateContextBase> | OrOptions)[]): Gate<GateContextBase> {\n const last = args.at(-1);\n const options = last !== undefined && isOrOptions(last) ? last : undefined;\n const gates = (options ? args.slice(0, -1) : args) as readonly Gate<GateContextBase>[];\n\n return defineGate(gates.map((gate) => gate.name).join(' | '), async (ctx) => {\n const summaries: string[] = [];\n let everyArmHasSummary = true;\n for (const gate of gates) {\n const mark = markCommits(ctx);\n try {\n await runCheck(gate, ctx);\n return;\n } catch (error) {\n // only a refusal is an arm declining, a Fault (even report-false), a Silence, or a raw error stops everything\n if (error instanceof Notice && !(error instanceof Fault) && !error.report) {\n // the arm may have queued an effect's commit before refusing, drop it so the winner does not carry it\n rollbackCommits(ctx, mark);\n if (error.summary === undefined) everyArmHasSummary = false;\n else summaries.push(error.summary);\n continue;\n }\n throw error;\n }\n }\n if (options) throw typeof options.fail === 'function' ? options.fail(ctx) : options.fail;\n // the auto-list shows only when every refusal gave a summary, a partial list would mislead by omission\n if (everyArmHasSummary && summaries.length > 0) throw new NeedsAny(summaries);\n throw new NotAllowed();\n });\n}\n","import { defineGate } from '@gates/Gate';\nimport { NotInDm, NotInGuild, NotOwner } from '@notices/index';\n\nimport { pickNotice } from './options';\n\nimport type { GateNoticeOptions } from './options';\nimport type { Gate, GateContextBase } from '@gates/Gate';\n\n/**\n * Passes only for a user id listed in `config.ownerIds`, else refuses.\n *\n * Agnostic, so it attaches to interaction and event handlers alike. With no `ownerIds` configured it refuses every caller. Pass {@link GateNoticeOptions} to reword or replace the refusal.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(OwnerOnly())\n * \\@SlashRoute('shutdown')\n * class ShutdownHandler extends SlashHandler<'shutdown'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // reword the refusal, keeping the embed styling\n * OwnerOnly({ message: 'Owners only.' });\n * ```\n */\nexport function OwnerOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'OwnerOnly'> {\n return defineGate('OwnerOnly', (ctx) => {\n const owners = ctx.core.config.ownerIds ?? [];\n if (ctx.userId !== null && owners.includes(ctx.userId)) return;\n throw pickNotice(options, (message) => new NotOwner(message));\n });\n}\n\n/**\n * Passes inside a guild, else refuses.\n *\n * Agnostic, so it attaches to any handler kind. Often paired with `RequirePermissions` in an {@link and}.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\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 * // ...\n * }\n * }\n * ```\n */\nexport function GuildOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'GuildOnly'> {\n return defineGate('GuildOnly', (ctx) => {\n if (ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInGuild(message));\n });\n}\n\n/**\n * Passes in a direct message, else refuses.\n *\n * Agnostic, so it attaches to any handler kind. The inverse of {@link GuildOnly}, so combining the two in an {@link and} can never pass.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(DmOnly())\n * \\@SlashRoute('verify')\n * class VerifyHandler extends SlashHandler<'verify'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function DmOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'DmOnly'> {\n return defineGate('DmOnly', (ctx) => {\n if (!ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInDm(message));\n });\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordTypeError } from '@seedcord/errors/internal';\nimport { parseDuration, type ValidDuration } from '@seedcord/utils';\n\nimport { defineEffectGate } from '@gates/Gate';\nimport { OnCooldown } from '@notices/index';\n\nimport type { EffectGate, GateContextBase } from '@gates/Gate';\nimport type { EpochMs } from '@seedcord/types';\nimport type { Notice } from '@stops/Notice';\n\n/**\n * Options for {@link Cooldown}. `per` sets the bucket the window applies to and `limit` the uses allowed per\n * window. `message` rewords the refusal and `notice` replaces it, both receiving the epoch ms the key frees\n * up so the refusal can show the retry time.\n *\n * @example\n * ```ts\n * // one use per channel, rewording the refusal with the retry time\n * Cooldown('10s', {\n * per: 'channel',\n * message: (resetAt) => `Slow down. Try again <t:${Math.round(resetAt / 1000)}:R>.`\n * });\n * ```\n *\n * @example\n * ```ts\n * // five uses per minute, per user\n * Cooldown('1m', { limit: 5 });\n * ```\n */\nexport interface CooldownOptions {\n /**\n * The bucket the cooldown window applies to. 'user' scopes by user ID, falls back to global when the source carries no user id. 'guild' scopes by guild ID (falls back to global if no guild), and 'channel' scopes by channel ID (falls back to global if no channel).\n *\n * @defaultValue `'user'`\n */\n per?: 'user' | 'guild' | 'channel';\n /**\n * Uses allowed inside one window before the gate refuses.\n *\n * @defaultValue `1`\n */\n limit?: number;\n /**\n * Reword the refusal, keeping the standard notice card. Receives the epoch ms the key frees up, so the\n * text can include the retry time with `<t:${Math.round(resetAt / 1000)}:R>`.\n */\n message?: (resetAt: EpochMs) => string;\n /**\n * Replace the refusal Notice entirely, for full control or a translated copy. Receives the epoch ms the\n * key frees up.\n */\n notice?: (resetAt: EpochMs) => Notice;\n}\n\n// off-route ctxs have no route to key on, so each Cooldown() gets its own id to keep unrelated event handlers isolated\nlet anonSeq = 0;\n\nfunction scopeValue(ctx: GateContextBase, per: 'user' | 'guild' | 'channel'): string {\n if (per === 'guild') return ctx.guildId ?? 'global';\n if (per === 'channel') return ctx.channelId ?? 'global';\n return ctx.userId ?? 'global';\n}\n\n/**\n * Allows `limit` uses per window, scoped by `per`. A number `duration` is **seconds**, a string is\n * a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError** at construction. The\n * slot is charged in commit, only after the whole gate set passes, so a later refusal never burns the cooldown.\n * That split also means two requests racing the same key can both pass before either charges the slot.\n * The key combines the handler's route with the window settings, so two different handlers keep separate\n * windows. Reword the refusal with {@link CooldownOptions.message} or replace it with {@link CooldownOptions.notice}.\n *\n * @param duration - A number is seconds, a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.\n * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n * @see {@link IRateLimiter}\n *\n * @example\n * ```ts\n * // a number argument is SECONDS\n * \\@Gated(Cooldown(5))\n * \\@SlashRoute('daily')\n * class DailyHandler extends SlashHandler<'daily'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // a string is a duration, here scoped per guild (the default is per user)\n * Cooldown('30m', { per: 'guild' });\n * ```\n *\n * @example\n * ```ts\n * // a burst, 3 uses per 10 minutes per user, then it refuses until a slot frees\n * \\@Gated(Cooldown('10m', { limit: 3 }))\n * \\@SlashRoute('report')\n * class ReportHandler extends SlashHandler<'report'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function Cooldown(\n duration: number | ValidDuration,\n options?: CooldownOptions\n): EffectGate<GateContextBase, 'Cooldown'> {\n let windowMs: number;\n if (typeof duration === 'number') {\n windowMs = duration * 1000;\n } else {\n const parsed = parseDuration(duration);\n if (parsed === null) throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [duration]);\n windowMs = parsed;\n }\n // a zero or negative window would never limit, refuse it the same way an unparseable string is refused\n if (windowMs <= 0) {\n throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [String(duration)]);\n }\n\n const per = options?.per ?? 'user';\n // omit limit when unset so the limiter applies its default of 1, exactOptionalPropertyTypes rejects an explicit undefined\n const window = options?.limit === undefined ? { windowMs } : { windowMs, limit: options.limit };\n const anonId = anonSeq++;\n // routed keys are stable across restarts, so a durable store rebuilds the same window\n const keyOf = (ctx: GateContextBase): string =>\n `cooldown:${ctx.routeId ?? `anon${anonId}`}:${per}:w${windowMs}:l${options?.limit ?? 1}:${scopeValue(ctx, per)}`;\n\n return defineEffectGate(\n 'Cooldown',\n async (ctx) => {\n const result = await ctx.core.rateLimiter.peek(keyOf(ctx), window);\n if (!result.limited) return;\n if (options?.notice) throw options.notice(result.resetAt);\n throw new OnCooldown(result.resetAt, options?.message?.(result.resetAt));\n },\n async (ctx) => {\n await ctx.core.rateLimiter.charge(keyOf(ctx), window);\n }\n );\n}\n","/**\n * Throw to stop a handler with no reply and no report.\n *\n * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.\n * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to\n * leave the user with no reply for an interaction.\n *\n * @example\n * ```ts\n * import { Silence } from '@seedcord/gateway';\n *\n * // before any reply or defer, drop the interaction with no reply and no report\n * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');\n * ```\n */\nexport class Silence extends Error {\n /**\n * @param reason - Optional note written only to a debug log, never shown to the user or reported.\n */\n public constructor(public readonly reason?: string) {\n super(reason ?? 'Silence');\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport type { PageView } from './PageView';\n\n/**\n * Pure page math, usable headless. Clamps `page` into range and slices the window.\n *\n * @param items - The full list to page over.\n * @param page - The requested zero-based page, clamped into `[0, totalPages - 1]`.\n * @param perPage - The page size. Must be a positive integer.\n * @returns The sliced {@link PageView}, with `totalPages` always known.\n * @throws SeedcordRangeError when `perPage` is not a positive integer.\n */\nexport function paginate<Item>(items: readonly Item[], page: number, perPage: number): PageView<Item> {\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n\n const totalPages = Math.max(1, Math.ceil(items.length / perPage));\n // a headless caller can pass a non-integer or out-of-range page.\n const clamped = Math.min(Math.max(Math.trunc(page), 0), totalPages - 1);\n const start = clamped * perPage;\n\n return {\n items: items.slice(start, start + perPage),\n page: clamped,\n perPage,\n totalPages,\n hasPrev: clamped > 0,\n hasNext: clamped < totalPages - 1\n };\n}\n","import 'reflect-metadata';\n\nexport type * from '@registries/ContextMenuRegistry';\nexport type * from '@registries/SlashOptionRegistry';\n\nexport { RegisterCommand } from '@decorators/Command';\nexport { SelectMenuKind } from '@decorators/interactionRoutes';\nexport {\n AutocompleteRoute,\n ButtonRoute,\n ContextMenuRoute,\n ModalRoute,\n SelectMenuRoute,\n SlashRoute\n} from '@decorators/routes';\n\nexport { DispatchContext } from '@src/dispatch/DispatchContext';\nexport type { DispatchState } from '@src/dispatch/DispatchContext';\n\nexport { BaseHandler } from '@src/handlers/BaseHandler';\nexport { RepliableHandler } from '@src/handlers/RepliableHandler';\n\nexport type { CoreBase } from '@interfaces/CoreBase';\n\nexport { defineEffectGate, defineGate } from '@gates/Gate';\nexport type { EffectGate, Gate, GateContextBase, GuildPermissionsContext, RequiredOf } from '@gates/Gate';\nexport { and, or } from '@gates/combinators';\nexport { DmOnly, GuildOnly, OwnerOnly } from '@gates/catalog/access';\nexport { Cooldown, type CooldownOptions } from '@gates/catalog/Cooldown';\nexport { RequireBotPermissions, RequirePermissions, RequireRole } from '@gates/catalog/permissions';\nexport type { PermissionScope, RequirePermissionsOptions, RequireRoleOptions } from '@gates/catalog/permissions';\nexport type { GateNoticeOptions } from '@gates/catalog/options';\n\nexport { BuilderComponent, RowComponent } from '@components/Component';\nexport { type RowType, type BuilderType } from '@components/builderTypes';\n\nexport { Notice } from '@stops/Notice';\nexport { Fault } from '@stops/Fault';\nexport { Silence } from '@stops/Silence';\n\nexport { CustomId } from '@customId/CustomId';\n\nexport type { AutocompleteOptions } from '@inputs/AutocompleteOptions';\n\nexport { paginate } from '@pagination/paginate';\nexport { type PageView } from '@pagination/PageView';\n\n/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["CommandMetadataKey","SeedcordError","SeedcordErrorCode","contextMenuRouteOf","selectMenuRouteOf","Logger","Notice","NoticeCard","defineGate","runCheck","markCommits","Notice","NeedsAny","NotAllowed","defineGate","pickNotice","NotOwner","NotInGuild","NotInDm","SeedcordTypeError","SeedcordErrorCode","defineEffectGate","OnCooldown","SeedcordRangeError","SeedcordErrorCode"],"sources":["../src/decorators/Command.ts","../src/decorators/routes.ts","../src/dispatch/DispatchContext.ts","../src/handlers/BaseHandler.ts","../src/handlers/RepliableHandler.ts","../src/stops/Fault.ts","../src/gates/combinators.ts","../src/gates/catalog/access.ts","../src/gates/catalog/Cooldown.ts","../src/stops/Silence.ts","../src/pagination/paginate.ts","../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { CommandMetadataKey } from '@src/metadataKeys';\n\nimport type { BuilderComponent } from '@components/Component';\nimport type { Constructor } from 'type-fest';\n\ntype CommandCtor = Constructor<BuilderComponent<'command' | 'context_menu'>>;\n\ninterface GlobalMeta {\n scope: 'global';\n}\n\ninterface GuildMeta {\n scope: 'guild';\n guilds: string[];\n}\n\nexport type CommandMeta = GlobalMeta | GuildMeta;\n\ntype CommandScope = CommandMeta['scope'];\n\n/**\n * Attaches deployment metadata so the framework registers this command globally or in specific guilds.\n *\n * @param scope - Must be 'global' for global registration\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('global')\n * class PingCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'global'): (ctor: CommandCtor) => void;\n\n/**\n * Registers a command for specific guild deployment.\n *\n * @param scope - Must be 'guild' for guild-specific registration\n * @param guilds - Array of guild IDs where the command should be registered\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('guild', ['123456789'])\n * class AdminCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'guild', guilds: string[]): (ctor: CommandCtor) => void;\n\nexport function RegisterCommand(scope: CommandScope, guilds: string[] = []) {\n return (ctor: CommandCtor): void => {\n const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n if (existingMeta) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [\n ctor.name,\n existingMeta.scope,\n scope\n ]);\n }\n\n if (scope === 'global' && guilds.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);\n }\n\n if (scope === 'guild' && (!Array.isArray(guilds) || guilds.length === 0)) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);\n }\n\n const meta: GlobalMeta | GuildMeta = scope === 'global' ? { scope } : { scope, guilds };\n Reflect.defineMetadata(CommandMetadataKey, meta, ctor);\n };\n}\n","import {\n contextMenuRouteOf,\n selectMenuRouteOf,\n storeComponentRoute,\n storeInteractionRoute\n} from '@decorators/interactionRoutes';\nimport { InteractionRoutes } from '@src/metadataKeys';\n\nimport type { AnyCustomId } from '@customId/CustomId';\nimport type { SelectMenuKind } from '@decorators/interactionRoutes';\nimport type { MessageContextMenuRegistry, UserContextMenuRegistry } from '@registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '@registries/SlashOptionRegistry';\nimport type { ApplicationCommandType } from 'discord-api-types/v10';\nimport type { Constructor } from 'type-fest';\n\ntype ContextMenuKind = ApplicationCommandType.User | ApplicationCommandType.Message;\n\ntype ComponentBrand = 'button' | 'modal' | SelectMenuKind;\n\n// phantom brands keep the decorators off transport-specific classes\ntype AnyHandlerCtor = new (...args: any[]) => unknown;\n\ntype SlashRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __slashRoute?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype AutocompleteRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __autocompleteRoute?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype ContextMenuKindOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __ctxKind?: infer Kind extends ContextMenuKind;\n }\n ? Kind\n : never;\n\ntype ComponentOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __component?: infer Brand extends ComponentBrand;\n }\n ? Brand\n : never;\n\ntype DefsOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __componentDefs?: infer Defs extends readonly AnyCustomId[];\n }\n ? Defs\n : never;\n\ntype AssertSlashRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n SlashRouteOf<TCtor>\n]\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\ntype AssertAutocompleteRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n AutocompleteRouteOf<TCtor>\n]\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\ntype AssertContextMenuRoute<Kind extends ContextMenuKind, TCtor extends AnyHandlerCtor> = [Kind] extends [\n ContextMenuKindOf<TCtor>\n]\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// one assignability direction for the defs, a bidirectional check would reject const-inferred readonly tuples\ntype AssertComponentRoute<\n Brand extends ComponentBrand,\n Defs extends readonly AnyCustomId[],\n TCtor extends AnyHandlerCtor\n> = [ComponentOf<TCtor>] extends [Brand]\n ? [Brand] extends [ComponentOf<TCtor>]\n ? [DefsOf<TCtor>] extends [Defs]\n ? TCtor\n : Constructor<['the customId definitions do not match the handler generic', DefsOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>;\n\ntype NamesFor<Kind extends ContextMenuKind> = Kind extends ApplicationCommandType.User\n ? keyof UserContextMenuRegistry\n : keyof MessageContextMenuRegistry;\n\n/**\n * Routes one or more slash commands to a `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 */\nexport function SlashRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertSlashRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Slash, routes, constructor);\n };\n}\n\n/**\n * Routes one or more commands' autocomplete to an `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 AnyHandlerCtor>(constructor: AssertAutocompleteRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Autocomplete, routes, constructor);\n };\n}\n\n/**\n * Routes one or more context-menu commands to a `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 handler's generic must\n * declare the same kind, cross-checked both directions. Context menus carry no options, so a multi-name\n * handler 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 ContextMenuKind>(kind: Kind, ...names: NamesFor<Kind>[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertContextMenuRoute<Kind, TCtor>): void {\n storeInteractionRoute(contextMenuRouteOf(kind), names, constructor);\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 AnyHandlerCtor>(constructor: AssertComponentRoute<'button', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Button, defs, constructor);\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 AnyHandlerCtor>(constructor: AssertComponentRoute<'modal', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Modal, defs, constructor);\n };\n}\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 kind and definitions, 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 * ```\n */\nexport function SelectMenuRoute<const Kind extends SelectMenuKind, const Defs extends readonly AnyCustomId[]>(\n type: Kind,\n ...defs: Defs\n) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<Kind, Defs, TCtor>): void {\n storeComponentRoute(selectMenuRouteOf(type), defs, constructor);\n };\n}\n","/**\n * The per-dispatch bag. Any code can merge fields into it by declaration merging, the\n * same pattern as {@link SlashOptionRegistry}. It stays empty until one does, so `keyof DispatchState` is\n * `never` and the bag is inert.\n */\nexport interface DispatchState {}\n\n/**\n * A typed bag allocated once per interaction dispatch and handed to the handler. The middleware and i18n\n * work reads and writes it through {@link DispatchState}. Today the bag is empty, so it only carries the\n * dispatched `routeId`.\n */\nexport class DispatchContext {\n private readonly state: Partial<DispatchState> = {};\n\n constructor(public readonly routeId: string | null) {}\n\n set<Key extends keyof DispatchState>(key: Key, value: DispatchState[Key]): void {\n this.state[key] = value;\n }\n\n get<Key extends keyof DispatchState>(key: Key): DispatchState[Key] | undefined {\n return this.state[key];\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { DispatchContext } from '@src/dispatch/DispatchContext';\n\n/**\n * Base class every transport handler extends. Don't register handlers directly, use the more specific\n * handler subclasses.\n *\n * @typeParam Event - The event or interaction this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class BaseHandler<Event, TCore extends CoreBase> {\n protected readonly event: Event;\n protected readonly logger: Logger;\n // absent on event handlers\n protected readonly dispatch?: DispatchContext | undefined;\n\n protected constructor(\n event: Event,\n public readonly core: TCore,\n dispatch?: DispatchContext\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name);\n this.dispatch = dispatch;\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","import { BaseHandler } from './BaseHandler';\n\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { BaseReplySender } from '@reply/BaseReplySender';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { DispatchContext } from '@src/dispatch/DispatchContext';\n\n/**\n * Shared base the repliable handlers on both transports extend. Defines the reply members over the sender\n * the transport builds.\n *\n * @typeParam Event - The repliable interaction type this handler processes\n * @typeParam TCore - The transport's Core\n * @typeParam TMessage - The transport's created-message lens\n * @typeParam TSender - The transport's reply sender\n */\nexport abstract class RepliableHandler<\n Event,\n TCore extends CoreBase,\n TMessage extends { id: string },\n TSender extends BaseReplySender<TMessage>\n> extends BaseHandler<Event, TCore> {\n protected readonly sender: TSender;\n protected readonly routeId: string;\n\n protected constructor(event: Event, core: TCore, dispatch?: DispatchContext) {\n super(event, core, dispatch);\n this.routeId = dispatch?.routeId ?? this.constructor.name;\n // runs inside the ctor, an override builds from its arguments only, subclass fields are not initialized yet\n this.sender = this.buildSender(event, core, this.routeId);\n }\n\n protected abstract buildSender(event: Event, core: TCore, routeId: string): TSender;\n\n /** @internal The dispatcher's fault boundary replies through the live ack state. */\n public getSender(): TSender {\n return this.sender;\n }\n\n /** Send the initial response, exactly once. */\n protected reply(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.reply(response, opts);\n }\n\n /** Show a \"thinking\" placeholder, then fill it later with {@link edit}. */\n protected defer(opts?: DeferOpts): Promise<void> {\n return this.sender.defer(opts);\n }\n\n /** Send a new message once the interaction is acknowledged. */\n protected followUp(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.followUp(response, opts);\n }\n\n /** Rewrite the initial reply or deferred placeholder. The targeted form rewrites a message a prior send returned. */\n protected edit(response: ReplyResponse | string): Promise<TMessage>;\n protected edit(target: TMessage, response: ReplyResponse | string): Promise<TMessage>;\n protected edit(\n targetOrResponse: TMessage | ReplyResponse | string,\n maybeResponse?: ReplyResponse | string\n ): Promise<TMessage> {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n if (maybeResponse === undefined) return this.sender.edit(targetOrResponse as ReplyResponse | string);\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n return this.sender.edit(targetOrResponse as TMessage, maybeResponse);\n }\n\n /** Routes to reply, followUp, or edit based on the current ack state. */\n protected send(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.send(response, opts);\n }\n\n /** Delete the initial reply or deferred placeholder. Pass a target to delete a message a prior send returned. */\n protected delete(target?: TMessage): Promise<void> {\n return target === undefined ? this.sender.delete() : this.sender.delete(target);\n }\n}\n","import { Notice } from './Notice';\nimport { NoticeCard } from './NoticeCard';\n\nimport type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * A generic fault you throw after catching an error you do not have a specific message for.\n *\n * The user sees a fixed generic reply with the tracking uuid, never the cause. `report` defaults to\n * `true`, so the framework logs it and publishes it to the `handledException` bus. Pass `report: false`\n * to show the generic reply without the bus publish. The original error is stored as the standard\n * `cause`, so the real stack reaches the webhook. For a fault the user should see a real message,\n * subclass {@link Notice} and write your own `render` instead.\n *\n * The framework also renders this for an unhandled throw, where it points the user at\n * `ctx.developerUsername`.\n *\n * @example\n * ```ts\n * import { Fault } from '@seedcord/gateway';\n *\n * try {\n * await db.write(record);\n * } catch (cause) {\n * // user sees the generic reply with the uuid, the real error rides along as cause for the webhook\n * throw new Fault({ cause });\n *\n * // pass report: false to show the same reply without publishing to the handledException bus\n * // throw new Fault({ cause, report: false });\n * }\n * ```\n */\nexport class Fault extends Notice {\n public constructor(options?: { cause?: unknown; report?: boolean }) {\n super('A fault occurred', options?.cause === undefined ? undefined : { cause: options.cause });\n this.report = options?.report ?? true;\n }\n\n public render(ctx: RenderContext): ReplyResponse {\n const contact = ctx.developerUsername ?? 'the developer';\n const card = new NoticeCard(\n `Something went wrong. Please reach out to ${contact} with a way to reproduce the error and the following:\\n### UUID: \\`${ctx.uuid}\\``,\n 'Error'\n );\n return { components: [card.component] };\n }\n}\n","import { NeedsAny, NotAllowed } from '@notices/index';\nimport { Fault } from '@stops/Fault';\nimport { Notice } from '@stops/Notice';\n\nimport { markCommits, rollbackCommits, runCheck } from './effects';\nimport { defineGate } from './Gate';\n\nimport type { Gate, GateContextBase, RequiredOf } from './Gate';\nimport type { IntersectRequired, JoinNames, TwoOrMore } from './matching';\n\n/**\n * Runs each gate in order and refuses on the first refusal. Takes two or more arms. The required\n * context is the intersection of the arms, so an event-only and an interaction-only gate cannot be\n * combined.\n *\n * @typeParam Gates - The tuple of two or more gate arms, run left to right.\n * @param gates - The gate arms to run in order, all refused on the first refusal.\n *\n * @see {@link or}\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(and(GuildOnly(), RequirePermissions([PermissionFlagsBits.BanMembers])))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function and<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<IntersectRequired<Gates> & GateContextBase, JoinNames<Gates, ' & '>>;\nexport function and(...gates: readonly Gate<GateContextBase>[]): Gate<GateContextBase> {\n return defineGate(gates.map((gate) => gate.name).join(' & '), async (ctx) => {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n });\n}\n\n// the caller-supplied refusal when every or arm refuses, replacing the default list or neutral refusal\ninterface OrOptions {\n fail: Notice | ((ctx: GateContextBase) => Notice);\n}\n\n// a gate has a check method, the options object does not\nfunction isOrOptions(arg: Gate<GateContextBase> | OrOptions): arg is OrOptions {\n return !('check' in arg);\n}\n\n/**\n * Runs each gate in order and passes on the first arm that passes. Takes two or more arms. The\n * required context is the union of the arms, so a handler that matches any one arm fits. When every\n * arm refuses it throws the trailing {@link OrOptions} `fail` if given, else an auto list of the\n * arms derived from the summary field, else a default refusal. The trailing options object does not\n * count as an arm.\n *\n * @typeParam Gates - The tuple of two or more gate arms, tried left to right.\n * @param gates - The gate arms to try in order, with an optional trailing {@link OrOptions} object.\n *\n * @see {@link and}\n *\n * @example\n * ```ts\n * \\@Gated(or(OwnerOnly(), RequireRole('123456789012345678')))\n * \\@SlashRoute('admin')\n * class AdminHandler extends SlashHandler<'admin'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\n/**\n * @example\n * ```ts\n * // custom refusal when every arm refuses\n * or(OwnerOnly(), RequireRole('123456789012345678'), { fail: new NotAllowedNotice() });\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...args: [...Gates, OrOptions]\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\nexport function or(...args: readonly (Gate<GateContextBase> | OrOptions)[]): Gate<GateContextBase> {\n const last = args.at(-1);\n const options = last !== undefined && isOrOptions(last) ? last : undefined;\n const gates = (options ? args.slice(0, -1) : args) as readonly Gate<GateContextBase>[];\n\n return defineGate(gates.map((gate) => gate.name).join(' | '), async (ctx) => {\n const summaries: string[] = [];\n let everyArmHasSummary = true;\n for (const gate of gates) {\n const mark = markCommits(ctx);\n try {\n await runCheck(gate, ctx);\n return;\n } catch (error) {\n // only a refusal is an arm declining, a Fault (even report-false), a Silence, or a raw error stops everything\n if (error instanceof Notice && !(error instanceof Fault) && !error.report) {\n // the arm may have queued an effect's commit before refusing, drop it so the winner does not carry it\n rollbackCommits(ctx, mark);\n if (error.summary === undefined) everyArmHasSummary = false;\n else summaries.push(error.summary);\n continue;\n }\n throw error;\n }\n }\n if (options) throw typeof options.fail === 'function' ? options.fail(ctx) : options.fail;\n // the auto-list shows only when every refusal gave a summary, a partial list would mislead by omission\n if (everyArmHasSummary && summaries.length > 0) throw new NeedsAny(summaries);\n throw new NotAllowed();\n });\n}\n","import { defineGate } from '@gates/Gate';\nimport { NotInDm, NotInGuild, NotOwner } from '@notices/index';\n\nimport { pickNotice } from './options';\n\nimport type { GateNoticeOptions } from './options';\nimport type { Gate, GateContextBase } from '@gates/Gate';\n\n/**\n * Passes only for a user id listed in `config.ownerIds`, else refuses.\n *\n * Agnostic, so it attaches to interaction and event handlers alike. With no `ownerIds` configured it refuses every caller. Pass {@link GateNoticeOptions} to reword or replace the refusal.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(OwnerOnly())\n * \\@SlashRoute('shutdown')\n * class ShutdownHandler extends SlashHandler<'shutdown'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // reword the refusal, keeping the embed styling\n * OwnerOnly({ message: 'Owners only.' });\n * ```\n */\nexport function OwnerOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'OwnerOnly'> {\n return defineGate('OwnerOnly', (ctx) => {\n const owners = ctx.core.config.ownerIds ?? [];\n if (ctx.userId !== null && owners.includes(ctx.userId)) return;\n throw pickNotice(options, (message) => new NotOwner(message));\n });\n}\n\n/**\n * Passes inside a guild, else refuses.\n *\n * Agnostic, so it attaches to any handler kind. Often paired with `RequirePermissions` in an {@link and}.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\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 * // ...\n * }\n * }\n * ```\n */\nexport function GuildOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'GuildOnly'> {\n return defineGate('GuildOnly', (ctx) => {\n if (ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInGuild(message));\n });\n}\n\n/**\n * Passes in a direct message, else refuses.\n *\n * Agnostic, so it attaches to any handler kind. The inverse of {@link GuildOnly}, so combining the two in an {@link and} can never pass.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(DmOnly())\n * \\@SlashRoute('verify')\n * class VerifyHandler extends SlashHandler<'verify'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function DmOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'DmOnly'> {\n return defineGate('DmOnly', (ctx) => {\n if (!ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInDm(message));\n });\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordTypeError } from '@seedcord/errors/internal';\nimport { parseDuration, type ValidDuration } from '@seedcord/utils';\n\nimport { defineEffectGate } from '@gates/Gate';\nimport { OnCooldown } from '@notices/index';\n\nimport type { EffectGate, GateContextBase } from '@gates/Gate';\nimport type { EpochMs } from '@seedcord/types';\nimport type { Notice } from '@stops/Notice';\n\n/**\n * Options for {@link Cooldown}. `per` sets the bucket the window applies to and `limit` the uses allowed per\n * window. `message` rewords the refusal and `notice` replaces it, both receiving the epoch ms the key frees\n * up so the refusal can show the retry time.\n *\n * @example\n * ```ts\n * // one use per channel, rewording the refusal with the retry time\n * Cooldown('10s', {\n * per: 'channel',\n * message: (resetAt) => `Slow down. Try again <t:${Math.round(resetAt / 1000)}:R>.`\n * });\n * ```\n *\n * @example\n * ```ts\n * // five uses per minute, per user\n * Cooldown('1m', { limit: 5 });\n * ```\n */\nexport interface CooldownOptions {\n /**\n * The bucket the cooldown window applies to. 'user' scopes by user ID, falls back to global when the source carries no user id. 'guild' scopes by guild ID (falls back to global if no guild), and 'channel' scopes by channel ID (falls back to global if no channel).\n *\n * @defaultValue `'user'`\n */\n per?: 'user' | 'guild' | 'channel';\n /**\n * Uses allowed inside one window before the gate refuses.\n *\n * @defaultValue `1`\n */\n limit?: number;\n /**\n * Reword the refusal, keeping the standard notice card. Receives the epoch ms the key frees up, so the\n * text can include the retry time with `<t:${Math.round(resetAt / 1000)}:R>`.\n */\n message?: (resetAt: EpochMs) => string;\n /**\n * Replace the refusal Notice entirely, for full control or a translated copy. Receives the epoch ms the\n * key frees up.\n */\n notice?: (resetAt: EpochMs) => Notice;\n}\n\n// off-route ctxs have no route to key on, so each Cooldown() gets its own id to keep unrelated event handlers isolated\nlet anonSeq = 0;\n\nfunction scopeValue(ctx: GateContextBase, per: 'user' | 'guild' | 'channel'): string {\n if (per === 'guild') return ctx.guildId ?? 'global';\n if (per === 'channel') return ctx.channelId ?? 'global';\n return ctx.userId ?? 'global';\n}\n\n/**\n * Allows `limit` uses per window, scoped by `per`. A number `duration` is **seconds**, a string is\n * a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError** at construction. The\n * slot is charged in commit, only after the whole gate set passes, so a later refusal never burns the cooldown.\n * That split also means two requests racing the same key can both pass before either charges the slot.\n * The key combines the handler's route with the window settings, so two different handlers keep separate\n * windows. Reword the refusal with {@link CooldownOptions.message} or replace it with {@link CooldownOptions.notice}.\n *\n * @param duration - A number is seconds, a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.\n * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n * @see {@link IRateLimiter}\n *\n * @example\n * ```ts\n * // a number argument is SECONDS\n * \\@Gated(Cooldown(5))\n * \\@SlashRoute('daily')\n * class DailyHandler extends SlashHandler<'daily'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // a string is a duration, here scoped per guild (the default is per user)\n * Cooldown('30m', { per: 'guild' });\n * ```\n *\n * @example\n * ```ts\n * // a burst, 3 uses per 10 minutes per user, then it refuses until a slot frees\n * \\@Gated(Cooldown('10m', { limit: 3 }))\n * \\@SlashRoute('report')\n * class ReportHandler extends SlashHandler<'report'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function Cooldown(\n duration: number | ValidDuration,\n options?: CooldownOptions\n): EffectGate<GateContextBase, 'Cooldown'> {\n let windowMs: number;\n if (typeof duration === 'number') {\n windowMs = duration * 1000;\n } else {\n const parsed = parseDuration(duration);\n if (parsed === null) throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [duration]);\n windowMs = parsed;\n }\n // a zero or negative window would never limit, refuse it the same way an unparseable string is refused\n if (windowMs <= 0) {\n throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [String(duration)]);\n }\n\n const per = options?.per ?? 'user';\n // omit limit when unset so the limiter applies its default of 1, exactOptionalPropertyTypes rejects an explicit undefined\n const window = options?.limit === undefined ? { windowMs } : { windowMs, limit: options.limit };\n const anonId = anonSeq++;\n // routed keys are stable across restarts, so a durable store rebuilds the same window\n const keyOf = (ctx: GateContextBase): string =>\n `cooldown:${ctx.routeId ?? `anon${anonId}`}:${per}:w${windowMs}:l${options?.limit ?? 1}:${scopeValue(ctx, per)}`;\n\n return defineEffectGate(\n 'Cooldown',\n async (ctx) => {\n const result = await ctx.core.rateLimiter.peek(keyOf(ctx), window);\n if (!result.limited) return;\n if (options?.notice) throw options.notice(result.resetAt);\n throw new OnCooldown(result.resetAt, options?.message?.(result.resetAt));\n },\n async (ctx) => {\n await ctx.core.rateLimiter.charge(keyOf(ctx), window);\n }\n );\n}\n","/**\n * Throw to stop a handler with no reply and no report.\n *\n * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.\n * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to\n * leave the user with no reply for an interaction.\n *\n * @example\n * ```ts\n * import { Silence } from '@seedcord/gateway';\n *\n * // before any reply or defer, drop the interaction with no reply and no report\n * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');\n * ```\n */\nexport class Silence extends Error {\n /**\n * @param reason - Optional note written only to a debug log, never shown to the user or reported.\n */\n public constructor(public readonly reason?: string) {\n super(reason ?? 'Silence');\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport type { PageView } from './PageView';\n\n/**\n * Pure page math, usable headless. Clamps `page` into range and slices the window.\n *\n * @param items - The full list to page over.\n * @param page - The requested zero-based page, clamped into `[0, totalPages - 1]`.\n * @param perPage - The page size. Must be a positive integer.\n * @returns The sliced {@link PageView}, with `totalPages` always known.\n * @throws SeedcordRangeError when `perPage` is not a positive integer.\n */\nexport function paginate<Item>(items: readonly Item[], page: number, perPage: number): PageView<Item> {\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n\n const totalPages = Math.max(1, Math.ceil(items.length / perPage));\n // a headless caller can pass a non-integer or out-of-range page.\n const clamped = Math.min(Math.max(Math.trunc(page), 0), totalPages - 1);\n const start = clamped * perPage;\n\n return {\n items: items.slice(start, start + perPage),\n page: clamped,\n perPage,\n totalPages,\n hasPrev: clamped > 0,\n hasNext: clamped < totalPages - 1\n };\n}\n","import 'reflect-metadata';\n\nexport type * from '@registries/ContextMenuRegistry';\nexport type * from '@registries/SlashOptionRegistry';\n\nexport { RegisterCommand } from '@decorators/Command';\nexport { SelectMenuKind } from '@decorators/interactionRoutes';\nexport {\n AutocompleteRoute,\n ButtonRoute,\n ContextMenuRoute,\n ModalRoute,\n SelectMenuRoute,\n SlashRoute\n} from '@decorators/routes';\n\nexport { DispatchContext } from '@src/dispatch/DispatchContext';\nexport type { DispatchState } from '@src/dispatch/DispatchContext';\n\nexport { BaseHandler } from '@src/handlers/BaseHandler';\nexport { RepliableHandler } from '@src/handlers/RepliableHandler';\n\nexport type { CoreBase } from '@interfaces/CoreBase';\n\nexport type { Initializeable } from '@src/plugin/Plugin';\n// root-visible so a transport can augment it through `declare module '@seedcord/core'`\nexport type { PluginCapabilityTypes } from '@src/plugin/context';\n\nexport { ShutdownPhase, StartupPhase } from '@src/lifecycle/phases';\n\nexport { defineEffectGate, defineGate } from '@gates/Gate';\nexport type { EffectGate, Gate, GateContextBase, GuildPermissionsContext, RequiredOf } from '@gates/Gate';\nexport { and, or } from '@gates/combinators';\nexport { DmOnly, GuildOnly, OwnerOnly } from '@gates/catalog/access';\nexport { Cooldown, type CooldownOptions } from '@gates/catalog/Cooldown';\nexport { RequireBotPermissions, RequirePermissions, RequireRole } from '@gates/catalog/permissions';\nexport type { PermissionScope, RequirePermissionsOptions, RequireRoleOptions } from '@gates/catalog/permissions';\nexport type { GateNoticeOptions } from '@gates/catalog/options';\n\nexport { BuilderComponent, RowComponent } from '@components/Component';\nexport { type RowType, type BuilderType } from '@components/builderTypes';\n\nexport { Notice } from '@stops/Notice';\nexport { Fault } from '@stops/Fault';\nexport { Silence } from '@stops/Silence';\n\nexport { CustomId } from '@customId/CustomId';\n\nexport type { AutocompleteOptions } from '@inputs/AutocompleteOptions';\n\nexport { paginate } from '@pagination/paginate';\nexport { type PageView } from '@pagination/PageView';\n\n/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { C as GuildPermissionsContext, D as BaseReplySender, E as defineGate, G as CustomId,
|
|
1
|
+
import { C as GuildPermissionsContext, D as BaseReplySender, E as defineGate, G as CustomId, L as SelectMenuKind, S as GateContextBase, T as defineEffectGate, W as AnyCustomId, _ as JoinNames, b as EffectGate, c as RequireBotPermissions, ct as BuilderComponent, d as RequireRole, dt as RowType, f as RequireRoleOptions, ft as OptionKind, g as IntersectRequired, l as RequirePermissions, lt as RowComponent, mt as SlashOptionRegistry, n as AutocompleteOptions, ot as RegisterCommand, p as GateNoticeOptions, pt as SlashOption, s as PermissionScope, st as Constructor, u as RequirePermissionsOptions, ut as BuilderType, v as TwoOrMore, w as RequiredOf, x as Gate, y as Notice } from "./AutocompleteOptions-eKhIe6Qt.mjs";
|
|
2
|
+
import { f as CoreBase, l as PluginCapabilityTypes, o as ShutdownPhase, s as StartupPhase, t as Initializeable } from "./Plugin-CNyRKDHT.mjs";
|
|
2
3
|
import { ApplicationCommandType } from "discord-api-types/v10";
|
|
3
4
|
import { Logger } from "@seedcord/logger";
|
|
4
5
|
import { ValidDuration } from "@seedcord/utils";
|
|
@@ -556,5 +557,5 @@ declare function paginate<Item>(items: readonly Item[], page: number, perPage: n
|
|
|
556
557
|
/** Package version */
|
|
557
558
|
declare const version: string;
|
|
558
559
|
//#endregion
|
|
559
|
-
export { type AutocompleteOptions, AutocompleteRoute, BaseHandler, BuilderComponent, type BuilderType, ButtonRoute, ContextMenuRoute, Cooldown, type CooldownOptions, type CoreBase, CustomId, DispatchContext, type DispatchState, DmOnly, type EffectGate, Fault, type Gate, type GateContextBase, type GateNoticeOptions, GuildOnly, type GuildPermissionsContext, type MessageContextMenuRegistry, ModalRoute, Notice, type OptionKind, OwnerOnly, type PageView, type PermissionScope, RegisterCommand, RepliableHandler, RequireBotPermissions, RequirePermissions, type RequirePermissionsOptions, RequireRole, type RequireRoleOptions, type RequiredOf, RowComponent, type RowType, SelectMenuKind, SelectMenuRoute, Silence, type SlashOption, type SlashOptionRegistry, SlashRoute, type UserContextMenuRegistry, and, defineEffectGate, defineGate, or, paginate, version };
|
|
560
|
+
export { type AutocompleteOptions, AutocompleteRoute, BaseHandler, BuilderComponent, type BuilderType, ButtonRoute, ContextMenuRoute, Cooldown, type CooldownOptions, type CoreBase, CustomId, DispatchContext, type DispatchState, DmOnly, type EffectGate, Fault, type Gate, type GateContextBase, type GateNoticeOptions, GuildOnly, type GuildPermissionsContext, type Initializeable, type MessageContextMenuRegistry, ModalRoute, Notice, type OptionKind, OwnerOnly, type PageView, type PermissionScope, type PluginCapabilityTypes, RegisterCommand, RepliableHandler, RequireBotPermissions, RequirePermissions, type RequirePermissionsOptions, RequireRole, type RequireRoleOptions, type RequiredOf, RowComponent, type RowType, SelectMenuKind, SelectMenuRoute, ShutdownPhase, Silence, type SlashOption, type SlashOptionRegistry, SlashRoute, StartupPhase, type UserContextMenuRegistry, and, defineEffectGate, defineGate, or, paginate, version };
|
|
560
561
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as storeComponentRoute, E as selectMenuRouteOf, F as BuilderComponent, I as RowComponent, O as storeInteractionRoute, P as NoticeCard, R as Notice, S as SelectMenuKind, W as InteractionRoutes, _ as NotInGuild, a as pickNotice, b as defineEffectGate, c as rollbackCommits, g as NotInDm, h as NotAllowed, i as RequireRole, j as CustomId, l as runCheck, m as NeedsAny, n as RequireBotPermissions, r as RequirePermissions, s as markCommits, v as NotOwner, w as contextMenuRouteOf, x as defineGate, y as OnCooldown, z as CommandMetadataKey } from "./permissions-RVCBhL2n.mjs";
|
|
2
|
+
import { n as StartupPhase, t as ShutdownPhase } from "./phases-BfpAG6w3.mjs";
|
|
2
3
|
import "reflect-metadata";
|
|
3
4
|
import { SeedcordErrorCode } from "@seedcord/errors";
|
|
4
5
|
import { SeedcordError, SeedcordRangeError, SeedcordTypeError } from "@seedcord/errors/internal";
|
|
@@ -550,8 +551,8 @@ function paginate(items, page, perPage) {
|
|
|
550
551
|
//#endregion
|
|
551
552
|
//#region src/index.ts
|
|
552
553
|
/** Package version */
|
|
553
|
-
const version = "0.1.0-next.
|
|
554
|
+
const version = "0.1.0-next.6";
|
|
554
555
|
|
|
555
556
|
//#endregion
|
|
556
|
-
export { AutocompleteRoute, BaseHandler, BuilderComponent, ButtonRoute, ContextMenuRoute, Cooldown, CustomId, DispatchContext, DmOnly, Fault, GuildOnly, ModalRoute, Notice, OwnerOnly, RegisterCommand, RepliableHandler, RequireBotPermissions, RequirePermissions, RequireRole, RowComponent, SelectMenuKind, SelectMenuRoute, Silence, SlashRoute, and, defineEffectGate, defineGate, or, paginate, version };
|
|
557
|
+
export { AutocompleteRoute, BaseHandler, BuilderComponent, ButtonRoute, ContextMenuRoute, Cooldown, CustomId, DispatchContext, DmOnly, Fault, GuildOnly, ModalRoute, Notice, OwnerOnly, RegisterCommand, RepliableHandler, RequireBotPermissions, RequirePermissions, RequireRole, RowComponent, SelectMenuKind, SelectMenuRoute, ShutdownPhase, Silence, SlashRoute, StartupPhase, and, defineEffectGate, defineGate, or, paginate, version };
|
|
557
558
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/decorators/Command.ts","../src/decorators/routes.ts","../src/dispatch/DispatchContext.ts","../src/handlers/BaseHandler.ts","../src/handlers/RepliableHandler.ts","../src/stops/Fault.ts","../src/gates/combinators.ts","../src/gates/catalog/access.ts","../src/gates/catalog/Cooldown.ts","../src/stops/Silence.ts","../src/pagination/paginate.ts","../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { CommandMetadataKey } from '@src/metadataKeys';\n\nimport type { BuilderComponent } from '@components/Component';\nimport type { Constructor } from 'type-fest';\n\ntype CommandCtor = Constructor<BuilderComponent<'command' | 'context_menu'>>;\n\ninterface GlobalMeta {\n scope: 'global';\n}\n\ninterface GuildMeta {\n scope: 'guild';\n guilds: string[];\n}\n\nexport type CommandMeta = GlobalMeta | GuildMeta;\n\ntype CommandScope = CommandMeta['scope'];\n\n/**\n * Attaches deployment metadata so the framework registers this command globally or in specific guilds.\n *\n * @param scope - Must be 'global' for global registration\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('global')\n * class PingCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'global'): (ctor: CommandCtor) => void;\n\n/**\n * Registers a command for specific guild deployment.\n *\n * @param scope - Must be 'guild' for guild-specific registration\n * @param guilds - Array of guild IDs where the command should be registered\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('guild', ['123456789'])\n * class AdminCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'guild', guilds: string[]): (ctor: CommandCtor) => void;\n\nexport function RegisterCommand(scope: CommandScope, guilds: string[] = []) {\n return (ctor: CommandCtor): void => {\n const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n if (existingMeta) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [\n ctor.name,\n existingMeta.scope,\n scope\n ]);\n }\n\n if (scope === 'global' && guilds.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);\n }\n\n if (scope === 'guild' && (!Array.isArray(guilds) || guilds.length === 0)) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);\n }\n\n const meta: GlobalMeta | GuildMeta = scope === 'global' ? { scope } : { scope, guilds };\n Reflect.defineMetadata(CommandMetadataKey, meta, ctor);\n };\n}\n","import {\n contextMenuRouteOf,\n selectMenuRouteOf,\n storeComponentRoute,\n storeInteractionRoute\n} from '@decorators/interactionRoutes';\nimport { InteractionRoutes } from '@src/metadataKeys';\n\nimport type { AnyCustomId } from '@customId/CustomId';\nimport type { SelectMenuKind } from '@decorators/interactionRoutes';\nimport type { MessageContextMenuRegistry, UserContextMenuRegistry } from '@registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '@registries/SlashOptionRegistry';\nimport type { ApplicationCommandType } from 'discord-api-types/v10';\nimport type { Constructor } from 'type-fest';\n\ntype ContextMenuKind = ApplicationCommandType.User | ApplicationCommandType.Message;\n\ntype ComponentBrand = 'button' | 'modal' | SelectMenuKind;\n\n// phantom brands keep the decorators off transport-specific classes\ntype AnyHandlerCtor = new (...args: any[]) => unknown;\n\ntype SlashRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __slashRoute?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype AutocompleteRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __autocompleteRoute?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype ContextMenuKindOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __ctxKind?: infer Kind extends ContextMenuKind;\n }\n ? Kind\n : never;\n\ntype ComponentOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __component?: infer Brand extends ComponentBrand;\n }\n ? Brand\n : never;\n\ntype DefsOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __componentDefs?: infer Defs extends readonly AnyCustomId[];\n }\n ? Defs\n : never;\n\ntype AssertSlashRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n SlashRouteOf<TCtor>\n]\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\ntype AssertAutocompleteRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n AutocompleteRouteOf<TCtor>\n]\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\ntype AssertContextMenuRoute<Kind extends ContextMenuKind, TCtor extends AnyHandlerCtor> = [Kind] extends [\n ContextMenuKindOf<TCtor>\n]\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// one assignability direction for the defs, a bidirectional check would reject const-inferred readonly tuples\ntype AssertComponentRoute<\n Brand extends ComponentBrand,\n Defs extends readonly AnyCustomId[],\n TCtor extends AnyHandlerCtor\n> = [ComponentOf<TCtor>] extends [Brand]\n ? [Brand] extends [ComponentOf<TCtor>]\n ? [DefsOf<TCtor>] extends [Defs]\n ? TCtor\n : Constructor<['the customId definitions do not match the handler generic', DefsOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>;\n\ntype NamesFor<Kind extends ContextMenuKind> = Kind extends ApplicationCommandType.User\n ? keyof UserContextMenuRegistry\n : keyof MessageContextMenuRegistry;\n\n/**\n * Routes one or more slash commands to a `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 */\nexport function SlashRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertSlashRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Slash, routes, constructor);\n };\n}\n\n/**\n * Routes one or more commands' autocomplete to an `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 AnyHandlerCtor>(constructor: AssertAutocompleteRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Autocomplete, routes, constructor);\n };\n}\n\n/**\n * Routes one or more context-menu commands to a `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 handler's generic must\n * declare the same kind, cross-checked both directions. Context menus carry no options, so a multi-name\n * handler 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 ContextMenuKind>(kind: Kind, ...names: NamesFor<Kind>[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertContextMenuRoute<Kind, TCtor>): void {\n storeInteractionRoute(contextMenuRouteOf(kind), names, constructor);\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 AnyHandlerCtor>(constructor: AssertComponentRoute<'button', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Button, defs, constructor);\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 AnyHandlerCtor>(constructor: AssertComponentRoute<'modal', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Modal, defs, constructor);\n };\n}\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 kind and definitions, 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 * ```\n */\nexport function SelectMenuRoute<const Kind extends SelectMenuKind, const Defs extends readonly AnyCustomId[]>(\n type: Kind,\n ...defs: Defs\n) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<Kind, Defs, TCtor>): void {\n storeComponentRoute(selectMenuRouteOf(type), defs, constructor);\n };\n}\n","/**\n * The per-dispatch bag. Any code can merge fields into it by declaration merging, the\n * same pattern as {@link SlashOptionRegistry}. It stays empty until one does, so `keyof DispatchState` is\n * `never` and the bag is inert.\n */\nexport interface DispatchState {}\n\n/**\n * A typed bag allocated once per interaction dispatch and handed to the handler. The middleware and i18n\n * work reads and writes it through {@link DispatchState}. Today the bag is empty, so it only carries the\n * dispatched `routeId`.\n */\nexport class DispatchContext {\n private readonly state: Partial<DispatchState> = {};\n\n constructor(public readonly routeId: string | null) {}\n\n set<Key extends keyof DispatchState>(key: Key, value: DispatchState[Key]): void {\n this.state[key] = value;\n }\n\n get<Key extends keyof DispatchState>(key: Key): DispatchState[Key] | undefined {\n return this.state[key];\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { DispatchContext } from '@src/dispatch/DispatchContext';\n\n/**\n * Base class every transport handler extends. Don't register handlers directly, use the more specific\n * handler subclasses.\n *\n * @typeParam Event - The event or interaction this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class BaseHandler<Event, TCore extends CoreBase> {\n protected readonly event: Event;\n protected readonly logger: Logger;\n // absent on event handlers\n protected readonly dispatch?: DispatchContext | undefined;\n\n protected constructor(\n event: Event,\n public readonly core: TCore,\n dispatch?: DispatchContext\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name);\n this.dispatch = dispatch;\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","import { BaseHandler } from './BaseHandler';\n\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { BaseReplySender } from '@reply/BaseReplySender';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { DispatchContext } from '@src/dispatch/DispatchContext';\n\n/**\n * Shared base the repliable handlers on both transports extend. Defines the reply members over the sender\n * the transport builds.\n *\n * @typeParam Event - The repliable interaction type this handler processes\n * @typeParam TCore - The transport's Core\n * @typeParam TMessage - The transport's created-message lens\n * @typeParam TSender - The transport's reply sender\n */\nexport abstract class RepliableHandler<\n Event,\n TCore extends CoreBase,\n TMessage extends { id: string },\n TSender extends BaseReplySender<TMessage>\n> extends BaseHandler<Event, TCore> {\n protected readonly sender: TSender;\n protected readonly routeId: string;\n\n protected constructor(event: Event, core: TCore, dispatch?: DispatchContext) {\n super(event, core, dispatch);\n this.routeId = dispatch?.routeId ?? this.constructor.name;\n // runs inside the ctor, an override builds from its arguments only, subclass fields are not initialized yet\n this.sender = this.buildSender(event, core, this.routeId);\n }\n\n protected abstract buildSender(event: Event, core: TCore, routeId: string): TSender;\n\n /** @internal The dispatcher's fault boundary replies through the live ack state. */\n public getSender(): TSender {\n return this.sender;\n }\n\n /** Send the initial response, exactly once. */\n protected reply(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.reply(response, opts);\n }\n\n /** Show a \"thinking\" placeholder, then fill it later with {@link edit}. */\n protected defer(opts?: DeferOpts): Promise<void> {\n return this.sender.defer(opts);\n }\n\n /** Send a new message once the interaction is acknowledged. */\n protected followUp(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.followUp(response, opts);\n }\n\n /** Rewrite the initial reply or deferred placeholder. The targeted form rewrites a message a prior send returned. */\n protected edit(response: ReplyResponse | string): Promise<TMessage>;\n protected edit(target: TMessage, response: ReplyResponse | string): Promise<TMessage>;\n protected edit(\n targetOrResponse: TMessage | ReplyResponse | string,\n maybeResponse?: ReplyResponse | string\n ): Promise<TMessage> {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n if (maybeResponse === undefined) return this.sender.edit(targetOrResponse as ReplyResponse | string);\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n return this.sender.edit(targetOrResponse as TMessage, maybeResponse);\n }\n\n /** Routes to reply, followUp, or edit based on the current ack state. */\n protected send(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.send(response, opts);\n }\n\n /** Delete the initial reply or deferred placeholder. Pass a target to delete a message a prior send returned. */\n protected delete(target?: TMessage): Promise<void> {\n return target === undefined ? this.sender.delete() : this.sender.delete(target);\n }\n}\n","import { Notice } from './Notice';\nimport { NoticeCard } from './NoticeCard';\n\nimport type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * A generic fault you throw after catching an error you do not have a specific message for.\n *\n * The user sees a fixed generic reply with the tracking uuid, never the cause. `report` defaults to\n * `true`, so the framework logs it and publishes it to the `handledException` bus. Pass `report: false`\n * to show the generic reply without the bus publish. The original error is stored as the standard\n * `cause`, so the real stack reaches the webhook. For a fault the user should see a real message,\n * subclass {@link Notice} and write your own `render` instead.\n *\n * The framework also renders this for an unhandled throw, where it points the user at\n * `ctx.developerUsername`.\n *\n * @example\n * ```ts\n * import { Fault } from '@seedcord/gateway';\n *\n * try {\n * await db.write(record);\n * } catch (cause) {\n * // user sees the generic reply with the uuid, the real error rides along as cause for the webhook\n * throw new Fault({ cause });\n *\n * // pass report: false to show the same reply without publishing to the handledException bus\n * // throw new Fault({ cause, report: false });\n * }\n * ```\n */\nexport class Fault extends Notice {\n public constructor(options?: { cause?: unknown; report?: boolean }) {\n super('A fault occurred', options?.cause === undefined ? undefined : { cause: options.cause });\n this.report = options?.report ?? true;\n }\n\n public render(ctx: RenderContext): ReplyResponse {\n const contact = ctx.developerUsername ?? 'the developer';\n const card = new NoticeCard(\n `Something went wrong. Please reach out to ${contact} with a way to reproduce the error and the following:\\n### UUID: \\`${ctx.uuid}\\``,\n 'Error'\n );\n return { components: [card.component] };\n }\n}\n","import { NeedsAny, NotAllowed } from '@notices/index';\nimport { Fault } from '@stops/Fault';\nimport { Notice } from '@stops/Notice';\n\nimport { markCommits, rollbackCommits, runCheck } from './effects';\nimport { defineGate } from './Gate';\n\nimport type { Gate, GateContextBase, RequiredOf } from './Gate';\nimport type { IntersectRequired, JoinNames, TwoOrMore } from './matching';\n\n/**\n * Runs each gate in order and refuses on the first refusal. Takes two or more arms. The required\n * context is the intersection of the arms, so an event-only and an interaction-only gate cannot be\n * combined.\n *\n * @typeParam Gates - The tuple of two or more gate arms, run left to right.\n * @param gates - The gate arms to run in order, all refused on the first refusal.\n *\n * @see {@link or}\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(and(GuildOnly(), RequirePermissions([PermissionFlagsBits.BanMembers])))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function and<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<IntersectRequired<Gates> & GateContextBase, JoinNames<Gates, ' & '>>;\nexport function and(...gates: readonly Gate<GateContextBase>[]): Gate<GateContextBase> {\n return defineGate(gates.map((gate) => gate.name).join(' & '), async (ctx) => {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n });\n}\n\n// the caller-supplied refusal when every or arm refuses, replacing the default list or neutral refusal\ninterface OrOptions {\n fail: Notice | ((ctx: GateContextBase) => Notice);\n}\n\n// a gate has a check method, the options object does not\nfunction isOrOptions(arg: Gate<GateContextBase> | OrOptions): arg is OrOptions {\n return !('check' in arg);\n}\n\n/**\n * Runs each gate in order and passes on the first arm that passes. Takes two or more arms. The\n * required context is the union of the arms, so a handler that matches any one arm fits. When every\n * arm refuses it throws the trailing {@link OrOptions} `fail` if given, else an auto list of the\n * arms derived from the summary field, else a default refusal. The trailing options object does not\n * count as an arm.\n *\n * @typeParam Gates - The tuple of two or more gate arms, tried left to right.\n * @param gates - The gate arms to try in order, with an optional trailing {@link OrOptions} object.\n *\n * @see {@link and}\n *\n * @example\n * ```ts\n * \\@Gated(or(OwnerOnly(), RequireRole('123456789012345678')))\n * \\@SlashRoute('admin')\n * class AdminHandler extends SlashHandler<'admin'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\n/**\n * @example\n * ```ts\n * // custom refusal when every arm refuses\n * or(OwnerOnly(), RequireRole('123456789012345678'), { fail: new NotAllowedNotice() });\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...args: [...Gates, OrOptions]\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\nexport function or(...args: readonly (Gate<GateContextBase> | OrOptions)[]): Gate<GateContextBase> {\n const last = args.at(-1);\n const options = last !== undefined && isOrOptions(last) ? last : undefined;\n const gates = (options ? args.slice(0, -1) : args) as readonly Gate<GateContextBase>[];\n\n return defineGate(gates.map((gate) => gate.name).join(' | '), async (ctx) => {\n const summaries: string[] = [];\n let everyArmHasSummary = true;\n for (const gate of gates) {\n const mark = markCommits(ctx);\n try {\n await runCheck(gate, ctx);\n return;\n } catch (error) {\n // only a refusal is an arm declining, a Fault (even report-false), a Silence, or a raw error stops everything\n if (error instanceof Notice && !(error instanceof Fault) && !error.report) {\n // the arm may have queued an effect's commit before refusing, drop it so the winner does not carry it\n rollbackCommits(ctx, mark);\n if (error.summary === undefined) everyArmHasSummary = false;\n else summaries.push(error.summary);\n continue;\n }\n throw error;\n }\n }\n if (options) throw typeof options.fail === 'function' ? options.fail(ctx) : options.fail;\n // the auto-list shows only when every refusal gave a summary, a partial list would mislead by omission\n if (everyArmHasSummary && summaries.length > 0) throw new NeedsAny(summaries);\n throw new NotAllowed();\n });\n}\n","import { defineGate } from '@gates/Gate';\nimport { NotInDm, NotInGuild, NotOwner } from '@notices/index';\n\nimport { pickNotice } from './options';\n\nimport type { GateNoticeOptions } from './options';\nimport type { Gate, GateContextBase } from '@gates/Gate';\n\n/**\n * Passes only for a user id listed in `config.ownerIds`, else refuses.\n *\n * Agnostic, so it attaches to interaction and event handlers alike. With no `ownerIds` configured it refuses every caller. Pass {@link GateNoticeOptions} to reword or replace the refusal.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(OwnerOnly())\n * \\@SlashRoute('shutdown')\n * class ShutdownHandler extends SlashHandler<'shutdown'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // reword the refusal, keeping the embed styling\n * OwnerOnly({ message: 'Owners only.' });\n * ```\n */\nexport function OwnerOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'OwnerOnly'> {\n return defineGate('OwnerOnly', (ctx) => {\n const owners = ctx.core.config.ownerIds ?? [];\n if (ctx.userId !== null && owners.includes(ctx.userId)) return;\n throw pickNotice(options, (message) => new NotOwner(message));\n });\n}\n\n/**\n * Passes inside a guild, else refuses.\n *\n * Agnostic, so it attaches to any handler kind. Often paired with `RequirePermissions` in an {@link and}.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\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 * // ...\n * }\n * }\n * ```\n */\nexport function GuildOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'GuildOnly'> {\n return defineGate('GuildOnly', (ctx) => {\n if (ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInGuild(message));\n });\n}\n\n/**\n * Passes in a direct message, else refuses.\n *\n * Agnostic, so it attaches to any handler kind. The inverse of {@link GuildOnly}, so combining the two in an {@link and} can never pass.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(DmOnly())\n * \\@SlashRoute('verify')\n * class VerifyHandler extends SlashHandler<'verify'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function DmOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'DmOnly'> {\n return defineGate('DmOnly', (ctx) => {\n if (!ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInDm(message));\n });\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordTypeError } from '@seedcord/errors/internal';\nimport { parseDuration, type ValidDuration } from '@seedcord/utils';\n\nimport { defineEffectGate } from '@gates/Gate';\nimport { OnCooldown } from '@notices/index';\n\nimport type { EffectGate, GateContextBase } from '@gates/Gate';\nimport type { EpochMs } from '@seedcord/types';\nimport type { Notice } from '@stops/Notice';\n\n/**\n * Options for {@link Cooldown}. `per` sets the bucket the window applies to and `limit` the uses allowed per\n * window. `message` rewords the refusal and `notice` replaces it, both receiving the epoch ms the key frees\n * up so the refusal can show the retry time.\n *\n * @example\n * ```ts\n * // one use per channel, rewording the refusal with the retry time\n * Cooldown('10s', {\n * per: 'channel',\n * message: (resetAt) => `Slow down. Try again <t:${Math.round(resetAt / 1000)}:R>.`\n * });\n * ```\n *\n * @example\n * ```ts\n * // five uses per minute, per user\n * Cooldown('1m', { limit: 5 });\n * ```\n */\nexport interface CooldownOptions {\n /**\n * The bucket the cooldown window applies to. 'user' scopes by user ID, falls back to global when the source carries no user id. 'guild' scopes by guild ID (falls back to global if no guild), and 'channel' scopes by channel ID (falls back to global if no channel).\n *\n * @defaultValue `'user'`\n */\n per?: 'user' | 'guild' | 'channel';\n /**\n * Uses allowed inside one window before the gate refuses.\n *\n * @defaultValue `1`\n */\n limit?: number;\n /**\n * Reword the refusal, keeping the standard notice card. Receives the epoch ms the key frees up, so the\n * text can include the retry time with `<t:${Math.round(resetAt / 1000)}:R>`.\n */\n message?: (resetAt: EpochMs) => string;\n /**\n * Replace the refusal Notice entirely, for full control or a translated copy. Receives the epoch ms the\n * key frees up.\n */\n notice?: (resetAt: EpochMs) => Notice;\n}\n\n// off-route ctxs have no route to key on, so each Cooldown() gets its own id to keep unrelated event handlers isolated\nlet anonSeq = 0;\n\nfunction scopeValue(ctx: GateContextBase, per: 'user' | 'guild' | 'channel'): string {\n if (per === 'guild') return ctx.guildId ?? 'global';\n if (per === 'channel') return ctx.channelId ?? 'global';\n return ctx.userId ?? 'global';\n}\n\n/**\n * Allows `limit` uses per window, scoped by `per`. A number `duration` is **seconds**, a string is\n * a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError** at construction. The\n * slot is charged in commit, only after the whole gate set passes, so a later refusal never burns the cooldown.\n * That split also means two requests racing the same key can both pass before either charges the slot.\n * The key combines the handler's route with the window settings, so two different handlers keep separate\n * windows. Reword the refusal with {@link CooldownOptions.message} or replace it with {@link CooldownOptions.notice}.\n *\n * @param duration - A number is seconds, a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.\n * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n * @see {@link IRateLimiter}\n *\n * @example\n * ```ts\n * // a number argument is SECONDS\n * \\@Gated(Cooldown(5))\n * \\@SlashRoute('daily')\n * class DailyHandler extends SlashHandler<'daily'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // a string is a duration, here scoped per guild (the default is per user)\n * Cooldown('30m', { per: 'guild' });\n * ```\n *\n * @example\n * ```ts\n * // a burst, 3 uses per 10 minutes per user, then it refuses until a slot frees\n * \\@Gated(Cooldown('10m', { limit: 3 }))\n * \\@SlashRoute('report')\n * class ReportHandler extends SlashHandler<'report'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function Cooldown(\n duration: number | ValidDuration,\n options?: CooldownOptions\n): EffectGate<GateContextBase, 'Cooldown'> {\n let windowMs: number;\n if (typeof duration === 'number') {\n windowMs = duration * 1000;\n } else {\n const parsed = parseDuration(duration);\n if (parsed === null) throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [duration]);\n windowMs = parsed;\n }\n // a zero or negative window would never limit, refuse it the same way an unparseable string is refused\n if (windowMs <= 0) {\n throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [String(duration)]);\n }\n\n const per = options?.per ?? 'user';\n // omit limit when unset so the limiter applies its default of 1, exactOptionalPropertyTypes rejects an explicit undefined\n const window = options?.limit === undefined ? { windowMs } : { windowMs, limit: options.limit };\n const anonId = anonSeq++;\n // routed keys are stable across restarts, so a durable store rebuilds the same window\n const keyOf = (ctx: GateContextBase): string =>\n `cooldown:${ctx.routeId ?? `anon${anonId}`}:${per}:w${windowMs}:l${options?.limit ?? 1}:${scopeValue(ctx, per)}`;\n\n return defineEffectGate(\n 'Cooldown',\n async (ctx) => {\n const result = await ctx.core.rateLimiter.peek(keyOf(ctx), window);\n if (!result.limited) return;\n if (options?.notice) throw options.notice(result.resetAt);\n throw new OnCooldown(result.resetAt, options?.message?.(result.resetAt));\n },\n async (ctx) => {\n await ctx.core.rateLimiter.charge(keyOf(ctx), window);\n }\n );\n}\n","/**\n * Throw to stop a handler with no reply and no report.\n *\n * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.\n * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to\n * leave the user with no reply for an interaction.\n *\n * @example\n * ```ts\n * import { Silence } from '@seedcord/gateway';\n *\n * // before any reply or defer, drop the interaction with no reply and no report\n * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');\n * ```\n */\nexport class Silence extends Error {\n /**\n * @param reason - Optional note written only to a debug log, never shown to the user or reported.\n */\n public constructor(public readonly reason?: string) {\n super(reason ?? 'Silence');\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport type { PageView } from './PageView';\n\n/**\n * Pure page math, usable headless. Clamps `page` into range and slices the window.\n *\n * @param items - The full list to page over.\n * @param page - The requested zero-based page, clamped into `[0, totalPages - 1]`.\n * @param perPage - The page size. Must be a positive integer.\n * @returns The sliced {@link PageView}, with `totalPages` always known.\n * @throws SeedcordRangeError when `perPage` is not a positive integer.\n */\nexport function paginate<Item>(items: readonly Item[], page: number, perPage: number): PageView<Item> {\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n\n const totalPages = Math.max(1, Math.ceil(items.length / perPage));\n // a headless caller can pass a non-integer or out-of-range page.\n const clamped = Math.min(Math.max(Math.trunc(page), 0), totalPages - 1);\n const start = clamped * perPage;\n\n return {\n items: items.slice(start, start + perPage),\n page: clamped,\n perPage,\n totalPages,\n hasPrev: clamped > 0,\n hasNext: clamped < totalPages - 1\n };\n}\n","import 'reflect-metadata';\n\nexport type * from '@registries/ContextMenuRegistry';\nexport type * from '@registries/SlashOptionRegistry';\n\nexport { RegisterCommand } from '@decorators/Command';\nexport { SelectMenuKind } from '@decorators/interactionRoutes';\nexport {\n AutocompleteRoute,\n ButtonRoute,\n ContextMenuRoute,\n ModalRoute,\n SelectMenuRoute,\n SlashRoute\n} from '@decorators/routes';\n\nexport { DispatchContext } from '@src/dispatch/DispatchContext';\nexport type { DispatchState } from '@src/dispatch/DispatchContext';\n\nexport { BaseHandler } from '@src/handlers/BaseHandler';\nexport { RepliableHandler } from '@src/handlers/RepliableHandler';\n\nexport type { CoreBase } from '@interfaces/CoreBase';\n\nexport { defineEffectGate, defineGate } from '@gates/Gate';\nexport type { EffectGate, Gate, GateContextBase, GuildPermissionsContext, RequiredOf } from '@gates/Gate';\nexport { and, or } from '@gates/combinators';\nexport { DmOnly, GuildOnly, OwnerOnly } from '@gates/catalog/access';\nexport { Cooldown, type CooldownOptions } from '@gates/catalog/Cooldown';\nexport { RequireBotPermissions, RequirePermissions, RequireRole } from '@gates/catalog/permissions';\nexport type { PermissionScope, RequirePermissionsOptions, RequireRoleOptions } from '@gates/catalog/permissions';\nexport type { GateNoticeOptions } from '@gates/catalog/options';\n\nexport { BuilderComponent, RowComponent } from '@components/Component';\nexport { type RowType, type BuilderType } from '@components/builderTypes';\n\nexport { Notice } from '@stops/Notice';\nexport { Fault } from '@stops/Fault';\nexport { Silence } from '@stops/Silence';\n\nexport { CustomId } from '@customId/CustomId';\n\nexport type { AutocompleteOptions } from '@inputs/AutocompleteOptions';\n\nexport { paginate } from '@pagination/paginate';\nexport { type PageView } from '@pagination/PageView';\n\n/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/decorators/Command.ts","../src/decorators/routes.ts","../src/dispatch/DispatchContext.ts","../src/handlers/BaseHandler.ts","../src/handlers/RepliableHandler.ts","../src/stops/Fault.ts","../src/gates/combinators.ts","../src/gates/catalog/access.ts","../src/gates/catalog/Cooldown.ts","../src/stops/Silence.ts","../src/pagination/paginate.ts","../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { CommandMetadataKey } from '@src/metadataKeys';\n\nimport type { BuilderComponent } from '@components/Component';\nimport type { Constructor } from 'type-fest';\n\ntype CommandCtor = Constructor<BuilderComponent<'command' | 'context_menu'>>;\n\ninterface GlobalMeta {\n scope: 'global';\n}\n\ninterface GuildMeta {\n scope: 'guild';\n guilds: string[];\n}\n\nexport type CommandMeta = GlobalMeta | GuildMeta;\n\ntype CommandScope = CommandMeta['scope'];\n\n/**\n * Attaches deployment metadata so the framework registers this command globally or in specific guilds.\n *\n * @param scope - Must be 'global' for global registration\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('global')\n * class PingCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'global'): (ctor: CommandCtor) => void;\n\n/**\n * Registers a command for specific guild deployment.\n *\n * @param scope - Must be 'guild' for guild-specific registration\n * @param guilds - Array of guild IDs where the command should be registered\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('guild', ['123456789'])\n * class AdminCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'guild', guilds: string[]): (ctor: CommandCtor) => void;\n\nexport function RegisterCommand(scope: CommandScope, guilds: string[] = []) {\n return (ctor: CommandCtor): void => {\n const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n if (existingMeta) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [\n ctor.name,\n existingMeta.scope,\n scope\n ]);\n }\n\n if (scope === 'global' && guilds.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);\n }\n\n if (scope === 'guild' && (!Array.isArray(guilds) || guilds.length === 0)) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);\n }\n\n const meta: GlobalMeta | GuildMeta = scope === 'global' ? { scope } : { scope, guilds };\n Reflect.defineMetadata(CommandMetadataKey, meta, ctor);\n };\n}\n","import {\n contextMenuRouteOf,\n selectMenuRouteOf,\n storeComponentRoute,\n storeInteractionRoute\n} from '@decorators/interactionRoutes';\nimport { InteractionRoutes } from '@src/metadataKeys';\n\nimport type { AnyCustomId } from '@customId/CustomId';\nimport type { SelectMenuKind } from '@decorators/interactionRoutes';\nimport type { MessageContextMenuRegistry, UserContextMenuRegistry } from '@registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '@registries/SlashOptionRegistry';\nimport type { ApplicationCommandType } from 'discord-api-types/v10';\nimport type { Constructor } from 'type-fest';\n\ntype ContextMenuKind = ApplicationCommandType.User | ApplicationCommandType.Message;\n\ntype ComponentBrand = 'button' | 'modal' | SelectMenuKind;\n\n// phantom brands keep the decorators off transport-specific classes\ntype AnyHandlerCtor = new (...args: any[]) => unknown;\n\ntype SlashRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __slashRoute?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype AutocompleteRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __autocompleteRoute?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype ContextMenuKindOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __ctxKind?: infer Kind extends ContextMenuKind;\n }\n ? Kind\n : never;\n\ntype ComponentOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __component?: infer Brand extends ComponentBrand;\n }\n ? Brand\n : never;\n\ntype DefsOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n __componentDefs?: infer Defs extends readonly AnyCustomId[];\n }\n ? Defs\n : never;\n\ntype AssertSlashRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n SlashRouteOf<TCtor>\n]\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\ntype AssertAutocompleteRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n AutocompleteRouteOf<TCtor>\n]\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\ntype AssertContextMenuRoute<Kind extends ContextMenuKind, TCtor extends AnyHandlerCtor> = [Kind] extends [\n ContextMenuKindOf<TCtor>\n]\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// one assignability direction for the defs, a bidirectional check would reject const-inferred readonly tuples\ntype AssertComponentRoute<\n Brand extends ComponentBrand,\n Defs extends readonly AnyCustomId[],\n TCtor extends AnyHandlerCtor\n> = [ComponentOf<TCtor>] extends [Brand]\n ? [Brand] extends [ComponentOf<TCtor>]\n ? [DefsOf<TCtor>] extends [Defs]\n ? TCtor\n : Constructor<['the customId definitions do not match the handler generic', DefsOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>;\n\ntype NamesFor<Kind extends ContextMenuKind> = Kind extends ApplicationCommandType.User\n ? keyof UserContextMenuRegistry\n : keyof MessageContextMenuRegistry;\n\n/**\n * Routes one or more slash commands to a `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 */\nexport function SlashRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertSlashRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Slash, routes, constructor);\n };\n}\n\n/**\n * Routes one or more commands' autocomplete to an `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 AnyHandlerCtor>(constructor: AssertAutocompleteRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Autocomplete, routes, constructor);\n };\n}\n\n/**\n * Routes one or more context-menu commands to a `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 handler's generic must\n * declare the same kind, cross-checked both directions. Context menus carry no options, so a multi-name\n * handler 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 ContextMenuKind>(kind: Kind, ...names: NamesFor<Kind>[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertContextMenuRoute<Kind, TCtor>): void {\n storeInteractionRoute(contextMenuRouteOf(kind), names, constructor);\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 AnyHandlerCtor>(constructor: AssertComponentRoute<'button', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Button, defs, constructor);\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 AnyHandlerCtor>(constructor: AssertComponentRoute<'modal', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Modal, defs, constructor);\n };\n}\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 kind and definitions, 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 * ```\n */\nexport function SelectMenuRoute<const Kind extends SelectMenuKind, const Defs extends readonly AnyCustomId[]>(\n type: Kind,\n ...defs: Defs\n) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<Kind, Defs, TCtor>): void {\n storeComponentRoute(selectMenuRouteOf(type), defs, constructor);\n };\n}\n","/**\n * The per-dispatch bag. Any code can merge fields into it by declaration merging, the\n * same pattern as {@link SlashOptionRegistry}. It stays empty until one does, so `keyof DispatchState` is\n * `never` and the bag is inert.\n */\nexport interface DispatchState {}\n\n/**\n * A typed bag allocated once per interaction dispatch and handed to the handler. The middleware and i18n\n * work reads and writes it through {@link DispatchState}. Today the bag is empty, so it only carries the\n * dispatched `routeId`.\n */\nexport class DispatchContext {\n private readonly state: Partial<DispatchState> = {};\n\n constructor(public readonly routeId: string | null) {}\n\n set<Key extends keyof DispatchState>(key: Key, value: DispatchState[Key]): void {\n this.state[key] = value;\n }\n\n get<Key extends keyof DispatchState>(key: Key): DispatchState[Key] | undefined {\n return this.state[key];\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { DispatchContext } from '@src/dispatch/DispatchContext';\n\n/**\n * Base class every transport handler extends. Don't register handlers directly, use the more specific\n * handler subclasses.\n *\n * @typeParam Event - The event or interaction this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class BaseHandler<Event, TCore extends CoreBase> {\n protected readonly event: Event;\n protected readonly logger: Logger;\n // absent on event handlers\n protected readonly dispatch?: DispatchContext | undefined;\n\n protected constructor(\n event: Event,\n public readonly core: TCore,\n dispatch?: DispatchContext\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name);\n this.dispatch = dispatch;\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","import { BaseHandler } from './BaseHandler';\n\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { BaseReplySender } from '@reply/BaseReplySender';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { DispatchContext } from '@src/dispatch/DispatchContext';\n\n/**\n * Shared base the repliable handlers on both transports extend. Defines the reply members over the sender\n * the transport builds.\n *\n * @typeParam Event - The repliable interaction type this handler processes\n * @typeParam TCore - The transport's Core\n * @typeParam TMessage - The transport's created-message lens\n * @typeParam TSender - The transport's reply sender\n */\nexport abstract class RepliableHandler<\n Event,\n TCore extends CoreBase,\n TMessage extends { id: string },\n TSender extends BaseReplySender<TMessage>\n> extends BaseHandler<Event, TCore> {\n protected readonly sender: TSender;\n protected readonly routeId: string;\n\n protected constructor(event: Event, core: TCore, dispatch?: DispatchContext) {\n super(event, core, dispatch);\n this.routeId = dispatch?.routeId ?? this.constructor.name;\n // runs inside the ctor, an override builds from its arguments only, subclass fields are not initialized yet\n this.sender = this.buildSender(event, core, this.routeId);\n }\n\n protected abstract buildSender(event: Event, core: TCore, routeId: string): TSender;\n\n /** @internal The dispatcher's fault boundary replies through the live ack state. */\n public getSender(): TSender {\n return this.sender;\n }\n\n /** Send the initial response, exactly once. */\n protected reply(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.reply(response, opts);\n }\n\n /** Show a \"thinking\" placeholder, then fill it later with {@link edit}. */\n protected defer(opts?: DeferOpts): Promise<void> {\n return this.sender.defer(opts);\n }\n\n /** Send a new message once the interaction is acknowledged. */\n protected followUp(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.followUp(response, opts);\n }\n\n /** Rewrite the initial reply or deferred placeholder. The targeted form rewrites a message a prior send returned. */\n protected edit(response: ReplyResponse | string): Promise<TMessage>;\n protected edit(target: TMessage, response: ReplyResponse | string): Promise<TMessage>;\n protected edit(\n targetOrResponse: TMessage | ReplyResponse | string,\n maybeResponse?: ReplyResponse | string\n ): Promise<TMessage> {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n if (maybeResponse === undefined) return this.sender.edit(targetOrResponse as ReplyResponse | string);\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n return this.sender.edit(targetOrResponse as TMessage, maybeResponse);\n }\n\n /** Routes to reply, followUp, or edit based on the current ack state. */\n protected send(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.send(response, opts);\n }\n\n /** Delete the initial reply or deferred placeholder. Pass a target to delete a message a prior send returned. */\n protected delete(target?: TMessage): Promise<void> {\n return target === undefined ? this.sender.delete() : this.sender.delete(target);\n }\n}\n","import { Notice } from './Notice';\nimport { NoticeCard } from './NoticeCard';\n\nimport type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * A generic fault you throw after catching an error you do not have a specific message for.\n *\n * The user sees a fixed generic reply with the tracking uuid, never the cause. `report` defaults to\n * `true`, so the framework logs it and publishes it to the `handledException` bus. Pass `report: false`\n * to show the generic reply without the bus publish. The original error is stored as the standard\n * `cause`, so the real stack reaches the webhook. For a fault the user should see a real message,\n * subclass {@link Notice} and write your own `render` instead.\n *\n * The framework also renders this for an unhandled throw, where it points the user at\n * `ctx.developerUsername`.\n *\n * @example\n * ```ts\n * import { Fault } from '@seedcord/gateway';\n *\n * try {\n * await db.write(record);\n * } catch (cause) {\n * // user sees the generic reply with the uuid, the real error rides along as cause for the webhook\n * throw new Fault({ cause });\n *\n * // pass report: false to show the same reply without publishing to the handledException bus\n * // throw new Fault({ cause, report: false });\n * }\n * ```\n */\nexport class Fault extends Notice {\n public constructor(options?: { cause?: unknown; report?: boolean }) {\n super('A fault occurred', options?.cause === undefined ? undefined : { cause: options.cause });\n this.report = options?.report ?? true;\n }\n\n public render(ctx: RenderContext): ReplyResponse {\n const contact = ctx.developerUsername ?? 'the developer';\n const card = new NoticeCard(\n `Something went wrong. Please reach out to ${contact} with a way to reproduce the error and the following:\\n### UUID: \\`${ctx.uuid}\\``,\n 'Error'\n );\n return { components: [card.component] };\n }\n}\n","import { NeedsAny, NotAllowed } from '@notices/index';\nimport { Fault } from '@stops/Fault';\nimport { Notice } from '@stops/Notice';\n\nimport { markCommits, rollbackCommits, runCheck } from './effects';\nimport { defineGate } from './Gate';\n\nimport type { Gate, GateContextBase, RequiredOf } from './Gate';\nimport type { IntersectRequired, JoinNames, TwoOrMore } from './matching';\n\n/**\n * Runs each gate in order and refuses on the first refusal. Takes two or more arms. The required\n * context is the intersection of the arms, so an event-only and an interaction-only gate cannot be\n * combined.\n *\n * @typeParam Gates - The tuple of two or more gate arms, run left to right.\n * @param gates - The gate arms to run in order, all refused on the first refusal.\n *\n * @see {@link or}\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(and(GuildOnly(), RequirePermissions([PermissionFlagsBits.BanMembers])))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function and<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<IntersectRequired<Gates> & GateContextBase, JoinNames<Gates, ' & '>>;\nexport function and(...gates: readonly Gate<GateContextBase>[]): Gate<GateContextBase> {\n return defineGate(gates.map((gate) => gate.name).join(' & '), async (ctx) => {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n });\n}\n\n// the caller-supplied refusal when every or arm refuses, replacing the default list or neutral refusal\ninterface OrOptions {\n fail: Notice | ((ctx: GateContextBase) => Notice);\n}\n\n// a gate has a check method, the options object does not\nfunction isOrOptions(arg: Gate<GateContextBase> | OrOptions): arg is OrOptions {\n return !('check' in arg);\n}\n\n/**\n * Runs each gate in order and passes on the first arm that passes. Takes two or more arms. The\n * required context is the union of the arms, so a handler that matches any one arm fits. When every\n * arm refuses it throws the trailing {@link OrOptions} `fail` if given, else an auto list of the\n * arms derived from the summary field, else a default refusal. The trailing options object does not\n * count as an arm.\n *\n * @typeParam Gates - The tuple of two or more gate arms, tried left to right.\n * @param gates - The gate arms to try in order, with an optional trailing {@link OrOptions} object.\n *\n * @see {@link and}\n *\n * @example\n * ```ts\n * \\@Gated(or(OwnerOnly(), RequireRole('123456789012345678')))\n * \\@SlashRoute('admin')\n * class AdminHandler extends SlashHandler<'admin'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\n/**\n * @example\n * ```ts\n * // custom refusal when every arm refuses\n * or(OwnerOnly(), RequireRole('123456789012345678'), { fail: new NotAllowedNotice() });\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...args: [...Gates, OrOptions]\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\nexport function or(...args: readonly (Gate<GateContextBase> | OrOptions)[]): Gate<GateContextBase> {\n const last = args.at(-1);\n const options = last !== undefined && isOrOptions(last) ? last : undefined;\n const gates = (options ? args.slice(0, -1) : args) as readonly Gate<GateContextBase>[];\n\n return defineGate(gates.map((gate) => gate.name).join(' | '), async (ctx) => {\n const summaries: string[] = [];\n let everyArmHasSummary = true;\n for (const gate of gates) {\n const mark = markCommits(ctx);\n try {\n await runCheck(gate, ctx);\n return;\n } catch (error) {\n // only a refusal is an arm declining, a Fault (even report-false), a Silence, or a raw error stops everything\n if (error instanceof Notice && !(error instanceof Fault) && !error.report) {\n // the arm may have queued an effect's commit before refusing, drop it so the winner does not carry it\n rollbackCommits(ctx, mark);\n if (error.summary === undefined) everyArmHasSummary = false;\n else summaries.push(error.summary);\n continue;\n }\n throw error;\n }\n }\n if (options) throw typeof options.fail === 'function' ? options.fail(ctx) : options.fail;\n // the auto-list shows only when every refusal gave a summary, a partial list would mislead by omission\n if (everyArmHasSummary && summaries.length > 0) throw new NeedsAny(summaries);\n throw new NotAllowed();\n });\n}\n","import { defineGate } from '@gates/Gate';\nimport { NotInDm, NotInGuild, NotOwner } from '@notices/index';\n\nimport { pickNotice } from './options';\n\nimport type { GateNoticeOptions } from './options';\nimport type { Gate, GateContextBase } from '@gates/Gate';\n\n/**\n * Passes only for a user id listed in `config.ownerIds`, else refuses.\n *\n * Agnostic, so it attaches to interaction and event handlers alike. With no `ownerIds` configured it refuses every caller. Pass {@link GateNoticeOptions} to reword or replace the refusal.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(OwnerOnly())\n * \\@SlashRoute('shutdown')\n * class ShutdownHandler extends SlashHandler<'shutdown'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // reword the refusal, keeping the embed styling\n * OwnerOnly({ message: 'Owners only.' });\n * ```\n */\nexport function OwnerOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'OwnerOnly'> {\n return defineGate('OwnerOnly', (ctx) => {\n const owners = ctx.core.config.ownerIds ?? [];\n if (ctx.userId !== null && owners.includes(ctx.userId)) return;\n throw pickNotice(options, (message) => new NotOwner(message));\n });\n}\n\n/**\n * Passes inside a guild, else refuses.\n *\n * Agnostic, so it attaches to any handler kind. Often paired with `RequirePermissions` in an {@link and}.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\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 * // ...\n * }\n * }\n * ```\n */\nexport function GuildOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'GuildOnly'> {\n return defineGate('GuildOnly', (ctx) => {\n if (ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInGuild(message));\n });\n}\n\n/**\n * Passes in a direct message, else refuses.\n *\n * Agnostic, so it attaches to any handler kind. The inverse of {@link GuildOnly}, so combining the two in an {@link and} can never pass.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(DmOnly())\n * \\@SlashRoute('verify')\n * class VerifyHandler extends SlashHandler<'verify'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function DmOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'DmOnly'> {\n return defineGate('DmOnly', (ctx) => {\n if (!ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInDm(message));\n });\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordTypeError } from '@seedcord/errors/internal';\nimport { parseDuration, type ValidDuration } from '@seedcord/utils';\n\nimport { defineEffectGate } from '@gates/Gate';\nimport { OnCooldown } from '@notices/index';\n\nimport type { EffectGate, GateContextBase } from '@gates/Gate';\nimport type { EpochMs } from '@seedcord/types';\nimport type { Notice } from '@stops/Notice';\n\n/**\n * Options for {@link Cooldown}. `per` sets the bucket the window applies to and `limit` the uses allowed per\n * window. `message` rewords the refusal and `notice` replaces it, both receiving the epoch ms the key frees\n * up so the refusal can show the retry time.\n *\n * @example\n * ```ts\n * // one use per channel, rewording the refusal with the retry time\n * Cooldown('10s', {\n * per: 'channel',\n * message: (resetAt) => `Slow down. Try again <t:${Math.round(resetAt / 1000)}:R>.`\n * });\n * ```\n *\n * @example\n * ```ts\n * // five uses per minute, per user\n * Cooldown('1m', { limit: 5 });\n * ```\n */\nexport interface CooldownOptions {\n /**\n * The bucket the cooldown window applies to. 'user' scopes by user ID, falls back to global when the source carries no user id. 'guild' scopes by guild ID (falls back to global if no guild), and 'channel' scopes by channel ID (falls back to global if no channel).\n *\n * @defaultValue `'user'`\n */\n per?: 'user' | 'guild' | 'channel';\n /**\n * Uses allowed inside one window before the gate refuses.\n *\n * @defaultValue `1`\n */\n limit?: number;\n /**\n * Reword the refusal, keeping the standard notice card. Receives the epoch ms the key frees up, so the\n * text can include the retry time with `<t:${Math.round(resetAt / 1000)}:R>`.\n */\n message?: (resetAt: EpochMs) => string;\n /**\n * Replace the refusal Notice entirely, for full control or a translated copy. Receives the epoch ms the\n * key frees up.\n */\n notice?: (resetAt: EpochMs) => Notice;\n}\n\n// off-route ctxs have no route to key on, so each Cooldown() gets its own id to keep unrelated event handlers isolated\nlet anonSeq = 0;\n\nfunction scopeValue(ctx: GateContextBase, per: 'user' | 'guild' | 'channel'): string {\n if (per === 'guild') return ctx.guildId ?? 'global';\n if (per === 'channel') return ctx.channelId ?? 'global';\n return ctx.userId ?? 'global';\n}\n\n/**\n * Allows `limit` uses per window, scoped by `per`. A number `duration` is **seconds**, a string is\n * a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError** at construction. The\n * slot is charged in commit, only after the whole gate set passes, so a later refusal never burns the cooldown.\n * That split also means two requests racing the same key can both pass before either charges the slot.\n * The key combines the handler's route with the window settings, so two different handlers keep separate\n * windows. Reword the refusal with {@link CooldownOptions.message} or replace it with {@link CooldownOptions.notice}.\n *\n * @param duration - A number is seconds, a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.\n * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n * @see {@link IRateLimiter}\n *\n * @example\n * ```ts\n * // a number argument is SECONDS\n * \\@Gated(Cooldown(5))\n * \\@SlashRoute('daily')\n * class DailyHandler extends SlashHandler<'daily'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // a string is a duration, here scoped per guild (the default is per user)\n * Cooldown('30m', { per: 'guild' });\n * ```\n *\n * @example\n * ```ts\n * // a burst, 3 uses per 10 minutes per user, then it refuses until a slot frees\n * \\@Gated(Cooldown('10m', { limit: 3 }))\n * \\@SlashRoute('report')\n * class ReportHandler extends SlashHandler<'report'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function Cooldown(\n duration: number | ValidDuration,\n options?: CooldownOptions\n): EffectGate<GateContextBase, 'Cooldown'> {\n let windowMs: number;\n if (typeof duration === 'number') {\n windowMs = duration * 1000;\n } else {\n const parsed = parseDuration(duration);\n if (parsed === null) throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [duration]);\n windowMs = parsed;\n }\n // a zero or negative window would never limit, refuse it the same way an unparseable string is refused\n if (windowMs <= 0) {\n throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [String(duration)]);\n }\n\n const per = options?.per ?? 'user';\n // omit limit when unset so the limiter applies its default of 1, exactOptionalPropertyTypes rejects an explicit undefined\n const window = options?.limit === undefined ? { windowMs } : { windowMs, limit: options.limit };\n const anonId = anonSeq++;\n // routed keys are stable across restarts, so a durable store rebuilds the same window\n const keyOf = (ctx: GateContextBase): string =>\n `cooldown:${ctx.routeId ?? `anon${anonId}`}:${per}:w${windowMs}:l${options?.limit ?? 1}:${scopeValue(ctx, per)}`;\n\n return defineEffectGate(\n 'Cooldown',\n async (ctx) => {\n const result = await ctx.core.rateLimiter.peek(keyOf(ctx), window);\n if (!result.limited) return;\n if (options?.notice) throw options.notice(result.resetAt);\n throw new OnCooldown(result.resetAt, options?.message?.(result.resetAt));\n },\n async (ctx) => {\n await ctx.core.rateLimiter.charge(keyOf(ctx), window);\n }\n );\n}\n","/**\n * Throw to stop a handler with no reply and no report.\n *\n * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.\n * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to\n * leave the user with no reply for an interaction.\n *\n * @example\n * ```ts\n * import { Silence } from '@seedcord/gateway';\n *\n * // before any reply or defer, drop the interaction with no reply and no report\n * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');\n * ```\n */\nexport class Silence extends Error {\n /**\n * @param reason - Optional note written only to a debug log, never shown to the user or reported.\n */\n public constructor(public readonly reason?: string) {\n super(reason ?? 'Silence');\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport type { PageView } from './PageView';\n\n/**\n * Pure page math, usable headless. Clamps `page` into range and slices the window.\n *\n * @param items - The full list to page over.\n * @param page - The requested zero-based page, clamped into `[0, totalPages - 1]`.\n * @param perPage - The page size. Must be a positive integer.\n * @returns The sliced {@link PageView}, with `totalPages` always known.\n * @throws SeedcordRangeError when `perPage` is not a positive integer.\n */\nexport function paginate<Item>(items: readonly Item[], page: number, perPage: number): PageView<Item> {\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n\n const totalPages = Math.max(1, Math.ceil(items.length / perPage));\n // a headless caller can pass a non-integer or out-of-range page.\n const clamped = Math.min(Math.max(Math.trunc(page), 0), totalPages - 1);\n const start = clamped * perPage;\n\n return {\n items: items.slice(start, start + perPage),\n page: clamped,\n perPage,\n totalPages,\n hasPrev: clamped > 0,\n hasNext: clamped < totalPages - 1\n };\n}\n","import 'reflect-metadata';\n\nexport type * from '@registries/ContextMenuRegistry';\nexport type * from '@registries/SlashOptionRegistry';\n\nexport { RegisterCommand } from '@decorators/Command';\nexport { SelectMenuKind } from '@decorators/interactionRoutes';\nexport {\n AutocompleteRoute,\n ButtonRoute,\n ContextMenuRoute,\n ModalRoute,\n SelectMenuRoute,\n SlashRoute\n} from '@decorators/routes';\n\nexport { DispatchContext } from '@src/dispatch/DispatchContext';\nexport type { DispatchState } from '@src/dispatch/DispatchContext';\n\nexport { BaseHandler } from '@src/handlers/BaseHandler';\nexport { RepliableHandler } from '@src/handlers/RepliableHandler';\n\nexport type { CoreBase } from '@interfaces/CoreBase';\n\nexport type { Initializeable } from '@src/plugin/Plugin';\n// root-visible so a transport can augment it through `declare module '@seedcord/core'`\nexport type { PluginCapabilityTypes } from '@src/plugin/context';\n\nexport { ShutdownPhase, StartupPhase } from '@src/lifecycle/phases';\n\nexport { defineEffectGate, defineGate } from '@gates/Gate';\nexport type { EffectGate, Gate, GateContextBase, GuildPermissionsContext, RequiredOf } from '@gates/Gate';\nexport { and, or } from '@gates/combinators';\nexport { DmOnly, GuildOnly, OwnerOnly } from '@gates/catalog/access';\nexport { Cooldown, type CooldownOptions } from '@gates/catalog/Cooldown';\nexport { RequireBotPermissions, RequirePermissions, RequireRole } from '@gates/catalog/permissions';\nexport type { PermissionScope, RequirePermissionsOptions, RequireRoleOptions } from '@gates/catalog/permissions';\nexport type { GateNoticeOptions } from '@gates/catalog/options';\n\nexport { BuilderComponent, RowComponent } from '@components/Component';\nexport { type RowType, type BuilderType } from '@components/builderTypes';\n\nexport { Notice } from '@stops/Notice';\nexport { Fault } from '@stops/Fault';\nexport { Silence } from '@stops/Silence';\n\nexport { CustomId } from '@customId/CustomId';\n\nexport type { AutocompleteOptions } from '@inputs/AutocompleteOptions';\n\nexport { paginate } from '@pagination/paginate';\nexport { type PageView } from '@pagination/PageView';\n\n/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":"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"}
|
package/dist/internal.index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_rolldown_runtime = require('./rolldown-runtime-C_NdSu1c.cjs');
|
|
3
|
-
const require_permissions = require('./permissions-
|
|
3
|
+
const require_permissions = require('./permissions-DSW_EZfN.cjs');
|
|
4
|
+
const require_devChannel = require('./devChannel-CoCmAVDx.cjs');
|
|
4
5
|
require("reflect-metadata");
|
|
5
6
|
let _seedcord_errors = require("@seedcord/errors");
|
|
6
7
|
let _seedcord_errors_internal = require("@seedcord/errors/internal");
|
|
@@ -76,18 +77,6 @@ function slowGateMonitor() {
|
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
//#endregion
|
|
80
|
-
//#region src/hmr/devChannel.ts
|
|
81
|
-
let channel;
|
|
82
|
-
/** @internal */
|
|
83
|
-
function setDevChannel(next) {
|
|
84
|
-
channel = next;
|
|
85
|
-
}
|
|
86
|
-
/** @internal */
|
|
87
|
-
function getDevChannel() {
|
|
88
|
-
return channel;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
80
|
//#endregion
|
|
92
81
|
//#region src/hmr/wrapHot.ts
|
|
93
82
|
/**
|
|
@@ -111,7 +100,7 @@ var HmrManager = class {
|
|
|
111
100
|
init() {
|
|
112
101
|
if (!{}.hot) return;
|
|
113
102
|
const channel = wrapHot({}.hot);
|
|
114
|
-
setDevChannel(channel);
|
|
103
|
+
require_devChannel.setDevChannel(channel);
|
|
115
104
|
if (envapt.Envapter.isDevelopment || envapt.Envapter.isTest) {
|
|
116
105
|
this.logger.info("Enabled");
|
|
117
106
|
channel.on("seedcord:hmr", (payload) => {
|
|
@@ -135,7 +124,7 @@ var HmrManager = class {
|
|
|
135
124
|
try {
|
|
136
125
|
await listener.onHmr(event);
|
|
137
126
|
} catch (error) {
|
|
138
|
-
this.logger.error(`Error handling HMR update in ${chalk.default.bold(listener.name)}: `, error);
|
|
127
|
+
this.logger.error(`Error handling HMR update in ${chalk.default.bold(listener.constructor.name)}: `, error);
|
|
139
128
|
}
|
|
140
129
|
});
|
|
141
130
|
await Promise.all(promises);
|
|
@@ -550,7 +539,8 @@ exports.contextMenuRouteOf = require_permissions.contextMenuRouteOf;
|
|
|
550
539
|
exports.decodeComponentRoute = require_permissions.decodeComponentRoute;
|
|
551
540
|
exports.decodeFor = require_permissions.decodeFor;
|
|
552
541
|
exports.deferFlags = deferFlags;
|
|
553
|
-
exports.getDevChannel = getDevChannel;
|
|
542
|
+
exports.getDevChannel = require_devChannel.getDevChannel;
|
|
543
|
+
exports.interactionRoutesOf = require_permissions.interactionRoutesOf;
|
|
554
544
|
exports.pageCursor = pageCursor;
|
|
555
545
|
exports.pickNotice = require_permissions.pickNotice;
|
|
556
546
|
exports.prefixOf = require_permissions.prefixOf;
|
|
@@ -562,7 +552,7 @@ exports.sendFlags = sendFlags;
|
|
|
562
552
|
exports.sendTarget = sendTarget;
|
|
563
553
|
exports.serializeReply = serializeReply;
|
|
564
554
|
exports.setBotColor = require_permissions.setBotColor;
|
|
565
|
-
exports.setDevChannel = setDevChannel;
|
|
555
|
+
exports.setDevChannel = require_devChannel.setDevChannel;
|
|
566
556
|
exports.slowGateMonitor = slowGateMonitor;
|
|
567
557
|
exports.storeComponentRoute = require_permissions.storeComponentRoute;
|
|
568
558
|
exports.storeInteractionRoute = require_permissions.storeInteractionRoute;
|