> ## Documentation Index
> Fetch the complete documentation index at: https://www.chapterjs.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> React to what happens on Discord: a new member, a deleted channel, a message

An event is something that happens on Discord. To react to one, declare it with `event()` in any file of `src/`, and export it:

```ts src/events/welcome.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { event } from 'chapterjs';

export default event({
  name: 'memberJoin',
  async run({ member, guild }) {
    await member.send(`Welcome to ${guild.name}, ${member.displayName}!`);
  },
});
```

That is all. `chapterjs dev` finds the declaration and runs your function every time someone joins your test server. Nothing to register, no list to keep up to date, and no type to write: your editor already knows that `member` is a [`GuildMember`](https://www.chapterjs.org/reference/member) and `guild` a [`Guild`](https://www.chapterjs.org/reference/guild).

Every event gives the same two things: **what it is about** (`member` here, `message`, `role`, `reaction`, `voice`...) and **the server** it happened in, `guild`. Nothing else, plus `t` when your project has [languages](https://www.chapterjs.org/translated-messages.md). What each event gives is listed in one table in the [reference](https://www.chapterjs.org/reference/events.md#what-each-event-gives).

## The name is the event

* **`name` is the event.** It is one of the [events](https://www.chapterjs.org/reference/events.md), and your editor offers them as you type; another word is underlined, and reported with the closest event name when the file loads.
* **A declaration is one reaction.** Where the file is and what it is called are yours to choose: `src/events/welcome.ts`, or `src/welcome/welcome.ts`, or `src/welcome.ts`, or next to the command it goes with, as the `tickets` template does. Declare as many as you want, in one file or several: they all run.
* **The import is the same everywhere.** `name` is what tells `event` what your function receives: a member for `'memberJoin'`, a role for `'roleDelete'`. The same line, `import { event } from 'chapterjs'`, works in every file.

## Several reactions to one event

When an event happens, every declaration of that event runs, **at the same time and in no particular order**. One never waits for another, and one that fails never stops the others.

Use one declaration per thing your bot does: `welcome`, `log`, `roles`... When two steps must happen one after the other, keep them in the same function:

```ts src/events/roles.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { event } from 'chapterjs';

export default event({
  name: 'memberJoin',
  async run({ member, guild }) {
    const role = [...guild.roles.values()].find(role => role.name === 'Newcomer');
    if (!role) return;
    await member.addRole(role, 'Just joined');
    await member.send(`You now have the ${role.name} role.`);
  },
});
```

Every declaration of an event receives the same thing, and can read it but not change it: assigning to it (`context.role = ...`) throws, and the error is reported like any other.

## What is never missing

Your function receives [structures](https://www.chapterjs.org/reference.md) you can read and act on. In a server, what must exist is always there, with no `?.` to write:

* `member.guild`, `role.guild`, `channel.guild` for a channel of a server, `member.highestRole`;
* `guild.me` (your bot as a member of the server), `guild.everyoneRole`;
* `message.guild`, `message.member` and `message.channel` in the [events about messages](https://www.chapterjs.org/events/messages.md).

They stay there while your function runs, even if the person leaves or the channel is deleted in the meantime: your function keeps them as they were. The bot also keeps `guild.me` apart from [what it remembers](https://www.chapterjs.org/memory.md), so it is there in a server of any size.

What can be `null` is what may really not exist: a channel without a category (`channel.parent`), a message that was never edited (`message.editedAt`), a member count Discord never sent (`guild.memberCount`), a deleted message the bot did not remember (`message.before` in `messageDelete`).

### What was deleted

The events about something that no longer exists give the thing itself **as it was**:

* `roleDelete`: `role` is always there, the bot knows every role of its servers.
* `channelDelete`: `channel` is the channel or thread as it was.
* `guildLeave`: `guild` is the server as it was.
* `memberLeave`: `user` is the account of who left, always there.

```ts src/events/goodbye.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { event } from 'chapterjs';

export default event({
  name: 'memberLeave',
  async run({ user, guild }) {
    const channel = guild.systemChannelId ? guild.channels.get(guild.systemChannelId) : undefined;
    if (!channel || !channel.isTextBased()) return;
    const name = user.displayName;
    await channel.send(`${name} left ${guild.name}.`);
  },
});
```

## The `ready` event

`ready` runs **once per start**, when the bot is connected and knows every server it is in. It is not an event of Discord: nothing can start it again, and saving a file in `chapterjs dev` never runs it a second time.

```ts src/events/online.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { event } from 'chapterjs';

export default event({
  name: 'ready',
  run({ user, guilds }) {
    console.log(`${user.username} is online in ${guilds.size} server(s)`);
  },
});
```

## Options

Some events take options, written next to `name`. Each declaration decides for itself: two reactions to the same event can have different options, and what your function receives follows them.

```ts src/events/relay.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { event } from 'chapterjs';

export default event({
  name: 'messageCreate',
  bots: true,
  run({ message }) {
    console.log(`${message.author.username}: ${message.content}`);
  },
});
```

An option is `true` or `false`, or one word of a list. Your editor only offers the options of the event named, and an option that does not exist, or a wrong value, is underlined, then reported when the file loads, before the bot runs it. The events that have options are the [events about messages](https://www.chapterjs.org/events/messages.md) and the [reactions, polls and typing](https://www.chapterjs.org/events/reactions.md).

## Intents: nothing to list

Discord only sends a bot the events it asked for, through *intents*. You never write them: ChapterJS works them out from the events your files declare, and tells you when it connects:

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
ℹ Intents computed from your files: GUILDS, GUILD_MEMBERS
```

When you save a file that needs more, `chapterjs dev` reconnects by itself:

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
↻ Your files now need more from Discord (GUILD_MESSAGES, MESSAGE_CONTENT): reconnecting...
```

Three of the intents your files can need are **privileged**: Discord asks you to enable them yourself, in the [Developer Portal](https://www.chapterjs.org/setup/discord-application.md).

| Events | Option to enable |
| - | - |
| `memberJoin`, `memberUpdate`, `memberLeave`, `threadMemberJoin`, `threadMemberLeave` | **Server Members Intent** |
| `messageCreate`, `messageUpdate` | **Message Content Intent**: without it, the messages of other people come without their text |
| `presenceUpdate` | **Presence Intent** |

When one is missing, `chapterjs dev` names the files that need it and gives you the link, then waits:

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
⚠ Your files need an option that is not enabled for your bot:
  - Server Members Intent, needed by src/events/welcome.ts
  Enable it under "Privileged Gateway Intents", then save:
  https://discord.com/developers/applications/123456789012345678/bot
  Waiting for you to enable it...
✓ Privileged intents enabled
```

> [!NOTE]
>
> The command only waits when it runs in a terminal. Started by another program, it stops with the same explanation.

## When your function fails

An error in one of your functions never stops the bot, nor the other files. It is shown in your terminal with the file and the line, whether it is a bug of yours or Discord refusing what you asked:

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
✗ src/events/welcome.ts:4 Discord refused POST /channels/{channel.id}/messages: Cannot send messages to this user (50007)
```

To handle a failure yourself, use `try` / `catch`: see [Errors](https://www.chapterjs.org/reference/errors.md).

## In dev, only your test server

`chapterjs dev` runs your bot in [your test server only](https://www.chapterjs.org/run/dev.md#only-your-test-server): what happens in other servers and in private messages is ignored, and the intents that only serve private messages are not asked for. With `chapterjs start`, your bot hears every server it is in and private messages too.

> [!NOTE]
>
> Every event, with what your function receives, is in the [reference](https://www.chapterjs.org/reference/events.md). The types of `event()` are in [event()](https://www.chapterjs.org/reference/event.md).

## Every kind of event

Beyond members, roles, channels and the servers themselves, your files can react to:

* **Messages**: sent, edited, deleted. See [Messages](https://www.chapterjs.org/events/messages.md).
* **Reactions, polls and typing**: a reaction added or removed, a vote, someone writing. See [Reactions, polls and typing](https://www.chapterjs.org/events/reactions.md).
* **Voice**: someone joining, leaving, moving, muting or streaming. See [Voice](https://www.chapterjs.org/events/voice.md).
* **Moderation and the server**: bans, the audit log, invites, emojis, scheduled events, who is in a thread, presences. See [Moderation and the server](https://www.chapterjs.org/events/server.md).

> [card] [Messages](https://www.chapterjs.org/events/messages.md)
>
> Servers or private messages, bots or people: the events about messages and their options.

> [card] [What your bot remembers](https://www.chapterjs.org/memory.md)
>
> Why reading a server or a member costs nothing, and how memory stays under control.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.