diff --git a/01-discordjs/.env-example b/01-discordjs/.env-example new file mode 100644 index 0000000..d0fb119 --- /dev/null +++ b/01-discordjs/.env-example @@ -0,0 +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 b3d2e1c..0000000 --- a/01-discordjs/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# Choo Choo Discord 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 module. - -``` -$ npm init -$ npm install discord.js -``` - -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. - -4. Add bot to the A2Z server with the url: `https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot` - -5. Write the code! - -Login to bot account: -```javascript -const Discord = require('discord.js'); -const client = new Discord.Client(); -client.login('YOUR BOT TOKEN'); -``` - -Callback for when the bot is connected and ready: -```javascript -client.once('ready', () => { - console.log('Ready!'); -}); -``` - -Callback for when a message is posted: -```javascript -client.on('message', gotMessage); - -function gotMessage(msg) { - console.log(msg.content); -} -``` - -9. Run the bot! - -``` -$ node index.js -``` - -## Limit to one server and one channel - -1. Enable developer mode in Discord (Settings->Appearance->Enable Developer Mode). -2. Copy server ID. -3. Copy channel ID. - -```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'); - } - } -} -``` - -## Store token and other secrets in .env file. - -1. Install [dotenv package](https://www.npmjs.com/package/dotenv). -``` -$ npm install dotenv -``` - -2. Create `.env` file: - -``` -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; -``` diff --git a/01-discordjs/bot.js b/01-discordjs/bot.js new file mode 100644 index 0000000..93f2a37 --- /dev/null +++ b/01-discordjs/bot.js @@ -0,0 +1,31 @@ +// Import the necessary discord.js classes using ES6 syntax +import { Client, Events, GatewayIntentBits } from 'discord.js'; +import dotenv from 'dotenv'; +import * as choochoo from './commands/choochoo.js'; +import * as gif from './commands/gif.js'; + +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('💖'); +} + +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..7cfa342 --- /dev/null +++ b/01-discordjs/commands/choochoo.js @@ -0,0 +1,14 @@ +// Importing modules using ES6 syntax +import { SlashCommandBuilder } from 'discord.js'; + +// Replies array +const replies = ['🚂🌈💖', 'Choo choo!', 'Ding! 🛎', 'Never forget this dot!']; + +// 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 new file mode 100644 index 0000000..f03d651 --- /dev/null +++ b/01-discordjs/commands/gif.js @@ -0,0 +1,39 @@ +// 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: false }); + + // 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 6ffaf8c..b8f472b 100644 --- a/01-discordjs/deploy-commands.js +++ b/01-discordjs/deploy-commands.js @@ -1,25 +1,42 @@ -require('dotenv').config(); - -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { REST } = require('@discordjs/rest'); -const { Routes } = require('discord-api-types/v9'); - -// 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 rest = new REST({ version: '9' }).setToken(process.env.TOKEN); - -rest - .put(Routes.applicationGuildCommands(process.env.CLIENTID, process.env.SERVERID), { - body: commands, - }) - .then(() => console.log('Successfully registered application commands.')) - .catch(console.error); +// Slash Commands Deployment Script +// https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands/ + +// 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 = await import(`./commands/${file}`); // Using dynamic import + 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(process.env.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, + }); + + 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/env-sample b/01-discordjs/env-sample deleted file mode 100644 index d3752e7..0000000 --- a/01-discordjs/env-sample +++ /dev/null @@ -1,4 +0,0 @@ -SERVERID=1234 -CLIENTID=1234 -TOKEN=1234 -TENORKEY=1234 \ No newline at end of file diff --git a/01-discordjs/index.js b/01-discordjs/index.js deleted file mode 100644 index f1d540a..0000000 --- a/01-discordjs/index.js +++ /dev/null @@ -1,61 +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 - -require('dotenv').config(); - -const fetch = require('node-fetch'); - -console.log('Beep beep! 🤖'); - -// Require the necessary discord.js classes -const { Client, Intents } = 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); - -function readyDiscord() { - // require('./deploy-commands'); - 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}`, - }); - - // NOTE TO SELF: look at embeds - // https://discordjs.guide/popular-topics/embeds.html#embed-preview - } -}); diff --git a/01-discordjs/package-lock.json b/01-discordjs/package-lock.json index 582d379..d22d286 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": { "": { @@ -9,367 +9,340 @@ "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", - "discord.js": "^13.2.0", - "dotenv": "^10.0.0", - "node-fetch": "^2.6.5" + "discord.js": "^14.13.0", + "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==", + "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==", + "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==" - }, - "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==", + "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==", "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/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==", + "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": ">=16.11.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)", + "node_modules/@discordjs/util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", + "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==", "engines": { - "node": ">=12" + "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==", + "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.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.18.0", - "npm": ">=7.24.2" + "node": ">=v14.0.0", + "npm": ">=7.0.0" } }, - "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.", + "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==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, "engines": { - "node": ">=12", - "npm": ">=6" + "node": ">=v14.0.0", + "npm": ">=7.0.0" } }, - "node_modules/@sindresorhus/is": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", - "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", + "node_modules/@sapphire/snowflake": { + "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": "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.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.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.6", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.6.tgz", + "integrity": "sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg==", "dependencies": { "@types/node": "*" } }, - "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": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "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==", "engines": { - "node": ">=6" + "node": ">=v14.0.0", + "npm": ">=7.0.0" } }, - "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==", + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dependencies": { - "delayed-stream": "~1.0.0" + "streamsearch": "^1.1.0" }, "engines": { - "node": ">= 0.8" + "node": ">=10.16.0" } }, - "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=", + "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.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==", - "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": "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==", "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_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==", - "engines": { - "node": ">=14.0.0" + "node": ">=16.11.0" } }, - "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" - }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "engines": { - "node": ">=10" - } - }, - "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==", + "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==" + }, + "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": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, "engines": { - "node": ">=6" + "node": "^12.20 || >= 14.13" } }, - "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==", + "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": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "fetch-blob": "^3.1.2" }, "engines": { - "node": ">= 6" + "node": ">=12.20.0" } }, - "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==", - "engines": { - "node": ">=8" - } + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "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=" + "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==" }, - "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==", - "engines": { - "node": ">= 0.6" - } + "node_modules/magic-bytes.js": { + "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.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", - "dependencies": { - "mime-db": "1.50.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.5", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", - "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "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" - } - }, - "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/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } }, "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==" - }, - "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" + "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==", + "dependencies": { + "busboy": "^1.6.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vali-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", - "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", "engines": { - "node": ">=0.10.0" + "node": ">=14.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "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": ">= 8" } }, "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.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "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 +353,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..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,11 +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", - "discord.js": "^13.2.0", - "dotenv": "^10.0.0", - "node-fetch": "^2.6.5" + "discord.js": "^14.13.0", + "dotenv": "^16.3.1", + "node-fetch": "^3.3.2" } } diff --git a/02-command-handler/.DS_Store b/02-command-handler/.DS_Store deleted file mode 100644 index 4008cec..0000000 Binary files a/02-command-handler/.DS_Store and /dev/null differ 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/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/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/package-lock.json b/02-command-handler/package-lock.json deleted file mode 100644 index 6a19439..0000000 --- a/02-command-handler/package-lock.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "name": "choochoobot", - "version": "1.0.0", - "lockfileVersion": 1, - "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": { - "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": { - "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==" - } - } -} diff --git a/02-command-handler/package.json b/02-command-handler/package.json deleted file mode 100644 index 95fd18a..0000000 --- a/02-command-handler/package.json +++ /dev/null @@ -1,16 +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": { - "discord.js": "^12.3.1", - "dotenv": "^8.2.0", - "node-fetch": "^2.6.1" - } -} diff --git a/README.md b/README.md index 852b802..3c7f185 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,145 @@ # Discord Bot Examples -## Steps to create you 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 -$ 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"). +### 2. Create a Discord Application -3. Select Bot from left navigation and "Add Bot" - set name and icon. Note the "Bot Token" (keep this secret). +- 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"). -4. Add bot to the A2Z server with the url: `https://discord.com/oauth2/authorize?client_id=YOUR_APPLICATION_ID&scope=bot` +### 3. Create and Configure Your Bot -5. Enable "Developer Mode" on your discord client, right-click the server icon, and "copy ID" for the server ID. +- 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). -6. Create a `.env` file with your CLIENTID, SERVERID, and BOTTOKEN: +### 4. Add Bot to a Server +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. Install additional node packages. +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('💖'); +} ``` -$ npm install @discordjs/builders @discordjs/rest discord-api-types + +Run to see if it works! (If you see the 💖 it's working!) + +```sh +$ node bot.js ``` -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 a Command -9. Create `deploy-commands.js`, see example code for content. Customize your commands and execute! +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 ``` -10. 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/)