diff --git a/src/classes/AoiError.js b/src/classes/AoiError.js index eb9251301..5d500eb61 100644 --- a/src/classes/AoiError.js +++ b/src/classes/AoiError.js @@ -1,234 +1,272 @@ const Util = require("./Util.js"); -const { - ComponentParser, - EmbedParser, - FileParser, -} = Util.parsers; -const {Time} = require("../utils/helpers/customParser.js"); -const {BaseInteraction} = require("discord.js"); +const chalk = require("chalk"); +const { ComponentParser, EmbedParser, FileParser } = Util.parsers; +const { Time } = require("../utils/helpers/customParser.js"); +const { BaseInteraction } = require("discord.js"); class AoiError { - constructor() { - const error = new Error(`Cannot initialize "AoiError" Class`); - error.name = "AoiError"; - throw error; - } + constructor() { + const error = new Error(`Cannot initialize "AoiError" Class`); + error.name = "AoiError"; + throw error; + } + + /** + * @param {string} event + * @param {string} intent + * @param {number} line + * @returns {Error} + */ + static EventError(event, intent, line) { + const error = new Error( + `(Missing Intents) : "${event}" requires "${intent}" intent.` + ); + error.name = "EventError"; + error.fileName = "./AoiClient.js"; + error.lineNumber = line; + throw error; + } - /** - * @param {string} event - * @param {string} intent - * @param {number} line - * @returns {Error} - */ - static EventError(event, intent, line) { - const error = new Error( - `(Missing Intents) : "${event}" requires "${intent}" intent.`, - ); - error.name = "EventError"; - error.fileName = "./AoiClient.js"; - error.lineNumber = line; - throw error; + /** + * @param {string} command + * @param {string} type + * @param {string} name + * @param {number} position + * @returns {Error} + */ + static CommandError(command, type, name, position) { + if (type === "name") { + const error = new Error( + `AoiError: "Name" property is missing in "${command}" (position: ${position})` + ); + error.name = "CommandNameError"; + throw error; + } else if (type === "code") { + const error = new Error( + `AoiError: "Code" is not provided in "${ + name || "the Command" + }" : ${command} (position: ${position})` + ); + error.name = "CommandCodeError"; + throw error; + } else if (type === "channel") { + const error = new Error( + `AoiError: "Channel" is not provided in "${ + name || "the Command" + }" : ${command} (position: ${position})` + ); + error.name = "CommandChannelError"; + throw error; } + } - /** - * @param {string} command - * @param {string} type - * @param {string} name - * @param {number} position - * @returns {Error} - */ - static CommandError(command, type, name, position) { - if (type === "name") { - const error = new Error( - `AoiError: "Name" property is missing in "${command}" (position: ${position})`, - ); - error.name = "CommandNameError"; - throw error; - } else if (type === "code") { - const error = new Error( - `AoiError: "Code" is not provided in "${ - name || "the Command" - }" : ${command} (position: ${position})`, - ); - error.name = "CommandCodeError"; - throw error; - } else if (type === "channel") { - const error = new Error( - `AoiError: "Channel" is not provided in "${ - name || "the Command" - }" : ${command} (position: ${position})`, - ); - error.name = "CommandChannelError"; - throw error; - } + /** + * @param {import('./AoiClient.js')} client + * @param {import('discord.js').TextChannel | + * import('discord.js').ThreadChannel | + * import('discord.js').NewsChannel | + * import('discord.js').User | + * import('discord.js').Webhook | import('discord.js').Interaction } channel + * @param {object} options={} + * @param {object} extraOptions={} + * @param {object} d + * @returns {Promise} + */ + static async makeMessageError( + client, + channel, + options = {}, + extraOptions = {}, + d + ) { + options = options.data ?? options; + if (typeof options === "object") { + options.content = options.content?.toString()?.trim() || " "; + if (options.embeds && typeof options.embeds === "string") { + options.embeds = await EmbedParser(options.embeds); + } + if (options.files && typeof options.files === "string") { + options.files = FileParser(options.files); + } + if (options.components && typeof options.components === "string") { + options.components = await ComponentParser(options.components, client); + } + } else { + options = { + content: options?.toString()?.trim() === "" ? " " : options?.toString(), + }; + } + let msg; + if (extraOptions.interaction) { + if ( + options.content === "" && + options.embeds?.length === 0 && + options.files?.length === 0 + ) + return; + msg = await d.data.interaction.reply(options); + } else { + if (channel instanceof BaseInteraction) { + if ( + options.content === "" && + options.embeds?.length === 0 && + options.files?.length === 0 + ) + return; + msg = await channel.reply(options).catch((e) => { + AoiError.consoleError("CreateMessageError", e); + return undefined; + }); + } else { + if ( + options.content === " " && + (options.embeds?.length ?? 0) === 0 && + (options.files?.length ?? 0) === 0 && + (options.stickers?.length ?? 0) === 0 + ) + return; + msg = await channel.send(options).catch((e) => { + AoiError.consoleError("CreateMessageError", e); + return undefined; + }); + } } - /** - * @param {import('./AoiClient.js')} client - * @param {import('discord.js').TextChannel | - * import('discord.js').ThreadChannel | - * import('discord.js').NewsChannel | - * import('discord.js').User | - * import('discord.js').Webhook | import('discord.js').Interaction } channel - * @param {object} options={} - * @param {object} extraOptions={} - * @param {object} d - * @returns {Promise} - */ - static async makeMessageError( - client, - channel, - options = {}, - extraOptions = {}, - d, - ) { - options = options.data ?? options; - if (typeof options === "object") { - options.content = options.content?.toString()?.trim() || " "; - if (options.embeds && typeof options.embeds === "string") { - options.embeds = await EmbedParser(options.embeds); - } - if (options.files && typeof options.files === "string") { - options.files = FileParser(options.files); - } - if (options.components && typeof options.components === "string") { - options.components = await ComponentParser( - options.components, - client, - ); - } - } else { - options = { - content: - options?.toString()?.trim() === "" - ? " " - : options?.toString(), - }; - } - let msg; - if (extraOptions.interaction) { - if ( - options.content === "" && - options.embeds?.length === 0 && - options.files?.length === 0 - ) - return; - msg = await d.data.interaction.reply(options); - } else { - if (channel instanceof BaseInteraction) { - if ( - options.content === "" && - options.embeds?.length === 0 && - options.files?.length === 0 - ) - return; - msg = await channel.reply(options).catch((e) => { - AoiError.consoleError("CreateMessageError", e); - return undefined; - }); - } else { - if ( - options.content === " " && - (options.embeds?.length ?? 0) === 0 && - (options.files?.length ?? 0) === 0 && - (options.stickers?.length ?? 0) === 0 - ) - return; - msg = await channel.send(options).catch((e) => { - AoiError.consoleError("CreateMessageError", e); - return undefined; - }); - } - } + if (extraOptions.reactions?.length) { + extraOptions.reactions.forEach((x) => msg.react(x)); + } + if (extraOptions.edits) { + const editIn = setInterval(async () => { + if (!extraOptions.edits.messages?.length) clearInterval(editIn); + else { + const obj = extraOptions.edits.messages.shift(); - if (extraOptions.reactions?.length) { - extraOptions.reactions.forEach((x) => msg.react(x)); - } - if (extraOptions.edits) { - const editIn = setInterval(async () => { - if (!extraOptions.edits.messages?.length) clearInterval(editIn); - else { - const obj = extraOptions.edits.messages.shift(); - - msg.edit(obj); - } - }, Time.parse(extraOptions.edits.time)?.ms); - } - if (extraOptions.deleteIn) { - extraOptions.deleteIn = Time.parse(extraOptions.deleteIn)?.ms; - setTimeout(() => msg.delete(), extraOptions.deleteIn); + msg.edit(obj); } - if (extraOptions.deleteCommand) { - d.message.delete(); - } - return msg; + }, Time.parse(extraOptions.edits.time)?.ms); + } + if (extraOptions.deleteIn) { + extraOptions.deleteIn = Time.parse(extraOptions.deleteIn)?.ms; + setTimeout(() => msg.delete(), extraOptions.deleteIn); } + if (extraOptions.deleteCommand) { + d.message.delete(); + } + return msg; + } + + /** + * @param {string} name + * @param {any} e + * @returns {void} + */ + static consoleError(name, err) { + return console.error(`${name}: ${err}`); + } + + /** + * @param {object} d + * @param {"member" | "message" | "channel" | "user" | "role" | 'guild' | "emoji" | "option" | "custom" } type + * @param {object} data + * @param {string | void} message + * @returns {string} + */ + static functionErrorResolve(d, type, data, message) { + let errorData = { + Function: `\`${d.func}\``, + Command: `\`${d.command.name}\``, + Version: require("../../package.json").version, + }; - /** - * @param {string} name - * @param {any} e - * @returns {void} - */ - static consoleError(name, e) { - return console.error(`${name}: ${e}`); + switch (type) { + case "member": + errorData.type = "Member ID"; + break; + case "message": + errorData.type = "Message ID"; + break; + case "channel": + errorData.type = "Channel ID"; + break; + case "user": + errorData.type = "User ID"; + break; + case "role": + errorData.type = "Role ID"; + break; + case "guild": + errorData.type = "Guild ID"; + break; + case "emoji": + errorData.type = "Emoji ID"; + break; + case "option": + errorData.type = "Option ID"; + break; + case "custom": + errorData.type = message; + break; } + return `\`\`\`js\nAoiError: Invalid ${errorData.type} ${ + data.inside || "" + } \n { \n Function : ${errorData.Function},\n Command : ${ + errorData.Command + },\n Version : ${errorData.Version} \n }\`\`\``; + } - /** - * @param {object} d - * @param {"member" | "message" | "channel" | "user" | "role" | 'guild' | "emoji" | "option" | "custom" } type - * @param {object} data - * @param {string | void} message - * @returns {string} - */ - static functionErrorResolve(d, type, data, message) { - let errorData = { - Function: `\`${d.func}\``, - Command: `\`${d.command.name}\``, - Version: require("../../package.json").version, - }; - - switch (type) { - case "member": - errorData.type = "Member ID"; - break; - case "message": - errorData.type = "Message ID"; - break; - case "channel": - errorData.type = "Channel ID"; - break; - case "user": - errorData.type = "User ID"; - break; - case "role": - errorData.type = "Role ID"; - break; - case "guild": - errorData.type = "Guild ID"; - break; - case "emoji": - errorData.type = "Emoji ID"; - break; - case "option": - errorData.type = "Option ID"; - break; - case "custom": - errorData.type = message; - break; - } - return `\`\`\`js\nAoiError: Invalid ${errorData.type} ${data.inside || ""} \n { \n Function : ${errorData.Function},\n Command : ${errorData.Command},\n Version : ${errorData.Version} \n }\`\`\``; + /** + * @param {object} d - The data object. + * @param {"member" | "message" | "channel" | "user" | "role" | "guild" | "emoji" | "option" | "custom"} type - The type of error. + * @param {object} data - The additional error data. + * @param {string} [message] - An optional custom error message. + * @returns {void} + */ + static fnError(d, type, data, message) { + d.error(this.functionErrorResolve(d, type, data, message)); + } + + /** + * Creates a custom boxed message with optional title and border color. + * @param {Array<{text: string, textColor?: string}> | {text: string, textColor?: string}} messages - The messages to be displayed in the box. + * @param {string} [borderColor="yellow"] - The color of the box border. Default is "yellow". + * @param {{text: string, textColor?: string}} [title] - The title of the box. + * @returns {void} + */ + static createCustomBoxedMessage(messages, borderColor = "yellow", title) { + if (!Array.isArray(messages)) { + messages = [messages]; } - /** - * @param {object} d - The data object. - * @param {"member" | "message" | "channel" | "user" | "role" | "guild" | "emoji" | "option" | "custom"} type - The type of error. - * @param {object} data - The additional error data. - * @param {string} [message] - An optional custom error message. - * @returns {void} - */ - static fnError(d, type, data, message) { - d.error(this.functionErrorResolve(d, type, data, message)); + const maxLength = title + ? Math.max(...messages.map((msg) => msg.text.length), title.text.length) + : Math.max(...messages.map((msg) => msg.text.length)); + + const topBorder = chalk[borderColor](`╭${"─".repeat(maxLength + 2)}╮`); + const bottomBorder = chalk[borderColor](`╰${"─".repeat(maxLength + 2)}╯`); + + console.log(topBorder); + + if (title) { + const titlePadding = " ".repeat((maxLength - title.text.length) / 2); + const titleText = `${chalk[borderColor]("│")} ${titlePadding}${chalk[ + title.textColor + ](title.text)}${titlePadding} ${chalk[borderColor]("│")}`; + console.log(titleText); } + + messages.forEach((message) => { + const paddingLength = (maxLength - message.text.length) / 2; + const leftPadding = " ".repeat(Math.floor(paddingLength)); + const rightPadding = " ".repeat(Math.ceil(paddingLength)); + const textColor = message.textColor || "reset"; + const messageText = `${chalk[borderColor]("│")} ${leftPadding}${chalk[ + textColor + ](message.text)}${rightPadding} ${chalk[borderColor]("│")}`; + console.log(messageText); + }); + + console.log(bottomBorder); + } } module.exports = AoiError; diff --git a/src/classes/Database.js b/src/classes/Database.js index ae3fc9fe8..6a594b2b4 100644 --- a/src/classes/Database.js +++ b/src/classes/Database.js @@ -1,72 +1,84 @@ const aoidb = require("@akarui/aoi.db"); +const AoiError = require("../classes/AoiError.js"); class Database { - /** - * @type {aoidb.KeyValue | aoidb.Transmitter} db - * @type {boolean} ready - * @type {number} readyAt - * @type {"aoi.db"} type - * @type {"KeyValue" | "Transmitter"} moduleType - * @type {string[]} tables - */ - db; - ready = false; - readyAt = 0; - type; - tables = []; - moduleType = "KeyValue"; - /** - * Description - * @param {any} module - * @param {"KeyValue" | "Transmitter"} type - * @param {aoidb.KeyValueOptions | aoidb.TransmitterOptions} config - * @returns {any} - */ - constructor(moduleType, module, type, config) { - this.moduleType = type; - this.db = new module[type](config); - this.tables = config.dataConfig.tables; - this.type = moduleType; - this.db.on(aoidb.DatabaseEvents.Connect, () => { - console.log(`[@akarui/aoi.db] Connected ${type} database`); - this.ready = true; - this.readyAt = Date.now(); - }); + /** + * @type {aoidb.KeyValue | aoidb.Transmitter} db + * @type {boolean} ready + * @type {number} readyAt + * @type {"aoi.db"} type + * @type {"KeyValue" | "Transmitter"} moduleType + * @type {string[]} tables + */ + db; + ready = false; + readyAt = 0; + type; + tables = []; + moduleType = "KeyValue"; + /** + * Description + * @param {any} module + * @param {"KeyValue" | "Transmitter"} type + * @param {aoidb.KeyValueOptions | aoidb.TransmitterOptions} config + * @returns {any} + */ + constructor(moduleType, module, type, config) { + this.moduleType = type; + this.db = new module[type](config); + this.tables = config.dataConfig.tables; + this.type = moduleType; + this.db.on(aoidb.DatabaseEvents.Connect, () => { + AoiError.createCustomBoxedMessage( + [ + { + text: `Successfully connected ${type} database`, + textColor: "white", + }, + ], + "white", + { text: "@akarui/db ", textColor: "cyan" } + ); - this.db.connect(); - } + // console.log(`[@akarui/aoi.db] Connected ${type} database`); + this.ready = true; + this.readyAt = Date.now(); + }); - async set(table, key, id, value) { - return await this.db.set(table, id ? `${key}_${id}` : key, { value }); - } + this.db.connect(); + } - async get(table, key, id) { - return await this.db.get(table, id ? `${key}_${id}` : key); - } + async set(table, key, id, value) { + return await this.db.set(table, id ? `${key}_${id}` : key, { value }); + } - async delete(table, key, id) { - return await this.db.delete(table, id ? `${key}_${id}` : key); - } + async get(table, key, id) { + return await this.db.get(table, id ? `${key}_${id}` : key); + } - async all(table, query, limit) { - return await this.db.all(table, query, limit); - } + async delete(table, key, id) { + return await this.db.delete(table, id ? `${key}_${id}` : key); + } - async has(table, key, id) { - return await this.db.has(table, id ? `${key}_${id}` : key); - } + async all(table, query, limit) { + return await this.db.all(table, query, limit); + } - async deleteMany(table, query) { - return await this.db.deleteMany(table, query); - } + async has(table, key, id) { + return await this.db.has(table, id ? `${key}_${id}` : key); + } - async findOne(table, query) { - return await this.db.findOne(table, query); - } + async deleteMany(table, query) { + return await this.db.deleteMany(table, query); + } - async findMany(table, query, limit) { - return await this.db.findMany(table, query, limit); - } + async findOne(table, query) { + return await this.db.findOne(table, query); + } + + async findMany(table, query, limit) { + return await this.db.findMany(table, query, limit); + } } -module.exports = Database; \ No newline at end of file +module.exports = Database; diff --git a/src/classes/LoadCommands.js b/src/classes/LoadCommands.js index 5f106e036..6b780cbb0 100644 --- a/src/classes/LoadCommands.js +++ b/src/classes/LoadCommands.js @@ -133,7 +133,7 @@ class LoadCommands { try { if (await fs.promises.stat(path).then((f) => !f.isDirectory())) - console.error("Error!"); + throw new TypeError("Path is not a valid directory!"); } catch (e) { throw new TypeError("Path is not a valid directory! ErrorMessage: " + e); } diff --git a/src/classes/Util.js b/src/classes/Util.js index ee9df3323..733582895 100644 --- a/src/classes/Util.js +++ b/src/classes/Util.js @@ -134,8 +134,8 @@ class Util { static get threadTypes() { return { - public: "GUILD_PUBLIC_THREAD", - private: "GUILD_PRIVATE_THREAD", + public: Discord.ChannelType.PublicThread, + private: Discord.ChannelType.PrivateThread, }; } diff --git a/src/functions/client/broadcastEval.js b/src/functions/client/broadcastEval.js index be1b587fa..3bc97572d 100644 --- a/src/functions/client/broadcastEval.js +++ b/src/functions/client/broadcastEval.js @@ -1,18 +1,22 @@ module.exports = async (d) => { - const data = d.util.aoiFunc(d); - if (data.err) return d.error(data.err); + const data = d.util.aoiFunc(d); + if (data.err) return d.error(data.err); - const [func] = data.inside.splits; + const [func] = data.inside.splits; - function evalfunc(client, {func}) { - return eval(func) - } + function evalfunc(client, { func }) { + return eval(func); + } - data.result = await d.client.shard.broadcastEval(evalfunc, {context: {func: func}}); + if (!d.client.shard) return d.aoiError.fnError(d,"custom", {}, "ClientShard Class is Not Initialised"); - data.result = data.result.join(" , "); + data.result = await d.client.shard.broadcastEval(evalfunc, { + context: { func: func }, + }); - return { - code: d.util.setCode(data), - }; -}; \ No newline at end of file + data.result = data.result.join(" , "); + + return { + code: d.util.setCode(data), + }; +}; diff --git a/src/functions/client/fetchClientValues.js b/src/functions/client/fetchClientValues.js index b3e84dc73..dca8d525d 100644 --- a/src/functions/client/fetchClientValues.js +++ b/src/functions/client/fetchClientValues.js @@ -3,9 +3,9 @@ module.exports = async d => { if (data.err) return d.error(data.err); const [func] = data.inside.splits; - if (!d.client.clientShard) return d.aoiError.fnError(d, 'custom', {}, 'ClientShard Class is Not Initialised'); + if (!d.client.shard) return d.aoiError.fnError(d, 'custom', {}, 'ClientShard Class is Not Initialised'); - data.result = await d.client.clientShard.fetchClientValues(func); + data.result = await d.client.shard.fetchClientValues(func); return { code: d.util.setCode(data), diff --git a/src/functions/event/bulk.js b/src/functions/event/bulk.js index e788e7638..df2c05a25 100644 --- a/src/functions/event/bulk.js +++ b/src/functions/event/bulk.js @@ -1,14 +1,14 @@ -const {BulkData} = require("../../utils/EventUtil.js"); +const { BulkData } = require("../../utils/EventUtil.js"); -module.exports = d => { - const data = d.util.aoiFunc(d); - if (data.err) return d.error(data.err); +module.exports = (d) => { + const data = d.util.aoiFunc(d); + if (data.err) return d.error(data.err); - const [option] = data.inside.splits; + const [option, sep = " , "] = data.inside.splits; - data.result = BulkData(d, option).deleteBrackets(); + data.result = BulkData(d, sep, option).deleteBrackets(); - return { - code: d.util.setCode(data) - } -} \ No newline at end of file + return { + code: d.util.setCode(data), + }; +}; diff --git a/src/functions/guild/createThread.js b/src/functions/guild/createThread.js index 59cf4d084..b19a84d44 100644 --- a/src/functions/guild/createThread.js +++ b/src/functions/guild/createThread.js @@ -1,28 +1,29 @@ module.exports = async d => { - const {code} = d.command; - const inside = d.unpack(); - const err = d.inside(inside); - if (err) return d.error(err); + const data = d.util.aoiFunc(d); + const { code } = d.command; + if (data.err) return d.error(data.err); - let [channelID, name, archive = "MAX", type = "public", startMessage, returnID = "false"] = inside.splits; + let [channelID, name, archive = "MAX", type = "public", startMessage, returnID = "false"] = data.inside.splits; const channel = await d.util.getChannel(d, channelID); - if (!channel) return d.aoiError.fnError(d, "channel", {inside}); + if (!channel) return d.aoiError.fnError(d, "channel", { inside: data.inside }); type = d.util.threadTypes[type]; - if (!type) return d.aoiError.fnError(d, "custom", {inside}, "Invalid Type Provided In"); - if (!["60", "1440", "4320", "10080", "MAX"].includes(archive.toUpperCase())) d.aoiError.fnError(d, "custom", {inside}, "Invalid Archive Duration Provided In"); + if (!type) return d.aoiError.fnError(d, "custom", { inside: data.inside }, "Invalid Type Provided In"); + if (!["60", "1440", "4320", "10080", "MAX"].includes(archive.toUpperCase())) return d.aoiError.fnError(d, "custom", { inside: data.inside }, "Archive Duration Provided In"); const result = await channel.threads.create({ name, - autoArchiveDuration: archive, + autoArchiveDuration: archive.toUpperCase().replace("MAX", "10080"), type, startMessage: startMessage?.trim() === "" ? undefined : startMessage }).catch(e => { - d.aoiError.fnError(d, "custom", {}, "Failed To Create Thread With Reason: " + e); + return d.aoiError.fnError(d, "custom", {}, "Failed To Create Thread With Reason: " + e); }); + data.result = returnID === "true" ? result?.id : undefined; + return { - code: d.util.setCode({function: d.func, code, inside, result: returnID === "true" ? result?.id : ""}) + code: d.util.setCode(data) } } \ No newline at end of file diff --git a/src/functions/guild/guildHighestRole.js b/src/functions/guild/guildHighestRole.js index e373082ee..51bbb0286 100644 --- a/src/functions/guild/guildHighestRole.js +++ b/src/functions/guild/guildHighestRole.js @@ -11,4 +11,4 @@ module.exports = async d => { return { code: d.util.setCode(data) } -} \ No newline at end of file +} diff --git a/src/functions/guild/guildLowestRole.js b/src/functions/guild/guildLowestRole.js index 60bf4af9d..6cca5792f 100644 --- a/src/functions/guild/guildLowestRole.js +++ b/src/functions/guild/guildLowestRole.js @@ -1,14 +1,18 @@ -module.exports = async d => { - const data = d.util.aoiFunc(d); +module.exports = async (d) => { + const data = d.util.aoiFunc(d); - const [guildID = d.guild?.id] = data.inside.splits; + const [guildID = d.guild?.id, option = "id"] = data.inside.splits; - const guild = await d.util.getGuild(d, guildID); - if (!guild) return d.aoiError.fnError(d, 'guild', {inside: data.inside}); + const guild = await d.util.getGuild(d, guildID); + if (!guild) return d.aoiError.fnError(d, "guild", { inside: data.inside }); - data.result = [...guild.roles.cache.sort((a, b) => a.position - b.position)][1]?.[0]; + const role = guild.roles.cache.filter((role) => role.id !== guild.id).sort((a, b) => a.position - b.position) .first(); - return { - code: d.util.setCode(data) - } -} \ No newline at end of file + data.result = !role + ? guild?.roles.everyone.id + : role === undefined + ? guild.id + : role?.[option.toLowerCase()]; + + return { code: d.util.setCode(data) }; +}; diff --git a/src/functions/info/customEmoji.js b/src/functions/info/customEmoji.js index 84dcc9ee0..1faa58c3f 100644 --- a/src/functions/info/customEmoji.js +++ b/src/functions/info/customEmoji.js @@ -7,7 +7,7 @@ module.exports = async d => { let result; if (id === "global") { - result = d.client.emojis.cache.find(x => x.name.toLowerCase() === emoji.toLowerCase() || x.toString() === emoji || x.id === emoji)?.toString() + result = (await d.util.getEmoji(d, emoji)).toString(); } else { result = d.client.guilds.cache.get(id)?.emojis.cache.find(x => x.name.toLowerCase() === emoji.toLowerCase() || x.toString() === emoji || x.id === emoji)?.toString() } diff --git a/src/functions/interaction/awaitExecute.js b/src/functions/interaction/awaitExecute.js new file mode 100644 index 000000000..3708c0203 --- /dev/null +++ b/src/functions/interaction/awaitExecute.js @@ -0,0 +1,37 @@ +const Interpreter = require("../../core/interpreter.js"); + +module.exports = async (d) => { + const data = d.util.aoiFunc(d); + if (data.err) return d.error(data.err); + + const [awaitfunc] = data.inside.splits; + + const cmd = d.client.cmd.awaited.find( + (x) => x.name.toLowerCase() === awaitfunc.addBrackets().toLowerCase() + ); + + if (!cmd) + return d.aoiError.fnError( + d, + "custom", + {}, + `Invalid Awaited Command: '${awaitfunc.addBrackets()}' Provided` + ); + + await Interpreter( + d.client, + d.message, + d.args, + cmd, + d.client.db, + false, + undefined, + d.data + ); + + data.result = null; + + return { + code: d.util.setCode(data), + }; +}; diff --git a/src/functions/message/sendSticker.js b/src/functions/message/sendSticker.js new file mode 100644 index 000000000..73ede4003 --- /dev/null +++ b/src/functions/message/sendSticker.js @@ -0,0 +1,19 @@ +module.exports = async (d) => { + const data = d.util.aoiFunc(d); + + let [resolver] = data.inside.splits; + + const guild = d.client.guilds.cache.get(d.guild?.id); + if (!guild) return d.aoiError.fnError(d, "guild", { inside: data.inside }); + + const sticker = await d.util.getSticker(guild, resolver); + if (!sticker) return d.aoiError.fnError(d, "custom", { inside: data.inside }, "sticker"); + + try { + await d.channel.send({ stickers: [sticker.id] }); + } catch (err) { + return d.aoiError.fnError(d, "custom", { inside: data.inside }, `Failed to send resolver: ${err}`); + } + + return { code: d.util.setCode(data) }; +}; diff --git a/src/functions/user/userHighestRole.js b/src/functions/user/userHighestRole.js index 15f7bfa50..57755c069 100644 --- a/src/functions/user/userHighestRole.js +++ b/src/functions/user/userHighestRole.js @@ -1,17 +1,18 @@ -module.exports = async d => { - const data = d.util.aoiFunc(d); +module.exports = async (d) => { + const data = d.util.aoiFunc(d); - const [userID = d.author?.id, guildID = d.guild?.id, option = 'id'] = data.inside.splits; + const [userID = d.author?.id, guildID = d.guild?.id, option = "id"] = data.inside.splits; - const guild = await d.util.getGuild(d, guildID); - if (!guild) return d.aoiError.fnError(d, 'guild', {inside: data.inside}); + const guild = await d.util.getGuild(d, guildID); + if (!guild) return d.aoiError.fnError(d, "guild", { inside: data.inside }); - const member = await d.util.getMember(guild, userID); - if (!member) return d.aoiError.fnError(d, 'member', {inside: data.inside}); + const member = await d.util.getMember(guild, userID); + if (!member) return d.aoiError.fnError(d, "member", { inside: data.inside }); - data.result = option === "mention" ? member.roles.highest.toString() : member.roles.highest[option]; + data.result = + option === "mention" + ? member.roles.highest.toString() + : member.roles.highest[option]; - return { - code: d.util.setCode(data) - } -} \ No newline at end of file + return { code: d.util.setCode(data) }; +}; diff --git a/src/functions/user/userLowestRole.js b/src/functions/user/userLowestRole.js index cd4c2b556..ff4b52b27 100644 --- a/src/functions/user/userLowestRole.js +++ b/src/functions/user/userLowestRole.js @@ -1,18 +1,21 @@ -module.exports = async d => { - const data = d.util.aoiFunc(d); +module.exports = async (d) => { + const data = d.util.aoiFunc(d); - const [userID = d.author?.id, guildID = d.guild?.id] = data.inside.splits; + const [userID = d.author?.id, guildID = d.guild?.id, option = "id"] = data.inside.splits; - const guild = await d.util.getGuild(d, guildID); - if (!guild) return d.aoiError.fnError(d, 'guild', {inside: data.inside}); + const guild = await d.util.getGuild(d, guildID); + if (!guild) return d.aoiError.fnError(d, "guild", { inside: data.inside }); - const member = await d.util.getMember(guild, userID); - if (!member) return d.aoiError.fnError(d, 'member', {inside: data.inside}); - const role = [...member.roles.cache.sort((a, b) => a.position - b.position)][1]; + const member = await d.util.getMember(guild, userID); + if (!member) return d.aoiError.fnError(d, "member", { inside: data.inside }); - data.result = role[0]; + const role = member.roles.cache.filter((role) => role.id !== guild.id).sort((a, b) => a.position - b.position).first(); - return { - code: d.util.setCode(data) - } -} \ No newline at end of file + data.result = !role + ? guild?.roles.everyone.id + : role === undefined + ? guild.id + : role?.[option.toLowerCase()]; + + return { code: d.util.setCode(data) }; +}; diff --git a/src/functions/util/emojiExists.js b/src/functions/util/emojiExists.js index e15879aa4..87a68472d 100644 --- a/src/functions/util/emojiExists.js +++ b/src/functions/util/emojiExists.js @@ -4,7 +4,7 @@ module.exports = async d => { const [emoji] = data.inside.splits; - data.result = d.client.emojis.cache.some(x => x.id === emoji || x.toString() === emoji || x.identifier.toLowerCase() === emoji.toLowerCase()) + data.result = !!(await d.util.getEmoji(d, emoji)); return { code: d.util.setCode(data) diff --git a/src/functions/util/resolveEmojiID.js b/src/functions/util/resolveEmojiID.js index e68d1811e..4fe804085 100644 --- a/src/functions/util/resolveEmojiID.js +++ b/src/functions/util/resolveEmojiID.js @@ -1,14 +1,10 @@ -module.exports = (d) => { +module.exports = async (d) => { const data = d.util.aoiFunc(d); if (data.err) return d.error(data.err); const emoji = data.inside.inside; - data.result = d.client.emojis.cache.find( - (x) => - x.name.toLowerCase() === emoji.addBrackets().toLowerCase() || - x.toString() === emoji.addBrackets(), - ); + data.result = (await d.util.getEmoji(d, emoji))?.id ?? ""; return { code: d.util.setCode(data), diff --git a/src/functions/util/resolveStickerID.js b/src/functions/util/resolveStickerID.js new file mode 100644 index 000000000..eacdbacb9 --- /dev/null +++ b/src/functions/util/resolveStickerID.js @@ -0,0 +1,12 @@ +module.exports = async (d) => { + const data = d.util.aoiFunc(d); + if (data.err) return d.error(data.err); + + const sticker = data.inside.inside; + + data.result = (await d.util.getSticker(d, sticker))?.id ?? ""; + + return { + code: d.util.setCode(data), + }; +}; \ No newline at end of file diff --git a/src/handler/AoiAutoUpdate.js b/src/handler/AoiAutoUpdate.js index a5f3782cd..2b8eec2b2 100644 --- a/src/handler/AoiAutoUpdate.js +++ b/src/handler/AoiAutoUpdate.js @@ -1,78 +1,120 @@ const { exec } = require("child_process"); -const { Agent, fetch } = require('undici'); +const { Agent, fetch } = require("undici"); const json = require("../../package.json"); +const AoiError = require("../classes/AoiError.js"); module.exports = async () => { - console.log("aoi.js AutoUpdate: \u001b[33mExecuting a contact with API...\u001b[0m"); + try { + const res = await fetch("https://registry.npmjs.org/aoi.js", { + dispatcher: new Agent({ + keepAliveTimeout: 10000, + keepAliveMaxTimeout: 15000, + }), + headers: { + "User-Agent": "aoi.js", + }, + }); - try { - const res = await fetch('https://registry.npmjs.org/aoi.js', { - dispatcher: new Agent({ - keepAliveTimeout: 10000, // 10 seconds - keepAliveMaxTimeout: 15000 // 15 seconds - }), - headers: { - 'User-Agent': 'aoi.js' // required by npm registry API - } - }); + const data = await res.json(); + if (json.version !== data["dist-tags"].latest) { + AoiError.createCustomBoxedMessage( + [ + { + text: "", + textColor: "white", + }, + { + text: "aoi.js is outdated!", + textColor: "red", + }, + { + text: `Available version: ${data["dist-tags"].latest} ready to install.`, + textColor: "white", + }, + { + text: "", + textColor: "white", + }, + { + text: "Installing latest aoi.js version...", + textColor: "yellow", + }, + ], + "white", + { text: "aoi.js AutoUpdate ", textColor: "yellow" } + ); - const data = await res.json(); - if (json.version !== data['dist-tags'].latest) { - console.log( - "aoi.js AutoUpdate: \u001b[33mAvailable version v" + - data['dist-tags'].latest + - " ready to install.\u001b[0m" - ); + const Process = exec("npm i aoi.js@latest", (error) => { + if (error) + return AoiError.createCustomBoxedMessage( + [ + { + text: `aoi.js AutoUpdate: ERR! ${error.message}`, + textColor: "red", + }, + ], + "white", + { text: "aoi.js AutoUpdate", textColor: "yellow" } + ); - // Install initiate - console.log("aoi.js AutoUpdate: \u001b[33m Installing version...\u001b[0m"); - const Process = exec("npm i aoi.js@latest", (error) => { - if (error) - return console.error( - "aoi.js AutoUpdate: \u001b[31mERR!\u001b[0m " + error.message - ); - - console.log( - "aoi.js AutoUpdate: \u001b[32mSuccessfully Installed aoi.js v" + - data['dist-tags'].latest + - ".\u001b[0m" - ); - console.log("aoi.js AutoUpdate: Commencing 'RESTART' in 3 Seconds..."); - - setTimeout(Reboot, 3000); - }); - Process.stdout.setEncoding("utf8"); - Process.stdout.on("data", (chunk) => { - console.log(chunk.toString()); - }); - - Process.stderr.setEncoding("utf8"); - Process.stderr.on("data", (chunk) => { - console.log(chunk.toString()); - }); - } else { - console.log("aoi.js AutoUpdate: \u001b[32mVersion is up-to-date.\u001b[0m"); - } - } catch (error) { - console.warn( - "aoi.js AutoUpdate: \u001b[31mUnexpected error when trying to reach API.\u001b[0m" + AoiError.createCustomBoxedMessage( + [ + { + text: `Successfully Installed aoi.js v${data["dist-tags"].latest}.`, + textColor: "white", + }, + { + text: "", + textColor: "white", + }, + { + text: "Commencing 'RESTART' in 3 seconds...", + textColor: "yellow", + }, + ], + "white", + { text: "aoi.js AutoUpdate ", textColor: "yellow" } ); + + setTimeout(Reboot, 3000); + }); + } else { + return; } + } catch (error) { + AoiError.createCustomBoxedMessage( + [ + { + text: "aoi.js AutoUpdate: Unexpected error when trying to reach API.", + textColor: "red", + }, + ], + "white", + { text: "aoi.js AutoUpdate ", textColor: "yellow" } + ); + } }; function Reboot() { - try { - process.on("exit", () => { - require("child_process").spawn(process.argv.shift(), process.argv, { - cwd: process.cwd(), - detached: true, - stdio: "inherit", - }); - }); - process.exit(); - } catch (e) { - console.error( - `aoi.js AutoUpdate: \u001b[31mERR!\u001b[0m Failed to commence 'RESTART', ${e.message}` - ); - } + try { + process.on("exit", () => { + require("child_process").spawn(process.argv.shift(), process.argv, { + cwd: process.cwd(), + detached: true, + stdio: "inherit", + }); + }); + process.exit(); + } catch (e) { + AoiError.createCustomBoxedMessage( + [ + { + text: `aoi.js AutoUpdate: ERR! Failed to commence 'RESTART', ${e.message}`, + textColor: "red", + }, + ], + "white", + { text: "aoi.js AutoUpdate ", textColor: "yellow" } + ); + } } diff --git a/src/handler/AoiLogs.js b/src/handler/AoiLogs.js index ca1605fc7..6fccdcc1e 100644 --- a/src/handler/AoiLogs.js +++ b/src/handler/AoiLogs.js @@ -1,18 +1,26 @@ const json = require("../../package.json"); -const createCustomBoxedMessage = require('../utils/CustomBox.js'); +const AoiError = require("../classes/AoiError.js"); module.exports = async () => { - try { - const version = json.version; - const installedVersion = { text: `Installed on v${version}`, textColor: 'green' }; - const discordServer = { text: 'Discord Server: https://discord.gg/HMUfMXDQsV', textColor: 'blue' }; - - createCustomBoxedMessage( - [installedVersion, discordServer], - 'white', - { text: 'aoi.js ', textColor: 'cyan' } - ); - } catch (error) { - console.error(`AoiLogs: Error during initialization: ${error.message}`); - } + try { + AoiError.createCustomBoxedMessage( + [ + { + text: `Installed on v${json.version}`, + textColor: "green", + }, + { + text: "Discord Server: https://discord.gg/HMUfMXDQsV", + textColor: "blue", + }, + ], + "white", + { + text: "aoi.js ", + textColor: "cyan", + } + ); + } catch (err) { + console.error(`AoiLogs: Error during initialization: ${err}`); + } }; diff --git a/src/handler/AoiWarning.js b/src/handler/AoiWarning.js index 2de65b9c1..44b06dddd 100644 --- a/src/handler/AoiWarning.js +++ b/src/handler/AoiWarning.js @@ -1,41 +1,61 @@ -const { Agent, fetch } = require('undici'); +const { Agent, fetch } = require("undici"); const json = require("../../package.json"); -const createCustomBoxedMessage = require('../utils/CustomBox.js'); +const AoiError = require("../classes/AoiError.js"); + +const compareVersions = (a, b) => a.split(".").map(Number).some((v, i) => v > (b.split(".")[i] || 0)); module.exports = async () => { - try { - const res = await fetch('https://registry.npmjs.org/aoi.js', { - dispatcher: new Agent({ - keepAliveTimeout: 10000, // 10 seconds - keepAliveMaxTimeout: 15000 // 15 seconds - }), - headers: { - 'User-Agent': 'aoi.js' // required by npm registry API - } - }); + try { + const res = await fetch("https://registry.npmjs.org/aoi.js", { + dispatcher: new Agent({ + keepAliveTimeout: 10000, // 10 seconds + keepAliveMaxTimeout: 15000, // 15 seconds + }), + headers: { + "User-Agent": "aoi.js", // required by npm registry API + }, + }); - const data = await res.json(); - const latestVersion = data['dist-tags'].latest; - const isDevVersion = json.version.includes('dev'); + const data = await res.json(); + const latestVersion = data["dist-tags"].latest; - if (!isDevVersion && json.version !== latestVersion) { - createCustomBoxedMessage( - [{ text: 'AoiWarning: aoi.js is outdated! Update with "npm install aoi.js@latest".', textColor: 'red' }], - 'white', - { text: 'AoiWarning', textColor: 'yellow' } - ); - } else if (isDevVersion) { - createCustomBoxedMessage( - [{ text: 'AoiWarning: You are currently on a development version.', textColor: 'yellow' }], - 'white', - { text: 'AoiWarning', textColor: 'yellow' } - ); - } - } catch (error) { - createCustomBoxedMessage( - [{ text: `AoiWarning: Failed to check for updates: ${error.message}`, textColor: 'white' }], - 'red', - { text: 'AoiWarning', textColor: 'yellow' } - ); + if (compareVersions(json.version, latestVersion) === false && json.version !== latestVersion) { + AoiError.createCustomBoxedMessage( + [ + { + text: 'aoi.js is outdated! Update with "npm install aoi.js@latest".', + textColor: "red", + }, + ], + "white", + { text: "AoiWarning", textColor: "yellow" } + ); + } else if (json.version.includes("dev") || compareVersions( json.version, latestVersion) === true) { + AoiError.createCustomBoxedMessage( + [ + { + text: "You are currently on a development version.", + textColor: "red", + }, + { + text: "This version may or may not contain unfinished features.", + textColor: "red", + }, + ], + "white", + { text: "AoiWarning ", textColor: "yellow" } + ); } + } catch (error) { + AoiError.createCustomBoxedMessage( + [ + { + text: `AoiWarning: Failed to check for updates: ${error.message}`, + textColor: "white", + }, + ], + "red", + { text: "AoiWarning", textColor: "yellow" } + ); + } }; diff --git a/src/utils/CustomBox.js b/src/utils/CustomBox.js deleted file mode 100644 index d5dd2b3b5..000000000 --- a/src/utils/CustomBox.js +++ /dev/null @@ -1,43 +0,0 @@ -const chalk = require('chalk'); - -function createCustomBoxedMessage( - messages, - borderColor = "yellow", - title = null -) { - if (!Array.isArray(messages)) { - messages = [messages]; - } - - const maxLength = title - ? Math.max(...messages.map((msg) => msg.text.length), title.text.length) - : Math.max(...messages.map((msg) => msg.text.length)); - - const topBorder = chalk[borderColor](`╭${"─".repeat(maxLength + 2)}╮`); - const bottomBorder = chalk[borderColor](`╰${"─".repeat(maxLength + 2)}╯`); - - console.log(topBorder); - - if (title) { - const titlePadding = " ".repeat((maxLength - title.text.length) / 2); - const titleText = `${chalk[borderColor]("│")} ${titlePadding}${chalk[ - title.textColor - ](title.text)}${titlePadding} ${chalk[borderColor]("│")}`; - console.log(titleText); - } - - messages.forEach((message, index) => { - const paddingLength = (maxLength - message.text.length) / 2; - const leftPadding = " ".repeat(Math.floor(paddingLength)); - const rightPadding = " ".repeat(Math.ceil(paddingLength)); - const textColor = message.textColor || "reset"; - const messageText = `${chalk[borderColor]("│")} ${leftPadding}${chalk[ - textColor - ](message.text)}${rightPadding} ${chalk[borderColor]("│")}`; - console.log(messageText); - }); - - console.log(bottomBorder); -} - -module.exports = createCustomBoxedMessage; diff --git a/src/utils/EventUtil.js b/src/utils/EventUtil.js index dad293d18..46222264c 100644 --- a/src/utils/EventUtil.js +++ b/src/utils/EventUtil.js @@ -1,22 +1,22 @@ -const BulkOptions = (d) => { +const BulkOptions = (d, sep) => { return { - messages: d.data.bulk.map((x) => x.content).join(" , "), - ids: d.data.bulk.map((x) => x.id).join(" , "), - createdTimestamp: d.data.bulk.map((x) => x.createdTimestamp).join(" , "), - createdAt: d.data.bulk.map((x) => x.createdAt).join(" , "), - userIds: d.data.bulk.map((x) => x.author.id).join(" , "), - usernames: d.data.bulk.map((x) => x.author.username).join(" , "), - userTags: d.data.bulk.map((x) => x.author.tag).join(" , "), - userMentions: d.data.bulk.map((x) => x.author.toString()).join(" , "), - guildId: d.data.bulk.first().guildId, + messages: d.data.bulk.map((x) => x.content).join(sep), + ids: d.data.bulk.map((x) => x.id).join(sep), + createdTimestamp: d.data.bulk.map((x) => x.createdTimestamp).join(sep), + createdAt: d.data.bulk.map((x) => x.createdAt).join(sep), + userIds: d.data.bulk.map((x) => x.author.id).join(sep), + usernames: d.data.bulk.map((x) => x.author.username).join(sep), + userTags: d.data.bulk.map((x) => x.author.tag).join(sep), + userMentions: d.data.bulk.map((x) => x.author.toString()).join(sep), + guildId: d.data.bulk.first().guild.id, guildName: d.data.bulk.first().guild.name, - channelID: d.data.bulk.first().channelID, + channelID: d.data.bulk.first().channel.id, channelName: d.data.bulk.first().channel.name, }; }; -const BulkData = (d, option) => { - return BulkOptions(d)[option]; +const BulkData = (d, sep, option) => { + return BulkOptions(d, sep)[option]; }; const PinData = (d) => {