From 767394582c660e992f3697651288bab7e021bc31 Mon Sep 17 00:00:00 2001 From: Shay Date: Sat, 18 Mar 2023 16:05:36 -0700 Subject: [PATCH] update command registration to npm --- .env.sample | 1 - README.md | 10 ++++++++- app.js | 15 ++----------- commands.js | 55 ++++++++------------------------------------- examples/command.js | 7 +++--- package.json | 3 ++- utils.js | 12 ++++++++++ 7 files changed, 37 insertions(+), 66 deletions(-) diff --git a/.env.sample b/.env.sample index ed9591f..3d448af 100644 --- a/.env.sample +++ b/.env.sample @@ -1,4 +1,3 @@ APP_ID= -GUILD_ID= DISCORD_TOKEN= PUBLIC_KEY= diff --git a/README.md b/README.md index 3fa863d..6f078fc 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,20 @@ npm install ``` ### Get app credentials -Fetch the credentials from your app's settings and add them to a `.env` file (see `.env.sample` for an example). You'll need your app ID (`APP_ID`), server ID (`GUILD_ID`), bot token (`DISCORD_TOKEN`), and public key (`PUBLIC_KEY`). +Fetch the credentials from your app's settings and add them to a `.env` file (see `.env.sample` for an example). You'll need your app ID (`APP_ID`), bot token (`DISCORD_TOKEN`), and public key (`PUBLIC_KEY`). Fetching credentials is covered in detail in the [getting started guide](https://discord.com/developers/docs/getting-started). > πŸ”‘ Environment variables can be added to the `.env` file in Glitch or when developing locally, and in the Secrets tab in Replit (the lock icon on the left). +### Install slash commands + +The commands for the example app are set up in `commands.js`. All of the commands in the `ALL_COMMANDS` array at the bottom of `commands.js` will be installed when you run the `register` command configured in `package.json`: + +``` +npm run register +``` + ### Run the app After your credentials are added, go ahead and run the app: diff --git a/app.js b/app.js index 5dd9398..cc83e7f 100644 --- a/app.js +++ b/app.js @@ -9,11 +9,6 @@ import { } from 'discord-interactions'; import { VerifyDiscordRequest, getRandomEmoji, DiscordRequest } from './utils.js'; import { getShuffledOptions, getResult } from './game.js'; -import { - CHALLENGE_COMMAND, - TEST_COMMAND, - HasGuildCommands, -} from './commands.js'; // Create an express app const app = express(); @@ -46,7 +41,7 @@ app.post('/interactions', async function (req, res) { if (type === InteractionType.APPLICATION_COMMAND) { const { name } = data; - // "test" guild command + // "test" command if (name === 'test') { // Send a message into the channel where command was triggered from return res.send({ @@ -57,7 +52,7 @@ app.post('/interactions', async function (req, res) { }, }); } - // "challenge" guild command + // "challenge" command if (name === 'challenge' && id) { const userId = req.body.member.user.id; // User's object choice @@ -177,10 +172,4 @@ app.post('/interactions', async function (req, res) { app.listen(PORT, () => { console.log('Listening on port', PORT); - - // Check if guild commands from commands.js are installed (if not, install them) - HasGuildCommands(process.env.APP_ID, process.env.GUILD_ID, [ - TEST_COMMAND, - CHALLENGE_COMMAND, - ]); }); diff --git a/commands.js b/commands.js index 6521ada..63e496c 100644 --- a/commands.js +++ b/commands.js @@ -1,47 +1,6 @@ +import 'dotenv/config'; import { getRPSChoices } from './game.js'; -import { capitalize, DiscordRequest } from './utils.js'; - -export async function HasGuildCommands(appId, guildId, commands) { - if (guildId === '' || appId === '') return; - - commands.forEach((c) => HasGuildCommand(appId, guildId, c)); -} - -// Checks for a command -async function HasGuildCommand(appId, guildId, command) { - // API endpoint to get and post guild commands - const endpoint = `applications/${appId}/guilds/${guildId}/commands`; - - try { - const res = await DiscordRequest(endpoint, { method: 'GET' }); - const data = await res.json(); - - if (data) { - const installedNames = data.map((c) => c['name']); - // This is just matching on the name, so it's not good for updates - if (!installedNames.includes(command['name'])) { - console.log(`Installing "${command['name']}"`); - InstallGuildCommand(appId, guildId, command); - } else { - console.log(`"${command['name']}" command already installed`); - } - } - } catch (err) { - console.error(err); - } -} - -// Installs a command -export async function InstallGuildCommand(appId, guildId, command) { - // API endpoint to get and post guild commands - const endpoint = `applications/${appId}/guilds/${guildId}/commands`; - // install command - try { - await DiscordRequest(endpoint, { method: 'POST', body: command }); - } catch (err) { - console.error(err); - } -} +import { capitalize, InstallGlobalCommands } from './utils.js'; // Get the game choices from game.js function createCommandChoices() { @@ -59,14 +18,14 @@ function createCommandChoices() { } // Simple test command -export const TEST_COMMAND = { +const TEST_COMMAND = { name: 'test', - description: 'Basic guild command', + description: 'Basic command', type: 1, }; // Command containing options -export const CHALLENGE_COMMAND = { +const CHALLENGE_COMMAND = { name: 'challenge', description: 'Challenge to a match of rock paper scissors', options: [ @@ -80,3 +39,7 @@ export const CHALLENGE_COMMAND = { ], type: 1, }; + +const ALL_COMMANDS = [TEST_COMMAND, CHALLENGE_COMMAND]; + +InstallGlobalCommands(process.env.APP_ID, ALL_COMMANDS); \ No newline at end of file diff --git a/examples/command.js b/examples/command.js index 795b948..8d6552c 100644 --- a/examples/command.js +++ b/examples/command.js @@ -27,19 +27,18 @@ app.post('/interactions', function (req, res) { async function createCommand() { const appId = process.env.APP_ID; - const guildId = process.env.GUILD_ID; /** * Globally-scoped slash commands (generally only recommended for production) * See https://discord.com/developers/docs/interactions/application-commands#create-global-application-command */ - // const globalEndpoint = `applications/${appId}/commands`; + const globalEndpoint = `applications/${appId}/commands`; /** * Guild-scoped slash commands * See https://discord.com/developers/docs/interactions/application-commands#create-guild-application-command */ - const guildEndpoint = `applications/${appId}/guilds/${guildId}/commands`; + // const guildEndpoint = `applications/${appId}/guilds//commands`; const commandBody = { name: 'test', description: 'Just your average command', @@ -49,7 +48,7 @@ async function createCommand() { try { // Send HTTP request with bot token - const res = await DiscordRequest(guildEndpoint, { + const res = await DiscordRequest(globalEndpoint, { method: 'POST', body: commandBody, }); diff --git a/package.json b/package.json index 81dd96f..cf433d5 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "getting-started", "version": "1.0.0", - "description": "", + "description": "Discord example app", "main": "app.js", "type": "module", "scripts": { "start": "node app.js", + "register": "node commands.js", "dev": "nodemon app.js" }, "author": "Shay DeWael", diff --git a/utils.js b/utils.js index d7b2881..a9cc3cd 100644 --- a/utils.js +++ b/utils.js @@ -39,6 +39,18 @@ export async function DiscordRequest(endpoint, options) { return res; } +export async function InstallGlobalCommands(appId, commands) { + // API endpoint to overwrite global commands + const endpoint = `applications/${appId}/commands`; + + try { + // This is calling the bulk overwrite endpoint: https://discord.com/developers/docs/interactions/application-commands#bulk-overwrite-global-application-commands + await DiscordRequest(endpoint, { method: 'PUT', body: commands }); + } catch (err) { + console.error(err); + } +} + // Simple method that returns a random emoji from list export function getRandomEmoji() { const emojiList = ['😭','πŸ˜„','😌','πŸ€“','😎','😀','πŸ€–','πŸ˜Άβ€πŸŒ«οΈ','🌏','πŸ“Έ','πŸ’Ώ','πŸ‘‹','🌊','✨'];