Skip to main content
Three events are about messages: messageCreate, messageUpdate and messageDelete. A messageCreate event runs every time someone writes in a server your bot is in:
src/events/ping.ts
That is all. By default, the file only runs for messages written by people, in servers: not for bots (yours included), not for webhooks, and not for private messages. So message.guild, message.channel and message.member are always there, and you never write if (message.author.bot) return;.
src/events/levels.ts
The full list of what a message has is in Message; the three events, with what they give, are in the reference.

Message Content Intent

Reading what people write is a privileged intent: messageCreate and messageUpdate need the Message Content Intent, enabled for your bot in the Developer Portal. Without it, the messages written by other people come without their text: message.content is empty. chapterjs dev tells you when it is missing and waits for you to enable it, like for every intent. messageDelete does not need it.

Where a file listens

where says where a declaration listens. Write it next to name, and what your function receives follows it:
The file runs for the messages of servers. The message is a MemberMessage: guild, channel and member are always there.
src/events/hello.ts
Each file decides for itself: in the same folder, one file can listen in servers and another in private messages.
chapterjs dev runs your bot in your test server only, so a file with where: 'dm' can’t be tried there. It tells you once:
Private messages reach your bot with chapterjs start.

Messages of bots and webhooks

By default, messageCreate and messageUpdate ignore the messages written by bots (this one included) and by webhooks: a bot that answers bots can end up answering itself, or another bot, forever. To receive them too, pass { bots: true }:
src/events/relay.ts
With bots: true, the message of a server is a GuildMessage: guild and channel are still there, but a webhook is not a member of the server, so message.member can be null. Both options go together: { bots: true, where: 'both' } receives everything, as a GuildMessage | PrivateMessage.

A deleted message

A message that was deleted no longer exists, so the message of messageDelete is what is left of it: its id, the channel it was in, and before, the message itself as it was when the bot remembered it.
src/events/log.ts
In a server, guild and message.channel (a GuildTextBasedChannel) are always there. message.before is null when the bot did not remember the message: the bot remembers no message today, so always use message.id. messageDelete takes where like the other two, and what your function receives follows it: with 'dm', there is no guild nor message.guildId at all; with 'both', guild is null for a private message and tells the two apart. It has no bots option: a deleted message has no author anymore.

Intents follow your options

Discord sends the messages of servers and private messages through two different intents, and ChapterJS only asks for what your files listen to: a file with where: 'dm' asks for private messages only, a file without where for the messages of servers only, and a file with 'both' for both.

A channel the bot does not know

A message can arrive in a channel your bot has never seen, like a thread created before it connected. ChapterJS then asks Discord for that channel once, before running your files, so that message.channel is always there. Everything that happens in that channel meanwhile waits for the same answer, and is delivered in the order it happened. When Discord refuses, the event is not delivered and you are told:

Sending messages

Everything a reply can contain: text, embeds, files, polls.

What your bot remembers

Members, users and messages: what is kept, and how little it costs.