npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

simple-discordjs

v2.0.0

Published

A command framework for Discord.JS, featuring pattern matching, middlewares and autogenerated help.

Downloads

74

Readme

Simple DiscordJS

TypeScript David npm

The commander class was originally designed to assist a programmer with the tedious task of setting up commands for Discord.js.

The syntax for the bot is as follows:

import Commands, { RateLimiter, RoleTypes, Auth } from 'simple-discordjs';

new Commands(configJson.prefix, client, options)
    .use(rateLimit.protect)
    .use(auth.authenticate)
    .defineCommand({
        command: {
            names: ['p', 'ping'],
            action: ping,
        },
        description: {
            message: 'Replies with pong.',
            example: '{{prefix}}ping',
        }
    })
    .defineCommand({
        command: {
            names: ['pang', 'pong'],
            action: pinger,
            pattern: /p[oa]ng/,
        },
        authentication: RoleTypes.ADMIN,
        description: {
            message: 'A joke reply to pong',
            example: 'pang'
        }
    })
    .generateHelp()
    .listen();

Bot Config

The bot settings is a simple object that accepts this interface:


export type botTypes = 'normal' | 'self' | 'guildonly';

export interface CommandsOptions {
    /**
     * Valid bot types
     * Normal replies to all text channels, including guildonly
     * Self bot, only replies to you and only you.
     * Guildonly will only work in discord guild channels
     *
     * @type {botTypes}
     * @memberof CommandsOptions
     */
    botType: botTypes;
    /**
     * If someone types a prefixed command like !action,
     * delete the message on successful reply
     *
     * @type {boolean}
     * @memberof CommandsOptions
     */
    deleteCommandMessage?: boolean;
    /**
     * Defines the amount of time the !action command will
     * stay in the channel until it is deleted.
     *
     * @type {number}
     * @memberof CommandsOptions
     */
    deleteMessageDelay?: number;
}

Bot Types

Bots can have multiple different types, including a self type for selfbots.

Type | Description --------------|------------ 'normal' | Standard default bot type, replies to all messages in all channels. 'self' | Selfbot, limited to only repling to its own client.id messages. 'guildonly' | Limits the bot to only reply messages sent in a guild channel. Users will not be able to interact with the bot in DMs.

Auto Message Deletion

Setting deleteCommandMessage allows for !action messages to be automatically deleted when they trigger a bot commnand. This helps remove some of the spam of !action commands, but only works when the bot is triggered explicitly. Pattern commands will not be deleted.

Commands Middlware Support

The .use syntax on the class is a form of middleware, accepting a promise that returns a boolean condition. The message chain will fail, and not send if the condition returns false.

new Commands(configJson.prefix, client)
    .use(async (message, options, parameters, client) => {
        // do stuff to check the message.
        return true;
    });

The middleware demonstrated above is a spam limiter, checking an auto-clearing object and rejecting a message middleware if they are above the spam limit.

Middlewares included

Rate Limiter

A simple rate limiter that prevents users from flooding a bot with commands.

Syntax is as follows

const limiter = new RateLimiter(['messages allowed per window'],
                                ['window length in seconds'])

                new RateLimiter(10, 5) // 10 messages every 5 seconds

A window is the period of time the user will be allowed to send message, within the limit. After the limit is reached, the bot will not respond to any messages from the user until the window is reset. Pass to the middleware acceptor with,

new Commands(prefix, client)
    .use(limiter.protect)

Authentication Module

The auth module exposes a middleware function and a command object for the user. It uses a SQLite database to keep track of what roles have what permissions on a server. All the roles are set up in a enumerable with 5 properties.

enum RoleTypes {
    ALL = 0,
    MOD,
    ADMIN,
    OWNER,
    SUPERUSER,
};

Due to properties being simple numbers, roles have hierarchy. A superuser will have access to all commands as it is the highest number. Admins will be able to use all mod and admin commands, and owners will be able to use all mod, admin and owner commands, etc.

Superuser should be your user ID.

Owner is automatically infered from the server owner exposed from discord.

Admin | Mod is set via the !addrole command. Only server owners or the superuser may use addrole.

!addrole mod @roleGroup

Usage is as follows:


const auth = new Auth(superuserToken);
// superuser token should be your discord user ID,
// you will have access to all commands.

new Commands(prefix, client)
    .use(auth.authenticate)
    .defineCommand(auth.getCommand())

Command Helper

Simple Command

The .defineCommand function defines a chat command that takes an action, a function that will be called once the command is verified and registered. An optional description is passed to generate a help command with the .generateHelp command.

    .defineCommand({
        command: {
            name: ['action', 'a', 'actionname']
            action:
               (message: Discord.Message,
                options: CommandOptions,
                parameters: ParameterOptions,
                client: Discord.Client) => Promise<boolean>,
            parameters: '{{param1}} {{param2}}',
            noPrefix: false,
            // a boolean that represents if the function
            // requres an explicit call, like .action or !action
        },
        description:  {
            message: 'A description of the function, for the generator',
            example: '{{prefix}}action',
        },
    });

For regex matching, pass a pattern: RegExp in the command object.

Parameter matching

Reverse string templating is supported with the parameter option in the function description. Parameters are defined with {{parameter}}, and are passed as an object to the action. Strings must match to register, you cannot ignore parts of message, e.g. 'action verb noun' !== '{{action}} ignore {{noun}}'. Instead, match it and add a junk name to it, e.g. 'action verb noun' === '{{action}} {{ignored}} {{noun}}'.

    export interface ParameterDefinition {
        array: string[];
        named?: {
            [key: string]: string;
        };
    }

    // called with .param ADD 1 2.
    .defineCommand(['param'], {
        command: {
            action: (message, options, params: ParameterDefintion) => {
                console.log(params)
                // {
                //     array: ['add', '1', '2'],
                //     named: {
                //        directive: 'ADD',
                //        num1: '1',
                //        num2: '2'
                //     }
                // }
            },
            parameters: '{{directive}} {{num1}} {{num2}}',
        }
    })

Help Generator

The command .generateHelp(descriptor?) will automatically take the current command list and generate a series of RichEmbed objects that will be DM'd to the user who calls either h or help with the assigned prefix. The function also accepts an optional RichEmbed element for a custom message to be sent after the commands.

In the example parameter in the description object, {{prefix}} is templated to return the default prefix of the command class.

{
    ...options
    description: {
        message: 'The description of the chat command',
        example: 'The chat command, e.g. {{prefix}}command',
    }
}

The returned help function looks as follows:

helper

Please do not remove the signature from the source code, it would be appreciated if you left that in for developers looking to use this library.