Skip to main content

SlashService

SlashService provides utilities for creating, extracting, registering, and handling Discord Slash Commands (/).

It supports both the standard Discord.js command structure and the Disfox Command Model (DFX).

BehaviorTable Result


Import​

import { SlashService } from "disfox";

Basic Command Structure​

Standard Discord.js command modules are supported.

import { SlashCommandBuilder } from "discord.js";

export default {
data: new SlashCommandBuilder()
.setName("ping")
.setDescription("Replies with Pong"),

async execute(interaction) {
await interaction.reply("Pong!");
}
};

A valid command must contain:

  • data
  • execute

Command Extraction​

Commands can be extracted from a single file or from a directory.

Extracting a Single File​

import { SlashService } from "disfox";

const command = SlashService.extractFile("./command.js");

Returns:

[
{
data: SlashCommandBuilder {
options: [],
name: "ping",
name_localizations: undefined,
description: "Replies with Pong",
description_localizations: undefined,
contexts: undefined,
default_permission: undefined,
default_member_permissions: undefined,
dm_permission: undefined,
integration_types: undefined,
nsfw: undefined
},

execute: [AsyncFunction: execute]
}
]

extractFile() supports both Discord.js and Disfox command models.


Extracting a Directory​

import { SlashService } from "disfox";

const commands = await SlashService.extractDir("./commands");

Returns:

{
valid: [
{
data: SlashCommandBuilder {
options: [],
name: "ping",
name_localizations: undefined,
description: "Replies with Pong",
description_localizations: undefined,
contexts: undefined,
default_permission: undefined,
default_member_permissions: undefined,
dm_permission: undefined,
integration_types: undefined,
nsfw: undefined
},

execute: [AsyncFunction: execute]
}
],

invalid: []
}

Valid commands are stored in valid. Invalid command structures are stored in invalid.


Validation Rules​

A command must contain both data and execute.

import { SlashCommandBuilder } from "discord.js";

export default {
data: new SlashCommandBuilder()
.setName("ping")
.setDescription("Replies with Pong!"),

async execute(interaction) {
await interaction.reply("Pong!");
}
};

Disfox Command Model (DFX)​

Since v0.0.7, Disfox includes its own model for creating Slash Commands.

Creating a Command with DFX​

import { SlashService } from "disfox";

const command = new SlashService.Command("ping")
.description("Replies with Pong!")
.action(interaction => {
interaction.reply("Pong!");
});

export default command;

Command names cannot contain spaces, uppercase letters, or special characters except - and _.


Using Tags​

Tags can change the visibility or behavior of a command.

import { SlashService, SlashTag } from "disfox";

const command = new SlashService.Command("ping")
.description("Replies with Pong!")
.mark(SlashTag.AdminOnly)
.action(interaction => {
interaction.reply("Pong!");
});

export default command;
TagDescriptionEnum
AdminOnlyMakes the command available only to users with administrator permissions.SlashTag.AdminOnly
NSFWMarks the command as age-restricted and available only in NSFW contexts.SlashTag.NSFW

Adding Options​

Options are created with SlashService.Option and attached to commands using .option().

import { SlashOptions, SlashService } from "disfox";

const option = new SlashService.Option("choice")
.type(SlashOptions.String)
.required(true)
.description("Select the weapon.");

const command = new SlashService.Command("rps")
.description("Play Rock, Paper, Scissors against the bot!")
.option(option)
.action(async interaction => {
// ...
});

export default command;

Methods​

MethodParameterReturnsDescription
.type()SlashOptionsthisSets the option type.
.description()stringthisSets the option description.
.required()booleanthisDefines whether the option is required.
.choices()Record<any, any>thisDefines predefined choices.
.minNumber()numberthisSets the minimum numeric value.
.maxNumber()numberthisSets the maximum numeric value.
.channelTypes()...ChannelType[]thisRestricts the allowed channel types.

Option Types​

SlashOptionDiscord.js classDescription
SlashOptions.StringSlashCommandStringOptionText input.
SlashOptions.NumberSlashCommandNumberOptionNumeric input, including decimal values.
SlashOptions.ChannelSlashCommandChannelOptionChannel selection.
SlashOptions.BooleanSlashCommandBooleanOptionBoolean value (true or false).
SlashOptions.RoleSlashCommandRoleOptionRole selection.
SlashOptions.AttachmentSlashCommandAttachmentOptionFile or attachment input.
SlashOptions.MentionableSlashCommandMentionableOptionMentionable user or role.

Multiple Options​

Call .option() multiple times to add more than one option.

import { SlashOptions, SlashService } from "disfox";

const option1 = new SlashService.Option("choice")
.type(SlashOptions.String)
.required(true)
.description("Select the weapon.");

const option2 = new SlashService.Option("target")
.type(SlashOptions.Mentionable)
.required(true)
.description("Select a target.");

const command = new SlashService.Command("rps")
.description("Play Rock, Paper, Scissors against the bot!")
.option(option1)
.option(option2)
.action(async interaction => {
// ...
});

export default command;

Adding Options with Choices​

.choices() defines a fixed set of values for an option.

import { SlashOptions, SlashService } from "disfox";

const option = new SlashService.Option("choice")
.type(SlashOptions.String)
.required(true)
.description("Select the weapon.")
.choices({
rock: "rock",
paper: "paper",
scissors: "scissors"
});

The key is used as the choice name, while the value is passed to the interaction.

const choice = interaction.options.getString("choice", true);

Numeric Limits​

Numeric options can use minNumber() and maxNumber().

import { SlashOptions, SlashService } from "disfox";

const option = new SlashService.Option("amount")
.type(SlashOptions.Number)
.description("Select an amount.")
.required(true)
.minNumber(1)
.maxNumber(100);

Channel Types​

Channel options can be restricted using channelTypes().

import { ChannelType } from "discord.js";
import { SlashOptions, SlashService } from "disfox";

const option = new SlashService.Option("channel")
.type(SlashOptions.Channel)
.description("Select a channel.")
.required(true)
.channelTypes(
ChannelType.GuildText,
ChannelType.GuildVoice,
ChannelType.GuildForum
);

Registering and Listening for Commands​

Both command models use the same registration process.

Disfox command models are converted internally before registration.


Global Registration​

import { SlashService } from "disfox";
import { Events } from "discord.js";

app.client.on(Events.ClientReady, async () => {
const commands = (
await SlashService.extractDir("./commands")
).valid;

await app.slash.deployGlobal(commands);
});

deployGlobal() registers the commands globally.


Guild Registration​

import { SlashService } from "disfox";
import { Events } from "discord.js";

app.client.on(Events.ClientReady, async () => {
const commands = (
await SlashService.extractDir("./commands")
).valid;

await app.slash.deployGuilds(
commands,
["1234", "12345"]
);
});

The second parameter contains the guild IDs where the commands will be registered.


Extraction Settings​

SlashService.extractDir() accepts optional extraction settings.

const commands = await SlashService.extractDir("./commands", {
autoConverts: true,
ignoreInvalidStructures: false
});

Options​

PropertyTypeDefaultDescription
autoConvertsbooleantrueAutomatically converts Disfox command models during extraction.
ignoreInvalidStructuresbooleanfalseReturns only valid commands instead of { valid, invalid }.

autoConverts​

Controls automatic conversion of Disfox command models.

const commands = await SlashService.extractDir("./commands", {
autoConverts: false
});

Automatic conversion is enabled by default.

const commands = await SlashService.extractDir("./commands");

ignoreInvalidStructures​

By default, extractDir() returns both valid and invalid structures.

const commands = await SlashService.extractDir("./commands");

console.log(commands.valid);
console.log(commands.invalid);

Return structure:

interface extractionValidates {
valid: SlashCommand[];
invalid: any[];
}

With ignoreInvalidStructures enabled:

const commands = await SlashService.extractDir("./commands", {
ignoreInvalidStructures: true
});

the method returns the valid command array directly.

// SlashCommand[]
console.log(commands);

Return Types​

ConfigurationReturn type
DefaultPromise<extractionValidates>
ignoreInvalidStructures: falsePromise<extractionValidates>
ignoreInvalidStructures: truePromise<SlashCommand[]>
static async extractDir(
dir: string,
options?: extractionOptions
): Promise<extractionValidates | SlashCommand[]>

Type Definitions​

interface extractionOptions {
autoConverts?: boolean;
ignoreInvalidStructures?: boolean;
}

interface extractionValidates {
valid: SlashCommand[];
invalid: any[];
}

Default Settings​

{
autoConverts: true,
ignoreInvalidStructures: false
}

Listening for Commands​

Use app.slash.listen() to handle registered Slash Commands.

Basic Usage​

import { SlashService } from "disfox";
import { Events } from "discord.js";

app.client.on(Events.ClientReady, async () => {
const commands = (
await SlashService.extractDir("./commands")
).valid;

await app.slash.deployGlobal(commands);

app.slash.listen();
});

Custom Error Message​

app.slash.listen({
onError: {
message: "An error occurred. Please try again.",
flags: 64
}
});

Custom Error Callback​

app.slash.listen({
onError: {
callback: (interaction, error) => {
console.error(
"Failed to execute command:",
error
);

interaction.reply(
"An error occurred. Please try again."
);
}
}
});

Attaching BehaviorTables​

A BehaviorTable can be attached to a command with .dock().

import {
SlashService,
BehaviorTable
} from "disfox";

const table = new BehaviorTable({});

const command = new SlashService.Command("ping")
.description("Replies with Pong!")
.dock(table)
.action(interaction => {
interaction.reply("Pong!");
});

export default command;

BehaviorTables provide reusable restrictions, permissions, and actions for commands.


Last updated: October 2, 2026