Guards
A guard is a function that will be executed before an handler (event, slash, simple command, etc) is called.
If you're familiar with the back-end and APIs development, think of it as middlewares.
The guard will call the next handler if and only if the function next()
is called within it. Otherwise, it will stop the process.
Simple example of a guard function that is meant to be used alongside the @On('messageCreate')
and that will validate it only if a certain regex is matched:
import type { ArgsOf, GuardFunction } from "discordx"
/**
* Pass only when the message match with a passed regular expression
* @param regex The regex to test
*/
export const Match = (regex: RegExp) => {
const guard: GuardFunction<
| ArgsOf<"messageCreate">
> = async ([message], client, next) => {
if (message.content.match(regex)) next()
}
return guard
}
And use it like this:
import { Client } from "discordx"
import { Discord, On } from "@/decorators"
import { Guard, Match } from "@/guards"
@Discord()
@Category('General')
export default class Tests {
@On('messageCreate')
@Guard(
Match(/foo/gm)
)
async matchFoo(): Promise<void> {
console.log('"foo" found!')
}
}
For more information, head over to the official discordx documentation.
Built-in guards
- Disabled
- OnlyGuild
- Maintenance
- Match
- NotBot
- NSFW
- RateLimit
- UserPermissions
Prevent interaction from running when it is disabled, except for devs.
Usage example:
@Discord()
export default class PingCommand {
@Slash({
name: 'ping',
description: 'Pong!'
})
@Guard(
Disabled()
)
async ping(
interaction: CommandInteraction
) {
interaction.reply('Pong!')
}
}
Prevent the command from running on DM
Usage example:
@Discord()
export default class PingCommand {
@Slash("ping", { description:
'Pong!'
})
@Guard(
GuildOnly()
)
async ping(
interaction: CommandInteraction
): Promise<void> {
interaction.reply('Pong, but only from a channel on a guild!')
}
}
Prevent interactions and simple message commands from running when bot is in maintenance
It is a global guard applied on the bot client directly, you don't have to touch it nor use it!
Pass only when the message content match with a passed regular expression
Arguments
Name | Type | Description | Required |
---|---|---|---|
regex | RegExp | The regex to test | ✔ |
Usage example:
@Discord()
export default class PingCommand {
@On('messageCreate')
@Guard(
Match(/ping/gm)
)
async ping(
interaction: CommandInteraction
): Promise<void> {
interaction.reply('Pong!')
}
}
Prevent other bots to interact with this bot.
It is a global guard applied on the bot client directly, you don't have to touch it nor use it!
Prevent the command from running in non-NSFW channels
Usage example:
@Discord()
export default class PingCommand {
@Slash("ping", { description:
'Pong!'
})
@Guard(
NSFW()
)
async ping(
interaction: CommandInteraction
): Promise<void> {
interaction.reply('Pong, but only from a NSFW channel!')
}
}
This guard will rate limit a user for a specified amount of time.
When set, a user can only call a command x amount of times after that, a cooldown is applied disallowing any more calls to the command until the cooldown is over.
This cooldown starts from the moment the user sends the last message.
If your cooldown is 10 seconds, and you allow 3 calls of your command, the user will have 10 seconds to call it 3 times, with the timer resetting after each call.
Usage example:
@Discord()
export default class RateLimitExample {
/**
* 1 command every 30 seconds with default message
*/
@Slash("rate_limit_1")
@Guard(
RateLimit(TIME_UNIT.seconds, 30)
)
rateLimit1(interaction: CommandInteraction): void {
interaction.reply("It worked!")
}
/**
* Allow 3 command before rate limit of 30 seconds (from last message)
*/
@Slash("rate_limit_3")
@Guard(
RateLimit(
TIME_UNIT.seconds,
30,
{ message: "Please wait `30` seconds!", rateValue: 3 }
)
)
rateLimit3(interaction: CommandInteraction): void {
interaction.reply("It worked!")
}
/**
* Rate limit simple command
*/
@SimpleCommand("rate_limit_simple")
@Guard(
RateLimit(TIME_UNIT.seconds, 10)
)
private async rateLimitSimpleCommand(
{ message }: SimpleCommandMessage
): Promise<void> {
message.reply("It worked!");
}
}
When you are using global commands, but still wish to restrict commands to permissions from roles, then you can use this guard to easily supply an array of Permissions that a user must have in order to execute the command.
The guard can take an array of permissions or an async resolver to the permission array.
Usage example:
@Discord()
export default class PingCommand {
@Slash("ping", { description:
'Pong!'
})
@Guard(
UserPermissions(["ADMINISTRATOR"])
)
async ping(
interaction: CommandInteraction
): Promise<void> {
interaction.reply('Pong, but only admins can invoke it!')
}
}