Skip to main content
You wrote /ping in the tour. Now write a command of your own, /dice, which rolls a die. It is four lines of logic, and it is a chance to understand each part of a command file: what it declares, what run receives, and what happens when something is wrong.

The file

Create src/commands/dice.ts:
src/commands/dice.ts
Save it with the bot running. The terminal says:
Type /dice in your test server. It is there, with its description under its name, and it answers.

Line by line

import { command } from 'chapterjs'. The function that makes a command. It takes an object describing the command and returns something the framework recognises as one. export default. The file hands its command to the framework by exporting it. The framework loads every file of src/ and keeps what they export made with command(), event(), button()…: a default export, or a named one (export const dice = command(...)), it does not matter. What is exported and is none of these is yours. description. The text Discord shows under the name in the / menu, 1 to 100 characters. Besides run, it is the only thing a command needs. (A later chapter moves it to the language files.) async run({ interaction, user }). The function that runs when someone uses the command. It receives one object, and you take out of it what you need: here interaction, the use of the command, and user, the person who used it. The next pages go through everything else that object holds. interaction.reply(...). The answer. Discord shows it under the command, with the name of the person who used it. await. Sending the answer is a request to Discord, which takes time. await waits for it, and lets the framework know when your function is really done. Always await what you ask Discord to do: an error in a request you did not await is reported without the line of your code that caused it.

The command has to answer

Discord waits for an answer to every use of a command, and tells the person “The application did not respond” when none comes. Try it: comment out the reply line, save, and use /dice.
The framework can’t answer for you (it does not know what to say), but it tells you right away, with the file. Put the line back.

What is checked before Discord sees it

Discord has rules for commands: a name is lowercase, with letters, digits, - and _ only, 32 characters at most; a description is 1 to 100 characters; and so on. Breaking one would make Discord refuse the whole list of your commands. So the framework checks each file when it loads, and explains in your terms. Change name to 'Dice' and save:
Put the name back. Now remove description and save:
Each time, the file is left out until it is fixed, and the other commands keep working. Most of these mistakes are underlined in your editor before you even save: command() only accepts what exists.

Why slash commands and not messages

An older kind of bot reads every message and reacts to the ones that start with !, like !dice. ChapterJS does not do that for commands, and Discord discourages it, for good reasons:
  • A slash command is discoverable: people type / and see what the bot can do, with descriptions and options, without reading a help page.
  • Discord validates what people type before sending it to the bot: a missing option or a wrong value never reaches your code.
  • Reading every message needs the Message Content Intent, a privileged one, while slash commands need nothing.
  • Discord shows a command only to the people who have the permissions it asks for.
You will still read messages in a later chapter, for things that are not commands, like reacting to a word.

Recap

  • A command is command({ name, description, run }), exported from any file of src/.
  • run receives one object; take interaction, user and the rest out of it.
  • await interaction.reply(...) answers; a command that does not answer is a warning with the file.
  • Every rule of Discord is checked when the file loads, with a message saying what to write.

Options

Let people choose the number of sides, and receive it typed.

Guide: Commands

Subcommands, permissions, private messages, in short.