Skip to main content

Creating a basic command

In order to start registering commands you need to create a subdirectory called commands (lowercase!) in your entry point directory. If you were following Getting Started, it'll be src/commands.

Normally, you'd export one command per file to keep things organized. However, as we support various ways of exporting commands from the file (export class ..., export default class, module.exports = class ... and exports.MyCommand = class ...) you can export multiple commands from the same file.

info

Note that this doesn't create subcommands. We'll cover those in Plugin Subcommands

info

Note that by default Sapphire does not load the listeners required for processing message commands. You will need to construct your SapphireClient with the loadMessageCommandListeners option set to true. For more information see the SapphireClientOptions#loadMessageCommandListeners interface.

Create a ping.js file in your commands folder, which will send a message and then edit it with the elapsed time. Arguments and other features are covered in other pages.

Creating a command class

Let's start by creating the file for the command class. In your commands folder, create a file named ping.js (or ping.mjs / ping.ts if you're using ESM or TypeScript respectively). This command will send a message, and then edit it with the bot's WebSocket latency.

Your project directory should now look something like this:

├── node_modules
├── package.json
└── src
├── commands
│ └── ping.js
└── index.js

With the file created, we can start writing our commands by extending the Command class, from which all commands must be derived.

That said, here is an example of a ping command:

const { Command } = require('@sapphire/framework');

class PingCommand extends Command {
constructor(context, options) {
super(context, {
...options,
name: 'ping',
aliases: ['pong'],
description: 'ping pong'
});
}
}
module.exports = {
PingCommand
};

Let's go over what is defined in the constructor in this code:

  • context: an object that contains file metadata required by the Piece class (which Command extends) in order to function.
  • name: by default, the name of the file without the extension, i.e. ping.js becomes ping, so there's no need to define it.
  • aliases: other ways users can call the command. You can have as many as you want!
  • description: some text that you can use to display when a "help" command is used.

There are many other properties available, all of which can be seen in the CommandOptions interface, but will also be explained in upcoming sections.

Creating the messageRun method

danger

If you want to use message commands in your Sapphire bot, you have to make sure you meet the following prerequisites:

  1. Enable the Message Content Intent under Privileged Gateway Intents on the Discord Developer Portal for your application.
  2. In your Sapphire client options, set the intents property to include the intents GatewayIntentBits.GuildMessages, GatewayIntentBits.Guilds, and GatewayIntentBits.MessageContent.
  3. In your Sapphire client options set loadMessageCommandListeners to true.

All in all your code should look something like this:

const { SapphireClient } = require('@sapphire/framework');
const { GatewayIntentBits } = require('discord.js');

const client = new SapphireClient({
intents: [GatewayIntentBits.MessageContent, GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
loadMessageCommandListeners: true
});

Commands have a messageRun method, which executes the command logic when it is invoked from a message. Define this below the command's constructor:

const { Command } = require('@sapphire/framework');

class PingCommand extends Command {
constructor(context, options) {
// ...
}

async messageRun(message) {
const msg = await message.channel.send('Ping?');

const content = `Pong from JavaScript! Bot Latency ${Math.round(this.container.client.ws.ping)}ms. API Latency ${msg.createdTimestamp - message.createdTimestamp}ms.`;

return msg.edit(content);
}
}
module.exports = {
PingCommand
};

Any discord.js code can be executed here since the Sapphire Framework is an extension of it. The command can be triggered with @bot ping or @bot pong (custom prefixes are mentioned in other documents).

Resulting code

Once you've set up the constructor and the messageRun method, your code should look like this:

const { Command } = require('@sapphire/framework');

class PingCommand extends Command {
constructor(context, options) {
super(context, {
...options,
name: 'ping',
aliases: ['pong'],
description: 'ping pong'
});
}

async messageRun(message) {
const msg = await message.channel.send('Ping?');

const content = `Pong from JavaScript! Bot Latency ${Math.round(this.container.client.ws.ping)}ms. API Latency ${msg.createdTimestamp - message.createdTimestamp}ms.`;

return msg.edit(content);
}
}
module.exports = {
PingCommand
};

Creating subcommands

note

For handling subcommands, please refer to the Sapphire Plugin Subcommands documentation.