1.1.2 • Published 1 year ago

discmd-handler v1.1.2

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
1 year ago

While this package has not been tested on Windows, we encourage you to try it out and let us know of any issues you encounter. We value your feedback and would love to work with you to improve compatibility with Windows. If you're interested in contributing to this effort, we welcome your input and pull requests!

Table of contents

Introduction

discmd-handler is a lightweight and easy-to-use command handler for Discord.js bots. This package is designed to simplify the process of implementing a command handler in your Discord bot by providing a flexible and customizable framework that can handle a wide range of commands.

The package currently contains handlers for the commands that the developer uses. However, if you need support for other types of commands, you can make a feature request or contribute to the development of the package.

With discmd-handler, you can easily create and manage commands for your bot without having to write the same boilerplate code every time. The package is designed to be modular and flexible, allowing you to customize it to fit your specific needs.

Whether you're a beginner or an experienced developer, discmd-handler can help you save time and streamline your bot development process. Try it out today and see how easy it can be to implement a powerful command handler for your Discord bot!

Installation

Requirements

  • discord.js@14

Install

npm i discmd-handler     # npm
yarn add discmd-handler  # yarn
pnpm add discmd-handler  # pnpm

Basic usage

Setup:

import { Client, GatewayIntentBits } from "discord.js";
import { handleCommands } from "discmd-handler";

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

handleCommands({
  client,
  // All the paths are relative to process.cwd()
  commands: {
    ButtonCommands: "commands/button",
    ChatInputCommands: "commands/chat-input",
    MessageCommands: "commands/message",
    SelectMenuCommands: "commands/select-menu",
  },
  // prefix can be either a string or an array of strings or a function that return a string or array of strings
  // When using a function, the first param will be the `Message` instance.
  prefix: "!",
});

client.login();

Inside commands/chat-input/ping.js:

import { SlashCommandBuilder } from "discord.js";

/** @type {import("discmd-handler").ChatInputCommandInterface} */
export default {
  data: new SlashCommandBuilder()
    .setName("ping")
    .setDescription("Replies with pong!"),
  execute(interaction) {
    interaction.reply("Pong!");
  },
};

We use jsdoc @type tag to get autocompletion.

Other commands

Message Command

import {
  ActionRowBuilder,
  ButtonBuilder,
  ButtonStyle,
  SlashCommandBuilder,
  StringSelectMenuBuilder,
} from "discord.js";

/** @type {import("discmd-handler").MessageCommandInterface} */
export default {
  name: "components",
  description: "Sends a message with a button and a select menu",
  execute(data) {
    const button = new ButtonBuilder()
      .setCustomId("button#" + data.author.id) // Anything after # is considerd metadata for the command
      .setLabel("This is a button")
      .setStyle(ButtonStyle.Primary);

    const selectMenu = new StringSelectMenuBuilder()
      .setCustomId("selectMenu#" + data.author.id) // Anything after # is considerd metadata for the command
      .addOptions(
        { label: "Option 1", value: "opt1" },
        { label: "Option 2", value: "opt2" }
      );

    const buttonActionRow = new ActionRowBuilder().addComponents(button);
    const selectMenuActionRow = new ActionRowBuilder().addComponents(
      selectMenu
    );

    return data.channel.send({
      components: [buttonActionRow, selectMenuActionRow],
    });
  },
};

Button Command

/** @type {import("discmd-handler").ButtonCommandInterface} */
export default {
  // name should be the part of the customId before #
  // if there is no #, it should be the full customId
  name: "button",
  execute(interaction, metadata) {
    // metadata contains the text after the first # in the customId
    // In this case, its the id of the user who ran the !components command
    if (interaction.user.id !== metadata)
      return interaction.reply({
        content: "You cannot click that button",
        ephemeral: true,
      });

    return interaction.reply(`${interaction.user} clicked the button`);
  },
};

Select Menu Command

/** @type {import("discmd-handler").SelectMenuCommandInterface} */
export default {
  // name should be the part of the customId before #
  // if there is no #, it should be the full customId
  name: "selectMenu",
  execute(interaction, metadata) {
    // metadata contains the text after the first # in the customId
    // In this case, its the id of the user who ran the !components command
    if (interaction.user.id !== metadata)
      return interaction.reply({
        content: "You cannot use this select menu",
        ephemeral: true,
      });

    return interaction.reply(
      `${interaction.user} choose ${interaction.values[0]}`
    );
  },
};

Registering Slash Commands

This code should be in a seperate file. You should only run it when you want to register slash commands.

import { registerApplicationCommands } from "discmd-handler";

registerApplicationCommands({
  token: process.env.DISCORD_TOKEN,
  commands: {
    ChatInputCommands: "commands/chat-input",
  },
  // Omit this option if you want to register global commands
  guildId: "guild id of the dev server",
});

Guides and concepts

Working with CommonJs or TypeScript

All the examples above are given in ESModule. However, this package also supports CommonJs and TypeScript.

CommonJs

const { SlashCommandBuilder } = require("discord.js");

/** @type {import("discmd-handler").ChatInputCommandInterface} */
module.exports = {
  data: new SlashCommandBuilder()
    .setName("ping")
    .setDescription("Replies with pong!"),
  execute(interaction) {
    interaction.reply("Pong!");
  },
};

TypeScript

import { SlashCommandBuilder } from "discord.js";
import { ChatInputCommandInterface } from "discmd-handler";

export default {
  data: new SlashCommandBuilder()
    .setName("ping")
    .setDescription("Replies with pong!"),
  execute(interaction) {
    interaction.reply("Pong!");
  },
} satisfies ChatInputCommandInterface;

The satisfies keyword in typescript is introduced in version 4.9. If you are using older version, your code should look like this instead.

export default <ChatInputCommandInterface>{
  data: ...,
  execute(interaction) {
    ....
  },
}

Error handling

Currently, error handling is not customizable. If an error occurs while running the execute function, the default behavior is to log it to the console. However, we recognize the importance of providing users with the ability to customize error handling to better suit their needs. As such, we are actively working on a solution and plan to make it available in future versions.

Changelog

View the changelog at CHANGELOG.md

1.1.1

1 year ago

1.1.0

1 year ago

1.1.2

1 year ago

1.0.0

1 year ago