Creators
Main base structures for creating commands and systems
On this base, to create commands and systems you must use the creator functions, which are createCommand
, createEvent
and createResponder
.
When executing these functions passing the data of the respective structures, they will be created and registered.
You can set some options in the index
file of the discord
folder, see:
export const { createCommand, createEvent, createResponder } = setupCreators();
This function receives options and returns the creators of commands, events and responders for you to use. By exporting this return you can import them at any time using the base import alias:
import { createCommand, createEvent, createResponder } from "#base";
Command Options
You can set some command options in the setupCreators
function:
Set what the default permissions will be for all commands, if none are defined with the defaultMemberPermissions
option (It is the same permissions array as the command).
/* ... */ setupCreators({
commands: {
defaultMemberPermissions: ["SendMessages", "Connect"]
},
});
This way, when you create a command and do not set any default member permissions, what you set in the setupCreators
function will be the default for all commands.
createCommand({
name: "ping",
description: "Responde com pong",
type: ApplicationCommandType.ChatInput,
// defaultMemberPermissions: [] <-- Not set!
// But by default it will be registered in the application with ["SendMessages", "Connect"]
async run(interaction){
// ...
}
})
You can set multiple guild IDs that you want to register your bot's commands with the guilds
option.
import { env } from "#env";
/* ... */ setupCreators({
commands: {
guilds: [env.MAIN_GUILD_ID, "537817462272557057"]
},
});
So, instead of registering the commands globally in the application, they will be registered only in the guilds, whose IDs were passed to this option.
You can set a middleware
function that will be executed before the commands` run function
/* ... */ setupCreators({
commands: {
async middleware(interaction){
console.log("Command executed:", interaction.commandName);
}
},
});
You can do a lot with this, such as displaying standardized logs for all executed commands, injecting additional information into the interaction, or even blocking execution based on checks.
You can call the block
function to block the execution of commands.
/* ... */ setupCreators({
commands: {
async middleware(interaction, block){
if (blockedUsers.includes(interaction.user.id)){
interaction.reply({ content: "You cannot use any commands!" });
block();
return;
}
}
},
});
It is possible to set a custom error handler for commands with the onError
function
/* ... */ setupCreators({
commands: {
async onError(error, interaction){
// ...
}
},
});
You can check what type of error it is and choose whether or not to send custom messages.
It is extremely important to use await
on Promises when their run is async
, so that the command error handler can catch it correctly.
createCommand({
name: "ping",
description: "Replies with pong",
async run(interaction){
await interaction.deferReply({ flags: ["Ephemeral"], });
const data = await dbOperation();
await interaction.editReply({ content: `Data: ${data.toString()}` });
}
})
If for some reason no handler is found for the command, the onNotFound
function will be called.
/* ... */ setupCreators({
commands: {
async onNotFound(interaction){
interaction.reply({ flags: ["Ephemeral"],,
content: "Command not found. Contact the team!"
});
}
},
});
This option makes the command logs more detailed, this way you can be sure that your commands were registered as it displays the direct response from the API.
/* ... */ setupCreators({
commands: {
verboose: true
},
});
See the example below with the commands that come by default:
● Awes online ✓
└ 2 commands successfully registered globally!
└ {/} 1342179401697333281 CREATED ping > Awes application > created at: 1:01:45 PM
└ {/} 1342179401252470856 CREATED counter > Awes application > created at: 1:01:45 PM
The response displays the command ID in the application or guild, its name and the time it was created.
Responder Options
You can set some responder options in the setupCreators
function:
You can set a middleware
function that will be executed before the responders` run function
/* ... */ setupCreators({
responders: {
async middleware(interaction, params){
console.log("Comand executed:", interaction.customId);
console.log("Params:", params);
}
},
});
Just like with commands, you can do a lot with this, such as displaying standardized logs for all executed responders, injecting additional information into the interaction, or even blocking execution based on checks.
You can run the block
function to block responders from executing.
/* ... */ setupCreators({
responders: {
async middleware(interaction, _params, block){
if (interaction.isButton() && blockedUsers.includes(interaction.user.id)){
interaction.reply({ content: "You can't click any buttons!" });
block();
return;
}
}
},
});
It is possible to set a custom error handler to respond with the onError
function.
/* ... */ setupCreators({
commands: {
async onError(error, interaction){
// ...
}
},
});
You can check what type of error it is and choose whether or not to send custom messages.
It is extremely important to use await
on Promises when their run is async
, so that the responder error handler can catch it correctly.
createResponder({
customId: "data/refresh",
types: [ResponderType.Button], cache: "cached",
async run(interaction){
await interaction.deferUpdate();
const data = await dbOperation();
await interaction.followUp({
flags: ["Ephemeral"],, content: `Dados: ${data.toString()}`
});
}
})
If no handler is found for the component or modal, the onNotFound
function will be called.
/* ... */ setupCreators({
responders: {
async onNotFound(interaction){
interaction.reply({ flags: ["Ephemeral"],,
content: "This has not been set up yet. Contact the team!"
});
}
},
});
Be careful! If you use component collectors or modals in any command, this function will still be called, as it looks for a handler created with the createResponder
function. So it is important to check if the interaction has already been responded to or wait a short time before actually responding.
Event options
You can set some event options in the setupCreators
function:
You can set a middleware
function that will be executed before the events run
function
/* ... */ setupCreators({
events: {
async middleware(event){
console.log("Event", event.name);
}
},
});
As with commands and responders, you can do a lot with this, such as displaying standardized logs for all executed events, injecting additional information into the arguments of specific events, or even blocking execution based on checks.
In the first argument, an object with the event data is received, where name
is the name of the event emitted and args
are the arguments of that event, so checking what the name of the event is, the typing of the arguments is automatically defined:
/* ... */ setupCreators({
events: {
async middleware(event) {
if (event.name === "guildMemberUpdate"){
const [oldMember, newMember] = event.args;
// ...
return;
}
if (event.name === "guildAuditLogEntryCreate"){
const [entry, guild] = event.args;
// ...
return;
}
if (event.name === "messageCreate"){
const [message] = event.args;
// ...
return;
}
},
},
});
You can run the block
function to block the execution of events.
/* ... */ setupCreators({
responders: {
async middleware(event, block){
if (event.name === "messageDelete"){
const [message] = event.args;
if (message.inGuild() && message.author.id == message.guild.id){
block();
return;
}
}
}
},
});
In the case of events, it is also possible to pass tags as arguments to the block function. This way, you can have 3 events of the same type, for example messageCreate
, but block only those with the previously defined tags:
createEvent({
name: "Morning workflow",
event: "messageCreate",
tags: ["morning"],
async run(message) {
// ...
},
});
createEvent({
name: "Night workflow",
event: "messageCreate",
tags: ["night"],
async run(message) {
// ...
},
});
createEvent({
name: "Messages Workflow",
event: "messageCreate",
async run(message) {
// ...
},
});
You can pass as many tags as you want to the block function.
// ...
block("morning", "night", "foo", "bar", "baz")
// ...
All events that contain any of the tags passed as arguments to the block function will not be executed.
It is possible to set a custom error handler for events with the onError
function
/* ... */ setupCreators({
events: {
async onError(error, interaction){
// ...
}
},
});
You can check what type of error it is and choose whether or not to send custom messages.
It is extremely important to use await
on Promises when their run is async
, so that the event error handler can catch it correctly.
createEvent({
name: "Register workflow",
event: "guildMemberAdd",
async run(member) {
const document = await db.members.create({
id: member.id,
username: member.user.username,
guildId: member.guild.id
});
// ...
},
})