Commands with the Plumbing Done

The router converts arguments, runs guards and cooldowns and builds the help from your definitions

A keycap with a slash cut into it

Each Key Is a Command

A prefix command is a message that starts with a prefix, such as !ping. Pass your commands to runBot, and its command router reads the name after the prefix and runs the matching execute

If a reply fails, the router reports it with the command's name, and every other command keeps working

A Small Bot with Commands
bot.ts
import { runBot } from "@neontechspace/fluxerly"await runBot({    token: process.env.FLUXER_BOT_TOKEN,    commands: {        prefix: "!",        commands: {            ping: {                description: "Check that the bot can reply",                execute: ({ reply }) => reply("Pong!"),            },            about: {                description: "Describe this bot",                execute: ({ reply }) => reply("Built with Fluxerly"),            },        },    },})

Arguments Arrive Typed

Describe each argument once, and the router converts the words after the name before execute runs. With parseQuoted a quoted name counts as one argument, and a duration such as 10m arrives as milliseconds

A missing or invalid argument never reaches your code. The bot answers with the reason and the command's usage instead

Convert Arguments in the Docs
bot.ts
import { commands, runBot } from "@neontechspace/fluxerly"await runBot({    token: process.env.FLUXER_BOT_TOKEN,    commands: {        prefix: "!",        parse: commands.parseQuoted,        commands: {            greet: {                description: "Greet a name",                arguments: { name: { type: "text" } },                execute: ({ values, reply }) => reply(`Hello, ${values.name}!`),            },            remind: {                description: "Repeat a note after a delay",                arguments: {                    delay: { type: "duration", min: 1_000, max: 3_600_000 },                    note: { type: "text", rest: true },                },                execute: ({ client, message, values, reply }) => {                    client.schedule((signal) => client.messages.reply(message, values.note, { signal }), {                        delayMs: values.delay,                    })                    return reply("Reminder set")                },            },        },    },})

Guards and Cooldowns

A guard decides whether a matched command may run, and a cooldown limits how often it can. Here !purge runs only in a community, only for members with Manage messages, and at most once every 30 seconds in each channel

Middleware wraps every command, here to time it. A guard's answer does not replace Fluxer's own check of each request the command makes

Guard and Limit Commands in the Commands Guide
An hourglass, for a command's cooldown
bot.ts
import { guards, runBot } from "@neontechspace/fluxerly"await runBot({    token: process.env.FLUXER_BOT_TOKEN,    commands: {        prefix: "!",        mentionPrefix: true,        use: [            async (context, next) => {                const started = Date.now()                await next()                console.info(`${context.name} took ${Date.now() - started} ms`)            },        ],        commands: {            purge: {                description: "Delete recent messages",                guard: [guards.guildOnly(), guards.requirePermissions(["ManageMessages"])],                cooldown: { durationMs: 30_000, per: "channel" },                arguments: { count: { type: "integer", min: 1, max: 100, default: 10 } },                execute: ({ values, reply }) => reply(`Would delete ${values.count} messages`),            },        },    },})

Groups for a Larger Bot

A group gives related commands a shared first word, such as tools in !tools ping, and can have a short alias like !t ping

Groups organize names and help only. A command that needs protection still carries its own guard

Help and Groups in the Docs
TypeScript
import { commands, type Client } from "@neontechspace/fluxerly"export function commandGroupExample(client: Client) {    return commands        .create({ prefix: "!" })        .registerGroup({ name: "tools", aliases: ["t"] })        .register({ name: "ping", execute: ({ reply }) => reply("Pong") }, { group: ["tools"] })        .attach(client)}

Help and Pages from the Same Definitions

Every command receives sendHelp, which lists the commands with their descriptions, and paginate, which shows any list as pages that the command's author flips with ◀ and ▶ reactions

Help is built from the definitions the router already has, so it matches the commands

Generated Help in the Docs
bot.ts
import { runBot } from "@neontechspace/fluxerly"await runBot({    token: process.env.FLUXER_BOT_TOKEN,    commands: {        prefix: "!",        commands: {            help: {                description: "List the commands",                execute: ({ sendHelp }) => sendHelp(),            },            rules: {                description: "Show the rules, five at a time",                execute: ({ paginate }) => paginate(["Rules 1 to 5", "Rules 6 to 10"]),            },        },    },})