@seedcord/core 0.11.0 → 0.12.0-next.2

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.
Files changed (54) hide show
  1. package/README.md +3 -3
  2. package/dist/Bus-VJw-QpoY.mjs +986 -0
  3. package/dist/Bus-VJw-QpoY.mjs.map +1 -0
  4. package/dist/{CoordinatedShutdown-H5YjZn8A.d.mts → CoordinatedShutdown-fPKLWjc5.d.mts} +13 -4
  5. package/dist/{CoordinatedStartup-CGnJrqcl.mjs → CoordinatedStartup-Zw_Lk7Zk.mjs} +22 -20
  6. package/dist/CoordinatedStartup-Zw_Lk7Zk.mjs.map +1 -0
  7. package/dist/Generated-ByC53_A2.d.mts +26 -0
  8. package/dist/HmrModuleHandler-Btgu8r96.mjs +165 -0
  9. package/dist/HmrModuleHandler-Btgu8r96.mjs.map +1 -0
  10. package/dist/{PluginHost-DB4j8unu.d.mts → PluginHost-DFnkIldj.d.mts} +43 -15
  11. package/dist/PluginHost-DTtxWRiL.mjs +552 -0
  12. package/dist/PluginHost-DTtxWRiL.mjs.map +1 -0
  13. package/dist/{PluginLifecycle-AhQ46NIr.mjs → PluginLifecycle-hx5zUc-P.mjs} +4 -4
  14. package/dist/PluginLifecycle-hx5zUc-P.mjs.map +1 -0
  15. package/dist/{ServerHost-DYeh0KTk.d.mts → ServerHost-B5o3ScCF.d.mts} +7 -6
  16. package/dist/{ServerHost-CtmAhEXn.mjs → ServerHost-CDaEDR4C.mjs} +17 -6
  17. package/dist/{ServerHost-CtmAhEXn.mjs.map → ServerHost-CDaEDR4C.mjs.map} +1 -1
  18. package/dist/bindViteEnv-NFzvdqlT.mjs +32 -0
  19. package/dist/{bindViteEnv-DWq5rftJ.mjs.map → bindViteEnv-NFzvdqlT.mjs.map} +1 -1
  20. package/dist/env-internal.index.mjs +1 -1
  21. package/dist/hmr.index.d.mts +20 -20
  22. package/dist/hmr.index.mjs +1 -1
  23. package/dist/{index-Du71Xx69.d.mts → index-DGHng1IN.d.mts} +115 -201
  24. package/dist/index.d.mts +321 -74
  25. package/dist/index.mjs +323 -102
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/internal.index.d.mts +223 -83
  28. package/dist/internal.index.mjs +573 -74
  29. package/dist/internal.index.mjs.map +1 -1
  30. package/dist/node-internal.index.d.mts +8 -4
  31. package/dist/node-internal.index.mjs +19 -6
  32. package/dist/node-internal.index.mjs.map +1 -1
  33. package/dist/node.index.d.mts +3 -3
  34. package/dist/node.index.mjs +22 -28
  35. package/dist/node.index.mjs.map +1 -1
  36. package/dist/{phases-FTM69J3a.d.mts → phases-C2QCSqRu.d.mts} +164 -55
  37. package/dist/plugin.index.d.mts +3 -2
  38. package/dist/plugin.index.mjs +1 -1
  39. package/dist/subscribers-CGuVjbrg.mjs +982 -0
  40. package/dist/subscribers-CGuVjbrg.mjs.map +1 -0
  41. package/dist/{bindViteEnv-DWq5rftJ.mjs → usingCtx-Cf2cZi96.mjs} +1 -31
  42. package/package.json +14 -11
  43. package/dist/CoordinatedStartup-CGnJrqcl.mjs.map +0 -1
  44. package/dist/HmrModuleHandler-8ZC-UuZh.mjs +0 -162
  45. package/dist/HmrModuleHandler-8ZC-UuZh.mjs.map +0 -1
  46. package/dist/PluginHost-B8kxLOeb.mjs +0 -245
  47. package/dist/PluginHost-B8kxLOeb.mjs.map +0 -1
  48. package/dist/PluginLifecycle-AhQ46NIr.mjs.map +0 -1
  49. package/dist/phases-BauKJOTT.mjs +0 -31
  50. package/dist/phases-BauKJOTT.mjs.map +0 -1
  51. package/dist/publishDefault-D3dAyzZ9.mjs +0 -7
  52. package/dist/publishDefault-D3dAyzZ9.mjs.map +0 -1
  53. package/dist/subscribers-Ce3SWy23.mjs +0 -1913
  54. package/dist/subscribers-Ce3SWy23.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["setCustomIdErrors"],"sources":["../src/customId/Errors.ts","../src/decorators/routes.ts","../src/dispatch/DispatchContext.ts","../src/handlers/BaseHandler.ts","../src/handlers/RepliableHandler.ts","../src/reply/BaseReplySender.ts","../src/stops/Fault.ts","../src/gates/combinators.ts","../src/gates/catalog/access.ts","../src/gates/catalog/Cooldown.ts","../src/permissions/assert.ts","../src/permissions/mergeRoles.ts","../src/pagination/paginate.ts","../src/pagination/Controls.ts","../src/pagination/render.ts","../src/pagination/PaginatorBase.ts","../src/pagination/sources.ts","../src/index.ts"],"sourcesContent":["import { setCustomIdErrors } from '@seedcord/custom-id';\n\nimport { Notice } from '#stops/Notice';\nimport { NoticeCard } from '#stops/NoticeCard';\n\nimport type { ReplyResponse } from '@seedcord/types';\n\n/**\n * Thrown when a customId was minted by an older version of its shape.\n *\n * This is normal after the shape changes.\n */\nexport class StaleCustomId extends Notice {\n constructor(prefix: string) {\n super(`Stale customId for \"${prefix}\".`);\n }\n\n render(): ReplyResponse {\n const card = new NoticeCard(\n 'This button or menu is from an older version. Please run the command again.',\n 'Outdated'\n );\n return { components: [card.component] };\n }\n}\n\n/**\n * Thrown when a customId wire is corrupt or tampered with and cannot be trusted.\n *\n * It reports because this is an odd case that should not happen.\n */\nexport class InvalidCustomId extends Notice {\n constructor(detail: string) {\n super(`Invalid customId. ${detail}`);\n this.report = true;\n }\n\n render(): ReplyResponse {\n const card = new NoticeCard('Something went wrong. Please try again.');\n return { components: [card.component] };\n }\n}\n\n// core's entry imports this file for the call below. a decode failure then reaches the boundary as a\n// Notice and renders a card.\nsetCustomIdErrors({\n stale: (prefix) => new StaleCustomId(prefix),\n invalid: (detail) => new InvalidCustomId(detail)\n});\n","/* eslint-disable max-lines -- this one file has all the route defs */\n\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { contextMenuRouteOf, storeComponentRoute, storeInteractionRoute } from '#decorators/interactionRoutes';\nimport { InteractionKind } from '#src/metadataKeys';\n\nimport type { ContextMenuKind, NamesFor } from '#registries/ContextMenuRegistry';\nimport type { SlashRegistry } from '#registries/SlashRegistry';\nimport type {\n AutocompleteRouteBrand,\n ComponentDefsBrand,\n ComponentKindBrand,\n ContextMenuKindBrand,\n ContextMenuNamesBrand,\n SlashRouteBrand\n} from './brands';\nimport type { AnyCustomId } from '@seedcord/custom-id';\nimport type { TypedExtract } from '@seedcord/types';\nimport type { Constructor } from 'type-fest';\n\n// Extract over Exclude so a kind added to the enum stays out until someone gives it a decorator\ntype ComponentBrand = TypedExtract<\n InteractionKind,\n | InteractionKind.Button\n | InteractionKind.Modal\n | InteractionKind.StringMenu\n | InteractionKind.UserMenu\n | InteractionKind.RoleMenu\n | InteractionKind.ChannelMenu\n | InteractionKind.MentionableMenu\n>;\n\n// core cannot import the transport handler bases. every route arrives on a phantom brand.\ntype AnyHandlerCtor = new (...args: never[]) => unknown;\n\ntype SlashRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [SlashRouteBrand]?: infer Route extends keyof SlashRegistry;\n }\n ? Route\n : never;\n\ntype AutocompleteRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [AutocompleteRouteBrand]?: infer Route extends keyof SlashRegistry;\n }\n ? Route\n : never;\n\ntype ContextMenuKindOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ContextMenuKindBrand]?: infer Kind extends ContextMenuKind;\n }\n ? Kind\n : never;\n\ntype ContextMenuNamesOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ContextMenuNamesBrand]?: infer Names;\n }\n ? Names\n : never;\n\ntype ComponentOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ComponentKindBrand]?: infer Brand extends ComponentBrand;\n }\n ? Brand\n : never;\n\ntype DefsOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ComponentDefsBrand]?: infer Defs extends readonly AnyCustomId[];\n }\n ? Defs\n : never;\n\ntype AssertSlashRoute<Route extends keyof SlashRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n SlashRouteOf<TCtor>\n]\n ? [SlashRouteOf<TCtor>] extends [Route]\n ? TCtor\n : Constructor<\n ['SlashHandler declares a route that the SlashRoute decorator does not list', SlashRouteOf<TCtor>]\n >\n : Constructor<['SlashRoute does not match the SlashHandler generic', Route]>;\n\ntype AssertAutocompleteRoute<Route extends keyof SlashRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n AutocompleteRouteOf<TCtor>\n]\n ? [AutocompleteRouteOf<TCtor>] extends [Route]\n ? TCtor\n : Constructor<\n [\n 'AutocompleteHandler declares a command that the AutocompleteRoute decorator does not list',\n AutocompleteRouteOf<TCtor>\n ]\n >\n : Constructor<['AutocompleteRoute does not match the AutocompleteHandler generic', Route]>;\n\ntype AssertContextMenuRoute<\n Kind extends ContextMenuKind,\n Names extends NamesFor<Kind>,\n TCtor extends AnyHandlerCtor\n> = [Kind] extends [ContextMenuKindOf<TCtor>]\n ? [ContextMenuKindOf<TCtor>] extends [Kind]\n ? [Names] extends [ContextMenuNamesOf<TCtor>]\n ? [ContextMenuNamesOf<TCtor>] extends [Names]\n ? TCtor\n : Constructor<\n [\n 'ContextMenuHandler declares a name that the ContextMenuRoute decorator does not list',\n ContextMenuNamesOf<TCtor>\n ]\n >\n : Constructor<['ContextMenuRoute lists a name that the ContextMenuHandler generic does not declare', Names]>\n : Constructor<\n [\n 'ContextMenuHandler declares a kind that the ContextMenuRoute decorator does not match',\n ContextMenuKindOf<TCtor>\n ]\n >\n : Constructor<['ContextMenuRoute does not match the ContextMenuHandler generic', Kind]>;\n\n// only one assignability direction, since 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\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. 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 SlashRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertSlashRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionKind.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. Listing fewer or more commands than the handler declares is a compile error, since the\n * decorator routes and the generic must match exactly.\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 SlashRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertAutocompleteRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionKind.Autocomplete, routes, constructor);\n };\n}\n\n/**\n * Routes one or more user context-menu commands to a `UserContextMenuHandler`.\n *\n * Every name is checked against the user registry. The handler's generic must declare the same names,\n * checked in both directions.\n *\n * @param names - The command name(s) this handler serves.\n * @decorator\n * @example\n * ```ts\n * \\@UserContextMenuRoute('View Profile')\n * class ViewProfile extends UserContextMenuHandler<'View Profile'> {\n * async execute() {\n * const user = this.target;\n * }\n * }\n * ```\n */\nexport function UserContextMenuRoute<const Names extends NamesFor<ApplicationCommandType.User>>(...names: Names[]) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertContextMenuRoute<ApplicationCommandType.User, Names, TCtor>\n ): void {\n storeInteractionRoute(contextMenuRouteOf(ApplicationCommandType.User), names, constructor);\n };\n}\n\n/**\n * Routes one or more message context-menu commands to a `MessageContextMenuHandler`.\n *\n * Every name is checked against the message registry. The handler's generic must declare the same names,\n * checked in both directions.\n *\n * @param names - The command name(s) this handler serves.\n * @decorator\n * @example\n * ```ts\n * \\@MessageContextMenuRoute('Report Message')\n * class ReportMessage extends MessageContextMenuHandler<'Report Message'> {\n * async execute() {\n * const message = this.target;\n * }\n * }\n * ```\n */\nexport function MessageContextMenuRoute<const Names extends NamesFor<ApplicationCommandType.Message>>(\n ...names: Names[]\n) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertContextMenuRoute<ApplicationCommandType.Message, Names, TCtor>\n ): void {\n storeInteractionRoute(contextMenuRouteOf(ApplicationCommandType.Message), 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>(\n constructor: AssertComponentRoute<InteractionKind.Button, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.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 here too, throwing StaleCustomId 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>(\n constructor: AssertComponentRoute<InteractionKind.Modal, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.Modal, defs, constructor);\n };\n}\n\n/**\n * Routes string select menu interactions to a `StringMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. The handler reads the chosen option values from `this.values`.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@StringMenuRoute(TopicsId)\n * class Topics extends StringMenuHandler<[typeof TopicsId]> {\n * async execute() {\n * await this.update(`following ${this.values.join(', ')}`);\n * }\n * }\n * ```\n */\nexport function StringMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.StringMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.StringMenu, defs, constructor);\n };\n}\n\n/**\n * Routes user select menu interactions to a `UserMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Beside `this.values` the handler declares `this.users` and `this.members`. Discord resolves\n * the members only inside a guild.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@UserMenuRoute(AssignId)\n * class Assign extends UserMenuHandler<[typeof AssignId]> {\n * async execute() {\n * const { roleId } = this.params;\n * await this.reply(`assigning ${this.users.size} member(s) to <@&${roleId}>`);\n * }\n * }\n * ```\n */\nexport function UserMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.UserMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.UserMenu, defs, constructor);\n };\n}\n\n/**\n * Routes role select menu interactions to a `RoleMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Beside `this.values` the handler declares `this.roles`.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@RoleMenuRoute(GrantId)\n * class Grant extends RoleMenuHandler<[typeof GrantId]> {\n * async execute() {\n * await this.update(`granting ${this.roles.size} role(s)`);\n * }\n * }\n * ```\n */\nexport function RoleMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.RoleMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.RoleMenu, defs, constructor);\n };\n}\n\n/**\n * Routes channel select menu interactions to a `ChannelMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Beside `this.values` the handler declares `this.channels`.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@ChannelMenuRoute(LogTargetId)\n * class LogTarget extends ChannelMenuHandler<[typeof LogTargetId]> {\n * async execute() {\n * await this.update(`logging to ${this.channels.size} channel(s)`);\n * }\n * }\n * ```\n */\nexport function ChannelMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.ChannelMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.ChannelMenu, defs, constructor);\n };\n}\n\n/**\n * Routes mentionable select menu interactions to a `MentionableMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. A mentionable menu accepts users and roles together. `this.users`, `this.members`, and\n * `this.roles` can each come back empty.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@MentionableMenuRoute(InviteId)\n * class Invite extends MentionableMenuHandler<[typeof InviteId]> {\n * async execute() {\n * await this.update(`inviting ${this.users.size} user(s) and ${this.roles.size} role(s)`);\n * }\n * }\n * ```\n */\nexport function MentionableMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.MentionableMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.MentionableMenu, defs, constructor);\n };\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { DispatchBag, DispatchState } from '@seedcord/types';\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 implements DispatchBag {\n // a {} here would let a key named toString or __proto__ reach Object.prototype\n private readonly state = Object.create(null) as Partial<DispatchState>;\n\n public readonly id = crypto.randomUUID();\n\n constructor(public readonly routeId: string) {}\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 /**\n * Read a key that must be present, with `undefined` stripped from the result.\n *\n * @throws A **SeedcordError** when nothing set the key on this dispatch.\n */\n require<Key extends keyof DispatchState>(key: Key): Exclude<DispatchState[Key], undefined> {\n const value = this.state[key];\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- an empty DispatchState types every value as undefined\n if (value === undefined) throw new SeedcordError(SeedcordErrorCode.DispatchStateMissing, [String(key)]);\n return value;\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { LoggerChannelId } from '@seedcord/types';\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 /** The bag for this dispatch. Each interaction gets its own. Every handler for one event shares a single bag. */\n protected readonly dispatch: DispatchContext;\n\n protected constructor(\n event: Event,\n public readonly core: TCore,\n dispatch: DispatchContext,\n channel?: LoggerChannelId\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name, { channel });\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 { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\n\n/**\n * Shared base the repliable handlers on both transports extend. Defines the reply members over one sender.\n * A handler builds its own through `buildSender`. A middleware takes the handler's.\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 TNative - The transport's own file forms, beyond the portable `ReplyFile`\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 TNative,\n TSender extends BaseReplySender<TMessage, TNative>\n> extends BaseHandler<Event, TCore> {\n /** The reply surface for this interaction. Pass the handler to reply from outside its class. */\n public readonly sender: TSender;\n protected readonly routeId: string;\n\n protected constructor(event: Event, core: TCore, dispatch: DispatchContext, sender?: TSender) {\n super(event, core, dispatch, 'interactions');\n this.routeId = dispatch.routeId;\n // the override runs before its own field initializers\n this.sender = sender ?? this.buildSender(event, core, dispatch);\n }\n\n protected abstract buildSender(event: Event, core: TCore, dispatch: DispatchContext): TSender;\n\n /** Send the initial response, exactly once. */\n protected reply(response: ReplyResponse<TNative> | 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<TNative> | 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<TNative> | string): Promise<TMessage>;\n protected edit(target: TMessage, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected edit(\n targetOrResponse: TMessage | ReplyResponse<TNative> | string,\n maybeResponse?: ReplyResponse<TNative> | 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<TNative> | 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<TNative> | 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 { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { checkAckLegality, sendTarget } from './ackLegality';\nimport { AckTrace } from './AckTrace';\nimport { attemptWrite, publishResponse } from './responseReport';\nimport { serializeReply } from './serializeReply';\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { AckState, ReplyMethod } from './ackLegality';\nimport type { ReplyTelemetry } from './responseReport';\nimport type { SerializedReply } from './serializeReply';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { APIModalInteractionResponseCallbackData } from 'discord-api-types/v10';\n\n/** The shape djs modal builders emit from `toJSON()`. */\nexport interface ModalLike {\n toJSON(): APIModalInteractionResponseCallbackData;\n}\n\n/**\n * Tracks acknowledgement state. Every verb runs the legality check, calls the transport's wire writer,\n * then updates the state and the ack trace. Each transport binds `TMessage` to its own created-message\n * type and supplies the writers.\n *\n * @throws A **SeedcordError** when you call a verb the current ack state doesn't allow. It throws before any transport call.\n */\nexport abstract class BaseReplySender<TMessage extends { id: string }, TNative = never> {\n private state: AckState;\n // the only ids a targeted edit accepts\n private readonly sent = new Set<string>();\n // the cause carries the first ack's stack so a double-ack reports both lines\n private ackedBy?: AckTrace;\n\n protected constructor(\n private readonly telemetry: ReplyTelemetry,\n initialState: AckState = 'unacked'\n ) {\n this.state = initialState;\n }\n\n protected get routeId(): string {\n return this.telemetry.dispatch.routeId;\n }\n\n // anything that threw already reported through attemptWrite\n private report(method: ReplyMethod, startedAt: number, messageId: string | null): void {\n publishResponse(this.telemetry, { method, startedAt, outcome: 'sent', messageId });\n }\n\n private async attempt<Result>(\n method: ReplyMethod,\n startedAt: number,\n write: () => Promise<Result>\n ): Promise<Result> {\n return await attemptWrite(this.telemetry, method, startedAt, write);\n }\n\n public async reply(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('reply');\n const startedAt = performance.now();\n const created = await this.attempt('reply', startedAt, () => this.writeReply(response, opts));\n // the callback already acked discord, so record replied before the message guard can throw\n this.transition('reply', 'replied');\n const message = this.remember(this.requireMessage(created, 'reply'));\n this.report('reply', startedAt, message.id);\n return message;\n }\n\n public async defer(opts?: DeferOpts): Promise<void> {\n this.checkLegality('defer');\n const startedAt = performance.now();\n await this.attempt('defer', startedAt, () => this.writeDefer(opts));\n this.transition('defer', 'deferred-reply');\n this.report('defer', startedAt, null);\n }\n\n public async deferUpdate(): Promise<void> {\n this.checkLegality('deferUpdate');\n const startedAt = performance.now();\n await this.attempt('deferUpdate', startedAt, () => this.writeDeferUpdate());\n this.transition('deferUpdate', 'deferred-update');\n this.report('deferUpdate', startedAt, null);\n }\n\n /**\n * After a deferUpdate the state stays deferred-update. Calling this again rewrites. The returned message\n * is the source message, editable only through a bare `update` or `edit`. A targeted `edit` or `delete`\n * of it throws the foreign-target error.\n */\n public async update(response: ReplyResponse<TNative> | string): Promise<TMessage> {\n this.checkLegality('update');\n const startedAt = performance.now();\n // in deferred-update the source message is @original and the ack-legality check above already passed\n if (this.state === 'deferred-update') {\n const edited = await this.attempt('update', startedAt, () => this.editOriginal(response));\n this.report('update', startedAt, edited.id);\n return edited;\n }\n const created = await this.attempt('update', startedAt, () => this.writeUpdate(response));\n this.transition('update', 'replied');\n const message = this.remember(this.requireMessage(created, 'update'));\n this.report('update', startedAt, message.id);\n return message;\n }\n\n public async followUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('followUp');\n const startedAt = performance.now();\n const created = await this.attempt('followUp', startedAt, () => this.writeFollowUp(response, opts));\n const message = this.remember(created);\n this.report('followUp', startedAt, message.id);\n return message;\n }\n\n public edit(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n public edit(target: TMessage, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n public async edit(\n targetOrResponse: TMessage | ReplyResponse<TNative> | string,\n maybeResponse?: ReplyResponse<TNative> | string\n ): Promise<TMessage> {\n this.checkLegality('edit');\n const startedAt = performance.now();\n if (maybeResponse === undefined) {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n const edited = await this.attempt('edit', startedAt, () =>\n this.editOriginal(targetOrResponse as ReplyResponse<TNative> | string)\n );\n this.report('edit', startedAt, edited.id);\n return edited;\n }\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n const target = targetOrResponse as TMessage;\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['edit', target.id, this.routeId]);\n }\n const written = await this.attempt('edit', startedAt, () => this.writeEditTarget(target.id, maybeResponse));\n const message = this.remember(written);\n this.report('edit', startedAt, message.id);\n return message;\n }\n\n public delete(): Promise<void>;\n public delete(target: TMessage): Promise<void>;\n public async delete(target?: TMessage): Promise<void> {\n this.checkLegality('delete');\n const startedAt = performance.now();\n if (target === undefined) {\n await this.attempt('delete', startedAt, () => this.writeDeleteOriginal());\n this.report('delete', startedAt, null);\n return;\n }\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['delete', target.id, this.routeId]);\n }\n await this.attempt('delete', startedAt, () => this.writeDeleteTarget(target.id));\n // evict so a later targeted edit of this id throws foreign\n this.sent.delete(target.id);\n this.report('delete', startedAt, null);\n }\n\n /** Routes to the verb the current ack state permits. Every state has a route, so the illegal-ack throw is unreachable. */\n public async send(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n const target = sendTarget(this.state);\n if (target === 'reply') return await this.reply(response, opts);\n if (target === 'edit') return await this.edit(response);\n return await this.followUp(response, opts);\n }\n\n /** Must be the initial response. */\n public async showModal(modal: ModalLike): Promise<void> {\n this.checkLegality('showModal');\n this.guardModalSource();\n let data: APIModalInteractionResponseCallbackData;\n try {\n data = modal.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype modal has no constructor at runtime\n const name = modal.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'modal' : name, 0, this.routeId);\n }\n const startedAt = performance.now();\n await this.attempt('showModal', startedAt, () => this.writeModal(data));\n this.transition('showModal', 'replied');\n this.report('showModal', startedAt, null);\n }\n\n protected serialize(response: ReplyResponse<TNative> | string): SerializedReply<TNative> {\n return serializeReply(response, this.routeId);\n }\n\n protected remember(created: TMessage): TMessage {\n this.sent.add(created.id);\n return created;\n }\n\n // a with_response callback always returns the created message. this only trips if the wire says otherwise\n private requireMessage(created: TMessage | undefined, method: 'reply' | 'update'): TMessage {\n if (!created) throw new SeedcordError(SeedcordErrorCode.ReplyCallbackMissingMessage, [method, this.routeId]);\n return created;\n }\n\n private async editOriginal(response: ReplyResponse<TNative> | string): Promise<TMessage> {\n const edited = await this.writeEditOriginal(response);\n // after a deferUpdate the source message is @original, which this interaction did not send\n if (this.state !== 'deferred-update') this.remember(edited);\n return edited;\n }\n\n private checkLegality(method: ReplyMethod): void {\n checkAckLegality(method, this.state, this.routeId, this.ackedBy);\n }\n\n private transition(method: ReplyMethod, state: AckState): void {\n this.state = state;\n this.ackedBy = new AckTrace(method);\n }\n\n // gateway overrides this to reject a modal-submit source\n protected guardModalSource(): void {}\n\n protected abstract writeReply(\n response: ReplyResponse<TNative> | string,\n opts?: SendOpts\n ): Promise<TMessage | undefined>;\n protected abstract writeDefer(opts?: DeferOpts): Promise<void>;\n protected abstract writeDeferUpdate(): Promise<void>;\n protected abstract writeUpdate(response: ReplyResponse<TNative> | string): Promise<TMessage | undefined>;\n protected abstract writeFollowUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage>;\n protected abstract writeEditOriginal(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected abstract writeEditTarget(targetId: string, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected abstract writeDeleteOriginal(): Promise<void>;\n protected abstract writeDeleteTarget(targetId: string): Promise<void>;\n protected abstract writeModal(data: APIModalInteractionResponseCallbackData): Promise<void>;\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. When the user should see a real message for a fault,\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, and 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// keep this in step with Grouped in matching.ts\nconst ALREADY_JOINED = / [&|] /;\n\nfunction joinNames(gates: readonly Gate<GateContextBase>[], separator: string): string {\n return gates.map((gate) => (ALREADY_JOINED.test(gate.name) ? `(${gate.name})` : gate.name)).join(separator);\n}\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(joinNames(gates, ' & '), async (ctx) => {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n });\n}\n\ninterface OrOptions {\n fail: Notice | ((ctx: GateContextBase) => Notice);\n}\n\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. A handler that matches any one arm fits. When every\n * arm refuses it throws the trailing {@link OrOptions} `fail` if given, else a list built from each\n * refusal's `summary`, else a default refusal. The trailing options object does not 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(joinNames(gates, ' | '), 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 counts as 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 it refused\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 // 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 { Gate, GateContextBase } from '#gates/Gate';\nimport type { GateNoticeOptions } from './options';\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 your transport package\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. 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 your transport package\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, fitting 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 your transport package\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 { SeedcordRangeError, 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 { Notice } from '#stops/Notice';\nimport type { EpochMs } from '@seedcord/types';\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, to\n * show 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. each Cooldown() call 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**, and a string is\n * a duration like `30m` or `24h`. The slot is charged in commit, only after the whole gate set passes,\n * 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, keeping two different handlers on 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, and a string is a duration like `30m` or `24h`.\n * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.\n * @throws A **SeedcordTypeError** when `duration` is a string that doesn't parse.\n * @throws A **SeedcordRangeError** when `duration` is zero or negative.\n *\n * @see the `@Gated` decorator from your transport package\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\n if (windowMs <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.GateInvalidCooldownDuration, [String(duration)]);\n }\n\n const per = options?.per ?? 'user';\n // exactOptionalPropertyTypes rejects an explicit undefined key\n const window = options?.limit === undefined ? { windowMs } : { windowMs, limit: options.limit };\n const anonId = anonSeq++;\n // routed keys stay stable across restarts, letting a durable store rebuild the same window\n const keyOf = (ctx: GateContextBase): string =>\n `cooldown:${ctx.declaredRoute ?? `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","import { HasDangerousPermissions, MissingPermissions } from '#notices/index';\n\nimport { hasAll, missingNames, presentNames } from './bits';\n\nimport type { Notice } from '#stops/Notice';\nimport type { PermissionScope } from './bits';\n\n/** Replacement notices for the two refusals {@link assertPermissions} raises. */\nexport interface PermissionNoticeOverrides {\n missingNotice?: new (message: string | undefined, subject: string, missingPerms: readonly string[]) => Notice;\n dangerousNotice?: new (message: string | undefined, subject: string, dangerousPerms: readonly string[]) => Notice;\n}\n\n/** The check {@link assertPermissions} runs. */\nexport interface PermissionAssertion extends PermissionNoticeOverrides {\n /** Mention string for who is checked, used as the refusal's subject. */\n subject: string;\n /** The effective permission bitfield the subject holds, computed by the caller. */\n permissions: bigint;\n /** The permission flag bits to check. */\n scope: PermissionScope;\n /** Refuse when the subject holds a scope bit. */\n inverse?: boolean;\n}\n\n/**\n * Refuses when the subject is missing a permission in `scope`, or with `inverse` when it holds one.\n * The Administrator bit passes any scope, and on the inverse arm it reports every bit in `scope`.\n *\n * The caller computes `permissions`, gateway off a discord.js role, member, or channel, and HTTP off the\n * bitfield the interaction payload carries.\n *\n * @throws A {@link Notice} when the check refuses. It lists the missing or present permissions.\n *\n * @example\n * ```ts\n * import { assertPermissions } from '@seedcord/core';\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * // gateway, the bits come off a discord.js member\n * assertPermissions({\n * subject: `<@${member.id}>`,\n * permissions: member.permissions.bitfield,\n * scope: [PermissionFlagsBits.BanMembers]\n * });\n * ```\n *\n * @example\n * ```ts\n * // HTTP, the payload carries the member's bits as a string\n * assertPermissions({\n * subject: `<@${this.event.member.user.id}>`,\n * permissions: BigInt(this.event.member.permissions),\n * scope: [PermissionFlagsBits.ManageMessages]\n * });\n * ```\n *\n * @example\n * ```ts\n * // inverse, refuse a role that carries Administrator\n * assertPermissions({\n * subject: `<@&${role.id}>`,\n * permissions: role.permissions.bitfield,\n * scope: [PermissionFlagsBits.Administrator],\n * inverse: true\n * });\n * ```\n *\n * @example\n * ```ts\n * import { Notice } from '@seedcord/core';\n *\n * // a replacement notice takes the same three arguments the default one does\n * class CannotBan extends Notice {\n * public constructor(\n * message: string | undefined,\n * private readonly subject: string,\n * private readonly missing: readonly string[]\n * ) {\n * super(message ?? 'You cannot ban here.');\n * }\n *\n * public render(): ReplyResponse {\n * return { components: [new BanDenied(this.subject, this.missing).component] };\n * }\n * }\n *\n * assertPermissions({\n * subject: `<@${member.id}>`,\n * permissions: member.permissions.bitfield,\n * scope: [PermissionFlagsBits.BanMembers],\n * missingNotice: CannotBan\n * });\n * ```\n */\nexport function assertPermissions(check: PermissionAssertion): void {\n const { subject, permissions, scope, inverse = false, missingNotice, dangerousNotice } = check;\n\n if (inverse) {\n const present = presentNames(permissions, scope);\n if (present.length === 0) return;\n const Dangerous = dangerousNotice ?? HasDangerousPermissions;\n throw new Dangerous(undefined, subject, present);\n }\n\n if (hasAll(permissions, scope)) return;\n const Missing = missingNotice ?? MissingPermissions;\n throw new Missing(undefined, subject, missingNames(permissions, scope));\n}\n","/**\n * The role ids a member holds after adding and removing the given sets. Removals win over additions.\n *\n * This does not write the roles. Apply the result with `member.roles.set()` on gateway, or PATCH the member over HTTP.\n *\n * @param current - The role ids the member holds.\n * @param add - The role ids to add.\n * @param remove - The role ids to remove.\n * @returns The merged role ids.\n *\n * @example\n * ```ts\n * import { mergeRoles } from '@seedcord/core';\n *\n * // gateway\n * const ids = mergeRoles(member.roles.cache.map((role) => role.id), ['123'], ['456']);\n * await member.roles.set(ids);\n * ```\n */\nexport function mergeRoles(current: readonly string[], add: readonly string[], remove: readonly string[]): string[] {\n return [...new Set(current).union(new Set(add)).difference(new Set(remove))];\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 A **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 // NaN comes back out of Math.trunc, Math.max, and Math.min unchanged.\n const requested = Number.isNaN(page) ? 0 : Math.trunc(page);\n const clamped = Math.min(Math.max(requested, 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 { ActionRowBuilder, ButtonBuilder } from '@discordjs/builders';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { ButtonStyle } from 'discord-api-types/v10';\n\nimport { PAGE_MAX } from '#pagination/cursor';\n\nimport type { PageCursor } from '#pagination/cursor';\nimport type { PageView } from '#pagination/PageView';\nimport type { APIMessageComponentEmoji } from 'discord-api-types/v10';\n\n/** The five built-in nav controls. */\nexport type ControlKey = 'first' | 'prev' | 'indicator' | 'next' | 'last';\n\n// Link and Premium have no custom_id, which un-routes a control.\ntype CustomIdStyle = ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success | ButtonStyle.Danger;\n\n/** Cosmetic overrides for a control button. `style` excludes Link and Premium, which would un-route it. */\nexport interface ControlCosmetics {\n label?: string;\n style?: CustomIdStyle;\n emoji?: APIMessageComponentEmoji;\n}\n\n/** The controls passed to `render`. */\nexport interface PaginatorControls {\n /**\n * A fresh `ButtonBuilder` for one control, already stamped with its target page and disabled-at-bounds\n * state. Call only cosmetic setters on it, because a `setCustomId` or `setStyle(Link)` un-routes it.\n */\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder;\n /**\n * Assemble an action row of the chosen controls, in order.\n *\n * @throws A **SeedcordRangeError** when `keys` is empty or holds more than five controls.\n * @throws A **SeedcordTypeError** when `keys` holds the same control twice.\n */\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder>;\n}\n\nconst DEFAULT_LABEL: Record<ControlKey, string> = {\n first: 'First',\n prev: 'Prev',\n indicator: '',\n next: 'Next',\n last: 'Last'\n};\n\n// a distinct slot keeps two controls on the same page off the same id. 0-4 is the cursor's SLOT_MAX.\nconst CONTROL_SLOT: Record<ControlKey, number> = {\n first: 0,\n prev: 1,\n indicator: 2,\n next: 3,\n last: 4\n};\n\nconst MAX_BUTTONS_PER_ROW = 5;\n\nexport class Controls implements PaginatorControls {\n constructor(\n private readonly cursor: PageCursor<string>,\n private readonly view: PageView<unknown>\n ) {}\n\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder {\n const { target, disabled } = this.navState(key);\n\n // an emoji with no explicit label makes an icon-only button. the indicator always shows its page text.\n const defaultLabel = key === 'indicator' ? this.indicatorText() : DEFAULT_LABEL[key];\n const label = cosmetics?.label ?? (key === 'indicator' || !cosmetics?.emoji ? defaultLabel : undefined);\n\n const button = new ButtonBuilder()\n // an enormous list could push last/next past PAGE_MAX, where encode throws.\n .setCustomId(this.cursor.encode({ page: Math.min(Math.max(0, target), PAGE_MAX), slot: CONTROL_SLOT[key] }))\n .setStyle(cosmetics?.style ?? ButtonStyle.Secondary)\n .setDisabled(disabled);\n if (label !== undefined) button.setLabel(label);\n if (cosmetics?.emoji) button.setEmoji(cosmetics.emoji);\n return button;\n }\n\n private navState(key: ControlKey): { target: number; disabled: boolean } {\n const { page, totalPages, hasPrev, hasNext } = this.view;\n const knownTotal = totalPages !== undefined;\n const target = {\n first: 0,\n prev: page - 1,\n indicator: page,\n next: page + 1,\n last: knownTotal ? totalPages - 1 : page\n }[key];\n // past PAGE_MAX the encoded page would clamp to a wrong one\n const disabled = {\n first: !hasPrev,\n prev: !hasPrev,\n indicator: true,\n next: !hasNext || page + 1 > PAGE_MAX,\n last: !hasNext || !knownTotal || totalPages - 1 > PAGE_MAX\n }[key];\n return { target, disabled };\n }\n\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder> {\n if (keys.length === 0 || keys.length > MAX_BUTTONS_PER_ROW) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationControlCount, [keys.length, MAX_BUTTONS_PER_ROW]);\n }\n // repeating a control reuses its slot and page, so the custom_ids collide and Discord rejects the message.\n const seen = new Set<ControlKey>();\n for (const key of keys) {\n if (seen.has(key)) throw new SeedcordTypeError(SeedcordErrorCode.PaginationDuplicateControls, [key]);\n seen.add(key);\n }\n return new ActionRowBuilder<ButtonBuilder>().addComponents(keys.map((key) => this.button(key)));\n }\n\n private indicatorText(): string {\n const { page, totalPages } = this.view;\n return totalPages === undefined ? `Page ${page + 1}` : `Page ${page + 1} of ${totalPages}`;\n }\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '#components/Component';\nimport { Controls } from '#pagination/Controls';\n\nimport type { ControlKey, PaginatorControls } from '#pagination/Controls';\nimport type { PageCursor } from '#pagination/cursor';\nimport type { PageView } from '#pagination/PageView';\nimport type { ButtonBuilder, ActionRowBuilder } from '@discordjs/builders';\nimport type { ReplyResponse, V2Component } from '@seedcord/types';\n\n/** What `renderItem` returns for one item, a text line or a section. */\nexport type ItemRender<Item> = (item: Item, index: number) => string | BuilderComponent<'section'>;\n\ntype Renderable = string | V2Component[] | ReplyResponse;\n\n/** A full-page render override. */\nexport type PageRender<Item> = (view: PageView<Item>, controls: PaginatorControls) => Renderable;\n\n// subclassed because BuilderComponent.instance is protected\nclass PageContainer<Item> extends BuilderComponent<'container'> {\n constructor(view: PageView<Item>, renderItem: ItemRender<Item>, controlRow: ActionRowBuilder<ButtonBuilder>) {\n super('container');\n const base = view.page * view.perPage;\n let lines: string[] = [];\n const flush = (): void => {\n if (lines.length === 0) return;\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(lines.join('\\n')));\n lines = [];\n };\n view.items.forEach((item, offset) => {\n const rendered = renderItem(item, base + offset);\n if (typeof rendered === 'string') {\n lines.push(rendered);\n return;\n }\n flush();\n this.instance.addSectionComponents(rendered.component);\n });\n flush();\n this.instance.addActionRowComponents(controlRow);\n }\n}\n\nfunction toReplyResponse(renderable: Renderable): ReplyResponse {\n if (typeof renderable === 'string') return { components: [new TextDisplayBuilder().setContent(renderable)] };\n if (Array.isArray(renderable)) return { components: renderable };\n return renderable;\n}\n\nconst ARRAY_KEYS: ControlKey[] = ['first', 'prev', 'indicator', 'next', 'last'];\nconst CURSOR_KEYS: ControlKey[] = ['prev', 'indicator', 'next'];\n\n// a render override builds the whole tree, or the default container lists the items and appends\n// the controls (all five for a known total, prev/indicator/next for a cursor source)\nexport function renderPage<Item>(\n view: PageView<Item>,\n cursor: PageCursor<string>,\n config: { renderItem?: ItemRender<Item>; render?: PageRender<Item> }\n): ReplyResponse {\n const controls = new Controls(cursor, view);\n if (config.render) return toReplyResponse(config.render(view, controls));\n\n const renderItem = config.renderItem ?? String;\n const row = controls.row(...(view.totalPages === undefined ? CURSOR_KEYS : ARRAY_KEYS));\n return { components: [new PageContainer(view, renderItem, row).component] };\n}\n","import { pageCursor } from '#pagination/cursor';\nimport { renderPage } from '#pagination/render';\n\nimport type { PageCursor } from '#pagination/cursor';\nimport type { ItemRender, PageRender } from '#pagination/render';\nimport type { PageSourceBase } from '#pagination/sources';\nimport type { ReplyResponse } from '@seedcord/types';\n\n/**\n * The transport-agnostic paginator configuration. Each transport adds its own handler wiring on top.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `prefix`.\n * @typeParam Ctx - The transport's page context.\n */\nexport interface PaginatorConfig<Item, Prefix extends string, Ctx> {\n /** The route prefix used to build the page cursor on the nav buttons. */\n prefix: Prefix;\n source: PageSourceBase<Item, Ctx>;\n /** Render one item, `index` is its absolute position across pages. Ignored when `render` is set. */\n renderItem?: ItemRender<Item>;\n /** Take over the whole page tree. Receives the page data and the controls factory. */\n render?: PageRender<Item>;\n /**\n * Whether the first page is ephemeral.\n *\n * @defaultValue `false`\n */\n ephemeral?: boolean;\n}\n\n/**\n * Holds a paginator's cursor and renders one page. Each transport extends this to add the nav handler and\n * the method that sends the first page.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `config.prefix`.\n * @typeParam Ctx - The transport's page context.\n */\nexport abstract class PaginatorBase<Item, Prefix extends string, Ctx> {\n /** The page cursor, pass it to your `@ButtonRoute`. */\n public readonly cursor: PageCursor<Prefix>;\n\n protected readonly config: PaginatorConfig<Item, Prefix, Ctx>;\n\n protected constructor(config: PaginatorConfig<Item, Prefix, Ctx>) {\n this.cursor = pageCursor(config.prefix);\n this.config = config;\n }\n\n /** Build one page as a {@link ReplyResponse}. Each transport wraps this in a `page()` taking its handler. */\n protected async buildPage(ctx: Ctx, n: number): Promise<ReplyResponse> {\n const view = await this.config.source.page(ctx, n);\n return renderPage(view, this.cursor, this.config);\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { paginate } from '#pagination/paginate';\n\nimport type { PageView } from '#pagination/PageView';\nimport type { Promisable } from 'type-fest';\n\nconst DEFAULT_PER_PAGE = 10;\n\n/**\n * The one method a paginator calls on a source, once per click. Implement it to supply a custom source.\n *\n * @typeParam Item - The item type the source pages over.\n * @typeParam Ctx - The transport's page context, handed to the loader.\n */\nexport interface PageSourceBase<Item, Ctx> {\n page(ctx: Ctx, n: number): Promise<PageView<Item>>;\n}\n\nfunction perPageOf(opts?: { perPage?: number }): number {\n const perPage = opts?.perPage ?? DEFAULT_PER_PAGE;\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n return perPage;\n}\n\n/**\n * A source for a bounded list you can load whole. It loads the full list on every click, then slices the\n * page via {@link paginate}, so the real total is known (a real last button, \"Page X of Y\"). Cache inside\n * your loader if the load is expensive.\n *\n * @typeParam Item - The item type, inferred from the loader's return.\n * @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.\n */\nexport class ArraySourceBase<Item, Ctx> implements PageSourceBase<Item, Ctx> {\n private readonly perPage: number;\n\n constructor(\n private readonly load: (ctx: Ctx) => Promisable<readonly Item[]>,\n opts?: { perPage?: number }\n ) {\n this.perPage = perPageOf(opts);\n }\n\n async page(ctx: Ctx, n: number): Promise<PageView<Item>> {\n return paginate(await this.load(ctx), n, this.perPage);\n }\n}\n\n/**\n * A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).\n * The fetcher receives the page index and the page size and reports whether a next page exists. A cursor\n * source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator\n * reads \"Page X\".\n *\n * @typeParam Item - The item type, inferred from the fetcher's slice.\n * @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.\n */\nexport class CursorSourceBase<Item, Ctx> implements PageSourceBase<Item, Ctx> {\n private readonly perPage: number;\n\n constructor(\n private readonly fetch: (\n ctx: Ctx,\n page: number,\n perPage: number\n ) => Promisable<{ items: readonly Item[]; hasNext: boolean }>,\n opts?: { perPage?: number }\n ) {\n this.perPage = perPageOf(opts);\n }\n\n async page(ctx: Ctx, n: number): Promise<PageView<Item>> {\n // a cursor source has no total to clamp against. Infinity and NaN both fall back to 0.\n const page = Number.isFinite(n) ? Math.max(0, Math.trunc(n)) : 0;\n const { items, hasNext } = await this.fetch(ctx, page, this.perPage);\n return { items: [...items], page, perPage: this.perPage, hasPrev: page > 0, hasNext };\n }\n}\n","import 'reflect-metadata';\n\n// Errors.ts registers the two notices thrown by a failed decode\nimport '#customId/Errors';\n\nexport type { MessageContextMenuRegistry, UserContextMenuRegistry } from '#registries/ContextMenuRegistry';\nexport type { SlashRegistry } from '#registries/SlashRegistry';\n\nexport { Commands, ContextMenus } from '#src/commands/CommandInjector';\nexport type {\n CommandInfo,\n ContextMenuInfo,\n InjectedCommandMap,\n InjectedContextMenuMap\n} from '#src/commands/CommandInjector';\n\nexport { RegisterCommand } from '#decorators/Command';\nexport type { GuildTarget } from '#decorators/Command';\nexport {\n AutocompleteRoute,\n ButtonRoute,\n ChannelMenuRoute,\n MentionableMenuRoute,\n MessageContextMenuRoute,\n UserContextMenuRoute,\n ModalRoute,\n RoleMenuRoute,\n SlashRoute,\n StringMenuRoute,\n UserMenuRoute\n} from '#decorators/routes';\n\nexport { InteractionKind } from '#src/metadataKeys';\nexport type { MiddlewareKind } from '#src/metadataKeys';\n\nexport { RegisterInteractionMiddleware } from '#decorators/middleware';\nexport type { InteractionMiddlewareOptions } from '#decorators/middleware';\n\nexport { DispatchContext } from '#src/dispatch/DispatchContext';\nexport type { DispatchResult, EventDispatchResult, HandlerOutcome, HandlerResult } from '#src/dispatch/dispatchResult';\n\nexport { BaseHandler } from '#src/handlers/BaseHandler';\nexport { RepliableHandler } from '#src/handlers/RepliableHandler';\n\nexport { BaseReplySender } from '#reply/BaseReplySender';\nexport type { ModalLike } from '#reply/BaseReplySender';\n\nexport type { CoreBase } from '#interfaces/CoreBase';\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 { assertPermissions } from '#src/permissions/assert';\nexport type { PermissionAssertion, PermissionNoticeOverrides } from '#src/permissions/assert';\nexport { mergeRoles } from '#src/permissions/mergeRoles';\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, decodeFor, prefixOf, setCustomIdErrors } from '@seedcord/custom-id';\nexport type {\n AnyCustomId,\n CustomIdField,\n CustomIdShape,\n DecodedParams,\n DecodedRoute,\n FieldOptions\n} from '@seedcord/custom-id';\n\nexport { ResolvedEmoji } from '#src/miscellaneous/ResolvedEmoji';\n\nexport type { AutocompleteOptions } from '#inputs/AutocompleteOptions';\n\nexport { paginate } from '#pagination/paginate';\nexport { type PageView } from '#pagination/PageView';\nexport { PaginatorBase } from '#pagination/PaginatorBase';\nexport type { PaginatorConfig } from '#pagination/PaginatorBase';\nexport { ArraySourceBase, CursorSourceBase } from '#pagination/sources';\nexport type { PageSourceBase } from '#pagination/sources';\nexport type { ControlCosmetics, ControlKey, PaginatorControls } from '#pagination/Controls';\nexport type { ItemRender, PageRender } from '#pagination/render';\n\nexport { Bus, Subscribe, Subscriber, WebhookLog, WebhookUrl } from '#subscribers/index';\nexport type {\n AttemptedWrite,\n DispatchOutcome,\n FaultSource,\n ResponseAttempt,\n ResponseFailed,\n ResponseOutcome,\n ResponseSent,\n SubscribeOptions,\n Subscriptions,\n SubscriptionData,\n SubscriptionKey,\n WebhookFile,\n WebhookReport\n} from '#subscribers/index';\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":["setCustomIdErrors"],"sources":["../src/customId/Errors.ts","../src/decorators/routes.ts","../src/handlers/BaseHandler.ts","../src/handlers/RepliableHandler.ts","../src/reply/BaseReplySender.ts","../src/gates/Gate.ts","../src/gates/combinators.ts","../src/gates/catalog/access.ts","../src/gates/catalog/Cooldown.ts","../src/permissions/bits.ts","../src/permissions/assert.ts","../src/gates/catalog/permissions.ts","../src/permissions/mergeRoles.ts","../src/pagination/paginate.ts","../src/pagination/Controls.ts","../src/pagination/render.ts","../src/pagination/PaginatorBase.ts","../src/pagination/sources.ts","../src/kv/KeyvDriver.ts","../src/kv/UnstorageDriver.ts","../src/rateLimiter/buildKey.ts","../src/index.ts"],"sourcesContent":["import { setCustomIdErrors } from '@seedcord/custom-id';\n\nimport { Notice } from '#stops/Notice';\nimport { NoticeCard } from '#stops/NoticeCard';\n\nimport type { ReplyResponse } from '@seedcord/types';\n\n/**\n * Thrown when a customId was minted by an older version of its shape.\n *\n * This is normal after the shape changes.\n */\nexport class StaleCustomId extends Notice {\n constructor(prefix: string) {\n super(`Stale customId for \"${prefix}\".`);\n }\n\n override render(): ReplyResponse {\n const card = new NoticeCard(\n 'This button or menu is from an older version. Please run the command again.',\n 'Outdated'\n );\n return { components: [card.component] };\n }\n}\n\n/**\n * Thrown when a customId wire is corrupt or tampered with and cannot be trusted.\n *\n * It reports because this is an odd case that should not happen.\n */\nexport class InvalidCustomId extends Notice {\n constructor(detail: string) {\n super(`Invalid customId. ${detail}`);\n this.report = true;\n }\n\n override render(): ReplyResponse {\n const card = new NoticeCard('Something went wrong. Please try again.');\n return { components: [card.component] };\n }\n}\n\n// core's entry imports this file for the call below. a decode failure then reaches the boundary as a\n// Notice and renders a card.\nsetCustomIdErrors({\n stale: (prefix) => new StaleCustomId(prefix),\n invalid: (detail) => new InvalidCustomId(detail)\n});\n","/* eslint-disable max-lines -- this one file has all the route defs */\n\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { contextMenuRouteOf, storeComponentRoute, storeInteractionRoute } from '#decorators/interactionRoutes';\nimport { InteractionKind } from '#src/metadataKeys';\n\nimport type { ContextMenuKind, NamesFor } from '#registries/ContextMenuRegistry';\nimport type { SlashRegistry } from '#registries/SlashRegistry';\nimport type {\n AutocompleteRouteBrand,\n ComponentDefsBrand,\n ComponentKindBrand,\n ContextMenuKindBrand,\n ContextMenuNamesBrand,\n SlashRouteBrand\n} from './brands';\nimport type { AnyCustomId } from '@seedcord/custom-id';\nimport type { TypedExtract } from '@seedcord/types';\nimport type { Constructor, LiteralUnion } from 'type-fest';\n\n// Extract over Exclude so a kind added to the enum stays out until someone gives it a decorator\ntype ComponentBrand = TypedExtract<\n InteractionKind,\n | InteractionKind.Button\n | InteractionKind.Modal\n | InteractionKind.StringMenu\n | InteractionKind.UserMenu\n | InteractionKind.RoleMenu\n | InteractionKind.ChannelMenu\n | InteractionKind.MentionableMenu\n>;\n\n// core cannot import the transport handler bases. every route arrives on a phantom brand.\ntype AnyHandlerCtor = new (...args: never[]) => unknown;\n\ntype SlashRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [SlashRouteBrand]?: infer Route extends keyof SlashRegistry;\n }\n ? Route\n : never;\n\ntype AutocompleteRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [AutocompleteRouteBrand]?: infer Route extends keyof SlashRegistry;\n }\n ? Route\n : never;\n\ntype ContextMenuKindOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ContextMenuKindBrand]?: infer Kind extends ContextMenuKind;\n }\n ? Kind\n : never;\n\ntype ContextMenuNamesOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ContextMenuNamesBrand]?: infer Names;\n }\n ? Names\n : never;\n\ntype ComponentOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ComponentKindBrand]?: infer Brand extends ComponentBrand;\n }\n ? Brand\n : never;\n\ntype DefsOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ComponentDefsBrand]?: infer Defs extends readonly AnyCustomId[];\n }\n ? Defs\n : never;\n\ntype SameSet<Left, Right> = [Left] extends [Right] ? ([Right] extends [Left] ? true : false) : false;\n\ntype Mismatch<Message extends string, Decorator, Generic> = Constructor<\n [Message, { decorator: Decorator; generic: Generic }]\n>;\n\n// this checks registry membership because the decorators accept any string\ntype AssertNames<\n Names extends string,\n Registered,\n Declared,\n Decorator extends string,\n Handler extends string,\n TCtor extends AnyHandlerCtor\n> = [Names] extends [Registered]\n ? SameSet<Names, Declared> extends true\n ? TCtor\n : Mismatch<`${Decorator} does not match the ${Handler} generic`, Names, Declared>\n : Constructor<[`${Decorator} lists a command that is not registered`, Exclude<Names, Registered>]>;\n\ntype AssertSlashRoute<Route extends string, TCtor extends AnyHandlerCtor> = AssertNames<\n Route,\n keyof SlashRegistry,\n SlashRouteOf<TCtor>,\n 'SlashRoute',\n 'SlashHandler',\n TCtor\n>;\n\ntype AssertAutocompleteRoute<Route extends string, TCtor extends AnyHandlerCtor> = AssertNames<\n Route,\n keyof SlashRegistry,\n AutocompleteRouteOf<TCtor>,\n 'AutocompleteRoute',\n 'AutocompleteHandler',\n TCtor\n>;\n\ntype AssertContextMenuRoute<Kind extends ContextMenuKind, Names extends string, TCtor extends AnyHandlerCtor> =\n SameSet<Kind, ContextMenuKindOf<TCtor>> extends true\n ? AssertNames<Names, NamesFor<Kind>, ContextMenuNamesOf<TCtor>, 'ContextMenuRoute', 'ContextMenuHandler', TCtor>\n : Mismatch<'ContextMenuRoute does not match the ContextMenuHandler kind', Kind, ContextMenuKindOf<TCtor>>;\n\ntype AssertComponentRoute<\n Brand extends ComponentBrand,\n Defs extends readonly AnyCustomId[],\n TCtor extends AnyHandlerCtor\n> =\n SameSet<Brand, ComponentOf<TCtor>> extends true\n ? // only one assignability direction, since a bidirectional check would reject const-inferred readonly tuples\n [DefsOf<TCtor>] extends [Defs]\n ? TCtor\n : Mismatch<'the customId definitions do not match the handler generic', Defs, DefsOf<TCtor>>\n : Mismatch<'the decorator does not match the handler kind', Brand, ComponentOf<TCtor>>;\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. On a handler for one command, read\n * `this.options`. On a handler for several, branch with `this.match`. The decorator routes and the generic must match exactly. 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 LiteralUnion<keyof SlashRegistry, string>>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertSlashRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionKind.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 cases span every command's\n * fields. Listing fewer or more commands than the handler declares is a compile error, since the\n * decorator routes and the generic must match exactly.\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 LiteralUnion<keyof SlashRegistry, string>>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertAutocompleteRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionKind.Autocomplete, routes, constructor);\n };\n}\n\n/**\n * Routes one or more user context-menu commands to a `UserContextMenuHandler`.\n *\n * Every name is checked against the user registry. The handler's generic must declare the same names,\n * checked in both directions.\n *\n * @param names - The command name(s) this handler serves.\n * @decorator\n * @example\n * ```ts\n * \\@UserContextMenuRoute('View Profile')\n * class ViewProfile extends UserContextMenuHandler<'View Profile'> {\n * async execute() {\n * const user = this.target;\n * }\n * }\n * ```\n */\nexport function UserContextMenuRoute<const Names extends LiteralUnion<NamesFor<ApplicationCommandType.User>, string>>(\n ...names: Names[]\n) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertContextMenuRoute<ApplicationCommandType.User, Names, TCtor>\n ): void {\n storeInteractionRoute(contextMenuRouteOf(ApplicationCommandType.User), names, constructor);\n };\n}\n\n/**\n * Routes one or more message context-menu commands to a `MessageContextMenuHandler`.\n *\n * Every name is checked against the message registry. The handler's generic must declare the same names,\n * checked in both directions.\n *\n * @param names - The command name(s) this handler serves.\n * @decorator\n * @example\n * ```ts\n * \\@MessageContextMenuRoute('Report Message')\n * class ReportMessage extends MessageContextMenuHandler<'Report Message'> {\n * async execute() {\n * const message = this.target;\n * }\n * }\n * ```\n */\nexport function MessageContextMenuRoute<\n const Names extends LiteralUnion<NamesFor<ApplicationCommandType.Message>, string>\n>(...names: Names[]) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertContextMenuRoute<ApplicationCommandType.Message, Names, TCtor>\n ): void {\n storeInteractionRoute(contextMenuRouteOf(ApplicationCommandType.Message), 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>(\n constructor: AssertComponentRoute<InteractionKind.Button, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.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 here too, throwing StaleCustomId 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>(\n constructor: AssertComponentRoute<InteractionKind.Modal, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.Modal, defs, constructor);\n };\n}\n\n/**\n * Routes string select menu interactions to a `StringMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Read the chosen option values from `this.values`.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@StringMenuRoute(TopicsId)\n * class Topics extends StringMenuHandler<[typeof TopicsId]> {\n * async execute() {\n * await this.update(`following ${this.values.join(', ')}`);\n * }\n * }\n * ```\n */\nexport function StringMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.StringMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.StringMenu, defs, constructor);\n };\n}\n\n/**\n * Routes user select menu interactions to a `UserMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Beside `this.values` the handler declares `this.users` and `this.members`. Discord resolves\n * the members only inside a guild.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@UserMenuRoute(AssignId)\n * class Assign extends UserMenuHandler<[typeof AssignId]> {\n * async execute() {\n * const { roleId } = this.params;\n * await this.reply(`assigning ${this.users.size} member(s) to <@&${roleId}>`);\n * }\n * }\n * ```\n */\nexport function UserMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.UserMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.UserMenu, defs, constructor);\n };\n}\n\n/**\n * Routes role select menu interactions to a `RoleMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Beside `this.values` the handler declares `this.roles`.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@RoleMenuRoute(GrantId)\n * class Grant extends RoleMenuHandler<[typeof GrantId]> {\n * async execute() {\n * await this.update(`granting ${this.roles.size} role(s)`);\n * }\n * }\n * ```\n */\nexport function RoleMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.RoleMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.RoleMenu, defs, constructor);\n };\n}\n\n/**\n * Routes channel select menu interactions to a `ChannelMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Beside `this.values` the handler declares `this.channels`.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@ChannelMenuRoute(LogTargetId)\n * class LogTarget extends ChannelMenuHandler<[typeof LogTargetId]> {\n * async execute() {\n * await this.update(`logging to ${this.channels.size} channel(s)`);\n * }\n * }\n * ```\n */\nexport function ChannelMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.ChannelMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.ChannelMenu, defs, constructor);\n };\n}\n\n/**\n * Routes mentionable select menu interactions to a `MentionableMenuHandler`.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. A mentionable menu accepts users and roles together. `this.users`, `this.members`, and\n * `this.roles` can each come back empty.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n * @example\n * ```ts\n * \\@MentionableMenuRoute(InviteId)\n * class Invite extends MentionableMenuHandler<[typeof InviteId]> {\n * async execute() {\n * await this.update(`inviting ${this.users.size} user(s) and ${this.roles.size} role(s)`);\n * }\n * }\n * ```\n */\nexport function MentionableMenuRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(\n constructor: AssertComponentRoute<InteractionKind.MentionableMenu, Defs, TCtor>\n ): void {\n storeComponentRoute(InteractionKind.MentionableMenu, defs, constructor);\n };\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { LoggerChannelId } from '@seedcord/types';\nimport type { Promisable } from 'type-fest';\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 /** The bag for this dispatch. Each interaction gets its own. Every handler for one event shares a single bag. */\n protected readonly dispatch: DispatchContext;\n /** The route that started this dispatch. Each handler base narrows it to its own routes. */\n protected readonly route: string;\n\n protected constructor(\n event: Event,\n public readonly core: TCore,\n dispatch: DispatchContext,\n channel?: LoggerChannelId\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name, { channel });\n this.dispatch = dispatch;\n this.route = dispatch.route;\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(): Promisable<void>;\n}\n","import { BaseHandler } from './BaseHandler';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { BaseReplySender } from '#reply/BaseReplySender';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\n\n/**\n * Shared base the repliable handlers on both transports extend. Defines the reply members over one sender.\n * The dispatch run builds that sender and passes it to the handler and each middleware.\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 TNative - The transport's own file forms, beyond the portable `ReplyFile`\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 TNative,\n TSender extends BaseReplySender<TMessage, TNative>\n> extends BaseHandler<Event, TCore> {\n /** The reply surface for this interaction. Pass the handler to reply from outside its class. */\n public readonly sender: TSender;\n\n protected constructor(event: Event, core: TCore, dispatch: DispatchContext, sender: TSender) {\n super(event, core, dispatch, 'interactions');\n this.sender = sender;\n }\n\n /** Send the initial response, exactly once. */\n protected reply(response: ReplyResponse<TNative> | 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<TNative> | 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<TNative> | string): Promise<TMessage>;\n protected edit(target: TMessage, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected edit(\n targetOrResponse: TMessage | ReplyResponse<TNative> | string,\n maybeResponse?: ReplyResponse<TNative> | 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<TNative> | 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<TNative> | 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 { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { checkAckLegality, sendTarget } from './ackLegality';\nimport { AckTrace } from './AckTrace';\nimport { attemptWrite, publishResponse } from './responseReport';\nimport { serializeReply } from './serializeReply';\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { AckState, ReplyMethod } from './ackLegality';\nimport type { ReplyTelemetry } from './responseReport';\nimport type { SerializedReply } from './serializeReply';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { APIModalInteractionResponseCallbackData } from 'discord-api-types/v10';\n\n/** The shape djs modal builders emit from `toJSON()`. */\nexport interface ModalLike {\n toJSON(): APIModalInteractionResponseCallbackData;\n}\n\n/**\n * Tracks acknowledgement state. Every verb runs the legality check, calls the transport's wire writer,\n * then updates the state and the ack trace. Each transport binds `TMessage` to its own created-message\n * type and supplies the writers.\n *\n * @throws A **SeedcordError** when you call a verb the current ack state doesn't allow. It throws before any transport call.\n */\nexport abstract class BaseReplySender<TMessage extends { id: string }, TNative = never> {\n private state: AckState;\n // the only ids a targeted edit accepts\n private readonly sent = new Set<string>();\n // the cause carries the first ack's stack so a double-ack reports both lines\n private ackedBy?: AckTrace;\n\n protected constructor(\n private readonly telemetry: ReplyTelemetry,\n initialState: AckState = 'unacked'\n ) {\n this.state = initialState;\n }\n\n protected get routeId(): string {\n return this.telemetry.dispatch.routeId;\n }\n\n // anything that threw already reported through attemptWrite\n private report(method: ReplyMethod, startedAt: number, messageId: string | null): void {\n publishResponse(this.telemetry, { method, startedAt, outcome: 'sent', messageId });\n }\n\n private async attempt<Result>(\n method: ReplyMethod,\n startedAt: number,\n write: () => Promise<Result>\n ): Promise<Result> {\n return await attemptWrite(this.telemetry, method, startedAt, write);\n }\n\n public async reply(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('reply');\n const startedAt = performance.now();\n const created = await this.attempt('reply', startedAt, () => this.writeReply(response, opts));\n // the callback already acked discord, so record replied before the message guard can throw\n this.transition('reply', 'replied');\n const message = this.remember(this.requireMessage(created, 'reply'));\n this.report('reply', startedAt, message.id);\n return message;\n }\n\n public async defer(opts?: DeferOpts): Promise<void> {\n this.checkLegality('defer');\n const startedAt = performance.now();\n await this.attempt('defer', startedAt, () => this.writeDefer(opts));\n this.transition('defer', 'deferred-reply');\n this.report('defer', startedAt, null);\n }\n\n public async deferUpdate(): Promise<void> {\n this.checkLegality('deferUpdate');\n const startedAt = performance.now();\n await this.attempt('deferUpdate', startedAt, () => this.writeDeferUpdate());\n this.transition('deferUpdate', 'deferred-update');\n this.report('deferUpdate', startedAt, null);\n }\n\n /**\n * After a deferUpdate the state stays deferred-update. Calling this again rewrites. The returned message\n * is the source message, editable only through a bare `update` or `edit`. A targeted `edit` or `delete`\n * of it throws the foreign-target error.\n */\n public async update(response: ReplyResponse<TNative> | string): Promise<TMessage> {\n this.checkLegality('update');\n const startedAt = performance.now();\n // in deferred-update the source message is @original and the ack-legality check above already passed\n if (this.state === 'deferred-update') {\n const edited = await this.attempt('update', startedAt, () => this.editOriginal(response));\n this.report('update', startedAt, edited.id);\n return edited;\n }\n const created = await this.attempt('update', startedAt, () => this.writeUpdate(response));\n this.transition('update', 'replied');\n const message = this.remember(this.requireMessage(created, 'update'));\n this.report('update', startedAt, message.id);\n return message;\n }\n\n public async followUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('followUp');\n const startedAt = performance.now();\n const created = await this.attempt('followUp', startedAt, () => this.writeFollowUp(response, opts));\n const message = this.remember(created);\n this.report('followUp', startedAt, message.id);\n return message;\n }\n\n public edit(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n public edit(target: TMessage, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n public async edit(\n targetOrResponse: TMessage | ReplyResponse<TNative> | string,\n maybeResponse?: ReplyResponse<TNative> | string\n ): Promise<TMessage> {\n this.checkLegality('edit');\n const startedAt = performance.now();\n if (maybeResponse === undefined) {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n const edited = await this.attempt('edit', startedAt, () =>\n this.editOriginal(targetOrResponse as ReplyResponse<TNative> | string)\n );\n this.report('edit', startedAt, edited.id);\n return edited;\n }\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n const target = targetOrResponse as TMessage;\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['edit', target.id, this.routeId]);\n }\n const written = await this.attempt('edit', startedAt, () => this.writeEditTarget(target.id, maybeResponse));\n const message = this.remember(written);\n this.report('edit', startedAt, message.id);\n return message;\n }\n\n public delete(): Promise<void>;\n public delete(target: TMessage): Promise<void>;\n public async delete(target?: TMessage): Promise<void> {\n this.checkLegality('delete');\n const startedAt = performance.now();\n if (target === undefined) {\n await this.attempt('delete', startedAt, () => this.writeDeleteOriginal());\n this.report('delete', startedAt, null);\n return;\n }\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['delete', target.id, this.routeId]);\n }\n await this.attempt('delete', startedAt, () => this.writeDeleteTarget(target.id));\n // evict so a later targeted edit of this id throws foreign\n this.sent.delete(target.id);\n this.report('delete', startedAt, null);\n }\n\n /** Routes to the verb the current ack state permits. Every state has a route, so the illegal-ack throw is unreachable. */\n public async send(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n const target = sendTarget(this.state);\n if (target === 'reply') return await this.reply(response, opts);\n if (target === 'edit') return await this.edit(response);\n return await this.followUp(response, opts);\n }\n\n /** Must be the initial response. */\n public async showModal(modal: ModalLike): Promise<void> {\n this.checkLegality('showModal');\n this.guardModalSource();\n let data: APIModalInteractionResponseCallbackData;\n try {\n data = modal.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype modal has no constructor at runtime\n const name = modal.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'modal' : name, 0, this.routeId);\n }\n const startedAt = performance.now();\n await this.attempt('showModal', startedAt, () => this.writeModal(data));\n this.transition('showModal', 'replied');\n this.report('showModal', startedAt, null);\n }\n\n protected serialize(response: ReplyResponse<TNative> | string): SerializedReply<TNative> {\n return serializeReply(response, this.routeId);\n }\n\n protected remember(created: TMessage): TMessage {\n this.sent.add(created.id);\n return created;\n }\n\n // a with_response callback always returns the created message. this only trips if the wire says otherwise\n private requireMessage(created: TMessage | undefined, method: 'reply' | 'update'): TMessage {\n if (!created) throw new SeedcordError(SeedcordErrorCode.ReplyCallbackMissingMessage, [method, this.routeId]);\n return created;\n }\n\n private async editOriginal(response: ReplyResponse<TNative> | string): Promise<TMessage> {\n const edited = await this.writeEditOriginal(response);\n // after a deferUpdate the source message is @original, which this interaction did not send\n if (this.state !== 'deferred-update') this.remember(edited);\n return edited;\n }\n\n private checkLegality(method: ReplyMethod): void {\n checkAckLegality(method, this.state, this.routeId, this.ackedBy);\n }\n\n private transition(method: ReplyMethod, state: AckState): void {\n this.state = state;\n this.ackedBy = new AckTrace(method);\n }\n\n // gateway overrides this to reject a modal-submit source\n protected guardModalSource(): void {}\n\n protected abstract writeReply(\n response: ReplyResponse<TNative> | string,\n opts?: SendOpts\n ): Promise<TMessage | undefined>;\n protected abstract writeDefer(opts?: DeferOpts): Promise<void>;\n protected abstract writeDeferUpdate(): Promise<void>;\n protected abstract writeUpdate(response: ReplyResponse<TNative> | string): Promise<TMessage | undefined>;\n protected abstract writeFollowUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage>;\n protected abstract writeEditOriginal(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected abstract writeEditTarget(targetId: string, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected abstract writeDeleteOriginal(): Promise<void>;\n protected abstract writeDeleteTarget(targetId: string): Promise<void>;\n protected abstract writeModal(data: APIModalInteractionResponseCallbackData): Promise<void>;\n}\n","import type { CoreBase } from '#interfaces/CoreBase';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { Promisable } from 'type-fest';\n\n/**\n * The transport-agnostic gate context, the scalar identity of the acting user resolvable from any\n * transport's payload. Every field except `core` is nullable, since an event or DM may carry no\n * guild or member. Each transport extends it with its own context. For example, the gateway adds the djs\n * `user`/`guild`/`member` objects and the live interaction or event payload.\n *\n * @example\n * ```ts\n * // a gate reading only the base fields fits any handler on any transport\n * const NeedsGuild = defineGate('NeedsGuild', (ctx: GateContextBase) => {\n * if (!ctx.guildId) throw new NotInGuild();\n * });\n * ```\n */\nexport interface GateContextBase {\n /** Gates read the config and the rate limiter through it. */\n readonly core: CoreBase;\n /** The acting user's id, or null on an event that carries none. */\n readonly userId: string | null;\n /** The guild id, or null outside a guild. */\n readonly guildId: string | null;\n /** The channel id, or null when the source carries none. */\n readonly channelId: string | null;\n /**\n * The member's role ids without the everyone role, the shape a raw interaction payload\n * contains. Empty outside a guild or when the source contains none.\n */\n readonly memberRoleIds: readonly string[];\n /**\n * The member's permission bits, or null outside a guild. On an interaction these are the\n * channel-scoped permissions the payload contains, and on a gateway event they're the member's guild-level ones.\n */\n readonly memberPermissions: bigint | null;\n /**\n * The bag for this dispatch, the same instance the handler and its middleware hold. Every middleware\n * runs before the first gate. A gate can therefore read what a middleware wrote.\n */\n readonly dispatch: DispatchContext;\n}\n\n/**\n * The context the guild-scoped permission gates require. It adds the base permission sets computed from\n * roles alone, which only the gateway transport can provide from its cache. The http transport's context\n * does not define these fields.\n *\n * @example\n * ```ts\n * // in:'guild' returns a Gate<GuildPermissionsContext>, which fits only a gateway handler\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' }))\n * ```\n */\nexport interface GuildPermissionsContext extends GateContextBase {\n /**\n * The member's base permission set, roles only, matching djs `GuildMember.permissions`. Null when the\n * member is unavailable.\n */\n readonly memberGuildPermissions: bigint | null;\n /**\n * The bot's base permission set from the transport's cache. It's `0n` in a guild the bot isn't in. It's null\n * when the guild is cached but the bot's member isn't.\n */\n readonly appGuildPermissions: bigint | null;\n}\n\n/**\n * The context an interaction provides on both transports, where Discord always sends the bot's channel\n * permissions. A gate that requires it fits no event handler.\n *\n * @example\n * ```ts\n * // the default channel scope returns a Gate<AppPermissionsContext>\n * \\@Gated(RequireBotPermissions([PermissionFlagsBits.ManageMessages]))\n * ```\n */\nexport interface AppPermissionsContext extends GateContextBase {\n /** The bot's permissions in the invoked channel, the wire `app_permissions` value. */\n readonly appPermissions: bigint;\n}\n\n// phantom brand rejects a bare check function or plain object where a Gate is expected\ndeclare const GateBrand: unique symbol;\n\n/**\n * A precondition attached to a handler. It refuses by throwing a `Notice` (a reply) or a `Silence`\n * (a drop with no reply), and passes by returning. `Ctx` is the context it requires, so a gate that reads\n * a field absent on a handler's context is rejected at compile time. `Name` is captured as a literal so\n * a mismatch error can name the gate. Build one with {@link defineGate} or {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context the gate requires. A field missing from it is a compile error.\n * @typeParam Name - The gate's literal name, named in a mismatch error.\n *\n * @example\n * ```ts\n * // a factory returning a typed, agnostic gate\n * function MyGate(): Gate<GateContextBase, 'MyGate'> {\n * return defineGate('MyGate', (ctx) => {\n * if (shouldRefuse(ctx)) throw new MyNotice();\n * });\n * }\n * ```\n *\n * @see {@link defineGate}\n */\nexport interface Gate<Ctx extends GateContextBase = GateContextBase, Name extends string = string> {\n /** The gate's name, surfaced in a mismatch error and joined by the combinators. */\n readonly name: Name;\n /** Reads the context and refuses by throwing a Notice or a Silence, or passes by resolving. */\n check(ctx: Ctx): Promise<void>;\n\n /** @internal */\n readonly [GateBrand]: true;\n}\n\n/**\n * A gate whose `check` method can refuse a request without applying its side effect. `commit` applies\n * the effect after every gate passes. {@link Cooldown} is the catalog gate that returns one. Build one with\n * {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context both `check` and `commit` require. A field missing from it fails to compile.\n * @typeParam Name - The literal name a mismatch error prints.\n *\n * @example\n * ```ts\n * // a factory returning a typed effect gate\n * function MyEffectGate(): EffectGate<GateContextBase, 'MyEffectGate'> {\n * return defineEffectGate(\n * 'MyEffectGate',\n * (ctx) => {\n * if (shouldRefuse(ctx)) throw new MyNotice();\n * },\n * (ctx) => {\n * applyMyEffect(ctx);\n * }\n * );\n * }\n * ```\n *\n * @see {@link defineEffectGate}\n */\nexport interface EffectGate<Ctx extends GateContextBase = GateContextBase, Name extends string = string> extends Gate<\n Ctx,\n Name\n> {\n /** Applies the side effect, run only after the whole gate set passes. */\n commit(ctx: Ctx): Promise<void>;\n}\n\n/**\n * Builds a {@link Gate} from a check. The check refuses by throwing a Notice or a Silence and passes\n * by returning. The required context is inferred from `ctx`, so annotate it as narrowly as the fields\n * the check reads. No annotation defaults to {@link GateContextBase}, an agnostic gate that fits every\n * handler.\n *\n * @typeParam Name - The gate's name, captured as a literal for mismatch errors.\n * @typeParam Ctx - The context the check reads, inferred from the `ctx` annotation.\n *\n * @param name - The gate's name, used in mismatch errors.\n * @param fn - The check, which refuses by throwing a Notice or a Silence and passes by returning.\n *\n * @see {@link defineEffectGate}\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * // a gate factory that takes its own option and closes over it\n * function MinRoles(min: number): Gate<GateContextBase, 'MinRoles'> {\n * return defineGate('MinRoles', (ctx) => {\n * if (ctx.memberRoleIds.length < min) throw new NotEnoughRoles(min);\n * });\n * }\n * ```\n *\n * @example\n * ```ts\n * // agnostic gate (no ctx annotation): fits any handler\n * const Owner = defineGate('owner', (ctx) => {\n * if (!ctx.userId) throw new NotOwner();\n * });\n * ```\n */\nexport function defineGate<const Name extends string, Ctx extends GateContextBase = GateContextBase>(\n name: Name,\n fn: (ctx: Ctx) => Promisable<void>\n): Gate<Ctx, Name> {\n return { name, check: async (ctx) => fn(ctx) } as Gate<Ctx, Name>;\n}\n\n/**\n * Builds an {@link EffectGate} from a `check` and a `commit`. `check` peeks and refuses by throwing, and\n * `commit` applies the side effect, running only once the whole gate set passes so a later refusal never\n * commits. In an `or`, seedcord rolls back the commit a refusing gate queued. This is how {@link Cooldown} peeks\n * in `check` and charges the slot in `commit`.\n *\n * @typeParam Name - The gate's literal name, used to name a mismatch error.\n * @typeParam Ctx - The context both `check` and `commit` read, inferred from the `ctx` annotation.\n *\n * @param name - The gate's name, used in mismatch errors.\n * @param check - Peeks and refuses by throwing, without applying the side effect.\n * @param commit - Applies the side effect, running only after the whole gate set passes.\n *\n * @see {@link defineGate}\n * @see the `@Gated` decorator from your transport package\n * @see {@link Cooldown}\n *\n * @example\n * ```ts\n * // an effect-gate factory that takes its own limit and closes over it\n * function UsesPerDay(max: number): EffectGate<GateContextBase, 'UsesPerDay'> {\n * return defineEffectGate(\n * 'UsesPerDay',\n * (ctx) => {\n * // peek and refuse by throwing. do not mutate yet\n * if (usedToday(ctx.userId) >= max) throw new OutOfUsesNotice(max);\n * },\n * (ctx) => {\n * // runs only after the whole gate set passes\n * recordUse(ctx.userId);\n * }\n * );\n * }\n * ```\n */\nexport function defineEffectGate<const Name extends string, Ctx extends GateContextBase = GateContextBase>(\n name: Name,\n check: (ctx: Ctx) => Promisable<void>,\n commit: (ctx: Ctx) => Promisable<void>\n): EffectGate<Ctx, Name> {\n return {\n name,\n check: async (ctx) => check(ctx),\n commit: async (ctx) => commit(ctx)\n } as EffectGate<Ctx, Name>;\n}\n\n/**\n * The context a {@link Gate} requires.\n *\n * @typeParam TGate - The gate type to read the required context from.\n *\n * @example\n * ```ts\n * type OwnerCtx = RequiredOf<ReturnType<typeof OwnerOnly>>; // GateContextBase\n * ```\n */\nexport type RequiredOf<TGate> = TGate extends Gate<infer Ctx> ? Ctx : never;\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// keep this in step with Grouped in matching.ts\nconst ALREADY_JOINED = / [&|] /;\n\nfunction joinNames(gates: readonly Gate<GateContextBase>[], separator: string): string {\n return gates.map((gate) => (ALREADY_JOINED.test(gate.name) ? `(${gate.name})` : gate.name)).join(separator);\n}\n\n/**\n * Runs each gate in order and refuses on the first refusal. Takes two or more gates. The required\n * context is the intersection of their contexts, so an event-only and an interaction-only gate cannot be\n * combined.\n *\n * @typeParam Gates - The tuple of two or more gates, run left to right.\n * @param gates - The gates 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(joinNames(gates, ' & '), async (ctx) => {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n });\n}\n\ninterface OrOptions {\n fail: Notice | ((ctx: GateContextBase) => Notice);\n}\n\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 gate that passes. Takes two or more gates. The\n * required context is the union of their contexts. A handler that matches any one gate fits. When every\n * gate refuses it throws the trailing {@link OrOptions} `fail` if given, else a list built from each\n * refusal's `summary`, else a default refusal. The trailing options object does not count as a gate.\n *\n * @typeParam Gates - The tuple of two or more gates, tried left to right.\n * @param gates - The gates 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 gate 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(joinNames(gates, ' | '), 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 counts as a gate 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 gate may have queued an effect's commit before it refused\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 // 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 type { Gate, GateContextBase } from '#gates/Gate';\nimport type { GateNoticeOptions } from './options';\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 a Notice class as `notice` to replace the refusal.\n *\n * @param options - Replace the refusal with a Notice class as `notice`.\n *\n * @see the `@Gated` decorator from your transport package\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 * // OwnersOnly is your own Notice class\n * OwnerOnly({ notice: OwnersOnly });\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 new (options?.notice ?? NotOwner)();\n });\n}\n\n/**\n * Passes inside a guild, else refuses.\n *\n * Agnostic. Attaches to any handler kind. Often paired with `RequirePermissions` in an {@link and}.\n *\n * @param options - Replace the refusal with a Notice class as `notice`.\n *\n * @see the `@Gated` decorator from your transport package\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 new (options?.notice ?? NotInGuild)();\n });\n}\n\n/**\n * Passes in a direct message, else refuses.\n *\n * Agnostic, fitting any handler kind. The inverse of {@link GuildOnly}, so combining the two in an {@link and} can never pass.\n *\n * @param options - Replace the refusal with a Notice class as `notice`.\n *\n * @see the `@Gated` decorator from your transport package\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 new (options?.notice ?? NotInDm)();\n });\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, 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 { NoticeConstructor } from '#stops/Notice';\nimport type { EpochMs } from '@seedcord/types';\n\n/**\n * Options for {@link Cooldown}. `per` sets the bucket the window applies to and `limit` the uses allowed per\n * window. `notice` replaces the refusal.\n *\n * @example\n * ```ts\n * // one use per channel, refusing with your own Notice class\n * class SlowDown extends Notice {\n * public constructor(resetAt: EpochMs) {\n * super(`Slow down. Try again <t:${toEpochSeconds(resetAt)}:R>.`);\n * }\n * }\n *\n * Cooldown('10s', { per: 'channel', notice: SlowDown });\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 /** Your Notice class, constructed with the epoch ms the key frees up and thrown in place of the default refusal. */\n notice?: NoticeConstructor<[resetAt: EpochMs]>;\n}\n\n// off-route ctxs have no route to key on. each Cooldown() call 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**, and a string is\n * a duration like `30m` or `24h`. The slot is charged in commit, only after the whole gate set passes,\n * 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, keeping two different handlers on separate\n * windows. Replace the refusal with {@link CooldownOptions.notice}.\n *\n * @param duration - A number is seconds, and a string is a duration like `30m` or `24h`.\n * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal with `notice`.\n * @throws A **SeedcordTypeError** when `duration` is a string that doesn't parse.\n * @throws A **SeedcordRangeError** when `duration` is zero or negative.\n *\n * @see the `@Gated` decorator from your transport package\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\n if (windowMs <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.GateInvalidCooldownDuration, [String(duration)]);\n }\n\n const per = options?.per ?? 'user';\n // exactOptionalPropertyTypes rejects an explicit undefined key\n const window = options?.limit === undefined ? { windowMs } : { windowMs, limit: options.limit };\n const anonId = anonSeq++;\n // routed keys stay stable across restarts, letting a durable store rebuild the same window\n const keyOf = (ctx: GateContextBase): string =>\n `cooldown:${ctx.dispatch.declaredRoute ?? `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 throw new (options?.notice ?? OnCooldown)(result.resetAt);\n },\n async (ctx) => {\n await ctx.core.rateLimiter.charge(keyOf(ctx), window);\n }\n );\n}\n","import { prettify } from '@seedcord/utils';\nimport { PermissionFlagsBits } from 'discord-api-types/v10';\n\n/**\n * The permission flag bits a caller or the bot must hold. Pass the `PermissionFlagsBits` values from\n * `discord-api-types/v10` (or `discord.js`).\n */\nexport type PermissionScope = readonly bigint[];\n\nconst PermissionNames = new Map<bigint, string>(\n Object.entries(PermissionFlagsBits).map(([key, bit]) => [bit, prettify(key)])\n);\n\nconst ADMINISTRATOR = PermissionFlagsBits.Administrator;\n\nfunction nameOf(bit: bigint): string {\n return PermissionNames.get(bit) ?? String(bit);\n}\n\n// discord treats the administrator bit as granting every permission\nfunction holds(held: bigint, bit: bigint): boolean {\n return (held & ADMINISTRATOR) === ADMINISTRATOR || (held & bit) === bit;\n}\n\nfunction namesWhere(held: bigint, scope: PermissionScope, isHeld: boolean): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if (holds(held, bit) === isHeld) names.push(nameOf(bit));\n return names;\n }, []);\n}\n\n/** @internal */\nexport function missingNames(held: bigint, scope: PermissionScope): string[] {\n return namesWhere(held, scope, false);\n}\n\n/** @internal */\nexport function presentNames(held: bigint, scope: PermissionScope): string[] {\n return namesWhere(held, scope, true);\n}\n","import { HasPresentPermissions, MissingPermissions } from '#notices/index';\n\nimport { missingNames, presentNames } from './bits';\n\nimport type { NoticeConstructor } from '#stops/Notice';\nimport type { PermissionScope } from './bits';\n\n/**\n * A Notice class for a permission refusal. seedcord constructs it with the subject and the permission names\n * the refusal lists. A null subject is the caller.\n */\nexport type PermissionNoticeConstructor = NoticeConstructor<[subject: string | null, permissions: readonly string[]]>;\n\n/** The check {@link assertPermissions} runs. */\nexport interface PermissionAssertion {\n /** Mention string for who is checked, used as the refusal's subject. Null addresses the caller. */\n subject: string | null;\n /** The effective permission bitfield the subject holds, computed by the caller. */\n permissions: bigint;\n /** The permission flag bits to check. */\n scope: PermissionScope;\n /** Refuse when the subject holds a scope bit. */\n inverse?: boolean;\n /** Your Notice class, thrown in place of the default refusal. seedcord constructs it with the missing names, or the held ones under `inverse`. */\n notice?: PermissionNoticeConstructor | undefined;\n}\n\n/**\n * Refuses when the subject is missing a permission in `scope`, or with `inverse` when it holds one.\n * The Administrator bit passes any scope, and with `inverse` it reports every bit in `scope`.\n *\n * The caller computes `permissions`, gateway off a discord.js role, member, or channel, and HTTP off the\n * bitfield the interaction payload carries.\n *\n * @throws A {@link Notice} when the check refuses. It lists the missing or present permissions.\n *\n * @example\n * ```ts\n * import { assertPermissions } from '@seedcord/core';\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * // gateway, the bits come off a discord.js member\n * assertPermissions({\n * subject: `<@${member.id}>`,\n * permissions: member.permissions.bitfield,\n * scope: [PermissionFlagsBits.BanMembers]\n * });\n * ```\n *\n * @example\n * ```ts\n * // HTTP, the payload carries the member's bits as a string\n * assertPermissions({\n * subject: `<@${this.event.member.user.id}>`,\n * permissions: BigInt(this.event.member.permissions),\n * scope: [PermissionFlagsBits.ManageMessages]\n * });\n * ```\n *\n * @example\n * ```ts\n * // inverse, refuse a role that carries Administrator\n * assertPermissions({\n * subject: `<@&${role.id}>`,\n * permissions: role.permissions.bitfield,\n * scope: [PermissionFlagsBits.Administrator],\n * inverse: true\n * });\n * ```\n *\n * @example\n * ```ts\n * import { Notice } from '@seedcord/core';\n *\n * class CannotBan extends Notice {\n * public constructor(\n * private readonly subject: string | null,\n * private readonly missing: readonly string[]\n * ) {\n * super('You cannot ban here.');\n * }\n *\n * public render(): ReplyResponse {\n * return { components: [new BanDenied(this.subject, this.missing).component] };\n * }\n * }\n *\n * assertPermissions({\n * subject: `<@${member.id}>`,\n * permissions: member.permissions.bitfield,\n * scope: [PermissionFlagsBits.BanMembers],\n * notice: CannotBan\n * });\n * ```\n */\nexport function assertPermissions({ subject, permissions, scope, inverse = false, notice }: PermissionAssertion): void {\n const [refused, Default] = inverse\n ? [presentNames(permissions, scope), HasPresentPermissions]\n : [missingNames(permissions, scope), MissingPermissions];\n if (refused.length === 0) return;\n throw new (notice ?? Default)(subject, refused);\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { defineGate } from '#gates/Gate';\nimport { MissingRole, NotInGuild, PermissionsUnresolved } from '#notices/index';\nimport { assertPermissions } from '#src/permissions/assert';\n\nimport type { AppPermissionsContext, Gate, GateContextBase, GuildPermissionsContext } from '#gates/Gate';\nimport type { PermissionNoticeConstructor } from '#src/permissions/assert';\nimport type { PermissionScope } from '#src/permissions/bits';\nimport type { NoticeConstructor } from '#stops/Notice';\n\nexport type { PermissionScope } from '#src/permissions/bits';\n\nconst BOT_SUBJECT = 'The bot';\n\n/**\n * Options for {@link RequireBotPermissions}.\n */\nexport interface RequireBotPermissionsOptions {\n /**\n * The set the check reads. `'channel'` reads the effective channel set the payload carries, what\n * Discord enforces in the invoked channel. `'guild'` reads the base set from roles, available on the\n * gateway transport only.\n *\n * @defaultValue `'channel'`\n */\n in?: 'channel' | 'guild';\n /** Your Notice class, constructed and thrown in place of the refusal outside a guild. */\n notInGuild?: NoticeConstructor;\n /** Your Notice class, constructed and thrown in place of the refusal when a permission is missing. */\n missing?: PermissionNoticeConstructor;\n}\n\n/**\n * Options for {@link RequirePermissions}.\n */\nexport interface RequirePermissionsOptions extends RequireBotPermissionsOptions {\n /** Your Notice class, constructed and thrown in place of the refusal when the member's permissions are unavailable inside a guild. */\n unresolved?: NoticeConstructor;\n}\n\n/**\n * Options for {@link RequireRole}.\n */\nexport interface RequireRoleOptions {\n /** Your Notice class, constructed and thrown in place of the refusal outside a guild. */\n notInGuild?: NoticeConstructor;\n /** Your Notice class, constructed with the role id and thrown in place of the refusal when the caller lacks the role. */\n missingRole?: NoticeConstructor<[roleId: string]>;\n}\n\ninterface HeldCheck {\n guildId: string | null;\n subject: string | null;\n readOrThrow: (guildId: string) => bigint;\n}\n\nfunction requireHeld(\n { guildId, subject, readOrThrow }: HeldCheck,\n scope: PermissionScope,\n options: RequireBotPermissionsOptions | undefined\n): void {\n if (!guildId) throw new (options?.notInGuild ?? NotInGuild)();\n const permissions = readOrThrow(guildId);\n assertPermissions({ subject, permissions, scope, notice: options?.missing });\n}\n\nfunction botMemberMissing(guildId: string): never {\n throw new SeedcordError(SeedcordErrorCode.CoreBotMemberMissing, [guildId]);\n}\n\n/**\n * Requires the caller to hold every permission in `scope`. Refuses outside a guild first, then when the\n * member's permissions are unavailable, then when a permission is missing. The Administrator bit passes any\n * scope.\n *\n * The default `'channel'` scope reads the effective channel set the payload carries, what Discord enforces\n * in the invoked channel. The `'guild'` scope reads the base set from roles and requires a\n * {@link GuildPermissionsContext}, so it fits a gateway handler only.\n *\n * @param scope - The permission flag bits the caller must all hold.\n * @param options - Pick the scope with `in`. Replace a refusal with a Notice class as `notInGuild`, `unresolved`, or `missing`.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers]))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // the base set from roles, on a gateway handler\n * RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' });\n * ```\n */\nexport function RequirePermissions(\n scope: PermissionScope,\n options: RequirePermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequirePermissions'>;\nexport function RequirePermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions & { in?: 'channel' }\n): Gate<GateContextBase, 'RequirePermissions'>;\nexport function RequirePermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions\n): Gate<GuildPermissionsContext, 'RequirePermissions'> | Gate<GateContextBase, 'RequirePermissions'> {\n const resolved = (held: bigint | null): bigint => {\n if (held === null) throw new (options?.unresolved ?? PermissionsUnresolved)();\n return held;\n };\n if (options?.in === 'guild') {\n return defineGate('RequirePermissions', (ctx: GuildPermissionsContext) => {\n const readOrThrow = (): bigint => resolved(ctx.memberGuildPermissions);\n requireHeld({ guildId: ctx.guildId, subject: null, readOrThrow }, scope, options);\n });\n }\n return defineGate('RequirePermissions', (ctx: GateContextBase) => {\n const readOrThrow = (): bigint => resolved(ctx.memberPermissions);\n requireHeld({ guildId: ctx.guildId, subject: null, readOrThrow }, scope, options);\n });\n}\n\n/**\n * Requires the bot to hold every permission in `scope`. Refuses outside a guild first, then when a\n * permission is missing. The Administrator bit passes any scope.\n *\n * The default `'channel'` scope reads the bot's effective channel set (wire `app_permissions`), what\n * Discord enforces in the invoked channel. The `'guild'` scope reads the bot's base set from roles and\n * requires a {@link GuildPermissionsContext}, fitting a gateway handler only. The channel scope requires an\n * {@link AppPermissionsContext}. An event handler takes `in: 'guild'`.\n *\n * @param scope - The permission flag bits the bot must all hold.\n * @param options - Pick the scope with `in`. Replace a refusal with a Notice class as `notInGuild` or `missing`.\n * @throws A **SeedcordError** when the `'guild'` scope runs and the bot's own member isn't cached.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * \\@Gated(RequireBotPermissions([PermissionFlagsBits.ManageMessages]))\n * \\@SlashRoute('purge')\n * class PurgeHandler extends SlashHandler<'purge'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options: RequireBotPermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequireBotPermissionsOptions & { in?: 'channel' }\n): Gate<AppPermissionsContext, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequireBotPermissionsOptions\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'> | Gate<AppPermissionsContext, 'RequireBotPermissions'> {\n if (options?.in === 'guild') {\n return defineGate('RequireBotPermissions', (ctx: GuildPermissionsContext) => {\n const readOrThrow = (guildId: string): bigint => ctx.appGuildPermissions ?? botMemberMissing(guildId);\n requireHeld({ guildId: ctx.guildId, subject: BOT_SUBJECT, readOrThrow }, scope, options);\n });\n }\n return defineGate('RequireBotPermissions', (ctx: AppPermissionsContext) => {\n requireHeld(\n { guildId: ctx.guildId, subject: BOT_SUBJECT, readOrThrow: () => ctx.appPermissions },\n scope,\n options\n );\n });\n}\n\n/**\n * Requires the caller to hold `roleId`, read from the member's role ids. Refuses outside a guild first,\n * then when the role is missing. Roles are guild-global, so there is no scope dimension.\n *\n * @param roleId - The role snowflake the caller must hold.\n * @param options - Replace a refusal with a Notice class as `notInGuild` or `missingRole`.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * \\@Gated(RequireRole('123456789012345678'))\n * \\@SlashRoute('vip')\n * class VipHandler extends SlashHandler<'vip'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireRole(roleId: string, options?: RequireRoleOptions): Gate<GateContextBase, 'RequireRole'> {\n return defineGate('RequireRole', (ctx) => {\n if (!ctx.guildId) throw new (options?.notInGuild ?? NotInGuild)();\n if (ctx.memberRoleIds.includes(roleId)) return;\n throw new (options?.missingRole ?? MissingRole)(roleId);\n });\n}\n","/**\n * The role ids a member holds after adding and removing the given sets. Removals win over additions.\n *\n * This does not write the roles. Apply the result with `member.roles.set()` on gateway, or PATCH the member over HTTP.\n *\n * @param current - The role ids the member holds.\n * @param add - The role ids to add.\n * @param remove - The role ids to remove.\n * @returns The merged role ids.\n *\n * @example\n * ```ts\n * import { mergeRoles } from '@seedcord/core';\n *\n * // gateway\n * const ids = mergeRoles(member.roles.cache.map((role) => role.id), ['123'], ['456']);\n * await member.roles.set(ids);\n * ```\n */\nexport function mergeRoles(current: readonly string[], add: readonly string[], remove: readonly string[]): string[] {\n return [...new Set(current).union(new Set(add)).difference(new Set(remove))];\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 A **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 // NaN comes back out of Math.trunc, Math.max, and Math.min unchanged.\n const requested = Number.isNaN(page) ? 0 : Math.trunc(page);\n const clamped = Math.min(Math.max(requested, 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 { ActionRowBuilder, ButtonBuilder } from '@discordjs/builders';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { ButtonStyle } from 'discord-api-types/v10';\n\nimport { PAGE_MAX } from '#pagination/cursor';\n\nimport type { PageCursor } from '#pagination/cursor';\nimport type { PageView } from '#pagination/PageView';\nimport type { APIMessageComponentEmoji } from 'discord-api-types/v10';\n\n/** The five built-in nav controls. */\nexport type ControlKey = 'first' | 'prev' | 'indicator' | 'next' | 'last';\n\n// Link and Premium have no custom_id, which un-routes a control.\ntype CustomIdStyle = ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success | ButtonStyle.Danger;\n\n/** Cosmetic overrides for a control button. `style` excludes Link and Premium, which would un-route it. */\nexport interface ControlCosmetics {\n label?: string;\n style?: CustomIdStyle;\n emoji?: APIMessageComponentEmoji;\n}\n\n/** The controls passed to `render`. */\nexport interface PaginatorControls {\n /**\n * A fresh `ButtonBuilder` for one control, already stamped with its target page and disabled-at-bounds\n * state. Call only cosmetic setters on it, because a `setCustomId` or `setStyle(Link)` un-routes it.\n */\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder;\n /**\n * Assemble an action row of the chosen controls, in order.\n *\n * @throws A **SeedcordRangeError** when `keys` is empty or holds more than five controls.\n * @throws A **SeedcordTypeError** when `keys` holds the same control twice.\n */\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder>;\n}\n\nconst DEFAULT_LABEL: Record<ControlKey, string> = {\n first: 'First',\n prev: 'Prev',\n indicator: '',\n next: 'Next',\n last: 'Last'\n};\n\n// a distinct slot keeps two controls on the same page off the same id. 0-4 is the cursor's SLOT_MAX.\nconst CONTROL_SLOT: Record<ControlKey, number> = {\n first: 0,\n prev: 1,\n indicator: 2,\n next: 3,\n last: 4\n};\n\nconst MAX_BUTTONS_PER_ROW = 5;\n\nexport class Controls implements PaginatorControls {\n constructor(\n private readonly cursor: PageCursor<string>,\n private readonly view: PageView<unknown>\n ) {}\n\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder {\n const { target, disabled } = this.navState(key);\n\n // an emoji with no explicit label makes an icon-only button. the indicator always shows its page text.\n const defaultLabel = key === 'indicator' ? this.indicatorText() : DEFAULT_LABEL[key];\n const label = cosmetics?.label ?? (key === 'indicator' || !cosmetics?.emoji ? defaultLabel : undefined);\n\n const button = new ButtonBuilder()\n // an enormous list could push last/next past PAGE_MAX, where encode throws.\n .setCustomId(this.cursor.encode({ page: Math.min(Math.max(0, target), PAGE_MAX), slot: CONTROL_SLOT[key] }))\n .setStyle(cosmetics?.style ?? ButtonStyle.Secondary)\n .setDisabled(disabled);\n if (label !== undefined) button.setLabel(label);\n if (cosmetics?.emoji) button.setEmoji(cosmetics.emoji);\n return button;\n }\n\n private navState(key: ControlKey): { target: number; disabled: boolean } {\n const { page, totalPages, hasPrev, hasNext } = this.view;\n const knownTotal = totalPages !== undefined;\n const target = {\n first: 0,\n prev: page - 1,\n indicator: page,\n next: page + 1,\n last: knownTotal ? totalPages - 1 : page\n }[key];\n // past PAGE_MAX the encoded page would clamp to a wrong one\n const disabled = {\n first: !hasPrev,\n prev: !hasPrev,\n indicator: true,\n next: !hasNext || page + 1 > PAGE_MAX,\n last: !hasNext || !knownTotal || totalPages - 1 > PAGE_MAX\n }[key];\n return { target, disabled };\n }\n\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder> {\n if (keys.length === 0 || keys.length > MAX_BUTTONS_PER_ROW) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationControlCount, [keys.length, MAX_BUTTONS_PER_ROW]);\n }\n // repeating a control reuses its slot and page, so the custom_ids collide and Discord rejects the message.\n const seen = new Set<ControlKey>();\n for (const key of keys) {\n if (seen.has(key)) throw new SeedcordTypeError(SeedcordErrorCode.PaginationDuplicateControls, [key]);\n seen.add(key);\n }\n return new ActionRowBuilder<ButtonBuilder>().addComponents(keys.map((key) => this.button(key)));\n }\n\n private indicatorText(): string {\n const { page, totalPages } = this.view;\n return totalPages === undefined ? `Page ${page + 1}` : `Page ${page + 1} of ${totalPages}`;\n }\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '#components/Component';\nimport { Controls } from '#pagination/Controls';\n\nimport type { ControlKey, PaginatorControls } from '#pagination/Controls';\nimport type { PageCursor } from '#pagination/cursor';\nimport type { PageView } from '#pagination/PageView';\nimport type { ButtonBuilder, ActionRowBuilder } from '@discordjs/builders';\nimport type { ReplyResponse } from '@seedcord/types';\n\n/** What `renderItem` returns for one item, a text line or a section. */\nexport type ItemRender<Item> = (item: Item, index: number) => string | BuilderComponent<'section'>;\n\ntype Renderable = string | ReplyResponse['components'] | ReplyResponse;\n\n/** A full-page render override. */\nexport type PageRender<Item> = (view: PageView<Item>, controls: PaginatorControls) => Renderable;\n\n// subclassed because BuilderComponent.instance is protected\nclass PageContainer<Item> extends BuilderComponent<'container'> {\n constructor(view: PageView<Item>, renderItem: ItemRender<Item>, controlRow: ActionRowBuilder<ButtonBuilder>) {\n super('container');\n const base = view.page * view.perPage;\n let lines: string[] = [];\n const flush = (): void => {\n if (lines.length === 0) return;\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(lines.join('\\n')));\n lines = [];\n };\n view.items.forEach((item, offset) => {\n const rendered = renderItem(item, base + offset);\n if (typeof rendered === 'string') {\n lines.push(rendered);\n return;\n }\n flush();\n this.instance.addSectionComponents(rendered.component);\n });\n flush();\n this.instance.addActionRowComponents(controlRow);\n }\n}\n\nfunction toReplyResponse(renderable: Renderable): ReplyResponse {\n if (typeof renderable === 'string') return { components: [new TextDisplayBuilder().setContent(renderable)] };\n if (Array.isArray(renderable)) return { components: renderable };\n return renderable;\n}\n\nconst ARRAY_KEYS: ControlKey[] = ['first', 'prev', 'indicator', 'next', 'last'];\nconst CURSOR_KEYS: ControlKey[] = ['prev', 'indicator', 'next'];\n\n// a render override builds the whole tree, or the default container lists the items and appends\n// the controls (all five for a known total, prev/indicator/next for a cursor source)\nexport function renderPage<Item>(\n view: PageView<Item>,\n cursor: PageCursor<string>,\n config: { renderItem?: ItemRender<Item>; render?: PageRender<Item> }\n): ReplyResponse {\n const controls = new Controls(cursor, view);\n if (config.render) return toReplyResponse(config.render(view, controls));\n\n const renderItem = config.renderItem ?? String;\n const row = controls.row(...(view.totalPages === undefined ? CURSOR_KEYS : ARRAY_KEYS));\n return { components: [new PageContainer(view, renderItem, row).component] };\n}\n","import { pageCursor } from '#pagination/cursor';\nimport { renderPage } from '#pagination/render';\n\nimport type { PageCursor } from '#pagination/cursor';\nimport type { ItemRender, PageRender } from '#pagination/render';\nimport type { PageSourceBase } from '#pagination/sources';\nimport type { ReplyResponse } from '@seedcord/types';\n\n/**\n * The transport-agnostic paginator configuration. Each transport adds its own handler wiring on top.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `prefix`.\n * @typeParam Ctx - The transport's page context.\n */\nexport interface PaginatorConfig<Item, Prefix extends string, Ctx> {\n /** The route prefix used to build the page cursor on the nav buttons. */\n prefix: Prefix;\n source: PageSourceBase<Item, Ctx>;\n /** Render one item, `index` is its absolute position across pages. Ignored when `render` is set. */\n renderItem?: ItemRender<Item>;\n /** Take over the whole page tree. Receives the page data and the controls factory. */\n render?: PageRender<Item>;\n /**\n * Whether the first page is ephemeral.\n *\n * @defaultValue `false`\n */\n ephemeral?: boolean;\n}\n\n/**\n * Holds a paginator's cursor and renders one page. Each transport extends this to add the nav handler and\n * the method that sends the first page.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `config.prefix`.\n * @typeParam Ctx - The transport's page context.\n */\nexport abstract class PaginatorBase<Item, Prefix extends string, Ctx> {\n /** The page cursor, pass it to your `@ButtonRoute`. */\n public readonly cursor: PageCursor<Prefix>;\n\n protected readonly config: PaginatorConfig<Item, Prefix, Ctx>;\n\n protected constructor(config: PaginatorConfig<Item, Prefix, Ctx>) {\n this.cursor = pageCursor(config.prefix);\n this.config = config;\n }\n\n /** Build one page as a {@link ReplyResponse}. Each transport wraps this in a `page()` taking its handler. */\n protected async buildPage(ctx: Ctx, n: number): Promise<ReplyResponse> {\n const view = await this.config.source.page(ctx, n);\n return renderPage(view, this.cursor, this.config);\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { paginate } from '#pagination/paginate';\n\nimport type { PageView } from '#pagination/PageView';\nimport type { Promisable } from 'type-fest';\n\nconst DEFAULT_PER_PAGE = 10;\n\n/**\n * The one method a paginator calls on a source, once per click. Implement it to supply a custom source.\n *\n * @typeParam Item - The item type the source pages over.\n * @typeParam Ctx - The transport's page context, handed to the loader.\n */\nexport interface PageSourceBase<Item, Ctx> {\n page(ctx: Ctx, n: number): Promise<PageView<Item>>;\n}\n\nfunction perPageOf(opts?: { perPage?: number }): number {\n const perPage = opts?.perPage ?? DEFAULT_PER_PAGE;\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n return perPage;\n}\n\n/**\n * A source for a bounded list you can load whole. It loads the full list on every click, then slices the\n * page via {@link paginate}, so the real total is known (a real last button, \"Page X of Y\"). Cache inside\n * your loader if the load is expensive.\n *\n * @typeParam Item - The item type, inferred from the loader's return.\n * @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.\n */\nexport class ArraySourceBase<Item, Ctx> implements PageSourceBase<Item, Ctx> {\n private readonly perPage: number;\n\n constructor(\n private readonly load: (ctx: Ctx) => Promisable<readonly Item[]>,\n opts?: { perPage?: number }\n ) {\n this.perPage = perPageOf(opts);\n }\n\n async page(ctx: Ctx, n: number): Promise<PageView<Item>> {\n return paginate(await this.load(ctx), n, this.perPage);\n }\n}\n\n/**\n * A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).\n * The fetcher receives the page index and the page size and reports whether a next page exists. A cursor\n * source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator\n * reads \"Page X\".\n *\n * @typeParam Item - The item type, inferred from the fetcher's slice.\n * @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.\n */\nexport class CursorSourceBase<Item, Ctx> implements PageSourceBase<Item, Ctx> {\n private readonly perPage: number;\n\n constructor(\n private readonly fetch: (\n ctx: Ctx,\n page: number,\n perPage: number\n ) => Promisable<{ items: readonly Item[]; hasNext: boolean }>,\n opts?: { perPage?: number }\n ) {\n this.perPage = perPageOf(opts);\n }\n\n async page(ctx: Ctx, n: number): Promise<PageView<Item>> {\n // a cursor source has no total to clamp against. Infinity and NaN both fall back to 0.\n const page = Number.isFinite(n) ? Math.max(0, Math.trunc(n)) : 0;\n const { items, hasNext } = await this.fetch(ctx, page, this.perPage);\n return { items: [...items], page, perPage: this.perPage, hasPrev: page > 0, hasNext };\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { KvDriver, KvEntry } from '@seedcord/types';\n\n// the slice of Keyv 6 this driver calls\ninterface KeyvLike {\n readonly store: {\n readonly capabilities?: {\n readonly store: string;\n readonly methods: { readonly iterator: { readonly exists: boolean } };\n };\n };\n get(key: string): Promise<unknown>;\n set(key: string, value: string, ttl?: number): Promise<boolean>;\n delete(key: string): Promise<boolean>;\n iterator(): AsyncGenerator<[string, unknown], void>;\n disconnect(): Promise<void>;\n}\n\n/**\n * Wraps a Keyv instance for `config.kv`.\n *\n * @example\n * ```ts\n * new Seedcord({ ...config, kv: new KeyvDriver(new Keyv(new KeyvSqlite('sqlite://./kv.sqlite'))) });\n * ```\n */\nexport class KeyvDriver<TKeyv extends KeyvLike> implements KvDriver, AsyncDisposable {\n constructor(\n /** The Keyv instance you passed, with its full type. */\n public readonly keyv: TKeyv\n ) {}\n\n public async get(key: string): Promise<string | undefined> {\n const value = await this.keyv.get(key);\n return typeof value === 'string' ? value : undefined;\n }\n\n public async set(key: string, value: string, ttlMs?: number): Promise<void> {\n if (!(await this.keyv.set(key, value, ttlMs)))\n throw new SeedcordError(SeedcordErrorCode.CoreKvDriverFailed, ['write', key]);\n }\n\n public async delete(key: string): Promise<void> {\n await this.keyv.delete(key);\n }\n\n /** @throws A **SeedcordError** when the Keyv store can't list its keys, like `@keyv/memcache`. */\n public async *entries(prefix: string): AsyncIterable<KvEntry> {\n if (!this.#canListKeys()) throw new SeedcordError(SeedcordErrorCode.CoreKvKeysUnsupported);\n\n for await (const [key, value] of this.keyv.iterator()) {\n if (key.startsWith(prefix) && typeof value === 'string') yield [key, value];\n }\n }\n\n public async [Symbol.asyncDispose](): Promise<void> {\n await this.keyv.disconnect();\n }\n\n // Keyv iterates a Map-like store itself. any other store without an iterator() doesn't yield anything\n #canListKeys(): boolean {\n const capabilities = this.keyv.store.capabilities;\n return capabilities?.store === 'mapLike' || capabilities?.methods.iterator.exists === true;\n }\n}\n","import type { KvDriver, KvEntry } from '@seedcord/types';\n\n// cloudflare KV rejects an expirationTtl under 60s. KvCollection checks the real expiry on read\nconst MIN_TTL_SECONDS = 60;\nconst MS_PER_SECOND = 1000;\n\n// the fs driver reads a Buffer back\ntype Bytes = NonNullable<Parameters<TextDecoder['decode']>[0]>;\n\n// the slice of unstorage 1.x and 2.x this driver calls\ninterface StorageLike {\n getItemRaw(key: string): Promise<string | Bytes | null>;\n setItemRaw(key: string, value: string, opts?: { ttl?: number }): Promise<void>;\n removeItem(key: string): Promise<void>;\n getKeys(): Promise<string[]>;\n dispose(): Promise<void>;\n}\n\n// unstorage rewrites `/`, `?` and empty segments. it hides a key ending in `$`.\n// its fs driver throws on `..` and can't store `a` beside `a:b`. escaping the whole key into one segment avoids each of these\nfunction storageKey(key: string): string {\n return `_${encodeURIComponent(key).replaceAll('.', '%2E')}`;\n}\n\nfunction originalKey(stored: string): string {\n return decodeURIComponent(stored.slice(1));\n}\n\nfunction text(raw: string | Bytes | null): string | undefined {\n if (raw === null) return undefined;\n return typeof raw === 'string' ? raw : new TextDecoder().decode(raw);\n}\n\n/**\n * Wraps an unstorage `Storage` for `config.kv`.\n *\n * @example\n * ```ts\n * new Seedcord({ ...config, kv: new UnstorageDriver(createStorage({ driver: fsDriver({ base: './.kv' }) })) });\n * ```\n */\nexport class UnstorageDriver<TStorage extends StorageLike> implements KvDriver, AsyncDisposable {\n constructor(\n /** The storage you passed, with its full type. */\n public readonly storage: TStorage\n ) {}\n\n public async get(key: string): Promise<string | undefined> {\n return text(await this.storage.getItemRaw(storageKey(key)));\n }\n\n public async set(key: string, value: string, ttlMs?: number): Promise<void> {\n // unstorage takes seconds\n const ttl = ttlMs === undefined ? {} : { ttl: Math.max(MIN_TTL_SECONDS, Math.ceil(ttlMs / MS_PER_SECOND)) };\n await this.storage.setItemRaw(storageKey(key), value, ttl);\n }\n\n public async delete(key: string): Promise<void> {\n await this.storage.removeItem(storageKey(key));\n }\n\n public async *entries(prefix: string): AsyncIterable<KvEntry> {\n // storageKey escapes one character at a time.\n // a stored key starts with the stored prefix exactly when the original does\n const storedPrefix = storageKey(prefix);\n for (const key of await this.storage.getKeys()) {\n if (!key.startsWith(storedPrefix)) continue;\n const value = text(await this.storage.getItemRaw(key));\n if (value !== undefined) yield [originalKey(key), value];\n }\n }\n\n public async [Symbol.asyncDispose](): Promise<void> {\n await this.storage.dispose();\n }\n}\n","/**\n * Builds a rate-limit key from a prefix and scope parts, joined with `:`. A null or undefined part\n * becomes `'global'`. A key built from a DM's guild id reads `<prefix>:global` for every DM caller.\n *\n * @param prefix - The bucket family, e.g. `'cooldown'`.\n * @param parts - Scope values, e.g. a user or guild id.\n *\n * @example\n * ```ts\n * buildKey('report', interaction.guildId); // 'report:1234...' or 'report:global' in a DM\n * ```\n */\nexport function buildKey(prefix: string, ...parts: readonly (string | null | undefined)[]): string {\n if (parts.length === 0) return prefix;\n return [prefix, ...parts.map((part) => part ?? 'global')].join(':');\n}\n","import 'reflect-metadata';\n\n// Errors.ts registers the two notices thrown by a failed decode\nimport '#customId/Errors';\n\nexport type { REST } from '@discordjs/rest';\n\nexport type { MessageContextMenuRegistry, UserContextMenuRegistry } from '#registries/ContextMenuRegistry';\nexport type { SlashRegistry } from '#registries/SlashRegistry';\n\nexport { Commands, ContextMenus } from '#src/commands/CommandInjector';\nexport type {\n CommandInfo,\n ContextMenuInfo,\n InjectedCommandMap,\n InjectedContextMenuMap\n} from '#src/commands/CommandInjector';\n\nexport { RegisterCommand } from '#decorators/Command';\nexport type { GuildTarget } from '#decorators/Command';\nexport {\n AutocompleteRoute,\n ButtonRoute,\n ChannelMenuRoute,\n MentionableMenuRoute,\n MessageContextMenuRoute,\n UserContextMenuRoute,\n ModalRoute,\n RoleMenuRoute,\n SlashRoute,\n StringMenuRoute,\n UserMenuRoute\n} from '#decorators/routes';\n\nexport { InteractionKind } from '#src/metadataKeys';\nexport type { MiddlewareKind } from '#src/metadataKeys';\n\nexport { RegisterInteractionMiddleware } from '#decorators/middleware';\nexport type { InteractionMiddlewareOptions } from '#decorators/middleware';\n\nexport type { DispatchContext } from '#src/dispatch/DispatchContext';\nexport type { DispatchResult, EventDispatchResult, HandlerOutcome, HandlerResult } from '#src/dispatch/dispatchResult';\n\nexport { BaseHandler } from '#src/handlers/BaseHandler';\nexport { RepliableHandler } from '#src/handlers/RepliableHandler';\n\nexport { BaseReplySender } from '#reply/BaseReplySender';\nexport type { ModalLike } from '#reply/BaseReplySender';\n\nexport type { CoreBase } from '#interfaces/CoreBase';\n\nexport { ShutdownPhase, StartupPhase } from '#src/lifecycle/phases';\n\nexport { defineEffectGate, defineGate } from '#gates/Gate';\nexport type {\n AppPermissionsContext,\n EffectGate,\n Gate,\n GateContextBase,\n GuildPermissionsContext,\n RequiredOf\n} 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 {\n PermissionScope,\n RequireBotPermissionsOptions,\n RequirePermissionsOptions,\n RequireRoleOptions\n} from '#gates/catalog/permissions';\nexport type { GateNoticeOptions } from '#gates/catalog/options';\n\nexport { assertPermissions } from '#src/permissions/assert';\nexport type { PermissionAssertion, PermissionNoticeConstructor } from '#src/permissions/assert';\nexport { mergeRoles } from '#src/permissions/mergeRoles';\n\nexport { BuilderComponent, RowComponent } from '#components/Component';\nexport { type RowType, type BuilderType } from '#components/builderTypes';\n\nexport { Notice, type NoticeConstructor } from '#stops/Notice';\nexport { Fault } from '#stops/Fault';\nexport { Silence } from '#stops/Silence';\n\nexport { CustomId, decodeFor, prefixOf, setCustomIdErrors } from '@seedcord/custom-id';\nexport type {\n AnyCustomId,\n CustomIdField,\n CustomIdShape,\n DecodedParams,\n DecodedRoute,\n FieldOptions\n} from '@seedcord/custom-id';\n\nexport { ResolvedEmoji } from '#src/miscellaneous/ResolvedEmoji';\n\nexport type { AutocompleteOptions } from '#inputs/AutocompleteOptions';\n\nexport { paginate } from '#pagination/paginate';\nexport { type PageView } from '#pagination/PageView';\nexport { PaginatorBase } from '#pagination/PaginatorBase';\nexport type { PaginatorConfig } from '#pagination/PaginatorBase';\nexport { ArraySourceBase, CursorSourceBase } from '#pagination/sources';\nexport type { PageSourceBase } from '#pagination/sources';\nexport type { ControlCosmetics, ControlKey, PaginatorControls } from '#pagination/Controls';\nexport type { ItemRender, PageRender } from '#pagination/render';\n\nexport { KeyvDriver } from '#src/kv/KeyvDriver';\nexport type { Kv } from '#src/kv/Kv';\nexport type { KvCollection } from '#src/kv/KvCollection';\nexport { MemoryDriver } from '#src/kv/MemoryDriver';\nexport { UnstorageDriver } from '#src/kv/UnstorageDriver';\nexport { buildKey } from '#src/rateLimiter/buildKey';\n\nexport type { Generated, PluginTypes } from '#src/plugin/Generated';\n\nexport { Bus, Subscribe, Subscriber, WebhookLog, WebhookUrl } from '#subscribers/index';\nexport type {\n AttemptedWrite,\n DispatchOutcome,\n FaultSource,\n ResponseAttempt,\n ResponseFailed,\n ResponseOutcome,\n ResponseSent,\n SubscribeOptions,\n Subscriptions,\n SubscriptionData,\n SubscriptionKey,\n WebhookFile,\n WebhookReport\n} from '#subscribers/index';\n\n/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":";;;;;;;;;;;;;;;;;AAYA,IAAa,gBAAb,cAAmC,OAAO;CACtC,YAAY,QAAgB;EACxB,MAAM,uBAAuB,OAAO,GAAG;CAC3C;CAEA,AAAS,SAAwB;EAK7B,OAAO,EAAE,YAAY,CAAC,IAJL,WACb,+EACA,UAEqB,CAAC,CAAC,SAAS,EAAE;CAC1C;AACJ;;;;;;AAOA,IAAa,kBAAb,cAAqC,OAAO;CACxC,YAAY,QAAgB;EACxB,MAAM,qBAAqB,QAAQ;EACnC,KAAK,SAAS;CAClB;CAEA,AAAS,SAAwB;EAE7B,OAAO,EAAE,YAAY,CAAC,IADL,WAAW,yCACH,CAAC,CAAC,SAAS,EAAE;CAC1C;AACJ;AAIAA,oBAAkB;CACd,QAAQ,WAAW,IAAI,cAAc,MAAM;CAC3C,UAAU,WAAW,IAAI,gBAAgB,MAAM;AACnD,CAAC;;;;;;;;;;;;;;;;;;;;;;;ACwGD,SAAgB,WAA0E,GAAG,QAAiB;CAC1G,OAAO,SAAwC,aAAmD;EAC9F,+BAA6C,QAAQ,WAAW;CACpE;AACJ;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,kBAAiF,GAAG,QAAiB;CACjH,OAAO,SAAwC,aAA0D;EACrG,sCAAoD,QAAQ,WAAW;CAC3E;AACJ;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,qBACZ,GAAG,OACL;CACE,OAAO,SACH,aACI;EACJ,sBAAsB,mBAAmB,uBAAuB,IAAI,GAAG,OAAO,WAAW;CAC7F;AACJ;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,wBAEd,GAAG,OAAgB;CACjB,OAAO,SACH,aACI;EACJ,sBAAsB,mBAAmB,uBAAuB,OAAO,GAAG,OAAO,WAAW;CAChG;AACJ;;;;;;;;;;;;AAaA,SAAgB,YAAuD,GAAG,MAAY;CAClF,OAAO,SACH,aACI;EACJ,8BAA4C,MAAM,WAAW;CACjE;AACJ;;;;;;;;;;;AAYA,SAAgB,WAAsD,GAAG,MAAY;CACjF,OAAO,SACH,aACI;EACJ,6BAA2C,MAAM,WAAW;CAChE;AACJ;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,gBAA2D,GAAG,MAAY;CACtF,OAAO,SACH,aACI;EACJ,kCAAgD,MAAM,WAAW;CACrE;AACJ;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,cAAyD,GAAG,MAAY;CACpF,OAAO,SACH,aACI;EACJ,gCAA8C,MAAM,WAAW;CACnE;AACJ;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,cAAyD,GAAG,MAAY;CACpF,OAAO,SACH,aACI;EACJ,gCAA8C,MAAM,WAAW;CACnE;AACJ;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,iBAA4D,GAAG,MAAY;CACvF,OAAO,SACH,aACI;EACJ,mCAAiD,MAAM,WAAW;CACtE;AACJ;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,qBAAgE,GAAG,MAAY;CAC3F,OAAO,SACH,aACI;EACJ,uCAAqD,MAAM,WAAW;CAC1E;AACJ;;;;;;;;;;;AC1YA,IAAsB,cAAtB,MAAiE;CAUzC;CATpB,AAAmB;CACnB,AAAmB;;CAEnB,AAAmB;;CAEnB,AAAmB;CAEnB,AAAU,YACN,OACA,AAAgB,MAChB,UACA,SACF;EAHkB;EAIhB,KAAK,QAAQ;EACb,KAAK,SAAS,IAAI,OAAO,KAAK,YAAY,MAAM,EAAE,QAAQ,CAAC;EAC3D,KAAK,WAAW;EAChB,KAAK,QAAQ,SAAS;CAC1B;AAOJ;;;;;;;;;;;;;;ACtBA,IAAsB,mBAAtB,cAMU,YAA0B;;CAEhC,AAAgB;CAEhB,AAAU,YAAY,OAAc,MAAa,UAA2B,QAAiB;EACzF,MAAM,OAAO,MAAM,UAAU,cAAc;EAC3C,KAAK,SAAS;CAClB;;CAGA,AAAU,MAAM,UAA2C,MAAoC;EAC3F,OAAO,KAAK,OAAO,MAAM,UAAU,IAAI;CAC3C;;CAGA,AAAU,MAAM,MAAiC;EAC7C,OAAO,KAAK,OAAO,MAAM,IAAI;CACjC;;CAGA,AAAU,SAAS,UAA2C,MAAoC;EAC9F,OAAO,KAAK,OAAO,SAAS,UAAU,IAAI;CAC9C;CAKA,AAAU,KACN,kBACA,eACiB;EAEjB,IAAI,kBAAkB,QAAW,OAAO,KAAK,OAAO,KAAK,gBAAmD;EAE5G,OAAO,KAAK,OAAO,KAAK,kBAA8B,aAAa;CACvE;;CAGA,AAAU,KAAK,UAA2C,MAAoC;EAC1F,OAAO,KAAK,OAAO,KAAK,UAAU,IAAI;CAC1C;;CAGA,AAAU,OAAO,QAAkC;EAC/C,OAAO,WAAW,SAAY,KAAK,OAAO,OAAO,IAAI,KAAK,OAAO,OAAO,MAAM;CAClF;AACJ;;;;;;;;;;;AC1CA,IAAsB,kBAAtB,MAAwF;CAQ/D;CAPrB,AAAQ;CAER,AAAiB,uBAAO,IAAI,IAAY;CAExC,AAAQ;CAER,AAAU,YACN,AAAiB,WACjB,eAAyB,WAC3B;EAFmB;EAGjB,KAAK,QAAQ;CACjB;CAEA,IAAc,UAAkB;EAC5B,OAAO,KAAK,UAAU,SAAS;CACnC;CAGA,AAAQ,OAAO,QAAqB,WAAmB,WAAgC;EACnF,gBAAgB,KAAK,WAAW;GAAE;GAAQ;GAAW,SAAS;GAAQ;EAAU,CAAC;CACrF;CAEA,MAAc,QACV,QACA,WACA,OACe;EACf,OAAO,MAAM,aAAa,KAAK,WAAW,QAAQ,WAAW,KAAK;CACtE;CAEA,MAAa,MAAM,UAA2C,MAAoC;EAC9F,KAAK,cAAc,OAAO;EAC1B,MAAM,YAAY,YAAY,IAAI;EAClC,MAAM,UAAU,MAAM,KAAK,QAAQ,SAAS,iBAAiB,KAAK,WAAW,UAAU,IAAI,CAAC;EAE5F,KAAK,WAAW,SAAS,SAAS;EAClC,MAAM,UAAU,KAAK,SAAS,KAAK,eAAe,SAAS,OAAO,CAAC;EACnE,KAAK,OAAO,SAAS,WAAW,QAAQ,EAAE;EAC1C,OAAO;CACX;CAEA,MAAa,MAAM,MAAiC;EAChD,KAAK,cAAc,OAAO;EAC1B,MAAM,YAAY,YAAY,IAAI;EAClC,MAAM,KAAK,QAAQ,SAAS,iBAAiB,KAAK,WAAW,IAAI,CAAC;EAClE,KAAK,WAAW,SAAS,gBAAgB;EACzC,KAAK,OAAO,SAAS,WAAW,IAAI;CACxC;CAEA,MAAa,cAA6B;EACtC,KAAK,cAAc,aAAa;EAChC,MAAM,YAAY,YAAY,IAAI;EAClC,MAAM,KAAK,QAAQ,eAAe,iBAAiB,KAAK,iBAAiB,CAAC;EAC1E,KAAK,WAAW,eAAe,iBAAiB;EAChD,KAAK,OAAO,eAAe,WAAW,IAAI;CAC9C;;;;;;CAOA,MAAa,OAAO,UAA8D;EAC9E,KAAK,cAAc,QAAQ;EAC3B,MAAM,YAAY,YAAY,IAAI;EAElC,IAAI,KAAK,UAAU,mBAAmB;GAClC,MAAM,SAAS,MAAM,KAAK,QAAQ,UAAU,iBAAiB,KAAK,aAAa,QAAQ,CAAC;GACxF,KAAK,OAAO,UAAU,WAAW,OAAO,EAAE;GAC1C,OAAO;EACX;EACA,MAAM,UAAU,MAAM,KAAK,QAAQ,UAAU,iBAAiB,KAAK,YAAY,QAAQ,CAAC;EACxF,KAAK,WAAW,UAAU,SAAS;EACnC,MAAM,UAAU,KAAK,SAAS,KAAK,eAAe,SAAS,QAAQ,CAAC;EACpE,KAAK,OAAO,UAAU,WAAW,QAAQ,EAAE;EAC3C,OAAO;CACX;CAEA,MAAa,SAAS,UAA2C,MAAoC;EACjG,KAAK,cAAc,UAAU;EAC7B,MAAM,YAAY,YAAY,IAAI;EAClC,MAAM,UAAU,MAAM,KAAK,QAAQ,YAAY,iBAAiB,KAAK,cAAc,UAAU,IAAI,CAAC;EAClG,MAAM,UAAU,KAAK,SAAS,OAAO;EACrC,KAAK,OAAO,YAAY,WAAW,QAAQ,EAAE;EAC7C,OAAO;CACX;CAIA,MAAa,KACT,kBACA,eACiB;EACjB,KAAK,cAAc,MAAM;EACzB,MAAM,YAAY,YAAY,IAAI;EAClC,IAAI,kBAAkB,QAAW;GAE7B,MAAM,SAAS,MAAM,KAAK,QAAQ,QAAQ,iBACtC,KAAK,aAAa,gBAAmD,CACzE;GACA,KAAK,OAAO,QAAQ,WAAW,OAAO,EAAE;GACxC,OAAO;EACX;EAEA,MAAM,SAAS;EACf,IAAI,CAAC,KAAK,KAAK,IAAI,OAAO,EAAE,GACxB,MAAM,IAAI,cAAc,kBAAkB,wBAAwB;GAAC;GAAQ,OAAO;GAAI,KAAK;EAAO,CAAC;EAEvG,MAAM,UAAU,MAAM,KAAK,QAAQ,QAAQ,iBAAiB,KAAK,gBAAgB,OAAO,IAAI,aAAa,CAAC;EAC1G,MAAM,UAAU,KAAK,SAAS,OAAO;EACrC,KAAK,OAAO,QAAQ,WAAW,QAAQ,EAAE;EACzC,OAAO;CACX;CAIA,MAAa,OAAO,QAAkC;EAClD,KAAK,cAAc,QAAQ;EAC3B,MAAM,YAAY,YAAY,IAAI;EAClC,IAAI,WAAW,QAAW;GACtB,MAAM,KAAK,QAAQ,UAAU,iBAAiB,KAAK,oBAAoB,CAAC;GACxE,KAAK,OAAO,UAAU,WAAW,IAAI;GACrC;EACJ;EACA,IAAI,CAAC,KAAK,KAAK,IAAI,OAAO,EAAE,GACxB,MAAM,IAAI,cAAc,kBAAkB,wBAAwB;GAAC;GAAU,OAAO;GAAI,KAAK;EAAO,CAAC;EAEzG,MAAM,KAAK,QAAQ,UAAU,iBAAiB,KAAK,kBAAkB,OAAO,EAAE,CAAC;EAE/E,KAAK,KAAK,OAAO,OAAO,EAAE;EAC1B,KAAK,OAAO,UAAU,WAAW,IAAI;CACzC;;CAGA,MAAa,KAAK,UAA2C,MAAoC;EAC7F,MAAM,SAAS,WAAW,KAAK,KAAK;EACpC,IAAI,WAAW,SAAS,OAAO,MAAM,KAAK,MAAM,UAAU,IAAI;EAC9D,IAAI,WAAW,QAAQ,OAAO,MAAM,KAAK,KAAK,QAAQ;EACtD,OAAO,MAAM,KAAK,SAAS,UAAU,IAAI;CAC7C;;CAGA,MAAa,UAAU,OAAiC;EACpD,KAAK,cAAc,WAAW;EAC9B,KAAK,iBAAiB;EACtB,IAAI;EACJ,IAAI;GACA,OAAO,MAAM,OAAO;EACxB,SAAS,OAAO;GAEZ,MAAM,OAAO,MAAM,aAAa;GAChC,MAAM,4BAA4B,OAAO,CAAC,QAAQ,SAAS,WAAW,UAAU,MAAM,GAAG,KAAK,OAAO;EACzG;EACA,MAAM,YAAY,YAAY,IAAI;EAClC,MAAM,KAAK,QAAQ,aAAa,iBAAiB,KAAK,WAAW,IAAI,CAAC;EACtE,KAAK,WAAW,aAAa,SAAS;EACtC,KAAK,OAAO,aAAa,WAAW,IAAI;CAC5C;CAEA,AAAU,UAAU,UAAqE;EACrF,OAAO,eAAe,UAAU,KAAK,OAAO;CAChD;CAEA,AAAU,SAAS,SAA6B;EAC5C,KAAK,KAAK,IAAI,QAAQ,EAAE;EACxB,OAAO;CACX;CAGA,AAAQ,eAAe,SAA+B,QAAsC;EACxF,IAAI,CAAC,SAAS,MAAM,IAAI,cAAc,kBAAkB,6BAA6B,CAAC,QAAQ,KAAK,OAAO,CAAC;EAC3G,OAAO;CACX;CAEA,MAAc,aAAa,UAA8D;EACrF,MAAM,SAAS,MAAM,KAAK,kBAAkB,QAAQ;EAEpD,IAAI,KAAK,UAAU,mBAAmB,KAAK,SAAS,MAAM;EAC1D,OAAO;CACX;CAEA,AAAQ,cAAc,QAA2B;EAC7C,iBAAiB,QAAQ,KAAK,OAAO,KAAK,SAAS,KAAK,OAAO;CACnE;CAEA,AAAQ,WAAW,QAAqB,OAAuB;EAC3D,KAAK,QAAQ;EACb,KAAK,UAAU,IAAI,SAAS,MAAM;CACtC;CAGA,AAAU,mBAAyB,CAAC;AAexC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA,SAAgB,WACZ,MACA,IACe;CACf,OAAO;EAAE;EAAM,OAAO,OAAO,QAAQ,GAAG,GAAG;CAAE;AACjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,iBACZ,MACA,OACA,QACqB;CACrB,OAAO;EACH;EACA,OAAO,OAAO,QAAQ,MAAM,GAAG;EAC/B,QAAQ,OAAO,QAAQ,OAAO,GAAG;CACrC;AACJ;;;;ACjOA,MAAM,iBAAiB;AAEvB,SAAS,UAAU,OAAyC,WAA2B;CACnF,OAAO,MAAM,KAAK,SAAU,eAAe,KAAK,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,IAAK,CAAC,CAAC,KAAK,SAAS;AAC9G;AA4BA,SAAgB,IAAI,GAAG,OAAgE;CACnF,OAAO,WAAW,UAAU,OAAO,KAAK,GAAG,OAAO,QAAQ;EACtD,KAAK,MAAM,QAAQ,OACf,MAAM,SAAS,MAAM,GAAG;CAEhC,CAAC;AACL;AAMA,SAAS,YAAY,KAA0D;CAC3E,OAAO,EAAE,WAAW;AACxB;AAqCA,SAAgB,GAAG,GAAG,MAA6E;CAC/F,MAAM,OAAO,KAAK,GAAG,EAAE;CACvB,MAAM,UAAU,SAAS,UAAa,YAAY,IAAI,IAAI,OAAO;CACjE,MAAM,QAAS,UAAU,KAAK,MAAM,GAAG,EAAE,IAAI;CAE7C,OAAO,WAAW,UAAU,OAAO,KAAK,GAAG,OAAO,QAAQ;EACtD,MAAM,YAAsB,CAAC;EAC7B,IAAI,qBAAqB;EACzB,KAAK,MAAM,QAAQ,OAAO;GACtB,MAAM,OAAO,YAAY,GAAG;GAC5B,IAAI;IACA,MAAM,SAAS,MAAM,GAAG;IACxB;GACJ,SAAS,OAAO;IAEZ,IAAI,iBAAiB,UAAU,EAAE,iBAAiB,UAAU,CAAC,MAAM,QAAQ;KAEvE,gBAAgB,KAAK,IAAI;KACzB,IAAI,MAAM,YAAY,QAAW,qBAAqB;UACjD,UAAU,KAAK,MAAM,OAAO;KACjC;IACJ;IACA,MAAM;GACV;EACJ;EACA,IAAI,SAAS,MAAM,OAAO,QAAQ,SAAS,aAAa,QAAQ,KAAK,GAAG,IAAI,QAAQ;EAEpF,IAAI,sBAAsB,UAAU,SAAS,GAAG,MAAM,IAAI,SAAS,SAAS;EAC5E,MAAM,IAAI,WAAW;CACzB,CAAC;AACL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5FA,SAAgB,UAAU,SAAiE;CACvF,OAAO,WAAW,cAAc,QAAQ;EACpC,MAAM,SAAS,IAAI,KAAK,OAAO,YAAY,CAAC;EAC5C,IAAI,IAAI,WAAW,QAAQ,OAAO,SAAS,IAAI,MAAM,GAAG;EACxD,MAAM,MAAK,SAAS,WAAU,UAAU;CAC5C,CAAC;AACL;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,UAAU,SAAiE;CACvF,OAAO,WAAW,cAAc,QAAQ;EACpC,IAAI,IAAI,SAAS;EACjB,MAAM,MAAK,SAAS,WAAU,YAAY;CAC9C,CAAC;AACL;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,OAAO,SAA8D;CACjF,OAAO,WAAW,WAAW,QAAQ;EACjC,IAAI,CAAC,IAAI,SAAS;EAClB,MAAM,MAAK,SAAS,WAAU,SAAS;CAC3C,CAAC;AACL;;;;AC3CA,IAAI,UAAU;AAEd,SAAS,WAAW,KAAsB,KAA2C;CACjF,IAAI,QAAQ,SAAS,OAAO,IAAI,WAAW;CAC3C,IAAI,QAAQ,WAAW,OAAO,IAAI,aAAa;CAC/C,OAAO,IAAI,UAAU;AACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,SACZ,UACA,SACuC;CACvC,IAAI;CACJ,IAAI,OAAO,aAAa,UACpB,WAAW,WAAW;MACnB;EACH,MAAM,SAAS,cAAc,QAAQ;EACrC,IAAI,WAAW,MAAM,MAAM,IAAI,kBAAkB,kBAAkB,6BAA6B,CAAC,QAAQ,CAAC;EAC1G,WAAW;CACf;CAEA,IAAI,YAAY,GACZ,MAAM,IAAI,mBAAmB,kBAAkB,6BAA6B,CAAC,OAAO,QAAQ,CAAC,CAAC;CAGlG,MAAM,MAAM,SAAS,OAAO;CAE5B,MAAM,SAAS,SAAS,UAAU,SAAY,EAAE,SAAS,IAAI;EAAE;EAAU,OAAO,QAAQ;CAAM;CAC9F,MAAM,SAAS;CAEf,MAAM,SAAS,QACX,YAAY,IAAI,SAAS,iBAAiB,OAAO,SAAS,GAAG,IAAI,IAAI,SAAS,IAAI,SAAS,SAAS,EAAE,GAAG,WAAW,KAAK,GAAG;CAEhI,OAAO,iBACH,YACA,OAAO,QAAQ;EACX,MAAM,SAAS,MAAM,IAAI,KAAK,YAAY,KAAK,MAAM,GAAG,GAAG,MAAM;EACjE,IAAI,CAAC,OAAO,SAAS;EACrB,MAAM,MAAK,SAAS,WAAU,YAAY,OAAO,OAAO;CAC5D,GACA,OAAO,QAAQ;EACX,MAAM,IAAI,KAAK,YAAY,OAAO,MAAM,GAAG,GAAG,MAAM;CACxD,CACJ;AACJ;;;;ACpIA,MAAM,kBAAkB,IAAI,IACxB,OAAO,QAAQ,mBAAmB,CAAC,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,KAAK,SAAS,GAAG,CAAC,CAAC,CAChF;AAEA,MAAM,gBAAgB,oBAAoB;AAE1C,SAAS,OAAO,KAAqB;CACjC,OAAO,gBAAgB,IAAI,GAAG,KAAK,OAAO,GAAG;AACjD;AAGA,SAAS,MAAM,MAAc,KAAsB;CAC/C,QAAQ,OAAO,mBAAmB,kBAAkB,OAAO,SAAS;AACxE;AAEA,SAAS,WAAW,MAAc,OAAwB,QAA2B;CACjF,OAAO,MAAM,QAAkB,OAAO,QAAQ;EAC1C,IAAI,MAAM,MAAM,GAAG,MAAM,QAAQ,MAAM,KAAK,OAAO,GAAG,CAAC;EACvD,OAAO;CACX,GAAG,CAAC,CAAC;AACT;;AAGA,SAAgB,aAAa,MAAc,OAAkC;CACzE,OAAO,WAAW,MAAM,OAAO,KAAK;AACxC;;AAGA,SAAgB,aAAa,MAAc,OAAkC;CACzE,OAAO,WAAW,MAAM,OAAO,IAAI;AACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACwDA,SAAgB,kBAAkB,EAAE,SAAS,aAAa,OAAO,UAAU,OAAO,UAAqC;CACnH,MAAM,CAAC,SAAS,WAAW,UACrB,CAAC,aAAa,aAAa,KAAK,GAAG,qBAAqB,IACxD,CAAC,aAAa,aAAa,KAAK,GAAG,kBAAkB;CAC3D,IAAI,QAAQ,WAAW,GAAG;CAC1B,MAAM,KAAK,UAAU,SAAS,SAAS,OAAO;AAClD;;;;ACvFA,MAAM,cAAc;AA4CpB,SAAS,YACL,EAAE,SAAS,SAAS,eACpB,OACA,SACI;CACJ,IAAI,CAAC,SAAS,MAAM,MAAK,SAAS,eAAc,YAAY;CAC5D,MAAM,cAAc,YAAY,OAAO;CACvC,kBAAkB;EAAE;EAAS;EAAa;EAAO,QAAQ,SAAS;CAAQ,CAAC;AAC/E;AAEA,SAAS,iBAAiB,SAAwB;CAC9C,MAAM,IAAI,cAAc,kBAAkB,sBAAsB,CAAC,OAAO,CAAC;AAC7E;AA2CA,SAAgB,mBACZ,OACA,SACiG;CACjG,MAAM,YAAY,SAAgC;EAC9C,IAAI,SAAS,MAAM,MAAM,MAAK,SAAS,eAAc,uBAAuB;EAC5E,OAAO;CACX;CACA,IAAI,SAAS,OAAO,SAChB,OAAO,WAAW,uBAAuB,QAAiC;EACtE,MAAM,oBAA4B,SAAS,IAAI,sBAAsB;EACrE,YAAY;GAAE,SAAS,IAAI;GAAS,SAAS;GAAM;EAAY,GAAG,OAAO,OAAO;CACpF,CAAC;CAEL,OAAO,WAAW,uBAAuB,QAAyB;EAC9D,MAAM,oBAA4B,SAAS,IAAI,iBAAiB;EAChE,YAAY;GAAE,SAAS,IAAI;GAAS,SAAS;GAAM;EAAY,GAAG,OAAO,OAAO;CACpF,CAAC;AACL;AAsCA,SAAgB,sBACZ,OACA,SAC6G;CAC7G,IAAI,SAAS,OAAO,SAChB,OAAO,WAAW,0BAA0B,QAAiC;EACzE,MAAM,eAAe,YAA4B,IAAI,uBAAuB,iBAAiB,OAAO;EACpG,YAAY;GAAE,SAAS,IAAI;GAAS,SAAS;GAAa;EAAY,GAAG,OAAO,OAAO;CAC3F,CAAC;CAEL,OAAO,WAAW,0BAA0B,QAA+B;EACvE,YACI;GAAE,SAAS,IAAI;GAAS,SAAS;GAAa,mBAAmB,IAAI;EAAe,GACpF,OACA,OACJ;CACJ,CAAC;AACL;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,YAAY,QAAgB,SAAoE;CAC5G,OAAO,WAAW,gBAAgB,QAAQ;EACtC,IAAI,CAAC,IAAI,SAAS,MAAM,MAAK,SAAS,eAAc,YAAY;EAChE,IAAI,IAAI,cAAc,SAAS,MAAM,GAAG;EACxC,MAAM,MAAK,SAAS,gBAAe,aAAa,MAAM;CAC1D,CAAC;AACL;;;;;;;;;;;;;;;;;;;;;;;ACnMA,SAAgB,WAAW,SAA4B,KAAwB,QAAqC;CAChH,OAAO,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,IAAI,MAAM,CAAC,CAAC;AAC/E;;;;;;;;;;;;;ACPA,SAAgB,SAAe,OAAwB,MAAc,SAAiC;CAClG,IAAI,CAAC,OAAO,cAAc,OAAO,KAAK,WAAW,GAC7C,MAAM,IAAI,mBAAmB,kBAAkB,0BAA0B,CAAC,OAAO,CAAC;CAGtF,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,SAAS,OAAO,CAAC;CAGhE,MAAM,UAAU,KAAK,IAAI,KAAK,IADZ,OAAO,MAAM,IAAI,IAAI,IAAI,KAAK,MAAM,IAAI,GACb,CAAC,GAAG,aAAa,CAAC;CAC/D,MAAM,QAAQ,UAAU;CAExB,OAAO;EACH,OAAO,MAAM,MAAM,OAAO,QAAQ,OAAO;EACzC,MAAM;EACN;EACA;EACA,SAAS,UAAU;EACnB,SAAS,UAAU,aAAa;CACpC;AACJ;;;;ACOA,MAAM,gBAA4C;CAC9C,OAAO;CACP,MAAM;CACN,WAAW;CACX,MAAM;CACN,MAAM;AACV;AAGA,MAAM,eAA2C;CAC7C,OAAO;CACP,MAAM;CACN,WAAW;CACX,MAAM;CACN,MAAM;AACV;AAEA,MAAM,sBAAsB;AAE5B,IAAa,WAAb,MAAmD;CAE1B;CACA;CAFrB,YACI,AAAiB,QACjB,AAAiB,MACnB;EAFmB;EACA;CAClB;CAEH,OAAO,KAAiB,WAA6C;EACjE,MAAM,EAAE,QAAQ,aAAa,KAAK,SAAS,GAAG;EAG9C,MAAM,eAAe,QAAQ,cAAc,KAAK,cAAc,IAAI,cAAc;EAChF,MAAM,QAAQ,WAAW,UAAU,QAAQ,eAAe,CAAC,WAAW,QAAQ,eAAe;EAE7F,MAAM,SAAS,IAAI,cAAc,CAAC,CAE7B,YAAY,KAAK,OAAO,OAAO;GAAE,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,QAAQ;GAAG,MAAM,aAAa;EAAK,CAAC,CAAC,CAAC,CAC3G,SAAS,WAAW,SAAS,YAAY,SAAS,CAAC,CACnD,YAAY,QAAQ;EACzB,IAAI,UAAU,QAAW,OAAO,SAAS,KAAK;EAC9C,IAAI,WAAW,OAAO,OAAO,SAAS,UAAU,KAAK;EACrD,OAAO;CACX;CAEA,AAAQ,SAAS,KAAwD;EACrE,MAAM,EAAE,MAAM,YAAY,SAAS,YAAY,KAAK;EACpD,MAAM,aAAa,eAAe;EAgBlC,OAAO;GAAE,QAfM;IACX,OAAO;IACP,MAAM,OAAO;IACb,WAAW;IACX,MAAM,OAAO;IACb,MAAM,aAAa,aAAa,IAAI;GACxC,EAAE;GASe,UAPA;IACb,OAAO,CAAC;IACR,MAAM,CAAC;IACP,WAAW;IACX,MAAM,CAAC,WAAW,OAAO;IACzB,MAAM,CAAC,WAAW,CAAC,cAAc,aAAa;GAClD,EAAE;EACwB;CAC9B;CAEA,IAAI,GAAG,MAAqD;EACxD,IAAI,KAAK,WAAW,KAAK,KAAK,SAAS,qBACnC,MAAM,IAAI,mBAAmB,kBAAkB,wBAAwB,CAAC,KAAK,QAAQ,mBAAmB,CAAC;EAG7G,MAAM,uBAAO,IAAI,IAAgB;EACjC,KAAK,MAAM,OAAO,MAAM;GACpB,IAAI,KAAK,IAAI,GAAG,GAAG,MAAM,IAAI,kBAAkB,kBAAkB,6BAA6B,CAAC,GAAG,CAAC;GACnG,KAAK,IAAI,GAAG;EAChB;EACA,OAAO,IAAI,iBAAgC,CAAC,CAAC,cAAc,KAAK,KAAK,QAAQ,KAAK,OAAO,GAAG,CAAC,CAAC;CAClG;CAEA,AAAQ,gBAAwB;EAC5B,MAAM,EAAE,MAAM,eAAe,KAAK;EAClC,OAAO,eAAe,SAAY,QAAQ,OAAO,MAAM,QAAQ,OAAO,EAAE,MAAM;CAClF;AACJ;;;;ACpGA,IAAM,gBAAN,cAAkC,iBAA8B;CAC5D,YAAY,MAAsB,YAA8B,YAA6C;EACzG,MAAM,WAAW;EACjB,MAAM,OAAO,KAAK,OAAO,KAAK;EAC9B,IAAI,QAAkB,CAAC;EACvB,MAAM,cAAoB;GACtB,IAAI,MAAM,WAAW,GAAG;GACxB,KAAK,SAAS,yBAAyB,IAAI,mBAAmB,CAAC,CAAC,WAAW,MAAM,KAAK,IAAI,CAAC,CAAC;GAC5F,QAAQ,CAAC;EACb;EACA,KAAK,MAAM,SAAS,MAAM,WAAW;GACjC,MAAM,WAAW,WAAW,MAAM,OAAO,MAAM;GAC/C,IAAI,OAAO,aAAa,UAAU;IAC9B,MAAM,KAAK,QAAQ;IACnB;GACJ;GACA,MAAM;GACN,KAAK,SAAS,qBAAqB,SAAS,SAAS;EACzD,CAAC;EACD,MAAM;EACN,KAAK,SAAS,uBAAuB,UAAU;CACnD;AACJ;AAEA,SAAS,gBAAgB,YAAuC;CAC5D,IAAI,OAAO,eAAe,UAAU,OAAO,EAAE,YAAY,CAAC,IAAI,mBAAmB,CAAC,CAAC,WAAW,UAAU,CAAC,EAAE;CAC3G,IAAI,MAAM,QAAQ,UAAU,GAAG,OAAO,EAAE,YAAY,WAAW;CAC/D,OAAO;AACX;AAEA,MAAM,aAA2B;CAAC;CAAS;CAAQ;CAAa;CAAQ;AAAM;AAC9E,MAAM,cAA4B;CAAC;CAAQ;CAAa;AAAM;AAI9D,SAAgB,WACZ,MACA,QACA,QACa;CACb,MAAM,WAAW,IAAI,SAAS,QAAQ,IAAI;CAC1C,IAAI,OAAO,QAAQ,OAAO,gBAAgB,OAAO,OAAO,MAAM,QAAQ,CAAC;CAEvE,MAAM,aAAa,OAAO,cAAc;CACxC,MAAM,MAAM,SAAS,IAAI,GAAI,KAAK,eAAe,SAAY,cAAc,UAAW;CACtF,OAAO,EAAE,YAAY,CAAC,IAAI,cAAc,MAAM,YAAY,GAAG,CAAC,CAAC,SAAS,EAAE;AAC9E;;;;;;;;;;;;AC3BA,IAAsB,gBAAtB,MAAsE;;CAElE,AAAgB;CAEhB,AAAmB;CAEnB,AAAU,YAAY,QAA4C;EAC9D,KAAK,SAAS,WAAW,OAAO,MAAM;EACtC,KAAK,SAAS;CAClB;;CAGA,MAAgB,UAAU,KAAU,GAAmC;EACnE,MAAM,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK,KAAK,CAAC;EACjD,OAAO,WAAW,MAAM,KAAK,QAAQ,KAAK,MAAM;CACpD;AACJ;;;;AC/CA,MAAM,mBAAmB;AAYzB,SAAS,UAAU,MAAqC;CACpD,MAAM,UAAU,MAAM,WAAW;CACjC,IAAI,CAAC,OAAO,cAAc,OAAO,KAAK,WAAW,GAC7C,MAAM,IAAI,mBAAmB,kBAAkB,0BAA0B,CAAC,OAAO,CAAC;CAEtF,OAAO;AACX;;;;;;;;;AAUA,IAAa,kBAAb,MAA6E;CAIpD;CAHrB,AAAiB;CAEjB,YACI,AAAiB,MACjB,MACF;EAFmB;EAGjB,KAAK,UAAU,UAAU,IAAI;CACjC;CAEA,MAAM,KAAK,KAAU,GAAoC;EACrD,OAAO,SAAS,MAAM,KAAK,KAAK,GAAG,GAAG,GAAG,KAAK,OAAO;CACzD;AACJ;;;;;;;;;;AAWA,IAAa,mBAAb,MAA8E;CAIrD;CAHrB,AAAiB;CAEjB,YACI,AAAiB,OAKjB,MACF;EANmB;EAOjB,KAAK,UAAU,UAAU,IAAI;CACjC;CAEA,MAAM,KAAK,KAAU,GAAoC;EAErD,MAAM,OAAO,OAAO,SAAS,CAAC,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC,IAAI;EAC/D,MAAM,EAAE,OAAO,YAAY,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,OAAO;EACnE,OAAO;GAAE,OAAO,CAAC,GAAG,KAAK;GAAG;GAAM,SAAS,KAAK;GAAS,SAAS,OAAO;GAAG;EAAQ;CACxF;AACJ;;;;;;;;;;;;ACpDA,IAAa,aAAb,MAAqF;CAG7D;CAFpB,YAEI,AAAgB,MAClB;EADkB;CACjB;CAEH,MAAa,IAAI,KAA0C;EACvD,MAAM,QAAQ,MAAM,KAAK,KAAK,IAAI,GAAG;EACrC,OAAO,OAAO,UAAU,WAAW,QAAQ;CAC/C;CAEA,MAAa,IAAI,KAAa,OAAe,OAA+B;EACxE,IAAI,CAAE,MAAM,KAAK,KAAK,IAAI,KAAK,OAAO,KAAK,GACvC,MAAM,IAAI,cAAc,kBAAkB,oBAAoB,CAAC,SAAS,GAAG,CAAC;CACpF;CAEA,MAAa,OAAO,KAA4B;EAC5C,MAAM,KAAK,KAAK,OAAO,GAAG;CAC9B;;CAGA,OAAc,QAAQ,QAAwC;EAC1D,IAAI,CAAC,KAAK,aAAa,GAAG,MAAM,IAAI,cAAc,kBAAkB,qBAAqB;EAEzF,WAAW,MAAM,CAAC,KAAK,UAAU,KAAK,KAAK,SAAS,GAChD,IAAI,IAAI,WAAW,MAAM,KAAK,OAAO,UAAU,UAAU,MAAM,CAAC,KAAK,KAAK;CAElF;CAEA,OAAc,OAAO,gBAA+B;EAChD,MAAM,KAAK,KAAK,WAAW;CAC/B;CAGA,eAAwB;EACpB,MAAM,eAAe,KAAK,KAAK,MAAM;EACrC,OAAO,cAAc,UAAU,aAAa,cAAc,QAAQ,SAAS,WAAW;CAC1F;AACJ;;;;AC/DA,MAAM,kBAAkB;AACxB,MAAM,gBAAgB;AAgBtB,SAAS,WAAW,KAAqB;CACrC,OAAO,IAAI,mBAAmB,GAAG,CAAC,CAAC,WAAW,KAAK,KAAK;AAC5D;AAEA,SAAS,YAAY,QAAwB;CACzC,OAAO,mBAAmB,OAAO,MAAM,CAAC,CAAC;AAC7C;AAEA,SAAS,KAAK,KAAgD;CAC1D,IAAI,QAAQ,MAAM,OAAO;CACzB,OAAO,OAAO,QAAQ,WAAW,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,GAAG;AACvE;;;;;;;;;AAUA,IAAa,kBAAb,MAAgG;CAGxE;CAFpB,YAEI,AAAgB,SAClB;EADkB;CACjB;CAEH,MAAa,IAAI,KAA0C;EACvD,OAAO,KAAK,MAAM,KAAK,QAAQ,WAAW,WAAW,GAAG,CAAC,CAAC;CAC9D;CAEA,MAAa,IAAI,KAAa,OAAe,OAA+B;EAExE,MAAM,MAAM,UAAU,SAAY,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,iBAAiB,KAAK,KAAK,QAAQ,aAAa,CAAC,EAAE;EAC1G,MAAM,KAAK,QAAQ,WAAW,WAAW,GAAG,GAAG,OAAO,GAAG;CAC7D;CAEA,MAAa,OAAO,KAA4B;EAC5C,MAAM,KAAK,QAAQ,WAAW,WAAW,GAAG,CAAC;CACjD;CAEA,OAAc,QAAQ,QAAwC;EAG1D,MAAM,eAAe,WAAW,MAAM;EACtC,KAAK,MAAM,OAAO,MAAM,KAAK,QAAQ,QAAQ,GAAG;GAC5C,IAAI,CAAC,IAAI,WAAW,YAAY,GAAG;GACnC,MAAM,QAAQ,KAAK,MAAM,KAAK,QAAQ,WAAW,GAAG,CAAC;GACrD,IAAI,UAAU,QAAW,MAAM,CAAC,YAAY,GAAG,GAAG,KAAK;EAC3D;CACJ;CAEA,OAAc,OAAO,gBAA+B;EAChD,MAAM,KAAK,QAAQ,QAAQ;CAC/B;AACJ;;;;;;;;;;;;;;;;AC/DA,SAAgB,SAAS,QAAgB,GAAG,OAAuD;CAC/F,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,OAAO,CAAC,QAAQ,GAAG,MAAM,KAAK,SAAS,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG;AACtE;;;;;ACwHA,MAAa"}