Discord-FP
A Beautiful Application Command Framework based on Discord.js
Features
- Type-safe
- Light-weight
- High performance
- Auto-complete & Middlewares
- File-system Based
- Beautiful code with Functional Programming
- Support both ESM and CommonJS
Install
npm install discord-fp
Note
Example below uses commonjs + typescript, you may convert it into normal common js syntax yourself
Slash command in the Best way
Stop writing lots of interaction.options.get("name")
just for getting the value of an option
Let us handle everything!
import { options, slash } from "discord-fp";
export default slash({
description: "Say Hello to you",
options: {
name: options.string({
description: "Your name",
}),
},
execute: async ({ event, options }) => {
await event.reply(`Hello, ${options.name}`);
},
});
Find your Command Instantly
Tired of finding your command all the place? All commands are file-system based!
Search file by name, you are able to find your command instantly
For slash command: test hello
commands/test/_meta.ts
import { group } from "discord-fp";
export default group({
description: "Your Command Group description",
});
commands/test/hello.ts
import { slash } from "discord-fp";
export default slash({
});
Powerful & Beautiful
Not just slash commands, you are able to create context menu commands with few lines of code
commands/Delete Message.ts
import { message } from "discord-fp";
export default message({
async execute({ event }) {
await event.reply("I don't wanna delete message!");
},
});
Middleware
Wanted to run something before executing a command?
With middleware, you can control how an event handler being fired, or pass context to the handler
commands/_meta.ts
import { initBuilder } from "discord-fp";
export const base = initBuilder();
export const safe = base.middleware(({ event, next }) => {
return next({
ctx: {
message: "hello world",
},
event,
});
});
commands/your-command.ts
export default safe.slash({ ... })
Everything is Type-safe + Null-safe
From config, middleware context, to options values, It's all type-safe!
export default slash({
description: "Say Hello to you",
options: {
enabled: options.boolean({
description: "Enabled",
required: false,
}),
number: options.number({
description: "Example number",
required: true,
}),
},
});
Take a look at options
:
(parameter) options: {
enabled: boolean | null;
number: number;
}
Getting Started
Try our template which includes everything you need
Start Discord-FP after the bot is ready
import { start } from "discord-fp";
import { join } from "path";
client.on("ready", () => {
start(client, {
load: ["./commands"],
});
});
Create Slash command
Create a file inside the folder
Since it's file-system based, command name is same as its file name
commands/hello.ts
import { slash } from "discord-fp";
export default slash({
description: "Say Hello World",
execute: async ({ event, options }) => {
await event.reply(`Hello World`);
},
});
Run your bot
Start your bot, and run the slash command in Discord
hello
Then you should see the bot replied "Hello World"!
Command Group & Sub commands
You may use command group & sub command for grouping tons of commands
-
Create a folder
-
Create a _meta.ts
/ meta.js
file
-
Define information for the command group in the _meta
file
import { group } from "discord-fp";
export default group({
description: "My Command group",
});
-
Create commands inside the folder
Inside the folder, Only slash commands are supported
import { options, slash } from "discord-fp";
export default slash({
description: "Say Hello World",
execute: async ({ event, options }) => {
await event.reply(`Hello World`);
},
});
What is _meta.ts & _meta.js ?
You may create a _meta
file for controling how the folder being loaded
For example, Command group is just a type of loader
import { group } from "discord-fp";
export default group({
description: "My Command group",
});
Middleware
Discord-fp provides type-safe middlewares & context with high code quality
In default, we use static builders from discord-fp
import { slash } from "discord-fp";
export default slash({ ... });
To enable middleware, you need to use initBuilder
instead
commands/_meta.ts
import { initBuilder } from "discord-fp";
export const base = initBuilder();
To add a middleware:
export const safe = base.middleware(({ event, next }) => {
return next({
ctx: {
message: "context here",
},
event,
});
});
Now create a slash command with the middleware enabled:
export default safe.slash({ ... })
Reject events
You can prevent calling the event handler by returning nothing
export const safe = base.middleware(({ event, next }) => {
if (isInvalid(event)) return;
return next({
ctx: {
message: "context here",
},
event,
});
});
Command Options
We provides type-safe options out-of-the-box
import { options } from "discord-fp";
options.string({
description: "Your name",
required: false,
});
Auto-complete
Enable auto-complete easily
options.string({
description: "Your name",
required: false,
autoComplete(e) {
const items = ["hello", "world"];
const v = e.options.getFocused();
e.respond(result);
},
});
Transform
Make your code even better with transform
options.string({
description: "Your name",
require: true,
}).transform((v) => {
return `Mr.${v}`;
}),
ESM Usage
ESM has been supported since v0.2.1
Note
If you have any problems with relative path, you may pass an absolute path instead
Common js
const { start } = require("discord-fp");
start(client, {
load: ["./commands"],
});
ESM
import { start } from "discord-fp";
start(client, {
load: ["./commands"],
});
Any issues?
Feel free to open an issue!
Give this repo a star if you loved this library