Middlewares de Comando
En Seyfert, los middlewares son funciones que se llaman antes de que se ejecute el comando. Puedes usarlos para realizar verificaciones, registrar información, etc.
Vamos a crear un middleware básico que registre el comando que se está ejecutando.
Creando un middleware
import { createMiddleware } from "seyfert";
// El tipo genérico le dice al middleware qué información pasará al comandoexport const loggerMiddleware = createMiddleware<void>( (middle) => { // Registrar el comando console.log( `${middle.context.author.username} (${middle.context.author.id}) ejecutó /(${middle.context.resolver.fullCommandName}` );
// Pasar al siguiente middleware middle.next(); });
Ahora vamos a registrar el middleware en Seyfert extendiendo el cliente, pero primero debemos crear un comando para exportar todos nuestros middlewares
import { loggerMiddleware } from "./path/to/logger.middleware";
export const middlewares = { // La clave es el nombre del middleware que se usará para referenciarlo en el comando logger: loggerMiddleware}
import { Client, type ParseMiddlewares, type ParseClient } from "seyfert";import { middlewares } from "./path/to/middlewares";
const client = new Client();
// Registrar los middlewaresclient.setServices({ middlewares: middlewares});
declare module "seyfert" { interface UsingClient extends ParseClient<Client<true>> {}
// Registrar los middlewares en los tipos de Seyfert interface RegisteredMiddlewares extends ParseMiddlewares<typeof middlewares> {}}
Ahora podemos usar el middleware logger
en cualquier comando.
import { Middlewares, Declare, Command, type CommandContext } from "seyfert";
@Declare({ name: "ping", description: "Haz ping al bot"})// Nota que estamos usando el nombre "logger" para referenciar al middleware@Middlewares(["logger"])export default class PingCommand extends Command { async run(ctx: CommandContext) { await ctx.reply("Pong!"); }}
Ahora cada vez que se ejecute el comando ping
, el middleware logger registrará el comando.
Parando middlewares
Como dijimos, puedes usar middlewares para hacer verificaciones, y puedes detener la ejecución del comando si la verificación falla.
Vamos a ver agregando algo de lógica al middleware de registro.
import { createMiddleware } from "seyfert";import { ChannelType } from "seyfert/lib/types";
export const loggerMiddleware = createMiddleware<void>((middle) => { // Registrar el comando console.log( `${middle.context.author.username} (${middle.context.author.id}) ejecutó /(${middle.context.resolver.fullCommandName}` );
// Verificar si el comando se está ejecutando en un servidor if (middle.context.interaction.channel?.type === ChannelType.DM) { return middle.stop("Este comando solo se puede usar en un servidor."); }
// Pasar al siguiente middleware si el comando se está ejecutando en un servidor middle.next();});
Ahora cada vez que el comando ping
se ejecute en un DM, el middleware de registro detendrá la ejecución del comando y enviará el mensaje de error al manejador. Aprende cómo manejar errores aquí.
Por otro lado, podríamos ignorar la interacción (ignorar la interacción y literalmente no hacer nada) usando middle.pass()
import { createMiddleware } from "seyfert";import { ChannelType } from "seyfert/lib/types";
export const loggerMiddleware = createMiddleware<void>((middle) => { // Registrar el comando console.log( `${middle.context.author.username} (${middle.context.author.id}) ejecutó /(${middle.context.resolver.fullCommandName}` );
// Ignorar la interacción si es un DM if (middle.context.interaction.channel?.type === ChannelType.DM) { return middle.pass(); }
// Pasar al siguiente middleware si el comando se está ejecutando en un servidor middle.next();});
Pasando datos
Lo último que podemos hacer con middlewares es pasar datos al comando. Esto puede ser útil para evitar repetir el mismo código en múltiples comandos, por ejemplo, obteniendo datos de la base de datos.
Continuaremos con el middleware de registro y pasaremos algunos datos al comando.
import { createMiddleware } from "seyfert";
// Esta interfaz se usará para que el middleware sepa qué tipo de datos pasará al comandointerface LoggerData { time: number;}
export const loggerMiddleware = createMiddleware<LoggerData>((middle) => { // Registrar el comando console.log(`${middle.context.author.username} (${middle.context.author.id}) ejecutó /(${middle.context.resolver.fullCommandName}`);
// Pasar los datos al comando middle.next({ time: Date.now() });});
Ahora modifiquemos el comando ping
para recibir los datos.
import { Middlewares, Declare, Command, type CommandContext } from "seyfert";
@Declare({ name: "ping", description: "Haz ping al bot"})@Middlewares(["logger"])export default class PingCommand extends Command { async run(ctx: CommandContext<never, "logger">) { const time = ctx.middleware.metadata.logger.time; console.log(time); await ctx.reply({ content: `Pong! Time: ${time}`, }); }}
Middlewares globales
Los middlewares globales siguen la misma regla y estructura explicada anteriormente, con la breve diferencia de que tienen una propiedad unica en el context y se declaran de forma separada
import { Client, type ParseMiddlewares, type ParseClient, type ParseGlobalMiddlewares} from 'seyfert';import { middlewares } from "./path/to/middlewares";import { global } from "./path/to/globals";
const globalMiddlewares: (keyof typeof global)[] = ['logger']
// Register middlewareconst client = new Client({ globalMiddlewares});
client.setServices({ middlewares: { ...global, ...middlewares },});
declare module 'seyfert' { interface RegisteredMiddlewares extends ParseMiddlewares<typeof middlewares & typeof global> {} interface GlobalMetadata extends ParseGlobalMiddlewares<typeof global> {}}