TypeError: commands.options?.map() is not a function when setting slash commands - javascript

discord js v13.3.1
I have a set up with my bot that allows me to update and push slash commands via a command, deploy. The deploy command looks like this:
module.exports = {
name: "deploy",
description: "deploys slash commands",
disabled: false,
async execute(interaction, args, client) {
if (interaction.author.id !== process.env.OWNERID) return interaction.reply('You must be the owner to use this!');
const cmds = client.commands
.filter(command => command.slash)
.map(command => {
let {
name,
description = "missing description",
options = [],
slash = false,
defaultPermission = true,
slashPermissions = [],
} = command;
if (typeof name === "string") name = [name];
const cmd = { name: name[0], description, options, defaultPermission, permissions: slashPermissions };
return cmd;
});
await setCommands(interaction.guild?.commands)
.then(interaction.reply(`Registered ${cmds.length} commands to this guild!`));
async function setCommands(commandManager) {
const appCommands = await commandManager.set(
commandManager?.guild ? cmds : cmds.filter(cmd => !cmd.permissions.length)
);
if (commandManager?.guild) {
const fullPermissions = appCommands
.map(appCommand => {
const permissions = cmds.find(cmd => cmd.name === appCommand.name).permissions;
return { id: appCommand.id, permissions };
})
.filter(appCommand => appCommand.permissions.length);
await commandManager.permissions.set({ fullPermissions });
}
}
}
}
I stopped work on my bot awhile back, and now am trying to update the rest of my commands to have slash functionality. I have slash commands registered to my guild, so this command has worked in the past as is. Now, when I try to deploy my slash commands, I am getting this error in my console:
main\node_modules\discord.js\src\managers\ApplicationCommandManager.js:246
options: command.options?.map(o => ApplicationCommand.transformOption(o)),
^
TypeError: command.options?.map is not a function
at Function.transformCommand (main\node_modules\discord.js\src\managers\ApplicationCommandManager.js:246:33)
at main\node_modules\discord.js\src\managers\ApplicationCommandManager.js:163:48
at Array.map (<anonymous>)
at GuildApplicationCommandManager.set (main\node_modules\discord.js\src\managers\ApplicationCommandManager.js:163:22)
at setCommands (main\commands\admin\deploy.js:34:54)
at Object.execute (main\commands\admin\deploy.js:29:19)
at module.exports (main\events\guild\messageCreate.js:28:51)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
For reference, my commands are built as such:
module.exports = {
name: "move",
description: "Move all users from one vc to another",
usage: `\`${process.env.PREFIX}move <vc1> <vc2>\``,
alias: ["mv"],
disabled: false,
slash: true,
options: [
{
name: 'target',
type: 'CHANNEL',
channelTypes: ['GUILD_VOICE'],
description: 'Channel to move users from',
required: true
},
{
name: 'destination',
type: 'CHANNEL',
channelTypes: ['GUILD_VOICE'],
description: 'Channel to move users into',
required: true
}
],
permission: ['MOVE_MEMBERS'],
async execute(interaction, args){
}
}
Is this an issue with how I am building my options blocks in my commands themselves, or how I am parsing them to send to guildCommandManager? I'm assuming the former because the error is a TypeError, but I am historically bad at working with maps and objects, so I could be wrong, and it's hard for me to figure out since the error is being thrown from the djs module and not my code itself

Just use the rest method which you can view the code of it here on the discord.js guide.
https://discordjs.guide/creating-your-bot/creating-commands.html#command-deployment-script
You can create global commands with: applicationCommands
and create local commands for 1 server with: applicationGuildCommands

Related

Discord.js TypeError: Cannot read properties of undefined (reading 'mentions')

Alright, so I'm making a command that rejoins an user from its vc by just moving him to another channel and moving him back. But I can't define the member somehow.
const { CommandType } = require("wokcommands")
module.exports = {
category: 'Admin',
description: 'Rejoins a member from a vc',
type: CommandType.BOTH,
ownerOnly: true,
minArgs: 0,
maxArgs: 1,
expectedArgs: "<member>",
expectedArgsTypes: ['USER'],
callback: async (client, message, args) => {
console.log(message)
let member = message.mentions.members.first().user
if (!member) member = message.author.id
let mainChannel = client.channels.cache.get('1051265089078046743')
let transferChannel = client.channels.cache.get('1051267237891280926')
message.reply({
content: 'Rejoining member...'
})
member.voice.setChannel(transferChannel)
member.voice.setChannel(mainChannel)
return "Rejoined!"
}
}
Note: I'm using a dependency called "WOKCommands" as a command handler
Edit: Alright it's solved already. I just needed to destructure the callback.

Creating slash commands without options Discord.js V14

In attempt to create slash commands in Discord.JS V14 following the official guide, I came across the following error:
DiscordAPIError[50035]: Invalid Form Body
0[LIST_TYPE_CONVERT]: Only iterables may be used in a ListType
The specific command (ping) that I would like to create doesn't have any additional options as it's a very basic command and simply is just unethical to add any options.
ping.js:
module.exports = {
name: "ping",
description: "View the reaction times",
slashInfo: {
enabled: true,
public: false,
},
getSlashInfo: function() {
const { SlashCommandBuilder } = require("discord.js");
const builder = new SlashCommandBuilder();
// Set basic command information
builder.setName(this.name);
builder.setDescription(this.description);
// If the command can be used in DMs
builder.setDMPermission(true);
// Return the information in JSON format
return builder.toJSON();
},
async execute(interaction, _prefix, client) {
interaction.reply({ content: `**Pong** in ${client.ws.ping}ms` });
}
}
commandHandler.js:
function postSlashCommand(data, to, client) {
if (!to) {
// Post command to all guilds
rest.put(
Routes.applicationCommands(client.user.id),
{ body: data }
);
} else {
// Post command for use only in a specific server
rest.put(
Routes.applicationGuildCommands(client.user.id, to),
{ body: data }
);
}
}
async function setupSlashCommands(directory, client) {
// Loop through known command files
const commandFolders = fs.readdirSync(`./${directory}`).filter(file => !file.endsWith(".js") && !file.endsWith(".json"));
for (const folder of commandFolders) {
const commandFiles = fs.readdirSync(`./${directory}/${folder}`).filter(file => file.endsWith(".js"));
for (const file of commandFiles) {
// Find the command object
const command = require(`../../${directory}/${folder}/${file}`);
// Ensure the command supports slash
if (!command.slashInfo?.enabled) return;
// Get the slash data
let data = command.getSlashInfo();
// Post the command to Discord
if (command.slashInfo.public) { // If the slash command is public
// Post command to all guilds
postSlashCommand(data, null, client);
} else { // If the slash command is in testing
// Post command for use only in the dev server
postSlashCommand(data, require("../../utils/config.json").DevServer, client);
}
}
}
}
module.exports = (client) => setupSlashCommands("commands", client);
Full error:
throw new DiscordAPIError.DiscordAPIError(data, "code" in data ? data.code : data.error, status, method, url, requestData);
^
DiscordAPIError[50035]: Invalid Form Body
0[LIST_TYPE_CONVERT]: Only iterables may be used in a ListType
at SequentialHandler.runRequest (D:\Projects\...\node_modules\#discordjs\rest\dist\lib\handlers\SequentialHandler.cjs:287:15)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async SequentialHandler.queueRequest (D:\Projects\...\node_modules\#discordjs\rest\dist\lib\handlers\SequentialHandler.cjs:99:14)
at async REST.request (D:\Projects\...\node_modules\#discordjs\rest\dist\lib\REST.cjs:52:22) {
rawError: {
code: 50035,
errors: {
_errors: [
{
code: 'LIST_TYPE_CONVERT',
message: 'Only iterables may be used in a ListType'
}
]
},
message: 'Invalid Form Body'
},
code: 50035,
status: 400,
method: 'PUT',
url: 'https://discord.com/api/v10/applications/<application_id>/guilds/<guild_id>/commands',
requestBody: {
files: undefined,
json: {
options: [],
name: 'ping',
name_localizations: undefined,
description: 'View the reaction times',
description_localizations: undefined,
default_permission: undefined,
default_member_permissions: undefined,
dm_permission: true
}
}
}
Is there any way to simply create a slash command without providing the options property?
That endpoint takes an array of application commands. Instead of attempting to put a single command at a time, put all of them at once. Add the data to an array, then you will register them
const globalCommands = [],
guildCommands = [];
// Loop through known command files
const commandFolders = fs.readdirSync(`./${directory}`).filter(file => !file.endsWith(".js") && !file.endsWith(".json"));
for (const folder of commandFolders) {
const commandFiles = fs.readdirSync(`./${directory}/${folder}`).filter(file => file.endsWith(".js"));
for (const file of commandFiles) {
const command = require(`../../${directory}/${folder}/${file}`);
// Ensure the command supports slash
if (!command.slashInfo?.enabled) return;
// Add the slash data to the array
if (command.slashInfo.public) globalCommands.push(command.getSlashInfo());
else guildCommands.push(command.getSlashInfo())
}
}
Afterward, simply put the commands, and with what I see, you want to do global and guild commands, separately
postSlashCommand(guildCommands, require("../../utils/config.json").DevServer, client)
postSlashCommand(globalCommands, null, client)

How can I change this kick command fully to get a reply when you try to kick a member that is not in the server?

So I have this kick command I have coded and it is working perfectly fine. My question is, how can I change the command so that I get a reply saying as an example "You can't kick this user since they are not in this server" or so.
Here is my code:
const { Client, CommandInteraction, MessageEmbed } = require("discord.js");
module.exports = {
name: "kick",
description: "Kick a member",
userPermission: ["KICK_MEMBERS"],
options: [
{
name: "target",
description: "target to kick",
type: "USER",
required: true
},
{
name: "reason",
description: "reason for this kick",
type: "STRING",
required: false,
}
],
/**
*
* #param {Client} client
* #param {CommandInteraction} interaction
* #param {String} args
*/
execute: async(interaction, client, args) => {
const { options, member, guild } = interaction;
const target = options.getMember("target");
const reason = options.getString("reason") || "No reason provided";
if(!target.roles.highest.position >= member.roles.highest.position) return interaction.reply({content: "You can't take action on this user as their role is higher than yours!",
});
await target.send({embeds: [new MessageEmbed().setColor("AQUA").setTitle("🚪 Kicked").setAuthor(target.user.tag, target.user.avatarURL({dynamic: true, size: 512})).setDescription(`You have been kicked from **${guild.name}**!\nReason: \`${reason}\``).setFooter(`ID: ${target.user.id}`)]});
target.kick(reason);
interaction.reply({embeds: [new MessageEmbed().setColor("GREEN").setTitle("🚪 Kick").setAuthor(target.user.tag, target.user.avatarURL({dynamic: true, size: 512})).setDescription(`**${target.user.tag}** has successfully been kicked from **${guild.name}**!\n**Reason:** \`${reason}\``).setFooter(`ID: ${target.user.id}`)]});
},
};
Because this is a slash command and requires a USER here:
name: "target",
description: "target to kick",
type: "USER",
required: true
Then there can never exist a possibility of this command running without the user being in the guild. The command would error before it was sent.
Edit:
Also your line
const target = options.getMember("target");
Should be
const target = options.getUser("target");
You would need to get the member using the below:
const targetMember = guild.members.cache.find(member => member.id === target)
Then every line below that where target is used change to targetMember
Edit answering question in comments:
To kick/ban someone not in the guild
const targetMember = guild.members.cache.find(member => member.id === target)
if (targetMember = undefined) {
// code to kick/ban
} else {
// normal code
}

403 Forbidden when connecting to pterodactyl websocket

I was wondering if someone could help me. I'm making a program that connects to pterodactyl's websocket but every time I try and connect it gives me a 403 - Forbidden. I've been researching this error for a few hours and I can't seem to find a fix. I'm using NodeJS v17.
Here's the code:
const embed = require('../../Configs/embed.json');
let PterodactylUser = require('../../Structures/Panel/PterodactylUser.js');
const SQL = require('../../Structures/Panel/SQL/SQL.js');
const mainConfig = require('../../Configs/config.json');
const WebSocket = require("ws");
module.exports = {
name: 'Output',
description: 'Sends live console output for the selected server!',
category: 'Servers',
enabled: true,
options: [
{
name: "start",
type: "SUB_COMMAND",
description: "Starts sending console output for the server.",
options: [
{
name: "id",
type: "STRING",
description: "The ID of the server to link!",
required: true
},
{
name: "channel",
type: "CHANNEL",
channelTypes: ["GUILD_TEXT", "GUILD_NEWS"],
description: "The channel to link if not set uses current channel!"
}
]
}
],
needsAPIKey: true,
async execute(client, Discord, mainConfig, interaction, args) {
const user = interaction.user || interaction.author;
const channel = args.getChannel('channel') ? args.getChannel('channel') : interaction.channel;
const serverId = args.getString('id');
const mysql = new SQL();
let apiKey = await mysql.getApiKey(user.id, interaction.guild.id);
let res = await new PterodactylUser(apiKey).getWebsocket(serverId);
const { socket, token } = res.data;
const ws = new WebSocket(socket);
}
}
I had similar problem caused by misconfigured panel access settings. You need to edit /etc/pterodactyl/config.yml
Citing the creator of PteroJS library from my issue:
The origin of the websocket request is not whitelisted. If you have access to Wings for the node you're using then set allowed_origins in "config.yml" to this:
allowed_origins:
- "*"
Otherwise, contact your panel administrator about it.

how to reference a currency collection from within a module in nodejs

I'm attempting to make an economy discord bot using node.js and I'm trying to move the commands into modules so that I can have a generic/dynamic command handler. How do I reference the currency collection and the models that I created within the main file within the command modules?
index.js file:
const currency = new Discord.Collection();
//defining methods for the currency collection
Reflect.defineProperty(currency, 'add', {
/* eslint-disable-next-line func-name-matching */
value: async function add(id, amount) {
const user = currency.get(id);
if (user) {
user.balance += Number(amount);
return user.save();
}
const newUser = await Users.create({ user_id: id, balance: amount });
currency.set(id, newUser);
return newUser;
},
});
Reflect.defineProperty(currency, 'getBalance', {
/* eslint-disable-next-line func-name-matching */
value: function getBalance(id) {
const user = currency.get(id);
return user ? user.balance : 0;
},
});
(In a subfolder) balance.js:
module.exports = {
name: 'balance',
description: 'get balance',
execute(message, args) {
const target = message.mentions.users.first() || message.author;
return message.channel.send(`${target.tag} has ${currency.getBalance(target.id)}🍉`);
},
};
Which currently throws an error on currency, since it's not defined. However, I don't know how to reference the currency collection I made in index.js, which also has methods created for it.
Thank you in advance.
To do this you could attach the Collection to your Client. Something like
Client.currency = new Discord.Collection()
Every time you then reference the collection, instead of doing currency you would then run Client.currency.
As for accessing the currency object across the files, I'd add another parameter to your execute method, something like this:
module.exports = {
name: 'balance',
description: 'get balance',
execute(client, message, args) { // Notice the added "client"
const target = message.mentions.users.first() || message.author;
return message.channel.send(`${target.tag} has ${client.currency.getBalance(target.id)}🍉`); // Added "client." in front of "currency", because currency is a property of your client now
},
};
Then, when executing the execute method, you'd run execute(Client, message, arguments);. Your client would then be passed into the command and be usable in there.

Categories

Resources