@hyperneutrino/djs-lite 1.6.0 → 1.7.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/index.ts +197 -35
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -35,16 +35,62 @@ const identity = <T>(value: T): T => value;
|
|
|
35
35
|
|
|
36
36
|
type Wrapper<T extends Function> = (fn: T) => T;
|
|
37
37
|
|
|
38
|
-
type
|
|
38
|
+
type Handleable = CommandInteraction | AutocompleteInteraction | MessageComponentInteraction | ModalSubmitInteraction;
|
|
39
|
+
|
|
40
|
+
type Handler<T extends Handleable> = (
|
|
39
41
|
interaction: T,
|
|
40
42
|
...args: T extends MessageComponentInteraction | ModalSubmitInteraction ? (string | undefined)[] : []
|
|
41
43
|
) => Awaitable<unknown>;
|
|
42
44
|
|
|
45
|
+
type WrapperConfig<R extends Record<string, Handleable>> = {
|
|
46
|
+
[K in keyof R]?: Wrapper<Handler<R[K]>>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* This is the type of `config.wrappers` in `loadCommands`. This type is exported so that you can expose the wrappers upstream if you are making a library
|
|
51
|
+
* surrounding this library.
|
|
52
|
+
*/
|
|
53
|
+
export interface CommandWrappers extends WrapperConfig<{
|
|
54
|
+
slashCommands: ChatInputCommandInteraction;
|
|
55
|
+
userCommands: UserContextMenuCommandInteraction;
|
|
56
|
+
messageCommands: MessageContextMenuCommandInteraction;
|
|
57
|
+
autocompletes: AutocompleteInteraction;
|
|
58
|
+
}> {}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* This is the type of `config.wrappers` in `loadInteractions`. This type is exported so that you can expose the wrappers upstream if you are making a library
|
|
62
|
+
* surrounding this library.
|
|
63
|
+
*/
|
|
64
|
+
export interface InteractionWrappers extends WrapperConfig<{
|
|
65
|
+
modal: ModalSubmitInteraction;
|
|
66
|
+
button: ButtonInteraction;
|
|
67
|
+
stringSelectMenu: StringSelectMenuInteraction;
|
|
68
|
+
userSelectMenu: UserSelectMenuInteraction;
|
|
69
|
+
roleSelectMenu: RoleSelectMenuInteraction;
|
|
70
|
+
mentionableSelectMenu: MentionableSelectMenuInteraction;
|
|
71
|
+
channelSelectMenu: ChannelSelectMenuInteraction;
|
|
72
|
+
}> {}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* This is a union type of `CommandWrappers` and `InteractionWrappers` so you can expose all of them at once (since there is no overlap in the field names).
|
|
76
|
+
*/
|
|
77
|
+
export interface Wrappers extends CommandWrappers, InteractionWrappers {}
|
|
78
|
+
|
|
43
79
|
abstract class Command<T extends BaseApplicationCommandData, U extends CommandInteraction, Z extends boolean = false> {
|
|
80
|
+
/** This is the command data for the configured command. */
|
|
44
81
|
data: T;
|
|
82
|
+
|
|
83
|
+
/** This is the handler for the configured command. */
|
|
45
84
|
handler: Handler<U>;
|
|
85
|
+
|
|
86
|
+
/** This is the handler for the configured command's autocomplete fields (always null if not on a slash command). */
|
|
46
87
|
autocomplete: Handler<AutocompleteInteraction> | null;
|
|
47
88
|
|
|
89
|
+
/**
|
|
90
|
+
* @param object This object should contain all of the fields that would be present in this command type's command data except for the `type`.
|
|
91
|
+
* @param object.handler This parameter must be a function that takes the interaction as the sole parameter and processes it.
|
|
92
|
+
* @param object.autocomplete If this is a slash command, this parameter may be a function that takes an autocomplete interaction as the sole parameter.
|
|
93
|
+
*/
|
|
48
94
|
constructor({ handler, ...data }: T & { handler: Handler<U> } & (Z extends true ? { autocomplete?: Handler<AutocompleteInteraction> } : {})) {
|
|
49
95
|
if ("autocomplete" in data) {
|
|
50
96
|
const { autocomplete, ...rest } = data;
|
|
@@ -59,56 +105,116 @@ abstract class Command<T extends BaseApplicationCommandData, U extends CommandIn
|
|
|
59
105
|
}
|
|
60
106
|
}
|
|
61
107
|
|
|
108
|
+
/** This is a slash command configuration object. Prefer {@link SlashCommandWithSubcommands} unless you are sure you want to do subcommand routing manually. */
|
|
62
109
|
export class SlashCommand extends Command<Omit<ChatInputApplicationCommandData, "type">, ChatInputCommandInteraction, true> {}
|
|
110
|
+
|
|
111
|
+
/** This is a user context menu command configuration object. */
|
|
63
112
|
export class UserCommand extends Command<Omit<UserApplicationCommandData, "type">, UserContextMenuCommandInteraction> {}
|
|
113
|
+
|
|
114
|
+
/** This is a message context menu command configuration object. */
|
|
64
115
|
export class MessageCommand extends Command<Omit<MessageApplicationCommandData, "type">, MessageContextMenuCommandInteraction> {}
|
|
65
116
|
|
|
117
|
+
/**
|
|
118
|
+
* This is a slash command configuration object when the slash command has subcommands/subcommand groups.
|
|
119
|
+
* There is no handler here; the handler is specified in each subcommand.
|
|
120
|
+
*/
|
|
66
121
|
export class SlashCommandWithSubcommands {
|
|
122
|
+
/** This is the command data for the root command with the options omitted. */
|
|
67
123
|
data: Omit<ChatInputApplicationCommandData, "options" | "type">;
|
|
68
124
|
|
|
125
|
+
/**
|
|
126
|
+
* @param data This is the command data for the root command with the options ommitted.
|
|
127
|
+
*/
|
|
69
128
|
constructor(data: typeof this.data) {
|
|
70
129
|
this.data = data;
|
|
71
130
|
}
|
|
72
131
|
}
|
|
73
132
|
|
|
133
|
+
/** This is a slash command subcommand group configuration object. There is no handler here; the handler is specified in each subcommand. */
|
|
74
134
|
export class SubcommandGroup {
|
|
135
|
+
/** This is the subcommand group data with the options omitted. */
|
|
75
136
|
data: Omit<ApplicationCommandSubGroupData, "options" | "type">;
|
|
76
137
|
|
|
138
|
+
/**
|
|
139
|
+
* @param data This is the subcommand group data with the options omitted.
|
|
140
|
+
*/
|
|
77
141
|
constructor(data: typeof this.data) {
|
|
78
142
|
this.data = data;
|
|
79
143
|
}
|
|
80
144
|
}
|
|
81
145
|
|
|
146
|
+
/** This is a slash command subcommand configuration object. */
|
|
82
147
|
export class Subcommand {
|
|
148
|
+
/** This is the subcommand data for the configured subcommand. */
|
|
83
149
|
data: Omit<ApplicationCommandSubCommandData, "type">;
|
|
150
|
+
|
|
151
|
+
/** This is the handler for the configured subcommand. */
|
|
84
152
|
handler: Handler<ChatInputCommandInteraction>;
|
|
85
153
|
|
|
86
|
-
|
|
154
|
+
/** This is the handler for the configured subcommand's autocomplete fields. */
|
|
155
|
+
autocomplete: Handler<AutocompleteInteraction> | null;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @param object This object should contain all of the fields that would be present in this command type's command data except for the `type`.
|
|
159
|
+
* @param object.handler This parameter must be a function that takes the interaction as the sole parameter and processes it.
|
|
160
|
+
* @param object.autocomplete If this is a slash command, this parameter may be a function that takes an autocomplete interaction as the sole parameter.
|
|
161
|
+
*/
|
|
162
|
+
constructor({ handler, autocomplete, ...data }: typeof this.data & { handler: Subcommand["handler"]; autocomplete?: Subcommand["autocomplete"] }) {
|
|
87
163
|
this.data = data;
|
|
88
164
|
this.handler = handler;
|
|
165
|
+
this.autocomplete = autocomplete ?? null;
|
|
89
166
|
}
|
|
90
167
|
}
|
|
91
168
|
|
|
92
169
|
abstract class ComponentHandler<T extends ModalSubmitInteraction | MessageComponentInteraction> {
|
|
170
|
+
/** This is the handler for the configured interaction. */
|
|
93
171
|
handler: Handler<T>;
|
|
94
172
|
|
|
173
|
+
/**
|
|
174
|
+
* @param handler This parameter must be a function that takes the interaction as the first parameter and processes it. Subsequent parameters are possible
|
|
175
|
+
* and will all be strings if present. These are derived from the interaction's `customId`; see {@link loadInteractions} for instructions.
|
|
176
|
+
*/
|
|
95
177
|
constructor(handler: Handler<T>) {
|
|
96
178
|
this.handler = handler;
|
|
97
179
|
}
|
|
98
180
|
}
|
|
99
181
|
|
|
182
|
+
/** This is a modal submit interaction configuration object. */
|
|
100
183
|
export class ModalHandler extends ComponentHandler<ModalSubmitInteraction> {}
|
|
184
|
+
|
|
185
|
+
/** This is a button component interaction configuration object. */
|
|
101
186
|
export class ButtonHandler extends ComponentHandler<ButtonInteraction> {}
|
|
187
|
+
|
|
188
|
+
/** This is a string select menu component interaction configuration object. */
|
|
102
189
|
export class StringSelectMenuHandler extends ComponentHandler<StringSelectMenuInteraction> {}
|
|
190
|
+
|
|
191
|
+
/** This is a user select menu component interaction configuration object. */
|
|
103
192
|
export class UserSelectMenuHandler extends ComponentHandler<UserSelectMenuInteraction> {}
|
|
193
|
+
|
|
194
|
+
/** This is a role select menu component interaction configuration object. */
|
|
104
195
|
export class RoleSelectMenuHandler extends ComponentHandler<RoleSelectMenuInteraction> {}
|
|
196
|
+
|
|
197
|
+
/** This is a mentionable select menu component interaction configuration object. */
|
|
105
198
|
export class MentionableSelectMenuHandler extends ComponentHandler<MentionableSelectMenuInteraction> {}
|
|
199
|
+
|
|
200
|
+
/** This is a channel select menu component interaction configuration object. */
|
|
106
201
|
export class ChannelSelectMenuHandler extends ComponentHandler<ChannelSelectMenuInteraction> {}
|
|
107
202
|
|
|
203
|
+
/**
|
|
204
|
+
* This is an event handler configuration object.
|
|
205
|
+
*/
|
|
108
206
|
export class EventHandler<T extends keyof ClientEvents> {
|
|
207
|
+
/** This is the event to watch. */
|
|
109
208
|
event: T;
|
|
209
|
+
|
|
210
|
+
/** This is the handler for the configured event type. */
|
|
110
211
|
handler: (...args: ClientEvents[T]) => unknown;
|
|
111
212
|
|
|
213
|
+
/**
|
|
214
|
+
* @param object.event This is the event to watch. This automatically configures the generic type argument.
|
|
215
|
+
* @param object.handler This is the handler for the configured event type. The parameter types are automatically configured from the generic type
|
|
216
|
+
* argument.
|
|
217
|
+
*/
|
|
112
218
|
constructor({ event, handler }: { event: T; handler: (...args: ClientEvents[T]) => unknown }) {
|
|
113
219
|
this.event = event;
|
|
114
220
|
this.handler = handler;
|
|
@@ -136,45 +242,44 @@ async function importAll(
|
|
|
136
242
|
);
|
|
137
243
|
}
|
|
138
244
|
|
|
139
|
-
async function loadSubcommands(directory: string)
|
|
140
|
-
options: ApplicationCommandSubCommandData[];
|
|
141
|
-
handlers: Map<string, Handler<ChatInputCommandInteraction>>;
|
|
142
|
-
}> {
|
|
245
|
+
async function loadSubcommands(directory: string) {
|
|
143
246
|
if (!(await fs.exists(directory))) throw new Error(`Loading subcommands within a group failed: ${directory} is required but could not be found.`);
|
|
144
247
|
|
|
145
248
|
const options: ApplicationCommandSubCommandData[] = [];
|
|
146
249
|
const handlers = new Map<string, Handler<ChatInputCommandInteraction>>();
|
|
250
|
+
const autocompletes = new Map<string, Handler<AutocompleteInteraction>>();
|
|
147
251
|
|
|
148
252
|
await importAll({ directory, recursive: false }, async ({ file, absolutePath, item }) => {
|
|
149
253
|
if (item instanceof Subcommand) {
|
|
150
254
|
options.push({ ...item.data, type: ApplicationCommandOptionType.Subcommand });
|
|
151
255
|
handlers.set(item.data.name, item.handler);
|
|
256
|
+
if (item.autocomplete) autocompletes.set(item.data.name, item.autocomplete);
|
|
152
257
|
} else throw new Error(`Loading commands failed: export from ${absolutePath} (third-level in commands folder) was not an instance of Subcommand.`);
|
|
153
258
|
|
|
154
259
|
if (item.data.name !== file.name.replace(/.[^/.]+$/, ""))
|
|
155
260
|
throw new Error(`Code style enforcement: name exported from ${absolutePath} does not match the filename`);
|
|
156
261
|
});
|
|
157
262
|
|
|
158
|
-
return { options, handlers };
|
|
263
|
+
return { options, handlers, autocompletes };
|
|
159
264
|
}
|
|
160
265
|
|
|
161
|
-
async function loadSubcommandsAndGroups(directory: string)
|
|
162
|
-
options: (ApplicationCommandSubGroupData | ApplicationCommandSubCommandData)[];
|
|
163
|
-
handler: Handler<ChatInputCommandInteraction>;
|
|
164
|
-
}> {
|
|
266
|
+
async function loadSubcommandsAndGroups(directory: string) {
|
|
165
267
|
if (!(await fs.exists(directory))) throw new Error(`Loading subcommands/groups failed: ${directory} is required but could not be found.`);
|
|
166
268
|
|
|
167
269
|
const options: (ApplicationCommandSubGroupData | ApplicationCommandSubCommandData)[] = [];
|
|
168
270
|
const handlers = new Map<string, Handler<ChatInputCommandInteraction>>();
|
|
271
|
+
const autocompletes = new Map<string, Handler<AutocompleteInteraction>>();
|
|
169
272
|
|
|
170
273
|
await importAll({ directory, recursive: false }, async ({ file, absolutePath, relativePath, item }) => {
|
|
171
274
|
if (item instanceof Subcommand) {
|
|
172
275
|
options.push({ ...item.data, type: ApplicationCommandOptionType.Subcommand });
|
|
173
276
|
handlers.set(`/${item.data.name}`, item.handler);
|
|
277
|
+
if (item.autocomplete) autocompletes.set(`/${item.data.name}`, item.autocomplete);
|
|
174
278
|
} else if (item instanceof SubcommandGroup) {
|
|
175
279
|
const subcommands = await loadSubcommands(relativePath.replace(/\.[^/.]+$/, ""));
|
|
176
280
|
options.push({ ...item.data, type: ApplicationCommandOptionType.SubcommandGroup, options: subcommands.options });
|
|
177
281
|
subcommands.handlers.entries().forEach(([key, handler]) => handlers.set(`${item.data.name}/${key}`, handler));
|
|
282
|
+
subcommands.autocompletes.entries().forEach(([key, autocomplete]) => autocompletes.set(`${item.data.name}/${key}`, autocomplete));
|
|
178
283
|
} else
|
|
179
284
|
throw new Error(
|
|
180
285
|
`Loading commands failed: export from ${absolutePath} (second-level in commands folder) was not an instance of SubcommandGroup or Subcommand.`,
|
|
@@ -186,23 +291,38 @@ async function loadSubcommandsAndGroups(directory: string): Promise<{
|
|
|
186
291
|
|
|
187
292
|
return {
|
|
188
293
|
options,
|
|
189
|
-
handler: (cmd) => handlers.get(`${cmd.options.getSubcommandGroup(false) ?? ""}/${cmd.options.getSubcommand(true)}`)?.(cmd),
|
|
294
|
+
handler: (cmd: ChatInputCommandInteraction) => handlers.get(`${cmd.options.getSubcommandGroup(false) ?? ""}/${cmd.options.getSubcommand(true)}`)?.(cmd),
|
|
295
|
+
autocomplete: (cmd: AutocompleteInteraction) =>
|
|
296
|
+
autocompletes.get(`${cmd.options.getSubcommandGroup(false) ?? ""}/${cmd.options.getSubcommand(true)}`)?.(cmd),
|
|
190
297
|
};
|
|
191
298
|
}
|
|
192
299
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
)
|
|
300
|
+
/**
|
|
301
|
+
* Load commands from a directory to a client. This will attach the command listeners. If the command data has been changed (based on the local .cache/
|
|
302
|
+
* directory), then the commands will be automatically set on the client (or the guild if `config.guildId` is set).
|
|
303
|
+
*
|
|
304
|
+
* Each file within the directory should be `command-name.{ts,js}` exporting a {@link SlashCommand}, {@link UserCommand}, {@link MessageCommand}, or
|
|
305
|
+
* {@link SlashCommandWithSubcommands}. If the file exports {@link SlashCommandWithSubcommands}, there should be a directory with the same command name.
|
|
306
|
+
*
|
|
307
|
+
* Each file within that subdirectory should be `subcommand-name.{ts,js}` exporting a {@link Subcommand} or `subcommand-group-name.{ts,js}` exporting a
|
|
308
|
+
* {@link SubcommandGroup}. If it exports a {@link SubcommandGroup}, there should be a directory with the same subcommand group name.
|
|
309
|
+
*
|
|
310
|
+
* Each file within the third directory level should be `subcommand-name.{ts,js}` exporting a {@link Subcommand}.
|
|
311
|
+
*
|
|
312
|
+
* The file name must match the command (or subcommand group, or subcommand) name for all types.
|
|
313
|
+
*
|
|
314
|
+
* @param client The post-login client into which to load the commands.
|
|
315
|
+
* @param directory The relative path (from your execution point) containing your command handlers.
|
|
316
|
+
* @param config Command-related configuration values.
|
|
317
|
+
* @param config.guildId The ID of the guild to which to set the commands.
|
|
318
|
+
* @param config.wrappers A set of wrappers which transform all handler functions for each handler type.
|
|
319
|
+
* @returns `commands`, the loaded command data (an array of objects).
|
|
320
|
+
* @returns `slashCommandHandlers`, the map from each slash command name to its handler.
|
|
321
|
+
* @returns `userCommandHandlers`, the map from each user context menu command name to its handler.
|
|
322
|
+
* @returns `messageCommandHandlers`, the map from each message context menu command name to its handler.
|
|
323
|
+
* @returns `setCommands`, indicating whether or not the commands were pushed to the Discord API.
|
|
324
|
+
*/
|
|
325
|
+
export async function loadCommands(client: Client<true>, directory: string, config?: { guildId?: string; wrappers?: CommandWrappers }) {
|
|
206
326
|
const commandData: (ChatInputApplicationCommandData | UserApplicationCommandData | MessageApplicationCommandData)[] = [];
|
|
207
327
|
|
|
208
328
|
const slashCommandHandlers = new Map<string, Handler<ChatInputCommandInteraction>>();
|
|
@@ -223,9 +343,10 @@ export async function loadCommands(
|
|
|
223
343
|
commandData.push({ ...item.data, type: ApplicationCommandType.Message });
|
|
224
344
|
messageCommandHandlers.set(item.data.name, (config?.wrappers?.messageCommands ?? identity)(item.handler));
|
|
225
345
|
} else if (item instanceof SlashCommandWithSubcommands) {
|
|
226
|
-
const { options, handler } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
|
|
346
|
+
const { options, handler, autocomplete } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
|
|
227
347
|
commandData.push({ ...item.data, options });
|
|
228
348
|
slashCommandHandlers.set(item.data.name, (config?.wrappers?.slashCommands ?? identity)(handler));
|
|
349
|
+
slashCommandAutocompletes.set(item.data.name, (config?.wrappers?.autocompletes ?? identity)(autocomplete));
|
|
229
350
|
} else {
|
|
230
351
|
throw new Error(`Loading commands failed: export from ${absolutePath} was not an instance of <Type>Command.`);
|
|
231
352
|
}
|
|
@@ -266,20 +387,44 @@ export async function loadCommands(
|
|
|
266
387
|
return { commands: commandData, slashCommandHandlers, userCommandHandlers, messageCommandHandlers, setCommands: commandDataHasBeenUpdated };
|
|
267
388
|
}
|
|
268
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Load interactions from a directory to a client. This will attach the interaction (modal submit and message component) listeners.
|
|
392
|
+
*
|
|
393
|
+
* Each file within the directory (recursively) should be `*.{ts,js}` exporting a {@link ModalHandler}, {@link ButtonHandler}, {@link StringSelectMenuHandler},
|
|
394
|
+
* {@link UserSelectMenuHandler}, {@link RoleSelectMenuHandler}, {@link MentionableSelectMenuHandler}, or {@link ChannelSelectMenuHandler}.
|
|
395
|
+
*
|
|
396
|
+
* To use these interactions, the `customId` on the modal/message component must start with the argument separator (`config.argumentSeparator`, which defaults
|
|
397
|
+
* to `:`). You can optionally put a user ID after this to restrict who can interact with that component. Otherwise, place another argument separator
|
|
398
|
+
* immediately. Since modals are only submittable by the user to whom they're shown, setting a user ID is not recommended as you should control who sees the
|
|
399
|
+
* modal at all instead, but it will technically work. If this ID is set, any other users will simply be ignored and your handler will not be invoked.
|
|
400
|
+
*
|
|
401
|
+
* After the second argument separator, specify the path (separated by slashes regardless of your operating system). This will be looked up relative to the
|
|
402
|
+
* provided directory, so if you provide `src/interactions` and the path argument of `customId` is `pages/next`, then this will point to
|
|
403
|
+
* `src/interactions/pages/next.{ts,js}`.
|
|
404
|
+
*
|
|
405
|
+
* You can specify any number of additional string arguments, separating each with the argument separator. The `customId` will be naively `.split()` on this
|
|
406
|
+
* separator, so it is impossible to include the separator symbol/sequence anywhere in any of the arguments. Your handler will receive these as additional
|
|
407
|
+
* arguments.
|
|
408
|
+
*
|
|
409
|
+
* @param client The client (may be pre-login) into which to load the interaction handlers.
|
|
410
|
+
* @param directory The relative path (from your execution point) containing your interaction handlers.
|
|
411
|
+
* @param config Interaction-related configuration values.
|
|
412
|
+
* @param config.argumentSeparator The separator used to split custom IDs. This defaults to `:`.
|
|
413
|
+
* @param config.wrappers A set of wrappers which transform all handler functions for each handler type.
|
|
414
|
+
* @returns `modalHandlers`, the map from each modal submit handler's configuration file path to its handler function.
|
|
415
|
+
* @returns `buttonHandlers`, the map from each button handler's configuration file path to its handler function.
|
|
416
|
+
* @returns `stringSelectMenuHandlers`, the map from each string select menu handler's file path to its handler function.
|
|
417
|
+
* @returns `userSelectMenuHandlers`, the map from each user select menu handler's file path to its handler function.
|
|
418
|
+
* @returns `roleSelectMenuHandlers`, the map from each role select menu handler's file path to its handler function.
|
|
419
|
+
* @returns `mentionableSelectMenuHandlers`, the map from each mentionable select menu handler's file path to its handler function.
|
|
420
|
+
* @returns `channelSelectMenuHandlers`, the map from each channel select menu handler's file path to its handler function.
|
|
421
|
+
*/
|
|
269
422
|
export async function loadInteractions(
|
|
270
423
|
client: Client,
|
|
271
424
|
directory: string,
|
|
272
425
|
config?: {
|
|
273
426
|
argumentSeparator?: string;
|
|
274
|
-
wrappers?:
|
|
275
|
-
modal?: Wrapper<Handler<ModalSubmitInteraction>>;
|
|
276
|
-
button?: Wrapper<Handler<ButtonInteraction>>;
|
|
277
|
-
stringSelectMenu?: Wrapper<Handler<StringSelectMenuInteraction>>;
|
|
278
|
-
userSelectMenu?: Wrapper<Handler<UserSelectMenuInteraction>>;
|
|
279
|
-
roleSelectMenu?: Wrapper<Handler<RoleSelectMenuInteraction>>;
|
|
280
|
-
mentionableSelectMenu?: Wrapper<Handler<MentionableSelectMenuInteraction>>;
|
|
281
|
-
channelSelectMenu?: Wrapper<Handler<ChannelSelectMenuInteraction>>;
|
|
282
|
-
};
|
|
427
|
+
wrappers?: InteractionWrappers;
|
|
283
428
|
},
|
|
284
429
|
) {
|
|
285
430
|
const modalHandlers = new Map<string, Handler<ModalSubmitInteraction>>();
|
|
@@ -335,6 +480,23 @@ export async function loadInteractions(
|
|
|
335
480
|
};
|
|
336
481
|
}
|
|
337
482
|
|
|
483
|
+
/**
|
|
484
|
+
* Load event listeners from a directory to a client.
|
|
485
|
+
*
|
|
486
|
+
* Each file within the directory should be `*.{ts,js}` exporting an {@link EventHandler}. The generic type argument of {@link EventHandler} will automatically
|
|
487
|
+
* be inferred by its {@link EventHandler.event} property, which will automatically establish the type for the handler.
|
|
488
|
+
*
|
|
489
|
+
* Whether the files are loaded recursively depends on {@link recursive} which is `false` by default. If it is `false`, then subdirectories will not be
|
|
490
|
+
* scanned, allowing you to place utility functions and similar files within them.
|
|
491
|
+
*
|
|
492
|
+
* Unlike with {@link loadCommands} and {@link loadInteractions}, event handler files can be named anything and the name is purely cosmetic.
|
|
493
|
+
*
|
|
494
|
+
* @param client The client (may be pre-login) into which to load the event handlers.
|
|
495
|
+
* @param directory The relative path (from your execution point) containing your event handlers.
|
|
496
|
+
* @param recursive Whether to load recursively from the directory (defaults to false).
|
|
497
|
+
* @returns `handlers`, a partial record from each event type to an array of its handler functions.
|
|
498
|
+
* @returns `filenames`, a partial record from each event type to an array of its files' paths (relative from `directory`).
|
|
499
|
+
*/
|
|
338
500
|
export async function loadEvents(client: Client, directory: string, recursive: boolean = false) {
|
|
339
501
|
const handlers: Partial<{ [K in keyof ClientEvents]: ((...args: ClientEvents[K]) => unknown)[] }> = {};
|
|
340
502
|
const filenames: Partial<{ [K in keyof ClientEvents]: string[] }> = {};
|