spearkit 0.1.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/LICENSE +92 -0
- package/README.md +228 -0
- package/dist/index.cjs +1242 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +849 -0
- package/dist/index.d.ts +849 -0
- package/dist/index.js +1190 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
import * as discord_js from 'discord.js';
|
|
2
|
+
import { RepliableInteraction, InteractionReplyOptions, InteractionResponse, Message, AutocompleteInteraction, ChatInputCommandInteraction, JSONEncodable, APIModalInteractionResponseCallbackData, ModalComponentData, ModalBuilder, APIApplicationCommandChannelOption, CommandInteractionOption, Attachment, ApplicationCommandOptionType, LocalizationMap, Awaitable, APIApplicationCommandBasicOption, PermissionResolvable, RESTPostAPIChatInputApplicationCommandsJSONBody, RESTPostAPIApplicationCommandsJSONBody, REST, RESTPutAPIApplicationCommandsResult, RESTPutAPIApplicationGuildCommandsResult, ClientEvents, Client, ButtonInteraction, StringSelectMenuInteraction, UserSelectMenuInteraction, RoleSelectMenuInteraction, ChannelSelectMenuInteraction, MentionableSelectMenuInteraction, InteractionUpdateOptions, ModalSubmitInteraction, Interaction, ButtonBuilder, ButtonStyle, ComponentEmojiResolvable, ChannelSelectMenuBuilder, MentionableSelectMenuBuilder, TextInputStyle, RoleSelectMenuBuilder, StringSelectMenuBuilder, SelectMenuComponentOptionData, UserSelectMenuBuilder, ChannelType, MessageActionRowComponentBuilder, ActionRowBuilder, GatewayIntentBits, ClientOptions } from 'discord.js';
|
|
3
|
+
export * from 'discord.js';
|
|
4
|
+
|
|
5
|
+
/** Reply options with an ergonomic `ephemeral` shortcut (mapped to flags). */
|
|
6
|
+
type ReplyData = InteractionReplyOptions & {
|
|
7
|
+
ephemeral?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/** Either a plain string or full reply options. */
|
|
10
|
+
type ReplyInput = string | ReplyData;
|
|
11
|
+
/** Normalises spearkit reply input into a discord.js reply payload. */
|
|
12
|
+
declare function normalizeReply(input: ReplyInput): InteractionReplyOptions;
|
|
13
|
+
/** Marks an input as ephemeral, regardless of how it was passed. */
|
|
14
|
+
declare function asEphemeral(input: ReplyInput): ReplyData;
|
|
15
|
+
/**
|
|
16
|
+
* Ergonomic base wrapper shared by every interaction context (commands,
|
|
17
|
+
* buttons, selects, modals). Exposes the common actor/location accessors plus
|
|
18
|
+
* reply helpers that smooth over discord.js' state machine.
|
|
19
|
+
*/
|
|
20
|
+
declare abstract class BaseContext<I extends RepliableInteraction = RepliableInteraction> {
|
|
21
|
+
readonly interaction: I;
|
|
22
|
+
constructor(interaction: I);
|
|
23
|
+
get client(): I["client"];
|
|
24
|
+
get user(): discord_js.User;
|
|
25
|
+
get member(): discord_js.GuildMember | discord_js.APIInteractionGuildMember | null;
|
|
26
|
+
get guild(): discord_js.Guild | null;
|
|
27
|
+
get guildId(): string | null;
|
|
28
|
+
get channel(): discord_js.TextBasedChannel | null;
|
|
29
|
+
get channelId(): string | null;
|
|
30
|
+
get locale(): discord_js.Locale;
|
|
31
|
+
/** Whether the interaction is already deferred. */
|
|
32
|
+
get deferred(): boolean;
|
|
33
|
+
/** Whether the interaction already received an initial response. */
|
|
34
|
+
get replied(): boolean;
|
|
35
|
+
/** Send the initial response to the interaction. */
|
|
36
|
+
reply(input: ReplyInput): Promise<InteractionResponse<boolean>>;
|
|
37
|
+
/** Reply, but always hidden to everyone except the invoking user. */
|
|
38
|
+
replyEphemeral(input: ReplyInput): Promise<InteractionResponse<boolean>>;
|
|
39
|
+
/** Acknowledge now and respond later via {@link editReply}. */
|
|
40
|
+
defer(options?: {
|
|
41
|
+
ephemeral?: boolean;
|
|
42
|
+
}): Promise<InteractionResponse<boolean>>;
|
|
43
|
+
/** Edit the original (or deferred) response. */
|
|
44
|
+
editReply(input: ReplyInput): Promise<Message>;
|
|
45
|
+
/** Add an additional message after the initial response. */
|
|
46
|
+
followUp(input: ReplyInput): Promise<Message>;
|
|
47
|
+
/**
|
|
48
|
+
* State-aware send: replies, edits a deferred response, or follows up —
|
|
49
|
+
* whichever is valid given the current interaction state. The single method
|
|
50
|
+
* most handlers ever need.
|
|
51
|
+
*/
|
|
52
|
+
send(input: ReplyInput): Promise<void>;
|
|
53
|
+
/** State-aware ephemeral error message. */
|
|
54
|
+
error(message: string): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The handler argument for a slash command. Wraps the discord.js interaction
|
|
59
|
+
* and exposes the resolved, fully-typed {@link options}.
|
|
60
|
+
*/
|
|
61
|
+
declare class CommandContext<O extends OptionMap = OptionMap> extends BaseContext<ChatInputCommandInteraction> {
|
|
62
|
+
/** Resolved option values, typed from the command's `options` map. */
|
|
63
|
+
readonly options: ResolvedOptions<O>;
|
|
64
|
+
constructor(interaction: ChatInputCommandInteraction,
|
|
65
|
+
/** Resolved option values, typed from the command's `options` map. */
|
|
66
|
+
options: ResolvedOptions<O>);
|
|
67
|
+
get commandName(): string;
|
|
68
|
+
/** The invoked subcommand name, if any. */
|
|
69
|
+
get subcommand(): string | null;
|
|
70
|
+
/** Present a modal to the user in response to this command. */
|
|
71
|
+
showModal(modal: JSONEncodable<APIModalInteractionResponseCallbackData> | ModalComponentData | ModalBuilder): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The handler argument for autocomplete requests. Provides the focused value
|
|
75
|
+
* and a typed {@link respond} helper.
|
|
76
|
+
*/
|
|
77
|
+
declare class AutocompleteContext {
|
|
78
|
+
readonly interaction: AutocompleteInteraction;
|
|
79
|
+
constructor(interaction: AutocompleteInteraction);
|
|
80
|
+
get client(): discord_js.Client<true>;
|
|
81
|
+
get user(): discord_js.User;
|
|
82
|
+
get guild(): discord_js.Guild | null;
|
|
83
|
+
get guildId(): string | null;
|
|
84
|
+
get commandName(): string;
|
|
85
|
+
/** Name of the option currently being completed. */
|
|
86
|
+
get focusedName(): string;
|
|
87
|
+
/** Current partial value typed by the user. */
|
|
88
|
+
get value(): string;
|
|
89
|
+
/** Send autocomplete suggestions (capped at the discord limit of 25). */
|
|
90
|
+
respond(choices: OptionChoice<string | number>[]): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Resolved runtime value types, derived directly from discord.js' option
|
|
95
|
+
* resolver so spearkit stays exactly in lockstep with the underlying getters.
|
|
96
|
+
*/
|
|
97
|
+
type Opt = CommandInteractionOption;
|
|
98
|
+
type UserValue = NonNullable<Opt["user"]>;
|
|
99
|
+
type ChannelValue = NonNullable<Opt["channel"]>;
|
|
100
|
+
type RoleValue = NonNullable<Opt["role"]>;
|
|
101
|
+
type MentionableValue = NonNullable<Opt["user" | "role" | "member"]>;
|
|
102
|
+
type AttachmentValue = Attachment;
|
|
103
|
+
/** The discord-allowed channel types for a channel option. */
|
|
104
|
+
type AllowedChannelType = NonNullable<APIApplicationCommandChannelOption["channel_types"]>[number];
|
|
105
|
+
/** The reader surface spearkit needs off a chat-input interaction. */
|
|
106
|
+
type OptionReader = ChatInputCommandInteraction["options"];
|
|
107
|
+
/** The closed set of values a slash option can resolve to. */
|
|
108
|
+
type OptionValue = string | number | boolean | UserValue | ChannelValue | RoleValue | MentionableValue | AttachmentValue;
|
|
109
|
+
/** A single choice for string/integer/number options. */
|
|
110
|
+
interface OptionChoice<V extends string | number = string | number> {
|
|
111
|
+
readonly name: string;
|
|
112
|
+
readonly value: V;
|
|
113
|
+
readonly nameLocalizations?: LocalizationMap;
|
|
114
|
+
}
|
|
115
|
+
/** Provides autocomplete suggestions for an option as the user types. */
|
|
116
|
+
type AutocompleteHandler<V extends string | number = string | number> = (ctx: AutocompleteContext) => Awaitable<OptionChoice<V>[]>;
|
|
117
|
+
/**
|
|
118
|
+
* A fully-described slash command option. The two type parameters are phantom
|
|
119
|
+
* markers used purely for compile-time inference of the resolved value:
|
|
120
|
+
* - `TValue` is the type produced for the command handler.
|
|
121
|
+
* - `TRequired` controls nullability (`true` => value, `false` => `| undefined`).
|
|
122
|
+
*/
|
|
123
|
+
interface OptionDef<TValue extends OptionValue, TRequired extends boolean> {
|
|
124
|
+
readonly type: ApplicationCommandOptionType;
|
|
125
|
+
readonly description: string;
|
|
126
|
+
readonly required: TRequired;
|
|
127
|
+
readonly choices?: readonly OptionChoice[];
|
|
128
|
+
readonly minValue?: number;
|
|
129
|
+
readonly maxValue?: number;
|
|
130
|
+
readonly minLength?: number;
|
|
131
|
+
readonly maxLength?: number;
|
|
132
|
+
readonly channelTypes?: readonly AllowedChannelType[];
|
|
133
|
+
readonly autocomplete?: AutocompleteHandler;
|
|
134
|
+
readonly nameLocalizations?: LocalizationMap;
|
|
135
|
+
readonly descriptionLocalizations?: LocalizationMap;
|
|
136
|
+
/** Phantom-only marker. Never populated at runtime. */
|
|
137
|
+
readonly __value?: TValue;
|
|
138
|
+
}
|
|
139
|
+
/** Any option definition, regardless of value/required type. */
|
|
140
|
+
type AnyOptionDef = OptionDef<OptionValue, boolean>;
|
|
141
|
+
/** A map of option name => definition. */
|
|
142
|
+
type OptionMap = Record<string, AnyOptionDef>;
|
|
143
|
+
/** Maps an {@link OptionDef} to the value passed into the command handler. */
|
|
144
|
+
type ResolvedOption<O extends AnyOptionDef> = O extends OptionDef<infer V, infer Req> ? Req extends true ? V : V | undefined : never;
|
|
145
|
+
/** Resolves a whole {@link OptionMap} into the handler's `options` object. */
|
|
146
|
+
type ResolvedOptions<O extends OptionMap> = {
|
|
147
|
+
[K in keyof O]: ResolvedOption<O[K]>;
|
|
148
|
+
};
|
|
149
|
+
interface BaseConfig {
|
|
150
|
+
readonly description: string;
|
|
151
|
+
readonly required?: boolean;
|
|
152
|
+
readonly nameLocalizations?: LocalizationMap;
|
|
153
|
+
readonly descriptionLocalizations?: LocalizationMap;
|
|
154
|
+
}
|
|
155
|
+
type IsRequired<C extends BaseConfig> = C["required"] extends true ? true : false;
|
|
156
|
+
interface StringConfig extends BaseConfig {
|
|
157
|
+
readonly choices?: readonly OptionChoice<string>[];
|
|
158
|
+
readonly minLength?: number;
|
|
159
|
+
readonly maxLength?: number;
|
|
160
|
+
readonly autocomplete?: AutocompleteHandler<string>;
|
|
161
|
+
}
|
|
162
|
+
interface NumericConfig extends BaseConfig {
|
|
163
|
+
readonly choices?: readonly OptionChoice<number>[];
|
|
164
|
+
readonly minValue?: number;
|
|
165
|
+
readonly maxValue?: number;
|
|
166
|
+
readonly autocomplete?: AutocompleteHandler<number>;
|
|
167
|
+
}
|
|
168
|
+
interface ChannelConfig extends BaseConfig {
|
|
169
|
+
readonly channelTypes?: readonly AllowedChannelType[];
|
|
170
|
+
}
|
|
171
|
+
type ChoiceValue<C, Fallback extends string | number> = C extends {
|
|
172
|
+
readonly choices: readonly {
|
|
173
|
+
value: infer V;
|
|
174
|
+
}[];
|
|
175
|
+
} ? [V] extends [string | number] ? V : Fallback : Fallback;
|
|
176
|
+
/**
|
|
177
|
+
* Type-safe slash command option builders.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* options: {
|
|
182
|
+
* target: option.user({ description: "Who to greet", required: true }),
|
|
183
|
+
* loud: option.boolean({ description: "Shout it" }),
|
|
184
|
+
* }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
declare const option: {
|
|
188
|
+
readonly string: <const C extends StringConfig>(config: C) => OptionDef<ChoiceValue<C, string>, IsRequired<C>>;
|
|
189
|
+
readonly integer: <const C extends NumericConfig>(config: C) => OptionDef<ChoiceValue<C, number>, IsRequired<C>>;
|
|
190
|
+
readonly number: <const C extends NumericConfig>(config: C) => OptionDef<ChoiceValue<C, number>, IsRequired<C>>;
|
|
191
|
+
readonly boolean: <const C extends BaseConfig>(config: C) => OptionDef<boolean, IsRequired<C>>;
|
|
192
|
+
readonly user: <const C extends BaseConfig>(config: C) => OptionDef<UserValue, IsRequired<C>>;
|
|
193
|
+
readonly channel: <const C extends ChannelConfig>(config: C) => OptionDef<ChannelValue, IsRequired<C>>;
|
|
194
|
+
readonly role: <const C extends BaseConfig>(config: C) => OptionDef<RoleValue, IsRequired<C>>;
|
|
195
|
+
readonly mentionable: <const C extends BaseConfig>(config: C) => OptionDef<MentionableValue, IsRequired<C>>;
|
|
196
|
+
readonly attachment: <const C extends BaseConfig>(config: C) => OptionDef<AttachmentValue, IsRequired<C>>;
|
|
197
|
+
};
|
|
198
|
+
/** Converts a spearkit option definition into the discord REST option payload. */
|
|
199
|
+
declare function toAPIOption(name: string, def: AnyOptionDef): APIApplicationCommandBasicOption;
|
|
200
|
+
/** Reads a resolved option value off a discord.js option resolver. */
|
|
201
|
+
declare function readOption(resolver: OptionReader, name: string, def: AnyOptionDef): OptionValue | undefined;
|
|
202
|
+
/** True if any option in the map declares an autocomplete handler. */
|
|
203
|
+
declare function optionsHaveAutocomplete(options: OptionMap): boolean;
|
|
204
|
+
|
|
205
|
+
/** Metadata shared by every kind of command. */
|
|
206
|
+
interface CommonMeta {
|
|
207
|
+
/** Permissions a member must have by default to see/use the command. */
|
|
208
|
+
defaultMemberPermissions?: PermissionResolvable | null;
|
|
209
|
+
/** Mark the command NSFW (age-restricted). */
|
|
210
|
+
nsfw?: boolean;
|
|
211
|
+
/** Restrict invocation to guilds only. */
|
|
212
|
+
guildOnly?: boolean;
|
|
213
|
+
nameLocalizations?: LocalizationMap;
|
|
214
|
+
descriptionLocalizations?: LocalizationMap;
|
|
215
|
+
}
|
|
216
|
+
/** Configuration for a leaf (non-subcommand) slash command. */
|
|
217
|
+
interface CommandConfig<O extends OptionMap, R> extends CommonMeta {
|
|
218
|
+
name: string;
|
|
219
|
+
description: string;
|
|
220
|
+
options?: O;
|
|
221
|
+
run: (ctx: CommandContext<O>) => Awaitable<R>;
|
|
222
|
+
}
|
|
223
|
+
/** Configuration for one subcommand. */
|
|
224
|
+
interface SubcommandConfig<O extends OptionMap, R> {
|
|
225
|
+
description: string;
|
|
226
|
+
options?: O;
|
|
227
|
+
nameLocalizations?: LocalizationMap;
|
|
228
|
+
descriptionLocalizations?: LocalizationMap;
|
|
229
|
+
run: (ctx: CommandContext<O>) => Awaitable<R>;
|
|
230
|
+
}
|
|
231
|
+
/** A type-erased, ready-to-run subcommand created with {@link subcommand}. */
|
|
232
|
+
interface Subcommand {
|
|
233
|
+
readonly kind: "subcommand";
|
|
234
|
+
readonly description: string;
|
|
235
|
+
readonly options: OptionMap;
|
|
236
|
+
readonly nameLocalizations?: LocalizationMap;
|
|
237
|
+
readonly descriptionLocalizations?: LocalizationMap;
|
|
238
|
+
readonly hasAutocomplete: boolean;
|
|
239
|
+
readonly execute: (interaction: ChatInputCommandInteraction) => Promise<void>;
|
|
240
|
+
readonly autocomplete: (interaction: AutocompleteInteraction) => Promise<void>;
|
|
241
|
+
}
|
|
242
|
+
/** Configuration for a subcommand group (a folder of subcommands). */
|
|
243
|
+
interface SubcommandGroupConfig {
|
|
244
|
+
description: string;
|
|
245
|
+
subcommands: Record<string, Subcommand>;
|
|
246
|
+
nameLocalizations?: LocalizationMap;
|
|
247
|
+
descriptionLocalizations?: LocalizationMap;
|
|
248
|
+
}
|
|
249
|
+
/** A subcommand group created with {@link subcommandGroup}. */
|
|
250
|
+
interface SubcommandGroup extends SubcommandGroupConfig {
|
|
251
|
+
readonly kind: "group";
|
|
252
|
+
}
|
|
253
|
+
/** Configuration for a command that contains subcommands and/or groups. */
|
|
254
|
+
interface CommandGroupConfig extends CommonMeta {
|
|
255
|
+
name: string;
|
|
256
|
+
description: string;
|
|
257
|
+
subcommands?: Record<string, Subcommand>;
|
|
258
|
+
groups?: Record<string, SubcommandGroup>;
|
|
259
|
+
}
|
|
260
|
+
/** Everything {@link SlashCommand} needs, pre-built by the factories. */
|
|
261
|
+
interface SlashCommandSpec {
|
|
262
|
+
name: string;
|
|
263
|
+
json: RESTPostAPIChatInputApplicationCommandsJSONBody;
|
|
264
|
+
hasAutocomplete: boolean;
|
|
265
|
+
executor: (interaction: ChatInputCommandInteraction) => Promise<void>;
|
|
266
|
+
autocompleter: (interaction: AutocompleteInteraction) => Promise<void>;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* A registered slash command. Serialises itself for the discord REST API and
|
|
270
|
+
* executes its matching interactions. Construct via {@link command} or
|
|
271
|
+
* {@link commandGroup} rather than directly.
|
|
272
|
+
*/
|
|
273
|
+
declare class SlashCommand {
|
|
274
|
+
/** The top-level command name (used as the registry lookup key). */
|
|
275
|
+
readonly name: string;
|
|
276
|
+
/** Whether any option declares an autocomplete handler. */
|
|
277
|
+
readonly hasAutocomplete: boolean;
|
|
278
|
+
private readonly json;
|
|
279
|
+
private readonly executor;
|
|
280
|
+
private readonly autocompleter;
|
|
281
|
+
/** @internal */
|
|
282
|
+
constructor(spec: SlashCommandSpec);
|
|
283
|
+
/** Serialise to the discord REST chat-input command payload. */
|
|
284
|
+
toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody;
|
|
285
|
+
/** Execute the command for an incoming chat-input interaction. */
|
|
286
|
+
execute(interaction: ChatInputCommandInteraction): Promise<void>;
|
|
287
|
+
/** Execute autocomplete for the focused option. */
|
|
288
|
+
autocomplete(interaction: AutocompleteInteraction): Promise<void>;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Define a slash command with type-safe options and a co-located handler.
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```ts
|
|
295
|
+
* export default command({
|
|
296
|
+
* name: "echo",
|
|
297
|
+
* description: "Repeat a message",
|
|
298
|
+
* options: { msg: option.string({ description: "Text", required: true }) },
|
|
299
|
+
* run: (ctx) => ctx.reply(ctx.options.msg),
|
|
300
|
+
* });
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
declare function command<O extends OptionMap = Record<string, never>, R = void>(config: CommandConfig<O, R>): SlashCommand;
|
|
304
|
+
/** Define a single subcommand with type-safe options and a handler. */
|
|
305
|
+
declare function subcommand<O extends OptionMap = Record<string, never>, R = void>(config: SubcommandConfig<O, R>): Subcommand;
|
|
306
|
+
/** Group several subcommands under a shared name. */
|
|
307
|
+
declare function subcommandGroup(config: SubcommandGroupConfig): SubcommandGroup;
|
|
308
|
+
/** Define a command that routes to subcommands and/or subcommand groups. */
|
|
309
|
+
declare function commandGroup(config: CommandGroupConfig): SlashCommand;
|
|
310
|
+
|
|
311
|
+
/** Error hook invoked when a command handler throws. */
|
|
312
|
+
type CommandErrorHandler = (error: Error, interaction: ChatInputCommandInteraction) => Awaitable<void>;
|
|
313
|
+
/** Options for pushing commands to discord. */
|
|
314
|
+
interface DeployOptions {
|
|
315
|
+
/** Bot token. Falls back to the client token when omitted. */
|
|
316
|
+
token?: string;
|
|
317
|
+
/** Application (client) id. */
|
|
318
|
+
applicationId: string;
|
|
319
|
+
/** Deploy to a single guild (updates instantly) instead of globally. */
|
|
320
|
+
guildId?: string;
|
|
321
|
+
/** Reuse an existing REST instance instead of creating one. */
|
|
322
|
+
rest?: REST;
|
|
323
|
+
}
|
|
324
|
+
/** Result of a {@link CommandRegistry.deploy} call. */
|
|
325
|
+
type DeployResult = RESTPutAPIApplicationCommandsResult | RESTPutAPIApplicationGuildCommandsResult;
|
|
326
|
+
/** Holds every slash command and routes interactions to them. */
|
|
327
|
+
declare class CommandRegistry {
|
|
328
|
+
private readonly commands;
|
|
329
|
+
private errorHandler?;
|
|
330
|
+
/** Register one or more commands. Later registrations override by name. */
|
|
331
|
+
add(...commands: SlashCommand[]): this;
|
|
332
|
+
/** Remove a command by name. */
|
|
333
|
+
remove(name: string): boolean;
|
|
334
|
+
/** Look up a command by name. */
|
|
335
|
+
get(name: string): SlashCommand | undefined;
|
|
336
|
+
/** All registered commands. */
|
|
337
|
+
all(): SlashCommand[];
|
|
338
|
+
/** All registered command names. */
|
|
339
|
+
get names(): string[];
|
|
340
|
+
/** Number of registered commands. */
|
|
341
|
+
get size(): number;
|
|
342
|
+
/** Set the handler used when a command throws. */
|
|
343
|
+
onError(handler: CommandErrorHandler): this;
|
|
344
|
+
/** Serialise every command to discord REST payloads. */
|
|
345
|
+
toJSON(): RESTPostAPIApplicationCommandsJSONBody[];
|
|
346
|
+
/** Dispatch an incoming chat-input interaction to its command. */
|
|
347
|
+
handle(interaction: ChatInputCommandInteraction): Promise<void>;
|
|
348
|
+
/** Dispatch an autocomplete interaction to its command. */
|
|
349
|
+
handleAutocomplete(interaction: AutocompleteInteraction): Promise<void>;
|
|
350
|
+
/**
|
|
351
|
+
* Push the registered commands to discord. Returns the API response.
|
|
352
|
+
*
|
|
353
|
+
* Guild deploys apply instantly and are ideal during development; global
|
|
354
|
+
* deploys can take up to an hour to propagate.
|
|
355
|
+
*/
|
|
356
|
+
deploy(options: DeployOptions): Promise<DeployResult>;
|
|
357
|
+
private defaultErrorReply;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** A typed handler for a discord.js client event. */
|
|
361
|
+
type EventHandler<E extends keyof ClientEvents> = (...args: ClientEvents[E]) => Awaitable<void>;
|
|
362
|
+
/** Object form accepted by {@link event}. */
|
|
363
|
+
interface EventConfig<E extends keyof ClientEvents> {
|
|
364
|
+
name: E;
|
|
365
|
+
/** Run the handler at most once, then auto-detach. */
|
|
366
|
+
once?: boolean;
|
|
367
|
+
run: EventHandler<E>;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* A type-erased, ready-to-attach event listener. Built by {@link event}; the
|
|
371
|
+
* concrete event type is captured in the closures so binding stays type-safe.
|
|
372
|
+
*/
|
|
373
|
+
interface EventDef {
|
|
374
|
+
readonly name: keyof ClientEvents;
|
|
375
|
+
readonly once: boolean;
|
|
376
|
+
/** Attach the listener to a client. */
|
|
377
|
+
attach(client: Client): void;
|
|
378
|
+
/** Remove the listener from a client it was attached to. */
|
|
379
|
+
detach(client: Client): void;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Define a discord.js event listener with a fully-typed handler. Thrown errors
|
|
383
|
+
* and rejected promises are routed to the client's `error` event instead of
|
|
384
|
+
* crashing the process.
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```ts
|
|
388
|
+
* export default event("messageCreate", (message) => {
|
|
389
|
+
* if (message.author.bot) return;
|
|
390
|
+
* // message is fully typed as Message
|
|
391
|
+
* });
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
declare function event<E extends keyof ClientEvents>(name: E, run: EventHandler<E>): EventDef;
|
|
395
|
+
declare function event<E extends keyof ClientEvents>(config: EventConfig<E>): EventDef;
|
|
396
|
+
/** Holds event listeners and attaches them to clients in bulk. */
|
|
397
|
+
declare class EventRegistry {
|
|
398
|
+
private readonly events;
|
|
399
|
+
private readonly attached;
|
|
400
|
+
/** Register one or more event definitions. */
|
|
401
|
+
add(...defs: EventDef[]): this;
|
|
402
|
+
/** Number of registered listeners. */
|
|
403
|
+
get size(): number;
|
|
404
|
+
/** Attach every registered listener to the client. */
|
|
405
|
+
attachAll(client: Client): void;
|
|
406
|
+
/** Detach every registered listener from the client. */
|
|
407
|
+
detachAll(client: Client): void;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Typed custom-id codec.
|
|
412
|
+
*
|
|
413
|
+
* Patterns follow the grammar `namespace(:{param})*`, e.g. `"vote"` or
|
|
414
|
+
* `"vote:{choice}"` or `"page:{id}:{dir}"`. The `namespace` is the routing key;
|
|
415
|
+
* each `{param}` becomes a positional, percent-escaped value in the encoded id.
|
|
416
|
+
* Param names are recovered at the type level so handlers get a typed `params`
|
|
417
|
+
* object and `build()` requires exactly the right params.
|
|
418
|
+
*/
|
|
419
|
+
/** Names of the `{param}` placeholders inside a pattern. */
|
|
420
|
+
type ParamNames<S extends string> = S extends `${string}{${infer Name}}${infer Rest}` ? Name | ParamNames<Rest> : never;
|
|
421
|
+
/** The params object a pattern resolves to (every value is a string). */
|
|
422
|
+
type Params<S extends string> = {
|
|
423
|
+
[K in ParamNames<S>]: string;
|
|
424
|
+
};
|
|
425
|
+
/** Arguments `build()` accepts: none when the pattern has no params. */
|
|
426
|
+
type BuildArgs<S extends string> = [ParamNames<S>] extends [never] ? [] : [params: Params<S>];
|
|
427
|
+
/** The discord custom-id length limit. */
|
|
428
|
+
declare const MAX_CUSTOM_ID_LENGTH = 100;
|
|
429
|
+
/** A compiled pattern: its routing namespace and ordered param names. */
|
|
430
|
+
interface CompiledPattern {
|
|
431
|
+
readonly pattern: string;
|
|
432
|
+
readonly namespace: string;
|
|
433
|
+
readonly paramNames: readonly string[];
|
|
434
|
+
}
|
|
435
|
+
/** Compile and validate a custom-id pattern. Throws on malformed input. */
|
|
436
|
+
declare function compilePattern(pattern: string): CompiledPattern;
|
|
437
|
+
/** Build a concrete custom-id from a compiled pattern and its params. */
|
|
438
|
+
declare function buildCustomId(compiled: CompiledPattern, params: Readonly<Record<string, string>>): string;
|
|
439
|
+
/** The namespace + raw values parsed out of an incoming custom-id. */
|
|
440
|
+
interface ParsedCustomId {
|
|
441
|
+
readonly namespace: string;
|
|
442
|
+
readonly values: readonly string[];
|
|
443
|
+
}
|
|
444
|
+
/** Parse an incoming custom-id into its namespace and decoded values. */
|
|
445
|
+
declare function parseCustomId(customId: string): ParsedCustomId;
|
|
446
|
+
/** Map ordered values onto their param names. */
|
|
447
|
+
declare function paramsFromValues(paramNames: readonly string[], values: readonly string[]): Record<string, string>;
|
|
448
|
+
|
|
449
|
+
type UpdateInput = string | InteractionUpdateOptions;
|
|
450
|
+
/** The concrete message-component interaction types (button + every select). */
|
|
451
|
+
type AnyComponentInteraction = ButtonInteraction | StringSelectMenuInteraction | UserSelectMenuInteraction | RoleSelectMenuInteraction | ChannelSelectMenuInteraction | MentionableSelectMenuInteraction;
|
|
452
|
+
/**
|
|
453
|
+
* Base context for message-component interactions (buttons and selects).
|
|
454
|
+
* Adds the component-only `update`/`deferUpdate`/`showModal` helpers and the
|
|
455
|
+
* routed, typed {@link params}.
|
|
456
|
+
*/
|
|
457
|
+
declare class MessageComponentContext<P, I extends AnyComponentInteraction = AnyComponentInteraction> extends BaseContext<I> {
|
|
458
|
+
/** Params extracted from the custom-id pattern. */
|
|
459
|
+
readonly params: P;
|
|
460
|
+
constructor(interaction: I,
|
|
461
|
+
/** Params extracted from the custom-id pattern. */
|
|
462
|
+
params: P);
|
|
463
|
+
/** The raw custom-id that triggered this interaction. */
|
|
464
|
+
get customId(): string;
|
|
465
|
+
/** The message the component lives on. */
|
|
466
|
+
get message(): discord_js.Message<boolean>;
|
|
467
|
+
/** Edit the message this component belongs to. */
|
|
468
|
+
update(input: UpdateInput): Promise<void>;
|
|
469
|
+
/** Acknowledge the interaction without editing the message yet. */
|
|
470
|
+
deferUpdate(): Promise<void>;
|
|
471
|
+
/** Open a modal in response to this component. */
|
|
472
|
+
showModal(modal: JSONEncodable<APIModalInteractionResponseCallbackData> | ModalComponentData | ModalBuilder): Promise<void>;
|
|
473
|
+
}
|
|
474
|
+
/** Context for a button click. */
|
|
475
|
+
declare class ButtonContext<P = Record<string, never>> extends MessageComponentContext<P, ButtonInteraction> {
|
|
476
|
+
}
|
|
477
|
+
/** Context for a string select; exposes the chosen {@link values}. */
|
|
478
|
+
declare class StringSelectContext<P = Record<string, never>> extends MessageComponentContext<P, StringSelectMenuInteraction> {
|
|
479
|
+
/** All selected values. */
|
|
480
|
+
get values(): string[];
|
|
481
|
+
/** The first selected value, or `undefined` if none. */
|
|
482
|
+
get value(): string | undefined;
|
|
483
|
+
}
|
|
484
|
+
/** Context for a user select; exposes selected ids, users and members. */
|
|
485
|
+
declare class UserSelectContext<P = Record<string, never>> extends MessageComponentContext<P, UserSelectMenuInteraction> {
|
|
486
|
+
get values(): string[];
|
|
487
|
+
get users(): discord_js.Collection<string, discord_js.User>;
|
|
488
|
+
get members(): discord_js.Collection<string, discord_js.GuildMember | discord_js.APIGuildMember>;
|
|
489
|
+
}
|
|
490
|
+
/** Context for a role select. */
|
|
491
|
+
declare class RoleSelectContext<P = Record<string, never>> extends MessageComponentContext<P, RoleSelectMenuInteraction> {
|
|
492
|
+
get values(): string[];
|
|
493
|
+
get roles(): discord_js.Collection<string, discord_js.Role | discord_js.APIRole>;
|
|
494
|
+
}
|
|
495
|
+
/** Context for a channel select. */
|
|
496
|
+
declare class ChannelSelectContext<P = Record<string, never>> extends MessageComponentContext<P, ChannelSelectMenuInteraction> {
|
|
497
|
+
get values(): string[];
|
|
498
|
+
get channels(): discord_js.Collection<string, discord_js.Channel | discord_js.APIChannel>;
|
|
499
|
+
}
|
|
500
|
+
/** Context for a mentionable (user + role) select. */
|
|
501
|
+
declare class MentionableSelectContext<P = Record<string, never>> extends MessageComponentContext<P, MentionableSelectMenuInteraction> {
|
|
502
|
+
get values(): string[];
|
|
503
|
+
get users(): discord_js.Collection<string, discord_js.User>;
|
|
504
|
+
get roles(): discord_js.Collection<string, discord_js.Role | discord_js.APIRole>;
|
|
505
|
+
get members(): discord_js.Collection<string, discord_js.GuildMember | discord_js.APIGuildMember>;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Context for a submitted modal. Exposes the routed {@link params} plus the
|
|
509
|
+
* resolved text-input {@link fields}, keyed by the field names you declared.
|
|
510
|
+
*/
|
|
511
|
+
declare class ModalContext<P, F extends string = string> extends BaseContext<ModalSubmitInteraction> {
|
|
512
|
+
readonly params: P;
|
|
513
|
+
/** Submitted values, keyed by the field names from your modal definition. */
|
|
514
|
+
readonly fields: Record<F, string>;
|
|
515
|
+
constructor(interaction: ModalSubmitInteraction, params: P,
|
|
516
|
+
/** Submitted values, keyed by the field names from your modal definition. */
|
|
517
|
+
fields: Record<F, string>);
|
|
518
|
+
/** The raw custom-id that triggered this modal submission. */
|
|
519
|
+
get customId(): string;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/** Shared shape of every routed component. */
|
|
523
|
+
interface RouteBase {
|
|
524
|
+
readonly namespace: string;
|
|
525
|
+
readonly paramNames: readonly string[];
|
|
526
|
+
}
|
|
527
|
+
/** Routing entry for a button. */
|
|
528
|
+
interface ButtonRoute extends RouteBase {
|
|
529
|
+
readonly kind: "button";
|
|
530
|
+
handle(interaction: ButtonInteraction, params: Record<string, string>): Promise<void>;
|
|
531
|
+
}
|
|
532
|
+
/** Routing entry for a string select. */
|
|
533
|
+
interface StringSelectRoute extends RouteBase {
|
|
534
|
+
readonly kind: "stringSelect";
|
|
535
|
+
handle(interaction: StringSelectMenuInteraction, params: Record<string, string>): Promise<void>;
|
|
536
|
+
}
|
|
537
|
+
/** Routing entry for a user select. */
|
|
538
|
+
interface UserSelectRoute extends RouteBase {
|
|
539
|
+
readonly kind: "userSelect";
|
|
540
|
+
handle(interaction: UserSelectMenuInteraction, params: Record<string, string>): Promise<void>;
|
|
541
|
+
}
|
|
542
|
+
/** Routing entry for a role select. */
|
|
543
|
+
interface RoleSelectRoute extends RouteBase {
|
|
544
|
+
readonly kind: "roleSelect";
|
|
545
|
+
handle(interaction: RoleSelectMenuInteraction, params: Record<string, string>): Promise<void>;
|
|
546
|
+
}
|
|
547
|
+
/** Routing entry for a channel select. */
|
|
548
|
+
interface ChannelSelectRoute extends RouteBase {
|
|
549
|
+
readonly kind: "channelSelect";
|
|
550
|
+
handle(interaction: ChannelSelectMenuInteraction, params: Record<string, string>): Promise<void>;
|
|
551
|
+
}
|
|
552
|
+
/** Routing entry for a mentionable select. */
|
|
553
|
+
interface MentionableSelectRoute extends RouteBase {
|
|
554
|
+
readonly kind: "mentionableSelect";
|
|
555
|
+
handle(interaction: MentionableSelectMenuInteraction, params: Record<string, string>): Promise<void>;
|
|
556
|
+
}
|
|
557
|
+
/** Routing entry for a modal submission. */
|
|
558
|
+
interface ModalRoute extends RouteBase {
|
|
559
|
+
readonly kind: "modal";
|
|
560
|
+
handle(interaction: ModalSubmitInteraction, params: Record<string, string>): Promise<void>;
|
|
561
|
+
}
|
|
562
|
+
/** Any registrable component routing entry. */
|
|
563
|
+
type ComponentDef = ButtonRoute | StringSelectRoute | UserSelectRoute | RoleSelectRoute | ChannelSelectRoute | MentionableSelectRoute | ModalRoute;
|
|
564
|
+
/** Error hook invoked when a component handler throws. */
|
|
565
|
+
type ComponentErrorHandler = (error: Error, interaction: RepliableInteraction) => Awaitable<void>;
|
|
566
|
+
/**
|
|
567
|
+
* Routes button, select and modal interactions to the handlers registered for
|
|
568
|
+
* their custom-id namespace. Decodes the custom-id, extracts typed params, and
|
|
569
|
+
* invokes the matching handler.
|
|
570
|
+
*/
|
|
571
|
+
declare class ComponentRegistry {
|
|
572
|
+
private readonly buttons;
|
|
573
|
+
private readonly stringSelects;
|
|
574
|
+
private readonly userSelects;
|
|
575
|
+
private readonly roleSelects;
|
|
576
|
+
private readonly channelSelects;
|
|
577
|
+
private readonly mentionableSelects;
|
|
578
|
+
private readonly modals;
|
|
579
|
+
private errorHandler?;
|
|
580
|
+
/** Register one or more components. Later registrations override by namespace. */
|
|
581
|
+
add(...defs: ComponentDef[]): this;
|
|
582
|
+
/** Set the handler used when a component throws. */
|
|
583
|
+
onError(handler: ComponentErrorHandler): this;
|
|
584
|
+
/** Total number of registered components. */
|
|
585
|
+
get size(): number;
|
|
586
|
+
/**
|
|
587
|
+
* Dispatch an interaction to its component handler. Returns `true` if a
|
|
588
|
+
* handler matched and ran, `false` otherwise.
|
|
589
|
+
*/
|
|
590
|
+
handle(interaction: Interaction): Promise<boolean>;
|
|
591
|
+
private exec;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/** Accepted button styles for an interactive (custom-id) button. */
|
|
595
|
+
type ButtonStyleInput = "Primary" | "Secondary" | "Success" | "Danger" | ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success | ButtonStyle.Danger;
|
|
596
|
+
/** Config for an interactive button created with {@link button}. */
|
|
597
|
+
interface ButtonConfig<P extends string, R> {
|
|
598
|
+
/** Custom-id pattern, e.g. `"vote"` or `"vote:{choice}"`. */
|
|
599
|
+
id: P;
|
|
600
|
+
label?: string;
|
|
601
|
+
style?: ButtonStyleInput;
|
|
602
|
+
emoji?: ComponentEmojiResolvable;
|
|
603
|
+
disabled?: boolean;
|
|
604
|
+
run: (ctx: ButtonContext<Params<P>>) => Awaitable<R>;
|
|
605
|
+
}
|
|
606
|
+
/** A registrable button with a typed {@link build}. */
|
|
607
|
+
interface Button<P extends string> extends ButtonRoute {
|
|
608
|
+
build(...args: BuildArgs<P>): ButtonBuilder;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Define an interactive button: its appearance, its custom-id pattern and its
|
|
612
|
+
* click handler, all in one place. Register it with `client.components.add`.
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* ```ts
|
|
616
|
+
* const vote = button({
|
|
617
|
+
* id: "vote:{choice}",
|
|
618
|
+
* label: "Yes",
|
|
619
|
+
* style: "Success",
|
|
620
|
+
* run: (ctx) => ctx.reply(`You chose ${ctx.params.choice}`),
|
|
621
|
+
* });
|
|
622
|
+
* row(vote.build({ choice: "yes" }));
|
|
623
|
+
* ```
|
|
624
|
+
*/
|
|
625
|
+
declare function button<const P extends string, R = void>(config: ButtonConfig<P, R>): Button<P>;
|
|
626
|
+
/** Config for a link button (no handler — just opens a URL). */
|
|
627
|
+
interface LinkButtonConfig {
|
|
628
|
+
url: string;
|
|
629
|
+
label?: string;
|
|
630
|
+
emoji?: ComponentEmojiResolvable;
|
|
631
|
+
disabled?: boolean;
|
|
632
|
+
}
|
|
633
|
+
/** Build a link button. Link buttons have no custom-id and run no handler. */
|
|
634
|
+
declare function linkButton(config: LinkButtonConfig): ButtonBuilder;
|
|
635
|
+
interface SelectConfigBase {
|
|
636
|
+
placeholder?: string;
|
|
637
|
+
minValues?: number;
|
|
638
|
+
maxValues?: number;
|
|
639
|
+
disabled?: boolean;
|
|
640
|
+
}
|
|
641
|
+
/** Config for a string select created with {@link stringSelect}. */
|
|
642
|
+
interface StringSelectConfig<P extends string, R> extends SelectConfigBase {
|
|
643
|
+
id: P;
|
|
644
|
+
options: readonly SelectMenuComponentOptionData[];
|
|
645
|
+
run: (ctx: StringSelectContext<Params<P>>) => Awaitable<R>;
|
|
646
|
+
}
|
|
647
|
+
/** A registrable string select with a typed {@link build}. */
|
|
648
|
+
interface StringSelect<P extends string> extends StringSelectRoute {
|
|
649
|
+
build(...args: BuildArgs<P>): StringSelectMenuBuilder;
|
|
650
|
+
}
|
|
651
|
+
/** Define a string select menu, its custom-id pattern and its handler. */
|
|
652
|
+
declare function stringSelect<const P extends string, R = void>(config: StringSelectConfig<P, R>): StringSelect<P>;
|
|
653
|
+
/** Config shared by the entity-select builders (user/role/channel/mentionable). */
|
|
654
|
+
interface EntitySelectConfig<P extends string> extends SelectConfigBase {
|
|
655
|
+
id: P;
|
|
656
|
+
}
|
|
657
|
+
/** A registrable user select. */
|
|
658
|
+
interface UserSelect<P extends string> extends UserSelectRoute {
|
|
659
|
+
build(...args: BuildArgs<P>): UserSelectMenuBuilder;
|
|
660
|
+
}
|
|
661
|
+
/** Define a user select menu. */
|
|
662
|
+
declare function userSelect<const P extends string, R = void>(config: EntitySelectConfig<P> & {
|
|
663
|
+
run: (ctx: UserSelectContext<Params<P>>) => Awaitable<R>;
|
|
664
|
+
}): UserSelect<P>;
|
|
665
|
+
/** A registrable role select. */
|
|
666
|
+
interface RoleSelect<P extends string> extends RoleSelectRoute {
|
|
667
|
+
build(...args: BuildArgs<P>): RoleSelectMenuBuilder;
|
|
668
|
+
}
|
|
669
|
+
/** Define a role select menu. */
|
|
670
|
+
declare function roleSelect<const P extends string, R = void>(config: EntitySelectConfig<P> & {
|
|
671
|
+
run: (ctx: RoleSelectContext<Params<P>>) => Awaitable<R>;
|
|
672
|
+
}): RoleSelect<P>;
|
|
673
|
+
/** A registrable channel select. */
|
|
674
|
+
interface ChannelSelect<P extends string> extends ChannelSelectRoute {
|
|
675
|
+
build(...args: BuildArgs<P>): ChannelSelectMenuBuilder;
|
|
676
|
+
}
|
|
677
|
+
/** Define a channel select menu, optionally restricted to channel types. */
|
|
678
|
+
declare function channelSelect<const P extends string, R = void>(config: EntitySelectConfig<P> & {
|
|
679
|
+
channelTypes?: readonly ChannelType[];
|
|
680
|
+
run: (ctx: ChannelSelectContext<Params<P>>) => Awaitable<R>;
|
|
681
|
+
}): ChannelSelect<P>;
|
|
682
|
+
/** A registrable mentionable select. */
|
|
683
|
+
interface MentionableSelect<P extends string> extends MentionableSelectRoute {
|
|
684
|
+
build(...args: BuildArgs<P>): MentionableSelectMenuBuilder;
|
|
685
|
+
}
|
|
686
|
+
/** Define a mentionable (user + role) select menu. */
|
|
687
|
+
declare function mentionableSelect<const P extends string, R = void>(config: EntitySelectConfig<P> & {
|
|
688
|
+
run: (ctx: MentionableSelectContext<Params<P>>) => Awaitable<R>;
|
|
689
|
+
}): MentionableSelect<P>;
|
|
690
|
+
/** Accepted text-input styles. */
|
|
691
|
+
type TextInputStyleInput = "Short" | "Paragraph" | TextInputStyle;
|
|
692
|
+
/** A resolved text-input field definition. */
|
|
693
|
+
interface TextInputDef {
|
|
694
|
+
readonly label: string;
|
|
695
|
+
readonly style: TextInputStyle;
|
|
696
|
+
readonly placeholder?: string;
|
|
697
|
+
readonly required?: boolean;
|
|
698
|
+
readonly minLength?: number;
|
|
699
|
+
readonly maxLength?: number;
|
|
700
|
+
readonly value?: string;
|
|
701
|
+
}
|
|
702
|
+
/** Define a single modal text-input field. */
|
|
703
|
+
declare function textInput(config: {
|
|
704
|
+
label: string;
|
|
705
|
+
style?: TextInputStyleInput;
|
|
706
|
+
placeholder?: string;
|
|
707
|
+
required?: boolean;
|
|
708
|
+
minLength?: number;
|
|
709
|
+
maxLength?: number;
|
|
710
|
+
value?: string;
|
|
711
|
+
}): TextInputDef;
|
|
712
|
+
/** Config for a modal created with {@link modal}. */
|
|
713
|
+
interface ModalConfig<P extends string, F extends Record<string, TextInputDef>, R> {
|
|
714
|
+
id: P;
|
|
715
|
+
title: string;
|
|
716
|
+
fields: F;
|
|
717
|
+
run: (ctx: ModalContext<Params<P>, keyof F & string>) => Awaitable<R>;
|
|
718
|
+
}
|
|
719
|
+
/** A registrable modal with a typed {@link build}. */
|
|
720
|
+
interface Modal<P extends string> extends ModalRoute {
|
|
721
|
+
build(...args: BuildArgs<P>): ModalBuilder;
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Define a modal: its title, its custom-id pattern, its text-input fields and
|
|
725
|
+
* a submit handler. The handler receives the submitted values keyed by field
|
|
726
|
+
* name in `ctx.fields`.
|
|
727
|
+
*
|
|
728
|
+
* @example
|
|
729
|
+
* ```ts
|
|
730
|
+
* const feedback = modal({
|
|
731
|
+
* id: "feedback:{ticket}",
|
|
732
|
+
* title: "Feedback",
|
|
733
|
+
* fields: { comment: textInput({ label: "Comment", style: "Paragraph" }) },
|
|
734
|
+
* run: (ctx) => ctx.reply(`Thanks! (${ctx.params.ticket}): ${ctx.fields.comment}`),
|
|
735
|
+
* });
|
|
736
|
+
* ```
|
|
737
|
+
*/
|
|
738
|
+
declare function modal<const P extends string, F extends Record<string, TextInputDef>, R = void>(config: ModalConfig<P, F, R>): Modal<P>;
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Wrap one or more component builders in an action row.
|
|
742
|
+
*
|
|
743
|
+
* A row holds up to five buttons, or exactly one select menu.
|
|
744
|
+
*
|
|
745
|
+
* @example
|
|
746
|
+
* ```ts
|
|
747
|
+
* const components = [row(yes.build(), no.build())];
|
|
748
|
+
* await channel.send({ content: "Vote:", components });
|
|
749
|
+
* ```
|
|
750
|
+
*/
|
|
751
|
+
declare function row<C extends MessageActionRowComponentBuilder>(...components: C[]): ActionRowBuilder<C>;
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* A spearkit plugin: a named, reusable bundle of commands, events and components.
|
|
755
|
+
* Its {@link setup} runs once when added to a client via `client.use(plugin)`.
|
|
756
|
+
*/
|
|
757
|
+
interface SpearPlugin {
|
|
758
|
+
readonly name: string;
|
|
759
|
+
setup(client: SpearClient): Awaitable<void>;
|
|
760
|
+
}
|
|
761
|
+
/** Identity helper that gives a plugin object its type and editor hints. */
|
|
762
|
+
declare function definePlugin(plugin: SpearPlugin): SpearPlugin;
|
|
763
|
+
|
|
764
|
+
/** Options for the directory loader. */
|
|
765
|
+
interface LoadOptions {
|
|
766
|
+
/** File extensions to import. Default: `.js`, `.mjs`, `.cjs`. */
|
|
767
|
+
extensions?: readonly string[];
|
|
768
|
+
/** Recurse into subdirectories. Default: `true`. */
|
|
769
|
+
recursive?: boolean;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Recursively import a directory and collect every spearkit-registrable export
|
|
773
|
+
* (commands, events, components) found in default or named exports.
|
|
774
|
+
*/
|
|
775
|
+
declare function collectModules(dir: string, options?: LoadOptions): Promise<Registerable[]>;
|
|
776
|
+
/**
|
|
777
|
+
* Load a directory and register everything it exports into the client.
|
|
778
|
+
* Returns the number of items registered.
|
|
779
|
+
*/
|
|
780
|
+
declare function loadInto(client: SpearClient, dir: string, options?: LoadOptions): Promise<number>;
|
|
781
|
+
|
|
782
|
+
/** Anything that can be handed to {@link SpearClient.register}. */
|
|
783
|
+
type Registerable = SlashCommand | EventDef | ComponentDef;
|
|
784
|
+
/**
|
|
785
|
+
* Ready-made intent presets. Pass one to {@link SpearClient} as `intents`.
|
|
786
|
+
* `all` includes privileged intents — enable them in the developer portal.
|
|
787
|
+
*/
|
|
788
|
+
declare const Intents: {
|
|
789
|
+
/** No intents. */
|
|
790
|
+
readonly none: GatewayIntentBits[];
|
|
791
|
+
/** Just `Guilds` — enough for slash commands and interactions. */
|
|
792
|
+
readonly default: readonly [GatewayIntentBits.Guilds];
|
|
793
|
+
/** Guild + member gateway data. */
|
|
794
|
+
readonly guilds: readonly [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers];
|
|
795
|
+
/** Read message content (privileged) alongside guild messages. */
|
|
796
|
+
readonly messages: readonly [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent];
|
|
797
|
+
/** Every intent, including privileged ones. */
|
|
798
|
+
readonly all: GatewayIntentBits[];
|
|
799
|
+
};
|
|
800
|
+
/** Options for {@link SpearClient}. Identical to discord.js but `intents` may be omitted. */
|
|
801
|
+
type SpearClientOptions = Partial<ClientOptions>;
|
|
802
|
+
/**
|
|
803
|
+
* A discord.js {@link Client} with batteries included: command, event and
|
|
804
|
+
* component registries plus interaction routing wired up automatically.
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* ```ts
|
|
808
|
+
* const client = new SpearClient({ intents: Intents.default });
|
|
809
|
+
* client.register(ping, onReady, voteButton);
|
|
810
|
+
* await client.start(process.env.TOKEN);
|
|
811
|
+
* await client.deployCommands({ guildId: "123" });
|
|
812
|
+
* ```
|
|
813
|
+
*/
|
|
814
|
+
declare class SpearClient extends Client {
|
|
815
|
+
/** Slash command registry and dispatcher. */
|
|
816
|
+
readonly commands: CommandRegistry;
|
|
817
|
+
/** Event listener registry. */
|
|
818
|
+
readonly events: EventRegistry;
|
|
819
|
+
/** Button / select / modal registry and router. */
|
|
820
|
+
readonly components: ComponentRegistry;
|
|
821
|
+
constructor(options?: SpearClientOptions);
|
|
822
|
+
/**
|
|
823
|
+
* Register commands, events and components in one call. Each item is routed
|
|
824
|
+
* to the matching registry based on its kind.
|
|
825
|
+
*/
|
|
826
|
+
register(...items: Registerable[]): this;
|
|
827
|
+
/** Install one or more plugins, running each plugin's `setup`. */
|
|
828
|
+
use(...plugins: SpearPlugin[]): Promise<this>;
|
|
829
|
+
/**
|
|
830
|
+
* Recursively load a directory and register every command, event and
|
|
831
|
+
* component it exports. Returns the number of items registered.
|
|
832
|
+
*/
|
|
833
|
+
load(dir: string, options?: LoadOptions): Promise<number>;
|
|
834
|
+
/**
|
|
835
|
+
* Log in. Falls back to the `DISCORD_TOKEN` environment variable when no
|
|
836
|
+
* token is passed.
|
|
837
|
+
*/
|
|
838
|
+
start(token?: string): Promise<this>;
|
|
839
|
+
/**
|
|
840
|
+
* Push the registered slash commands to discord using the client's own
|
|
841
|
+
* authenticated REST connection. Call after the client is ready.
|
|
842
|
+
*/
|
|
843
|
+
deployCommands(options?: {
|
|
844
|
+
guildId?: string;
|
|
845
|
+
}): Promise<DeployResult>;
|
|
846
|
+
private route;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
export { type AllowedChannelType, type AnyComponentInteraction, type AnyOptionDef, AutocompleteContext, type AutocompleteHandler, BaseContext, type BuildArgs, type Button, type ButtonConfig, ButtonContext, type ButtonRoute, type ButtonStyleInput, type ChannelSelect, ChannelSelectContext, type ChannelSelectRoute, type CommandConfig, CommandContext, type CommandErrorHandler, type CommandGroupConfig, CommandRegistry, type CompiledPattern, type ComponentDef, type ComponentErrorHandler, ComponentRegistry, type DeployOptions, type DeployResult, type EntitySelectConfig, type EventConfig, type EventDef, type EventHandler, EventRegistry, Intents, type LinkButtonConfig, type LoadOptions, MAX_CUSTOM_ID_LENGTH, type MentionableSelect, MentionableSelectContext, type MentionableSelectRoute, MessageComponentContext, type Modal, type ModalConfig, ModalContext, type ModalRoute, type OptionChoice, type OptionDef, type OptionMap, type OptionValue, type ParamNames, type Params, type ParsedCustomId, type Registerable, type ReplyData, type ReplyInput, type ResolvedOption, type ResolvedOptions, type RoleSelect, RoleSelectContext, type RoleSelectRoute, SlashCommand, SpearClient, type SpearClientOptions, type SpearPlugin, type StringSelect, type StringSelectConfig, StringSelectContext, type StringSelectRoute, type Subcommand, type SubcommandConfig, type SubcommandGroup, type SubcommandGroupConfig, type TextInputDef, type TextInputStyleInput, type UserSelect, UserSelectContext, type UserSelectRoute, asEphemeral, buildCustomId, button, channelSelect, collectModules, command, commandGroup, compilePattern, definePlugin, event, linkButton, loadInto, mentionableSelect, modal, normalizeReply, option, optionsHaveAutocomplete, paramsFromValues, parseCustomId, readOption, roleSelect, row, stringSelect, subcommand, subcommandGroup, textInput, toAPIOption, userSelect };
|