A powerful and extendable Discord bot, with it's own module system :3
thevoid.cafe/projects/voidy
1import type { ButtonInteraction, Interaction } from "discord.js";
2import { MessageFlags } from "discord.js";
3import type { InteractionStep, InteractionStepContext } from "../../types/Step";
4import type { ButtonResource } from "../../types/Resource";
5import { runMiddleware } from "../../types/Middleware";
6import { createContext } from "../../core/context";
7
8export const buttonInteractionStep: InteractionStep = {
9 name: "button",
10
11 match(interaction: Interaction): boolean {
12 return interaction.isButton();
13 },
14
15 async handle(interaction: Interaction, { client, cache }: InteractionStepContext): Promise<void> {
16 const i = interaction as ButtonInteraction;
17
18 // Exact match first
19 let button = cache.get<ButtonResource>("button", i.customId);
20
21 // Prefix match for dynamic button IDs (e.g. "guild.MemberLogging-Kick-123")
22 if (!button) {
23 const allButtons = cache.getAll<ButtonResource>("button");
24 for (const [id, btn] of allButtons) {
25 if (i.customId.startsWith(id)) {
26 button = btn;
27 break;
28 }
29 }
30 }
31
32 if (!button) {
33 await i.reply({
34 content: `Sorry, but the button \`${i.customId}\` could not be found.`,
35 flags: [MessageFlags.Ephemeral],
36 });
37 return;
38 }
39
40 const lines = [
41 `# ButtonInteraction`,
42 `### Metadata`,
43 `- **Button:** \`${button.id}\``,
44 `- **Custom ID:** \`${i.customId}\``,
45 `- **User:** \`${i.user.tag}\` (${i.user.id})`,
46 `- **Guild:** \`${i.guild?.name ?? "DM"}\` (${i.guildId ?? "N/A"})`,
47 `- **Channel:** <#${i.channelId}>`,
48 ];
49
50 client.logger.send(lines.join("\n"));
51
52 const ctx = createContext(client, button, i);
53
54 await runMiddleware(button.use, i, client, () => button.execute(ctx));
55 },
56};