> ## 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.

# Les événements

> Réagir à ce qui se passe sur Discord avec un event() par réaction : accueillir les nouveaux membres, suivre les changements, lancer du code à la connexion, et voir comment les intents suivent vos fichiers

Les commandes tournent quand quelqu’un demande. Les événements tournent quand quelque chose **se passe** : un membre arrive, un rôle est supprimé, un salon est renommé, le bot se connecte. Cette page fait accueillir les nouveaux venus par votre bot, et explique au passage la seule chose dont les événements ont besoin dans le Developer Portal.

## Une déclaration par réaction

Pour réagir à un événement, déclarez-le avec `event()` et exportez-le : `name` est l’événement, et le reste est une réaction. Le fichier est à vous à placer et à nommer ; ce tutoriel garde ses événements dans `src/events/`. Créez `src/events/hello.ts` :

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

export default event({
  name: 'memberJoin',
  async run({ member, guild }) {
    const channel = guild.systemChannelId ? guild.channels.get(guild.systemChannelId) : undefined;
    if (!channel?.isTextBased()) return;
    await channel.send(`Bienvenue sur ${guild.name}, ${member} ! Vous êtes le membre numéro ${guild.memberCount ?? '?'}.`);
  },
});
```

Comparez avec une commande : un événement n’a ni description ni options à déclarer, seulement son `name` et `run`. Et la fonction reçoit ce dont parle l’événement : ici un `member` (qui est arrivé) et un `guild` (où). Survolez `member` dans votre éditeur : c’est un `GuildMember`, avec tout ce que les pages précédentes ont montré. La même ligne `import { event } from 'chapterjs'`, avec `name: 'roleDelete'`, donnerait un `role` à votre fonction. Chaque événement marche ainsi : ce dont il parle, et le serveur, `guild`. Rien d’autre, donc vous ne cherchez jamais où se trouve quelque chose.

`guild.systemChannelId` est le salon où Discord lui-même publie « X a rejoint le serveur », quand le serveur en a un : un choix par défaut raisonnable pour un accueil. `guild.channels.get()` le lit dans ce que sait le bot, et `isTextBased()` s’assure qu’un message peut y aller.

## Le premier intent privilégié

Enregistrez le fichier. Le terminal ne dit pas « Reloaded ». Il dit :

```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/hello.ts
  Enable it under "Privileged Gateway Intents", then save:
  https://discord.com/developers/applications/123456789012345678/bot
  Waiting for you to enable it...
```

C’est le mécanisme des intents de [Comment fonctionne un bot](https://www.chapterjs.org/fr/tutorial/how-a-bot-works.md), à l’œuvre. Le bot a demandé à Discord les serveurs (`GUILDS`) en se connectant. Être prévenu des arrivées de membres est un autre intent, `GUILD_MEMBERS`, et celui-là est privilégié : Discord veut que vous l’activiez à la main, parce que la liste des membres d’un serveur est une donnée personnelle.

Ouvrez le lien (il mène directement à la page **Bot** de votre application de dev), activez **Server Members Intent**, cliquez sur **Save Changes**. Le terminal continue tout seul :

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
✓ Privileged intents enabled
↻ Your files now need more from Discord (GUILD_MEMBERS): reconnecting...
✓ Reconnected, 1 event, a presence loaded
```

Les intents sont donnés à Discord à la connexion, donc avoir besoin d’un nouvel intent veut dire se reconnecter. Le framework l’a fait. Désormais, chaque fois que quelqu’un rejoint votre serveur de test, votre fichier tourne. Essayez avec un second compte, ou en quittant et en revenant.

> [!NOTE]
>
> Vous n’avez jamais écrit un intent. Le framework lit les événements que vos fichiers déclarent, déduit ce dont ils ont besoin, demande exactement cela à Discord, et vous prévient quand l’un d’eux nécessite un interrupteur dans le Developer Portal. Quand vous supprimez le dossier, l’intent n’est plus demandé. C’est ce que veut dire « intents computed from your files » sur la première ligne de chaque démarrage.

## Plusieurs fichiers pour un événement

Déclarez autant de réactions que vous voulez à un même événement, et **toutes tournent** quand il se produit, en même temps, sans ordre particulier. Ajoutez `src/events/role.ts`, qui donne un rôle aux nouveaux venus :

```ts src/events/role.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, 'Vient d’arriver');
  },
});
```

Créez un rôle appelé « Newcomer » sur votre serveur de test, et assurez-vous que le rôle du bot est **au-dessus** dans les paramètres du serveur : Discord ne laisse un bot donner que les rôles situés sous son propre rôle le plus haut.

Pourquoi une déclaration par chose, plutôt qu’une grosse fonction ? Parce qu’une déclaration qui échoue n’arrête jamais les autres. Si `role.ts` lève une erreur (le rôle a été supprimé, le rôle du bot est trop bas), `hello.ts` accueille quand même. Et chaque fichier reste assez court pour être lu. Quand deux étapes doivent se faire dans l’ordre, gardez-les dans le même fichier.

## L’événement ready

`ready` est spécial : ce n’est pas quelque chose qui se passe sur Discord, mais le moment où votre bot est connecté et connaît chaque serveur où il se trouve. Il tourne **une fois par démarrage**, jamais lors d’un rechargement. Créez `src/events/ready.ts` :

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

export default event({
  name: 'ready',
  run({ user, guilds }) {
    console.log(`${user.username} est en ligne sur ${guilds.size} serveur(s)`);
  },
});
```

Enregistrez-le, puis arrêtez le bot et relancez-le : le terminal affiche `buddy est en ligne sur 1 serveur(s)`, une fois. `user` est le bot lui-même, `guilds` les serveurs où il se trouve. Servez-vous-en pour ce qui doit se faire une fois au démarrage. Ne vous en servez pas pour ce qui doit se faire régulièrement : c’est le rôle des tâches, quelques chapitres plus loin.

## Les événements auxquels réagir

| `name` | Se produit quand | Votre fonction reçoit |
| - | - | - |
| `ready` | Le bot est connecté | `user`, `guilds` |
| `guildJoin`, `guildLeave` | Le bot est ajouté à un serveur, ou retiré | `guild` |
| `memberJoin`, `memberUpdate`, `memberLeave` | Quelqu’un arrive, change (surnom, rôles...), part | `member`, `guild` (`user` pour un départ) |
| `roleCreate`, `roleUpdate`, `roleDelete` | Un rôle est créé, modifié, supprimé | `role`, `guild` |
| `channelCreate`, `channelUpdate`, `channelDelete` | Un salon est créé, modifié, supprimé | `channel`, `guild` |
| `messageCreate`, `messageUpdate`, `messageDelete` | Un message est envoyé, modifié, supprimé | `message`, `guild` : la page suivante |
| `reactionAdd`, `voiceJoin`, `banAdd`... | Une réaction, quelqu’un en vocal, un bannissement, et d’autres | Dans deux pages |

Un `name` qui n’est pas un événement est souligné dans l’éditeur, puis signalé au chargement, avec le nom d’événement le plus proche quand il y en a un. Le contenu exact de chacun est dans la [Référence](https://www.chapterjs.org/fr/reference/events.md).

### Ce qui a été supprimé

Pour quelque chose qui n’existe plus, l’événement vous le donne **tel qu’il était** : `roleDelete` donne le rôle, `channelDelete` le salon, `guildLeave` le serveur. Le bot s’en souvenait, donc ils sont là. `memberLeave` donne le compte de la personne partie, `user` : un serveur peut avoir plus de membres que le bot n’en garde en mémoire, donc le membre qu’elle était peut être oublié depuis longtemps, mais le compte est toujours là.

```ts src/events/bye.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?.isTextBased()) return;
    const name = user.displayName;
    await channel.send(`${name} est parti. Nous sommes ${guild.memberCount ?? '?'} maintenant.`);
  },
});
```

## Points d’attention

* **Tout ce que reçoit votre fonction est en lecture seule.** Y affecter une valeur lève une erreur ; c’est partagé par chaque réaction à l’événement.
* **Ce qui doit exister est là.** `member.guild`, `channel.guild`, `guild.me` : pas de `?.`. Ce qui peut vraiment manquer est nullable, comme `guild.memberCount`, que Discord n’envoie pas toujours.
* **En dev, seulement votre serveur de test.** `chapterjs dev` ignore ce qui se passe dans les autres serveurs et en messages privés. C’est pour cela que vous pouvez faire tourner le bot de dev et le bot de production avec un seul token sans qu’ils répondent deux fois ; `chapterjs start` entend tout.
* **Un fichier qui échoue est signalé avec le fichier et la ligne**, et rien d’autre ne s’arrête :

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
✗ src/events/role.ts:6 Discord refused PUT /guilds/{guild.id}/members/{user.id}/roles/{role.id}: Missing Permissions (50013). The bot is missing a permission for this, or acts on someone above it: the owner of the server, or a member or role higher than the bot's highest role.
```

## Récapitulatif

* `event({ name, run })` est une réaction à l’événement `name` ; déclarez-en autant que vous voulez, et toutes tournent.
* Ce que reçoit `run` suit `name`, sans type à écrire.
* Les intents sont déduits des événements que vous déclarez ; un intent privilégié est un interrupteur dans le Developer Portal, et le terminal vous attend.
* `ready` tourne une fois par démarrage ; ce qui est supprimé arrive tel qu’il était.

> [card] [Les messages comme événements](https://www.chapterjs.org/fr/tutorial/message-events.md)
>
> Réagir à ce que les gens écrivent, où, et de qui.

> [card] [Guide : Événements](https://www.chapterjs.org/fr/events.md)
>
> La même chose, en bref.


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