Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

commandkit

Package Overview
Dependencies
Maintainers
1
Versions
106
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

commandkit - npm Package Compare versions

Comparing version 0.0.8 to 0.0.9

.github/workflows/publish.yaml

21

CHANGELOG.md

@@ -7,2 +7,13 @@ # Change Log

## [0.0.9] - 2023-08-09
### Added
- Support for developer role IDs
- Ability to skip built-in validations by setting `skipBuiltInValidations` to true inside the `CommandKit` constructor
### Changed
- Change validations to run custom user validations first, then CommandKit's built-in validations.
## [0.0.8] - 2023-07-03

@@ -12,3 +23,3 @@

- Support for nested files inside of each event folder.
- Support for nested files inside of each event folder.

@@ -19,3 +30,3 @@ ## [0.0.7] - 2023-07-02

- Give validation functions access to the full command object (commandObj) excluding the run function (as that is handled by the command handler), as opposed to just the `data` and `options` properties.
- Give validation functions access to the full command object (commandObj) excluding the run function (as that is handled by the command handler), as opposed to just the `data` and `options` properties.

@@ -26,3 +37,3 @@ ## [0.0.6] - 2023-07-02

- Fixed a bug where wrong event names were being registered on Windows.
- Fixed a bug where wrong event names were being registered on Windows.

@@ -33,3 +44,3 @@ ## [0.0.5] - 2023-07-02

- Ability to automatically update application commands (guilds and global) when there's changes to the description or number of options (slash commands only).
- Ability to automatically update application commands (guilds and global) when there's changes to the description or number of options (slash commands only).

@@ -40,3 +51,3 @@ ## [0.0.4] - 2023-07-01

- Update package.json with new URLs, scripts, and version
- Update package.json with new URLs, scripts, and version

@@ -43,0 +54,0 @@ ## [0.0.3] - 2023-07-01

@@ -34,3 +34,3 @@ "use strict";

});
validationFunctions = validationHandler.getValidations();
validationHandler.getValidations().forEach((v) => validationFunctions.push(v));
}

@@ -44,3 +44,5 @@ // Command handler

devUserIds: this._data.devUserIds || [],
validations: validationFunctions,
devRoleIds: this._data.devRoleIds || [],
customValidations: validationFunctions,
skipBuiltInValidations: this._data.skipBuiltInValidations || false,
});

@@ -47,0 +49,0 @@ this._data.commands = commandHandler.getCommands();

@@ -8,6 +8,6 @@ import { CommandHandlerData, CommandHandlerOptions } from './typings';

_buildCommands(): void;
_buildValidations(): void;
_registerCommands(): void;
_handleCommands(): void;
_areSlashCommandsDifferent(appCommand: any, localCommand: any): true | undefined;
getCommands(): (SlashCommandObject | ContextCommandObject)[];
}
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommandHandler = void 0;
const get_paths_1 = require("../../utils/get-paths");
const registerCommands_1 = __importDefault(require("./functions/registerCommands"));
const handleCommands_1 = __importDefault(require("./functions/handleCommands"));
const path_1 = __importDefault(require("path"));
class CommandHandler {

@@ -10,2 +16,3 @@ _data;

...options,
builtInValidations: [],
commands: [],

@@ -17,2 +24,3 @@ };

this._buildCommands();
this._buildValidations();
this._registerCommands();

@@ -36,222 +44,18 @@ this._handleCommands();

}
_registerCommands() {
const client = this._data.client;
const commands = this._data.commands;
client.once('ready', async () => {
const devGuilds = [];
for (const devGuildId of this._data.devGuildIds) {
const guild = client.guilds.cache.get(devGuildId);
if (!guild) {
console.log(`⏩ Ignoring: Guild ${devGuildId} does not exist or client isn't in this guild.`);
continue;
}
devGuilds.push(guild);
_buildValidations() {
const validationFilePaths = (0, get_paths_1.getFilePaths)(path_1.default.join(__dirname, 'validations'), true).filter((path) => path.endsWith('.js'));
for (const validationFilePath of validationFilePaths) {
const validationFunction = require(validationFilePath);
if (typeof validationFunction !== 'function') {
continue;
}
const appCommands = client.application?.commands;
await appCommands?.fetch();
const devGuildCommands = [];
for (const guild of devGuilds) {
const guildCommands = guild.commands;
await guildCommands?.fetch();
devGuildCommands.push(guildCommands);
}
for (const command of commands) {
// <!-- Delete command if options.deleted -->
if (command.options?.deleted) {
const targetCommand = appCommands?.cache.find((cmd) => cmd.name === command.data.name);
if (!targetCommand) {
console.log(`⏩ Ignoring: Command "${command.data.name}" is globally marked as deleted.`);
}
else {
targetCommand.delete().then(() => {
console.log(`🚮 Deleted command "${command.data.name}" globally.`);
});
}
for (const guildCommands of devGuildCommands) {
const targetCommand = guildCommands.cache.find((cmd) => cmd.name === command.data.name);
if (!targetCommand) {
console.log(`⏩ Ignoring: Command "${command.data.name}" is marked as deleted for ${guildCommands.guild.name}.`);
}
else {
targetCommand.delete().then(() => {
console.log(`🚮 Deleted command "${command.data.name}" in ${guildCommands.guild.name}.`);
});
}
}
continue;
}
// <!-- Edit command if there's any changes -->
let commandData = command.data;
let editedCommand = false;
(() => {
// global
const appGlobalCommand = appCommands?.cache.find((cmd) => cmd.name === command.data.name);
if (appGlobalCommand) {
const commandsAreDifferent = this._areSlashCommandsDifferent(appGlobalCommand, commandData);
if (commandsAreDifferent) {
appGlobalCommand
.edit(commandData)
.then(() => {
console.log(`✅ Edited command "${commandData.name}" globally.`);
})
.catch((error) => {
console.log(`❌ Failed to edit command "${commandData.name}" globally.`);
console.error(error);
});
editedCommand = true;
}
}
// guilds
for (const guildCommands of devGuildCommands) {
const appGuildCommand = guildCommands.cache.find((cmd) => cmd.name === commandData.name);
if (appGuildCommand) {
const commandsAreDifferent = this._areSlashCommandsDifferent(appGuildCommand, commandData);
if (commandsAreDifferent) {
appGuildCommand
.edit(commandData)
.then(() => {
console.log(`✅ Edited command "${commandData.name}" in ${guildCommands.guild.name}.`);
})
.catch((error) => {
console.log(`❌ Failed to edit command "${commandData.name}" in ${guildCommands.guild.name}.`);
console.error(error);
});
editedCommand = true;
}
}
}
})();
if (editedCommand)
continue;
// <!-- Registration -->
// guild-based command registration
if (command.options?.devOnly) {
if (!devGuilds.length) {
console.log(`⏩ Ignoring: Cannot register command "${command.data.name}" as no valid "devGuildIds" were provided.`);
continue;
}
for (const guild of devGuilds) {
const cmdExists = guild.commands.cache.some((cmd) => cmd.name === command.data.name);
if (cmdExists)
continue;
guild?.commands
.create(command.data)
.then(() => {
console.log(`✅ Registered command "${command.data.name}" in ${guild.name}.`);
})
.catch((error) => {
console.log(`❌ Failed to register command "${command.data.name}" in ${guild.name}.`);
console.error(error);
});
}
}
// global command registration
else {
const cmdExists = appCommands?.cache.some((cmd) => cmd.name === command.data.name);
if (cmdExists)
continue;
appCommands
?.create(command.data)
.then(() => {
console.log(`✅ Registered command "${command.data.name}" globally.`);
})
.catch((error) => {
console.log(`❌ Failed to register command "${command.data.name}" globally.`);
console.error(error);
});
}
}
});
this._data.builtInValidations.push(validationFunction);
}
}
_registerCommands() {
(0, registerCommands_1.default)(this);
}
_handleCommands() {
const client = this._data.client;
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand() && !interaction.isContextMenuCommand())
return;
const targetCommand = this._data.commands.find((cmd) => cmd.data.name === interaction.commandName);
if (!targetCommand)
return;
// Options validation
// options.guildOnly
if (targetCommand.options?.guildOnly && !interaction.inGuild()) {
interaction.reply({
content: '❌ This command can only be used inside a server.',
ephemeral: true,
});
return;
}
// options.devOnly
if (targetCommand.options?.devOnly) {
const isDevUser = this._data.devUserIds.includes(interaction.user.id);
if (!isDevUser) {
interaction.reply({
content: '❌ This command can only be used by developers.',
ephemeral: true,
});
return;
}
}
// options.userPermissions
const memberPermissions = interaction.memberPermissions;
if (targetCommand.options?.userPermissions && memberPermissions) {
for (const permission of targetCommand.options.userPermissions) {
const hasPermission = memberPermissions.has(permission);
if (!hasPermission) {
interaction.reply({
content: `❌ You do not have enough permission to run this command. Required permission: \`${permission}\``,
ephemeral: true,
});
return;
}
}
}
// options.botPermissions
const botMember = interaction.guild?.members.me;
if (targetCommand.options?.botPermissions && botMember) {
for (const permission of targetCommand.options.botPermissions) {
const hasPermission = botMember.permissions.has(permission);
if (!hasPermission) {
interaction.reply({
content: `❌ I do not have enough permission to execute this command. Required permission: \`${permission}\``,
ephemeral: true,
});
return;
}
}
}
// Run user validation functions
const validationFunctions = this._data.validations;
const { data, options, run, ...rest } = targetCommand;
const commandObj = {
data: targetCommand.data,
options: targetCommand.options,
...rest,
};
let canRun = true;
for (const validationFunction of validationFunctions) {
const stopValidationLoop = await validationFunction({ interaction, client, commandObj });
if (stopValidationLoop) {
canRun = false;
break;
}
}
if (canRun) {
targetCommand.run({ interaction, client });
}
});
(0, handleCommands_1.default)(this);
}
_areSlashCommandsDifferent(appCommand, localCommand) {
if (!appCommand.options)
appCommand.options = [];
if (!localCommand.options)
localCommand.options = [];
if (!appCommand.description)
appCommand.description = '';
if (!localCommand.description)
localCommand.description = '';
if (localCommand.description !== appCommand.description ||
localCommand.options.length !== appCommand.options.length) {
return true;
}
}
getCommands() {

@@ -258,0 +62,0 @@ return this._data.commands;

{
"name": "commandkit",
"version": "0.0.8",
"main": "dist/index.js",
"license": "MIT",
"scripts": {
"build": "tsc"
},
"repository": {
"type": "git",
"url": "https://github.com/notunderctrl/commandkit"
},
"homepage": "https://commandkit.underctrl.io",
"keywords": [
"discord.js",
"command handler",
"event handler",
"command validations"
],
"dependencies": {},
"devDependencies": {
"discord.js": "^14.11.0",
"tsc": "^2.0.4"
}
"name": "commandkit",
"version": "0.0.9",
"main": "dist/index.js",
"license": "MIT",
"scripts": {
"build": "tsc"
},
"repository": {
"type": "git",
"url": "https://github.com/notunderctrl/commandkit"
},
"homepage": "https://commandkit.underctrl.io",
"keywords": [
"discord.js",
"command handler",
"event handler",
"command validations"
],
"devDependencies": {
"discord.js": "^14.12.1",
"typescript": "^5.1.6"
}
}
# CommandKit
CommandKit is a library that makes it easy to handle commands (+validations), and events in your Discord.js projects.
CommandKit is a library that makes it easy to handle commands (+ validations), and events in your Discord.js projects.
_Tested with Discord.js version `v14.11.0`_
**Supports Discord.js version 14**
# Features
- Very beginner friendly 🚀
- Support for slash and context menu commands ✅
- Automatic command registration, edits, and deletion 🤖
- Supports multiple development servers 🤝
- Supports multiple users as bot developers 👥
- Object oriented 💻
- Very beginner friendly 🚀
- Support for slash and context menu commands ✅
- Automatic command registration, edits, and deletion 🤖
- Supports multiple development servers 🤝
- Supports multiple users as bot developers 👥
- Object oriented 💻

@@ -40,9 +40,7 @@ # Documentation

This is a simple overview of how to set up this library with all the options.
This is a simple overview of how to set up this library with all the options. You can read more in the [full documentation](https://commandkit.underctrl.io)
**It's highly recommended you check out the [documentation](https://commandkit.underctrl.io) to fully understand how to work with this library.**
```js
// index.js
const { Client, IntentsBitField } = require('discord.js');
const { Client, GatewayIntentBits } = require('discord.js');
const { CommandKit } = require('commandkit');

@@ -52,23 +50,33 @@ const path = require('path');

const client = new Client({
intents: [IntentsBitField.Flags.Guilds],
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
new CommandKit({
// Your discord.js client object
client,
// Your discord.js client object
client,
// Path to the commands folder
commandsPath: path.join(__dirname, 'commands'),
// Path to the commands folder
commandsPath: path.join(__dirname, 'commands'),
// Path to the events folder
eventsPath: path.join(__dirname, 'events'),
// Path to the events folder
eventsPath: path.join(__dirname, 'events'),
// Path to the validations folder (only valid if "commandsPath" was provided)
validationsPath: path.join(__dirname, 'validations'),
// Path to the validations folder (only valid if "commandsPath" was provided)
validationsPath: path.join(__dirname, 'validations'),
// Array of development server IDs (used to register and run devOnly commands)
devGuildIds: ['DEV_SERVER_ID_1', 'DEV_SERVER_ID_2'],
// Array of development server IDs (used to register and run devOnly commands)
devGuildIds: ['DEV_SERVER_ID_1', 'DEV_SERVER_ID_2'],
// Array of developer user IDs (used for devOnly commands)
devUserIds: ['DEV_USER_ID_1', 'DEV_USER_ID_2'],
// Array of developer user IDs (used for devOnly commands)
devUserIds: ['DEV_USER_ID_1', 'DEV_USER_ID_2'],
// Array of developer role IDs (used for devOnly commands)
devRoleIds: ['DEV_ROLE_ID_1', 'DEV_ROLE_ID_2'],
// A property that disables CommandKit's built-in validations
skipBuiltInValidations: true,
});

@@ -75,0 +83,0 @@

{
"compilerOptions": {
"outDir": "dist",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
"strictNullChecks": true,
"target": "ES2022",
"moduleResolution": "Node",
"module": "CommonJS",
"declaration": true
},
"include": ["src/**/*"]
"compilerOptions": {
"outDir": "dist",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
"strictNullChecks": true,
"target": "ES2022",
"moduleResolution": "Node",
"module": "CommonJS",
"declaration": true
},
"include": ["src/**/*"]
}
import {
Client,
APIApplicationCommandOption,
ContextMenuCommandType,
Interaction,
PermissionResolvable,
SlashCommandBuilder,
ContextMenuCommandBuilder,
Client,
APIApplicationCommandOption,
ContextMenuCommandType,
Interaction,
PermissionResolvable,
SlashCommandBuilder,
ContextMenuCommandBuilder,
} from 'discord.js';
export interface CommandKitOptions {
client: Client;
commandsPath?: string;
eventsPath?: string;
validationsPath?: string;
devGuildIds?: string[];
devUserIds?: string[];
client: Client;
commandsPath?: string;
eventsPath?: string;
validationsPath?: string;
devGuildIds?: string[];
devUserIds?: string[];
devRoleIds?: string[];
skipBuiltInValidations?: boolean;
}
export interface CommandKitData extends CommandKitOptions {
commands: Array<SlashCommandObject | ContextCommandObject>;
commands: Array<SlashCommandObject | ContextCommandObject>;
}
export interface SlashCommandObject {
data:
| SlashCommandBuilder
| {
name: string;
name_localizations?: any;
description: string;
dm_permission?: boolean;
options?: APIApplicationCommandOption[];
};
options?: {
guildOnly?: boolean;
devOnly?: boolean;
deleted?: boolean;
userPermissions?: PermissionResolvable[];
botPermissions?: PermissionResolvable[];
};
run: ({}: { interaction: Interaction; client: Client }) => void;
data:
| SlashCommandBuilder
| {
name: string;
name_localizations?: any;
description: string;
dm_permission?: boolean;
options?: APIApplicationCommandOption[];
};
options?: {
guildOnly?: boolean;
devOnly?: boolean;
deleted?: boolean;
userPermissions?: PermissionResolvable[];
botPermissions?: PermissionResolvable[];
};
run: ({}: { interaction: Interaction; client: Client }) => void;
}
export interface ContextCommandObject {
data:
| ContextMenuCommandBuilder
| {
name: string;
name_localizations?: any;
type: ContextMenuCommandType;
dm_permission?: boolean;
};
options?: {
guildOnly?: boolean;
devOnly?: boolean;
deleted?: boolean;
userPermissions?: PermissionResolvable[];
botPermissions?: PermissionResolvable[];
};
run: ({}: { interaction: Interaction; client: Client }) => void;
data:
| ContextMenuCommandBuilder
| {
name: string;
name_localizations?: any;
type: ContextMenuCommandType;
dm_permission?: boolean;
};
options?: {
guildOnly?: boolean;
devOnly?: boolean;
deleted?: boolean;
userPermissions?: PermissionResolvable[];
botPermissions?: PermissionResolvable[];
};
run: ({}: { interaction: Interaction; client: Client }) => void;
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc