@fmfl-devteam.de/easy-discord.js
v1.0.2
Published
A discord.js v14 wrapper that makes bot development easier with custom classes, file-based auto-loading, and simplified builders.
Downloads
201
Readme
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.jsis a peer dependency — you must install it alongside this package.
Table of Contents
- Quick Start
- EasyClient
- Slash Commands
- Context Menu Commands
- Events
- Component Handlers
- Builders
- Logger
- File Structure
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:
- Load and register all slash/context-menu commands with Discord
- Attach all event listeners
- Load all component handlers
- 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 commandsclient.eventManager— access registered eventsclient.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 setRecommended 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