@hyperneutrino/djs-lite 1.6.1 → 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 +169 -12
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -46,6 +46,10 @@ type WrapperConfig<R extends Record<string, Handleable>> = {
|
|
|
46
46
|
[K in keyof R]?: Wrapper<Handler<R[K]>>;
|
|
47
47
|
};
|
|
48
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
|
+
*/
|
|
49
53
|
export interface CommandWrappers extends WrapperConfig<{
|
|
50
54
|
slashCommands: ChatInputCommandInteraction;
|
|
51
55
|
userCommands: UserContextMenuCommandInteraction;
|
|
@@ -53,6 +57,10 @@ export interface CommandWrappers extends WrapperConfig<{
|
|
|
53
57
|
autocompletes: AutocompleteInteraction;
|
|
54
58
|
}> {}
|
|
55
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
|
+
*/
|
|
56
64
|
export interface InteractionWrappers extends WrapperConfig<{
|
|
57
65
|
modal: ModalSubmitInteraction;
|
|
58
66
|
button: ButtonInteraction;
|
|
@@ -63,13 +71,26 @@ export interface InteractionWrappers extends WrapperConfig<{
|
|
|
63
71
|
channelSelectMenu: ChannelSelectMenuInteraction;
|
|
64
72
|
}> {}
|
|
65
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
|
+
*/
|
|
66
77
|
export interface Wrappers extends CommandWrappers, InteractionWrappers {}
|
|
67
78
|
|
|
68
79
|
abstract class Command<T extends BaseApplicationCommandData, U extends CommandInteraction, Z extends boolean = false> {
|
|
80
|
+
/** This is the command data for the configured command. */
|
|
69
81
|
data: T;
|
|
82
|
+
|
|
83
|
+
/** This is the handler for the configured command. */
|
|
70
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). */
|
|
71
87
|
autocomplete: Handler<AutocompleteInteraction> | null;
|
|
72
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
|
+
*/
|
|
73
94
|
constructor({ handler, ...data }: T & { handler: Handler<U> } & (Z extends true ? { autocomplete?: Handler<AutocompleteInteraction> } : {})) {
|
|
74
95
|
if ("autocomplete" in data) {
|
|
75
96
|
const { autocomplete, ...rest } = data;
|
|
@@ -84,56 +105,116 @@ abstract class Command<T extends BaseApplicationCommandData, U extends CommandIn
|
|
|
84
105
|
}
|
|
85
106
|
}
|
|
86
107
|
|
|
108
|
+
/** This is a slash command configuration object. Prefer {@link SlashCommandWithSubcommands} unless you are sure you want to do subcommand routing manually. */
|
|
87
109
|
export class SlashCommand extends Command<Omit<ChatInputApplicationCommandData, "type">, ChatInputCommandInteraction, true> {}
|
|
110
|
+
|
|
111
|
+
/** This is a user context menu command configuration object. */
|
|
88
112
|
export class UserCommand extends Command<Omit<UserApplicationCommandData, "type">, UserContextMenuCommandInteraction> {}
|
|
113
|
+
|
|
114
|
+
/** This is a message context menu command configuration object. */
|
|
89
115
|
export class MessageCommand extends Command<Omit<MessageApplicationCommandData, "type">, MessageContextMenuCommandInteraction> {}
|
|
90
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
|
+
*/
|
|
91
121
|
export class SlashCommandWithSubcommands {
|
|
122
|
+
/** This is the command data for the root command with the options omitted. */
|
|
92
123
|
data: Omit<ChatInputApplicationCommandData, "options" | "type">;
|
|
93
124
|
|
|
125
|
+
/**
|
|
126
|
+
* @param data This is the command data for the root command with the options ommitted.
|
|
127
|
+
*/
|
|
94
128
|
constructor(data: typeof this.data) {
|
|
95
129
|
this.data = data;
|
|
96
130
|
}
|
|
97
131
|
}
|
|
98
132
|
|
|
133
|
+
/** This is a slash command subcommand group configuration object. There is no handler here; the handler is specified in each subcommand. */
|
|
99
134
|
export class SubcommandGroup {
|
|
135
|
+
/** This is the subcommand group data with the options omitted. */
|
|
100
136
|
data: Omit<ApplicationCommandSubGroupData, "options" | "type">;
|
|
101
137
|
|
|
138
|
+
/**
|
|
139
|
+
* @param data This is the subcommand group data with the options omitted.
|
|
140
|
+
*/
|
|
102
141
|
constructor(data: typeof this.data) {
|
|
103
142
|
this.data = data;
|
|
104
143
|
}
|
|
105
144
|
}
|
|
106
145
|
|
|
146
|
+
/** This is a slash command subcommand configuration object. */
|
|
107
147
|
export class Subcommand {
|
|
148
|
+
/** This is the subcommand data for the configured subcommand. */
|
|
108
149
|
data: Omit<ApplicationCommandSubCommandData, "type">;
|
|
150
|
+
|
|
151
|
+
/** This is the handler for the configured subcommand. */
|
|
109
152
|
handler: Handler<ChatInputCommandInteraction>;
|
|
110
153
|
|
|
111
|
-
|
|
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"] }) {
|
|
112
163
|
this.data = data;
|
|
113
164
|
this.handler = handler;
|
|
165
|
+
this.autocomplete = autocomplete ?? null;
|
|
114
166
|
}
|
|
115
167
|
}
|
|
116
168
|
|
|
117
169
|
abstract class ComponentHandler<T extends ModalSubmitInteraction | MessageComponentInteraction> {
|
|
170
|
+
/** This is the handler for the configured interaction. */
|
|
118
171
|
handler: Handler<T>;
|
|
119
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
|
+
*/
|
|
120
177
|
constructor(handler: Handler<T>) {
|
|
121
178
|
this.handler = handler;
|
|
122
179
|
}
|
|
123
180
|
}
|
|
124
181
|
|
|
182
|
+
/** This is a modal submit interaction configuration object. */
|
|
125
183
|
export class ModalHandler extends ComponentHandler<ModalSubmitInteraction> {}
|
|
184
|
+
|
|
185
|
+
/** This is a button component interaction configuration object. */
|
|
126
186
|
export class ButtonHandler extends ComponentHandler<ButtonInteraction> {}
|
|
187
|
+
|
|
188
|
+
/** This is a string select menu component interaction configuration object. */
|
|
127
189
|
export class StringSelectMenuHandler extends ComponentHandler<StringSelectMenuInteraction> {}
|
|
190
|
+
|
|
191
|
+
/** This is a user select menu component interaction configuration object. */
|
|
128
192
|
export class UserSelectMenuHandler extends ComponentHandler<UserSelectMenuInteraction> {}
|
|
193
|
+
|
|
194
|
+
/** This is a role select menu component interaction configuration object. */
|
|
129
195
|
export class RoleSelectMenuHandler extends ComponentHandler<RoleSelectMenuInteraction> {}
|
|
196
|
+
|
|
197
|
+
/** This is a mentionable select menu component interaction configuration object. */
|
|
130
198
|
export class MentionableSelectMenuHandler extends ComponentHandler<MentionableSelectMenuInteraction> {}
|
|
199
|
+
|
|
200
|
+
/** This is a channel select menu component interaction configuration object. */
|
|
131
201
|
export class ChannelSelectMenuHandler extends ComponentHandler<ChannelSelectMenuInteraction> {}
|
|
132
202
|
|
|
203
|
+
/**
|
|
204
|
+
* This is an event handler configuration object.
|
|
205
|
+
*/
|
|
133
206
|
export class EventHandler<T extends keyof ClientEvents> {
|
|
207
|
+
/** This is the event to watch. */
|
|
134
208
|
event: T;
|
|
209
|
+
|
|
210
|
+
/** This is the handler for the configured event type. */
|
|
135
211
|
handler: (...args: ClientEvents[T]) => unknown;
|
|
136
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
|
+
*/
|
|
137
218
|
constructor({ event, handler }: { event: T; handler: (...args: ClientEvents[T]) => unknown }) {
|
|
138
219
|
this.event = event;
|
|
139
220
|
this.handler = handler;
|
|
@@ -161,45 +242,44 @@ async function importAll(
|
|
|
161
242
|
);
|
|
162
243
|
}
|
|
163
244
|
|
|
164
|
-
async function loadSubcommands(directory: string)
|
|
165
|
-
options: ApplicationCommandSubCommandData[];
|
|
166
|
-
handlers: Map<string, Handler<ChatInputCommandInteraction>>;
|
|
167
|
-
}> {
|
|
245
|
+
async function loadSubcommands(directory: string) {
|
|
168
246
|
if (!(await fs.exists(directory))) throw new Error(`Loading subcommands within a group failed: ${directory} is required but could not be found.`);
|
|
169
247
|
|
|
170
248
|
const options: ApplicationCommandSubCommandData[] = [];
|
|
171
249
|
const handlers = new Map<string, Handler<ChatInputCommandInteraction>>();
|
|
250
|
+
const autocompletes = new Map<string, Handler<AutocompleteInteraction>>();
|
|
172
251
|
|
|
173
252
|
await importAll({ directory, recursive: false }, async ({ file, absolutePath, item }) => {
|
|
174
253
|
if (item instanceof Subcommand) {
|
|
175
254
|
options.push({ ...item.data, type: ApplicationCommandOptionType.Subcommand });
|
|
176
255
|
handlers.set(item.data.name, item.handler);
|
|
256
|
+
if (item.autocomplete) autocompletes.set(item.data.name, item.autocomplete);
|
|
177
257
|
} else throw new Error(`Loading commands failed: export from ${absolutePath} (third-level in commands folder) was not an instance of Subcommand.`);
|
|
178
258
|
|
|
179
259
|
if (item.data.name !== file.name.replace(/.[^/.]+$/, ""))
|
|
180
260
|
throw new Error(`Code style enforcement: name exported from ${absolutePath} does not match the filename`);
|
|
181
261
|
});
|
|
182
262
|
|
|
183
|
-
return { options, handlers };
|
|
263
|
+
return { options, handlers, autocompletes };
|
|
184
264
|
}
|
|
185
265
|
|
|
186
|
-
async function loadSubcommandsAndGroups(directory: string)
|
|
187
|
-
options: (ApplicationCommandSubGroupData | ApplicationCommandSubCommandData)[];
|
|
188
|
-
handler: Handler<ChatInputCommandInteraction>;
|
|
189
|
-
}> {
|
|
266
|
+
async function loadSubcommandsAndGroups(directory: string) {
|
|
190
267
|
if (!(await fs.exists(directory))) throw new Error(`Loading subcommands/groups failed: ${directory} is required but could not be found.`);
|
|
191
268
|
|
|
192
269
|
const options: (ApplicationCommandSubGroupData | ApplicationCommandSubCommandData)[] = [];
|
|
193
270
|
const handlers = new Map<string, Handler<ChatInputCommandInteraction>>();
|
|
271
|
+
const autocompletes = new Map<string, Handler<AutocompleteInteraction>>();
|
|
194
272
|
|
|
195
273
|
await importAll({ directory, recursive: false }, async ({ file, absolutePath, relativePath, item }) => {
|
|
196
274
|
if (item instanceof Subcommand) {
|
|
197
275
|
options.push({ ...item.data, type: ApplicationCommandOptionType.Subcommand });
|
|
198
276
|
handlers.set(`/${item.data.name}`, item.handler);
|
|
277
|
+
if (item.autocomplete) autocompletes.set(`/${item.data.name}`, item.autocomplete);
|
|
199
278
|
} else if (item instanceof SubcommandGroup) {
|
|
200
279
|
const subcommands = await loadSubcommands(relativePath.replace(/\.[^/.]+$/, ""));
|
|
201
280
|
options.push({ ...item.data, type: ApplicationCommandOptionType.SubcommandGroup, options: subcommands.options });
|
|
202
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));
|
|
203
283
|
} else
|
|
204
284
|
throw new Error(
|
|
205
285
|
`Loading commands failed: export from ${absolutePath} (second-level in commands folder) was not an instance of SubcommandGroup or Subcommand.`,
|
|
@@ -211,10 +291,37 @@ async function loadSubcommandsAndGroups(directory: string): Promise<{
|
|
|
211
291
|
|
|
212
292
|
return {
|
|
213
293
|
options,
|
|
214
|
-
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),
|
|
215
297
|
};
|
|
216
298
|
}
|
|
217
299
|
|
|
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
|
+
*/
|
|
218
325
|
export async function loadCommands(client: Client<true>, directory: string, config?: { guildId?: string; wrappers?: CommandWrappers }) {
|
|
219
326
|
const commandData: (ChatInputApplicationCommandData | UserApplicationCommandData | MessageApplicationCommandData)[] = [];
|
|
220
327
|
|
|
@@ -236,9 +343,10 @@ export async function loadCommands(client: Client<true>, directory: string, conf
|
|
|
236
343
|
commandData.push({ ...item.data, type: ApplicationCommandType.Message });
|
|
237
344
|
messageCommandHandlers.set(item.data.name, (config?.wrappers?.messageCommands ?? identity)(item.handler));
|
|
238
345
|
} else if (item instanceof SlashCommandWithSubcommands) {
|
|
239
|
-
const { options, handler } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
|
|
346
|
+
const { options, handler, autocomplete } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
|
|
240
347
|
commandData.push({ ...item.data, options });
|
|
241
348
|
slashCommandHandlers.set(item.data.name, (config?.wrappers?.slashCommands ?? identity)(handler));
|
|
349
|
+
slashCommandAutocompletes.set(item.data.name, (config?.wrappers?.autocompletes ?? identity)(autocomplete));
|
|
242
350
|
} else {
|
|
243
351
|
throw new Error(`Loading commands failed: export from ${absolutePath} was not an instance of <Type>Command.`);
|
|
244
352
|
}
|
|
@@ -279,6 +387,38 @@ export async function loadCommands(client: Client<true>, directory: string, conf
|
|
|
279
387
|
return { commands: commandData, slashCommandHandlers, userCommandHandlers, messageCommandHandlers, setCommands: commandDataHasBeenUpdated };
|
|
280
388
|
}
|
|
281
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
|
+
*/
|
|
282
422
|
export async function loadInteractions(
|
|
283
423
|
client: Client,
|
|
284
424
|
directory: string,
|
|
@@ -340,6 +480,23 @@ export async function loadInteractions(
|
|
|
340
480
|
};
|
|
341
481
|
}
|
|
342
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
|
+
*/
|
|
343
500
|
export async function loadEvents(client: Client, directory: string, recursive: boolean = false) {
|
|
344
501
|
const handlers: Partial<{ [K in keyof ClientEvents]: ((...args: ClientEvents[K]) => unknown)[] }> = {};
|
|
345
502
|
const filenames: Partial<{ [K in keyof ClientEvents]: string[] }> = {};
|