Commands
Define, register, and dispatch slash and prefix commands with @djs-commands/core.
A command in DJS Commands is a plain object. There are no decorators, no class hierarchies, and no on-disk conventions you have to follow. You build the object with defineCommand, you put the object somewhere your bot can find it, and you pass it to createCommandHandler.
defineCommand
defineCommand(command) returns its argument unchanged. It exists purely so the TypeScript compiler can give you autocomplete and structural validation as you type. At runtime it's identity.
import { defineCommand } from "@djs-commands/core";
const ping = defineCommand({
name: "ping",
description: "Replies with pong",
run: async ({ reply }) => {
await reply("pong");
},
});Required fields
| Field | Type | Description |
|---|---|---|
name | string | The slash-command name. Must match Discord's naming rules: 1–32 characters, lowercase, [a-z0-9_-]. |
description | string | The 1–100-character description shown in the Discord client. |
run | (ctx) => void | Promise<void> | The handler. Receives a CommandRunContext. |
Optional fields
| Field | Type | Notes |
|---|---|---|
options | CommandOptions | Typed schema for slash-command options — see Options. |
validators | Validator[] | Custom pre-handler checks. See Validators. |
cooldown | CooldownConfig | Rate limit. See Cooldowns. |
ownerOnly | boolean | When true, only IDs in botOwners (passed to the handler) can run it. |
guildOnly | boolean | When true, blocks DM invocations. |
channels | string[] | Allow-list of channel IDs the command can run in. |
permissions | PermissionsString[] | Discord member permissions required (e.g. ["BanMembers"]). |
roles | string[] | Role IDs the invoking member must have. |
legacy | CommandLegacyConfig | Opt this command into legacy prefix invocation; supports aliases. |
CommandRunContext
CommandRunContext is a discriminated union over the invocation source. Both branches share a unified surface so most handlers don't need to care whether they were invoked via slash or prefix:
type CommandRunContext = SlashRunContext | LegacyRunContext;
interface BaseRunContext {
client: Client;
author: User;
guild: Guild | null;
member: GuildMember | null;
channel: TextBasedChannel | null;
channelId: string | null;
options: ResolveOptions<S>; // typed from your `options` schema
reply: (content: CommandReplyInput) => Promise<unknown>; // use flags: MessageFlags.Ephemeral for ephemeral slash replies
}
type SlashRunContext = BaseRunContext & { type: "slash"; interaction: ChatInputCommandInteraction };
type LegacyRunContext = BaseRunContext & { type: "legacy"; message: Message };When you need source-specific behavior, narrow on ctx.type:
import { MessageFlags } from "discord.js";
run: 