Merge pull request #73 from Vylpes/feature/23-migrate-to-typescript

Feature/23 migrate to typescript
This commit is contained in:
Vylpes 2021-12-04 15:51:41 +00:00 committed by GitHub
commit 598a0b5a44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 1421 additions and 1346 deletions

36
.env.template Normal file
View file

@ -0,0 +1,36 @@
# Security Warning! Do not commit this file to any VCS!
# This is a local file to speed up development process,
# so you don't have to change your environment variables.
#
# This is not applied to `.env.template`!
# Template files must be committed to the VCS, but must not contain
# any secret values.
BOT_TOKEN=
BOT_PREFIX=v!
BOT_VER=3.0
BOT_AUTHOR=Vylpes
BOT_DATE=28 Nov 2021
BOT_OWNERID=147392775707426816
CORE_VER=2.0.2
FOLDERS_COMMANDS=src/commands
FOLDERS_EVENTS=src/events
COMMANDS_DISABLED=
COMMANDS_DISABLED_MESSAGE=This command is disabled.
COMMANDS_ROLE_ROLES=Notify,VotePings,ProjectUpdates
COMMANDS_RULES_FILE=data/rules/rules.json
EMBED_COLOUR=0x3050ba
EMBED_COLOUR_ERROR=0xD52803
ROLES_MODERATOR=Moderator
ROLES_MUTED=Muted
CHANNELS_LOGS_MESSAGE=message-logs
CHANNELS_LOGS_MEMBER=member-logs
CHANNELS_LOGS_MOD=mod-logs

View file

@ -1,45 +0,0 @@
// Required components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const embedColor = "0x3050ba";
// Command Class
class about extends command {
constructor() {
// Set execute method, description, and category
super("about");
super.description = "About the bot";
super.category = "General";
// Set required configs in the config.about json string.
// description: The bot description
// version: The bot version
// author: Bot author
// date: Date of build
super.requiredConfigs = "description";
super.requiredConfigs = "version";
super.requiredConfigs = "core-ver";
super.requiredConfigs = "author";
super.requiredConfigs = "date";
}
// The execution method
about(context) {
// Create an embed containing data about the bot
const embed = new MessageEmbed()
.setTitle("About")
.setColor(embedColor)
.setDescription(context.client.config.about.description)
.addField("Version", context.client.config.about.version, true)
.addField("VylBot Core", context.client.config.about['core-ver'], true)
.addField("Author", context.client.config.about.author)
.addField("Date", context.client.config.about.date);
// Send embed to the channel the command was sent in
context.message.channel.send(embed);
}
}
// Set the about class to be exported
module.exports = about;

View file

@ -1,93 +0,0 @@
// Required components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const embedColor = "0x3050ba";
// Command Class
class ban extends command {
constructor() {
// Set execution method, description, category, and usage
super("ban");
super.description = "Bans the mentioned user with an optional reason";
super.category = "Moderation";
super.usage = "<@user> [reason]";
// Set required configs in the config.ban json string
super.requiredConfigs = "modrole";
super.requiredCofigs = "logchannel";
}
// Command execution method
ban(context) {
// If the user has the modrole (set in config.ban.modrole)
if (context.message.guild.roles.cache.find(role => role.name == context.client.config.ban.modrole)) {
// Gets the user pinged in the command
const user = context.message.mentions.users.first();
// If the user pinged is a valid user
if (user) {
// Get the guild member object from the pinged user
const member = context.message.guild.member(user);
// If the member object exists, i.e. if they are in the server
if (member) {
// Get the arguments and remove what isn't the reason
const reasonArgs = context.arguments;
reasonArgs.splice(0, 1);
// Join the array into a string
const reason = reasonArgs.join(" ");
// If the guild is available to work with
if (context.message.guild.available) {
// If the bot client is able to ban the member
if (member.bannable) {
// The Message Embed which goes into the bot log
const embedLog = new MessageEmbed()
.setTitle("Member Banned")
.setColor(embedColor)
.addField("User", `${user} \`${user.tag}\``, true)
.addField("Moderator", `${context.message.author} \`${context.message.author.tag}\``, true)
.addField("Reason", reason || "*none*")
.setThumbnail(user.displayAvatarURL);
// The Message Embed which goes into the public channel the message was sent in
const embedPublic = new MessageEmbed()
.setColor(embedColor)
.setDescription(`${user} has been banned`);
// Ban the member and send the embeds into the appropriate channel, then delete the initial message
member.ban({ reason: reason }).then(() => {
context.message.guild.channels.cache.find(channel => channel.name == context.client.config.ban.logchannel).send(embedLog);
context.message.channel.send(embedPublic);
context.message.delete();
}).catch(err => { // If the bot couldn't ban the member, say so and log the error to the console
errorEmbed(context, "An error occurred");
console.log(err);
});
}
}
} else { // If the member object doesn't exist
errorEmbed(context, "User is not in this server");
}
} else { // If the user object doesn't exist
errorEmbed(context, "User does not exist");
}
} else { // If the user doesn't have the mod role
errorEmbed(context, `You require the \`${context.client.config.ban.modrole}\` role to run this command`);
}
}
}
// Post an error embed
function errorEmbed(context, message) {
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(message);
context.message.channel.send(embed);
}
module.exports = ban;

View file

@ -1,35 +0,0 @@
// Required components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const randomBunny = require('random-bunny');
// Command variables
const embedColor = "0x3050ba";
// Command class
class bunny extends command {
constructor() {
// Set run method, description, and category
super("bunny");
super.description = "Gives you a random bunny";
super.category = "Fun";
}
// Run method
bunny(context) {
// Get a random post from r/Rabbits
randomBunny('rabbits', 'hot', (image, title) => {
// Create an embed containing the random image
const embed = new MessageEmbed()
.setColor(embedColor)
.setTitle(title)
.setImage(image)
.setFooter('r/Rabbits');
// Send the embed
context.message.channel.send(embed);
});
}
}
module.exports = bunny;

View file

@ -1,58 +0,0 @@
// Required components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const embedColor = "0x3050ba";
// Command Class
class clear extends command {
constructor() {
// Set execute method, description, category, and usage
super("clear");
super.description = "Bulk deletes the chat for up to 100 messages";
super.category = "Moderation";
super.usage = "<amount>";
// Set required configs in the config.clear json string
super.requiredConfigs = "modrole";
super.requiredConfigs = "logchannel";
}
// Execute method
clear(context) {
// If the user has the config.clear.modrole role
if (context.message.member.roles.cache.find(role => role.name == context.client.config.clear.modrole)) {
// If the command specifies a number between 1 and 100
if (context.arguments.length > 0 && context.arguments[0] > 0 && context.arguments[0] < 101) {
// Attempt to bulk delete the amount of messages specified as an argument
context.message.channel.bulkDelete(context.arguments[0]).then(() => {
// Public embed
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(`${context.arguments[0]} messages were removed`);
// Send the embed into the channel the command was sent in
context.message.channel.send(embed);
}).catch(err => { // If the bot couldn't bulk delete
errorEmbed(context, "An error has occurred");
console.log(err);
});
} else { // If the user didn't give a number valid (between 1 and 100)
errorEmbed(context, "Please specify an amount between 1 and 100");
}
} else { // If the user doesn't have the mod role
errorEmbed(context, `This command requires the \`${context.client.config.clear.modrole}\` role to run`);
}
}
}
// Function to send an error embed
function errorEmbed(context, message) {
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(message);
context.message.channel.send(embed);
}
module.exports = clear;

View file

@ -1,25 +0,0 @@
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
class evaluate extends command {
constructor() {
super("evaluate");
super.description = "Evaluates an expression";
super.category = "Administration";
super.requiredConfigs = "ownerid";
}
evaluate(context) {
if (context.message.author.id == context.client.config.eval.ownerid) {
const result = eval(context.arguments.join(" "));
const embed = new MessageEmbed()
.setDescription(result)
.setColor(0x3050ba);
context.message.channel.send(embed);
}
}
}
module.exports = evaluate;

View file

@ -1,150 +0,0 @@
// Required Components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const { readdirSync } = require('fs');
const embedColor = "0x3050ba";
// Command Class
class help extends command {
constructor() {
// Set the execute method, description, category, and example usage
super("help");
super.description = "Gives a list of commands available in the bot";
super.category = "General";
super.usage = "[command]";
}
// Execute method
help(context) {
// Get the list of command folders the bot has been setup to check
const commandFolders = context.client.config.commands;
// Empty arrays for commands
// allCommands: Will contain objects of all commands with their related info
// categories: Will contain strings of all the categories the commands are set to, unique
const allCommands = [];
const categories = [];
// Loop through all the command folders set
// i = folder index
for (let i = 0; i < commandFolders.length; i++) {
// The current folder the bot is looking through
const folder = commandFolders[i];
// Read the directory of the current folder
const contents = readdirSync(`${process.cwd()}/${folder}`);
// Loop through the contents of the folder
// j = file index in folder i
for (let j = 0; j < contents.length; j++) {
// Get command in the current folder to read
const file = require(`${process.cwd()}/${folder}/${contents[j]}`);
// Initialise the command
const obj = new file();
// Data object containing the command information
const data = {
"name": contents[j].replace(".js", ""),
"description": obj.description,
"category": obj.category,
"usage": obj.usage,
"roles": obj.roles
};
// Push the command data to the allCommands Array
allCommands.push(data);
}
}
// Loop through all the commands discovered by the previous loop
for (let i = 0; i < allCommands.length; i++) {
// Get the current command category name, otherwise "none"
const category = allCommands[i].category || "none";
// If the command isn't already set, set it.
// This will then make the categories array be an array of all categories which have been used but only one of each.
if (!categories.includes(category)) categories.push(category);
}
// If an command name has been passed as an argument
// If so, send information about that command
// If not, send the help embed of all commands
if (context.arguments[0]) {
sendCommand(context, allCommands, context.arguments[0]);
} else {
sendAll(context, categories, allCommands);
}
}
}
// Send embed of all commands
// context: The command context json string
// categories: The array of categories found
// allCommands: The array of the commands found
function sendAll(context, categories, allCommands) {
// Embed to be sent
const embed = new MessageEmbed()
.setColor(embedColor)
.setTitle("Commands");
// Loop through each command
for (let i = 0; i < categories.length; i++) {
// The category name of the current one to check
const category = categories[i];
// Empty Array for the next loop to filter out the current category
const commandsFilter = [];
// Loop through allCommands
// If the command is set to the current category being checked, add it to the filter array
for (let j = 0; j < allCommands.length; j++) {
if (allCommands[j].category == category) commandsFilter.push(`\`${allCommands[j].name}\``);
}
// Add a field to the embed which contains the category name and all the commands in that category
embed.addField(category, commandsFilter.join(", "));
}
// Send the embed
context.message.channel.send(embed);
}
// Send information about a specific command
// context: The command context json string
// allCommands: The array of categories found
// name: The command name to check
function sendCommand(context, allCommands, name) {
let command = {};
// Loop through all commands, if the command name is the same as the one we're looking for, select it
for (let i = 0; i < allCommands.length; i++) {
if (allCommands[i].name == name) command = allCommands[i];
}
// If a matching command has been found
if (command.name) {
// Create an embed containing the related information of the command
// The title is the command name but sets the first letter to be capitalised
// If a set of information isn't set, set it to say "none"
const embed = new MessageEmbed()
.setColor(embedColor)
.setTitle(command.name[0].toUpperCase() + command.name.substring(1))
.setDescription(command.description || "*none*")
.addField("Category", command.category || "*none*", true)
.addField("Usage", command.usage || "*none*", true)
.addField("Required Roles", command.roles.join(", ") || "*none*");
// Send the embed
context.message.channel.send(embed);
} else { // If no command has been found, then send an embed which says this
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription("Command does not exist");
context.message.channel.send(embed);
}
}
module.exports = help;

View file

@ -1,93 +0,0 @@
// Required Components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const embedColor = "0x3050ba";
// Command Class
class kick extends command {
constructor() {
// Sets the command's run method, description, category, and usage
super("kick");
super.description = "Kicks the mentioned user with an optional reason";
super.category = "Moderation";
super.usage = "<@user> [reason]";
// Sets the required configs for the command
super.requiredConfigs = "modrole";
super.requiredConfigs = "logchannel";
}
// The command's run method
kick(context) {
// Checks if the user has the mod role, set in the config json string
if (context.message.member.roles.cache.find(role => role.name == context.client.config.kick.modrole)) {
// Gets the first user pinged in the command
const user = context.message.mentions.users.first();
// If a user was pinged
if (user) {
// Gets the guild member object of the pinged user
const member = context.message.guild.member(user);
// If the member object exists, i.e if the user is in the server
if (member) {
// Gets the part of the argument array which holds the reason
const reasonArgs = context.arguments;
reasonArgs.splice(0, 1);
// Joins the reason into a string
const reason = reasonArgs.join(" ");
// If the server is available
if (context.message.guild.available) {
// If the bot client can kick the mentioned member
if (member.kickable) {
// The embed to go into the bot log
const embedLog = new MessageEmbed()
.setTitle("Member Kicked")
.setColor(embedColor)
.addField("User", `${user} \`${user.tag}\``, true)
.addField("Moderator", `${context.message.author} \`${context.message.author.tag}\``, true)
.addField("Reason", reason || "*none*")
.setThumbnail(user.displayAvatarURL);
// The embed to go into channel the command was sent in
const embedPublic = new MessageEmbed()
.setColor(embedColor)
.setDescription(`${user} has been kicked`);
// Attemtp to kick the user, if successful send the embeds, if unsuccessful notify the chat and log the error
member.kick({ reason: reason }).then(() => {
context.message.guild.channels.cache.find(channel => channel.name == context.client.config.kick.logchannel).send(embedLog);
context.message.channel.send(embedPublic);
context.message.delete();
}).catch(err => {
errorEmbed(context, "An error has occurred");
console.log(err);
});
} else { // If the user isn't kickable
errorEmbed(context, "I am unable to kick this user");
}
}
} else { // If the member object is invalid
errorEmbed(context, "Please specify a valid user");
}
} else { // If the user object is invalid
errorEmbed(context, "Please specify a valid user");
}
}
}
}
// Function to post an embed in case of an error
function errorEmbed(context, message) {
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(message);
context.message.channel.send(embed);
}
module.exports = kick;

View file

@ -1,98 +0,0 @@
// Required Components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const embedColor = "0x3050ba";
// Command Class
class mute extends command {
constructor() {
// Set the command's run method, description, category, and usage
super("mute");
super.description = "Mutes the mentioned user with an optional reason";
super.category = "Moderation";
super.usage = "<@user> [reason]";
// Set the required configs for the command
super.requiredConfigs = "modrole";
super.requiredConfigs = "logchannel";
super.requiredConfigs = "muterole";
}
// The command's run method
mute(context) {
// Check if the user has the mod role
if (context.message.member.roles.cache.find(role => role.name == context.client.config.mute.modrole)) {
// Get the user first pinged in the message
const user = context.message.mentions.users.first();
// If the user object exists
if (user) {
// Get the guild member object of the mentioned user
const member = context.message.guild.member(user);
// If the member object exists, i.e. if the user is in the server
if (member) {
// Get the part of the arguments array which contains the reason
const reasonArgs = context.arguments;
reasonArgs.splice(0, 1);
// Join the reason into a string
const reason = reasonArgs.join(" ");
// If the server is available
if (context.message.guild.available) {
// If the bot client can manage the user's roles
if (member.manageable) {
// The embed to go into the bot log
const embedLog = new MessageEmbed()
.setTitle("Member Muted")
.setColor(embedColor)
.addField("User", `${user} \`${user.tag}\``, true)
.addField("Moderator", `${context.message.author} \`${context.message.author.tag}\``, true)
.addField("Reason", reason || "*none*")
.setThumbnail(user.displayAvatarURL);
// The embed to go into the channel the command was sent in
const embedPublic = new MessageEmbed()
.setColor(embedColor)
.setDescription(`${user} has been muted`)
.addField("Reason", reason || "*none*");
// Get the 'Muted' role
const mutedRole = context.message.guild.roles.cache.find(role => role.name == context.client.config.mute.muterole);
// Attempt to mute the user, if successful send the embeds, if not log the error
member.roles.add(mutedRole, reason).then(() => {
context.message.guild.channels.cache.find(channel => channel.name == context.client.config.mute.logchannel).send(embedLog);
context.message.channel.send(embedPublic);
context.message.delete();
}).catch(err => {
errorEmbed(context, "An error occurred");
console.log(err);
});
} else { // If the bot can't manage the user
errorEmbed(context, "I am unable to mute this user");
}
}
} else { // If the member object doesn't exist
errorEmbed(context, "Please specify a valid user");
}
} else { // If the user object doesn't exist
errorEmbed(context, "Please specify a valid user");
}
}
}
}
// Send an embed when an error occurs
function errorEmbed(context, message) {
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(message);
context.message.channel.send(embed);
}
module.exports = mute;

View file

@ -1,60 +0,0 @@
// Required components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const { existsSync, readFileSync } = require('fs');
// Command Variables
const embedColor = "0x3050ba";
// Command class
class partner extends command {
constructor() {
// Set the command's run method, description, and category
super("partner");
super.description = "Generates the embeds for the partner from the partners.json file";
super.category = "Admin";
// Require in the config the name of the admin role and the rules file name
super.requiredConfigs = "adminrole";
super.requiredConfigs = "partnersfile";
}
// Run method
partner(context) {
if (context.message.member.roles.cache.find(role => role.name == context.client.config.partner.adminrole)) {
if (existsSync(context.client.config.partner.partnersfile)) {
const partnerJson = JSON.parse(readFileSync(context.client.config.partner.partnersfile));
for (const i in partnerJson) {
const serverName = partnerJson[i].name;
const serverInvite = partnerJson[i].invite;
const serverDescription = partnerJson[i].description;
const serverIcon = partnerJson[i].icon;
const embed = new MessageEmbed()
.setColor(embedColor)
.setTitle(serverName)
.setDescription(serverDescription)
.setURL(serverInvite)
.setThumbnail(serverIcon);
context.message.channel.send(embed);
}
} else {
const errorEmbed = new MessageEmbed()
.setColor(embedColor)
.setDescription('File does not exist');
context.message.channel.send(errorEmbed);
}
} else {
const errorEmbed = new MessageEmbed()
.setColor(embedColor)
.setDescription('You do not have permission to run this command');
context.message.channel.send(errorEmbed);
}
}
}
module.exports = partner;

View file

@ -1,150 +0,0 @@
// Required components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const emojiRegex = require('emoji-regex/RGI_Emoji');
// Command variables
const embedColor = "0x3050ba";
// Command class
class poll extends command {
constructor() {
// Set the command's run method, description, category, and example usage
super("poll");
super.description = "Generates a poll with reaction numbers";
super.category = "General";
super.usage = "<title>;<option 1>;<option 2>...";
}
// Run method
poll(context) {
// Get the command's arguments, and split them by a semicolon rather than a space
// This allows the variables to be able to use spaces in them
let args = context.arguments;
const argsJoined = args.join(' ');
args = argsJoined.split(';');
// If the argument has 3 or more arguments and less than 11 arguments
// This allows the title and 2-9 options
if (args.length >= 3 && args.length < 11) {
// Set the title to the first argument
const title = args[0];
let optionString = "";
// Array used to get the numbers as their words
// arrayOfNumbers[n] = "n written in full words"
const arrayOfNumbers = [
':zero:',
':one:',
':two:',
':three:',
':four:',
':five:',
':six:',
':seven:',
':eight:',
':nine:'
];
// Array containing the numbers as their emoji
const reactionEmojis = ["0⃣", "1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣"];
// Loop through all the arguments after the title
// Add them to the optionString, with their index turned into a number emoji
// Example: :one: Option 1
for (let i = 1; i < args.length; i++) {
// If the option contains an emoji, replace the emoji with it
const regex = emojiRegex();
const match = regex.exec(args[i]);
if (match) {
const emoji = match[0];
reactionEmojis[i] = emoji;
arrayOfNumbers[i] = '';
}
optionString += `${arrayOfNumbers[i]} ${args[i]}\n`;
}
// Create the embed with the title at the top of the description with the options below
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(`**${title}**\n\n${optionString}`);
// Send the embed and then react with the numbers for users to react with,
// the bot will determine how many to react with for the amount of options inputted
context.message.channel.send(embed).then(message => {
if (args.length == 2) {
message.react(reactionEmojis[1]);
} else if (args.length == 3) {
message.react(reactionEmojis[1])
.then(() => message.react(reactionEmojis[2]));
} else if (args.length == 4) {
message.react(reactionEmojis[1])
.then(() => message.react(reactionEmojis[2]))
.then(() => message.react(reactionEmojis[3]));
} else if (args.length == 5) {
message.react(reactionEmojis[1])
.then(() => message.react(reactionEmojis[2]))
.then(() => message.react(reactionEmojis[3]))
.then(() => message.react(reactionEmojis[4]));
} else if (args.length == 6) {
message.react(reactionEmojis[1])
.then(() => message.react(reactionEmojis[2]))
.then(() => message.react(reactionEmojis[3]))
.then(() => message.react(reactionEmojis[4]))
.then(() => message.react(reactionEmojis[5]));
} else if (args.length == 7) {
message.react(reactionEmojis[1])
.then(() => message.react(reactionEmojis[2]))
.then(() => message.react(reactionEmojis[3]))
.then(() => message.react(reactionEmojis[4]))
.then(() => message.react(reactionEmojis[5]))
.then(() => message.react(reactionEmojis[6]));
} else if (args.length == 8) {
message.react(reactionEmojis[1])
.then(() => message.react(reactionEmojis[2]))
.then(() => message.react(reactionEmojis[3]))
.then(() => message.react(reactionEmojis[4]))
.then(() => message.react(reactionEmojis[5]))
.then(() => message.react(reactionEmojis[6]))
.then(() => message.react(reactionEmojis[7]));
} else if (args.length == 9) {
message.react(reactionEmojis[1])
.then(() => message.react(reactionEmojis[2]))
.then(() => message.react(reactionEmojis[3]))
.then(() => message.react(reactionEmojis[4]))
.then(() => message.react(reactionEmojis[5]))
.then(() => message.react(reactionEmojis[6]))
.then(() => message.react(reactionEmojis[7]))
.then(() => message.react(reactionEmojis[8]));
} else if (args.length == 10) {
message.react(reactionEmojis[1])
.then(() => message.react(reactionEmojis[2]))
.then(() => message.react(reactionEmojis[3]))
.then(() => message.react(reactionEmojis[4]))
.then(() => message.react(reactionEmojis[5]))
.then(() => message.react(reactionEmojis[6]))
.then(() => message.react(reactionEmojis[7]))
.then(() => message.react(reactionEmojis[8]))
.then(() => message.react(reactionEmojis[9]));
}
}).catch(console.error);
// Delete the message
context.message.delete();
} else if (args.length >= 11) { // If the user inputted more than 9 options
const errorEmbed = new MessageEmbed()
.setDescription("The poll command can only accept up to 9 options");
context.message.channel.send(errorEmbed);
} else { // If the user didn't give enough data
const errorEmbed = new MessageEmbed()
.setDescription("Please use the correct usage: <title>;<option 1>;<option 2>... (separate options with semicolons)");
context.message.channel.send(errorEmbed);
}
}
}
module.exports = poll;

View file

@ -1,105 +0,0 @@
// Required components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
// Command variables
const embedColor = "0x3050ba";
// Command class
class role extends command {
constructor() {
// Set the command's run method, description, category, and example usage
super("role");
super.description = "Toggles a role for the user to gain/remove";
super.category = "General";
super.usage = "[name]";
// Require in the config the 'assignable roles' array
super.requiredConfigs = "assignable";
}
// Run method
role(context) {
// Get the array containing the assignable roles
const roles = context.client.config.role.assignable;
let requestedRole = "";
// If the arguments specifys a specific role
if (context.arguments.length > 0) {
// Loop through all the assignable roles and check against the first parameter
// Save the role name if they match, i.e. the role can be assignable
for (let i = 0; i < roles.length; i++) {
if (roles[i].toLowerCase() == context.arguments[0].toLowerCase()) {
requestedRole = roles[i];
}
}
// If a matching assignable role was found
if (requestedRole != "") {
// Get the role object from the server with the role name
const role = context.message.guild.roles.cache.find(r => r.name == requestedRole);
// If the user already has the role, remove the role from them and send an embed
// Otherwise, add the role and send an embed
if (context.message.member.roles.cache.find(r => r.name == requestedRole)) {
context.message.member.roles.remove(role).then(() => {
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(`Removed role: ${requestedRole}`);
context.message.channel.send(embed);
}).catch(err => {
console.error(err);
const errorEmbed = new MessageEmbed()
.setColor(embedColor)
.setDescription("An error occured. Please check logs");
context.message.channel.send(errorEmbed);
});
} else { // If the user doesn't have the role
context.message.member.roles.add(role).then(() => {
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(`Gave role: ${requestedRole}`);
context.message.channel.send(embed);
}).catch(err => {
console.error(err);
const errorEmbed = new MessageEmbed()
.setColor(embedColor)
.setDescription("An error occured. Please check logs");
context.message.channel.send(errorEmbed);
});
}
} else { // If the role can't be found, send an error embed
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription("This role does not exist, see assignable roles with the role command (no arguments)");
context.message.channel.send(embed);
}
} else { // If no role was specified, Send a list of the roles you can assign
// The start of the embed text
let rolesString = `Do ${context.client.config.prefix}role <role> to get the role!\n`;
// Loop through all the roles, and add them to the embed text
for (let i = 0; i < roles.length; i++) {
rolesString += `${roles[i]}\n`;
}
// Create an embed containing the text
const embed = new MessageEmbed()
.setTitle("Roles")
.setColor(embedColor)
.setDescription(rolesString);
// Send the embed
context.message.channel.send(embed);
}
}
}
module.exports = role;

View file

@ -1,70 +0,0 @@
// Required Components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const { existsSync, readFileSync } = require('fs');
// Command variables
const embedColor = "0x3050ba";
// Command class
class rules extends command {
constructor() {
// Set the command's run method, description, and category
super("rules");
super.description = "Generates the rules embeds from the rules.txt file";
super.category = "Admin";
// Require in the config the name of the admin role and the rules file name
super.requiredConfigs = "adminrole";
super.requiredConfigs = "rulesfile";
}
// Run method
rules(context) {
// If the user is an Admin (has the admin role)
if (context.message.member.roles.cache.find(role => role.name == context.client.config.rules.adminrole)) {
// If the rulesfile exists
if (existsSync(context.client.config.rules.rulesfile)) {
const rulesJson = readFileSync(context.client.config.rules.rulesfile);
const rules = JSON.parse(rulesJson);
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
const embed = new MessageEmbed();
embed.setColor(embedColor);
if (rule.image) embed.setImage(rule.image);
if (rule.title) embed.setTitle(rule.title);
if (rule.footer) embed.setFooter(rule.footer);
if (rule.description) {
let description = "";
for (let j = 0; j < rule.description.length; j++) {
const line = rule.description[j];
description += `${line}\n`;
}
embed.setDescription(description);
}
context.message.channel.send(embed);
}
} else { // If the rules file doesn't exist
const errorEmbed = new MessageEmbed()
.setColor(embedColor)
.setDescription(`${context.client.config.rules.rulesfile} doesn't exist`);
context.message.channel.send(errorEmbed);
}
} else { // If the user doesn't have the Admin role
const errorEmbed = new MessageEmbed()
.setColor(embedColor)
.setDescription("You do not have permission to run this command");
context.message.channel.send(errorEmbed);
}
}
}
module.exports = rules;

View file

@ -1,98 +0,0 @@
// Required components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const embedColor = "0x3050ba";
// Command Class
class unmute extends command {
constructor() {
// Set run method, description, category, usage
super("unmute");
super.description = "Unmutes the mentioned user with an optional reason";
super.category = "Moderation";
super.usage = "<@user> [reason]";
// Set required configs
super.requiredConfigs = "modrole";
super.requiredConfigs = "logchannel";
super.requiredConfigs = "muterole";
}
// The command's run method
unmute(context) {
// Check if the user has the mod role
if (context.message.member.roles.cache.find(role => role.name == context.client.config.mute.modrole)) {
// Get the user first pinged in the message
const user = context.message.mentions.users.first();
// If the user object exists
if (user) {
// Get the guild member object from the pinged user
const member = context.message.guild.member(user);
// If the member object exists, i.e. if the user is in the server
if (member) {
// Get the part of the argument array which contains the reason
const reasonArgs = context.arguments;
reasonArgs.splice(0, 1);
// Join the array into a string
const reason = reasonArgs.join(" ");
// If the server is available
if (context.message.guild.available) {
// If the bot client can manage the user
if (member.manageable) {
// The embed to go into the bot log
const embedLog = new MessageEmbed()
.setColor(embedColor)
.setTitle("Member Unmuted")
.addField("User", `${user} \`${user.tag}\``, true)
.addField("Moderator", `${context.message.author} \`${context.message.author.tag}\``, true)
.addField("Reason", reason || "*none*")
.setThumbnail(user.displayAvatarURL);
// The embed to go into the channel the command was sent in
const embedPublic = new MessageEmbed()
.setColor(embedColor)
.setDescription(`${user} has been unmuted`)
.addField("Reason", reason || "*none*");
// Get the muted role
const mutedRole = context.message.guild.roles.cache.find(role => role.name == context.client.config.unmute.muterole);
// Attempt to remove the role from the user, and then send the embeds. If unsuccessful log the error
member.roles.remove(mutedRole, reason).then(() => {
context.message.guild.channels.cache.find(channel => channel.name == context.client.config.unmute.logchannel).send(embedLog);
context.message.channel.send(embedPublic);
context.message.delete();
}).catch(err => {
errorEmbed(context, "An error occurred");
console.log(err);
});
} else { // If the bot can't manage the user
errorEmbed(context, "I am unable to unmute this user");
}
}
} else { // If the member object doesn't exist
errorEmbed(context, "Please specify a valid user");
}
} else { // If the user object doesn't exist
errorEmbed(context, "Please specify a valid user");
}
}
}
}
// Send an embed in case of an error
function errorEmbed(context, message) {
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(message);
context.message.channel.send(embed);
}
module.exports = unmute;

View file

@ -1,86 +0,0 @@
// Required Components
const { command } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
const embedColor = "0x3050ba";
// Command Class
class warn extends command {
constructor() {
// Set the run method, description, category, and usage
super("warn");
super.description = "Warns the mentioned user with an optional reason";
super.category = "Moderation";
super.usage = "<@user> [reason]";
// Set the required configs
super.requiredConfigs = "modrole";
super.requiredConfigs = "logchannel";
}
// The command's run method
warn(context) {
// If the user has the mod role
if (context.message.member.roles.cache.find(role => role.name == context.client.config.warn.modrole)) {
// Get the user first pinged in the message
const user = context.message.mentions.users.first();
// If the user object exists
if (user) {
// Get the guild member object from the user
const member = context.message.guild.member(user);
// If the member object exists. i.e. if the user is in the server
if (member) {
// Get the part of the argument array which the reason is in
const reasonArgs = context.arguments;
reasonArgs.splice(0, 1);
// Join the array into a string
const reason = reasonArgs.join(" ");
// If the server is available
if (context.message.guild.available) {
// The embed to go into the bot log
const embedLog = new MessageEmbed()
.setColor(embedColor)
.setTitle("Member Warned")
.addField("User", `${user} \`${user.tag}\``, true)
.addField("Moderator", `${context.message.author} \`${context.message.author.tag}\``, true)
.addField("Reason", reason || "*none*")
.setThumbnail(user.displayAvatarURL);
// The embed to go into the channel the command was sent in
const embedPublic = new MessageEmbed()
.setColor(embedColor)
.setDescription(`${user} has been warned`)
.addField("Reason", reason || "*none*");
// Send the embeds
context.message.guild.channels.cache.find(channel => channel.name == context.client.config.warn.logchannel).send(embedLog);
context.message.channel.send(embedPublic);
context.message.delete();
}
} else { // If the member objest doesn't exist
errorEmbed(context, "Please specify a valid user");
}
} else { // If the user object doesn't exist
errorEmbed(context, "Please specify a valid user");
}
} else { // If the user isn't mod
errorEmbed(context, "You do not have permission to run this command");
}
}
}
// Send an embed in case of an error
function errorEmbed(context, message) {
const embed = new MessageEmbed()
.setColor(embedColor)
.setDescription(message);
context.message.channel.send(embed);
}
module.exports = warn;

View file

@ -1,14 +0,0 @@
[
{
"name": "Cuzethstan",
"description": "Cuzeth Server. Yes.",
"invite": "http://discord.gg/uhEFNw7",
"icon": "https://cdn.discordapp.com/icons/720177983016665251/a_e4250e57b26559c6609dfe562774ee27.gif"
},
{
"name": "Boblin",
"description": "Official server of the... Boblin?\n- Multiple Topics\n- Lots of Very Active Members",
"invite": "https://discord.gg/Td4uzVu",
"icon": "https://cdn.discordapp.com/attachments/464708407010787328/487824441846267907/image0.png"
}
]

View file

@ -1,32 +0,0 @@
// Required components
const { event } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
// Event variables
const embedColor = "0x3050ba";
const logchannel = "member-logs";
// Event class
class guildmemberadd extends event {
constructor() {
// Set the event's run method
super("guildmemberadd");
}
// Run method
guildmemberadd(member) {
// Create an embed with the user who joined's information
const embed = new MessageEmbed()
.setTitle("Member Joined")
.setColor(embedColor)
.addField("User", `${member} \`${member.user.tag}\``)
.addField("Created", `${member.user.createdAt}`)
.setFooter(`User ID: ${member.user.id}`)
.setThumbnail(member.user.displayAvatarURL({ type: 'png', dynamic: true }));
// Send the embed in the mod's log channel
member.guild.channels.cache.find(channel => channel.name == logchannel).send(embed);
}
}
module.exports = guildmemberadd;

View file

@ -1,32 +0,0 @@
// Required components
const { event } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
// Event variables
const embedColor = "0x3050ba";
const logchannel = "member-logs";
// Event class
class guildmemberremove extends event {
constructor() {
// Set the event's run method
super("guildmemberremove");
}
// Run method
guildmemberremove(member) {
// Create an embed with the user's information
const embed = new MessageEmbed()
.setTitle("Member Left")
.setColor(embedColor)
.addField("User", `${member} \`${member.user.tag}\``)
.addField("Joined", `${member.joinedAt}`)
.setFooter(`User ID: ${member.user.id}`)
.setThumbnail(member.user.displayAvatarURL({ type: 'png', dynamic: true }));
// Send the embed in the log channel
member.guild.channels.cache.find(channel => channel.name == logchannel).send(embed);
}
}
module.exports = guildmemberremove;

View file

@ -1,41 +0,0 @@
// Required components
const { event } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
// Event variables
const embedColor = "0x3050ba";
const logchannel = "member-logs";
// Event class
class guildmemberupdate extends event {
constructor() {
// Set the event's run method
super("guildmemberupdate");
}
// Run method
guildmemberupdate(oldMember, newMember) {
// If the user's nickname was changed
if (oldMember.nickname != newMember.nickname) {
// Get the user's name with tag, their old nickname and their new nickname
// If they didn't have a nickname or they removed it, set it to "none" in italics
const oldNickname = oldMember.nickname || "*none*";
const newNickname = newMember.nickname || "*none*";
// Create the embed with the user's information
const embed = new MessageEmbed()
.setTitle("Nickname Changed")
.setColor(embedColor)
.addField("User", `${newMember} \`${newMember.user.tag}\``)
.addField("Before", oldNickname, true)
.addField("After", newNickname, true)
.setFooter(`User ID: ${newMember.user.id}`)
.setThumbnail(newMember.user.displayAvatarURL({ type: 'png', dynamic: true }));
// Send the embed in the log channel
newMember.guild.channels.cache.find(channel => channel.name == logchannel).send(embed);
}
}
}
module.exports = guildmemberupdate;

View file

@ -1,32 +0,0 @@
// Required components
const { event } = require('vylbot-core');
const { MessageEmbed } = require('discord.js');
// Event variables
const embedColor = "0x3050ba";
const logchannel = "message-logs";
// Event class
class messagedelete extends event {
constructor() {
// The event's run method
super("messagedelete");
}
// Run method
messagedelete(message) {
// Create an embed with the message's information
const embed = new MessageEmbed()
.setTitle("Message Deleted")
.setColor(embedColor)
.addField("User", `${message.author} \`${message.author.tag}\``)
.addField("Channel", message.channel)
.addField("Content", `\`\`\`${message.content || "*none*"}\`\`\``)
.setThumbnail(message.author.displayAvatarURL({ type: 'png', dynamic: true }));
// Send the embed in the logging channel
message.guild.channels.cache.find(channel => channel.name == logchannel).send(embed);
}
}
module.exports = messagedelete;

View file

@ -1,29 +1,31 @@
{
"name": "vylbot-app",
"version": "2.1.1",
"description": "",
"main": "vylbot.js",
"version": "3.0",
"description": "A discord bot made for Vylpes' Den",
"main": "./dist/vylbot",
"typings": "./dist",
"scripts": {
"start": "node vylbot.js",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
"build": "tsc",
"start": "ts-node ./src/vylbot"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Vylpes/vylbot-app.git"
},
"author": "Vylpes",
"license": "ISC",
"bugs": {
"url": "https://github.com/Vylpes/vylbot-app/issues"
},
"homepage": "https://github.com/Vylpes/vylbot-app#readme",
"license": "MIT",
"bugs": "https://github.com/Vylpes/vylbot-app/issues",
"homepage": "https://github.com/Vylpes/vylbot-app",
"dependencies": {
"dotenv": "^10.0.0",
"emoji-regex": "^9.2.0",
"random-bunny": "^1.0.0",
"vylbot-core": "^1.0.4"
"random-bunny": "^2.0.0",
"vylbot-core": "^2.0.3"
},
"devDependencies": {
"eslint": "^7.17.0"
"@types/node": "^16.11.10",
"eslint": "^7.17.0",
"ts-node": "^10.4.0",
"typescript": "^4.5.2"
}
}

19
src/commands/about.ts Normal file
View file

@ -0,0 +1,19 @@
import { Command, ICommandContext } from "vylbot-core";
import PublicEmbed from "../helpers/PublicEmbed";
export default class About extends Command {
constructor() {
super();
super._category = "General";
}
public override execute(context: ICommandContext) {
const embed = new PublicEmbed(context, "About", "")
.addField("Version", process.env.BOT_VER)
.addField("VylBot Core", process.env.CORE_VER)
.addField("Author", process.env.BOT_AUTHOR)
.addField("Date", process.env.BOT_DATE);
embed.SendToCurrentChannel();
}
}

61
src/commands/ban.ts Normal file
View file

@ -0,0 +1,61 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorEmbed from "../helpers/ErrorEmbed";
import ErrorMessages from "../constants/ErrorMessages";
import LogEmbed from "../helpers/LogEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
export default class Bane extends Command {
constructor() {
super();
super._category = "Moderation";
super._roles = [
process.env.ROLES_MODERATOR!
];
}
public override async execute(context: ICommandContext) {
const targetUser = context.message.mentions.users.first();
if (!targetUser) {
const embed = new ErrorEmbed(context, "User does not exist");
embed.SendToCurrentChannel();
return;
}
const targetMember = context.message.guild?.member(targetUser);
if (!targetMember) {
const embed = new ErrorEmbed(context, "User is not in this server");
embed.SendToCurrentChannel();
return;
}
const reasonArgs = context.args;
reasonArgs.splice(0, 1)
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
}
if (!targetMember.bannable) {
const embed = new ErrorEmbed(context, ErrorMessages.InsufficientBotPermissions);
embed.SendToCurrentChannel();
return;
}
const logEmbed = new LogEmbed(context, "Member Banned");
logEmbed.AddUser("User", targetUser, true);
logEmbed.AddUser("Moderator", context.message.author);
logEmbed.AddReason(reason);
const publicEmbed = new PublicEmbed(context, "", `${targetUser} has been banned`);
await targetMember.ban({ reason: reason });
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
}
}

36
src/commands/clear.ts Normal file
View file

@ -0,0 +1,36 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorEmbed from "../helpers/ErrorEmbed";
import { TextChannel } from "discord.js";
import PublicEmbed from "../helpers/PublicEmbed";
export default class Clear extends Command {
constructor() {
super();
super._category = "Moderation";
super._roles = [
process.env.ROLES_MODERATOR!
];
}
public override async execute(context: ICommandContext) {
if (context.args.length == 0) {
const errorEmbed = new ErrorEmbed(context, "Please specify an amount between 1 and 100");
errorEmbed.SendToCurrentChannel();
return;
}
const totalToClear = Number.parseInt(context.args[0]);
if (!totalToClear || totalToClear <= 0 || totalToClear > 100) {
const errorEmbed = new ErrorEmbed(context, "Please specify an amount between 1 and 100");
errorEmbed.SendToCurrentChannel();
return;
}
await (context.message.channel as TextChannel).bulkDelete(totalToClear);
const embed = new PublicEmbed(context, "", `${totalToClear} message(s) were removed`);
embed.SendToCurrentChannel();
}
}

32
src/commands/eval.ts Normal file
View file

@ -0,0 +1,32 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorEmbed from "../helpers/ErrorEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
export default class Evaluate extends Command {
constructor() {
super();
super._category = "Owner";
}
public override execute(context: ICommandContext) {
if (context.message.author.id != process.env.BOT_OWNERID) {
return;
}
const stmt = context.args;
console.log(`Eval Statement: ${stmt.join(" ")}`);
try {
const result = eval(stmt.join(" "));
const embed = new PublicEmbed(context, "", result);
embed.SendToCurrentChannel();
}
catch (err: any) {
const errorEmbed = new ErrorEmbed(context, err);
errorEmbed.SendToCurrentChannel();
}
}
}

118
src/commands/help.ts Normal file
View file

@ -0,0 +1,118 @@
import { existsSync, readdirSync } from "fs";
import { Command, ICommandContext } from "vylbot-core";
import ErrorEmbed from "../helpers/ErrorEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
import StringTools from "../helpers/StringTools";
interface ICommandData {
Exists: boolean;
Name?: string;
Category?: string;
Roles?: string[];
}
export default class Help extends Command {
constructor() {
super();
super._category = "General";
}
public override execute(context: ICommandContext) {
if (context.args.length == 0) {
this.SendAll(context);
} else {
this.SendSingle(context);
}
}
private SendAll(context: ICommandContext) {
const allCommands = this.GetAllCommandData();
const cateogries = this.DetermineCategories(allCommands);
const embed = new PublicEmbed(context, "Commands", "");
cateogries.forEach(category => {
let filtered = allCommands.filter(x => x.Category == category);
embed.addField(StringTools.Capitalise(category), filtered.flatMap(x => x.Name).join(", "));
});
embed.SendToCurrentChannel();
}
private SendSingle(context: ICommandContext) {
const command = this.GetCommandData(context.args[0]);
if (!command.Exists) {
const errorEmbed = new ErrorEmbed(context, "Command does not exist");
errorEmbed.SendToCurrentChannel();
return;
}
const embed = new PublicEmbed(context, StringTools.Capitalise(command.Name!), "");
embed.addField("Category", StringTools.Capitalise(command.Category!));
embed.addField("Required Roles", StringTools.Capitalise(command.Roles!.join(", ")) || "*none*");
embed.SendToCurrentChannel();
}
private GetAllCommandData(): ICommandData[] {
const result: ICommandData[] = [];
const folder = process.env.FOLDERS_COMMANDS!;
const contents = readdirSync(`${process.cwd()}/${folder}`);
contents.forEach(name => {
const file = require(`${process.cwd()}/${folder}/${name}`).default;
const command = new file() as Command;
const data: ICommandData = {
Exists: true,
Name: name.replace(".ts", ""),
Category: command._category || "none",
Roles: command._roles,
};
result.push(data);
});
return result;
}
private GetCommandData(name: string): ICommandData {
const folder = process.env.FOLDERS_COMMANDS!;
const path = `${process.cwd()}/${folder}/${name}.ts`;
if (!existsSync(path)) {
return {
Exists: false
};
}
const file = require(path).default;
const command = new file() as Command;
const data: ICommandData = {
Exists: true,
Name: name,
Category: command._category || "none",
Roles: command._roles
};
return data;
}
private DetermineCategories(commands: ICommandData[]): string[] {
const result: string[] = [];
commands.forEach(cmd => {
if (!result.includes(cmd.Category!)) {
result.push(cmd.Category!);
}
});
return result;
}
}

61
src/commands/kick.ts Normal file
View file

@ -0,0 +1,61 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorMessages from "../constants/ErrorMessages";
import ErrorEmbed from "../helpers/ErrorEmbed";
import LogEmbed from "../helpers/LogEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
export default class Kick extends Command {
constructor() {
super();
super._category = "Moderation";
super._roles = [
process.env.ROLES_MODERATOR!
];
}
public override async execute(context: ICommandContext) {
const targetUser = context.message.mentions.users.first();
if (!targetUser) {
const embed = new ErrorEmbed(context, "User does not exist");
embed.SendToCurrentChannel();
return;
}
const targetMember = context.message.guild?.member(targetUser);
if (!targetMember) {
const embed = new ErrorEmbed(context, "User is not in this server");
embed.SendToCurrentChannel();
return;
}
const reasonArgs = context.args;
reasonArgs.splice(0, 1)
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
}
if (!targetMember.kickable) {
const embed = new ErrorEmbed(context, ErrorMessages.InsufficientBotPermissions);
embed.SendToCurrentChannel();
return;
}
const logEmbed = new LogEmbed(context, "Member Kicked");
logEmbed.AddUser("User", targetUser, true);
logEmbed.AddUser("Moderator", context.message.author);
logEmbed.AddReason(reason);
const publicEmbed = new PublicEmbed(context, "", `${targetUser} has been kicked`);
await targetMember.kick(reason);
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
}
}

70
src/commands/mute.ts Normal file
View file

@ -0,0 +1,70 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorMessages from "../constants/ErrorMessages";
import ErrorEmbed from "../helpers/ErrorEmbed";
import LogEmbed from "../helpers/LogEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
export default class Mute extends Command {
constructor() {
super();
super._category = "Moderation";
super._roles = [
process.env.ROLES_MODERATOR!
];
}
public override async execute(context: ICommandContext) {
const targetUser = context.message.mentions.users.first();
if (!targetUser) {
const embed = new ErrorEmbed(context, "User does not exist");
embed.SendToCurrentChannel();
return;
}
const targetMember = context.message.guild?.member(targetUser);
if (!targetMember) {
const embed = new ErrorEmbed(context, "User is not in this server");
embed.SendToCurrentChannel();
return;
}
const reasonArgs = context.args;
reasonArgs.splice(0, 1);
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
}
if (!targetMember.manageable) {
const embed = new ErrorEmbed(context, ErrorMessages.InsufficientBotPermissions);
embed.SendToCurrentChannel();
return;
}
const logEmbed = new LogEmbed(context, "Member Muted");
logEmbed.AddUser("User", targetUser, true)
logEmbed.AddUser("Moderator", context.message.author);
logEmbed.AddReason(reason);
const publicEmbed = new PublicEmbed(context, "", `${targetUser} has been muted`);
publicEmbed.AddReason(reason);
const mutedRole = context.message.guild.roles.cache.find(role => role.name == process.env.ROLES_MUTED);
if (!mutedRole) {
const embed = new ErrorEmbed(context, ErrorMessages.RoleNotFound);
embed.SendToCurrentChannel();
return;
}
await targetMember.roles.add(mutedRole, reason);
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
}
}

56
src/commands/poll.ts Normal file
View file

@ -0,0 +1,56 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorEmbed from "../helpers/ErrorEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
export default class Poll extends Command {
constructor() {
super();
super._category = "General";
}
public override async execute(context: ICommandContext) {
const argsJoined = context.args.join(" ");
const argsSplit = argsJoined.split(";");
if (argsSplit.length < 3 || argsSplit.length > 10) {
const errorEmbed = new ErrorEmbed(context, "Usage: <title>;<option 1>;<option 2>... (separate options with semicolons), maximum of 9 options");
errorEmbed.SendToCurrentChannel();
return;
}
const title = argsSplit[0];
const arrayOfNumbers = [
':one:',
':two:',
':three:',
':four:',
':five:',
':six:',
':seven:',
':eight:',
':nine:'
];
const reactionEmojis = ["1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣"];
const description = arrayOfNumbers.splice(0, argsSplit.length - 1);
description.forEach((value, index) => {
description[index] = `${value} ${argsSplit[index + 1]}`;
});
const embed = new PublicEmbed(context, title, description.join("\n"));
const message = await context.message.channel.send(embed);
description.forEach(async (value, index) => {
await message.react(reactionEmojis[index]);
});
if (context.message.deletable) {
await context.message.delete({ reason: "Poll command" });
}
}
}

69
src/commands/role.ts Normal file
View file

@ -0,0 +1,69 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorEmbed from "../helpers/ErrorEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
import { Role as DiscordRole } from "discord.js";
export default class Role extends Command {
constructor() {
super();
super._category = "General";
}
public override execute(context: ICommandContext) {
const roles = process.env.COMMANDS_ROLE_ROLES!.split(',');
if (context.args.length == 0) {
this.SendRolesList(context, roles);
} else {
this.ToggleRole(context, roles);
}
}
private SendRolesList(context: ICommandContext, roles: String[]) {
const description = `Do ${process.env.BOT_PREFIX}role <role> to get the role!\n${roles.join('\n')}`;
const embed = new PublicEmbed(context, "Roles", description);
embed.SendToCurrentChannel();
}
private ToggleRole(context: ICommandContext, roles: String[]) {
const requestedRole = context.args[0];
if (!roles.includes(requestedRole)) {
const errorEmbed = new ErrorEmbed(context, "This role isn't marked as assignable, to see a list of assignable roles, run this command without any parameters");
errorEmbed.SendToCurrentChannel();
return;
}
const assignRole = context.message.guild?.roles.cache.find(x => x.name == requestedRole);
if (!assignRole) {
const errorEmbed = new ErrorEmbed(context, "The current server doesn't have this role. Please contact the server's moderators");
errorEmbed.SendToCurrentChannel();
return;
}
const role = context.message.member?.roles.cache.find(x => x.name == requestedRole)
if (!role) {
this.AddRole(context, assignRole);
} else {
this.RemoveRole(context, assignRole);
}
}
private async AddRole(context: ICommandContext, role: DiscordRole) {
await context.message.member?.roles.add(role);
const embed = new PublicEmbed(context, "", `Gave role: ${role.name}`);
embed.SendToCurrentChannel();
}
private async RemoveRole(context: ICommandContext, role: DiscordRole) {
await context.message.member?.roles.remove(role);
const embed = new PublicEmbed(context, "", `Removed role: ${role.name}`);
embed.SendToCurrentChannel();
}
}

46
src/commands/rules.ts Normal file
View file

@ -0,0 +1,46 @@
import { existsSync, readFileSync } from "fs";
import { Command, ICommandContext } from "vylbot-core";
import ErrorEmbed from "../helpers/ErrorEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
interface IRules {
title?: string;
description?: string[];
image?: string;
footer?: string;
}
export default class Rules extends Command {
constructor() {
super();
super._category = "Admin";
super._roles = [
process.env.ROLES_MODERATOR!
];
}
public override execute(context: ICommandContext) {
if (!existsSync(process.env.COMMANDS_RULES_FILE!)) {
const errorEmbed = new ErrorEmbed(context, "Rules file doesn't exist");
errorEmbed.SendToCurrentChannel();
return;
}
const rulesFile = readFileSync(`${process.cwd()}/${process.env.COMMANDS_RULES_FILE}`).toString();
const rules = JSON.parse(rulesFile) as IRules[];
const embeds: PublicEmbed[] = [];
rules.forEach(rule => {
const embed = new PublicEmbed(context, rule.title || "", rule.description?.join("\n") || "");
embed.setImage(rule.image || "");
embed.setFooter(rule.footer || "");
embeds.push(embed);
});
embeds.forEach(x => x.SendToCurrentChannel());
}
}

70
src/commands/unmute.ts Normal file
View file

@ -0,0 +1,70 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorMessages from "../constants/ErrorMessages";
import ErrorEmbed from "../helpers/ErrorEmbed";
import LogEmbed from "../helpers/LogEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
export default class Unmute extends Command {
constructor() {
super();
super._category = "Moderation";
super._roles = [
process.env.ROLES_MODERATOR!
];
}
public override async execute(context: ICommandContext) {
const targetUser = context.message.mentions.users.first();
if (!targetUser) {
const embed = new ErrorEmbed(context, "User does not exist");
embed.SendToCurrentChannel();
return;
}
const targetMember = context.message.guild?.member(targetUser);
if (!targetMember) {
const embed = new ErrorEmbed(context, "User is not in this server");
embed.SendToCurrentChannel();
return;
}
const reasonArgs = context.args;
reasonArgs.splice(0, 1);
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
}
if (!targetMember.manageable) {
const embed = new ErrorEmbed(context, ErrorMessages.InsufficientBotPermissions);
embed.SendToCurrentChannel();
return;
}
const logEmbed = new LogEmbed(context, "Member Unmuted");
logEmbed.AddUser("User", targetUser, true)
logEmbed.AddUser("Moderator", context.message.author);
logEmbed.AddReason(reason);
const publicEmbed = new PublicEmbed(context, "", `${targetUser} has been unmuted`);
publicEmbed.AddReason(reason);
const mutedRole = context.message.guild.roles.cache.find(role => role.name == process.env.ROLES_MUTED);
if (!mutedRole) {
const embed = new ErrorEmbed(context, ErrorMessages.RoleNotFound);
embed.SendToCurrentChannel();
return;
}
await targetMember.roles.remove(mutedRole, reason);
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
}
}

53
src/commands/warn.ts Normal file
View file

@ -0,0 +1,53 @@
import { Command, ICommandContext } from "vylbot-core";
import ErrorEmbed from "../helpers/ErrorEmbed";
import LogEmbed from "../helpers/LogEmbed";
import PublicEmbed from "../helpers/PublicEmbed";
export default class Warn extends Command {
constructor() {
super();
super._category = "Moderation";
super._roles = [
process.env.ROLES_MODERATOR!
];
}
public override execute(context: ICommandContext) {
const user = context.message.mentions.users.first();
if (!user) {
const errorEmbed = new ErrorEmbed(context, "Please specify a valid user");
errorEmbed.SendToCurrentChannel();
return;
}
const member = context.message.guild?.member(user);
if (!member) {
const errorEmbed = new ErrorEmbed(context, "Please specify a valid user");
errorEmbed.SendToCurrentChannel();
return;
}
const reasonArgs = context.args;
reasonArgs.splice(0, 1);
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
}
const logEmbed = new LogEmbed(context, "Member Warned");
logEmbed.AddUser("User", user, true);
logEmbed.AddUser("Moderator", context.message.author);
logEmbed.AddReason(reason);
const publicEmbed = new PublicEmbed(context, "", `${user} has been warned`);
publicEmbed.AddReason(reason);
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
}
}

View file

@ -0,0 +1,5 @@
export default class ErrorMessages {
public static readonly InsufficientBotPermissions = "Unable to do this action, am I missing permissions?";
public static readonly ChannelNotFound = "Unable to find channel";
public static readonly RoleNotFound = "Unable to find role";
}

View file

@ -0,0 +1,36 @@
import { Event } from "vylbot-core";
import { GuildMember } from "discord.js";
import EventEmbed from "../helpers/EventEmbed";
import GuildMemberUpdate from "./MemberEvents/GuildMemberUpdate";
export default class MemberEvents extends Event {
constructor() {
super();
}
public override guildMemberAdd(member: GuildMember) {
const embed = new EventEmbed(member.guild, "Member Joined");
embed.AddUser("User", member.user, true);
embed.addField("Created", member.user.createdAt);
embed.setFooter(`Id: ${member.user.id}`);
embed.SendToMemberLogsChannel();
}
public override guildMemberRemove(member: GuildMember) {
const embed = new EventEmbed(member.guild, "Member Left");
embed.AddUser("User", member.user, true);
embed.addField("Joined", member.joinedAt);
embed.setFooter(`Id: ${member.user.id}`);
embed.SendToMemberLogsChannel();
}
public override guildMemberUpdate(oldMember: GuildMember, newMember: GuildMember) {
const handler = new GuildMemberUpdate(oldMember, newMember);
if (oldMember.nickname != newMember.nickname) { // Nickname change
handler.NicknameChanged();
}
}
}

View file

@ -0,0 +1,25 @@
import { GuildMember } from "discord.js";
import EventEmbed from "../../helpers/EventEmbed";
export default class GuildMemberUpdate {
private _oldMember: GuildMember;
private _newMember: GuildMember;
constructor(oldMember: GuildMember, newMember: GuildMember) {
this._oldMember = oldMember;
this._newMember = newMember;
}
public NicknameChanged() {
const oldNickname = this._oldMember.nickname || "*none*";
const newNickname = this._newMember.nickname || "*none*";
const embed = new EventEmbed(this._newMember.guild, "Nickname Changed");
embed.AddUser("User", this._newMember.user, true);
embed.addField("Before", oldNickname, true);
embed.addField("After", newNickname, true);
embed.setFooter(`Id: ${this._newMember.user.id}`);
embed.SendToMemberLogsChannel();
}
}

View file

@ -0,0 +1,35 @@
import { Event } from "vylbot-core";
import { Message } from "discord.js";
import EventEmbed from "../helpers/EventEmbed";
export default class MessageEvents extends Event {
constructor() {
super();
}
public override messageDelete(message: Message) {
if (!message.guild) return;
const embed = new EventEmbed(message.guild, "Message Deleted");
embed.AddUser("User", message.author, true);
embed.addField("Channel", message.channel, true);
embed.addField("Content", `\`\`\`${message.content || "*none*"}\`\`\``);
embed.addField("Attachments", `\`\`\`${message.attachments.map(x => x.url).join("\n")}`);
embed.SendToMessageLogsChannel();
}
public override messageUpdate(oldMessage: Message, newMessage: Message) {
if (!newMessage.guild) return;
if (newMessage.author.bot) return;
if (oldMessage.content == newMessage.content) return;
const embed = new EventEmbed(newMessage.guild, "Message Edited");
embed.AddUser("User", newMessage.author, true);
embed.addField("Channel", newMessage.channel, true);
embed.addField("Before", `\`\`\`${oldMessage.content || "*none*"}\`\`\``);
embed.addField("After", `\`\`\`${newMessage.content || "*none*"}\`\`\``);
embed.SendToMessageLogsChannel();
}
}

19
src/helpers/ErrorEmbed.ts Normal file
View file

@ -0,0 +1,19 @@
import { MessageEmbed } from "discord.js";
import { ICommandContext } from "vylbot-core";
export default class ErrorEmbed extends MessageEmbed {
private _context: ICommandContext;
constructor(context: ICommandContext, message: String) {
super();
super.setColor(process.env.EMBED_COLOUR_ERROR!);
super.setDescription(message);
this._context = context;
}
public SendToCurrentChannel() {
this._context.message.channel.send(this);
}
}

54
src/helpers/EventEmbed.ts Normal file
View file

@ -0,0 +1,54 @@
import { MessageEmbed, TextChannel, User, Guild } from "discord.js";
import ErrorMessages from "../constants/ErrorMessages";
import ErrorEmbed from "./ErrorEmbed";
export default class EventEmbed extends MessageEmbed {
private _guild: Guild;
constructor(guild: Guild, title: string) {
super();
super.setColor(process.env.EMBED_COLOUR!);
super.setTitle(title);
this._guild = guild;
}
// Detail methods
public AddUser(title: string, user: User, setThumbnail: boolean = false) {
super.addField(title, `${user} \`${user.tag}\``, true);
if (setThumbnail) {
super.setThumbnail(user.displayAvatarURL());
}
}
public AddReason(message: String) {
super.addField("Reason", message || "*none*");
}
// Send methods
public SendToChannel(name: string) {
const channel = this._guild.channels.cache
.find(channel => channel.name == name) as TextChannel;
if (!channel) {
console.error(`Unable to find channel ${name}`);
return;
}
channel.send(this);
}
public SendToMessageLogsChannel() {
this.SendToChannel(process.env.CHANNELS_LOGS_MESSAGE!)
}
public SendToMemberLogsChannel() {
this.SendToChannel(process.env.CHANNELS_LOGS_MEMBER!)
}
public SendToModLogsChannel() {
this.SendToChannel(process.env.CHANNELS_LOGS_MOD!)
}
}

60
src/helpers/LogEmbed.ts Normal file
View file

@ -0,0 +1,60 @@
import { MessageEmbed, TextChannel, User } from "discord.js";
import { ICommandContext } from "vylbot-core";
import ErrorMessages from "../constants/ErrorMessages";
import ErrorEmbed from "./ErrorEmbed";
export default class LogEmbed extends MessageEmbed {
private _context: ICommandContext;
constructor(context: ICommandContext, title: string) {
super();
super.setColor(process.env.EMBED_COLOUR!);
super.setTitle(title);
this._context = context;
}
// Detail methods
public AddUser(title: string, user: User, setThumbnail: boolean = false) {
super.addField(title, `${user} \`${user.tag}\``, true);
if (setThumbnail) {
super.setThumbnail(user.displayAvatarURL());
}
}
public AddReason(message: String) {
super.addField("Reason", message || "*none*");
}
// Send methods
public SendToCurrentChannel() {
this._context.message.channel.send(this);
}
public SendToChannel(name: string) {
const channel = this._context.message.guild?.channels.cache
.find(channel => channel.name == name) as TextChannel;
if (!channel) {
const errorEmbed = new ErrorEmbed(this._context, ErrorMessages.ChannelNotFound);
errorEmbed.SendToCurrentChannel();
return;
}
channel.send(this);
}
public SendToMessageLogsChannel() {
this.SendToChannel(process.env.CHANNELS_LOGS_MESSAGE!)
}
public SendToMemberLogsChannel() {
this.SendToChannel(process.env.CHANNELS_LOGS_MEMBER!)
}
public SendToModLogsChannel() {
this.SendToChannel(process.env.CHANNELS_LOGS_MOD!)
}
}

View file

@ -0,0 +1,26 @@
import { MessageEmbed } from "discord.js";
import { ICommandContext } from "vylbot-core";
export default class PublicEmbed extends MessageEmbed {
private _context: ICommandContext;
constructor(context: ICommandContext, title: string, description: string) {
super();
super.setColor(process.env.EMBED_COLOUR!);
super.setTitle(title);
super.setDescription(description);
this._context = context;
}
// Detail methods
public AddReason(message: String) {
super.addField("Reason", message || "*none*");
}
// Send methods
public SendToCurrentChannel() {
this._context.message.channel.send(this);
}
}

View file

@ -0,0 +1,15 @@
export default class StringTools {
public static Capitalise(str: string): string {
const words = str.split(" ");
let result: string[] = [];
words.forEach(word => {
const firstLetter = word.substring(0, 1).toUpperCase();
const rest = word.substring(1);
result.push(firstLetter + rest);
});
return result.join(" ");
}
}

25
src/vylbot.ts Normal file
View file

@ -0,0 +1,25 @@
import { CoreClient } from "vylbot-core";
import * as dotenv from "dotenv";
dotenv.config();
const requiredConfigs = [
"EMBED_COLOUR",
"EMBED_COLOUR_ERROR",
"ROLES_MODERATOR",
"ROLES_MUTED",
"CHANNELS_LOGS_MESSAGE",
"CHANNELS_LOGS_MEMBER",
"CHANNELS_LOGS_MOD",
"COMMANDS_ROLE_ROLES",
"COMMANDS_RULES_FILE"
];
requiredConfigs.forEach(config => {
if (!process.env[config]) {
throw `${config} is required in .env`;
}
});
const client = new CoreClient();
client.start();

78
tsconfig.json Normal file
View file

@ -0,0 +1,78 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
"declaration": true, /* Generates corresponding '.d.ts' file. */
"declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"include": [
"./src",
],
"exclude": [
"./tests"
]
}

View file

@ -1,5 +0,0 @@
const vylbot = require('vylbot-core');
const config = require('./config.json');
const client = new vylbot.client(config);
client.start();

310
yarn.lock
View file

@ -23,6 +23,18 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@cspotcode/source-map-consumer@0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b"
integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==
"@cspotcode/source-map-support@0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5"
integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==
dependencies:
"@cspotcode/source-map-consumer" "0.8.0"
"@discordjs/collection@^0.1.6":
version "0.1.6"
resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.1.6.tgz#9e9a7637f4e4e0688fd8b2b5c63133c91607682c"
@ -66,6 +78,77 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@sindresorhus/is@^4.0.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.2.0.tgz#667bfc6186ae7c9e0b45a08960c551437176e1ca"
integrity sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==
"@szmarczak/http-timer@^4.0.5":
version "4.0.6"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
dependencies:
defer-to-connect "^2.0.0"
"@tsconfig/node10@^1.0.7":
version "1.0.8"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==
"@tsconfig/node12@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c"
integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==
"@tsconfig/node14@^1.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2"
integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==
"@tsconfig/node16@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
"@types/cacheable-request@^6.0.1":
version "6.0.2"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9"
integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==
dependencies:
"@types/http-cache-semantics" "*"
"@types/keyv" "*"
"@types/node" "*"
"@types/responselike" "*"
"@types/http-cache-semantics@*":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==
"@types/keyv@*":
version "3.1.3"
resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.3.tgz#1c9aae32872ec1f20dcdaee89a9f3ba88f465e41"
integrity sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==
dependencies:
"@types/node" "*"
"@types/node@*":
version "16.11.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234"
integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==
"@types/node@^16.11.10":
version "16.11.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.10.tgz#2e3ad0a680d96367103d3e670d41c2fed3da61ae"
integrity sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==
"@types/responselike@*", "@types/responselike@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
dependencies:
"@types/node" "*"
abort-controller@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
@ -78,11 +161,21 @@ acorn-jsx@^5.3.1:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn-walk@^8.1.1:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^7.4.0:
version "7.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.4.1:
version "8.6.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895"
integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==
ajv@^6.10.0, ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@ -127,6 +220,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@ -157,6 +255,24 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
cacheable-lookup@^5.0.3:
version "5.0.4"
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
cacheable-request@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27"
integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==
dependencies:
clone-response "^1.0.2"
get-stream "^5.1.0"
http-cache-semantics "^4.0.0"
keyv "^4.0.0"
lowercase-keys "^2.0.0"
normalize-url "^6.0.1"
responselike "^2.0.0"
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@ -179,6 +295,13 @@ chalk@^4.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
clone-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -215,6 +338,11 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@ -231,16 +359,33 @@ debug@^4.0.1, debug@^4.1.1:
dependencies:
ms "2.1.2"
decompress-response@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
dependencies:
mimic-response "^3.1.0"
deep-is@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
defer-to-connect@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
discord.js@^12.3.1:
version "12.5.3"
resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-12.5.3.tgz#56820d473c24320871df9ea0bbc6b462f21cf85c"
@ -262,6 +407,11 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dotenv@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@ -272,6 +422,13 @@ emoji-regex@^9.2.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
enquirer@^2.3.5:
version "2.3.6"
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
@ -453,6 +610,13 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
glob-parent@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@ -486,6 +650,23 @@ globals@^13.6.0, globals@^13.9.0:
dependencies:
type-fest "^0.20.2"
got@^11.8.3:
version "11.8.3"
resolved "https://registry.yarnpkg.com/got/-/got-11.8.3.tgz#f496c8fdda5d729a90b4905d2b07dbd148170770"
integrity sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==
dependencies:
"@sindresorhus/is" "^4.0.0"
"@szmarczak/http-timer" "^4.0.5"
"@types/cacheable-request" "^6.0.1"
"@types/responselike" "^1.0.0"
cacheable-lookup "^5.0.3"
cacheable-request "^7.0.2"
decompress-response "^6.0.0"
http2-wrapper "^1.0.0-beta.5.2"
lowercase-keys "^2.0.0"
p-cancelable "^2.0.0"
responselike "^2.0.0"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@ -496,6 +677,19 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
http-cache-semantics@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
http2-wrapper@^1.0.0-beta.5.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
dependencies:
quick-lru "^5.1.1"
resolve-alpn "^1.0.0"
ignore@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
@ -562,6 +756,11 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
json-buffer@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@ -577,6 +776,13 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
keyv@^4.0.0:
version "4.0.4"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.4.tgz#f040b236ea2b06ed15ed86fbef8407e1a1c8e376"
integrity sha512-vqNHbAc8BBsxk+7QBYLW0Y219rWcClspR6WSeoHYKG5mnsSoOH+BL1pWq02DDCVdvvuUny5rkBlzMRzoqc+GIg==
dependencies:
json-buffer "3.0.1"
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@ -595,6 +801,11 @@ lodash.truncate@^4.4.2:
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
lowercase-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
@ -602,6 +813,11 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
mime-db@1.51.0:
version "1.51.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c"
@ -614,6 +830,16 @@ mime-types@^2.1.12:
dependencies:
mime-db "1.51.0"
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
mimic-response@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@ -638,7 +864,12 @@ node-fetch@^2.6.1:
dependencies:
whatwg-url "^5.0.0"
once@^1.3.0:
normalize-url@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@ -657,6 +888,11 @@ optionator@^0.9.1:
type-check "^0.4.0"
word-wrap "^1.2.3"
p-cancelable@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@ -689,18 +925,31 @@ progress@^2.0.0:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
random-bunny@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/random-bunny/-/random-bunny-1.2.2.tgz#821882ba33b6be05e3a538c43e822e5e9896862d"
integrity sha512-m12WIb4uNeEA8eLk9vxK6U9x/+KlRwBqOoiuGku6C6kF6DcbyMTq0RaRUXF3fXxpRtZbpoU7dgttLoETTXXL/g==
quick-lru@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
random-bunny@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/random-bunny/-/random-bunny-2.0.0.tgz#f9950f53c7f5183a6dad26386db14f702d477cf7"
integrity sha512-xIDaPghs0nslKWNfxDLAGNtsUPUlmNagUmdNAHP7U4LSrGySbgSfAzCV8eECTeuny2csmf0SL5dBxEZdVvHgOA==
dependencies:
glob-parent "^6.0.0"
node-fetch "^2.6.1"
got "^11.8.3"
regexpp@^3.1.0:
version "3.2.0"
@ -712,11 +961,23 @@ require-from-string@^2.0.2:
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
resolve-alpn@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
responselike@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
dependencies:
lowercase-keys "^2.0.0"
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@ -818,6 +1079,24 @@ tr46@~0.0.3:
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
ts-node@^10.4.0:
version "10.4.0"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7"
integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==
dependencies:
"@cspotcode/source-map-support" "0.7.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
yn "3.1.1"
tweetnacl@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
@ -835,6 +1114,11 @@ type-fest@^0.20.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
typescript@^4.5.2:
version "4.5.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.2.tgz#8ac1fba9f52256fdb06fb89e4122fa6a346c2998"
integrity sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
@ -847,12 +1131,13 @@ v8-compile-cache@^2.0.3:
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
vylbot-core@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/vylbot-core/-/vylbot-core-1.0.5.tgz#44a0a38d3c8bfda38883cab1a16e5e15435c98d7"
integrity sha512-N86HpZnQadi+d4w4ZaTcbSRAjRInhzG8BN/WDNGUvFjF2UuA8SUKfd9Wk6rbs7mLLyXw+VFFLYdDbe0Q6ZfNYA==
vylbot-core@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/vylbot-core/-/vylbot-core-2.0.3.tgz#e7d844bc54e72b14f06f14b63866854e3b846d55"
integrity sha512-RxABRcwhVIVZcIssVP8yosLlUXzcdrNLiYJzcvkAIz4KeHfoARcxjsz2vG2x9GIzeFpfn/hjrPvjFC5lN6zclw==
dependencies:
discord.js "^12.3.1"
dotenv "^10.0.0"
webidl-conversions@^3.0.0:
version "3.0.1"
@ -893,3 +1178,8 @@ yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==