Skip to content

Événements ​

BloumeChat étend EventEmitter (Node.js) et expose une interface ClientEvents entièrement typée : client.on("messageCreate", ...) infère automatiquement le bon type de payload, sans any. En JavaScript, ce typage disparaît (pas de vérification statique) mais le comportement à l'exécution est identique — message est le même objet Message dans les deux cas.

ts
client.on("messageCreate", (message) => {
  //                        ^? Message
});
js
client.on("messageCreate", (message) => {
  // pas d'inférence de type ici, mais `message` est bien un objet Message
});

Tous les événements sont diffusés en interne par le socket, mappés une fois pour toutes vers ce nom d'événement stable côté client — vous n'avez jamais besoin d'écouter le socket brut (client.getSocket() existe mais reste réservé à un usage interne/avancé).

Cycle de vie ​

EventPayloadDéclenchement
ready—Le client est connecté, client.user et client.guilds.cache sont peuplés. Émis une seule fois par process (le premier connect du socket).
reconnect—Le socket s'est reconnecté après une coupure (le client était déjà ready au moment de la coupure). Ne redéclenche pas ready.
disconnectreason: stringLe socket s'est déconnecté (raison fournie par Socket.IO, ex. "transport close", "io server disconnect").
errorerror: ErrorErreur de connexion Socket.IO (connect_error) — token invalide, réseau indisponible, etc. Si l'erreur survient avant le premier ready, la promesse de login() est aussi rejetée avec la même erreur.

Toujours écouter error

Un EventEmitter Node.js sans listener sur "error" peut faire planter le process si une erreur y est émise. Écoutez systématiquement client.on("error", ...), même juste pour logger — voir l'exemple dans Démarrage rapide.

ts
client.on("ready", () => console.log("Bot en ligne."));
client.on("reconnect", () => console.log("Reconnecté après une coupure."));
client.on("disconnect", (reason) => console.warn(`Déconnecté : ${reason}`));
client.on("error", (error) => console.error("Erreur de connexion :", error.message));
js
client.on("ready", () => console.log("Bot en ligne."));
client.on("reconnect", () => console.log("Reconnecté après une coupure."));
client.on("disconnect", (reason) => console.warn(`Déconnecté : ${reason}`));
client.on("error", (error) => console.error("Erreur de connexion :", error.message));

Messages ​

EventPayloadNotes
message / messageCreateMessageAlias strictement identiques pour capter les nouveaux messages — n'écoutez qu'un seul des deux pour éviter un traitement en double.
messageUpdatedata: anyMessage édité.
messageDeletedata: anyMessage supprimé.
messageReactionAdd(reaction: ReactionInfo, user: User, messagePublicId: string)Émis une fois par utilisateur ayant ajouté reaction.emoji. reaction = { emoji, messagePublicId, count } (le count reflète l'état après ce changement). (Depuis 4.2.0 — le SDK diffuse maintenant en interne la liste brute que le serveur renvoie en message:reaction contre le dernier état connu pour retrouver qui a fait quoi ; voir l'avertissement ci-dessous.)
messageReactionRemove(reaction: ReactionInfo, user: User, messagePublicId: string)Même forme que messageReactionAdd, pour un retrait. (4.2.0+)
messageReactionRemoveAlldata: anyToutes les réactions ont été effacées (déclenché par message.clearReactions(), voir Message).
messagePindata: anyUn message a été épinglé.

messageReactionAdd/Remove : la toute première réaction vue sur un message

Le serveur renvoie toujours la liste complète des réactions courantes sur message:reaction, jamais un delta. Le SDK compare chaque nouvelle liste à la précédente pour reconstituer les ajouts/retraits individuels — mais s'il n'a encore rien vu pour ce message (le bot vient de se connecter, ou le message a des réactions posées avant que le bot ne les observe), tout apparaît comme un lot d'ajouts au premier événement reçu. Il n'y a pas moyen de distinguer "vraiment nouveau" de "déjà là" sans re-fetcher l'historique des réactions, ce que le SDK ne fait pas automatiquement.

ts
client.on("messageCreate", async (message) => {
  if (message.author.bot) return;
  if (message.content.startsWith("!")) {
    console.log(`Commande reçue de ${message.author.tagString}: ${message.content}`);
  }
});

client.on("messageDelete", (data) => {
  console.log(`Message supprimé dans le salon ${data.channelPublicId}`);
});
js
client.on("messageCreate", async (message) => {
  if (message.author.bot) return;
  if (message.content.startsWith("!")) {
    console.log(`Commande reçue de ${message.author.tagString}: ${message.content}`);
  }
});

client.on("messageDelete", (data) => {
  console.log(`Message supprimé dans le salon ${data.channelPublicId}`);
});

Voir aussi : Message pour les méthodes disponibles sur l'objet reçu (reply(), edit(), delete(), pin(), react()…) et EmbedBuilder pour construire des réponses riches.

Serveurs (guilds) ​

EventPayloadNotes
guildCreateguild: GuildLe bot vient d'être ajouté à un nouveau serveur. guild est déjà présent dans client.guilds.cache au moment où le listener s'exécute.
guildUpdateguild: GuildNom, icône… modifiés — le Guild mis en cache est patché avant l'émission, plus besoin de le refetch.
guildDeleteguild: GuildLe serveur a été supprimé, ou le bot en a été retiré/l'a quitté (déclenché par server:deleted, server:you_removed ou server:you_left — les trois remontent sur ce même événement client). Le serveur est déjà retiré de client.guilds.cache au moment de l'émission.
guildMemberAddmember: MemberUn membre a rejoint. client.members.cache est déjà à jour au moment où le listener s'exécute.
guildMemberRemovemember: Member | data: anyUn membre est parti, a été expulsé ou banni (voir guildBanAdd ci-dessous — les deux se déclenchent ensemble en cas de ban). client.members.cache a déjà été purgé de l'entrée correspondante ; vous recevez le Member retiré s'il était en cache, sinon le payload brut.
guildMemberUpdatemember: Member | data: anyRôles ou pseudo d'un membre modifiés — le SDK refetch automatiquement le membre pour vous donner l'état à jour (le payload socket brut ne contient que des ids).
guildBanAdddata: anyDérivé de guildMemberRemove quand reason === "banned" — pratique pour ne pas re-tester la raison vous-même dans chaque handler.
guildBanRemovedata: anyUn bannissement a été levé.
guildChannelsUpdatedata: anyLa liste des salons a changé (création, suppression, renommage, réorganisation).
guildCategoriesUpdatedata: anyLa liste des catégories a changé.

Pas d'événement CRUD par salon

Le serveur ne diffuse pas d'événement fin-grain channelCreate/channelUpdate/channelDelete : tout changement de structure remonte via guildChannelsUpdate (juste un signal « resynchronise-toi »). Rafraîchissez avec guild.fetchChannels() si vous avez besoin du détail — voir Guild.

ts
client.on("guildCreate", (guild) => {
  console.log(`Ajouté au serveur ${guild.name} (${guild.memberCount} membres)`);
});

client.on("guildMemberAdd", async (member) => {
  const guild = client.guilds.cache.get(member.serverId);
  const welcomeChannel = guild?.channels.find((c) => c.name === "bienvenue");
  await welcomeChannel?.send(`👋 <@${member.user.id}> vient de rejoindre !`);
});

client.on("guildBanAdd", (data) => {
  console.log(`Membre banni : ${data.userPublicId} — raison : ${data.reason ?? "non précisée"}`);
});

client.on("guildChannelsUpdate", async (data) => {
  const guild = client.guilds.cache.get(data.serverPublicId);
  await guild?.fetchChannels(); // resynchronise le cache des salons de ce serveur
});
js
client.on("guildCreate", (guild) => {
  console.log(`Ajouté au serveur ${guild.name} (${guild.memberCount} membres)`);
});

client.on("guildMemberAdd", async (member) => {
  const guild = client.guilds.cache.get(member.serverId);
  const welcomeChannel = guild && guild.channels.find((c) => c.name === "bienvenue");
  if (welcomeChannel) await welcomeChannel.send(`👋 <@${member.user.id}> vient de rejoindre !`);
});

client.on("guildBanAdd", (data) => {
  console.log(`Membre banni : ${data.userPublicId} — raison : ${data.reason || "non précisée"}`);
});

client.on("guildChannelsUpdate", async (data) => {
  const guild = client.guilds.cache.get(data.serverPublicId);
  if (guild) await guild.fetchChannels();
});

Voir aussi : Guild, GuildManager.

Rôles ​

EventPayload
roleCreateRole
roleUpdateRole
roleDeleteRole | string — le rôle si il était encore en cache au moment de la suppression, sinon uniquement son ID public.
roleOrderUpdatedata: any — réorganisation de la hiérarchie des rôles d'un serveur.

Ces quatre événements sont émis en plus de la mise à jour automatique du cache : roleCreate/roleUpdate mettent d'abord à jour guild.roles.cache avant de déclencher l'événement, donc lire guild.roles.cache dans votre handler reflète déjà le nouvel état.

ts
client.on("roleCreate", (role) => {
  console.log(`Nouveau rôle « ${role.name} » créé.`);
});

client.on("roleDelete", (role) => {
  const name = typeof role === "string" ? role : role.name;
  console.log(`Rôle supprimé : ${name}`);
});
js
client.on("roleCreate", (role) => {
  console.log(`Nouveau rôle « ${role.name} » créé.`);
});

client.on("roleDelete", (role) => {
  const name = typeof role === "string" ? role : role.name;
  console.log(`Rôle supprimé : ${name}`);
});

Voir aussi : Role, RoleManager, et le guide Permissions pour le bitmask associé à chaque rôle.

Présence & activité ​

EventPayload
userUpdatedata: any — profil d'un utilisateur modifié (nom, avatar…).
typingStart / typingStopdata: any — indicateur de saisie dans un salon.
presenceUpdatedata: any — changement de statut (online/idle/dnd/invisible).
activityUpdateActivityUpdateData — { userPublicId, activity }, émis quand un utilisateur change son activité Rich Presence.

ActivityUpdateData ​

ts
interface ActivityUpdateData {
  userPublicId: string;
  activity: (ActivityData & { startedAt: number }) | null;
}

activity vaut null si l'utilisateur a effacé son activité. Sinon il reprend la forme d'ActivityData (type, name, details?) avec startedAt toujours renseigné (timestamp ms).

ts
client.on("activityUpdate", ({ userPublicId, activity }) => {
  if (!activity) {
    console.log(`${userPublicId} n'a plus d'activité.`);
    return;
  }
  console.log(`${userPublicId} : ${activity.type} — ${activity.name}`);
});

client.on("presenceUpdate", (data) => {
  console.log(`${data.userPublicId} est maintenant ${data.status}`);
});
js
client.on("activityUpdate", ({ userPublicId, activity }) => {
  if (!activity) {
    console.log(`${userPublicId} n'a plus d'activité.`);
    return;
  }
  console.log(`${userPublicId} : ${activity.type} — ${activity.name}`);
});

client.on("presenceUpdate", (data) => {
  console.log(`${data.userPublicId} est maintenant ${data.status}`);
});

Voir aussi : client.setActivity() et client.setPresence() dans BloumeChat pour définir votre propre activité/statut.

Voix, DMs ​

Rejoindre un salon vocal et parler

Ces événements couvrent la présence (qui est connecté, muet, en train de parler…). Pour que le bot rejoigne réellement un salon vocal et diffuse de l'audio (musique, TTS…), voir le guide dédié Salons vocaux.

Pas besoin de les suivre vous-même pour savoir « qui est où »

(4.1.0+) Ces événements alimentent automatiquement client.voiceStates (et le raccourci member.voice) — voir Savoir dans quel salon vocal se trouve un membre. Écoutez ces événements directement seulement si vous avez besoin de réagir à l'instant du changement (notification, log…), pas juste de connaître l'état courant.

EventPayloadNotes
voiceStateUpdateVoiceUsersSnapshotSnapshot complet des participants d'un salon vocal — émis à la fois pour une connexion/mise à jour (voice:state-update) et pour un départ (voice:user-left, par compatibilité).
voiceUserJoinedVoiceUserJoinedDataUn utilisateur (potentiellement le bot lui-même) vient de rejoindre un salon vocal.
voiceUserLeft{ channelPublicId, userPublicId, users: VoiceUser[] }Un utilisateur a quitté un salon vocal.
voiceUserStateVoiceUserStateDataUn participant a changé d'état (muet, sourdine, en train de parler, partage d'écran…).
voiceIncomingCallVoiceIncomingCallDataLe bot reçoit un appel entrant (DM ou salon vocal).
voiceCallCancelled{ channelPublicId }Un appel entrant a été annulé avant d'être décroché.
dmNewdata: anyNouveau message reçu dans un canal de messages directs.
ts
client.on("voiceUserJoined", ({ channelPublicId, user }) => {
  console.log(`${user.userName} a rejoint le salon vocal ${channelPublicId}`);
});

client.on("voiceUserState", (data) => {
  if (data.speaking !== undefined) console.log(`${data.userPublicId} parle : ${data.speaking}`);
});

client.on("dmNew", (data) => {
  console.log("Nouveau DM reçu :", data);
});
js
client.on("voiceUserJoined", ({ channelPublicId, user }) => {
  console.log(`${user.userName} a rejoint le salon vocal ${channelPublicId}`);
});

client.on("voiceUserState", (data) => {
  if (data.speaking !== undefined) console.log(`${data.userPublicId} parle : ${data.speaking}`);
});

client.on("dmNew", (data) => {
  console.log("Nouveau DM reçu :", data);
});

Voir aussi : client.createDM() dans BloumeChat, DMChannel, et Référence API — Voix.

Écouter un événement une seule fois ​

client.once(...) fonctionne comme sur n'importe quel EventEmitter Node — le listener est automatiquement retiré après son premier déclenchement :

ts
client.once("ready", () => console.log("premier ready seulement"));
js
client.once("ready", () => console.log("premier ready seulement"));

Se désabonner d'un événement ​

client.off(event, listener) retire un listener précis (il faut garder une référence à la fonction passée à on) :

ts
function onReady() {
  console.log("prêt");
}

client.on("ready", onReady);
client.off("ready", onReady); // ne sera plus jamais appelé
js
function onReady() {
  console.log("prêt");
}

client.on("ready", onReady);
client.off("ready", onReady); // ne sera plus jamais appelé

client.destroy() retire d'un coup tous les listeners de tous les événements (removeAllListeners()) en plus de fermer le socket — voir BloumeChat.

Prochaine étape ​

Consultez le guide Permissions pour restreindre vos handlers messageCreate (commandes de modération, etc.) selon les droits du membre qui a écrit le message.

SDK publié sous licence ISC.