Command Middlewares
On Seyfert middleware are functions that are called before the command is executed. You can use them to do verifications, logging, etc.
Let’s create a basic middleware that logs the command that is being executed.
Creating a middleware
1import { createMiddleware } from "seyfert";2
3// The generic type tells the middleware what information it will pass to the command4export const loggerMiddleware = createMiddleware<void>(5 (middle) => {6 // Log the command7 console.log(8 `${middle.context.author.username} (${middle.context.author.id}) ran /(${middle.context.resolver.fullCommandName}`9 );10
11 // Pass to the next middleware12 middle.next();13 }14);
Now let’s register the middle on seyfert extending the client but first we should create a command to export all our middleware
1import { loggerMiddleware } from "./path/to/logger.middleware";2
3export const middlewares = {4 // The key is the name of the middleware which will be used to reference it on the command5 logger: loggerMiddleware6}
1import { ParseLocales, Client, ParseMiddlewares, ParseClient } from "seyfert";2import { middlewares } from "./path/to/middlewares";3
4const client = new Client();5
6// Register the middlewares7client.setServices({8 middlewares: middlewares9});10
11declare module "seyfert" {12 interface UsingClient extends ParseClient<Client<true>> {}13
14 // Register the middlewares on seyfert types15 interface RegisteredMiddlewares16 extends ParseMiddlewares<typeof middlewares> {}17}
Now we can use the logger
middleware on any command.
1import { Middlewares, Declare, Command } from "seyfert";2
3@Declare({4 name: "ping",5 description: "Ping the bot"6})7// Note we are using the name "logger" to reference the middleware8@Middlewares(["logger"])9export default class PingCommand extends Command {10 async run(ctx: CommandContext) {11 await ctx.reply("Pong!");12 }13}
Now every time the ping
command is executed, the logger middleware will log the command.
Stop middleware
As we said you can use middlewares to do verifications, and you can stop the execution of the command if the verification fails.
Let’s take a look adding some logic to the logger middleware.
1import { createMiddleware } from "seyfert";2
3export const loggerMiddleware = createMiddleware<void>((middle) => {4 // Log the command5 console.log(6 `${middle.context.author.username} (${middle.context.author.id}) ran /(${middle.context.resolver.fullCommandName}`7 );8
9 // Check if the command is being executed in a guild10 if (middle.context.interaction.channel?.type === ChannelType.DM) {11 return middle.stop("This command can only be used in a guild.");12 }13
14 // Pass to the next middleware if the command is being executed in a guild15 middle.next();16});
Now every time the ping
command is executed in a DM, the logger middleware will stop the execution of the command and send the error message to the handler. Learn how to handle errors here.
On the other hand we could skip the interaction (ignore the interaction and literally do nothing) by using middle.pass()
1import { createMiddleware } from "seyfert";2
3export const loggerMiddleware = createMiddleware<void>((middle) => {4 // Log the command5 console.log(6 `${middle.context.author.username} (${middle.context.author.id}) ran /(${middle.context.resolver.fullCommandName}`7 );8
9 // Ignore the interaction if it's a DM10 if (middle.context.interaction.channel?.type === ChannelType.DM) {11 return middle.pass();12 }13
14 // Pass to the next middleware if the command is being executed in a guild15 middle.next();16});
Passing data
The last thing we can do with middlewares is to pass data to the command. This can be useful to avoid repeating the same code in multiple commands for example fetching data from the database.
We will continue with the logger middleware and pass some data to the command.
1import { createMiddleware } from "seyfert";2
3// This interface will be used to let the middleware know what type of data it will pass to the command4interface LoggerData {5 time: number;6}7
8export const loggerMiddleware = createMiddleware<LoggerData>((middle) => {9 // Log the command10 console.log(`${middle.context.author.username} (${middle.context.author.id}) ran /(${middle.context.resolver.fullCommandName}`);11
12 // Pass the data to the command13 middle.next({ time: Date.now() });14});
Now let’s modify the ping
command to receive the data.
1import { Middlewares, Declare, Command } from "seyfert";2
3@Declare({4 name: "ping",5 description: "Ping the bot"6})7@Middlewares(["logger"])8export default class PingCommand extends Command {9 async run(ctx: CommandContext<never, "logger">) {10 const time = ctx.metadata.logger.time;11 console.log(time);12 await ctx.reply({13 content: `Pong! Time: ${data.time}`,14 });15 }16}