@hyperneutrino/djs-lite 1.5.1 → 1.6.1

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.
Files changed (2) hide show
  1. package/index.ts +84 -35
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -31,11 +31,40 @@ import path from "node:path";
31
31
 
32
32
  process.on("uncaughtException", (err) => console.error(err));
33
33
 
34
- type Handler<T extends CommandInteraction | AutocompleteInteraction | MessageComponentInteraction | ModalSubmitInteraction> = (
34
+ const identity = <T>(value: T): T => value;
35
+
36
+ type Wrapper<T extends Function> = (fn: T) => T;
37
+
38
+ type Handleable = CommandInteraction | AutocompleteInteraction | MessageComponentInteraction | ModalSubmitInteraction;
39
+
40
+ type Handler<T extends Handleable> = (
35
41
  interaction: T,
36
42
  ...args: T extends MessageComponentInteraction | ModalSubmitInteraction ? (string | undefined)[] : []
37
43
  ) => Awaitable<unknown>;
38
44
 
45
+ type WrapperConfig<R extends Record<string, Handleable>> = {
46
+ [K in keyof R]?: Wrapper<Handler<R[K]>>;
47
+ };
48
+
49
+ export interface CommandWrappers extends WrapperConfig<{
50
+ slashCommands: ChatInputCommandInteraction;
51
+ userCommands: UserContextMenuCommandInteraction;
52
+ messageCommands: MessageContextMenuCommandInteraction;
53
+ autocompletes: AutocompleteInteraction;
54
+ }> {}
55
+
56
+ export interface InteractionWrappers extends WrapperConfig<{
57
+ modal: ModalSubmitInteraction;
58
+ button: ButtonInteraction;
59
+ stringSelectMenu: StringSelectMenuInteraction;
60
+ userSelectMenu: UserSelectMenuInteraction;
61
+ roleSelectMenu: RoleSelectMenuInteraction;
62
+ mentionableSelectMenu: MentionableSelectMenuInteraction;
63
+ channelSelectMenu: ChannelSelectMenuInteraction;
64
+ }> {}
65
+
66
+ export interface Wrappers extends CommandWrappers, InteractionWrappers {}
67
+
39
68
  abstract class Command<T extends BaseApplicationCommandData, U extends CommandInteraction, Z extends boolean = false> {
40
69
  data: T;
41
70
  handler: Handler<U>;
@@ -95,11 +124,11 @@ abstract class ComponentHandler<T extends ModalSubmitInteraction | MessageCompon
95
124
 
96
125
  export class ModalHandler extends ComponentHandler<ModalSubmitInteraction> {}
97
126
  export class ButtonHandler extends ComponentHandler<ButtonInteraction> {}
98
- export class StringSelectHandler extends ComponentHandler<StringSelectMenuInteraction> {}
99
- export class UserSelectHandler extends ComponentHandler<UserSelectMenuInteraction> {}
100
- export class RoleSelectHandler extends ComponentHandler<RoleSelectMenuInteraction> {}
101
- export class MentionSelectHandler extends ComponentHandler<MentionableSelectMenuInteraction> {}
102
- export class ChannelSelectHandler extends ComponentHandler<ChannelSelectMenuInteraction> {}
127
+ export class StringSelectMenuHandler extends ComponentHandler<StringSelectMenuInteraction> {}
128
+ export class UserSelectMenuHandler extends ComponentHandler<UserSelectMenuInteraction> {}
129
+ export class RoleSelectMenuHandler extends ComponentHandler<RoleSelectMenuInteraction> {}
130
+ export class MentionableSelectMenuHandler extends ComponentHandler<MentionableSelectMenuInteraction> {}
131
+ export class ChannelSelectMenuHandler extends ComponentHandler<ChannelSelectMenuInteraction> {}
103
132
 
104
133
  export class EventHandler<T extends keyof ClientEvents> {
105
134
  event: T;
@@ -186,7 +215,7 @@ async function loadSubcommandsAndGroups(directory: string): Promise<{
186
215
  };
187
216
  }
188
217
 
189
- export async function loadCommands(client: Client<true>, directory: string, guildId?: string) {
218
+ export async function loadCommands(client: Client<true>, directory: string, config?: { guildId?: string; wrappers?: CommandWrappers }) {
190
219
  const commandData: (ChatInputApplicationCommandData | UserApplicationCommandData | MessageApplicationCommandData)[] = [];
191
220
 
192
221
  const slashCommandHandlers = new Map<string, Handler<ChatInputCommandInteraction>>();
@@ -198,18 +227,18 @@ export async function loadCommands(client: Client<true>, directory: string, guil
198
227
  await importAll({ directory, recursive: false }, async ({ file, absolutePath, relativePath, item }) => {
199
228
  if (item instanceof SlashCommand) {
200
229
  commandData.push({ ...item.data, type: ApplicationCommandType.ChatInput });
201
- slashCommandHandlers.set(item.data.name, item.handler);
202
- if (item.autocomplete) slashCommandAutocompletes.set(item.data.name, item.autocomplete);
230
+ slashCommandHandlers.set(item.data.name, (config?.wrappers?.slashCommands ?? identity)(item.handler));
231
+ if (item.autocomplete) slashCommandAutocompletes.set(item.data.name, (config?.wrappers?.autocompletes ?? identity)(item.autocomplete));
203
232
  } else if (item instanceof UserCommand) {
204
233
  commandData.push({ ...item.data, type: ApplicationCommandType.User });
205
- userCommandHandlers.set(item.data.name, item.handler);
234
+ userCommandHandlers.set(item.data.name, (config?.wrappers?.userCommands ?? identity)(item.handler));
206
235
  } else if (item instanceof MessageCommand) {
207
236
  commandData.push({ ...item.data, type: ApplicationCommandType.Message });
208
- messageCommandHandlers.set(item.data.name, item.handler);
237
+ messageCommandHandlers.set(item.data.name, (config?.wrappers?.messageCommands ?? identity)(item.handler));
209
238
  } else if (item instanceof SlashCommandWithSubcommands) {
210
239
  const { options, handler } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
211
240
  commandData.push({ ...item.data, options });
212
- slashCommandHandlers.set(item.data.name, handler);
241
+ slashCommandHandlers.set(item.data.name, (config?.wrappers?.slashCommands ?? identity)(handler));
213
242
  } else {
214
243
  throw new Error(`Loading commands failed: export from ${absolutePath} was not an instance of <Type>Command.`);
215
244
  }
@@ -235,10 +264,12 @@ export async function loadCommands(client: Client<true>, directory: string, guil
235
264
  await fs.mkdir(".cache", { recursive: true }).catch(() => null);
236
265
  await fs.writeFile(".cache/command-data.json", JSON.stringify(commandData)).catch(() => null);
237
266
 
238
- if (guildId) {
239
- const testGuild = client.guilds.resolve(guildId);
267
+ if (config?.guildId) {
268
+ const testGuild = client.guilds.resolve(config.guildId);
240
269
  if (!testGuild)
241
- throw new Error(`Provided test guild (${guildId}) can not be found, please make sure the bot you started this project on is in this guild.`);
270
+ throw new Error(
271
+ `Provided test guild (${config.guildId}) can not be found, please make sure the bot you started this project on is in this guild.`,
272
+ );
242
273
  await testGuild.commands.set(commandData);
243
274
  } else {
244
275
  await client.application.commands.set(commandData);
@@ -248,14 +279,21 @@ export async function loadCommands(client: Client<true>, directory: string, guil
248
279
  return { commands: commandData, slashCommandHandlers, userCommandHandlers, messageCommandHandlers, setCommands: commandDataHasBeenUpdated };
249
280
  }
250
281
 
251
- export async function loadInteractions(client: Client, directory: string, argumentSeparator: string = ":") {
282
+ export async function loadInteractions(
283
+ client: Client,
284
+ directory: string,
285
+ config?: {
286
+ argumentSeparator?: string;
287
+ wrappers?: InteractionWrappers;
288
+ },
289
+ ) {
252
290
  const modalHandlers = new Map<string, Handler<ModalSubmitInteraction>>();
253
291
  const buttonHandlers = new Map<string, Handler<ButtonInteraction>>();
254
- const stringSelectHandlers = new Map<string, Handler<StringSelectMenuInteraction>>();
255
- const userSelectHandlers = new Map<string, Handler<UserSelectMenuInteraction>>();
256
- const roleSelectHandlers = new Map<string, Handler<RoleSelectMenuInteraction>>();
257
- const mentionSelectHandlers = new Map<string, Handler<MentionableSelectMenuInteraction>>();
258
- const channelSelectHandlers = new Map<string, Handler<ChannelSelectMenuInteraction>>();
292
+ const stringSelectMenuHandlers = new Map<string, Handler<StringSelectMenuInteraction>>();
293
+ const userSelectMenuHandlers = new Map<string, Handler<UserSelectMenuInteraction>>();
294
+ const roleSelectMenuHandlers = new Map<string, Handler<RoleSelectMenuInteraction>>();
295
+ const mentionableSelectMenuHandlers = new Map<string, Handler<MentionableSelectMenuInteraction>>();
296
+ const channelSelectMenuHandlers = new Map<string, Handler<ChannelSelectMenuInteraction>>();
259
297
 
260
298
  await importAll({ directory, recursive: true }, async ({ absolutePath, item }) => {
261
299
  const handlerKey = path
@@ -263,32 +301,43 @@ export async function loadInteractions(client: Client, directory: string, argume
263
301
  .replace(/\.[^/.]+$/, "")
264
302
  .replace(/\\/g, "/");
265
303
 
266
- if (item instanceof ModalHandler) modalHandlers.set(handlerKey, item.handler);
267
- else if (item instanceof ButtonHandler) buttonHandlers.set(handlerKey, item.handler);
268
- else if (item instanceof StringSelectHandler) stringSelectHandlers.set(handlerKey, item.handler);
269
- else if (item instanceof UserSelectHandler) userSelectHandlers.set(handlerKey, item.handler);
270
- else if (item instanceof RoleSelectHandler) roleSelectHandlers.set(handlerKey, item.handler);
271
- else if (item instanceof MentionSelectHandler) mentionSelectHandlers.set(handlerKey, item.handler);
272
- else if (item instanceof ChannelSelectHandler) channelSelectHandlers.set(handlerKey, item.handler);
304
+ if (item instanceof ModalHandler) modalHandlers.set(handlerKey, (config?.wrappers?.modal ?? identity)(item.handler));
305
+ else if (item instanceof ButtonHandler) buttonHandlers.set(handlerKey, (config?.wrappers?.button ?? identity)(item.handler));
306
+ else if (item instanceof StringSelectMenuHandler)
307
+ stringSelectMenuHandlers.set(handlerKey, (config?.wrappers?.stringSelectMenu ?? identity)(item.handler));
308
+ else if (item instanceof UserSelectMenuHandler) userSelectMenuHandlers.set(handlerKey, (config?.wrappers?.userSelectMenu ?? identity)(item.handler));
309
+ else if (item instanceof RoleSelectMenuHandler) roleSelectMenuHandlers.set(handlerKey, (config?.wrappers?.roleSelectMenu ?? identity)(item.handler));
310
+ else if (item instanceof MentionableSelectMenuHandler)
311
+ mentionableSelectMenuHandlers.set(handlerKey, (config?.wrappers?.mentionableSelectMenu ?? identity)(item.handler));
312
+ else if (item instanceof ChannelSelectMenuHandler)
313
+ channelSelectMenuHandlers.set(handlerKey, (config?.wrappers?.channelSelectMenu ?? identity)(item.handler));
273
314
  else throw new Error(`Loading interactions failed: export from ${absolutePath} was not an instance of <InteractionType>Handler.`);
274
315
  });
275
316
 
276
317
  client.on(Events.InteractionCreate, (interaction) => {
277
318
  if (!interaction.isMessageComponent() && !interaction.isModalSubmit()) return;
278
319
 
279
- const [, userId, path, ...args] = interaction.customId.split(argumentSeparator);
320
+ const [, userId, path, ...args] = interaction.customId.split(config?.argumentSeparator ?? ":");
280
321
  if (!path || (userId && interaction.user.id !== userId)) return;
281
322
 
282
323
  if (interaction.isModalSubmit()) modalHandlers.get(path)?.(interaction, ...args);
283
324
  else if (interaction.isButton()) buttonHandlers.get(path)?.(interaction, ...args);
284
- else if (interaction.isStringSelectMenu()) stringSelectHandlers.get(path)?.(interaction, ...args);
285
- else if (interaction.isUserSelectMenu()) userSelectHandlers.get(path)?.(interaction, ...args);
286
- else if (interaction.isRoleSelectMenu()) roleSelectHandlers.get(path)?.(interaction, ...args);
287
- else if (interaction.isMentionableSelectMenu()) mentionSelectHandlers.get(path)?.(interaction, ...args);
288
- else if (interaction.isChannelSelectMenu()) channelSelectHandlers.get(path)?.(interaction, ...args);
325
+ else if (interaction.isStringSelectMenu()) stringSelectMenuHandlers.get(path)?.(interaction, ...args);
326
+ else if (interaction.isUserSelectMenu()) userSelectMenuHandlers.get(path)?.(interaction, ...args);
327
+ else if (interaction.isRoleSelectMenu()) roleSelectMenuHandlers.get(path)?.(interaction, ...args);
328
+ else if (interaction.isMentionableSelectMenu()) mentionableSelectMenuHandlers.get(path)?.(interaction, ...args);
329
+ else if (interaction.isChannelSelectMenu()) channelSelectMenuHandlers.get(path)?.(interaction, ...args);
289
330
  });
290
331
 
291
- return { modalHandlers, buttonHandlers, stringSelectHandlers, userSelectHandlers, roleSelectHandlers, mentionSelectHandlers, channelSelectHandlers };
332
+ return {
333
+ modalHandlers,
334
+ buttonHandlers,
335
+ stringSelectHandlers: stringSelectMenuHandlers,
336
+ userSelectHandlers: userSelectMenuHandlers,
337
+ roleSelectHandlers: roleSelectMenuHandlers,
338
+ mentionSelectHandlers: mentionableSelectMenuHandlers,
339
+ channelSelectHandlers: channelSelectMenuHandlers,
340
+ };
292
341
  }
293
342
 
294
343
  export async function loadEvents(client: Client, directory: string, recursive: boolean = false) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hyperneutrino/djs-lite",
3
3
  "private": false,
4
- "version": "1.5.1",
4
+ "version": "1.6.1",
5
5
  "module": "index.ts",
6
6
  "type": "module",
7
7
  "devDependencies": {