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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@somehiddenkey/discord-command-utils

v2.7.1

Published

A utility library for building Discord bot commands using discord.js

Readme

DiscordUtilsLibrary

The purpose of this Library is to hide and abstract many of the common aspects that comes with coding discord bots in javascript. The main focus is configurations as well as registering all types of commands and interactions between different guilds.

Setup

  1. Installation
npm install @somehiddenkey/discord-command-utils --registry=https://registry.npmjs.org/
  1. Libary Import
import { Something } from "DiscordUtilsLibrary";
// or
const { Something } = require("DiscordUtilsLibrary");

Configurations

We will use 3 different kinds of configurations:

  • local : settings specific to this specific bot like it's prefix etc
  • global : information used by all bot instances
  • secret : environment variables that contain all the secrets of your bot instance

Local configuration

Loads the local configuration of that specific bot. It only contains public configs, no secrets, and may thus be included in the git tracing. Load a new instance of your local config through the following code:

export const localConfig = LocalConfig.load("./config/local_config.json");

Your local configuration JSON file should look like this:

{
	"prefix": "!",
	"client_id": "123456789123456789",
	"local": {
		"any_local_configuration": "any values"
	},
	"rest_options" : {
		"version": "10",
		"rejectOnRateLimit": ["/channels"]
	},
	"activity": {
		"name": "the communities",
		"type": 0
	}
}

Global configuration

Loads the global configuration that contains information related to all bot instances, like snowflake IDs of channels, categories, guild, etc. Load a new instance of your global config through the following code:

export const globalConfig = GlobalConfig.load("../global_config.json", bot);

It contains the IDs of the following sections: guilds, categories, channels, log channels and roles. These can be used as constant values throughout your code, making sure that if an ID ever changes, that all bot instances would take the new updated value by simply updating the json once.

Properties

The properties of the different guilds can read per scope/guild. We differentiate the main, tutor, staff and community server:

  • Get the ID of the main server : globalConfig.main.guild.id
  • Get the ID of the general chat in the main server: globalConfig.main.channels.international.id

Caching

You can fetch and cache the value of a guild, channel or role from discordjs, as to access it immidiately afterwards. However, at all times, the id is available even without fetching

console.write(globalConfig.main.guild.name); //error: not fetched yet
console.write(globalConfig.main.guild.id); 	//still fine, ID always accessible

await globalConfig.main.guild.fetchFromBot();
await globalConfig.main.channels.international.fetchFromBot();
console.write(globalConfig.main.guild.name); //uses the cached value

Please keep in mind that cached value may contain outdated data! If you call fetchFromBot() it will either return the cached value or fetch the value once. If you want to reload the value e.g. to read the updated members that are in a specific voicechannel, you must call refreshFromBot()

console.write(globalConfig.main.channels.break_afk.members.length); 
//shows the member count at the time of the fetchFromBot()

await globalConfig.main.channels.break_afk.refreshFromBot();
//fetches the value again, and caches it again

console.write(globalConfig.main.channels.break_afk.members.length); 
//shows the now updated member count

You can fetch and refreshFromBot entire groups or guilds. Please keep in mind that, if you fetch the values of a specific guild, the bot has to actually be part of that server. A value that cannot be fetched will result in an error.

await globalConfig.community.fetchFromBot();
await globalConfig.main.channels.fetchFromBot();

console.write(globalConfig.main.channel.international.name); //uses the cached value

Secrets configuration

Loads the environment variables that contain all secrets for that bot, like your bot token and database credentials. It goes without saying that these actual values may never be git traced. Load new instance of your secret config through the following code:

import { config } from 'dotenv';

config();
export const secretConfig = new SecretConfig(process.env);

Your .env file should look like this:

NODE_ENV="production"

TOKEN="someDiscordBotToken"

DATABASE__0__HOST="localhost"
DATABASE__0__USER="userName"
DATABASE__0__NAME="databaseName"
DATABASE__0__PASSWORD="passwordValue"

Please take the following into account:

  • NODE_ENV must be of one of the following values:
    • "development" : Uses your development configurations for local testing
    • "production" : Uses your production configurations for PRD env. Do not use for local tests, it won't work
  • If you use multiple databases, prefix each one with another index, starting at 0

You can retrieve the various database configurations with the following code:

export const db_connection_0 = knex(secretConfig.DatabaseConfig[0]);

You can initiate the bot with the following code:

bot.login(secretConfig.token);

Interactions

Register Interaction

You can register new interaction callbacks based on a set of factors:

  • the scope : type InteractionScope -- in which server is this interaction called (main, tutor, communities, dm, etc)
  • the type : type InteractionType -- is it a button, a modal, a slash command, a message, etc
  • the unique id: custom unique ID per interaction of this type

An example for a slash command called in the main server:

Interaction.OnSlashCommand(
    "ping", 
    InteractionScope.Main, 
    async (interaction) => await interaction.reply("pong")
);

The same exists for:

  • Button : OnButton
  • Selection menu : OnSelectMenu
  • Message : OnMessageCommand
  • Modal submission : OnModal

A slash command with a specific subcommand can be defined as follows:

Interaction.OnSlashCommand(
    {name: "ping", subcommand: "webping"}, 
    InteractionScope.Main, 
    async (interaction) => await interaction.reply("pong")
);

Callback arguments

Message arguments

Message commands start with a prefix, after which the proceeding arguments are the arguments. E.g. the message !ping "google.com" would trigger async (interaction, website) => //...

Interaction IDs

You can burry hidden information in the custom ID of a selection menu, button and modal submission by concatting them to them to the custom ID. The helper function Interaction.makeCustomId() exists for this. This is handy to e.g. hide session IDs as not to have to recompute them. Example:

new ButtonBuilder().setCustomId(Interaction.makeCustomId("ping", session_id))

Interaction.OnButton(
    "ping", InteractionScope.Main, 
    async (interaction, session_id) => await interaction.reply(`pong from ${session_id}`)
);

Call Interaction

All interactions get stored in a so-called InteractionContainer that still needs to be called. If someone goes wrong in an unexpected way, the interaction will be replied to with "something went wrong" and a consola error will be displayed. Optionally, you can provide an extra error handler as second argument to the interaction caller.

const interactionContainer = new InteractionContainer(localConfig, globalConfig);

bot.on(Events.MessageCreate, async (message) => {
  await interactionContainer.call_message_interaction(message, e => consola.error(e))
});

bot.on(Events.InteractionCreate, async (interaction) => 
  await interactionContainer.call_interaction(interaction, e => consola.error(e))
);

Register slash commands to REST

For slash commands to work, you need to register them to a bot. There are two kinds:

  • Guild commands : a slash command that will only be registered in one specific guild
  • Public commands : a slash command available in all guilds that have this bot

You can add a set of slash commands through the following abstraction:

const rest = await interactionContainer.Rest
	.add([firstSlashCommand, secondSlashCommand], localConfig.guilds.tutor)
	.add([firstSlashCommand, secondSlashCommand], localConfig.guilds.community)
	.add([somePublicSlashCommand])
	.register(secretConfig.token);

Utils

Contains various check functions to verify the access level of a user as well as useful enums for scoping, community modlevels, etc