Skip to content

TypeScript library for rapid Discord bot development. Reduces code duplication with structured command handling, localization, and built-in API client with circuit breaker protection.

License

Notifications You must be signed in to change notification settings

Pekno/simple-discordbot

Repository files navigation

Logo Simple-DiscordBot

GitHub License TypeScript npm version npm download

SimpleDiscordBot is a TypeScript library designed to simplify the creation of Discord bots using discord.js. It provides a structured approach to handling bot interactions, command registration, and localization.

πŸš€ Why This Package?

This package was created to reduce code duplication across my Discord bot projects. After noticing a lot of shared logic between my bots, I decided to extract the core functionalities into a reusable NPM package. This makes bot development faster, cleaner, and easier to maintain.

Tip

You can checkout my bots that use this libray, League of Legends Gamble Bot & SUNO Discord Bot


πŸ“¦ Installation

npm install @pekno/simple-discordbot

πŸ› οΈ Configuration

To initialize SimpleDiscordBot, provide a configuration object containing your bot credentials, intents, and localization settings.

Example: Instantiating the Bot

import { SimpleDiscordBot } from "simple-discordbot";
import { GatewayIntentBits } from "discord.js";

class MyService {
  // Your custom service logic here
}

const myService = new MyService();

const simpleBot = new SimpleDiscordBot<MyService>(
  {
    discord_token: CONFIG.DISCORD_TOKEN ?? "",
    discord_id: CONFIG.DISCORD_ID ?? "",
    intents: [GatewayIntentBits.Guilds],
    locale: CONFIG.LOCALE,
    available_locale: localList,
    locale_directory: localesPath,
  },
  myService
);

Configuration Options:

Option Type Description
discord_token string Your bot's authentication token.
discord_id string Your bot's application ID.
intents GatewayIntentBits[] List of intents required.
locale string Default bot locale.
available_locale string[] Supported locales.
locale_directory string Path to locale JSON files.

πŸ”₯ Creating Commands

Command Parameters

Parameter Type Description
name string Command name.
clickAlias string Alias for triggering the command via interactions.
description string Command description.
options CommandOption[] List of available options for the command.
execute (interaction, client, service, extraInfo?, modalPayload?) => Promise<void> Function to execute when the command is triggered.
registerPredicate () => boolean Function to determine if the command should be registered (usefull for command only based on available features).

Tip

execute's' extraInfo is an object containing all data passed through customId, for example if you fill a button with command;A:=1;B:=2;C:=3, extraInfo will be equal {A: "1", B: "2", C: "3"}. execute's' modalPayload is an object containing data from modals.

Basic Command Example

import { Command, CommandList } from "simple-discordbot";
import { ChatInputCommandInteraction, Client } from "discord.js";

const simpleCommandsList = new CommandList<MyService>();

simpleCommandsList.push(
  new Command({
    name: "start",
    description: "Starts an action",
    execute: async (
      interaction: ChatInputCommandInteraction,
      client: Client,
      myService: MyService
    ) => {
      await interaction.deferReply();
      // Use myService inside command execution
      await interaction.editReply("Command executed successfully.");
    },
  })
);

Command with Options

The CommandOption class now provides factory methods for easier creation of different option types:

import { Command, CommandList, CommandOption } from "simple-discordbot";
import { ChatInputCommandInteraction, Client } from "discord.js";

simpleCommandsList.push(
  new Command({
    name: "add",
    description: "Adds an item",
    options: [
      // Using the string factory method
      CommandOption.string(
        "item_name",
        "The name of the item",
        true, // required
        false // autocomplete
      ),
      // Using the integer factory method
      CommandOption.integer(
        "quantity",
        "The quantity to add",
        false // optional
      ),
      // Using the boolean factory method
      CommandOption.boolean(
        "notify",
        "Whether to send a notification",
        false // optional
      )
    ],
    execute: async (
      interaction: ChatInputCommandInteraction,
      client: Client,
      myService: MyService
    ) => {
      await interaction.deferReply();
      const itemName = interaction.options.getString("item_name");
      const quantity = interaction.options.getInteger("quantity") ?? 1;
      const notify = interaction.options.getBoolean("notify") ?? false;
      
      await interaction.editReply(`Added ${quantity} of ${itemName}. Notification: ${notify ? 'Yes' : 'No'}`);
    },
  })
);

You can still use the traditional constructor approach if needed:

new CommandOption({
  name: "item_name",
  description: "The name of the item",
  type: ApplicationCommandOptionType.String,
  required: true,
})

Modal Submission Example

import { ModalSubmitCommand } from "simple-discordbot";
import { ModalSubmitInteraction, Client } from "discord.js";

simpleCommandsList.push(
  new ModalSubmitCommand({
    name: "submit_feedback_modal",
    execute: async (
      interaction: ModalSubmitInteraction,
      client: Client,
      myService: MyService,
      extraInfo: any,
      modalPayload: ModalSubmitFields
    ) => {
      const { userId } = extraInfo as { userId: string };
      const feedback = modalPayload?.getField('feedback')?.value;
      await interaction.deferReply({ ephemeral: true });
      if (!feedback) throw new Error("Feedback cannot be empty.");
      console.log(`User ${userId} submitted feedback: ${feedback}`);
      interaction.editReply({ content: "Thank you for your feedback!" });
    },
  })
);

πŸš€ Running the Bot

Once your bot and commands are set up, start your bot with:

const client = await simpleBot.start(simpleCommandsList);

Tip

Calling start will return the Client object used by the bot, if you ever need it somewhere else.

πŸ”₯ Using the API Client with Circuit Breaker

Creating API Classes

You can extend MainApi to create custom API clients with built-in request queuing, rate limiting, and circuit breaker functionality.

class MyFirstApi extends MainApi {
    //...
}
const requestPerMinutes = 30;
const myFirstApi = new MyFirstApi(
    { 'My-Header-Token': "value" },
    requestPerMinutes
);
class MySecondApi extends MainApi {
    //...
}
const mySecondApi = new MySecondApi();

Making API Requests

The MainApi class now provides methods for all common HTTP verbs. All requests are queued and processed according to rate limits.

// GET request
const getData = async (endpoint: string): Promise<any> => {
  try {
    const response = await this.get(`https://api.example.com/${endpoint}`);
    return response.data;
  } catch (error: any) {
    if (error.response?.status === 404) return null;
    throw error;
  }
};

// POST request
const createData = async (endpoint: string, data: any): Promise<any> => {
  try {
    const response = await this.post(`https://api.example.com/${endpoint}`, data);
    return response.data;
  } catch (error: any) {
    throw error;
  }
};

// Other available methods: put(), delete(), patch()

Circuit Breaker Protection

The API client includes a circuit breaker that prevents cascading failures when external services are experiencing issues:

  • Closed State: Normal operation, requests flow through
  • Open State: After multiple failures, requests are blocked to prevent overloading the failing service
  • Half-Open State: After a timeout period, allows a test request to check if the service has recovered

Resource Management

When you're done with an API instance, properly dispose of it to prevent memory leaks:

// Clean up resources when done
myApi.dispose();

πŸ“œ License

This project is licensed under MIT.


πŸ“š Additional Notes

  • This package relies on discord.js, make sure to install it.
  • The library includes i18n support, allowing easy localization.
  • The command structure is fully typed, making development safer.
  • All classes and methods are thoroughly documented with JSDoc comments.

πŸ”— Contributing & Source Code

Contributions and feedback are always welcome! If you have any suggestions or issues, feel free to open an issue or submit a pull request.

Happy coding! πŸŽ‰

About

TypeScript library for rapid Discord bot development. Reduces code duplication with structured command handling, localization, and built-in API client with circuit breaker protection.

Resources

License

Stars

Watchers

Forks

Packages

No packages published