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;