├── .gitattributes ├── .github └── workflows │ └── npm-publish.yml ├── .gitignore ├── README.md ├── index.js ├── package.json └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Node.js Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | 9 | publish-npm: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: 12 16 | registry-url: https://registry.npmjs.org/ 17 | - run: npm publish 18 | env: 19 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 20 | 21 | publish-gpr: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v2 25 | - uses: actions/setup-node@v1 26 | with: 27 | node-version: 12 28 | registry-url: https://npm.pkg.github.com/ 29 | - run: npm install 30 | - run: npm publish 31 | env: 32 | NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node 2 | node_modules 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discord Sync Commands 2 | 3 | A Discord.js v14.20.0 compatible slash command synchronization utility that automatically keeps your bot's slash commands synchronized with Discord. 4 | 5 | ## ✨ Features 6 | 7 | - ✅ **Smart Synchronization**: Only updates commands that have actually changed 8 | - 🔄 **Automatic CRUD**: Automatically creates, updates, and deletes commands 9 | - 🎯 **Guild & Global**: Supports both guild-specific and global commands 10 | - 🔍 **Comprehensive Comparison**: Uses Discord.js built-in `ApplicationCommand.optionsEqual()` method 11 | - 📊 **Detailed Logging**: Debug mode with detailed operation logs 12 | - 🛡️ **Safe**: Robust error handling and validation 13 | - 🏗️ **Modern**: Discord.js v14.20.0 compatible with ES6+ syntax 14 | 15 | ## 📦 Installation 16 | 17 | ```bash 18 | npm install discord-sync-commands 19 | ``` 20 | 21 | ## 🚀 Usage 22 | 23 | ### Basic Usage 24 | 25 | ```javascript 26 | const { Client, GatewayIntentBits, ApplicationCommandType, ApplicationCommandOptionType } = require('discord.js'); 27 | const syncCommands = require('discord-sync-commands'); 28 | 29 | const client = new Client({ 30 | intents: [GatewayIntentBits.Guilds] 31 | }); 32 | 33 | const commands = [ 34 | { 35 | name: 'ping', 36 | description: 'Replies with Pong!', 37 | type: ApplicationCommandType.ChatInput 38 | }, 39 | { 40 | name: 'echo', 41 | description: 'Echo back a message', 42 | type: ApplicationCommandType.ChatInput, 43 | options: [ 44 | { 45 | name: 'message', 46 | description: 'Message to echo', 47 | type: ApplicationCommandOptionType.String, 48 | required: true 49 | } 50 | ] 51 | } 52 | ]; 53 | 54 | client.once('ready', async () => { 55 | console.log('Bot is ready!'); 56 | 57 | // Synchronize commands 58 | const result = await syncCommands(client, commands, { 59 | debug: true // Enable debug logging 60 | }); 61 | 62 | console.log(`${result.newCommandCount} commands created`); 63 | console.log(`${result.updatedCommandCount} commands updated`); 64 | console.log(`${result.deletedCommandCount} commands deleted`); 65 | }); 66 | 67 | client.login('YOUR_BOT_TOKEN'); 68 | ``` 69 | 70 | ### Using SlashCommandBuilder 71 | 72 | You can also use Discord.js SlashCommandBuilder for cleaner code: 73 | 74 | ```javascript 75 | const { Client, GatewayIntentBits, SlashCommandBuilder, ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js'); 76 | const syncCommands = require('discord-sync-commands'); 77 | 78 | const client = new Client({ 79 | intents: [GatewayIntentBits.Guilds] 80 | }); 81 | 82 | // Using SlashCommandBuilder for better type safety and cleaner syntax 83 | const commands = [ 84 | new SlashCommandBuilder() 85 | .setName('ping') 86 | .setDescription('Replies with Pong!') 87 | .toJSON(), 88 | 89 | new SlashCommandBuilder() 90 | .setName('echo') 91 | .setDescription('Echo back a message') 92 | .addStringOption(option => 93 | option.setName('message') 94 | .setDescription('Message to echo back') 95 | .setRequired(true) 96 | .setMinLength(1) 97 | .setMaxLength(2000) 98 | ) 99 | .addChannelOption(option => 100 | option.setName('channel') 101 | .setDescription('Channel to send the message to') 102 | .setRequired(false) 103 | ) 104 | .toJSON(), 105 | 106 | new SlashCommandBuilder() 107 | .setName('user-info') 108 | .setDescription('Get information about a user') 109 | .addUserOption(option => 110 | option.setName('user') 111 | .setDescription('User to get info about') 112 | .setRequired(false) 113 | ) 114 | .toJSON(), 115 | 116 | // Context Menu Commands 117 | new ContextMenuCommandBuilder() 118 | .setName('Get User Avatar') 119 | .setType(ApplicationCommandType.User) 120 | .toJSON(), 121 | 122 | new ContextMenuCommandBuilder() 123 | .setName('Quote Message') 124 | .setType(ApplicationCommandType.Message) 125 | .toJSON() 126 | ]; 127 | 128 | client.once('ready', async () => { 129 | console.log('Bot is ready!'); 130 | 131 | const result = await syncCommands(client, commands, { 132 | debug: true 133 | }); 134 | 135 | console.log(`Commands synchronized: ${result.newCommandCount} created, ${result.updatedCommandCount} updated`); 136 | }); 137 | 138 | client.login('YOUR_BOT_TOKEN'); 139 | ``` 140 | 141 | ### Guild-Specific Commands 142 | 143 | ```javascript 144 | // Commands that only work in a specific guild 145 | await syncCommands(client, commands, { 146 | debug: true, 147 | guildId: 'YOUR_GUILD_ID' 148 | }); 149 | ``` 150 | 151 | ### Advanced Command Examples 152 | 153 | #### Traditional Object Syntax 154 | 155 | ```javascript 156 | const { PermissionFlagsBits } = require('discord.js'); 157 | 158 | const advancedCommands = [ 159 | { 160 | name: 'admin', 161 | description: 'Admin commands', 162 | type: ApplicationCommandType.ChatInput, 163 | defaultMemberPermissions: PermissionFlagsBits.Administrator, 164 | dmPermission: false, 165 | nsfw: false, 166 | options: [ 167 | { 168 | name: 'action', 169 | description: 'Action to perform', 170 | type: ApplicationCommandOptionType.String, 171 | required: true, 172 | autocomplete: true, 173 | choices: [ 174 | { name: 'Ban User', value: 'ban' }, 175 | { name: 'Clear Messages', value: 'clear' } 176 | ] 177 | }, 178 | { 179 | name: 'reason', 180 | description: 'Reason for the action', 181 | type: ApplicationCommandOptionType.String, 182 | required: false, 183 | minLength: 3, 184 | maxLength: 200 185 | } 186 | ] 187 | } 188 | ]; 189 | ``` 190 | 191 | #### SlashCommandBuilder Syntax 192 | 193 | ```javascript 194 | const { SlashCommandBuilder, PermissionFlagsBits, ChannelType } = require('discord.js'); 195 | 196 | const advancedCommands = [ 197 | // Admin command with permissions and choices 198 | new SlashCommandBuilder() 199 | .setName('admin') 200 | .setDescription('Admin commands') 201 | .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) 202 | .setDMPermission(false) 203 | .addStringOption(option => 204 | option.setName('action') 205 | .setDescription('Action to perform') 206 | .setRequired(true) 207 | .setAutocomplete(true) 208 | .addChoices( 209 | { name: 'Ban User', value: 'ban' }, 210 | { name: 'Clear Messages', value: 'clear' }, 211 | { name: 'Kick User', value: 'kick' }, 212 | { name: 'Timeout User', value: 'timeout' } 213 | ) 214 | ) 215 | .addStringOption(option => 216 | option.setName('reason') 217 | .setDescription('Reason for the action') 218 | .setRequired(false) 219 | .setMinLength(3) 220 | .setMaxLength(200) 221 | ) 222 | .addUserOption(option => 223 | option.setName('target') 224 | .setDescription('Target user for the action') 225 | .setRequired(false) 226 | ) 227 | .toJSON(), 228 | 229 | // Math command with number constraints 230 | new SlashCommandBuilder() 231 | .setName('math') 232 | .setDescription('Perform mathematical operations') 233 | .addStringOption(option => 234 | option.setName('operation') 235 | .setDescription('Mathematical operation') 236 | .setRequired(true) 237 | .addChoices( 238 | { name: 'Add (+)', value: 'add' }, 239 | { name: 'Subtract (-)', value: 'subtract' }, 240 | { name: 'Multiply (×)', value: 'multiply' }, 241 | { name: 'Divide (÷)', value: 'divide' }, 242 | { name: 'Power (^)', value: 'power' }, 243 | { name: 'Square Root (√)', value: 'sqrt' } 244 | ) 245 | ) 246 | .addNumberOption(option => 247 | option.setName('number1') 248 | .setDescription('First number') 249 | .setRequired(true) 250 | .setMinValue(-1000000) 251 | .setMaxValue(1000000) 252 | ) 253 | .addNumberOption(option => 254 | option.setName('number2') 255 | .setDescription('Second number (not needed for square root)') 256 | .setRequired(false) 257 | .setMinValue(-1000000) 258 | .setMaxValue(1000000) 259 | ) 260 | .toJSON(), 261 | 262 | // Complex command with subcommands 263 | new SlashCommandBuilder() 264 | .setName('server') 265 | .setDescription('Server management commands') 266 | .addSubcommand(subcommand => 267 | subcommand 268 | .setName('info') 269 | .setDescription('Get server information') 270 | ) 271 | .addSubcommand(subcommand => 272 | subcommand 273 | .setName('channels') 274 | .setDescription('Manage server channels') 275 | .addStringOption(option => 276 | option.setName('action') 277 | .setDescription('Channel action') 278 | .setRequired(true) 279 | .addChoices( 280 | { name: 'List All', value: 'list' }, 281 | { name: 'Create New', value: 'create' }, 282 | { name: 'Delete', value: 'delete' } 283 | ) 284 | ) 285 | .addChannelOption(option => 286 | option.setName('channel') 287 | .setDescription('Target channel') 288 | .setRequired(false) 289 | .addChannelTypes(ChannelType.GuildText, ChannelType.GuildVoice) 290 | ) 291 | ) 292 | .addSubcommandGroup(group => 293 | group 294 | .setName('roles') 295 | .setDescription('Role management') 296 | .addSubcommand(subcommand => 297 | subcommand 298 | .setName('create') 299 | .setDescription('Create a new role') 300 | .addStringOption(option => 301 | option.setName('name') 302 | .setDescription('Role name') 303 | .setRequired(true) 304 | .setMinLength(1) 305 | .setMaxLength(100) 306 | ) 307 | .addStringOption(option => 308 | option.setName('color') 309 | .setDescription('Role color (hex format)') 310 | .setRequired(false) 311 | ) 312 | ) 313 | .addSubcommand(subcommand => 314 | subcommand 315 | .setName('assign') 316 | .setDescription('Assign role to user') 317 | .addUserOption(option => 318 | option.setName('user') 319 | .setDescription('User to assign role to') 320 | .setRequired(true) 321 | ) 322 | .addRoleOption(option => 323 | option.setName('role') 324 | .setDescription('Role to assign') 325 | .setRequired(true) 326 | ) 327 | ) 328 | ) 329 | .toJSON(), 330 | 331 | // NSFW command example 332 | new SlashCommandBuilder() 333 | .setName('nsfw-content') 334 | .setDescription('Age-restricted content command') 335 | .setNSFW(true) 336 | .addStringOption(option => 337 | option.setName('type') 338 | .setDescription('Type of content') 339 | .setRequired(true) 340 | .addChoices( 341 | { name: 'Image', value: 'image' }, 342 | { name: 'Video', value: 'video' }, 343 | { name: 'Text', value: 'text' } 344 | ) 345 | ) 346 | .toJSON() 347 | ]; 348 | ``` 349 | 350 | ## 📚 API Reference 351 | 352 | ### syncCommands(client, commands, options) 353 | 354 | Synchronizes commands with Discord. 355 | 356 | #### Parameters 357 | 358 | - `client` (Client): Discord.js Client instance 359 | - `commands` (Array): Array of command objects to synchronize 360 | - `options` (Object): Optional configuration 361 | - `debug` (boolean): Enable debug logging (default: false) 362 | - `guildId` (string|null): Guild ID for guild-specific commands (default: null - global commands) 363 | 364 | #### Returns 365 | 366 | Promise\: 367 | ```javascript 368 | { 369 | currentCommandCount: number, // Current number of commands 370 | newCommandCount: number, // Number of commands created 371 | deletedCommandCount: number, // Number of commands deleted 372 | updatedCommandCount: number // Number of commands updated 373 | } 374 | ``` 375 | 376 | ## 🔧 Supported Features 377 | 378 | ### Discord.js v14.20.0 Features 379 | 380 | - ✅ **Application Command Types**: ChatInput, User, Message 381 | - ✅ **Option Types**: String, Integer, Boolean, User, Channel, Role, Mentionable, Number, Attachment 382 | - ✅ **Permissions**: defaultMemberPermissions, dmPermission 383 | - ✅ **NSFW**: Age-restricted commands 384 | - ✅ **Autocomplete**: Dynamic option suggestions 385 | - ✅ **Choices**: Predefined option values 386 | - ✅ **Subcommands**: Nested command structure 387 | - ✅ **Localizations**: Multi-language support 388 | - ✅ **Constraints**: minValue, maxValue, minLength, maxLength 389 | - ✅ **Channel Types**: Specific channel type restrictions 390 | 391 | ### Comparison Features 392 | 393 | The module detects changes in: 394 | - 📝 Command description 395 | - ⚙️ Options (recursive comparison using Discord.js built-in method) 396 | - 🔐 Permissions 397 | - 🔞 NSFW status 398 | - 🌍 Localizations 399 | 400 | ## 🏗️ Technical Details 401 | 402 | ### Built-in Discord.js Integration 403 | 404 | This module leverages Discord.js's official `ApplicationCommand.optionsEqual()` method for reliable option comparison, ensuring compatibility with Discord's API specifications. 405 | 406 | ```javascript 407 | // Uses Discord.js built-in method for accurate comparison 408 | return !ApplicationCommand.optionsEqual(previousCommand.options ?? [], newCommand.options ?? []); 409 | ``` 410 | 411 | ### Modern Event Handling 412 | 413 | Uses Discord.js v14 event constants for better type safety: 414 | 415 | ```javascript 416 | const { Events } = require('discord.js'); 417 | client.once(Events.ClientReady, () => { 418 | // Bot is ready 419 | }); 420 | ``` 421 | 422 | ## 🛠️ Development 423 | 424 | ### Project Structure 425 | 426 | ``` 427 | discord-sync-commands/ 428 | ├── index.js # Main module 429 | ├── package.json # Package information 430 | └── README.md # Documentation 431 | ``` 432 | 433 | ### Contributing 434 | 435 | 1. Fork the repository 436 | 2. Create a feature branch (`git checkout -b feature/amazing-feature`) 437 | 3. Commit your changes (`git commit -m 'Add amazing feature'`) 438 | 4. Push to the branch (`git push origin feature/amazing-feature`) 439 | 5. Open a Pull Request 440 | 441 | ## 📄 License 442 | 443 | MIT License - See [LICENSE](LICENSE) file for details. 444 | 445 | ## 🔗 Links 446 | 447 | - [Discord.js Guide](https://discordjs.guide/) 448 | - [Discord.js Documentation](https://discord.js.org/) 449 | - [Discord Developer Portal](https://discord.com/developers/applications) 450 | - [ApplicationCommand.optionsEqual() Documentation](https://discord.js.org/docs/packages/discord.js/14.20.0/ApplicationCommand:Class#optionsEqual) 451 | 452 | ## ⚠️ Important Notes 453 | 454 | - Your bot must have the **applications.commands** scope 455 | - Global commands can take up to 1 hour to propagate on Discord 456 | - Guild commands are active immediately 457 | - Be mindful of rate limits (200 global command limit) 458 | 459 | ## 🆘 Troubleshooting 460 | 461 | ### Common Errors 462 | 463 | **"Missing applications.commands scope"** 464 | ```javascript 465 | // Add &scope=applications.commands to your bot invitation URL 466 | // Example: https://discord.com/oauth2/authorize?client_id=YOUR_BOT_ID&scope=bot%20applications.commands&permissions=0 467 | ``` 468 | 469 | **"Commands not updating"** 470 | - Global commands can take up to 1 hour to propagate 471 | - Try testing with guild commands first 472 | - Enable debug mode to check logs 473 | 474 | **"RESTJSONErrorCodes.MissingAccess"** 475 | - Ensure your bot has the correct permissions 476 | - Verify the bot is in the guild for guild-specific commands 477 | - Check that the client application is properly initialized 478 | 479 | ## 📊 Performance 480 | 481 | - ⚡ **Fast**: Only updates changed commands 482 | - 🔄 **Efficient**: Uses Discord.js's built-in comparison methods 483 | - 💾 **Lightweight**: Minimal dependencies 484 | - 🛡️ **Reliable**: Comprehensive error handling and validation 485 | 486 | ## 🔄 What's New in v14.20.0 Compatibility 487 | 488 | - 🆕 **Enhanced Option Comparison**: Now uses `ApplicationCommand.optionsEqual()` for more accurate comparison 489 | - 🆕 **Modern Event Handling**: Uses `Events.ClientReady` constant 490 | - 🆕 **Improved Error Handling**: Better error messages with `RESTJSONErrorCodes` 491 | - 🆕 **Comprehensive JSDoc**: Full documentation with TypeScript-style annotations 492 | - 🆕 **Optimized Performance**: Removed custom comparison functions in favor of Discord.js built-ins 493 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { Client, RESTJSONErrorCodes, ApplicationCommand, Events } = require('discord.js'); 2 | 3 | /** 4 | * Discord slash commands synchronization utility 5 | * @param {Client} client - Discord.js client instance 6 | * @param {Array} commands - Array of command objects to synchronize 7 | * @param {Object} options - Configuration options 8 | * @param {boolean} [options.debug=false] - Enable debug logging 9 | * @param {string|null} [options.guildId=null] - Guild ID for guild-specific commands (null for global commands) 10 | * @returns {Promise} Synchronization results with counts 11 | * @throws {TypeError} When client is not a Client instance or commands is not an array 12 | * @throws {Error} When client application is not available 13 | * @example 14 | * const syncCommands = require('discord-sync-commands'); 15 | * 16 | * const commands = [ 17 | * { 18 | * name: 'ping', 19 | * description: 'Replies with Pong!', 20 | * type: ApplicationCommandType.ChatInput 21 | * } 22 | * ]; 23 | * 24 | * const result = await syncCommands(client, commands, { debug: true }); 25 | * console.log(`Created: ${result.newCommandCount}, Updated: ${result.updatedCommandCount}`); 26 | */ 27 | module.exports = async (client, commands, options = { 28 | debug: false, 29 | guildId: null 30 | }) => { 31 | if (!(client instanceof Client)) { 32 | throw new TypeError('Client instance is required'); 33 | }; 34 | 35 | if (!Array.isArray(commands)) { 36 | throw new TypeError('Commands must be an array'); 37 | }; 38 | 39 | /** 40 | * Debug logging function 41 | * @param {string} message - Message to log if debug is enabled 42 | */ 43 | const log = (message) => options.debug && console.log(`[discord-sync-commands] ${message}`); 44 | 45 | try { 46 | /** 47 | * Wait for client to be ready if not already ready 48 | */ 49 | const ready = client.isReady() ? Promise.resolve() : new Promise(resolve => client.once(Events.ClientReady, resolve)); 50 | await ready; 51 | 52 | 53 | /** 54 | * Fetch existing commands from Discord API 55 | * @type {Collection} 56 | */ 57 | const currentCommands = await client.application.commands 58 | .fetch(options.guildId ? { guildId: options.guildId } : {}) 59 | .catch(err => { 60 | if (err.code === RESTJSONErrorCodes.MissingAccess) { 61 | throw new Error('The client does not have the "applications.commands" scope authorized.'); 62 | } 63 | throw err; 64 | }); 65 | 66 | 67 | log(`Synchronizing commands...`); 68 | log(`Currently ${currentCommands.size} commands registered.`); 69 | 70 | /** 71 | * Find commands that need to be created (exist in local but not in Discord) 72 | * @type {Array} 73 | */ 74 | const newCommands = commands.filter((command) => !currentCommands.some((c) => c.name === command.name)); 75 | let createdCount = 0; 76 | 77 | for (const newCommand of newCommands) { 78 | try { 79 | await client.application.commands.create(newCommand, options.guildId); 80 | createdCount++; 81 | log(`Created command: ${newCommand.name}`); 82 | } catch (error) { 83 | log(`Error creating command ${newCommand.name}: ${error.message}`); 84 | } 85 | } 86 | 87 | log(`Created ${createdCount} new commands!`); 88 | 89 | /** 90 | * Find commands that need to be deleted (exist in Discord but not in local) 91 | * @type {Collection} 92 | */ 93 | const deletedCommands = currentCommands.filter((command) => !commands.some((c) => c.name === command.name)); 94 | let deletedCount = 0; 95 | 96 | for (const deletedCommand of deletedCommands.values()) { 97 | try { 98 | await deletedCommand.delete(); 99 | deletedCount++; 100 | log(`Deleted command: ${deletedCommand.name}`); 101 | } catch (error) { 102 | log(`Error deleting command ${deletedCommand.name}: ${error.message}`); 103 | } 104 | } 105 | 106 | log(`Deleted ${deletedCount} obsolete commands!`); 107 | 108 | /** 109 | * Find commands that need to be updated (exist in both but with differences) 110 | * @type {Array} 111 | */ 112 | const updatedCommands = commands.filter((command) => currentCommands.some((c) => c.name === command.name)); 113 | let updatedCommandCount = 0; 114 | 115 | for (const updatedCommand of updatedCommands) { 116 | try { 117 | const previousCommand = currentCommands.find((c) => c.name === updatedCommand.name); 118 | 119 | if (isCommandModified(previousCommand, updatedCommand)) { 120 | await previousCommand.edit(updatedCommand); 121 | updatedCommandCount++; 122 | log(`Updated command: ${updatedCommand.name}`); 123 | } 124 | } catch (error) { 125 | log(`Error updating command ${updatedCommand.name}: ${error.message}`); 126 | } 127 | } 128 | 129 | log(`Updated ${updatedCommandCount} commands!`); 130 | log(`Command synchronization completed successfully!`); 131 | 132 | return { 133 | currentCommandCount: currentCommands.size, 134 | newCommandCount: createdCount, 135 | deletedCommandCount: deletedCount, 136 | updatedCommandCount 137 | }; 138 | 139 | } catch (error) { 140 | log(`Error during command synchronization: ${error.message}`); 141 | throw error; 142 | } 143 | }; 144 | 145 | /** 146 | * Check if a command has been modified by comparing all relevant properties 147 | * @param {ApplicationCommand} previousCommand - The existing command from Discord 148 | * @param {Object} newCommand - The new command definition 149 | * @returns {boolean} True if the command needs to be updated 150 | */ 151 | function isCommandModified(previousCommand, newCommand) { 152 | if (previousCommand.description !== newCommand.description) return true; 153 | if (previousCommand.defaultMemberPermissions !== newCommand.defaultMemberPermissions) return true; 154 | if (previousCommand.nsfw !== newCommand.nsfw) return true; 155 | 156 | // Use Discord.js built-in optionsEqual method for more reliable comparison 157 | return !ApplicationCommand.optionsEqual(previousCommand.options ?? [], newCommand.options ?? []); 158 | } 159 | 160 | 161 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "discord.js": "^14.20.0" 4 | }, 5 | "name": "discord-sync-commands", 6 | "version": "0.5.2", 7 | "description": "Easily keep your bot's slash commands synchronized with Discord", 8 | "main": "index.js", 9 | "repository": "https://github.com/Androz2091/discord-sync-commands", 10 | "author": "Androz2091 ", 11 | "license": "MIT" 12 | } 13 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@discordjs/builders@^1.11.2": 6 | version "1.11.2" 7 | resolved "https://registry.npmjs.org/@discordjs/builders/-/builders-1.11.2.tgz" 8 | integrity sha512-F1WTABdd8/R9D1icJzajC4IuLyyS8f3rTOz66JsSI3pKvpCAtsMBweu8cyNYsIyvcrKAVn9EPK+Psoymq+XC0A== 9 | dependencies: 10 | "@discordjs/formatters" "^0.6.1" 11 | "@discordjs/util" "^1.1.1" 12 | "@sapphire/shapeshift" "^4.0.0" 13 | discord-api-types "^0.38.1" 14 | fast-deep-equal "^3.1.3" 15 | ts-mixer "^6.0.4" 16 | tslib "^2.6.3" 17 | 18 | "@discordjs/collection@^2.1.0": 19 | version "2.1.1" 20 | resolved "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz" 21 | integrity sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg== 22 | 23 | "@discordjs/collection@^2.1.1": 24 | version "2.1.1" 25 | resolved "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz" 26 | integrity sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg== 27 | 28 | "@discordjs/collection@1.5.3": 29 | version "1.5.3" 30 | resolved "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz" 31 | integrity sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ== 32 | 33 | "@discordjs/formatters@^0.6.1": 34 | version "0.6.1" 35 | resolved "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.1.tgz" 36 | integrity sha512-5cnX+tASiPCqCWtFcFslxBVUaCetB0thvM/JyavhbXInP1HJIEU+Qv/zMrnuwSsX3yWH2lVXNJZeDK3EiP4HHg== 37 | dependencies: 38 | discord-api-types "^0.38.1" 39 | 40 | "@discordjs/rest@^2.5.1": 41 | version "2.5.1" 42 | resolved "https://registry.npmjs.org/@discordjs/rest/-/rest-2.5.1.tgz" 43 | integrity sha512-Tg9840IneBcbrAjcGaQzHUJWFNq1MMWZjTdjJ0WS/89IffaNKc++iOvffucPxQTF/gviO9+9r8kEPea1X5J2Dw== 44 | dependencies: 45 | "@discordjs/collection" "^2.1.1" 46 | "@discordjs/util" "^1.1.1" 47 | "@sapphire/async-queue" "^1.5.3" 48 | "@sapphire/snowflake" "^3.5.3" 49 | "@vladfrangu/async_event_emitter" "^2.4.6" 50 | discord-api-types "^0.38.1" 51 | magic-bytes.js "^1.10.0" 52 | tslib "^2.6.3" 53 | undici "6.21.3" 54 | 55 | "@discordjs/util@^1.1.0", "@discordjs/util@^1.1.1": 56 | version "1.1.1" 57 | resolved "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz" 58 | integrity sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g== 59 | 60 | "@discordjs/ws@^1.2.3": 61 | version "1.2.3" 62 | resolved "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz" 63 | integrity sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw== 64 | dependencies: 65 | "@discordjs/collection" "^2.1.0" 66 | "@discordjs/rest" "^2.5.1" 67 | "@discordjs/util" "^1.1.0" 68 | "@sapphire/async-queue" "^1.5.2" 69 | "@types/ws" "^8.5.10" 70 | "@vladfrangu/async_event_emitter" "^2.2.4" 71 | discord-api-types "^0.38.1" 72 | tslib "^2.6.2" 73 | ws "^8.17.0" 74 | 75 | "@sapphire/async-queue@^1.5.2", "@sapphire/async-queue@^1.5.3": 76 | version "1.5.5" 77 | resolved "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz" 78 | integrity sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg== 79 | 80 | "@sapphire/shapeshift@^4.0.0": 81 | version "4.0.0" 82 | resolved "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz" 83 | integrity sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg== 84 | dependencies: 85 | fast-deep-equal "^3.1.3" 86 | lodash "^4.17.21" 87 | 88 | "@sapphire/snowflake@^3.5.3", "@sapphire/snowflake@3.5.3": 89 | version "3.5.3" 90 | resolved "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.3.tgz" 91 | integrity sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ== 92 | 93 | "@types/node@*": 94 | version "16.7.1" 95 | resolved "https://registry.npmjs.org/@types/node/-/node-16.7.1.tgz" 96 | integrity sha512-ncRdc45SoYJ2H4eWU9ReDfp3vtFqDYhjOsKlFFUDEn8V1Bgr2RjYal8YT5byfadWIRluhPFU6JiDOl0H6Sl87A== 97 | 98 | "@types/ws@^8.5.10": 99 | version "8.18.1" 100 | resolved "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz" 101 | integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== 102 | dependencies: 103 | "@types/node" "*" 104 | 105 | "@vladfrangu/async_event_emitter@^2.2.4", "@vladfrangu/async_event_emitter@^2.4.6": 106 | version "2.4.6" 107 | resolved "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz" 108 | integrity sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA== 109 | 110 | discord-api-types@^0.38.1: 111 | version "0.38.12" 112 | resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.12.tgz" 113 | integrity sha512-vqkRM50N5Zc6OVckAqtSslbUEoXmpN4bd9xq2jkoK9fgO3KNRIOyMMQ7ipqjwjKuAgzWvU6G8bRIcYWaUe1sCA== 114 | 115 | discord.js@^14.20.0: 116 | version "14.20.0" 117 | resolved "https://registry.npmjs.org/discord.js/-/discord.js-14.20.0.tgz" 118 | integrity sha512-5fRTptK2vpuz+bTuAEUQLSo/3AgCSLHl6Mm9+/ofb+8cbbnjWllhtaqRBq7XcpzlBnfNEugKv8HvCwcOtIHpCg== 119 | dependencies: 120 | "@discordjs/builders" "^1.11.2" 121 | "@discordjs/collection" "1.5.3" 122 | "@discordjs/formatters" "^0.6.1" 123 | "@discordjs/rest" "^2.5.1" 124 | "@discordjs/util" "^1.1.1" 125 | "@discordjs/ws" "^1.2.3" 126 | "@sapphire/snowflake" "3.5.3" 127 | discord-api-types "^0.38.1" 128 | fast-deep-equal "3.1.3" 129 | lodash.snakecase "4.1.1" 130 | magic-bytes.js "^1.10.0" 131 | tslib "^2.6.3" 132 | undici "6.21.3" 133 | 134 | fast-deep-equal@^3.1.3, fast-deep-equal@3.1.3: 135 | version "3.1.3" 136 | resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" 137 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 138 | 139 | lodash.snakecase@4.1.1: 140 | version "4.1.1" 141 | resolved "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz" 142 | integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw== 143 | 144 | lodash@^4.17.21: 145 | version "4.17.21" 146 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" 147 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 148 | 149 | magic-bytes.js@^1.10.0: 150 | version "1.12.1" 151 | resolved "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.12.1.tgz" 152 | integrity sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA== 153 | 154 | ts-mixer@^6.0.4: 155 | version "6.0.4" 156 | resolved "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz" 157 | integrity sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA== 158 | 159 | tslib@^2.6.2, tslib@^2.6.3: 160 | version "2.8.1" 161 | resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" 162 | integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== 163 | 164 | undici@6.21.3: 165 | version "6.21.3" 166 | resolved "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz" 167 | integrity sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw== 168 | 169 | ws@^8.17.0: 170 | version "8.18.2" 171 | resolved "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz" 172 | integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== 173 | --------------------------------------------------------------------------------