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
- 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, andawaitis needed. The bot answers from memory when it can and asks Discord otherwise.
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
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.” andrunnever 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 areason.try/catcharoundsend(). Some people close their private messages; Discord then refuses with the code50007. The error is aDiscordApiError, and itscodeis 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:
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
useris the account,memberthe person in this server,guildthe server,channelthe 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.codesays why. permissionson a command decides who may use it, beforerun.
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.