@seedcord/core 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/{HmrModuleHandler-CTBng7wV.cjs → HmrModuleHandler-CxGOo1LT.cjs} +43 -31
  2. package/dist/HmrModuleHandler-CxGOo1LT.cjs.map +1 -0
  3. package/dist/{HmrModuleHandler-3sNgKHdf.mjs → HmrModuleHandler-KxRP8lqJ.mjs} +43 -29
  4. package/dist/HmrModuleHandler-KxRP8lqJ.mjs.map +1 -0
  5. package/dist/{Plugin-BZit5HUI.d.mts → Plugin-BPz0obbN.d.mts} +19 -13
  6. package/dist/Plugin-CDAV7P9l.mjs.map +1 -1
  7. package/dist/{Plugin-BlkhHNRm.cjs → Plugin-DVNh1kvX.cjs} +3 -3
  8. package/dist/{Plugin-BlkhHNRm.cjs.map → Plugin-DVNh1kvX.cjs.map} +1 -1
  9. package/dist/{basic-1hebYVcN.d.mts → basic-CeSFvbaz.d.mts} +2 -3
  10. package/dist/{contextMenuLeaves-f2rbyo83.d.mts → contextMenuLeaves-CC3-qObq.d.mts} +1 -2
  11. package/dist/{cursor-j5bRcn2O.d.mts → cursor-Bk-W5MTq.d.mts} +16 -16
  12. package/dist/{cursor-BMkFAwO2.cjs → cursor-D2iP-CCS.cjs} +7 -4
  13. package/dist/cursor-D2iP-CCS.cjs.map +1 -0
  14. package/dist/{cursor-BvSH8tgw.mjs → cursor-Y6ct-N_8.mjs} +7 -4
  15. package/dist/{cursor-BvSH8tgw.mjs.map → cursor-Y6ct-N_8.mjs.map} +1 -1
  16. package/dist/{devChannel-CoCmAVDx.cjs → devChannel-Cdnmz6hd.cjs} +1 -2
  17. package/dist/{devChannel-CoCmAVDx.cjs.map → devChannel-Cdnmz6hd.cjs.map} +1 -1
  18. package/dist/hmr.index.cjs +1 -1
  19. package/dist/hmr.index.d.mts +2 -1
  20. package/dist/hmr.index.mjs +1 -1
  21. package/dist/{index-DafutfX8.d.mts → index-Dm0WKN37.d.mts} +4 -4
  22. package/dist/index.cjs +11 -7
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.mts +5 -5
  25. package/dist/index.mjs +10 -6
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/internal.index.cjs +28 -29
  28. package/dist/internal.index.cjs.map +1 -1
  29. package/dist/internal.index.d.mts +9 -15
  30. package/dist/internal.index.mjs +28 -27
  31. package/dist/internal.index.mjs.map +1 -1
  32. package/dist/node-internal.index.cjs +63 -74
  33. package/dist/node-internal.index.cjs.map +1 -1
  34. package/dist/node-internal.index.d.mts +17 -24
  35. package/dist/node-internal.index.mjs +59 -70
  36. package/dist/node-internal.index.mjs.map +1 -1
  37. package/dist/{phases-DcuDHoQl.cjs → phases-8qiiLKjS.cjs} +1 -2
  38. package/dist/{phases-DcuDHoQl.cjs.map → phases-8qiiLKjS.cjs.map} +1 -1
  39. package/dist/plugin.index.cjs +1 -1
  40. package/dist/plugin.index.d.mts +1 -1
  41. package/dist/slashRouteLeaves-nfxOAM7Q.cjs.map +1 -1
  42. package/dist/{subscribers-CojcCgj1.cjs → subscribers-CDbep0RH.cjs} +36 -4
  43. package/dist/subscribers-CDbep0RH.cjs.map +1 -0
  44. package/dist/{subscribers-CmDKqC7y.mjs → subscribers-xO6DZ-70.mjs} +2 -2
  45. package/dist/{subscribers-CmDKqC7y.mjs.map → subscribers-xO6DZ-70.mjs.map} +1 -1
  46. package/package.json +18 -15
  47. package/dist/HmrModuleHandler-3sNgKHdf.mjs.map +0 -1
  48. package/dist/HmrModuleHandler-CTBng7wV.cjs.map +0 -1
  49. package/dist/cursor-BMkFAwO2.cjs.map +0 -1
  50. package/dist/rolldown-runtime-C_NdSu1c.cjs +0 -34
  51. package/dist/subscribers-CojcCgj1.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"cursor-BvSH8tgw.mjs","names":[],"sources":["../src/miscellaneous/guarded.ts","../src/commands/CommandInjector.ts","../src/stops/Notice.ts","../src/stops/NoticeCard.ts","../src/customId/Errors.ts","../src/customId/codec.ts","../src/customId/CustomId.ts","../src/customId/routing.ts","../src/decorators/interactionRoutes.ts","../src/gates/Gate.ts","../src/notices/index.ts","../src/gates/effects.ts","../src/gates/catalog/options.ts","../src/permissions/bits.ts","../src/gates/catalog/permissions.ts","../src/stops/Silence.ts","../src/pagination/cursor.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n/**\n * A backing record for a generated accessor. Null-prototype, on a plain object a key named `__proto__` sets\n * the store's prototype and adds no entry.\n *\n * @internal\n */\nexport function accessorStore<Value>(): Record<string, Value> {\n return Object.create(null) as Record<string, Value>;\n}\n\n/** Empties a store in place, keeping the reference the accessor's Proxy wraps. @internal */\nexport function clearStore(store: Record<string, unknown>): void {\n for (const key of Object.keys(store)) Reflect.deleteProperty(store, key);\n}\n\n/**\n * Wraps a generated accessor's backing record so a read of an absent key throws. Handler modules import before\n * startup fills the record, and an unguarded read there returns `undefined` and renders as an empty string.\n *\n * @internal\n */\nexport function guardedAccessor<Value>(accessor: string, storage: Record<string, Value>): Record<string, Value> {\n return new Proxy(storage, {\n get(target, key, receiver): unknown {\n // hasOwn, since `in` walks the prototype and would read a key like `constructor` as resolved\n if (typeof key !== 'string' || Object.hasOwn(target, key)) return Reflect.get(target, key, receiver);\n throw new SeedcordError(SeedcordErrorCode.CoreAccessorUnresolved, [accessor, key]);\n }\n });\n}\n","import { SlashCommandBuilder } from '@discordjs/builders';\nimport { Logger, paint } from '@seedcord/logger';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { contextMenuLeaves } from '@src/commands/contextMenuLeaves';\nimport { accessorStore, clearStore, guardedAccessor } from '@src/miscellaneous/guarded';\n\nimport type {\n ContextMenuKind,\n MessageContextMenuRegistry,\n UserContextMenuRegistry\n} from '@registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '@registries/SlashOptionRegistry';\nimport type { CommandBuilder, DeployResult } from '@src/commands/types';\nimport type { APIApplicationCommand, Snowflake } from 'discord-api-types/v10';\n\nconst commandStorage = accessorStore<CommandInfo>();\nconst userMenuStorage = accessorStore<ContextMenuInfo>();\nconst messageMenuStorage = accessorStore<ContextMenuInfo>();\n\n/** What {@link Commands} resolves to for one slash route. */\nexport interface CommandInfo {\n /** The clickable `</config set:id>` mention. A route whose id did not resolve falls back to `/config set`. */\n readonly mention: string;\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The full route, e.g. `config/set`. */\n readonly route: string;\n /** The route's own description, taken from the subcommand for a nested route. */\n readonly description: string;\n}\n\n/** Each registered slash route mapped to its deployed command. */\nexport type InjectedCommandMap = {\n [K in keyof SlashOptionRegistry]: CommandInfo;\n};\n\n/**\n * The bot's deployed slash commands, keyed by {@link SlashOptionRegistry}. Filled by\n * {@link CommandInjector} after each deploy, and a read before that throws.\n *\n * @example\n * ```ts\n * import { Commands } from '@seedcord/gateway';\n *\n * await this.reply(`Try ${Commands['config/set'].mention}`);\n *\n * // a help listing\n * const lines = Object.values(Commands).map((c) => `${c.mention} ${c.description}`);\n * ```\n */\nexport const Commands = guardedAccessor('Commands', commandStorage) as InjectedCommandMap;\n\n/** What {@link ContextMenus} resolves to for one context-menu command. */\nexport interface ContextMenuInfo {\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The name shown in Discord's right-click menu. */\n readonly name: string;\n readonly kind: ContextMenuKind;\n}\n\n/** Deployed context-menu commands, split by kind because Discord scopes name uniqueness per command type. */\nexport interface InjectedContextMenuMap {\n readonly user: { [K in keyof UserContextMenuRegistry]: ContextMenuInfo };\n readonly message: { [K in keyof MessageContextMenuRegistry]: ContextMenuInfo };\n}\n\n/**\n * The bot's deployed context-menu commands. Filled by {@link CommandInjector} after each deploy, and a read\n * before that throws.\n *\n * @example\n * ```ts\n * import { ContextMenus } from '@seedcord/gateway';\n *\n * const id = ContextMenus.user['View Profile'].id;\n * ```\n */\nexport const ContextMenus = {\n user: guardedAccessor('ContextMenus.user', userMenuStorage),\n message: guardedAccessor('ContextMenus.message', messageMenuStorage)\n} as InjectedContextMenuMap;\n\nconst MULTI_GUILD = Symbol('seedcord:commands:multi-guild');\n\n// Discord scopes name uniqueness per type, and a context-menu name may be all lowercase like a slash name\nfunction commandKey(type: ApplicationCommandType, name: string): string {\n return `${type}:${name}`;\n}\n\nfunction slashBuildersOf(all: readonly CommandBuilder[]): SlashCommandBuilder[] {\n const slash = all.filter((command): command is SlashCommandBuilder => command instanceof SlashCommandBuilder);\n // a guild command in N guilds is the same builder pushed once per guild\n return [...new Set(slash)];\n}\n\ninterface DeployedIds {\n readonly global: Map<string, Snowflake>;\n readonly guild: Map<string, Snowflake | typeof MULTI_GUILD>;\n readonly warned: Set<string>;\n}\n\n/**\n * Records each deployed command on {@link Commands} and {@link ContextMenus}.\n *\n * @internal\n */\nexport class CommandInjector {\n private readonly logger = new Logger('Commands', { channel: 'bot' });\n\n public inject(deploy: DeployResult, all: readonly CommandBuilder[]): void {\n this.clear();\n\n const ids: DeployedIds = {\n global: this.indexByKey(deploy.global),\n guild: this.indexGuilds(deploy.guilds),\n warned: new Set<string>()\n };\n let clickable = 0;\n\n for (const command of slashBuildersOf(all)) {\n const id = this.resolveId(\n ApplicationCommandType.ChatInput,\n command.name,\n ids,\n 'falling back to plain text (not clickable)'\n );\n for (const leaf of routeLeavesOf(command.toJSON())) {\n commandStorage[leaf.route] = {\n mention: id ? this.toMention(leaf.route, id) : this.toPlain(leaf.route),\n ...(id && { id }),\n route: leaf.route,\n description: leaf.description\n };\n if (id) clickable++;\n }\n }\n\n const menus = contextMenuLeaves(all);\n this.injectMenus(menus.user, ApplicationCommandType.User, userMenuStorage, ids);\n this.injectMenus(menus.message, ApplicationCommandType.Message, messageMenuStorage, ids);\n\n this.logger.utils.summary('Linked commands', {\n clickable,\n plain: Object.keys(commandStorage).length - clickable,\n 'context menus': menus.user.size + menus.message.size\n });\n }\n\n private injectMenus(\n names: ReadonlySet<string>,\n kind: ContextMenuKind,\n storage: Record<string, ContextMenuInfo>,\n ids: DeployedIds\n ): void {\n for (const name of names) {\n const id = this.resolveId(kind, name, ids, 'leaving its id unset');\n storage[name] = { ...(id && { id }), name, kind };\n }\n }\n\n private indexByKey(collection: Map<Snowflake, APIApplicationCommand>): Map<string, Snowflake> {\n const map = new Map<string, Snowflake>();\n for (const command of collection.values()) map.set(commandKey(command.type, command.name), command.id);\n return map;\n }\n\n private indexGuilds(\n guilds: Map<Snowflake, Map<Snowflake, APIApplicationCommand>>\n ): Map<string, Snowflake | typeof MULTI_GUILD> {\n const map = new Map<string, Snowflake | typeof MULTI_GUILD>();\n for (const collection of guilds.values()) {\n for (const command of collection.values()) {\n const key = commandKey(command.type, command.name);\n const existing = map.get(key);\n // Discord assigns a separate id per guild, so two ids for one name means no single mention\n if (existing === undefined) map.set(key, command.id);\n else if (existing !== command.id) map.set(key, MULTI_GUILD);\n }\n }\n return map;\n }\n\n private resolveId(\n type: ApplicationCommandType,\n name: string,\n ids: DeployedIds,\n consequence: string\n ): Snowflake | undefined {\n const key = commandKey(type, name);\n const global = ids.global.get(key);\n if (global) return global;\n\n const guild = ids.guild.get(key);\n if (guild === undefined) return undefined;\n if (guild === MULTI_GUILD) {\n if (!ids.warned.has(key)) {\n this.logger.warn(`${paint.sky.bold(name)} is deployed to multiple guilds, ${consequence}.`);\n ids.warned.add(key);\n }\n return undefined;\n }\n return guild;\n }\n\n private toMention(route: string, id: Snowflake): string {\n return `</${route.replaceAll('/', ' ')}:${id}>`;\n }\n\n private toPlain(route: string): string {\n return `/${route.replaceAll('/', ' ')}`;\n }\n\n private clear(): void {\n for (const store of [commandStorage, userMenuStorage, messageMenuStorage]) clearStore(store);\n }\n}\n","import type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * Base class for a user-facing refusal or a reported fault.\n *\n * Throw a `Notice` to stop a handler and reply to the user. The framework catches it at the controller\n * boundary and renders {@link Notice.render}, which always decides what the user sees. With `report`\n * false that render is all that happens. With `report` true the framework also logs the fault and\n * publishes it to the `handledException` bus. A raw, non-Notice throw shows the generic message.\n *\n * @example\n * ```ts\n * import { Notice, BuilderComponent, type RenderContext, type ReplyResponse } from '@seedcord/gateway';\n * import { TextDisplayBuilder } from '@discordjs/builders';\n *\n * // reading `.component` applies the configured bot color to the container accent\n * class TooPoorCard extends BuilderComponent<'container'> {\n * constructor(balance: number) {\n * super('container');\n * this.instance.addTextDisplayComponents(\n * new TextDisplayBuilder().setContent(`### Insufficient balance\\nYou need more than ${balance} coins.`)\n * );\n * }\n * }\n *\n * class TooPoor extends Notice {\n * constructor(private readonly balance: number) {\n * super(`balance ${balance} is below the cost`);\n * }\n *\n * render(_ctx: RenderContext): ReplyResponse {\n * return { components: [new TooPoorCard(this.balance).component] };\n * }\n * }\n *\n * // in a handler, throwing stops the handler and replies with render(ctx)\n * if (wallet.balance < cost) throw new TooPoor(wallet.balance);\n * ```\n */\nexport abstract class Notice extends Error {\n /**\n * Whether this denial is a reported fault. True also logs it and publishes it to the `handledException`\n * bus. The user always sees {@link Notice.render} either way.\n *\n * @defaultValue `false`\n */\n public report = false;\n\n /**\n * Whether the reply is ephemeral, so only the invoking user sees it. Set it false for a refusal the\n * whole channel should see.\n *\n * @defaultValue `true`\n */\n public ephemeral = true;\n\n /**\n * A short one-line reason. When every arm of an `or` gate refuses and each refusal sets this, `or`\n * lists them instead of showing a neutral message.\n */\n public summary?: string;\n\n protected constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n\n // Error sets name to 'Error', so stamp the concrete subclass name for logs and the fault report\n this.name = new.target.name;\n Error.captureStackTrace(this, this.constructor);\n }\n\n /**\n * Builds what the user sees. Called fresh each time the denial is shown, so the builders are new\n * and the bot color resolves at render time rather than at construction time.\n */\n public abstract render(ctx: RenderContext): ReplyResponse;\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '@components/Component';\n\n/**\n * Built fresh inside a {@link Notice}'s `render` to back its ComponentsV2 reply. The title renders as\n * an h3 line with the description on the next line.\n */\nexport class NoticeCard extends BuilderComponent<'container'> {\n public constructor(description: string, title = 'Cannot Proceed') {\n super('container');\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(`### ${title}\\n${description}`));\n }\n}\n","import { 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. The reply tells the user to run the command again.\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 * This should not happen in normal use, so it reports.\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","/* eslint-disable no-magic-numbers -- lots of bigints */\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { InvalidCustomId } from './Errors';\n\nimport type { CustomIdField, CustomIdShape } from './Field';\n\n// wire is routeKey, a colon, then the body. the routeKey is the stable prefix plus a short shape\n// hash, so a shape change produces a new routeKey and decode rejects an old wire as stale. bounded\n// fields (known range) fold into one base64 integer by mixed-radix packing, unbounded ones (free\n// string, unbounded int) trail it as delimited tokens.\n//\n// works on runtime values (unknown), CustomId.ts adds the typed layer.\n\n// url-safe base64, one utf-16 unit per char so encode's wire.length cap counts chars exactly.\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\nconst BASE = 64n;\nconst CHAR_TO_VALUE = new Map([...ALPHABET].map((char, index) => [char, index] as const));\n\nconst DELIMITER = '\\u{1F}';\nconst ESCAPE = '\\u{1B}';\n\n/** @internal */\nexport const HASH_LENGTH = 3;\n\nconst SAFE_MAX = BigInt(Number.MAX_SAFE_INTEGER);\nconst SAFE_MIN = BigInt(Number.MIN_SAFE_INTEGER);\n\n// toString and parseInt top out at base 36, and float64 loses integers past 2^53.\nfunction bigintToBase64(value: bigint): string {\n if (value === 0n) return ALPHABET.charAt(0);\n let text = '';\n for (let remaining = value; remaining > 0n; remaining /= BASE) {\n text = ALPHABET.charAt(Number(remaining % BASE)) + text;\n }\n return text;\n}\n\nfunction base64ToBigint(text: string): bigint {\n let value = 0n;\n for (const char of text) {\n const digit = CHAR_TO_VALUE.get(char);\n if (digit === undefined) throw new InvalidCustomId(`bad character ${JSON.stringify(char)}`);\n value = value * BASE + BigInt(digit);\n }\n return value;\n}\n\n// zigzag keeps a small negative number short on the wire.\nfunction zigzagEncode(value: number): bigint {\n const big = BigInt(value);\n return big >= 0n ? big << 1n : (-big << 1n) - 1n;\n}\nfunction zigzagDecode(encoded: bigint): bigint {\n return (encoded & 1n) === 1n ? -((encoded + 1n) >> 1n) : encoded >> 1n;\n}\n\nfunction escapeToken(text: string): string {\n return text.replaceAll(/[\\x1B\\x1F]/g, (char) => ESCAPE + char);\n}\nfunction unescapeToken(text: string): string {\n let out = '';\n for (let i = 0; i < text.length; i++) {\n if (text.charAt(i) !== ESCAPE) {\n out += text.charAt(i);\n continue;\n }\n const next = text.charAt(i + 1);\n if (next === '') throw new InvalidCustomId('dangling escape at end of token');\n out += next;\n i++;\n }\n return out;\n}\nfunction splitTokens(body: string): string[] {\n const pieces: string[] = [];\n let current = '';\n for (let i = 0; i < body.length; i++) {\n const char = body.charAt(i);\n if (char === ESCAPE) {\n current += char + body.charAt(i + 1);\n i++;\n } else if (char === DELIMITER) {\n pieces.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n pieces.push(current);\n return pieces;\n}\n\n// bounded means the full range is known, so the field can fold into the shared packed integer.\nfunction isBounded(field: CustomIdField<unknown>): boolean {\n if (field.kind === 'int') return field.min !== undefined && field.max !== undefined;\n return field.kind === 'snowflake' || field.kind === 'uuid' || field.kind === 'bool' || field.kind === 'oneOf';\n}\n\n// how many distinct values the field can hold.\nfunction radixOf(field: CustomIdField<unknown>): bigint {\n switch (field.kind) {\n case 'snowflake': {\n return 1n << 64n;\n }\n case 'uuid': {\n return 1n << 128n;\n }\n case 'bool': {\n return 2n;\n }\n case 'oneOf': {\n // oneOf() rejects an empty list at define time, so no choices here means a hand-built\n // corrupt shape.\n if (!field.choices?.length) throw new InvalidCustomId('oneOf field has no choices');\n return BigInt(field.choices.length);\n }\n case 'int': {\n // isBounded only routes a min-and-max int here, so a missing bound means a corrupt shape.\n if (field.min === undefined || field.max === undefined)\n throw new InvalidCustomId('bounded int field is missing a bound');\n // bigint before the math, max - min + 1 in float64 drops the +1 at 2^53.\n return BigInt(field.max) - BigInt(field.min) + 1n;\n }\n default: {\n throw new InvalidCustomId(`field kind ${field.kind} has no radix`);\n }\n }\n}\n\nfunction boundedToBigint(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n const slot = boundedSlot(field, name, value);\n // out of range would carry into the neighbouring field on decode.\n if (slot < 0n || slot >= radixOf(field)) outOfRange(name, value);\n return slot;\n}\n\n// a slot is the value as an integer in [0, radix).\nfunction boundedSlot(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n switch (field.kind) {\n case 'snowflake': {\n // BigInt() throws a bare TypeError or SyntaxError on a bad value, so the guard throws\n // the branded error first.\n if (typeof value !== 'string' || !/^\\d+$/.test(value)) return outOfRange(name, value);\n return BigInt(value);\n }\n case 'uuid': {\n if (typeof value !== 'string') return outOfRange(name, value);\n const hex = value.replaceAll('-', '');\n if (!/^[0-9a-fA-F]{32}$/.test(hex)) return outOfRange(name, value);\n return BigInt(`0x${hex}`);\n }\n case 'bool': {\n return value ? 1n : 0n;\n }\n case 'oneOf': {\n const index = (field.choices ?? []).indexOf(value as string);\n return index === -1 ? outOfRange(name, value) : BigInt(index);\n }\n case 'int': {\n // eslint-disable-next-line unicorn/prefer-number-is-safe-integer -- a bounded int field may declare max up to 2**53 exactly (a power of two, exact in float64)\n if (!Number.isInteger(value)) return outOfRange(name, value);\n return BigInt((value as number) - (field.min ?? 0));\n }\n default: {\n return outOfRange(name, value);\n }\n }\n}\n\nfunction outOfRange(name: string, value: unknown): never {\n throw new SeedcordRangeError(SeedcordErrorCode.CustomIdValueOutOfRange, [name, String(value)]);\n}\n\n// inverse of boundedSlot.\nfunction bigintToBoundedValue(field: CustomIdField<unknown>, slot: bigint): unknown {\n switch (field.kind) {\n case 'snowflake': {\n return slot.toString();\n }\n case 'uuid': {\n return bigintToUuid(slot);\n }\n case 'bool': {\n return slot === 1n;\n }\n case 'oneOf': {\n return (field.choices ?? [])[Number(slot)];\n }\n case 'int': {\n return Number(slot) + (field.min ?? 0);\n }\n default: {\n throw new InvalidCustomId(`field kind ${field.kind} is not bounded`);\n }\n }\n}\n\nfunction bigintToUuid(value: bigint): string {\n const hex = value.toString(16).padStart(32, '0');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nfunction encodeUnboundedToken(field: CustomIdField<unknown>, name: string, value: unknown): string {\n if (field.kind === 'int') {\n if (!Number.isSafeInteger(value)) outOfRange(name, value);\n return bigintToBase64(zigzagEncode(value as number));\n }\n return escapeToken(value as string);\n}\nfunction decodeUnboundedToken(field: CustomIdField<unknown>, piece: string): unknown {\n if (field.kind !== 'int') return unescapeToken(piece);\n // an int always encodes to at least one char, so an empty piece is a truncated wire\n if (piece === '') throw new InvalidCustomId('empty integer token');\n const decoded = zigzagDecode(base64ToBigint(piece));\n // an unbounded int is authored as a js number, so a value past 2^53 cannot come from encode.\n if (decoded > SAFE_MAX || decoded < SAFE_MIN) throw new InvalidCustomId('integer out of safe range');\n return Number(decoded);\n}\n\n/** @internal */\nexport function computeLayoutHash(shape: CustomIdShape): string {\n // stringify escapes the choice strings, so two different shapes cannot produce the same signature.\n const signature = JSON.stringify(\n Object.entries(shape).map(([name, field]) => [\n name,\n field.kind,\n isBounded(field),\n field.kind === 'oneOf' ? (field.choices ?? []) : null,\n field.kind === 'int' ? [field.min ?? null, field.max ?? null] : null\n ])\n );\n const modulus = BASE ** BigInt(HASH_LENGTH);\n let hash = 0n;\n for (const char of signature) hash = (hash * 131n + BigInt(char.charCodeAt(0))) % modulus;\n\n let text = '';\n for (let i = 0; i < HASH_LENGTH; i++) {\n text = ALPHABET.charAt(Number(hash % BASE)) + text;\n hash /= BASE;\n }\n return text;\n}\n\n/** @internal */\nexport function encodeBody(shape: CustomIdShape, values: Record<string, unknown>): string {\n const fields = Object.entries(shape);\n const pieces: string[] = [];\n\n const bounded = fields.filter(([, field]) => isBounded(field));\n if (bounded.length > 0) {\n let packed = 0n;\n for (const [name, field] of bounded)\n packed = packed * radixOf(field) + boundedToBigint(field, name, values[name]);\n pieces.push(bigintToBase64(packed));\n }\n for (const [name, field] of fields) {\n if (!isBounded(field)) pieces.push(encodeUnboundedToken(field, name, values[name]));\n }\n return pieces.join(DELIMITER);\n}\n\nfunction unpackBounded(\n bounded: [string, CustomIdField<unknown>][],\n blob: string | undefined,\n result: Record<string, unknown>\n): void {\n // zero packs to one char, so an empty block means the body was truncated.\n if (blob === undefined || blob === '') throw new InvalidCustomId('empty packed block');\n let packed = base64ToBigint(blob);\n // last field packed is the first one back out.\n for (const [name, field] of [...bounded].reverse()) {\n const radix = radixOf(field);\n result[name] = bigintToBoundedValue(field, packed % radix);\n packed /= radix;\n }\n if (packed !== 0n) throw new InvalidCustomId('leftover bits after unpacking');\n}\n\n/** @internal */\nexport function decodeBody(shape: CustomIdShape, body: string): Record<string, unknown> {\n const fields = Object.entries(shape);\n const bounded = fields.filter(([, field]) => isBounded(field));\n const unbounded = fields.filter(([, field]) => !isBounded(field));\n\n // a shape with no fields encodes to an empty body.\n const expected = (bounded.length > 0 ? 1 : 0) + unbounded.length;\n if (expected === 0) {\n if (body !== '') throw new InvalidCustomId(`expected an empty body, got ${JSON.stringify(body)}`);\n return {};\n }\n\n const pieces = splitTokens(body);\n if (pieces.length !== expected) throw new InvalidCustomId(`expected ${expected} piece(s), got ${pieces.length}`);\n\n const result: Record<string, unknown> = {};\n let cursor = 0;\n\n if (bounded.length > 0) {\n unpackBounded(bounded, pieces[cursor], result);\n cursor++;\n }\n\n for (const [name, field] of unbounded) {\n const piece = pieces[cursor];\n cursor++;\n if (piece === undefined) throw new InvalidCustomId('missing trailing piece');\n result[name] = decodeUnboundedToken(field, piece);\n }\n\n return result;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { computeLayoutHash, decodeBody, encodeBody, HASH_LENGTH } from './codec';\nimport { InvalidCustomId, StaleCustomId } from './Errors';\n\nimport type { CustomIdField, CustomIdShape, DecodedParams } from './Field';\nimport type { Snowflake } from 'discord-api-types/v10';\nimport type { NonEmptyTuple } from 'type-fest';\n\n// discord caps a customId at 100 chars.\nconst MAX_WIRE_LENGTH = 100;\n\nfunction routeKeyOf(wire: string): string {\n const colon = wire.indexOf(':');\n return colon === -1 ? '' : wire.slice(0, colon);\n}\n\n/** Strip the layout hash off the routeKey to recover the stable prefix the controller routes by. @internal */\nexport function prefixOf(wire: string): string {\n const key = routeKeyOf(wire);\n return key.length <= HASH_LENGTH ? '' : key.slice(0, key.length - HASH_LENGTH);\n}\n\n/**\n * A typed customId. The single source of truth shared by the component that mints it and the handler\n * that reads it. This gives you typed reads on the `.customId` field in components. Values are packed into a compact wire string rather than plain stringified tokens, so the 100-char Discord limit goes further. More string per string, basically.\n *\n * @typeParam Prefix - The stable route prefix, e.g. 'approve'.\n * @typeParam Shape - The accumulated fields, filled in by the chain.\n *\n * @example\n * ```ts\n * const ApproveId = new CustomId('approve')\n * .snowflake('userId')\n * .oneOf('action', ['approve', 'deny']);\n *\n * // Set the custom id on a button when creating it.\n * new ButtonBuilder().setCustomId(ApproveId.encode({ userId: '123', action: 'approve' }));\n *\n * // reading in the handler: userId comes back a string\n * const { userId, action } = this.params; // userId: string, action: 'approve' | 'deny'\n * await this.event.guild?.members.fetch(userId);\n * ```\n */\nexport class CustomId<Prefix extends string, Shape extends CustomIdShape = {}> {\n /** The stable route prefix, e.g. 'approve'. */\n readonly prefix: Prefix;\n /** Like a zod shape */\n readonly shape: Shape;\n /** The prefix plus a short hash of the shape, the part of the wire before the colon. */\n readonly routeKey: string;\n\n constructor(prefix: Prefix, shape: Shape = {} as Shape) {\n // an empty prefix would make the routeKey all-hash so prefixOf strips it to nothing and the\n // controller cannot route it, and a colon or control char would break the wire framing.\n if (!prefix || /[:\\x1B\\x1F]/.test(prefix)) {\n throw new SeedcordError(SeedcordErrorCode.CustomIdInvalidPrefix, [prefix]);\n }\n this.prefix = prefix;\n this.shape = shape;\n this.routeKey = prefix + computeLayoutHash(shape);\n }\n\n // a fresh immutable CustomId with one more field so we don't need a `as unknown as this` cast.\n private add<Name extends string, Decoded>(\n name: Name,\n field: CustomIdField<Decoded>\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<Decoded>>> {\n // integer-like keys get reordered by js, which would scramble the field order.\n if (/^(?:0|[1-9]\\d*)$/.test(name)) throw new SeedcordError(SeedcordErrorCode.CustomIdReservedFieldName, [name]);\n // a repeat name collapses the field's decoded type to never and overwrites the earlier field\n // at runtime, so reject it here at define time.\n if (name in this.shape) throw new SeedcordError(SeedcordErrorCode.CustomIdDuplicateFieldName, [name]);\n // justified, the spread plus a computed key cannot be proven to the exact intersection\n const shape = { ...this.shape, [name]: field } as Shape & Record<Name, CustomIdField<Decoded>>;\n return new CustomId(this.prefix, shape);\n }\n\n /**\n * Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).\n *\n * @example\n * ```ts\n * new CustomId('ban').snowflake('userId');\n * ```\n */\n snowflake<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<Snowflake>>> {\n return this.add<Name, Snowflake>(name, { kind: 'snowflake' });\n }\n\n /**\n * Add a UUID field, decoded as a lowercase uuid string.\n *\n * @example\n * ```ts\n * new CustomId('ticket').uuid('ticketId');\n * ```\n */\n uuid<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>> {\n return this.add<Name, string>(name, { kind: 'uuid' });\n }\n\n /**\n * Add an integer field with no bounds, for a value up to 2^53.\n *\n * @example\n * ```ts\n * new CustomId('shop').int('amount');\n * ```\n */\n int<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;\n /**\n * Add an integer field bounded by min and max, so it packs into fewer characters on the wire.\n *\n * @example\n * ```ts\n * new CustomId('paginate').int('page', 1, 50);\n * ```\n */\n int<Name extends string>(\n name: Name,\n min: number,\n max: number\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;\n int<Name extends string>(\n name: Name,\n min?: number,\n max?: number\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>> {\n if (min !== undefined && max !== undefined && min > max) {\n throw new SeedcordError(SeedcordErrorCode.CustomIdInvalidBounds, [name, min, max]);\n }\n const field: CustomIdField<number> =\n min === undefined || max === undefined ? { kind: 'int' } : { kind: 'int', min, max };\n return this.add<Name, number>(name, field);\n }\n\n /**\n * Add a boolean flag.\n *\n * @example\n * ```ts\n * new CustomId('settings').bool('silent');\n * ```\n */\n bool<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<boolean>>> {\n return this.add<Name, boolean>(name, { kind: 'bool' });\n }\n\n /**\n * Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.\n *\n * @example\n * ```ts\n * new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);\n * ```\n */\n oneOf<Name extends string, const Choices extends NonEmptyTuple<string>>(\n name: Name,\n choices: Choices\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<Choices[number]>>> {\n if (choices.length === 0) throw new SeedcordError(SeedcordErrorCode.CustomIdEmptyChoices, [name]);\n return this.add<Name, Choices[number]>(name, { kind: 'oneOf', choices });\n }\n\n /**\n * Add a free short text field. Avoid it where possible, it cannot be packed so it costs the most wire space.\n *\n * @example\n * ```ts\n * new CustomId('note').str('message');\n * ```\n */\n str<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>> {\n return this.add<Name, string>(name, { kind: 'string' });\n }\n\n /**\n * Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.\n *\n * @param values - One value per field, typed by the chain.\n * @returns The wire string to put on the component's customId.\n */\n encode(values: DecodedParams<Shape>): string {\n const wire = `${this.routeKey}:${encodeBody(this.shape, values)}`;\n if (wire.length > MAX_WIRE_LENGTH) {\n throw new SeedcordRangeError(SeedcordErrorCode.CustomIdWireTooLong, [wire.length]);\n }\n return wire;\n }\n\n /**\n * Read a wire string back into values.\n *\n * - This will refuse with a default Notice when the shape changed since the wire was minted.\n * - Or refuse with a different default Notice on a corrupt or foreign wire.\n *\n * @param wire - The customId string from the interaction.\n * @returns The decoded values, typed by the chain.\n */\n decode(wire: string): DecodedParams<Shape> {\n const key = routeKeyOf(wire);\n if (key !== this.routeKey) {\n // same prefix but a different hash means the shape changed since this wire was minted.\n if (prefixOf(wire) === this.prefix) throw new StaleCustomId(this.prefix);\n throw new InvalidCustomId(`routeKey ${JSON.stringify(key)} is not ${JSON.stringify(this.routeKey)}`);\n }\n // justified, the codec returns runtime values and the shape guarantees their decoded types.\n return decodeBody(this.shape, wire.slice(key.length + 1)) as DecodedParams<Shape>;\n }\n\n /** True if this wire was minted from this customId's prefix, ignoring the shape hash. */\n owns(wire: string): boolean {\n return prefixOf(wire) === this.prefix;\n }\n}\n\n/**\n * Any customId, for places where the exact prefix and shape do not matter.\n *\n * @internal\n */\nexport type AnyCustomId = CustomId<string, CustomIdShape>;\n\n/**\n * The outcome of decoding a wire against several customIds, the matched prefix paired with its values.\n *\n * @internal\n */\nexport type DecodedRoute<Defs extends readonly AnyCustomId[]> = {\n [Index in keyof Defs]: Defs[Index] extends AnyCustomId\n ? { readonly prefix: Defs[Index]['prefix']; readonly params: DecodedParams<Defs[Index]['shape']> }\n : never;\n}[number];\n\n/**\n * Find the customId whose prefix owns this wire, decode against it, and report which one matched.\n *\n * @internal\n */\nexport function decodeFor<Defs extends readonly AnyCustomId[]>(defs: Defs, wire: string): DecodedRoute<Defs> {\n const match = defs.find((def) => def.owns(wire));\n if (!match) throw new InvalidCustomId(`no customId owns ${JSON.stringify(routeKeyOf(wire))}`);\n // justified, the matched customId fixes both prefix and params together but find() loses that link.\n return { prefix: match.prefix, params: match.decode(wire) } as DecodedRoute<Defs>;\n}\n","import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { decodeFor } from './CustomId';\n\nimport type { AnyCustomId } from './CustomId';\nimport type { DecodedParams } from './Field';\nimport type { Promisable } from 'type-fest';\n\n/**\n * The route decorators store a handler's customId definitions here so the component base can decode\n * against them at runtime.\n *\n * @internal\n */\nexport const ComponentDefsKey = Symbol('seedcord:customId:componentDefs');\n\n/**\n * The phantom a component handler base carries. A route decorator constrains its argument to this, so\n * passing different definitions to the decorator and the handler's generic is a compile error. Never set at runtime.\n *\n * @internal\n */\nexport interface HasComponentDefs<Defs extends readonly AnyCustomId[]> {\n /** @internal */\n readonly __componentDefs?: Defs;\n}\n\n/** @internal */\nexport interface DecodedComponentRoute {\n prefix: string;\n params: Record<string, unknown>;\n}\n\n/**\n * Throws `CustomIdHandlerRouteMissing` when the class has no stored defs. A drifted or corrupt wire\n * throws `StaleCustomId` or `InvalidCustomId`.\n *\n * @internal\n */\nexport function decodeComponentRoute(handlerClass: { name: string }, wire: string): DecodedComponentRoute {\n const defs = Reflect.getMetadata(ComponentDefsKey, handlerClass) as readonly AnyCustomId[] | undefined;\n if (!defs) throw new SeedcordError(SeedcordErrorCode.CustomIdHandlerRouteMissing, [handlerClass.name]);\n return decodeFor(defs, wire);\n}\n\n/** @internal */\nexport type SingleParams<Defs extends readonly AnyCustomId[]> = Defs extends readonly [infer One extends AnyCustomId]\n ? DecodedParams<One['shape']>\n : never;\n\n/** @internal */\nexport type MatchArms<Defs extends readonly AnyCustomId[], Ret> = {\n [Def in Defs[number] as Def['prefix']]: (params: DecodedParams<Def['shape']>) => Promisable<Ret>;\n};\n","import 'reflect-metadata';\n\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { ComponentDefsKey } from '@customId/routing';\nimport { InteractionMetadataKey, InteractionRouteKeys, InteractionRoutes } from '@src/metadataKeys';\n\nimport type { AnyCustomId } from '@customId/CustomId';\nimport type { ContextMenuKind } from '@registries/ContextMenuRegistry';\n\n/** The select menu kinds the select route decorators take. */\nexport enum SelectMenuKind {\n String = 'string',\n User = 'user',\n Role = 'role',\n Channel = 'channel',\n Mentionable = 'mentionable'\n}\n\n// loose on purpose, each transport's typed decorators pass their asserted ctors straight in\nexport type RoutableConstructor = new (...args: never[]) => unknown;\n\nexport function areRoutes(routes: unknown): routes is string[] {\n return Array.isArray(routes) && routes.every((route) => typeof route === 'string');\n}\n\n/**\n * Every stored route kind and its route strings on a decorated constructor. The build's manifest\n * emitter reads the same pairs.\n */\nexport function interactionRoutesOf(constructor: RoutableConstructor): [InteractionRoutes, string[]][] {\n const pairs: [InteractionRoutes, string[]][] = [];\n for (const route of Object.values(InteractionRoutes)) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[route], constructor);\n if (areRoutes(meta)) pairs.push([route, meta]);\n }\n return pairs;\n}\n\nexport function storeInteractionRoute(\n route: InteractionRoutes,\n routes: string | readonly string[],\n constructor: RoutableConstructor\n): void {\n const key = InteractionRouteKeys[route];\n const saved: unknown = Reflect.getMetadata(key, constructor);\n const existing = areRoutes(saved) ? saved : [];\n const toStore = typeof routes === 'string' ? [routes] : routes;\n Reflect.defineMetadata(key, [...existing, ...toStore], constructor);\n Reflect.defineMetadata(InteractionMetadataKey, true, constructor);\n}\n\n// each definition's stable prefix is the routing key, the full defs stay on the ctor for decoding\nexport function storeComponentRoute(\n route: InteractionRoutes,\n defs: readonly AnyCustomId[],\n constructor: RoutableConstructor\n): void {\n storeInteractionRoute(\n route,\n defs.map((def) => def.prefix),\n constructor\n );\n Reflect.defineMetadata(ComponentDefsKey, defs, constructor);\n}\n\nconst SELECT_ROUTES: Record<SelectMenuKind, InteractionRoutes> = {\n [SelectMenuKind.String]: InteractionRoutes.StringMenu,\n [SelectMenuKind.User]: InteractionRoutes.UserMenu,\n [SelectMenuKind.Role]: InteractionRoutes.RoleMenu,\n [SelectMenuKind.Channel]: InteractionRoutes.ChannelMenu,\n [SelectMenuKind.Mentionable]: InteractionRoutes.MentionableMenu\n};\n\nexport function selectMenuRouteOf(kind: SelectMenuKind): InteractionRoutes {\n return SELECT_ROUTES[kind];\n}\n\nexport function contextMenuRouteOf(kind: ContextMenuKind): InteractionRoutes {\n return kind === ApplicationCommandType.User\n ? InteractionRoutes.UserContextMenu\n : InteractionRoutes.MessageContextMenu;\n}\n","import type { CoreBase } from '@interfaces/CoreBase';\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 arm. 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, on a gateway event the member's guild-level ones.\n */\n readonly memberPermissions: bigint | null;\n /**\n * The bot's permissions in the invoked channel, the wire `app_permissions` value. Null on gateway events.\n */\n readonly appPermissions: bigint | null;\n /**\n * The dispatched handler as `kind:route` (`slash:daily`, `button:confirm`), or null off a route (a\n * plain event handler, or a gate run outside a handler). `runHandlerGates` sets it from the handler's\n * metadata. `Cooldown` uses it so its window is stable across restarts and isolates.\n */\n readonly routeId: string | null;\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. Null when the cached member is unavailable.\n */\n readonly appGuildPermissions: bigint | null;\n}\n\n// phantom brand, so a bare check function or a plain object is rejected 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, so reading a field absent on a handler's context is a compile error.\n * @typeParam Name - The gate's name captured as a literal, so a mismatch error can name the gate.\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 that carries a side effect, split so the effect fires only once the gate is the one that\n * let the request through. `check` peeks and refuses, `commit` applies the effect after the whole\n * gate set passes. {@link Cooldown} is the catalog gate that returns one. Build one with\n * {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context the gate requires, so reading a field absent on a handler's context is a compile error.\n * @typeParam Name - The gate's name captured as a literal, so a mismatch error can name the gate.\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, so a mismatch error can name the gate.\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 `seedcord`\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) => void | Promise<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`, a refusing arm's queued commit is rolled back. This is how {@link Cooldown} peeks\n * in `check` and charges the slot in `commit`.\n *\n * @typeParam Name - The gate's name captured as a literal, so a mismatch error can name the gate.\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 `seedcord`\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) => void | Promise<void>,\n commit: (ctx: Ctx) => void | Promise<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 { toEpochSeconds } from '@seedcord/utils';\n\nimport { Notice } from '@stops/Notice';\nimport { NoticeCard } from '@stops/NoticeCard';\n\nimport type { EpochMs, ReplyResponse } from '@seedcord/types';\n\nexport abstract class GateNotice extends Notice {\n public render(): ReplyResponse {\n return { components: [new NoticeCard(this.message).component] };\n }\n}\n\nexport class NotOwner extends GateNotice {\n public constructor(message = 'Only the bot owner can use this.') {\n super(message);\n }\n}\n\nexport class NotInGuild extends GateNotice {\n public constructor(message = 'This can only be used in a server.') {\n super(message);\n }\n}\n\nexport class NotInDm extends GateNotice {\n public constructor(message = 'This can only be used in a direct message.') {\n super(message);\n }\n}\n\nexport class OnCooldown extends GateNotice {\n public constructor(\n public readonly resetAt: EpochMs,\n message?: string\n ) {\n super(message ?? `You are doing that too fast. Try again <t:${toEpochSeconds(resetAt)}:R>.`);\n }\n}\n\nexport class NotAllowed extends Notice {\n public constructor() {\n super('not allowed');\n }\n\n public render(): ReplyResponse {\n return { components: [new NoticeCard('You are not allowed to use this command.').component] };\n }\n}\n\nexport class NeedsAny extends Notice {\n public constructor(private readonly summaries: readonly string[]) {\n super('not allowed');\n }\n\n public render(): ReplyResponse {\n const bullets = this.summaries.map((summary) => `• ${summary}`).join('\\n');\n return { components: [new NoticeCard(`You need any of:\\n${bullets}`).component] };\n }\n}\n\nexport class MissingRole extends GateNotice {\n public constructor(message: string | undefined, roleId: string | null) {\n super(\n message ?? (roleId ? `You need the <@&${roleId}> role to use this.` : 'You do not have the required role.')\n );\n }\n}\n\nexport class MissingPermissions extends Notice {\n private readonly customLead: string | undefined;\n\n public constructor(\n message: string | undefined,\n private readonly subject: string | null,\n private readonly missingPerms: readonly string[]\n ) {\n super(message ?? 'A required permission is missing.');\n this.customLead = message;\n }\n\n public render(): ReplyResponse {\n const bullets = this.missingPerms.map((perm) => `• ${perm}`).join('\\n');\n const lead =\n this.customLead ??\n `${this.subject === null ? 'You are' : `${this.subject} is`} missing the following permission entries:`;\n return {\n components: [new NoticeCard(`${lead}\\n\\n${bullets}`).component]\n };\n }\n}\n\nexport class HasDangerousPermissions extends Notice {\n private readonly customLead: string | undefined;\n\n public constructor(\n message: string | undefined,\n public subject: string,\n public dangerousPerms: readonly string[]\n ) {\n super(message ?? 'A dangerous permission is enabled.');\n this.customLead = message;\n }\n\n public render(): ReplyResponse {\n const bullets = this.dangerousPerms.map((perm) => `• ${perm}`).join('\\n');\n const lead =\n this.customLead ?? `${this.subject} has the following permission entries that must not be enabled:`;\n return { components: [new NoticeCard(`${lead}\\n\\n${bullets}`).component] };\n }\n}\n","import type { EffectGate, Gate, GateContextBase } from './Gate';\n\ntype CommitFn = () => Promise<void>;\n\n// per-request commit queue keyed on the context, so an effect gate's commit runs only after the whole\n// set passes. WeakMap so each entry is dropped once its request's context is gone\nconst commitQueues = new WeakMap<GateContextBase, CommitFn[]>();\n\nfunction isEffectGate(gate: Gate<GateContextBase>): gate is EffectGate<GateContextBase> {\n return typeof (gate as Partial<EffectGate<GateContextBase>>).commit === 'function';\n}\n\n// a refusal throws before the queue, so a refused effect gate never commits. the combinators and the\n// runner both route through here, so an effect gate inside `and`/`or` queues the same way\nexport async function runCheck(gate: Gate<GateContextBase>, ctx: GateContextBase): Promise<void> {\n await gate.check(ctx);\n if (!isEffectGate(gate)) return;\n\n let queue = commitQueues.get(ctx);\n if (!queue) {\n queue = [];\n commitQueues.set(ctx, queue);\n }\n queue.push(() => gate.commit(ctx));\n}\n\nexport async function runCommits(ctx: GateContextBase): Promise<void> {\n const queue = commitQueues.get(ctx);\n if (!queue) return;\n for (const commit of queue) await commit();\n}\n\n// the runner calls this after every run, so a refused or drained run leaves no stale queue behind\nexport function discardCommits(ctx: GateContextBase): void {\n commitQueues.delete(ctx);\n}\n\n// the queued-commit count, the mark an `or` arm rolls back to if it refuses\nexport function markCommits(ctx: GateContextBase): number {\n return commitQueues.get(ctx)?.length ?? 0;\n}\n\n// drops commits queued after `mark`, so a refused `or` arm leaves no commit behind\nexport function rollbackCommits(ctx: GateContextBase, mark: number): void {\n const queue = commitQueues.get(ctx);\n if (queue && queue.length > mark) queue.length = mark;\n}\n","import type { Notice } from '@stops/Notice';\n\n/**\n * The override a catalog gate accepts. A one-line `message` reword or a full `notice` replacement. Accepted by\n * the agnostic catalog gates and, nested per refusal, by {@link RequireRole}. {@link RequirePermissions} and\n * {@link RequireBotPermissions} take `RequirePermissionsOptions` instead.\n *\n * @example\n * ```ts\n * // reword the default refusal\n * OwnerOnly({ message: 'Bot owners only.' });\n * ```\n *\n * @example\n * ```ts\n * // replace the refusal entirely, for example a translated Notice\n * GuildOnly({ notice: new MyTranslatedNotice() });\n * ```\n */\nexport interface GateNoticeOptions {\n /** Reword the default refusal, keeping its embed styling. */\n message?: string;\n /** Replace the default refusal Notice entirely, for full control or a translated copy. */\n notice?: Notice;\n}\n\nexport function pickNotice(options: GateNoticeOptions | undefined, makeDefault: (message?: string) => Notice): Notice {\n return options?.notice ?? makeDefault(options?.message);\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\n/** Permission bit to its prettified human-readable name. */\nexport const 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\n/** @internal */\nexport function hasAll(held: bigint, scope: PermissionScope): boolean {\n return scope.every((bit) => holds(held, bit));\n}\n\n/** @internal only reached once hasAll failed, so the administrator bit is absent */\nexport function missingNames(held: bigint, scope: PermissionScope): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if ((held & bit) !== bit) names.push(nameOf(bit));\n return names;\n }, []);\n}\n\n/** @internal */\nexport function presentNames(held: bigint, scope: PermissionScope): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if (holds(held, bit)) names.push(nameOf(bit));\n return names;\n }, []);\n}\n","import { defineGate } from '@gates/Gate';\nimport { MissingPermissions, MissingRole, NotInGuild } from '@notices/index';\nimport { hasAll, missingNames } from '@src/permissions/bits';\n\nimport { pickNotice } from './options';\n\nimport type { GateNoticeOptions } from './options';\nimport type { Gate, GateContextBase, GuildPermissionsContext } from '@gates/Gate';\nimport type { PermissionScope } from '@src/permissions/bits';\n\nexport type { PermissionScope } from '@src/permissions/bits';\nexport { PermissionNames } from '@src/permissions/bits';\n\ninterface PermCheckKind {\n unresolved: string;\n subject: string | null;\n}\n\nconst MEMBER_CHECK: PermCheckKind = {\n unresolved: 'Your server member data could not be resolved. Try again.',\n subject: null\n};\nconst BOT_CHECK: PermCheckKind = {\n unresolved: \"The bot's permissions could not be resolved. Try again.\",\n subject: 'The bot'\n};\n\nfunction refusePermissions(\n held: bigint | null,\n scope: PermissionScope,\n options: RequirePermissionsOptions | undefined,\n guildId: string | null,\n kind: PermCheckKind\n): void {\n if (held === null) {\n throw pickNotice(\n options?.notInGuild,\n (message) => new NotInGuild(message ?? (guildId ? kind.unresolved : undefined))\n );\n }\n if (hasAll(held, scope)) return;\n throw pickNotice(\n options?.missing,\n (message) => new MissingPermissions(message, kind.subject, missingNames(held, scope))\n );\n}\n\n/**\n * Options for {@link RequirePermissions} and {@link RequireBotPermissions}.\n */\nexport interface RequirePermissionsOptions {\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 /** Reword or replace the refusal shown when the set is unavailable (outside a guild, or unresolved inside one). */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when a permission is missing. */\n missing?: GateNoticeOptions;\n}\n\n/**\n * Options for {@link RequireRole}.\n */\nexport interface RequireRoleOptions {\n /** Reword or replace the refusal shown outside a guild. */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when the caller lacks the role. */\n missingRole?: GateNoticeOptions;\n}\n\n/**\n * Requires the caller to hold every permission in `scope`. 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 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`, and override each refusal with `notInGuild` or `missing`.\n *\n * @see the `@Gated` decorator from `seedcord`\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 if (options?.in === 'guild') {\n return defineGate('RequirePermissions', (ctx: GuildPermissionsContext) => {\n refusePermissions(ctx.memberGuildPermissions, scope, options, ctx.guildId, MEMBER_CHECK);\n });\n }\n return defineGate('RequirePermissions', (ctx: GateContextBase) => {\n refusePermissions(ctx.memberPermissions, scope, options, ctx.guildId, MEMBER_CHECK);\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}, so it fits a gateway handler only. `app_permissions` is\n * absent on gateway events, the channel scope refuses there as unresolved, use `in: 'guild'` on an\n * event handler.\n *\n * @param scope - The permission flag bits the bot must all hold.\n * @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.\n *\n * @see the `@Gated` decorator from `seedcord`\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: RequirePermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions & { in?: 'channel' }\n): Gate<GateContextBase, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'> | Gate<GateContextBase, 'RequireBotPermissions'> {\n if (options?.in === 'guild') {\n return defineGate('RequireBotPermissions', (ctx: GuildPermissionsContext) => {\n refusePermissions(ctx.appGuildPermissions, scope, options, ctx.guildId, BOT_CHECK);\n });\n }\n return defineGate('RequireBotPermissions', (ctx: GateContextBase) => {\n refusePermissions(ctx.appPermissions, scope, options, ctx.guildId, BOT_CHECK);\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 - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.\n *\n * @see the `@Gated` decorator from `seedcord`\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 pickNotice(options?.notInGuild, (message) => new NotInGuild(message));\n if (ctx.memberRoleIds.includes(roleId)) return;\n throw pickNotice(options?.missingRole, (message) => new MissingRole(message, roleId));\n });\n}\n","/**\n * Throw to stop a handler with no reply and no report.\n *\n * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.\n * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to\n * leave the user with no reply for an interaction.\n *\n * @example\n * ```ts\n * import { Silence } from '@seedcord/gateway';\n *\n * // before any reply or defer, drop the interaction with no reply and no report\n * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');\n * ```\n */\nexport class Silence extends Error {\n /**\n * @param reason - Optional note written only to a debug log, never shown to the user or reported.\n */\n public constructor(public readonly reason?: string) {\n super(reason ?? 'Silence');\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n","import { CustomId } from '@customId/CustomId';\n\nimport type { CustomIdField } from '@customId/Field';\n\n// Included in the layout hash so it is fixed per prefix. Reducing it marks every active button as StaleCustomId.\n// @internal\nexport const PAGE_MAX = 1_000_000;\n\n// Discord rejects a message with duplicate custom_ids, and two controls can target the same page (first and\n// prev both hit 0), so each control uses a distinct slot.\n// @internal\nconst SLOT_MAX = 4;\n\n/** Page cursor for a paginator. */\nexport type PageCursor<Prefix extends string> = CustomId<\n Prefix,\n { page: CustomIdField<number>; slot: CustomIdField<number> }\n>;\n\n/** Build the page cursor for a paginator. */\nexport function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix> {\n return new CustomId(prefix).int('page', 0, PAGE_MAX).int('slot', 0, SLOT_MAX);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cursor-Y6ct-N_8.mjs","names":[],"sources":["../src/miscellaneous/guarded.ts","../src/commands/CommandInjector.ts","../src/stops/Notice.ts","../src/stops/NoticeCard.ts","../src/customId/Errors.ts","../src/customId/codec.ts","../src/customId/CustomId.ts","../src/customId/routing.ts","../src/decorators/interactionRoutes.ts","../src/gates/Gate.ts","../src/notices/index.ts","../src/gates/effects.ts","../src/gates/catalog/options.ts","../src/permissions/bits.ts","../src/gates/catalog/permissions.ts","../src/stops/Silence.ts","../src/pagination/cursor.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n/**\n * A backing record for a generated accessor. Null-prototype, on a plain object a key named `__proto__` sets\n * the store's prototype and adds no entry.\n *\n * @internal\n */\nexport function accessorStore<Value>(): Record<string, Value> {\n return Object.create(null) as Record<string, Value>;\n}\n\n/** Empties a store in place, keeping the reference the accessor's Proxy wraps. @internal */\nexport function clearStore(store: Record<string, unknown>): void {\n for (const key of Object.keys(store)) Reflect.deleteProperty(store, key);\n}\n\n/**\n * Wraps a generated accessor's backing record so a read of an absent key throws. Handler modules import before\n * startup fills the record, and an unguarded read there returns `undefined` and renders as an empty string.\n *\n * @internal\n */\nexport function guardedAccessor<Value>(accessor: string, storage: Record<string, Value>): Record<string, Value> {\n return new Proxy(storage, {\n get(target, key, receiver): unknown {\n // hasOwn, since `in` walks the prototype and would read a key like `constructor` as resolved\n if (typeof key !== 'string' || Object.hasOwn(target, key)) return Reflect.get(target, key, receiver);\n throw new SeedcordError(SeedcordErrorCode.CoreAccessorUnresolved, [accessor, key]);\n }\n });\n}\n","import { SlashCommandBuilder } from '@discordjs/builders';\nimport { Logger, paint } from '@seedcord/logger';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { contextMenuLeaves } from '@src/commands/contextMenuLeaves';\nimport { accessorStore, clearStore, guardedAccessor } from '@src/miscellaneous/guarded';\n\nimport type {\n ContextMenuKind,\n MessageContextMenuRegistry,\n UserContextMenuRegistry\n} from '@registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '@registries/SlashOptionRegistry';\nimport type { CommandBuilder, DeployResult } from '@src/commands/types';\nimport type { APIApplicationCommand, Snowflake } from 'discord-api-types/v10';\n\nconst commandStorage = accessorStore<CommandInfo>();\nconst userMenuStorage = accessorStore<ContextMenuInfo>();\nconst messageMenuStorage = accessorStore<ContextMenuInfo>();\n\n/** What {@link Commands} resolves to for one slash route. */\nexport interface CommandInfo {\n /** The clickable `</config set:id>` mention. A route whose id did not resolve falls back to `/config set`. */\n readonly mention: string;\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The full route, e.g. `config/set`. */\n readonly route: string;\n /** The route's own description, taken from the subcommand for a nested route. */\n readonly description: string;\n}\n\n/** Each registered slash route mapped to its deployed command. */\nexport type InjectedCommandMap = {\n [K in keyof SlashOptionRegistry]: CommandInfo;\n};\n\n/**\n * The bot's deployed slash commands, keyed by {@link SlashOptionRegistry}. Filled by\n * {@link CommandInjector} after each deploy, and a read before that throws.\n *\n * @example\n * ```ts\n * import { Commands } from '@seedcord/gateway';\n *\n * await this.reply(`Try ${Commands['config/set'].mention}`);\n *\n * // a help listing\n * const lines = Object.values(Commands).map((c) => `${c.mention} ${c.description}`);\n * ```\n */\nexport const Commands = guardedAccessor('Commands', commandStorage) as InjectedCommandMap;\n\n/** What {@link ContextMenus} resolves to for one context-menu command. */\nexport interface ContextMenuInfo {\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The name shown in Discord's right-click menu. */\n readonly name: string;\n readonly kind: ContextMenuKind;\n}\n\n/** Deployed context-menu commands, split by kind because Discord scopes name uniqueness per command type. */\nexport interface InjectedContextMenuMap {\n readonly user: { [K in keyof UserContextMenuRegistry]: ContextMenuInfo };\n readonly message: { [K in keyof MessageContextMenuRegistry]: ContextMenuInfo };\n}\n\n/**\n * The bot's deployed context-menu commands. Filled by {@link CommandInjector} after each deploy, and a read\n * before that throws.\n *\n * @example\n * ```ts\n * import { ContextMenus } from '@seedcord/gateway';\n *\n * const id = ContextMenus.user['View Profile'].id;\n * ```\n */\nexport const ContextMenus = {\n user: guardedAccessor('ContextMenus.user', userMenuStorage),\n message: guardedAccessor('ContextMenus.message', messageMenuStorage)\n} as InjectedContextMenuMap;\n\nconst MULTI_GUILD = Symbol('seedcord:commands:multi-guild');\n\n// Discord scopes name uniqueness per type, and a context-menu name may be all lowercase like a slash name\nfunction commandKey(type: ApplicationCommandType, name: string): string {\n return `${type}:${name}`;\n}\n\nfunction slashBuildersOf(all: readonly CommandBuilder[]): SlashCommandBuilder[] {\n const slash = all.filter((command): command is SlashCommandBuilder => command instanceof SlashCommandBuilder);\n // a guild command in N guilds is the same builder pushed once per guild\n return [...new Set(slash)];\n}\n\ninterface DeployedIds {\n readonly global: Map<string, Snowflake>;\n readonly guild: Map<string, Snowflake | typeof MULTI_GUILD>;\n readonly warned: Set<string>;\n}\n\n/**\n * Records each deployed command on {@link Commands} and {@link ContextMenus}.\n *\n * @internal\n */\nexport class CommandInjector {\n private readonly logger = new Logger('Commands', { channel: 'bot' });\n\n public inject(deploy: DeployResult, all: readonly CommandBuilder[]): void {\n this.clear();\n\n const ids: DeployedIds = {\n global: this.indexByKey(deploy.global),\n guild: this.indexGuilds(deploy.guilds),\n warned: new Set<string>()\n };\n let clickable = 0;\n\n for (const command of slashBuildersOf(all)) {\n const id = this.resolveId(\n ApplicationCommandType.ChatInput,\n command.name,\n ids,\n 'falling back to plain text (not clickable)'\n );\n for (const leaf of routeLeavesOf(command.toJSON())) {\n commandStorage[leaf.route] = {\n mention: id ? this.toMention(leaf.route, id) : this.toPlain(leaf.route),\n ...(id && { id }),\n route: leaf.route,\n description: leaf.description\n };\n if (id) clickable++;\n }\n }\n\n const menus = contextMenuLeaves(all);\n this.injectMenus(menus.user, ApplicationCommandType.User, userMenuStorage, ids);\n this.injectMenus(menus.message, ApplicationCommandType.Message, messageMenuStorage, ids);\n\n this.logger.utils.summary('Linked commands', {\n clickable,\n plain: Object.keys(commandStorage).length - clickable,\n 'context menus': menus.user.size + menus.message.size\n });\n }\n\n private injectMenus(\n names: ReadonlySet<string>,\n kind: ContextMenuKind,\n storage: Record<string, ContextMenuInfo>,\n ids: DeployedIds\n ): void {\n for (const name of names) {\n const id = this.resolveId(kind, name, ids, 'leaving its id unset');\n storage[name] = { ...(id && { id }), name, kind };\n }\n }\n\n private indexByKey(collection: Map<Snowflake, APIApplicationCommand>): Map<string, Snowflake> {\n const map = new Map<string, Snowflake>();\n for (const command of collection.values()) map.set(commandKey(command.type, command.name), command.id);\n return map;\n }\n\n private indexGuilds(\n guilds: Map<Snowflake, Map<Snowflake, APIApplicationCommand>>\n ): Map<string, Snowflake | typeof MULTI_GUILD> {\n const map = new Map<string, Snowflake | typeof MULTI_GUILD>();\n for (const collection of guilds.values()) {\n for (const command of collection.values()) {\n const key = commandKey(command.type, command.name);\n const existing = map.get(key);\n // Discord assigns a separate id per guild, so two ids for one name means no single mention\n if (existing === undefined) map.set(key, command.id);\n else if (existing !== command.id) map.set(key, MULTI_GUILD);\n }\n }\n return map;\n }\n\n private resolveId(\n type: ApplicationCommandType,\n name: string,\n ids: DeployedIds,\n consequence: string\n ): Snowflake | undefined {\n const key = commandKey(type, name);\n const global = ids.global.get(key);\n if (global) return global;\n\n const guild = ids.guild.get(key);\n if (guild === undefined) return undefined;\n if (guild === MULTI_GUILD) {\n if (!ids.warned.has(key)) {\n this.logger.warn(`${paint.sky.bold(name)} is deployed to multiple guilds, ${consequence}.`);\n ids.warned.add(key);\n }\n return undefined;\n }\n return guild;\n }\n\n private toMention(route: string, id: Snowflake): string {\n return `</${route.replaceAll('/', ' ')}:${id}>`;\n }\n\n private toPlain(route: string): string {\n return `/${route.replaceAll('/', ' ')}`;\n }\n\n private clear(): void {\n for (const store of [commandStorage, userMenuStorage, messageMenuStorage]) clearStore(store);\n }\n}\n","import type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * Base class for a user-facing refusal or a reported fault.\n *\n * Throw a `Notice` to stop a handler and reply to the user. The framework catches it at the controller\n * boundary and renders {@link Notice.render}, which always decides what the user sees. With `report`\n * false that render is all that happens. With `report` true the framework also logs the fault and\n * publishes it to the `handledException` bus. A raw, non-Notice throw shows the generic message.\n *\n * @example\n * ```ts\n * import { Notice, BuilderComponent, type RenderContext, type ReplyResponse } from '@seedcord/gateway';\n * import { TextDisplayBuilder } from '@discordjs/builders';\n *\n * // reading `.component` applies the configured bot color to the container accent\n * class TooPoorCard extends BuilderComponent<'container'> {\n * constructor(balance: number) {\n * super('container');\n * this.instance.addTextDisplayComponents(\n * new TextDisplayBuilder().setContent(`### Insufficient balance\\nYou need more than ${balance} coins.`)\n * );\n * }\n * }\n *\n * class TooPoor extends Notice {\n * constructor(private readonly balance: number) {\n * super(`balance ${balance} is below the cost`);\n * }\n *\n * render(_ctx: RenderContext): ReplyResponse {\n * return { components: [new TooPoorCard(this.balance).component] };\n * }\n * }\n *\n * // in a handler, throwing stops the handler and replies with render(ctx)\n * if (wallet.balance < cost) throw new TooPoor(wallet.balance);\n * ```\n */\nexport abstract class Notice extends Error {\n /**\n * Whether this denial is a reported fault. True also logs it and publishes it to the `handledException`\n * bus. The user always sees {@link Notice.render} either way.\n *\n * @defaultValue `false`\n */\n public report = false;\n\n /**\n * Whether the reply is ephemeral, so only the invoking user sees it. Set it false for a refusal the\n * whole channel should see.\n *\n * @defaultValue `true`\n */\n public ephemeral = true;\n\n /**\n * A short one-line reason. When every arm of an `or` gate refuses and each refusal sets this, `or`\n * lists them instead of showing a neutral message.\n */\n public summary?: string;\n\n protected constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n\n // Error sets name to 'Error', so stamp the concrete subclass name for logs and the fault report\n this.name = new.target.name;\n Error.captureStackTrace(this, this.constructor);\n }\n\n /**\n * Builds what the user sees. Called fresh each time the denial is shown, so the builders are new\n * and the bot color resolves at render time rather than at construction time.\n */\n public abstract render(ctx: RenderContext): ReplyResponse;\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '@components/Component';\n\n/**\n * Built fresh inside a {@link Notice}'s `render` to back its ComponentsV2 reply. The title renders as\n * an h3 line with the description on the next line.\n */\nexport class NoticeCard extends BuilderComponent<'container'> {\n public constructor(description: string, title = 'Cannot Proceed') {\n super('container');\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(`### ${title}\\n${description}`));\n }\n}\n","import { 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. The reply tells the user to run the command again.\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 * This should not happen in normal use, so it reports.\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","/* eslint-disable no-magic-numbers -- lots of bigints */\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { InvalidCustomId } from './Errors';\n\nimport type { CustomIdField, CustomIdShape } from './Field';\n\n// wire is routeKey, a colon, then the body. the routeKey is the stable prefix plus a short shape\n// hash, so a shape change produces a new routeKey and decode rejects an old wire as stale. bounded\n// fields (known range) fold into one base64 integer by mixed-radix packing, unbounded ones (free\n// string, unbounded int) trail it as delimited tokens.\n//\n// works on runtime values (unknown), CustomId.ts adds the typed layer.\n\n// url-safe base64, one utf-16 unit per char so encode's wire.length cap counts chars exactly.\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\nconst BASE = 64n;\nconst CHAR_TO_VALUE = new Map([...ALPHABET].map((char, index) => [char, index] as const));\n\nconst DELIMITER = '\\u{1F}';\nconst ESCAPE = '\\u{1B}';\n\n/** @internal */\nexport const HASH_LENGTH = 3;\n\nconst SAFE_MAX = BigInt(Number.MAX_SAFE_INTEGER);\nconst SAFE_MIN = BigInt(Number.MIN_SAFE_INTEGER);\n\n// toString and parseInt top out at base 36, and float64 loses integers past 2^53.\nfunction bigintToBase64(value: bigint): string {\n if (value === 0n) return ALPHABET.charAt(0);\n let text = '';\n for (let remaining = value; remaining > 0n; remaining /= BASE) {\n text = ALPHABET.charAt(Number(remaining % BASE)) + text;\n }\n return text;\n}\n\nfunction base64ToBigint(text: string): bigint {\n let value = 0n;\n for (const char of text) {\n const digit = CHAR_TO_VALUE.get(char);\n if (digit === undefined) throw new InvalidCustomId(`bad character ${JSON.stringify(char)}`);\n value = value * BASE + BigInt(digit);\n }\n return value;\n}\n\n// zigzag keeps a small negative number short on the wire.\nfunction zigzagEncode(value: number): bigint {\n const big = BigInt(value);\n return big >= 0n ? big << 1n : (-big << 1n) - 1n;\n}\nfunction zigzagDecode(encoded: bigint): bigint {\n return (encoded & 1n) === 1n ? -((encoded + 1n) >> 1n) : encoded >> 1n;\n}\n\nfunction escapeToken(text: string): string {\n return text.replaceAll(/[\\x1B\\x1F]/g, (char) => ESCAPE + char);\n}\nfunction unescapeToken(text: string): string {\n let out = '';\n for (let i = 0; i < text.length; i++) {\n if (text.charAt(i) !== ESCAPE) {\n out += text.charAt(i);\n continue;\n }\n const next = text.charAt(i + 1);\n if (next === '') throw new InvalidCustomId('dangling escape at end of token');\n out += next;\n i++;\n }\n return out;\n}\nfunction splitTokens(body: string): string[] {\n const pieces: string[] = [];\n let current = '';\n for (let i = 0; i < body.length; i++) {\n const char = body.charAt(i);\n if (char === ESCAPE) {\n current += char + body.charAt(i + 1);\n i++;\n } else if (char === DELIMITER) {\n pieces.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n pieces.push(current);\n return pieces;\n}\n\n// bounded means the full range is known, so the field can fold into the shared packed integer.\nfunction isBounded(field: CustomIdField<unknown>): boolean {\n if (field.kind === 'int') return field.min !== undefined && field.max !== undefined;\n return field.kind === 'snowflake' || field.kind === 'uuid' || field.kind === 'bool' || field.kind === 'oneOf';\n}\n\n// how many distinct values the field can hold.\nfunction radixOf(field: CustomIdField<unknown>): bigint {\n switch (field.kind) {\n case 'snowflake': {\n return 1n << 64n;\n }\n case 'uuid': {\n return 1n << 128n;\n }\n case 'bool': {\n return 2n;\n }\n case 'oneOf': {\n // oneOf() rejects an empty list at define time, so no choices here means a hand-built\n // corrupt shape.\n if (!field.choices?.length) throw new InvalidCustomId('oneOf field has no choices');\n return BigInt(field.choices.length);\n }\n case 'int': {\n // isBounded only routes a min-and-max int here, so a missing bound means a corrupt shape.\n if (field.min === undefined || field.max === undefined)\n throw new InvalidCustomId('bounded int field is missing a bound');\n // bigint before the math, max - min + 1 in float64 drops the +1 at 2^53.\n return BigInt(field.max) - BigInt(field.min) + 1n;\n }\n default: {\n throw new InvalidCustomId(`field kind ${field.kind} has no radix`);\n }\n }\n}\n\nfunction boundedToBigint(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n const slot = boundedSlot(field, name, value);\n // out of range would carry into the neighbouring field on decode.\n if (slot < 0n || slot >= radixOf(field)) outOfRange(name, value);\n return slot;\n}\n\n// a slot is the value as an integer in [0, radix).\nfunction boundedSlot(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n switch (field.kind) {\n case 'snowflake': {\n // BigInt() throws a bare TypeError or SyntaxError on a bad value, so the guard throws\n // the branded error first.\n if (typeof value !== 'string' || !/^\\d+$/.test(value)) return outOfRange(name, value);\n return BigInt(value);\n }\n case 'uuid': {\n if (typeof value !== 'string') return outOfRange(name, value);\n const hex = value.replaceAll('-', '');\n if (!/^[0-9a-fA-F]{32}$/.test(hex)) return outOfRange(name, value);\n return BigInt(`0x${hex}`);\n }\n case 'bool': {\n return value ? 1n : 0n;\n }\n case 'oneOf': {\n const index = (field.choices ?? []).indexOf(value as string);\n return index === -1 ? outOfRange(name, value) : BigInt(index);\n }\n case 'int': {\n // eslint-disable-next-line unicorn/prefer-number-is-safe-integer -- a bounded int field may declare max up to 2**53 exactly (a power of two, exact in float64)\n if (!Number.isInteger(value)) return outOfRange(name, value);\n return BigInt((value as number) - (field.min ?? 0));\n }\n default: {\n return outOfRange(name, value);\n }\n }\n}\n\nfunction outOfRange(name: string, value: unknown): never {\n throw new SeedcordRangeError(SeedcordErrorCode.CustomIdValueOutOfRange, [name, String(value)]);\n}\n\n// inverse of boundedSlot.\nfunction bigintToBoundedValue(field: CustomIdField<unknown>, slot: bigint): unknown {\n switch (field.kind) {\n case 'snowflake': {\n return slot.toString();\n }\n case 'uuid': {\n return bigintToUuid(slot);\n }\n case 'bool': {\n return slot === 1n;\n }\n case 'oneOf': {\n return (field.choices ?? [])[Number(slot)];\n }\n case 'int': {\n return Number(slot) + (field.min ?? 0);\n }\n default: {\n throw new InvalidCustomId(`field kind ${field.kind} is not bounded`);\n }\n }\n}\n\nfunction bigintToUuid(value: bigint): string {\n const hex = value.toString(16).padStart(32, '0');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nfunction encodeUnboundedToken(field: CustomIdField<unknown>, name: string, value: unknown): string {\n if (field.kind === 'int') {\n if (!Number.isSafeInteger(value)) outOfRange(name, value);\n return bigintToBase64(zigzagEncode(value as number));\n }\n return escapeToken(value as string);\n}\nfunction decodeUnboundedToken(field: CustomIdField<unknown>, piece: string): unknown {\n if (field.kind !== 'int') return unescapeToken(piece);\n // an int always encodes to at least one char, so an empty piece is a truncated wire\n if (piece === '') throw new InvalidCustomId('empty integer token');\n const decoded = zigzagDecode(base64ToBigint(piece));\n // an unbounded int is authored as a js number, so a value past 2^53 cannot come from encode.\n if (decoded > SAFE_MAX || decoded < SAFE_MIN) throw new InvalidCustomId('integer out of safe range');\n return Number(decoded);\n}\n\n/** @internal */\nexport function computeLayoutHash(shape: CustomIdShape): string {\n // stringify escapes the choice strings, so two different shapes cannot produce the same signature.\n const signature = JSON.stringify(\n Object.entries(shape).map(([name, field]) => [\n name,\n field.kind,\n isBounded(field),\n field.kind === 'oneOf' ? (field.choices ?? []) : null,\n field.kind === 'int' ? [field.min ?? null, field.max ?? null] : null\n ])\n );\n const modulus = BASE ** BigInt(HASH_LENGTH);\n let hash = 0n;\n for (const char of signature) hash = (hash * 131n + BigInt(char.charCodeAt(0))) % modulus;\n\n let text = '';\n for (let i = 0; i < HASH_LENGTH; i++) {\n text = ALPHABET.charAt(Number(hash % BASE)) + text;\n hash /= BASE;\n }\n return text;\n}\n\n/** @internal */\nexport function encodeBody(shape: CustomIdShape, values: Record<string, unknown>): string {\n const fields = Object.entries(shape);\n const pieces: string[] = [];\n\n const bounded = fields.filter(([, field]) => isBounded(field));\n if (bounded.length > 0) {\n let packed = 0n;\n for (const [name, field] of bounded)\n packed = packed * radixOf(field) + boundedToBigint(field, name, values[name]);\n pieces.push(bigintToBase64(packed));\n }\n for (const [name, field] of fields) {\n if (!isBounded(field)) pieces.push(encodeUnboundedToken(field, name, values[name]));\n }\n return pieces.join(DELIMITER);\n}\n\nfunction unpackBounded(\n bounded: [string, CustomIdField<unknown>][],\n blob: string | undefined,\n result: Record<string, unknown>\n): void {\n // zero packs to one char, so an empty block means the body was truncated.\n if (blob === undefined || blob === '') throw new InvalidCustomId('empty packed block');\n let packed = base64ToBigint(blob);\n // last field packed is the first one back out.\n for (const [name, field] of [...bounded].reverse()) {\n const radix = radixOf(field);\n result[name] = bigintToBoundedValue(field, packed % radix);\n packed /= radix;\n }\n if (packed !== 0n) throw new InvalidCustomId('leftover bits after unpacking');\n}\n\n/** @internal */\nexport function decodeBody(shape: CustomIdShape, body: string): Record<string, unknown> {\n const fields = Object.entries(shape);\n const bounded = fields.filter(([, field]) => isBounded(field));\n const unbounded = fields.filter(([, field]) => !isBounded(field));\n\n // a shape with no fields encodes to an empty body.\n const expected = (bounded.length > 0 ? 1 : 0) + unbounded.length;\n if (expected === 0) {\n if (body !== '') throw new InvalidCustomId(`expected an empty body, got ${JSON.stringify(body)}`);\n return {};\n }\n\n const pieces = splitTokens(body);\n if (pieces.length !== expected) throw new InvalidCustomId(`expected ${expected} piece(s), got ${pieces.length}`);\n\n const result: Record<string, unknown> = {};\n let cursor = 0;\n\n if (bounded.length > 0) {\n unpackBounded(bounded, pieces[cursor], result);\n cursor++;\n }\n\n for (const [name, field] of unbounded) {\n const piece = pieces[cursor];\n cursor++;\n if (piece === undefined) throw new InvalidCustomId('missing trailing piece');\n result[name] = decodeUnboundedToken(field, piece);\n }\n\n return result;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { computeLayoutHash, decodeBody, encodeBody, HASH_LENGTH } from './codec';\nimport { InvalidCustomId, StaleCustomId } from './Errors';\n\nimport type { CustomIdField, CustomIdShape, DecodedParams } from './Field';\nimport type { Snowflake } from 'discord-api-types/v10';\nimport type { NonEmptyTuple } from 'type-fest';\n\n// discord caps a customId at 100 chars.\nconst MAX_WIRE_LENGTH = 100;\n\nfunction routeKeyOf(wire: string): string {\n const colon = wire.indexOf(':');\n return colon === -1 ? '' : wire.slice(0, colon);\n}\n\n/** Strip the layout hash off the routeKey to recover the stable prefix the controller routes by. @internal */\nexport function prefixOf(wire: string): string {\n const key = routeKeyOf(wire);\n return key.length <= HASH_LENGTH ? '' : key.slice(0, key.length - HASH_LENGTH);\n}\n\n/**\n * A typed customId. The single source of truth shared by the component that mints it and the handler\n * that reads it. This gives you typed reads on the `.customId` field in components. Values are packed into a compact wire string rather than plain stringified tokens, so the 100-char Discord limit goes further. More string per string, basically.\n *\n * @typeParam Prefix - The stable route prefix, e.g. 'approve'.\n * @typeParam Shape - The accumulated fields, filled in by the chain.\n *\n * @example\n * ```ts\n * const ApproveId = new CustomId('approve')\n * .snowflake('userId')\n * .oneOf('action', ['approve', 'deny']);\n *\n * // Set the custom id on a button when creating it.\n * new ButtonBuilder().setCustomId(ApproveId.encode({ userId: '123', action: 'approve' }));\n *\n * // reading in the handler: userId comes back a string\n * const { userId, action } = this.params; // userId: string, action: 'approve' | 'deny'\n * await this.event.guild?.members.fetch(userId);\n * ```\n */\nexport class CustomId<Prefix extends string, Shape extends CustomIdShape = {}> {\n /** The stable route prefix, e.g. 'approve'. */\n readonly prefix: Prefix;\n /** Like a zod shape */\n readonly shape: Shape;\n /** The prefix plus a short hash of the shape, the part of the wire before the colon. */\n readonly routeKey: string;\n\n constructor(prefix: Prefix, shape: Shape = {} as Shape) {\n // an empty prefix would make the routeKey all-hash so prefixOf strips it to nothing and the\n // controller cannot route it, and a colon or control char would break the wire framing.\n if (!prefix || /[:\\x1B\\x1F]/.test(prefix)) {\n throw new SeedcordError(SeedcordErrorCode.CustomIdInvalidPrefix, [prefix]);\n }\n this.prefix = prefix;\n this.shape = shape;\n this.routeKey = prefix + computeLayoutHash(shape);\n }\n\n // a fresh immutable CustomId with one more field so we don't need a `as unknown as this` cast.\n private add<Name extends string, Decoded>(\n name: Name,\n field: CustomIdField<Decoded>\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<Decoded>>> {\n // integer-like keys get reordered by js, which would scramble the field order.\n if (/^(?:0|[1-9]\\d*)$/.test(name)) throw new SeedcordError(SeedcordErrorCode.CustomIdReservedFieldName, [name]);\n // a repeat name collapses the field's decoded type to never and overwrites the earlier field\n // at runtime, so reject it here at define time.\n if (name in this.shape) throw new SeedcordError(SeedcordErrorCode.CustomIdDuplicateFieldName, [name]);\n // justified, the spread plus a computed key cannot be proven to the exact intersection\n const shape = { ...this.shape, [name]: field } as Shape & Record<Name, CustomIdField<Decoded>>;\n return new CustomId(this.prefix, shape);\n }\n\n /**\n * Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).\n *\n * @example\n * ```ts\n * new CustomId('ban').snowflake('userId');\n * ```\n */\n snowflake<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<Snowflake>>> {\n return this.add<Name, Snowflake>(name, { kind: 'snowflake' });\n }\n\n /**\n * Add a UUID field, decoded as a lowercase uuid string.\n *\n * @example\n * ```ts\n * new CustomId('ticket').uuid('ticketId');\n * ```\n */\n uuid<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>> {\n return this.add<Name, string>(name, { kind: 'uuid' });\n }\n\n /**\n * Add an integer field with no bounds, for a value up to 2^53.\n *\n * @example\n * ```ts\n * new CustomId('shop').int('amount');\n * ```\n */\n int<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;\n /**\n * Add an integer field bounded by min and max, so it packs into fewer characters on the wire.\n *\n * @example\n * ```ts\n * new CustomId('paginate').int('page', 1, 50);\n * ```\n */\n int<Name extends string>(\n name: Name,\n min: number,\n max: number\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;\n int<Name extends string>(\n name: Name,\n min?: number,\n max?: number\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>> {\n if (min !== undefined && max !== undefined && min > max) {\n throw new SeedcordError(SeedcordErrorCode.CustomIdInvalidBounds, [name, min, max]);\n }\n const field: CustomIdField<number> =\n min === undefined || max === undefined ? { kind: 'int' } : { kind: 'int', min, max };\n return this.add<Name, number>(name, field);\n }\n\n /**\n * Add a boolean flag.\n *\n * @example\n * ```ts\n * new CustomId('settings').bool('silent');\n * ```\n */\n bool<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<boolean>>> {\n return this.add<Name, boolean>(name, { kind: 'bool' });\n }\n\n /**\n * Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.\n *\n * @example\n * ```ts\n * new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);\n * ```\n */\n oneOf<Name extends string, const Choices extends NonEmptyTuple<string>>(\n name: Name,\n choices: Choices\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<Choices[number]>>> {\n if (choices.length === 0) throw new SeedcordError(SeedcordErrorCode.CustomIdEmptyChoices, [name]);\n return this.add<Name, Choices[number]>(name, { kind: 'oneOf', choices });\n }\n\n /**\n * Add a free short text field. Avoid it where possible, it cannot be packed so it costs the most wire space.\n *\n * @example\n * ```ts\n * new CustomId('note').str('message');\n * ```\n */\n str<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>> {\n return this.add<Name, string>(name, { kind: 'string' });\n }\n\n /**\n * Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.\n *\n * @param values - One value per field, typed by the chain.\n * @returns The wire string to put on the component's customId.\n */\n encode(values: DecodedParams<Shape>): string {\n const wire = `${this.routeKey}:${encodeBody(this.shape, values)}`;\n if (wire.length > MAX_WIRE_LENGTH) {\n throw new SeedcordRangeError(SeedcordErrorCode.CustomIdWireTooLong, [wire.length]);\n }\n return wire;\n }\n\n /**\n * Read a wire string back into values.\n *\n * - This will refuse with a default Notice when the shape changed since the wire was minted.\n * - Or refuse with a different default Notice on a corrupt or foreign wire.\n *\n * @param wire - The customId string from the interaction.\n * @returns The decoded values, typed by the chain.\n */\n decode(wire: string): DecodedParams<Shape> {\n const key = routeKeyOf(wire);\n if (key !== this.routeKey) {\n // same prefix but a different hash means the shape changed since this wire was minted.\n if (prefixOf(wire) === this.prefix) throw new StaleCustomId(this.prefix);\n throw new InvalidCustomId(`routeKey ${JSON.stringify(key)} is not ${JSON.stringify(this.routeKey)}`);\n }\n // justified, the codec returns runtime values and the shape guarantees their decoded types.\n return decodeBody(this.shape, wire.slice(key.length + 1)) as DecodedParams<Shape>;\n }\n\n /** True if this wire was minted from this customId's prefix, ignoring the shape hash. */\n owns(wire: string): boolean {\n return prefixOf(wire) === this.prefix;\n }\n}\n\n/**\n * Any customId, for places where the exact prefix and shape do not matter.\n *\n * @internal\n */\nexport type AnyCustomId = CustomId<string, CustomIdShape>;\n\n/**\n * The outcome of decoding a wire against several customIds, the matched prefix paired with its values.\n *\n * @internal\n */\nexport type DecodedRoute<Defs extends readonly AnyCustomId[]> = {\n [Index in keyof Defs]: Defs[Index] extends AnyCustomId\n ? { readonly prefix: Defs[Index]['prefix']; readonly params: DecodedParams<Defs[Index]['shape']> }\n : never;\n}[number];\n\n/**\n * Find the customId whose prefix owns this wire, decode against it, and report which one matched.\n *\n * @internal\n */\nexport function decodeFor<Defs extends readonly AnyCustomId[]>(defs: Defs, wire: string): DecodedRoute<Defs> {\n const match = defs.find((def) => def.owns(wire));\n if (!match) throw new InvalidCustomId(`no customId owns ${JSON.stringify(routeKeyOf(wire))}`);\n // justified, the matched customId fixes both prefix and params together but find() loses that link.\n return { prefix: match.prefix, params: match.decode(wire) } as DecodedRoute<Defs>;\n}\n","import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { decodeFor } from './CustomId';\n\nimport type { AnyCustomId } from './CustomId';\nimport type { DecodedParams } from './Field';\nimport type { Promisable } from 'type-fest';\n\n/**\n * The route decorators store a handler's customId definitions here so the component base can decode\n * against them at runtime.\n *\n * @internal\n */\nexport const ComponentDefsKey = Symbol('seedcord:customId:componentDefs');\n\n/**\n * The phantom a component handler base carries. A route decorator constrains its argument to this, so\n * passing different definitions to the decorator and the handler's generic is a compile error. Never set at runtime.\n *\n * @internal\n */\nexport interface HasComponentDefs<Defs extends readonly AnyCustomId[]> {\n /** @internal */\n readonly __componentDefs?: Defs;\n}\n\n/** @internal */\nexport interface DecodedComponentRoute {\n prefix: string;\n params: Record<string, unknown>;\n}\n\n/**\n * Throws `CustomIdHandlerRouteMissing` when the class has no stored defs. A drifted or corrupt wire\n * throws `StaleCustomId` or `InvalidCustomId`.\n *\n * @internal\n */\nexport function decodeComponentRoute(handlerClass: { name: string }, wire: string): DecodedComponentRoute {\n const defs = Reflect.getMetadata(ComponentDefsKey, handlerClass) as readonly AnyCustomId[] | undefined;\n if (!defs) throw new SeedcordError(SeedcordErrorCode.CustomIdHandlerRouteMissing, [handlerClass.name]);\n return decodeFor(defs, wire);\n}\n\n/** @internal */\nexport type SingleParams<Defs extends readonly AnyCustomId[]> = Defs extends readonly [infer One extends AnyCustomId]\n ? DecodedParams<One['shape']>\n : never;\n\n/** @internal */\nexport type MatchArms<Defs extends readonly AnyCustomId[], Ret> = {\n [Def in Defs[number] as Def['prefix']]: (params: DecodedParams<Def['shape']>) => Promisable<Ret>;\n};\n","import 'reflect-metadata';\n\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { ComponentDefsKey } from '@customId/routing';\nimport { InteractionMetadataKey, InteractionRouteKeys, InteractionRoutes } from '@src/metadataKeys';\n\nimport type { AnyCustomId } from '@customId/CustomId';\nimport type { ContextMenuKind } from '@registries/ContextMenuRegistry';\n\n/** The select menu kinds the select route decorators take. */\nexport enum SelectMenuKind {\n String = 'string',\n User = 'user',\n Role = 'role',\n Channel = 'channel',\n Mentionable = 'mentionable'\n}\n\n// loose on purpose, each transport's typed decorators pass their asserted ctors straight in\nexport type RoutableConstructor = new (...args: never[]) => unknown;\n\nexport function areRoutes(routes: unknown): routes is string[] {\n return Array.isArray(routes) && routes.every((route) => typeof route === 'string');\n}\n\n/**\n * Every stored route kind and its route strings on a decorated constructor. The build's manifest\n * emitter reads the same pairs.\n */\nexport function interactionRoutesOf(constructor: RoutableConstructor): [InteractionRoutes, string[]][] {\n const pairs: [InteractionRoutes, string[]][] = [];\n for (const route of Object.values(InteractionRoutes)) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[route], constructor);\n if (areRoutes(meta)) pairs.push([route, meta]);\n }\n return pairs;\n}\n\nexport function storeInteractionRoute(\n route: InteractionRoutes,\n routes: string | readonly string[],\n constructor: RoutableConstructor\n): void {\n const key = InteractionRouteKeys[route];\n const saved: unknown = Reflect.getMetadata(key, constructor);\n const existing = areRoutes(saved) ? saved : [];\n const toStore = typeof routes === 'string' ? [routes] : routes;\n Reflect.defineMetadata(key, [...existing, ...toStore], constructor);\n Reflect.defineMetadata(InteractionMetadataKey, true, constructor);\n}\n\n// each definition's stable prefix is the routing key, the full defs stay on the ctor for decoding\nexport function storeComponentRoute(\n route: InteractionRoutes,\n defs: readonly AnyCustomId[],\n constructor: RoutableConstructor\n): void {\n storeInteractionRoute(\n route,\n defs.map((def) => def.prefix),\n constructor\n );\n Reflect.defineMetadata(ComponentDefsKey, defs, constructor);\n}\n\nconst SELECT_ROUTES: Record<SelectMenuKind, InteractionRoutes> = {\n [SelectMenuKind.String]: InteractionRoutes.StringMenu,\n [SelectMenuKind.User]: InteractionRoutes.UserMenu,\n [SelectMenuKind.Role]: InteractionRoutes.RoleMenu,\n [SelectMenuKind.Channel]: InteractionRoutes.ChannelMenu,\n [SelectMenuKind.Mentionable]: InteractionRoutes.MentionableMenu\n};\n\nexport function selectMenuRouteOf(kind: SelectMenuKind): InteractionRoutes {\n return SELECT_ROUTES[kind];\n}\n\nexport function contextMenuRouteOf(kind: ContextMenuKind): InteractionRoutes {\n return kind === ApplicationCommandType.User\n ? InteractionRoutes.UserContextMenu\n : InteractionRoutes.MessageContextMenu;\n}\n","import type { CoreBase } from '@interfaces/CoreBase';\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 arm. 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, on a gateway event the member's guild-level ones.\n */\n readonly memberPermissions: bigint | null;\n /**\n * The bot's permissions in the invoked channel, the wire `app_permissions` value. Null on gateway events.\n */\n readonly appPermissions: bigint | null;\n /**\n * The dispatched handler as `kind:route` (`slash:daily`, `button:confirm`), or null off a route (a\n * plain event handler, or a gate run outside a handler). `runHandlerGates` sets it from the handler's\n * metadata. `Cooldown` uses it so its window is stable across restarts and isolates.\n */\n readonly routeId: string | null;\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. Null when the cached member is unavailable.\n */\n readonly appGuildPermissions: bigint | null;\n}\n\n// phantom brand, so a bare check function or a plain object is rejected 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, so reading a field absent on a handler's context is a compile error.\n * @typeParam Name - The gate's name captured as a literal, so a mismatch error can name the gate.\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 that carries a side effect, split so the effect fires only once the gate is the one that\n * let the request through. `check` peeks and refuses, `commit` applies the effect after the whole\n * gate set passes. {@link Cooldown} is the catalog gate that returns one. Build one with\n * {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context the gate requires, so reading a field absent on a handler's context is a compile error.\n * @typeParam Name - The gate's name captured as a literal, so a mismatch error can name the gate.\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, so a mismatch error can name the gate.\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 `seedcord`\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) => void | Promise<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`, a refusing arm's queued commit is rolled back. This is how {@link Cooldown} peeks\n * in `check` and charges the slot in `commit`.\n *\n * @typeParam Name - The gate's name captured as a literal, so a mismatch error can name the gate.\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 `seedcord`\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) => void | Promise<void>,\n commit: (ctx: Ctx) => void | Promise<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 { toEpochSeconds } from '@seedcord/utils';\n\nimport { Notice } from '@stops/Notice';\nimport { NoticeCard } from '@stops/NoticeCard';\n\nimport type { EpochMs, ReplyResponse } from '@seedcord/types';\n\nexport abstract class GateNotice extends Notice {\n public render(): ReplyResponse {\n return { components: [new NoticeCard(this.message).component] };\n }\n}\n\nexport class NotOwner extends GateNotice {\n public constructor(message = 'Only the bot owner can use this.') {\n super(message);\n }\n}\n\nexport class NotInGuild extends GateNotice {\n public constructor(message = 'This can only be used in a server.') {\n super(message);\n }\n}\n\nexport class NotInDm extends GateNotice {\n public constructor(message = 'This can only be used in a direct message.') {\n super(message);\n }\n}\n\nexport class OnCooldown extends GateNotice {\n public constructor(\n public readonly resetAt: EpochMs,\n message?: string\n ) {\n super(message ?? `You are doing that too fast. Try again <t:${toEpochSeconds(resetAt)}:R>.`);\n }\n}\n\nexport class NotAllowed extends Notice {\n public constructor() {\n super('not allowed');\n }\n\n public render(): ReplyResponse {\n return { components: [new NoticeCard('You are not allowed to use this command.').component] };\n }\n}\n\nexport class NeedsAny extends Notice {\n public constructor(private readonly summaries: readonly string[]) {\n super('not allowed');\n }\n\n public render(): ReplyResponse {\n const bullets = this.summaries.map((summary) => `• ${summary}`).join('\\n');\n return { components: [new NoticeCard(`You need any of:\\n${bullets}`).component] };\n }\n}\n\nexport class MissingRole extends GateNotice {\n public constructor(message: string | undefined, roleId: string | null) {\n super(\n message ?? (roleId ? `You need the <@&${roleId}> role to use this.` : 'You do not have the required role.')\n );\n }\n}\n\nexport class MissingPermissions extends Notice {\n private readonly customLead: string | undefined;\n\n public constructor(\n message: string | undefined,\n private readonly subject: string | null,\n private readonly missingPerms: readonly string[]\n ) {\n super(message ?? 'A required permission is missing.');\n this.customLead = message;\n }\n\n public render(): ReplyResponse {\n const bullets = this.missingPerms.map((perm) => `• ${perm}`).join('\\n');\n const lead =\n this.customLead ??\n `${this.subject === null ? 'You are' : `${this.subject} is`} missing the following permission entries:`;\n return {\n components: [new NoticeCard(`${lead}\\n\\n${bullets}`).component]\n };\n }\n}\n\nexport class HasDangerousPermissions extends Notice {\n private readonly customLead: string | undefined;\n\n public constructor(\n message: string | undefined,\n public subject: string,\n public dangerousPerms: readonly string[]\n ) {\n super(message ?? 'A dangerous permission is enabled.');\n this.customLead = message;\n }\n\n public render(): ReplyResponse {\n const bullets = this.dangerousPerms.map((perm) => `• ${perm}`).join('\\n');\n const lead =\n this.customLead ?? `${this.subject} has the following permission entries that must not be enabled:`;\n return { components: [new NoticeCard(`${lead}\\n\\n${bullets}`).component] };\n }\n}\n","import type { EffectGate, Gate, GateContextBase } from './Gate';\n\ntype CommitFn = () => Promise<void>;\n\n// per-request commit queue keyed on the context, so an effect gate's commit runs only after the whole\n// set passes. WeakMap so each entry is dropped once its request's context is gone\nconst commitQueues = new WeakMap<GateContextBase, CommitFn[]>();\n\nfunction isEffectGate(gate: Gate<GateContextBase>): gate is EffectGate<GateContextBase> {\n return typeof (gate as Partial<EffectGate<GateContextBase>>).commit === 'function';\n}\n\n// a refusal throws before the queue, so a refused effect gate never commits. the combinators and the\n// runner both route through here, so an effect gate inside `and`/`or` queues the same way\nexport async function runCheck(gate: Gate<GateContextBase>, ctx: GateContextBase): Promise<void> {\n await gate.check(ctx);\n if (!isEffectGate(gate)) return;\n\n let queue = commitQueues.get(ctx);\n if (!queue) {\n queue = [];\n commitQueues.set(ctx, queue);\n }\n queue.push(() => gate.commit(ctx));\n}\n\nexport async function runCommits(ctx: GateContextBase): Promise<void> {\n const queue = commitQueues.get(ctx);\n if (!queue) return;\n for (const commit of queue) await commit();\n}\n\n// the runner calls this after every run, so a refused or drained run leaves no stale queue behind\nexport function discardCommits(ctx: GateContextBase): void {\n commitQueues.delete(ctx);\n}\n\n// the queued-commit count, the mark an `or` arm rolls back to if it refuses\nexport function markCommits(ctx: GateContextBase): number {\n return commitQueues.get(ctx)?.length ?? 0;\n}\n\n// drops commits queued after `mark`, so a refused `or` arm leaves no commit behind\nexport function rollbackCommits(ctx: GateContextBase, mark: number): void {\n const queue = commitQueues.get(ctx);\n if (queue && queue.length > mark) queue.length = mark;\n}\n","import type { Notice } from '@stops/Notice';\n\n/**\n * The override a catalog gate accepts. A one-line `message` reword or a full `notice` replacement. Accepted by\n * the agnostic catalog gates and, nested per refusal, by {@link RequireRole}. {@link RequirePermissions} and\n * {@link RequireBotPermissions} take `RequirePermissionsOptions` instead.\n *\n * @example\n * ```ts\n * // reword the default refusal\n * OwnerOnly({ message: 'Bot owners only.' });\n * ```\n *\n * @example\n * ```ts\n * // replace the refusal entirely, for example a translated Notice\n * GuildOnly({ notice: new MyTranslatedNotice() });\n * ```\n */\nexport interface GateNoticeOptions {\n /** Reword the default refusal, keeping its embed styling. */\n message?: string;\n /** Replace the default refusal Notice entirely, for full control or a translated copy. */\n notice?: Notice;\n}\n\nexport function pickNotice(options: GateNoticeOptions | undefined, makeDefault: (message?: string) => Notice): Notice {\n return options?.notice ?? makeDefault(options?.message);\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\n/** Permission bit to its prettified human-readable name. */\nexport const 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\n/** @internal */\nexport function hasAll(held: bigint, scope: PermissionScope): boolean {\n return scope.every((bit) => holds(held, bit));\n}\n\n/** @internal only reached once hasAll failed, so the administrator bit is absent */\nexport function missingNames(held: bigint, scope: PermissionScope): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if ((held & bit) !== bit) names.push(nameOf(bit));\n return names;\n }, []);\n}\n\n/** @internal */\nexport function presentNames(held: bigint, scope: PermissionScope): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if (holds(held, bit)) names.push(nameOf(bit));\n return names;\n }, []);\n}\n","import { defineGate } from '@gates/Gate';\nimport { MissingPermissions, MissingRole, NotInGuild } from '@notices/index';\nimport { hasAll, missingNames } from '@src/permissions/bits';\n\nimport { pickNotice } from './options';\n\nimport type { GateNoticeOptions } from './options';\nimport type { Gate, GateContextBase, GuildPermissionsContext } from '@gates/Gate';\nimport type { PermissionScope } from '@src/permissions/bits';\n\nexport type { PermissionScope } from '@src/permissions/bits';\nexport { PermissionNames } from '@src/permissions/bits';\n\ninterface PermCheckKind {\n unresolved: string;\n subject: string | null;\n}\n\nconst MEMBER_CHECK: PermCheckKind = {\n unresolved: 'Your server member data could not be resolved. Try again.',\n subject: null\n};\nconst BOT_CHECK: PermCheckKind = {\n unresolved: \"The bot's permissions could not be resolved. Try again.\",\n subject: 'The bot'\n};\n\nfunction refusePermissions(\n held: bigint | null,\n scope: PermissionScope,\n options: RequirePermissionsOptions | undefined,\n guildId: string | null,\n kind: PermCheckKind\n): void {\n if (held === null) {\n throw pickNotice(\n options?.notInGuild,\n (message) => new NotInGuild(message ?? (guildId ? kind.unresolved : undefined))\n );\n }\n if (hasAll(held, scope)) return;\n throw pickNotice(\n options?.missing,\n (message) => new MissingPermissions(message, kind.subject, missingNames(held, scope))\n );\n}\n\n/**\n * Options for {@link RequirePermissions} and {@link RequireBotPermissions}.\n */\nexport interface RequirePermissionsOptions {\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 /** Reword or replace the refusal shown when the set is unavailable (outside a guild, or unresolved inside one). */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when a permission is missing. */\n missing?: GateNoticeOptions;\n}\n\n/**\n * Options for {@link RequireRole}.\n */\nexport interface RequireRoleOptions {\n /** Reword or replace the refusal shown outside a guild. */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when the caller lacks the role. */\n missingRole?: GateNoticeOptions;\n}\n\n/**\n * Requires the caller to hold every permission in `scope`. 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 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`, and override each refusal with `notInGuild` or `missing`.\n *\n * @see the `@Gated` decorator from `seedcord`\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 if (options?.in === 'guild') {\n return defineGate('RequirePermissions', (ctx: GuildPermissionsContext) => {\n refusePermissions(ctx.memberGuildPermissions, scope, options, ctx.guildId, MEMBER_CHECK);\n });\n }\n return defineGate('RequirePermissions', (ctx: GateContextBase) => {\n refusePermissions(ctx.memberPermissions, scope, options, ctx.guildId, MEMBER_CHECK);\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}, so it fits a gateway handler only. `app_permissions` is\n * absent on gateway events, the channel scope refuses there as unresolved, use `in: 'guild'` on an\n * event handler.\n *\n * @param scope - The permission flag bits the bot must all hold.\n * @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.\n *\n * @see the `@Gated` decorator from `seedcord`\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: RequirePermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions & { in?: 'channel' }\n): Gate<GateContextBase, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'> | Gate<GateContextBase, 'RequireBotPermissions'> {\n if (options?.in === 'guild') {\n return defineGate('RequireBotPermissions', (ctx: GuildPermissionsContext) => {\n refusePermissions(ctx.appGuildPermissions, scope, options, ctx.guildId, BOT_CHECK);\n });\n }\n return defineGate('RequireBotPermissions', (ctx: GateContextBase) => {\n refusePermissions(ctx.appPermissions, scope, options, ctx.guildId, BOT_CHECK);\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 - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.\n *\n * @see the `@Gated` decorator from `seedcord`\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 pickNotice(options?.notInGuild, (message) => new NotInGuild(message));\n if (ctx.memberRoleIds.includes(roleId)) return;\n throw pickNotice(options?.missingRole, (message) => new MissingRole(message, roleId));\n });\n}\n","/**\n * Throw to stop a handler with no reply and no report.\n *\n * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.\n * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to\n * leave the user with no reply for an interaction.\n *\n * @example\n * ```ts\n * import { Silence } from '@seedcord/gateway';\n *\n * // before any reply or defer, drop the interaction with no reply and no report\n * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');\n * ```\n */\nexport class Silence extends Error {\n /**\n * @param reason - Optional note written only to a debug log, never shown to the user or reported.\n */\n public constructor(public readonly reason?: string) {\n super(reason ?? 'Silence');\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n","import { CustomId } from '@customId/CustomId';\n\nimport type { CustomIdField } from '@customId/Field';\n\n// Included in the layout hash so it is fixed per prefix. Reducing it marks every active button as StaleCustomId.\n// @internal\nexport const PAGE_MAX = 1_000_000;\n\n// Discord rejects a message with duplicate custom_ids, and two controls can target the same page (first and\n// prev both hit 0), so each control uses a distinct slot.\n// @internal\nconst SLOT_MAX = 4;\n\n/** Page cursor for a paginator. */\nexport type PageCursor<Prefix extends string> = CustomId<\n Prefix,\n { page: CustomIdField<number>; slot: CustomIdField<number> }\n>;\n\n/** Build the page cursor for a paginator. */\nexport function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix> {\n return new CustomId(prefix).int('page', 0, PAGE_MAX).int('slot', 0, SLOT_MAX);\n}\n"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
-
2
1
  //#region src/hmr/devChannel.ts
3
2
  let channel;
4
3
  /** @internal */
@@ -23,4 +22,4 @@ Object.defineProperty(exports, 'setDevChannel', {
23
22
  return setDevChannel;
24
23
  }
25
24
  });
26
- //# sourceMappingURL=devChannel-CoCmAVDx.cjs.map
25
+ //# sourceMappingURL=devChannel-Cdnmz6hd.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"devChannel-CoCmAVDx.cjs","names":[],"sources":["../src/hmr/devChannel.ts"],"sourcesContent":["import type { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\n// one module instance per process, the HmrManager write and every framework read share it\nlet channel: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined;\n\n/** @internal */\nexport function setDevChannel(next: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined): void {\n channel = next;\n}\n\n/** @internal */\nexport function getDevChannel(): DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined {\n return channel;\n}\n"],"mappings":";;AAGA,IAAI;;AAGJ,SAAgB,cAAc,MAAgF;CAC1G,UAAU;AACd;;AAGA,SAAgB,gBAAoF;CAChG,OAAO;AACX"}
1
+ {"version":3,"file":"devChannel-Cdnmz6hd.cjs","names":[],"sources":["../src/hmr/devChannel.ts"],"sourcesContent":["import type { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\n// one module instance per process, the HmrManager write and every framework read share it\nlet channel: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined;\n\n/** @internal */\nexport function setDevChannel(next: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined): void {\n channel = next;\n}\n\n/** @internal */\nexport function getDevChannel(): DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined {\n return channel;\n}\n"],"mappings":";AAGA,IAAI;;AAGJ,SAAgB,cAAc,MAAgF;CAC1G,UAAU;AACd;;AAGA,SAAgB,gBAAoF;CAChG,OAAO;AACX"}
@@ -1,4 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_HmrModuleHandler = require('./HmrModuleHandler-CTBng7wV.cjs');
2
+ const require_HmrModuleHandler = require('./HmrModuleHandler-CxGOo1LT.cjs');
3
3
 
4
4
  exports.HmrModuleHandler = require_HmrModuleHandler.HmrModuleHandler;
@@ -1,6 +1,5 @@
1
1
  import { Logger } from "@seedcord/logger";
2
2
  import { HmrUpdateEvent } from "@seedcord/types";
3
-
4
3
  //#region src/hmr/HmrModuleHandler.d.ts
5
4
  interface HmrModuleHandlerOptions<THandler, TMiddleware = void, TArtifacts = unknown> {
6
5
  handlersDir: string;
@@ -28,6 +27,8 @@ declare class HmrModuleHandler<THandler, TMiddleware = void, TArtifacts = unknow
28
27
  constructor(options: HmrModuleHandlerOptions<THandler, TMiddleware, TArtifacts>);
29
28
  /** Unloads or reloads the modules affected by an {@link HmrUpdateEvent}, scoped to the handler and middleware directories. */
30
29
  handle(event: HmrUpdateEvent): Promise<void>;
30
+ private inScope;
31
+ private report;
31
32
  private reloadWithRollback;
32
33
  /** Links the handler to its source file so a later update can unload it. */
33
34
  trackHandler(file: string, handler: THandler): void;
@@ -1,3 +1,3 @@
1
- import { t as HmrModuleHandler } from "./HmrModuleHandler-3sNgKHdf.mjs";
1
+ import { t as HmrModuleHandler } from "./HmrModuleHandler-KxRP8lqJ.mjs";
2
2
 
3
3
  export { HmrModuleHandler };
@@ -1,8 +1,8 @@
1
- import { t as Constructor } from "./basic-1hebYVcN.mjs";
2
- import { T as SubscriptionKey, b as Subscriber, g as CoreBase } from "./Plugin-BZit5HUI.mjs";
1
+ import { t as Constructor } from "./basic-CeSFvbaz.mjs";
2
+ import { T as SubscriptionKey, b as Subscriber, g as CoreBase } from "./Plugin-BPz0obbN.mjs";
3
+ import "reflect-metadata";
3
4
  import { APIMessageTopLevelComponent } from "discord-api-types/v10";
4
5
  import { EventFrequency, ReplyFile } from "@seedcord/types";
5
-
6
6
  //#region src/subscribers/decorators/Subscribe.d.ts
7
7
  /**
8
8
  * Options accepted by the `@Subscribe` decorator.
@@ -132,4 +132,4 @@ declare abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey, TCor
132
132
  declare function WebhookUrl(envKey: string): <HandlerCtor extends Constructor<WebhookLog<SubscriptionKey, CoreBase>>>(constructor: HandlerCtor) => void;
133
133
  //#endregion
134
134
  export { Subscribe as a, WebhookFile as i, WebhookLog as n, SubscribeOptions as o, WebhookReport as r, WebhookUrl as t };
135
- //# sourceMappingURL=index-DafutfX8.d.mts.map
135
+ //# sourceMappingURL=index-Dm0WKN37.d.mts.map
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_subscribers = require('./subscribers-CDbep0RH.cjs');
2
3
  const require_publishDefault = require('./publishDefault-CVlwYUS5.cjs');
3
- const require_cursor = require('./cursor-BMkFAwO2.cjs');
4
- const require_phases = require('./phases-DcuDHoQl.cjs');
5
- const require_subscribers = require('./subscribers-CojcCgj1.cjs');
4
+ const require_cursor = require('./cursor-D2iP-CCS.cjs');
5
+ const require_phases = require('./phases-8qiiLKjS.cjs');
6
6
  require("reflect-metadata");
7
7
  let _discordjs_builders = require("@discordjs/builders");
8
8
  let _seedcord_logger = require("@seedcord/logger");
@@ -289,7 +289,8 @@ var Fault = class extends require_cursor.Notice {
289
289
  this.report = options?.report ?? true;
290
290
  }
291
291
  render(ctx) {
292
- return { components: [new require_cursor.NoticeCard(`Something went wrong. Please reach out to ${ctx.developerUsername ?? "the developer"} with a way to reproduce the error and the following:\n### UUID: \`${ctx.uuid}\``, "Error").component] };
292
+ const contact = ctx.developerUsername ?? "the developer";
293
+ return { components: [new require_cursor.NoticeCard(`Something went wrong. Please reach out to ${contact} with a way to reproduce the error and the following:\n### UUID: \`${ctx.uuid}\``, "Error").component] };
293
294
  }
294
295
  };
295
296
 
@@ -754,7 +755,9 @@ const CURSOR_KEYS = [
754
755
  function renderPage(view, cursor, config) {
755
756
  const controls = new Controls(cursor, view);
756
757
  if (config.render) return toReplyResponse(config.render(view, controls));
757
- return { components: [new PageContainer(view, config.renderItem ?? String, controls.row(...view.totalPages === void 0 ? CURSOR_KEYS : ARRAY_KEYS)).component] };
758
+ const renderItem = config.renderItem ?? String;
759
+ const row = controls.row(...view.totalPages === void 0 ? CURSOR_KEYS : ARRAY_KEYS);
760
+ return { components: [new PageContainer(view, renderItem, row).component] };
758
761
  }
759
762
 
760
763
  //#endregion
@@ -777,7 +780,8 @@ var PaginatorBase = class {
777
780
  }
778
781
  /** Render a page as a {@link ReplyResponse}. To post it elsewhere, add `flags: MessageFlags.IsComponentsV2`. */
779
782
  async page(ctx, n) {
780
- return renderPage(await this.config.source.page(ctx, n), this.cursor, this.config);
783
+ const view = await this.config.source.page(ctx, n);
784
+ return renderPage(view, this.cursor, this.config);
781
785
  }
782
786
  };
783
787
 
@@ -840,7 +844,7 @@ var CursorSource = class {
840
844
  //#endregion
841
845
  //#region src/index.ts
842
846
  /** Package version */
843
- const version = "0.1.0";
847
+ const version = "0.1.1";
844
848
 
845
849
  //#endregion
846
850
  exports.ArraySource = ArraySource;