This commit is contained in:
Erik 2020-05-21 11:52:47 +03:00
commit 9b38c3a609
50 changed files with 1362 additions and 655 deletions

1
.gitignore vendored
View File

@ -4,4 +4,3 @@ node_modules
yarn-error.log
.eslintrc.json
logs
permissionExample.json

View File

@ -1,2 +1,15 @@
//Grant Command
[A_CHANNEL_GRANT_DESCRIPTION]
Specify channels to grant specific permissions to.
//Revoke Command
[A_CHANNEL_REVOKE_DESCRIPTION]
Specify channels to revoke permissions from.
//Permissions Command
[A_USER_PERMISSIONS_DESCRIPTION]
Enable viewing all user's permissions.
[A_RAW_PERMISSIONS_DESCRIPTION]
Upload a raw JSON file of all of the permissions in the guild.

View File

@ -0,0 +1,5 @@
[A_USER_SETTINGS_DESCRIPTION]
View or edit user-only settings.
[A_ALL_SETTINGS_DESCRIPTION]
View all guild, user, or restricted settings.

View File

@ -1,7 +1,8 @@
//Grant Command
[C_GRANT_DESCRIPTION]
Grant roles or users permissions for commands or modules.
Grant roles or users permissions to use commands or modules.
To view all grantable permissions, use the command `{prefix}perms list`.
[C_GRANT_RESOLVEERROR]
Unable to find a role or member, view `{prefix}cmd grant` for more help.
@ -15,16 +16,14 @@ There was an issue pushing the permissions to the database. Contact a bot develo
[C_GRANT_SUCCESS]
Successfully granted **{resolveable}** the following permissions: {permissions}
[C_GRANT_SUCCESSALT]S
[C_GRANT_SUCCESSALT]
in channel(s) {channels}.
[C_GRANT_SUCCESSFAILED]
Some permissions have failed to add, likely because the {resolveable} already has the permissions or you did not supply valid permissions.
Some permissions failed to grant, likely because they already have the permissions or you did not supply valid permissions.
[C_GRANT_FAILED]
Failed to grant the following permissions: {failed}.
This is likely because the {resolveable} already has the permissions or you did not supply valid permissions.
Failed to grant the permissions provided, view `{prefix}cmd grant` for more help.
//Revoke Command
@ -41,7 +40,52 @@ You must provide permissions to revoke, view `{prefix}cmd grant` for more help.
[C_REVOKE_DATABASEERROR]
There was an issue removing the permissions from the database. Contact a bot developer.
[C_REVOKE_SUCCESS]
Successfully revoked **{resolveable}** the following permissions: {removed}
[C_REVOKE_SUCCESSALT]
in channel(s) {channels}.
[C_REVOKE_SUCCESSFAILED]
Some permissions failed to revoke, likely because they did not have the permissions in the first place.
[C_REVOKE_FAILED]
Failed to revoke the permissions provided, try double-checking the permissions with `{prefix}perms {resolveable}`.
//Permissions Command
[C_PERMISSIONS_DESCRIPTION]
View permissions granted to roles or users.
[C_PERMISSIONS_LIST]
You can **grant**/**revoke** the following permissions: {permissions}.
[C_PERMISSIONS_SHOWTITLE]
switch({user}) {
case true:
"User Permissions"
break;
case false:
"Role Permissions"
break;
}
[C_PERMISSIONS_SHOWDESCRIPTION]
An overview of all {resolve}'s permissions in the guild. If you would like to see an in-depth view of the role or user's permissions, use `{prefix}perms [user|role]`.
[C_PERMISSIONS_MAXFIELDS]
:warning: **You have met the max amount of fields and you will need to use `{prefix}perms --json` to view them.** :warning:
[C_PERMISSIONS_NOTFOUND]
Unable to find any roles or users with those arguments.
[C_PERMISSIONS_JSON]
Attached the JSON-formatted permission file in the file below.
You may want to format this file for your viewing pleasure.
[C_PERMISSIONS_GLOBAL]
**Global Permissions:** {permissions}
Global permissions can be used in all channels, but you can add specific channels if needed.
[C_PERMISSIONS_GLOBALALT]
Channel-specific permissions are listed below.

View File

@ -1,8 +1,5 @@
//Ping Command
[C_PING_RESPONSE]
Pong!
[C_PING_DESCRIPTION]
Shows the millisecond delay between the bot and the discord server.
@ -12,7 +9,7 @@ Shows the millisecond delay between the bot and the discord server.
Configure your guild and user settings.
[C_SETTINGS_ADMINISTRATORERROR]
You must have the `ADMINISTRATOR` permission to reset the {type} settings.
You must have the `ADMINISTRATOR` permission to run this.
[C_SETTINGS_CLIENTPERMISSIONERROR]
The setting **{setting}** requires __the bot__ to have permissions to use.
@ -29,6 +26,9 @@ This prompt will time out in __30 seconds__.
[C_SETTINGS_RESETERROR]
You provided an invalid input, please try again.
[C_SETTINGS_RESETABORT]
Successfully aborted the operation.
[C_SETTINGS_RESETSUCCESS]
All {type} settings were successfully deleted and set to default.
@ -73,5 +73,18 @@ Found {matches} matches, displaying {count}
To search server members with similar names use `{prefix}user search <arguments..>`
//Avatar Command
[C_AVATAR_DESCRIPTION]
Fetches avatars for various users in different formats and sizes.
[C_AVATAR_FORMATERROR]
Unable to find an avatar with those arguments, try a different size or format.
//Lookup Command
[C_LOOKUP_DESCRIPTION]
Looks up a discord invite code and returns the information of the invite.
[C_LOOKUP_FAILEDMATCH]
Couldn't find a discord invite code, try again.
[C_LOOKUP_NONEXISTANT]
Unable to find any data about that invite code.

View File

@ -19,3 +19,9 @@ Aliases
[GENERAL_ARGUMENTS]
Arguments
[GENERAL_CURRENT]
Current Settings
[GENERAL_SETTINGRESET]
Successfully reset the setting {setting} to the default value.

View File

@ -1,19 +0,0 @@
[M_UTILITY_NAME]
Utility
[M_MODERATION_NAME]
Moderation
[M_DEVELOPER_NAME]
Developer
[M_ADMINISTRATOR_NAME]
Administrator
[M_INFORMATION_NAME]
Information
[M_MUSIC_NAME]
Music
[

View File

@ -1,3 +1,8 @@
//Guild Settings
//guildPrefix Setting
[S_GUILDPREFIX_DESCRIPTION]
Customizes your prefix in the guild.
@ -7,5 +12,99 @@ Successfully set the guild prefix to `{prefix}`.
[S_GUILDPREFIX_LENGTH]
The guild prefix cannot exceed {max} characters. `[{length}/{max}]`.
[S_GUILDPREFIX_SPACES]
The guild prefix cannot include spaces.
[S_GUILDPREFIX_RESET]
Successfully reset the guild prefix to `{prefix}`.
//mute Setting
[S_MUTE_DESCRIPTION]
Assign or create a muted role and choose mute functionality for your guild.
__Mute Types__
**`0`:** Mutes only add/remove the muted role. *(default)*
**`1`:** Mutes remove all roles except for the muted role.
**`2`:** Mutes remove all roles, does not require a muted role.
[S_MUTE_TYPENAN]
The argument provided is not a number! The available types are: `0`, `1`, or `2`.
View `{prefix}setting mute` for more help.
[S_MUTE_TYPEINVALID]
The argument provided is not a valid type! The available types are: `0`, `1`, or `2`.
View `{prefix}setting mute` for more help.
[S_MUTE_TYPESUCCESS]
Successfully set the **mute type** to `{type}`.
[S_MUTE_TYPESWITCH]
switch({type}) {
case 0:
"Mutes will now *only add/remove* the muted role.";
break;
case 1:
"Mutes will now *remove all roles except for the muted role*, and then add them back once done.";
break;
case 2:
"Mutes will now *remove all roles* and then add them back once done.";
break;
}
[S_MUTE_ROLEMISSINGPERMISSION]
The bot *must have* the `MANAGE_ROLES` permission to create a new mute role.
[S_MUTE_ROLEPROMPT]
Found an existing role named **{name}** `({id})`, would you like to use it and update these roles permissions?
Answering no will create a new role with updated permissions. *(__y__es, __n__o)*
This prompt will time out in __30 seconds__.
[S_MUTE_ROLEPROMPTERROR]
You provided an invalid input, please try again.
[S_MUTE_ROLECREATEERROR]
The bot encountered an issue while creating a role for the guild.
[S_MUTE_ROLEMISSING]
Cannot find a specified role with those arguments.
To create a new role, try `{prefix}setting createmute Muted`
[S_MUTE_ROLESUCCESS]
Successfully {type} the **mute role** to `{role}`.
[S_MUTE_GENERATEDPERMISSIONS]
**Permissions have been applied to all possible channels.**
[S_MUTE_UNGENERATEDPERMISSIONS]
**None of the permissions have been changed.**
[S_MUTEDROLE_MISSINGPERMISSION]
The bot must have the `MANAGE_ROLES` permission to create a new muted role in the guild.
[S_MUTEDROLE_ERRORCREATE]
There was an issue creating the muted role for your guild.
[S_MUTEDROLE_CANNOTFIND]
I cannot find a role name with those arguments. If you would like to create a new one, use the command `{prefix}settings mute create`.
[S_MUTEDROLE_SUCCESS]
Successfully set the muted role to `{role}`.
//User Settings

View File

@ -1,4 +1,4 @@
/* Adopted from Discord.js */
/*Adopted from Discord.js */
const path = require('path');
const EventEmitter = require('events');
@ -15,18 +15,17 @@ class Shard extends EventEmitter {
super();
if(manager.mode === 'process') childProcess = require('child_process');
else if(manager.mode === 'worker') Worker = require('worker_threads').Worker;
else if(manager.mode === 'worker') Worker = require('worker_threads').Worker; //eslint-disable-line prefer-destructuring
this.manager = manager;
this.id = id;
this.args = manager.shardArgs || [];
this.execArgv = manager.execArgv;
this.env = Object.assign({}, process.env, {
SHARDING_MANAGER: true,
this.env = { ...process.env, SHARDING_MANAGER: true,
SHARDS: this.id,
TOTAL_SHARD_COUNT: this.manager.totalShards,
DISCORD_TOKEN: this.manager.token
});
};
this.ready = false;
this.process = null;
@ -47,13 +46,13 @@ class Shard extends EventEmitter {
this.process = childProcess.fork(path.resolve(this.manager.file), this.args, {
env: this.env,
execArgv: this.execArgv
})
.on('message', this._handleMessage.bind(this))
.on('exit', this._exitListener);
}).
on('message', this._handleMessage.bind(this)).
on('exit', this._exitListener);
} else if(this.manager.mode === 'worker') {
this.worker = new Worker(path.resolve(this.manager.file), { workerData: this.env })
.on('message', this._handleMessage.bind(this))
.on('exit', this._exitListener);
this.worker = new Worker(path.resolve(this.manager.file), { workerData: this.env }).
on('message', this._handleMessage.bind(this)).
on('exit', this._exitListener);
}
this.emit('spawn', this.process || this.worker);
@ -92,7 +91,7 @@ class Shard extends EventEmitter {
send(message) {
return new Promise((resolve, reject) => {
if(this.process) {
this.process.send(message, error => {
this.process.send(message, (error) => {
if(error) reject(error); else resolve(this);
});
} else {
@ -108,7 +107,7 @@ class Shard extends EventEmitter {
const promise = new Promise((resolve, reject) => {
const child = this.process || this.worker;
const listener = message => {
const listener = (message) => {
if(!message || message._fetchProp !== prop) return;
child.removeListener('message', listener);
this._fetches.delete(prop);
@ -116,7 +115,7 @@ class Shard extends EventEmitter {
};
child.on('message', listener);
this.send({ _fetchProp: prop }).catch(err => {
this.send({ _fetchProp: prop }).catch((err) => {
child.removeListener('message', listener);
this._fetches.delete(prop);
reject(err);
@ -135,7 +134,7 @@ class Shard extends EventEmitter {
const promise = new Promise((resolve, reject) => {
const child = this.process || this.worker;
const listener = message => {
const listener = (message) => {
if(!message || message._eval !== script) return;
child.removeListener('message', listener);
this._evals.delete(script);
@ -144,7 +143,7 @@ class Shard extends EventEmitter {
child.on('message', listener);
const _eval = typeof script === 'function' ? `(${script})(this)` : script;
this.send({ _eval }).catch(err => {
this.send({ _eval }).catch((err) => {
child.removeListener('message', listener);
this._evals.delete(script);
reject(err);
@ -175,21 +174,21 @@ class Shard extends EventEmitter {
}
if(message._sFetchProp) { //Shard requesting property fetch
this.manager.fetchClientValues(message._sFetchProp).then(
results => this.send({ _sFetchProp: message._sFetchProp, _result: results }),
err => this.send({ _sFetchProp: message._sFetchProp, _error: Util.makePlainError(err) })
(results) => this.send({ _sFetchProp: message._sFetchProp, _result: results }),
(err) => this.send({ _sFetchProp: message._sFetchProp, _error: Util.makePlainError(err) })
);
return;
}
if(message._sEval) { //Shard requesting eval broadcast
this.manager.broadcastEval(message._sEval).then(
results => this.send({ _sEval: message._sEval, _result: results }),
err => this.send({ _sEval: message._sEval, _error: Util.makePlainError(err) })
(results) => this.send({ _sEval: message._sEval, _result: results }),
(err) => this.send({ _sEval: message._sEval, _error: Util.makePlainError(err) })
);
return;
}
if(message._sRespawnAll) { //Shard requesting to respawn all shards.
const { shardDelay, respawnDelay, waitForReady } = message._sRespawnAll;
this.manager.respawnAll(shardDelay, respawnDelay, waitForReady).catch(() => {
this.manager.respawnAll(shardDelay, respawnDelay, waitForReady).catch(() => { //eslint-disable-line no-empty-function
});
return;
}
@ -208,7 +207,7 @@ class Shard extends EventEmitter {
this._evals.clear();
this._fetches.clear();
if(respawn) this.spawn().catch(err => this.emit('error', err));
if(respawn) this.spawn().catch((err) => this.emit('error', err));
}

View File

@ -1,4 +1,4 @@
/* Adopted from Discord.js */
/*Adopted from Discord.js */
const path = require('path');
const fs = require('fs');
@ -36,10 +36,10 @@ class ShardManager extends EventEmitter {
}
this.shardList = [...new Set(this.shardList)];
if(this.shardList.length < 1) throw new RangeError('[shardmanager] ShardList must have one ID.');
if(this.shardList.some(shardID => typeof shardID !== 'number'
|| isNaN(shardID)
|| !Number.isInteger(shardID)
|| shardID < 0)
if(this.shardList.some((shardID) => typeof shardID !== 'number' ||
isNaN(shardID) ||
!Number.isInteger(shardID) ||
shardID < 0)
) {
throw new TypeError('[shardmanager] ShardList must be an array of positive integers.');
}
@ -102,7 +102,7 @@ class ShardManager extends EventEmitter {
if(this.totalShards === 'auto' || this.totalShards !== amount) {
this.totalShards = amount;
}
if(this.shardList.some(id => id >= amount)) {
if(this.shardList.some((id) => id >= amount)) {
throw new RangeError('[shardmanager] Amount of shards cannot be larger than the highest shard ID.');
}

View File

@ -1,12 +1,11 @@
const Transport = require('winston-transport');
const { WebhookClient } = require('discord.js');
const { username } = require('os').userInfo();
const { inspect } = require('util');
const options = require('../../../options.json');
// eslint-disable-next-line no-control-regex
const regex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g
//eslint-disable-next-line no-control-regex
const regex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/gu;
class DiscordWebhook extends Transport {
constructor(opts) {
@ -24,11 +23,14 @@ class DiscordWebhook extends Transport {
});
const message = info.message.replace(regex, '')
.replace(new RegExp(options.bot.token, 'g'), '<redacted>')
.replace(new RegExp(username, 'g'), '<redacted>');
.replace(new RegExp(options.bot.token, 'gu'), '<redacted>')
.replace(new RegExp(username, 'gu'), '<redacted>');
const developers = ['nolan', 'navy'];
const random = developers[Math.floor(Math.random()*developers.length)];
const developers = [
'nolan',
'navy'
];
const random = developers[Math.floor(Math.random() * developers.length)];
const embed = {
color: 0xe88388,
@ -43,6 +45,6 @@ class DiscordWebhook extends Transport {
callback();
}
};
}
module.exports = DiscordWebhook;

View File

@ -1,4 +1,4 @@
/* eslint-disable no-control-regex */
/* eslint-disable */
const { transports: { File }} = require('winston');
const debug = require('diagnostics')('winston:file');
const { MESSAGE } = require('triple-beam');

View File

@ -1,4 +1,3 @@
/* eslint-disable linebreak-style */
module.exports = {
DiscordWebhook: require('./DiscordWebhook.js'),
FileExtension: require('./FileExtension.js')

View File

@ -21,7 +21,7 @@
"common-tags": "^1.8.0",
"discord.js": "discordjs/discord.js",
"escape-string-regexp": "^3.0.0",
"eslint": "^6.8.0",
"eslint": "^7.0.0",
"moment": "^2.24.0",
"mongodb": "^3.5.7",
"mysql": "^2.18.1",

View File

@ -18,15 +18,15 @@ class MariaDBProvider extends Provider {
this.db = MySQL.createPool(this.config);
this.db.on('connection', async connection => {
this.db.on('connection', async (connection) => {
// this.manager.logger.log('MariaDB connected.');
connection.on('error', err => {
connection.on('error', (err) => {
// this.manager.logger.error('MariaDB errored.', err);
});
connection.on('close', data => {
connection.on('close', (data) => {
// this.manager.logger.log('MariaDB connection closed.', data);
});

View File

@ -59,37 +59,22 @@ class MongoDBProvider extends Provider {
stats({ collection, options = { } }) {
return new Promise((resolve, reject) => {
if (!collection || collection.length) {
this.db.stats(options, (err, stats) => {
if (err) return reject(err);
this.db.stats(options, (error, stats) => {
if (error) return reject(error);
else {
let { db, collections, objects, averageSize: avgObjSize, dataSize } = stats;
return resolve({ db, collections, objects, averageSize: avgObjSize, dataSize });
}
const { db, collections, objects, avgObjSize, dataSize } = stats;
return resolve({ db, collections, objects, averageSize: avgObjSize, dataSize });
});
} else {
this.db.collection(collection).stats(options, (err, stats) => {
if (err) return reject(err);
else {
let { ns, size, count, averageSize: avgObjSize } = stats;
return resolve({ index: ns, size, count, averageSize: avgObjSize });
}
const { ns, size, count, avgObjSize } = stats;
return resolve({ index: ns, size, count, averageSize: avgObjSize });
});
}
});
}
@ -109,10 +94,8 @@ class MongoDBProvider extends Provider {
this.db.collection(collection).countDocuments(query, options, (error, result) => {
if (error)
return reject(error);
else
return resolve(result);
if (error) return reject(error);
return resolve(result);
});
@ -239,14 +222,14 @@ class MongoDBProvider extends Provider {
if(!this._initialized) reject(new Error('MongoDB not connected'));
this.db.collection(collection).updateOne(query, { $set: data }, { upsert: upsert }, async (error, result) => {
this.db.collection(collection).updateOne(query, { $set: data }, { upsert }, async (error, result) => {
if(error) return reject(error);
else {
//return resolve(result)
let { matchedCount, upsertedCount, modifiedCount } = result;
return resolve({ matched: matchedCount, upserted: upsertedCount, modified: modifiedCount });
}
//return resolve(result)
const { matchedCount, upsertedCount, modifiedCount } = result;
return resolve({ matched: matchedCount, upserted: upsertedCount, modified: modifiedCount });
});
});
@ -265,17 +248,16 @@ class MongoDBProvider extends Provider {
removeProperty({ collection, query, data }) {
return new Promise((resolve, reject) => {
let unset = {};
for (let field in data) unset[field] = '';
const unset = {};
for (const field of data) unset[field] = '';
this.db.collection(collection).updateOne(query, { $unset: unset }, async (error, result) => {
if(error) return reject(error);
else {
let { matchedCount, modifiedCount } = result;
return resolve({ matched: matchedCount, modified: modifiedCount });
}
const { matchedCount, modifiedCount } = result;
return resolve({ matched: matchedCount, modified: modifiedCount });
});
@ -300,10 +282,10 @@ class MongoDBProvider extends Provider {
if(!this._initialized) reject(new Error('MongoDB not connected'));
this.db.collection(collection).updateOne(query, { $push: data }, { upsert: upsert }, async (error, result) => {
this.db.collection(collection).updateOne(query, { $push: data }, { upsert }, async (error, result) => {
if(error) return reject(error);
else return resolve(result);
return resolve(result);
});
@ -325,15 +307,13 @@ class MongoDBProvider extends Provider {
//if(this.manager.debug) this.manager.logger.debug(`Incoming random query for ${db} with parameters ${JSON.stringify(filter)} and amount ${amount}`);
if(amount > 100) amount = 100;
return new Promise((resolve, reject)=>{
return new Promise((resolve, reject) => {
if(!this._initialized) reject(new Error('MongoDB not connected'));
this.db.collection(collection).aggregate([{ $match: query }, { $sample: {size: amount}}], function(err, item) {
this.db.collection(collection).aggregate([{ $match: query }, { $sample: { size: amount } }], (err, item) => {
if(err) return reject(err);
resolve(item);
return resolve(item);
});
});

View File

@ -57,12 +57,13 @@ class DiscordClient extends Client {
await this.dispatcher.dispatch();
this._built = true;
return this._built;
}
get defaultConfig() {
if(this._defaultConfig) return this._defaultConfig;
const settings = this.registry.components.filter(c=>c.type === 'setting' && c.resolve === 'GUILD');
const settings = this.registry.components.filter((c) => c.type === 'setting' && c.resolve === 'GUILD');
let def = {};
for(const setting of settings.values()) {
if(setting.default !== null) {

View File

@ -9,11 +9,11 @@ class Dispatcher {
async dispatch() {
const observers = this.client.registry.components
.filter(c=>c.type === 'observer' && !c.disabled)
.filter((c) => c.type === 'observer' && !c.disabled)
.sort((a, b) => b.priority - a.priority);
for(const observer of observers.values()) {
for(let [hook, func] of observer.hooks) {
for(const [hook, func] of observer.hooks) {
this.client.eventHooker.hook(hook, func);
}
}

View File

@ -3,7 +3,7 @@ const EventEmitter = require('events');
class EventHooker {
constructor(target) {
if(!(target instanceof EventEmitter)) return new TypeError('Invalid EventEmitter passed to EventHooker.');
if(!(target instanceof EventEmitter)) TypeError('Invalid EventEmitter passed to EventHooker.');
this.target = target;
this.events = new Map();
@ -22,7 +22,7 @@ class EventHooker {
unhook(eventName, func) {
if(this.events.has(eventName)) {
let funcs = this.events.get(eventName);
const funcs = this.events.get(eventName);
const index = funcs.indexOf(func);
if(index > -1) {
funcs.splice(index, 1);

View File

@ -12,7 +12,7 @@ class Logger {
});
this.client.eventHooker.hook('componentUpdate', ({ component, type }) => {
this.info(`Component ${chalk.bold(component.resolveable)} was ${chalk.bold(Constants.ComponentTypes[type])}.`);
this.info(`Component ${chalk.bold(component.resolveable)} was ${chalk.bold(Constants.ComponentTypes[type])}.`); //eslint-disable-line no-use-before-define
});
this.client.eventHooker.hook('reconnect', () => {

View File

@ -5,13 +5,13 @@ class Resolver {
this.client = client;
}
components(str = '', type, exact = true) { //used for CommandHandler
components(str = '', type, exact = true) {
const string = str.toLowerCase();
const components = this.client.registry.components
.filter(c => c.type === type)
.filter(exact ? filterExact(string) : filterInexact(string))
.filter((c) => c.type === type)
.filter(exact ? filterExact(string) : filterInexact(string)) //eslint-disable-line no-use-before-define
.array();
return components || [];
@ -27,9 +27,9 @@ class Resolver {
return true;
} else if (falsey.includes(input)) {
return false;
} else {
return null;
}
return null;
}
// resolveTrue(input) {
@ -46,8 +46,8 @@ class Resolver {
const index = guild ? guild.members.cache : this.client.users.cache;
let member = null;
if(/<@!?(\d{17,21})>/iy.test(str)) { //mentions
const matches = /<@!?(\d{17,21})>/iy.exec(str);
if((/<@!?(\d{17,21})>/iyu).test(str)) { //mentions
const matches = (/<@!?(\d{17,21})>/iuy).exec(str);
member = index.get(matches[1]);
if(!member) {
try {
@ -58,8 +58,8 @@ class Resolver {
} catch(e) {} //eslint-disable-line no-empty
} //eslint-disable-line no-empty
}
} else if(/\d{17,21}/iy.test(str)) { //id
const matches = /(\d{17,21})/iy.exec(str);
} else if((/\d{17,21}/iuy).test(str)) { //id
const matches = (/(\d{17,21})/iuy).exec(str);
member = index.get(matches[1]);
if(!member) {
try {
@ -70,11 +70,11 @@ class Resolver {
} catch(e) {} //eslint-disable-line no-empty
} //eslint-disable-line no-empty
}
} else if(/(.{2,32})#(\d{4})/iy.test(str)) { //username#discrim
const matches = /(.{2,32})#(\d{4})/iy.exec(str);
} else if((/(.{2,32})#(\d{4})/iuy).test(str)) { //username#discrim
const matches = (/(.{2,32})#(\d{4})/iuy).exec(str);
member = guild
? guild.members.cache.filter(m=>m.user.username === matches[1] && m.user.discriminator === matches[2]).first()
: this.client.users.cache.filter(u=>u.username === matches[1] && u.discriminator === matches[2]).first();
? guild.members.cache.filter((m) => m.user.username === matches[1] && m.user.discriminator === matches[2]).first()
: this.client.users.cache.filter((u) => u.username === matches[1] && u.discriminator === matches[2]).first();
}
return member || null;
@ -93,39 +93,43 @@ class Resolver {
if(typeof resolveables === 'string') resolveables = [ resolveables ];
if(resolveables.length === 0) return false;
let users = this.client.users;
let resolved = [];
const { users } = this.client;
const resolved = [];
for(let resolveable of resolveables) {
for(const resolveable of resolveables) {
if(/<@!?([0-9]{17,21})>/.test(resolveable)) {
if((/<@!?([0-9]{17,21})>/u).test(resolveable)) {
let id = resolveable.match(/<@!?([0-9]{17,21})>/)[1];
let user = await users.fetch(id).catch(err => { if(err.code === 10013) return false; else { this.client.logger.warn(err); return false; } });
const [, id] = resolveable.match(/<@!?([0-9]{17,21})>/u);
const user = await users.fetch(id).catch((err) => {
if(err.code === 10013) return false;
this.client.logger.warn(err); return false;
});
if(user) resolved.push(user);
} else if(/(id\:)?([0-9]{17,21})/.test(resolveable)) {
} else if((/(id:)?([0-9]{17,21})/u).test(resolveable)) {
let id = resolveable.match(/(id\:)?([0-9]{17,21})/)[2];
let user = await users.fetch(id).catch(err => { if(err.code === 10013) return false; else { this.client.logger.warn(err); return false; } });
const [,, id] = resolveable.match(/(id:)?([0-9]{17,21})/u);
const user = await users.fetch(id).catch((err) => {
if(err.code === 10013) return false;
this.client.logger.warn(err); return false;
});
if(user) resolved.push(user);
} else if(/^\@?([\S\s]{1,32})\#([0-9]{4})/.test(resolveable)) {
} else if((/^@?([\S\s]{1,32})#([0-9]{4})/u).test(resolveable)) {
let m = resolveable.match(/^\@?([\S\s]{1,32})\#([0-9]{4})/);
let username = m[1].toLowerCase();
let discrim = m[2].toLowerCase();
let user = users.cache.filter(u => {
return u.username.toLowerCase() === username && u.discriminator === discrim;
}).first();
const m = resolveable.match(/^@?([\S\s]{1,32})#([0-9]{4})/u);
const username = m[1].toLowerCase();
const discrim = m[2].toLowerCase();
const user = users.cache.filter((u) => u.username.toLowerCase() === username && u.discriminator === discrim).first();
if(user) resolved.push(user);
} else if(!strict) {
let name = resolveable.toLowerCase();
let user = users.cache.filter(u => {
return u.username.toLowerCase().includes(name);
}).first();
const name = resolveable.toLowerCase();
const user = users.cache.filter((u) => u.username.toLowerCase().includes(name)).first();
if(user) resolved.push(user);
}
@ -137,7 +141,7 @@ class Resolver {
}
async resolveUser(resolveable, strict) {
let result = await this.resolveUsers([ resolveable ], strict);
const result = await this.resolveUsers([ resolveable ], strict);
return result ? result[0] : false;
}
@ -154,43 +158,47 @@ class Resolver {
if(typeof resolveables === 'string') resolveables = [ resolveables ];
if(resolveables.length === 0) return false;
let members = guild.members;
let resolved = [];
const { members } = guild;
const resolved = [];
for(let resolveable of resolveables) {
for(const resolveable of resolveables) {
if(/<@!?([0-9]{17,21})>/.test(resolveable)) {
if((/<@!?([0-9]{17,21})>/u).test(resolveable)) {
let id = resolveable.match(/<@!?([0-9]{17,21})>/)[1];
let member = await members.fetch(id).catch(err => { if(err.code === 10007) return false; else { this.client.logger.warn(err); return false; } });
const [, id] = resolveable.match(/<@!?([0-9]{17,21})>/u);
const member = await members.fetch(id).catch((err) => {
if(err.code === 10007) return false;
this.client.logger.warn(err); return false;
});
if(member) resolved.push(member);
} else if(/(id\:)?([0-9]{17,21})/.test(resolveable)) {
} else if((/(id:)?([0-9]{17,21})/u).test(resolveable)) {
let id = resolveable.match(/(id\:)?([0-9]{17,21})/)[2];
let member = await members.fetch(id).catch(err => { if(err.code === 10007) return false; else { this.client.logger.warn(err); return false; } });
const [,, id] = resolveable.match(/(id:)?([0-9]{17,21})/u);
const member = await members.fetch(id).catch((err) => {
if(err.code === 10007) return false;
this.client.logger.warn(err); return false;
});
if(member) resolved.push(member);
} else if(/^\@?([\S\s]{1,32})\#([0-9]{4})/.test(resolveable)) {
} else if((/^@?([\S\s]{1,32})#([0-9]{4})/u).test(resolveable)) {
let m = resolveable.match(/^\@?([\S\s]{1,32})\#([0-9]{4})/);
let username = m[1].toLowerCase();
let discrim = m[2].toLowerCase();
let member = members.cache.filter(m => {
return m.user.username.toLowerCase() === username && m.user.discriminator === discrim;
}).first();
const m = resolveable.match(/^@?([\S\s]{1,32})#([0-9]{4})/u);
const username = m[1].toLowerCase();
const discrim = m[2].toLowerCase();
const member = members.cache.filter((m) => m.user.username.toLowerCase() === username && m.user.discriminator === discrim).first();
if(member) resolved.push(member);
} else if(/^\@?([\S\s]{1,32})/.test(resolveable) && guild && !strict) {
} else if((/^@?([\S\s]{1,32})/u).test(resolveable) && guild && !strict) {
let nickname = resolveable.match(/^\@?([\S\s]{1,32})/)[0].toLowerCase();
let member = members.cache.filter((m) => {
return (m && m.user) &&
((!m.nickname ? false : m.nickname.toLowerCase() == nickname ) ||
const nickname = resolveable.match(/^@?([\S\s]{1,32})/u)[0].toLowerCase();
const member = members.cache.filter((m) => m && m.user &&
((!m.nickname ? false : m.nickname.toLowerCase() === nickname) ||
(!m.nickname ? false : m.nickname.toLowerCase().includes(nickname)) ||
m.user.username.toLowerCase().includes(nickname) ||
m.user.username.toLowerCase() == nickname);
}).first();
m.user.username.toLowerCase() === nickname)).first();
if(member) resolved.push(member);
}
@ -203,7 +211,7 @@ class Resolver {
async resolveMember(resolveable, guild, strict) {
let result = await this.resolveMembers([ resolveable ], guild, strict);
const result = await this.resolveMembers([ resolveable ], guild, strict);
return result ? result[0] : false;
}
@ -221,35 +229,35 @@ class Resolver {
if(typeof resolveables === 'string') resolveables = [ resolveables ];
if(resolveables.length === 0) return false;
let channels = guild.channels;
let resolved = [];
const { channels } = guild;
const resolved = [];
for(let resolveable of resolveables) {
for(const resolveable of resolveables) {
let channel = channels.resolve(resolveable);
const channel = channels.resolve(resolveable);
if(channel) {
resolved.push(channel);
continue;
}
let name = /^\#?([a-z0-9\-\_0]*)/i;
let id = /^\<\#([0-9]*)\>/i;
const name = /^#?([a-z0-9\-_0]*)/iu;
const id = /^<#([0-9]*)>/iu;
if (id.test(resolveable)) {
let match = resolveable.match(id);
let ch = match[1];
const match = resolveable.match(id);
const [, ch] = match;
let channel = channels.resolve(ch);
const channel = channels.resolve(ch);
if (channel) resolved.push(channel);
} else if (name.test(resolveable)) {
let match = resolveable.match(name);
let ch = match[1].toLowerCase();
const match = resolveable.match(name);
const ch = match[1].toLowerCase();
let [ channel ] = channels.cache.filter(c => {
const [ channel ] = channels.cache.filter((c) => {
if(!strict) return c.name.toLowerCase().includes(ch);
return c.name.toLowerCase() === ch;
}).first(1);
@ -266,7 +274,7 @@ class Resolver {
resolveChannel(resolveable, guild, strict) {
let result = this.resolveChannels([resolveable], guild, strict);
const result = this.resolveChannels([resolveable], guild, strict);
return result ? result[0] : false;
}
@ -284,25 +292,25 @@ class Resolver {
if(typeof resolveables === 'string') resolveables = [ resolveables ];
if(resolveables.length === 0) return false;
let roles = guild.roles;
let resolved = [];
const { roles } = guild;
const resolved = [];
for(let resolveable of resolveables) {
for(const resolveable of resolveables) {
let id = /^(<@&)?([0-9]{16,22})>?/i;
const id = /^(<@&)?([0-9]{16,22})>?/iu;
if(id.test(resolveable)) {
let match = resolveable.match(id);
let r_id = match[2];
const match = resolveable.match(id);
const [,, rId] = match;
let role = await roles.fetch(r_id).catch(this.client.logger.error);
const role = await roles.fetch(rId).catch(this.client.logger.error);
if(role) resolved.push(role);
} else {
let role = roles.cache.filter(r => {
const role = roles.cache.filter((r) => {
if(!strict) return r.name.toLowerCase().includes(resolveable.toLowerCase());
return r.name.toLowerCase() === resolveable.toLowerCase();
}).first();
@ -319,7 +327,7 @@ class Resolver {
async resolveRole(resolveable, guild, strict) {
let result = await this.resolveRoles([resolveable], guild, strict);
const result = await this.resolveRoles([resolveable], guild, strict);
return result ? result[0] : false;
}
@ -328,16 +336,12 @@ class Resolver {
module.exports = Resolver;
const filterExact = (search) => {
return comp => comp.id.toLowerCase() === search ||
const filterExact = (search) => (comp) => comp.id.toLowerCase() === search ||
comp.resolveable.toLowerCase() === search ||
(comp.aliases && (comp.aliases.some(ali => `${comp.type}:${ali}`.toLowerCase() === search) ||
comp.aliases.some(ali => ali.toLowerCase() === search)));
};
comp.aliases && (comp.aliases.some((ali) => `${comp.type}:${ali}`.toLowerCase() === search) ||
comp.aliases.some((ali) => ali.toLowerCase() === search));
const filterInexact = (search) => {
return comp => comp.id.toLowerCase().includes(search) ||
const filterInexact = (search) => (comp) => comp.id.toLowerCase().includes(search) ||
comp.resolveable.toLowerCase().includes(search) ||
(comp.aliases && (comp.aliases.some(ali => `${comp.type}:${ali}`.toLowerCase().includes(search)) ||
comp.aliases.some(ali => ali.toLowerCase().includes(search))));
};
comp.aliases && (comp.aliases.some((ali) => `${comp.type}:${ali}`.toLowerCase().includes(search)) ||
comp.aliases.some((ali) => ali.toLowerCase().includes(search)));

View File

@ -26,7 +26,7 @@ class TransactionHandler {
return new Promise((resolve, reject) => {
const id = this.transactionID;
this.transactions.set(id, { id, resolve, reject } );
this.transactions.set(id, { id, resolve, reject });
process.send({ _storage: true, transactionID: id, ...message, ...options });
@ -44,7 +44,7 @@ class TransactionHandler {
if(message.error) transaction.reject(message.message);
else transaction.resolve(message.result);
this.transactions.delete(message.transactionID);
return this.transactions.delete(message.transactionID);
}

View File

@ -14,17 +14,19 @@ class GrantCommand extends Command {
"\"Server Moderators\" module:moderation",
"@nolan#2887 command:kick"
],
memberPermissions: ['ADMINISTRATOR', 'MANAGE_SERVER'],
//memberPermissions: ['ADMINISTRATOR', 'MANAGE_GUILD'],
showUsage: true,
guildOnly: true,
grantable: true,
arguments: [
{
name: 'channel',
aliases: [
'channels'
],
aliases: ['channels'],
type: 'CHANNEL',
types: ['FLAG', 'VERBAL'],
types: [
'FLAG',
'VERBAL'
],
infinite: true
}
]
@ -34,11 +36,12 @@ class GrantCommand extends Command {
async execute(message, { params, args }) {
// console.log(args.channel);
const _permissions = await message.guild.permissions();
const [ parse, ...perms ] = params;
const [
parse,
...perms
] = params;
const resolveable = await this._parseResolveable(message, parse);
if(!resolveable) return undefined;
@ -47,25 +50,21 @@ class GrantCommand extends Command {
return undefined;
}
const permissions = this.client.registry.components.filter(c=>
c.type === 'command'
|| c.type === 'module'
);
const permissions = this.client.registry.components.filter((c) => c.type === 'command' ||
c.type === 'module');
let parsed = [];
if(perms.join(' ') === 'all') {
parsed = this.client.registry.components.filter(c=>c.grantable && c.type === 'command').map(c=>c.resolveable);
parsed = this.client.registry.components.filter((c) => c.type === 'command').map((c) => c.resolveable); //filter for grantable
} else {
for(const perm of perms) {
const search = permissions.filter(filterInexact(perm)).first();
if(!search) failed.push(perm);
const search = permissions.filter(filterInexact(perm)).first(); //eslint-disable-line no-use-before-define
if(!search) continue;
if(search.type === 'module') {
for(const component of search.components.values()) {
if(component.type === 'command') parsed.push(component.resolveable);
//add check for grantable
}
} else {
//add check for grantable
parsed.push(search.resolveable);
}
}
@ -77,34 +76,36 @@ class GrantCommand extends Command {
channels: {}
};
}
let existing = _permissions[resolveable.id];
const existing = _permissions[resolveable.id];
let pushed = [];
let failed = [];
let granted = [];
if(args.channel) {
for(const channel of args.channel.value) {
const existingChannel = existing.channels[channel.id];
if(existingChannel) {
for(const perm of parsed) {
if(existingChannel.includes(perm)) {
failed.push(perm);
continue;
} else {
existingChannel.push(perm);
pushed.push(perm);
granted.push(perm);
}
}
} else {
existing.channels[channel.id] = parsed;
pushed.concat(parsed)
granted = [
...granted,
...parsed
];
}
}
} else {
for(const perm of parsed) {
if(existing.global.includes(perm)) {
failed.push(perm);
continue;
} else {
existing.global.push(perm);
pushed.push(perm);
granted.push(perm);
}
}
}
@ -124,16 +125,15 @@ class GrantCommand extends Command {
}
});
} catch(error) {
await message.respond(message.format('C_GRANT_DATABASEERROR'), { emoji: 'failure' });
return undefined;
await message.respond(message.format('C_GRANT_DATABASEERROR'), { emoji: 'failure' });
return undefined;
}
if(pushed.length > 0) {
return await message.respond(stripIndents`${message.format('C_GRANT_SUCCESS', { resolveable: resolveable.name || resolveable.user?.tag, permissions: pushed.map(p=>`\`${p}\``).join(', ') })}${args.channel ? ` ${message.format('C_GRANT_SUCCESSALT', { channels: args.channel.value.map(c=>`\`#${c.name}\``).join(', ')})}`: '.'}
${failed.length > 0 ? message.format('C_GRANT_SUCCESSFAILED', { resolveable: resolveable.user ? 'user' : 'role' }) : ''}`, { emoji: 'success' });
} else {
return await message.respond(message.format('C_GRANT_FAILED', { failed: failed.map(f=>`\`${f}\``).join(', '), resolveable: resolveable.user ? 'user' : 'role' }), { emoji: 'failure' })
if(granted.length > 0) {
return message.respond(stripIndents`${message.format('C_GRANT_SUCCESS', { permissions: granted.map((g) => `\`${g}\``).join(', '), resolveable: resolveable.user ? resolveable.user.tag : resolveable.name })}${args.channel ? ` ${message.format('C_GRANT_SUCCESSALT', { channels: args.channel.value.map((c) => `\`#${c.name}\``).join(', ') })}` : '.'}
${granted.length < parsed.length ? message.format('C_GRANT_SUCCESSFAILED') : ''}`, { emoji: 'success' });
}
return message.respond(message.format('C_GRANT_FAILED', { resolveable: resolveable.user ? resolveable.user.tag : resolveable.name }), { emoji: 'failure' });
}
@ -154,9 +154,7 @@ class GrantCommand extends Command {
module.exports = GrantCommand;
const filterInexact = (search) => {
return comp => comp.id.toLowerCase().includes(search) ||
const filterInexact = (search) => (comp) => comp.id.toLowerCase().includes(search) ||
comp.resolveable.toLowerCase().includes(search) ||
(comp.aliases && (comp.aliases.some(ali => `${comp.type}:${ali}`.toLowerCase().includes(search)) ||
comp.aliases.some(ali => ali.toLowerCase().includes(search))));
};
comp.aliases && (comp.aliases.some((ali) => `${comp.type}:${ali}`.toLowerCase().includes(search)) ||
comp.aliases.some((ali) => ali.toLowerCase().includes(search)));

View File

@ -1,40 +1,211 @@
const { Role, MessageAttachment } = require('discord.js');
const { Command } = require('../../../../interfaces/');
const { stripIndents } = require('common-tags');
class GrantCommand extends Command {
class PermissionsCommand extends Command {
constructor(client) {
super(client, {
name: 'permissions',
module: 'administration',
usage: '<role|user>',
usage: "<list|role-name|user-name>",
aliases: [
'perms',
'permission',
'perm'
],
examples: [
'Server Moderators',
'@nolan#2887'
"list",
"Server Moderators",
"@nolan#2887"
],
memberPermissions: ['ADMINISTRATOR', 'MANAGE_SERVER'],
arguments: [
{
name: 'user',
aliases: ['users'],
type: 'BOOLEAN',
types: ['VERBAL', 'FLAG'],
default: true
},
{
name: 'raw',
aliases: ['json'],
type: 'BOOLEAN',
types: ['VERBAL', 'FLAG'],
default: true
}
],
// memberPermissions: ['ADMINISTRATOR', 'MANAGE_GUILD'],
guildOnly: true
});
}
async execute(message) {
async execute(message, { params, args }) {
await message.guild.permissions();
const permissions = await message.guild.permissions();
if(args.json) {
await this._displayRaw(message, permissions);
return undefined;
}
message.respond(`\`\`\`js
${JSON.stringify(message.guild._permissions)}\`\`\``);
if(params.length === 0) {
await this._showPermissions(message, Boolean(args.user));
return undefined;
}
if(params[0] === 'list') {
await this._listAvailablePermissions(message);
return undefined;
} else {
const parameters = params.join(' ');
const resolveable = await this._parseResolveable(message, parameters);
const permission = permissions[resolveable?.id || parameters];
if(!permission) {
await message.respond(message.format('C_PERMISSIONS_NOTFOUND'), { emoji: 'failure' });
return undefined;
}
const embed = {
author: {
name: `${resolveable?.user?.tag || resolveable?.tag || resolveable?.name || parameters} Permissions`,
// icon_url: resolveable?.user?.displayAvatarURL() || resolveable?.displayAvatarURL() || message.guild.iconURL()
},
description: `${message.format('C_PERMISSIONS_GLOBAL', { permissions: permission.global.length > 0 ? this._displayNames(permission.global).map(p=>`\`${p}\``).join(', ') : "`N/A`" })} ${Object.values(permission.channels).length > 0 ? message.format('C_PERMISSIONS_GLOBALALT') : ''}`,
fields: []
};
let update = false;
for(const [channelId, perms] of Object.entries(permission.channels)) {
const channel = this.client.resolver.resolveChannels(channelId, message.guild, true)[0];
if(!channel) {
delete permission.channels[channelId];
update = true;
continue;
} else {
if(embed.fields.length === 25) {
embed.description += `\n${message.format('C_PERMISSIONS_MAXFIELDS')}`;
break;
}
embed.fields.push({
name: `#${channel.name}`,
value: this._displayNames(perms).map(p=>`\`${p}\``).join(', ')
});
}
}
if(update) {
delete permissions._id
try {
await this.client.transactionHandler.send({
provider: 'mongodb',
request: {
type: 'updateOne',
collection: 'permissions',
query: {
guildId: message.guild.id
},
data: permissions
}
});
} catch(error) {
this.client.logger.error(`Error removing channel permissions to ${message.guild.id}:\n${error.stack || error}`);
}
}
return await message.embed(embed);
}
}
async _showPermissions(message, user = false) {
const embed = {
author: {
name: message.format('C_PERMISSIONS_SHOWTITLE', { user }, true),
icon_url: message.guild.iconURL()
},
description: message.format('C_PERMISSIONS_SHOWDESCRIPTION', { resolve: user ? 'user' : 'role' }),
fields: []
};
const permissions = message.guild._permissions;
for(const [id, value] of Object.entries(permissions)) {
if(id === '_id' || id === 'guildId') continue;
const item = await this.client.resolver[user ? 'resolveMemberAndUser' : 'resolveRole'](id, message.guild); //dont kill me
if(item instanceof Role && user) continue;
else if(!user && !(item instanceof Role)) continue;
if(embed.fields.length === 25) {
embed.description += `\n${message.format('C_PERMISSIONS_MAXFIELDS')}`;
break;
}
const name = item?.user?.tag || item?.tag || item?.name || id; //please dont kill me again
const channels = Object.values(value.channels).length;
embed.fields.push({
name,
value: stripIndents`${this._displayNames(value.global).map(n=>`\`${n}\``).join('\n')}
${channels > 0 ? `\`..${channels} channel${channels === 1 ? '' : 's'}\`` : ''}`
});
}
return await message.embed(embed);
}
async _listAvailablePermissions(message) {
const components = this.client.registry.components.filter(c=>(c.type === 'command' && c.grantable) || (c.type === 'module' && c.components.some(c=>c.type === 'command' && c.grantable)))
.sort((a, b) => a - b);
return await message.respond(message.format('C_PERMISSIONS_LIST', { permissions: components.map(c => `\`${c.resolveable}\``).join(', ') }), { emoji: 'success' });
}
async _parseResolveable(message, resolveable) {
let parsed = await this.client.resolver.resolveRoles(resolveable, message.guild);
if(!parsed) {
parsed = await this.client.resolver.resolveMembers(resolveable, message.guild);
if(!parsed) {
parsed = await this.client.resolver.resolveUsers(resolveable);
if(!parsed) return null;
}
}
return parsed[0];
}
async _displayRaw(message, permissions) {
const string = JSON.stringify(permissions);
const attachment = new MessageAttachment(Buffer.from(string), "permissions.json");
return await message.respond(message.format('C_PERMISSIONS_JSON'), { emoji: 'success', attachments: [ attachment ] })
}
_displayNames(permissions) {
const modules = this.client.registry.components.filter(c=>c.type === 'module');
let names = [];
let temp = [];
for(const module of modules.values()) {
for(const component of module.components.filter(c=>c.type === 'command').values()) {
if(permissions.includes(component.resolveable)) {
temp.push(component.resolveable);
}
}
temp.length === module.components.filter(c=>c.type === 'command').size
? names.push(module.resolveable)
: names = names.concat(temp);
temp = [];
}
return names;
}
}
module.exports = GrantCommand;
module.exports = PermissionsCommand;

View File

@ -1,3 +1,6 @@
const { User, GuildMember } = require('discord.js');
const { stripIndents } = require('common-tags')
const { Command } = require('../../../../interfaces/');
class RevokeCommand extends Command {
@ -13,7 +16,7 @@ class RevokeCommand extends Command {
"@nolan#2887 command:kick",
"132620781791346688 moderation"
],
memberPermissions: ['ADMINISTRATOR'],
// memberPermissions: ['ADMINISTRATOR', 'MANAGE_GUILD'],
showUsage: true,
guildOnly: true,
arguments: [
@ -107,30 +110,10 @@ class RevokeCommand extends Command {
}
}
//check for deletion, saves DB space.
//NOTE: DO NOT REMOVE THE _PERMISSIONS VARIABLE.
console.log(permission.global.length, Object.keys(permission.channels).length);
if(permission.global.length === 0
&& Object.keys(permission.channels).length === 0) {
try {
const blah = await this.client.transactionHandler.send({
provider: 'mongodb',
request: {
type: 'remove',
collection: 'permissions',
query: {
guildId: message.guild.id
}
}
});
console.log(blah);
} catch(error) {
this.client.logger.warn(`Attempted to delete collection permissions:${message.guild.id} but failed.`);
}
}
delete _permissions._id; //some bullshit..
//check for deletion, saves DB space.
//NOTE: DO NOT REMOVE THE _PERMISSIONS VARIABLE.
if(permission.global.length === 0 && Object.keys(permission.channels).length === 0) {
try {
await this.client.transactionHandler.send({
@ -165,7 +148,18 @@ class RevokeCommand extends Command {
}
}
const name = resolveable instanceof GuildMember
? resolveable?.user?.tag
: resolveable instanceof User
? resolveable?.tag
: resolveable?.name;
if(removed.length > 0) {
await message.respond(stripIndents`${message.format('C_REVOKE_SUCCESS', { removed: removed.map(r=>`\`${r}\``).join(', '), resolveable: name || parsed })}${args.channel ? ` ${message.format('C_REVOKE_SUCCESSALT', { channels: args.channel.value.map(c=>`\`#${c.name}\``).join(', ')})}` : '.'}
${removed.length < parsed.length ? message.format('C_REVOKE_SUCCESSFAILED'): ''}`, { emoji: 'success' });
} else {
await message.respond(message.format('C_REVOKE_FAILED', { resolveable: name || parsed }), { emoji: 'failure' });
}
}

View File

@ -24,7 +24,7 @@ class ComponentCommand extends Command {
// description: "Reloads the language library",
// default: 'all'
// }
],
]
});
this.client = client;
@ -36,21 +36,16 @@ class ComponentCommand extends Command {
//<load|unload|reload|disable|enable> <component>
const method = params.shift().toLowerCase();
let response;
let response = null;
if (method === 'reload' || method === 'r')
response = this._handleReload(params);
else if (method === 'enable')
response = this._handleDisableEnable(params.shift().toLowerCase(), true);
else if (method === 'disable')
response = this._handleDisableEnable(params.shift().toLowerCase(), false);
else if (method === 'load')
response = this._handleLoadUnload(params.shift().toLowerCase(), true);
else if (method === 'unload')
response = this._handleLoadUnload(params.shift().toLowerCase(), false);
else return await message.respond('Invalid method. Can only be `reload`, `enable`, `disable`, `load`, `unload`', 'failure');
if (method === 'reload' || method === 'r') response = this._handleReload(params);
else if (method === 'enable') response = this._handleDisableEnable(params.shift().toLowerCase(), true);
else if (method === 'disable') response = this._handleDisableEnable(params.shift().toLowerCase(), false);
else if (method === 'load') response = this._handleLoadUnload(params.shift().toLowerCase(), true);
else if (method === 'unload') response = this._handleLoadUnload(params.shift().toLowerCase(), false);
else return message.respond('Invalid method. Can only be `reload`, `enable`, `disable`, `load`, `unload`', 'failure');
return await message.respond(response.msg, { emoji: response.error ? 'failure' : 'success' });
return message.respond(response.msg, { emoji: response.error ? 'failure' : 'success' });
}
@ -64,39 +59,37 @@ class ComponentCommand extends Command {
if (value === 'all') {
this.client.localeLoader.loadLanguages();
return { msg: 'Reloaded all languages' };
} else {
try {
this.client.localeLoader.loadLanguage(value);
return { msg: `Reloaded locale \`${value}\`` };
} catch (err) {
return { error: true, msg: err.message };
}
}
try {
this.client.localeLoader.loadLanguage(value);
return { msg: `Reloaded locale \`${value}\`` };
} catch (err) {
return { error: true, msg: err.message };
}
} else {
if (name === 'all') {
const errors = [];
const components = this.client.registry.components;
for (let component of components.values()) {
const { components } = this.client.registry;
for (const component of components.values()) {
const result = component.reload();
if (result.error) errors.push(`Component ${component.id} errored while reloading with code \`${result.code}\``);
}
if (errors.length) return { error: true, msg: `The following errors occurred during reload:\n${errors.join('\n')}` };
return { msg: `Successfully reloaded all components` };
} else {
const component = this.client.registry.components.get(name);
if (!component) return { error: true, msg: `Component ${name} doesn't exist.` };
const result = component.reload();
if (result.error) return { error: true, msg: `Component ${name} errored while reloading with code \`${result.code}\`` };
else return { msg: `Successfully reloaded ${name}` };
}
const component = this.client.registry.components.get(name);
if (!component) return { error: true, msg: `Component ${name} doesn't exist.` };
const result = component.reload();
if (result.error) return { error: true, msg: `Component ${name} errored while reloading with code \`${result.code}\`` };
return { msg: `Successfully reloaded ${name}` };
}
}
@ -104,19 +97,19 @@ class ComponentCommand extends Command {
_handleDisableEnable(name, enable) {
const component = this.client.registry.components.get(name);
let result;
let result = null;
if (!component) return { error: true, msg: `Component ${name} doesn't exist.` };
if (enable) result = component.enable();
else result = component.disable();
if (result.error) return { error: true, msg: `Cannot ${enable ? 'enable' : 'disable'} ${name} due to ${result.code}` };
else return { msg: `Successfully ${enable ? 'enabled' : 'disabled'} component ${name}` };
return { msg: `Successfully ${enable ? 'enabled' : 'disabled'} component ${name}` };
}
_handleLoadUnload(name, load) {
let result;
let result = null;
if (load) {
const directory = path.join(process.cwd(), 'structure/client/components', name);
try {
@ -135,14 +128,14 @@ class ComponentCommand extends Command {
if (!result) return { error: true, msg: `Failed to load component ${name}, see console.` };
return { msg: `Successfully loaded component: ${component.resolveable}` };
} else {
const component = this.client.registry.components.filter(filterInexact(name)).first();
if (!component) return { error: true, msg: `Component ${name} doesn't exist.` };
result = component.unload();
}
const component = this.client.registry.components.filter(filterInexact(name)).first(); //eslint-disable-line no-use-before-define
if (!component) return { error: true, msg: `Component ${name} doesn't exist.` };
result = component.unload();
if (result.error) return { error: true, msg: `Cannot ${load ? 'load' : 'unload'} ${name} due to ${result.code}` };
else return { msg: `Successfully ${load ? 'loaded' : 'unloaded'} component ${name}` };
return { msg: `Successfully ${load ? 'loaded' : 'unloaded'} component ${name}` };
}
@ -150,9 +143,7 @@ class ComponentCommand extends Command {
module.exports = ComponentCommand;
const filterInexact = (search) => {
return comp => comp.id.toLowerCase().includes(search) ||
const filterInexact = (search) => (comp) => comp.id.toLowerCase().includes(search) ||
comp.resolveable.toLowerCase().includes(search) ||
(comp.aliases && (comp.aliases.some(ali => `${comp.type}:${ali}`.toLowerCase().includes(search)) ||
comp.aliases.some(ali => ali.toLowerCase().includes(search))));
};
comp.aliases && (comp.aliases.some((ali) => `${comp.type}:${ali}`.toLowerCase().includes(search)) ||
comp.aliases.some((ali) => ali.toLowerCase().includes(search)));

View File

@ -1,12 +1,10 @@
const { inspect } = require('util');
const { username } = require('os').userInfo();
let _storage = null; //eslint-disable-line no-unused-vars
let _storage = null; //eslint-disable-line
const { Command } = require('../../../../interfaces/');
class Evaluate extends Command {
constructor(client) {
@ -44,21 +42,21 @@ class Evaluate extends Command {
params = params.join(' ');
try {
let evaled = eval(params);
let evaled = eval(params); //eslint-disable-line no-eval
if(evaled instanceof Promise) await evaled;
if(typeof evaled !== 'string') evaled = inspect(evaled);
evaled = evaled
.replace(new RegExp(this.client.token, 'g'), '<redacted>')
.replace(new RegExp(username, 'g'), '<redacted>');
.replace(new RegExp(this.client.token, 'gu'), '<redacted>')
.replace(new RegExp(username, 'gu'), '<redacted>');
if(args.log) this.client.logger.debug(`[${message.author.tag}] Evaluation Result: ${evaled}`);
if (evaled.length > 1850) {
console.log(evaled);
evaled = `${evaled.substring(0, 1850)}...`;
}
await message.respond(`Evaluation was successful.\`\`\`js\n${evaled}\`\`\``,
await message.respond(
`Evaluation was successful.\`\`\`js\n${evaled}\`\`\``,
{ emoji: 'success' }
);
@ -70,7 +68,8 @@ class Evaluate extends Command {
if(args.log) this.client.logger.debug(`[${message.author.tag}] Evaluation Failed: ${msg}`);
if(msg.length > 2000) msg = `${msg.substring(0, 1900)}...`;
await message.respond(`Evaluation failed.\`\`\`js\n${msg}\`\`\``,
await message.respond(
`Evaluation failed.\`\`\`js\n${msg}\`\`\``,
{ emoji: 'failure' }
);

View File

@ -29,8 +29,7 @@ class CommandsCommand extends Command {
async execute(message, { params }) {
if (!params.length) // list all commands
return this._listCommands(message);
if (!params.length) return this._listCommands(message);
params = params.join(' ');
@ -38,23 +37,23 @@ class CommandsCommand extends Command {
if(!mod) {
const [ command ] = this.client.resolver.components(params, 'command', false);
if (!command) return message.format('C_COMMAND_INVALID');
return await message._showUsage(command);
return message._showUsage(command);
}
//list module's commands
const commands = mod.components.filter(c=>c.type === 'command');
const commands = mod.components.filter((c) => c.type === 'command');
let text = '';
for(let command of commands.values()) {
for(const command of commands.values()) {
text += command.disabled ? `~~${command.name}~~\n` : `${command.name}`; //TODO: Denote disabled commands somehow
}
const embed = {
author: {
name: message.format('C_COMMANDS_TITLE'),
icon_url: this.client.user.avatarURL()
icon_url: this.client.user.avatarURL() //eslint-disable-line camelcase
},
description: message.format('C_COMMANDS') + '\n' + message.format('C_COMMANDS_TEMPLATE', { mod: mod.name, text }),
description: `${message.format('C_COMMANDS')}\n${message.format('C_COMMANDS_TEMPLATE', { mod: mod.name, text })}`,
footer: {
text: message.format('C_COMMANDS_FOOTER')
}
@ -66,24 +65,24 @@ class CommandsCommand extends Command {
_listCommands(message) {
let fields = [];
const fields = [];
const sortedModules = this.client.registry.components
.filter(c => c.type === 'module')
.filter((c) => c.type === 'module')
.sort((a, b) => {
const filter = c => c.type === 'command';
const filter = (c) => c.type === 'command';
return b.components.filter(filter) - a.components.filter(filter);
});
for (const mod of sortedModules.values()) {
let field = {
const field = {
name: mod.id,
value: '',
inline: true
};
for (const command of mod.components.values()) {
if (command.type !== 'command'
|| (command.restricted && !this.client._options.bot.owners.includes(message.author.id))) continue;
if (command.type !== 'command' ||
command.restricted && !this.client._options.bot.owners.includes(message.author.id)) continue;
field.value += `${command.name}\n`;
}
if (field.value) fields.push(field);
@ -92,7 +91,7 @@ class CommandsCommand extends Command {
const embed = {
author: {
name: message.format('C_COMMANDS_TITLE'),
icon_url: this.client.user.avatarURL()
icon_url: this.client.user.avatarURL() //eslint-disable-line camelcase
},
description: message.format('C_COMMANDS'),
fields,

View File

@ -15,21 +15,19 @@ class HelpCommand extends Command {
async execute(message, { params }) {
if (!params.length)
return await message.embed({
description: message.format('C_HELP')
});
if (!params.length) return message.embed({
description: message.format('C_HELP')
});
const [ key ] = params;
let [ result ] = this.client.resolver.components(key, 'command');
if (!result) [ result ] = this.client.resolver.components(key, 'setting');
if (!result)
return await message.embed({
description: message.format('C_HELP_404', { component: key })
});
if (!result) return message.embed({
description: message.format('C_HELP_404', { component: key })
});
//let index = `${result.type.slice(0, 1).toUpperCase()}_${result.name.toUpperCase()}_HELP`;
return await message.embed({
return message.embed({
description: message.format('C_HELP_TEMPLATE', {
desc: message.format(result.description),
component: result.name.toUpperCase(),

View File

@ -50,7 +50,8 @@ class PingCommand extends Command {
}
async execute(message, { args, params }) {
await message.respond(stripIndents`**arguments:** ${Object.values(args).map(a=>`${a.name}: ${a.value}`).join(' | ')}
await message.respond(stripIndents`**arguments:** ${Object.values(args).map((a) => `${a.name}: ${a.value}`)
.join(' | ')}
**words:** ${params.join(', ')}`, { emoji: 'success' });
}

View File

@ -41,7 +41,7 @@ class AvatarCommand extends Command {
if (!user) user = message.author;
let avatar = null;
try {
avatar = user.displayAvatarURL({ format: args.format?.value || 'webp', size: args.size?.value || 512, dynamic: true });
avatar = user.displayAvatarURL({ format: args.format?.value || 'webp', size: args.size?.value || 128, dynamic: true });
} catch(error) {
message.respond(message.format('C_AVATAR_FORMATERROR'), { emoji: 'failure' });
return undefined;

View File

@ -0,0 +1,87 @@
const fetch = require('node-fetch');
const { Command } = require('../../../../interfaces/');
//Apparently hit ratelimits pretty damn quick and doesn't expire often.
class LookupCommand extends Command {
constructor(client) {
super(client, {
name: 'lookup',
module: 'utility',
usage: "<invite-code>",
showUsage: true,
parameterType: 'PLAIN',
examples: [
"SvJgtEj",
"discord.gg/SvJgtEj"
],
restricted: true, //For now
// throttling: {
// usages: 1,
// duration: 30
// }
});
this.client = client;
}
async execute(message, { params }) {
const invite = await this.client.fetchInvite(params)
.catch((error) => {
console.error(error);
});
let fields = [];
if(invite.inviter) {
fields.push({
name: "Inviter",
value: `${invite.inviter.username}#${invite.inviter.discriminator} \`(${invite.inviter.id})\``,
inline: true
});
}
if(invite.channel) {
fields.push({
name: "Default Channel",
value: `#${invite.channel.name} \`(${invite.channel.id})\``,
inline: true
});
}
if(invite?.guild?.features.length > 0) {
fields.push({
name: "Features",
value: invite.guild.features.map(f=>`\`${f}\``).join(', '),
inline: true,
});
}
const embed = {
author: {
name: `${invite.guild.name} (${invite.guild.id})`,
icon_url: invite.guild.iconURL()
},
thumbnail: {
url: invite.guild.splash ? invite.guild.splashURL() : null
},
description: invite.guild.description || null,
fields,
footer: {
text: ` https://discord.gg/${invite.code}`
}
};
return message.embed(embed);
}
}
module.exports = LookupCommand;

View File

@ -16,7 +16,9 @@ class PingCommand extends Command {
async execute(message) {
const ping = this.client.ws.ping.toFixed(0);
return message.respond(`${message.format('C_PING_RESPONSE')} \`${ping}ms\``, { emoji: 'success' });
const number = (ping/40).toFixed(0);
const repeat = number > 1 ? number : 1;
return message.respond(`P${'o'.repeat(repeat)}ng! \`${ping}ms\``, { emoji: 'success' });
}
}

View File

@ -2,18 +2,18 @@ const { Command } = require('../../../../interfaces/');
const { stripIndents } = require('common-tags');
class SettingCommand extends Command {
class SettingsCommand extends Command {
constructor(client) {
super(client, {
name: 'setting',
name: 'settings',
module: 'utility',
description: "Sets user or guild settings.",
aliases: [
'settings',
'setting',
'set'
],
usage: "[list|reset|setting-name] <value..>",
arguments: [
{
name: 'user',
@ -45,10 +45,7 @@ class SettingCommand extends Command {
this._listSettings(message, type, Boolean(args.all));
return undefined;
} else if(target === 'reset') {
if(message.channel.permissionsFor(message.member).missing('ADMINISTRATOR').length > 0) {
await message.respond(message.format('C_SETTINGS_ADMINISTRATORERROR', { type: type.toLowerCase() }), { emoji: 'failure' });
return undefined;
}
if(type === 'GUILD' && !this._checkAdministrator(message)) return undefined; //does not have admin
const prompt = await message.prompt(message.format('C_SETTINGS_RESET', { type: type.toLowerCase() }), { emoji: 'warning' });
return await this._handleReset(prompt, message, type);
} else if(target === 'walkthrough') {
@ -64,7 +61,7 @@ class SettingCommand extends Command {
}
//Setting permission handling
if(setting.clientPermissions.length > 0) {
if(setting.clientPermissions.length > 0 && setting.resolve === 'GUILD') {
const missing = message.channel.permissionsFor(message.guild.me).missing(setting.clientPermissions);
if(missing.length > 0) {
await message.respond(message.format('C_SETTINGS_CLIENTPERMISSIONERROR', { setting: setting.moduleResolveable, missing: missing.join(', ')}), { emoji: 'failure' });
@ -72,12 +69,20 @@ class SettingCommand extends Command {
}
}
if(message.channel.permissionsFor(message.member).missing('ADMINISTRATOR').length > 0 && setting.resolve === 'GUILD') {
await message.respond(message.format('C_SETTINGS_ADMINISTRATORERROR', { type: type.toLowerCase() }), { emoji: 'failure' });
setting._caller = target;
if(setting.resolve === 'GUILD' && !this._checkAdministrator(message)) return undefined; //does not have admin
const parameters = params.splice(1);
if(!parameters || parameters.length === 0) {
await this._showSetting(message, setting)
return undefined;
}
const response = await setting.handle(message, params.splice(1));
if(parameters.join(' ').toLowerCase() === 'reset') {
return await setting._handleReset(message);
}
const response = await setting.handle(message, parameters);
message.respond(response.msg, { emoji: response.error ? 'failure' : 'success' });
}
@ -85,11 +90,11 @@ class SettingCommand extends Command {
_listSettings(message, type, all) {
if(!message.guild && type === 'GUILD') type = 'USER';
const prefix = message.guild?.prefix || this.client._options.bot.prefix;
const prefix = message.guild?.prefix || this.client._options.bot.prefix; //eslint-disable-line parsing-error
let fields = [];
const sorted = this.client.registry.components
.filter(c=>c.type === 'module')
.filter(c=>c.type == 'module')
.sort((a, b) => {
const filter = c=>c.type === 'setting';
return b.components.filter(filter) - a.components.filter(filter);
@ -126,6 +131,35 @@ class SettingCommand extends Command {
}
async _showSetting(message, setting) {
const prefix = message.guild.prefix;
let description = stripIndents`\`${prefix}setting ${setting.name}${setting.usage ? ` ${setting.usage}` : ''}\` ${setting.resolve === 'GUILD' ? ' *(guild-only)*' : '*(user-only)*'}
${message.format(setting.description)}`;
if(setting.examples.length > 0) {
description += `\n\n**${message.format('GENERAL_EXAMPLES')}**`;
for(let example of setting.examples) {
description += `\n\`${prefix}setting ${example}\``;
}
}
let fields = setting.fields(message.guild);
if(fields instanceof Promise) fields = await fields;
const embed = {
author: {
name: `${setting.name} (${setting.module.resolveable})`,
icon_url: this.client.user.displayAvatarURL()
},
description,
fields
}
return await message.embed(embed);
}
async _handleReset(prompt, message, type) {
if(!prompt) return;
@ -135,13 +169,23 @@ class SettingCommand extends Command {
if(!bool) return message.respond(message.format('C_SETTINGS_RESETABORT'), { emoji: 'success' });
type === 'USER'
? await message.author._delete()
: await message.guild._delete('guilds');
? await message.author._deleteSettings()
: await message.guild._deleteSettings();
return message.respond(message.format('C_SETTINGS_RESETSUCCESS', { type: type.toLowerCase() }), { emoji: 'success' })
}
_checkAdministrator(message) {
const missing = message.channel.permissionsFor(message.member).missing(['ADMINISTRATOR']);
if(missing > 0) {
message.respond(message.format('C_SETTINGS_ADMINISTRATORERROR'), { emoji: 'failure' })
return false;
} else {
return true;
}
}
}
module.exports = SettingCommand;
module.exports = SettingsCommand;

View File

@ -27,19 +27,17 @@ class UserCommand extends Command {
async execute(message, { params, args }) {
let response;
let response = null;
if(args.search && args.search.value.length > 1) {
let key = args.search.value,
count = 0;
const key = args.search.value;
let count = 0;
let members = message.guild.members.cache.filter(m => {
return (m.nickname && (m.nickname.toLowerCase().includes(key) || (similarity(m.nickname.toLowerCase(), key) > 0.75 && Math.abs(m.nickname.length - key.length) < 3) )) ||
m.user.username.toLowerCase().includes(key) || (similarity(m.user.username.toLowerCase(), key) > 0.75 && Math.abs(m.user.username.length - key.length) < 3);
});
const members = message.guild.members.cache.filter((m) => m.nickname && (m.nickname.toLowerCase().includes(key) || similarity(m.nickname.toLowerCase(), key) > 0.75 && Math.abs(m.nickname.length - key.length) < 3) ||
m.user.username.toLowerCase().includes(key) || similarity(m.user.username.toLowerCase(), key) > 0.75 && Math.abs(m.user.username.length - key.length) < 3);
for(let [ id, member ] of members) {
response += `${member.user.tag} ${member.nickname ? `- ${member.nickname}` : '' } [${id}]\n`;
for(const [ id, member ] of members) {
response += `${member.user.tag} ${member.nickname ? `- ${member.nickname}` : ''} [${id}]\n`;
count++;
if(response.length > 1900) break;
}
@ -47,7 +45,7 @@ class UserCommand extends Command {
response = {
description: response,
title: message.format('C_USER_SEARCH_TITLE', {
key: key
key
}),
color: 0x0088cc,
footer: {
@ -60,13 +58,13 @@ class UserCommand extends Command {
} else {
let user;
let user = null;
if (params.length > 0) {
user = await this.client.resolver.resolveUser(params.join(' ')).catch(console.error);
user = await this.client.resolver.resolveUser(params.join(' '));
if (!user) return message.respond('No user found.');
} else user = message.author;
let member = await message.guild.members.fetch(user.id).catch(console.error);
const member = await message.guild.members.fetch(user.id);
response = message.format('C_USER', {
nickname: member && member.nickname ? member.nickname : 'N/A',
@ -77,7 +75,8 @@ class UserCommand extends Command {
activity: user.presence.activities.length > 0 ? user.presence.activities[0].name : 'N/A',
serverActivity: member && member.lastMessage ? member.lastMessage.createdAt.toDateString() : 'N/A',
globalActivity: user.lastMessage ? user.lastMessage.createdAt.toDateString() : 'N/A',
roles: member ? member.roles.cache.filter(r => r.name !== '@everyone').map(r => r.name).join(', ') : 'N/A'
roles: member ? member.roles.cache.filter((r) => r.name !== '@everyone').map((r) => r.name)
.join(', ') : 'N/A'
});
response = {

View File

@ -19,9 +19,8 @@ class ClientPermissions extends Inhibitor {
if(missing.length > 0) {
return super._fail(stripIndents`The command **${command.resolveable}** requires the bot to have permissions to use.
*Missing: ${missing.join(', ')}*`);
} else {
return super._succeed();
}
return super._succeed();
}
}

View File

@ -16,7 +16,7 @@ class Disabled extends Inhibitor {
execute(message, command) {
if(command.disabled && message.author.id !== this.client._options.bot.owner) return super._fail(`The command **${command.resolveable}** is currently disabled.`);
else return super._succeed();
return super._succeed();
}

View File

@ -15,9 +15,9 @@ class GuildOnly extends Inhibitor {
execute(message, command) {
if(command.guildOnly && !message.guild) {
return super._fail(`The command **${command.moduleResolveable}** can only be run in servers.`);
} else {
return super._succeed();
}
return super._succeed();
}
}

View File

@ -19,9 +19,9 @@ class MemberPermissions extends Inhibitor {
if(missing.length > 0) {
return super._fail(stripIndents`The command **${command.resolveable}** requires you to have permissions to use.
*Missing: ${missing.join(', ')}*`);
} else {
return super._succeed();
}
return super._succeed();
}
}

View File

@ -15,9 +15,9 @@ class Restricted extends Inhibitor {
execute(message, command) {
if(command.restricted && !this.client._options.bot.owners.includes(message.author.id)) {
return super._fail(`The command **${command.moduleResolveable}** can only be run by developers.`);
} else {
return super._succeed();
}
return super._succeed();
}
}

View File

@ -19,7 +19,7 @@ class Throttle extends Inhibitor {
if(throttle) {
throttle.usages++;
if(throttle.usages > command.throttling.usages) {
const remaining = (throttle.start + (command.throttling.duration*1000) - Date.now()) / 1000;
const remaining = (throttle.start + (command.throttling.duration*1000) - Date.now()) / 1000; //eslint-disable-line no-extra-parens
return super._fail(stripIndents`The command **${command.moduleResolveable}** is currently throttled.
*You can use this command again in* *\`${remaining.toFixed(2)}\`* *seconds.*`);
}

View File

@ -93,9 +93,16 @@ class CommandHandler extends Observer {
const inhibitor = await this._handleInhibitors(message);
if(inhibitor.error) return this._handleError({ type: 'inhibitor', info: inhibitor , message });
const { parsedArguments, newArgs } = await this._parseArguments(message, args);
message.parameters = newArgs;
message.args = parsedArguments;
const response = await this._parseArguments(args, message.command.arguments, message.guild);
if(response.error) {
return this._handleError({
...response,
message
});
} else {
message.parameters = message.command.parameterType === 'PLAIN' ? response.newArgs.join(' ') : response.newArgs;
message.args = response.parsedArguments;
}
const resolved = await message.resolve();
if(resolved.error) {
@ -147,13 +154,11 @@ class CommandHandler extends Observer {
}
async _parseArguments(message, args = []) {
async _parseArguments(args = [], passedArguments = [], guild = null) { //Only need guild parameter if using a resolver type in your arguments e.g. channel, user, member, role
args = this._getWords(args.join(' ')).map(w=>w[0]);
const command = message.command;
const { shortFlags, longFlags, keys } = await this._createFlags(command.arguments);
const { shortFlags, longFlags, keys } = await this._createFlags(passedArguments);
const regex = new RegExp(`([0-9]*)(${Object.keys(longFlags).map(k=>escapeRegex(k)).join('|')})([0-9]*)`, 'i');
let parsedArguments = [];
@ -178,7 +183,12 @@ class CommandHandler extends Observer {
continue;
}
if(currentArgument.required && !args[i+1]) {
return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: true }, message });
return {
error: true,
type: 'argument',
info: { argument: currentArgument, word, missing: true }
}
// return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: true }, message });
}
continue;
} else if((one === '-' && two === '-') || (one === '—')) { //Handling for "long dash" on mobile phones x_x
@ -197,7 +207,12 @@ class CommandHandler extends Observer {
continue;
}
if(currentArgument.required && !args[i+1]) {
return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: true }, message });
return {
error: true,
type: 'argument',
info: { argument: currentArgument, word, missing: true }
}
// return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: true }, message });
}
continue;
} else {
@ -206,7 +221,7 @@ class CommandHandler extends Observer {
currentArgument = longFlags[match[2]];
if(params.length > 0 && ['INTEGER', 'FLOAT'].includes(currentArgument.type)) { //15 pts
const lastItem = params[params.length-1];
const beforeError = await this._handleTypeParsing(currentArgument, lastItem, message.guild);
const beforeError = await this._handleTypeParsing(currentArgument, lastItem, guild);
if(beforeError) {
continue;
} else {
@ -218,11 +233,16 @@ class CommandHandler extends Observer {
}
}
const value = match[1] || match[3];
const error = await this._handleTypeParsing(currentArgument, value, message.guild);
const error = await this._handleTypeParsing(currentArgument, value, guild);
if(value) {
if(error) {
if(currentArgument.required) {
return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: false }, message });
return {
error: true,
type: 'argument',
info: { argument: currentArgument, word, missing: false }
}
// return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: false }, message });
} else {
parsedArguments.push(currentArgument);
currentArgument = null;
@ -239,7 +259,7 @@ class CommandHandler extends Observer {
}
} else {
if(currentArgument) {
const error = await this._handleTypeParsing(currentArgument, word, message.guild);
const error = await this._handleTypeParsing(currentArgument, word, guild);
if(error) {
if(currentArgument.default !== null) {
params.push(word);
@ -251,7 +271,12 @@ class CommandHandler extends Observer {
if(currentArgument.required) {
if(currentArgument.infinite) {
if(currentArgument.value.length === 0) {
return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: false }, message });
return {
error: true,
type: 'argument',
info: { argument: currentArgument, word, missing: false }
}
// return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: false }, message });
} else {
parsedArguments.push(currentArgument);
currentArgument = null;
@ -259,7 +284,12 @@ class CommandHandler extends Observer {
continue;
}
} else {
return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: false }, message });
return {
error: true,
type: 'argument',
info: { argument: currentArgument, word, missing: false }
}
// return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: false }, message });
}
} else {
currentArgument = null;
@ -275,7 +305,7 @@ class CommandHandler extends Observer {
} else {
const lastArgument = parsedArguments[parsedArguments.length-1];
if(lastArgument && lastArgument.type === 'BOOLEAN' && lastArgument.value === lastArgument.default) {
const error = await this._handleTypeParsing(lastArgument, word, message.guild);
const error = await this._handleTypeParsing(lastArgument, word, guild);
if(!error) continue;
}
params.push(word);
@ -289,7 +319,11 @@ class CommandHandler extends Observer {
const blah = parsedArguments.filter(a=>a.requiredArgument && !a.value);
const missingArgument = blah[0];
if(missingArgument) return this._handleError({ type: 'argument', info: { argument: missingArgument, missing: true }, message });
if(missingArgument) return {
error: true,
type: 'argument',
info: { argument: missingArgument, missing: true }
};
//fucking kill me
@ -451,7 +485,7 @@ class CommandHandler extends Observer {
}
static async parseType(type, str, resolver, guild) { //this is in the class for a reason, will soon reference to a user resolver etc.
static async parseType(type, str, resolver, guild) {
//INTEGER AND FLOAT ARE SAME FUNCTION
@ -462,12 +496,12 @@ class CommandHandler extends Observer {
INTEGER: (str) => {
const int = parseInt(str);
if(Math.round(int) !== int) return { error: true };
if(Number.isNaN(int)) return { error: true };
if(isNaN(int)) return { error: true };
return { error: false, value: int };
},
FLOAT: (str) => {
const float = parseInt(str);
if(Number.isNaN(float)) return { error: true };
if(isNaN(float)) return { error: true };
return { error: false, value: float };
},
BOOLEAN: (str) => {

View File

@ -0,0 +1,186 @@
const { Setting } = require('../../../../interfaces/');
const maxCharacters = 98;
class MuteSetting extends Setting {
constructor(client) {
super(client, {
name: 'mute',
module: 'moderation',
aliases: [
'muted',
'muteType',
'mutedType',
'muteRole',
'mutedRole',
'createMute'
],
arguments: [
{
name: 'create',
type: 'BOOLEAN',
types: ['VERBAL', 'FLAG'],
default: true
},
{
name: 'type',
type: 'BOOLEAN',
types: ['VERBAL', 'FLAG'],
default: true
}
],
usage: "[test] <what>",
examples: [
'muterole Muted',
'mutetype 1',
'createmute galacticbot-mute'
],
resolve: 'GUILD',
default: {
mute: {
role: null,
type: 0
}
}
});
this.client = client;
}
async handle(message, args) {
const { params, parsedArguments } = await this._parseArguments(args, message.guild);
args = params;
if(['mutetype', 'mutedtype'].includes(this._caller) || parsedArguments.type) {
const num = args[0].toLowerCase() === 'type' ? args[1] || 0 : args[0];
const number = parseInt(num);
if(isNaN(number)) return {
msg: message.format('S_MUTE_TYPENAN'),
error: true
};
if(![0, 1, 2].includes(number)) return {
msg: message.format('S_MUTE_TYPEINVALID'),
error: true
};
await message.guild._updateSettings({
[this.index]: {
...message.guild._settings[this.index],
type: number
}
});
return {
msg: `${message.format('S_MUTE_TYPESUCCESS', { type: number })} ${message.format('S_MUTE_TYPESWITCH', { type: number }, true)}`,
error: false
};
}
let role = null;
let updatedPermissions = false;
let created = false;
if(parsedArguments.create || this._caller === 'createmute') {
const missing = message.channel.permissionsFor(message.guild.me).missing('MANAGE_ROLES');
if(missing.length > 0) return {
msg: message.format('S_MUTE_ROLEMISSINGPERMISSION'),
error: true
};
const foundRole = await this.client.resolver.resolveRole(args.join(' '), message.guild);
if(foundRole) {
const prompt = await message.prompt(message.format('S_MUTE_ROLEPROMPT', { name: foundRole.name, id: foundRole.id }), { emoji: 'loading' });
const response = prompt.content.toLowerCase();
const bool = this.client.resolver.resolveBoolean(response);
if(bool === null) return { msg: message.format('S_MUTE_ROLEPROMPTERROR'), error: true };
if(!bool) {
role = await this._createRole(message, args);
if(role.error) return role;
created = true;
} else {
role = foundRole;
}
} else {
role = await this._createRole(message, args);
if(role.error) return role;
created = true;
}
const channels = message.guild.channels.cache.filter((c) => c.type === 'text');
for(const channel of channels.values()) {
try {
await channel.createOverwrite(role, {
SEND_MESSAGES: false,
ADD_REACTIONS: false
}, super.reason(message.author));
} catch(err) {} //eslint-disable-line no-empty
}
updatedPermissions = true;
} else {
const search = args.join(' ');
role = await this.client.resolver.resolveRole(search, message.guild);
}
if(!role) return {
msg: message.format('S_MUTE_ROLEMISSING'),
error: true
};
await message.guild._updateSettings({
[this.index]: {
...message.guild._settings[this.index],
role: role.id
}
});
return {
msg: `${message.format('S_MUTE_ROLESUCCESS', { role: role.name, type: created ? 'created' : 'set' })} ${updatedPermissions ? message.format('S_MUTE_GENERATEDPERMISSIONS') : message.format('S_MUTE_UNGENERATEDPERMISSIONS')}`,
error: false
};
}
async _createRole(message, args) {
let role = null;
let name = args.join(' ') || 'Muted';
if(name.length > maxCharacters) name = name.slice(0, maxCharacters);
try {
role = await message.guild.roles.create({
data: {
name
},
reason: super.reason(message.author)
});
} catch(error) {
return {
msg: message.format('S_MUTE_ROLECREATEERROR'),
error: true
};
}
return role;
}
data(guild) {
return `**Muted Role:** ${guild._settings[this.index].role ? `<@&${guild._settings[this.index].role}>` : 'N/A'}\n**Mute Type:** \`${guild._setting[this.index].type}\``;
}
fields(guild) {
return [
{
name: "Muted Role",
value: guild._settings[this.index].role ? `<@&${guild._settings[this.index].role}>` : '`N/A`',
inline: true
},
{
name: "Mute Type",
value: `\`${guild._settings[this.index].type}\``,
inline: true
}
];
}
}
module.exports = MuteSetting;

View File

@ -24,30 +24,33 @@ class GuildPrefixSetting extends Setting {
}
async handle(message, params, operator) {
if (operator === 'RESET') {
return await super._handleReset(message, params);
}
// let { params, parsedArguments } = await this._parseArguments(params);
async handle(message, params) {
let [ prefix ] = params;
const MaxCharacters = 6;
if(prefix.length > MaxCharacters) return {
msg: message.format('S_GPREFIX_LENGTH', { length: prefix.length, max: MaxCharacters }),
msg: message.format('S_GUILDPREFIX_LENGTH', { length: prefix.length, max: MaxCharacters }),
error: true
};
await message.guild._updateSettings({ prefix });
if(prefix.includes(' ')) return {
msg: message.format('S_GUILDPREFIX_SPACES'),
error: true
};
await message.guild._updateSettings({ [this.index]: prefix });
return {
msg: message.format(`S_${this.name.toUpperCase()}_SUCCESS`, { prefix }),
msg: message.format(`S_GUILDPREFIX_SUCCESS`, { prefix }),
error: false
};
}
data(guild) {
return `**Prefix:** \`${guild.prefix}\``;
}
}

View File

@ -0,0 +1,65 @@
const { Setting } = require('../../../../interfaces/');
class PermissionTypeSetting extends Setting {
constructor(client) {
super(client, {
name: 'permissionType',
module: 'utility',
aliases: ['permission'],
guarded: true,
resolve: 'GUILD',
default: {
permissionType: 2
},
custom: true
});
this.client = client;
}
async handle(message, params) {
const [prefix] = params;
const MaxCharacters = 6;
if(prefix.length > MaxCharacters) return {
msg: message.format('S_GUILDPREFIX_LENGTH', { length: prefix.length, max: MaxCharacters }),
error: true
};
if(prefix.includes(' ')) return {
msg: message.format('S_GUILDPREFIX_SPACES'),
error: true
};
await message.guild._updateSettings({ [this.index]: prefix });
return {
msg: message.format(`S_GUILDPREFIX_SUCCESS`, { prefix }),
error: false
};
}
fields(guild) {
return [
{
name: "》Prefix",
value: `\`${guild.prefix}\``
}
];
}
}
module.exports = PermissionTypeSetting;
const Constants = { //eslint-disable-line no-unused-vars
Types: {
'discord': 0,
'grants': 1,
'both': 2
}
};

View File

@ -18,7 +18,7 @@ const Guild = Structures.extend('Guild', (Guild) => {
async settings() {
if(!this._settings) this._settings = this.client.transactionHandler.send({ provider: 'mongodb', request: { collection: 'guilds', type: 'findOne', query: { guildId: this.id } } });
if(this._settings instanceof Promise) this._settings = await this._settings || null;
if(!this._settings) this._settings = { guildId: this.id, ...this.client.defaultConfig } ;
if(!this._settings) this._settings = { guildId: this.id, ...this.client.defaultConfig };
return this._settings;
}
@ -32,13 +32,13 @@ const Guild = Structures.extend('Guild', (Guild) => {
/* Settings Wrapper */
async _dbDelete(collection) { //Delete whole entry - remove
async _deleteSettings() { //Delete whole entry - remove
try {
await this.client.transactionHandler.send({
provider: 'mongodb',
request: {
type: 'remove',
collection,
collection: 'guilds',
query: {
guildId: this.id
}
@ -49,35 +49,35 @@ const Guild = Structures.extend('Guild', (Guild) => {
} catch(error) {
this._storageError(error);
}
return true;
}
async _dbUpdateOne(data, collection) { //Update property (upsert true) - updateOne
var index = this.dbIndex(collection); //eslint-disable-line no-unused-vars
async _updateSettings(data) { //Update property (upsert true) - updateOne
try {
await this.client.transactionHandler.send({
provider: 'mongodb',
request: {
type: 'updateOne',
collection,
collection: 'guilds',
query: {
guildId: this.id
},
data
}
});
index = {
...index,
this._settings = {
...this._settings,
...data
};
this._storageLog(`Database Update (guild:${this.id}).`);
} catch(error) {
this._storageError(error);
}
return true;
}
async _dbRemoveProperty(value, collection) { //Remove property
const index = this.dbIndex(collection);
if(collection === 'guild' && this.client.defaultConfig[value]) {
async _removeSettings(value) { //Remove property
if(this.client.defaultConfig[value]) {
await this._updateSettings(this.client.defaultConfig[value]);
return undefined;
}
@ -86,7 +86,7 @@ const Guild = Structures.extend('Guild', (Guild) => {
provider: 'mongodb',
request: {
type: 'removeProperty',
collection,
collection: 'guilds',
query: {
guildId: this.id
},
@ -95,24 +95,14 @@ const Guild = Structures.extend('Guild', (Guild) => {
]
}
});
delete index[value];
this._storageLog(`Database Remove (guild:${this.id}).`);
delete this._settings[value];
} catch(error) {
this._storageError(error);
}
return true;
}
_dbIndex(collection) {
return {
'guilds': this._settings,
'permissions': this._permissions
}[collection];
}
/* Permissions Wrapper */
/* Language Formatting */
format(key, parameters = {}) {
@ -121,7 +111,7 @@ const Guild = Structures.extend('Guild', (Guild) => {
let value = this.client.localeLoader.languages[language][key];
for(const [param, val] of Object.entries(parameters)) {
value = value.replace(new RegExp(`{${escapeRegex(param.toLowerCase())}}`, 'gi'), val);
value = value.replace(new RegExp(`{${escapeRegex(param.toLowerCase())}}`, 'giu'), val);
}
return value;
@ -131,45 +121,44 @@ const Guild = Structures.extend('Guild', (Guild) => {
async resolveMembers(members, strict = false) {
return await this.client.resolver.resolveMembers(members, this, strict);
return this.client.resolver.resolveMembers(members, this, strict);
}
async resolveMember(member, strict) {
let [ result ] = await this.resolveMembers([ member ], strict);
const [ result ] = await this.resolveMembers([ member ], strict);
return result;
}
async resolveChannels(channels, strict = false) {
return await this.client.resolver.resolveChannels(channels, this, strict);
return this.client.resolver.resolveChannels(channels, this, strict);
}
async resolveChannel(channel, strict) {
let [ result ] = await this.resolveMembers([ channel ], strict);
const [ result ] = await this.resolveMembers([ channel ], strict);
return result;
}
async resolveRoles(roles, strict = false) {
return await this.client.resolver.resolveRoles(roles, this, strict);
return this.client.resolver.resolveRoles(roles, this, strict);
}
async resolveRole(role, strict) {
let [ result ] = await this.resolveRoles([ role ], strict);
const [ result ] = await this.resolveRoles([ role ], strict);
return result;
}
/* Logging */
_storageLog(log) {

View File

@ -78,7 +78,7 @@ const Message = Structures.extend('Message', (Message) => {
}
async respond(str, opts = {}) {
async respond(str, opts = { attachments: [] }) {
if(typeof str === 'string') {
if(opts.emoji) {
@ -90,7 +90,7 @@ const Message = Structures.extend('Message', (Message) => {
}
//console.log(str)
this._pending = await this.channel.send(str);
this._pending = await this.channel.send(str, { files: opts.attachments });
return this._pending;
}
@ -151,7 +151,7 @@ const Message = Structures.extend('Message', (Message) => {
let embed = {
author: {
name: `${component.name}${component.module ? ` (${component.module.resolveable})` : ''}`,
icon_url: this.client.user.avatarURL()
icon_url: this.client.user.displayAvatarURL()
},
description: stripIndents`\`${prefix}${component.name}${component.usage ? ` ${component.usage}` : ''}\`
${this.format(component.description)}${component.guildOnly ? ' *(guild-only)*' : ''}`,

View File

@ -28,6 +28,9 @@ class Command extends Component {
this.archivable = opts.archivable === undefined ? false : Boolean(opts.archivable);
this.arguments = opts.arguments || [];
this.parameterType = opts.parameterType || 'SPLIT'; //SPLIT or PLAIN, PLAIN = string, SPLIT = split into array, includes quotes
this.grantable = Boolean(opts.grantable);
this.clientPermissions = opts.clientPermissions || [];
this.memberPermissions = opts.memberPermissions || [];

View File

@ -17,13 +17,14 @@ class Setting extends Component {
this.module = opts.module;
this.restricted = Boolean(opts.restricted);
this.description = `S_${opts.name}_DESCRIPTION`;
this.examples = `S_${opts.name}_EXAMPLES`;
this.description = `S_${opts.name.toUpperCase()}_DESCRIPTION`;
this.examples = opts.examples || [];
this.usage = opts.usage || '';
this.archiveable = Boolean(opts.archiveable);
this.index = opts.index || opts.name;
this.aliases = opts.aliases || [];
this.resolve = (opts.resolve && Constants.Resolves.includes(opts.resolve)) ? opts.resolve : 'GUILD';
this.resolve = opts.resolve && Constants.Resolves.includes(opts.resolve) ? opts.resolve : 'GUILD'; //eslint-disable-line no-use-before-define
this.default = opts.default;
this.arguments = opts.arguments || [];
this.custom = Boolean(opts.custom);
@ -40,17 +41,31 @@ class Setting extends Component {
this.client.logger.error(`No handle function found in ${this.moduleResolveable}.`);
}
async _parseArguments(params) {
const { parsedArguments, newArgs } = await this.commandHandler._parseArguments(this.arguments, params);
return { parsedArguments, params: newArgs };
async _parseArguments(params, guild) {
const response = await this.commandHandler._parseArguments(params, this.arguments, guild);
if(response.error) return response;
return { parsedArguments: response.parsedArguments, params: response.newArgs, error: false };
}
reason(executor) {
return `[${this.moduleResolveable}] Executed by ${executor.tag} (${executor.id}).`;
}
async _handleReset(message) {
await message.guild._removeSettings(this.index);
const msg = message.format('GENERAL_SETTINGRESET', { setting: this.resolveable });
return {
error: false,
msg
};
}
get commandHandler() {
if(this._commandHandler) return this._commandHandler;
else return this._commandHandler = this.client.registry.components.get('observer:commandHandler');
this._commandHandler = this.client.registry.components.get('observer:commandHandler');
return this._commandHandler;
}
get moduleResolveable() {
return `${this.module.id}:${this.id}`;
}

301
yarn.lock
View File

@ -28,6 +28,15 @@
resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.1.5.tgz#1781c620b4c88d619bd0373a1548e5a6025e3d3a"
integrity sha512-CU1q0UXQUpFNzNB7gufgoisDHP7n+T3tkqTsp3MNUkVJ5+hS3BCvME8uCXAUFlz+6T2FbTCu75A+yQ7HMKqRKw==
"@discordjs/form-data@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@discordjs/form-data/-/form-data-3.0.1.tgz#5c9e6be992e2e57d0dfa0e39979a850225fb4697"
integrity sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
"@types/color-name@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
@ -46,14 +55,14 @@ acorn-jsx@^5.2.0:
integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==
acorn@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==
version "7.2.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==
ajv@^6.10.0, ajv@^6.10.2:
version "6.12.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7"
integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==
version "6.12.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
@ -152,7 +161,7 @@ callsites@^3.0.0:
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
chalk@^2.0.0, chalk@^2.1.0:
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@ -190,9 +199,9 @@ cli-cursor@^3.1.0:
restore-cursor "^3.1.0"
cli-width@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
version "2.2.1"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
color-convert@^1.9.0, color-convert@^1.9.1:
version "1.9.3"
@ -274,16 +283,14 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
cross-spawn@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.2.tgz#d0d7dcfa74e89115c7619f4f721a94e1fdb716d6"
integrity sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
semver "^5.5.0"
shebang-command "^1.2.0"
which "^1.2.9"
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
debug@^4.0.1:
version "4.1.1"
@ -292,7 +299,7 @@ debug@^4.0.1:
dependencies:
ms "^2.1.1"
deep-is@~0.1.3:
deep-is@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
@ -317,12 +324,12 @@ diagnostics@^1.1.1:
kuler "1.0.x"
discord.js@discordjs/discord.js:
version "12.1.1"
resolved "https://codeload.github.com/discordjs/discord.js/tar.gz/828640ca263db2c95ed21e7353a2746fe6ac9fb8"
version "12.2.0"
resolved "https://codeload.github.com/discordjs/discord.js/tar.gz/153a030c1fc04fd2a144108680dbf7bb1d5b9cc9"
dependencies:
"@discordjs/collection" "^0.1.5"
"@discordjs/form-data" "^3.0.1"
abort-controller "^3.0.0"
form-data "^3.0.0"
node-fetch "^2.6.0"
prism-media "^1.2.0"
setimmediate "^1.0.5"
@ -376,10 +383,10 @@ eslint-scope@^5.0.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-utils@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f"
integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==
eslint-utils@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd"
integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==
dependencies:
eslint-visitor-keys "^1.1.0"
@ -388,22 +395,22 @@ eslint-visitor-keys@^1.1.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
eslint@^6.8.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==
eslint@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.0.0.tgz#c35dfd04a4372110bd78c69a8d79864273919a08"
integrity sha512-qY1cwdOxMONHJfGqw52UOpZDeqXy8xmD0u8CT6jIstil72jkhURC704W8CFyTPDPllz4z4lu0Ql1+07PG/XdIg==
dependencies:
"@babel/code-frame" "^7.0.0"
ajv "^6.10.0"
chalk "^2.1.0"
cross-spawn "^6.0.5"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.0.1"
doctrine "^3.0.0"
eslint-scope "^5.0.0"
eslint-utils "^1.4.3"
eslint-utils "^2.0.0"
eslint-visitor-keys "^1.1.0"
espree "^6.1.2"
esquery "^1.0.1"
espree "^7.0.0"
esquery "^1.2.0"
esutils "^2.0.2"
file-entry-cache "^5.0.1"
functional-red-black-tree "^1.0.1"
@ -416,25 +423,24 @@ eslint@^6.8.0:
is-glob "^4.0.0"
js-yaml "^3.13.1"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.3.0"
levn "^0.4.1"
lodash "^4.17.14"
minimatch "^3.0.4"
mkdirp "^0.5.1"
natural-compare "^1.4.0"
optionator "^0.8.3"
optionator "^0.9.1"
progress "^2.0.0"
regexpp "^2.0.1"
semver "^6.1.2"
strip-ansi "^5.2.0"
strip-json-comments "^3.0.1"
regexpp "^3.1.0"
semver "^7.2.1"
strip-ansi "^6.0.0"
strip-json-comments "^3.1.0"
table "^5.2.3"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
espree@^6.1.2:
version "6.2.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a"
integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==
espree@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-7.0.0.tgz#8a7a60f218e69f120a842dc24c5a88aa7748a74e"
integrity sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw==
dependencies:
acorn "^7.1.1"
acorn-jsx "^5.2.0"
@ -445,12 +451,12 @@ esprima@^4.0.0:
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esquery@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.2.0.tgz#a010a519c0288f2530b3404124bfb5f02e9797fe"
integrity sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q==
esquery@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57"
integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==
dependencies:
estraverse "^5.0.0"
estraverse "^5.1.0"
esrecurse@^4.1.0:
version "4.2.1"
@ -464,10 +470,10 @@ estraverse@^4.1.0, estraverse@^4.1.1:
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estraverse@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.0.0.tgz#ac81750b482c11cca26e4b07e83ed8f75fbcdc22"
integrity sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==
estraverse@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642"
integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==
esutils@^2.0.2:
version "2.0.3"
@ -498,7 +504,7 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@~2.0.6:
fast-levenshtein@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
@ -541,15 +547,6 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
form-data@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@ -680,11 +677,6 @@ is-glob@^4.0.0, is-glob@^4.0.1:
dependencies:
is-extglob "^2.1.1"
is-promise@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@ -735,13 +727,13 @@ levenshtein-edit-distance@^2.0.0:
resolved "https://registry.yarnpkg.com/levenshtein-edit-distance/-/levenshtein-edit-distance-2.0.5.tgz#a066eca8afb350e4d9054aed9ffeef66e78ffc83"
integrity sha512-Yuraz7QnMX/JENJU1HA6UtdsbhRzoSFnGpVGVryjQgHtl2s/YmVgmNYkVs5yzVZ9aAvQR9wPBUH3lG755ylxGA==
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
dependencies:
prelude-ls "~1.1.2"
type-check "~0.3.2"
prelude-ls "^1.2.1"
type-check "~0.4.0"
lodash@^4.17.14, lodash@^4.17.15:
version "4.17.15"
@ -764,17 +756,17 @@ memory-pager@^1.0.2:
resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5"
integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==
mime-db@1.43.0:
version "1.43.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
mime-db@1.44.0:
version "1.44.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
mime-types@^2.1.12:
version "2.1.26"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
version "2.1.27"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
dependencies:
mime-db "1.43.0"
mime-db "1.44.0"
mimic-fn@^2.1.0:
version "2.1.0"
@ -801,9 +793,9 @@ mkdirp@^0.5.1:
minimist "^1.2.5"
moment@^2.24.0:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
version "2.26.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a"
integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==
mongodb@^3.5.7:
version "3.5.7"
@ -843,11 +835,6 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-fetch@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
@ -872,17 +859,17 @@ onetime@^5.1.0:
dependencies:
mimic-fn "^2.1.0"
optionator@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
optionator@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
dependencies:
deep-is "~0.1.3"
fast-levenshtein "~2.0.6"
levn "~0.3.0"
prelude-ls "~1.1.2"
type-check "~0.3.2"
word-wrap "~1.2.3"
deep-is "^0.1.3"
fast-levenshtein "^2.0.6"
levn "^0.4.1"
prelude-ls "^1.2.1"
type-check "^0.4.0"
word-wrap "^1.2.3"
os-tmpdir@~1.0.2:
version "1.0.2"
@ -901,20 +888,20 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prism-media@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.2.1.tgz#168f323712bcaacb1d70ae613bf9d9dc44cf43d4"
integrity sha512-R3EbKwJiYlTvGwcG1DpUt+06DsxOGS5W4AMEHT7oVOjG93MjpdhGX1whHyjnqknylLMupKAsKMEXcTNRbPe6Vw==
version "1.2.2"
resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.2.2.tgz#4f1c841f248b67d325a24b4e6b1a491b8f50a24f"
integrity sha512-I+nkWY212lJ500jLe4tN9tWO7nRiBAVdMv76P9kffZjYhw20raMlW1HSSvS+MLXC9MmbNZCazMrAr+5jEEgTuw==
process-nextick-args@~2.0.0:
version "2.0.1"
@ -953,10 +940,10 @@ readable-stream@^3.1.1:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
regexpp@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
regexpp@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
require_optional@^1.0.1:
version "1.0.1"
@ -992,11 +979,9 @@ rimraf@2.6.3:
glob "^7.1.3"
run-async@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.0.tgz#e59054a5b86876cfae07f431d18cbaddc594f1e8"
integrity sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==
dependencies:
is-promise "^2.1.0"
version "2.4.1"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
rxjs@^6.5.3:
version "6.5.5"
@ -1011,9 +996,9 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
"safer-buffer@>= 2.1.2 < 3":
version "2.1.2"
@ -1027,32 +1012,32 @@ saslprep@^1.0.0:
dependencies:
sparse-bitfield "^3.0.3"
semver@^5.1.0, semver@^5.5.0:
semver@^5.1.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
semver@^6.1.2:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.2.1:
version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^1.0.0"
shebang-regex "^3.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
signal-exit@^3.0.2:
version "3.0.3"
@ -1136,7 +1121,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
strip-ansi@^5.1.0, strip-ansi@^5.2.0:
strip-ansi@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
@ -1150,7 +1135,7 @@ strip-ansi@^6.0.0:
dependencies:
ansi-regex "^5.0.0"
strip-json-comments@^3.0.1:
strip-json-comments@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180"
integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==
@ -1207,21 +1192,21 @@ triple-beam@^1.2.0, triple-beam@^1.3.0:
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
tslib@^1.9.0:
version "1.11.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==
version "1.13.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
tweetnacl@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
type-check@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
dependencies:
prelude-ls "~1.1.2"
prelude-ls "^1.2.1"
type-fest@^0.11.0:
version "0.11.0"
@ -1250,10 +1235,10 @@ v8-compile-cache@^2.0.3:
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
@ -1280,7 +1265,7 @@ winston@^3.2.1:
triple-beam "^1.3.0"
winston-transport "^4.3.0"
word-wrap@~1.2.3:
word-wrap@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
@ -1298,6 +1283,6 @@ write@1.0.3:
mkdirp "^0.5.1"
ws@^7.2.1:
version "7.2.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46"
integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==
version "7.3.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd"
integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==