@seedcord/core 0.9.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{Bus-DUDafYDD.mjs → Bus-BxPa-Uvp.mjs} +6 -6
- package/dist/Bus-BxPa-Uvp.mjs.map +1 -0
- package/dist/{Pluggable-CXyUZIvT.mjs → Pluggable-afy2H0Dr.mjs} +44 -15
- package/dist/Pluggable-afy2H0Dr.mjs.map +1 -0
- package/dist/{cursor-DNFyo_BI.mjs → cursor-CgNBnJfu.mjs} +2 -2
- package/dist/cursor-CgNBnJfu.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.d.mts +1 -1
- package/dist/internal.index.mjs +4 -4
- package/dist/node-internal.index.mjs +5 -5
- package/dist/node-internal.index.mjs.map +1 -1
- package/dist/node.index.mjs +1 -1
- package/dist/{slashRouteLeaves-D__G9vsr.mjs → slashRouteLeaves-k1hJnXDO.mjs} +2 -2
- package/dist/{slashRouteLeaves-D__G9vsr.mjs.map → slashRouteLeaves-k1hJnXDO.mjs.map} +1 -1
- package/dist/{subscribers-Bxut8U6g.mjs → subscribers-xGy7a7xR.mjs} +2 -2
- package/dist/{subscribers-Bxut8U6g.mjs.map → subscribers-xGy7a7xR.mjs.map} +1 -1
- package/package.json +13 -12
- package/dist/Bus-DUDafYDD.mjs.map +0 -1
- package/dist/Pluggable-CXyUZIvT.mjs.map +0 -1
- package/dist/cursor-DNFyo_BI.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
<div align="center">
|
|
19
19
|
|
|
20
|
-
[](https://www.npmjs.com/package/@seedcord/core) [](https://nodejs.org) [](https://bun.com) [](LICENSE)
|
|
21
21
|
|
|
22
22
|
</div>
|
|
23
23
|
|
|
@@ -12,12 +12,12 @@ import { DiscordAPIError, REST } from "@discordjs/rest";
|
|
|
12
12
|
|
|
13
13
|
//#region src/components/botColorHolder.ts
|
|
14
14
|
const DEFAULT_COLOR = "Default";
|
|
15
|
-
let
|
|
16
|
-
function
|
|
17
|
-
|
|
15
|
+
let readBotColor = () => void 0;
|
|
16
|
+
function bindBotColor(read) {
|
|
17
|
+
readBotColor = read;
|
|
18
18
|
}
|
|
19
19
|
function getBotColor() {
|
|
20
|
-
return
|
|
20
|
+
return readBotColor() ?? DEFAULT_COLOR;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
@@ -862,5 +862,5 @@ function busLoggerOf(bus) {
|
|
|
862
862
|
}
|
|
863
863
|
|
|
864
864
|
//#endregion
|
|
865
|
-
export { BuilderComponent as A, InteractionRouteKeys as C, clearStore as D, accessorStore as E, isBuilderComponentClass as M,
|
|
866
|
-
//# sourceMappingURL=Bus-
|
|
865
|
+
export { BuilderComponent as A, InteractionRouteKeys as C, clearStore as D, accessorStore as E, isBuilderComponentClass as M, bindBotColor as N, guardedAccessor as O, InteractionMiddlewareMetadataKey as S, WebhookUrlMetadataKey as T, EventMetadataKey as _, RegisterSubscriber as a, InteractionKind as b, VerifyWebhooks as c, WebhookLog as d, Subscriber as f, CommandMetadataKey as g, sendFlags as h, RegisterDefaults as i, RowComponent as j, contextMenuLeaves as k, WebhookUrl as l, deferFlags as m, busLoggerOf as n, RegisteredCount as o, ReportThrottle as p, registrationFor as r, UnregisterSubscriber as s, Bus as t, Subscribe as u, EventMiddlewareMetadataKey as v, SubscribeMetadataKey as w, InteractionMetadataKey as x, GatedMetadataKey as y };
|
|
866
|
+
//# sourceMappingURL=Bus-BxPa-Uvp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Bus-BxPa-Uvp.mjs","names":[],"sources":["../src/components/botColorHolder.ts","../src/components/builderTypes.ts","../src/components/colors.ts","../src/components/resolveColor.ts","../src/components/Component.ts","../src/commands/contextMenuLeaves.ts","../src/miscellaneous/guarded.ts","../src/metadataKeys.ts","../src/reply/flags.ts","../src/subscribers/ReportThrottle.ts","../src/subscribers/Subscriber.ts","../src/subscribers/bases/webhookHelpers.ts","../src/subscribers/bases/WebhookSender.ts","../src/subscribers/bases/WebhookLog.ts","../src/subscribers/decorators/Subscribe.ts","../src/subscribers/decorators/WebhookUrl.ts","../src/subscribers/default/HandledException.ts","../src/subscribers/default/UnknownException.ts","../src/subscribers/slots.ts","../src/subscribers/Bus.ts"],"sourcesContent":["import type { BotColor } from '@seedcord/types';\n\n// must be 'Default' so the container guard in applyBotColor leaves the accent unset\nconst DEFAULT_COLOR: BotColor = 'Default';\n\nlet readBotColor: () => BotColor | undefined = () => undefined;\n\nexport function bindBotColor(read: () => BotColor | undefined): void {\n readBotColor = read;\n}\n\nexport function getBotColor(): BotColor {\n return readBotColor() ?? DEFAULT_COLOR;\n}\n","import {\n ActionRowBuilder,\n ButtonBuilder,\n ChannelSelectMenuBuilder,\n CheckboxBuilder,\n CheckboxGroupBuilder,\n CheckboxGroupOptionBuilder,\n ContainerBuilder,\n ContextMenuCommandBuilder,\n EmbedBuilder,\n FileBuilder,\n FileUploadBuilder,\n LabelBuilder,\n MediaGalleryBuilder,\n MentionableSelectMenuBuilder,\n ModalBuilder,\n RadioGroupBuilder,\n RadioGroupOptionBuilder,\n RoleSelectMenuBuilder,\n SectionBuilder,\n SeparatorBuilder,\n SlashCommandBuilder,\n SlashCommandSubcommandBuilder,\n SlashCommandSubcommandGroupBuilder,\n StringSelectMenuBuilder,\n StringSelectMenuOptionBuilder,\n TextDisplayBuilder,\n TextInputBuilder,\n UserSelectMenuBuilder\n} from '@discordjs/builders';\n\n/**\n * Available Discord.js builder classes for use with BuilderComponent for commands, embeds, modals, etc.\n *\n * @internal\n */\nexport const BuilderTypes = {\n // Command Components\n command: SlashCommandBuilder,\n context_menu: ContextMenuCommandBuilder,\n subcommand: SlashCommandSubcommandBuilder,\n group: SlashCommandSubcommandGroupBuilder,\n\n // Embed Components\n embed: EmbedBuilder,\n\n // Modal Components\n modal: ModalBuilder,\n label: LabelBuilder,\n text_input: TextInputBuilder,\n file_upload: FileUploadBuilder,\n checkbox: CheckboxBuilder,\n checkbox_group: CheckboxGroupBuilder,\n checkbox_group_option: CheckboxGroupOptionBuilder,\n radio_group: RadioGroupBuilder,\n radio_group_option: RadioGroupOptionBuilder,\n\n // Action Row Components\n button: ButtonBuilder,\n menu_string: StringSelectMenuBuilder,\n menu_option_string: StringSelectMenuOptionBuilder,\n menu_user: UserSelectMenuBuilder,\n menu_channel: ChannelSelectMenuBuilder,\n menu_mentionable: MentionableSelectMenuBuilder,\n menu_role: RoleSelectMenuBuilder,\n\n // ComponentsV2\n container: ContainerBuilder,\n text_display: TextDisplayBuilder,\n file: FileBuilder,\n media: MediaGalleryBuilder,\n section: SectionBuilder,\n separator: SeparatorBuilder\n};\n\n/**\n * Available Discord.js action row classes for use with RowComponent for Select Menus and Buttons\n *\n * @internal\n */\nexport const RowTypes: {\n button: typeof ActionRowBuilder<ButtonBuilder>;\n menu_string: typeof ActionRowBuilder<StringSelectMenuBuilder>;\n menu_user: typeof ActionRowBuilder<UserSelectMenuBuilder>;\n menu_channel: typeof ActionRowBuilder<ChannelSelectMenuBuilder>;\n menu_mentionable: typeof ActionRowBuilder<MentionableSelectMenuBuilder>;\n menu_role: typeof ActionRowBuilder<RoleSelectMenuBuilder>;\n} = {\n button: ActionRowBuilder<ButtonBuilder>,\n menu_string: ActionRowBuilder<StringSelectMenuBuilder>,\n menu_user: ActionRowBuilder<UserSelectMenuBuilder>,\n menu_channel: ActionRowBuilder<ChannelSelectMenuBuilder>,\n menu_mentionable: ActionRowBuilder<MentionableSelectMenuBuilder>,\n menu_role: ActionRowBuilder<RoleSelectMenuBuilder>\n};\n\n/**\n * Available Discord.js builder types for use with BuilderComponent\n */\nexport type BuilderType = keyof typeof BuilderTypes;\n\n/**\n * @internal\n */\nexport type InstantiatedBuilder<BuilderKey extends BuilderType> = InstanceType<(typeof BuilderTypes)[BuilderKey]>;\n\n/**\n * Available Discord.js action row types for use with RowComponent\n */\nexport type RowType = keyof typeof RowTypes;\n\n/**\n * @internal\n */\nexport type InstantiatedActionRow<RowKey extends RowType> = InstanceType<(typeof RowTypes)[RowKey]>;\n","import type { ColorName, TypedOmit } from '@seedcord/types';\n\n// ported verbatim from discord.js (Apache-2.0), src/util/Colors.js\nexport const Colors: TypedOmit<Record<ColorName, number>, 'Random'> = {\n Aqua: 0x1a_bc_9c,\n Blue: 0x34_98_db,\n Blurple: 0x58_65_f2,\n DarkAqua: 0x11_80_6a,\n DarkBlue: 0x20_66_94,\n DarkButNotBlack: 0x2c_2f_33,\n DarkerGrey: 0x7f_8c_8d,\n DarkGold: 0xc2_7c_0e,\n DarkGreen: 0x1f_8b_4c,\n DarkGrey: 0x97_9c_9f,\n DarkNavy: 0x2c_3e_50,\n DarkOrange: 0xa8_43_00,\n DarkPurple: 0x71_36_8a,\n DarkRed: 0x99_2d_22,\n DarkVividPink: 0xad_14_57,\n Default: 0x00_00_00,\n Fuchsia: 0xeb_45_9e,\n Gold: 0xf1_c4_0f,\n Green: 0x57_f2_87,\n Grey: 0x95_a5_a6,\n Greyple: 0x99_aa_b5,\n LightGrey: 0xbc_c0_c0,\n LuminousVividPink: 0xe9_1e_63,\n Navy: 0x34_49_5e,\n NotQuiteBlack: 0x23_27_2a,\n Orange: 0xe6_7e_22,\n Purple: 0x9b_59_b6,\n Red: 0xed_42_45,\n White: 0xff_ff_ff,\n Yellow: 0xfe_e7_5c\n} as const;\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, SeedcordTypeError } from '@seedcord/errors/internal';\n\nimport { Colors } from './colors';\n\nimport type { BotColor } from '@seedcord/types';\n\nconst MAX_COLOR = 0xff_ff_ff;\nconst RED_SHIFT = 16;\nconst GREEN_SHIFT = 8;\n\nconst palette: Record<string, number | undefined> = Colors;\n\n/**\n * Resolves a {@link BotColor} to the integer Discord expects.\n *\n * Ported from discord.js (Apache-2.0), `resolveColor` in src/util/Util.js.\n */\nexport function resolveColor(color: BotColor): number {\n let resolved: number | undefined;\n\n if (typeof color === 'string') {\n if (color === 'Random') return Math.floor(Math.random() * (MAX_COLOR + 1));\n if (color === 'Default') return 0;\n if (/^#?[\\da-f]{6}$/i.test(color)) return Number.parseInt(color.replace('#', ''), 16);\n resolved = palette[color];\n } else if (typeof color === 'number') {\n resolved = color;\n } else {\n resolved = (color[0] << RED_SHIFT) + (color[1] << GREEN_SHIFT) + color[2];\n }\n\n if (resolved === undefined || !Number.isSafeInteger(resolved)) {\n throw new SeedcordTypeError(SeedcordErrorCode.ColorUnresolvable, [JSON.stringify(color)]);\n }\n if (resolved < 0 || resolved > MAX_COLOR) {\n throw new SeedcordRangeError(SeedcordErrorCode.ColorOutOfRange);\n }\n\n return resolved;\n}\n","import { ContainerBuilder, ContextMenuCommandBuilder, EmbedBuilder, SlashCommandBuilder } from '@discordjs/builders';\nimport { InteractionContextType } from 'discord-api-types/v10';\n\nimport { getBotColor } from './botColorHolder';\nimport { BuilderTypes, RowTypes } from './builderTypes';\nimport { resolveColor } from './resolveColor';\n\nimport type { BuilderType, InstantiatedActionRow, InstantiatedBuilder, RowType } from './builderTypes';\n\n/** @internal */\nabstract class BaseComponent<TComponent> {\n private readonly _component: TComponent;\n\n protected constructor(ComponentClass: new () => TComponent) {\n this._component = new ComponentClass();\n }\n\n /**\n * Returns the live builder, ready to send in a Discord message or nest in another component.\n *\n * Reading this can apply the bot color (see {@link BuilderComponent}), so it has a side effect.\n * @example new SomeComponent().component\n */\n public abstract get component(): InstantiatedBuilder<BuilderType> | InstantiatedActionRow<RowType>;\n\n /**\n * The wrapped builder, for calling Discord.js methods like setTitle() and setDescription() inside a subclass.\n *\n * @example this.instance.setTitle('My Modal')\n */\n protected get instance(): TComponent {\n return this._component;\n }\n}\n\n/**\n * Base class for Discord.js builder components\n *\n * Wraps Discord.js builders (SlashCommandBuilder, EmbedBuilder, etc.) with\n * Seedcord-specific defaults and helper methods.\n *\n * @typeParam BuilderKey - The type of Discord.js builder being wrapped\n */\nexport abstract class BuilderComponent<BuilderKey extends BuilderType> extends BaseComponent<\n InstantiatedBuilder<BuilderKey>\n> {\n private colorApplied = false;\n\n protected constructor(public readonly type: BuilderKey) {\n const ComponentClass = BuilderTypes[type] as unknown;\n super(ComponentClass as new () => InstantiatedBuilder<BuilderKey>);\n\n if (this.instance instanceof SlashCommandBuilder || this.instance instanceof ContextMenuCommandBuilder) {\n this.instance.setContexts(InteractionContextType.Guild);\n }\n }\n\n get component(): InstantiatedBuilder<BuilderKey> {\n this.applyBotColor();\n return this.instance;\n }\n\n // this is so the bot color doesn't override an color set in this instance of the component\n private applyBotColor(): void {\n if (this.colorApplied) return;\n this.colorApplied = true;\n\n const color = getBotColor();\n if (this.instance instanceof EmbedBuilder) {\n if (this.instance.data.color === undefined) this.instance.setColor(resolveColor(color));\n } else if (this.instance instanceof ContainerBuilder) {\n const accent = this.instance.data.accent_color;\n if (accent === null || accent === undefined) {\n this.instance.setAccentColor(color === 'Default' ? undefined : resolveColor(color));\n }\n }\n }\n}\n\n// instanceof fails across the cli's separate module registry\nconst BUILDER_COMPONENT = Symbol.for('seedcord:core:builder-component');\n\nObject.defineProperty(BuilderComponent.prototype, BUILDER_COMPONENT, { value: true });\n\n/** @internal */\nexport function isBuilderComponentClass(value: unknown): value is new () => BuilderComponent<BuilderType> {\n if (typeof value !== 'function') return false;\n const proto: unknown = (value as { prototype?: unknown }).prototype;\n return typeof proto === 'object' && proto !== null && BUILDER_COMPONENT in proto;\n}\n\n/**\n * Base class for Discord action row components\n *\n * Wraps Discord.js action row builder with Seedcord-specific defaults and helper methods.\n *\n * @typeParam RowKey - The Discord.js action row type being wrapped\n */\nexport abstract class RowComponent<RowKey extends RowType> extends BaseComponent<InstantiatedActionRow<RowKey>> {\n protected constructor(public readonly type: RowKey) {\n const ComponentClass = RowTypes[type] as unknown;\n super(ComponentClass as new () => InstantiatedActionRow<RowKey>);\n }\n\n get component(): InstantiatedActionRow<RowKey> {\n return this.instance;\n }\n}\n","import { ContextMenuCommandBuilder } from '@discordjs/builders';\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport type { SlashCommandBuilder } from '@discordjs/builders';\n\n/** @internal */\nexport interface ContextMenuLeaves {\n readonly user: Set<string>;\n readonly message: Set<string>;\n}\n\n/**\n * dedupes names across builders, since the same builder repeats once per guild.\n * a user and a message command can share a name.\n *\n * @internal\n */\nexport function contextMenuLeaves(\n commands: Iterable<SlashCommandBuilder | ContextMenuCommandBuilder>\n): ContextMenuLeaves {\n const user = new Set<string>();\n const message = new Set<string>();\n for (const command of commands) {\n if (!(command instanceof ContextMenuCommandBuilder)) continue;\n if (command.type === ApplicationCommandType.User) user.add(command.name);\n else message.add(command.name);\n }\n return { user, message };\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// null-prototype, on a plain object a key named __proto__ sets the store's prototype and adds no entry\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\nexport function clearStore(store: Record<string, unknown>): void {\n for (const key of Object.keys(store)) Reflect.deleteProperty(store, key);\n}\n\n// handler modules import before startup fills the record, and an unguarded read there returns undefined and renders as an empty string\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 type { TypedExclude } from '@seedcord/types';\n\n/**\n * Every interaction kind seedcord routes.\n */\nexport enum InteractionKind {\n Slash = 'slash',\n Button = 'button',\n Modal = 'modal',\n StringMenu = 'stringMenu',\n UserMenu = 'userMenu',\n RoleMenu = 'roleMenu',\n ChannelMenu = 'channelMenu',\n MentionableMenu = 'mentionableMenu',\n MessageContextMenu = 'messageContextMenu',\n UserContextMenu = 'userContextMenu',\n Autocomplete = 'autocomplete'\n}\n\n/**\n * The interaction kinds a middleware can filter on. Autocomplete carries no reply target.\n */\nexport type MiddlewareKind = TypedExclude<InteractionKind, InteractionKind.Autocomplete>;\n\n// Symbol.for so a second copy of this module reads the same slots\nexport const CommandMetadataKey = Symbol.for('seedcord:command:metadata');\nexport const InteractionMetadataKey = Symbol.for('seedcord:interaction:metadata');\nexport const InteractionMiddlewareMetadataKey = Symbol.for('seedcord:middleware:interaction:metadata');\nexport const EventMiddlewareMetadataKey = Symbol.for('seedcord:middleware:event:metadata');\nexport const SubscribeMetadataKey = Symbol.for('seedcord:subscribe:metadata');\nexport const EventMetadataKey = Symbol.for('seedcord:event:metadata');\nexport const GatedMetadataKey = Symbol.for('seedcord:gated:metadata');\nexport const WebhookUrlMetadataKey = Symbol.for('seedcord:webhook-url:metadata');\n\nexport const InteractionRouteKeys: Record<InteractionKind, symbol> = {\n [InteractionKind.Slash]: Symbol.for('seedcord:interaction:slash'),\n [InteractionKind.Button]: Symbol.for('seedcord:interaction:button'),\n [InteractionKind.Modal]: Symbol.for('seedcord:interaction:modal'),\n [InteractionKind.StringMenu]: Symbol.for('seedcord:interaction:string-menu'),\n [InteractionKind.UserMenu]: Symbol.for('seedcord:interaction:user-menu'),\n [InteractionKind.RoleMenu]: Symbol.for('seedcord:interaction:role-menu'),\n [InteractionKind.ChannelMenu]: Symbol.for('seedcord:interaction:channel-menu'),\n [InteractionKind.MentionableMenu]: Symbol.for('seedcord:interaction:mentionable-menu'),\n [InteractionKind.MessageContextMenu]: Symbol.for('seedcord:interaction:message-context-menu'),\n [InteractionKind.UserContextMenu]: Symbol.for('seedcord:interaction:user-context-menu'),\n [InteractionKind.Autocomplete]: Symbol.for('seedcord:interaction:autocomplete')\n};\n","import { MessageFlags } from 'discord-api-types/v10';\n\nimport type { DeferOpts, SendOpts } from '@seedcord/types';\n\n// IsComponentsV2 is unconditional, since every framework reply is v2\nexport function sendFlags(opts?: SendOpts): number {\n let flags = MessageFlags.IsComponentsV2;\n if (opts?.ephemeral ?? true) flags |= MessageFlags.Ephemeral;\n if (opts?.silent) flags |= MessageFlags.SuppressNotifications;\n return flags;\n}\n\n// a deferral carries no content\nexport function deferFlags(opts?: DeferOpts): number {\n return (opts?.ephemeral ?? true) ? MessageFlags.Ephemeral : 0;\n}\n","interface ThrottleWindow {\n lastSentAt: number;\n suppressedSinceSend: number;\n}\n\nexport class ReportThrottle {\n private static readonly perCore = new WeakMap<object, ReportThrottle>();\n\n public static for(core: object): ReportThrottle {\n let throttle = ReportThrottle.perCore.get(core);\n if (!throttle) {\n throttle = new ReportThrottle();\n ReportThrottle.perCore.set(core, throttle);\n }\n return throttle;\n }\n\n private readonly windows = new Map<string, ThrottleWindow>();\n\n constructor(\n private readonly windowMs = 60_000,\n private readonly now: () => number = () => Date.now()\n ) {}\n\n // null while the window is open, otherwise how many were dropped since the last send\n public take(key: string): number | null {\n const window = this.windows.get(key);\n if (window && this.now() - window.lastSentAt < this.windowMs) {\n window.suppressedSinceSend += 1;\n return null;\n }\n\n const suppressed = window?.suppressedSinceSend ?? 0;\n this.windows.set(key, { lastSentAt: this.now(), suppressedSinceSend: 0 });\n return suppressed;\n }\n\n // gives a failed send's count to the open window, plus the one card that never went out\n public restore(key: string, suppressed: number): void {\n const window = this.windows.get(key);\n if (window) window.suppressedSinceSend += suppressed + 1;\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { SubscriptionKey, AllSubscriptions } from './types/Subscriptions';\n\n/**\n * Abstract base class for handling application subscribers.\n *\n * Provides type-safe access to subscribers data and the core framework instance.\n * Extend this class to create custom subscriber handlers.\n *\n * @typeParam KeyOfSubscribers - The specific subscriber type this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey, TCore extends CoreBase> {\n protected readonly logger: Logger;\n\n /**\n * Instantiates the subscriber with event data and core.\n *\n * @param data - The subscriber event data\n * @param core - The core framework instance\n */\n constructor(\n protected readonly data: AllSubscriptions[KeyOfSubscribers],\n protected readonly core: TCore\n ) {\n this.logger = new Logger(this.constructor.name, { channel: 'subscribers' });\n }\n\n /**\n * Executes the subscriber handler logic.\n */\n abstract execute(): Promise<void>;\n}\n","import { filterCirculars, stripAnsi } from '@seedcord/utils';\nimport { SeparatorSpacingSize } from 'discord-api-types/v10';\n\nimport { BuilderComponent } from '#components/Component';\n\nimport type { WebhookFile } from './WebhookSender';\n\nconst DISCORD_WEBHOOK_REGEX = new RegExp(\n String.raw`^https?:\\/\\/(?:canary\\.|ptb\\.)?discord(?:app)?\\.com\\/api\\/webhooks\\/\\d+\\/[\\w$-]+$`\n);\n\nexport function isDiscordWebhookUrl(value: string): boolean {\n return URL.canParse(value) && DISCORD_WEBHOOK_REGEX.test(value);\n}\n\nexport function jsonAttachment(name: string, description: string, data: unknown): WebhookFile {\n const content = filterCirculars(data);\n return { name, description, data: new TextEncoder().encode(JSON.stringify(content, undefined, 2)) };\n}\n\n// the report goes inside a ``` code block, so a stray ``` in the text would close it early\nexport function breakBackticks(text: string): string {\n return text.replaceAll('```', '```');\n}\n\n// discord caps a message at 2000 characters. the backticks and heading take the rest.\nconst REPORT_BUDGET = 1800;\n\n// breakBackticks grows the text by 2 chars per run\nfunction body(value: unknown): string {\n const raw = Error.isError(value) ? (value.stack ?? `${value.name}: ${value.message}`) : String(value);\n return breakBackticks(stripAnsi(raw));\n}\n\nfunction clamp(text: string, budget: number): string {\n if (text.length <= budget) return text;\n return budget > 0 ? `${text.slice(0, budget - 1)}…` : '';\n}\n\nfunction omittedLine(count: number): string {\n return `\\n\\nand ${count} more failure${count === 1 ? '' : 's'}`;\n}\n\nfunction memberReport(members: readonly unknown[], budget: number): string {\n // the dropped-count line has to fit even when every member is dropped\n const room = Math.max(budget - omittedLine(members.length).length, 0);\n const share = Math.floor(room / members.length);\n\n let report = '';\n let shown = 0;\n for (const [index, member] of members.entries()) {\n const heading = `\\n\\nFailure ${index + 1} of ${members.length}:\\n`;\n const entry = heading + clamp(body(member), Math.max(share - heading.length, 0));\n if (report.length + entry.length > room) break;\n report += entry;\n shown++;\n }\n\n const hidden = members.length - shown;\n return hidden > 0 ? report + omittedLine(hidden) : report;\n}\n\n// ansi codes are stripped because discord won't render them\nexport function errorReport(error: Error): string {\n let head = body(error);\n if (Error.isError(error.cause)) head += `\\n\\nCaused by:\\n${body(error.cause)}`;\n\n const members: unknown[] = error instanceof AggregateError ? error.errors : [];\n if (members.length === 0) return clamp(head, REPORT_BUDGET);\n\n // a long parent stack would otherwise push the dropped-count line off the end\n const report = clamp(head, REPORT_BUDGET - omittedLine(members.length).length);\n return report + memberReport(members, REPORT_BUDGET - report.length);\n}\n\nexport class WebhookSeparator extends BuilderComponent<'separator'> {\n constructor() {\n super('separator');\n this.instance.setSpacing(SeparatorSpacingSize.Small).setDivider(true);\n }\n}\n","import { DiscordAPIError, REST } from '@discordjs/rest';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordTypeError } from '@seedcord/errors/internal';\nimport { Routes } from 'discord-api-types/v10';\n\nimport type { ReplyFile } from '@seedcord/types';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\nconst HTTP_NOT_FOUND = 404;\nconst HTTP_UNAUTHORIZED = 401;\n\n/** A file attached to a webhook report. */\nexport interface WebhookFile extends ReplyFile {\n readonly description: string;\n}\n\nexport interface WebhookSendOptions {\n flags: number;\n username: string;\n avatarUrl?: string | undefined;\n components: readonly { toJSON(): APIMessageTopLevelComponent }[];\n files?: readonly WebhookFile[] | undefined;\n}\n\nexport class WebhookSender {\n private readonly rest = new REST();\n private readonly route: `/${string}`;\n\n constructor(url: string) {\n const match = /\\/webhooks\\/(\\d+)\\/([\\w$-]+)$/.exec(url);\n if (!match?.[1] || !match[2])\n throw new SeedcordTypeError(SeedcordErrorCode.ConfigWebhookUrlInvalid, ['The url']);\n this.route = Routes.webhook(match[1], match[2]);\n }\n\n // missing means discord answered 404 or 401\n async verify(): Promise<'ok' | 'missing' | 'unreachable'> {\n try {\n await this.rest.get(this.route, { auth: false });\n return 'ok';\n } catch (error) {\n const gone =\n error instanceof DiscordAPIError &&\n (error.status === HTTP_NOT_FOUND || error.status === HTTP_UNAUTHORIZED);\n return gone ? 'missing' : 'unreachable';\n }\n }\n\n async send(options: WebhookSendOptions): Promise<void> {\n const { flags, username, avatarUrl, components, files } = options;\n await this.rest.post(this.route, {\n auth: false,\n // with_components=true makes discord accept a components-v2 payload. wait=true makes it\n // return payload errors in the response\n query: new URLSearchParams({ with_components: 'true', wait: 'true' }),\n body: {\n flags,\n username,\n ...(avatarUrl && { avatar_url: avatarUrl }),\n components: components.map((component) => component.toJSON()),\n ...(files?.length && {\n attachments: files.map((file, id) => ({ id, filename: file.name, description: file.description }))\n })\n },\n ...(files?.length && { files: files.map((file) => ({ name: file.name, data: file.data })) })\n });\n }\n}\n","import { SeedcordErrorCode, paint } from '@seedcord/errors';\nimport { SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { Converters, Envapter } from 'envapt';\n\nimport { sendFlags } from '#reply/flags';\nimport { WebhookUrlMetadataKey } from '#src/metadataKeys';\nimport { ReportThrottle } from '#subscribers/ReportThrottle';\nimport { Subscriber } from '#subscribers/Subscriber';\n\nimport { isDiscordWebhookUrl } from './webhookHelpers';\nimport { WebhookSender } from './WebhookSender';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { SubscriptionKey } from '#subscribers/types/Subscriptions';\nimport type { WebhookFile } from './WebhookSender';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\n/**\n * The content a reporter returns from {@link WebhookLog.report}.\n */\nexport interface WebhookReport {\n /** Shown as the webhook message author. Defaults to the reporter's class name. */\n username?: string;\n /** Shown as the webhook message avatar. Defaults to the webhook's own. */\n avatarUrl?: string;\n components: readonly { toJSON(): APIMessageTopLevelComponent }[];\n files?: readonly WebhookFile[] | undefined;\n}\n\n/**\n * Base class for subscribers that deliver their event to a Discord webhook.\n *\n * Declare the url's environment variable with `@WebhookUrl` and implement {@link report}. The base\n * resolves the url, validates it, reuses one sender per url, and sends. Registration skips a reporter\n * whose variable is unset and warns at boot.\n *\n * @typeParam KeyOfSubscribers - The subscription key this reporter receives\n * @typeParam TCore - The transport's Core\n */\nexport abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey, TCore extends CoreBase> extends Subscriber<\n KeyOfSubscribers,\n TCore\n> {\n private static readonly senders = new Map<string, WebhookSender>();\n\n /**\n * Builds the message for one published event.\n *\n * @param suppressed - How many events were dropped since the last card\n */\n abstract report(suppressed: number): WebhookReport | Promise<WebhookReport>;\n\n /**\n * Events sharing this key collapse into one card per minute. Return `null` to send every event.\n */\n protected throttleKey(): string | null {\n return null;\n }\n\n async execute(): Promise<void> {\n const envKey = WebhookLog.envKeyOf(this.constructor);\n const url = WebhookLog.urlOf(envKey);\n // Bus.probeWebhook dropped every url-less reporter at registration. reaching this means the env changed since.\n if (url === null) throw new SeedcordError(SeedcordErrorCode.ConfigMissingEnv, [envKey]);\n\n const key = this.throttleKey();\n const throttle = ReportThrottle.for(this.core);\n const suppressed = key === null ? 0 : throttle.take(key);\n if (suppressed === null) {\n this.logger.debug(`counted a repeat into the next ${paint.sky.bold(this.constructor.name)} card`);\n return;\n }\n\n try {\n const { username, avatarUrl, components, files } = await this.report(suppressed);\n await WebhookLog.senderFor(url).send({\n flags: sendFlags({ ephemeral: false }),\n username: username ?? this.constructor.name,\n avatarUrl,\n components,\n files\n });\n } catch (error) {\n if (key !== null) throttle.restore(key, suppressed);\n this.logger.error('Webhook report failed', error);\n }\n }\n\n /** @internal */\n static senderFor(url: string): WebhookSender {\n let sender = WebhookLog.senders.get(url);\n if (!sender) {\n sender = new WebhookSender(url);\n WebhookLog.senders.set(url, sender);\n }\n return sender;\n }\n\n /** @internal */\n static envKeyOf(ctor: NewableFunction): string {\n const envKey = Reflect.getMetadata(WebhookUrlMetadataKey, ctor) as string | undefined;\n if (!envKey) throw new SeedcordError(SeedcordErrorCode.DecoratorWebhookUrlMissing, [ctor.name]);\n return envKey;\n }\n\n /** @internal Returns null when the env var is unset, throws when set but malformed. */\n static urlOf(envKey: string): string | null {\n if (!Envapter.has(envKey)) return null;\n const raw = Envapter.getRequired(envKey, Converters.String).trim();\n if (raw === '') return null;\n if (!isDiscordWebhookUrl(raw)) throw new SeedcordTypeError(SeedcordErrorCode.ConfigWebhookUrlInvalid, [envKey]);\n return raw;\n }\n}\n","// the default reporters are decorated at Bus module load, before any entry's own polyfill import runs\nimport 'reflect-metadata';\n\nimport { SubscribeMetadataKey } from '#src/metadataKeys';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { Subscriber } from '#subscribers/Subscriber';\nimport type { SubscriptionKey } from '#subscribers/types/Subscriptions';\nimport type { EventFrequency } from '@seedcord/types';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Options accepted by the `@Subscribe` decorator.\n */\nexport interface SubscribeOptions {\n /**\n * Frequency: `'once'` or `'on'`.\n *\n * @defaultValue `'on'`\n */\n readonly frequency?: EventFrequency | undefined;\n}\n\n/** @internal */\nexport interface SubscribeMetadataEntry {\n readonly subscriber: SubscriptionKey;\n readonly frequency?: EventFrequency | undefined;\n}\n\n/**\n * Registers a subscriber handler class with a specific subscriber event.\n *\n * Associates the decorated class with a subscriber event type for automatic\n * registration and execution when the subscriber is emitted.\n *\n * @typeParam TSubscriber - The subscriber event name to register for\n * @param subscriber - The subscriber event name to register for\n * @param options - Options to configure the subscriber handler registration.\n * @decorator\n * @example\n * ```typescript\n * \\@Subscribe('userJoin')\n * class WelcomeHandler extends Subscriber<'userJoin'> {\n * async execute() {\n * }\n * }\n * ```\n * @example\n * ```ts\n * \\@Subscribe('userJoin', { frequency: 'once' })\n * // or\n * \\@Subscribe('userJoin')\n * ```\n */\nexport function Subscribe<TSubscriber extends SubscriptionKey>(subscriber: TSubscriber, options?: SubscribeOptions) {\n return function <HandlerCtor extends Constructor<Subscriber<TSubscriber, CoreBase>>>(\n constructor: HandlerCtor\n ): void {\n const meta: SubscribeMetadataEntry = {\n subscriber,\n frequency: options?.frequency\n };\n\n Reflect.defineMetadata(SubscribeMetadataKey, meta, constructor);\n };\n}\n","import 'reflect-metadata';\n\nimport { WebhookUrlMetadataKey } from '#src/metadataKeys';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { WebhookLog } from '#subscribers/bases/WebhookLog';\nimport type { SubscriptionKey } from '#subscribers/types/Subscriptions';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Declares the environment variable a {@link WebhookLog} reporter reads its webhook url from.\n *\n * An unset variable disables the reporter with a boot warning. A set but malformed value throws\n * at boot.\n *\n * @param envKey - The environment variable name holding the webhook url\n * @decorator\n * @example\n * ```ts\n * \\@Subscribe('memberBanned')\n * \\@WebhookUrl('BAN_LOG_WEBHOOK_URL')\n * class BanLog extends WebhookLog<'memberBanned'> {\n * report() {\n * return { components: [new BanCard(this.data).component] };\n * }\n * }\n * ```\n */\nexport function WebhookUrl(envKey: string) {\n return function <HandlerCtor extends Constructor<WebhookLog<SubscriptionKey, CoreBase>>>(\n constructor: HandlerCtor\n ): void {\n Reflect.defineMetadata(WebhookUrlMetadataKey, envKey, constructor);\n };\n}\n","import { stripAnsi } from '@seedcord/utils';\n\nimport { BuilderComponent } from '#components/Component';\nimport { breakBackticks, jsonAttachment, WebhookSeparator } from '#subscribers/bases/webhookHelpers';\nimport { WebhookLog } from '#subscribers/bases/WebhookLog';\nimport { Subscribe } from '#subscribers/decorators/Subscribe';\nimport { WebhookUrl } from '#subscribers/decorators/WebhookUrl';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { Notice } from '#stops/Notice';\nimport type { WebhookReport } from '#subscribers/bases/WebhookLog';\nimport type { AllSubscriptions, FaultSource } from '#subscribers/types/Subscriptions';\n\n// no HANDLED_EXCEPTION_WEBHOOK_URL disables the reporter with a boot warning\n@Subscribe('handledException')\n@WebhookUrl('HANDLED_EXCEPTION_WEBHOOK_URL')\nexport class HandledException extends WebhookLog<'handledException', CoreBase> {\n protected override throttleKey(): string {\n return `handledException:${this.data.origin}:${this.data.denial.name}`;\n }\n\n report(suppressed: number): WebhookReport {\n return {\n username: 'Handled Exception',\n components: [new HandledExceptionContainer(this.data, suppressed).component],\n files: [jsonAttachment('source.json', 'The raw source the fault came from', this.data.source.raw)]\n };\n }\n}\n\nclass HandledExceptionContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['handledException'], suppressed: number) {\n super('container');\n\n const { denial, uuid, source } = data;\n\n this.instance\n .addTextDisplayComponents((text) => text.setContent(faultSummary(denial, source)))\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(`### UUID \\`${uuid}\\`\\n\\`\\`\\`${breakBackticks(causeStack(denial))}\\`\\`\\``)\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Source'))\n .addFileComponents((file) => file.setURL('attachment://source.json'));\n\n this.addSuppressedCount(suppressed);\n }\n\n private addSuppressedCount(suppressed: number): void {\n if (suppressed === 0) return;\n\n this.instance.addTextDisplayComponents((text) =>\n text.setContent(`-# ${suppressed} more of these since the last report`)\n );\n }\n}\n\nfunction faultSummary(denial: Notice, source: FaultSource): string {\n // name and message carry chalk codes\n const head = stripAnsi(`### A handled fault was reported: \\`${denial.name}\\`\\n**Message:** ${denial.message}\\n`);\n if (source.kind === 'event') {\n return (\n `${head}**Event:** ${source.eventName}\\n` +\n `**Handler:** ${source.handler}\\n` +\n `**User ID:** \\`${source.userId ?? 'n/a'}\\`\\n` +\n `**Guild ID:** \\`${source.guildId ?? 'n/a'}\\`\\n` +\n `**Channel ID:** \\`${source.channelId ?? 'n/a'}\\``\n );\n }\n return (\n `${head}**Kind:** ${source.interactionKind}\\n` +\n `**Command:** ${source.command ?? 'n/a'}\\n` +\n `**CustomId:** ${source.customId ?? 'n/a'}\\n` +\n `**User ID:** \\`${source.userId}\\`\\n` +\n `**Guild ID:** \\`${source.guildId ?? 'n/a'}\\`\\n` +\n `**Channel ID:** \\`${source.channelId ?? 'n/a'}\\`\\n` +\n `**Interaction ID:** \\`${source.interactionId}\\``\n );\n}\n\n// building the report must not throw on a bigint or a circular cause\nfunction causeStack(denial: Notice): string {\n const { cause } = denial;\n if (Error.isError(cause)) return stripAnsi(cause.stack ?? cause.message);\n if (typeof cause === 'string') return stripAnsi(cause);\n if (typeof cause === 'bigint' || typeof cause === 'symbol' || typeof cause === 'function') return cause.toString();\n if (cause !== undefined) {\n try {\n return JSON.stringify(cause);\n } catch {\n return '[unserializable cause]';\n }\n }\n return stripAnsi(denial.stack ?? 'No cause recorded.');\n}\n","import { DiscordAPIError } from '@discordjs/rest';\nimport { timestampFromSnowflake } from '@seedcord/utils';\n\nimport { BuilderComponent } from '#components/Component';\nimport { errorReport, jsonAttachment, WebhookSeparator } from '#subscribers/bases/webhookHelpers';\nimport { WebhookLog } from '#subscribers/bases/WebhookLog';\nimport { Subscribe } from '#subscribers/decorators/Subscribe';\nimport { WebhookUrl } from '#subscribers/decorators/WebhookUrl';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { WebhookReport } from '#subscribers/bases/WebhookLog';\nimport type { AllSubscriptions } from '#subscribers/types/Subscriptions';\n\n// no UNKNOWN_EXCEPTION_WEBHOOK_URL disables the reporter with a boot warning\n@Subscribe('unknownException')\n@WebhookUrl('UNKNOWN_EXCEPTION_WEBHOOK_URL')\nexport class UnknownException extends WebhookLog<'unknownException', CoreBase> {\n protected override throttleKey(): string {\n return `unknownException:${this.data.origin}:${nameOf(this.data.error)}`;\n }\n\n report(suppressed: number): WebhookReport {\n const { metadata } = this.data;\n return {\n username: 'Unknown Exception',\n components: [new UnhandledErrorContainer(this.data, suppressed).component],\n files: metadata\n ? [jsonAttachment('metadata.json', 'Metadata associated with the error', metadata)]\n : undefined\n };\n }\n}\n\n// discord.js puts the api code in the name, as `DiscordAPIError[10062]`\nfunction nameOf(error: Error): string {\n return error.name === 'Error' ? error.constructor.name : error.name;\n}\n\nclass UnhandledErrorContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['unknownException'], suppressed: number) {\n super('container');\n\n const { uuid, error, guild, user, metadata } = data;\n\n this.instance\n .addTextDisplayComponents((text) =>\n text.setContent(\n `### An unknown exception was thrown\\n` +\n `**Guild ID:** \\`${guild?.id ?? 'Not used in a guild'}\\`\\n` +\n `**Guild Name:** ${guild?.name ?? 'Not used in a guild'}\\n` +\n `**User ID:** \\`${user?.id ?? 'Missing user info'}\\`\\n` +\n `**Username:** ${user?.username ?? 'Missing user info'}\\n`\n )\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(`### UUID \\`${uuid}\\`\\n\\`\\`\\`${errorReport(error)}\\`\\`\\``)\n );\n\n this.addTimestampsIfAvailable(error);\n this.addMetadataIfAvailable(metadata);\n this.addSuppressedCount(suppressed);\n }\n\n private addSuppressedCount(suppressed: number): void {\n if (suppressed === 0) return;\n\n this.instance.addTextDisplayComponents((text) =>\n text.setContent(`-# ${suppressed} more of these since the last report`)\n );\n }\n\n private addTimestampsIfAvailable(error: Error): void {\n if (!(error instanceof DiscordAPIError)) return;\n\n const now = Date.now();\n\n const snowflake = error.url.match(/\\/interactions\\/(\\d+)\\//)?.[1];\n if (!snowflake) return undefined;\n\n const interactionTs = timestampFromSnowflake(snowflake);\n\n const diff = now - interactionTs;\n const seconds = Math.floor(diff / 1000);\n const millis = diff % 1000;\n\n this.instance\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(\n `### Timestamps\\n` +\n `- **\\`Interaction sent\\` :** ${new Date(interactionTs).toISOString()} (${interactionTs})\\n` +\n `- **\\`Error logged \\` :** ${new Date(now).toISOString()} (${now})\\n` +\n `- **\\`Offset \\` :** ${seconds}s ${millis}ms`\n )\n );\n }\n\n private addMetadataIfAvailable(metadata: unknown): void {\n if (!metadata) return;\n\n this.instance\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Metadata'))\n .addFileComponents((file) => file.setURL('attachment://metadata.json'));\n }\n}\n","// the framework's own Bus calls. a bot author reaches the Bus through publish() and a Subscriber subclass\nexport const RegisterDefaults = Symbol('seedcord:bus:register-defaults');\nexport const VerifyWebhooks = Symbol('seedcord:bus:verify-webhooks');\nexport const RegisteredCount = Symbol('seedcord:bus:registered-count');\nexport const RegisterSubscriber = Symbol('seedcord:bus:register');\nexport const UnregisterSubscriber = Symbol('seedcord:bus:unregister');\n","import { SeedcordErrorCode, paint } from '@seedcord/errors';\nimport { SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { TypedEventEmitter } from '@seedcord/event-emitter';\nimport { Logger } from '@seedcord/logger';\n\nimport { SubscribeMetadataKey } from '#src/metadataKeys';\n\nimport { WebhookLog } from './bases/WebhookLog';\nimport { HandledException } from './default/HandledException';\nimport { UnknownException } from './default/UnknownException';\nimport { PublishDefault } from './publishDefault';\nimport { RegisterDefaults, RegisteredCount, RegisterSubscriber, UnregisterSubscriber, VerifyWebhooks } from './slots';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { SubscribeMetadataEntry } from './decorators/Subscribe';\nimport type { Subscriber } from './Subscriber';\nimport type {\n AllSubscriptions,\n DefaultSubscriptions,\n PublishableKey,\n SubscriptionKey,\n SubscriptionTuples\n} from './types/Subscriptions';\nimport type { EventFrequency, TypedConstructor } from '@seedcord/types';\nimport type { Constructor } from 'type-fest';\n\n// typed construct parameters would exclude every subscriber that narrows them\n/** @internal */\nexport type StoredSubscriberCtor = Constructor<Subscriber<SubscriptionKey, CoreBase>, never[]>;\n\n/** @internal */\nexport interface SubscriberRegistration {\n readonly keys: readonly SubscriptionKey[];\n readonly frequency: EventFrequency;\n readonly ctor: StoredSubscriberCtor;\n}\n\nconst loggerSlot = Symbol('seedcord:bus:logger');\n\n/**\n * Registers and dispatches subscribers. Subscribers run on a programmatic or framework publish.\n * Accessed via `core.bus`. Do not construct it directly.\n */\nexport class Bus extends TypedEventEmitter<SubscriptionTuples> {\n private readonly logger = new Logger('Subscribers', { channel: 'subscribers' });\n\n /** @internal */\n readonly [loggerSlot]: Logger = this.logger;\n\n private readonly subscribersMap = new Map<SubscriptionKey, SubscriberRegistration[]>();\n private readonly executedOnce = new Set<SubscriberRegistration>();\n // url -> env keys\n private readonly webhookProbes = new Map<string, string[]>();\n\n constructor(protected core: CoreBase) {\n super();\n }\n\n /** @internal keep this inside start(). a bad webhook url thrown outside it never resets the singleton guard */\n public [RegisterDefaults](): void {\n this[RegisterSubscriber](registrationFor(UnknownException));\n this[RegisterSubscriber](registrationFor(HandledException));\n }\n\n /** @internal */\n public [RegisterSubscriber](registration: SubscriberRegistration): void {\n if (!this.probeWebhook(registration.ctor)) return;\n\n for (const key of registration.keys) {\n let registrations = this.subscribersMap.get(key);\n if (!registrations) {\n registrations = [];\n this.subscribersMap.set(key, registrations);\n }\n registrations.push(registration);\n }\n }\n\n /** @internal */\n public [UnregisterSubscriber](ctor: StoredSubscriberCtor, keys?: readonly SubscriptionKey[]): void {\n for (const key of keys ?? [...this.subscribersMap.keys()]) {\n const registrations = this.subscribersMap.get(key);\n if (!registrations) continue;\n const index = registrations.findIndex((entry) => entry.ctor === ctor);\n if (index !== -1) registrations.splice(index, 1);\n }\n // a re-registered subscriber runs again because executedOnce is keyed by registration identity\n }\n\n /** @internal */\n public get [RegisteredCount](): number {\n return [...this.subscribersMap.values()].reduce((total, entries) => total + entries.length, 0);\n }\n\n /** @internal registration already dropped every reporter with no url set */\n public async [VerifyWebhooks](): Promise<void> {\n const missing: string[] = [];\n await Promise.all(\n [...this.webhookProbes].map(async ([url, envKeys]) => {\n const result = await WebhookLog.senderFor(url).verify();\n if (result === 'missing') missing.push(...envKeys);\n else if (result === 'unreachable')\n this.logger.warn(\n `could not verify webhook at ${envKeys.map((key) => paint.amber.bold(key)).join(', ')}`\n );\n })\n );\n // collected first so one throw names every missing webhook\n if (missing.length > 0) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookNotFound, [missing.join(', ')]);\n }\n\n // true means the class registers\n private probeWebhook(ctor: StoredSubscriberCtor): boolean {\n if (!(ctor.prototype instanceof WebhookLog)) return true;\n\n const envKey = WebhookLog.envKeyOf(ctor);\n const url = WebhookLog.urlOf(envKey);\n if (url === null) {\n this.logger.warn(`${paint.sky.bold(ctor.name)} disabled, ${paint.amber.bold(envKey)} is not set`);\n return false;\n }\n const envKeys = this.webhookProbes.get(url) ?? [];\n if (!envKeys.includes(envKey)) envKeys.push(envKey);\n this.webhookProbes.set(url, envKeys);\n return true;\n }\n\n /**\n * Publishes an event to its subscribers and native listeners.\n *\n * Fire-and-forget. Subscriber handlers run asynchronously and this returns before they finish.\n * Errors thrown by a subscriber or by an `on()` listener are caught and logged, never surfaced\n * here. One throwing listener does not stop the others. Subscribers on one key run concurrently\n * and carry no ordering guarantee. A `'once'` subscriber is marked as executed when it starts,\n * even if it throws. It never runs twice.\n *\n * The framework's own keys are excluded. Subscribe to those and listen with `on`. The framework\n * is their only publisher.\n *\n * @param event - The subscription key to publish\n * @param data - Payload passed to each subscriber\n * @returns Whether the underlying emitter had native listeners for the event\n */\n public publish<KeyOfSubscribers extends PublishableKey>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n return this.dispatchKey(event, data);\n }\n\n /**\n * @deprecated Always throws. Call {@link Bus.publish} to reach subscribers and listeners together.\n * @throws A **SeedcordTypeError** with `CoreBusEmitUnavailable`. `emit` reaches only the `on()` listeners.\n */\n public override emit<KeyOfSubscribers extends SubscriptionKey>(\n event: KeyOfSubscribers,\n ..._args: SubscriptionTuples[KeyOfSubscribers]\n ): never {\n throw new SeedcordTypeError(SeedcordErrorCode.CoreBusEmitUnavailable, [String(event)]);\n }\n\n /** @internal the framework's own publish path, keyed by a symbol no public entry exports */\n public [PublishDefault]<KeyOfSubscribers extends keyof DefaultSubscriptions>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n return this.dispatchKey(event, data);\n }\n\n private dispatchKey<KeyOfSubscribers extends SubscriptionKey>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n void this.processSubscriber(event, data);\n // justified: a generic key can't reduce SubscriptionTuples[K], but data is this event's payload by the signature\n return this.emitSafe(event, ...([data] as SubscriptionTuples[KeyOfSubscribers]));\n }\n\n protected override onListenerError(error: unknown, event: string | symbol): void {\n this.logger.error(`listener for ${String(event)} threw`, error);\n }\n\n private async processSubscriber<KeyOfSubscribers extends SubscriptionKey>(\n subscriberName: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): Promise<void> {\n const registrations = this.subscribersMap.get(subscriberName);\n if (!registrations) return;\n\n const pending = registrations.reduce<Promise<void>[]>((acc, entry) => {\n if (entry.frequency === 'once') {\n if (this.executedOnce.has(entry)) return acc;\n // mark before awaiting, so a re-entrant publish can't run a 'once' subscriber twice mid-flight\n this.executedOnce.add(entry);\n }\n acc.push(this.runSubscriber(entry, subscriberName, data));\n return acc;\n }, []);\n\n await Promise.allSettled(pending);\n }\n\n private async runSubscriber<KeyOfSubscribers extends SubscriptionKey>(\n entry: SubscriberRegistration,\n subscriberName: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): Promise<void> {\n // named outside the try so the catch can say which subscriber threw\n let name = '<unresolved>';\n try {\n // data matches this ctor's payload arm because the registration keyed it to its subscriptions\n const Ctor = entry.ctor as TypedConstructor<typeof Subscriber>;\n name = Ctor.name;\n await new Ctor(data, this.core).execute();\n } catch (err) {\n this.logger.error(\n `Error in subscriber ${paint.mute(String(subscriberName))} handler ${paint.sky.bold(name)}:`,\n err\n );\n }\n }\n}\n\n// every caller already checked that the Subscribe metadata is there\n/** @internal */\nexport function registrationFor(ctor: StoredSubscriberCtor): SubscriberRegistration {\n const meta = Reflect.getMetadata(SubscribeMetadataKey, ctor) as SubscribeMetadataEntry;\n return { keys: [meta.subscriber], frequency: meta.frequency ?? 'on', ctor };\n}\n\n/** @internal */\nexport function busLoggerOf(bus: Bus): Logger {\n return bus[loggerSlot];\n}\n"],"mappings":"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"}
|
|
@@ -37,19 +37,48 @@ function settleWithin(work, timeoutMs) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
//#endregion
|
|
40
|
-
//#region src/node/
|
|
41
|
-
const
|
|
42
|
-
const VERSION = /^v?(\d+)\.(\d+)/;
|
|
40
|
+
//#region src/node/assertRuntimeVersion.ts
|
|
41
|
+
const MINIMUM = ">=";
|
|
43
42
|
const SPACES = /\s/g;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
43
|
+
function parseVersion(text) {
|
|
44
|
+
const [withoutBuild = ""] = text.replace(/^v/, "").split("+");
|
|
45
|
+
const [release = "", ...prerelease] = withoutBuild.split("-");
|
|
46
|
+
const parts = release.split(".").map(Number);
|
|
47
|
+
return parts.every(Number.isInteger) ? {
|
|
48
|
+
parts,
|
|
49
|
+
prerelease: prerelease.length > 0
|
|
50
|
+
} : void 0;
|
|
51
|
+
}
|
|
52
|
+
function meetsMinimum(required, running) {
|
|
53
|
+
const length = Math.max(required.parts.length, running.parts.length);
|
|
54
|
+
for (let index = 0; index < length; index++) {
|
|
55
|
+
const wanted = required.parts[index] ?? 0;
|
|
56
|
+
const got = running.parts[index] ?? 0;
|
|
57
|
+
if (got !== wanted) return got > wanted;
|
|
58
|
+
}
|
|
59
|
+
return !running.prerelease;
|
|
60
|
+
}
|
|
61
|
+
function assertDeclaredRuntime() {
|
|
62
|
+
const { bun, node } = process.versions;
|
|
63
|
+
const runtime = bun === void 0 ? {
|
|
64
|
+
name: "Node",
|
|
65
|
+
range: ">=24.11",
|
|
66
|
+
running: node
|
|
67
|
+
} : {
|
|
68
|
+
name: "Bun",
|
|
69
|
+
range: ">=1.4.2",
|
|
70
|
+
running: bun
|
|
71
|
+
};
|
|
72
|
+
const range = runtime.range.replaceAll(SPACES, "");
|
|
73
|
+
if (!range.startsWith(MINIMUM)) return;
|
|
74
|
+
const required = parseVersion(range.slice(2));
|
|
75
|
+
const running = parseVersion(runtime.running);
|
|
76
|
+
if (!required || !running || meetsMinimum(required, running)) return;
|
|
77
|
+
throw new SeedcordError(SeedcordErrorCode.UnsupportedRuntimeVersion, [
|
|
78
|
+
runtime.name,
|
|
79
|
+
runtime.range,
|
|
80
|
+
runtime.running
|
|
81
|
+
]);
|
|
53
82
|
}
|
|
54
83
|
|
|
55
84
|
//#endregion
|
|
@@ -117,7 +146,7 @@ var Pluggable = class Pluggable {
|
|
|
117
146
|
static liveShutdown;
|
|
118
147
|
static liveProcessErrors;
|
|
119
148
|
constructor(shutdown, startup) {
|
|
120
|
-
|
|
149
|
+
assertDeclaredRuntime();
|
|
121
150
|
if (Pluggable.isInstantiated) {
|
|
122
151
|
shutdown.removeSignalHandlers();
|
|
123
152
|
throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);
|
|
@@ -306,5 +335,5 @@ function shutdownOf(host) {
|
|
|
306
335
|
}
|
|
307
336
|
|
|
308
337
|
//#endregion
|
|
309
|
-
export { withTimeout as a, settleWithin as i, shutdownOf as n,
|
|
310
|
-
//# sourceMappingURL=Pluggable-
|
|
338
|
+
export { withTimeout as a, settleWithin as i, shutdownOf as n, assertDeclaredRuntime as r, Pluggable as t };
|
|
339
|
+
//# sourceMappingURL=Pluggable-afy2H0Dr.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pluggable-afy2H0Dr.mjs","names":[],"sources":["../src/node/Lifecycle/withTimeout.ts","../src/node/assertRuntimeVersion.ts","../src/node/processErrors.ts","../src/node/Pluggable.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// calling start() in here turns its synchronous throw into a rejection\nasync function raceTimer(\n start: () => Promise<unknown>,\n timeoutMs: number,\n onTimeout: (resolve: () => void, reject: (error: unknown) => void) => void\n): Promise<void> {\n let timer: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n start(),\n new Promise<void>((resolve, reject) => {\n // node's timer can go off before performance.now() reaches timeoutMs\n const expiresAt = performance.now() + timeoutMs;\n const tick = (): void => {\n const remaining = expiresAt - performance.now();\n if (remaining > 0) {\n timer = setTimeout(tick, remaining);\n return;\n }\n onTimeout(resolve, reject);\n };\n timer = setTimeout(tick, timeoutMs);\n })\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n// rejects with a LifecycleTaskTimeout when run outlasts the bound\nexport function withTimeout(name: string, run: () => Promise<void>, timeoutMs: number): Promise<void> {\n return raceTimer(run, timeoutMs, (_, reject) => {\n reject(new SeedcordError(SeedcordErrorCode.LifecycleTaskTimeout, [name, timeoutMs]));\n });\n}\n\n// the caller does not get work's rejection\nexport function settleWithin(work: Promise<unknown>, timeoutMs: number): Promise<void> {\n return raceTimer(\n () =>\n work.then(\n () => undefined,\n () => undefined\n ),\n timeoutMs,\n (resolve) => resolve()\n );\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// every seedcord package writes each engines range as `>=` and a version\nconst MINIMUM = '>=';\nconst SPACES = /\\s/g;\n\ninterface Version {\n parts: number[];\n prerelease: boolean;\n}\n\nfunction parseVersion(text: string): Version | undefined {\n const [withoutBuild = ''] = text.replace(/^v/, '').split('+');\n const [release = '', ...prerelease] = withoutBuild.split('-');\n const parts = release.split('.').map(Number);\n return parts.every(Number.isInteger) ? { parts, prerelease: prerelease.length > 0 } : undefined;\n}\n\n// semver ranks 1.4.2-canary.1 below 1.4.2\nfunction meetsMinimum(required: Version, running: Version): boolean {\n const length = Math.max(required.parts.length, running.parts.length);\n for (let index = 0; index < length; index++) {\n const wanted = required.parts[index] ?? 0;\n const got = running.parts[index] ?? 0;\n if (got !== wanted) return got > wanted;\n }\n return !running.prerelease;\n}\n\nexport function assertDeclaredRuntime(): void {\n const { bun, node } = process.versions;\n // tsdown-config bakes both ranges in from this package's engines\n const runtime =\n bun === undefined\n ? { name: 'Node', range: process.env.PACKAGE_NODE_RANGE ?? '', running: node }\n : { name: 'Bun', range: process.env.PACKAGE_BUN_RANGE ?? '', running: bun };\n\n const range = runtime.range.replaceAll(SPACES, '');\n if (!range.startsWith(MINIMUM)) return;\n\n const required = parseVersion(range.slice(MINIMUM.length));\n const running = parseVersion(runtime.running);\n if (!required || !running || meetsMinimum(required, running)) return;\n\n throw new SeedcordError(SeedcordErrorCode.UnsupportedRuntimeVersion, [\n runtime.name,\n runtime.range,\n runtime.running\n ]);\n}\n","import crypto from 'node:crypto';\n\nimport { Logger } from '@seedcord/logger';\n\nimport { asError } from '#stops/asError';\nimport { PublishDefault } from '#subscribers/publishDefault';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { CoordinatedShutdown } from '#node/Lifecycle/CoordinatedShutdown';\n\nconst logger = new Logger('Faults', { channel: 'errors' });\n\n/** @internal */\nexport function registerProcessErrors(core: CoreBase, shutdown: CoordinatedShutdown): () => void {\n function report(caught: unknown, origin: string): void {\n const error = asError(caught);\n const uuid = crypto.randomUUID();\n\n if (core.config.errors?.errorStack ?? false) logger.error(uuid, error);\n else logger.error(`${uuid} | ${error.message}`);\n\n core.bus[PublishDefault]('unknownException', { uuid, dispatchId: null, error, origin });\n }\n\n const onRejection = (reason: unknown): void => {\n report(reason, 'process:unhandledRejection');\n };\n\n const onException = (caught: unknown): void => {\n report(caught, 'process:uncaughtException');\n // node does not exit on its own once a listener is registered\n void shutdown.run(1);\n };\n\n process.on('unhandledRejection', onRejection);\n process.on('uncaughtException', onException);\n\n return () => {\n process.off('unhandledRejection', onRejection);\n process.off('uncaughtException', onException);\n };\n}\n","import { SeedcordErrorCode, isSeedcordError } from '@seedcord/errors';\nimport { SeedcordAggregateError, SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { FRAMEWORK_CHANNELS, Logger } from '@seedcord/logger';\nimport { HostPluginKeys, HostShutdown, HostStartup } from '@seedcord/types/internal';\n\nimport { assertDeclaredRuntime } from '#node/assertRuntimeVersion';\nimport { StartupPhase } from '#src/lifecycle/phases';\nimport { extendsThisCorePlugin, pluginLoggerOf, resolvedLifecycleSpecOf } from '#src/plugin/Plugin';\n\nimport { withTimeout } from './Lifecycle/withTimeout';\nimport { registerProcessErrors } from './processErrors';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { CoordinatedShutdown } from '#node/Lifecycle/CoordinatedShutdown';\nimport type { CoordinatedStartup } from '#node/Lifecycle/CoordinatedStartup';\nimport type { ShutdownPhase } from '#src/lifecycle/phases';\nimport type { Runtime, Transport } from '#src/plugin/options';\nimport type { AttachableCtor, Attached, AttachKeyAssert, PluginArgs, PluginCtor, PluginLike } from '#src/plugin/Plugin';\nimport type { Bus } from '#subscribers/Bus';\nimport type { REST } from '@discordjs/rest';\nimport type { Config, IRateLimiter } from '@seedcord/types';\n\ninterface Attachment {\n readonly key: string;\n readonly instance: PluginLike;\n}\n\nconst RESERVED_KEYS: ReadonlySet<string> = new Set(FRAMEWORK_CHANNELS);\n\n/**\n * Base class for a plugin host, a transport `Seedcord` class.\n *\n * You attach plugins while configuring the bot. Within one startup phase, their `init()` calls run\n * one after another in attach order.\n */\n// BotRt has no default because RuntimeAssert rejects every plugin once 'edge' is in the union\nexport abstract class Pluggable<BotT extends Transport, BotRt extends Runtime> implements CoreBase {\n public abstract readonly config: Config;\n public abstract readonly rest: REST;\n public abstract readonly applicationId: string;\n public abstract readonly rateLimiter: IRateLimiter;\n public abstract readonly bus: Bus;\n\n /** @internal */\n readonly [HostShutdown]: CoordinatedShutdown;\n /** @internal */\n readonly [HostStartup]: CoordinatedStartup;\n\n /** Add a task that runs while the bot shuts down. */\n public readonly shutdown: Pick<CoordinatedShutdown, 'addTask'>;\n\n /** Add a task that runs while the bot starts. */\n public readonly startup: Pick<CoordinatedStartup, 'addTask'>;\n\n protected isInitialized = false;\n protected startFailed = false;\n protected readonly plugins: PluginLike[] = [];\n private readonly groups = new Map<string, Record<string, PluginLike>>();\n\n private readonly pluginLogger = new Logger('Plugins', { channel: 'plugins' });\n\n private readonly attachments: Attachment[] = [];\n private readonly completedInits = new Set<Attachment>();\n private readonly disposePhases = new Set<ShutdownPhase>();\n private pluginTasksRegistered = false;\n private initPromise?: Promise<this> | undefined;\n\n private static isInstantiated = false;\n private static liveHost?: object | undefined;\n private static liveShutdown?: CoordinatedShutdown | undefined;\n private static liveProcessErrors?: (() => void) | undefined;\n\n constructor(shutdown: CoordinatedShutdown, startup: CoordinatedStartup) {\n // a `sideEffects: false` build would drop the same call in the node entry\n assertDeclaredRuntime();\n\n if (Pluggable.isInstantiated) {\n // signal handlers from the caller's shutdown stay on the process unless dropped here\n shutdown.removeSignalHandlers();\n throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);\n }\n\n Pluggable.isInstantiated = true;\n Pluggable.liveHost = this;\n Pluggable.liveShutdown = shutdown;\n this[HostShutdown] = shutdown;\n this[HostStartup] = startup;\n // a getter returning the slot would expose run() and the signal handlers too\n this.shutdown = { addTask: shutdown.addTask.bind(shutdown) };\n this.startup = { addTask: startup.addTask.bind(startup) };\n }\n\n /** @internal */\n protected init(): Promise<this> {\n // clearing the slot on a rejection means a later retry throws its own error\n this.initPromise ??= this.runInit().catch((caught: unknown) => {\n this.initPromise = undefined;\n throw caught;\n });\n return this.initPromise;\n }\n\n private async runInit(): Promise<this> {\n if (this.isInitialized) return this;\n // a rerun after a failed startup would re-init the rolled-back plugins\n if (this.startFailed) throw new SeedcordError(SeedcordErrorCode.LifecycleRestartAfterFailure);\n\n this.registerPluginTasks();\n\n if (this.config.errors?.catchProcessErrors ?? true) {\n Pluggable.liveProcessErrors = registerProcessErrors(this, this[HostShutdown]);\n }\n\n const startupSettled: PromiseWithResolvers<void> = Promise.withResolvers();\n this[HostShutdown].gateOnStartup(startupSettled.promise);\n\n try {\n await this[HostStartup].run();\n } catch (caught) {\n await this.rollback();\n throw caught;\n } finally {\n startupSettled.resolve();\n }\n\n this.isInitialized = true;\n return this;\n }\n\n /** @internal codegen reads this to emit the `Core` augmentation */\n public get [HostPluginKeys](): readonly string[] {\n return this.attachments.map((attachment) => attachment.key);\n }\n\n /** @internal */\n protected static reset(host?: object): boolean {\n if (host !== undefined && Pluggable.liveHost !== host) return false;\n\n Pluggable.liveShutdown?.removeSignalHandlers();\n Pluggable.liveShutdown = undefined;\n Pluggable.liveProcessErrors?.();\n Pluggable.liveProcessErrors = undefined;\n Pluggable.liveHost = undefined;\n Pluggable.isInstantiated = false;\n return true;\n }\n\n /**\n * Attaches a plugin under `key`. Read the instance back as `core[key]`. `seedcord codegen`\n * writes the `Core` augmentation that types it there.\n *\n * Put one dot in the key to nest the plugin under a group, so `'services.users'` reads back as\n * `core.services.users`. Each name holds one plugin or one group.\n *\n * Startup runs each plugin's `init()` in attach order within its phase.\n *\n * Attaching a plugin whose `transport` or `runtime` differs from this host fails to compile.\n * Your constructor takes `CoreBase` as its first parameter (you don't need to pass it though).\n * A narrower one fails to compile here.\n *\n * @param key - Also the channel the plugin logs on, dots included. Reserved channel names throw.\n * @param args - Whatever your constructor takes after the host.\n * @throws A **SeedcordError** if you attach after the bot has started. A taken or reserved key throws too.\n * So does a plugin that extends `Plugin` from another copy of `@seedcord/core`.\n * @example\n * ```ts\n * seedcord.attach('db', Mongoose, { uri: 'mongodb://...', name: 'seedcord', dir: ... });\n * ```\n */\n public attach<Key extends string, Ctor extends PluginCtor>(\n this: this,\n key: AttachKeyAssert<Key, this>,\n Plugin: AttachableCtor<Ctor, BotT, BotRt>,\n ...args: PluginArgs<Ctor>\n ): this & Attached<Key, InstanceType<Ctor>>;\n public attach<Key extends string, Ctor extends PluginCtor>(\n this: this,\n key: Key,\n Plugin: Ctor,\n ...args: PluginArgs<Ctor>\n ): this & Attached<Key, InstanceType<Ctor>> {\n if (this.isInitialized) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);\n }\n\n const dot = key.indexOf('.');\n const head = dot === -1 ? key : key.slice(0, dot);\n\n // several reserved channels are also members on a host, which the next check would report first\n if (RESERVED_KEYS.has(head)) {\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginReservedChannel, [head]);\n }\n\n const leaf = dot === -1 ? undefined : key.slice(dot + 1);\n if (head === '' || leaf === '') {\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyMalformed, [key, 'has an empty part.']);\n }\n if (leaf?.includes('.')) {\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyMalformed, [key, 'has more than one dot.']);\n }\n this.assertFree(head, leaf, key);\n\n if (!extendsThisCorePlugin(Plugin)) {\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginFromOtherCore, [Plugin.name]);\n }\n\n const instance = new Plugin(this, ...args);\n pluginLoggerOf(instance).setChannel(key);\n this.plugins.push(instance);\n this.attachments.push({ key, instance });\n\n if (leaf === undefined) {\n return Object.assign(this, { [key]: instance }) as this & Attached<Key, InstanceType<Ctor>>;\n }\n\n this.groupFor(head)[leaf] = instance;\n return this as this & Attached<Key, InstanceType<Ctor>>;\n }\n\n private assertFree(head: string, leaf: string | undefined, key: string): void {\n if (leaf === undefined) {\n if (this.groups.has(key)) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyHoldsGroup, [key]);\n if (key in this) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n return;\n }\n\n const group = this.groups.get(head);\n if (!group) {\n if (head in this) throw new SeedcordError(SeedcordErrorCode.CorePluginGroupTaken, [head, key]);\n return;\n }\n if (Object.hasOwn(group, leaf)) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n }\n\n private groupFor(head: string): Record<string, PluginLike> {\n const existing = this.groups.get(head);\n if (existing) return existing;\n\n // a null prototype makes a leaf called __proto__ or valueOf an ordinary key\n const group = Object.create(null) as Record<string, PluginLike>;\n this.groups.set(head, group);\n Object.assign(this, { [head]: group });\n return group;\n }\n\n // one combined task per phase keeps plugin inits sequential while the phase's other tasks run concurrently\n private registerPluginTasks(): void {\n if (this.pluginTasksRegistered) return;\n this.pluginTasksRegistered = true;\n\n const groups = Map.groupBy(\n this.attachments,\n (attachment) => resolvedLifecycleSpecOf(attachment.instance).init.phase\n );\n\n for (const [phase, group] of groups) {\n // Ready inits run in the combined Ready task, before the ready hooks\n if (phase === StartupPhase.Ready) continue;\n const budget = group.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).init.timeout, 0);\n this.startup.addTask(phase, 'plugins-init', () => this.runInits(group), budget);\n }\n\n this.registerReadyTask(groups.get(StartupPhase.Ready) ?? []);\n }\n\n private async runInits(group: readonly Attachment[]): Promise<void> {\n for (const attachment of group) {\n const { key, instance } = attachment;\n const spec = resolvedLifecycleSpecOf(instance);\n\n pluginLoggerOf(instance).utils.initialization(key, 'start');\n const running = instance.init();\n try {\n await withTimeout(`Plugin (${key})`, () => running, spec.init.timeout);\n } catch (caught) {\n if (isSeedcordError(caught, undefined, SeedcordErrorCode.LifecycleTaskTimeout)) {\n this.disposeWhenInitResolves(attachment, running);\n }\n throw caught;\n }\n pluginLoggerOf(instance).utils.initialization(key, 'end');\n\n this.completedInits.add(attachment);\n if (instance.dispose) this.registerDisposeTask(spec.dispose.phase);\n }\n }\n\n // disposeCompleted skips a plugin missing from completedInits\n private disposeWhenInitResolves(attachment: Attachment, running: Promise<void>): void {\n const dispose = attachment.instance.dispose?.bind(attachment.instance);\n const spec = resolvedLifecycleSpecOf(attachment.instance);\n\n void running.then(\n async () => {\n if (!dispose) return;\n await withTimeout(`Plugin:${attachment.key}:dispose`, dispose, spec.dispose.timeout).catch(\n (caught: unknown) =>\n this.pluginLogger.warn(`${attachment.key} dispose failed after a timed-out init`, caught)\n );\n },\n (caught: unknown) => this.pluginLogger.warn(`${attachment.key} init failed after its timeout`, caught)\n );\n }\n\n private registerReadyTask(readyInits: readonly Attachment[]): void {\n const steps = this.attachments.reduce<{ key: string; run: () => Promise<void>; timeout: number }[]>(\n (acc, a) => {\n const ready = a.instance.ready?.bind(a.instance);\n if (ready) {\n acc.push({\n key: a.key,\n run: ready,\n timeout: resolvedLifecycleSpecOf(a.instance).ready.timeout\n });\n }\n return acc;\n },\n []\n );\n if (readyInits.length === 0 && steps.length === 0) return;\n\n const budget =\n readyInits.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).init.timeout, 0) +\n steps.reduce((sum, step) => sum + step.timeout, 0);\n this.startup.addTask(\n StartupPhase.Ready,\n 'plugins-ready',\n async () => {\n await this.runInits(readyInits);\n for (const step of steps) {\n await withTimeout(`Plugin:${step.key}:ready`, step.run, step.timeout);\n }\n },\n budget\n );\n }\n\n private registerDisposeTask(phase: ShutdownPhase): void {\n if (this.disposePhases.has(phase)) return;\n this.disposePhases.add(phase);\n\n // the budget covers every dispose in this phase because they all run in this one task\n const budget = this.attachments.reduce((sum, a) => {\n const spec = resolvedLifecycleSpecOf(a.instance);\n return a.instance.dispose && spec.dispose.phase === phase ? sum + spec.dispose.timeout : sum;\n }, 0);\n this.shutdown.addTask(phase, 'plugins-dispose', () => this.runDisposals(phase), budget);\n }\n\n private async runDisposals(phase: ShutdownPhase): Promise<void> {\n const failures: unknown[] = [];\n await this.disposeCompleted(phase, (caught) => failures.push(caught));\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) {\n throw new SeedcordAggregateError(SeedcordErrorCode.PluginDisposeFailures, failures, [failures.length]);\n }\n }\n\n private async disposeCompleted(\n phase: ShutdownPhase | undefined,\n onError: (caught: unknown) => void\n ): Promise<void> {\n for (const attachment of [...this.attachments].reverse()) {\n if (!this.completedInits.has(attachment)) continue;\n const dispose = attachment.instance.dispose?.bind(attachment.instance);\n if (!dispose) continue;\n const spec = resolvedLifecycleSpecOf(attachment.instance);\n if (phase !== undefined && spec.dispose.phase !== phase) continue;\n\n try {\n await withTimeout(`Plugin:${attachment.key}:dispose`, dispose, spec.dispose.timeout);\n } catch (caught) {\n onError(caught);\n }\n }\n }\n\n private async rollback(): Promise<void> {\n this.startFailed = true;\n // log rollback dispose failures so they do not hide the startup error\n await this.disposeCompleted(undefined, (caught) => this.pluginLogger.warn('rollback dispose failed', caught));\n // prevents re-dispose when shutdown runs after rollback\n this.completedInits.clear();\n }\n}\n\n// the public `shutdown` field carries addTask alone\nexport function shutdownOf(host: Pick<Pluggable<Transport, Runtime>, typeof HostShutdown>): CoordinatedShutdown {\n return host[HostShutdown];\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as BuilderComponent, C as InteractionRouteKeys, S as InteractionMiddlewareMetadataKey, b as InteractionKind, x as InteractionMetadataKey } from "./Bus-
|
|
1
|
+
import { A as BuilderComponent, C as InteractionRouteKeys, S as InteractionMiddlewareMetadataKey, b as InteractionKind, x as InteractionMetadataKey } from "./Bus-BxPa-Uvp.mjs";
|
|
2
2
|
import { n as asError, t as PublishDefault } from "./publishDefault-BuSZPbjT.mjs";
|
|
3
3
|
import "reflect-metadata";
|
|
4
4
|
import { CustomId, decodeFor } from "@seedcord/custom-id";
|
|
@@ -799,4 +799,4 @@ function pageCursor(prefix) {
|
|
|
799
799
|
|
|
800
800
|
//#endregion
|
|
801
801
|
export { translateSerializationError as A, contextMenuRouteOf as B, NotInDm as C, defineEffectGate as D, OnCooldown as E, checkAckLegality as F, decodeComponentRoute as G, storeComponentRoute as H, sendTarget as I, NoticeCard as K, RegisterInteractionMiddleware as L, publishResponse as M, reportedWrite as N, defineGate as O, AckTrace as P, interactionMiddlewareMetaOf as R, NotAllowed as S, NotOwner as T, storeInteractionRoute as U, interactionRoutesOf as V, ComponentDefsKey as W, GateNotice as _, RequirePermissions as a, MissingRole as b, hasAll as c, pickNotice as d, discardCommits as f, runCommits as g, runCheck as h, RequireBotPermissions as i, attemptWrite as j, serializeReply as k, missingNames as l, rollbackCommits as m, pageCursor as n, RequireRole as o, markCommits as p, Notice as q, Silence as r, PermissionNames as s, PAGE_MAX as t, presentNames as u, HasDangerousPermissions as v, NotInGuild as w, NeedsAny as x, MissingPermissions as y, areRoutes as z };
|
|
802
|
-
//# sourceMappingURL=cursor-
|
|
802
|
+
//# sourceMappingURL=cursor-CgNBnJfu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-CgNBnJfu.mjs","names":[],"sources":["../src/stops/Notice.ts","../src/stops/NoticeCard.ts","../src/customId/routing.ts","../src/decorators/interactionRoutes.ts","../src/decorators/middleware.ts","../src/reply/ackLegality.ts","../src/reply/AckTrace.ts","../src/reply/responseReport.ts","../src/reply/translateSerialization.ts","../src/reply/serializeReply.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 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, seen only by the invoking user. 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 {@link or} gate refuses and each one sets this, `or`\n * throws a refusal listing them under `You need to meet at least one of these:`. Write a verb phrase that\n * finishes that line, for example, \"be the bot owner\".\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.\n */\n public abstract render(ctx: RenderContext): ReplyResponse;\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '#components/Component';\n\n// built fresh inside a Notice's render to back its ComponentsV2 reply\n// discord renders the ### line as an h3 with the description below\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 'reflect-metadata';\n\nimport { decodeFor } from '@seedcord/custom-id';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { ComponentDefsBrand } from '#src/decorators/brands';\nimport type { AnyCustomId, DecodedParams } from '@seedcord/custom-id';\nimport type { Promisable } from 'type-fest';\n\n/**\n * route decorators store a handler's customId defs here, so the component base can decode\n * against them at runtime.\n *\n * @internal\n */\n// storeComponentRoute writes this beside the route keys in metadataKeys.ts\nexport const ComponentDefsKey = Symbol.for('seedcord:custom-id:component-defs');\n\n/**\n * the phantom a component handler base carries. a route decorator constrains its argument to this, so\n * passing different defs 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 [ComponentDefsBrand]?: 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, InteractionKind } from '#src/metadataKeys';\n\nimport type { ContextMenuKind } from '#registries/ContextMenuRegistry';\nimport type { AnyCustomId } from '@seedcord/custom-id';\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// the build's manifest emitter reads the same pairs\nexport function interactionRoutesOf(constructor: RoutableConstructor): [InteractionKind, string[]][] {\n const pairs: [InteractionKind, string[]][] = [];\n for (const route of Object.values(InteractionKind)) {\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: InteractionKind,\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\nexport function storeComponentRoute(\n route: InteractionKind,\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\nexport function contextMenuRouteOf(kind: ContextMenuKind): InteractionKind {\n return kind === ApplicationCommandType.User ? InteractionKind.UserContextMenu : InteractionKind.MessageContextMenu;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordTypeError } from '@seedcord/errors/internal';\n\nimport { InteractionMiddlewareMetadataKey } from '#src/metadataKeys';\n\nimport type { MiddlewareKind } from '#src/metadataKeys';\nimport type { MiddlewareKindsBrand } from './brands';\nimport type { Constructor, NonEmptyTuple } from 'type-fest';\n\n/** @internal */\nexport type AnyMiddlewareCtor = Constructor<unknown, never[]>;\n\n// core cannot import the transport's middleware base. the kinds arrive on a phantom brand.\ntype KindsOf<TCtor extends AnyMiddlewareCtor> =\n InstanceType<TCtor> extends { [MiddlewareKindsBrand]?: infer Kind extends MiddlewareKind } ? Kind : never;\n\ntype AssertMiddlewareKinds<Kinds extends MiddlewareKind, TCtor extends AnyMiddlewareCtor> = [Kinds] extends [\n KindsOf<TCtor>\n]\n ? [KindsOf<TCtor>] extends [Kinds]\n ? TCtor\n : Constructor<\n ['the middleware generic declares a kind that RegisterInteractionMiddleware omits', KindsOf<TCtor>]\n >\n : Constructor<['RegisterInteractionMiddleware lists a kind that the middleware generic omits', Kinds]>;\n\n/** Registration options for an interaction middleware. */\nexport interface InteractionMiddlewareOptions<Kinds extends NonEmptyTuple<MiddlewareKind>> {\n /**\n * Restrict this middleware to certain interaction kinds. The middleware's generic must list the same\n * kinds, or applying the decorator is a compile error. Omit it to run on every repliable kind.\n */\n readonly kinds?: Kinds;\n /**\n * Lower runs earlier. Two middleware sharing a priority run in registration order.\n *\n * @defaultValue 0\n */\n readonly priority?: number;\n}\n\n/** @internal */\nexport interface InteractionMiddlewareMetadata {\n readonly priority: number;\n readonly kinds?: readonly MiddlewareKind[];\n}\n\n/**\n * Registers an interaction middleware. It runs after the dispatcher builds the handler and before its\n * gates, over that handler's reply surface.\n *\n * @param options - The kinds this middleware runs on and its ordering.\n * @decorator\n *\n * @example\n * ```ts\n * \\@RegisterInteractionMiddleware({ kinds: [InteractionKind.Button], priority: 10 })\n * class Audit extends InteractionMiddleware<InteractionKind.Button> {\n * async execute() {\n * this.logger.info(this.dispatch.routeId);\n * }\n * }\n * ```\n *\n * @throws A **SeedcordTypeError** If `priority` is not a finite number.\n */\nexport function RegisterInteractionMiddleware<\n const Kinds extends NonEmptyTuple<MiddlewareKind> = NonEmptyTuple<MiddlewareKind>\n>(options: InteractionMiddlewareOptions<Kinds> = {}) {\n return function <TCtor extends AnyMiddlewareCtor>(ctor: AssertMiddlewareKinds<Kinds[number], TCtor>): void {\n const priority = Number(options.priority ?? 0);\n if (!Number.isFinite(priority))\n throw new SeedcordTypeError(SeedcordErrorCode.DecoratorInvalidMiddlewarePriority);\n if (options.kinds?.length === 0)\n throw new SeedcordTypeError(SeedcordErrorCode.DecoratorEmptyMiddlewareFilter, ['kinds']);\n\n const metadata: InteractionMiddlewareMetadata = {\n priority,\n ...(options.kinds && { kinds: options.kinds })\n };\n\n Reflect.defineMetadata(InteractionMiddlewareMetadataKey, metadata, ctor);\n };\n}\n\n/** @internal */\nexport function interactionMiddlewareMetaOf(constructor: AnyMiddlewareCtor): InteractionMiddlewareMetadata | undefined {\n const saved: unknown = Reflect.getMetadata(InteractionMiddlewareMetadataKey, constructor);\n return saved as InteractionMiddlewareMetadata | undefined;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { AckTrace } from './AckTrace';\n\nexport type AckState = 'unacked' | 'deferred-reply' | 'deferred-update' | 'replied';\n\nexport type ReplyMethod =\n 'reply' | 'defer' | 'deferUpdate' | 'update' | 'followUp' | 'edit' | 'delete' | 'send' | 'showModal';\n\ninterface Illegal {\n // spliced into the message after \"was called when\"\n readonly reason: string;\n readonly alternative: string;\n}\n\nconst showModalReason: Illegal = {\n reason: 'this interaction was already acknowledged',\n alternative: 'showModal() must be the initial response.'\n};\n\nfunction deferReason(what: string): Illegal {\n return {\n reason: `this interaction was already acknowledged with ${what}`,\n alternative: 'A deferral can only be the initial response.'\n };\n}\n\n// a missing entry means legal in that state\nconst ILLEGAL: Record<Exclude<ReplyMethod, 'send'>, Partial<Record<AckState, Illegal>>> = {\n reply: {\n 'deferred-reply': {\n reason: 'this interaction was already deferred',\n alternative: 'Use edit() to fill the deferred reply or followUp() for a new message.'\n },\n 'deferred-update': {\n reason: 'this interaction was already acknowledged with a deferred update',\n alternative: 'Use followUp() for a new message.'\n },\n replied: {\n reason: 'this interaction was already replied to',\n alternative: 'Use followUp() for a new message or edit() to rewrite the reply.'\n }\n },\n defer: {\n 'deferred-reply': deferReason('a deferred reply'),\n 'deferred-update': deferReason('a deferred update'),\n replied: deferReason('a reply')\n },\n deferUpdate: {\n 'deferred-reply': deferReason('a deferred reply'),\n 'deferred-update': deferReason('a deferred update'),\n replied: deferReason('a reply')\n },\n update: {\n 'deferred-reply': {\n reason: 'this interaction was deferred as a reply',\n alternative: 'The placeholder is yours via edit(). update() rewrites a source message.'\n },\n replied: {\n reason: 'this interaction was already replied to',\n alternative: 'update() rewrites a source message. Use edit() or followUp() instead.'\n }\n },\n followUp: {\n unacked: {\n reason: 'this interaction has not been acknowledged yet',\n alternative: 'Ack first with reply() or defer().'\n }\n },\n edit: {\n unacked: {\n reason: 'nothing has been sent yet',\n alternative: 'Send with reply() or defer() first, then edit() rewrites it.'\n }\n },\n delete: {\n unacked: {\n reason: 'nothing has been sent yet',\n alternative: 'Acknowledge first with reply() or defer(), then delete() removes it.'\n }\n },\n showModal: {\n 'deferred-reply': showModalReason,\n 'deferred-update': showModalReason,\n replied: showModalReason\n }\n};\n\nconst SEND_TARGET: Record<AckState, 'reply' | 'edit' | 'followUp'> = {\n unacked: 'reply',\n 'deferred-reply': 'edit',\n 'deferred-update': 'followUp',\n replied: 'followUp'\n};\n\n// throws before any API call, and ackedBy becomes the throw cause with its stack pointing at the first ack\nexport function checkAckLegality(method: ReplyMethod, state: AckState, routeId: string, ackedBy?: AckTrace): void {\n if (method === 'send') return;\n const illegal = ILLEGAL[method][state];\n if (!illegal) return;\n throw new SeedcordError(\n SeedcordErrorCode.ReplyIllegalAckState,\n [method, illegal.reason, illegal.alternative, routeId],\n { cause: ackedBy }\n );\n}\n\nexport function sendTarget(state: AckState): 'reply' | 'edit' | 'followUp' {\n return SEND_TARGET[state];\n}\n","import type { ReplyMethod } from './ackLegality';\n\n// the first ack's stack, passed as the throw cause so a double-ack points to both lines\nexport class AckTrace extends Error {\n public constructor(method: ReplyMethod) {\n super(`${method}() acknowledged this interaction`);\n this.name = 'AckTrace';\n }\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\n\nimport { asError } from '#stops/asError';\nimport { PublishDefault } from '#subscribers/publishDefault';\n\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { Bus } from '#subscribers/Bus';\nimport type { ReplyMethod } from './ackLegality';\n\nlet replyLogger: Logger | undefined;\nfunction logger(): Logger {\n replyLogger ??= new Logger('Reply', { channel: 'interactions' });\n return replyLogger;\n}\n\nexport interface ReplyTelemetry {\n readonly bus: Bus;\n readonly dispatch: DispatchContext;\n readonly interactionId: string;\n}\n\n// the reply verbs plus the autocomplete choices callback, which runs outside the ack state machine\nexport type WriteMethod = ReplyMethod | 'respond';\n\ninterface WriteStart {\n readonly method: WriteMethod;\n // performance.now() captured before the write began\n readonly startedAt: number;\n}\n\ninterface SentReport extends WriteStart {\n readonly outcome: 'sent';\n readonly messageId: string | null;\n}\n\ninterface FailedReport extends WriteStart {\n readonly outcome: 'failed';\n readonly error: Error;\n}\n\nexport type ResponseReport = SentReport | FailedReport;\n\n/** @internal */\nexport function publishResponse(telemetry: ReplyTelemetry, report: ResponseReport): void {\n const durationMs = performance.now() - report.startedAt;\n const { routeId } = telemetry.dispatch;\n const write = {\n dispatchId: telemetry.dispatch.id,\n routeId,\n interactionId: telemetry.interactionId,\n method: report.method,\n durationMs\n };\n telemetry.bus[PublishDefault](\n 'responseAttempted',\n report.outcome === 'failed'\n ? { ...write, outcome: 'failed', messageId: null, error: report.error }\n : { ...write, outcome: 'sent', messageId: report.messageId }\n );\n\n // after publish so a throwing sink doesn't reach the publish above\n logger().trace(\n `${paint.sky.bold(routeId)} ${report.method} ${report.outcome} ${paint.mute('in')} ${Math.round(durationMs)}ms`\n );\n}\n\nexport async function reportedWrite<Result>(\n telemetry: ReplyTelemetry,\n method: WriteMethod,\n write: () => Promise<Result>\n): Promise<Result> {\n const startedAt = performance.now();\n const result = await attemptWrite(telemetry, method, startedAt, write);\n publishResponse(telemetry, { method, startedAt, outcome: 'sent', messageId: null });\n return result;\n}\n\n// publishes the failed arm when write() throws, since the caller's success report sits after the write and a throw skips it\nexport async function attemptWrite<Result>(\n telemetry: ReplyTelemetry,\n method: WriteMethod,\n startedAt: number,\n write: () => Promise<Result>\n): Promise<Result> {\n try {\n return await write();\n } catch (caught) {\n const error = asError(caught);\n publishResponse(telemetry, { method, startedAt, outcome: 'failed', error });\n // rethrown raw\n throw caught;\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// shapeshift aggregate errors nest, so the cap bounds the recursion\nconst MAX_DEPTH = 8;\n\ninterface ShapeshiftLike {\n readonly message?: unknown;\n readonly errors?: unknown;\n readonly constraint?: unknown;\n readonly validator?: unknown;\n readonly expected?: unknown;\n readonly given?: unknown;\n}\n\nconst OPERATOR_WORD: Record<string, string> = {\n '<=': 'at most',\n '>=': 'at least',\n '<': 'fewer than',\n '>': 'more than'\n};\n\nconst KIND_WORD: Record<string, string> = {\n string: 'a string',\n number: 'a number',\n boolean: 'a boolean',\n bigint: 'a bigint',\n array: 'a list',\n tuple: 'a list',\n date: 'a date',\n object: 'an object'\n};\n\nfunction asRecord(value: unknown): ShapeshiftLike | null {\n return typeof value === 'object' && value !== null ? value : null;\n}\n\nfunction firstLine(message: unknown): string {\n if (typeof message !== 'string') return 'unknown validation failure';\n return message.split('\\n')[0] ?? message;\n}\n\n// strings over this limit render as a character count\nconst GIVEN_PREVIEW_LIMIT = 40;\n\nfunction gotPhrase(given: unknown): string {\n if (given === undefined) return 'nothing';\n if (given === null) return 'null';\n if (typeof given === 'string') {\n if (given.length === 0) return 'an empty string';\n if (given.length > GIVEN_PREVIEW_LIMIT) return `${given.length} characters`;\n return JSON.stringify(given);\n }\n if (Array.isArray(given)) return given.length === 0 ? 'an empty list' : `${given.length} items`;\n if (typeof given === 'number' || typeof given === 'bigint' || typeof given === 'boolean') return String(given);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype value has no constructor at runtime\n if (typeof given === 'object') return given.constructor?.name ?? 'an object';\n return typeof given;\n}\n\n// shapeshift constraint strings take the form 'expected.length >= 1' or 'expected <= 16777215'\nfunction needPhrase(expected: string, given: unknown): string | null {\n const bounds = [...expected.matchAll(/expected(\\.length)?\\s*(<=|>=|<|>)\\s*(\\d+)/g)];\n if (bounds.length === 0) return null;\n const phrases = bounds.map(([, lengthPart, operator, limit]) => {\n const word = OPERATOR_WORD[operator ?? ''] ?? operator ?? '';\n if (!lengthPart) return `${word} ${limit}`;\n const unit = typeof given === 'string' ? 'character' : 'item';\n return `${word} ${limit} ${Number(limit) === 1 ? unit : `${unit}s`}`;\n });\n return phrases.join(' and ');\n}\n\nfunction instanceName(expected: unknown): string {\n if (typeof expected === 'function' && expected.name) return expected.name;\n return 'specific class instance';\n}\n\nfunction describeLeaf(record: ShapeshiftLike): string {\n if (typeof record.constraint === 'string') {\n const need = typeof record.expected === 'string' ? needPhrase(record.expected, record.given) : null;\n if (need) return `need ${need}, got ${gotPhrase(record.given)}`;\n return `${firstLine(record.message)}${'given' in record ? ` (got ${gotPhrase(record.given)})` : ''}`;\n }\n if (typeof record.expected === 'function') {\n return `need a ${instanceName(record.expected)}, got ${gotPhrase(record.given)}`;\n }\n if (typeof record.validator === 'string') {\n const kind = KIND_WORD[record.validator.replace(/^s\\./, '').replace(/\\(.*$/, '')];\n if (kind) return `need ${kind}, got ${gotPhrase(record.given)}`;\n return `${firstLine(record.message)}, got ${gotPhrase(record.given)}`;\n }\n return firstLine(record.message);\n}\n\nfunction describeUnion(branches: unknown[], depth: number): string {\n const records: ShapeshiftLike[] = [];\n for (const branch of branches) {\n const record = asRecord(branch);\n if (record) records.push(record);\n }\n const bounded = records.find((record) => typeof record.constraint === 'string');\n if (bounded) return describeLeaf(bounded);\n\n const names: string[] = [];\n let allInstances = records.length > 0;\n for (const record of records) {\n if (typeof record.expected === 'function') names.push(instanceName(record.expected));\n else allInstances = false;\n }\n if (allInstances) {\n return `need a ${[...new Set(names)].join(' or ')}, got ${gotPhrase(records[0]?.given)}`;\n }\n return detailOf(branches[0], depth + 1);\n}\n\n// shapeshift nests errors as [key, inner] tuples\nfunction detailOf(value: unknown, depth: number): string {\n const record = asRecord(value);\n if (!record || depth >= MAX_DEPTH) return firstLine(record?.message);\n\n if (Array.isArray(record.errors) && record.errors.length > 0) {\n const errors = record.errors as unknown[];\n const [first] = errors;\n if (Array.isArray(first)) {\n const [key, inner] = first as [unknown, unknown];\n return `${String(key)}: ${detailOf(inner, depth + 1)}`;\n }\n return describeUnion(errors, depth);\n }\n\n return describeLeaf(record);\n}\n\n// a shapeshift throw becomes an actionable message with the cause kept, while anything else contributes its own message as the detail\nexport function translateSerializationError(\n error: unknown,\n componentClass: string,\n index: number,\n routeId: string\n): SeedcordError<SeedcordErrorCode.ReplyComponentSerialization> {\n const detail = detailOf(error, 0);\n return new SeedcordError(SeedcordErrorCode.ReplyComponentSerialization, [componentClass, index, detail, routeId], {\n cause: error\n });\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\nexport interface SerializedReply<TNative = never> {\n readonly components: APIMessageTopLevelComponent[];\n readonly allowedMentions?: ReplyResponse['allowedMentions'];\n readonly files?: ReplyResponse<TNative>['files'];\n}\n\nexport function serializeReply<TNative>(\n response: ReplyResponse<TNative> | string,\n routeId: string\n): SerializedReply<TNative> {\n if (typeof response === 'string') {\n try {\n return { components: [new TextDisplayBuilder().setContent(response).toJSON()] };\n } catch (error) {\n throw translateSerializationError(error, 'TextDisplayBuilder', 0, routeId);\n }\n }\n\n const components = response.components.map((component, index) => {\n try {\n return component.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype value has no constructor at runtime\n const name = component.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'component' : name, index, routeId);\n }\n });\n\n return {\n components,\n ...(response.allowedMentions && { allowedMentions: response.allowedMentions }),\n ...(response.files && { files: response.files })\n };\n}\n","import type { CoreBase } from '#interfaces/CoreBase';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\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, and on a gateway event they're 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 handler's own route, as `kind:route` (`slash:daily`, `button:confirm`). A handler registered\n * on several reports the one this dispatch matched. Null when the handler declares none, which\n * covers a plain event handler, the unhandled default, and a gate run outside a handler.\n */\n readonly declaredRoute: string | null;\n /**\n * The bag for this dispatch, the same instance the handler and its middleware hold. Every middleware\n * runs before the first gate. A gate therefore reads what a middleware wrote.\n */\n readonly dispatch: DispatchContext;\n}\n\n/**\n * The context the guild-scoped permission gates require. It adds the base permission sets computed from\n * roles alone, which only the gateway transport can provide from its cache. The http transport's context\n * does not define these fields.\n *\n * @example\n * ```ts\n * // in:'guild' returns a Gate<GuildPermissionsContext>, which fits only a gateway handler\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' }))\n * ```\n */\nexport interface GuildPermissionsContext extends GateContextBase {\n /**\n * The member's base permission set, roles only, matching djs `GuildMember.permissions`. Null when the\n * member is unavailable.\n */\n readonly memberGuildPermissions: bigint | null;\n /**\n * The bot's base permission set from the transport's cache. Null when the cached member is unavailable.\n */\n readonly appGuildPermissions: bigint | null;\n}\n\n// phantom brand rejects a bare check function or plain object where a Gate is expected\ndeclare const GateBrand: unique symbol;\n\n/**\n * A precondition attached to a handler. It refuses by throwing a `Notice` (a reply) or a `Silence`\n * (a drop with no reply), and passes by returning. `Ctx` is the context it requires, so a gate that reads\n * a field absent on a handler's context is rejected at compile time. `Name` is captured as a literal so\n * a mismatch error can name the gate. Build one with {@link defineGate} or {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context the gate requires. A field missing from it is a compile error.\n * @typeParam Name - The gate's literal name, named in a mismatch error.\n *\n * @example\n * ```ts\n * // a factory returning a typed, agnostic gate\n * function MyGate(): Gate<GateContextBase, 'MyGate'> {\n * return defineGate('MyGate', (ctx) => {\n * if (shouldRefuse(ctx)) throw new MyNotice();\n * });\n * }\n * ```\n *\n * @see {@link defineGate}\n */\nexport interface Gate<Ctx extends GateContextBase = GateContextBase, Name extends string = string> {\n /** The gate's name, surfaced in a mismatch error and joined by the combinators. */\n readonly name: Name;\n /** Reads the context and refuses by throwing a Notice or a Silence, or passes by resolving. */\n check(ctx: Ctx): Promise<void>;\n\n /** @internal */\n readonly [GateBrand]: true;\n}\n\n/**\n * A gate 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, while `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 both `check` and `commit` require. A field missing from it fails to compile.\n * @typeParam Name - The gate's literal name, shown when a mismatch error names 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 for mismatch errors.\n * @typeParam Ctx - The context the check reads, inferred from the `ctx` annotation.\n *\n * @param name - The gate's name, used in mismatch errors.\n * @param fn - The check, which refuses by throwing a Notice or a Silence and passes by returning.\n *\n * @see {@link defineEffectGate}\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * // a gate factory that takes its own option and closes over it\n * function MinRoles(min: number): Gate<GateContextBase, 'MinRoles'> {\n * return defineGate('MinRoles', (ctx) => {\n * if (ctx.memberRoleIds.length < min) throw new NotEnoughRoles(min);\n * });\n * }\n * ```\n *\n * @example\n * ```ts\n * // agnostic gate (no ctx annotation): fits any handler\n * const Owner = defineGate('owner', (ctx) => {\n * if (!ctx.userId) throw new NotOwner();\n * });\n * ```\n */\nexport function defineGate<const Name extends string, Ctx extends GateContextBase = GateContextBase>(\n name: Name,\n fn: (ctx: Ctx) => 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 literal name, used to name a mismatch error.\n * @typeParam Ctx - The context both `check` and `commit` read, inferred from the `ctx` annotation.\n *\n * @param name - The gate's name, used in mismatch errors.\n * @param check - Peeks and refuses by throwing, without applying the side effect.\n * @param commit - Applies the side effect, running only after the whole gate set passes.\n *\n * @see {@link defineGate}\n * @see the `@Gated` decorator from your transport package\n * @see {@link Cooldown}\n *\n * @example\n * ```ts\n * // an effect-gate factory that takes its own limit and closes over it\n * function UsesPerDay(max: number): EffectGate<GateContextBase, 'UsesPerDay'> {\n * return defineEffectGate(\n * 'UsesPerDay',\n * (ctx) => {\n * // peek and refuse by throwing. do not mutate yet\n * if (usedToday(ctx.userId) >= max) throw new OutOfUsesNotice(max);\n * },\n * (ctx) => {\n * // runs only after the whole gate set passes\n * recordUse(ctx.userId);\n * }\n * );\n * }\n * ```\n */\nexport function defineEffectGate<const Name extends string, Ctx extends GateContextBase = GateContextBase>(\n name: Name,\n check: (ctx: Ctx) => 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 this.summary = 'be the bot owner';\n }\n}\n\nexport class NotInGuild extends GateNotice {\n public constructor(message = 'This can only be used in a server.') {\n super(message);\n this.summary = 'be in a server';\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 this.summary = 'be in a direct message';\n }\n}\n\nfunction retryAt(resetAt: EpochMs): string {\n return `<t:${toEpochSeconds(resetAt)}:R>`;\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 ${retryAt(resetAt)}.`);\n this.summary = `try again ${retryAt(resetAt)}`;\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 private readonly summaries: readonly string[];\n\n public constructor(summaries: readonly string[]) {\n super('not allowed');\n // two arms can refuse with the same summary\n this.summaries = [...new Set(summaries)];\n }\n\n public render(): ReplyResponse {\n const bullets = this.summaries.map((summary) => `• ${summary}`).join('\\n');\n return { components: [new NoticeCard(`You need to meet at least one of these:\\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 this.summary = roleId ? `hold the <@&${roleId}> role` : 'hold the required role';\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 const names = missingPerms.join(', ');\n this.summary = subject === null ? `hold ${names}` : `${subject} needs ${names}`;\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 private readonly subject: string,\n private readonly dangerousPerms: readonly string[]\n ) {\n super(message ?? 'A dangerous permission is enabled.');\n this.customLead = message;\n this.summary = `${subject} must not hold ${dangerousPerms.join(', ')}`;\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// commits wait here until the whole gate set passes, one queue per request. the key is the context\n// itself and the map is weak, so an entry goes when its request does\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 refused effect gate never commits. combinators call this too\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 from a finally, refused run or not\nexport function discardCommits(ctx: GateContextBase): void {\n commitQueues.delete(ctx);\n}\n\n// an `or` arm takes this mark before it runs\nexport function markCommits(ctx: GateContextBase): number {\n return commitQueues.get(ctx)?.length ?? 0;\n}\n\n// and rolls back to it when the arm refuses, leaving 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 { Gate, GateContextBase, GuildPermissionsContext } from '#gates/Gate';\nimport type { PermissionScope } from '#src/permissions/bits';\nimport type { GateNoticeOptions } from './options';\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 your transport package\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers]))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // the base set from roles, on a gateway handler\n * RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' });\n * ```\n */\nexport function RequirePermissions(\n scope: PermissionScope,\n options: RequirePermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequirePermissions'>;\nexport function RequirePermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions & { in?: 'channel' }\n): Gate<GateContextBase, 'RequirePermissions'>;\nexport function RequirePermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions\n): Gate<GuildPermissionsContext, 'RequirePermissions'> | Gate<GateContextBase, 'RequirePermissions'> {\n 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}, fitting 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 your transport package\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * \\@Gated(RequireBotPermissions([PermissionFlagsBits.ManageMessages]))\n * \\@SlashRoute('purge')\n * class PurgeHandler extends SlashHandler<'purge'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options: 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 your transport package\n *\n * @example\n * ```ts\n * \\@Gated(RequireRole('123456789012345678'))\n * \\@SlashRoute('vip')\n * class VipHandler extends SlashHandler<'vip'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireRole(roleId: string, options?: RequireRoleOptions): Gate<GateContextBase, 'RequireRole'> {\n return defineGate('RequireRole', (ctx) => {\n if (!ctx.guildId) throw 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 * // a helper under a guildMemberAdd handler, stopping when this guild configured nothing to send\n * const template = await settings.welcome(member.guild.id);\n * if (!template) throw new Silence('no welcome message set');\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 '@seedcord/custom-id';\n\nimport type { CustomIdField } from '@seedcord/custom-id';\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).\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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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -802,7 +802,7 @@ export declare class Silence extends Error {
|
|
|
802
802
|
constructor(reason?: string | undefined);
|
|
803
803
|
}
|
|
804
804
|
//#endregion
|
|
805
|
-
//#region src/miscellaneous/
|
|
805
|
+
//#region src/miscellaneous/ResolvedEmoji.d.ts
|
|
806
806
|
/**
|
|
807
807
|
* A resolved custom emoji. Renders as `<:name:id>` in message content, or `<a:name:id>` when animated,
|
|
808
808
|
* and passes straight to a builder's `setEmoji`.
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as translateSerializationError, B as contextMenuRouteOf, C as NotInDm, D as defineEffectGate, E as OnCooldown, F as checkAckLegality, H as storeComponentRoute, I as sendTarget, K as NoticeCard, L as RegisterInteractionMiddleware, M as publishResponse, O as defineGate, P as AckTrace, S as NotAllowed, T as NotOwner, U as storeInteractionRoute, a as RequirePermissions, c as hasAll, d as pickNotice, h as runCheck, i as RequireBotPermissions, j as attemptWrite, k as serializeReply, l as missingNames, m as rollbackCommits, n as pageCursor, o as RequireRole, p as markCommits, q as Notice, r as Silence, t as PAGE_MAX, u as presentNames, v as HasDangerousPermissions, w as NotInGuild, x as NeedsAny, y as MissingPermissions } from "./cursor-
|
|
2
|
-
import { A as BuilderComponent, b as InteractionKind, d as WebhookLog, f as Subscriber, j as RowComponent, l as WebhookUrl, t as Bus, u as Subscribe } from "./Bus-
|
|
3
|
-
import { a as ContextMenus, i as Commands, n as RegisterCommand } from "./subscribers-
|
|
1
|
+
import { A as translateSerializationError, B as contextMenuRouteOf, C as NotInDm, D as defineEffectGate, E as OnCooldown, F as checkAckLegality, H as storeComponentRoute, I as sendTarget, K as NoticeCard, L as RegisterInteractionMiddleware, M as publishResponse, O as defineGate, P as AckTrace, S as NotAllowed, T as NotOwner, U as storeInteractionRoute, a as RequirePermissions, c as hasAll, d as pickNotice, h as runCheck, i as RequireBotPermissions, j as attemptWrite, k as serializeReply, l as missingNames, m as rollbackCommits, n as pageCursor, o as RequireRole, p as markCommits, q as Notice, r as Silence, t as PAGE_MAX, u as presentNames, v as HasDangerousPermissions, w as NotInGuild, x as NeedsAny, y as MissingPermissions } from "./cursor-CgNBnJfu.mjs";
|
|
2
|
+
import { A as BuilderComponent, b as InteractionKind, d as WebhookLog, f as Subscriber, j as RowComponent, l as WebhookUrl, t as Bus, u as Subscribe } from "./Bus-BxPa-Uvp.mjs";
|
|
3
|
+
import { a as ContextMenus, i as Commands, n as RegisterCommand } from "./subscribers-xGy7a7xR.mjs";
|
|
4
4
|
import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
|
|
5
5
|
import "reflect-metadata";
|
|
6
6
|
import { CustomId, decodeFor, prefixOf, setCustomIdErrors, setCustomIdErrors as setCustomIdErrors$1 } from "@seedcord/custom-id";
|
|
@@ -918,7 +918,7 @@ function mergeRoles(current, add, remove) {
|
|
|
918
918
|
}
|
|
919
919
|
|
|
920
920
|
//#endregion
|
|
921
|
-
//#region src/miscellaneous/
|
|
921
|
+
//#region src/miscellaneous/ResolvedEmoji.ts
|
|
922
922
|
/**
|
|
923
923
|
* A resolved custom emoji. Renders as `<:name:id>` in message content, or `<a:name:id>` when animated,
|
|
924
924
|
* and passes straight to a builder's `setEmoji`.
|
|
@@ -1169,7 +1169,7 @@ var CursorSourceBase = class {
|
|
|
1169
1169
|
//#endregion
|
|
1170
1170
|
//#region src/index.ts
|
|
1171
1171
|
/** Package version */
|
|
1172
|
-
const version = "0.
|
|
1172
|
+
const version = "0.10.0";
|
|
1173
1173
|
|
|
1174
1174
|
//#endregion
|
|
1175
1175
|
export { ArraySourceBase, AutocompleteRoute, BaseHandler, BaseReplySender, BuilderComponent, Bus, ButtonRoute, ChannelMenuRoute, Commands, ContextMenus, Cooldown, CursorSourceBase, CustomId, DispatchContext, DmOnly, Fault, GuildOnly, InteractionKind, MentionableMenuRoute, MessageContextMenuRoute, ModalRoute, Notice, OwnerOnly, PaginatorBase, RegisterCommand, RegisterInteractionMiddleware, RepliableHandler, RequireBotPermissions, RequirePermissions, RequireRole, ResolvedEmoji, RoleMenuRoute, RowComponent, ShutdownPhase, Silence, SlashRoute, StartupPhase, StringMenuRoute, Subscribe, Subscriber, UserContextMenuRoute, UserMenuRoute, WebhookLog, WebhookUrl, and, assertPermissions, decodeFor, defineEffectGate, defineGate, mergeRoles, or, paginate, prefixOf, setCustomIdErrors, version };
|