@seedcord/gateway 0.1.0-next.4 → 0.1.0-next.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,38 +1,39 @@
1
1
  import { AnyCustomId, AutocompletableNames, BaseReplySender, ChoiceValueOf, EntryFor, FocusedField, GateFitsWith, HasComponentDefs, MatchArms, ModalLike, PageCursor, SingleParams, SlashOptions as SlashOptions$1 } from "@seedcord/core/internal";
2
- import { AutocompleteOptions, BaseHandler, BuilderComponent, CoreBase, DispatchContext, Gate, GateContextBase, GateNoticeOptions, GuildPermissionsContext, Initializeable, Notice, PageView, PermissionScope, RepliableHandler as RepliableHandler$1, RequiredOf, SelectMenuKind, SlashOptionRegistry } from "@seedcord/core";
2
+ import { ArraySource as ArraySource$1, AutocompleteOptions, BaseHandler, Bus, ContextMenuKind, CoreBase, CursorSource as CursorSource$1, DispatchContext, Gate, GateContextBase, GateNoticeOptions, GuildPermissionsContext, Initializeable, Notice, PaginatorBase, PaginatorConfig, PermissionNoticeOverrides, PermissionScope, RepliableHandler as RepliableHandler$1, RequiredOf, SelectMenuKind, SlashOptionRegistry, Subscriber as Subscriber$1, SubscriptionKey, WebhookLog as WebhookLog$1 } from "@seedcord/core";
3
3
  import { Logger } from "@seedcord/logger";
4
- import { ActionRowBuilder, ButtonBuilder, ContextMenuCommandBuilder, SlashCommandBuilder } from "@discordjs/builders";
5
- import { APIInteractionGuildMember, APIMessageComponentEmoji, APIModalInteractionResponseCallbackData, AnySelectMenuInteraction, ApplicationCommand, ApplicationCommandOptionChoiceData, ApplicationCommandType, ApplicationEmoji, AutocompleteInteraction, BooleanCache, ButtonInteraction, ButtonStyle, CacheType, CacheTypeReducer, ChannelSelectMenuInteraction, ChatInputCommandInteraction, Client, ClientEvents, ClientOptions, Collection, CommandInteractionOption, ContextMenuCommandInteraction, Events, Guild, GuildEmoji, GuildMember, Interaction, MentionableSelectMenuInteraction, Message, MessageContextMenuCommandInteraction, ModalSubmitInteraction, Role, RoleSelectMenuInteraction, Snowflake, StringSelectMenuInteraction, TextChannel, TextChannelResolvable, User, UserContextMenuCommandInteraction, UserSelectMenuInteraction } from "discord.js";
6
- import { UUID } from "node:crypto";
7
- import { APIMessageTopLevelComponent } from "discord-api-types/v10";
8
- import { REST } from "@discordjs/rest";
9
- import { CoordinatedShutdown, CoordinatedStartup, Pluggable, PluginCapabilities } from "@seedcord/core/node/internal";
4
+ import { APIInteractionGuildMember, APIModalInteractionResponseCallbackData, AnySelectMenuInteraction, ApplicationCommandOptionChoiceData, ApplicationCommandType, ApplicationEmoji, AutocompleteInteraction, BooleanCache, ButtonInteraction, ButtonStyle, CacheType, CacheTypeReducer, ChannelSelectMenuInteraction, ChatInputCommandInteraction, Client, ClientEvents, ClientOptions, CommandInteractionOption, ContextMenuCommandInteraction, Events, Guild, GuildEmoji, GuildMember, Interaction, MentionableSelectMenuInteraction, Message, MessageContextMenuCommandInteraction, ModalSubmitInteraction, Role, RoleSelectMenuInteraction, StringSelectMenuInteraction, TextChannel, User, UserContextMenuCommandInteraction, UserSelectMenuInteraction } from "discord.js";
5
+ import { Plugin as Plugin$1, PluginLifecycleSpec, PluginOptions, PluginOptions as PluginOptions$1 } from "@seedcord/core/plugin";
6
+ import { CoordinatedShutdown, CoordinatedStartup, Pluggable } from "@seedcord/core/node/internal";
10
7
  import { SeedcordBrand, SeedcordInstance } from "@seedcord/types/internal";
11
- import { TypedEventEmitter } from "@seedcord/event-emitter";
12
- import { BotConfig, Config, DeferOpts, EmojiMap, HealthCheckOption, HmrAware, HmrUpdateEvent, IRateLimiter, ReplyResponse, SendOpts, V2Component } from "@seedcord/types";
8
+ import { BotConfig, Config, DeferOpts, EmojiMap, EventFrequency, HealthCheckOption, HmrAware, HmrUpdateEvent, IRateLimiter, ReplyResponse, SendOpts, TypedOmit } from "@seedcord/types";
9
+ import { REST } from "@discordjs/rest";
13
10
  export * from "@seedcord/errors";
14
11
  export * from "@seedcord/core";
15
12
  export * from "@seedcord/logger";
16
- export * from "@seedcord/utils";
17
13
  export * from "@seedcord/rate-limiter";
14
+ export * from "@seedcord/utils";
18
15
  export * from "@seedcord/event-emitter";
19
16
  export type * from "@seedcord/types";
20
17
 
21
- //#region src/plugin-capabilities.d.ts
22
- declare module '@seedcord/core' {
23
- interface PluginCapabilityTypes {
24
- client: Client;
25
- rest: REST;
18
+ //#region src/subscriptions.d.ts
19
+ declare module '@seedcord/core/internal' {
20
+ interface DefaultSubscriptions {
21
+ /** Triggered when an event dispatch throws past the fault boundary. */
22
+ unhandledEventError: {
23
+ error: Error;
24
+ };
25
+ /** Triggered for every client event the bot receives, before its handlers run. */
26
+ anyEvent: { [Name in keyof ClientEvents]: {
27
+ name: Name;
28
+ args: ClientEvents[Name];
29
+ } }[keyof ClientEvents];
30
+ /** Triggered for every interaction the bot receives, before routing. */
31
+ anyInteraction: {
32
+ interaction: Interaction;
33
+ };
26
34
  }
27
35
  }
28
36
  //#endregion
29
- //#region src/bot/utilities/miscellaneous/contextMenuLeaves.d.ts
30
- /** The registered context-menu command names, split by kind, deduplicated. @internal */
31
- interface ContextMenuLeaves {
32
- readonly user: Set<string>;
33
- readonly message: Set<string>;
34
- }
35
- //#endregion
36
37
  //#region src/interfaces/Config.d.ts
37
38
  /**
38
39
  * Djs Events handlers
@@ -74,132 +75,35 @@ interface GatewayConfig extends Config {
74
75
  healthCheck?: HealthCheckOption;
75
76
  }
76
77
  //#endregion
77
- //#region src/subscribers/types/Subscriptions.d.ts
78
- /**
79
- * Where a reported fault came from.
80
- */
81
- type FaultSource = InteractionFaultSource | EventFaultSource;
82
- /**
83
- * A fault that came from a discord interaction, JSON-safe for a webhook payload.
84
- */
85
- interface InteractionFaultSource {
86
- kind: 'interaction';
87
- interactionKind: 'slash' | 'context-menu' | 'button' | 'select' | 'modal';
88
- /** Slash or context-menu command name, null for component and modal interactions. */
89
- command: string | null;
90
- /** Component or modal customId, null for slash and context-menu interactions. */
91
- customId: string | null;
92
- userId: string;
93
- /** Guild the interaction came from, null in DMs. */
94
- guildId: string | null;
95
- /** Channel the interaction came from, null when unavailable. */
96
- channelId: string | null;
97
- interactionId: string;
98
- /** The raw interaction, made JSON-safe at serialization with filterCirculars. */
99
- raw: unknown;
100
- }
101
- /**
102
- * A fault that came from a client event, JSON-safe for a webhook payload. The actor, guild, and channel
103
- * are best-effort, derived from the event args, so each is nullable. The raw args carry the full detail.
104
- */
105
- interface EventFaultSource {
106
- kind: 'event';
107
- eventName: string;
108
- handler: string;
109
- userId: string | null;
110
- /** Null outside a guild. */
111
- guildId: string | null;
112
- channelId: string | null;
113
- /** The raw event args, made JSON-safe at serialization with filterCirculars. */
114
- raw: unknown;
115
- }
116
- interface DefaultSubscriptions {
117
- /** Triggered when an unhandled exception (a raw non-Notice throw) occurs */
118
- unknownException: {
119
- uuid: UUID;
120
- error: Error;
121
- guild?: {
122
- id: string;
123
- name: string;
124
- } | undefined;
125
- user?: {
126
- id: string;
127
- username: string;
128
- } | undefined;
129
- metadata?: unknown;
130
- };
131
- /** Triggered when a reported Notice (`report: true`) is caught */
132
- handledException: {
133
- denial: Notice;
134
- uuid: UUID;
135
- source: FaultSource;
136
- };
137
- }
138
- /**
139
- * Custom subscribers defined by the application. Augment it via declaration merging to type your
140
- * own subscriber payloads.
141
- *
142
- * @example
143
- * ```typescript
144
- * declare module '@seedcord/gateway' {
145
- * interface Subscriptions {
146
- * 'userJoin': { userId: string; guildId: string };
147
- * 'levelUp': { userId: string; level: number };
148
- * }
149
- * }
150
- * ```
151
- */
152
- interface Subscriptions {}
153
- interface AllSubscriptions extends DefaultSubscriptions, Subscriptions {}
154
- /** All subscriber event names available to publish and augment. */
155
- type SubscriptionKey = keyof AllSubscriptions;
156
- /**
157
- * The payload type for a subscriber event.
158
- *
159
- * @typeParam KeyOfSubscribers - The subscriber event name
160
- */
161
- type SubscriptionData<KeyOfSubscribers extends SubscriptionKey> = AllSubscriptions[KeyOfSubscribers];
162
- type SubscriptionTuples = { [K in SubscriptionKey]: [AllSubscriptions[K]] };
163
- //#endregion
164
- //#region src/subscribers/Bus.d.ts
78
+ //#region src/bot/Bot.d.ts
165
79
  /**
166
- * Registers and dispatches subscribers. Subscribers load from the configured directories and run
167
- * on a programmatic or framework-event publish. Accessed via `core.bus`. Do not construct it directly.
80
+ * The Discord client and its controllers. Access it through `core.bot`.
168
81
  */
169
- declare class Bus extends TypedEventEmitter<SubscriptionTuples> implements Initializeable, HmrAware {
170
- protected core: Core;
82
+ declare class Bot implements Initializeable, HmrAware {
83
+ readonly botToken: string;
84
+ /** @internal */
171
85
  readonly logger: Logger;
172
86
  private isInitialized;
173
- private readonly subscribersMap;
174
- private readonly executedOnceHandlers;
175
- private readonly webhookProbes;
176
- private readonly hmrHandler?;
87
+ private readonly _client;
88
+ private readonly interactions?;
89
+ private readonly events?;
90
+ private readonly emojiInjector;
91
+ private readonly commandRegistry?;
92
+ /** @internal */
93
+ onHmr(event: HmrUpdateEvent): Promise<void>;
94
+ /** @internal */
177
95
  constructor(core: Core);
178
- private getArtifacts;
96
+ private applicationId;
97
+ private registerShutdownTasks;
98
+ private stopAccepting;
99
+ private drain;
179
100
  /** @internal */
180
101
  init(): Promise<void>;
181
- /** @internal Exposed for tests. */
182
- verifyWebhooks(): Promise<void>;
183
102
  /** @internal */
184
- onHmr(event: HmrUpdateEvent): Promise<void>;
185
- private loadSubscribers;
186
- private registerSubscriber;
187
- private unregisterSubscriber;
188
- private isSubscriber;
189
- /**
190
- * Publishes an event to its subscribers and native listeners.
191
- *
192
- * Fire-and-forget, so subscriber handlers run asynchronously and this returns before they
193
- * complete, and callers must not assume side effects have landed. Errors thrown by a subscriber
194
- * are caught and logged, never surfaced here. A `'once'` subscriber is marked as executed when
195
- * it starts (even if it throws), so it never runs twice.
196
- *
197
- * @param event - The subscription key to publish
198
- * @param data - Payload passed to each subscriber
199
- * @returns Whether the underlying emitter had native listeners for the event
200
- */
201
- publish<KeyOfSubscribers extends SubscriptionKey>(event: KeyOfSubscribers, data: AllSubscriptions[KeyOfSubscribers]): boolean;
202
- private processSubscriber;
103
+ stop(): Promise<void>;
104
+ private login;
105
+ private logout;
106
+ get client(): Client;
203
107
  }
204
108
  //#endregion
205
109
  //#region src/interfaces/Core.d.ts
@@ -215,143 +119,16 @@ declare class Bus extends TypedEventEmitter<SubscriptionTuples> implements Initi
215
119
  * ```typescript
216
120
  * declare module '@seedcord/gateway' {
217
121
  * interface Core {
218
- * db: Mongo;
122
+ * db: Mongoose;
219
123
  * }
220
124
  * }
221
125
  * ```
222
126
  * */
223
- interface Core extends CoreBase, SeedcordInstance {
224
- readonly shutdown: CoordinatedShutdown;
225
- readonly startup: CoordinatedStartup;
127
+ interface Core extends CoreBase {
128
+ readonly shutdown: Pick<CoordinatedShutdown, 'addTask'>;
129
+ readonly startup: Pick<CoordinatedStartup, 'addTask'>;
226
130
  readonly bot: Bot;
227
- readonly bus: Bus;
228
131
  readonly config: GatewayConfig;
229
- start(): Promise<this>;
230
- }
231
- //#endregion
232
- //#region src/bot/controllers/CommandRegistry.d.ts
233
- /** The command collections Discord returns from each scope's deploy, keyed by command id. */
234
- interface DeployResult {
235
- global: Collection<Snowflake, ApplicationCommand>;
236
- guilds: Collection<Snowflake, Collection<Snowflake, ApplicationCommand>>;
237
- }
238
- /**
239
- * Manages Discord application command registration and deployment.
240
- *
241
- * Scans command directories, builds command structures, and registers both global and guild-scoped commands
242
- * to Discord's API. Accessed via `core.bot.commands`. Do not construct it directly.
243
- */
244
- declare class CommandRegistry implements Initializeable, HmrAware {
245
- private readonly core;
246
- private readonly onDeployed?;
247
- private readonly logger;
248
- private isInitialised;
249
- readonly globalCommands: (SlashCommandBuilder | ContextMenuCommandBuilder)[];
250
- readonly guildCommands: Collection<string, (SlashCommandBuilder | ContextMenuCommandBuilder)[]>;
251
- private readonly ctorToCommand;
252
- private loading;
253
- private readonly loadedCommands;
254
- private readonly hmrHandler?;
255
- private readonly pendingEvents;
256
- constructor(core: Core, onDeployed?: ((result: DeployResult) => void) | undefined);
257
- private getArtifacts;
258
- /** @internal */
259
- init(): Promise<void>;
260
- private reportLoad;
261
- /** @internal */
262
- refresh(shouldRefresh?: boolean): Promise<void>;
263
- /** @internal */
264
- onHmr(event: HmrUpdateEvent): Promise<void>;
265
- private loadCommands;
266
- private isCommandClass;
267
- private registerCommand;
268
- private unregisterCommand;
269
- /** @internal */
270
- setCommands(): Promise<DeployResult>;
271
- /** The deduplicated slash route keys across every global and guild command. @internal */
272
- routeLeaves(): Set<string>;
273
- /** The registered context-menu command names, split by kind, across every global and guild command. @internal */
274
- contextMenuLeaves(): ContextMenuLeaves;
275
- }
276
- //#endregion
277
- //#region src/bot/injectors/CommandMentionInjector.d.ts
278
- /** Each registered slash route mapped to its mention string. */
279
- type InjectedMentionMap = { [K in keyof SlashOptionRegistry]: string };
280
- /**
281
- * Ready-to-send command mention strings, keyed by {@link SlashOptionRegistry}.
282
- *
283
- * A value is a clickable `</name:id>` when the command's id resolved from the deploy, otherwise the plain
284
- * `/name` text. Populated by {@link CommandMentionInjector} after each deploy.
285
- */
286
- declare const CommandMentions: InjectedMentionMap;
287
- //#endregion
288
- //#region src/bot/injectors/EmojiInjector.d.ts
289
- /**
290
- * The global {@link Emojis} accessor type. Each key resolves to its precise class, `GuildEmoji` for a `'guild'`
291
- * tag and `ApplicationEmoji` for an `'application'` tag, the tags `seedcord codegen` writes into {@link EmojiMap}.
292
- */
293
- type InjectedEmojiMap = { [K in keyof EmojiMap]: EmojiMap[K] extends 'guild' ? GuildEmoji : ApplicationEmoji };
294
- /**
295
- * Global emoji mappings object
296
- *
297
- * @see {@link EmojiMap}
298
- */
299
- declare const Emojis: InjectedEmojiMap;
300
- //#endregion
301
- //#region src/bot/Bot.d.ts
302
- /**
303
- * Types of events emitted by the {@link Core.bot} instance.
304
- */
305
- interface BotEvents {
306
- /** Emitted when an unhandled interaction error occurs */
307
- 'error:unhandled:interaction': [error: Error];
308
- /** Emitted when an unhandled event error occurs */
309
- 'error:unhandled:event': [error: Error];
310
- /** Emitted for any event */
311
- 'any:event': { [K in keyof ClientEvents]: [K, ...ClientEvents[K]] }[keyof ClientEvents];
312
- /** Emitted for any interaction */
313
- 'any:interaction': [interaction: Interaction];
314
- /** @internal */
315
- ready: [];
316
- }
317
- /**
318
- * The Discord client and its controllers. Access it through `core.bot`.
319
- */
320
- declare class Bot extends TypedEventEmitter<BotEvents> implements Initializeable, HmrAware {
321
- readonly botToken: string;
322
- /** @internal */
323
- readonly logger: Logger;
324
- private isInitialized;
325
- private readonly _client;
326
- private readonly interactions?;
327
- private readonly events?;
328
- private readonly emojiInjector;
329
- readonly commands?: CommandRegistry;
330
- readonly emojis: InjectedEmojiMap;
331
- readonly mentions: InjectedMentionMap;
332
- /** @internal */
333
- onHmr(event: HmrUpdateEvent): Promise<void>;
334
- /** @internal */
335
- constructor(core: Core);
336
- private registerShutdownTasks;
337
- private stopAccepting;
338
- private drain;
339
- /** @internal */
340
- init(): Promise<void>;
341
- /** @internal */
342
- stop(): Promise<void>;
343
- private login;
344
- private logout;
345
- get client(): Client;
346
- /** @internal */
347
- emit<TKey extends keyof ClientEvents>(event: 'any:event', name: TKey, ...args: ClientEvents[TKey]): boolean;
348
- /** @internal */
349
- emit<TEventKey extends keyof BotEvents>(event: TEventKey, ...args: BotEvents[TEventKey]): boolean;
350
- /** @internal */
351
- emitSafe<TKey extends keyof ClientEvents>(event: 'any:event', name: TKey, ...args: ClientEvents[TKey]): boolean;
352
- /** @internal */
353
- emitSafe<TEventKey extends keyof BotEvents>(event: TEventKey, ...args: BotEvents[TEventKey]): boolean;
354
- protected onListenerError(error: unknown, event: string | symbol): void;
355
132
  }
356
133
  //#endregion
357
134
  //#region src/handlers/interactionTypes.d.ts
@@ -569,7 +346,7 @@ type EventMatchArms<Names extends ValidNonInteractionKeys, Ret> = { [Name in Nam
569
346
  * }
570
347
  * ```
571
348
  */
572
- declare abstract class EventHandler<Names extends ValidNonInteractionKeys> extends BaseHandler$1<ClientEvents[Names]> {
349
+ declare abstract class EventHandler<in out Names extends ValidNonInteractionKeys> extends BaseHandler$1<ClientEvents[Names]> {
573
350
  private readonly firedEvent;
574
351
  constructor(event: ClientEvents[Names], core: Core, eventName?: Names);
575
352
  protected readonly event: SingleEventPayload<Names>;
@@ -625,12 +402,6 @@ declare abstract class EventMiddleware<in out EventName extends ValidNonInteract
625
402
  protected get eventName(): EventName;
626
403
  }
627
404
  //#endregion
628
- //#region src/miscellaneous/types.d.ts
629
- /**
630
- * The frequency at which the event handler should be executed.
631
- */
632
- type EventFrequency = 'once' | 'on';
633
- //#endregion
634
405
  //#region src/bot/decorators/Events.d.ts
635
406
  /** Options accepted by the event registration decorator. */
636
407
  interface RegisterEventOptions {
@@ -781,7 +552,7 @@ type SentMessage = Message;
781
552
  */
782
553
  declare class ReplySender extends BaseReplySender<SentMessage> {
783
554
  private readonly interaction;
784
- constructor(interaction: Repliables, routeId: string);
555
+ constructor(interaction: Repliables, routeId: string, bus?: Bus);
785
556
  protected writeReply(response: ReplyResponse | string, opts?: SendOpts): Promise<SentMessage | undefined>;
786
557
  protected writeDefer(opts?: DeferOpts): Promise<void>;
787
558
  protected writeDeferUpdate(): Promise<void>;
@@ -814,7 +585,7 @@ declare class ReplySender extends BaseReplySender<SentMessage> {
814
585
  declare abstract class RepliableHandler<Event extends Repliables> extends RepliableHandler$1<Event, Core, SentMessage, ReplySender> {
815
586
  /** @internal */
816
587
  getEvent(): Event;
817
- protected buildSender(event: Event, _core: Core, routeId: string): ReplySender;
588
+ protected buildSender(event: Event, core: Core, routeId: string): ReplySender;
818
589
  }
819
590
  //#endregion
820
591
  //#region src/handlers/interaction/InteractionHandler.d.ts
@@ -979,7 +750,6 @@ declare abstract class SlashHandler<Route extends keyof SlashOptionRegistry, Cac
979
750
  }
980
751
  //#endregion
981
752
  //#region src/handlers/interaction/ContextMenuHandler.d.ts
982
- type ContextMenuKind = ApplicationCommandType.User | ApplicationCommandType.Message;
983
753
  type InteractionFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User ? UserContextMenuCommandInteraction<Cache> : MessageContextMenuCommandInteraction<Cache>;
984
754
  type TargetFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User ? User : Message<BooleanCache<Cache>>;
985
755
  type TargetMemberFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User ? CacheTypeReducer<Cache, GuildMember, APIInteractionGuildMember> | null : never;
@@ -1200,6 +970,11 @@ declare abstract class ButtonHandler<Defs extends readonly AnyCustomId[], Cache
1200
970
  declare abstract class ModalHandler<Defs extends readonly AnyCustomId[], Cache extends CacheType = 'cached'> extends ComponentHandler<ModalSubmitInteraction<Cache>, Defs> {
1201
971
  /** @internal */
1202
972
  readonly __component?: 'modal';
973
+ /** Rewrite the message this modal was opened from. Throws when a command opened the modal. */
974
+ protected update(response: ReplyResponse | string): Promise<SentMessage>;
975
+ /** Acknowledge the submit without changing the source message. Throws when a command opened the modal. */
976
+ protected deferUpdate(): Promise<void>;
977
+ private ensureSourceMessage;
1203
978
  }
1204
979
  //#endregion
1205
980
  //#region src/handlers/interaction/components/SelectMenuHandler.d.ts
@@ -1258,7 +1033,7 @@ interface MiddlewareOptions<MType extends MiddlewareType, Events extends readonl
1258
1033
  * Interaction middleware cannot specify event filters.
1259
1034
  *
1260
1035
  * @param type - Middleware kind from {@link MiddlewareType}
1261
- * @param priority - Ordering value where lower runs earlier. {@default `0`}
1036
+ * @param priority - Ordering value where lower runs earlier. {@default `0` }
1262
1037
  * @param options - Additional registration options
1263
1038
  *
1264
1039
  * @decorator
@@ -1318,182 +1093,100 @@ declare const IgnoreBots: import("@seedcord/core").Gate<EventGateContext<ValidNo
1318
1093
  */
1319
1094
  declare function Nsfw(options?: GateNoticeOptions): Gate<InteractionGateContext<NonModalInteraction>, 'Nsfw'>;
1320
1095
  //#endregion
1321
- //#region src/bot/utilities/channels/fetchText.d.ts
1096
+ //#region src/bot/injectors/EmojiInjector.d.ts
1322
1097
  /**
1323
- * Fetches and validates a text channel. Refuses when the channel doesn't exist or isn't a text channel.
1324
- *
1325
- * @param client - The Discord client instance
1326
- * @param channelId - Channel ID or TextChannel instance
1327
- * @returns Promise resolving to the text channel
1098
+ * The global {@link Emojis} accessor type. Each key resolves to its precise class, `GuildEmoji` for a `'guild'`
1099
+ * tag and `ApplicationEmoji` for an `'application'` tag, the tags `seedcord codegen` writes into {@link EmojiMap}.
1328
1100
  */
1329
- declare function fetchText(client: Client, channelId: TextChannelResolvable): Promise<TextChannel>;
1330
- //#endregion
1331
- //#region src/bot/utilities/permissions/checkPermissions.d.ts
1101
+ type InjectedEmojiMap = { [K in keyof EmojiMap]: EmojiMap[K] extends 'guild' ? GuildEmoji : ApplicationEmoji };
1332
1102
  /**
1333
- * Optional custom error constructors for {@link CheckPermissionOptions}.
1103
+ * The bot's resolved emojis, keyed by {@link EmojiMap}. Filled by {@link EmojiInjector} during startup.
1104
+ * A read before that throws.
1334
1105
  */
1335
- interface PermissionErrorNoticeOverrides {
1336
- missingNotice?: new (message: string | undefined, subject: string, missingPerms: readonly string[]) => Notice;
1337
- dangerousNotice?: new (message: string | undefined, subject: string, dangerousPerms: readonly string[]) => Notice;
1338
- }
1106
+ declare const Emojis: InjectedEmojiMap;
1107
+ //#endregion
1108
+ //#region src/bot/utilities/permissions/checkBotPermissions.d.ts
1339
1109
  /**
1340
- * Options for {@link checkPermissions}.
1110
+ * Checks the bot's own permissions in a {@link Guild} or {@link TextChannel}. Refuses when a permission in
1111
+ * `scope` is missing, or with `inverse` when one is present. When the bot member is uncached, the refusal
1112
+ * reports every permission in `scope` as missing.
1341
1113
  *
1342
- * @see {@link PermissionErrorNoticeOverrides}
1114
+ * @example
1115
+ * ```ts
1116
+ * import { PermissionFlagsBits } from 'discord.js';
1117
+ * import { checkBotPermissions } from '@seedcord/gateway';
1118
+ *
1119
+ * checkBotPermissions(textChannel, [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]);
1120
+ * ```
1343
1121
  */
1344
- interface CheckPermissionOptions extends PermissionErrorNoticeOverrides {
1345
- /** Role or member whose permissions will be checked */
1122
+ declare function checkBotPermissions(target: Guild | TextChannel, scope: PermissionScope, inverse?: boolean, errors?: PermissionNoticeOverrides): void;
1123
+ //#endregion
1124
+ //#region src/bot/utilities/permissions/checkPermissions.d.ts
1125
+ /** Options for {@link checkPermissions}. */
1126
+ interface CheckPermissionOptions extends PermissionNoticeOverrides {
1127
+ /** The role or member to check. */
1346
1128
  for: Role | GuildMember;
1347
- /** Context where permissions apply */
1129
+ /** A guild reads the base bits from roles, a text channel reads the overwrite-resolved set. */
1348
1130
  in: Guild | TextChannel;
1349
- /** Permission bits to validate */
1131
+ /** The permission flag bits to check. */
1350
1132
  scope: PermissionScope;
1351
- /** When true, ensure target does NOT have the given permissions */
1133
+ /** Refuse when the target holds a scope bit. */
1352
1134
  inverse?: boolean;
1353
1135
  }
1354
1136
  /**
1355
- * Checks permissions for a {@link Role} or a {@link GuildMember} in a {@link Guild}. Refuses when a
1356
- * permission in `scope` is missing, or with `inverse` when one is present.
1357
- *
1358
- * @param target - Role or member to check
1359
- * @param ctx - Guild context
1360
- * @param scope - Permission bits to validate
1361
- * @param inverse - Whether to ensure absence of the given permissions
1362
- * @param errors - Optional custom error constructors
1363
- *
1137
+ * Checks a {@link Role} or a {@link GuildMember} against the base permission bits in a {@link Guild},
1138
+ * before channel overwrites. Refuses when a permission in `scope` is missing, or with `inverse` when one
1139
+ * is present.
1364
1140
  *
1365
1141
  * @example
1366
1142
  * ```ts
1367
1143
  * import { PermissionFlagsBits } from 'discord.js';
1368
1144
  * import { checkPermissions } from '@seedcord/gateway';
1369
1145
  *
1370
- * // Check if a role has ManageMessages and KickMembers permissions in a guild
1371
- * checkPermissions(role, guild, [
1372
- * PermissionFlagsBits.ManageMessages,
1373
- * PermissionFlagsBits.KickMembers
1374
- * ]);
1146
+ * checkPermissions(role, guild, [PermissionFlagsBits.ManageMessages, PermissionFlagsBits.KickMembers]);
1375
1147
  * ```
1376
1148
  *
1377
1149
  * @example
1378
1150
  * ```ts
1379
- * import { PermissionFlagsBits } from 'discord.js';
1380
- * import { checkPermissions } from '@seedcord/gateway';
1381
- *
1382
- * // Ensure a member does NOT have Administrator permission in a guild and show custom errors
1383
- * checkPermissions(member, guild, [
1384
- * PermissionFlagsBits.Administrator
1385
- * ], true, {
1386
- * missing: CustomMissingPermissionsError,
1387
- * dangerous: CustomDangerousPermissionsError
1151
+ * // refuse when the member holds Administrator, and replace the refusal
1152
+ * checkPermissions(member, guild, [PermissionFlagsBits.Administrator], true, {
1153
+ * dangerousNotice: CustomDangerousNotice
1388
1154
  * });
1389
1155
  * ```
1390
1156
  */
1391
- declare function checkPermissions(target: Role | GuildMember, ctx: Guild, scope: PermissionScope, inverse?: boolean, errors?: PermissionErrorNoticeOverrides): void;
1157
+ declare function checkPermissions(target: Role | GuildMember, ctx: Guild, scope: PermissionScope, inverse?: boolean, errors?: PermissionNoticeOverrides): void;
1392
1158
  /**
1393
- * Checks permissions for a {@link Role} or a {@link GuildMember} in a {@link TextChannel}. Refuses when a
1394
- * permission in `scope` is missing, or with `inverse` when one is present.
1395
- *
1396
- * @param target - Role or member to check
1397
- * @param ctx - Channel context
1398
- * @param scope - Permission bits to validate
1399
- * @param inverse - Whether to ensure absence of the given permissions
1400
- * @param errors - Optional custom error constructors
1401
- *
1159
+ * Checks a {@link Role} or a {@link GuildMember} against the overwrite-resolved set in a
1160
+ * {@link TextChannel}. Refuses when a permission in `scope` is missing, or with `inverse` when one is
1161
+ * present.
1402
1162
  *
1403
1163
  * @example
1404
1164
  * ```ts
1405
1165
  * import { PermissionFlagsBits } from 'discord.js';
1406
1166
  * import { checkPermissions } from '@seedcord/gateway';
1407
1167
  *
1408
- * // Check if a role has SendMessages and ViewChannel permissions in a text channel
1409
- * checkPermissions(role, textChannel, [
1410
- * PermissionFlagsBits.SendMessages,
1411
- * PermissionFlagsBits.ViewChannel
1412
- * ]);
1413
- * ```
1414
- *
1415
- * @example
1416
- * ```ts
1417
- * import { PermissionFlagsBits } from 'discord.js';
1418
- * import { checkPermissions } from '@seedcord/gateway';
1419
- *
1420
- * // Ensure a member does NOT have ManageChannels permission in a text channel and show custom errors
1421
- * checkPermissions(member, textChannel, [
1422
- * PermissionFlagsBits.ManageChannels
1423
- * ], true, {
1424
- * missing: CustomMissingPermissionsError,
1425
- * dangerous: CustomDangerousPermissionsError
1426
- * });
1168
+ * checkPermissions(role, textChannel, [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]);
1427
1169
  * ```
1428
1170
  */
1429
- declare function checkPermissions(target: Role | GuildMember, ctx: TextChannel, scope: PermissionScope, inverse?: boolean, errors?: PermissionErrorNoticeOverrides): void;
1171
+ declare function checkPermissions(target: Role | GuildMember, ctx: TextChannel, scope: PermissionScope, inverse?: boolean, errors?: PermissionNoticeOverrides): void;
1430
1172
  /**
1431
- * Checks permissions using an options object. Refuses when a permission in {@link CheckPermissionOptions.scope} is missing,
1432
- * or with `options.inverse` when one is present.
1433
- *
1434
- * @param options - Complete options for the check
1435
- *
1173
+ * Checks permissions with an options object. Refuses when a permission in
1174
+ * {@link CheckPermissionOptions.scope} is missing, or with `options.inverse` when one is present.
1436
1175
  *
1437
1176
  * @example
1438
1177
  * ```ts
1439
1178
  * import { PermissionFlagsBits } from 'discord.js';
1440
1179
  * import { checkPermissions } from '@seedcord/gateway';
1441
1180
  *
1442
- * // Check permissions using an options object
1443
1181
  * checkPermissions({
1444
1182
  * for: member,
1445
1183
  * in: textChannel,
1446
- * scope: [
1447
- * PermissionFlagsBits.SendMessages,
1448
- * PermissionFlagsBits.ViewChannel
1449
- * ]
1450
- * });
1451
- * ```
1452
- *
1453
- * @example
1454
- * ```ts
1455
- * import { PermissionFlagsBits } from 'discord.js';
1456
- * import { checkPermissions } from '@seedcord/gateway';
1457
- *
1458
- * // Ensure a role does NOT have BanMembers permission in a guild using an options object
1459
- * checkPermissions({
1460
- * for: role,
1461
- * in: guild,
1462
- * scope: [
1463
- * PermissionFlagsBits.BanMembers
1464
- * ],
1465
- * inverse: true,
1466
- * missing: CustomMissingPermissionsError,
1467
- * dangerous: CustomDangerousPermissionsError
1184
+ * scope: [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel]
1468
1185
  * });
1469
1186
  * ```
1470
1187
  */
1471
1188
  declare function checkPermissions(options: CheckPermissionOptions): void;
1472
1189
  //#endregion
1473
- //#region src/bot/utilities/permissions/checkBotPermissions.d.ts
1474
- /**
1475
- * Checks if the bot has required permissions in a {@link Guild} or {@link TextChannel}. Refuses when a
1476
- * required permission is missing.
1477
- *
1478
- * @param target - Guild or text channel to check in
1479
- * @param scope - Permission bits to validate
1480
- * @param inverse - Whether to check for absence of the given permissions
1481
- * @param errors - Optional custom error constructors
1482
- *
1483
- * @example
1484
- * ```ts
1485
- * import { PermissionFlagsBits } from 'discord.js';
1486
- * import { checkBotPermissions } from '@seedcord/gateway';
1487
- *
1488
- * // Check if the bot has SendMessages and ViewChannel permissions in a text channel
1489
- * checkBotPermissions(textChannel, [
1490
- * PermissionFlagsBits.SendMessages,
1491
- * PermissionFlagsBits.ViewChannel
1492
- * ]);
1493
- * ```
1494
- */
1495
- declare function checkBotPermissions(target: Guild | TextChannel, scope: PermissionScope, inverse?: boolean, errors?: PermissionErrorNoticeOverrides): void;
1496
- //#endregion
1497
1190
  //#region src/bot/utilities/permissions/hasPermsToAssign.d.ts
1498
1191
  /**
1499
1192
  * Optional custom error constructors for {@link HasPermsToAssignOptions}.
@@ -1511,9 +1204,10 @@ interface HasPermsToAssignOptions {
1511
1204
  noticeOverrides?: AssignRoleNoticeOverrides;
1512
1205
  }
1513
1206
  /**
1514
- * Validates if the bot can assign a target role. Refuses when the target role is above the bot's, is managed, or the bot lacks Manage Roles.
1207
+ * Validates that the bot can assign a target role. Refuses when the target role is above the bot's, is managed, or the bot lacks Manage Roles.
1515
1208
  *
1516
1209
  * @param roleOrOptions - Target role or complete options for the check
1210
+ * @throws A `Notice` on refusal, or a `SeedcordError` when the bot has no role in the guild's role cache.
1517
1211
  *
1518
1212
  * @example
1519
1213
  * ```ts
@@ -1535,86 +1229,6 @@ interface HasPermsToAssignOptions {
1535
1229
  */
1536
1230
  declare function hasPermsToAssign(roleOrOptions: Role | HasPermsToAssignOptions): void;
1537
1231
  //#endregion
1538
- //#region src/bot/utilities/roles/fetchRole.d.ts
1539
- /**
1540
- * Fetches a role by ID from a client or guild. Refuses when the role doesn't exist.
1541
- *
1542
- * @param clientOrGuild - Discord client or guild instance
1543
- * @param roleId - The role ID to fetch
1544
- * @returns Promise resolving to the role
1545
- */
1546
- declare function fetchRole(clientOrGuild: Client | Guild, roleId: string): Promise<Role>;
1547
- //#endregion
1548
- //#region src/bot/utilities/roles/getBotRole.d.ts
1549
- /**
1550
- * Gets the bot's managed role in a guild.
1551
- *
1552
- * @param guild - The guild to get the bot role from
1553
- * @returns The bot's managed role in the guild
1554
- * @throws A **SeedcordError** if the client user is unavailable or if the bot role is missing
1555
- */
1556
- declare function getBotRole(guild: Guild): Role;
1557
- //#endregion
1558
- //#region src/bot/utilities/users/fetchGuildMember.d.ts
1559
- /**
1560
- * Fetches a guild member by user ID. Refuses when the user is not in the guild.
1561
- *
1562
- * @param guild - The guild to fetch the member from
1563
- * @param userId - The Discord user ID
1564
- * @returns Promise resolving to the guild member
1565
- */
1566
- declare function fetchGuildMember(guild: Guild, userId: string): Promise<GuildMember>;
1567
- //#endregion
1568
- //#region src/bot/utilities/users/fetchManyGuildMembers.d.ts
1569
- /**
1570
- * Fetches multiple guild members by user IDs.
1571
- *
1572
- * @param guild - The guild to fetch members from
1573
- * @param userIds - Array of Discord user IDs
1574
- * @returns Promise resolving to array of successfully fetched members
1575
- */
1576
- declare function fetchManyGuildMembers(guild: Guild, userIds: string[]): Promise<GuildMember[]>;
1577
- //#endregion
1578
- //#region src/bot/utilities/users/fetchUser.d.ts
1579
- /**
1580
- * Options for {@link fetchUser}.
1581
- */
1582
- interface FetchUserOptions {
1583
- /** Notice shown when the user does not exist, defaulting to the standard user-not-found notice. */
1584
- throwAs?: new (userArg: string) => Notice;
1585
- }
1586
- /**
1587
- * Fetches a Discord user by ID. Refuses when the user doesn't exist, with `options.throwAs` or the default.
1588
- *
1589
- * @param client - The Discord client instance
1590
- * @param userId - The Discord user ID
1591
- * @param options - Optional overrides, including the {@link FetchUserOptions.throwAs} notice
1592
- * @returns Promise resolving to the user
1593
- */
1594
- declare function fetchUser(client: Client, userId: string, options?: FetchUserOptions): Promise<User>;
1595
- //#endregion
1596
- //#region src/bot/utilities/users/fetchManyUsers.d.ts
1597
- /**
1598
- * Fetches multiple Discord users by IDs.
1599
- *
1600
- * @param client - The Discord client instance
1601
- * @param userIds - Array of Discord user IDs
1602
- * @param options - Optional overrides threaded to each {@link fetchUser} call
1603
- * @returns Promise resolving to array of successfully fetched users
1604
- */
1605
- declare function fetchManyUsers(client: Client, userIds: string[], options?: FetchUserOptions): Promise<User[]>;
1606
- //#endregion
1607
- //#region src/bot/utilities/users/updateMemberRoles.d.ts
1608
- /**
1609
- * Updates a guild member's roles by adding and removing specified roles.
1610
- *
1611
- * @param rolesToAdd - Array of role IDs to add to the member
1612
- * @param rolesToRemove - Array of role IDs to remove from the member
1613
- * @param member - The guild member to update
1614
- * @returns Promise that resolves when roles are updated
1615
- */
1616
- declare function updateMemberRoles(rolesToAdd: Snowflake[], rolesToRemove: Snowflake[], member: GuildMember): Promise<void>;
1617
- //#endregion
1618
1232
  //#region src/bot/confirm/getConfirmation.d.ts
1619
1233
  type Outcome = ReplyResponse | (() => Promisable<ReplyResponse>);
1620
1234
  /** Options shared by both confirmation forms. */
@@ -1663,10 +1277,10 @@ interface DefaultConfirmOptions extends ConfirmOptions {
1663
1277
  /**
1664
1278
  * Shows a confirm/cancel prompt with built-in Confirm and Cancel buttons and resolves to `true` only if the
1665
1279
  * invoking user clicks confirm. A cancel click or a timeout resolves to `false`. Gate the action behind it
1666
- * with an early return. A failed prompt send throws into the fault boundary. Not usable from a
1667
- * {@link ModalHandler}, the `interaction` parameter excludes a modal submit at compile time.
1280
+ * with an early return. A failed prompt send throws into the fault boundary. A {@link ModalHandler} is
1281
+ * excluded at compile time.
1668
1282
  *
1669
- * @param interaction - The repliable interaction to prompt on, `this.event` inside a non-modal handler.
1283
+ * @param handler - The handler to prompt from, `this` inside a non-modal handler.
1670
1284
  * @param prompt - The message shown above the Confirm and Cancel buttons.
1671
1285
  * @param options - Ephemeral flag, timeout, the built-in buttons' labels and style, and the optional
1672
1286
  * `onConfirm`/`onCancel`/`onTimeout` outcome replies that edit the prompt in place.
@@ -1680,29 +1294,29 @@ interface DefaultConfirmOptions extends ConfirmOptions {
1680
1294
  * class BanHandler extends SlashHandler<'ban'> {
1681
1295
  * async execute() {
1682
1296
  * const target = this.options.getUser('target', true);
1683
- * if (!(await getConfirmation(this.event, `Ban ${target.tag}? This cannot be undone.`))) return;
1297
+ * if (!(await getConfirmation(this, `Ban ${target.tag}? This cannot be undone.`))) return;
1684
1298
  * await this.event.guild?.members.ban(target.id);
1685
1299
  * }
1686
1300
  * }
1687
1301
  * ```
1688
1302
  */
1689
- declare function getConfirmation(interaction: NonModalInteraction, prompt: string, options?: DefaultConfirmOptions): Promise<boolean>;
1303
+ declare function getConfirmation(handler: RepliableHandler<NonModalInteraction>, prompt: string, options?: DefaultConfirmOptions): Promise<boolean>;
1690
1304
  /**
1691
1305
  * Shows a confirm/cancel prompt you build yourself and resolves to `true` only if the invoking user clicks
1692
1306
  * confirm. The factory receives the two minted button ids. Set them on your own buttons. A cancel click or a
1693
- * timeout resolves to `false`. A failed prompt send throws into the fault boundary. Not usable from a
1694
- * {@link ModalHandler}.
1307
+ * timeout resolves to `false`. A failed prompt send throws into the fault boundary. A {@link ModalHandler} is
1308
+ * excluded at compile time.
1695
1309
  *
1696
- * @param interaction - The repliable interaction to prompt on, `this.event` inside a non-modal handler.
1310
+ * @param handler - The handler to prompt from, `this` inside a non-modal handler.
1697
1311
  * @param prompt - A factory given the minted `{ confirm, cancel }` ids that returns the reply to show. Build
1698
- * it with the kit `BuilderComponent`/`RowComponent` wrappers, not raw discord.js builders.
1312
+ * it with the `BuilderComponent` and `RowComponent` wrappers.
1699
1313
  * @param options - Ephemeral flag, timeout, and the optional `onConfirm`/`onCancel`/`onTimeout` outcome
1700
1314
  * replies that edit the prompt in place.
1701
1315
  * @returns `true` if confirmed, `false` on cancel or timeout.
1702
1316
  *
1703
1317
  * @remarks
1704
- * The prompt is collected in-process, so it does not survive a bot restart. Without an outcome hook, deliver
1705
- * a result after confirming with a fresh `interaction.followUp(...)`, the prompt is already gone.
1318
+ * The prompt is collected in-process, so it does not survive a bot restart. Without an outcome hook the
1319
+ * prompt is gone once the user confirms, so deliver the result with a fresh `this.followUp(...)`.
1706
1320
  *
1707
1321
  * @example
1708
1322
  * ```ts
@@ -1732,14 +1346,14 @@ declare function getConfirmation(interaction: NonModalInteraction, prompt: strin
1732
1346
  *
1733
1347
  * const target = this.options.getUser('target', true);
1734
1348
  * const confirmed = await getConfirmation(
1735
- * this.event,
1349
+ * this,
1736
1350
  * (ids) => ({ components: [new BanPrompt(`Ban ${target.tag}?`).component, new ConfirmRow(ids).component] }),
1737
1351
  * { onConfirm: { components: [new BanPrompt(`Banned ${target.tag}.`).component] } }
1738
1352
  * );
1739
1353
  * if (!confirmed) return;
1740
1354
  * ```
1741
1355
  */
1742
- declare function getConfirmation(interaction: NonModalInteraction, prompt: (ids: {
1356
+ declare function getConfirmation(handler: RepliableHandler<NonModalInteraction>, prompt: (ids: {
1743
1357
  confirm: string;
1744
1358
  cancel: string;
1745
1359
  }) => Promisable<ReplyResponse>, options?: ConfirmOptions): Promise<boolean>;
@@ -1755,103 +1369,11 @@ interface PageContext {
1755
1369
  user: User;
1756
1370
  /** The guild, or `null` in a DM. */
1757
1371
  guild: Guild | null;
1758
- /** The framework core, passed only when a source requires framework services. */
1759
- core?: Core;
1760
- }
1761
- //#endregion
1762
- //#region src/pagination/controls.d.ts
1763
- /** The five built-in nav controls. */
1764
- type ControlKey = 'first' | 'prev' | 'indicator' | 'next' | 'last';
1765
- type CustomIdStyle = ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success | ButtonStyle.Danger;
1766
- /** Cosmetic overrides for a control button. `style` excludes Link and Premium, which would un-route it. */
1767
- interface ControlCosmetics {
1768
- label?: string;
1769
- style?: CustomIdStyle;
1770
- emoji?: APIMessageComponentEmoji;
1771
- }
1772
- /** The controls passed to `render`. Each accessor returns a fresh builder stamped with its target page. */
1773
- interface PaginatorControls {
1774
- /**
1775
- * A fresh `ButtonBuilder` for one control, already stamped with its target page and disabled-at-bounds
1776
- * state. Call only cosmetic setters on it, a `setCustomId` or `setStyle(Link)` un-routes it.
1777
- */
1778
- button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder;
1779
- /**
1780
- * Assemble an action row of the chosen controls, in order. Throws on an empty set, more than five
1781
- * controls, or a duplicate.
1782
- */
1783
- row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder>;
1784
- }
1785
- //#endregion
1786
- //#region src/pagination/render.d.ts
1787
- /** What `renderItem` returns for one item, a text line or a section. */
1788
- type ItemRender<Item> = (item: Item, index: number) => string | BuilderComponent<'section'>;
1789
- /** What the V2 reply can be built from. Each arm is normalized into a {@link ReplyResponse}. */
1790
- type Renderable = string | V2Component[] | ReplyResponse;
1791
- /** A full-page render override, handed the page data and the controls factory. */
1792
- type PageRender<Item> = (view: PageView<Item>, controls: PaginatorControls) => Renderable;
1793
- //#endregion
1794
- //#region src/pagination/sources.d.ts
1795
- /**
1796
- * The one method a paginator calls on a source, once per click. Implement it to supply a custom source.
1797
- *
1798
- * @typeParam Item - The item type the source pages over.
1799
- */
1800
- interface PageSource<Item> {
1801
- page(ctx: PageContext, n: number): Promise<PageView<Item>>;
1802
- }
1803
- /**
1804
- * A source for a bounded list you can load whole. It loads the full list on every click, then slices the
1805
- * page via {@link paginate}, so the real total is known (a real last button, "Page X of Y"). Cache inside
1806
- * your loader if the load is expensive.
1807
- *
1808
- * @typeParam Item - The item type, inferred from the loader's return.
1809
- */
1810
- declare class ArraySource<Item> implements PageSource<Item> {
1811
- private readonly load;
1812
- private readonly perPage;
1813
- constructor(load: (ctx: PageContext) => Promisable<readonly Item[]>, opts?: {
1814
- perPage?: number;
1815
- });
1816
- page(ctx: PageContext, n: number): Promise<PageView<Item>>;
1817
- }
1818
- /**
1819
- * A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).
1820
- * The fetcher receives the page index and the page size and reports whether a next page exists. A cursor
1821
- * source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator
1822
- * reads "Page X".
1823
- *
1824
- * @typeParam Item - The item type, inferred from the fetcher's slice.
1825
- */
1826
- declare class CursorSource<Item> implements PageSource<Item> {
1827
- private readonly fetch;
1828
- private readonly perPage;
1829
- constructor(fetch: (ctx: PageContext, page: number, perPage: number) => Promisable<{
1830
- items: readonly Item[];
1831
- hasNext: boolean;
1832
- }>, opts?: {
1833
- perPage?: number;
1834
- });
1835
- page(ctx: PageContext, n: number): Promise<PageView<Item>>;
1372
+ /** The framework core. */
1373
+ core: Core;
1836
1374
  }
1837
1375
  //#endregion
1838
1376
  //#region src/pagination/Paginator.d.ts
1839
- interface PaginatorConfig<Item, Prefix extends string> {
1840
- /** The route prefix used to build the page cursor on the nav buttons. */
1841
- prefix: Prefix;
1842
- /** Where the page data comes from. */
1843
- source: PageSource<Item>;
1844
- /** Render one item, `index` is its absolute position across pages. Ignored when `render` is set. */
1845
- renderItem?: ItemRender<Item>;
1846
- /** Take over the whole page tree. Receives the page data and the controls factory. */
1847
- render?: PageRender<Item>;
1848
- /**
1849
- * Whether the first page is ephemeral.
1850
- *
1851
- * @defaultValue `false`
1852
- */
1853
- ephemeral?: boolean;
1854
- }
1855
1377
  type PaginatorHandlerCtor<Prefix extends string> = new (event: ButtonInteraction<'cached'>, core: Core) => ButtonHandler<[PageCursor<Prefix>]> & {
1856
1378
  execute(): Promise<void>;
1857
1379
  };
@@ -1874,184 +1396,74 @@ type PaginatorHandlerCtor<Prefix extends string> = new (event: ButtonInteraction
1874
1396
  * export class BansNav extends Bans.Handler {}
1875
1397
  * ```
1876
1398
  */
1877
- declare class Paginator<Item, const Prefix extends string> {
1878
- /** The page cursor, pass it to your `@ButtonRoute`. */
1879
- readonly cursor: PageCursor<Prefix>;
1399
+ declare class Paginator<Item, const Prefix extends string> extends PaginatorBase<Item, Prefix, PageContext> {
1880
1400
  /** The nav handler base. Extend it with an empty body and decorate it, `@ButtonRoute(p.cursor)`. */
1881
1401
  readonly Handler: PaginatorHandlerCtor<Prefix>;
1882
- private readonly config;
1883
- constructor(config: PaginatorConfig<Item, Prefix>);
1884
- /** Render page 0 and send it, picking reply or followUp from the interaction's state. */
1885
- start(interaction: Repliables, core?: Core): Promise<Message>;
1886
- /** Render a page as a {@link ReplyResponse}. To post it elsewhere, add `flags: MessageFlags.IsComponentsV2`. */
1887
- page(ctx: PageContext, n: number): Promise<ReplyResponse>;
1888
- }
1889
- //#endregion
1890
- //#region src/subscribers/Subscriber.d.ts
1891
- /**
1892
- * Abstract base class for handling application subscribers.
1893
- *
1894
- * Provides type-safe access to subscribers data and the core framework instance.
1895
- * Extend this class to create custom subscriber handlers.
1896
- *
1897
- * @typeParam KeyOfSubscribers - The specific subscriber type this handler processes
1898
- */
1899
- declare abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey> {
1900
- protected readonly data: AllSubscriptions[KeyOfSubscribers];
1901
- protected readonly core: Core;
1902
- protected readonly logger: Logger;
1402
+ constructor(config: PaginatorConfig<Item, Prefix, PageContext>);
1903
1403
  /**
1904
- * Instantiates the subscriber with event data and core.
1404
+ * Render page 0 and send it through the handler's sender, which picks reply, edit, or followUp from its
1405
+ * ack state.
1905
1406
  *
1906
- * @param data - The subscriber event data
1907
- * @param core - The core framework instance
1908
- */
1909
- constructor(data: AllSubscriptions[KeyOfSubscribers], core: Core);
1910
- /**
1911
- * Executes the subscriber handler logic.
1407
+ * @param handler - The handler starting the paginator, normally `this`.
1912
1408
  */
1913
- abstract execute(): Promise<void>;
1409
+ start(handler: RepliableHandler<Repliables>): Promise<Message>;
1914
1410
  }
1915
1411
  //#endregion
1916
- //#region src/subscribers/decorators/Subscribe.d.ts
1917
- /**
1918
- * Options accepted by the `@Subscribe` decorator.
1919
- */
1920
- interface SubscribeOptions {
1921
- /**
1922
- * Frequency: `'once'` or `'on'`.
1923
- *
1924
- * @defaultValue `'on'`
1925
- */
1926
- readonly frequency?: EventFrequency | undefined;
1927
- }
1412
+ //#region src/pagination/sources.d.ts
1928
1413
  /**
1929
- * Registers a subscriber handler class with a specific subscriber event.
1930
- *
1931
- * Associates the decorated class with a subscriber event type for automatic
1932
- * registration and execution when the subscriber is emitted.
1414
+ * A source for a bounded list you can load whole. It loads the full list on every click, then slices the
1415
+ * page, so the real total is known (a real last button, "Page X of Y"). Cache inside your loader if the
1416
+ * load is expensive.
1933
1417
  *
1934
- * @typeParam TSubscriber - The subscriber event name to register for
1935
- * @param subscriber - The subscriber event name to register for
1936
- * @param options - Options to configure the subscriber handler registration.
1937
- * @decorator
1938
- * @example
1939
- * ```typescript
1940
- * \@Subscribe('userJoin')
1941
- * class WelcomeHandler extends Subscriber<'userJoin'> {
1942
- * async execute() {
1943
- * // Handle user join event
1944
- * }
1945
- * }
1946
- * ```
1947
- * @example
1948
- * ```ts
1949
- * \@Subscribe('userJoin', { frequency: 'once' })
1950
- * // or
1951
- * \@Subscribe('userJoin')
1952
- * ```
1953
- */
1954
- declare function Subscribe<TSubscriber extends SubscriptionKey>(subscriber: TSubscriber, options?: SubscribeOptions): <HandlerCtor extends Constructor<Subscriber<TSubscriber>>>(constructor: HandlerCtor) => void;
1955
- //#endregion
1956
- //#region src/subscribers/bases/WebhookSender.d.ts
1957
- /**
1958
- * A file attached to a webhook report.
1959
- */
1960
- interface WebhookFile {
1961
- name: string;
1962
- description: string;
1963
- data: Buffer;
1964
- }
1965
- /**
1966
- * The payload {@link WebhookSender.send} posts.
1418
+ * @typeParam Item - The item type, inferred from the loader's return.
1967
1419
  */
1968
- interface WebhookSendOptions {
1969
- flags: number;
1970
- username: string;
1971
- components: readonly {
1972
- toJSON(): APIMessageTopLevelComponent;
1973
- }[];
1974
- files?: readonly WebhookFile[] | undefined;
1975
- }
1420
+ declare class ArraySource<Item> extends ArraySource$1<Item, PageContext> {}
1976
1421
  /**
1977
- * Sends component messages to a Discord webhook through `@discordjs/rest`.
1422
+ * A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).
1423
+ * The fetcher receives the page index and the page size and reports whether a next page exists. A cursor
1424
+ * source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator
1425
+ * reads "Page X".
1978
1426
  *
1979
- * @throws A `SeedcordError` when the url does not carry a webhook id and token.
1427
+ * @typeParam Item - The item type, inferred from the fetcher's slice.
1980
1428
  */
1981
- declare class WebhookSender {
1982
- private readonly rest;
1983
- private readonly route;
1984
- constructor(url: string);
1985
- /**
1986
- * Fetches the webhook object, sending no message. Returns `missing` on a 404 or 401 from
1987
- * Discord and `unreachable` on any other failure.
1988
- */
1989
- verify(): Promise<'ok' | 'missing' | 'unreachable'>;
1990
- send(options: WebhookSendOptions): Promise<void>;
1991
- }
1429
+ declare class CursorSource<Item> extends CursorSource$1<Item, PageContext> {}
1992
1430
  //#endregion
1993
- //#region src/subscribers/bases/WebhookLog.d.ts
1431
+ //#region src/subscribers/index.d.ts
1994
1432
  /**
1995
- * The content a reporter returns from {@link WebhookLog.report}.
1433
+ * Base class for a gateway subscriber, binding `this.core` to the gateway {@link Core}.
1434
+ *
1435
+ * @typeParam KeyOfSubscribers - The subscription key this handler receives
1996
1436
  */
1997
- interface WebhookReport {
1998
- /** Shown as the webhook message author. Defaults to the reporter's class name. */
1999
- username?: string;
2000
- components: readonly {
2001
- toJSON(): APIMessageTopLevelComponent;
2002
- }[];
2003
- files?: readonly WebhookFile[] | undefined;
2004
- }
1437
+ declare abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey> extends Subscriber$1<KeyOfSubscribers, Core> {}
2005
1438
  /**
2006
- * Base class for subscribers that deliver their event to a Discord webhook.
2007
- *
2008
- * Declare the url's environment variable with `@WebhookUrl` and implement {@link report}. Url
2009
- * resolution, validation, sender reuse, and sending run in the base. When the variable is unset
2010
- * the reporter is skipped at registration with a boot warning.
1439
+ * Base class for a gateway subscriber that delivers its event to a Discord webhook, binding
1440
+ * `this.core` to the gateway {@link Core}.
2011
1441
  *
2012
1442
  * @typeParam KeyOfSubscribers - The subscription key this reporter receives
2013
1443
  */
2014
- declare abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey> extends Subscriber<KeyOfSubscribers> {
2015
- private static readonly senders;
2016
- /** Builds the message for one published event. */
2017
- abstract report(): WebhookReport | Promise<WebhookReport>;
2018
- execute(): Promise<void>;
2019
- /** @internal */
2020
- static senderFor(url: string): WebhookSender;
2021
- /** @internal */
2022
- static envKeyOf(ctor: NewableFunction): string;
2023
- /** @internal Returns null when the env var is unset, throws when set but malformed. */
2024
- static urlOf(envKey: string): string | null;
2025
- }
1444
+ declare abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey> extends WebhookLog$1<KeyOfSubscribers, Core> {}
2026
1445
  //#endregion
2027
- //#region src/subscribers/decorators/WebhookUrl.d.ts
1446
+ //#region src/plugin.d.ts
1447
+ /** The options a gateway plugin declares, narrowed to the transports this base serves. */
1448
+ type GatewayPluginOptions = TypedOmit<PluginOptions$1, 'transport'> & {
1449
+ transport?: 'gateway' | 'any';
1450
+ };
2028
1451
  /**
2029
- * Declares the environment variable a {@link WebhookLog} reporter reads its webhook url from.
1452
+ * Base class for a gateway plugin, binding `this.core` to the gateway {@link Core}.
2030
1453
  *
2031
- * An unset variable disables the reporter with a boot warning. A set but malformed value throws
2032
- * at boot.
1454
+ * A plugin that runs on either transport extends the base from `@seedcord/core/plugin`, whose
1455
+ * `this.core` is typed to the shared members only.
2033
1456
  *
2034
- * @param envKey - The environment variable name holding the webhook url
2035
- * @decorator
2036
- * @example
2037
- * ```ts
2038
- * \@Subscribe('memberBanned')
2039
- * \@WebhookUrl('BAN_LOG_WEBHOOK_URL')
2040
- * class BanLog extends WebhookLog<'memberBanned'> {
2041
- * report() {
2042
- * return { components: [new BanCard(this.data).component] };
2043
- * }
2044
- * }
2045
- * ```
1457
+ * @typeParam Opts - The transport and runtime the plugin declares.
2046
1458
  */
2047
- declare function WebhookUrl(envKey: string): <HandlerCtor extends Constructor<WebhookLog<SubscriptionKey>>>(constructor: HandlerCtor) => void;
1459
+ declare abstract class Plugin<Opts extends GatewayPluginOptions = {}> extends Plugin$1<Opts, Core> {}
2048
1460
  //#endregion
2049
1461
  //#region src/Seedcord.d.ts
2050
1462
  /**
2051
1463
  * The gateway bot host. Opens a discord.js gateway session, discovers handlers, and runs
2052
1464
  * coordinated startup and shutdown. Attach plugins with `attach()`.
2053
1465
  */
2054
- declare class Seedcord extends Pluggable implements Core {
1466
+ declare class Seedcord extends Pluggable<'gateway', 'server'> implements Core, SeedcordInstance {
2055
1467
  readonly config: GatewayConfig;
2056
1468
  /** @internal */
2057
1469
  readonly [SeedcordBrand] = true;
@@ -2061,14 +1473,13 @@ declare class Seedcord extends Pluggable implements Core {
2061
1473
  readonly version: string;
2062
1474
  private readonly healthCheck?;
2063
1475
  private readonly hmrManager;
2064
- /** @see {@link CoordinatedShutdown} */
2065
- readonly shutdown: CoordinatedShutdown;
2066
- /** @see {@link CoordinatedStartup} */
2067
- readonly startup: CoordinatedStartup;
2068
1476
  /** @see {@link Bus} */
2069
1477
  readonly bus: Bus;
1478
+ private readonly subscribers;
2070
1479
  /** @see {@link Bot} */
2071
1480
  readonly bot: Bot;
1481
+ /** The discord.js client's REST client. Its token is set during the Login phase. */
1482
+ readonly rest: REST;
2072
1483
  /** @see {@link IRateLimiter} */
2073
1484
  readonly rateLimiter: IRateLimiter;
2074
1485
  /**
@@ -2078,7 +1489,6 @@ declare class Seedcord extends Pluggable implements Core {
2078
1489
  constructor(config: GatewayConfig);
2079
1490
  /** The bot's discord username, populated after login. */
2080
1491
  get username(): string | undefined;
2081
- protected pluginCapabilities(): PluginCapabilities;
2082
1492
  protected static reset(): void;
2083
1493
  private registerStartupTasks;
2084
1494
  /**
@@ -2094,5 +1504,5 @@ declare class Seedcord extends Pluggable implements Core {
2094
1504
  /** Package version */
2095
1505
  declare const version: string;
2096
1506
  //#endregion
2097
- export { ArraySource, AssignRoleNoticeOverrides, AutocompleteHandler, type BotEvents, ButtonHandler, type CheckPermissionOptions, CommandMentions, type ConfirmOptions, ContextMenuHandler, type Core, CursorSource, type DefaultConfirmOptions, Emojis, type EventGateContext, EventHandler, EventMiddleware, type EventSpec, type EventsConfig, type FaultSource, FetchUserOptions, type GateContext, Gated, type GatewayBotConfig, type GatewayConfig, HasPermsToAssignOptions, IgnoreBots, type InjectedEmojiMap, type InjectedMentionMap, type InteractionGateContext, InteractionHandler, InteractionMiddleware, Middleware, type MiddlewareOptions, MiddlewareType, ModalHandler, Nsfw, Paginator, type PaginatorControls, type PermissionErrorNoticeOverrides, RegisterEvent, type RegisterEventOptions, RepliableHandler, type Repliables, Seedcord, SelectMenuHandler, SlashHandler, type SlashOptions, Subscribe, type SubscribeOptions, Subscriber, type SubscriptionData, type SubscriptionKey, type Subscriptions, type ValidEventTypes, type ValidInteractionTypes, type ValidNonInteractionKeys, type WebhookFile, WebhookLog, type WebhookReport, WebhookUrl, checkBotPermissions, checkPermissions, fetchGuildMember, fetchManyGuildMembers, fetchManyUsers, fetchRole, fetchText, fetchUser, getBotRole, getConfirmation, hasPermsToAssign, updateMemberRoles, version };
1507
+ export { ArraySource, AssignRoleNoticeOverrides, AutocompleteHandler, ButtonHandler, type CheckPermissionOptions, type ConfirmOptions, ContextMenuHandler, type Core, CursorSource, type DefaultConfirmOptions, Emojis, type EventGateContext, EventHandler, EventMiddleware, type EventSpec, type EventsConfig, type GateContext, Gated, type GatewayBotConfig, type GatewayConfig, type GatewayPluginOptions, HasPermsToAssignOptions, IgnoreBots, type InjectedEmojiMap, type InteractionGateContext, InteractionHandler, InteractionMiddleware, Middleware, type MiddlewareOptions, MiddlewareType, ModalHandler, Nsfw, type PageContext, Paginator, Plugin, type PluginLifecycleSpec, type PluginOptions, RegisterEvent, type RegisterEventOptions, RepliableHandler, type Repliables, Seedcord, SelectMenuHandler, SlashHandler, type SlashOptions, Subscriber, type ValidEventTypes, type ValidInteractionTypes, type ValidNonInteractionKeys, WebhookLog, checkBotPermissions, checkPermissions, getConfirmation, hasPermsToAssign, version };
2098
1508
  //# sourceMappingURL=index.d.mts.map