commandkit 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yaml +26 -0
- package/CHANGELOG.md +16 -5
- package/README.md +33 -25
- package/dist/CommandKit.js +4 -2
- package/dist/handlers/command-handler/CommandHandler.d.ts +1 -1
- package/dist/handlers/command-handler/CommandHandler.js +20 -216
- package/dist/handlers/command-handler/functions/handleCommands.d.ts +2 -0
- package/dist/handlers/command-handler/functions/handleCommands.js +50 -0
- package/dist/handlers/command-handler/functions/registerCommands.d.ts +2 -0
- package/dist/handlers/command-handler/functions/registerCommands.js +135 -0
- package/dist/handlers/command-handler/utils/areSlashCommandsDifferent.d.ts +1 -0
- package/dist/handlers/command-handler/utils/areSlashCommandsDifferent.js +17 -0
- package/dist/handlers/command-handler/validations/botPermissions.d.ts +1 -0
- package/dist/handlers/command-handler/validations/botPermissions.js +17 -0
- package/dist/handlers/command-handler/validations/devOnly.d.ts +1 -0
- package/dist/handlers/command-handler/validations/devOnly.js +29 -0
- package/dist/handlers/command-handler/validations/guildOnly.d.ts +1 -0
- package/dist/handlers/command-handler/validations/guildOnly.js +11 -0
- package/dist/handlers/command-handler/validations/userPermissions.d.ts +1 -0
- package/dist/handlers/command-handler/validations/userPermissions.js +17 -0
- package/package.json +22 -23
- package/tsconfig.json +12 -12
- package/typings.d.ts +49 -47
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: 'publish'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
release:
|
|
9
|
+
name: 🚀 publish
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- name: 📚 checkout
|
|
13
|
+
uses: actions/checkout@v3
|
|
14
|
+
- name: 🟢 node
|
|
15
|
+
uses: actions/setup-node@v2
|
|
16
|
+
with:
|
|
17
|
+
node-version: 16
|
|
18
|
+
registry-url: https://registry.npmjs.org
|
|
19
|
+
- name: 🍳 prepare
|
|
20
|
+
run: |
|
|
21
|
+
npm install
|
|
22
|
+
npm run build
|
|
23
|
+
- name: 🚚 publish
|
|
24
|
+
run: npm publish
|
|
25
|
+
env:
|
|
26
|
+
NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}}
|
package/CHANGELOG.md
CHANGED
|
@@ -4,35 +4,46 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|
6
6
|
|
|
7
|
+
## [0.0.9] - 2023-08-09
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Support for developer role IDs
|
|
12
|
+
- Ability to skip built-in validations by setting `skipBuiltInValidations` to true inside the `CommandKit` constructor
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Change validations to run custom user validations first, then CommandKit's built-in validations.
|
|
17
|
+
|
|
7
18
|
## [0.0.8] - 2023-07-03
|
|
8
19
|
|
|
9
20
|
### Added
|
|
10
21
|
|
|
11
|
-
-
|
|
22
|
+
- Support for nested files inside of each event folder.
|
|
12
23
|
|
|
13
24
|
## [0.0.7] - 2023-07-02
|
|
14
25
|
|
|
15
26
|
### Changed
|
|
16
27
|
|
|
17
|
-
-
|
|
28
|
+
- 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.
|
|
18
29
|
|
|
19
30
|
## [0.0.6] - 2023-07-02
|
|
20
31
|
|
|
21
32
|
### Fixed
|
|
22
33
|
|
|
23
|
-
-
|
|
34
|
+
- Fixed a bug where wrong event names were being registered on Windows.
|
|
24
35
|
|
|
25
36
|
## [0.0.5] - 2023-07-02
|
|
26
37
|
|
|
27
38
|
### Added
|
|
28
39
|
|
|
29
|
-
-
|
|
40
|
+
- Ability to automatically update application commands (guilds and global) when there's changes to the description or number of options (slash commands only).
|
|
30
41
|
|
|
31
42
|
## [0.0.4] - 2023-07-01
|
|
32
43
|
|
|
33
44
|
### Updated
|
|
34
45
|
|
|
35
|
-
-
|
|
46
|
+
- Update package.json with new URLs, scripts, and version
|
|
36
47
|
|
|
37
48
|
## [0.0.3] - 2023-07-01
|
|
38
49
|
|
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# CommandKit
|
|
2
2
|
|
|
3
|
-
CommandKit is a library that makes it easy to handle commands (+validations), and events in your Discord.js projects.
|
|
3
|
+
CommandKit is a library that makes it easy to handle commands (+ validations), and events in your Discord.js projects.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Supports Discord.js version 14**
|
|
6
6
|
|
|
7
7
|
# Features
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
9
|
+
- Very beginner friendly 🚀
|
|
10
|
+
- Support for slash and context menu commands ✅
|
|
11
|
+
- Automatic command registration, edits, and deletion 🤖
|
|
12
|
+
- Supports multiple development servers 🤝
|
|
13
|
+
- Supports multiple users as bot developers 👥
|
|
14
|
+
- Object oriented 💻
|
|
15
15
|
|
|
16
16
|
# Documentation
|
|
17
17
|
|
|
@@ -37,38 +37,46 @@ yarn add commandkit
|
|
|
37
37
|
|
|
38
38
|
# Usage
|
|
39
39
|
|
|
40
|
-
This is a simple overview of how to set up this library with all the options.
|
|
41
|
-
|
|
42
|
-
**It's highly recommended you check out the [documentation](https://commandkit.underctrl.io) to fully understand how to work with this library.**
|
|
40
|
+
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)
|
|
43
41
|
|
|
44
42
|
```js
|
|
45
43
|
// index.js
|
|
46
|
-
const { Client,
|
|
44
|
+
const { Client, GatewayIntentBits } = require('discord.js');
|
|
47
45
|
const { CommandKit } = require('commandkit');
|
|
48
46
|
const path = require('path');
|
|
49
47
|
|
|
50
48
|
const client = new Client({
|
|
51
|
-
|
|
49
|
+
intents: [
|
|
50
|
+
GatewayIntentBits.Guilds,
|
|
51
|
+
GatewayIntentBits.GuildMessages,
|
|
52
|
+
GatewayIntentBits.MessageContent,
|
|
53
|
+
],
|
|
52
54
|
});
|
|
53
55
|
|
|
54
56
|
new CommandKit({
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
// Your discord.js client object
|
|
58
|
+
client,
|
|
59
|
+
|
|
60
|
+
// Path to the commands folder
|
|
61
|
+
commandsPath: path.join(__dirname, 'commands'),
|
|
62
|
+
|
|
63
|
+
// Path to the events folder
|
|
64
|
+
eventsPath: path.join(__dirname, 'events'),
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
// Path to the validations folder (only valid if "commandsPath" was provided)
|
|
67
|
+
validationsPath: path.join(__dirname, 'validations'),
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
// Array of development server IDs (used to register and run devOnly commands)
|
|
70
|
+
devGuildIds: ['DEV_SERVER_ID_1', 'DEV_SERVER_ID_2'],
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
// Array of developer user IDs (used for devOnly commands)
|
|
73
|
+
devUserIds: ['DEV_USER_ID_1', 'DEV_USER_ID_2'],
|
|
66
74
|
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
// Array of developer role IDs (used for devOnly commands)
|
|
76
|
+
devRoleIds: ['DEV_ROLE_ID_1', 'DEV_ROLE_ID_2'],
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
// A property that disables CommandKit's built-in validations
|
|
79
|
+
skipBuiltInValidations: true,
|
|
72
80
|
});
|
|
73
81
|
|
|
74
82
|
client.login('YOUR_TOKEN_HERE');
|
package/dist/CommandKit.js
CHANGED
|
@@ -31,7 +31,7 @@ class CommandKit {
|
|
|
31
31
|
const validationHandler = new handlers_1.ValidationHandler({
|
|
32
32
|
validationsPath: this._data.validationsPath,
|
|
33
33
|
});
|
|
34
|
-
|
|
34
|
+
validationHandler.getValidations().forEach((v) => validationFunctions.push(v));
|
|
35
35
|
}
|
|
36
36
|
// Command handler
|
|
37
37
|
if (this._data.commandsPath) {
|
|
@@ -40,7 +40,9 @@ class CommandKit {
|
|
|
40
40
|
commandsPath: this._data.commandsPath,
|
|
41
41
|
devGuildIds: this._data.devGuildIds || [],
|
|
42
42
|
devUserIds: this._data.devUserIds || [],
|
|
43
|
-
|
|
43
|
+
devRoleIds: this._data.devRoleIds || [],
|
|
44
|
+
customValidations: validationFunctions,
|
|
45
|
+
skipBuiltInValidations: this._data.skipBuiltInValidations || false,
|
|
44
46
|
});
|
|
45
47
|
this._data.commands = commandHandler.getCommands();
|
|
46
48
|
}
|
|
@@ -5,8 +5,8 @@ export declare class CommandHandler {
|
|
|
5
5
|
constructor({ ...options }: CommandHandlerOptions);
|
|
6
6
|
_init(): void;
|
|
7
7
|
_buildCommands(): void;
|
|
8
|
+
_buildValidations(): void;
|
|
8
9
|
_registerCommands(): void;
|
|
9
10
|
_handleCommands(): void;
|
|
10
|
-
_areSlashCommandsDifferent(appCommand: any, localCommand: any): true | undefined;
|
|
11
11
|
getCommands(): (SlashCommandObject | ContextCommandObject)[];
|
|
12
12
|
}
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.CommandHandler = void 0;
|
|
4
7
|
const get_paths_1 = require("../../utils/get-paths");
|
|
8
|
+
const registerCommands_1 = __importDefault(require("./functions/registerCommands"));
|
|
9
|
+
const handleCommands_1 = __importDefault(require("./functions/handleCommands"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
5
11
|
class CommandHandler {
|
|
6
12
|
_data;
|
|
7
13
|
constructor({ ...options }) {
|
|
8
14
|
this._data = {
|
|
9
15
|
...options,
|
|
16
|
+
builtInValidations: [],
|
|
10
17
|
commands: [],
|
|
11
18
|
};
|
|
12
19
|
this._init();
|
|
13
20
|
}
|
|
14
21
|
_init() {
|
|
15
22
|
this._buildCommands();
|
|
23
|
+
this._buildValidations();
|
|
16
24
|
this._registerCommands();
|
|
17
25
|
this._handleCommands();
|
|
18
26
|
}
|
|
@@ -31,225 +39,21 @@ class CommandHandler {
|
|
|
31
39
|
this._data.commands.push(commandObj);
|
|
32
40
|
}
|
|
33
41
|
}
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const guild = client.guilds.cache.get(devGuildId);
|
|
41
|
-
if (!guild) {
|
|
42
|
-
console.log(`⏩ Ignoring: Guild ${devGuildId} does not exist or client isn't in this guild.`);
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
devGuilds.push(guild);
|
|
46
|
-
}
|
|
47
|
-
const appCommands = client.application?.commands;
|
|
48
|
-
await appCommands?.fetch();
|
|
49
|
-
const devGuildCommands = [];
|
|
50
|
-
for (const guild of devGuilds) {
|
|
51
|
-
const guildCommands = guild.commands;
|
|
52
|
-
await guildCommands?.fetch();
|
|
53
|
-
devGuildCommands.push(guildCommands);
|
|
54
|
-
}
|
|
55
|
-
for (const command of commands) {
|
|
56
|
-
// <!-- Delete command if options.deleted -->
|
|
57
|
-
if (command.options?.deleted) {
|
|
58
|
-
const targetCommand = appCommands?.cache.find((cmd) => cmd.name === command.data.name);
|
|
59
|
-
if (!targetCommand) {
|
|
60
|
-
console.log(`⏩ Ignoring: Command "${command.data.name}" is globally marked as deleted.`);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
targetCommand.delete().then(() => {
|
|
64
|
-
console.log(`🚮 Deleted command "${command.data.name}" globally.`);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
for (const guildCommands of devGuildCommands) {
|
|
68
|
-
const targetCommand = guildCommands.cache.find((cmd) => cmd.name === command.data.name);
|
|
69
|
-
if (!targetCommand) {
|
|
70
|
-
console.log(`⏩ Ignoring: Command "${command.data.name}" is marked as deleted for ${guildCommands.guild.name}.`);
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
targetCommand.delete().then(() => {
|
|
74
|
-
console.log(`🚮 Deleted command "${command.data.name}" in ${guildCommands.guild.name}.`);
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
// <!-- Edit command if there's any changes -->
|
|
81
|
-
let commandData = command.data;
|
|
82
|
-
let editedCommand = false;
|
|
83
|
-
(() => {
|
|
84
|
-
// global
|
|
85
|
-
const appGlobalCommand = appCommands?.cache.find((cmd) => cmd.name === command.data.name);
|
|
86
|
-
if (appGlobalCommand) {
|
|
87
|
-
const commandsAreDifferent = this._areSlashCommandsDifferent(appGlobalCommand, commandData);
|
|
88
|
-
if (commandsAreDifferent) {
|
|
89
|
-
appGlobalCommand
|
|
90
|
-
.edit(commandData)
|
|
91
|
-
.then(() => {
|
|
92
|
-
console.log(`✅ Edited command "${commandData.name}" globally.`);
|
|
93
|
-
})
|
|
94
|
-
.catch((error) => {
|
|
95
|
-
console.log(`❌ Failed to edit command "${commandData.name}" globally.`);
|
|
96
|
-
console.error(error);
|
|
97
|
-
});
|
|
98
|
-
editedCommand = true;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// guilds
|
|
102
|
-
for (const guildCommands of devGuildCommands) {
|
|
103
|
-
const appGuildCommand = guildCommands.cache.find((cmd) => cmd.name === commandData.name);
|
|
104
|
-
if (appGuildCommand) {
|
|
105
|
-
const commandsAreDifferent = this._areSlashCommandsDifferent(appGuildCommand, commandData);
|
|
106
|
-
if (commandsAreDifferent) {
|
|
107
|
-
appGuildCommand
|
|
108
|
-
.edit(commandData)
|
|
109
|
-
.then(() => {
|
|
110
|
-
console.log(`✅ Edited command "${commandData.name}" in ${guildCommands.guild.name}.`);
|
|
111
|
-
})
|
|
112
|
-
.catch((error) => {
|
|
113
|
-
console.log(`❌ Failed to edit command "${commandData.name}" in ${guildCommands.guild.name}.`);
|
|
114
|
-
console.error(error);
|
|
115
|
-
});
|
|
116
|
-
editedCommand = true;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
})();
|
|
121
|
-
if (editedCommand)
|
|
122
|
-
continue;
|
|
123
|
-
// <!-- Registration -->
|
|
124
|
-
// guild-based command registration
|
|
125
|
-
if (command.options?.devOnly) {
|
|
126
|
-
if (!devGuilds.length) {
|
|
127
|
-
console.log(`⏩ Ignoring: Cannot register command "${command.data.name}" as no valid "devGuildIds" were provided.`);
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
for (const guild of devGuilds) {
|
|
131
|
-
const cmdExists = guild.commands.cache.some((cmd) => cmd.name === command.data.name);
|
|
132
|
-
if (cmdExists)
|
|
133
|
-
continue;
|
|
134
|
-
guild?.commands
|
|
135
|
-
.create(command.data)
|
|
136
|
-
.then(() => {
|
|
137
|
-
console.log(`✅ Registered command "${command.data.name}" in ${guild.name}.`);
|
|
138
|
-
})
|
|
139
|
-
.catch((error) => {
|
|
140
|
-
console.log(`❌ Failed to register command "${command.data.name}" in ${guild.name}.`);
|
|
141
|
-
console.error(error);
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
// global command registration
|
|
146
|
-
else {
|
|
147
|
-
const cmdExists = appCommands?.cache.some((cmd) => cmd.name === command.data.name);
|
|
148
|
-
if (cmdExists)
|
|
149
|
-
continue;
|
|
150
|
-
appCommands
|
|
151
|
-
?.create(command.data)
|
|
152
|
-
.then(() => {
|
|
153
|
-
console.log(`✅ Registered command "${command.data.name}" globally.`);
|
|
154
|
-
})
|
|
155
|
-
.catch((error) => {
|
|
156
|
-
console.log(`❌ Failed to register command "${command.data.name}" globally.`);
|
|
157
|
-
console.error(error);
|
|
158
|
-
});
|
|
159
|
-
}
|
|
42
|
+
_buildValidations() {
|
|
43
|
+
const validationFilePaths = (0, get_paths_1.getFilePaths)(path_1.default.join(__dirname, 'validations'), true).filter((path) => path.endsWith('.js'));
|
|
44
|
+
for (const validationFilePath of validationFilePaths) {
|
|
45
|
+
const validationFunction = require(validationFilePath);
|
|
46
|
+
if (typeof validationFunction !== 'function') {
|
|
47
|
+
continue;
|
|
160
48
|
}
|
|
161
|
-
|
|
49
|
+
this._data.builtInValidations.push(validationFunction);
|
|
50
|
+
}
|
|
162
51
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
client.on('interactionCreate', async (interaction) => {
|
|
166
|
-
if (!interaction.isChatInputCommand() && !interaction.isContextMenuCommand())
|
|
167
|
-
return;
|
|
168
|
-
const targetCommand = this._data.commands.find((cmd) => cmd.data.name === interaction.commandName);
|
|
169
|
-
if (!targetCommand)
|
|
170
|
-
return;
|
|
171
|
-
// Options validation
|
|
172
|
-
// options.guildOnly
|
|
173
|
-
if (targetCommand.options?.guildOnly && !interaction.inGuild()) {
|
|
174
|
-
interaction.reply({
|
|
175
|
-
content: '❌ This command can only be used inside a server.',
|
|
176
|
-
ephemeral: true,
|
|
177
|
-
});
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
// options.devOnly
|
|
181
|
-
if (targetCommand.options?.devOnly) {
|
|
182
|
-
const isDevUser = this._data.devUserIds.includes(interaction.user.id);
|
|
183
|
-
if (!isDevUser) {
|
|
184
|
-
interaction.reply({
|
|
185
|
-
content: '❌ This command can only be used by developers.',
|
|
186
|
-
ephemeral: true,
|
|
187
|
-
});
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
// options.userPermissions
|
|
192
|
-
const memberPermissions = interaction.memberPermissions;
|
|
193
|
-
if (targetCommand.options?.userPermissions && memberPermissions) {
|
|
194
|
-
for (const permission of targetCommand.options.userPermissions) {
|
|
195
|
-
const hasPermission = memberPermissions.has(permission);
|
|
196
|
-
if (!hasPermission) {
|
|
197
|
-
interaction.reply({
|
|
198
|
-
content: `❌ You do not have enough permission to run this command. Required permission: \`${permission}\``,
|
|
199
|
-
ephemeral: true,
|
|
200
|
-
});
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
// options.botPermissions
|
|
206
|
-
const botMember = interaction.guild?.members.me;
|
|
207
|
-
if (targetCommand.options?.botPermissions && botMember) {
|
|
208
|
-
for (const permission of targetCommand.options.botPermissions) {
|
|
209
|
-
const hasPermission = botMember.permissions.has(permission);
|
|
210
|
-
if (!hasPermission) {
|
|
211
|
-
interaction.reply({
|
|
212
|
-
content: `❌ I do not have enough permission to execute this command. Required permission: \`${permission}\``,
|
|
213
|
-
ephemeral: true,
|
|
214
|
-
});
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
// Run user validation functions
|
|
220
|
-
const validationFunctions = this._data.validations;
|
|
221
|
-
const { data, options, run, ...rest } = targetCommand;
|
|
222
|
-
const commandObj = {
|
|
223
|
-
data: targetCommand.data,
|
|
224
|
-
options: targetCommand.options,
|
|
225
|
-
...rest,
|
|
226
|
-
};
|
|
227
|
-
let canRun = true;
|
|
228
|
-
for (const validationFunction of validationFunctions) {
|
|
229
|
-
const stopValidationLoop = await validationFunction({ interaction, client, commandObj });
|
|
230
|
-
if (stopValidationLoop) {
|
|
231
|
-
canRun = false;
|
|
232
|
-
break;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
if (canRun) {
|
|
236
|
-
targetCommand.run({ interaction, client });
|
|
237
|
-
}
|
|
238
|
-
});
|
|
52
|
+
_registerCommands() {
|
|
53
|
+
(0, registerCommands_1.default)(this);
|
|
239
54
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
appCommand.options = [];
|
|
243
|
-
if (!localCommand.options)
|
|
244
|
-
localCommand.options = [];
|
|
245
|
-
if (!appCommand.description)
|
|
246
|
-
appCommand.description = '';
|
|
247
|
-
if (!localCommand.description)
|
|
248
|
-
localCommand.description = '';
|
|
249
|
-
if (localCommand.description !== appCommand.description ||
|
|
250
|
-
localCommand.options.length !== appCommand.options.length) {
|
|
251
|
-
return true;
|
|
252
|
-
}
|
|
55
|
+
_handleCommands() {
|
|
56
|
+
(0, handleCommands_1.default)(this);
|
|
253
57
|
}
|
|
254
58
|
getCommands() {
|
|
255
59
|
return this._data.commands;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function handleCommands(commandHandler) {
|
|
4
|
+
const client = commandHandler._data.client;
|
|
5
|
+
client.on('interactionCreate', async (interaction) => {
|
|
6
|
+
if (!interaction.isChatInputCommand() && !interaction.isContextMenuCommand())
|
|
7
|
+
return;
|
|
8
|
+
const targetCommand = commandHandler._data.commands.find((cmd) => cmd.data.name === interaction.commandName);
|
|
9
|
+
if (!targetCommand)
|
|
10
|
+
return;
|
|
11
|
+
const { data, options, run, ...rest } = targetCommand;
|
|
12
|
+
const commandObj = {
|
|
13
|
+
data: targetCommand.data,
|
|
14
|
+
options: targetCommand.options,
|
|
15
|
+
...rest,
|
|
16
|
+
};
|
|
17
|
+
let canRun = true;
|
|
18
|
+
for (const validationFunction of commandHandler._data.customValidations) {
|
|
19
|
+
const stopValidationLoop = await validationFunction({
|
|
20
|
+
interaction,
|
|
21
|
+
client,
|
|
22
|
+
commandObj,
|
|
23
|
+
});
|
|
24
|
+
if (stopValidationLoop) {
|
|
25
|
+
canRun = false;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (!canRun)
|
|
30
|
+
return;
|
|
31
|
+
// If custom validations pass and !skipBuiltInValidations, run built-in CommandKit validation functions
|
|
32
|
+
if (!commandHandler._data.skipBuiltInValidations) {
|
|
33
|
+
for (const validation of commandHandler._data.builtInValidations) {
|
|
34
|
+
const stopValidationLoop = validation({
|
|
35
|
+
targetCommand,
|
|
36
|
+
interaction,
|
|
37
|
+
handlerData: commandHandler._data,
|
|
38
|
+
});
|
|
39
|
+
if (stopValidationLoop) {
|
|
40
|
+
canRun = false;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!canRun)
|
|
46
|
+
return;
|
|
47
|
+
targetCommand.run({ interaction, client });
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
exports.default = handleCommands;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const areSlashCommandsDifferent_1 = __importDefault(require("../utils/areSlashCommandsDifferent"));
|
|
7
|
+
function registerCommands(commandHandler) {
|
|
8
|
+
const client = commandHandler._data.client;
|
|
9
|
+
const devGuildIds = commandHandler._data.devGuildIds;
|
|
10
|
+
const commands = commandHandler._data.commands;
|
|
11
|
+
client.once('ready', async () => {
|
|
12
|
+
const devGuilds = [];
|
|
13
|
+
for (const devGuildId of devGuildIds) {
|
|
14
|
+
const guild = client.guilds.cache.get(devGuildId);
|
|
15
|
+
if (!guild) {
|
|
16
|
+
console.log(`⏩ Ignoring: Guild ${devGuildId} does not exist or client isn't in this guild.`);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
devGuilds.push(guild);
|
|
20
|
+
}
|
|
21
|
+
const appCommands = client.application?.commands;
|
|
22
|
+
await appCommands?.fetch();
|
|
23
|
+
const devGuildCommands = [];
|
|
24
|
+
for (const guild of devGuilds) {
|
|
25
|
+
const guildCommands = guild.commands;
|
|
26
|
+
await guildCommands?.fetch();
|
|
27
|
+
devGuildCommands.push(guildCommands);
|
|
28
|
+
}
|
|
29
|
+
for (const command of commands) {
|
|
30
|
+
// <!-- Delete command if options.deleted -->
|
|
31
|
+
if (command.options?.deleted) {
|
|
32
|
+
const targetCommand = appCommands?.cache.find((cmd) => cmd.name === command.data.name);
|
|
33
|
+
if (!targetCommand) {
|
|
34
|
+
console.log(`⏩ Ignoring: Command "${command.data.name}" is globally marked as deleted.`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
targetCommand.delete().then(() => {
|
|
38
|
+
console.log(`🚮 Deleted command "${command.data.name}" globally.`);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
for (const guildCommands of devGuildCommands) {
|
|
42
|
+
const targetCommand = guildCommands.cache.find((cmd) => cmd.name === command.data.name);
|
|
43
|
+
if (!targetCommand) {
|
|
44
|
+
console.log(`⏩ Ignoring: Command "${command.data.name}" is marked as deleted for ${guildCommands.guild.name}.`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
targetCommand.delete().then(() => {
|
|
48
|
+
console.log(`🚮 Deleted command "${command.data.name}" in ${guildCommands.guild.name}.`);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// <!-- Edit command -->
|
|
55
|
+
let commandData = command.data;
|
|
56
|
+
let editedCommand = false;
|
|
57
|
+
// Edit command globally
|
|
58
|
+
const appGlobalCommand = appCommands?.cache.find((cmd) => cmd.name === command.data.name);
|
|
59
|
+
if (appGlobalCommand) {
|
|
60
|
+
const commandsAreDifferent = (0, areSlashCommandsDifferent_1.default)(appGlobalCommand, commandData);
|
|
61
|
+
if (commandsAreDifferent) {
|
|
62
|
+
appGlobalCommand
|
|
63
|
+
.edit(commandData)
|
|
64
|
+
.then(() => {
|
|
65
|
+
console.log(`✅ Edited command "${commandData.name}" globally.`);
|
|
66
|
+
})
|
|
67
|
+
.catch((error) => {
|
|
68
|
+
console.log(`❌ Failed to edit command "${commandData.name}" globally.`);
|
|
69
|
+
console.error(error);
|
|
70
|
+
});
|
|
71
|
+
editedCommand = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Edit command in a specific guild
|
|
75
|
+
for (const guildCommands of devGuildCommands) {
|
|
76
|
+
const appGuildCommand = guildCommands.cache.find((cmd) => cmd.name === commandData.name);
|
|
77
|
+
if (appGuildCommand) {
|
|
78
|
+
const commandsAreDifferent = (0, areSlashCommandsDifferent_1.default)(appGuildCommand, commandData);
|
|
79
|
+
if (commandsAreDifferent) {
|
|
80
|
+
appGuildCommand
|
|
81
|
+
.edit(commandData)
|
|
82
|
+
.then(() => {
|
|
83
|
+
console.log(`✅ Edited command "${commandData.name}" in ${guildCommands.guild.name}.`);
|
|
84
|
+
})
|
|
85
|
+
.catch((error) => {
|
|
86
|
+
console.log(`❌ Failed to edit command "${commandData.name}" in ${guildCommands.guild.name}.`);
|
|
87
|
+
console.error(error);
|
|
88
|
+
});
|
|
89
|
+
editedCommand = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (editedCommand)
|
|
94
|
+
continue;
|
|
95
|
+
// <!-- Register command -->
|
|
96
|
+
// Register command in a specific guild
|
|
97
|
+
if (command.options?.devOnly) {
|
|
98
|
+
if (!devGuilds.length) {
|
|
99
|
+
console.log(`⏩ Ignoring: Cannot register command "${command.data.name}" as no valid "devGuildIds" were provided.`);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
for (const guild of devGuilds) {
|
|
103
|
+
const cmdExists = guild.commands.cache.some((cmd) => cmd.name === command.data.name);
|
|
104
|
+
if (cmdExists)
|
|
105
|
+
continue;
|
|
106
|
+
guild?.commands
|
|
107
|
+
.create(command.data)
|
|
108
|
+
.then(() => {
|
|
109
|
+
console.log(`✅ Registered command "${command.data.name}" in ${guild.name}.`);
|
|
110
|
+
})
|
|
111
|
+
.catch((error) => {
|
|
112
|
+
console.log(`❌ Failed to register command "${command.data.name}" in ${guild.name}.`);
|
|
113
|
+
console.error(error);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Register command globally
|
|
118
|
+
else {
|
|
119
|
+
const cmdExists = appCommands?.cache.some((cmd) => cmd.name === command.data.name);
|
|
120
|
+
if (cmdExists)
|
|
121
|
+
continue;
|
|
122
|
+
appCommands
|
|
123
|
+
?.create(command.data)
|
|
124
|
+
.then(() => {
|
|
125
|
+
console.log(`✅ Registered command "${command.data.name}" globally.`);
|
|
126
|
+
})
|
|
127
|
+
.catch((error) => {
|
|
128
|
+
console.log(`❌ Failed to register command "${command.data.name}" globally.`);
|
|
129
|
+
console.error(error);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
exports.default = registerCommands;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function areSlashCommandsDifferent(appCommand: any, localCommand: any): true | undefined;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function areSlashCommandsDifferent(appCommand, localCommand) {
|
|
4
|
+
if (!appCommand.options)
|
|
5
|
+
appCommand.options = [];
|
|
6
|
+
if (!localCommand.options)
|
|
7
|
+
localCommand.options = [];
|
|
8
|
+
if (!appCommand.description)
|
|
9
|
+
appCommand.description = '';
|
|
10
|
+
if (!localCommand.description)
|
|
11
|
+
localCommand.description = '';
|
|
12
|
+
if (localCommand.description !== appCommand.description ||
|
|
13
|
+
localCommand.options.length !== appCommand.options.length) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.default = areSlashCommandsDifferent;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
module.exports = ({ interaction, targetCommand }) => {
|
|
4
|
+
const botMember = interaction.guild?.members.me;
|
|
5
|
+
if (targetCommand.options?.botPermissions && botMember) {
|
|
6
|
+
for (const permission of targetCommand.options.botPermissions) {
|
|
7
|
+
const hasPermission = botMember.permissions.has(permission);
|
|
8
|
+
if (!hasPermission) {
|
|
9
|
+
interaction.reply({
|
|
10
|
+
content: `❌ I do not have enough permission to execute this command. Required permission: \`${permission}\``,
|
|
11
|
+
ephemeral: true,
|
|
12
|
+
});
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
module.exports = ({ interaction, targetCommand, handlerData }) => {
|
|
4
|
+
if (targetCommand.options?.devOnly) {
|
|
5
|
+
if (interaction.inGuild() && !handlerData.devGuildIds.includes(interaction.guildId)) {
|
|
6
|
+
interaction.reply({
|
|
7
|
+
content: '❌ This command can only be used inside development servers.',
|
|
8
|
+
ephemeral: true,
|
|
9
|
+
});
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
const guildMember = interaction.guild?.members.cache.get(interaction.user.id);
|
|
13
|
+
const memberRoles = guildMember?.roles.cache;
|
|
14
|
+
let hasDevRole = false;
|
|
15
|
+
memberRoles?.forEach((role) => {
|
|
16
|
+
if (handlerData.devRoleIds?.includes(role.id)) {
|
|
17
|
+
hasDevRole = true;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const isDevUser = handlerData.devUserIds.includes(interaction.user.id) || hasDevRole;
|
|
21
|
+
if (!isDevUser) {
|
|
22
|
+
interaction.reply({
|
|
23
|
+
content: '❌ This command can only be used by developers.',
|
|
24
|
+
ephemeral: true,
|
|
25
|
+
});
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
module.exports = ({ interaction, targetCommand }) => {
|
|
4
|
+
if (targetCommand.options?.guildOnly && !interaction.inGuild()) {
|
|
5
|
+
interaction.reply({
|
|
6
|
+
content: '❌ This command can only be used inside a server.',
|
|
7
|
+
ephemeral: true,
|
|
8
|
+
});
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
module.exports = ({ interaction, targetCommand }) => {
|
|
4
|
+
const memberPermissions = interaction.memberPermissions;
|
|
5
|
+
if (targetCommand.options?.userPermissions && memberPermissions) {
|
|
6
|
+
for (const permission of targetCommand.options.userPermissions) {
|
|
7
|
+
const hasPermission = memberPermissions.has(permission);
|
|
8
|
+
if (!hasPermission) {
|
|
9
|
+
interaction.reply({
|
|
10
|
+
content: `❌ You do not have enough permission to run this command. Required permission: \`${permission}\``,
|
|
11
|
+
ephemeral: true,
|
|
12
|
+
});
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
package/package.json
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
2
|
+
"name": "commandkit",
|
|
3
|
+
"version": "0.0.9",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/notunderctrl/commandkit"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://commandkit.underctrl.io",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"discord.js",
|
|
16
|
+
"command handler",
|
|
17
|
+
"event handler",
|
|
18
|
+
"command validations"
|
|
19
|
+
],
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"discord.js": "^14.12.1",
|
|
22
|
+
"typescript": "^5.1.6"
|
|
23
|
+
}
|
|
25
24
|
}
|
package/tsconfig.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"outDir": "dist",
|
|
4
|
+
"strict": true,
|
|
5
|
+
"noImplicitAny": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"strictNullChecks": true,
|
|
8
|
+
"target": "ES2022",
|
|
9
|
+
"moduleResolution": "Node",
|
|
10
|
+
"module": "CommonJS",
|
|
11
|
+
"declaration": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*"]
|
|
14
14
|
}
|
package/typings.d.ts
CHANGED
|
@@ -1,61 +1,63 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
Client,
|
|
3
|
+
APIApplicationCommandOption,
|
|
4
|
+
ContextMenuCommandType,
|
|
5
|
+
Interaction,
|
|
6
|
+
PermissionResolvable,
|
|
7
|
+
SlashCommandBuilder,
|
|
8
|
+
ContextMenuCommandBuilder,
|
|
9
9
|
} from 'discord.js';
|
|
10
10
|
|
|
11
11
|
export interface CommandKitOptions {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
client: Client;
|
|
13
|
+
commandsPath?: string;
|
|
14
|
+
eventsPath?: string;
|
|
15
|
+
validationsPath?: string;
|
|
16
|
+
devGuildIds?: string[];
|
|
17
|
+
devUserIds?: string[];
|
|
18
|
+
devRoleIds?: string[];
|
|
19
|
+
skipBuiltInValidations?: boolean;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export interface CommandKitData extends CommandKitOptions {
|
|
21
|
-
|
|
23
|
+
commands: Array<SlashCommandObject | ContextCommandObject>;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export interface SlashCommandObject {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
27
|
+
data:
|
|
28
|
+
| SlashCommandBuilder
|
|
29
|
+
| {
|
|
30
|
+
name: string;
|
|
31
|
+
name_localizations?: any;
|
|
32
|
+
description: string;
|
|
33
|
+
dm_permission?: boolean;
|
|
34
|
+
options?: APIApplicationCommandOption[];
|
|
35
|
+
};
|
|
36
|
+
options?: {
|
|
37
|
+
guildOnly?: boolean;
|
|
38
|
+
devOnly?: boolean;
|
|
39
|
+
deleted?: boolean;
|
|
40
|
+
userPermissions?: PermissionResolvable[];
|
|
41
|
+
botPermissions?: PermissionResolvable[];
|
|
42
|
+
};
|
|
43
|
+
run: ({}: { interaction: Interaction; client: Client }) => void;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
export interface ContextCommandObject {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
data:
|
|
48
|
+
| ContextMenuCommandBuilder
|
|
49
|
+
| {
|
|
50
|
+
name: string;
|
|
51
|
+
name_localizations?: any;
|
|
52
|
+
type: ContextMenuCommandType;
|
|
53
|
+
dm_permission?: boolean;
|
|
54
|
+
};
|
|
55
|
+
options?: {
|
|
56
|
+
guildOnly?: boolean;
|
|
57
|
+
devOnly?: boolean;
|
|
58
|
+
deleted?: boolean;
|
|
59
|
+
userPermissions?: PermissionResolvable[];
|
|
60
|
+
botPermissions?: PermissionResolvable[];
|
|
61
|
+
};
|
|
62
|
+
run: ({}: { interaction: Interaction; client: Client }) => void;
|
|
61
63
|
}
|