Skip to content

Commands

The ZombieClient framework makes creating robust commands incredibly easy. It handles automatic deployment to Discord API, intelligent diffing (to avoid rate limits), parameter autocomplete, and execution.

Slash Commands

A standard Slash Command requires exporting an object that matches the SlashCommand interface.

typescript
import { ChatInputCommandBuilder, MessageFlags } from 'discord.js';
import type { SlashCommand } from '@thezombiepl/zombieclient/interfaces';

export default {
    data: new ChatInputCommandBuilder()
        .setName('ping')
        .setDescription('Sprawdź opóźnienie bota.'),
        
    // (Optional) Deploy only to specific guilds
    guild: ['1004821657455706153'],
    
    // (Optional) Developer-only command (only client.ownerId can use it)
    dev: true,
    
    // (Optional) Cooldown in seconds for this specific command
    cooldown: 3,

    execute: async (client, interaction) => {
        await interaction.reply({
            content: `Pong! ${client.ws.ping}ms`,
            flags: MessageFlags.Ephemeral,
        });
    },
} satisfies SlashCommand;

Autocomplete

ZombieClient automatically routes autocomplete interactions to the matching command file if you provide the autocomplete function.

typescript
import { ChatInputCommandBuilder } from 'discord.js';
import type { SlashCommand } from '@thezombiepl/zombieclient/interfaces';

export default {
    data: new ChatInputCommandBuilder()
        .setName('select')
        .setDescription('Wybierz coś')
        .addStringOption((option) =>
            option
                .setName('choice')
                .setDescription('Wybierz jedną z opcji')
                .setAutocomplete(true) // Required for autocomplete
                .setRequired(true)
        ),
        
    execute: async (client, interaction) => {
        const choice = interaction.options.getString('choice');
        await interaction.reply(`Wybrano: ${choice}`);
    },
    
    // Autocomplete handler
    autocomplete: async (client, interaction) => {
        const focusedValue = interaction.options.getFocused();
        const options = ['Opcja A', 'Opcja B', 'Opcja C'];

        const filtered = options.filter((option) =>
            option.toLowerCase().includes(focusedValue.value.toLowerCase()),
        );

        await interaction.respond(filtered.map((option) => ({ name: option, value: option })));
    },
} satisfies SlashCommand;

Context Menu Commands

Context Menu commands (User Context or Message Context) follow a very similar structure, but use ContextMenuCommandBuilder and the ContextMenuCommand interface.

typescript
import { 
  UserContextCommandBuilder, 
  APIEmbedFooter, 
  EmbedBuilder, 
  GuildMember, 
  MessageFlags
} from 'discord.js';
import type { ContextMenuCommand } from '@thezombiepl/zombieclient/interfaces';

export default {
  data: new UserContextCommandBuilder()
    .setName('avatar'), // Name shown in the user context menu
    
  execute: async (client, interaction) => {
    // Cast is safe since we know this is a user context command
    const targetMember = interaction.member as GuildMember;

    const embed = new EmbedBuilder()
      .setColor(client.colors.BOT_ORANGE)
      .setTitle(`Awatar użytkownika: ${targetMember.displayName}`)
      .setImage(targetMember.displayAvatarURL({ size: 1024 }))
      .setTimestamp();

    await interaction.reply({ embeds: [embed], flags: MessageFlags.Ephemeral });
  },
} satisfies ContextMenuCommand;

Wszelkie prawa zastrzeżone.