Skip to main content
run receives interaction, user, options… and also member, guild and channel. These are the structures of ChapterJS: objects that wrap what Discord sent, with readable names and actions. Everything you do in a bot goes through them, so this page is a guided tour. It uses /whois and a new command, /warn.

The object run receives

In a command used in a server: User and member are the same person seen from two sides. A User is the account: username, avatar, when it was created. A GuildMember is that account in one server: the nickname, the roles, what they may do here, when they joined. Someone in three servers is one user and three members. In a server, member, guild and channel are always there. You never write guild?.name or check for null: the framework guarantees them, and the editor knows it. (A command can also work in private messages, where there is no server; that is a where setting shown in the Guide.)

Reading costs nothing

Open /whois again and show more:
src/commands/whois.ts
Two kinds of things happen here, and the difference matters:
  • Properties read what the bot already knows. guild.name, member.roles, member.highestRole: no request to Discord, the answer is immediate. The bot remembers its servers, their channels and roles, because Discord told it when it connected and tells it every change.
  • fetch…() methods ask Discord. guild.fetchMember(user) gets a member the bot may not know yet, and await is needed. The bot answers from memory when it can and asks Discord otherwise.
The rule to remember: a property never sends a request, and a fetch…() does. Anything you can read without await is free.
Why fetchMember for a member, while guild.name is there at once? A server can have millions of members, so a bot can’t remember all of them: it keeps the ones it saw recently. Servers, channels and roles are few, so it keeps them all. The page Memory and limits says exactly what is kept.
member.joinedAt is Date | null because Discord does not always send it: the ?. and ?? are honest. In ChapterJS, a value is nullable only when it may really be missing; what can’t be missing never is.

Actions: asking Discord to do something

Every structure has methods that do something: channel.send(), member.addRole(), member.kick(), message.react(). They send a request, so they are awaited, and they can fail, since Discord may refuse. Here is /warn, which times someone out for ten minutes and tells them in private:
src/commands/warn.ts
Things to see:
  • permissions: ['ModerateMembers'] says who may use the command. Discord hides it from the others, and the framework checks again when it is used: someone without the permission reads “You need the Moderate Members permission to use this command.” and run never starts. Permissions are written by name, and the editor completes them.
  • member.isHigherThan(target) compares roles: Discord refuses to moderate someone whose highest role is above yours, so checking first gives a better answer than letting Discord refuse.
  • timeout(duration, reason) takes milliseconds, and a reason that goes to the audit log of the server. Actions that appear in the audit log all take a reason.
  • try / catch around send(). Some people close their private messages; Discord then refuses with the code 50007. The error is a DiscordApiError, and its code is the thing to test: the text may change, the code never does. Anything else is rethrown, so that a real problem is reported.

The structures you will meet

A few properties worth knowing by heart: user.displayName (the name to show), user.username (the unique handle), member.displayName (the nickname when there is one), guild.me (your bot as a member of this server, always there), guild.everyoneRole, channel.name. Channels come in kinds, and only some can receive a message. When you have a channel without knowing its kind, channel.isTextBased() tells you whether it can:
Every structure has a page in the Reference with all its properties and methods; GuildMember is a good one to skim.

Mentions in a text

Put a structure in a text and it becomes a mention: ${member} pings the member, ${channel} links the channel, ${role} pings the role. /whois could answer ${member} joined on... to make the name clickable.

Recap

  • user is the account, member the person in this server, guild the server, channel the channel; in a server, none of them is ever missing.
  • A property reads what the bot knows, at once; a fetch…() asks Discord.
  • Actions are awaited and can fail; DiscordApiError.code says why.
  • permissions on a command decides who may use it, before run.

Sending messages

Texts, embeds, files, mentions, polls, and what to do with a message once sent.

Reference: GuildMember

Every property and action of a member.