Commands
Overview
Commands in glyria.js are file-based. Every file in src/commands/ is automatically loaded and registered on Discord at startup — no manual registration needed.
Each command file exports a command instance as default:
// src/commands/ping.ts
export default new GlyriaCommand()
.setName("ping")
.setDescription("Pong!")
.execute(async (ctx) => {
await ctx.reply({ content: "Pong!" })
})
GlyriaCommand, GlyriaUserCommand and GlyriaMessageCommand are available globally — no import needed.Slash commands
Options
Add typed options to your command with the add*Option methods:
export default new GlyriaCommand()
.setName("hello")
.setDescription("Say hello to someone")
.addUserOption((option) =>
option
.setName("user")
.setDescription("The user to greet")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("message")
.setDescription("A custom message")
.setRequired(false)
)
.execute(async (ctx) => {
await ctx.reply({ content: "Hello!" })
})
Available option types
| Method | Type |
|---|---|
addStringOption | Text input |
addIntegerOption | Integer number |
addNumberOption | Decimal number |
addBooleanOption | True / False |
addUserOption | Discord user |
addRoleOption | Discord role |
Each option exposes:
| Method | Description |
|---|---|
.setName(name) | Option name (lowercase, no spaces) |
.setDescription(desc) | Option description |
.setRequired(bool) | Whether the option is required |
Subcommands
Group related actions under a single command with .addSubCommand():
export default new GlyriaCommand()
.setName("moderation")
.setDescription("Moderation commands")
.addSubCommand((cmd) =>
cmd
.setName("ban")
.setDescription("Ban a user")
.addUserOption((option) =>
option
.setName("user")
.setDescription("User to ban")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("reason")
.setDescription("Reason of the ban")
.setRequired(false)
)
.execute(async (ctx) => {
// handle ban
})
)
.execute(async (ctx) => {
// handle base command
})
Subcommand groups
For deeper organization, group subcommands with .addSubCommandGroup():
export default new GlyriaCommand()
.setName("moderation")
.setDescription("Moderation commands")
.addSubCommand((cmd) =>
cmd
.setName("ban")
.setDescription("Ban a user")
.addUserOption((option) =>
option
.setName("user")
.setDescription("User to ban")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("reason")
.setDescription("Reason of the ban")
.setRequired(false)
)
.execute((ctx) => {
console.log("ban command")
})
)
.addSubCommandGroup((group) =>
group
.setName("config")
.setDescription("Configuration commands")
.addSubCommand((cmd) =>
cmd
.setName("logs")
.setDescription("Configure logs")
.addBooleanOption((option) =>
option
.setName("enabled")
.setDescription("Enable logs")
.setRequired(true)
)
.execute(async (ctx) => {
// handle logs config
})
)
)
.execute((ctx) => {
ctx.reply({ content: "Moderation command executed!" })
})
This generates the following Discord command structure:
/moderation ban <user> [reason]
/moderation config logs <enabled>
Context menus
Context menus appear when a user right-clicks on a user or a message, under the Apps section. They have no description, no options, and no subcommands.
User context menu
Triggered by right-clicking on a user. The handler receives a UserContextMenuCommandInteraction — the targeted user is available via ctx.targetUser.
// src/commands/profile.ts
export default new GlyriaUserCommand()
.setName("View profile")
.execute(async (ctx) => {
const user = ctx.targetUser
await ctx.reply({
content: `Profile of ${user.username}`,
flags: djs.MessageFlags.Ephemeral,
})
})
Message context menu
Triggered by right-clicking on a message. The handler receives a MessageContextMenuCommandInteraction — the targeted message is available via ctx.targetMessage.
// src/commands/translate.ts
export default new GlyriaMessageCommand()
.setName("Translate")
.execute(async (ctx) => {
const message = ctx.targetMessage
await ctx.reply({
content: `Translating: "${message.content}"`,
flags: djs.MessageFlags.Ephemeral,
})
})
Permissions
Restrict any command to members with specific Discord permissions using .setPermissions(). Works on GlyriaCommand, GlyriaUserCommand and GlyriaMessageCommand:
export default new GlyriaCommand()
.setName("ban")
.setDescription("Ban a user")
.setPermissions(djs.PermissionsBitField.Flags.BanMembers)
.execute(async (ctx) => {
// only members with BanMembers permission can use this
})
PermissionsBitField and MessageFlags are available via the djs namespace — no import needed.Metadata
Attach custom data to a command with .setMetaData(). Works on GlyriaCommand, GlyriaUserCommand and GlyriaMessageCommand. Glyria stores it as-is and never interprets it — it's entirely up to you.
export default new GlyriaCommand()
.setName("ban")
.setDescription("Ban a user")
.setMetaData({
category: "moderation",
cooldown: 5000,
premium: false,
guildOnly: true,
})
.execute(async (ctx) => {
// your logic here
})
useCommands()
useCommands() returns the full list of loaded commands with their metadata. It's available globally and always reflects the current state of the bot.
const commands = useCommands()
// [
// { name: "ban", description: "Ban a user", meta: { category: "moderation", cooldown: 5000 } },
// { name: "ping", description: "Pong!", meta: {} },
// { name: "View profile", description: "", meta: {} },
// ]
A common use case is building a /help command organized by category:
export default new GlyriaCommand()
.setName("help")
.setDescription("List all commands")
.execute(async (ctx) => {
const commands = useCommands()
const byCategory = commands.reduce((acc, cmd) => {
const cat = (cmd.meta.category as string) ?? "general"
acc[cat] ??= []
acc[cat].push(cmd)
return acc
}, {} as Record<string, typeof commands>)
// build your embed from byCategory
})
Organizing files
Subfolders inside src/commands/ are for organization only — every file at any depth is loaded automatically.
src/commands/
ping.ts
moderation/
ban.ts
kick.ts
config/
advanced/
logs.ts
context-menus/
profile.ts
translate.ts
GlyriaCommand.
