From 64561db99307c0a20ce77f2d015d4cecac45f09d Mon Sep 17 00:00:00 2001 From: Kline Gareth Date: Wed, 26 Jul 2023 08:25:30 -0400 Subject: [PATCH 1/5] Added where to find developer mode toggle, removed uneccessary steps for discordjs v14 --- README.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 852b802..0cb9925 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ $ npm install dotenv 4. Add bot to the A2Z server with the url: `https://discord.com/oauth2/authorize?client_id=YOUR_APPLICATION_ID&scope=bot` -5. Enable "Developer Mode" on your discord client, right-click the server icon, and "copy ID" for the server ID. +5. Enable "Developer Mode" under the "Advanced" settings tab on your discord client, right-click the server icon, and "copy ID" for the server ID. 6. Create a `.env` file with your CLIENTID, SERVERID, and BOTTOKEN: @@ -28,21 +28,15 @@ SERVERID=1234 TOKEN=1234 ``` -7. Install additional node packages. +7. Add slash commands permission. Go to your applicaiton page in the Discord developer portal, select "OAuth", check "application.commands", and open the URL that populates at the bottom. -``` -$ npm install @discordjs/builders @discordjs/rest discord-api-types -``` - -8. Add slash commands permission. Go to your applicaiton page in the Discord developer portal, select "OAuth", check "application.commands", and open the URL that populates at the bottom. - -9. Create `deploy-commands.js`, see example code for content. Customize your commands and execute! +8. Create `deploy-commands.js`, see example code for content. Customize your commands and execute! ``` $ node deploy-commands.js ``` -10. Create `bot.js`, see example code for content. Handle your commands and run the bot! +9. Create `bot.js`, see example code for content. Handle your commands and run the bot! ``` $ node bot.js From 0372ca6fbe2c3bb2448c4bec9d40ea161cf21c25 Mon Sep 17 00:00:00 2001 From: Kline Gareth Date: Sun, 10 Sep 2023 17:49:08 -0400 Subject: [PATCH 2/5] Updated examples to discord.js v14, added documentation --- 01-discordjs/{env-sample => .env-example} | 3 +- 01-discordjs/README.md | 101 +-- 01-discordjs/deploy-commands.js | 73 +- 01-discordjs/index.js | 56 +- 01-discordjs/package-lock.json | 654 +++++++++--------- 01-discordjs/package.json | 6 +- 02-command-handler/.env-example | 4 + 02-command-handler/.env-sample | 2 - 02-command-handler/README.md | 153 ++++ 02-command-handler/bot.js | 23 - 02-command-handler/commands.js | 21 - 02-command-handler/commands/choochoo.js | 12 - 02-command-handler/commands/fun/gif.js | 43 ++ 02-command-handler/commands/gif.js | 20 - .../commands/testing/choochoo.js | 18 + 02-command-handler/deploy-commands.js | 59 ++ 02-command-handler/index.js | 85 +++ 02-command-handler/package-lock.json | 400 ++++++++--- 02-command-handler/package.json | 6 +- README.md | 7 +- package-lock.json | 293 ++++++++ package.json | 6 + 22 files changed, 1386 insertions(+), 659 deletions(-) rename 01-discordjs/{env-sample => .env-example} (53%) create mode 100644 02-command-handler/.env-example delete mode 100644 02-command-handler/.env-sample create mode 100644 02-command-handler/README.md delete mode 100644 02-command-handler/bot.js delete mode 100644 02-command-handler/commands.js delete mode 100644 02-command-handler/commands/choochoo.js create mode 100644 02-command-handler/commands/fun/gif.js delete mode 100644 02-command-handler/commands/gif.js create mode 100644 02-command-handler/commands/testing/choochoo.js create mode 100644 02-command-handler/deploy-commands.js create mode 100644 02-command-handler/index.js create mode 100644 package-lock.json create mode 100644 package.json diff --git a/01-discordjs/env-sample b/01-discordjs/.env-example similarity index 53% rename from 01-discordjs/env-sample rename to 01-discordjs/.env-example index d3752e7..886b3d9 100644 --- a/01-discordjs/env-sample +++ b/01-discordjs/.env-example @@ -1,4 +1,3 @@ SERVERID=1234 CLIENTID=1234 -TOKEN=1234 -TENORKEY=1234 \ No newline at end of file +TOKEN=abcd1234 diff --git a/01-discordjs/README.md b/01-discordjs/README.md index b3d2e1c..77f2bb9 100644 --- a/01-discordjs/README.md +++ b/01-discordjs/README.md @@ -1,98 +1,65 @@ -# Choo Choo Discord Bot! +# Choo Choo Discord Bot! (Setting Up Your Bot) [Discord Bot Tutorial](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6avBYxeBSwF48YhAnSn_sA4) 🚂🌈💖🤖 All aboard! [Coding Train Tutorial Videos](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6avBYxeBSwF48YhAnSn_sA4) 🚂🌈💖🤖 -## Steps to create new bot +## Steps to create new bot -1. Create node project and install discord.js module. +1. Create node project and install discord.js and dotenv module. -``` +```bash $ npm init -$ npm install discord.js +$ npm install discord.js dotenv ``` -2. [Create an application](https://discord.com/developers/applications/) - optionally set name, description, avatar. - -3. Select Bot from left navigation and "Add Bot" - set name and icon. +3. [Create an application](https://discord.com/developers/applications/) - optionally set name, description, avatar. -4. Add bot to the A2Z server with the url: `https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot` +4. Select Bot from left navigation and "Add Bot" - set name and icon. -5. Write the code! +5. Add bot to the A2Z server with the url: `https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot` -Login to bot account: -```javascript -const Discord = require('discord.js'); -const client = new Discord.Client(); -client.login('YOUR BOT TOKEN'); -``` +6. Write the code! -Callback for when the bot is connected and ready: -```javascript -client.once('ready', () => { - console.log('Ready!'); -}); -``` +Load environment variables using `dotenv` and `.env`: -Callback for when a message is posted: -```javascript -client.on('message', gotMessage); +1. Create `.env` file: -function gotMessage(msg) { - console.log(msg.content); -} +```dotenv +CLIENTID=123456789 +SERVERID=123456789 +TOKEN=123456789 ``` -9. Run the bot! +2. Use `process.env` to access `.env` variables in your javascript: -``` -$ node index.js -``` +```javascript +const dotenv = require("dotenv"); +const TOKEN = process.env.TOKEN; -## Limit to one server and one channel +// We'll use these later when we deploy commands +const clientID = process.env.CLIENTID; +const serverID = process.env.SERVERID; +``` -1. Enable developer mode in Discord (Settings->Appearance->Enable Developer Mode). -2. Copy server ID. -3. Copy channel ID. +Login to bot account: ```javascript -const serverID = 'SERVER ID'; -const channelID = 'CHANNEL ID'; - -client.on('message', gotMessage); - -function gotMessage(msg) { - // Only for this server and this channel - if (msg.guild.id === serverID && msg.channel.id === channelID) { - // Reply to the message ping! - if (msg.content === 'ping') { - msg.channel.send('pong'); - } - } -} +const { Client, Events, GatewayIntentBits } = require("discord.js"); +const client = new Client({ intents: [GatewayIntentBits.Guilds] }); +client.login(TOKEN); ``` -## Store token and other secrets in .env file. +Callback for when the bot is connected and ready: -1. Install [dotenv package](https://www.npmjs.com/package/dotenv). -``` -$ npm install dotenv +```javascript +client.once(Events.ClientReady, () => { + console.log("Ready!"); +}); ``` -2. Create `.env` file: +9. Run the bot! ``` -SERVERID=123456789 -CHANNELID=123456789 -TOKEN=123456789 -``` - -3. Load environment variables using `dotenv` and `.env`: - -```javascript -require('dotenv').config(); -const serverID = process.env.SERVERID; -const channelID = process.env.CHANNELID; -const TOKEN = process.env.TOKEN; +$ node index.js ``` diff --git a/01-discordjs/deploy-commands.js b/01-discordjs/deploy-commands.js index 6ffaf8c..82e1ab2 100644 --- a/01-discordjs/deploy-commands.js +++ b/01-discordjs/deploy-commands.js @@ -1,25 +1,56 @@ -require('dotenv').config(); +// Slash Commands Deployment Script +// https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands/ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { REST } = require('@discordjs/rest'); -const { Routes } = require('discord-api-types/v9'); +const { REST, Routes } = require("discord.js"); +require("dotenv").config(); +const fs = require("node:fs"); +const path = require("node:path"); -// Note to self: define options for command arguments -const commands = [ - new SlashCommandBuilder().setName('choochoo').setDescription('Replies with a random message!'), - new SlashCommandBuilder() - .setName('gif') - .setDescription('Replies with a gif!') - .addStringOption((option) => - option.setName('keywords').setDescription('The gif to search for').setRequired(false) - ), -].map((command) => command.toJSON()); +const commands = []; -const rest = new REST({ version: '9' }).setToken(process.env.TOKEN); +// Grab all the command files from the commands directory +const foldersPath = path.join(__dirname, "commands"); +const commandFolders = fs.readdirSync(foldersPath); -rest - .put(Routes.applicationGuildCommands(process.env.CLIENTID, process.env.SERVERID), { - body: commands, - }) - .then(() => console.log('Successfully registered application commands.')) - .catch(console.error); +for (const folder of commandFolders) { + // Grab all the command files from the commands directory you created earlier + const commandsPath = path.join(foldersPath, folder); + const commandFiles = fs + .readdirSync(commandsPath) + .filter((file) => file.endsWith(".js")); + // Grab the SlashCommandBuilder#toJSON() output of each commands's data for deployment + for (const file of commandFiles) { + const filePath = path.join(commandsPath, file); + const command = require(filePath); + if ("data" in command && "execute" in command) { + commands.push(command.data.toJSON()); + } else { + console.log( + `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property` + ); + } + } +} + +// Construct and prepare an insance of the REST module +const rest = new REST().setToken(token); + +// and deploy your commands! +async () => { + try { + console.log( + `Started refreshing ${commands.length} application (/) commands.` + ); + // The put method is used to fully refresh all commands in the guild with the current set + const data = await rest.put( + Routes.applicationGuildCommands( + process.env.CLIENTID, + process.env.SERVERID + ), + { body: commands } + ); + } catch (error) { + // And of course, make sure you catch and log any errors! + console.error(error); + } +}; diff --git a/01-discordjs/index.js b/01-discordjs/index.js index f1d540a..8d05f4d 100644 --- a/01-discordjs/index.js +++ b/01-discordjs/index.js @@ -4,58 +4,24 @@ // https://thecodingtrain.com/learning/bots/discord/03-discordjs.html // https://youtu.be/8k-zyUyuvlM -require('dotenv').config(); +// Setup dotenv and tell it to look for `.env` in the same folder as our main file +const dotenv = require("dotenv"); +dotenv.config(); -const fetch = require('node-fetch'); - -console.log('Beep beep! 🤖'); +console.log("Beep beep! 🤖"); // Require the necessary discord.js classes -const { Client, Intents } = require('discord.js'); +const { Client, Events, GatewayIntentBits } = require("discord.js"); // Create a new client instance -const client = new Client({ intents: [Intents.FLAGS.GUILDS] }); - -// Login to Discord with your client's token -client.login(process.env.TOKEN); - -// When the client is ready, run this code (only once) -client.once('ready', readyDiscord); +const client = new Client({ intents: [GatewayIntentBits.Guilds] }); function readyDiscord() { - // require('./deploy-commands'); - console.log('💖'); + console.log("💖"); } -const replies = ['🚂🌈💖', 'Choo choo!', 'Ding! 🛎', 'Never forget this dot!']; - -client.on('interactionCreate', async (interaction) => { - if (!interaction.isCommand()) return; - - const { commandName, user, options } = interaction; - console.log(commandName, user.username); - - if (commandName === 'choochoo') { - const index = Math.floor(Math.random() * replies.length); - await interaction.reply({ - content: replies[index], - // ephemeral: true, - }); - } else if (commandName === 'gif') { - let keywords = options.getString('keywords') || 'coding train'; - - // Avoiding the 3 second issue? - await interaction.deferReply(); - let url = `https://api.tenor.com/v1/search?q=${keywords}&key=${process.env.TENORKEY}&contentfilter=high`; - let response = await fetch(url); - let json = await response.json(); - const index = Math.floor(Math.random() * json.results.length); - - await interaction.editReply({ - content: `GIF from Tenor: ${keywords}\n${json.results[index].url}`, - }); +// When the client is ready, run this code (only once) +client.once(Events.ClientReady, readyDiscord); - // NOTE TO SELF: look at embeds - // https://discordjs.guide/popular-topics/embeds.html#embed-preview - } -}); +// Login to Discord with your client's token +client.login(process.env.TOKEN); diff --git a/01-discordjs/package-lock.json b/01-discordjs/package-lock.json index 582d379..6664898 100644 --- a/01-discordjs/package-lock.json +++ b/01-discordjs/package-lock.json @@ -1,7 +1,7 @@ { "name": "discord-bot-a2z", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -12,15 +12,18 @@ "@discordjs/builders": "^0.6.0", "@discordjs/rest": "^0.1.0-canary.0", "discord-api-types": "^0.23.1", - "discord.js": "^13.2.0", - "dotenv": "^10.0.0", "node-fetch": "^2.6.5" + }, + "devDependencies": { + "discord.js": "^14.13.0", + "dotenv": "^16.3.1" } }, "node_modules/@discordjs/builders": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz", "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==", + "deprecated": "no longer supported", "dependencies": { "@sindresorhus/is": "^4.0.1", "discord-api-types": "^0.22.0", @@ -37,6 +40,7 @@ "version": "0.22.0", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==", + "deprecated": "No longer supported. Install the latest release!", "engines": { "node": ">=12" } @@ -44,25 +48,32 @@ "node_modules/@discordjs/collection": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", - "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" - }, - "node_modules/@discordjs/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", + "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==", + "deprecated": "no longer supported" + }, + "node_modules/@discordjs/formatters": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz", + "integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==", + "dev": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "discord-api-types": "0.37.50" }, "engines": { - "node": ">= 6" + "node": ">=16.11.0" } }, + "node_modules/@discordjs/formatters/node_modules/discord-api-types": { + "version": "0.37.50", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", + "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", + "dev": true + }, "node_modules/@discordjs/rest": { "version": "0.1.0-canary.0", "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-0.1.0-canary.0.tgz", "integrity": "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ==", + "deprecated": "no longer supported", "dependencies": { "@discordjs/collection": "^0.1.6", "@sapphire/async-queue": "^1.1.4", @@ -86,13 +97,101 @@ "node": ">=12" } }, + "node_modules/@discordjs/util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", + "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==", + "dev": true, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz", + "integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==", + "dev": true, + "dependencies": { + "@discordjs/collection": "^1.5.3", + "@discordjs/rest": "^2.0.1", + "@discordjs/util": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@types/ws": "^8.5.5", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.50", + "tslib": "^2.6.1", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "dev": true, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/rest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", + "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", + "dev": true, + "dependencies": { + "@discordjs/collection": "^1.5.3", + "@discordjs/util": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.50", + "magic-bytes.js": "^1.0.15", + "tslib": "^2.6.1", + "undici": "5.22.1" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws/node_modules/@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@discordjs/ws/node_modules/discord-api-types": { + "version": "0.37.50", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", + "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", + "dev": true + }, "node_modules/@sapphire/async-queue": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.6.tgz", - "integrity": "sha512-M5CbgMgesemMUCQo5G/InGHvp+GZx6uuJNV1iwvSWD8EFNVrfxaTcqhcAXM3MPYkjlxvNnoDNk0R1lfzvca6LA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", + "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, "engines": { - "node": ">=v14.18.0", - "npm": ">=7.24.2" + "node": ">=v14.0.0", + "npm": ">=7.0.0" } }, "node_modules/@sapphire/snowflake": { @@ -106,9 +205,9 @@ } }, "node_modules/@sindresorhus/is": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", - "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "engines": { "node": ">=10" }, @@ -117,18 +216,30 @@ } }, "node_modules/@types/node": { - "version": "16.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.4.tgz", - "integrity": "sha512-EITwVTX5B4nDjXjGeQAfXOrm+Jn+qNjDmyDRtWoD+wZsl/RDPRTFRKivs4Mt74iOFlLOrE5+Kf+p5yjyhm3+cA==" + "version": "20.5.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", + "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==", + "dev": true }, "node_modules/@types/ws": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", - "integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dev": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", + "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -143,7 +254,19 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } }, "node_modules/callsites": { "version": "3.1.0", @@ -167,7 +290,7 @@ "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "engines": { "node": ">=0.4.0" } @@ -176,37 +299,99 @@ "version": "0.23.1", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.23.1.tgz", "integrity": "sha512-igWmn+45mzXRWNEPU25I/pr8MwxHb767wAr51oy3VRLRcTlp5ADBbrBR0lq3SA1Rfw3MtM4TQu1xo3kxscfVdQ==", + "deprecated": "No longer supported. Install the latest release!", "engines": { "node": ">=12" } }, "node_modules/discord.js": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.2.0.tgz", - "integrity": "sha512-nyxUvL8wuQG38zx13wUMkpcA8koFszyiXdkSLwwM9opKW2LC2H5gD0cTZxImeJ6GtEnKPWT8xBiE8lLBmbNIhw==", + "version": "14.13.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz", + "integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==", + "dev": true, "dependencies": { - "@discordjs/builders": "^0.6.0", - "@discordjs/collection": "^0.2.1", - "@discordjs/form-data": "^3.0.1", - "@sapphire/async-queue": "^1.1.5", - "@types/ws": "^8.2.0", - "discord-api-types": "^0.23.1", - "node-fetch": "^2.6.1", - "ws": "^8.2.3" + "@discordjs/builders": "^1.6.5", + "@discordjs/collection": "^1.5.3", + "@discordjs/formatters": "^0.3.2", + "@discordjs/rest": "^2.0.1", + "@discordjs/util": "^1.0.1", + "@discordjs/ws": "^1.0.1", + "@sapphire/snowflake": "^3.5.1", + "@types/ws": "^8.5.5", + "discord-api-types": "0.37.50", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.6.1", + "undici": "5.22.1", + "ws": "^8.13.0" }, "engines": { - "node": ">=16.6.0", - "npm": ">=7.0.0" + "node": ">=16.11.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/builders": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", + "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", + "dev": true, + "dependencies": { + "@discordjs/formatters": "^0.3.2", + "@discordjs/util": "^1.0.1", + "@sapphire/shapeshift": "^3.9.2", + "discord-api-types": "0.37.50", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.1" + }, + "engines": { + "node": ">=16.11.0" } }, "node_modules/discord.js/node_modules/@discordjs/collection": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.1.tgz", - "integrity": "sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "dev": true, "engines": { - "node": ">=14.0.0" + "node": ">=16.11.0" } }, + "node_modules/discord.js/node_modules/@discordjs/rest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", + "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", + "dev": true, + "dependencies": { + "@discordjs/collection": "^1.5.3", + "@discordjs/util": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.50", + "magic-bytes.js": "^1.0.15", + "tslib": "^2.6.1", + "undici": "5.22.1" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/discord.js/node_modules/@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/discord.js/node_modules/discord-api-types": { + "version": "0.37.50", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", + "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", + "dev": true + }, "node_modules/dot-prop": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", @@ -222,11 +407,15 @@ } }, "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, "node_modules/event-target-shim": { @@ -237,6 +426,12 @@ "node": ">=6" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -258,39 +453,65 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "node_modules/magic-bytes.js": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz", + "integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==", + "dev": true }, "node_modules/mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.50.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/node-fetch": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", - "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dependencies": { "whatwg-url": "^5.0.0" }, "engines": { "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/ow": { @@ -312,20 +533,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/ts-mixer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", - "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", + "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" }, "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" }, "node_modules/type-fest": { "version": "1.4.0", @@ -338,10 +568,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/undici": { + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/vali-date": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", - "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", + "integrity": "sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg==", "engines": { "node": ">=0.10.0" } @@ -349,27 +591,28 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.0.tgz", + "integrity": "sha512-WR0RJE9Ehsio6U4TuM+LmunEsjQ5ncHlw4sn9ihD6RoJKZrVyH9FWV3dmnwu8B2aNib1OvG2X6adUCyFpQyWcg==", + "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -380,266 +623,5 @@ } } } - }, - "dependencies": { - "@discordjs/builders": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz", - "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==", - "requires": { - "@sindresorhus/is": "^4.0.1", - "discord-api-types": "^0.22.0", - "ow": "^0.27.0", - "ts-mixer": "^6.0.0", - "tslib": "^2.3.1" - }, - "dependencies": { - "discord-api-types": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", - "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==" - } - } - }, - "@discordjs/collection": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", - "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" - }, - "@discordjs/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "@discordjs/rest": { - "version": "0.1.0-canary.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-0.1.0-canary.0.tgz", - "integrity": "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ==", - "requires": { - "@discordjs/collection": "^0.1.6", - "@sapphire/async-queue": "^1.1.4", - "@sapphire/snowflake": "^1.3.5", - "abort-controller": "^3.0.0", - "discord-api-types": "^0.18.1", - "form-data": "^4.0.0", - "node-fetch": "^2.6.1", - "tslib": "^2.3.0" - }, - "dependencies": { - "discord-api-types": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.18.1.tgz", - "integrity": "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg==" - } - } - }, - "@sapphire/async-queue": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.6.tgz", - "integrity": "sha512-M5CbgMgesemMUCQo5G/InGHvp+GZx6uuJNV1iwvSWD8EFNVrfxaTcqhcAXM3MPYkjlxvNnoDNk0R1lfzvca6LA==" - }, - "@sapphire/snowflake": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-1.3.6.tgz", - "integrity": "sha512-QnzuLp+p9D7agynVub/zqlDVriDza9y3STArBhNiNBUgIX8+GL5FpQxstRfw1jDr5jkZUjcuKYAHxjIuXKdJAg==" - }, - "@sindresorhus/is": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", - "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==" - }, - "@types/node": { - "version": "16.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.4.tgz", - "integrity": "sha512-EITwVTX5B4nDjXjGeQAfXOrm+Jn+qNjDmyDRtWoD+wZsl/RDPRTFRKivs4Mt74iOFlLOrE5+Kf+p5yjyhm3+cA==" - }, - "@types/ws": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", - "integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", - "requires": { - "@types/node": "*" - } - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "discord-api-types": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.23.1.tgz", - "integrity": "sha512-igWmn+45mzXRWNEPU25I/pr8MwxHb767wAr51oy3VRLRcTlp5ADBbrBR0lq3SA1Rfw3MtM4TQu1xo3kxscfVdQ==" - }, - "discord.js": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.2.0.tgz", - "integrity": "sha512-nyxUvL8wuQG38zx13wUMkpcA8koFszyiXdkSLwwM9opKW2LC2H5gD0cTZxImeJ6GtEnKPWT8xBiE8lLBmbNIhw==", - "requires": { - "@discordjs/builders": "^0.6.0", - "@discordjs/collection": "^0.2.1", - "@discordjs/form-data": "^3.0.1", - "@sapphire/async-queue": "^1.1.5", - "@types/ws": "^8.2.0", - "discord-api-types": "^0.23.1", - "node-fetch": "^2.6.1", - "ws": "^8.2.3" - }, - "dependencies": { - "@discordjs/collection": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.1.tgz", - "integrity": "sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog==" - } - } - }, - "dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" - }, - "mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==" - }, - "mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", - "requires": { - "mime-db": "1.50.0" - } - }, - "node-fetch": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", - "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "ow": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", - "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", - "requires": { - "@sindresorhus/is": "^4.0.1", - "callsites": "^3.1.0", - "dot-prop": "^6.0.1", - "lodash.isequal": "^4.5.0", - "type-fest": "^1.2.1", - "vali-date": "^1.0.0" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "ts-mixer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", - "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" - }, - "vali-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", - "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "requires": {} - } } } diff --git a/01-discordjs/package.json b/01-discordjs/package.json index 27a4ad8..29c509b 100644 --- a/01-discordjs/package.json +++ b/01-discordjs/package.json @@ -20,8 +20,10 @@ "@discordjs/builders": "^0.6.0", "@discordjs/rest": "^0.1.0-canary.0", "discord-api-types": "^0.23.1", - "discord.js": "^13.2.0", - "dotenv": "^10.0.0", "node-fetch": "^2.6.5" + }, + "devDependencies": { + "discord.js": "^14.13.0", + "dotenv": "^16.3.1" } } diff --git a/02-command-handler/.env-example b/02-command-handler/.env-example new file mode 100644 index 0000000..742d419 --- /dev/null +++ b/02-command-handler/.env-example @@ -0,0 +1,4 @@ +SERVERID=1234 +CLIENTID=1234 +TOKEN=abcd1234 +TENORKEY=abcd1234 diff --git a/02-command-handler/.env-sample b/02-command-handler/.env-sample deleted file mode 100644 index 7dd93eb..0000000 --- a/02-command-handler/.env-sample +++ /dev/null @@ -1,2 +0,0 @@ -BOTTOKEN=0123456789 -TENORKEY=0123456789 \ No newline at end of file diff --git a/02-command-handler/README.md b/02-command-handler/README.md new file mode 100644 index 0000000..8a5ec53 --- /dev/null +++ b/02-command-handler/README.md @@ -0,0 +1,153 @@ +# Choo Choo Discord Bot! (Deploying Commands) + +[Discord Bot Tutorial](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6avBYxeBSwF48YhAnSn_sA4) + +🚂🌈💖🤖 All aboard! [Coding Train Tutorial Videos](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6avBYxeBSwF48YhAnSn_sA4) 🚂🌈💖🤖 + +Once you've set up your bot, it's time to add commands! + +## Organizing command folders + +1. Create a folder named `commands`. This is where we'll put all of our command files. +2. discord.js recommends you organize commands in topic folders under your `commands` folder. Inside your `commands` folder, add a folder called `testing`. + +## Writing a command + +1. In `testing`, let's add our first command file! This command will just send a random phrase to the user whenever it gets called. In this example the file is called `choochoo.js`, but you can call it whatever you want! +2. Import the `SlashCommandBuilder` class and make a list of phrases the bot should say: + +```javascript +const { SlashCommandBuilder } = require("discord.js"); +const replies = ["🚂🌈💖", "Choo choo!", "Ding! 🛎", "Never forget this dot!"]; +``` + +3. Set command options and write an `execute()` function: + +```javascript +// We're putting this all inside `module.exports` so our command handler will be able to import our command later +module.exports = { + data: new SlashCommandBuilder() + .setName("choochoo") + .setDescription("Replies with a random phrase!"), + async execute(interaction) { + const index = Math.floor(Math.random() * replies.length); + await interaction.reply(replies[index]); + }, +}; +``` + +## Writing the command handler + +Now our main bot file needs to import our command files. + +1. In your `index.js`, add a command collection and set your command folder: + +```javascript +client.commands = new Collection(); +const foldersPath = path.join(__dirname, "commands"); +const commandFolders = fs.readdirSync(foldersPath); +``` + +2. Add a nested `for` loop to iterate over command folders and import your commands, logging to the console if the command has an error: + +```javascript +for (const folder of commandFolders) { + // Grab all the command files from the commands directory you created earlier + const commandFolder = path.join(commandsPath, folder); + const commandFiles = fs + .readdirSync(commandFolder) + .filter((file) => file.endsWith(".js")); + for (const file of commandFiles) { + const filePath = path.join(commandFolder, file); + const command = require(filePath); + // Set a new item in the Collection with the key as the command name and the value as the exported module + if ("data" in command && "execute" in command) { + client.commands.set(command.data.name, command); + } else { + console.log( + `[WARNING] The command at ${filePath} is missing a required "data" or execute property.` + ); + } + } +} +``` + +## Registering commands + +1. Create a file in the root of your project called `deploy-commands.js` +2. Copy the deployment script from the discord.js [guide](https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands) +3. Replace... + +```javascript +const { clientId, guildId, token } = require("./config.json"); +``` + +...with... + +```javascript +require("dotenv").config(); +``` + +4. And replace... + +```javascript +Routes.applicationGuildCommands(clientId, guildId), +``` + +...with.... + +```javascript +Routes.applicationGuildCommands( + process.env.CLIENTID, + process.env.SERVERID +), +``` + +5. Run the deployment script! + +```bash +$ node deploy-commands.js +``` + +## Executing commands + +1. Back in `index.js`, let's add a callback that will execute a command whenever it's called by the user. + +```javascript +client.on(Events.InteractionCreate, async (interaction) => { + // Ignore interaction if it isn't a slash command + if (!interaction.isChatInputCommand()) return; + console.log(interaction.client.commands); + + const command = interaction.client.commands.get(interaction.commandName); + if (!command) { + console.error(`No command matching ${interaction.commandName} was found.`); + return; + } + + // Execute the command and send a followup if the command fails + try { + await command.execute(interaction); + } catch (error) { + console.error(error); + if (interaction.replied || interaction.deferred) { + await interaction.followUp({ + content: "There was an error while executing this command!", + ephemeral: true, + }); + } else { + await interaction.reply({ + content: "There was an error while executing this command!", + ephemeral: true, + }); + } + } + console.log(interaction); +}); +``` + +2. Run the bot! + +```bash +$ node index.js +``` diff --git a/02-command-handler/bot.js b/02-command-handler/bot.js deleted file mode 100644 index 19eda46..0000000 --- a/02-command-handler/bot.js +++ /dev/null @@ -1,23 +0,0 @@ -// Command Handler -// Discord Bots -// The Coding Train / Daniel Shiffman -// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html -// https://youtu.be/B60Q74FHFBQ - -console.log('Beep beep! 🤖'); - -require('dotenv').config(); - -const Discord = require('discord.js'); -const client = new Discord.Client(); -client.login(process.env.BOTTOKEN); - -client.on('ready', readyDiscord); - -function readyDiscord() { - console.log('💖'); -} - -const commandHandler = require('./commands'); - -client.on('message', commandHandler); diff --git a/02-command-handler/commands.js b/02-command-handler/commands.js deleted file mode 100644 index 30fb9db..0000000 --- a/02-command-handler/commands.js +++ /dev/null @@ -1,21 +0,0 @@ -// Command Handler -// Discord Bots -// The Coding Train / Daniel Shiffman -// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html -// https://youtu.be/B60Q74FHFBQ - -const gif = require('./commands/gif.js'); -const choochoo = require('./commands/choochoo.js'); - -const commands = { choochoo, gif }; - -module.exports = async function(msg) { - if (msg.channel.id == '715786219770085396') { - let tokens = msg.content.split(' '); - let command = tokens.shift(); - if (command.charAt(0) === '!') { - command = command.substring(1); - commands[command](msg, tokens); - } - } -}; diff --git a/02-command-handler/commands/choochoo.js b/02-command-handler/commands/choochoo.js deleted file mode 100644 index 1c610b7..0000000 --- a/02-command-handler/commands/choochoo.js +++ /dev/null @@ -1,12 +0,0 @@ -// Command Handler -// Discord Bots -// The Coding Train / Daniel Shiffman -// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html -// https://youtu.be/B60Q74FHFBQ - -const replies = ['🚂🌈💖', 'Choo choo!', 'Ding! 🛎', 'Never forget this dot!']; - -module.exports = function(msg, args) { - const index = Math.floor(Math.random() * replies.length); - msg.channel.send(replies[index]); -}; diff --git a/02-command-handler/commands/fun/gif.js b/02-command-handler/commands/fun/gif.js new file mode 100644 index 0000000..8cff666 --- /dev/null +++ b/02-command-handler/commands/fun/gif.js @@ -0,0 +1,43 @@ +// Command Handler +// Discord Bots +// The Coding Train / Daniel Shiffman +// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html +// https://youtu.be/B60Q74FHFBQ -- Outdated! + +const fetch = require("node-fetch"); +const { + SlashCommandBuilder, + AttachmentBuilder, + EmbedBuilder, +} = require("discord.js"); + +module.exports = { + data: new SlashCommandBuilder() + .setName("gif") + .setDescription("Searches Tenor for gifs!") + .addStringOption((option) => + option + .setName("keywords") + .setDescription("The keywords to search Tenor with") + ), + async execute(interaction) { + let defaultKeyword = "coding train"; + const keywords = + interaction.options.getString("keywords") ?? defaultKeyword; + let url = `https://tenor.googleapis.com/v2/search?q=${keywords}&key=${process.env.TENORKEY}&client_key=a2z_discord_bot&contentfilter=high`; + let response = await fetch(url); + let json = await response.json(); + console.log(json); + console.log(json.results[0].media_formats); + const index = Math.floor(Math.random() * json.results.length); + const embed = new EmbedBuilder().setImage( + json.results[index].media_formats.gif.url + ); + await interaction.deferReply({ ephemeral: true }); + await interaction.followUp({ + embeds: [embed], + content: "GIF from Tenor:" + keywords, + ephemeral: true, + }); + }, +}; diff --git a/02-command-handler/commands/gif.js b/02-command-handler/commands/gif.js deleted file mode 100644 index 66299e0..0000000 --- a/02-command-handler/commands/gif.js +++ /dev/null @@ -1,20 +0,0 @@ -// Command Handler -// Discord Bots -// The Coding Train / Daniel Shiffman -// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html -// https://youtu.be/B60Q74FHFBQ - -const fetch = require('node-fetch'); - -module.exports = async function(msg, args) { - let keywords = 'coding train'; - if (args.length > 0) { - keywords = args.join(' '); - } - let url = `https://api.tenor.com/v1/search?q=${keywords}&key=${process.env.TENORKEY}&contentfilter=high`; - let response = await fetch(url); - let json = await response.json(); - const index = Math.floor(Math.random() * json.results.length); - msg.channel.send(json.results[index].url); - msg.channel.send('GIF from Tenor: ' + keywords); -}; diff --git a/02-command-handler/commands/testing/choochoo.js b/02-command-handler/commands/testing/choochoo.js new file mode 100644 index 0000000..fc18f04 --- /dev/null +++ b/02-command-handler/commands/testing/choochoo.js @@ -0,0 +1,18 @@ +// Command Handler +// Discord Bots +// The Coding Train / Daniel Shiffman +// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html +// https://youtu.be/B60Q74FHFBQ + +const { SlashCommandBuilder } = require("discord.js"); +const replies = ["🚂🌈💖", "Choo choo!", "Ding! 🛎", "Never forget this dot!"]; + +module.exports = { + data: new SlashCommandBuilder() + .setName("choochoo") + .setDescription("Replies with a random phrase!"), + async execute(interaction) { + const index = Math.floor(Math.random() * replies.length); + await interaction.reply(replies[index]); + }, +}; diff --git a/02-command-handler/deploy-commands.js b/02-command-handler/deploy-commands.js new file mode 100644 index 0000000..a8202fa --- /dev/null +++ b/02-command-handler/deploy-commands.js @@ -0,0 +1,59 @@ +// Slash Commands Deployment Script +// https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands/ + +const { REST, Routes } = require("discord.js"); +require("dotenv").config(); +const fs = require("node:fs"); +const path = require("node:path"); + +const commands = []; + +// Grab all the command files from the commands directory +const foldersPath = path.join(__dirname, "commands"); +const commandFolders = fs.readdirSync(foldersPath); + +for (const folder of commandFolders) { + // Grab all the command files from the commands directory you created earlier + const commandsPath = path.join(foldersPath, folder); + const commandFiles = fs + .readdirSync(commandsPath) + .filter((file) => file.endsWith(".js")); + // Grab the SlashCommandBuilder#toJSON() output of each commands's data for deployment + for (const file of commandFiles) { + const filePath = path.join(commandsPath, file); + const command = require(filePath); + if ("data" in command && "execute" in command) { + commands.push(command.data.toJSON()); + } else { + console.log( + `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property` + ); + } + } +} + +// Construct and prepare an insance of the REST module +const rest = new REST().setToken(process.env.CLIENTSECRET); + +// and deploy your commands! +(async () => { + try { + console.log( + `Started refreshing ${commands.length} application (/) commands.` + ); + // The put method is used to fully refresh all commands in the guild with the current set + const data = await rest.put( + Routes.applicationGuildCommands( + process.env.CLIENTID, + process.env.SERVERID + ), + { body: commands } + ); + console.log( + `Successfully reloaded ${data.length} application (/) commands.` + ); + } catch (error) { + // And of course, make sure you catch and log any errors! + console.error(error); + } +})() diff --git a/02-command-handler/index.js b/02-command-handler/index.js new file mode 100644 index 0000000..7b5a2b7 --- /dev/null +++ b/02-command-handler/index.js @@ -0,0 +1,85 @@ +// Command Handler +// Discord Bots +// The Coding Train / Daniel Shiffman +// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html +// https://youtu.be/B60Q74FHFBQ + +console.log("Beep beep! 🤖"); + +// Setup dotenv and tell it to look for `.env` in the same folder as our main file +const dotenv = require("dotenv"); +dotenv.config({ path: "./.env" }); + +const fs = require("node:fs"); +const path = require("node:path"); + +const { Client, Collection, Events, GatewayIntentBits } = require("discord.js"); +const client = new Client({ intents: [GatewayIntentBits.Guilds] }); +const token = process.env.TOKEN; +client.login(token); + +client.on("ready", readyDiscord); + +function readyDiscord() { + console.log("💖"); +} + +// Create a new Collection to hold our slash commands +client.commands = new Collection(); + +// Read the slash commands from the `commands` directory +const commandsPath = path.join(__dirname, "commands"); +console.log(commandsPath); +const commandFolders = fs.readdirSync(commandsPath); + +// Add slash commands to the client +for (const folder of commandFolders) { + // Grab all the command files from the commands directory you created earlier + const commandFolder = path.join(commandsPath, folder); + const commandFiles = fs + .readdirSync(commandFolder) + .filter((file) => file.endsWith(".js")); + for (const file of commandFiles) { + const filePath = path.join(commandFolder, file); + const command = require(filePath); + // Set a new item in the Collection with the key as the command name and the value as the exported module + if ("data" in command && "execute" in command) { + client.commands.set(command.data.name, command); + } else { + console.log( + `[WARNING] The command at ${filePath} is missing a required "data" or execute property.` + ); + } + } +} + +client.on(Events.InteractionCreate, async (interaction) => { + // Ignore interaction if it isn't a slash command + if (!interaction.isChatInputCommand()) return; + console.log(interaction.client.commands); + + const command = interaction.client.commands.get(interaction.commandName); + if (!command) { + console.error(`No command matching ${interaction.commandName} was found.`); + return; + } + + // Execute the command and send a followup if the command fails + try { + await command.execute(interaction); + } catch (error) { + console.error(error); + if (interaction.replied || interaction.deferred) { + await interaction.followUp({ + content: "There was an error while executing this command!", + ephemeral: true, + }); + } else { + await interaction.reply({ + content: "There was an error while executing this command!", + ephemeral: true, + }); + } + } + console.log(interaction); +}); diff --git a/02-command-handler/package-lock.json b/02-command-handler/package-lock.json index 6a19439..fe8e2b7 100644 --- a/02-command-handler/package-lock.json +++ b/02-command-handler/package-lock.json @@ -1,112 +1,308 @@ { "name": "choochoobot", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@discordjs/collection": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", - "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" - }, - "@discordjs/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "delayed-stream": { + "packages": { + "": { + "name": "choochoobot", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "discord.js": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.3.1.tgz", - "integrity": "sha512-mSFyV/mbvzH12UXdS4zadmeUf8IMQOo/YdunubG1wWt1xjWvtaJz/s9CGsFD2B5pTw1W/LXxxUbrQjIZ/xlUdw==", - "requires": { - "@discordjs/collection": "^0.1.6", - "@discordjs/form-data": "^3.0.1", - "abort-controller": "^3.0.0", - "node-fetch": "^2.6.0", - "prism-media": "^1.2.2", - "setimmediate": "^1.0.5", - "tweetnacl": "^1.0.3", - "ws": "^7.3.1" - } - }, - "dotenv": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", - "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "requires": { - "mime-db": "1.44.0" - } - }, - "node-fetch": { + "license": "ISC", + "dependencies": { + "node-fetch": "^2.6.1" + }, + "devDependencies": { + "discord.js": "^14.13.0", + "dotenv": "^16.3.1" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", + "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", + "dev": true, + "dependencies": { + "@discordjs/formatters": "^0.3.2", + "@discordjs/util": "^1.0.1", + "@sapphire/shapeshift": "^3.9.2", + "discord-api-types": "0.37.50", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.1" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "dev": true, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz", + "integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==", + "dev": true, + "dependencies": { + "discord-api-types": "0.37.50" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", + "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", + "dev": true, + "dependencies": { + "@discordjs/collection": "^1.5.3", + "@discordjs/util": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.50", + "magic-bytes.js": "^1.0.15", + "tslib": "^2.6.1", + "undici": "5.22.1" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", + "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==", + "dev": true, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz", + "integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==", + "dev": true, + "dependencies": { + "@discordjs/collection": "^1.5.3", + "@discordjs/rest": "^2.0.1", + "@discordjs/util": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@types/ws": "^8.5.5", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.50", + "tslib": "^2.6.1", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", + "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@types/node": { + "version": "20.5.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.6.tgz", + "integrity": "sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", + "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/discord-api-types": { + "version": "0.37.50", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", + "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", + "dev": true + }, + "node_modules/discord.js": { + "version": "14.13.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz", + "integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==", + "dev": true, + "dependencies": { + "@discordjs/builders": "^1.6.5", + "@discordjs/collection": "^1.5.3", + "@discordjs/formatters": "^0.3.2", + "@discordjs/rest": "^2.0.1", + "@discordjs/util": "^1.0.1", + "@discordjs/ws": "^1.0.1", + "@sapphire/snowflake": "^3.5.1", + "@types/ws": "^8.5.5", + "discord-api-types": "0.37.50", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.6.1", + "undici": "5.22.1", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "node_modules/magic-bytes.js": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz", + "integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==", + "dev": true + }, + "node_modules/node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, - "prism-media": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.2.tgz", - "integrity": "sha512-I+nkWY212lJ500jLe4tN9tWO7nRiBAVdMv76P9kffZjYhw20raMlW1HSSvS+MLXC9MmbNZCazMrAr+5jEEgTuw==" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ts-mixer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", + "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/undici": { + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } } } } diff --git a/02-command-handler/package.json b/02-command-handler/package.json index 95fd18a..95b8525 100644 --- a/02-command-handler/package.json +++ b/02-command-handler/package.json @@ -9,8 +9,10 @@ "author": "", "license": "ISC", "dependencies": { - "discord.js": "^12.3.1", - "dotenv": "^8.2.0", "node-fetch": "^2.6.1" + }, + "devDependencies": { + "discord.js": "^14.13.0", + "dotenv": "^16.3.1" } } diff --git a/README.md b/README.md index 0cb9925..5e970b6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Discord Bot Examples -## Steps to create you bot! +## Steps to create your bot! The following is based on the [discord.js guide](https://discordjs.guide/#before-you-begin). @@ -8,8 +8,7 @@ The following is based on the [discord.js guide](https://discordjs.guide/#before ``` $ npm init -$ npm install discord.js -$ npm install dotenv +$ npm install discord.js dotenv ``` 2. [Create an application](https://discord.com/developers/applications/) - optionally set name, description, avatar. Note the "Application ID" (aka "Client ID"). @@ -20,7 +19,7 @@ $ npm install dotenv 5. Enable "Developer Mode" under the "Advanced" settings tab on your discord client, right-click the server icon, and "copy ID" for the server ID. -6. Create a `.env` file with your CLIENTID, SERVERID, and BOTTOKEN: +6. Create a `.env` file with your CLIENTID, SERVERID, and TOKEN: ``` CLIENTID=1234 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8f86c1e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,293 @@ +{ + "name": "Discord-Bots-F21", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "discord.js": "^14.13.0", + "dotenv": "^16.3.1" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", + "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", + "dev": true, + "dependencies": { + "@discordjs/formatters": "^0.3.2", + "@discordjs/util": "^1.0.1", + "@sapphire/shapeshift": "^3.9.2", + "discord-api-types": "0.37.50", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.1" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "dev": true, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz", + "integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==", + "dev": true, + "dependencies": { + "discord-api-types": "0.37.50" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", + "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", + "dev": true, + "dependencies": { + "@discordjs/collection": "^1.5.3", + "@discordjs/util": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.50", + "magic-bytes.js": "^1.0.15", + "tslib": "^2.6.1", + "undici": "5.22.1" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", + "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==", + "dev": true, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz", + "integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==", + "dev": true, + "dependencies": { + "@discordjs/collection": "^1.5.3", + "@discordjs/rest": "^2.0.1", + "@discordjs/util": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@types/ws": "^8.5.5", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.50", + "tslib": "^2.6.1", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", + "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@types/node": { + "version": "20.5.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", + "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", + "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/discord-api-types": { + "version": "0.37.50", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", + "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", + "dev": true + }, + "node_modules/discord.js": { + "version": "14.13.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz", + "integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==", + "dev": true, + "dependencies": { + "@discordjs/builders": "^1.6.5", + "@discordjs/collection": "^1.5.3", + "@discordjs/formatters": "^0.3.2", + "@discordjs/rest": "^2.0.1", + "@discordjs/util": "^1.0.1", + "@discordjs/ws": "^1.0.1", + "@sapphire/snowflake": "^3.5.1", + "@types/ws": "^8.5.5", + "discord-api-types": "0.37.50", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.6.1", + "undici": "5.22.1", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "node_modules/magic-bytes.js": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz", + "integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==", + "dev": true + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ts-mixer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", + "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/undici": { + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/ws": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.0.tgz", + "integrity": "sha512-WR0RJE9Ehsio6U4TuM+LmunEsjQ5ncHlw4sn9ihD6RoJKZrVyH9FWV3dmnwu8B2aNib1OvG2X6adUCyFpQyWcg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f9f86a6 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "discord.js": "^14.13.0", + "dotenv": "^16.3.1" + } +} From 80d0d574fa18b3b1fbbe8f32386c7ff24b6d2a7a Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Thu, 5 Oct 2023 18:29:30 -0400 Subject: [PATCH 3/5] finishing the example and expanding README --- 01-discordjs/.env-example | 1 + 01-discordjs/README.md | 65 ---- 01-discordjs/bot.js | 34 ++ 01-discordjs/commands/choochoo.js | 10 + 01-discordjs/commands/gif.js | 26 ++ 01-discordjs/deploy-commands.js | 60 ++-- 01-discordjs/index.js | 27 -- 02-command-handler/.DS_Store | Bin 6148 -> 0 bytes 02-command-handler/.env-example | 4 - 02-command-handler/README.md | 153 --------- 02-command-handler/commands/fun/gif.js | 43 --- .../commands/testing/choochoo.js | 18 - 02-command-handler/deploy-commands.js | 59 ---- 02-command-handler/index.js | 85 ----- 02-command-handler/package-lock.json | 308 ------------------ 02-command-handler/package.json | 18 - README.md | 131 +++++++- package-lock.json | 293 ----------------- package.json | 6 - 19 files changed, 210 insertions(+), 1131 deletions(-) delete mode 100644 01-discordjs/README.md create mode 100644 01-discordjs/bot.js create mode 100644 01-discordjs/commands/choochoo.js create mode 100644 01-discordjs/commands/gif.js delete mode 100644 01-discordjs/index.js delete mode 100644 02-command-handler/.DS_Store delete mode 100644 02-command-handler/.env-example delete mode 100644 02-command-handler/README.md delete mode 100644 02-command-handler/commands/fun/gif.js delete mode 100644 02-command-handler/commands/testing/choochoo.js delete mode 100644 02-command-handler/deploy-commands.js delete mode 100644 02-command-handler/index.js delete mode 100644 02-command-handler/package-lock.json delete mode 100644 02-command-handler/package.json delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/01-discordjs/.env-example b/01-discordjs/.env-example index 886b3d9..d0fb119 100644 --- a/01-discordjs/.env-example +++ b/01-discordjs/.env-example @@ -1,3 +1,4 @@ SERVERID=1234 CLIENTID=1234 TOKEN=abcd1234 +TENORKEY=abcd2345 \ No newline at end of file diff --git a/01-discordjs/README.md b/01-discordjs/README.md deleted file mode 100644 index 77f2bb9..0000000 --- a/01-discordjs/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Choo Choo Discord Bot! (Setting Up Your Bot) - -[Discord Bot Tutorial](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6avBYxeBSwF48YhAnSn_sA4) - -🚂🌈💖🤖 All aboard! [Coding Train Tutorial Videos](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6avBYxeBSwF48YhAnSn_sA4) 🚂🌈💖🤖 - -## Steps to create new bot - -1. Create node project and install discord.js and dotenv module. - -```bash -$ npm init -$ npm install discord.js dotenv -``` - -3. [Create an application](https://discord.com/developers/applications/) - optionally set name, description, avatar. - -4. Select Bot from left navigation and "Add Bot" - set name and icon. - -5. Add bot to the A2Z server with the url: `https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot` - -6. Write the code! - -Load environment variables using `dotenv` and `.env`: - -1. Create `.env` file: - -```dotenv -CLIENTID=123456789 -SERVERID=123456789 -TOKEN=123456789 -``` - -2. Use `process.env` to access `.env` variables in your javascript: - -```javascript -const dotenv = require("dotenv"); -const TOKEN = process.env.TOKEN; - -// We'll use these later when we deploy commands -const clientID = process.env.CLIENTID; -const serverID = process.env.SERVERID; -``` - -Login to bot account: - -```javascript -const { Client, Events, GatewayIntentBits } = require("discord.js"); -const client = new Client({ intents: [GatewayIntentBits.Guilds] }); -client.login(TOKEN); -``` - -Callback for when the bot is connected and ready: - -```javascript -client.once(Events.ClientReady, () => { - console.log("Ready!"); -}); -``` - -9. Run the bot! - -``` -$ node index.js -``` diff --git a/01-discordjs/bot.js b/01-discordjs/bot.js new file mode 100644 index 0000000..1af2fc9 --- /dev/null +++ b/01-discordjs/bot.js @@ -0,0 +1,34 @@ +// Require the necessary discord.js classes +const { Client, Events, GatewayIntentBits } = require('discord.js'); + +require('dotenv').config(); + +const fs = require('fs'); +const path = require('path'); + +// Create a new client instance +const client = new Client({ + intents: [GatewayIntentBits.Guilds], +}); + +// When the client is ready, run this code (only once) +client.once(Events.ClientReady, readyDiscord); + +// Login to Discord with your client's token +client.login(process.env.TOKEN); + +function readyDiscord() { + console.log('💖'); +} + +const choochoo = require('./commands/choochoo'); +const gif = require('./commands/gif'); + +client.on('interactionCreate', async (interaction) => { + if (!interaction.isCommand()) return; + if (interaction.commandName === 'choochoo') { + await choochoo.execute(interaction); + } else if (interaction.commandName === 'gif') { + await gif.execute(interaction); + } +}); diff --git a/01-discordjs/commands/choochoo.js b/01-discordjs/commands/choochoo.js new file mode 100644 index 0000000..447412b --- /dev/null +++ b/01-discordjs/commands/choochoo.js @@ -0,0 +1,10 @@ +const { SlashCommandBuilder } = require('discord.js'); +const replies = ['🚂🌈💖', 'Choo choo!', 'Ding! 🛎', 'Never forget this dot!']; + +module.exports = { + data: new SlashCommandBuilder().setName('choochoo').setDescription('Replies with a random phrase!'), + async execute(interaction) { + const index = Math.floor(Math.random() * replies.length); + await interaction.reply(replies[index]); + }, +}; diff --git a/01-discordjs/commands/gif.js b/01-discordjs/commands/gif.js new file mode 100644 index 0000000..3dd282b --- /dev/null +++ b/01-discordjs/commands/gif.js @@ -0,0 +1,26 @@ +const fetch = require('node-fetch'); +const { SlashCommandBuilder, AttachmentBuilder, EmbedBuilder } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('gif') + .setDescription('Searches Tenor for gifs!') + .addStringOption((option) => option.setName('keywords').setDescription('The keywords to search Tenor with')), + async execute(interaction) { + let defaultKeyword = 'kitten'; + const keywords = interaction.options.getString('keywords') ?? defaultKeyword; + let url = `https://tenor.googleapis.com/v2/search?q=${keywords}&key=${process.env.TENORKEY}&client_key=a2z_discord_bot&contentfilter=high`; + let response = await fetch(url); + let json = await response.json(); + console.log(json); + console.log(json.results[0].media_formats); + const index = Math.floor(Math.random() * json.results.length); + const embed = new EmbedBuilder().setImage(json.results[index].media_formats.gif.url); + await interaction.deferReply({ ephemeral: true }); + await interaction.followUp({ + embeds: [embed], + content: 'GIF from Tenor:' + keywords, + // ephemeral: true, + }); + }, +}; diff --git a/01-discordjs/deploy-commands.js b/01-discordjs/deploy-commands.js index 82e1ab2..5c3f266 100644 --- a/01-discordjs/deploy-commands.js +++ b/01-discordjs/deploy-commands.js @@ -1,56 +1,40 @@ // Slash Commands Deployment Script // https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands/ -const { REST, Routes } = require("discord.js"); -require("dotenv").config(); -const fs = require("node:fs"); -const path = require("node:path"); +const { REST, Routes } = require('discord.js'); +require('dotenv').config(); +const fs = require('node:fs'); +const path = require('node:path'); const commands = []; +const commandFiles = fs.readdirSync('./commands').filter((file) => file.endsWith('.js')); -// Grab all the command files from the commands directory -const foldersPath = path.join(__dirname, "commands"); -const commandFolders = fs.readdirSync(foldersPath); - -for (const folder of commandFolders) { - // Grab all the command files from the commands directory you created earlier - const commandsPath = path.join(foldersPath, folder); - const commandFiles = fs - .readdirSync(commandsPath) - .filter((file) => file.endsWith(".js")); - // Grab the SlashCommandBuilder#toJSON() output of each commands's data for deployment - for (const file of commandFiles) { - const filePath = path.join(commandsPath, file); - const command = require(filePath); - if ("data" in command && "execute" in command) { - commands.push(command.data.toJSON()); - } else { - console.log( - `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property` - ); - } +// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment +for (const file of commandFiles) { + const command = require(`./commands/${file}`); + if ('data' in command && 'execute' in command) { + commands.push(command.data.toJSON()); + } else { + console.log(`[WARNING] The command ${file} is missing a required "data" or "execute" property.`); } } // Construct and prepare an insance of the REST module -const rest = new REST().setToken(token); +const rest = new REST().setToken(process.env.TOKEN); // and deploy your commands! -async () => { +(async () => { try { - console.log( - `Started refreshing ${commands.length} application (/) commands.` - ); + console.log(`Started refreshing ${commands.length} application (/) commands.`); + // The put method is used to fully refresh all commands in the guild with the current set - const data = await rest.put( - Routes.applicationGuildCommands( - process.env.CLIENTID, - process.env.SERVERID - ), - { body: commands } - ); + const data = await rest.put(Routes.applicationGuildCommands(process.env.CLIENTID, process.env.SERVERID), { + body: commands, + }); + + console.log(`Successfully reloaded ${data.length} application (/) commands.`); } catch (error) { // And of course, make sure you catch and log any errors! console.error(error); } -}; +})(); diff --git a/01-discordjs/index.js b/01-discordjs/index.js deleted file mode 100644 index 8d05f4d..0000000 --- a/01-discordjs/index.js +++ /dev/null @@ -1,27 +0,0 @@ -// Coding a Bot with discord.js (With Env) -// Discord Bots -// The Coding Train / Daniel Shiffman -// https://thecodingtrain.com/learning/bots/discord/03-discordjs.html -// https://youtu.be/8k-zyUyuvlM - -// Setup dotenv and tell it to look for `.env` in the same folder as our main file -const dotenv = require("dotenv"); -dotenv.config(); - -console.log("Beep beep! 🤖"); - -// Require the necessary discord.js classes -const { Client, Events, GatewayIntentBits } = require("discord.js"); - -// Create a new client instance -const client = new Client({ intents: [GatewayIntentBits.Guilds] }); - -function readyDiscord() { - console.log("💖"); -} - -// When the client is ready, run this code (only once) -client.once(Events.ClientReady, readyDiscord); - -// Login to Discord with your client's token -client.login(process.env.TOKEN); diff --git a/02-command-handler/.DS_Store b/02-command-handler/.DS_Store deleted file mode 100644 index 4008cec2fb4feb36493848782d8ee03aa3071330..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~F>b>!3`IX14*|M(%&4UY=naG*S+nExyJQUq^^nOxY;&d*I;u9dBNSUzx z2g?Lt`|s%!7y)eQPJDP+m@yx4!i)*`>Ff5m&hx{Iw6_j;N*}S<&uu{pNC7Dz1*Cu! zSdjvGjBnpp^h|mbDIf*bp@4rM3f)FOW6aI$5DvP7ju? z7GsFlqn#{yT}`&m-VV#*!}8ANQw+^|JFGCFSq&&i0V%LhVAJ!_&;KL+xA}k3qEre< zfq$le4Ttk#&zH)x_2u=ve#xq@8=Z{H8J>OunD|k=qla<7_=2p-*2xM@KLR0xf)w~u G1%3cvo)U`y diff --git a/02-command-handler/.env-example b/02-command-handler/.env-example deleted file mode 100644 index 742d419..0000000 --- a/02-command-handler/.env-example +++ /dev/null @@ -1,4 +0,0 @@ -SERVERID=1234 -CLIENTID=1234 -TOKEN=abcd1234 -TENORKEY=abcd1234 diff --git a/02-command-handler/README.md b/02-command-handler/README.md deleted file mode 100644 index 8a5ec53..0000000 --- a/02-command-handler/README.md +++ /dev/null @@ -1,153 +0,0 @@ -# Choo Choo Discord Bot! (Deploying Commands) - -[Discord Bot Tutorial](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6avBYxeBSwF48YhAnSn_sA4) - -🚂🌈💖🤖 All aboard! [Coding Train Tutorial Videos](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6avBYxeBSwF48YhAnSn_sA4) 🚂🌈💖🤖 - -Once you've set up your bot, it's time to add commands! - -## Organizing command folders - -1. Create a folder named `commands`. This is where we'll put all of our command files. -2. discord.js recommends you organize commands in topic folders under your `commands` folder. Inside your `commands` folder, add a folder called `testing`. - -## Writing a command - -1. In `testing`, let's add our first command file! This command will just send a random phrase to the user whenever it gets called. In this example the file is called `choochoo.js`, but you can call it whatever you want! -2. Import the `SlashCommandBuilder` class and make a list of phrases the bot should say: - -```javascript -const { SlashCommandBuilder } = require("discord.js"); -const replies = ["🚂🌈💖", "Choo choo!", "Ding! 🛎", "Never forget this dot!"]; -``` - -3. Set command options and write an `execute()` function: - -```javascript -// We're putting this all inside `module.exports` so our command handler will be able to import our command later -module.exports = { - data: new SlashCommandBuilder() - .setName("choochoo") - .setDescription("Replies with a random phrase!"), - async execute(interaction) { - const index = Math.floor(Math.random() * replies.length); - await interaction.reply(replies[index]); - }, -}; -``` - -## Writing the command handler - -Now our main bot file needs to import our command files. - -1. In your `index.js`, add a command collection and set your command folder: - -```javascript -client.commands = new Collection(); -const foldersPath = path.join(__dirname, "commands"); -const commandFolders = fs.readdirSync(foldersPath); -``` - -2. Add a nested `for` loop to iterate over command folders and import your commands, logging to the console if the command has an error: - -```javascript -for (const folder of commandFolders) { - // Grab all the command files from the commands directory you created earlier - const commandFolder = path.join(commandsPath, folder); - const commandFiles = fs - .readdirSync(commandFolder) - .filter((file) => file.endsWith(".js")); - for (const file of commandFiles) { - const filePath = path.join(commandFolder, file); - const command = require(filePath); - // Set a new item in the Collection with the key as the command name and the value as the exported module - if ("data" in command && "execute" in command) { - client.commands.set(command.data.name, command); - } else { - console.log( - `[WARNING] The command at ${filePath} is missing a required "data" or execute property.` - ); - } - } -} -``` - -## Registering commands - -1. Create a file in the root of your project called `deploy-commands.js` -2. Copy the deployment script from the discord.js [guide](https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands) -3. Replace... - -```javascript -const { clientId, guildId, token } = require("./config.json"); -``` - -...with... - -```javascript -require("dotenv").config(); -``` - -4. And replace... - -```javascript -Routes.applicationGuildCommands(clientId, guildId), -``` - -...with.... - -```javascript -Routes.applicationGuildCommands( - process.env.CLIENTID, - process.env.SERVERID -), -``` - -5. Run the deployment script! - -```bash -$ node deploy-commands.js -``` - -## Executing commands - -1. Back in `index.js`, let's add a callback that will execute a command whenever it's called by the user. - -```javascript -client.on(Events.InteractionCreate, async (interaction) => { - // Ignore interaction if it isn't a slash command - if (!interaction.isChatInputCommand()) return; - console.log(interaction.client.commands); - - const command = interaction.client.commands.get(interaction.commandName); - if (!command) { - console.error(`No command matching ${interaction.commandName} was found.`); - return; - } - - // Execute the command and send a followup if the command fails - try { - await command.execute(interaction); - } catch (error) { - console.error(error); - if (interaction.replied || interaction.deferred) { - await interaction.followUp({ - content: "There was an error while executing this command!", - ephemeral: true, - }); - } else { - await interaction.reply({ - content: "There was an error while executing this command!", - ephemeral: true, - }); - } - } - console.log(interaction); -}); -``` - -2. Run the bot! - -```bash -$ node index.js -``` diff --git a/02-command-handler/commands/fun/gif.js b/02-command-handler/commands/fun/gif.js deleted file mode 100644 index 8cff666..0000000 --- a/02-command-handler/commands/fun/gif.js +++ /dev/null @@ -1,43 +0,0 @@ -// Command Handler -// Discord Bots -// The Coding Train / Daniel Shiffman -// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html -// https://youtu.be/B60Q74FHFBQ -- Outdated! - -const fetch = require("node-fetch"); -const { - SlashCommandBuilder, - AttachmentBuilder, - EmbedBuilder, -} = require("discord.js"); - -module.exports = { - data: new SlashCommandBuilder() - .setName("gif") - .setDescription("Searches Tenor for gifs!") - .addStringOption((option) => - option - .setName("keywords") - .setDescription("The keywords to search Tenor with") - ), - async execute(interaction) { - let defaultKeyword = "coding train"; - const keywords = - interaction.options.getString("keywords") ?? defaultKeyword; - let url = `https://tenor.googleapis.com/v2/search?q=${keywords}&key=${process.env.TENORKEY}&client_key=a2z_discord_bot&contentfilter=high`; - let response = await fetch(url); - let json = await response.json(); - console.log(json); - console.log(json.results[0].media_formats); - const index = Math.floor(Math.random() * json.results.length); - const embed = new EmbedBuilder().setImage( - json.results[index].media_formats.gif.url - ); - await interaction.deferReply({ ephemeral: true }); - await interaction.followUp({ - embeds: [embed], - content: "GIF from Tenor:" + keywords, - ephemeral: true, - }); - }, -}; diff --git a/02-command-handler/commands/testing/choochoo.js b/02-command-handler/commands/testing/choochoo.js deleted file mode 100644 index fc18f04..0000000 --- a/02-command-handler/commands/testing/choochoo.js +++ /dev/null @@ -1,18 +0,0 @@ -// Command Handler -// Discord Bots -// The Coding Train / Daniel Shiffman -// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html -// https://youtu.be/B60Q74FHFBQ - -const { SlashCommandBuilder } = require("discord.js"); -const replies = ["🚂🌈💖", "Choo choo!", "Ding! 🛎", "Never forget this dot!"]; - -module.exports = { - data: new SlashCommandBuilder() - .setName("choochoo") - .setDescription("Replies with a random phrase!"), - async execute(interaction) { - const index = Math.floor(Math.random() * replies.length); - await interaction.reply(replies[index]); - }, -}; diff --git a/02-command-handler/deploy-commands.js b/02-command-handler/deploy-commands.js deleted file mode 100644 index a8202fa..0000000 --- a/02-command-handler/deploy-commands.js +++ /dev/null @@ -1,59 +0,0 @@ -// Slash Commands Deployment Script -// https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands/ - -const { REST, Routes } = require("discord.js"); -require("dotenv").config(); -const fs = require("node:fs"); -const path = require("node:path"); - -const commands = []; - -// Grab all the command files from the commands directory -const foldersPath = path.join(__dirname, "commands"); -const commandFolders = fs.readdirSync(foldersPath); - -for (const folder of commandFolders) { - // Grab all the command files from the commands directory you created earlier - const commandsPath = path.join(foldersPath, folder); - const commandFiles = fs - .readdirSync(commandsPath) - .filter((file) => file.endsWith(".js")); - // Grab the SlashCommandBuilder#toJSON() output of each commands's data for deployment - for (const file of commandFiles) { - const filePath = path.join(commandsPath, file); - const command = require(filePath); - if ("data" in command && "execute" in command) { - commands.push(command.data.toJSON()); - } else { - console.log( - `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property` - ); - } - } -} - -// Construct and prepare an insance of the REST module -const rest = new REST().setToken(process.env.CLIENTSECRET); - -// and deploy your commands! -(async () => { - try { - console.log( - `Started refreshing ${commands.length} application (/) commands.` - ); - // The put method is used to fully refresh all commands in the guild with the current set - const data = await rest.put( - Routes.applicationGuildCommands( - process.env.CLIENTID, - process.env.SERVERID - ), - { body: commands } - ); - console.log( - `Successfully reloaded ${data.length} application (/) commands.` - ); - } catch (error) { - // And of course, make sure you catch and log any errors! - console.error(error); - } -})() diff --git a/02-command-handler/index.js b/02-command-handler/index.js deleted file mode 100644 index 7b5a2b7..0000000 --- a/02-command-handler/index.js +++ /dev/null @@ -1,85 +0,0 @@ -// Command Handler -// Discord Bots -// The Coding Train / Daniel Shiffman -// https://thecodingtrain.com/learning/bots/discord/06-command-handler.html -// https://youtu.be/B60Q74FHFBQ - -console.log("Beep beep! 🤖"); - -// Setup dotenv and tell it to look for `.env` in the same folder as our main file -const dotenv = require("dotenv"); -dotenv.config({ path: "./.env" }); - -const fs = require("node:fs"); -const path = require("node:path"); - -const { Client, Collection, Events, GatewayIntentBits } = require("discord.js"); -const client = new Client({ intents: [GatewayIntentBits.Guilds] }); -const token = process.env.TOKEN; -client.login(token); - -client.on("ready", readyDiscord); - -function readyDiscord() { - console.log("💖"); -} - -// Create a new Collection to hold our slash commands -client.commands = new Collection(); - -// Read the slash commands from the `commands` directory -const commandsPath = path.join(__dirname, "commands"); -console.log(commandsPath); -const commandFolders = fs.readdirSync(commandsPath); - -// Add slash commands to the client -for (const folder of commandFolders) { - // Grab all the command files from the commands directory you created earlier - const commandFolder = path.join(commandsPath, folder); - const commandFiles = fs - .readdirSync(commandFolder) - .filter((file) => file.endsWith(".js")); - for (const file of commandFiles) { - const filePath = path.join(commandFolder, file); - const command = require(filePath); - // Set a new item in the Collection with the key as the command name and the value as the exported module - if ("data" in command && "execute" in command) { - client.commands.set(command.data.name, command); - } else { - console.log( - `[WARNING] The command at ${filePath} is missing a required "data" or execute property.` - ); - } - } -} - -client.on(Events.InteractionCreate, async (interaction) => { - // Ignore interaction if it isn't a slash command - if (!interaction.isChatInputCommand()) return; - console.log(interaction.client.commands); - - const command = interaction.client.commands.get(interaction.commandName); - if (!command) { - console.error(`No command matching ${interaction.commandName} was found.`); - return; - } - - // Execute the command and send a followup if the command fails - try { - await command.execute(interaction); - } catch (error) { - console.error(error); - if (interaction.replied || interaction.deferred) { - await interaction.followUp({ - content: "There was an error while executing this command!", - ephemeral: true, - }); - } else { - await interaction.reply({ - content: "There was an error while executing this command!", - ephemeral: true, - }); - } - } - console.log(interaction); -}); diff --git a/02-command-handler/package-lock.json b/02-command-handler/package-lock.json deleted file mode 100644 index fe8e2b7..0000000 --- a/02-command-handler/package-lock.json +++ /dev/null @@ -1,308 +0,0 @@ -{ - "name": "choochoobot", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "choochoobot", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "node-fetch": "^2.6.1" - }, - "devDependencies": { - "discord.js": "^14.13.0", - "dotenv": "^16.3.1" - } - }, - "node_modules/@discordjs/builders": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", - "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", - "dev": true, - "dependencies": { - "@discordjs/formatters": "^0.3.2", - "@discordjs/util": "^1.0.1", - "@sapphire/shapeshift": "^3.9.2", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.3", - "tslib": "^2.6.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/collection": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", - "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", - "dev": true, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/formatters": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz", - "integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==", - "dev": true, - "dependencies": { - "discord-api-types": "0.37.50" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/rest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", - "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", - "dev": true, - "dependencies": { - "@discordjs/collection": "^1.5.3", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@sapphire/snowflake": "^3.5.1", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "magic-bytes.js": "^1.0.15", - "tslib": "^2.6.1", - "undici": "5.22.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", - "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==", - "dev": true, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/ws": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz", - "integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==", - "dev": true, - "dependencies": { - "@discordjs/collection": "^1.5.3", - "@discordjs/rest": "^2.0.1", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@types/ws": "^8.5.5", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "tslib": "^2.6.1", - "ws": "^8.13.0" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@sapphire/async-queue": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", - "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", - "dev": true, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/shapeshift": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", - "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/snowflake": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", - "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", - "dev": true, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@types/node": { - "version": "20.5.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.6.tgz", - "integrity": "sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@vladfrangu/async_event_emitter": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", - "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==", - "dev": true, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dev": true, - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", - "dev": true - }, - "node_modules/discord.js": { - "version": "14.13.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz", - "integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==", - "dev": true, - "dependencies": { - "@discordjs/builders": "^1.6.5", - "@discordjs/collection": "^1.5.3", - "@discordjs/formatters": "^0.3.2", - "@discordjs/rest": "^2.0.1", - "@discordjs/util": "^1.0.1", - "@discordjs/ws": "^1.0.1", - "@sapphire/snowflake": "^3.5.1", - "@types/ws": "^8.5.5", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "lodash.snakecase": "^4.1.1", - "tslib": "^2.6.1", - "undici": "5.22.1", - "ws": "^8.13.0" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", - "dev": true - }, - "node_modules/magic-bytes.js": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz", - "integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==", - "dev": true - }, - "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/ts-mixer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", - "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==", - "dev": true - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", - "dev": true, - "dependencies": { - "busboy": "^1.6.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - } - } -} diff --git a/02-command-handler/package.json b/02-command-handler/package.json deleted file mode 100644 index 95b8525..0000000 --- a/02-command-handler/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "choochoobot", - "version": "1.0.0", - "description": "", - "main": "bot.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "node-fetch": "^2.6.1" - }, - "devDependencies": { - "discord.js": "^14.13.0", - "dotenv": "^16.3.1" - } -} diff --git a/README.md b/README.md index 5e970b6..3c7f185 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,145 @@ # Discord Bot Examples -## Steps to create your bot! +This repository provides examples and a step-by-step guide on how to create a simple Discord bot using [discord.js](https://discord.js.org/#/). -The following is based on the [discord.js guide](https://discordjs.guide/#before-you-begin). +## Steps to Create Your Bot! -1. Create node project and install discord.js module as well as dotenv. +### 1. Set Up Your Project -``` +Create a new Node.js project and install necessary dependencies. + +```sh $ npm init $ npm install discord.js dotenv ``` -2. [Create an application](https://discord.com/developers/applications/) - optionally set name, description, avatar. Note the "Application ID" (aka "Client ID"). +### 2. Create a Discord Application + +- Navigate to the [Discord Developer Portal](https://discord.com/developers/applications/) and create a new application. +- Optionally, set the application name, description, and avatar. +- Note down the "Application ID" (also known as "Client ID"). -3. Select Bot from left navigation and "Add Bot" - set name and icon. Note the "Bot Token" (keep this secret). +### 3. Create and Configure Your Bot -4. Add bot to the A2Z server with the url: `https://discord.com/oauth2/authorize?client_id=YOUR_APPLICATION_ID&scope=bot` +- In the Discord Developer Portal, select "Bot" from the left navigation and click "Add Bot". +- Set a name and icon for your bot. +- Note down the "Bot Token" (keep this secret). -5. Enable "Developer Mode" under the "Advanced" settings tab on your discord client, right-click the server icon, and "copy ID" for the server ID. +### 4. Add Bot to a Server -6. Create a `.env` file with your CLIENTID, SERVERID, and TOKEN: +Use the following URL to add the bot to your Discord server, replacing `YOUR_APPLICATION_ID` with your actual application ID: +```plaintext +https://discord.com/oauth2/authorize?client_id=YOUR_APPLICATION_ID&scope=bot ``` + +### 5. Enable Developer Mode in Discord + +- Enable "Developer Mode" under the "Advanced" settings tab on your Discord client. +- Right-click on the server icon, and select "Copy ID" to get the server ID. + +### 6. Configure Environment Variables + +Create a `.env` file in your project root and add your client ID, server ID, and bot token: + +```plaintext CLIENTID=1234 SERVERID=1234 TOKEN=1234 ``` -7. Add slash commands permission. Go to your applicaiton page in the Discord developer portal, select "OAuth", check "application.commands", and open the URL that populates at the bottom. +These environment variables are used to keep sensitive data, like your bot token, out of your code. This is especially important if you're sharing your code with others or storing your code publicly on GitHub. (Notice how `.env` is included in `.gitignore`.) + +### 7. Add Slash Commands Permission + +- Go to your application page in the Discord developer portal. +- Navigate to "OAuth" -> "URL Generator". +- Check "application.commands". +- Open the URL that populates at the bottom and authorize the bot to access your server. + +### 8. Create the bot code! + +Create `bot.js` (or `index.js`) and paste this code: + +```javascript +const { Client, Events, GatewayIntentBits } = require('discord.js'); +require('dotenv').config(); +// Create a new client instance +const client = new Client({ + intents: [GatewayIntentBits.Guilds], +}); + +// When the client is ready, run this code (only once) +client.once(Events.ClientReady, readyDiscord); + +// Login to Discord with your client's token +client.login(process.env.TOKEN); + +function readyDiscord() { + console.log('💖'); +} +``` + +Run to see if it works! (If you see the 💖 it's working!) -8. Create `deploy-commands.js`, see example code for content. Customize your commands and execute! +```sh +$ node bot.js +``` + +## 9. Create a Command + +Each command should be handled in a separate JS file, there are many ways you can manage this, but I suggest putting them in a folder called commands: + +```javascript +const { SlashCommandBuilder } = require('discord.js'); +module.exports = { + data: new SlashCommandBuilder().setName('choochoo').setDescription('Says choo choo back!'), + async execute(interaction) { + await interaction.reply('Choo Choo! 🚂'); + }, +}; ``` -$ node deploy-commands.js + +## 10. Deploy the commands + +Create `deploy-commands.js` and copy the example code. Then run it! + +```sh +node deploy-commands.js ``` -9. Create `bot.js`, see example code for content. Handle your commands and run the bot! +You only have to do this once. If you change the command (altering descriptions, changing options, etc.), then you do need to re-run `deploy-commands.js`. + +## 11. Add the code to handle the command +You also need to handle the command in bot.js, add the equivalent code: + +```javascript +const choochoo = require('./commands/choochoo'); + +client.on('interactionCreate', async (interaction) => { + if (!interaction.isCommand()) return; + if (interaction.commandName === 'choochoo') { + await choochoo.execute(interaction); + } +}); ``` -$ node bot.js + +Then run the bot again! + +```sh +node bot.js ``` + +## Recap of the code elements + +- `commands/choochoo.js`: Defines a simple slash command. +- `index.js`: Handles interactions with Discord and executes commands. +- `deploy-commands.js`: Script to register slash commands with Discord API. + +## Additional Resources + +- [Discord.js Guide](https://discordjs.guide/) +- [Discord.js Documentation](https://discord.js.org/#/docs/main/stable/general/welcome) +- [Discord Developer Portal](https://discord.com/developers/applications/) diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 8f86c1e..0000000 --- a/package-lock.json +++ /dev/null @@ -1,293 +0,0 @@ -{ - "name": "Discord-Bots-F21", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "devDependencies": { - "discord.js": "^14.13.0", - "dotenv": "^16.3.1" - } - }, - "node_modules/@discordjs/builders": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", - "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", - "dev": true, - "dependencies": { - "@discordjs/formatters": "^0.3.2", - "@discordjs/util": "^1.0.1", - "@sapphire/shapeshift": "^3.9.2", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.3", - "tslib": "^2.6.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/collection": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", - "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", - "dev": true, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/formatters": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz", - "integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==", - "dev": true, - "dependencies": { - "discord-api-types": "0.37.50" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/rest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", - "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", - "dev": true, - "dependencies": { - "@discordjs/collection": "^1.5.3", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@sapphire/snowflake": "^3.5.1", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "magic-bytes.js": "^1.0.15", - "tslib": "^2.6.1", - "undici": "5.22.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", - "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==", - "dev": true, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/ws": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz", - "integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==", - "dev": true, - "dependencies": { - "@discordjs/collection": "^1.5.3", - "@discordjs/rest": "^2.0.1", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@types/ws": "^8.5.5", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "tslib": "^2.6.1", - "ws": "^8.13.0" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@sapphire/async-queue": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", - "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", - "dev": true, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/shapeshift": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", - "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/snowflake": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", - "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", - "dev": true, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@types/node": { - "version": "20.5.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", - "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@vladfrangu/async_event_emitter": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", - "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==", - "dev": true, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dev": true, - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", - "dev": true - }, - "node_modules/discord.js": { - "version": "14.13.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz", - "integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==", - "dev": true, - "dependencies": { - "@discordjs/builders": "^1.6.5", - "@discordjs/collection": "^1.5.3", - "@discordjs/formatters": "^0.3.2", - "@discordjs/rest": "^2.0.1", - "@discordjs/util": "^1.0.1", - "@discordjs/ws": "^1.0.1", - "@sapphire/snowflake": "^3.5.1", - "@types/ws": "^8.5.5", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "lodash.snakecase": "^4.1.1", - "tslib": "^2.6.1", - "undici": "5.22.1", - "ws": "^8.13.0" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", - "dev": true - }, - "node_modules/magic-bytes.js": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz", - "integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==", - "dev": true - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/ts-mixer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", - "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==", - "dev": true - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", - "dev": true, - "dependencies": { - "busboy": "^1.6.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/ws": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.0.tgz", - "integrity": "sha512-WR0RJE9Ehsio6U4TuM+LmunEsjQ5ncHlw4sn9ihD6RoJKZrVyH9FWV3dmnwu8B2aNib1OvG2X6adUCyFpQyWcg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index f9f86a6..0000000 --- a/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "devDependencies": { - "discord.js": "^14.13.0", - "dotenv": "^16.3.1" - } -} From 88e2894c0ac6732f73204862abbc700e13057225 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Thu, 5 Oct 2023 18:48:47 -0400 Subject: [PATCH 4/5] es6 update --- 01-discordjs/bot.js | 17 +- 01-discordjs/commands/choochoo.js | 20 +- 01-discordjs/commands/gif.js | 65 ++-- 01-discordjs/deploy-commands.js | 12 +- 01-discordjs/package-lock.json | 504 +++++++----------------------- 01-discordjs/package.json | 10 +- 6 files changed, 186 insertions(+), 442 deletions(-) diff --git a/01-discordjs/bot.js b/01-discordjs/bot.js index 1af2fc9..12598db 100644 --- a/01-discordjs/bot.js +++ b/01-discordjs/bot.js @@ -1,10 +1,12 @@ -// Require the necessary discord.js classes -const { Client, Events, GatewayIntentBits } = require('discord.js'); +// Import the necessary discord.js classes using ES6 syntax +import { Client, Events, GatewayIntentBits } from 'discord.js'; +import dotenv from 'dotenv'; +import { readFile, readdir } from 'fs/promises'; // Node.js built-in module for file system actions +import path from 'path'; +import * as choochoo from './commands/choochoo.mjs'; // Assume the command file also uses ES6 syntax +import * as gif from './commands/gif.mjs'; // Assume the command file also uses ES6 syntax -require('dotenv').config(); - -const fs = require('fs'); -const path = require('path'); +dotenv.config(); // Create a new client instance const client = new Client({ @@ -21,9 +23,6 @@ function readyDiscord() { console.log('💖'); } -const choochoo = require('./commands/choochoo'); -const gif = require('./commands/gif'); - client.on('interactionCreate', async (interaction) => { if (!interaction.isCommand()) return; if (interaction.commandName === 'choochoo') { diff --git a/01-discordjs/commands/choochoo.js b/01-discordjs/commands/choochoo.js index 447412b..7cfa342 100644 --- a/01-discordjs/commands/choochoo.js +++ b/01-discordjs/commands/choochoo.js @@ -1,10 +1,14 @@ -const { SlashCommandBuilder } = require('discord.js'); +// Importing modules using ES6 syntax +import { SlashCommandBuilder } from 'discord.js'; + +// Replies array const replies = ['🚂🌈💖', 'Choo choo!', 'Ding! 🛎', 'Never forget this dot!']; -module.exports = { - data: new SlashCommandBuilder().setName('choochoo').setDescription('Replies with a random phrase!'), - async execute(interaction) { - const index = Math.floor(Math.random() * replies.length); - await interaction.reply(replies[index]); - }, -}; +// Command Builder export +export const data = new SlashCommandBuilder().setName('choochoo').setDescription('Replies with a random phrase!'); + +// Execute function export +export async function execute(interaction) { + const index = Math.floor(Math.random() * replies.length); + await interaction.reply(replies[index]); +} diff --git a/01-discordjs/commands/gif.js b/01-discordjs/commands/gif.js index 3dd282b..a74ef8c 100644 --- a/01-discordjs/commands/gif.js +++ b/01-discordjs/commands/gif.js @@ -1,26 +1,39 @@ -const fetch = require('node-fetch'); -const { SlashCommandBuilder, AttachmentBuilder, EmbedBuilder } = require('discord.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('gif') - .setDescription('Searches Tenor for gifs!') - .addStringOption((option) => option.setName('keywords').setDescription('The keywords to search Tenor with')), - async execute(interaction) { - let defaultKeyword = 'kitten'; - const keywords = interaction.options.getString('keywords') ?? defaultKeyword; - let url = `https://tenor.googleapis.com/v2/search?q=${keywords}&key=${process.env.TENORKEY}&client_key=a2z_discord_bot&contentfilter=high`; - let response = await fetch(url); - let json = await response.json(); - console.log(json); - console.log(json.results[0].media_formats); - const index = Math.floor(Math.random() * json.results.length); - const embed = new EmbedBuilder().setImage(json.results[index].media_formats.gif.url); - await interaction.deferReply({ ephemeral: true }); - await interaction.followUp({ - embeds: [embed], - content: 'GIF from Tenor:' + keywords, - // ephemeral: true, - }); - }, -}; +// Importing modules using ES6 syntax +import fetch from 'node-fetch'; +import { SlashCommandBuilder, EmbedBuilder } from 'discord.js'; + +export const data = new SlashCommandBuilder() + .setName('gif') + .setDescription('Searches Tenor for gifs!') + .addStringOption((option) => option.setName('keywords').setDescription('The keywords to search Tenor with')); + +// Execute function to interact with Tenor API and reply with a GIF +export async function execute(interaction) { + // Default keyword set to 'kitten' if none provided + let defaultKeyword = 'kitten'; + const keywords = interaction.options.getString('keywords') ?? defaultKeyword; + + // URL constructed with the provided or default keyword + let url = `https://tenor.googleapis.com/v2/search?q=${keywords}&key=${process.env.TENORKEY}&client_key=a2z_discord_bot&contentfilter=high`; + + // Fetching data from Tenor API + let response = await fetch(url); + let json = await response.json(); + console.log(json); + console.log(json.results[0].media_formats); + + // Randomly select a GIF from the response + const index = Math.floor(Math.random() * json.results.length); + + // Creating an embed to display the GIF in the Discord message + const embed = new EmbedBuilder().setImage(json.results[index].media_formats.gif.url); + + // Initially acknowledging the command interaction with a hidden (ephemeral) reply + await interaction.deferReply({ ephemeral: true }); + + // Following up with the selected GIF embedded in the message + await interaction.followUp({ + embeds: [embed], + content: 'GIF from Tenor: ' + keywords, + }); +} diff --git a/01-discordjs/deploy-commands.js b/01-discordjs/deploy-commands.js index 5c3f266..b8f472b 100644 --- a/01-discordjs/deploy-commands.js +++ b/01-discordjs/deploy-commands.js @@ -1,17 +1,19 @@ // Slash Commands Deployment Script // https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands/ -const { REST, Routes } = require('discord.js'); -require('dotenv').config(); -const fs = require('node:fs'); -const path = require('node:path'); +// Importing modules using ES6 syntax +import { REST, Routes } from 'discord.js'; +import { config } from 'dotenv'; +import fs from 'node:fs'; + +config(); // Using dotenv config function directly const commands = []; const commandFiles = fs.readdirSync('./commands').filter((file) => file.endsWith('.js')); // Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment for (const file of commandFiles) { - const command = require(`./commands/${file}`); + const command = await import(`./commands/${file}`); // Using dynamic import if ('data' in command && 'execute' in command) { commands.push(command.data.toJSON()); } else { diff --git a/01-discordjs/package-lock.json b/01-discordjs/package-lock.json index 6664898..d22d286 100644 --- a/01-discordjs/package-lock.json +++ b/01-discordjs/package-lock.json @@ -9,53 +9,40 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@discordjs/builders": "^0.6.0", - "@discordjs/rest": "^0.1.0-canary.0", - "discord-api-types": "^0.23.1", - "node-fetch": "^2.6.5" - }, - "devDependencies": { "discord.js": "^14.13.0", - "dotenv": "^16.3.1" + "dotenv": "^16.3.1", + "node-fetch": "^3.3.2" } }, "node_modules/@discordjs/builders": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz", - "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==", - "deprecated": "no longer supported", + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", + "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", "dependencies": { - "@sindresorhus/is": "^4.0.1", - "discord-api-types": "^0.22.0", - "ow": "^0.27.0", - "ts-mixer": "^6.0.0", - "tslib": "^2.3.1" + "@discordjs/formatters": "^0.3.2", + "@discordjs/util": "^1.0.1", + "@sapphire/shapeshift": "^3.9.2", + "discord-api-types": "0.37.50", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.1" }, "engines": { - "node": ">=14.0.0", - "npm": ">=7.0.0" + "node": ">=16.11.0" } }, - "node_modules/@discordjs/builders/node_modules/discord-api-types": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", - "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==", - "deprecated": "No longer supported. Install the latest release!", + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", "engines": { - "node": ">=12" + "node": ">=16.11.0" } }, - "node_modules/@discordjs/collection": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", - "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==", - "deprecated": "no longer supported" - }, "node_modules/@discordjs/formatters": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz", "integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==", - "dev": true, "dependencies": { "discord-api-types": "0.37.50" }, @@ -63,45 +50,29 @@ "node": ">=16.11.0" } }, - "node_modules/@discordjs/formatters/node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", - "dev": true - }, "node_modules/@discordjs/rest": { - "version": "0.1.0-canary.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-0.1.0-canary.0.tgz", - "integrity": "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ==", - "deprecated": "no longer supported", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", + "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", "dependencies": { - "@discordjs/collection": "^0.1.6", - "@sapphire/async-queue": "^1.1.4", - "@sapphire/snowflake": "^1.3.5", - "abort-controller": "^3.0.0", - "discord-api-types": "^0.18.1", - "form-data": "^4.0.0", - "node-fetch": "^2.6.1", - "tslib": "^2.3.0" + "@discordjs/collection": "^1.5.3", + "@discordjs/util": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.50", + "magic-bytes.js": "^1.0.15", + "tslib": "^2.6.1", + "undici": "5.22.1" }, "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@discordjs/rest/node_modules/discord-api-types": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.18.1.tgz", - "integrity": "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg==", - "deprecated": "No longer supported. Install the latest release (0.20.2)", - "engines": { - "node": ">=12" + "node": ">=16.11.0" } }, "node_modules/@discordjs/util": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==", - "dev": true, "engines": { "node": ">=16.11.0" } @@ -110,7 +81,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz", "integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==", - "dev": true, "dependencies": { "@discordjs/collection": "^1.5.3", "@discordjs/rest": "^2.0.1", @@ -126,51 +96,6 @@ "node": ">=16.11.0" } }, - "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", - "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", - "dev": true, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/ws/node_modules/@discordjs/rest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", - "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", - "dev": true, - "dependencies": { - "@discordjs/collection": "^1.5.3", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@sapphire/snowflake": "^3.5.1", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "magic-bytes.js": "^1.0.15", - "tslib": "^2.6.1", - "undici": "5.22.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/ws/node_modules/@sapphire/snowflake": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", - "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", - "dev": true, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@discordjs/ws/node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", - "dev": true - }, "node_modules/@sapphire/async-queue": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", @@ -184,7 +109,6 @@ "version": "3.9.2", "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" @@ -195,37 +119,23 @@ } }, "node_modules/@sapphire/snowflake": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-1.3.6.tgz", - "integrity": "sha512-QnzuLp+p9D7agynVub/zqlDVriDza9y3STArBhNiNBUgIX8+GL5FpQxstRfw1jDr5jkZUjcuKYAHxjIuXKdJAg==", - "deprecated": "This version has been automatically deprecated by @favware/npm-deprecate. Please use a newer version.", - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "node": ">=v14.0.0", + "npm": ">=7.0.0" } }, "node_modules/@types/node": { - "version": "20.5.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", - "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==", - "dev": true + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" }, "node_modules/@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", - "dev": true, + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.6.tgz", + "integrity": "sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg==", "dependencies": { "@types/node": "*" } @@ -234,33 +144,15 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==", - "dev": true, "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dev": true, "dependencies": { "streamsearch": "^1.1.0" }, @@ -268,47 +160,23 @@ "node": ">=10.16.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "engines": { - "node": ">= 0.8" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" + "node": ">= 12" } }, "node_modules/discord-api-types": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.23.1.tgz", - "integrity": "sha512-igWmn+45mzXRWNEPU25I/pr8MwxHb767wAr51oy3VRLRcTlp5ADBbrBR0lq3SA1Rfw3MtM4TQu1xo3kxscfVdQ==", - "deprecated": "No longer supported. Install the latest release!", - "engines": { - "node": ">=12" - } + "version": "0.37.50", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", + "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" }, "node_modules/discord.js": { "version": "14.13.0", "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz", "integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==", - "dev": true, "dependencies": { "@discordjs/builders": "^1.6.5", "@discordjs/collection": "^1.5.3", @@ -329,88 +197,10 @@ "node": ">=16.11.0" } }, - "node_modules/discord.js/node_modules/@discordjs/builders": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", - "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", - "dev": true, - "dependencies": { - "@discordjs/formatters": "^0.3.2", - "@discordjs/util": "^1.0.1", - "@sapphire/shapeshift": "^3.9.2", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.3", - "tslib": "^2.6.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/discord.js/node_modules/@discordjs/collection": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", - "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", - "dev": true, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/discord.js/node_modules/@discordjs/rest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", - "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", - "dev": true, - "dependencies": { - "@discordjs/collection": "^1.5.3", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@sapphire/snowflake": "^3.5.1", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "magic-bytes.js": "^1.0.15", - "tslib": "^2.6.1", - "undici": "5.22.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/discord.js/node_modules/@sapphire/snowflake": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", - "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", - "dev": true, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/discord.js/node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==", - "dev": true - }, - "node_modules/dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dotenv": { "version": "16.3.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "dev": true, "engines": { "node": ">=12" }, @@ -418,161 +208,116 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" }, "engines": { - "node": ">= 6" + "node": "^12.20 || >= 14.13" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, "engines": { - "node": ">=8" + "node": ">=12.20.0" } }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.snakecase": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", - "dev": true + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" }, "node_modules/magic-bytes.js": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz", - "integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==", - "dev": true - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.5.0.tgz", + "integrity": "sha512-wJkXvutRbNWcc37tt5j1HyOK1nosspdh3dj6LUYYAvF6JYNqs53IfRvK9oEpcwiDA1NdoIi64yAMfdivPeVAyw==" }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], "engines": { - "node": ">= 0.6" + "node": ">=10.5.0" } }, "node_modules/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dependencies": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/ow": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", - "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", - "dependencies": { - "@sindresorhus/is": "^4.0.1", - "callsites": "^3.1.0", - "dot-prop": "^6.0.1", - "lodash.isequal": "^4.5.0", - "type-fest": "^1.2.1", - "vali-date": "^1.0.0" - }, - "engines": { - "node": ">=12" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "dev": true, "engines": { "node": ">=10.0.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, "node_modules/ts-mixer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" }, "node_modules/tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" - }, - "node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/undici": { "version": "5.22.1", "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", - "dev": true, "dependencies": { "busboy": "^1.6.0" }, @@ -580,33 +325,18 @@ "node": ">=14.0" } }, - "node_modules/vali-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", - "integrity": "sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg==", + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "node": ">= 8" } }, "node_modules/ws": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.0.tgz", - "integrity": "sha512-WR0RJE9Ehsio6U4TuM+LmunEsjQ5ncHlw4sn9ihD6RoJKZrVyH9FWV3dmnwu8B2aNib1OvG2X6adUCyFpQyWcg==", - "dev": true, + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "engines": { "node": ">=10.0.0" }, diff --git a/01-discordjs/package.json b/01-discordjs/package.json index 29c509b..cec2fcc 100644 --- a/01-discordjs/package.json +++ b/01-discordjs/package.json @@ -6,6 +6,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, + "type": "module", "repository": { "type": "git", "url": "git+https://github.com/shiffman/Discord-Bot-A2Z.git" @@ -17,13 +18,8 @@ }, "homepage": "https://github.com/shiffman/Discord-Bot-A2Z#readme", "dependencies": { - "@discordjs/builders": "^0.6.0", - "@discordjs/rest": "^0.1.0-canary.0", - "discord-api-types": "^0.23.1", - "node-fetch": "^2.6.5" - }, - "devDependencies": { "discord.js": "^14.13.0", - "dotenv": "^16.3.1" + "dotenv": "^16.3.1", + "node-fetch": "^3.3.2" } } From 6dede93c564a6d7ed557d777a578496d852df44b Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Thu, 5 Oct 2023 18:51:39 -0400 Subject: [PATCH 5/5] fix ephemeral --- 01-discordjs/bot.js | 6 ++---- 01-discordjs/commands/gif.js | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/01-discordjs/bot.js b/01-discordjs/bot.js index 12598db..93f2a37 100644 --- a/01-discordjs/bot.js +++ b/01-discordjs/bot.js @@ -1,10 +1,8 @@ // Import the necessary discord.js classes using ES6 syntax import { Client, Events, GatewayIntentBits } from 'discord.js'; import dotenv from 'dotenv'; -import { readFile, readdir } from 'fs/promises'; // Node.js built-in module for file system actions -import path from 'path'; -import * as choochoo from './commands/choochoo.mjs'; // Assume the command file also uses ES6 syntax -import * as gif from './commands/gif.mjs'; // Assume the command file also uses ES6 syntax +import * as choochoo from './commands/choochoo.js'; +import * as gif from './commands/gif.js'; dotenv.config(); diff --git a/01-discordjs/commands/gif.js b/01-discordjs/commands/gif.js index a74ef8c..f03d651 100644 --- a/01-discordjs/commands/gif.js +++ b/01-discordjs/commands/gif.js @@ -29,7 +29,7 @@ export async function execute(interaction) { const embed = new EmbedBuilder().setImage(json.results[index].media_formats.gif.url); // Initially acknowledging the command interaction with a hidden (ephemeral) reply - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: false }); // Following up with the selected GIF embedded in the message await interaction.followUp({