Ajouter une commande
1. Creer le fichier
Creer un fichier dans le dossier commands/ du module concerne :
src/modules/<module>/commands/<nom>.command.ts2. Implementer l'interface SlashCommand
Chaque commande exporte un objet conforme a l'interface SlashCommand :
typescript
import { ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js';
import type { SlashCommand } from '../../../shared/types/command.js';
export const exampleCommand: SlashCommand = {
data: new SlashCommandBuilder()
.setName('example')
.setDescription('Description de la commande'),
async execute(interaction: ChatInputCommandInteraction) {
await interaction.reply('Hello !');
},
};Interface
typescript
export interface SlashCommand {
data:
| SlashCommandBuilder
| SlashCommandOptionsOnlyBuilder
| SlashCommandSubcommandsOnlyBuilder
| Omit<SlashCommandBuilder, 'addSubcommand' | 'addSubcommandGroup'>;
execute: (interaction: ChatInputCommandInteraction, client: Client) => Promise<void>;
autocomplete?: (interaction: AutocompleteInteraction) => Promise<void>;
}3. Exemple avec sous-commandes
typescript
export const myCommand: SlashCommand = {
data: new SlashCommandBuilder()
.setName('mymod')
.setDescription('Module example')
.addSubcommand((sub) =>
sub.setName('action')
.setDescription('Faire une action')
.addStringOption((opt) =>
opt.setName('param').setDescription('Parametre').setRequired(true),
),
),
async execute(interaction: ChatInputCommandInteraction) {
const sub = interaction.options.getSubcommand();
if (sub === 'action') {
const param = interaction.options.getString('param', true);
await interaction.reply(`Action avec : ${param}`);
}
},
};4. Permissions
Commande owner only
typescript
import { isOwner } from '../../../core/permissions.js';
async execute(interaction: ChatInputCommandInteraction) {
if (!isOwner(interaction)) {
await interaction.reply({
content: '❌ Commande reservee au proprietaire du bot.',
ephemeral: true,
});
return;
}
// ...
}Commande moderateur
typescript
import { PermissionFlagsBits } from 'discord.js';
// Dans le builder :
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers)5. Reponses longues (deferReply)
Pour les commandes qui prennent du temps (appels API, requetes DB complexes), utiliser deferReply :
typescript
async execute(interaction: ChatInputCommandInteraction) {
await interaction.deferReply({ ephemeral: true });
// ... traitement long ...
await interaction.editReply('Resultat');
}WARNING
Apres deferReply, utiliser editReply et followUp au lieu de reply. Discord donne 3 secondes pour la premiere reponse, 15 minutes apres un defer.
6. Reponses ephemerales
typescript
await interaction.reply({ content: 'Visible uniquement par toi.', ephemeral: true });7. Enregistrer la commande
a. Importer dans register-commands.ts
typescript
// src/app/register-commands.ts
import { exampleCommand } from '../modules/<module>/commands/example.command.js';
const allCommands: SlashCommand[] = [
// ... autres commandes ...
exampleCommand,
];b. Deployer sur Discord
bash
npm run registerCette commande execute register-commands.ts en mode standalone, qui envoie les definitions de commandes a l'API Discord via REST.
Cooldown global
Toutes les commandes sont soumises a un cooldown global de 5 secondes par utilisateur, gere dans le dispatcher central (bootstrap.ts). Il n'est pas necessaire de l'implementer dans chaque commande.
