Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions playground/src/middlewares/btn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ButtonMiddleware } from "djs-core";

export default new ButtonMiddleware().run(async (interaction) => {
console.log("Just a log from the button middleware");
console.log(interaction.customId);
return true;
});
6 changes: 6 additions & 0 deletions playground/src/middlewares/modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ModalMiddleware } from "djs-core";

export default new ModalMiddleware().run(async (interaction) => {
console.log(interaction.id);
return true;
});
6 changes: 6 additions & 0 deletions playground/src/middlewares/select.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { SelectMiddleware } from "djs-core";

export default new SelectMiddleware().run(async (interaction) => {
console.log("Select Middleware");
return true;
});
10 changes: 10 additions & 0 deletions playground/src/middlewares/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { CommandMiddleware } from "djs-core";

//Try to do most speed as possible because this function is called for each command
export default new CommandMiddleware().run(async (inteaction) => {
if (inteaction.commandName === "ping") {
await inteaction.reply("Pong! from middleware");
return false; // To prevent the command from being executed
}
return true; // To allow the command to be executed
});
17 changes: 12 additions & 5 deletions src/class/BotClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ import SubCommandHandler from "../handlers/SubCommand";
import SubCommandGroup from "./interactions/SubCommandGroup";
import { Handler } from "../handlers/Handler";
import { pathToFileURL } from "node:url";
import ModalMiddleware from "./middlewares/ModalMiddleware";
import SelectMiddleware from "./middlewares/SelectMiddleware";

export default class BotClient extends Client {
logger: Logger = new Logger();
config: Config | null = null;
middlewares: Array<ComandMiddleware | ButtonMiddleware> = [];
middlewares: Array<
ComandMiddleware | ButtonMiddleware | ModalMiddleware | SelectMiddleware
> = [];
constructor() {
super({
intents: [
Expand Down Expand Up @@ -96,7 +100,7 @@ export default class BotClient extends Client {
Promise.resolve(require("../handlers/Modal")),
Promise.resolve(require("../handlers/Event")),
];
const middlewaresPath = path.join(process.cwd(), "src", "middlewares");
const middlewaresPath = path.join(process.cwd(), "middlewares");
if (fs.existsSync(middlewaresPath)) {
await fs.promises
.readdir(middlewaresPath)
Expand All @@ -106,11 +110,14 @@ export default class BotClient extends Client {
this.logger.warn(`The file ${file} is not a middleware`);
return;
}
const middleware = (await import(path.join(middlewaresPath, file)))
.default;
const middleware = (
await import(pathToFileURL(path.join(middlewaresPath, file)).href)
).default.default;
if (
!(middleware instanceof ComandMiddleware) &&
!(middleware instanceof ButtonMiddleware)
!(middleware instanceof ButtonMiddleware) &&
!(middleware instanceof ModalMiddleware) &&
!(middleware instanceof SelectMiddleware)
) {
this.logger.error(`The middleware ${file} is not correct!`);
return;
Expand Down
23 changes: 20 additions & 3 deletions src/class/middlewares/ButtonMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,33 @@

import { ButtonInteraction } from "discord.js";

/**
* fn
* @type {Function} - Function to execute
* @param {CommandInteraction} interaction - The interaction to check
* @returns {boolean} - Return true if accepted event, false otherwise
* @public
*/

type fn = (interaction: ButtonInteraction) => Promise<boolean>;

export default class ButtonMiddleware {
private fn: (interaction: ButtonInteraction) => void = () => {};
private fn: fn | null = null;
constructor() {}

run(fn: (interaction: ButtonInteraction) => void) {
run(fn: fn) {
this.fn = fn;
return this;
}

execute(interaction: ButtonInteraction) {
return this.fn(interaction);
if (this.fn) {
return this.fn(interaction);
}
interaction.reply({
content: "An error occured",
ephemeral: true,
});
return new Promise((resolve) => resolve(false));
}
}
10 changes: 7 additions & 3 deletions src/class/middlewares/CommandMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { ChatInputCommandInteraction } from "discord.js";
* @public
*/

type fn = (interaction: ChatInputCommandInteraction) => boolean;
type fn = (interaction: ChatInputCommandInteraction) => Promise<boolean>;

export default class ComandMiddleware {
private fn: fn | null = null;
Expand All @@ -30,10 +30,14 @@ export default class ComandMiddleware {
* DO NOT USE
* Internal method to execute the function
*/
execute(interaction: ChatInputCommandInteraction) {
execute(interaction: ChatInputCommandInteraction): Promise<boolean> {
if (this.fn) {
return this.fn(interaction);
}
return true;
interaction.reply({
content: "An error occured",
ephemeral: true,
});
return new Promise((resolve) => resolve(false));
}
}
43 changes: 43 additions & 0 deletions src/class/middlewares/ModalMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Copyright (c) 2025 Cleboost
* External contributor can be found on the GitHub
* Licence: on the GitHub
*/

import { ModalSubmitInteraction } from "discord.js";

/**
* fn
* @type {Function} - Function to execute
* @param {ModalSubmitInteraction} interaction - The interaction to check
* @returns {boolean} - Return true if accepted event, false otherwise
* @public
*/

type fn = (interaction: ModalSubmitInteraction) => Promise<boolean>;

export default class ModalMiddleware {
private fn: fn | null = null;
constructor() {}

run(fn: fn) {
this.fn = fn;
return this;
}

/**
* @private
* DO NOT USE
* Internal method to execute the function
*/
execute(interaction: ModalSubmitInteraction): Promise<boolean> {
if (this.fn) {
return this.fn(interaction);
}
interaction.reply({
content: "An error occured",
ephemeral: true,
});
return new Promise((resolve) => resolve(false));
}
}
43 changes: 43 additions & 0 deletions src/class/middlewares/SelectMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Copyright (c) 2025 Cleboost
* External contributor can be found on the GitHub
* Licence: on the GitHub
*/

import { AnySelectMenuInteraction } from "discord.js";

/**
* fn
* @type {Function} - Function to execute
* @param {AnySelectMenuInteraction} interaction - The interaction to check
* @returns {boolean} - Return true if accepted event, false otherwise
* @public
*/

type fn = (interaction: AnySelectMenuInteraction) => Promise<boolean>;

export default class ModalMiddleware {
private fn: fn | null = null;
constructor() {}

run(fn: fn) {
this.fn = fn;
return this;
}

/**
* @private
* DO NOT USE
* Internal method to execute the function
*/
execute(interaction: AnySelectMenuInteraction): Promise<boolean> {
if (this.fn) {
return this.fn(interaction);
}
interaction.reply({
content: "An error occured",
ephemeral: true,
});
return new Promise((resolve) => resolve(false));
}
}
13 changes: 8 additions & 5 deletions src/handlers/Button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import { Events, Interaction } from "discord.js";
import Button from "../class/interactions/Button";
import { pathToFileURL } from "node:url";
import { underline } from "chalk";
import ButtonMiddleware from "../class/middlewares/ButtonMiddleware";

export default class ButtonHandler extends Handler {
// private middleware: Array<CommandMiddleware> = [];
private middleware: Array<ButtonMiddleware> = [];
async load() {
// this.middleware = this.client.middlewares.filter((middleware: unknown) => middleware instanceof CommandMiddleware) as Array<CommandMiddleware>;
this.middleware = this.client.middlewares.filter(
(middleware: unknown) => middleware instanceof ButtonMiddleware,
);

/* eslint-disable no-async-promise-executor */
return new Promise<void>(async (resolve) => {
Expand Down Expand Up @@ -89,9 +92,9 @@ export default class ButtonHandler extends Handler {
Events.InteractionCreate,
async (interaction: Interaction) => {
if (!interaction.isButton()) return;
// for (const middleware of this.middleware) {
// if (!middleware.execute(interaction)) return;
// }
for (const middleware of this.middleware) {
if (!(await middleware.execute(interaction))) return;
}
const button: Button | undefined = this.collection.get(
interaction.customId,
) as Button | undefined;
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/Command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class CommandHandler extends Handler {
async load() {
this.middleware = this.client.middlewares.filter(
(middleware: unknown) => middleware instanceof CommandMiddleware,
) as Array<CommandMiddleware>;
);

/* eslint-disable no-async-promise-executor */
return new Promise<void>(async (resolve) => {
Expand Down Expand Up @@ -63,7 +63,7 @@ export default class CommandHandler extends Handler {
if (interaction.isContextMenuCommand()) return;
if (interaction.options.getSubcommand(false)) return;
for (const middleware of this.middleware) {
if (!middleware.execute(interaction)) return;
if (!(await middleware.execute(interaction))) return;
}
const command: Command = this.collection.get(
interaction.commandName,
Expand Down
17 changes: 9 additions & 8 deletions src/handlers/Modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import { Handler } from "./Handler";
import path from "path";
import fs from "node:fs";
import { Events, Interaction, MessageFlags } from "discord.js";
import CommandMiddleware from "../class/middlewares/CommandMiddleware";
import Modal from "../class/interactions/Modal";
import { pathToFileURL } from "node:url";
import { underline } from "chalk";
import ModalMiddleware from "../class/middlewares/ModalMiddleware";

export default class ModalHandler extends Handler {
private middleware: Array<CommandMiddleware> = [];
private middleware: Array<ModalMiddleware> = [];
async load() {
// this.middleware = this.client.middlewares.filter((middleware: unknown) => middleware instanceof CommandMiddleware) as Array<CommandMiddleware>;
this.middleware = this.client.middlewares.filter(
(middleware: unknown) => middleware instanceof ModalMiddleware,
);

/* eslint-disable no-async-promise-executor */
return new Promise<void>(async (resolve) => {
Expand Down Expand Up @@ -59,10 +61,9 @@ export default class ModalHandler extends Handler {
Events.InteractionCreate,
async (interaction: Interaction) => {
if (!interaction.isModalSubmit()) return;
// for (const middleware of this.middleware) {
// if (!middleware.execute(interaction)) return;
// }

for (const middleware of this.middleware) {
if (!(await middleware.execute(interaction))) return;
}
const select = this.collection.get(interaction.customId) as
| Modal
| undefined;
Expand All @@ -73,7 +74,7 @@ export default class ModalHandler extends Handler {
flags: [MessageFlags.Ephemeral],
});
select.execute(this.client, interaction);
// if (this.client.config?.logger?.log) this.client.logger.info(`Modal ${underline(interaction.customId)} used by ${interaction.user.username} (${interaction.user.id})`);
// if (this.client.config?.logger?.) this.client.logger.info(`Modal ${underline(interaction.customId)} used by ${interaction.user.username} (${interaction.user.id})`);
},
);
}
Expand Down
13 changes: 8 additions & 5 deletions src/handlers/SelectMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import { Events, Interaction, MessageFlags } from "discord.js";
import SelectMenu from "../class/interactions/SelectMenu";
import { pathToFileURL } from "node:url";
import { underline } from "chalk";
import { SelectMiddleware } from "..";

export default class SelectMenuHandler extends Handler {
// private middleware: Array<CommandMiddleware> = [];
private middleware: Array<SelectMiddleware> = [];
async load() {
// this.middleware = this.client.middlewares.filter((middleware: unknown) => middleware instanceof CommandMiddleware) as Array<CommandMiddleware>;
this.middleware = this.client.middlewares.filter(
(middleware: unknown) => middleware instanceof SelectMiddleware,
);

/* eslint-disable no-async-promise-executor */
return new Promise<void>(async (resolve) => {
Expand Down Expand Up @@ -64,9 +67,9 @@ export default class SelectMenuHandler extends Handler {
Events.InteractionCreate,
async (interaction: Interaction) => {
if (!interaction.isAnySelectMenu()) return;
// for (const middleware of this.middleware) {
// if (!middleware.execute(interaction)) return;
// }
for (const middleware of this.middleware) {
if (!(await middleware.execute(interaction))) return;
}
const select = this.collection.get(interaction.customId) as
| SelectMenu
| undefined;
Expand Down
8 changes: 8 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import Button from "./class/interactions/Button";
import SelectMenu from "./class/interactions/SelectMenu";
import Modal from "./class/interactions/Modal";
import EventListner from "./class/interactions/Event";
import CommandMiddleware from "./class/middlewares/CommandMiddleware";
import ButtonMiddleware from "./class/middlewares/ButtonMiddleware";
import ModalMiddleware from "./class/middlewares/ModalMiddleware";
import SelectMiddleware from "./class/middlewares/SelectMiddleware";

export {
BotClient,
Expand All @@ -23,5 +27,9 @@ export {
SelectMenu,
Modal,
EventListner,
CommandMiddleware,
ButtonMiddleware,
ModalMiddleware,
SelectMiddleware,
};
export type { Config };