zyno-bot-addons
Advanced tools
Comparing version 1.0.0-beta.0 to 1.0.0-beta.1
17
index.js
@@ -0,5 +1,18 @@ | ||
const { PermissionFlagsBits, EmbedBuilder } = require('discord.js'); | ||
const numberTypes = require('./src/utils/numberTypes.js'); | ||
module.exports = { | ||
bitfields: require('./src/bitfields/scopes.js'), | ||
bitfield: require('./src/bitfields/scopes.js').bitfield, | ||
Addon: require('./src/classes/addon.js'), | ||
createBitfield: require('./src/functions.js').createBitfield | ||
CommandBuilder: require('./src/classes/builders/commandBuilder.js'), | ||
CommandOptionsBuilder: require('./src/classes/builders/commandOptionsBuilder.js'), | ||
CommandOptionChoiceBuilder: require('./src/classes/builders/commandOptionChoiceBuilder.js'), | ||
createBitfield: require('./src/utils/functions.js').createBitfield, | ||
permissionsBitfield: PermissionFlagsBits, | ||
...numberTypes, | ||
Embed: EmbedBuilder, | ||
ButtonBuilder: require('./src/classes/builders/buttonBuilder.js'), | ||
SelectMenuBuilder: require('./src/classes/builders/selectMenuBuilder.js'), | ||
SelectMenuOptionBuilder: require('./src/classes/builders/selectMenuOptionBuilder.js'), | ||
ActionRowBuilder: require('./src/classes/builders/actionRowBuilder.js') | ||
} |
{ | ||
"name": "zyno-bot-addons", | ||
"version": "1.0.0-beta.0", | ||
"version": "1.0.0-beta.1", | ||
"description": "Create easily addons for Zyno Bot", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"keywords": [ | ||
@@ -17,6 +14,24 @@ "Zyno", | ||
"license": "MIT", | ||
"typings": "index.d.ts", | ||
"dependencies": { | ||
"discord.js": "^14.7.1", | ||
"valuesaver": "^1.9.3" | ||
} | ||
"discord.js": "^14.11.0", | ||
"valuesaver": "^1.9.3", | ||
"yt-stream": "^1.4.5" | ||
}, | ||
"readme": "readme.MD", | ||
"repository": { | ||
"url": "https://github.com/Luuk-Dev/Zyno-Bot-addons" | ||
}, | ||
"publisher": "Luuk", | ||
"categories": [ | ||
"Other" | ||
], | ||
"homepage": "https://zyno-bot-addons.luukdev.nl", | ||
"bugs": { | ||
"url": "https://github.com/Luuk-Dev/Zyno-Bot-addons/issues" | ||
}, | ||
"displayName": "Zyno Bot addons", | ||
"contributors": [{ | ||
"name": "Luuk" | ||
}] | ||
} |
module.exports = { | ||
COMMANDS: 1, | ||
MEMBERS: 2, | ||
MESSAGES: 4, | ||
KICKS: 8, | ||
BANS: 16, | ||
GUILDS: 32, | ||
CHANNELS: 64, | ||
SAVES: 128, | ||
ADDONS: 256 | ||
bitfield: { | ||
COMMANDS: 1, | ||
MEMBERS: 2, | ||
MESSAGES: 4, | ||
KICKS: 8, | ||
BANS: 16, | ||
GUILDS: 32, | ||
CHANNELS: 64, | ||
SAVES: 128, | ||
ADDONS: 256, | ||
EMOJIS: 512, | ||
ROLES: 1024, | ||
SERVERS: 2048, | ||
BOT: 4096, | ||
INTERACTIONS: 8192 | ||
}, | ||
strings: { | ||
COMMANDS: "Detect when a command get's executed and make possible changes to them", | ||
MEMBERS: "Detect changes to members and make changes to them", | ||
MESSAGES: "Read messages that are send and make changes to them", | ||
KICKS: "Detect when a member gets kicked", | ||
BANS: "Detect when a member gets banned", | ||
GUILDS: "Read and make changes to guilds", | ||
CHANNELS: "Read and make changes to the channels the bot has access to", | ||
SAVES: "Read all the data that has been saved and save or delete data", | ||
ADDONS: "Read all other registered addons and make changes to them", | ||
EMOJIS: "Create, edit and delete emoji's for guilds", | ||
ROLES: "Create, edit and delete roles in a guild", | ||
SERVERS: "Start a HTTP or WebSocket server and handle requests of the server", | ||
BOT: "Make changes to the bot", | ||
INTERACTIONS: "Detect interactions like buttons or menu's, get information about them and reply to them" | ||
} | ||
} |
const EventEmitter = require('events'); | ||
const { createBitfield } = require('../functions.js'); | ||
const { registerAddon } = require('./handlers/addonHandler.js'); | ||
const Save = require('./save.js'); | ||
const { createBitfield, validatePermission, getAddonPermission } = require('../utils/functions.js'); | ||
const { commandListeners, eventListeners, addons, addonCreate, botClasses } = require('../utils/saves.js'); | ||
const { registerAddon, commandRegistrant } = require('./handlers/addonHandler.js'); | ||
const Bot = require('./structures/bot.js'); | ||
const CommandBuilder = require('./builders/commandBuilder.js'); | ||
const scopes = require('../bitfields/scopes.js'); | ||
const { getClientParser } = require('../utils/parser.js'); | ||
const HttpServerHandler = require('./server/handler.js'); | ||
const clientParser = getClientParser(); | ||
class Addon extends EventEmitter{ | ||
@@ -9,30 +18,71 @@ constructor(options = {}){ | ||
(async () => { | ||
Object.defineProperty(this, 'ready', { | ||
value: false, | ||
writable: false | ||
}); | ||
if(typeof options !== 'object' || Array.isArray(options) || !options) throw new Error(`Addon is invalid, please follow the documentation to create an addon`); | ||
var keys = Object.keys(options); | ||
if(keys.indexOf('name') < 0 && keys.indexOf('connection') < 0) throw new Error(`No name or connected addon was provided`); | ||
if(typeof options.description !== 'string') throw new Error(`A description is required for the addon and must be a string`) | ||
if(keys.indexOf('name') < 0) throw new Error(`No name was provided`); | ||
if(typeof options.description !== 'string') throw new Error(`A description is required for the addon and must be a string`); | ||
if(options.description.length === 0 || options.description.length > 100) throw new Error(`Description must be between 1-100 characters long`); | ||
if(!Array.isArray(options.bitfield) && typeof options.bitfield !== 'number') throw new Error(`A bitfield with the required permissions for the addon is required and must be an array or number`); | ||
if(typeof options.version !== 'string') throw new Error(`A version is required for the addon and must be a string`); | ||
if(options.version.length === 0 || options.version.length > 10) throw new Error(`Version must be between 1-10 characters long`); | ||
if(typeof options.author !== 'string') throw new Error(`An author is required for the addon and must be a string`); | ||
if(options.author.length === 0 || options.author.length > 50) throw new Error(`Author must be between 1-50 characters long`); | ||
if(keys.indexOf('name') >= 0){ | ||
if(typeof options.name !== 'string') throw new Error(`The addon name must be a string`); | ||
this.name = options.name; | ||
} | ||
if(keys.indexOf('connection') >= 0){ | ||
if(typeof options.connection !== 'string') throw new Error(`The connection addon must be a string`); | ||
this.connection = options.connection; | ||
} | ||
this.description = options.description; | ||
if(typeof options.name !== 'string') throw new Error(`The addon name must be a string`); | ||
if(options.name.length === 0 || options.name.length > 50) throw new Error(`Name must be between 1-50 characters long`); | ||
Object.defineProperty(this, 'name', { | ||
value: options.name, | ||
writable: false | ||
}); | ||
Object.defineProperties(this, { | ||
description: { | ||
value: options.description, | ||
writable: false | ||
}, | ||
version: { | ||
value: options.version, | ||
writable: false | ||
}, | ||
author: { | ||
value: options.author, | ||
writable: false | ||
} | ||
}); | ||
if(Array.isArray(options.bitfield)){ | ||
if(!!options.bitfield.filter(v => typeof v !== 'number').length) throw new Error(`The bitfield is incorrect, make sure to use the correct bitfield values`); | ||
this.permissions = createBitfield(options.bitfield); | ||
Object.defineProperty(this, 'permissions', { | ||
value: createBitfield(options.bitfield), | ||
writable: false | ||
}); | ||
} else if(typeof options.bitfield === 'number'){ | ||
this.permissions = options.bitfield; | ||
Object.defineProperty(this, 'permissions', { | ||
value: options.bitfield, | ||
writable: false | ||
}); | ||
} else { | ||
throw new Error(`The bitfield must be an Array of scopes or a number`); | ||
} | ||
const registrant = await registerAddon(this); | ||
if(registrant !== true) throw new Error(registrant.error); | ||
Object.defineProperty(this, 'ready', { | ||
value: true, | ||
writable: false | ||
}); | ||
if(registrant === true){ | ||
Object.defineProperty(this, 'ready', { | ||
value: true, | ||
writable: false | ||
}); | ||
if(clientParser.ready === false){ | ||
clientParser.once('ready', () => { | ||
this.emit('ready'); | ||
}); | ||
} else { | ||
this.emit('ready'); | ||
} | ||
} else if(registrant !== false) { | ||
console.log(`Error while registering addon '${this.name}':`, registrant.error); | ||
return; | ||
} | ||
})().catch(err => { | ||
@@ -42,9 +92,196 @@ throw new Error(err); | ||
} | ||
createCommand(command){ | ||
return new Promise((resolve, reject) => { | ||
if(!(command instanceof CommandBuilder)) throw new Error(`Invalid command: Command is not instance of CommandBuilder class`); | ||
var commandJSON = command.toJSON(); | ||
if(typeof commandJSON.name !== 'string') throw new Error('Invalid command: Command name must be a string'); | ||
if(typeof commandJSON.description !== 'string') throw new Error('Invalid command: Command description must be a string'); | ||
commandRegistrant.register(commandJSON, this.name).then(resolve).catch(reject); | ||
}); | ||
} | ||
createEventListener(){ | ||
const filterEventListener = eventListeners.filter(e => e.addonName === this.name); | ||
if(filterEventListener.length > 0){ | ||
return filterEventListener[0].listener; | ||
} else { | ||
const event = new EventEmitter(); | ||
eventListeners.push({listener: event, addonName: this.name}); | ||
return event; | ||
} | ||
} | ||
createCommandListener(){ | ||
const filterCommandListener = commandListeners.filter(e => e.addonName === this.name); | ||
if(filterCommandListener.length > 0){ | ||
return filterCommandListener[0].listener; | ||
} else { | ||
const event = new EventEmitter(); | ||
commandListeners.push({listener: event, addonName: this.name}); | ||
return event; | ||
} | ||
} | ||
getBot(){ | ||
return new Promise((resolve, reject) => { | ||
let addonInfo = addons.get(this.name); | ||
new Promise((resolve, _reject) => { | ||
if(addonInfo) resolve(); | ||
else { | ||
addonCreate.once(this.name, (allowed) => { | ||
if(allowed === true){ | ||
addonInfo = addons.get(this.name); | ||
resolve(); | ||
} else { | ||
_reject('The addon has been declined by the bot\'s owner'); | ||
} | ||
}); | ||
} | ||
}).then(() => { | ||
if(addonInfo.verified === false || addonInfo.allowed === false) return reject('Addon hasn\'t been enabled by the owner of the bot'); | ||
new Promise((parse) => { | ||
if(clientParser.ready === false){ | ||
clientParser.once('ready', () => { | ||
parse() | ||
}) | ||
} else { | ||
parse(); | ||
} | ||
}).then(() => { | ||
const filter = botClasses.filter(b => b.addonName === this.name); | ||
if(filter.length > 0){ | ||
resolve(filter[0].bot); | ||
} else { | ||
const bot = new Bot(this); | ||
botClasses.push({addonName: this.name, bot: bot}); | ||
resolve(bot); | ||
} | ||
}); | ||
}).catch(reject) | ||
}); | ||
} | ||
getHttpServer(){ | ||
return new Promise((resolve, reject) => { | ||
let addonInfo = addons.get(this.name); | ||
new Promise((resolve, _reject) => { | ||
if(addonInfo) resolve(); | ||
else { | ||
addonCreate.once(this.name, (allowed) => { | ||
if(allowed === true){ | ||
addonInfo = addons.get(this.name); | ||
resolve(); | ||
} else { | ||
_reject('The addon has been declined by the bot\'s owner'); | ||
} | ||
}); | ||
} | ||
}).then(() => { | ||
if(addonInfo.verified === false || addonInfo.allowed === false) return reject('Addon hasn\'t been enabled by the owner of the bot'); | ||
if(!validatePermission(getAddonPermission(this.name), scopes.bitfield.SERVERS)) return reject('The addon doesn\'t have permissions to make use of the HTTP server'); | ||
new Promise((parse) => { | ||
if(clientParser.ready === false){ | ||
clientParser.once('ready', () => { | ||
parse(clientParser.getClient()); | ||
}) | ||
} else { | ||
parse(clientParser.getClient()); | ||
} | ||
}).then(client => { | ||
const port = client.config.port; | ||
if(typeof port === 'string' || typeof port === 'number'){ | ||
resolve(HttpServerHandler.startHTTPServer(parseInt(port))); | ||
} else { | ||
return reject('The owner of the bot hasn\'t set a port for the HTTP server'); | ||
} | ||
}); | ||
}).catch(reject); | ||
}); | ||
} | ||
getWSServer(){ | ||
return new Promise((resolve, reject) => { | ||
let addonInfo = addons.get(this.name); | ||
new Promise((resolve, reject) => { | ||
if(addonInfo) resolve(); | ||
else { | ||
addonCreate.once(this.name, (allowed) => { | ||
if(allowed === true){ | ||
addonInfo = addons.get(this.name); | ||
resolve(); | ||
} else { | ||
reject('The addon has been declined by the bot\'s owner'); | ||
} | ||
}); | ||
} | ||
}).then(() => { | ||
if(addonInfo.verified === false || addonInfo.allowed === false) return reject('Addon hasn\'t been enabled by the owner of the bot'); | ||
if(!validatePermission(getAddonPermission(this.name), scopes.bitfield.SERVERS)) return reject('The addon doesn\'t have permissions to make use of the WebSocket server'); | ||
new Promise((parse) => { | ||
if(clientParser.ready === false){ | ||
clientParser.once('ready', () => { | ||
parse(clientParser.getClient()); | ||
}) | ||
} else { | ||
parse(clientParser.getClient()); | ||
} | ||
}).then(client => { | ||
const port = client.config.port; | ||
if(typeof port === 'string' || typeof port === 'number'){ | ||
resolve(HttpServerHandler.startWSServer(parseInt(port))); | ||
} else { | ||
return reject('The owner of the bot hasn\'t set a port for the HTTP server'); | ||
} | ||
}); | ||
}).catch(reject); | ||
}); | ||
} | ||
getRawSaves(){ | ||
return new Promise((resolve, reject) => { | ||
let addonInfo = addons.get(this.name); | ||
new Promise((resolve, reject) => { | ||
if(addonInfo) resolve(); | ||
else { | ||
addonCreate.once(this.name, (allowed) => { | ||
if(allowed === true){ | ||
addonInfo = addons.get(this.name); | ||
resolve(); | ||
} else { | ||
reject('The addon has been declined by the bot\'s owner'); | ||
} | ||
}); | ||
} | ||
}).then(() => { | ||
if(addonInfo.verified === false || addonInfo.allowed === false) return reject('Addon hasn\'t been enabled by the owner of the bot'); | ||
if(!validatePermission(getAddonPermission(this.name), scopes.bitfield.SAVES)) return reject('The addon doesn\'t have permissions to read the saves'); | ||
new Promise((parse) => { | ||
if(clientParser.ready === false){ | ||
clientParser.once('ready', () => { | ||
parse(clientParser.getClient()); | ||
}) | ||
} else { | ||
parse(clientParser.getClient()); | ||
} | ||
}).then(client => { | ||
resolve({ | ||
tickets: new Save(client.tickets), | ||
level: new Save(client.xp), | ||
economy: new Save(client.economy), | ||
afk: new Save(client.afk), | ||
badwords: new Save(client.badwords), | ||
giveaways: new Save(client.giveaways), | ||
reactrole: new Save(client.reactrole), | ||
suggestions: new Save(client.suggestions), | ||
warns: new Save(client.warns) | ||
}); | ||
}); | ||
}).catch(reject); | ||
}) | ||
} | ||
name = null; | ||
connection = null; | ||
description = null; | ||
version = null; | ||
author = null; | ||
permissions = 0; | ||
ready = false; | ||
guilds = new Save(); | ||
channels = new Save(); | ||
commands = new Save(); | ||
} | ||
module.exports = Addon; |
@@ -1,46 +0,98 @@ | ||
const { EventEmitter } = require('events'); | ||
const path = require('path'); | ||
const { ValueSaver } = require('valuesaver'); | ||
const Embed = require('./embed.js'); | ||
const Save = require('./save.js'); | ||
const Member = require('./structures/member.js'); | ||
const User = require('./structures/user.js'); | ||
const Role = require('./structures/role.js'); | ||
const Message = require('./structures/message.js'); | ||
const TextChannel = require('./structures/channel/textChannel.js'); | ||
const CategoryChannel = require('./structures/channel/categoryChannel.js'); | ||
const VoiceChannel = require('./structures/channel/voiceChannel.js'); | ||
const StageChannel = require('./structures/channel/stageChannel.js'); | ||
const ForumChannel = require('./structures/channel/forumChannel.js'); | ||
const DirectoryChannel = require('./structures/channel/directoryChannel.js'); | ||
const { getClient } = require('../utils/functions.js'); | ||
const { getMessageContent } = require('../utils/messageFunctions.js'); | ||
const { ApplicationCommandOptionType, ChannelType } = require('discord.js'); | ||
class Command extends EventEmitter{ | ||
constructor(info){ | ||
super(); | ||
this.name = info.commandName; | ||
this.description = info.commandDescription; | ||
this.channel = info.channel; | ||
this.defaultCommand = info.command; | ||
this.type = info.type; | ||
this.arguments = new ValueSaver(); | ||
} | ||
reply(...content){ | ||
var sendContent = {content: '', embeds: [], files: []}; | ||
for(var i = 0; i < content.length; i++){ | ||
var arg = content[i]; | ||
if(typeof arg === 'string'){ | ||
sendContent['content'] += arg; | ||
} else if(arg instanceof Embed){ | ||
sendContent['embeds'].push(arg.toJSON()); | ||
if(arg.data.attachments.length > 0){ | ||
for(var z = 0; z < arg.data.attachments.length; z++){ | ||
var attachment = arg.data.attachments[z]; | ||
if(path.isAbsolute(attachment)){ | ||
sendContent['files'].push(attachment); | ||
} else { | ||
sendContent['files'].push(path.join(require.main.path, attachment)); | ||
} | ||
class Command{ | ||
constructor(data, interaction, registeredCommandData, addonData){ | ||
let client = getClient(); | ||
this.name = registeredCommandData.name; | ||
this.description = registeredCommandData.description; | ||
this.slashCommand = interaction === true; | ||
this.member = new Member(data.member, addonData.addon); | ||
this.created = new Date(); | ||
this.createdTimestamp = this.created.getTime(); | ||
this.reply = (...content) => { | ||
return new Promise(async (resolve, reject) => { | ||
if(content.length === 0) return reject(`At least one argument must be given`); | ||
let _content = getMessageContent(content); | ||
if(interaction === true){ | ||
data.reply({..._content, fetchReply: true}).then(msg => { | ||
resolve(new Message(msg, addonData.addon)); | ||
}).catch(reject); | ||
} else { | ||
data.channel.send(_content).then(msg => { | ||
resolve(new Message(msg, addonData.addon)); | ||
}).catch(reject); | ||
} | ||
}); | ||
} | ||
this.guild = this.member.guild; | ||
this.channel = this.guild.channels.get(data.channelId); | ||
this.message = interaction === false ? new Message(data, addonData.addon) : undefined; | ||
if(interaction === false) this.args.push(...(data.content || '').substring(client.config.prefix.length).split(' ')); | ||
else { | ||
let args = data.options.data.reduce((arr, item) => { | ||
var add; | ||
if(item.type === ApplicationCommandOptionType.String){ | ||
add = item.value.split(' '); | ||
this.options.set(item.name, item.value); | ||
} else if(item.type === ApplicationCommandOptionType.Number || item.type === ApplicationCommandOptionType.Integer){ | ||
add = item.value; | ||
this.options.set(item.name, item.value); | ||
} else if(item.type === ApplicationCommandOptionType.Channel){ | ||
let channel; | ||
if(item.channel.type === ChannelType.GuildText || item.channel.type === ChannelType.GuildAnnouncement){ | ||
channel = new TextChannel(item.channel, addonData.addon, this.guild); | ||
} else if(item.channel.type === ChannelType.GuildCategory){ | ||
channel = new CategoryChannel(item.channel, addonData.addon, this.guild); | ||
} else if(item.channel.type === ChannelType.GuildVoice){ | ||
channel = new VoiceChannel(item.channel, addonData.addon, this.guild); | ||
} else if(item.channel.type === ChannelType.GuildStageVoice){ | ||
channel = new StageChannel(item.channel, addonData.addon, this.guild); | ||
} else if(item.channel.type === ChannelType.GuildForum){ | ||
channel = new ForumChannel(item.channel, addonData.addon, this.guild); | ||
} else if(item.channel.type === ChannelType.GuildDirectory){ | ||
channel = new DirectoryChannel(item.channel, addonData.addon, this.guild); | ||
} | ||
add = channel.string; | ||
this.options.set(item.name, channel); | ||
} else if(item.type === ApplicationCommandOptionType.Role){ | ||
let role = new Role(item.role, addonData.addon, this.guild) | ||
add = role.string; | ||
this.options.set(item.name, role); | ||
} else if(item.type === ApplicationCommandOptionType.User){ | ||
let user = new User(item.user, addonData.addon, false); | ||
add = user.string; | ||
this.options.set(item.name, user); | ||
} | ||
} else if(typeof arg === 'object' && !Array.isArray(arg)){ | ||
sendContent = {...sendContent, ...arg}; | ||
} | ||
if(Array.isArray(add)){ | ||
arr.push(...add); | ||
} else { | ||
arr.push(add); | ||
} | ||
return arr; | ||
}, [registeredCommandData.name]); | ||
this.args = args; | ||
} | ||
if(this.type === 'slash'){ | ||
this.defaultCommand.reply(sendContent).catch(err => {}); | ||
} else { | ||
this.channel.send(sendContent).catch(err => {}); | ||
this.isSlashCommand = () => { | ||
return this.slashCommand; | ||
} | ||
} | ||
}; | ||
name = null; | ||
description = null; | ||
args = []; | ||
options = new Save(); | ||
} | ||
module.exports = Command; |
const { ValueSaver } = require('valuesaver'); | ||
const Addon = require('../addon.js'); | ||
const CommandHandler = require('./commandHandler.js'); | ||
const Command = require('../command.js'); | ||
const { getPermissionsString, generateId } = require('../../utils/functions.js'); | ||
const { getClientParser } = require('../../utils/parser.js'); | ||
const { createStructures } = require('./eventHandler.js'); | ||
const { addons, addonCreate } = require('../../utils/saves.js'); | ||
const EventEmitter = require('events'); | ||
const fs = require('fs/promises'); | ||
const { existsSync } = require('fs'); | ||
const path = require('path'); | ||
const { getClientParser } = require('../../functions.js'); | ||
const registeredAddons = new ValueSaver(); | ||
registeredAddons.import(`addons`); | ||
var clientParser = null; | ||
var clientParser = getClientParser(); | ||
var addons = new ValueSaver(); | ||
function validateRegistrant(addon, registrant){ | ||
if(!registrant) return false; | ||
if(addon.name !== registrant.name) return false; | ||
if(addon.permissions !== registrant.bitfield) return false; | ||
return true; | ||
} | ||
function registerAddon(addon = Addon.prototype){ | ||
return new Promise((resolve, reject) => { | ||
clientParser = getClientParser(); | ||
class CommandRegister extends EventEmitter{ | ||
constructor(){ | ||
super(); | ||
if(clientParser.ready === false){ | ||
clientParser.once('ready', () => { | ||
this.registeredCommands.writeValueSaver(clientParser.getClient().commands.toReadableArray()); | ||
this.emit('ready'); | ||
this.ready = true; | ||
}); | ||
} else { | ||
this.registeredCommands.writeValueSaver(clientParser.getClient().commands.toReadableArray()); | ||
this.emit('ready'); | ||
this.ready = true; | ||
} | ||
this.once('ready', () => { | ||
for(var i = 0; i < this.queue.length; i++){ | ||
var commandQueue = this.queue[i].command; | ||
if((this.registeredCommands.get(commandQueue.name) || this.addonCommands.get(commandQueue.name)) && commandQueue.overwrite === false){ | ||
this.queue[i].functions.reject('There has already been another command registered with this name'); | ||
return; | ||
} else if(this.registeredCommands.get(commandQueue.name) || this.addonCommands.get(commandQueue.name)){ | ||
this.addonCommands.delete(commandQueue.name); | ||
} | ||
} | ||
this.registerCommands(); | ||
}); | ||
} | ||
register(commandJSON, addonName){ | ||
return new Promise(async (resolve, reject) => { | ||
var addon = addons.get(addonName); | ||
if(!addon){ | ||
var abortTooLong = setTimeout(function(){ | ||
reject('The owner of the bot took too long to response'); | ||
}, 3*6e4); | ||
addonCreate.once(addonName, (allowed) => { | ||
clearTimeout(abortTooLong); | ||
if(allowed === true){ | ||
this.register(commandJSON, addonName).then(resolve).catch(reject); | ||
} else { | ||
reject(`The addon was disabled by the bot's owner`); | ||
return; | ||
} | ||
}); | ||
} else if(addon.verified === false){ | ||
if(addon.allowed === false){ | ||
reject(`The addon was disabled by the bot's owner`); | ||
return; | ||
} | ||
var abortTooLong = setTimeout(function(){ | ||
reject('The owner of the bot took too long to response'); | ||
}, 3*6e4); | ||
addonCreate.once(addonName, (allowed) => { | ||
clearTimeout(abortTooLong); | ||
if(allowed === true){ | ||
this.register(commandJSON, addonName).then(resolve).catch(reject); | ||
} else { | ||
reject(`The addon was disabled by the bot's owner`); | ||
return; | ||
} | ||
}); | ||
} else if(this.ready === false){ | ||
if(!!this.queue.filter(c => c.command.name === commandJSON.name).length && commandJSON.overwrite === false){ | ||
reject('There has already been another command registered with this name'); | ||
return; | ||
} else { | ||
if(!!this.queue.filter(c => c.command.name === commandJSON.name).length){ | ||
var getCommand = this.queue.filter(c => c.command.name === commandJSON.name)[0]; | ||
var getIndex = this.queue.indexOf(getCommand); | ||
this.queue.splice(getIndex, 1); | ||
} | ||
this.queue.push({ | ||
command: commandJSON, | ||
addon: addonName, | ||
functions: { | ||
resolve: resolve, | ||
reject: reject | ||
} | ||
}); | ||
} | ||
} else { | ||
if((this.registeredCommands.get(commandJSON.name) || this.addonCommands.get(commandJSON.name)) && commandJSON.overwrite === false){ | ||
reject('There has already been another command registered with this name'); | ||
return; | ||
} else { | ||
if(this.registeredCommands.get(commandJSON.name) || this.addonCommands.get(commandJSON.name)){ | ||
this.addonCommands.delete(commandJSON.name); | ||
} | ||
if(!!this.queue.filter(c => c.command.name === commandJSON.name).length && commandJSON.overwrite === false){ | ||
reject('There has already been another command registered with this name'); | ||
return; | ||
} else { | ||
if(!!this.queue.filter(c => c.command.name === commandJSON.name).length){ | ||
var getCommand = this.queue.filter(c => c.command.name === commandJSON.name)[0]; | ||
var getIndex = this.queue.indexOf(getCommand); | ||
this.queue.splice(getIndex, 1); | ||
} | ||
this.queue.push({ | ||
command: commandJSON, | ||
addon: addonName, | ||
functions: { | ||
resolve: resolve, | ||
reject: reject | ||
} | ||
}); | ||
this.registerCommands(); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
registerCommands(){ | ||
if(this.timeout !== undefined){ | ||
clearTimeout(timeout); | ||
} | ||
this.timeout = setTimeout(async () => { | ||
this.timeout = undefined; | ||
var commands = this.queue.map(q => q.command); | ||
commands.push(...this.addonCommands.toReadableArray().map(a => a.value)); | ||
for(var i = 0; i < commands.length; i++){ | ||
delete commands[i]['overwrite']; | ||
} | ||
try{ | ||
await clientParser.getClient().updateCommands(commands); | ||
var commandIds = this.addonCommands.toReadableArray().map(c => c.value.command.id); | ||
for(var i = 0; i < this.queue.length; i++){ | ||
var commandQueue = this.queue[i]; | ||
var cmdId = generateId(); | ||
while(commandIds.indexOf(cmdId) >= 0){ | ||
cmdId = generateId(); | ||
} | ||
commandQueue.command['id'] = cmdId; | ||
var cmd = new CommandHandler(commandQueue.command); | ||
commandQueue.functions.resolve(cmd); | ||
delete commandQueue.functions; | ||
commandQueue.command['passedClass'] = cmd; | ||
this.addonCommands.set(commandQueue.command.name, commandQueue); | ||
addons.get(commandQueue.addon).addon.commands.set(commandQueue.command.name, cmd); | ||
} | ||
clientParser.getClient().addons.writeValueSaver(this.addonCommands.toReadableArray()); | ||
} catch { | ||
for(var i = 0; i < this.queue.length; i++){ | ||
var commandQueue = this.queue[i]; | ||
commandQueue.functions.reject("The command couldn't be registered due to an error received from the Discord API"); | ||
} | ||
} | ||
this.queue = []; | ||
}, 2000); | ||
} | ||
timeout = undefined; | ||
ready = false; | ||
queue = []; | ||
registeredCommands = new ValueSaver(); | ||
addonCommands = new ValueSaver(); | ||
} | ||
var commandRegistrant = new CommandRegister(); | ||
class InteractionHandler extends EventEmitter{ | ||
constructor(commandRegistrant){ | ||
super(); | ||
this.on('execute', (commandData, interaction) => { | ||
var cmdName = interaction === true ? commandData.commandName : (commandData.content || '').split(' ')[0].slice(clientParser.getClient().config.prefix.length); | ||
var cmd = commandRegistrant.addonCommands.get(cmdName.toLowerCase()); | ||
if(!cmd) return; | ||
if(!cmd.command.passedClass) return; | ||
var addon = addons.get(cmd.addon); | ||
if(!addon) return; | ||
if(typeof cmd.command.default_member_permissions === 'string'){ | ||
if(!commandData.member.permissions.has(cmd.command.default_member_permissions)) return; | ||
} | ||
var getExecuteableCommand = new Command(commandData, interaction, cmd.command, addon); | ||
cmd.command.passedClass.emit('execute', getExecuteableCommand); | ||
}); | ||
} | ||
} | ||
var interactionHandler = new InteractionHandler(commandRegistrant); | ||
clientParser.parseInteractionHandler(interactionHandler); | ||
function registerAddon(addon){ | ||
return new Promise(async (resolve) => { | ||
if(registeredAddons.size === 0){ | ||
if(existsSync(path.join(__dirname, `../../addons.json`))){ | ||
try{ | ||
let addonContent = await fs.readFile(path.join(__dirname, `../../addons.json`), {encoding: 'utf-8'}); | ||
try{ | ||
addonContent = JSON.parse(addonContent); | ||
} catch {} | ||
registeredAddons.writeValueSaver(addonContent); | ||
} catch {} | ||
} | ||
} | ||
var baseName = `${addon.name}@${addon.version}-${addon.author}`; | ||
if(typeof addon.name === 'string'){ | ||
@@ -19,26 +220,58 @@ if(addons.get(addon.name)){ | ||
} else { | ||
var baseName = path.basename(require.main.filename); | ||
if(registeredAddons.get(baseName)){ | ||
var getRegistrant = registeredAddons.get(baseName); | ||
if(validateRegistrant(addon, getRegistrant)){ | ||
addons.set(addon.name, { | ||
baseName: path.basename(require.main.filename), | ||
baseName: baseName, | ||
addon: addon, | ||
verified: true | ||
permissions: addon.permissions, | ||
verified: true, | ||
allowed: true | ||
}); | ||
addonCreate.emit(addon.name, true); | ||
resolve(true); | ||
} else { | ||
addons.set(addon.name, { | ||
baseName: path.basename(require.main.filename), | ||
baseName: baseName, | ||
addon: addon, | ||
verified: false | ||
permissions: addon.permissions, | ||
verified: false, | ||
allowed: true | ||
}); | ||
if(clientParser.ready === true){ | ||
clientParser.getClient().registerAddon(addon); | ||
} else { | ||
clientParser.once('parse', (client) => { | ||
client.registerAddon(addon); | ||
}); | ||
} | ||
new Promise(async resolve => { | ||
var permissionsString = getPermissionsString(addon.permissions); | ||
if(clientParser.ready === true){ | ||
const addonRegistrant = await clientParser.getClient().registerAddon(addon, permissionsString); | ||
resolve(addonRegistrant); | ||
} else { | ||
clientParser.once('ready', async () => { | ||
const addonRegistrant = await clientParser.getClient().registerAddon(addon, permissionsString); | ||
resolve(addonRegistrant); | ||
}); | ||
} | ||
}).then(async val => { | ||
var getAddon = addons.get(addon.name); | ||
if(val === true){ | ||
getAddon['verified'] = true; | ||
addons.set(addon.name, getAddon); | ||
registeredAddons.set(baseName, { | ||
name: addon.name, | ||
bitfield: addon.permissions | ||
}); | ||
addonCreate.emit(addon.name, true); | ||
try{ | ||
let addonValuesaver = registeredAddons.toReadableArray(); | ||
await fs.writeFile(path.join(__dirname, `../../addons.json`), JSON.stringify(addonValuesaver), {encoding: 'utf-8'}); | ||
} catch {} | ||
await createStructures(clientParser.getClient(), addons.toReadableArray()); | ||
resolve(true); | ||
} else { | ||
getAddon['allowed'] = false; | ||
addons.set(addon.name, getAddon); | ||
addonCreate.emit(addon.name, false); | ||
resolve(false); | ||
} | ||
}); | ||
} | ||
resolve(true); | ||
} | ||
} else if(typeof addon.connection !== 'string'){ | ||
} else { | ||
resolve({error: 'Invalid addon: The addon has no name or connection'}); | ||
@@ -49,2 +282,2 @@ } | ||
module.exports = { registerAddon }; | ||
module.exports = { registerAddon, commandRegistrant, InteractionHandler }; |
const EventEmitter = require('events'); | ||
const { Client } = require('discord.js'); | ||
const { commandListeners, addons } = require('../../utils/saves.js'); | ||
const Command = require('../command.js'); | ||
const { handleEvents, createStructures } = require('./eventHandler.js'); | ||
const { validatePermission } = require('../../utils/functions.js'); | ||
const bitfields = require('../../bitfields/scopes.js'); | ||
var client = null; | ||
@@ -8,2 +13,9 @@ | ||
super(); | ||
this.once('ready', async () => { | ||
this.client_ready = true; | ||
if(this.interactionHandler !== null){ | ||
this.ready = true; | ||
await handleEvents(client, this.event); | ||
} | ||
}); | ||
} | ||
@@ -14,4 +26,2 @@ parse(_client){ | ||
client = _client; | ||
this.emit('parse', client); | ||
this.ready = true; | ||
} | ||
@@ -21,5 +31,56 @@ getClient(){ | ||
} | ||
parseInteractionHandler(interactionHandler){ | ||
return new Promise(async resolve => { | ||
this.interactionHandler = interactionHandler; | ||
if(client instanceof Client){ | ||
if(this.client_ready === true){ | ||
this.ready = true; | ||
await handleEvents(client, this.event); | ||
} | ||
} | ||
resolve(); | ||
}); | ||
} | ||
commandAvailability(data, interaction){ | ||
return new Promise(async (resolve, reject) => { | ||
let commandName; | ||
if(interaction === true){ | ||
commandName = data.commandName; | ||
} else { | ||
commandName = (data.content || '').split(' ')[0].slice(client.config.prefix.length); | ||
} | ||
for(var i = 0; i < commandListeners.length; i++){ | ||
var commandListener = commandListeners[i]; | ||
try{ | ||
await new Promise((accept, stop) => { | ||
const addonData = addons.get(commandListener.addonName); | ||
if(!validatePermission(addonData.permissions, bitfields.bitfield.COMMANDS)) return accept(); | ||
const command = new Command(data, interaction, {name: commandName, description: null}, addonData); | ||
if(commandListener.listener.listenerCount(commandName) > 0){ | ||
commandListener.listener.emit(commandName, command, accept, stop); | ||
} else { | ||
accept(); | ||
} | ||
}); | ||
} catch { | ||
reject(); | ||
break; | ||
} | ||
} | ||
resolve(); | ||
}); | ||
} | ||
updateStructures(){ | ||
return new Promise(async resolve => { | ||
let _addons = client.addons.toReadableArray(); | ||
await createStructures(client, _addons); | ||
resolve(); | ||
}); | ||
} | ||
client_ready = false; | ||
ready = false; | ||
InteractionHandler = null; | ||
event = new EventEmitter(); | ||
} | ||
module.exports = ClientParser; |
const { EventEmitter } = require('events'); | ||
class CommandHandler extends EventEmitter{ | ||
constructor(info){ | ||
super(); | ||
this.name = info.commandName; | ||
this.description = info.commandDescription; | ||
constructor(data){ | ||
super(); | ||
Object.defineProperties(this, { | ||
name: { | ||
value: data.name, | ||
writable: false | ||
}, | ||
description: { | ||
value: data.description, | ||
writable: false | ||
}, | ||
id: { | ||
value: data.id, | ||
writable: false | ||
} | ||
}); | ||
} | ||
name = null; | ||
description = null; | ||
id = null; | ||
} | ||
module.exports = CommandHandler; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
353029
69
7596
0
1
1
2
3
5
6
+ Addedyt-stream@^1.4.5
+ Addedagent-base@7.1.1(transitive)
+ Addeddebug@4.3.7(transitive)
+ Addedhttp-cookie-agent@6.0.6(transitive)
+ Addedms@2.1.3(transitive)
+ Addedpsl@1.9.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedquerystringify@2.2.0(transitive)
+ Addedrequires-port@1.0.0(transitive)
+ Addedtough-cookie@4.1.4(transitive)
+ Addeduniversalify@0.2.0(transitive)
+ Addedurl-parse@1.5.10(transitive)
+ Addedyt-stream@1.7.4(transitive)
Updateddiscord.js@^14.11.0