@seedcord/gateway 0.0.1 → 0.1.0-next.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 +7 -3
- package/dist/index.cjs +4023 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2528 -2
- package/dist/index.mjs +3914 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +94 -52
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,2532 @@
|
|
|
1
|
-
|
|
1
|
+
import { BuilderComponent, CoreBase, Gate, GateContextBase, GateNoticeOptions, MessageContextMenuRegistry, Notice, OptionKind, PageView, RegisterCommand, RequiredOf, SlashOptionRegistry, UserContextMenuRegistry } from "@seedcord/core";
|
|
2
|
+
import { AnyCustomId, DecodedParams, GateFitsWith, HasComponentDefs, PageCursor } from "@seedcord/core/internal";
|
|
3
|
+
import { APIInteractionGuildMember, APIMessageComponentEmoji, 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, WebhookClient } from "discord.js";
|
|
4
|
+
import { CoordinatedShutdown, CoordinatedStartup, Logger, SEEventMapLike, SENoEvents, StartupPhase, StrictEventEmitter } from "@seedcord/services";
|
|
5
|
+
import { ActionRowBuilder, ButtonBuilder, ContextMenuCommandBuilder, SlashCommandBuilder } from "@discordjs/builders";
|
|
6
|
+
import { HmrAware, HmrUpdateEvent, SeedcordBrand, SeedcordInstance } from "@seedcord/types/internal";
|
|
7
|
+
import { UUID } from "node:crypto";
|
|
8
|
+
import { BotConfig, Config, EmojiMap, IRateLimiter, Nullable, ReplyResponse, Tail, V2Component } from "@seedcord/types";
|
|
9
|
+
export * from "@seedcord/core";
|
|
10
|
+
export * from "@seedcord/errors";
|
|
11
|
+
export * from "@seedcord/utils";
|
|
12
|
+
export * from "@seedcord/services";
|
|
13
|
+
export * from "@seedcord/rate-limiter";
|
|
14
|
+
export type * from "@seedcord/types";
|
|
15
|
+
|
|
16
|
+
//#region src/bot/utilities/miscellaneous/contextMenuLeaves.d.ts
|
|
17
|
+
/** The registered context-menu command names, split by kind, deduplicated. @internal */
|
|
18
|
+
interface ContextMenuLeaves {
|
|
19
|
+
readonly user: Set<string>;
|
|
20
|
+
readonly message: Set<string>;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/interfaces/Config.d.ts
|
|
24
|
+
/**
|
|
25
|
+
* Djs Events handlers
|
|
26
|
+
*/
|
|
27
|
+
type EventsConfig = {
|
|
28
|
+
/**
|
|
29
|
+
* Path to dir containing event handlers.
|
|
30
|
+
*/
|
|
31
|
+
path: string;
|
|
32
|
+
/**
|
|
33
|
+
* Optional path to event middleware directory
|
|
34
|
+
*/
|
|
35
|
+
middlewares?: string;
|
|
36
|
+
} | {
|
|
37
|
+
/** No events configured */path: null;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* The gateway transport's bot configuration, the shared {@link BotConfig} plus the pieces only a
|
|
41
|
+
* gateway bot has, the discord.js client options and the gateway event handlers.
|
|
42
|
+
*/
|
|
43
|
+
interface GatewayBotConfig extends BotConfig {
|
|
44
|
+
/**
|
|
45
|
+
* Passed directly to the discord.js `Client` constructor.
|
|
46
|
+
*/
|
|
47
|
+
clientOptions: ClientOptions;
|
|
48
|
+
events: EventsConfig;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The gateway transport's configuration, what the {@link Seedcord} constructor takes.
|
|
52
|
+
*/
|
|
53
|
+
interface GatewayConfig extends Config {
|
|
54
|
+
bot: GatewayBotConfig;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/interfaces/Plugin.d.ts
|
|
58
|
+
/** Interface for objects that can be initialized asynchronously */
|
|
59
|
+
interface Initializeable {
|
|
60
|
+
init(): Promise<void>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Base class for Seedcord plugins
|
|
64
|
+
*
|
|
65
|
+
* Extend this class to create plugins that integrate with the Seedcord lifecycle.
|
|
66
|
+
* Plugins have access to the core instance and must implement initialization logic.
|
|
67
|
+
*/
|
|
68
|
+
declare abstract class Plugin<TPluginEvents extends SEEventMapLike<TPluginEvents> = SENoEvents> extends StrictEventEmitter<TPluginEvents> implements Initializeable, HmrAware {
|
|
69
|
+
protected pluggable: Core;
|
|
70
|
+
/** Logger instance for this plugin. */
|
|
71
|
+
abstract logger: Logger;
|
|
72
|
+
name: string;
|
|
73
|
+
constructor(pluggable: Core);
|
|
74
|
+
/**
|
|
75
|
+
* Initialize the plugin.
|
|
76
|
+
* @virtual
|
|
77
|
+
*/
|
|
78
|
+
abstract init(): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Reloads plugin state on an HMR update. The base implementation is a no-op, override it in your plugin.
|
|
81
|
+
* @virtual
|
|
82
|
+
*/
|
|
83
|
+
onHmr(_event: HmrUpdateEvent): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
|
|
86
|
+
* @param patterns - Glob patterns relative to the project root
|
|
87
|
+
*/
|
|
88
|
+
protected registerCriticalFiles(patterns: string[]): void;
|
|
89
|
+
/** @internal */
|
|
90
|
+
setMaxListeners(n: number): this;
|
|
91
|
+
/** @internal */
|
|
92
|
+
removeListener<TEventKey extends Extract<keyof TPluginEvents, string | symbol>>(event: TEventKey, listener: (...args: TPluginEvents[TEventKey]) => void): this;
|
|
93
|
+
/** @internal */
|
|
94
|
+
removeAllListeners(eventName?: string | symbol): this;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Constructor type for plugins that can accept additional arguments after Core
|
|
98
|
+
* @typeParam TPlugin - The plugin type being constructed
|
|
99
|
+
*
|
|
100
|
+
* @internal
|
|
101
|
+
*/
|
|
102
|
+
type PluginCtor<TPlugin extends Plugin = Plugin> = new (core: Core, ...args: any[]) => TPlugin;
|
|
103
|
+
/**
|
|
104
|
+
* Extracts the argument types for a plugin constructor (excluding the Core parameter)
|
|
105
|
+
* @typeParam Ctor - The plugin constructor to extract arguments from
|
|
106
|
+
*
|
|
107
|
+
* @internal
|
|
108
|
+
*/
|
|
109
|
+
type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;
|
|
110
|
+
/**
|
|
111
|
+
* Base class for objects that can have plugins attached.
|
|
112
|
+
*
|
|
113
|
+
* Provides plugin attachment capabilities and lifecycle management. Plugins are attached during
|
|
114
|
+
* configuration and initialized during startup. Not constructed directly, the host is a {@link Seedcord}.
|
|
115
|
+
*/
|
|
116
|
+
declare class Pluggable<TPluggableEvents extends SEEventMapLike<TPluggableEvents> = SENoEvents> extends StrictEventEmitter<TPluggableEvents> {
|
|
117
|
+
protected isInitialized: boolean;
|
|
118
|
+
protected readonly shutdown: CoordinatedShutdown;
|
|
119
|
+
protected readonly startup: CoordinatedStartup;
|
|
120
|
+
protected readonly plugins: Plugin[];
|
|
121
|
+
private static readonly PLUGIN_INIT_TIMEOUT_MS;
|
|
122
|
+
constructor(shutdown: CoordinatedShutdown, startup: CoordinatedStartup);
|
|
123
|
+
/** @internal */
|
|
124
|
+
protected init(): Promise<this>;
|
|
125
|
+
/**
|
|
126
|
+
* Attaches a plugin to this instance
|
|
127
|
+
*
|
|
128
|
+
* Plugins provide external functionality and are initialized during the specified startup phase.
|
|
129
|
+
* The plugin instance becomes available as a property in `core` wherever it's available.
|
|
130
|
+
*
|
|
131
|
+
* Make sure to augment the {@link Core} interface with the plugin type to ensure TypeScript recognizes it and provides intellisense.
|
|
132
|
+
*
|
|
133
|
+
* @typeParam Key - The property name for accessing the plugin
|
|
134
|
+
* @typeParam Ctor - The plugin constructor type
|
|
135
|
+
* @param key - Property name to access the plugin instance
|
|
136
|
+
* @param Plugin - Plugin constructor class
|
|
137
|
+
* @param startupPhase - When during startup to initialize this plugin ({@link StartupPhase})
|
|
138
|
+
* @param args - Additional arguments to pass to the plugin constructor
|
|
139
|
+
* @returns This instance with the plugin attached as a typed property
|
|
140
|
+
* @throws A **SeedcordError** When called after initialization or if key already exists
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* seedcord.attach('db', Mongo, StartupPhase.Configuration, { uri: 'mongodb://...', name: 'seedcord', dir: ... })
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
attach<Key extends string, Ctor extends PluginCtor>(this: this, key: Key, Plugin: Ctor, startupPhase: StartupPhase, ...args: PluginArgs<Ctor>): this & Record<Key, InstanceType<Ctor>>;
|
|
147
|
+
/** @internal */
|
|
148
|
+
setMaxListeners(n: number): this;
|
|
149
|
+
/** @internal */
|
|
150
|
+
removeListener<TEventKey extends Extract<keyof TPluggableEvents, string | symbol>>(event: TEventKey, listener: (...args: TPluggableEvents[TEventKey]) => void): this;
|
|
151
|
+
/** @internal */
|
|
152
|
+
removeAllListeners(eventName?: string | symbol): this;
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/subscribers/types/Subscriptions.d.ts
|
|
156
|
+
/**
|
|
157
|
+
* Where a reported fault came from. A union over `kind`.
|
|
158
|
+
*/
|
|
159
|
+
type FaultSource = InteractionFaultSource | EventFaultSource;
|
|
160
|
+
/**
|
|
161
|
+
* A fault that came from a discord interaction, JSON-safe for a webhook payload.
|
|
162
|
+
*/
|
|
163
|
+
interface InteractionFaultSource {
|
|
164
|
+
kind: 'interaction';
|
|
165
|
+
/** Which interaction kind produced the fault. */
|
|
166
|
+
interactionKind: 'slash' | 'context-menu' | 'button' | 'select' | 'modal';
|
|
167
|
+
/** Slash or context-menu command name, null for component and modal interactions. */
|
|
168
|
+
command: string | null;
|
|
169
|
+
/** Component or modal customId, null for slash and context-menu interactions. */
|
|
170
|
+
customId: string | null;
|
|
171
|
+
/** User who triggered the interaction. */
|
|
172
|
+
userId: string;
|
|
173
|
+
/** Guild the interaction came from, null in DMs. */
|
|
174
|
+
guildId: string | null;
|
|
175
|
+
/** Channel the interaction came from, null when unavailable. */
|
|
176
|
+
channelId: string | null;
|
|
177
|
+
/** The interaction's own id. */
|
|
178
|
+
interactionId: string;
|
|
179
|
+
/** The raw interaction, made JSON-safe at serialization with filterCirculars. */
|
|
180
|
+
raw: unknown;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* A fault that came from a client event, JSON-safe for a webhook payload. The actor, guild, and channel
|
|
184
|
+
* are best-effort, derived from the event args, so each is nullable. The raw args carry the full detail.
|
|
185
|
+
*/
|
|
186
|
+
interface EventFaultSource {
|
|
187
|
+
kind: 'event';
|
|
188
|
+
eventName: string;
|
|
189
|
+
handler: string;
|
|
190
|
+
/** Actor derived from the event args, null when none is present. */
|
|
191
|
+
userId: string | null;
|
|
192
|
+
/** Guild derived from the event args, null outside a guild. */
|
|
193
|
+
guildId: string | null;
|
|
194
|
+
/** Channel derived from the event args, null when none is present. */
|
|
195
|
+
channelId: string | null;
|
|
196
|
+
/** The raw event args, made JSON-safe at serialization with filterCirculars. */
|
|
197
|
+
raw: unknown;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Default subscribers that are always available in the framework.
|
|
201
|
+
*/
|
|
202
|
+
interface DefaultSubscriptions {
|
|
203
|
+
/** Triggered when an unhandled exception (a raw non-Notice throw) occurs */
|
|
204
|
+
unknownException: {
|
|
205
|
+
uuid: UUID;
|
|
206
|
+
error: Error;
|
|
207
|
+
guild: Nullable<Guild>;
|
|
208
|
+
user: Nullable<User>;
|
|
209
|
+
metadata?: unknown;
|
|
210
|
+
};
|
|
211
|
+
/** Triggered when a reported Notice (`report: true`) is caught */
|
|
212
|
+
handledException: {
|
|
213
|
+
denial: Notice;
|
|
214
|
+
uuid: UUID;
|
|
215
|
+
source: FaultSource;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Custom subscribers defined by the application.
|
|
220
|
+
*
|
|
221
|
+
* This interface can be augmented via declaration merging to add
|
|
222
|
+
* type-safe custom subscriber definitions for emitting custom subscribers anywhere in the application.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```typescript
|
|
226
|
+
* declare module '@seedcord/gateway' {
|
|
227
|
+
* interface Subscriptions {
|
|
228
|
+
* 'userJoin': { user: User; guild: Guild };
|
|
229
|
+
* 'levelUp': { user: User; level: number; guild: Guild };
|
|
230
|
+
* }
|
|
231
|
+
* }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
interface Subscriptions {}
|
|
235
|
+
/**
|
|
236
|
+
* Combined subscribers interface containing both default and custom subscribers.
|
|
237
|
+
*/
|
|
238
|
+
interface AllSubscriptions extends DefaultSubscriptions, Subscriptions {}
|
|
239
|
+
/**
|
|
240
|
+
* Helper type to extract all available subscriber event names.
|
|
241
|
+
*/
|
|
242
|
+
type SubscriptionKey = keyof AllSubscriptions;
|
|
243
|
+
/**
|
|
244
|
+
* Helper type to get parameters for a specific subscriber event.
|
|
245
|
+
*
|
|
246
|
+
* @typeParam KeyOfSubscribers - The subscriber event name
|
|
247
|
+
*/
|
|
248
|
+
type SubscriptionData<KeyOfSubscribers extends SubscriptionKey> = AllSubscriptions[KeyOfSubscribers];
|
|
249
|
+
/**
|
|
250
|
+
* Event map for Bus, compatible with StrictEventEmitter.
|
|
251
|
+
*
|
|
252
|
+
* @internal
|
|
253
|
+
*/
|
|
254
|
+
type SubscriptionTuples = { [K in SubscriptionKey]: [AllSubscriptions[K]] };
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region src/subscribers/Bus.d.ts
|
|
257
|
+
/**
|
|
258
|
+
* Manages application subscribers and event handling
|
|
259
|
+
*
|
|
260
|
+
* Provides a centralized system for registering and executing custom subscribers
|
|
261
|
+
* throughout the application lifecycle. Bus subscribers are loaded from configured directories
|
|
262
|
+
* and can be triggered programmatically or by framework events. Accessed via `core.bus`. Do not
|
|
263
|
+
* construct it directly.
|
|
264
|
+
*/
|
|
265
|
+
declare class Bus extends Plugin<SubscriptionTuples> {
|
|
266
|
+
protected core: Core;
|
|
267
|
+
readonly logger: Logger;
|
|
268
|
+
/** @internal */
|
|
269
|
+
readonly name = "Subscribers";
|
|
270
|
+
private isInitialized;
|
|
271
|
+
private readonly subscribersMap;
|
|
272
|
+
private readonly executedOnceHandlers;
|
|
273
|
+
private readonly hmrHandler?;
|
|
274
|
+
constructor(core: Core);
|
|
275
|
+
private getArtifacts;
|
|
276
|
+
/** @internal */
|
|
277
|
+
init(): Promise<void>;
|
|
278
|
+
/** @internal For use in dev mode */
|
|
279
|
+
onHmr(event: HmrUpdateEvent): Promise<void>;
|
|
280
|
+
private loadSubscribers;
|
|
281
|
+
private registerSubscriber;
|
|
282
|
+
private unregisterSubscriber;
|
|
283
|
+
private isSubscriber;
|
|
284
|
+
/**
|
|
285
|
+
* Publishes an event to its subscribers and native listeners.
|
|
286
|
+
*
|
|
287
|
+
* Fire-and-forget, so subscriber handlers run asynchronously and this returns before they
|
|
288
|
+
* complete, and callers must not assume side effects have landed. Errors thrown by a subscriber
|
|
289
|
+
* are caught and logged, never surfaced here. A `'once'` subscriber is marked as executed when
|
|
290
|
+
* it starts (even if it throws), so it never runs twice.
|
|
291
|
+
*
|
|
292
|
+
* @param event - The subscription key to publish
|
|
293
|
+
* @param data - Payload passed to each subscriber
|
|
294
|
+
* @returns Whether the underlying emitter had native listeners for the event
|
|
295
|
+
*/
|
|
296
|
+
publish<KeyOfSubscribers extends SubscriptionKey>(event: KeyOfSubscribers, data: AllSubscriptions[KeyOfSubscribers]): boolean;
|
|
297
|
+
private processSubscriber;
|
|
298
|
+
}
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/interfaces/Core.d.ts
|
|
301
|
+
/**
|
|
302
|
+
* Main interface for Seedcord core functionality
|
|
303
|
+
*
|
|
304
|
+
* This interface can be augmented via declaration merging to add
|
|
305
|
+
* type-safe plugin definitions when using `this.core#` in handlers.
|
|
306
|
+
*
|
|
307
|
+
* Only add classes that extend {@link Plugin} to this
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```typescript
|
|
311
|
+
* declare module '@seedcord/gateway' {
|
|
312
|
+
* interface Core {
|
|
313
|
+
* db: Mongo;
|
|
314
|
+
* }
|
|
315
|
+
* }
|
|
316
|
+
* ```
|
|
317
|
+
* */
|
|
318
|
+
interface Core extends CoreBase, SeedcordInstance {
|
|
319
|
+
readonly shutdown: CoordinatedShutdown;
|
|
320
|
+
readonly startup: CoordinatedStartup;
|
|
321
|
+
readonly bot: Bot;
|
|
322
|
+
readonly bus: Bus;
|
|
323
|
+
readonly config: GatewayConfig;
|
|
324
|
+
start(): Promise<this>;
|
|
325
|
+
}
|
|
326
|
+
//#endregion
|
|
327
|
+
//#region src/bot/controllers/CommandRegistry.d.ts
|
|
328
|
+
/** The command collections Discord returns from each scope's deploy, keyed by command id. */
|
|
329
|
+
interface DeployResult {
|
|
330
|
+
global: Collection<Snowflake, ApplicationCommand>;
|
|
331
|
+
guilds: Collection<Snowflake, Collection<Snowflake, ApplicationCommand>>;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Manages Discord application command registration and deployment.
|
|
335
|
+
*
|
|
336
|
+
* Scans command directories, builds command structures, and registers both global and guild-scoped commands
|
|
337
|
+
* to Discord's API. Accessed via `core.bot.commands`. Do not construct it directly.
|
|
338
|
+
*/
|
|
339
|
+
declare class CommandRegistry implements Initializeable, HmrAware {
|
|
340
|
+
private readonly core;
|
|
341
|
+
private readonly onDeployed?;
|
|
342
|
+
readonly name = "Commands";
|
|
343
|
+
private readonly logger;
|
|
344
|
+
private isInitialised;
|
|
345
|
+
readonly globalCommands: (SlashCommandBuilder | ContextMenuCommandBuilder)[];
|
|
346
|
+
readonly guildCommands: Collection<string, (SlashCommandBuilder | ContextMenuCommandBuilder)[]>;
|
|
347
|
+
private readonly ctorToCommand;
|
|
348
|
+
private readonly hmrHandler?;
|
|
349
|
+
private readonly pendingEvents;
|
|
350
|
+
constructor(core: Core, onDeployed?: ((result: DeployResult) => void) | undefined);
|
|
351
|
+
private getArtifacts;
|
|
352
|
+
/** @internal */
|
|
353
|
+
init(): Promise<void>;
|
|
354
|
+
/** @internal */
|
|
355
|
+
refresh(shouldRefresh?: boolean): Promise<void>;
|
|
356
|
+
/** @internal */
|
|
357
|
+
onHmr(event: HmrUpdateEvent): Promise<void>;
|
|
358
|
+
private loadCommands;
|
|
359
|
+
private isCommandClass;
|
|
360
|
+
private registerCommand;
|
|
361
|
+
private unregisterCommand;
|
|
362
|
+
/** @internal */
|
|
363
|
+
setCommands(): Promise<DeployResult>;
|
|
364
|
+
/** The deduplicated slash route keys across every global and guild command. @internal */
|
|
365
|
+
routeLeaves(): Set<string>;
|
|
366
|
+
/** The registered context-menu command names, split by kind, across every global and guild command. @internal */
|
|
367
|
+
contextMenuLeaves(): ContextMenuLeaves;
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/bot/injectors/CommandMentionInjector.d.ts
|
|
371
|
+
/** Each registered slash route mapped to its mention string. */
|
|
372
|
+
type InjectedMentionMap = { [K in keyof SlashOptionRegistry]: string };
|
|
373
|
+
/**
|
|
374
|
+
* Ready-to-send command mention strings, keyed by {@link SlashOptionRegistry}.
|
|
375
|
+
*
|
|
376
|
+
* A value is a clickable `</name:id>` when the command's id resolved from the deploy, otherwise the plain
|
|
377
|
+
* `/name` text. Populated by {@link CommandMentionInjector} after each deploy.
|
|
378
|
+
*/
|
|
379
|
+
declare const CommandMentions: InjectedMentionMap;
|
|
380
|
+
//#endregion
|
|
381
|
+
//#region src/bot/injectors/EmojiInjector.d.ts
|
|
382
|
+
/**
|
|
383
|
+
* The global {@link Emojis} accessor type. Each key resolves to its precise class, `GuildEmoji` for a `'guild'`
|
|
384
|
+
* tag and `ApplicationEmoji` for an `'application'` tag, the tags `seedcord codegen` writes into {@link EmojiMap}.
|
|
385
|
+
*/
|
|
386
|
+
type InjectedEmojiMap = { [K in keyof EmojiMap]: EmojiMap[K] extends 'guild' ? GuildEmoji : ApplicationEmoji };
|
|
387
|
+
/**
|
|
388
|
+
* Global emoji mappings object
|
|
389
|
+
*
|
|
390
|
+
* @see {@link EmojiMap}
|
|
391
|
+
*/
|
|
392
|
+
declare const Emojis: InjectedEmojiMap;
|
|
393
|
+
//#endregion
|
|
394
|
+
//#region src/bot/Bot.d.ts
|
|
395
|
+
/**
|
|
396
|
+
* Types of events emitted by the {@link Core.bot} instance.
|
|
397
|
+
*/
|
|
398
|
+
interface BotEvents {
|
|
399
|
+
/** Emitted when an unhandled interaction error occurs */
|
|
400
|
+
'error:unhandled:interaction': [error: Error];
|
|
401
|
+
/** Emitted when an unhandled event error occurs */
|
|
402
|
+
'error:unhandled:event': [error: Error];
|
|
403
|
+
/** Emitted for any event */
|
|
404
|
+
'any:event': { [K in keyof ClientEvents]: [K, ...ClientEvents[K]] }[keyof ClientEvents];
|
|
405
|
+
/** Emitted for any interaction */
|
|
406
|
+
'any:interaction': [interaction: Interaction];
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Discord bot implementation that manages client and controllers
|
|
410
|
+
*
|
|
411
|
+
* Don't instantiate this class directly. Use `core.bot` instead.
|
|
412
|
+
*/
|
|
413
|
+
declare class Bot extends Plugin<BotEvents> {
|
|
414
|
+
readonly botToken: string;
|
|
415
|
+
/** @internal */
|
|
416
|
+
readonly logger: Logger;
|
|
417
|
+
private isInitialized;
|
|
418
|
+
private readonly _client;
|
|
419
|
+
private readonly interactions?;
|
|
420
|
+
private readonly events?;
|
|
421
|
+
readonly commands?: CommandRegistry;
|
|
422
|
+
private readonly emojiInjector;
|
|
423
|
+
readonly emojis: InjectedEmojiMap;
|
|
424
|
+
readonly mentions: InjectedMentionMap;
|
|
425
|
+
/** @internal For use in dev mode */
|
|
426
|
+
onHmr(event: HmrUpdateEvent): Promise<void>;
|
|
427
|
+
/** @internal */
|
|
428
|
+
constructor(core: Core);
|
|
429
|
+
/**
|
|
430
|
+
* Initializes Discord client and all controllers
|
|
431
|
+
* @internal
|
|
432
|
+
*/
|
|
433
|
+
init(): Promise<void>;
|
|
434
|
+
/**
|
|
435
|
+
* Stops the bot and cleans up connections
|
|
436
|
+
* @internal
|
|
437
|
+
*/
|
|
438
|
+
stop(): Promise<void>;
|
|
439
|
+
/**
|
|
440
|
+
* Logs the bot into Discord using the configured token
|
|
441
|
+
*/
|
|
442
|
+
private login;
|
|
443
|
+
/**
|
|
444
|
+
* Logs out and destroys the Discord client connection
|
|
445
|
+
*/
|
|
446
|
+
private logout;
|
|
447
|
+
get client(): Client;
|
|
448
|
+
/**
|
|
449
|
+
* Emits a Discord event with its argument tuple. The overloads enforce the key/args correlation
|
|
450
|
+
* at compile time only; at runtime this forwards straight to the underlying EventEmitter.
|
|
451
|
+
*
|
|
452
|
+
* @internal
|
|
453
|
+
*/
|
|
454
|
+
emit<TKey extends keyof ClientEvents>(event: 'any:event', name: TKey, ...args: ClientEvents[TKey]): boolean;
|
|
455
|
+
/** @internal */
|
|
456
|
+
emit<TEventKey extends keyof BotEvents>(event: TEventKey, ...args: BotEvents[TEventKey]): boolean;
|
|
457
|
+
}
|
|
458
|
+
//#endregion
|
|
459
|
+
//#region src/handlers/BaseHandler.d.ts
|
|
460
|
+
type ValidInteractionTypes = ChatInputCommandInteraction | ButtonInteraction | ModalSubmitInteraction | AutocompleteInteraction | AnySelectMenuInteraction | ContextMenuCommandInteraction;
|
|
461
|
+
type ValidNonInteractionKeys = Exclude<keyof ClientEvents, Events.InteractionCreate>;
|
|
462
|
+
type ValidEventTypes = ValidInteractionTypes | ClientEvents[ValidNonInteractionKeys];
|
|
463
|
+
type Repliables = Exclude<ValidInteractionTypes, AutocompleteInteraction>;
|
|
464
|
+
type NonModalInteraction = Exclude<Repliables, ModalSubmitInteraction>;
|
|
465
|
+
/** @internal */
|
|
466
|
+
interface Handler {
|
|
467
|
+
execute(): Promise<void>;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Base class for a Discord event or interaction handler. Don't register handlers directly, use the more specific handler subclasses.
|
|
471
|
+
*/
|
|
472
|
+
declare abstract class BaseHandler<ValidEvent extends ValidEventTypes> implements Handler {
|
|
473
|
+
readonly core: Core;
|
|
474
|
+
protected readonly event: ValidEvent;
|
|
475
|
+
protected readonly logger: Logger;
|
|
476
|
+
protected constructor(event: ValidEvent, core: Core);
|
|
477
|
+
/**
|
|
478
|
+
* Holds the main logic of your handler. The dispatcher calls it after the handler's gates pass, so a
|
|
479
|
+
* gate that refuses stops `execute()` from running.
|
|
480
|
+
*/
|
|
481
|
+
abstract execute(): Promise<void>;
|
|
482
|
+
/** @internal */
|
|
483
|
+
getEvent(): ValidEvent;
|
|
484
|
+
}
|
|
485
|
+
//#endregion
|
|
486
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/basic.d.ts
|
|
487
|
+
/**
|
|
488
|
+
Matches a [`class` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).
|
|
489
|
+
|
|
490
|
+
@category Class
|
|
491
|
+
*/
|
|
492
|
+
type Constructor<T, Arguments extends unknown[] = any[]> = new (...arguments_: Arguments) => T;
|
|
493
|
+
//#endregion
|
|
494
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-never.d.ts
|
|
495
|
+
/**
|
|
496
|
+
Returns a boolean for whether the given type is `never`.
|
|
497
|
+
|
|
498
|
+
@link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
|
|
499
|
+
@link https://stackoverflow.com/a/53984913/10292952
|
|
500
|
+
@link https://www.zhenghao.io/posts/ts-never
|
|
501
|
+
|
|
502
|
+
Useful in type utilities, such as checking if something does not occur.
|
|
503
|
+
|
|
504
|
+
@example
|
|
505
|
+
```
|
|
506
|
+
import type {IsNever, And} from 'type-fest';
|
|
507
|
+
|
|
508
|
+
type A = IsNever<never>;
|
|
509
|
+
//=> true
|
|
510
|
+
|
|
511
|
+
type B = IsNever<any>;
|
|
512
|
+
//=> false
|
|
513
|
+
|
|
514
|
+
type C = IsNever<unknown>;
|
|
515
|
+
//=> false
|
|
516
|
+
|
|
517
|
+
type D = IsNever<never[]>;
|
|
518
|
+
//=> false
|
|
519
|
+
|
|
520
|
+
type E = IsNever<object>;
|
|
521
|
+
//=> false
|
|
522
|
+
|
|
523
|
+
type F = IsNever<string>;
|
|
524
|
+
//=> false
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
@example
|
|
528
|
+
```
|
|
529
|
+
import type {IsNever} from 'type-fest';
|
|
530
|
+
|
|
531
|
+
type IsTrue<T> = T extends true ? true : false;
|
|
532
|
+
|
|
533
|
+
// When a distributive conditional is instantiated with `never`, the entire conditional results in `never`.
|
|
534
|
+
type A = IsTrue<never>;
|
|
535
|
+
//=> never
|
|
536
|
+
|
|
537
|
+
// If you don't want that behaviour, you can explicitly add an `IsNever` check before the distributive conditional.
|
|
538
|
+
type IsTrueFixed<T> =
|
|
539
|
+
IsNever<T> extends true ? false : T extends true ? true : false;
|
|
540
|
+
|
|
541
|
+
type B = IsTrueFixed<never>;
|
|
542
|
+
//=> false
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
@category Type Guard
|
|
546
|
+
@category Utilities
|
|
547
|
+
*/
|
|
548
|
+
type IsNever<T> = [T] extends [never] ? true : false;
|
|
549
|
+
//#endregion
|
|
550
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-equal.d.ts
|
|
551
|
+
/**
|
|
552
|
+
Returns a boolean for whether the two given types are equal.
|
|
553
|
+
|
|
554
|
+
@link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
|
|
555
|
+
@link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796
|
|
556
|
+
|
|
557
|
+
Use-cases:
|
|
558
|
+
- If you want to make a conditional branch based on the result of a comparison of two types.
|
|
559
|
+
|
|
560
|
+
@example
|
|
561
|
+
```
|
|
562
|
+
import type {IsEqual} from 'type-fest';
|
|
563
|
+
|
|
564
|
+
// This type returns a boolean for whether the given array includes the given item.
|
|
565
|
+
// `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal.
|
|
566
|
+
type Includes<Value extends readonly any[], Item> =
|
|
567
|
+
Value extends readonly [Value[0], ...infer rest]
|
|
568
|
+
? IsEqual<Value[0], Item> extends true
|
|
569
|
+
? true
|
|
570
|
+
: Includes<rest, Item>
|
|
571
|
+
: false;
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
@category Type Guard
|
|
575
|
+
@category Utilities
|
|
576
|
+
*/
|
|
577
|
+
type IsEqual<A, B> = [A] extends [B] ? [B] extends [A] ? _IsEqual<A, B> : false : false;
|
|
578
|
+
// This version fails the `equalWrappedTupleIntersectionToBeNeverAndNeverExpanded` test in `test-d/is-equal.ts`.
|
|
579
|
+
type _IsEqual<A, B> = (<G>() => G extends A & G | G ? 1 : 2) extends (<G>() => G extends B & G | G ? 1 : 2) ? true : false;
|
|
580
|
+
//#endregion
|
|
581
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/non-empty-tuple.d.ts
|
|
582
|
+
/**
|
|
583
|
+
Matches any non-empty tuple.
|
|
584
|
+
|
|
585
|
+
@example
|
|
586
|
+
```
|
|
587
|
+
import type {NonEmptyTuple} from 'type-fest';
|
|
588
|
+
|
|
589
|
+
const sum = (...numbers: NonEmptyTuple<number>) => numbers.reduce((total, value) => total + value, 0);
|
|
590
|
+
|
|
591
|
+
sum(1, 2, 3);
|
|
592
|
+
// Ok
|
|
593
|
+
|
|
594
|
+
// @ts-expect-error
|
|
595
|
+
sum();
|
|
596
|
+
// Error: Expected at least 1 arguments, but got 0.
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
@see {@link RequireAtLeastOne} for objects
|
|
600
|
+
|
|
601
|
+
@category Array
|
|
602
|
+
*/
|
|
603
|
+
type NonEmptyTuple<T = unknown> = readonly [T, ...T[]];
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-union.d.ts
|
|
606
|
+
/**
|
|
607
|
+
Returns a boolean for whether the given type is a union.
|
|
608
|
+
|
|
609
|
+
@example
|
|
610
|
+
```
|
|
611
|
+
import type {IsUnion} from 'type-fest';
|
|
612
|
+
|
|
613
|
+
type A = IsUnion<string | number>;
|
|
614
|
+
//=> true
|
|
615
|
+
|
|
616
|
+
type B = IsUnion<string>;
|
|
617
|
+
//=> false
|
|
618
|
+
```
|
|
619
|
+
*/
|
|
620
|
+
type IsUnion<T> = InternalIsUnion<T>;
|
|
621
|
+
/**
|
|
622
|
+
The actual implementation of `IsUnion`.
|
|
623
|
+
*/
|
|
624
|
+
type InternalIsUnion<T, U = T> = (IsNever<T> extends true ? false : T extends any ? IsEqual<U, T> extends true ? false : true : never) extends infer Result // In some cases `Result` will return `false | true` which is `boolean`,
|
|
625
|
+
// that means `T` has at least two types and it's a union type,
|
|
626
|
+
// so we will return `true` instead of `boolean`.
|
|
627
|
+
? boolean extends Result ? true : Result : never; // Should never happen
|
|
628
|
+
//#endregion
|
|
629
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/promisable.d.ts
|
|
630
|
+
/**
|
|
631
|
+
Create a type that represents either the value or the value wrapped in `PromiseLike`.
|
|
632
|
+
|
|
633
|
+
Use-cases:
|
|
634
|
+
- A function accepts a callback that may either return a value synchronously or may return a promised value.
|
|
635
|
+
- This type could be the return type of `Promise#then()`, `Promise#catch()`, and `Promise#finally()` callbacks.
|
|
636
|
+
|
|
637
|
+
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/31394) if you want to have this type as a built-in in TypeScript.
|
|
638
|
+
|
|
639
|
+
@example
|
|
640
|
+
```
|
|
641
|
+
import type {Promisable} from 'type-fest';
|
|
642
|
+
|
|
643
|
+
async function logger(getLogEntry: () => Promisable<string>): Promise<void> {
|
|
644
|
+
const entry = await getLogEntry();
|
|
645
|
+
console.log(entry);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
await logger(() => 'foo');
|
|
649
|
+
await logger(() => Promise.resolve('bar'));
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
@category Async
|
|
653
|
+
*/
|
|
654
|
+
type Promisable<T> = T | PromiseLike<T>;
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/handlers/event/payload.d.ts
|
|
657
|
+
/** @internal */
|
|
658
|
+
type SingleEventPayload<Names extends ValidNonInteractionKeys> = IsUnion<Names> extends true ? never : ClientEvents[Names];
|
|
659
|
+
//#endregion
|
|
660
|
+
//#region src/handlers/event/EventHandler.d.ts
|
|
661
|
+
type EventMatchArms<Names extends ValidNonInteractionKeys, Ret> = { [Name in Names]: (...args: ClientEvents[Name]) => Promisable<Ret> };
|
|
662
|
+
/**
|
|
663
|
+
* Base class for a Discord client event handler.
|
|
664
|
+
*
|
|
665
|
+
* Pass the event name(s) as the generic, the same one(s) as `@RegisterEvent`. A single-event handler reads
|
|
666
|
+
* `this.event` (the payload tuple) directly. A handler registered for several events branches with `this.match`,
|
|
667
|
+
* keyed by event name, since the union of payload tuples is not directly readable.
|
|
668
|
+
*
|
|
669
|
+
* @typeParam Names - One or more `ClientEvents` keys, e.g. `Events.MessageCreate` or `Events.MessageCreate | Events.MessageUpdate`.
|
|
670
|
+
*
|
|
671
|
+
* @example
|
|
672
|
+
* ```ts
|
|
673
|
+
* \@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])
|
|
674
|
+
* class PingPong extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {
|
|
675
|
+
* async execute() {
|
|
676
|
+
* await this.match({
|
|
677
|
+
* [Events.MessageCreate]: (message) => message.reply('pong'),
|
|
678
|
+
* [Events.MessageUpdate]: (_oldMessage, edited) => edited.reply('pong')
|
|
679
|
+
* });
|
|
680
|
+
* }
|
|
681
|
+
* }
|
|
682
|
+
* ```
|
|
683
|
+
*/
|
|
684
|
+
declare abstract class EventHandler<Names extends ValidNonInteractionKeys> extends BaseHandler<ClientEvents[Names]> implements Handler {
|
|
685
|
+
private readonly firedEvent;
|
|
686
|
+
constructor(event: ClientEvents[Names], core: Core, eventName?: Names);
|
|
687
|
+
protected readonly event: SingleEventPayload<Names>;
|
|
688
|
+
/**
|
|
689
|
+
* Run the arm for whichever event fired. Use this only when the handler is registered for several
|
|
690
|
+
* events. A single-event handler reads `this.event` directly. On a multi-event handler `this.event` is
|
|
691
|
+
* `never`, so match is the only way to read the payload.
|
|
692
|
+
*
|
|
693
|
+
* Provide one arm per registered event, keyed by its name, and each arm receives that event's own
|
|
694
|
+
* payload tuple. The arms must cover every event in the generic, a missing event or an unknown key is a
|
|
695
|
+
* compile error.
|
|
696
|
+
*
|
|
697
|
+
* @param arms - One handler per registered event, keyed by event name.
|
|
698
|
+
* @returns The result of the arm that ran.
|
|
699
|
+
*
|
|
700
|
+
* @example
|
|
701
|
+
* ```ts
|
|
702
|
+
* \@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])
|
|
703
|
+
* class MessageWatcher extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {
|
|
704
|
+
* async execute() {
|
|
705
|
+
* await this.match({
|
|
706
|
+
* [Events.MessageCreate]: (message) => this.scan(message),
|
|
707
|
+
* [Events.MessageUpdate]: (_old, updated) => this.scan(updated)
|
|
708
|
+
* });
|
|
709
|
+
* }
|
|
710
|
+
* }
|
|
711
|
+
* ```
|
|
712
|
+
*/
|
|
713
|
+
protected match<Ret>(arms: EventMatchArms<Names, Ret>): Promise<Ret>;
|
|
714
|
+
}
|
|
715
|
+
//#endregion
|
|
716
|
+
//#region src/handlers/event/EventMiddleware.d.ts
|
|
717
|
+
/**
|
|
718
|
+
* Base class for Discord event middleware.
|
|
719
|
+
*
|
|
720
|
+
* Middleware runs before event handlers and can stop the event by throwing a `Silence`. Unlike `EventHandler`, it
|
|
721
|
+
* runs the SAME for every event it is registered for, so it has no `match`. Specify a single event in the
|
|
722
|
+
* generic and `{ events }` to read `this.event` fully typed. Span several events (or omit `{ events }` for a
|
|
723
|
+
* catchall) and `this.event` narrows to `never`, read `this.eventName` and do work that does not depend on the
|
|
724
|
+
* payload shape. A middleware that needs each event's payload is written one event per class.
|
|
725
|
+
*
|
|
726
|
+
* @typeParam EventName - One or more `ClientEvents` keys. Defaults to every event (catchall).
|
|
727
|
+
*/
|
|
728
|
+
declare abstract class EventMiddleware<in out EventName extends ValidNonInteractionKeys = ValidNonInteractionKeys> extends BaseHandler<ClientEvents[EventName]> implements Handler {
|
|
729
|
+
private readonly firedEvent;
|
|
730
|
+
constructor(event: ClientEvents[EventName], core: Core, eventName?: EventName);
|
|
731
|
+
protected readonly event: SingleEventPayload<EventName>;
|
|
732
|
+
/**
|
|
733
|
+
* The event that fired this middleware. Read it on a catchall or multi-event middleware, where `this.event`
|
|
734
|
+
* is `never`, to do work that does not depend on the payload shape. A single-event middleware reads
|
|
735
|
+
* `this.event` directly and does not need this.
|
|
736
|
+
*/
|
|
737
|
+
protected get eventName(): EventName;
|
|
738
|
+
}
|
|
739
|
+
//#endregion
|
|
740
|
+
//#region src/miscellaneous/types.d.ts
|
|
741
|
+
/**
|
|
742
|
+
* The frequency at which the event handler should be executed.
|
|
743
|
+
*/
|
|
744
|
+
type EventFrequency = 'once' | 'on';
|
|
745
|
+
//#endregion
|
|
746
|
+
//#region src/bot/decorators/Events.d.ts
|
|
747
|
+
/** Options accepted by the event registration decorator. */
|
|
748
|
+
interface RegisterEventOptions {
|
|
749
|
+
/**
|
|
750
|
+
* Frequency: 'once' or 'on'.
|
|
751
|
+
*
|
|
752
|
+
* @defaultValue `'on'`
|
|
753
|
+
*/
|
|
754
|
+
readonly frequency?: EventFrequency | undefined;
|
|
755
|
+
}
|
|
756
|
+
/** Tuple describing a single event and optional options. */
|
|
757
|
+
type EventSpec<EventKey extends ValidNonInteractionKeys> = readonly [event: EventKey, options?: RegisterEventOptions];
|
|
758
|
+
/**
|
|
759
|
+
* Registers an event handler class with one or more Discord.js events.
|
|
760
|
+
*
|
|
761
|
+
* Associates the decorated class with the provided Discord client events for automatic registration and execution when those events are emitted.
|
|
762
|
+
*
|
|
763
|
+
* Supply any number of event tuples. Each tuple can include per event options.
|
|
764
|
+
*
|
|
765
|
+
* @typeParam EventKey - Union of Discord.js ClientEvents keys to register for
|
|
766
|
+
* @param defs - One or more tuples of [event, options]
|
|
767
|
+
* @decorator
|
|
768
|
+
* @example
|
|
769
|
+
* ```ts
|
|
770
|
+
* \@RegisterEvent([Events.MessageCreate])
|
|
771
|
+
* class MessageHandler extends EventHandler<Events.MessageCreate> {
|
|
772
|
+
* async execute() {
|
|
773
|
+
* // Handle message creation
|
|
774
|
+
* }
|
|
775
|
+
* }
|
|
776
|
+
* ```
|
|
777
|
+
*
|
|
778
|
+
* @example
|
|
779
|
+
* ```ts
|
|
780
|
+
* \@RegisterEvent([Events.MessageCreate], [Events.MessageUpdate])
|
|
781
|
+
* class MessageHandler extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {
|
|
782
|
+
* async execute() {
|
|
783
|
+
* // Handle message creation or update
|
|
784
|
+
* }
|
|
785
|
+
* }
|
|
786
|
+
* ```
|
|
787
|
+
*
|
|
788
|
+
* @example
|
|
789
|
+
* ```ts
|
|
790
|
+
* \@RegisterEvent([Events.MessageCreate, { frequency: 'once' }], [Events.MessageUpdate])
|
|
791
|
+
* class OneTimeMessageHandler extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {
|
|
792
|
+
* async execute() {
|
|
793
|
+
* // Handle only the first message creation, and message update normally
|
|
794
|
+
* }
|
|
795
|
+
* }
|
|
796
|
+
* ```
|
|
797
|
+
*/
|
|
798
|
+
declare function RegisterEvent<const Defs extends readonly EventSpec<ValidNonInteractionKeys>[]>(...defs: Defs): <HandlerCtor extends Constructor<EventHandler<Defs[number][0]>>>(constructor: HandlerCtor) => void;
|
|
799
|
+
//#endregion
|
|
800
|
+
//#region src/bot/gates/Gate.d.ts
|
|
801
|
+
/**
|
|
802
|
+
* The interaction arm. It extends the scalar {@link GateContextBase} with the live interaction and
|
|
803
|
+
* the rich djs objects the gateway cache provides. `Repliable` is the interaction type the gate
|
|
804
|
+
* supports, inferred from the `ctx` annotation, so a gate reading button-specific fields is rejected
|
|
805
|
+
* on a slash handler. `interaction` is the reply target, so `user` is always present. Use
|
|
806
|
+
* {@link NonModalInteraction} to exclude ModalSubmit when the gate needs a reliable caller member or
|
|
807
|
+
* channel.
|
|
808
|
+
*
|
|
809
|
+
* @typeParam Repliable - The interaction type the gate reads, narrowing which handlers accept it.
|
|
810
|
+
*
|
|
811
|
+
* @example
|
|
812
|
+
* ```ts
|
|
813
|
+
* import type { ButtonInteraction } from 'discord.js';
|
|
814
|
+
*
|
|
815
|
+
* // a button-only gate: the Repliable generic narrows which handlers accept it
|
|
816
|
+
* const ButtonGate = defineGate('btn', (ctx: InteractionGateContext<ButtonInteraction>) => {
|
|
817
|
+
* void ctx.interaction; // ButtonInteraction
|
|
818
|
+
* });
|
|
819
|
+
* ```
|
|
820
|
+
*/
|
|
821
|
+
interface InteractionGateContext<Repliable extends Repliables = Repliables> extends GateContextBase {
|
|
822
|
+
/** Marks the interaction arm, narrow on it before reading `interaction`. */
|
|
823
|
+
readonly kind: 'interaction';
|
|
824
|
+
/** The running framework, with the gateway's bot and bus. */
|
|
825
|
+
readonly core: Core;
|
|
826
|
+
/** The interaction being handled, which is the reply target. */
|
|
827
|
+
readonly interaction: Repliable;
|
|
828
|
+
/** The invoking user, always present on an interaction. */
|
|
829
|
+
readonly user: User;
|
|
830
|
+
/** The guild the interaction happened in, or null in a DM. */
|
|
831
|
+
readonly guild: Guild | null;
|
|
832
|
+
/** The invoking member from the cache, or null outside a guild or when uncached. */
|
|
833
|
+
readonly member: GuildMember | null;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* The event arm. It extends the scalar {@link GateContextBase} with the event payload and the djs
|
|
837
|
+
* objects derived from it. `Names` is the event(s) the gate supports, inferred from the `ctx`
|
|
838
|
+
* annotation, so a gate that reads one event's `payload` is rejected on a handler for a different
|
|
839
|
+
* event. The default supports every event.
|
|
840
|
+
*
|
|
841
|
+
* @typeParam Names - The event name or names the gate reads, typing `payload` to that event's args tuple.
|
|
842
|
+
*
|
|
843
|
+
* @example
|
|
844
|
+
* ```ts
|
|
845
|
+
* import { Events } from 'discord.js';
|
|
846
|
+
*
|
|
847
|
+
* // gate keyed to one event, so payload is typed to that event's args tuple
|
|
848
|
+
* const OnMessage = defineGate('msg', (ctx: EventGateContext<Events.MessageCreate>) => {
|
|
849
|
+
* void ctx.payload; // [Message]
|
|
850
|
+
* });
|
|
851
|
+
* ```
|
|
852
|
+
*/
|
|
853
|
+
interface EventGateContext<Names extends ValidNonInteractionKeys = ValidNonInteractionKeys> extends GateContextBase {
|
|
854
|
+
/** Marks the event arm, narrow on it before reading `payload`. */
|
|
855
|
+
readonly kind: 'event';
|
|
856
|
+
/** The running framework, with the gateway's bot and bus. */
|
|
857
|
+
readonly core: Core;
|
|
858
|
+
/** The event being handled. */
|
|
859
|
+
readonly eventName: Names;
|
|
860
|
+
/** The event's arguments, typed to that event's args tuple. */
|
|
861
|
+
readonly payload: ClientEvents[Names];
|
|
862
|
+
/** The acting user derived from the payload, or null when the event carries none. */
|
|
863
|
+
readonly user: User | null;
|
|
864
|
+
/** The guild derived from the payload, or null. */
|
|
865
|
+
readonly guild: Guild | null;
|
|
866
|
+
/** The acting member derived from the payload, or null. */
|
|
867
|
+
readonly member: GuildMember | null;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* What a gateway gate's check receives, tagged by `ctx.kind`. Narrow on `kind` before reading
|
|
871
|
+
* `interaction` or `payload`.
|
|
872
|
+
*
|
|
873
|
+
* @see {@link InteractionGateContext}
|
|
874
|
+
* @see {@link EventGateContext}
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* ```ts
|
|
878
|
+
* // a gate that handles either arm narrows on ctx.kind
|
|
879
|
+
* const Either = defineGate('either', (ctx: GateContext) => {
|
|
880
|
+
* if (ctx.kind === 'interaction') void ctx.interaction;
|
|
881
|
+
* else void ctx.payload;
|
|
882
|
+
* });
|
|
883
|
+
* ```
|
|
884
|
+
*/
|
|
885
|
+
type GateContext = InteractionGateContext | EventGateContext;
|
|
886
|
+
//#endregion
|
|
887
|
+
//#region src/handlers/interaction/InteractionHandler.d.ts
|
|
888
|
+
/**
|
|
889
|
+
* Shared base the typed interaction handlers extend.
|
|
890
|
+
*
|
|
891
|
+
* Not a public entry point. You should be using {@link SlashHandler}, {@link ButtonHandler}, {@link ModalHandler},
|
|
892
|
+
* or {@link SelectMenuHandler} instead. This class only carries the repliable-event plumbing those bases share,
|
|
893
|
+
* so DO NOT use it directly.
|
|
894
|
+
*
|
|
895
|
+
* @typeParam Repliable - The interaction type this handler processes
|
|
896
|
+
*/
|
|
897
|
+
declare abstract class InteractionHandler<Repliable extends Repliables> extends BaseHandler<Repliable> implements Handler {
|
|
898
|
+
constructor(event: Repliable, core: Core);
|
|
899
|
+
}
|
|
900
|
+
//#endregion
|
|
901
|
+
//#region src/bot/gates/matching.d.ts
|
|
902
|
+
type AnyHandlerCtor = abstract new (...args: never[]) => {
|
|
903
|
+
execute(): Promise<void>;
|
|
904
|
+
getEvent(): ValidEventTypes;
|
|
905
|
+
};
|
|
906
|
+
declare const UngateableBrand: unique symbol;
|
|
907
|
+
interface Ungateable {
|
|
908
|
+
readonly [UngateableBrand]: true;
|
|
909
|
+
}
|
|
910
|
+
type ProvidedContext<TCtor extends AnyHandlerCtor> = InstanceType<TCtor> extends InteractionHandler<infer Repliable> ? InteractionGateContext<Repliable> : InstanceType<TCtor> extends EventHandler<infer Names> ? EventGateContext<Names> : Ungateable;
|
|
911
|
+
type KindName<Ctx> = Ctx extends Ungateable ? 'autocomplete' : Ctx extends InteractionGateContext<infer R> ? R extends ChatInputCommandInteraction ? 'Slash' : R extends MessageContextMenuCommandInteraction ? 'MessageMenu' : R extends UserContextMenuCommandInteraction ? 'UserMenu' : R extends StringSelectMenuInteraction ? 'StringSelect' : R extends UserSelectMenuInteraction ? 'UserSelect' : R extends RoleSelectMenuInteraction ? 'RoleSelect' : R extends ChannelSelectMenuInteraction ? 'ChannelSelect' : R extends MentionableSelectMenuInteraction ? 'MentionableSelect' : R extends ButtonInteraction ? 'Button' : R extends ModalSubmitInteraction ? 'Modal' : 'an interaction' : Ctx extends EventGateContext<infer N> ? `${N & string} event` : 'an agnostic';
|
|
912
|
+
type FitAll<TCtor extends AnyHandlerCtor, Gates extends readonly Gate<GateContextBase>[]> = { [Index in keyof Gates]: GateFitsWith<ProvidedContext<TCtor>, KindName<ProvidedContext<TCtor>>, Gates[Index], KindName<RequiredOf<Gates[Index]>>> };
|
|
913
|
+
//#endregion
|
|
914
|
+
//#region src/bot/decorators/Gated.d.ts
|
|
915
|
+
/**
|
|
916
|
+
* Attaches gates to a handler. The gates run before `execute`, and a gate refusing stops the handler with
|
|
917
|
+
* the reply or drop the gate threw. Multiple gates are ANDed, so each must pass. A gate that requires a
|
|
918
|
+
* context the handler does not provide (a button gate on a slash handler, an interaction gate on an event
|
|
919
|
+
* handler) is a compile error at this line, and the error names the gate and the handler kind. Place it
|
|
920
|
+
* above the route decorator.
|
|
921
|
+
*
|
|
922
|
+
* Combine gates with {@link and} or {@link or} to build a single gate from multiple arms.
|
|
923
|
+
*
|
|
924
|
+
* @example
|
|
925
|
+
* ```ts
|
|
926
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
927
|
+
*
|
|
928
|
+
* \@Gated(GuildOnly(), RequirePermissions([PermissionFlagsBits.Administrator]))
|
|
929
|
+
* \@SlashRoute('maintenance')
|
|
930
|
+
* class Maintenance extends SlashHandler<'maintenance'> {
|
|
931
|
+
* async execute() {
|
|
932
|
+
* // both gates passed, so this runs in a guild with an admin caller
|
|
933
|
+
* }
|
|
934
|
+
* }
|
|
935
|
+
* ```
|
|
936
|
+
*
|
|
937
|
+
* @typeParam Gates - The non-empty tuple of gates to run, in order, against the handler's context.
|
|
938
|
+
* @typeParam TCtor - The decorated handler's constructor, checked against every gate's required context.
|
|
939
|
+
* @param gates - One or more gates to attach, each ANDed so the handler runs only when all pass.
|
|
940
|
+
* @param ctor - The handler class being decorated, rejected at compile time when a gate needs a context it lacks.
|
|
941
|
+
*
|
|
942
|
+
* @see {@link defineGate}
|
|
943
|
+
* @see {@link defineEffectGate}
|
|
944
|
+
* @decorator
|
|
945
|
+
*/
|
|
946
|
+
declare function Gated<const Gates extends NonEmptyTuple<Gate<GateContextBase>>>(...gates: Gates): <TCtor extends AnyHandlerCtor>(ctor: FitAll<TCtor, Gates> extends Gates ? TCtor : FitAll<TCtor, Gates>) => void;
|
|
947
|
+
//#endregion
|
|
948
|
+
//#region src/inputs/AutocompleteOptions.d.ts
|
|
949
|
+
type Row$2<Route extends keyof SlashOptionRegistry> = SlashOptionRegistry[Route];
|
|
950
|
+
type EntryFor$1<Route extends keyof SlashOptionRegistry, Name extends PropertyKey> = Route extends unknown ? Name extends keyof Row$2<Route> ? Row$2<Route>[Name] : never : never;
|
|
951
|
+
type NamesOfKind$1<Route extends keyof SlashOptionRegistry, Kind extends OptionKind> = Route extends unknown ? { [Name in keyof Row$2<Route>]: Row$2<Route>[Name] extends {
|
|
952
|
+
kind: Kind;
|
|
953
|
+
} ? Name : never }[keyof Row$2<Route>] : never;
|
|
954
|
+
type ResolvedValue$1<Entry> = Entry extends {
|
|
955
|
+
choices: readonly (infer Choice)[];
|
|
956
|
+
} ? Choice : Entry extends {
|
|
957
|
+
kind: 'string';
|
|
958
|
+
} ? string : Entry extends {
|
|
959
|
+
kind: 'integer' | 'number';
|
|
960
|
+
} ? number : Entry extends {
|
|
961
|
+
kind: 'boolean';
|
|
962
|
+
} ? boolean : never;
|
|
963
|
+
type Getter$1<Route extends keyof SlashOptionRegistry, Kind extends OptionKind, Method extends string> = IsNever<NamesOfKind$1<Route, Kind>> extends true ? unknown : Record<Method, <Name extends NamesOfKind$1<Route, Kind>>(name: Name) => ResolvedValue$1<EntryFor$1<Route, Name>> | null>;
|
|
964
|
+
/**
|
|
965
|
+
* The sibling-option view for an autocomplete handler. Only the four kinds Discord resolves during autocomplete
|
|
966
|
+
* appear (string, integer, number, boolean), every read is `T | null` because a sibling is partial while the
|
|
967
|
+
* user types the focused field, and a getter appears only when a registered command has an option of that kind.
|
|
968
|
+
* Across several registered commands the view is the union of their options, so a getter for an option absent on
|
|
969
|
+
* the firing command returns null. Read the focused field from `this.focused`.
|
|
970
|
+
*
|
|
971
|
+
* @typeParam Route - One or more route keys from {@link SlashOptionRegistry}.
|
|
972
|
+
*/
|
|
973
|
+
type AutocompleteOptions<Route extends keyof SlashOptionRegistry> = Getter$1<Route, 'string', 'getString'> & Getter$1<Route, 'integer', 'getInteger'> & Getter$1<Route, 'number', 'getNumber'> & Getter$1<Route, 'boolean', 'getBoolean'>;
|
|
974
|
+
//#endregion
|
|
975
|
+
//#region src/handlers/interaction/AutocompleteHandler.d.ts
|
|
976
|
+
type Row$1<Route extends keyof SlashOptionRegistry> = SlashOptionRegistry[Route];
|
|
977
|
+
type AutocompletableNames<Route extends keyof SlashOptionRegistry> = Route extends unknown ? { [Name in keyof Row$1<Route>]: Row$1<Route>[Name] extends {
|
|
978
|
+
autocomplete: true;
|
|
979
|
+
} ? Name : never }[keyof Row$1<Route>] : never;
|
|
980
|
+
type EntryFor<Route extends keyof SlashOptionRegistry, Name extends PropertyKey> = Route extends unknown ? Name extends keyof Row$1<Route> ? Row$1<Route>[Name] : never : never;
|
|
981
|
+
type ChoiceValueOf<Entry> = Entry extends {
|
|
982
|
+
kind: 'string';
|
|
983
|
+
} ? string : Entry extends {
|
|
984
|
+
kind: 'integer' | 'number';
|
|
985
|
+
} ? number : never;
|
|
986
|
+
/** The focused option. `value` is the raw partial Discord delivers mid-type, always a string regardless of kind. */
|
|
987
|
+
interface FocusedField<Route extends keyof SlashOptionRegistry> {
|
|
988
|
+
name: AutocompletableNames<Route>;
|
|
989
|
+
value: string;
|
|
990
|
+
}
|
|
991
|
+
/** One arm per autocompletable field, `value` is the focused partial, `respond` is pinned to the field's choice type. */
|
|
992
|
+
type FocusedArms<Route extends keyof SlashOptionRegistry, Ret> = { [Name in AutocompletableNames<Route>]: (value: string, respond: (choices: readonly ApplicationCommandOptionChoiceData<ChoiceValueOf<EntryFor<Route, Name>>>[]) => Promise<void>) => Promisable<Ret> };
|
|
993
|
+
/**
|
|
994
|
+
* Base class for a Discord autocomplete handler.
|
|
995
|
+
*
|
|
996
|
+
* Pass the command route(s) from the generated registry as the generic, the same string(s) as
|
|
997
|
+
* `@AutocompleteRoute`. Branch on the focused field with `this.match`, read already-entered sibling options
|
|
998
|
+
* with `this.options`, and find which command fired with `this.route`.
|
|
999
|
+
*
|
|
1000
|
+
* @typeParam Route - One or more route keys from {@link SlashOptionRegistry}, e.g. `'search'` or `'search' | 'find'`.
|
|
1001
|
+
* @typeParam Cache - The interaction cache state, `'cached'` by default.
|
|
1002
|
+
*
|
|
1003
|
+
* @example
|
|
1004
|
+
* ```ts
|
|
1005
|
+
* \@AutocompleteRoute('search')
|
|
1006
|
+
* class SearchAutocomplete extends AutocompleteHandler<'search'> {
|
|
1007
|
+
* async execute() {
|
|
1008
|
+
* await this.match({
|
|
1009
|
+
* query: (value, respond) => respond([{ name: value, value }])
|
|
1010
|
+
* });
|
|
1011
|
+
* }
|
|
1012
|
+
* }
|
|
1013
|
+
* ```
|
|
1014
|
+
*/
|
|
1015
|
+
declare abstract class AutocompleteHandler<Route extends keyof SlashOptionRegistry, Cache extends CacheType = 'cached'> extends BaseHandler<AutocompleteInteraction<Cache>> implements Handler {
|
|
1016
|
+
constructor(event: AutocompleteInteraction<Cache>, core: Core);
|
|
1017
|
+
/**
|
|
1018
|
+
* The focused option for this interaction. `value` is always the raw partial string the user is typing,
|
|
1019
|
+
* even for an integer or number option, so coerce it yourself when you need a number.
|
|
1020
|
+
*/
|
|
1021
|
+
private decodedFocused?;
|
|
1022
|
+
protected get focused(): FocusedField<Route>;
|
|
1023
|
+
/**
|
|
1024
|
+
* Run the arm for the focused field. An autocomplete always dispatches by which field is focused, so
|
|
1025
|
+
* match is how you read it. There is no single-field shortcut the way slash/component handlers have one.
|
|
1026
|
+
*
|
|
1027
|
+
* Provide one arm per autocompletable field across the registered commands, keyed by field name. Each
|
|
1028
|
+
* arm receives the focused partial value and a `respond` pinned to that field's choice value type. The
|
|
1029
|
+
* arms must cover every autocompletable field, a missing field or an unknown key is a compile error. A
|
|
1030
|
+
* focused field with no arm, only reachable from a stale-deployed command, throws at runtime.
|
|
1031
|
+
*
|
|
1032
|
+
* @param arms - One handler per autocompletable field, keyed by field name.
|
|
1033
|
+
* @returns The result of the arm that ran.
|
|
1034
|
+
*
|
|
1035
|
+
* @example
|
|
1036
|
+
* ```ts
|
|
1037
|
+
* \@AutocompleteRoute('search')
|
|
1038
|
+
* class SearchAutocomplete extends AutocompleteHandler<'search'> {
|
|
1039
|
+
* async execute() {
|
|
1040
|
+
* await this.match({
|
|
1041
|
+
* query: (value, respond) => respond(titles(value).map((s) => ({ name: s, value: s }))),
|
|
1042
|
+
* tag: (value, respond) => respond(tags(value).map((s) => ({ name: s, value: s })))
|
|
1043
|
+
* });
|
|
1044
|
+
* }
|
|
1045
|
+
* }
|
|
1046
|
+
* ```
|
|
1047
|
+
*/
|
|
1048
|
+
protected match<Ret>(arms: FocusedArms<Route, Ret>): Promise<Ret>;
|
|
1049
|
+
/** The firing command route, for a field whose completion differs per registered command. */
|
|
1050
|
+
protected get route(): Route;
|
|
1051
|
+
/**
|
|
1052
|
+
* The already-entered options on this command, restricted to the kinds Discord resolves during autocomplete
|
|
1053
|
+
* (string, integer, number, boolean) with every read nullable, since a sibling is partial while the user
|
|
1054
|
+
* types the focused field. Read the focused field from `this.focused`, not here.
|
|
1055
|
+
*/
|
|
1056
|
+
protected get options(): AutocompleteOptions<Route>;
|
|
1057
|
+
}
|
|
1058
|
+
//#endregion
|
|
1059
|
+
//#region src/handlers/interaction/ContextMenuHandler.d.ts
|
|
1060
|
+
type ContextMenuKind = ApplicationCommandType.User | ApplicationCommandType.Message;
|
|
1061
|
+
type InteractionFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User ? UserContextMenuCommandInteraction<Cache> : MessageContextMenuCommandInteraction<Cache>;
|
|
1062
|
+
type TargetFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User ? User : Message<BooleanCache<Cache>>;
|
|
1063
|
+
type TargetMemberFor<Kind extends ContextMenuKind, Cache extends CacheType> = Kind extends ApplicationCommandType.User ? CacheTypeReducer<Cache, GuildMember, APIInteractionGuildMember> | null : never;
|
|
1064
|
+
/**
|
|
1065
|
+
* Base class for a context-menu command handler (right-click a user or a message).
|
|
1066
|
+
*
|
|
1067
|
+
* Pass the kind from `discord.js`'s {@link ApplicationCommandType} as the generic, the same value as
|
|
1068
|
+
* `@ContextMenuRoute`. Read the right-clicked entity from `this.target`, a `User` for a user menu and a
|
|
1069
|
+
* `Message` for a message menu. Context menus carry no options, so a handler registered for several names
|
|
1070
|
+
* reads `this.target` uniformly with no per-name branch.
|
|
1071
|
+
*
|
|
1072
|
+
* @typeParam Kind - `ApplicationCommandType.User` or `ApplicationCommandType.Message`.
|
|
1073
|
+
* @typeParam Cache - The interaction cache state, `'cached'` by default.
|
|
1074
|
+
*
|
|
1075
|
+
* @example
|
|
1076
|
+
* ```ts
|
|
1077
|
+
* \@ContextMenuRoute(ApplicationCommandType.Message, 'Report Message')
|
|
1078
|
+
* class ReportMessage extends ContextMenuHandler<ApplicationCommandType.Message> {
|
|
1079
|
+
* async execute() {
|
|
1080
|
+
* const message = this.target;
|
|
1081
|
+
* }
|
|
1082
|
+
* }
|
|
1083
|
+
* ```
|
|
1084
|
+
*/
|
|
1085
|
+
declare abstract class ContextMenuHandler<Kind extends ContextMenuKind, Cache extends CacheType = 'cached'> extends InteractionHandler<InteractionFor<Kind, Cache>> {
|
|
1086
|
+
protected get target(): TargetFor<Kind, Cache>;
|
|
1087
|
+
/**
|
|
1088
|
+
* The invoking guild member, resolved only on user menus. Reading it on a message menu is a compile
|
|
1089
|
+
* error since the type is `never` there.
|
|
1090
|
+
*/
|
|
1091
|
+
protected get targetMember(): TargetMemberFor<Kind, Cache>;
|
|
1092
|
+
}
|
|
1093
|
+
//#endregion
|
|
1094
|
+
//#region src/inputs/SlashOptions.d.ts
|
|
1095
|
+
type Row<Route extends keyof SlashOptionRegistry> = SlashOptionRegistry[Route];
|
|
1096
|
+
type NamesOfKind<Route extends keyof SlashOptionRegistry, Kind extends OptionKind> = { [Name in keyof Row<Route>]: Row<Route>[Name] extends {
|
|
1097
|
+
kind: Kind;
|
|
1098
|
+
} ? Name : never }[keyof Row<Route>];
|
|
1099
|
+
type ResolvedValue<Cache extends CacheType, Entry> = Entry extends {
|
|
1100
|
+
choices: readonly (infer Choice)[];
|
|
1101
|
+
} ? Choice : Entry extends {
|
|
1102
|
+
kind: 'string';
|
|
1103
|
+
} ? string : Entry extends {
|
|
1104
|
+
kind: 'integer' | 'number';
|
|
1105
|
+
} ? number : Entry extends {
|
|
1106
|
+
kind: 'boolean';
|
|
1107
|
+
} ? boolean : Entry extends {
|
|
1108
|
+
kind: 'user';
|
|
1109
|
+
} ? NonNullable<CommandInteractionOption<Cache>['user']> : Entry extends {
|
|
1110
|
+
kind: 'channel';
|
|
1111
|
+
} ? NonNullable<CommandInteractionOption<Cache>['channel']> : Entry extends {
|
|
1112
|
+
kind: 'role';
|
|
1113
|
+
} ? NonNullable<CommandInteractionOption<Cache>['role']> : Entry extends {
|
|
1114
|
+
kind: 'mentionable';
|
|
1115
|
+
} ? NonNullable<CommandInteractionOption<Cache>['member' | 'role' | 'user']> : Entry extends {
|
|
1116
|
+
kind: 'attachment';
|
|
1117
|
+
} ? NonNullable<CommandInteractionOption<Cache>['attachment']> : never;
|
|
1118
|
+
type Returned<Cache extends CacheType, Entry> = Entry extends {
|
|
1119
|
+
required: true;
|
|
1120
|
+
} ? ResolvedValue<Cache, Entry> : ResolvedValue<Cache, Entry> | null;
|
|
1121
|
+
type Getter<Route extends keyof SlashOptionRegistry, Cache extends CacheType, Kind extends OptionKind, Method extends string> = IsNever<NamesOfKind<Route, Kind>> extends true ? unknown : Record<Method, <Name extends NamesOfKind<Route, Kind>>(name: Name) => Returned<Cache, Row<Route>[Name]>>;
|
|
1122
|
+
type MemberGetter<Route extends keyof SlashOptionRegistry, Cache extends CacheType> = IsNever<NamesOfKind<Route, 'user'>> extends true ? unknown : {
|
|
1123
|
+
getMember: <Name extends NamesOfKind<Route, 'user'>>(name: Name) => NonNullable<CommandInteractionOption<Cache>['member']> | null;
|
|
1124
|
+
};
|
|
1125
|
+
/**
|
|
1126
|
+
* The typed view over a chat-input command's options for one route. Each getter mirrors the discord.js
|
|
1127
|
+
* resolver method but restricts its `name` to that route's options of the matching kind, drops the null
|
|
1128
|
+
* on required options, narrows `choices` to their literal union, and only appears when the route has an
|
|
1129
|
+
* option of that kind. The rich kinds return exactly what the djs resolver returns.
|
|
1130
|
+
*
|
|
1131
|
+
* Pass the raw `this.event.options` resolver for anything this view does not cover, such as narrowing a
|
|
1132
|
+
* channel option with `getChannel(name, channelTypes)`.
|
|
1133
|
+
*
|
|
1134
|
+
* @typeParam Route - A route key from the generated {@link SlashOptionRegistry}.
|
|
1135
|
+
* @typeParam Cache - The interaction cache state, `'cached'` by default.
|
|
1136
|
+
*/
|
|
1137
|
+
type SlashOptions<Route extends keyof SlashOptionRegistry, Cache extends CacheType = 'cached'> = Getter<Route, Cache, 'string', 'getString'> & Getter<Route, Cache, 'integer', 'getInteger'> & Getter<Route, Cache, 'number', 'getNumber'> & Getter<Route, Cache, 'boolean', 'getBoolean'> & Getter<Route, Cache, 'user', 'getUser'> & Getter<Route, Cache, 'channel', 'getChannel'> & Getter<Route, Cache, 'role', 'getRole'> & Getter<Route, Cache, 'mentionable', 'getMentionable'> & Getter<Route, Cache, 'attachment', 'getAttachment'> & MemberGetter<Route, Cache>;
|
|
1138
|
+
//#endregion
|
|
1139
|
+
//#region src/handlers/interaction/SlashHandler.d.ts
|
|
1140
|
+
type SlashMatchArms<Route extends keyof SlashOptionRegistry, Cache extends CacheType, Ret> = { [Key in Route]: (options: SlashOptions<Key, Cache>) => Promisable<Ret> };
|
|
1141
|
+
/**
|
|
1142
|
+
* Base class for a chat-input (slash) command handler.
|
|
1143
|
+
*
|
|
1144
|
+
* Pass the route from the generated registry as the generic, the same string as `@SlashRoute`, then read
|
|
1145
|
+
* `this.options` for a single command or `this.match` for several. Command authoring stays plain
|
|
1146
|
+
* discord.js, `seedcord codegen` reads its `toJSON()` to type these options.
|
|
1147
|
+
*
|
|
1148
|
+
* @typeParam Route - One or more route keys from {@link SlashOptionRegistry}, e.g. `'ban'` or `'ban' | 'kick'`.
|
|
1149
|
+
* @typeParam Cache - The interaction cache state, `'cached'` by default.
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* ```ts
|
|
1153
|
+
* \@SlashRoute('ban')
|
|
1154
|
+
* class BanHandler extends SlashHandler<'ban'> {
|
|
1155
|
+
* async execute() {
|
|
1156
|
+
* const target = this.options.getUser('target'); // User
|
|
1157
|
+
* const reason = this.options.getString('reason'); // string | null
|
|
1158
|
+
* }
|
|
1159
|
+
* }
|
|
1160
|
+
* ```
|
|
1161
|
+
*/
|
|
1162
|
+
declare abstract class SlashHandler<Route extends keyof SlashOptionRegistry, Cache extends CacheType = 'cached'> extends InteractionHandler<ChatInputCommandInteraction<Cache>> {
|
|
1163
|
+
/**
|
|
1164
|
+
* The typed options for this command's route. Required options drop the null, choices narrow to their
|
|
1165
|
+
* literal union, and only the getters for kinds this command actually uses appear. Use `this.event.options`
|
|
1166
|
+
* directly for anything outside this view, such as narrowing a channel option by type.
|
|
1167
|
+
*/
|
|
1168
|
+
protected get options(): SlashOptions<Route, Cache>;
|
|
1169
|
+
/**
|
|
1170
|
+
* Run the arm for whichever command fired. Use this only when the handler is registered for several
|
|
1171
|
+
* routes. A single-route handler reads `this.options` directly instead, match buys nothing there.
|
|
1172
|
+
*
|
|
1173
|
+
* Provide one arm per registered route, keyed by its route string, and each arm receives that route's
|
|
1174
|
+
* own narrowed options. The arms must cover every route in the generic, a missing route or an unknown
|
|
1175
|
+
* key is a compile error.
|
|
1176
|
+
*
|
|
1177
|
+
* @param arms - One handler per registered route, keyed by route string.
|
|
1178
|
+
* @returns The result of the arm that ran.
|
|
1179
|
+
*
|
|
1180
|
+
* @example
|
|
1181
|
+
* ```ts
|
|
1182
|
+
* \@SlashRoute('ban', 'kick')
|
|
1183
|
+
* class ModHandler extends SlashHandler<'ban' | 'kick'> {
|
|
1184
|
+
* async execute() {
|
|
1185
|
+
* await this.match({
|
|
1186
|
+
* ban: (options) => this.event.guild?.members.ban(options.getUser('target', true).id),
|
|
1187
|
+
* kick: (options) => this.event.guild?.members.kick(options.getUser('member', true).id)
|
|
1188
|
+
* });
|
|
1189
|
+
* }
|
|
1190
|
+
* }
|
|
1191
|
+
* ```
|
|
1192
|
+
*/
|
|
1193
|
+
protected match<Ret>(arms: SlashMatchArms<Route, Cache, Ret>): Promise<Ret>;
|
|
1194
|
+
}
|
|
1195
|
+
//#endregion
|
|
1196
|
+
//#region src/bot/decorators/Interactions.d.ts
|
|
1197
|
+
/**
|
|
1198
|
+
* Types of select menus supported for routing
|
|
1199
|
+
*/
|
|
1200
|
+
declare enum SelectMenuKind {
|
|
1201
|
+
String = "string",
|
|
1202
|
+
User = "user",
|
|
1203
|
+
Role = "role",
|
|
1204
|
+
Channel = "channel",
|
|
1205
|
+
Mentionable = "mentionable"
|
|
1206
|
+
}
|
|
1207
|
+
/** @internal */
|
|
1208
|
+
type HandlerEventType<TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> = InstanceType<TCtor> extends InteractionHandler<infer TEvent> ? TEvent : never;
|
|
1209
|
+
/**
|
|
1210
|
+
* Compile-time assertion that the required event type(s) `TRequired` are included in the handler event union.
|
|
1211
|
+
*
|
|
1212
|
+
* @internal
|
|
1213
|
+
*/
|
|
1214
|
+
type AssertHandles<TRequired, TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> = Extract<HandlerEventType<TCtor>, TRequired> extends never ? Constructor<['Handler event generic must include', TRequired]> : TCtor;
|
|
1215
|
+
/**
|
|
1216
|
+
* The slash route(s) a handler serves, read off its `SlashHandler` generic.
|
|
1217
|
+
*
|
|
1218
|
+
* @internal
|
|
1219
|
+
*/
|
|
1220
|
+
type SlashRouteOf<TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> = InstanceType<TCtor> extends SlashHandler<infer Route, CacheType> ? Route : never;
|
|
1221
|
+
/**
|
|
1222
|
+
* On a route/generic mismatch, resolves to a non-constructor type so applying the decorator is a TS1238.
|
|
1223
|
+
*
|
|
1224
|
+
* @internal
|
|
1225
|
+
*/
|
|
1226
|
+
type AssertSlashRoute<Route extends string, TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> = [Route] extends [SlashRouteOf<TCtor>] ? [SlashRouteOf<TCtor>] extends [Route] ? TCtor : Constructor<['SlashHandler declares a route the SlashRoute decorator does not list', SlashRouteOf<TCtor>]> : Constructor<['SlashRoute does not match the SlashHandler generic', Route]>;
|
|
1227
|
+
/**
|
|
1228
|
+
* Routes one or more slash commands to a {@link SlashHandler}.
|
|
1229
|
+
*
|
|
1230
|
+
* Pass the same route string(s) as the handler's generic. A single command reads `this.options`, several
|
|
1231
|
+
* commands branch with `this.match`. The decorator routes and the generic must match exactly, so listing
|
|
1232
|
+
* fewer or more than the handler declares is a compile error. Subcommands use a slash path.
|
|
1233
|
+
*
|
|
1234
|
+
* @param routes - The route string(s) this handler serves, e.g. `'ban'`, `'ban', 'kick'`, or `'demo/setup'`.
|
|
1235
|
+
* @decorator
|
|
1236
|
+
* @example
|
|
1237
|
+
* ```ts
|
|
1238
|
+
* \@SlashRoute('ban')
|
|
1239
|
+
* class BanHandler extends SlashHandler<'ban'> {
|
|
1240
|
+
* async execute() {
|
|
1241
|
+
* const target = this.options.getUser('target');
|
|
1242
|
+
* }
|
|
1243
|
+
* }
|
|
1244
|
+
* ```
|
|
1245
|
+
*
|
|
1246
|
+
* @example
|
|
1247
|
+
* ```ts
|
|
1248
|
+
* \@SlashRoute('ban', 'kick')
|
|
1249
|
+
* class ModerationHandler extends SlashHandler<'ban' | 'kick'> {
|
|
1250
|
+
* async execute() {
|
|
1251
|
+
* await this.match({ ban: (o) => o.getUser('target'), kick: (o) => o.getUser('member') });
|
|
1252
|
+
* }
|
|
1253
|
+
* }
|
|
1254
|
+
* ```
|
|
1255
|
+
*/
|
|
1256
|
+
declare function SlashRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]): <TCtor extends new (...args: any[]) => InteractionHandler<Repliables>>(constructor: AssertSlashRoute<Route, TCtor>) => void;
|
|
1257
|
+
/**
|
|
1258
|
+
* Routes button interactions to handler classes.
|
|
1259
|
+
*
|
|
1260
|
+
* Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's
|
|
1261
|
+
* generic. Passing different definitions to the decorator and the generic is a compile error. Routing
|
|
1262
|
+
* matches the stable prefix, so a wire minted from an older shape still reaches the handler, where
|
|
1263
|
+
* reading this.params throws StaleCustomId and the controller boundary turns it into a reply.
|
|
1264
|
+
*
|
|
1265
|
+
* @param defs - The customId definition(s) this handler decodes, one per route.
|
|
1266
|
+
* @decorator
|
|
1267
|
+
*/
|
|
1268
|
+
declare function ButtonRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs): <TCtor extends new (...args: any[]) => InteractionHandler<Repliables> & HasComponentDefs<Defs>>(constructor: AssertHandles<ButtonInteraction, TCtor>) => void;
|
|
1269
|
+
/**
|
|
1270
|
+
* Routes modal submissions to handler classes.
|
|
1271
|
+
*
|
|
1272
|
+
* Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's
|
|
1273
|
+
* generic. Passing different definitions to the decorator and the generic is a compile error. Routing
|
|
1274
|
+
* matches the stable prefix, so an older-shape wire still reaches the handler and throws StaleCustomId
|
|
1275
|
+
* on read, the same as a button route.
|
|
1276
|
+
*
|
|
1277
|
+
* @param defs - The customId definition(s) this handler decodes, one per route.
|
|
1278
|
+
* @decorator
|
|
1279
|
+
*/
|
|
1280
|
+
declare function ModalRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs): <TCtor extends new (...args: any[]) => InteractionHandler<Repliables> & HasComponentDefs<Defs>>(constructor: AssertHandles<ModalSubmitInteraction, TCtor>) => void;
|
|
1281
|
+
/** The context-menu command names valid for a kind, read off the matching registry. @internal */
|
|
1282
|
+
type NamesFor<Kind extends ApplicationCommandType.User | ApplicationCommandType.Message> = Kind extends ApplicationCommandType.User ? keyof UserContextMenuRegistry : keyof MessageContextMenuRegistry;
|
|
1283
|
+
/**
|
|
1284
|
+
* The context-menu kind a handler serves, read off its event's `commandType` discriminant. Direct
|
|
1285
|
+
* inference from the `ContextMenuHandler` generic widens the kind to the whole union because the handler's
|
|
1286
|
+
* conditional members blur it, so this uses the event literal to keep it narrow.
|
|
1287
|
+
*
|
|
1288
|
+
* @internal
|
|
1289
|
+
*/
|
|
1290
|
+
type ContextMenuKindOf<TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> = InstanceType<TCtor> extends ContextMenuHandler<infer Kind, CacheType> ? [Kind] extends [ApplicationCommandType.User | ApplicationCommandType.Message] ? HandlerEventType<TCtor> extends {
|
|
1291
|
+
commandType: infer K;
|
|
1292
|
+
} ? Extract<K, ApplicationCommandType.User | ApplicationCommandType.Message> : never : never : never;
|
|
1293
|
+
/**
|
|
1294
|
+
* On a kind mismatch between the decorator and the handler generic, resolves to a non-constructor type so
|
|
1295
|
+
* applying the decorator is a TS1238. Cross-checks both directions, mirroring {@link AssertSlashRoute}.
|
|
1296
|
+
*
|
|
1297
|
+
* @internal
|
|
1298
|
+
*/
|
|
1299
|
+
type AssertContextMenuRoute<Kind extends ApplicationCommandType.User | ApplicationCommandType.Message, TCtor extends new (...args: any[]) => InteractionHandler<Repliables>> = [Kind] extends [ContextMenuKindOf<TCtor>] ? [ContextMenuKindOf<TCtor>] extends [Kind] ? TCtor : Constructor<['ContextMenuHandler declares a kind the ContextMenuRoute decorator does not match', ContextMenuKindOf<TCtor>]> : Constructor<['ContextMenuRoute does not match the ContextMenuHandler generic', Kind]>;
|
|
1300
|
+
/**
|
|
1301
|
+
* Routes one or more context-menu commands to a {@link ContextMenuHandler}.
|
|
1302
|
+
*
|
|
1303
|
+
* Pass the kind (`ApplicationCommandType.User` or `ApplicationCommandType.Message`) and the command name(s),
|
|
1304
|
+
* each checked against that kind's registry, so a typo is a compile error. The same kind must sit on the
|
|
1305
|
+
* handler's generic, cross-checked both directions. Context menus carry no options, so a multi-name handler
|
|
1306
|
+
* reads `this.target` uniformly with no branch.
|
|
1307
|
+
*
|
|
1308
|
+
* @param kind - The context-menu kind, `ApplicationCommandType.User` or `ApplicationCommandType.Message`.
|
|
1309
|
+
* @param names - The command name(s) this handler serves, keyed off the matching registry.
|
|
1310
|
+
* @decorator
|
|
1311
|
+
* @example
|
|
1312
|
+
* ```ts
|
|
1313
|
+
* \@ContextMenuRoute(ApplicationCommandType.User, 'View Profile')
|
|
1314
|
+
* class ViewProfile extends ContextMenuHandler<ApplicationCommandType.User> {
|
|
1315
|
+
* async execute() {
|
|
1316
|
+
* const user = this.target;
|
|
1317
|
+
* }
|
|
1318
|
+
* }
|
|
1319
|
+
* ```
|
|
1320
|
+
*/
|
|
1321
|
+
declare function ContextMenuRoute<const Kind extends ApplicationCommandType.User | ApplicationCommandType.Message>(kind: Kind, ...names: NamesFor<Kind>[]): <TCtor extends new (...args: any[]) => InteractionHandler<Repliables>>(constructor: AssertContextMenuRoute<Kind, TCtor>) => void;
|
|
1322
|
+
/**
|
|
1323
|
+
* The command route(s) an autocomplete handler serves, read off its `AutocompleteHandler` generic.
|
|
1324
|
+
*
|
|
1325
|
+
* @internal
|
|
1326
|
+
*/
|
|
1327
|
+
type AutocompleteRouteOf<TCtor extends new (...args: any[]) => BaseHandler<AutocompleteInteraction<CacheType>>> = InstanceType<TCtor> extends AutocompleteHandler<infer Route, CacheType> ? Route : never;
|
|
1328
|
+
/**
|
|
1329
|
+
* On a route/generic mismatch, resolves to a non-constructor type so applying the decorator is a TS1238.
|
|
1330
|
+
*
|
|
1331
|
+
* @internal
|
|
1332
|
+
*/
|
|
1333
|
+
type AssertAutocompleteRoute<Route extends keyof SlashOptionRegistry, TCtor extends new (...args: any[]) => BaseHandler<AutocompleteInteraction<CacheType>>> = [Route] extends [AutocompleteRouteOf<TCtor>] ? [AutocompleteRouteOf<TCtor>] extends [Route] ? TCtor : Constructor<['AutocompleteHandler declares a command the AutocompleteRoute decorator does not list', AutocompleteRouteOf<TCtor>]> : Constructor<['AutocompleteRoute does not match the AutocompleteHandler generic', Route]>;
|
|
1334
|
+
/**
|
|
1335
|
+
* Routes one or more commands' autocomplete to an {@link AutocompleteHandler}.
|
|
1336
|
+
*
|
|
1337
|
+
* Pass the same command route string(s) as the handler's generic. One command branches with `this.match`
|
|
1338
|
+
* over its autocompletable fields, several commands share one handler whose arms span every command's
|
|
1339
|
+
* fields. The decorator routes and the generic must match exactly, so listing fewer or more than the
|
|
1340
|
+
* handler declares is a compile error.
|
|
1341
|
+
*
|
|
1342
|
+
* @param routes - The command route string(s) this handler serves, e.g. `'search'` or `'search', 'find'`.
|
|
1343
|
+
* @decorator
|
|
1344
|
+
* @example
|
|
1345
|
+
* ```ts
|
|
1346
|
+
* \@AutocompleteRoute('search')
|
|
1347
|
+
* class SearchAutocomplete extends AutocompleteHandler<'search'> {
|
|
1348
|
+
* async execute() {
|
|
1349
|
+
* await this.match({ query: (value, respond) => respond([{ name: value, value }]) });
|
|
1350
|
+
* }
|
|
1351
|
+
* }
|
|
1352
|
+
* ```
|
|
1353
|
+
*/
|
|
1354
|
+
declare function AutocompleteRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]): <TCtor extends new (...args: any[]) => BaseHandler<AutocompleteInteraction<CacheType>>>(constructor: AssertAutocompleteRoute<Route, TCtor>) => void;
|
|
1355
|
+
/** @internal */
|
|
1356
|
+
type SelectMenuInteractionFor<SelectMenu extends SelectMenuKind, Cache extends CacheType = CacheType> = SelectMenu extends SelectMenuKind.String ? StringSelectMenuInteraction<Cache> : SelectMenu extends SelectMenuKind.User ? UserSelectMenuInteraction<Cache> : SelectMenu extends SelectMenuKind.Role ? RoleSelectMenuInteraction<Cache> : SelectMenu extends SelectMenuKind.Channel ? ChannelSelectMenuInteraction<Cache> : SelectMenu extends SelectMenuKind.Mentionable ? MentionableSelectMenuInteraction<Cache> : never;
|
|
1357
|
+
/**
|
|
1358
|
+
* Routes select menu interactions to handler classes.
|
|
1359
|
+
*
|
|
1360
|
+
* Pass the select kind and the {@link CustomId} definition(s) this handler decodes. The handler's
|
|
1361
|
+
* generic must list the same definitions, and its second generic argument must be the matching select
|
|
1362
|
+
* interaction type, or it is a compile error.
|
|
1363
|
+
*
|
|
1364
|
+
* @param type - Select menu kind from {@link SelectMenuKind}.
|
|
1365
|
+
* @param defs - The customId definition(s) this handler decodes, one per route.
|
|
1366
|
+
* @decorator
|
|
1367
|
+
*
|
|
1368
|
+
* @example
|
|
1369
|
+
* ```typescript
|
|
1370
|
+
* \@SelectMenuRoute(SelectMenuKind.User, AssignId)
|
|
1371
|
+
* class AssignSelect extends SelectMenuHandler<SelectMenuKind.User, [typeof AssignId]> {
|
|
1372
|
+
* // handles user select menus minted from AssignId
|
|
1373
|
+
* }
|
|
1374
|
+
* ```
|
|
1375
|
+
*/
|
|
1376
|
+
declare function SelectMenuRoute<SelectMenu extends SelectMenuKind, const Defs extends readonly AnyCustomId[]>(type: SelectMenu, ...defs: Defs): <TCtor extends new (...args: any[]) => InteractionHandler<Repliables> & HasComponentDefs<Defs>>(constructor: AssertHandles<SelectMenuInteractionFor<SelectMenu>, TCtor>) => void;
|
|
1377
|
+
//#endregion
|
|
1378
|
+
//#region src/handlers/interaction/InteractionMiddleware.d.ts
|
|
1379
|
+
/**
|
|
1380
|
+
* Base class for interaction middleware
|
|
1381
|
+
*
|
|
1382
|
+
* Middleware runs before interaction handlers and can modify behavior or block execution.
|
|
1383
|
+
* Unlike handlers, middleware should not send responses directly.
|
|
1384
|
+
*
|
|
1385
|
+
* @typeParam Repliable - The interaction type this middleware processes
|
|
1386
|
+
*/
|
|
1387
|
+
declare abstract class InteractionMiddleware<Repliable extends Repliables> extends BaseHandler<Repliable> implements Handler {
|
|
1388
|
+
constructor(event: Repliable, core: Core);
|
|
1389
|
+
}
|
|
1390
|
+
//#endregion
|
|
1391
|
+
//#region src/handlers/interaction/components/ComponentHandler.d.ts
|
|
1392
|
+
type ComponentInteraction = ButtonInteraction | ModalSubmitInteraction | AnySelectMenuInteraction;
|
|
1393
|
+
type SingleParams<Defs extends readonly AnyCustomId[]> = Defs extends readonly [infer One extends AnyCustomId] ? DecodedParams<One['shape']> : never;
|
|
1394
|
+
type MatchArms<Defs extends readonly AnyCustomId[], Ret> = { [Def in Defs[number] as Def['prefix']]: (params: DecodedParams<Def['shape']>) => Promisable<Ret> };
|
|
1395
|
+
/**
|
|
1396
|
+
* Shared base the customId-routed component handlers extend.
|
|
1397
|
+
*
|
|
1398
|
+
* Not a public entry point. You should be using {@link ButtonHandler}, {@link SelectMenuHandler}, or
|
|
1399
|
+
* {@link ModalHandler} instead. This class only carries the customId decode and route-matching plumbing
|
|
1400
|
+
* those bases share, so DO NOT use it directly.
|
|
1401
|
+
*
|
|
1402
|
+
* @typeParam Event - The component interaction type this handler processes
|
|
1403
|
+
* @typeParam Defs - The customId route definitions registered on the concrete handler
|
|
1404
|
+
*/
|
|
1405
|
+
declare abstract class ComponentHandler<Event extends ComponentInteraction, Defs extends readonly AnyCustomId[]> extends InteractionHandler<Event> implements HasComponentDefs<Defs> {
|
|
1406
|
+
/** @internal */
|
|
1407
|
+
readonly __componentDefs?: Defs;
|
|
1408
|
+
private get registeredDefs();
|
|
1409
|
+
private decoded?;
|
|
1410
|
+
private get route();
|
|
1411
|
+
/**
|
|
1412
|
+
* The decoded params of the single route this handler is registered for.
|
|
1413
|
+
*
|
|
1414
|
+
* Reading this decodes `this.event.customId` once (cached after the first read) and throws
|
|
1415
|
+
* `StaleCustomId` or `InvalidCustomId` when the wire no longer matches the current shape, which the
|
|
1416
|
+
* controller boundary turns into a reply. On a handler registered for several routes this is
|
|
1417
|
+
* `never`, so use {@link match} instead.
|
|
1418
|
+
*/
|
|
1419
|
+
protected get params(): SingleParams<Defs>;
|
|
1420
|
+
/**
|
|
1421
|
+
* Run the arm for whichever route the component was minted from. Use this only when the handler is
|
|
1422
|
+
* registered for several routes. A single-route handler reads `this.params` directly. On a multi-route
|
|
1423
|
+
* handler `this.params` is `never`, so match is the only way to read the decoded params.
|
|
1424
|
+
*
|
|
1425
|
+
* Provide one arm per registered route, keyed by its prefix, and each arm receives that route's own
|
|
1426
|
+
* decoded params. The arms must cover every registered def, a missing prefix or an unknown key is a
|
|
1427
|
+
* compile error. Decoding runs before any arm, so a stale or corrupt wire throws before an arm body executes.
|
|
1428
|
+
*
|
|
1429
|
+
* @param arms - One handler per registered route, keyed by prefix.
|
|
1430
|
+
* @returns The result of the arm that ran.
|
|
1431
|
+
*
|
|
1432
|
+
* @example
|
|
1433
|
+
* ```ts
|
|
1434
|
+
* \@ButtonRoute(Approve, Reject)
|
|
1435
|
+
* class ReviewButtons extends ButtonHandler<[typeof Approve, typeof Reject]> {
|
|
1436
|
+
* async execute() {
|
|
1437
|
+
* await this.match({
|
|
1438
|
+
* approve: ({ userId }) => this.event.reply(`approved <@${userId}>`),
|
|
1439
|
+
* reject: ({ userId }) => this.event.reply(`rejected <@${userId}>`)
|
|
1440
|
+
* });
|
|
1441
|
+
* }
|
|
1442
|
+
* }
|
|
1443
|
+
* ```
|
|
1444
|
+
*/
|
|
1445
|
+
protected match<Ret>(arms: MatchArms<Defs, Ret>): Promise<Ret>;
|
|
1446
|
+
}
|
|
1447
|
+
//#endregion
|
|
1448
|
+
//#region src/handlers/interaction/components/ButtonHandler.d.ts
|
|
1449
|
+
/**
|
|
1450
|
+
* Base class for a button interaction handler.
|
|
1451
|
+
*
|
|
1452
|
+
* Register the customId definitions this handler decodes with `@ButtonRoute`, list the same ones in the
|
|
1453
|
+
* generic, then read `this.params` for a single route or `this.match` for several. Passing different
|
|
1454
|
+
* definitions to the decorator and the generic is a compile error.
|
|
1455
|
+
*
|
|
1456
|
+
* @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof ApproveId]`.
|
|
1457
|
+
* @typeParam Cache - The interaction cache state, `'cached'` by default.
|
|
1458
|
+
*
|
|
1459
|
+
* @example
|
|
1460
|
+
* ```ts
|
|
1461
|
+
* \@ButtonRoute(ApproveId)
|
|
1462
|
+
* class ApproveButton extends ButtonHandler<[typeof ApproveId]> {
|
|
1463
|
+
* async execute() {
|
|
1464
|
+
* const { userId } = this.params;
|
|
1465
|
+
* await this.event.reply(`approved <@${userId}>`);
|
|
1466
|
+
* }
|
|
1467
|
+
* }
|
|
1468
|
+
* ```
|
|
1469
|
+
*/
|
|
1470
|
+
declare abstract class ButtonHandler<Defs extends readonly AnyCustomId[], Cache extends CacheType = 'cached'> extends ComponentHandler<ButtonInteraction<Cache>, Defs> {}
|
|
1471
|
+
//#endregion
|
|
1472
|
+
//#region src/handlers/interaction/components/ModalHandler.d.ts
|
|
1473
|
+
/**
|
|
1474
|
+
* Base class for a modal submit handler.
|
|
1475
|
+
*
|
|
1476
|
+
* Register the customId definitions this handler decodes with `@ModalRoute`, list the same ones in the
|
|
1477
|
+
* generic, then read `this.params` for a single route or `this.match` for several. Read the submitted
|
|
1478
|
+
* inputs from `this.event.fields`.
|
|
1479
|
+
*
|
|
1480
|
+
* @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof ConfigId]`.
|
|
1481
|
+
* @typeParam Cache - The interaction cache state, `'cached'` by default.
|
|
1482
|
+
*
|
|
1483
|
+
* @example
|
|
1484
|
+
* ```ts
|
|
1485
|
+
* \@ModalRoute(ConfigId)
|
|
1486
|
+
* class ConfigModal extends ModalHandler<[typeof ConfigId]> {
|
|
1487
|
+
* async execute() {
|
|
1488
|
+
* const { guildId } = this.params;
|
|
1489
|
+
* const name = this.event.fields.getTextInputValue('name');
|
|
1490
|
+
* await this.event.reply(`saved ${name} for ${guildId}`);
|
|
1491
|
+
* }
|
|
1492
|
+
* }
|
|
1493
|
+
* ```
|
|
1494
|
+
*/
|
|
1495
|
+
declare abstract class ModalHandler<Defs extends readonly AnyCustomId[], Cache extends CacheType = 'cached'> extends ComponentHandler<ModalSubmitInteraction<Cache>, Defs> {}
|
|
1496
|
+
//#endregion
|
|
1497
|
+
//#region src/handlers/interaction/components/SelectMenuHandler.d.ts
|
|
1498
|
+
/**
|
|
1499
|
+
* Base class for a select menu handler.
|
|
1500
|
+
*
|
|
1501
|
+
* Pass the select kind first and the customId definitions second, the same order as `@SelectMenuRoute`,
|
|
1502
|
+
* so `this.event` and `this.event.values` are narrowed to that kind. Read `this.params` for a single
|
|
1503
|
+
* route or `this.match` for several.
|
|
1504
|
+
*
|
|
1505
|
+
* @typeParam Kind - The select kind from {@link SelectMenuKind}, e.g. `SelectMenuKind.User`.
|
|
1506
|
+
* @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof AssignId]`.
|
|
1507
|
+
* @typeParam Cache - The interaction cache state, `'cached'` by default.
|
|
1508
|
+
*
|
|
1509
|
+
* @example
|
|
1510
|
+
* ```ts
|
|
1511
|
+
* \@SelectMenuRoute(SelectMenuKind.User, AssignId)
|
|
1512
|
+
* class AssignSelect extends SelectMenuHandler<SelectMenuKind.User, [typeof AssignId]> {
|
|
1513
|
+
* async execute() {
|
|
1514
|
+
* const { roleId } = this.params;
|
|
1515
|
+
* await this.event.reply(`assigning ${this.event.values.length} member(s) to <@&${roleId}>`);
|
|
1516
|
+
* }
|
|
1517
|
+
* }
|
|
1518
|
+
* ```
|
|
1519
|
+
*/
|
|
1520
|
+
declare abstract class SelectMenuHandler<Kind extends SelectMenuKind, Defs extends readonly AnyCustomId[], Cache extends CacheType = 'cached'> extends ComponentHandler<SelectMenuInteractionFor<Kind, Cache>, Defs> {}
|
|
1521
|
+
//#endregion
|
|
1522
|
+
//#region src/bot/decorators/Middlewares.d.ts
|
|
1523
|
+
/**
|
|
1524
|
+
* Middleware types supported by Seedcord
|
|
1525
|
+
*/
|
|
1526
|
+
declare enum MiddlewareType {
|
|
1527
|
+
Interaction = "interaction",
|
|
1528
|
+
Event = "event"
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Additional middleware registration options
|
|
1532
|
+
*
|
|
1533
|
+
* @typeParam MType - The type of middleware being registered
|
|
1534
|
+
*/
|
|
1535
|
+
interface MiddlewareOptions<MType extends MiddlewareType, Events extends readonly ValidNonInteractionKeys[] = readonly ValidNonInteractionKeys[]> {
|
|
1536
|
+
/**
|
|
1537
|
+
* Restrict event middleware execution to specific Discord client events. The middleware's `EventMiddleware`
|
|
1538
|
+
* generic must list the same events, or applying the decorator is a compile error.
|
|
1539
|
+
*/
|
|
1540
|
+
readonly events?: MType extends MiddlewareType.Event ? Events : never;
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Decorator used to register middleware with priority ordering. The lower the priority number, the earlier it runs.
|
|
1544
|
+
*
|
|
1545
|
+
* Interaction middleware cannot specify event filters.
|
|
1546
|
+
*
|
|
1547
|
+
* @param type - Middleware kind from {@link MiddlewareType}
|
|
1548
|
+
* @param priority - Ordering value where lower runs earlier. {@default `0`}
|
|
1549
|
+
* @param options - Additional registration options
|
|
1550
|
+
*
|
|
1551
|
+
* @decorator
|
|
1552
|
+
*
|
|
1553
|
+
* @example
|
|
1554
|
+
* ```ts
|
|
1555
|
+
* \@Middleware(MiddlewareType.Event, 10, { events: [Events.MessageCreate, Events.MessageUpdate] })
|
|
1556
|
+
* class MyEventMiddleware extends EventMiddleware {}
|
|
1557
|
+
* ```
|
|
1558
|
+
* @throws A **SeedcordTypeError** If priority is not a finite number
|
|
1559
|
+
* @throws A **SeedcordError** If interaction middleware specifies event filters
|
|
1560
|
+
*/
|
|
1561
|
+
declare function Middleware<MType extends MiddlewareType, const Events extends readonly ValidNonInteractionKeys[] = []>(type: MType, priority?: number, options?: MiddlewareOptions<MType, Events>): (ctor: MType extends MiddlewareType.Interaction ? Constructor<InteractionMiddleware<Repliables>> : Events extends readonly [] ? Constructor<EventMiddleware<ValidNonInteractionKeys>> : Constructor<EventMiddleware<Events[number]>>) => void;
|
|
1562
|
+
//#endregion
|
|
1563
|
+
//#region src/bot/gates/catalog/IgnoreBots.d.ts
|
|
1564
|
+
/**
|
|
1565
|
+
* Drops a client event whose actor is a bot, with a {@link Silence} so nothing is replied. Event-only, because a
|
|
1566
|
+
* Silence on an interaction would leave Discord's failed-interaction state. It rejects an interaction handler at
|
|
1567
|
+
* the decorator line. Takes no options, so attach it directly without calling it.
|
|
1568
|
+
*
|
|
1569
|
+
* @see {@link Gated}
|
|
1570
|
+
*
|
|
1571
|
+
* @example
|
|
1572
|
+
* ```ts
|
|
1573
|
+
* import { Events } from 'discord.js';
|
|
1574
|
+
*
|
|
1575
|
+
* \@Gated(IgnoreBots)
|
|
1576
|
+
* class OnMessage extends EventHandler<Events.MessageCreate> {
|
|
1577
|
+
* async execute() {
|
|
1578
|
+
* // ...
|
|
1579
|
+
* }
|
|
1580
|
+
* }
|
|
1581
|
+
* ```
|
|
1582
|
+
*/
|
|
1583
|
+
declare const IgnoreBots: import("@seedcord/core").Gate<EventGateContext<ValidNonInteractionKeys>, "IgnoreBots">;
|
|
1584
|
+
//#endregion
|
|
1585
|
+
//#region src/bot/gates/catalog/Nsfw.d.ts
|
|
1586
|
+
/**
|
|
1587
|
+
* Requires an age-restricted channel, else refuses. Pass {@link GateNoticeOptions} to reword or replace the refusal.
|
|
1588
|
+
*
|
|
1589
|
+
* A thread inherits its parent channel's nsfw flag. ModalSubmit has no reliable channel, so it is excluded.
|
|
1590
|
+
*
|
|
1591
|
+
* @param options - Reword the default refusal with `message`, or replace it with `notice`.
|
|
1592
|
+
*
|
|
1593
|
+
* @see {@link Gated}
|
|
1594
|
+
*
|
|
1595
|
+
* @example
|
|
1596
|
+
* ```ts
|
|
1597
|
+
* \@Gated(Nsfw())
|
|
1598
|
+
* \@SlashRoute('nsfwcmd')
|
|
1599
|
+
* class NsfwHandler extends SlashHandler<'nsfwcmd'> {
|
|
1600
|
+
* async execute() {
|
|
1601
|
+
* // ...
|
|
1602
|
+
* }
|
|
1603
|
+
* }
|
|
1604
|
+
* ```
|
|
1605
|
+
*/
|
|
1606
|
+
declare function Nsfw(options?: GateNoticeOptions): Gate<InteractionGateContext<NonModalInteraction>, 'Nsfw'>;
|
|
1607
|
+
//#endregion
|
|
1608
|
+
//#region src/bot/notices/utils.d.ts
|
|
1609
|
+
/** Whose permissions a check ran against, used to mention and label the subject in a refusal. */
|
|
1610
|
+
type PermSubject = Role | TextChannel | Guild | GuildMember;
|
|
1611
|
+
//#endregion
|
|
1612
|
+
//#region src/bot/utilities/permissions/checkPermissions.d.ts
|
|
1613
|
+
/**
|
|
1614
|
+
* Array of permission bits for permission validation.
|
|
1615
|
+
* Import any of the predefined sets or pass a custom bigint[].
|
|
1616
|
+
*/
|
|
1617
|
+
type BotPermissionScope = readonly bigint[];
|
|
1618
|
+
/**
|
|
1619
|
+
* Optional custom error constructors for {@link CheckPermissionOptions}.
|
|
1620
|
+
*/
|
|
1621
|
+
interface PermissionErrorCtors {
|
|
1622
|
+
missing?: new (message: string, where: PermSubject, missingPerms: string[]) => Notice;
|
|
1623
|
+
dangerous?: new (message: string, target: PermSubject, dangerousPerms: string[]) => Notice;
|
|
1624
|
+
}
|
|
1625
|
+
/**
|
|
1626
|
+
* Options for {@link checkPermissions}.
|
|
1627
|
+
*
|
|
1628
|
+
* @see {@link PermissionErrorCtors}
|
|
1629
|
+
*/
|
|
1630
|
+
interface CheckPermissionOptions extends PermissionErrorCtors {
|
|
1631
|
+
/** Role or member whose permissions will be checked */
|
|
1632
|
+
for: Role | GuildMember;
|
|
1633
|
+
/** Context where permissions apply, guild or channel */
|
|
1634
|
+
in: Guild | TextChannel;
|
|
1635
|
+
/** Permission bits to validate */
|
|
1636
|
+
scope: BotPermissionScope;
|
|
1637
|
+
/** When true, ensure target does not have the given permissions */
|
|
1638
|
+
inverse?: boolean;
|
|
1639
|
+
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Checks permissions for a {@link Role} or a {@link GuildMember} in a {@link Guild}. Refuses when a
|
|
1642
|
+
* permission in `scope` is missing, or with `inverse` when one is present.
|
|
1643
|
+
*
|
|
1644
|
+
* @param target - Role or member to check
|
|
1645
|
+
* @param ctx - Guild context
|
|
1646
|
+
* @param scope - Permission bits to validate
|
|
1647
|
+
* @param inverse - Whether to ensure absence of the given permissions
|
|
1648
|
+
* @param errors - Optional custom error constructors
|
|
1649
|
+
*
|
|
1650
|
+
*
|
|
1651
|
+
* @example
|
|
1652
|
+
* ```ts
|
|
1653
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1654
|
+
* import { checkPermissions } from '@seedcord/gateway';
|
|
1655
|
+
*
|
|
1656
|
+
* // Check if a role has ManageMessages and KickMembers permissions in a guild
|
|
1657
|
+
* checkPermissions(role, guild, [
|
|
1658
|
+
* PermissionFlagsBits.ManageMessages,
|
|
1659
|
+
* PermissionFlagsBits.KickMembers
|
|
1660
|
+
* ]);
|
|
1661
|
+
* ```
|
|
1662
|
+
*
|
|
1663
|
+
* @example
|
|
1664
|
+
* ```ts
|
|
1665
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1666
|
+
* import { checkPermissions } from '@seedcord/gateway';
|
|
1667
|
+
*
|
|
1668
|
+
* // Ensure a member does NOT have Administrator permission in a guild and show custom errors
|
|
1669
|
+
* checkPermissions(member, guild, [
|
|
1670
|
+
* PermissionFlagsBits.Administrator
|
|
1671
|
+
* ], true, {
|
|
1672
|
+
* missing: CustomMissingPermissionsError,
|
|
1673
|
+
* dangerous: CustomDangerousPermissionsError
|
|
1674
|
+
* });
|
|
1675
|
+
* ```
|
|
1676
|
+
*/
|
|
1677
|
+
declare function checkPermissions(target: Role | GuildMember, ctx: Guild, scope: BotPermissionScope, inverse?: boolean, errors?: PermissionErrorCtors): void;
|
|
1678
|
+
/**
|
|
1679
|
+
* Checks permissions for a {@link Role} or a {@link GuildMember} in a {@link TextChannel}. Refuses when a
|
|
1680
|
+
* permission in `scope` is missing, or with `inverse` when one is present.
|
|
1681
|
+
*
|
|
1682
|
+
* @param target - Role or member to check
|
|
1683
|
+
* @param ctx - Channel context
|
|
1684
|
+
* @param scope - Permission bits to validate
|
|
1685
|
+
* @param inverse - Whether to ensure absence of the given permissions
|
|
1686
|
+
* @param errors - Optional custom error constructors
|
|
1687
|
+
*
|
|
1688
|
+
*
|
|
1689
|
+
* @example
|
|
1690
|
+
* ```ts
|
|
1691
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1692
|
+
* import { checkPermissions } from '@seedcord/gateway';
|
|
1693
|
+
*
|
|
1694
|
+
* // Check if a role has SendMessages and ViewChannel permissions in a text channel
|
|
1695
|
+
* checkPermissions(role, textChannel, [
|
|
1696
|
+
* PermissionFlagsBits.SendMessages,
|
|
1697
|
+
* PermissionFlagsBits.ViewChannel
|
|
1698
|
+
* ]);
|
|
1699
|
+
* ```
|
|
1700
|
+
*
|
|
1701
|
+
* @example
|
|
1702
|
+
* ```ts
|
|
1703
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1704
|
+
* import { checkPermissions } from '@seedcord/gateway';
|
|
1705
|
+
*
|
|
1706
|
+
* // Ensure a member does NOT have ManageChannels permission in a text channel and show custom errors
|
|
1707
|
+
* checkPermissions(member, textChannel, [
|
|
1708
|
+
* PermissionFlagsBits.ManageChannels
|
|
1709
|
+
* ], true, {
|
|
1710
|
+
* missing: CustomMissingPermissionsError,
|
|
1711
|
+
* dangerous: CustomDangerousPermissionsError
|
|
1712
|
+
* });
|
|
1713
|
+
* ```
|
|
1714
|
+
*/
|
|
1715
|
+
declare function checkPermissions(target: Role | GuildMember, ctx: TextChannel, scope: BotPermissionScope, inverse?: boolean, errors?: PermissionErrorCtors): void;
|
|
1716
|
+
/**
|
|
1717
|
+
* Checks permissions using an options object. Refuses when a permission in {@link CheckPermissionOptions.scope} is missing,
|
|
1718
|
+
* or with `options.inverse` when one is present.
|
|
1719
|
+
*
|
|
1720
|
+
* @param options - Complete options for the check
|
|
1721
|
+
*
|
|
1722
|
+
*
|
|
1723
|
+
* @example
|
|
1724
|
+
* ```ts
|
|
1725
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1726
|
+
* import { checkPermissions } from '@seedcord/gateway';
|
|
1727
|
+
*
|
|
1728
|
+
* // Check permissions using an options object
|
|
1729
|
+
* checkPermissions({
|
|
1730
|
+
* for: member,
|
|
1731
|
+
* in: textChannel,
|
|
1732
|
+
* scope: [
|
|
1733
|
+
* PermissionFlagsBits.SendMessages,
|
|
1734
|
+
* PermissionFlagsBits.ViewChannel
|
|
1735
|
+
* ]
|
|
1736
|
+
* });
|
|
1737
|
+
* ```
|
|
1738
|
+
*
|
|
1739
|
+
* @example
|
|
1740
|
+
* ```ts
|
|
1741
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1742
|
+
* import { checkPermissions } from '@seedcord/gateway';
|
|
1743
|
+
*
|
|
1744
|
+
* // Ensure a role does NOT have BanMembers permission in a guild using an options object
|
|
1745
|
+
* checkPermissions({
|
|
1746
|
+
* for: role,
|
|
1747
|
+
* in: guild,
|
|
1748
|
+
* scope: [
|
|
1749
|
+
* PermissionFlagsBits.BanMembers
|
|
1750
|
+
* ],
|
|
1751
|
+
* inverse: true,
|
|
1752
|
+
* missing: CustomMissingPermissionsError,
|
|
1753
|
+
* dangerous: CustomDangerousPermissionsError
|
|
1754
|
+
* });
|
|
1755
|
+
* ```
|
|
1756
|
+
*/
|
|
1757
|
+
declare function checkPermissions(options: CheckPermissionOptions): void;
|
|
1758
|
+
//#endregion
|
|
1759
|
+
//#region src/bot/gates/catalog/permissions.d.ts
|
|
1760
|
+
/**
|
|
1761
|
+
* Options for {@link RequirePermissions} and {@link RequireBotPermissions}, one override per refusal the gate
|
|
1762
|
+
* can show.
|
|
1763
|
+
*
|
|
1764
|
+
* @example
|
|
1765
|
+
* ```ts
|
|
1766
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1767
|
+
* import type { Guild, GuildMember, Role, TextChannel } from 'discord.js';
|
|
1768
|
+
*
|
|
1769
|
+
* // `missing` is a Notice ctor: (message, where, missingPerms)
|
|
1770
|
+
* class MissingPermsNotice extends Notice {
|
|
1771
|
+
* public constructor(message: string, where: Role | TextChannel | Guild | GuildMember, missing: string[]) {
|
|
1772
|
+
* super(`${message} (${missing.join(', ')})`);
|
|
1773
|
+
* }
|
|
1774
|
+
* }
|
|
1775
|
+
*
|
|
1776
|
+
* RequirePermissions([PermissionFlagsBits.BanMembers], { missing: MissingPermsNotice });
|
|
1777
|
+
* ```
|
|
1778
|
+
*/
|
|
1779
|
+
interface RequirePermissionsOptions {
|
|
1780
|
+
/** Reword or replace the refusal shown outside a guild. */
|
|
1781
|
+
notInGuild?: GateNoticeOptions;
|
|
1782
|
+
/** Replace the missing-permissions refusal with a ctor that receives the where and the missing perm names. */
|
|
1783
|
+
missing?: PermissionErrorCtors['missing'];
|
|
1784
|
+
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Options for {@link RequireRole}, one override per refusal the gate can show.
|
|
1787
|
+
*/
|
|
1788
|
+
interface RequireRoleOptions {
|
|
1789
|
+
/** Reword or replace the refusal shown outside a guild. */
|
|
1790
|
+
notInGuild?: GateNoticeOptions;
|
|
1791
|
+
/** Reword or replace the refusal shown when the caller lacks the role. */
|
|
1792
|
+
missingRole?: GateNoticeOptions;
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Requires the caller to hold every permission in `scope`, via `checkPermissions`. Refuses outside a guild.
|
|
1796
|
+
*
|
|
1797
|
+
* Interaction-only and excludes ModalSubmit, since a modal lacks a reliable cached caller member.
|
|
1798
|
+
*
|
|
1799
|
+
* @param scope - The permission flag bits the caller must all hold.
|
|
1800
|
+
* @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-permissions one with `missing`.
|
|
1801
|
+
*
|
|
1802
|
+
* @see {@link Gated}
|
|
1803
|
+
*
|
|
1804
|
+
* @example
|
|
1805
|
+
* ```ts
|
|
1806
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1807
|
+
*
|
|
1808
|
+
* \@Gated(RequirePermissions([PermissionFlagsBits.BanMembers]))
|
|
1809
|
+
* \@SlashRoute('ban')
|
|
1810
|
+
* class BanHandler extends SlashHandler<'ban'> {
|
|
1811
|
+
* async execute() {
|
|
1812
|
+
* const target = this.options.getUser('target');
|
|
1813
|
+
* }
|
|
1814
|
+
* }
|
|
1815
|
+
* ```
|
|
1816
|
+
*/
|
|
1817
|
+
declare function RequirePermissions(scope: BotPermissionScope, options?: RequirePermissionsOptions): Gate<InteractionGateContext<NonModalInteraction>, 'RequirePermissions'>;
|
|
1818
|
+
/**
|
|
1819
|
+
* Requires the bot to hold every permission in `scope`, via `checkPermissions`. Refuses outside a guild.
|
|
1820
|
+
*
|
|
1821
|
+
* It reads the bot's own member, so it attaches to modal handlers as well.
|
|
1822
|
+
*
|
|
1823
|
+
* @param scope - The permission flag bits the bot must all hold.
|
|
1824
|
+
* @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-permissions one with `missing`.
|
|
1825
|
+
*
|
|
1826
|
+
* @see {@link Gated}
|
|
1827
|
+
*
|
|
1828
|
+
* @example
|
|
1829
|
+
* ```ts
|
|
1830
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1831
|
+
*
|
|
1832
|
+
* \@Gated(RequireBotPermissions([PermissionFlagsBits.BanMembers]))
|
|
1833
|
+
* \@ModalRoute(MyModalId)
|
|
1834
|
+
* class MyModalHandler extends ModalHandler<[typeof MyModalId]> {
|
|
1835
|
+
* async execute() {
|
|
1836
|
+
* // ...
|
|
1837
|
+
* }
|
|
1838
|
+
* }
|
|
1839
|
+
* ```
|
|
1840
|
+
*/
|
|
1841
|
+
declare function RequireBotPermissions(scope: BotPermissionScope, options?: RequirePermissionsOptions): Gate<InteractionGateContext, 'RequireBotPermissions'>;
|
|
1842
|
+
/**
|
|
1843
|
+
* Requires the caller to have `roleId`, read from the member's role cache. Refuses outside a guild first, then
|
|
1844
|
+
* when the role is missing.
|
|
1845
|
+
*
|
|
1846
|
+
* Interaction-only and excludes ModalSubmit.
|
|
1847
|
+
*
|
|
1848
|
+
* @param roleId - The role snowflake the caller must hold, read from the member's role cache.
|
|
1849
|
+
* @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.
|
|
1850
|
+
*
|
|
1851
|
+
* @see {@link Gated}
|
|
1852
|
+
*
|
|
1853
|
+
* @example
|
|
1854
|
+
* ```ts
|
|
1855
|
+
* \@Gated(RequireRole('123456789012345678'))
|
|
1856
|
+
* \@SlashRoute('vip')
|
|
1857
|
+
* class VipHandler extends SlashHandler<'vip'> {
|
|
1858
|
+
* async execute() {
|
|
1859
|
+
* // ...
|
|
1860
|
+
* }
|
|
1861
|
+
* }
|
|
1862
|
+
* ```
|
|
1863
|
+
*/
|
|
1864
|
+
declare function RequireRole(roleId: string, options?: RequireRoleOptions): Gate<InteractionGateContext<NonModalInteraction>, 'RequireRole'>;
|
|
1865
|
+
//#endregion
|
|
1866
|
+
//#region src/bot/utilities/channels/fetchText.d.ts
|
|
1867
|
+
/**
|
|
1868
|
+
* Fetches and validates a text channel. Refuses when the channel doesn't exist or isn't a text channel.
|
|
1869
|
+
*
|
|
1870
|
+
* @param client - The Discord client instance
|
|
1871
|
+
* @param channelId - Channel ID or TextChannel instance
|
|
1872
|
+
* @returns Promise resolving to the text channel
|
|
1873
|
+
*/
|
|
1874
|
+
declare function fetchText(client: Client, channelId: TextChannelResolvable): Promise<TextChannel>;
|
|
1875
|
+
//#endregion
|
|
1876
|
+
//#region src/bot/utilities/permissions/checkBotPermissions.d.ts
|
|
1877
|
+
/**
|
|
1878
|
+
* Checks if the bot has required permissions in a {@link Guild} or {@link TextChannel}. Refuses when a
|
|
1879
|
+
* required permission is missing.
|
|
1880
|
+
*
|
|
1881
|
+
* @param target - Guild or text channel to check in
|
|
1882
|
+
* @param scope - Permission bits to validate
|
|
1883
|
+
* @param inverse - Whether to check for absence of the given permissions
|
|
1884
|
+
* @param errors - Optional custom error constructors
|
|
1885
|
+
*
|
|
1886
|
+
* @example
|
|
1887
|
+
* ```ts
|
|
1888
|
+
* import { PermissionFlagsBits } from 'discord.js';
|
|
1889
|
+
* import { checkBotPermissions } from '@seedcord/gateway';
|
|
1890
|
+
*
|
|
1891
|
+
* // Check if the bot has SendMessages and ViewChannel permissions in a text channel
|
|
1892
|
+
* checkBotPermissions(textChannel, [
|
|
1893
|
+
* PermissionFlagsBits.SendMessages,
|
|
1894
|
+
* PermissionFlagsBits.ViewChannel
|
|
1895
|
+
* ]);
|
|
1896
|
+
* ```
|
|
1897
|
+
*/
|
|
1898
|
+
declare function checkBotPermissions(target: Guild | TextChannel, scope: BotPermissionScope, inverse?: boolean, errors?: PermissionErrorCtors): void;
|
|
1899
|
+
//#endregion
|
|
1900
|
+
//#region src/bot/utilities/permissions/hasPermsToAssign.d.ts
|
|
1901
|
+
/**
|
|
1902
|
+
* Optional custom error constructors for {@link HasPermsToAssignOptions}.
|
|
1903
|
+
*/
|
|
1904
|
+
interface AssignRoleErrorCtors {
|
|
1905
|
+
/** Custom error for role higher than bot */
|
|
1906
|
+
higher?: new (message: string, role: Role, botRole: Role) => Notice;
|
|
1907
|
+
/** Custom error for managed role assignment */
|
|
1908
|
+
managed?: new (message: string) => Notice;
|
|
1909
|
+
/** Custom error for missing Manage Roles permission */
|
|
1910
|
+
missing?: new (message: string, where: Role | TextChannel | Guild | GuildMember, missingPerms: string[]) => Notice;
|
|
1911
|
+
}
|
|
1912
|
+
/**
|
|
1913
|
+
* Options for {@link hasPermsToAssign}.
|
|
1914
|
+
*/
|
|
1915
|
+
interface HasPermsToAssignOptions {
|
|
1916
|
+
/** Target role to validate for assignment */
|
|
1917
|
+
targetRole: Role;
|
|
1918
|
+
/** Optional custom error constructors */
|
|
1919
|
+
errors?: AssignRoleErrorCtors;
|
|
1920
|
+
}
|
|
1921
|
+
/**
|
|
1922
|
+
* 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.
|
|
1923
|
+
*
|
|
1924
|
+
* @param roleOrOptions - Target role or complete options for the check
|
|
1925
|
+
*
|
|
1926
|
+
* @example
|
|
1927
|
+
* ```ts
|
|
1928
|
+
* import { hasPermsToAssign } from '@seedcord/gateway';
|
|
1929
|
+
*
|
|
1930
|
+
* // Check if the bot can assign a specific role
|
|
1931
|
+
* hasPermsToAssign(role);
|
|
1932
|
+
*
|
|
1933
|
+
* // Check with custom error handling
|
|
1934
|
+
* hasPermsToAssign({
|
|
1935
|
+
* targetRole: role,
|
|
1936
|
+
* errors: {
|
|
1937
|
+
* higher: CustomHigherError,
|
|
1938
|
+
* managed: CustomManagedError,
|
|
1939
|
+
* missing: CustomMissingPermissionsError
|
|
1940
|
+
* }
|
|
1941
|
+
* });
|
|
1942
|
+
* ```
|
|
1943
|
+
*/
|
|
1944
|
+
declare function hasPermsToAssign(roleOrOptions: Role | HasPermsToAssignOptions): void;
|
|
1945
|
+
//#endregion
|
|
1946
|
+
//#region src/bot/utilities/roles/fetchRole.d.ts
|
|
1947
|
+
/**
|
|
1948
|
+
* Fetches a role by ID from a client or guild. Refuses when the role doesn't exist.
|
|
1949
|
+
*
|
|
1950
|
+
* @param clientOrGuild - Discord client or guild instance
|
|
1951
|
+
* @param roleId - The role ID to fetch
|
|
1952
|
+
* @returns Promise resolving to the role
|
|
1953
|
+
*/
|
|
1954
|
+
declare function fetchRole(clientOrGuild: Client | Guild, roleId: string): Promise<Role>;
|
|
1955
|
+
//#endregion
|
|
1956
|
+
//#region src/bot/utilities/roles/getBotRole.d.ts
|
|
1957
|
+
/**
|
|
1958
|
+
* Gets the bot's managed role in a guild.
|
|
1959
|
+
*
|
|
1960
|
+
* @param guild - The guild to get the bot role from
|
|
1961
|
+
* @returns The bot's managed role in the guild
|
|
1962
|
+
* @throws A **SeedcordError** if the client user is unavailable or if the bot role is missing
|
|
1963
|
+
*/
|
|
1964
|
+
declare function getBotRole(guild: Guild): Role;
|
|
1965
|
+
//#endregion
|
|
1966
|
+
//#region src/bot/utilities/users/fetchGuildMember.d.ts
|
|
1967
|
+
/**
|
|
1968
|
+
* Fetches a guild member by user ID. Refuses when the user is not in the guild.
|
|
1969
|
+
*
|
|
1970
|
+
* @param guild - The guild to fetch the member from
|
|
1971
|
+
* @param userId - The Discord user ID
|
|
1972
|
+
* @returns Promise resolving to the guild member
|
|
1973
|
+
*/
|
|
1974
|
+
declare function fetchGuildMember(guild: Guild, userId: string): Promise<GuildMember>;
|
|
1975
|
+
//#endregion
|
|
1976
|
+
//#region src/bot/utilities/users/fetchManyGuildMembers.d.ts
|
|
1977
|
+
/**
|
|
1978
|
+
* Fetches multiple guild members by user IDs.
|
|
1979
|
+
*
|
|
1980
|
+
* @param guild - The guild to fetch members from
|
|
1981
|
+
* @param userIds - Array of Discord user IDs
|
|
1982
|
+
* @returns Promise resolving to array of successfully fetched members
|
|
1983
|
+
*/
|
|
1984
|
+
declare function fetchManyGuildMembers(guild: Guild, userIds: string[]): Promise<GuildMember[]>;
|
|
1985
|
+
//#endregion
|
|
1986
|
+
//#region src/bot/utilities/users/fetchUser.d.ts
|
|
1987
|
+
/**
|
|
1988
|
+
* Options for {@link fetchUser}.
|
|
1989
|
+
*/
|
|
1990
|
+
interface FetchUserOptions {
|
|
1991
|
+
/** Notice shown when the user does not exist, defaulting to the standard user-not-found notice. */
|
|
1992
|
+
throwAs?: new (userArg: string) => Notice;
|
|
1993
|
+
}
|
|
1994
|
+
/**
|
|
1995
|
+
* Fetches a Discord user by ID. Refuses when the user doesn't exist, with `options.throwAs` or the default.
|
|
1996
|
+
*
|
|
1997
|
+
* @param client - The Discord client instance
|
|
1998
|
+
* @param userId - The Discord user ID
|
|
1999
|
+
* @param options - Optional overrides, including the {@link FetchUserOptions.throwAs} notice
|
|
2000
|
+
* @returns Promise resolving to the user
|
|
2001
|
+
*/
|
|
2002
|
+
declare function fetchUser(client: Client, userId: string, options?: FetchUserOptions): Promise<User>;
|
|
2003
|
+
//#endregion
|
|
2004
|
+
//#region src/bot/utilities/users/fetchManyUsers.d.ts
|
|
2005
|
+
/**
|
|
2006
|
+
* Fetches multiple Discord users by IDs.
|
|
2007
|
+
*
|
|
2008
|
+
* @param client - The Discord client instance
|
|
2009
|
+
* @param userIds - Array of Discord user IDs
|
|
2010
|
+
* @param options - Optional overrides threaded to each {@link fetchUser} call
|
|
2011
|
+
* @returns Promise resolving to array of successfully fetched users
|
|
2012
|
+
*/
|
|
2013
|
+
declare function fetchManyUsers(client: Client, userIds: string[], options?: FetchUserOptions): Promise<User[]>;
|
|
2014
|
+
//#endregion
|
|
2015
|
+
//#region src/bot/utilities/users/updateMemberRoles.d.ts
|
|
2016
|
+
/**
|
|
2017
|
+
* Updates a guild member's roles by adding and removing specified roles.
|
|
2018
|
+
*
|
|
2019
|
+
* @param rolesToAdd - Array of role IDs to add to the member
|
|
2020
|
+
* @param rolesToRemove - Array of role IDs to remove from the member
|
|
2021
|
+
* @param member - The guild member to update
|
|
2022
|
+
* @returns Promise that resolves when roles are updated
|
|
2023
|
+
*/
|
|
2024
|
+
declare function updateMemberRoles(rolesToAdd: Snowflake[], rolesToRemove: Snowflake[], member: GuildMember): Promise<void>;
|
|
2025
|
+
//#endregion
|
|
2026
|
+
//#region src/bot/ReplySender.d.ts
|
|
2027
|
+
/**
|
|
2028
|
+
* Sends a {@link ReplyResponse} to an interaction, picking reply, editReply, or followUp from the live
|
|
2029
|
+
* acknowledgement state. Logs and drops its own send failures so a dead token never escapes into the
|
|
2030
|
+
* controller.
|
|
2031
|
+
*/
|
|
2032
|
+
declare class ReplySender {
|
|
2033
|
+
private readonly interaction;
|
|
2034
|
+
private readonly logger;
|
|
2035
|
+
constructor(interaction: Repliables);
|
|
2036
|
+
/**
|
|
2037
|
+
* Sends the reply and returns the sent message so a caller can attach a collector to it. Never throws,
|
|
2038
|
+
* a failed send is logged and dropped and resolves to `undefined`.
|
|
2039
|
+
*
|
|
2040
|
+
* @param response - The ComponentsV2 reply to show.
|
|
2041
|
+
* @param ephemeral - Whether the reply is ephemeral. {@default `true`}
|
|
2042
|
+
* @returns The sent {@link Message}, or `undefined` when the send was swallowed.
|
|
2043
|
+
*/
|
|
2044
|
+
send(response: ReplyResponse, ephemeral?: boolean): Promise<Message | undefined>;
|
|
2045
|
+
/**
|
|
2046
|
+
* Edits an already-sent message to a new {@link ReplyResponse}. Used to swap a confirmation prompt for
|
|
2047
|
+
* its outcome. Never throws, a failed edit is logged and dropped.
|
|
2048
|
+
*
|
|
2049
|
+
* @param message - The message to edit (the handle a prior {@link send} returned).
|
|
2050
|
+
* @param response - The reply to replace it with.
|
|
2051
|
+
*/
|
|
2052
|
+
edit(message: Message, response: ReplyResponse): Promise<void>;
|
|
2053
|
+
private dispatch;
|
|
2054
|
+
private replyOptions;
|
|
2055
|
+
private editBody;
|
|
2056
|
+
private logSwallowed;
|
|
2057
|
+
}
|
|
2058
|
+
//#endregion
|
|
2059
|
+
//#region src/bot/confirm/getConfirmation.d.ts
|
|
2060
|
+
/** A confirm outcome to show, the reply itself or a factory for it. */
|
|
2061
|
+
type Outcome = ReplyResponse | (() => Promisable<ReplyResponse>);
|
|
2062
|
+
/** Options shared by both confirmation forms. */
|
|
2063
|
+
interface ConfirmOptions {
|
|
2064
|
+
/**
|
|
2065
|
+
* Whether the prompt is ephemeral. Only the invoking user can act on it either way, a non-invoker's
|
|
2066
|
+
* click is ignored.
|
|
2067
|
+
*
|
|
2068
|
+
* @defaultValue `true`
|
|
2069
|
+
*/
|
|
2070
|
+
ephemeral?: boolean;
|
|
2071
|
+
/**
|
|
2072
|
+
* Milliseconds to wait for a click before the prompt is settled and the result resolves to `false`.
|
|
2073
|
+
*
|
|
2074
|
+
* @defaultValue `30_000`
|
|
2075
|
+
*/
|
|
2076
|
+
timeoutMs?: number;
|
|
2077
|
+
/** Shown in place of the prompt when the user confirms. Absent removes the prompt. */
|
|
2078
|
+
onConfirm?: Outcome;
|
|
2079
|
+
/** Shown in place of the prompt when the user cancels. Absent removes the prompt. */
|
|
2080
|
+
onCancel?: Outcome;
|
|
2081
|
+
/** Shown in place of the prompt when the prompt times out. Absent removes the prompt. */
|
|
2082
|
+
onTimeout?: Outcome;
|
|
2083
|
+
}
|
|
2084
|
+
/** Options for the string-prompt form, adding the built-in Confirm/Cancel buttons' labels and style. */
|
|
2085
|
+
interface DefaultConfirmOptions extends ConfirmOptions {
|
|
2086
|
+
/**
|
|
2087
|
+
* Confirm-button label.
|
|
2088
|
+
*
|
|
2089
|
+
* @defaultValue `'Confirm'`
|
|
2090
|
+
*/
|
|
2091
|
+
confirmLabel?: string;
|
|
2092
|
+
/**
|
|
2093
|
+
* Cancel-button label.
|
|
2094
|
+
*
|
|
2095
|
+
* @defaultValue `'Cancel'`
|
|
2096
|
+
*/
|
|
2097
|
+
cancelLabel?: string;
|
|
2098
|
+
/**
|
|
2099
|
+
* Confirm-button style.
|
|
2100
|
+
*
|
|
2101
|
+
* @defaultValue {@link ButtonStyle.Danger}
|
|
2102
|
+
*/
|
|
2103
|
+
confirmStyle?: ButtonStyle;
|
|
2104
|
+
}
|
|
2105
|
+
/**
|
|
2106
|
+
* Shows a confirm/cancel prompt with built-in Confirm and Cancel buttons and resolves to `true` only if the
|
|
2107
|
+
* invoking user clicks confirm. A cancel click or a timeout resolves to `false`. Gate the action behind it
|
|
2108
|
+
* with an early return. Never throws, a swallowed send resolves to `false`. Not usable from a
|
|
2109
|
+
* {@link ModalHandler}, the `interaction` parameter excludes a modal submit at compile time.
|
|
2110
|
+
*
|
|
2111
|
+
* @param interaction - The repliable interaction to prompt on, `this.event` inside a non-modal handler.
|
|
2112
|
+
* @param prompt - The message shown above the Confirm and Cancel buttons.
|
|
2113
|
+
* @param options - Ephemeral flag, timeout, the built-in buttons' labels and style, and the optional
|
|
2114
|
+
* `onConfirm`/`onCancel`/`onTimeout` outcome replies that edit the prompt in place.
|
|
2115
|
+
* @returns `true` if confirmed, `false` on cancel or timeout.
|
|
2116
|
+
*
|
|
2117
|
+
* @example
|
|
2118
|
+
* ```ts
|
|
2119
|
+
* import { getConfirmation } from '@seedcord/gateway';
|
|
2120
|
+
*
|
|
2121
|
+
* \@SlashRoute('ban')
|
|
2122
|
+
* class BanHandler extends SlashHandler<'ban'> {
|
|
2123
|
+
* async execute() {
|
|
2124
|
+
* const target = this.options.getUser('target', true);
|
|
2125
|
+
* if (!(await getConfirmation(this.event, `Ban ${target.tag}? This cannot be undone.`))) return;
|
|
2126
|
+
* await this.event.guild?.members.ban(target.id);
|
|
2127
|
+
* }
|
|
2128
|
+
* }
|
|
2129
|
+
* ```
|
|
2130
|
+
*/
|
|
2131
|
+
declare function getConfirmation(interaction: NonModalInteraction, prompt: string, options?: DefaultConfirmOptions): Promise<boolean>;
|
|
2132
|
+
/**
|
|
2133
|
+
* Shows a confirm/cancel prompt you build yourself and resolves to `true` only if the invoking user clicks
|
|
2134
|
+
* confirm. The factory receives the two minted button ids, set them on your own buttons. A cancel click or a
|
|
2135
|
+
* timeout resolves to `false`. Never throws. Not usable from a {@link ModalHandler}.
|
|
2136
|
+
*
|
|
2137
|
+
* @param interaction - The repliable interaction to prompt on, `this.event` inside a non-modal handler.
|
|
2138
|
+
* @param prompt - A factory given the minted `{ confirm, cancel }` ids that returns the reply to show. Build
|
|
2139
|
+
* it with the kit `BuilderComponent`/`RowComponent` wrappers, not raw discord.js builders.
|
|
2140
|
+
* @param options - Ephemeral flag, timeout, and the optional `onConfirm`/`onCancel`/`onTimeout` outcome
|
|
2141
|
+
* replies that edit the prompt in place.
|
|
2142
|
+
* @returns `true` if confirmed, `false` on cancel or timeout.
|
|
2143
|
+
*
|
|
2144
|
+
* @remarks
|
|
2145
|
+
* The prompt is collected in-process, so it does not survive a bot restart. Without an outcome hook, deliver
|
|
2146
|
+
* a result after confirming with a fresh `interaction.followUp(...)`, the prompt is already gone.
|
|
2147
|
+
*
|
|
2148
|
+
* @example
|
|
2149
|
+
* ```ts
|
|
2150
|
+
* import { ButtonBuilder, TextDisplayBuilder } from '@discordjs/builders';
|
|
2151
|
+
* import { ButtonStyle } from 'discord.js';
|
|
2152
|
+
* import { BuilderComponent, RowComponent, getConfirmation } from '@seedcord/gateway';
|
|
2153
|
+
*
|
|
2154
|
+
* class BanPrompt extends BuilderComponent<'container'> {
|
|
2155
|
+
* constructor(text: string) {
|
|
2156
|
+
* super('container');
|
|
2157
|
+
* this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(text));
|
|
2158
|
+
* }
|
|
2159
|
+
* }
|
|
2160
|
+
*
|
|
2161
|
+
* class ConfirmRow extends RowComponent<'button'> {
|
|
2162
|
+
* constructor(ids: { confirm: string; cancel: string }) {
|
|
2163
|
+
* super('button');
|
|
2164
|
+
* const buttons = [
|
|
2165
|
+
* [ids.confirm, 'Ban', ButtonStyle.Danger],
|
|
2166
|
+
* [ids.cancel, 'Cancel', ButtonStyle.Secondary]
|
|
2167
|
+
* ] as const;
|
|
2168
|
+
* this.instance.addComponents(
|
|
2169
|
+
* ...buttons.map(([id, label, style]) => new ButtonBuilder().setCustomId(id).setLabel(label).setStyle(style))
|
|
2170
|
+
* );
|
|
2171
|
+
* }
|
|
2172
|
+
* }
|
|
2173
|
+
*
|
|
2174
|
+
* const target = this.options.getUser('target', true);
|
|
2175
|
+
* const confirmed = await getConfirmation(
|
|
2176
|
+
* this.event,
|
|
2177
|
+
* (ids) => ({ components: [new BanPrompt(`Ban ${target.tag}?`).component, new ConfirmRow(ids).component] }),
|
|
2178
|
+
* { onConfirm: { components: [new BanPrompt(`Banned ${target.tag}.`).component] } }
|
|
2179
|
+
* );
|
|
2180
|
+
* if (!confirmed) return;
|
|
2181
|
+
* ```
|
|
2182
|
+
*/
|
|
2183
|
+
declare function getConfirmation(interaction: NonModalInteraction, prompt: (ids: {
|
|
2184
|
+
confirm: string;
|
|
2185
|
+
cancel: string;
|
|
2186
|
+
}) => Promisable<ReplyResponse>, options?: ConfirmOptions): Promise<boolean>;
|
|
2187
|
+
//#endregion
|
|
2188
|
+
//#region src/pagination/PageContext.d.ts
|
|
2189
|
+
/**
|
|
2190
|
+
* The context passed to a source loader. In a DM `guild` is `null` and `user` is still present.
|
|
2191
|
+
*/
|
|
2192
|
+
interface PageContext {
|
|
2193
|
+
/** The interaction that triggered this load (a command or a nav click). */
|
|
2194
|
+
interaction: Repliables;
|
|
2195
|
+
/** The acting user, always present. */
|
|
2196
|
+
user: User;
|
|
2197
|
+
/** The guild, or `null` in a DM. */
|
|
2198
|
+
guild: Guild | null;
|
|
2199
|
+
/** The framework core, passed only when a source requires framework services. */
|
|
2200
|
+
core?: Core;
|
|
2201
|
+
}
|
|
2202
|
+
//#endregion
|
|
2203
|
+
//#region src/pagination/controls.d.ts
|
|
2204
|
+
/** The five built-in nav controls. */
|
|
2205
|
+
type ControlKey = 'first' | 'prev' | 'indicator' | 'next' | 'last';
|
|
2206
|
+
type CustomIdStyle = ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success | ButtonStyle.Danger;
|
|
2207
|
+
/** Cosmetic overrides for a control button. `style` excludes Link and Premium, which would un-route it. */
|
|
2208
|
+
interface ControlCosmetics {
|
|
2209
|
+
label?: string;
|
|
2210
|
+
style?: CustomIdStyle;
|
|
2211
|
+
emoji?: APIMessageComponentEmoji;
|
|
2212
|
+
}
|
|
2213
|
+
/** The controls passed to `render`. Each accessor returns a fresh builder stamped with its target page. */
|
|
2214
|
+
interface PaginatorControls {
|
|
2215
|
+
/**
|
|
2216
|
+
* A fresh `ButtonBuilder` for one control, already stamped with its target page and disabled-at-bounds
|
|
2217
|
+
* state. Call only cosmetic setters on it, a `setCustomId` or `setStyle(Link)` un-routes it.
|
|
2218
|
+
*/
|
|
2219
|
+
button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder;
|
|
2220
|
+
/**
|
|
2221
|
+
* Assemble an action row of the chosen controls, in order. Throws on an empty set, more than five
|
|
2222
|
+
* controls, or a duplicate.
|
|
2223
|
+
*/
|
|
2224
|
+
row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder>;
|
|
2225
|
+
}
|
|
2226
|
+
//#endregion
|
|
2227
|
+
//#region src/pagination/render.d.ts
|
|
2228
|
+
/** What `renderItem` returns for one item, a text line or a section. */
|
|
2229
|
+
type ItemRender<Item> = (item: Item, index: number) => string | BuilderComponent<'section'>;
|
|
2230
|
+
/** What the V2 reply can be built from. Each arm is normalized into a {@link ReplyResponse}. */
|
|
2231
|
+
type Renderable = string | V2Component[] | ReplyResponse;
|
|
2232
|
+
/** A full-page render override, handed the page data and the controls factory. */
|
|
2233
|
+
type PageRender<Item> = (view: PageView<Item>, controls: PaginatorControls) => Renderable;
|
|
2234
|
+
//#endregion
|
|
2235
|
+
//#region src/pagination/sources.d.ts
|
|
2236
|
+
/**
|
|
2237
|
+
* The one method a paginator calls on a source, once per click. Implement it to supply a custom source.
|
|
2238
|
+
*
|
|
2239
|
+
* @typeParam Item - The item type the source pages over.
|
|
2240
|
+
*/
|
|
2241
|
+
interface PageSource<Item> {
|
|
2242
|
+
page(ctx: PageContext, n: number): Promise<PageView<Item>>;
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* A source for a bounded list you can load whole. It loads the full list on every click, then slices the
|
|
2246
|
+
* page via {@link paginate}, so the real total is known (a real last button, "Page X of Y"). Cache inside
|
|
2247
|
+
* your loader if the load is expensive.
|
|
2248
|
+
*
|
|
2249
|
+
* @typeParam Item - The item type, inferred from the loader's return.
|
|
2250
|
+
*/
|
|
2251
|
+
declare class ArraySource<Item> implements PageSource<Item> {
|
|
2252
|
+
private readonly load;
|
|
2253
|
+
private readonly perPage;
|
|
2254
|
+
constructor(load: (ctx: PageContext) => Promisable<readonly Item[]>, opts?: {
|
|
2255
|
+
perPage?: number;
|
|
2256
|
+
});
|
|
2257
|
+
page(ctx: PageContext, n: number): Promise<PageView<Item>>;
|
|
2258
|
+
}
|
|
2259
|
+
/**
|
|
2260
|
+
* A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).
|
|
2261
|
+
* The fetcher receives the page index and the page size and reports whether a next page exists. A cursor
|
|
2262
|
+
* source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator
|
|
2263
|
+
* reads "Page X".
|
|
2264
|
+
*
|
|
2265
|
+
* @typeParam Item - The item type, inferred from the fetcher's slice.
|
|
2266
|
+
*/
|
|
2267
|
+
declare class CursorSource<Item> implements PageSource<Item> {
|
|
2268
|
+
private readonly fetch;
|
|
2269
|
+
private readonly perPage;
|
|
2270
|
+
constructor(fetch: (ctx: PageContext, page: number, perPage: number) => Promisable<{
|
|
2271
|
+
items: readonly Item[];
|
|
2272
|
+
hasNext: boolean;
|
|
2273
|
+
}>, opts?: {
|
|
2274
|
+
perPage?: number;
|
|
2275
|
+
});
|
|
2276
|
+
page(ctx: PageContext, n: number): Promise<PageView<Item>>;
|
|
2277
|
+
}
|
|
2278
|
+
//#endregion
|
|
2279
|
+
//#region src/pagination/Paginator.d.ts
|
|
2280
|
+
interface PaginatorConfig<Item, Prefix extends string> {
|
|
2281
|
+
/** The route prefix used to build the page cursor on the nav buttons. */
|
|
2282
|
+
prefix: Prefix;
|
|
2283
|
+
/** Where the page data comes from. */
|
|
2284
|
+
source: PageSource<Item>;
|
|
2285
|
+
/** Render one item, `index` is its absolute position across pages. Ignored when `render` is set. */
|
|
2286
|
+
renderItem?: ItemRender<Item>;
|
|
2287
|
+
/** Take over the whole page tree. Receives the page data and the controls factory. */
|
|
2288
|
+
render?: PageRender<Item>;
|
|
2289
|
+
/** Whether the first page is ephemeral. {@default false} */
|
|
2290
|
+
ephemeral?: boolean;
|
|
2291
|
+
}
|
|
2292
|
+
type PaginatorHandlerCtor<Prefix extends string> = new (event: ButtonInteraction<'cached'>, core: Core) => ButtonHandler<[PageCursor<Prefix>]> & {
|
|
2293
|
+
execute(): Promise<void>;
|
|
2294
|
+
};
|
|
2295
|
+
/**
|
|
2296
|
+
* A restart-proof paginator. Each nav button's customId encodes its full target page, so clicks are
|
|
2297
|
+
* idempotent and survive a restart. A persistent `@ButtonRoute` on `Handler` dispatches the clicks.
|
|
2298
|
+
*
|
|
2299
|
+
* @typeParam Item - The item type, inferred from the source.
|
|
2300
|
+
* @typeParam Prefix - The route prefix, inferred from `config.prefix`.
|
|
2301
|
+
*
|
|
2302
|
+
* @example
|
|
2303
|
+
* ```ts
|
|
2304
|
+
* export const Bans = new Paginator({
|
|
2305
|
+
* prefix: 'bans',
|
|
2306
|
+
* source: new ArraySource((ctx) => ctx.guild.bans.fetch().then((b) => [...b.values()]), { perPage: 10 }),
|
|
2307
|
+
* renderItem: (ban) => ban.user.tag
|
|
2308
|
+
* });
|
|
2309
|
+
*
|
|
2310
|
+
* \@ButtonRoute(Bans.cursor)
|
|
2311
|
+
* export class BansNav extends Bans.Handler {}
|
|
2312
|
+
* ```
|
|
2313
|
+
*/
|
|
2314
|
+
declare class Paginator<Item, const Prefix extends string> {
|
|
2315
|
+
/** The page cursor, pass it to your `@ButtonRoute`. */
|
|
2316
|
+
readonly cursor: PageCursor<Prefix>;
|
|
2317
|
+
/** The nav handler base. Extend it with an empty body and decorate it, `@ButtonRoute(p.cursor)`. */
|
|
2318
|
+
readonly Handler: PaginatorHandlerCtor<Prefix>;
|
|
2319
|
+
private readonly config;
|
|
2320
|
+
constructor(config: PaginatorConfig<Item, Prefix>);
|
|
2321
|
+
/** Render page 0 and send it, picking reply or followUp from the interaction's state. */
|
|
2322
|
+
start(interaction: Repliables, core?: Core): Promise<Message | undefined>;
|
|
2323
|
+
/** Render a page as a {@link ReplyResponse}. To post it elsewhere, add `flags: MessageFlags.IsComponentsV2`. */
|
|
2324
|
+
page(ctx: PageContext, n: number): Promise<ReplyResponse>;
|
|
2325
|
+
}
|
|
2326
|
+
//#endregion
|
|
2327
|
+
//#region src/subscribers/Subscriber.d.ts
|
|
2328
|
+
/**
|
|
2329
|
+
* Abstract base class for handling application subscribers.
|
|
2330
|
+
*
|
|
2331
|
+
* Provides type-safe access to subscribers data and the core framework instance.
|
|
2332
|
+
* Extend this class to create custom subscriber handlers.
|
|
2333
|
+
*
|
|
2334
|
+
* @typeParam KeyOfSubscribers - The specific subscriber type this handler processes
|
|
2335
|
+
*/
|
|
2336
|
+
declare abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey> {
|
|
2337
|
+
protected readonly data: AllSubscriptions[KeyOfSubscribers];
|
|
2338
|
+
protected readonly core: Core;
|
|
2339
|
+
protected readonly logger: Logger;
|
|
2340
|
+
/**
|
|
2341
|
+
* Instantiates the subscriber with event data and core.
|
|
2342
|
+
*
|
|
2343
|
+
* @param data - The subscriber event data
|
|
2344
|
+
* @param core - The core framework instance
|
|
2345
|
+
*/
|
|
2346
|
+
constructor(data: AllSubscriptions[KeyOfSubscribers], core: Core);
|
|
2347
|
+
/**
|
|
2348
|
+
* Executes the subscriber handler logic.
|
|
2349
|
+
*/
|
|
2350
|
+
abstract execute(): Promise<void>;
|
|
2351
|
+
}
|
|
2352
|
+
//#endregion
|
|
2353
|
+
//#region src/subscribers/decorators/Subscribe.d.ts
|
|
2354
|
+
/**
|
|
2355
|
+
* Options accepted by the `@Subscribe` decorator.
|
|
2356
|
+
*/
|
|
2357
|
+
interface SubscribeOptions {
|
|
2358
|
+
/**
|
|
2359
|
+
* Frequency: `'once'` or `'on'`.
|
|
2360
|
+
*
|
|
2361
|
+
* @defaultValue `'on'`
|
|
2362
|
+
*/
|
|
2363
|
+
readonly frequency?: EventFrequency | undefined;
|
|
2364
|
+
}
|
|
2365
|
+
/**
|
|
2366
|
+
* Registers a subscriber handler class with a specific subscriber event.
|
|
2367
|
+
*
|
|
2368
|
+
* Associates the decorated class with a subscriber event type for automatic
|
|
2369
|
+
* registration and execution when the subscriber is emitted.
|
|
2370
|
+
*
|
|
2371
|
+
* @typeParam TSubscriber - The subscriber event name to register for
|
|
2372
|
+
* @param subscriber - The subscriber event name to register for
|
|
2373
|
+
* @param options - Options to configure the subscriber handler registration.
|
|
2374
|
+
* @decorator
|
|
2375
|
+
* @example
|
|
2376
|
+
* ```typescript
|
|
2377
|
+
* \@Subscribe('userJoin')
|
|
2378
|
+
* class WelcomeHandler extends Subscriber<'userJoin'> {
|
|
2379
|
+
* async execute() {
|
|
2380
|
+
* // Handle user join event
|
|
2381
|
+
* }
|
|
2382
|
+
* }
|
|
2383
|
+
* ```
|
|
2384
|
+
* @example
|
|
2385
|
+
* ```ts
|
|
2386
|
+
* \@Subscribe('userJoin', { frequency: 'once' })
|
|
2387
|
+
* // or
|
|
2388
|
+
* \@Subscribe('userJoin')
|
|
2389
|
+
* ```
|
|
2390
|
+
*/
|
|
2391
|
+
declare function Subscribe<TSubscriber extends SubscriptionKey>(subscriber: TSubscriber, options?: SubscribeOptions): <HandlerCtor extends Constructor<Subscriber<TSubscriber>>>(constructor: HandlerCtor) => void;
|
|
2392
|
+
//#endregion
|
|
2393
|
+
//#region src/subscribers/bases/WebhookLog.d.ts
|
|
2394
|
+
/**
|
|
2395
|
+
* Abstract webhook logging handler for subscriber events.
|
|
2396
|
+
*
|
|
2397
|
+
* Extends Subscriber to provide webhook-based logging capabilities.
|
|
2398
|
+
* Implementations must define the webhook client to send messages to by implementing the webhook property.
|
|
2399
|
+
*
|
|
2400
|
+
* @typeParam KeyOfSubscribers - The specific subscriber type this handler processes
|
|
2401
|
+
*/
|
|
2402
|
+
declare abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey> extends Subscriber<KeyOfSubscribers> {
|
|
2403
|
+
/** The Discord webhook client for sending log messages */
|
|
2404
|
+
abstract webhook: WebhookClient;
|
|
2405
|
+
constructor(data: AllSubscriptions[KeyOfSubscribers], core: Core);
|
|
2406
|
+
}
|
|
2407
|
+
//#endregion
|
|
2408
|
+
//#region src/hmr/HmrModuleHandler.d.ts
|
|
2409
|
+
/**
|
|
2410
|
+
* Options for configuring the HmrModuleHandler.
|
|
2411
|
+
*
|
|
2412
|
+
* This is only useful during development.
|
|
2413
|
+
*/
|
|
2414
|
+
interface HmrModuleHandlerOptions<THandler, TMiddleware = void, TArtifacts = unknown> {
|
|
2415
|
+
/** Directory containing handler modules. */
|
|
2416
|
+
handlersDir: string;
|
|
2417
|
+
/** Directory containing middleware modules. Optional because not all setups use middleware. */
|
|
2418
|
+
middlewaresDir?: string;
|
|
2419
|
+
/** Function to determine if a value is a handler module of type THandler. */
|
|
2420
|
+
isHandler: (val: unknown) => val is THandler;
|
|
2421
|
+
/** Function to determine if a value is a middleware module of type TMiddleware. Optional because not all setups use middleware. */
|
|
2422
|
+
isMiddleware?: (val: unknown) => val is TMiddleware;
|
|
2423
|
+
/** Function to register a handler module. */
|
|
2424
|
+
registerHandler: (handler: THandler, file: string) => void;
|
|
2425
|
+
/** Function to register a middleware module. Optional because not all setups use middleware. */
|
|
2426
|
+
registerMiddleware?: (middleware: TMiddleware, file: string) => void;
|
|
2427
|
+
/** Function to unregister a handler module. */
|
|
2428
|
+
unregisterHandler: (handler: THandler, artifacts?: TArtifacts) => void;
|
|
2429
|
+
/** Function to unregister a middleware module. Optional because not all setups use middleware. */
|
|
2430
|
+
unregisterMiddleware?: (middleware: TMiddleware) => void;
|
|
2431
|
+
/** Function to extract artifacts from a handler to be stored across hmr cache invalidations. */
|
|
2432
|
+
getArtifacts?: (handler: THandler) => TArtifacts;
|
|
2433
|
+
/** Logger instance for logging HMR activities.*/
|
|
2434
|
+
logger: Logger;
|
|
2435
|
+
}
|
|
2436
|
+
/**
|
|
2437
|
+
* Reloads THandler and optional TMiddleware modules on HMR updates.
|
|
2438
|
+
*
|
|
2439
|
+
* You can either implement a custom `onHmr()` method in your class by extending `HmrAware`, or if it's a plugin, override the existing `onHmr()` with fully custom logic. Or, use this class's `handle()` method inside your `onHmr()` to get standard HMR handling for your modules based on the provided options you give to the constructor.
|
|
2440
|
+
*
|
|
2441
|
+
* This is only useful during development.
|
|
2442
|
+
*/
|
|
2443
|
+
declare class HmrModuleHandler<THandler, TMiddleware = void, TArtifacts = unknown> {
|
|
2444
|
+
private readonly store;
|
|
2445
|
+
private readonly options;
|
|
2446
|
+
constructor(options: HmrModuleHandlerOptions<THandler, TMiddleware, TArtifacts>);
|
|
2447
|
+
/**
|
|
2448
|
+
* Handles an HMR update event by reloading affected modules based on the event details and config. It receives an {@link HmrUpdateEvent}, then checks the type of update.
|
|
2449
|
+
*
|
|
2450
|
+
* - If it's a deletion, it unloads the module.
|
|
2451
|
+
* - If it's an update/creation, it checks if the file is tracked, unloads it if so, then reloads the file if it is in the handlers or middlewares directory and is a valid handler/middleware.
|
|
2452
|
+
*/
|
|
2453
|
+
handle(event: HmrUpdateEvent): Promise<void>;
|
|
2454
|
+
private reloadWithRollback;
|
|
2455
|
+
/**
|
|
2456
|
+
* Tracks a handler module as being loaded from a specific file.
|
|
2457
|
+
* @param file - The file path the handler was loaded from.
|
|
2458
|
+
* @param handler - The handler module instance.
|
|
2459
|
+
*/
|
|
2460
|
+
trackHandler(file: string, handler: THandler): void;
|
|
2461
|
+
/**
|
|
2462
|
+
* Tracks a middleware module as being loaded from a specific file.
|
|
2463
|
+
* @param file - The file path the middleware was loaded from.
|
|
2464
|
+
* @param middleware - The middleware module instance.
|
|
2465
|
+
*/
|
|
2466
|
+
trackMiddleware(file: string, middleware: TMiddleware): void;
|
|
2467
|
+
private isTracked;
|
|
2468
|
+
private unload;
|
|
2469
|
+
private reloadFile;
|
|
2470
|
+
private snapshotUnits;
|
|
2471
|
+
private restoreUnits;
|
|
2472
|
+
}
|
|
2473
|
+
//#endregion
|
|
2474
|
+
//#region src/Seedcord.d.ts
|
|
2475
|
+
/**
|
|
2476
|
+
* Main Seedcord bot framework class
|
|
2477
|
+
*
|
|
2478
|
+
* Primary entry point for creating Discord bots with Seedcord.
|
|
2479
|
+
* Manages component lifecycle and provides plugin support.
|
|
2480
|
+
*/
|
|
2481
|
+
declare class Seedcord extends Pluggable implements Core {
|
|
2482
|
+
readonly config: GatewayConfig;
|
|
2483
|
+
/** @internal */
|
|
2484
|
+
readonly [SeedcordBrand] = true;
|
|
2485
|
+
/** @internal */
|
|
2486
|
+
readonly augmentTarget = "@seedcord/gateway";
|
|
2487
|
+
/** @internal */
|
|
2488
|
+
readonly version: string;
|
|
2489
|
+
private static isInstantiated;
|
|
2490
|
+
/** @see {@link CoordinatedShutdown} */
|
|
2491
|
+
readonly shutdown: CoordinatedShutdown;
|
|
2492
|
+
/** @see {@link CoordinatedStartup} */
|
|
2493
|
+
readonly startup: CoordinatedStartup;
|
|
2494
|
+
/** @see {@link Bus} */
|
|
2495
|
+
readonly bus: Bus;
|
|
2496
|
+
/** @see {@link Bot} */
|
|
2497
|
+
readonly bot: Bot;
|
|
2498
|
+
/** @see {@link IRateLimiter} */
|
|
2499
|
+
readonly rateLimiter: IRateLimiter;
|
|
2500
|
+
/** @see {@link HealthCheck} */
|
|
2501
|
+
private readonly healthCheck;
|
|
2502
|
+
/** @see {@link HmrManager} */
|
|
2503
|
+
private readonly hmrManager;
|
|
2504
|
+
/**
|
|
2505
|
+
* Creates a new Seedcord instance
|
|
2506
|
+
*
|
|
2507
|
+
* @param config - Bot configuration including paths and Discord client options
|
|
2508
|
+
* @throws A **SeedcordError** When attempting to create multiple instances (singleton)
|
|
2509
|
+
*/
|
|
2510
|
+
constructor(config: GatewayConfig);
|
|
2511
|
+
/** @internal */
|
|
2512
|
+
private static reset;
|
|
2513
|
+
/**
|
|
2514
|
+
* Registers default startup tasks
|
|
2515
|
+
* @internal
|
|
2516
|
+
*/
|
|
2517
|
+
private registerStartupTasks;
|
|
2518
|
+
/**
|
|
2519
|
+
* Starts the bot and runs all initialization tasks
|
|
2520
|
+
*
|
|
2521
|
+
* @returns This Seedcord instance when fully initialized
|
|
2522
|
+
*/
|
|
2523
|
+
start(): Promise<this>;
|
|
2524
|
+
private registerHmrAwareModules;
|
|
2525
|
+
}
|
|
2526
|
+
//#endregion
|
|
2527
|
+
//#region src/version.d.ts
|
|
2
2528
|
/** Package version */
|
|
3
2529
|
declare const version: string;
|
|
4
2530
|
//#endregion
|
|
5
|
-
export { version };
|
|
2531
|
+
export { type AllSubscriptions, ArraySource, AssignRoleErrorCtors, AutocompleteHandler, type AutocompleteOptions, AutocompleteRoute, type BotEvents, type BotPermissionScope, ButtonHandler, ButtonRoute, type CheckPermissionOptions, CommandMentions, type ConfirmOptions, ContextMenuHandler, ContextMenuRoute, 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, HmrModuleHandler, IgnoreBots, type Initializeable, type InjectedEmojiMap, type InjectedMentionMap, type InteractionGateContext, InteractionHandler, InteractionMiddleware, Middleware, type MiddlewareOptions, MiddlewareType, ModalHandler, ModalRoute, Nsfw, Paginator, type PaginatorControls, type PermissionErrorCtors, Pluggable, Plugin, type PluginArgs, type PluginCtor, RegisterCommand, RegisterEvent, type RegisterEventOptions, type Repliables, ReplySender, RequireBotPermissions, RequirePermissions, type RequirePermissionsOptions, RequireRole, type RequireRoleOptions, Seedcord, SelectMenuHandler, SelectMenuKind, SelectMenuRoute, SlashHandler, type SlashOptions, SlashRoute, Subscribe, type SubscribeOptions, Subscriber, type SubscriptionData, type SubscriptionKey, type Subscriptions, type ValidEventTypes, type ValidInteractionTypes, type ValidNonInteractionKeys, WebhookLog, checkBotPermissions, checkPermissions, fetchGuildMember, fetchManyGuildMembers, fetchManyUsers, fetchRole, fetchText, fetchUser, getBotRole, getConfirmation, hasPermsToAssign, updateMemberRoles, version };
|
|
6
2532
|
//# sourceMappingURL=index.d.mts.map
|