Skip to content

Messages & salons ​

Cette page couvre Channel (salons texte/vocal), DMChannel (messages privés), Message, et EmbedBuilder.

Channel ​

Représente un salon texte ou vocal appartenant à un serveur (ou un canal DM/groupe — voir DMChannel plus bas, qui étend cette classe).

Propriétés ​

PropriétéTypeDescription
idstringpublicId (Snowflake) du salon.
namestringNom du salon.
typestring"TEXT", "VOICE", "DM", "GROUP_DM", "ANNOUNCEMENT"…
serverIdstring | nullID du serveur parent — null pour un DM ou un groupe.
webhooksWebhookManager(1.5.0+) Manager de webhooks scopé à ce salon — voir WebhookManager.

Messagerie ​

send(content, embeds?): Promise<Message> ​

ParamètreTypeRequisDescription
contentstring | { content?: string; embeds?: Array<EmbedBuilder | EmbedPayload | Record<string, unknown>>; replyToId?: string }OuiTexte brut, ou un objet payload complet.
embedsArray<EmbedBuilder | EmbedPayload | Record<string, unknown>>NonUtilisé uniquement si content est une string — sinon ignoré (mettez embeds dans l'objet payload à la place).

Envoie un message dans ce salon via le socket temps réel (délègue à client.sendMessage). Rejette si content est vide et qu'aucun embed n'est fourni, ou si le socket n'est pas connecté. La promesse résout avec l'objet Message créé, une fois l'accusé de réception du serveur reçu (timeout 10s — voir sendMessage).

ts
await channel.send("Bonjour !");
await channel.send({ content: "Avec embed", embeds: [{ title: "Titre" }] });
await channel.send({ content: "En réponse", replyToId: someMessage.id });
js
await channel.send("Bonjour !");
await channel.send({ content: "Avec embed", embeds: [{ title: "Titre" }] });
await channel.send({ content: "En réponse", replyToId: someMessage.id });

fetchMessages(limit?, before?): Promise<Message[]> ​

ParamètreTypeRequisDéfautDescription
limitnumberNon50Nombre de messages à récupérer (le serveur plafonne généralement à 100).
beforestringNon—Récupère les messages envoyés avant ce messagePublicId — utile pour paginer en remontant l'historique.

Retourne les messages les plus récents en premier (ordre antéchronologique typique d'une API de chat). Un tableau vide si le salon n'a aucun message.

ts
const recent = await channel.fetchMessages(20);
const older = await channel.fetchMessages(20, recent[recent.length - 1].publicId);
js
const recent = await channel.fetchMessages(20);
const older = await channel.fetchMessages(20, recent[recent.length - 1].publicId);

bulkDelete(messageIds): Promise<void> ​

Supprime plusieurs messages en un seul appel. Requiert la permission MANAGE_MESSAGES — sinon la requête rejette avec une erreur 403 côté API.

ts
const spam = await channel.fetchMessages(50);
const toDelete = spam.filter(m => m.author.publicId === spammerId).map(m => m.publicId);
await channel.bulkDelete(toDelete);
js
const spam = await channel.fetchMessages(50);
const toDelete = spam.filter(m => m.author.publicId === spammerId).map(m => m.publicId);
await channel.bulkDelete(toDelete);

search(query, options?): Promise<Message[]> ​

ParamètreTypeRequisDescription
querystringOuiTermes de recherche.
options.limitnumberNonNombre maximum de résultats.
options.before / options.afterstringNonBornes temporelles par messagePublicId.

Équivalent scoped à ce salon de client.searchMessages(channel.id, query, options).

ts
const results = await channel.search("roadmap", { limit: 10 });
js
const results = await channel.search("roadmap", { limit: 10 });

fetchPins(): Promise<Message[]> ​

Retourne la liste des messages épinglés dans ce salon, tableau vide si aucun. Ces trois méthodes (fetchMessages, search, fetchPins) enveloppent désormais leurs résultats dans de vraies instances Message (depuis la 1.5.0 — c'était auparavant du JSON brut).

Typing (indicateur de frappe) ​

ts
sendTyping(): void
stopTyping(): void

Émettent respectivement typing:start et typing:stop sur le socket. Synchrones (pas de Promise) — lèvent immédiatement une BloumeChatAuthError si le socket n'est pas établi, plutôt que de rejeter une promesse. L'indicateur de frappe expire automatiquement côté serveur après quelques secondes ; appelez sendTyping() en boucle si une opération longue est en cours.

ts
channel.sendTyping();
const answer = await generateSlowAnswer(); // ex: appel à une IA externe
channel.stopTyping();
await channel.send(answer);
js
channel.sendTyping();
const answer = await generateSlowAnswer(); // ex: appel à une IA externe
channel.stopTyping();
await channel.send(answer);

Gestion du salon ​

ts
edit(data: { name?: string; description?: string | null }): Promise<void>
setName(name: string): Promise<void>
delete(): Promise<void>
duplicate(): Promise<Channel>

edit() ne modifie que les champs fournis. setName() est un raccourci vers edit({ name }). delete() supprime définitivement le salon et son historique — irréversible, aucune confirmation supplémentaire n'est demandée côté SDK. duplicate() crée une copie du salon avec les mêmes permissions et paramètres, et retourne le nouvel objet Channel.

delete() est irréversible

Il n'existe pas de corbeille — un salon supprimé et son historique de messages sont perdus définitivement. Confirmez toujours l'action côté utilisateur avant d'appeler channel.delete() dans un bot.

ts
await channel.setName("annonces-2026");
const copy = await channel.duplicate();
console.log(`Copie créée : ${copy.name} (${copy.id})`);
js
await channel.setName("annonces-2026");
const copy = await channel.duplicate();
console.log(`Copie créée : ${copy.name} (${copy.id})`);

Invitations ​

ts
createInvite(options?: { maxAge?: number; maxUses?: number }): Promise<GuildInviteDTO>

Crée une invitation pointant vers ce salon spécifique. maxAge (secondes) et maxUses sont optionnels — omis, l'invitation n'expire pas et n'a pas de limite d'utilisation.

Permissions ​

ts
fetchPermissionOverrides(): Promise<PermissionOverrideDTO[]>
editPermissions(targetId: string, type: "ROLE" | "MEMBER", options: { allow: bigint | string; deny: bigint | string }): Promise<void>
deletePermissionOverride(overrideId: string): Promise<void>
syncPermissions(): Promise<void>
MéthodeDescription
fetchPermissionOverrides()Liste tous les overrides de permission (rôle ou membre) définis sur ce salon.
editPermissions(targetId, type, options)Crée ou met à jour un override pour un rôle ou un membre. allow/deny sont des bitmasks bigint (voir Permissions) — sérialisés automatiquement en string pour le transport JSON.
deletePermissionOverride(overrideId)Supprime un override par son ID (pas par targetId — récupérez l'ID de l'override via fetchPermissionOverrides() d'abord).
syncPermissions()Réinitialise les overrides de ce salon pour qu'ils héritent de ceux de sa catégorie parente.
ts
import { PermissionFlags } from "bloumechat";

await channel.editPermissions(roleId, "ROLE", {
  allow: PermissionFlags.SEND_MESSAGES,
  deny: PermissionFlags.MENTION_EVERYONE,
});
js
const { PermissionFlags } = require("bloumechat");

await channel.editPermissions(roleId, "ROLE", {
  allow: PermissionFlags.SEND_MESSAGES,
  deny: PermissionFlags.MENTION_EVERYONE,
});

Voir aussi

Pour la hiérarchie catégorie → salon et le bitmask complet, voir le guide Permissions et Category.

Webhooks ​

Depuis la 1.5.0 : channel.webhooks

Ces raccourcis délèguent maintenant à WebhookManager (channel.webhooks), qui expose aussi cache et delete(id).

ts
fetchWebhooks(): Promise<Webhook[]>
createWebhook(options: { name: string; avatarUrl?: string }): Promise<Webhook>

Voir la page dédiée Webhooks, emojis & invitations pour l'API complète de Webhook, y compris la gestion du token.

DMChannel extends Channel ​

Représente un canal de messages privés entre deux utilisateurs. Hérite de toutes les méthodes de Channel (send, fetchMessages, search, fetchPins…) — un DM se manipule exactement comme un salon de serveur pour l'envoi/lecture de messages. Les méthodes propres aux serveurs (permissions, webhooks, invitations) n'ont pas de sens sur un DM et échoueront côté API si appelées.

Propriétés ​

PropriétéTypeDescription
recipientIdstringpublicId du destinataire. Chaîne vide si la donnée recipient n'était pas présente à la construction.
recipientUser | nullObjet User du destinataire, null s'il n'a pas encore été chargé.
friendshipStatus"ACCEPTED" | "PENDING" | "NONE"État de la relation d'amitié avec ce destinataire au moment de la création de l'objet.
friendshipIdstring | undefinedID de l'enregistrement d'amitié, si une relation existe.

fetchRecipient(): Promise<User> ​

Recharge le profil complet du destinataire depuis l'API et met à jour this.recipient ainsi que le cache global client.users.cache. Utile quand le DMChannel a été construit avec des données partielles (par ex. reçu via l'event dmNew).

ts
const dm = await client.createDM(userId);
await dm.send("Salut !");
js
const dm = await client.createDM(userId);
await dm.send("Salut !");
ts
client.on("dmNew", async (data) => {
  const dm = new DMChannel(client, data);
  const recipient = await dm.fetchRecipient();
  console.log(`Nouveau DM de ${recipient.tagString}`);
});
js
client.on("dmNew", async (data) => {
  const dm = new DMChannel(client, data);
  const recipient = await dm.fetchRecipient();
  console.log(`Nouveau DM de ${recipient.tagString}`);
});

Message ​

Représente un message envoyé dans un salon ou un DM. Instancié automatiquement par le SDK sur messageCreate et fourni comme argument aux callbacks correspondants.

Propriétés ​

PropriétéTypeDescription
idstringpublicId du message.
contentstringContenu texte, automatiquement décodé des entités HTML (&lt;, &gt;, &amp;) que le serveur échappe à l'écriture pour se protéger du XSS — vous récupérez donc les caractères <, >, & d'origine, pas leur forme échappée.
authorUserAuteur du message.
channelIdstringID du salon d'envoi.
serverIdstring | undefinedID du serveur, absent pour un message envoyé en DM.
createdAtDateDate d'envoi.
embedsArray<EmbedPayload | Record<string, unknown>>Embeds attachés au message.
fileUrlstring | nullURL d'une pièce jointe unique, null si aucune.
channelChannel (getter)Résout depuis le cache si disponible, sinon construit un Channel minimal (id/serverId seulement — pas de name fiable) à la volée.
guildGuild | null (getter)null si le message n'a pas de serverId (DM) ou si le serveur n'est pas en cache.
memberMember | null (getter)Résolu uniquement depuis le cache — recherche par (serverId, user.id), pas par ID de membership. Retourne null si le membre n'a pas déjà été chargé via client.members.fetch() ou guild.fetchChannels()/équivalent ; ce getter ne fait jamais d'appel réseau.

message.member ne déclenche jamais de fetch

Si le membre n'est pas encore en cache, message.member renvoie null même si l'auteur est bel et bien membre du serveur. Appelez client.members.fetch(message.serverId, message.author.id) explicitement avant de lire message.member si vous avez besoin d'une garantie de fraîcheur.

Répondre, éditer, supprimer ​

reply(content, embeds?): Promise<Message> ​

Identique à channel.send() mais définit automatiquement replyToId sur this.id.

ts
client.on("messageCreate", async (message) => {
  if (message.content === "!ping") await message.reply("🏓 Pong !");
});
js
client.on("messageCreate", async (message) => {
  if (message.content === "!ping") await message.reply("🏓 Pong !");
});

edit(options): Promise<Message> ​

ParamètreTypeDescription
optionsstring | EmbedBuilder | { content?: string; embeds?: Array<EmbedBuilder | EmbedPayload | Record<string, unknown>> }Nouveau contenu et/ou embeds.

Émet message:edit sur le socket (nécessite d'être connecté — sinon lève une BloumeChatAuthError). Met à jour this.content/this.embeds de façon optimiste (avant confirmation serveur) et retourne this. Il n'existe pas de mécanisme d'annulation si le serveur rejette l'édition (par ex. permissions insuffisantes) — dans ce cas l'état local reste désynchronisé jusqu'au prochain messageUpdate.

ts
const sent = await channel.send("Chargement…");
await sent.edit("Terminé ✅");
js
const sent = await channel.send("Chargement…");
await sent.edit("Terminé ✅");

delete(): Promise<void> ​

Émet message:delete sur le socket. Lève une BloumeChatAuthError si le socket n'est pas établi.

Réactions ​

ts
react(emoji: string): Promise<void>
clearReactions(): Promise<void>
fetchReactions(emoji: string): Promise<ReactionUserDTO[]>
awaitReactions(options?: { max?: number; time?: number }): Promise<MessageReactionEventData | null>
MéthodeDescription
react(emoji)Ajoute une réaction. Accepte un emoji unicode ("👍") ou le nom d'un emoji personnalisé du serveur.
clearReactions()Retire toutes les réactions du message (nécessite généralement MANAGE_MESSAGES côté serveur).
fetchReactions(emoji)Retourne le détail des utilisateurs ayant réagi avec un emoji précis : { userPublicId, userName, userImage }[]. L'emoji est URL-encodé automatiquement.
awaitReactions(options)Attend un lot de réactions en temps réel, résout une seule fois (voir ci-dessous).
createReactionCollector(options)(4.2.0+) Collecte en continu les réactions sur le message via un ReactionCollector (on('collect', ...)), jusqu'à time/max ou .stop().

awaitReactions — attendre une réaction en direct

ts
const msg = await channel.send("Réagissez avec 👍 dans les 30s !");
const result = await msg.awaitReactions({ max: 1, time: 30_000 });
if (result) console.log("Quelqu'un a réagi !");
else console.log("Personne n'a réagi à temps.");

options.max arrête l'attente dès que ce nombre de réactions est atteint (compte tous les events messageReactionAdd reçus pour ce message, sans distinguer par emoji ni dédupliquer par utilisateur). options.time (ms) est un timeout — sans lui, la promesse peut rester en attente indéfiniment si max n'est jamais atteint. Sans aucune des deux options, résout immédiatement undefined (aucune attente réelle configurée). Résout avec null en cas de timeout, ou avec { messagePublicId, emoji, userPublicId } de la dernière réaction reçue.

Identique en JavaScript, sans annotation de type — channel.send, awaitReactions fonctionnent à l'exécution exactement de la même façon.

createReactionCollector — collecter plusieurs réactions dans la durée

ts
const collector = msg.createReactionCollector({ time: 60_000 });
collector.on("collect", (reaction, user) => {
  console.log(`${user.tagString} a réagi ${reaction.emoji}`);
});
collector.on("end", (reason) => console.log(`Terminé : ${reason}`));

Contrairement à awaitReactions() (une seule résolution), le collector reste actif et émet collect pour chaque réaction correspondante jusqu'à ce que options.time s'écoule, que options.max collectes soient atteintes, ou que .stop() soit appelé manuellement. options.filter?: (reaction, user) => boolean permet de ne garder que certaines réactions (ex. un utilisateur précis).

Épingler ​

ts
pin(): Promise<void>
unpin(): Promise<void>

Appels REST (pas socket) vers /chat/:channelId/pin/:messageId.

EmbedBuilder ​

API fluent pour construire un embed riche, convertie en EmbedPayload via .toJSON() — appelé automatiquement quand un EmbedBuilder est passé à send()/reply()/edit(), donc vous n'avez normalement jamais besoin d'appeler .toJSON() vous-même.

Méthodes ​

MéthodeDescription
setTitle(title: string | null)Titre de l'embed. null le retire.
setDescription(description: string | null)Corps du texte. null le retire.
setURL(url: string | null)Rend le titre cliquable. null le retire.
setTimestamp(timestamp?: Date | number | null)Sans argument (ou undefined), utilise l'heure actuelle. null retire le timestamp.
setColor(color: number | string | null)Accepte un nombre décimal ou une chaîne hex ("#5e72e4", convertie automatiquement). null le retire.
setFooter(options: EmbedFooter | null){ text: string; iconUrl?: string }. null le retire.
setImage(url: string | null)Image principale, pleine largeur.
setThumbnail(url: string | null)Petite image en coin.
setAuthor(options: EmbedAuthor | null){ name: string; url?: string; iconUrl?: string }.
addFields(...fields: EmbedField[])Ajoute un ou plusieurs champs à la suite des existants.
setFields(...fields: EmbedField[])Remplace tous les champs existants.
spliceFields(index, deleteCount, ...fields)Insertion/suppression chirurgicale de champs, comme Array.prototype.splice.
toJSON(): EmbedPayloadSérialise en objet brut — appelé automatiquement par le SDK.

EmbedField : { name: string; value: string; inline?: boolean }.

Toutes les méthodes setX retournent this, permettant le chaînage complet.

ts
new EmbedBuilder()
  .setTitle("Titre")
  .setDescription("Description")
  .setURL("https://bloumechat.com")
  .setColor("#5e72e4")           // hex string ou number
  .setTimestamp()                 // maintenant, par défaut
  .setAuthor({ name: "Auteur", iconUrl: "..." })
  .setFooter({ text: "Pied de page" })
  .setImage("https://...")
  .setThumbnail("https://...")
  .addFields({ name: "Champ", value: "Valeur", inline: true });
js
new EmbedBuilder()
  .setTitle("Titre")
  .setDescription("Description")
  .setURL("https://bloumechat.com")
  .setColor("#5e72e4")           // hex string ou number
  .setTimestamp()                 // maintenant, par défaut
  .setAuthor({ name: "Auteur", iconUrl: "..." })
  .setFooter({ text: "Pied de page" })
  .setImage("https://...")
  .setThumbnail("https://...")
  .addFields({ name: "Champ", value: "Valeur", inline: true });
ts
// Remplacer entièrement les champs d'un embed déjà construit
const embed = new EmbedBuilder().setTitle("Statut du build");
embed.setFields(
  { name: "Étape", value: "Tests", inline: true },
  { name: "Résultat", value: "✅ Réussi", inline: true },
);
await channel.send(embed);
js
// Remplacer entièrement les champs d'un embed déjà construit
const embed = new EmbedBuilder().setTitle("Statut du build");
embed.setFields(
  { name: "Étape", value: "Tests", inline: true },
  { name: "Résultat", value: "✅ Réussi", inline: true },
);
await channel.send(embed);

Voir aussi ​

SDK publié sous licence ISC.