Skip to content

Fmfl-Devteam/easy-discord.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

easy-discord.js

A discord.js v14 wrapper that makes bot development faster and easier β€” file-based auto-loading, typed base classes for commands, events, and components, plus simplified builder helpers.

npm install @fmfl-devteam.de/easy-discord.js discord.js

discord.js is a peer dependency β€” you must install it alongside this package.


Table of Contents


Quick Start

import { EasyClient } from '@fmfl-devteam/easy-discord.js';
import { GatewayIntentBits } from 'discord.js';
import path from 'path';

const client = new EasyClient({
  token: process.env.TOKEN!,
  clientId: process.env.CLIENT_ID!,
  clientOptions: {
    intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
  },
  commandsPath: path.join(__dirname, 'commands'),
  eventsPath: path.join(__dirname, 'events'),
  componentsPath: path.join(__dirname, 'components'),
  // guildId: 'YOUR_GUILD_ID', // Optional: scope commands to a guild (instant, good for dev)
});

await client.start();

client.start() will:

  1. Load and register all slash/context-menu commands with Discord
  2. Attach all event listeners
  3. Load all component handlers
  4. Log in the bot

EasyClient

new EasyClient(options: EasyClientOptions)
Option Type Required Description
token string βœ… Your bot token
clientId string βœ… Your application's client ID
clientOptions ClientOptions βœ… Standard discord.js client options (intents, etc.)
commandsPath string β€” Absolute path to commands directory
eventsPath string β€” Absolute path to events directory
componentsPath string β€” Absolute path to components directory
guildId string β€” Register commands to a specific guild (omit for global)

Properties:

  • client.commandManager β€” access loaded commands
  • client.eventManager β€” access registered events
  • client.componentManager β€” access component handlers

Slash Commands

Create a file in your commands/ folder. The default export must be an instance of SlashCommand.

// commands/ping.ts
import { SlashCommand } from '@fmfl-devteam/easy-discord.js';
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';

export default new class PingCommand extends SlashCommand {
  data = new SlashCommandBuilder()
    .setName('ping')
    .setDescription('Replies with Pong!');

  async execute(interaction: ChatInputCommandInteraction) {
    await interaction.reply('Pong! πŸ“');
  }
};

With autocomplete:

import { SlashCommand } from '@fmfl-devteam/easy-discord.js';
import {
  SlashCommandBuilder,
  ChatInputCommandInteraction,
  AutocompleteInteraction,
} from 'discord.js';

export default new class SearchCommand extends SlashCommand {
  data = new SlashCommandBuilder()
    .setName('search')
    .setDescription('Search something')
    .addStringOption(o => o.setName('query').setDescription('Search query').setAutocomplete(true));

  async execute(interaction: ChatInputCommandInteraction) {
    const query = interaction.options.getString('query', true);
    await interaction.reply(`Searching for: ${query}`);
  }

  async autocomplete(interaction: AutocompleteInteraction) {
    const focused = interaction.options.getFocused();
    const choices = ['apple', 'banana', 'cherry'].filter(c => c.startsWith(focused));
    await interaction.respond(choices.map(c => ({ name: c, value: c })));
  }
};

Context Menu Commands

// commands/avatar.ts
import { ContextMenuCommand } from '@fmfl-devteam/easy-discord.js';
import {
  ContextMenuCommandBuilder,
  ApplicationCommandType,
  UserContextMenuCommandInteraction,
} from 'discord.js';

export default new class AvatarCommand extends ContextMenuCommand {
  data = new ContextMenuCommandBuilder()
    .setName('Get Avatar')
    .setType(ApplicationCommandType.User);

  async execute(interaction: UserContextMenuCommandInteraction) {
    await interaction.reply(interaction.targetUser.displayAvatarURL({ size: 512 }));
  }
};

Events

Create a file in your events/ folder. The default export must be an instance of Event.

// events/ready.ts
import { Event } from '@fmfl-devteam/easy-discord.js';
import { Client } from 'discord.js';

export default new class ReadyEvent extends Event<'ready'> {
  name = 'ready' as const;
  once = true;

  async execute(client: Client<true>) {
    console.log(`Logged in as ${client.user.tag}`);
  }
};
// events/guildMemberAdd.ts
import { Event } from '@fmfl-devteam/easy-discord.js';
import { GuildMember } from 'discord.js';

export default new class GuildMemberAddEvent extends Event<'guildMemberAdd'> {
  name = 'guildMemberAdd' as const;

  async execute(member: GuildMember) {
    console.log(`${member.user.tag} joined ${member.guild.name}`);
  }
};

Component Handlers

Buttons

// components/confirm.ts
import { ButtonHandler } from '@fmfl-devteam/easy-discord.js';
import { ButtonInteraction } from 'discord.js';

export default new class ConfirmButton extends ButtonHandler {
  customId = 'confirm';

  async execute(interaction: ButtonInteraction) {
    await interaction.reply({ content: 'βœ… Confirmed!', ephemeral: true });
  }
};

Select Menus

// components/role-select.ts
import { SelectMenuHandler } from '@fmfl-devteam/easy-discord.js';
import { AnySelectMenuInteraction } from 'discord.js';

export default new class RoleSelectMenu extends SelectMenuHandler {
  customId = 'role-select';

  async execute(interaction: AnySelectMenuInteraction) {
    await interaction.reply({ content: `You picked: ${interaction.values.join(', ')}`, ephemeral: true });
  }
};

Modals

// components/feedback-modal.ts
import { ModalHandler } from '@fmfl-devteam/easy-discord.js';
import { ModalSubmitInteraction } from 'discord.js';

export default new class FeedbackModal extends ModalHandler {
  customId = 'feedback-modal';

  async execute(interaction: ModalSubmitInteraction) {
    const feedback = interaction.fields.getTextInputValue('feedback');
    await interaction.reply({ content: `Thanks for your feedback: ${feedback}`, ephemeral: true });
  }
};

Builders

EasyEmbed

Extends EmbedBuilder with color presets and convenience methods.

import { EasyEmbed } from '@fmfl-devteam/easy-discord.js';

// Color presets
new EasyEmbed().success().setTitle('Done!').setDescription('It worked!');
new EasyEmbed().error().setTitle('Error').setDescription('Something went wrong.');
new EasyEmbed().warning().setTitle('Warning').setDescription('Proceed with caution.');
new EasyEmbed().info().setTitle('Info').setDescription('Here is some info.');

// Helpers
new EasyEmbed()
  .info()
  .setTitle('Hello')
  .setTimestampNow()
  .setDefaultFooter('My Bot', 'https://example.com/icon.png');
Method Color
.success() Green #57F287
.error() Red #ED4245
.warning() Yellow #FEE75C
.info() Blurple #5865F2

EasyButton

import { EasyButton } from '@fmfl-devteam/easy-discord.js';
import { ButtonStyle } from 'discord.js';

// Interaction button
new EasyButton({ label: 'Confirm', customId: 'confirm', style: ButtonStyle.Success });
new EasyButton({ label: 'Cancel', customId: 'cancel', style: ButtonStyle.Danger });
new EasyButton({ label: 'Click', customId: 'click', emoji: 'πŸŽ‰' });

// Link button
EasyButton.link({ label: 'Visit Site', url: 'https://example.com' });

EasySelectMenu

import { EasySelectMenu } from '@fmfl-devteam/easy-discord.js';

const menu = new EasySelectMenu('color-select', 'Pick a color')
  .addOption('Red', 'red', 'The color red', 'πŸ”΄')
  .addOption('Blue', 'blue', 'The color blue', 'πŸ”΅')
  .addOption('Green', 'green', 'The color green', '🟒')
  .setMinValues(1)
  .setMaxValues(1);

EasyModal

import { EasyModal } from '@fmfl-devteam/easy-discord.js';
import { TextInputStyle } from 'discord.js';

const modal = new EasyModal('feedback-modal', 'Submit Feedback')
  .addInput('name', 'Your name', TextInputStyle.Short, 'e.g. John')
  .addInput('feedback', 'Your feedback', TextInputStyle.Paragraph, 'Tell us what you think...', true, 10, 500);

EasyActionRow

import { EasyActionRow, EasyButton } from '@fmfl-devteam/easy-discord.js';
import { ButtonStyle } from 'discord.js';

const row = new EasyActionRow().addComponents(
  new EasyButton({ label: 'Yes', customId: 'yes', style: ButtonStyle.Success }),
  new EasyButton({ label: 'No', customId: 'no', style: ButtonStyle.Danger }),
);

Logger

A built-in ANSI color-coded logger, prefixed with [easy-discord.js].

import { Logger } from '@fmfl-devteam/easy-discord.js';

Logger.info('Bot is starting...');
Logger.success('Commands registered!');
Logger.warn('Missing optional config.');
Logger.error('Something broke!', new Error('details'));
Logger.debug('Variable value: foo'); // only prints when process.env.DEBUG is set

Recommended File Structure

src/
  index.ts            ← bot entry point (new EasyClient(...).start())
  commands/
    ping.ts
    avatar.ts
  events/
    ready.ts
    guildMemberAdd.ts
  components/
    confirm.ts        ← ButtonHandler
    role-select.ts    ← SelectMenuHandler
    feedback-modal.ts ← ModalHandler

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Sponsor this project

Packages

 
 
 

Contributors