diff --git a/LICENSE b/LICENSE index 6b88609..74c6bf4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,7 @@ -MIT License +# Custom License -Copyright (c) 2025 NextEra Development +This project is licensed under the following terms: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +1. **Personal Use Only**: This software is only usable for personal usages with your own hosting. +2. **Credit Requirement**: Visible credit to the original developers must be present somewhere visible at first sight. +3. **Commercial Use Prohibited**: Commercial usage is strictly prohibited. If found, the commercial use company or individual would be charged as theft. diff --git a/Owner/Status.js b/Owner/Status.js new file mode 100644 index 0000000..6c1362d --- /dev/null +++ b/Owner/Status.js @@ -0,0 +1,31 @@ +const { Client } = require("discord.js"); + +module.exports = { + data: { + name: "Owner", + description: "Change the status of Tiger Bot!", + options: [{ + name: "status", + description: "the new status of Tiger Bot!", + required: true, + type: 3, // Corrected type to STRING (3) + }], + }, + + /** + * + * @param {Client} client + * @param {*} interaction + * @returns + */ + run: async (client, interaction,args) => { + if (!client.owners.includes(interaction.user.id)) return interaction.reply({ content: `You are not a owner` }); + + client.user.setActivity({ + name: interaction.options.getString("status", true), + type: "PLAYING" + }); + + interaction.reply({ content: `Status changed to : ${interaction.options.getString("status")}` }); + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..be11a7e --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# Tiger Bot + +Tiger Bot is an advanced multipurpose Discord bot with slash commands. Originally developed in 2022, it has been recently reviewed and updated by NextEra Development. This project holds historical significance as it was the first project of NextEra Development. + +## Features + +- **Multipurpose Bot**: Supports a variety of commands and functionalities. +- **Slash Commands**: Utilizes Discord's slash commands for ease of use. +- **Giveaways**: Integrated with `discord-giveaways` for managing giveaways. +- **Games**: Includes fun games like fight and rock-paper-scissors. +- **Customizable**: Easily configurable to suit different server needs. + +## Installation + +1. Clone the repository: + ```sh + git clone https://github.com/yourusername/tiger-bot.git + cd tiger-bot + ``` + +2. Install dependencies: + ```sh + npm install + ``` + +3. Create a `.env` file in the root directory and add your configuration: + ```dotenv + TOKEN=your_discord_bot_token + MONGO_URI=your_mongodb_uri + CLIENT_ID=your_discord_client_id + OWNER_ID=your_discord_owner_id + ``` + +4. Start the bot: + ```sh + npm run dev + ``` + +## Configuration + +The bot uses environment variables for configuration. Ensure you have a `.env` file with the following variables: + +- `TOKEN`: Your Discord bot token. +- `MONGO_URI`: Your MongoDB connection string. +- `CLIENT_ID`: Your Discord client ID. +- `OWNER_ID`: Your Discord owner ID. + +## Contributing + +We welcome contributions! Please fork the repository and create a pull request with your changes. + +## License + +This project is licensed under a custom license. It is only usable for personal usages with your own hosting and with visible credit to us. Commercial usage is strictly prohibited. If found, the commercial use company or individual would be charged as theft. + +## Acknowledgements + +- Special thanks to the original developers and the NextEra Development team for their efforts in reviewing and updating this project. diff --git a/commands/Admin/menu.js b/commands/Admin/menu.js new file mode 100644 index 0000000..579e8bd --- /dev/null +++ b/commands/Admin/menu.js @@ -0,0 +1,215 @@ +const { SlashCommandBuilder, MessageActionRow, MessageButton } = require('discord.js'); +const menus = require('../../models/reactionRole'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('menu') + .setDescription('Manage guild reaction role') + .addSubcommand(subcommand => + subcommand + .setName('create') + .setDescription('Create a new role menu') + .addStringOption(option => + option + .setName('name') + .setDescription('Name of the role menu') + .setRequired(true))) + .addSubcommand(subcommand => + subcommand + .setName('delete') + .setDescription('Delete a role menu') + .addStringOption(option => + option + .setName('name') + .setDescription('Name of the role menu') + .setRequired(true))) + .addSubcommand(subcommand => + subcommand + .setName('start') + .setDescription('Start a new role menu') + .addStringOption(option => + option + .setName('name') + .setDescription('Name of the role menu') + .setRequired(true)) + .addChannelOption(option => + option + .setName('channel') + .setDescription('Mention the channel') + .setRequired(true))) + .addSubcommand(subcommand => + subcommand + .setName('add-role') + .setDescription('Add a role in a reaction role menu') + .addStringOption(option => + option + .setName('name') + .setDescription('Name of the role menu') + .setRequired(true)) + .addRoleOption(option => + option + .setName('role') + .setDescription('Mention the role') + .setRequired(true))) + .addSubcommand(subcommand => + subcommand + .setName('remove-role') + .setDescription('Remove a role from a reaction role menu') + .addStringOption(option => + option + .setName('name') + .setDescription('Name of the role menu') + .setRequired(true)) + .addRoleOption(option => + option + .setName('role') + .setDescription('Mention the role') + .setRequired(true))), + permissions: ["MANAGE_GUILD", "MANAGE_ROLES"], // Corrected permission name + + async execute(interaction) { + await interaction.reply({ content: `${interaction.client.user.username} is thinking...`, ephemeral: true }); + + const option = interaction.options.getSubcommand(true).toLowerCase(); + const name = interaction.options.getString("name")?.toLowerCase()?.trim(); + const menu = await menus.findOne({ name, guild: interaction.guildId }); + const my_role = interaction.guild.me.roles.highest.position; + const role = interaction.options.getRole("role"); + const channel = interaction.options.getChannel("channel"); + + switch (option) { + case "create": + await handleCreate(interaction, menu, name); + break; + case "delete": + await handleDelete(interaction, menu, name); + break; + case "start": + await handleStart(interaction, menu, channel); + break; + case "add-role": + await handleAddRole(interaction, menu, role, my_role); + break; + case "remove-role": + await handleRemoveRole(interaction, menu, role); + break; + default: + await interaction.editReply({ content: "Invalid subcommand" }); + } + } +}; + +async function handleCreate(interaction, menu, name) { + if (menu) { + return interaction.editReply({ content: `A Reaction Role menu already exists with that name. Please use a different name.` }); + } + + await menus.create({ guild: interaction.guildId, name, roles: [], message: "0" }); // Initialize roles as an empty array + interaction.editReply({ content: `Role menu created with name: \`${name}\`.` }); +} + +async function handleDelete(interaction, menu, name) { + if (!menu) { + return interaction.editReply({ content: `No Reaction Role menu exists with that name. Please provide a valid menu name.` }); + } + + await menus.findOneAndDelete({ guild: interaction.guildId, name }); + interaction.editReply({ content: `Role menu deleted with name: \`${name}\`.` }); +} + +async function handleStart(interaction, menu, channel) { + if (channel.type !== "GUILD_TEXT" && channel.type !== "GUILD_NEWS") { + return interaction.editReply({ content: "Invalid channel was provided" }); + } + if (!menu?.roles?.length) { + return interaction.editReply({ content: "This menu has 0 roles." }); + } + + const { content, rows } = createMenuContentAndButtons(interaction, menu); + + const msg = await channel.send({ content, components: rows }); + + await menus.findOneAndUpdate({ name: menu.name, guild: interaction.guildId }, { message: msg.id }); + + interaction.editReply({ content: "Menu started successfully" }); +} + +function createMenuContentAndButtons(interaction, menu) { + let content = `Reaction Menu : **${menu.name}**\n\nReact to get yourself a role\n\n`, + rows = [new MessageActionRow()], index; + + menu.roles.forEach((v, i) => { + content += `> ${interaction.guild.emojis.cache.get(v.emoji)?.toString() || v.emoji} : \`${interaction.guild.roles.cache.get(v.role).name}\`\n\n`; + + index = parseInt(i / 5); + const button = new MessageButton({ + customId: `reaction_role_${i}`, + style: "SECONDARY", + emoji: v.emoji, + }); + + rows[index] ? rows[index].addComponents(button) : rows[index] = new MessageActionRow().addComponents(button); + }); + + return { content, rows }; +} + +async function handleAddRole(interaction, menu, role, my_role) { + if (!menu) { + return interaction.editReply({ content: `Reaction Role menu does not exist with that name. Please provide a valid menu name.` }); + } + + if (role.position >= my_role) { + return interaction.editReply({ content: `The provided role is above my highest role. Please adjust the role hierarchy and try again.` }); + } + + const msg = await interaction.channel.send({ content: `React with the emoji you want for this role` }); + + const reactions = await msg.awaitReactions({ + errors: ["time"], + filter: (r, u) => u.id === interaction.user.id, + max: 1, + time: 300000 + }).catch(e => { }); + + const emoji = reactions.first()?.emoji; + + if (!emoji) { + return interaction.editReply({ content: "You took too much time to respond" }); + } + + if (isRoleOrEmojiInMenu(menu, role, emoji)) { + return interaction.editReply({ content: `Reaction Role menu already has either the provided role or the emoji` }); + } + + menu.roles.push({ role: role.id, emoji: emoji.id || emoji.name }); + + await menus.findOneAndUpdate({ name, guild: interaction.guildId }, { roles: menu.roles }); + + interaction.editReply({ content: `Added role \`${role.name}\` with emoji: ${emoji.toString()} for menu: \`${menu.name}\`` }); + await msg.delete(); +} + +async function handleRemoveRole(interaction, menu, role) { + if (!menu) { + return interaction.editReply({ content: `Reaction Role menu does not exist with that name. Please provide a valid menu name.` }); + } + + if (!isRoleInMenu(menu, role)) { + return interaction.editReply({ content: `Reaction Role menu does not have this role as part of it` }); + } + + menu.roles = menu.roles.filter((v) => v.role !== role.id); + + await menus.findOneAndUpdate({ name, guild: interaction.guildId }, { roles: menu.roles }); + + interaction.editReply({ content: `Removed role \`${role.name}\` from menu: \`${menu.name}\`` }); +} + +function isRoleOrEmojiInMenu(menu, role, emoji) { + return menu.roles.some(v => v.role === role.id) || menu.roles.some(v => v.emoji === emoji.id || v.emoji === emoji.name); +} + +function isRoleInMenu(menu, role) { + return menu.roles.some(v => v.role === role.id); +} diff --git a/commands/Admin/pokemon.js b/commands/Admin/pokemon.js new file mode 100644 index 0000000..358ffe3 --- /dev/null +++ b/commands/Admin/pokemon.js @@ -0,0 +1,106 @@ +const { SlashCommandBuilder } = require('discord.js'); +const guildConfig = require('../../models/guildConfig'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('pokemon') + .setDescription('Setup the pokemon game for your server') + .addSubcommand(subcommand => + subcommand + .setName('enable-spawn') + .setDescription('Enable the slash commands')) + .addSubcommand(subcommand => + subcommand + .setName('disable-spawn') + .setDescription('Disable the slash commands')) + .addSubcommand(subcommand => + subcommand + .setName('spawn-after') + .setDescription('Random pokemon spawning points') + .addIntegerOption(option => + option + .setName('number') + .setDescription('Number of points') + .setRequired(true))) + .addSubcommand(subcommand => + subcommand + .setName('spawn-channel') + .setDescription('Set the random pokemon spawn\'s channel') + .addStringOption(option => + option + .setName('channel') + .setDescription('Mention or give ID, 0 for same channel spawn') + .setRequired(true))), + permissions: ["MANAGE_SERVER"], + + async execute(interaction) { + await interaction.deferReply(); + const data = await guildConfig.findOne({ id: interaction.guildId }) || await guildConfig.create({ id: interaction.guildId }); + const command = interaction.options.getSubcommand(); + + switch (command) { + case "enable-spawn": + await this.enableSpawn(interaction, data); + break; + case "disable-spawn": + await this.disableSpawn(interaction, data); + break; + case "spawn-after": + await this.spawnAfter(interaction); + break; + case "spawn-channel": + await this.spawnChannel(interaction); + break; + } + }, + + async enableSpawn(interaction, data) { + if (data.pokemon.spawn) { + return interaction.editReply({ content: `The pokemon spawning is already enabled` }); + } + + await guildConfig.findOneAndUpdate({ id: interaction.guildId }, { "pokemon.spawn": true }); + interaction.editReply({ content: "Enabled pokemon spawning" }); + }, + + async disableSpawn(interaction, data) { + if (!data.pokemon.spawn) { + return interaction.editReply({ content: `The pokemon spawning is already disabled` }); + } + + await guildConfig.findOneAndUpdate({ id: interaction.guildId }, { "pokemon.spawn": false }); + interaction.editReply({ content: "Disabled pokemon spawning" }); + }, + + async spawnAfter(interaction) { + const points = interaction.options.getInteger("number"); + + if (points < 10) { + return interaction.editReply({ content: "The points can't be below 10" }); + } + + await guildConfig.findOneAndUpdate({ id: interaction.guildId }, { "pokemon.afterPoints": points }); + interaction.editReply({ content: `Pokemon spawning required points are now set to ${points}` }); + }, + + async spawnChannel(interaction) { + const raw = interaction.options.getString("channel"); + const channel = getChannel(raw, interaction); + + if (!isValidChannel(channel)) { + return interaction.editReply("Invalid channel was provided, either type 0 for same channel, or mention / give id of a text channel"); + } + + await guildConfig.findOneAndUpdate({ id: interaction.guildId }, { "pokemon.spawnAt": channel === "0" ? "0" : channel.id }); + interaction.editReply({ content: `${channel === "0" ? "Set the pokemon spawning to the same channel where the latest message was sent" : `Now pokemons will spawn in <#${channel.id}>`}` }); + } +}; + +// Helper functions +function isValidChannel(channel) { + return channel && (channel.type === "GUILD_TEXT" || channel.type === "GUILD_NEWS"); +} + +function getChannel(raw, interaction) { + return raw === "0" ? raw : interaction.guild.channels.cache.get(raw) || interaction.guild.channels.cache.get(raw.substring(2, raw.length - 1)); +} diff --git a/commands/Admin/polls.js b/commands/Admin/polls.js new file mode 100644 index 0000000..f4a8d29 --- /dev/null +++ b/commands/Admin/polls.js @@ -0,0 +1,240 @@ +const { find } = require('node-emoji'); +const polls = require("../../models/polls") +const { MessageButton, MessageActionRow } = require('discord.js'); + +module.exports = { + data: { + name: "poll", + description: "Manage polls of your server", + options: [{ + name: "create", + type: 1, + description: "Create a poll", + options: [{ + name: "question", + type: 3, + required: true, + description: "The question of the poll" + }, { + name: "channel", + type: 7, + required: true, + description: "The channel where you want create the poll" + }, { + name: "options", + type: 3, + required: true, + description: "The choices of this poll, seprate them by |", + }, { + name: "custom-emojis", + type: 3, + required: false, + description: "Custom emojis for the chocies, seprate them by |" + }] + }, { + name: "end", + type: 1, + description: "End a poll", + options: [{ + name: "id", + type: 3, + required: true, + description: "Message ID of the poll" + }] + }], + }, + timeout: 5000, + permissions: ["MANAGE_GUILD"], + + run: async (client, interaction) => { + await interaction.deferReply(); + + const option = interaction.options.getSubcommand(); + const channel = interaction.options.getChannel("channel"); + const rawOptions = interaction.options.getString("options"); + const cEmojis = interaction.options.getString("custom-emojis") || ""; + const id = interaction.options.getString("id"); + const question = interaction.options.getString("question"); + const poll = await polls.findOne({ message: id }); + + if (option === "create") { + await handleCreatePoll({ client, interaction, channel, rawOptions, cEmojis, question }); + } else if (option === "end") { + await handleEndPoll(interaction, poll, id); + } + } +} + +async function handleCreatePoll(params) { + const { client, interaction, channel, rawOptions, cEmojis, question } = params; + let _emoji = ["🇦", "🇧", "🇨", "🇩", "🇪", "🇫", "🇬", "🇭", "🇮", "🇯", "🇰", "🇱", "🇲", "🇳", "🇴", "🇵", "🇶", "🇷", "🇸", "🇹", "🇺", "🇻", "🇼", "🇽", "🇾", "🇿"]; + let emojis = []; + + const options = parseOptions(rawOptions, cEmojis); + if (!validateOptions(options.rawOptions)) { + return sendInvalidOptionsReply(interaction); + } + + const rows = createMessageActionRows({ client, rawOptions: options.rawOptions, cEmojis: options.cEmojis, _emoji, emojis }); + + try { + const v = await sendPollMessage({ channel, question, rawOptions: options.rawOptions, cEmojis: options.cEmojis, rows }); + await savePollToDatabase({ question, messageId: v.id, channelId: channel.id, guildId: interaction.guildId, emojis }); + sendPollCreatedReply(interaction, v.url); + } catch (e) { + sendPollCreationErrorReply(interaction); + } +} + +function parseOptions(rawOptions, cEmojis) { + return { + rawOptions: rawOptions.split("|"), + cEmojis: cEmojis?.trim()?.replace(/ +/g, "")?.split("|") + }; +} + +function validateOptions(rawOptions) { + return rawOptions.length >= 2 && rawOptions.length <= 25; +} + +function sendInvalidOptionsReply(interaction) { + return interaction.editReply({ + embeds: [{ + color: "RED", + title: "❌ Invalid Options", + description: "You need at least 2 options and a maximum of 25 options, You need to separate options via `|`" + }] + }); +} + +function createMessageActionRows({ client, rawOptions, cEmojis, _emoji, emojis }) { + const rows = [new MessageActionRow()]; + for (let i = 0; i < rawOptions.length; i++) { + let ind = Math.floor(i / 5); + emojis.push(fixEmoji(client, cEmojis[i]) || _emoji[i]); + + const button = new MessageButton({ + customId: emojis[i], + emoji: emojis[i], + label: "0", + style: "SECONDARY" + }); + + rows[ind] ? rows[ind].addComponents(button) : rows[ind] = new MessageActionRow({ + components: [button] + }); + } + return rows; +} + +async function sendPollMessage({ channel, question, rawOptions, cEmojis, rows }) { + return await channel.send({ + embeds: [{ + color: "BLUE", + title: question.slice(0, 256), + description: rawOptions.map((v, i) => `${cEmojis[i] || emojis[i]} ${v}`).join("\n"), + timestamp: Date.now(), + footer: { + text: `Poll Started At` + } + }], + components: rows + }); +} + +async function savePollToDatabase({ question, messageId, channelId, guildId, emojis }) { + await polls.create({ + question, + message: messageId, + channel: channelId, + guild: guildId, + votes: {}, + voters: [], + emojis + }); +} + +function sendPollCreatedReply(interaction, url) { + interaction.editReply({ + embeds: [{ + color: "GREEN", + title: "✅ Poll Created", + description: `Check the poll [here](${url})` + }] + }); +} + +function sendPollCreationErrorReply(interaction) { + interaction.editReply({ + embeds: [{ + color: "RED", + title: "❌ Unable To Create The Poll", + }] + }); +} + +async function handleEndPoll(interaction, poll, id) { + if (!poll) { + return interaction.editReply({ + embeds: [{ + color: "RED", + title: "❌ Invalid Poll Message ID", + }] + }); + } + + if (poll.ended) { + return interaction.editReply({ + embeds: [{ + color: "RED", + title: "❌ Poll is already Ended", + }] + }); + } + + const msg = await interaction.guild.channels.cache.get(poll.channel).messages.fetch(id); + + if (!msg) { + return interaction.editReply({ + embeds: [{ + color: "RED", + title: "❌ Poll Not Endable", + description: `Poll message is deleted, So it is no longer endable` + }] + }); + } + + const opt = msg.embeds[0].description?.split("\n"); + const x = Object.entries(poll.votes)?.sort((a, b) => b[1] - a[1]); + let winner = opt.filter(v => v.includes(x[0][0])); + + interaction.editReply({ + embeds: [{ + color: "GREEN", + title: "Poll Ended" + }] + }); + + msg.edit({ + components: [], + embeds: [{ + title: msg.embeds[0].title, + color: "RED", + description: `**Poll ended**\nThe most voted option got ${x[0][1]} votes and it was:\n${winner}`, + timestamp: Date.now(), + footer: { + text: `Poll Ended At` + } + }] + }); + + await polls.findOneAndUpdate({ message: id }, { ended: true }); +} + +function fixEmoji(client, emj = "") { + const e = find(emj)?.emoji; + const e2 = client.emojis.cache.find(v => v.toString() === emj); + + return e2?.id || e; +} + diff --git a/commands/Admin/stats.js b/commands/Admin/stats.js new file mode 100644 index 0000000..f810aa8 --- /dev/null +++ b/commands/Admin/stats.js @@ -0,0 +1,35 @@ +const { SlashCommandBuilder } = require('discord.js'); +const stats = require('../../models/guildStats'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('stats') + .setDescription('Configure the stats for your server') + .addStringOption(option => + option.setName('type') + .setDescription('What kind of stats you want to setup') + .setRequired(true) + .addChoices( + { name: 'members-stats', value: 'members' }, + { name: 'server-stats', value: 'server' } + )) + .addChannelOption(option => + option.setName('channel') + .setDescription('The voice channel in which you wanna show the stats') + .setRequired(false)), + + async execute(interaction) { + await interaction.deferReply(); + const channel = interaction.options.getChannel('channel') || await interaction.guild.channels.create(`Members : ${interaction.guild.memberCount}`, { + reason: 'for stats', + type: 'GUILD_VOICE' + }); + + const newData = { guild: interaction.guildId }; + newData[interaction.options.getString('type')] = channel.id; + + const data = await stats.findOneAndUpdate({ guild: interaction.guildId }, newData, { new: true }) || await stats.create(newData); + + await interaction.editReply({ content: `Added stats for ${interaction.options.getString('type')}` }); + }, +}; diff --git a/commands/Admin/ticket.js b/commands/Admin/ticket.js new file mode 100644 index 0000000..525c5bb --- /dev/null +++ b/commands/Admin/ticket.js @@ -0,0 +1,392 @@ +const tickets = require('../../models/tickets'); +const ticket = require('../../models/ticket'); +const { MessageEmbed, MessageActionRow, MessageButton, CommandInteraction } = require('discord.js'); + +module.exports = { + data: { + name: "ticket", + description: "Configure your server's tickets / panels", + options: [{ + name: "create", + type: 1, + description: "Create a ticket panel", + options: [{ + name: "panel-name", + description: "The name of the panel you want to create", + type: 3, + required: true + }] + }, { + name: "remove", + type: 1, + description: "Remove a ticket panel", + options: [{ + name: "panel-name", + description: "The name of the panel you want to remove", + type: 3, + required: true + }] + }, { + name: "start", + type: 1, + description: "Start a ticket panel", + options: [{ + name: "panel-name", + description: "The name of the panel you want to start", + type: 3, + required: true + }, { + name: "channel", + description: "The channel where you want to start the panel", + required: true, + type: 7 + }] + }, { + name: "close", + type: 1, + description: "Close an open ticket for your discord server", + }, { + name: "re-open", + type: 1, + description: "Re-open a closed ticket for your discord server", + }, { + name: "delete", + type: 1, + description: "Delete a ticket for your discord server", + }, { + name: "logs-disable", + type: 1, + description: "Disable ticket logs for your server", + options: [{ + name: "panel-name", + description: "The name of the panel", + type: 3, + required: true + }] + }, { + name: "logs-enable", + type: 1, + description: "Enable ticket logs for your server", + options: [{ + name: "panel-name", + description: "The name of the panel", + type: 3, + required: true + }, { + name: "channel", + type: 7, + description: "Channel to send ticket logs for your server", + required: true + }] + }, { + name: "moderator-add", + type: 1, + description: "Add a moderator role for your server's ticket panel", + options: [{ + name: "panel-name", + description: "The name of the panel", + type: 3, + required: true + }, { + name: "role", + type: 8, + description: "The role to add as a moderator", + required: true + }] + }, { + name: "moderator-remove", + type: 1, + description: "Remove a moderator role for your server's ticket panel", + options: [{ + name: "panel-name", + description: "The name of the panel", + type: 3, + required: true + }, { + name: "role", + type: 8, + description: "The role to remove from moderator role", + required: true + }] + }, { + name: "banned-add", + type: 1, + description: "Add a banned role for your server's ticket panel", + options: [{ + name: "panel-name", + description: "The name of the panel", + type: 3, + required: true + }, { + name: "role", + type: 8, + description: "The role to add as a banned", + required: true + }] + }, { + name: "banned-remove", + type: 1, + description: "Remove a banned role for your server's ticket panel", + options: [{ + name: "panel-name", + description: "The name of the panel", + type: 3, + required: true + }, { + name: "role", + type: 8, + description: "The role to remove from banned role", + required: true + }] + }, { + name: "max-ticket", + type: 1, + description: "Set maximum number of tickets a user can create in a panel", + options: [{ + name: "panel-name", + description: "The name of the panel", + type: 3, + required: true + }, { + name: "limit", + type: 4, + description: "The number of tickets a user can create", + required: true + }] + }] + }, + permissions: ["MANAGE_SERVER"], + + /** + * + * @param {*} client + * @param {CommandInteraction} interaction + * @returns + */ + run: async (client, interaction) => { + await interaction.deferReply(); + const command = interaction.options.getSubcommand(); + const commandHandlers = { + 'create': createPanel, + 'remove': removePanel, + 'start': startPanel, + 'close': closeTicket, + 're-open': reopenTicket, + 'delete': deleteTicket, + 'logs-disable': disableLogs, + 'logs-enable': enableLogs, + 'moderator-add': addModerator, + 'moderator-remove': removeModerator, + 'banned-add': addBanned, + 'banned-remove': removeBanned, + 'max-ticket': setMaxTicket + }; + + if (commandHandlers[command]) { + await commandHandlers[command](interaction); + } else { + await interaction.editReply({ content: 'Unknown command' }); + } + } +} + +async function createPanel(interaction) { + const name = interaction.options.getString('panel-name'); + const data = await tickets.findOne({ guild: interaction.guildId, name }); + if (data) { + return interaction.editReply({ content: `You already have a panel with name \`${name}\`` }); + } + await tickets.create({ name, guild: interaction.guildId }); + interaction.editReply({ content: `I created a panel with name \`${name}\`` }); +} + +async function removePanel(interaction) { + const name = interaction.options.getString('panel-name'); + const data = await tickets.findOne({ guild: interaction.guildId, name }); + if (!data) { + return interaction.editReply({ content: `You do not have a panel with name \`${name}\`` }); + } + await tickets.findOneAndDelete({ name, guild: interaction.guildId }); + interaction.editReply({ content: `I deleted the panel with name \`${name}\`` }); +} + +async function startPanel(interaction) { + const name = interaction.options.getString('panel-name'); + const channel = interaction.options.getChannel('channel'); + const data = await tickets.findOne({ guild: interaction.guildId, name }); + if (!data) { + return interaction.editReply({ content: `You do not have a panel with name \`${name}\`` }); + } + if (channel.type !== "GUILD_TEXT") { + return interaction.editReply({ content: "Channel should be a text channel" }); + } + + const embed = new MessageEmbed().setTitle(`Panel : ${name}`).setDescription("Click on to create a ticket").setColor('#353A3C'); + const row = new MessageActionRow().addComponents(new MessageButton().setCustomId("ticket_button").setLabel("Create Ticket").setEmoji("962175422567702578").setStyle("PRIMARY")); + + channel.send({ embeds: [embed], components: [row] }).then(async v => { + await tickets.findOneAndUpdate({ guild: interaction.guildId, name }, { message: v.id }); + interaction.editReply({ content: `Successfully started the panel with name : \`${name}\` in ${channel.toString()}` }); + }).catch(e => { + interaction.editReply({ content: `Unable to send the message in ${channel.toString()}` }); + }); +} + +async function handleTicketOperation(interaction, operation) { + const ticketData = await ticket.findOne({ guild: interaction.guildId, channel: interaction.channel.id }); + const data = await tickets.findOne({ guild: interaction.guildId, name: ticketData?.panel }); + const member = interaction.guild.members.cache.get(ticketData?.user); + + if (!ticketData || !ticketData.panel) { + return interaction.editReply({ content: "This is not a ticket channel." }); + } + + await operation(interaction, ticketData, data, member); +} + +async function closeTicket(interaction) { + await handleTicketOperation(interaction, async (interaction, ticketData, data, member) => { + if (ticketData.closed) { + return interaction.editReply({ content: "This ticket is already closed" }); + } + + await updateTicketStatus({ interaction, member, viewChannel: false, sendMessages: true, logTitle: "Ticket closed", replyMessage: "This ticket is now closed" }); + }); +} + +async function reopenTicket(interaction) { + await handleTicketOperation(interaction, async (interaction, ticketData, data, member) => { + if (!ticketData.closed) { + return interaction.editReply({ content: "This ticket is not closed" }); + } + + await updateTicketStatus({ interaction, member, viewChannel: true, sendMessages: false, logTitle: "Ticket re-opened", replyMessage: "This ticket is now re-opened" }); + }); +} + +async function deleteTicket(interaction) { + await handleTicketOperation(interaction, async (interaction, ticketData, data, member) => { + interaction.editReply({ content: "This ticket is closed and channel will be deleted in few seconds" }); + await ticket.findOneAndDelete({ channel: interaction.channel.id }); + await new Promise(res => setTimeout(res, 2000)); + + interaction.channel.delete().catch(e => { + interaction.editReply({ content: "Ticket was deleted from database but I was unable to delete this channel" }); + }); + + interaction.guild.channels.cache.get(data.logs)?.send({ + embeds: [{ + title: "Ticket deleted", + timestamps: Date.now(), + fields: [ + { name: "Panel", value: data.name, inline: true }, + { name: "User", value: member.user.username, inline: true }, + { name: "Ticket", value: interaction.channel.toString(), inline: true }, + { name: "\u200b", value: "\u200b", inline: true }, + { name: "Moderator", value: interaction.user.username, inline: true } + ] + }] + }); + }); +} + +async function handleLogOperation(interaction, operation) { + const name = interaction.options.getString('panel-name'); + const data = await tickets.findOne({ guild: interaction.guildId, name }); + if (!data) { + return interaction.editReply({ content: `You do not have a panel with name \`${name}\`` }); + } + + await operation(interaction, data); +} + +async function disableLogs(interaction) { + await handleLogOperation(interaction, async (interaction, data) => { + await tickets.findOneAndUpdate({ guild: interaction.guildId, name: data.name }, { logs: "0" }); + interaction.editReply({ content: "Successfully disabled Ticket logs for this server." }); + }); +} + +async function enableLogs(interaction) { + await handleLogOperation(interaction, async (interaction, data) => { + const channel = interaction.options.getChannel('channel'); + if (channel.type !== "GUILD_TEXT") { + return interaction.editReply({ content: "Channel should be a text channel" }); + } + await tickets.findOneAndUpdate({ guild: interaction.guildId, name: data.name }, { logs: channel.id }); + interaction.editReply({ content: "Successfully enabled Ticket logs for this server in " + channel.toString() }); + }); +} + +async function addModerator(interaction) { + await handleRoleOperation(interaction, 'moderators', 'add', `Successfully added **${role.name}** as a moderator role in the panel \`${data.name}\``); +} + +async function removeModerator(interaction) { + await handleRoleOperation(interaction, 'moderators', 'remove', `Successfully removed **${role.name}** from moderator roles in the panel \`${data.name}\``); +} + +async function addBanned(interaction) { + await handleRoleOperation(interaction, 'banned', 'add', `Successfully added **${role.name}** as a banned role in the panel \`${data.name}\``); +} + +async function removeBanned(interaction) { + await handleRoleOperation(interaction, 'banned', 'remove', `Successfully removed **${role.name}** from banned roles in the panel \`${data.name}\``); +} + +async function setMaxTicket(interaction) { + const name = interaction.options.getString('panel-name'); + const limit = interaction.options.getInteger('limit'); + const data = await tickets.findOne({ guild: interaction.guildId, name }); + if (!data) { + return interaction.editReply({ content: `You do not have a panel with name \`${name}\`` }); + } + if (limit < 1 || limit > 1000) { + return interaction.editReply({ content: "The maximum ticket limit can't be less than 1 or greater than 1000" }); + } + await tickets.findOneAndUpdate({ guild: interaction.guildId, name }, { max: limit }); + interaction.editReply({ content: `Successfully set maximum ticket limit to **${limit}** in the panel \`${data.name}\`` }); +} + +async function updateTicketStatus({ interaction, member, viewChannel, sendMessages, logTitle, replyMessage }) { + interaction.channel.permissionOverwrites.create(member, { + VIEW_CHANNEL: viewChannel, + SEND_MESSAGES: sendMessages, + }); + + await ticket.findOneAndUpdate({ channel: interaction.channel.id }, { closed: !viewChannel }); + interaction.editReply({ content: replyMessage }); + + interaction.guild.channels.cache.get(data.logs)?.send({ + embeds: [{ + title: logTitle, + timestamps: Date.now(), + fields: [ + { name: "Panel", value: data.name, inline: true }, + { name: "User", value: member.user.username, inline: true }, + { name: "Ticket", value: interaction.channel.toString(), inline: true }, + { name: "\u200b", value: "\u200b", inline: true }, + { name: "Moderator", value: interaction.user.username, inline: true } + ] + }] + }); +} + +async function handleRoleOperation(interaction, roleType, operation, successMessage) { + const name = interaction.options.getString('panel-name'); + const role = interaction.options.getRole('role'); + const data = await tickets.findOne({ guild: interaction.guildId, name }); + if (!data) { + return interaction.editReply({ content: `You do not have a panel with name \`${name}\`` }); + } + const roleList = data[roleType] || []; + if (operation === 'add' && roleList.includes(role.id)) { + return interaction.editReply({ content: `This role is already a ${roleType.slice(0, -1)} role in the panel \`${data.name}\`` }); + } + if (operation === 'remove' && !roleList.includes(role.id)) { + return interaction.editReply({ content: `This role is not a ${roleType.slice(0, -1)} role in the panel \`${data.name}\`` }); + } + const update = operation === 'add' ? { $push: { [roleType]: role.id } } : { $pull: { [roleType]: { $in: role.id } } }; + await tickets.findOneAndUpdate({ guild: interaction.guildId, name }, update); + interaction.editReply({ content: successMessage }); +} diff --git a/commands/Fun/fight.js b/commands/Fun/fight.js new file mode 100644 index 0000000..3b5348f --- /dev/null +++ b/commands/Fun/fight.js @@ -0,0 +1,48 @@ +const fight = require('discord-fight-game'); + +module.exports = { + data: { + name: "fight", + description: "Fight someone", + options: [{ + name: "user", + description: "Mention a user", + required: false, + type: 6, // Corrected type to USER (6) + }], + }, + + run: async (client, interaction) => { + const game = new fight(client, { + oneEmoji: "", + oneName: "Sword", + twoEmoji: " ", + twoName: "Bow", + threeEmoji: " ", + threeName: "Shield", + endEmoji: " ", + endName: "run away", + + // Custom Messages + startMessage: "The war has begun, get ready warriors", + midMessage: "The fighters chose their move, Current battle condition :", + endMessage: "{winner} gloriously defeated {looser}", + forceEndMessage: "{user} was scared so they ended the war", + timeEndMessage: "{user} ran away from the war", + + // Custom Game LOgic + startHealth: 69, + }); + + interaction.reply({ content: `The game is started` }); + + const user = interaction.options.getUser("user"); + + interaction.author = interaction.user; + + if (user && user.bot) return interaction.editReply({ content: "You can not play the game with bots" }) + + if (!user) game.solo(interaction) + else game.duo(interaction, user); + } +} diff --git a/commands/Fun/pokemons.js b/commands/Fun/pokemons.js new file mode 100644 index 0000000..340e829 --- /dev/null +++ b/commands/Fun/pokemons.js @@ -0,0 +1,35 @@ +const userConfig = require('../../models/userConfig'); +const pokecord = require('pokecord'); + +module.exports = { + data: { + name: "pokemons", + description: "Get list of pokemons your pokemons or someone else's", + options: [{ + name: "user", + description: "Mention a user to get their pokemons", + required: false, + type: 6, + }], + }, + + run: async (client, interaction) => { + await interaction.deferReply(); + + const user = interaction.options.getUser("user") || interaction.user; + const data = await userConfig.findOne({ user: user.id }) || await userConfig.create({ user: user.id }); + let pokemons = "ID\tPokemon"; + + for (let i = 0; i < data.pokemons.length; i++) { + const v = data.pokemons[i]; + pokemons += `${i}. ${(await pokecord.Spawn(v)).name}\n` + } + + interaction.editReply({ + embeds: [{ + title: `${user.username}'s Pokemon's`, + description: pokemons + }] + }) + } +} \ No newline at end of file diff --git a/commands/Fun/ptrade.js b/commands/Fun/ptrade.js new file mode 100644 index 0000000..14d3c03 --- /dev/null +++ b/commands/Fun/ptrade.js @@ -0,0 +1,157 @@ +const userConfig = require('../../models/userConfig'); +const pokecord = require('pokecord'); +const { ReactionCollector, MessageCollector } = require('discord.js'); + +module.exports = { + data: { + name: "trade", + description: "Trade your pokemons", + options: [{ + name: "user", + description: "Mention a user to trade with", + required: true, + type: 6, + }, { + name: "item", + description: "The item you want to trade, type -1 for nothing", + required: true, + type: 4, + }], + }, + + run: async (client, interaction) => { + await interaction.reply("Fetching the details"); + + const u1_data = await userConfig.findOne({ user: interaction.user.id }) || await userConfig.create({ user: interaction.user.id }), + user = interaction.options.getUser("user"), + u2_data = await userConfig.findOne({ user: user.id }) || await userConfig.create({ user: user.id }), + P1_id = interaction.options.getInteger("item"); + + if (user.id === interaction.user.id || user.bot) return interaction.editReply("you can't trae with yourself or with a bot"); + + if (P1_id !== -1 && !u1_data.pokemons[P1_id]) return interaction.editReply(`❌ Invalid Pokemon ID was provided`); + + let P1 = P1_id === -1 ? -1 : await pokecord.Spawn(u1_data.pokemons[P1_id]), P2, P2_id; + + const msg = await interaction.channel.send({ + embeds: [{ + title: "Trade Offer", + description: `Hello ${user.username}, ${interaction.user.username} gave you a trade offer for a **${P1 === -1 ? "nothing" : P1.name}**, react with ✅ for continuing the trade or react with ❌ for rejecting the trade offer` + }], + content: `${user.toString()}` + }); + + await msg.react("✅"); + await msg.react("❌"); + + const c = new ReactionCollector(msg, { time: 30000, filter: (r, u) => ["✅", "❌"].includes(r.emoji.name) && u.id === user.id }); + + c.on('collect', (rec) => c.stop(rec.emoji.name)); + + c.on('end', (shit, reason) => { + if (reason === "time") { + interaction.followUp("The mentioned user ignored the trade offer"); + msg.edit({ + embeds: [{ + title: "Trade Offer Expired", + color: "#ff0000", + descrption: `Trade offer from ${interaction.user.username} is expired` + }] + }) + } else if (reason === "❌") { + interaction.followUp("The mentioned user denied ❌ the trade offer"); + + msg.edit({ + embeds: [{ + title: "Trade Offer Declined Successfully", + descrption: `Trade offer from ${interaction.user.username} is declined` + }] + }) + } else { + msg.edit({ + embeds: [{ + title: "Trade Offer Accepted Successfully", + description: `${user.toString()}, Now give the pokemon ID you want to trade or type \`-1\` for \`nothing\` or type \`cancel\` to cancel the trade` + }], + }); + + const col = new MessageCollector(msg.channel, { time: 120000, filter: (m) => m.author.id === user.id }); + + col.on('collect', async (msg) => { + if (msg.content.toLowerCase() === "cancel") return col.stop("cancel"); + + P2_id = parseInt(msg.content); + if (isNaN(P2_id) || (!u2_data.pokemons[P2_id] && P2_id !== -1)) return msg.reply("Invalid pokemon ID was provided, provide a valid ID, or -1 for nothing or type `cancel` to cancel the trade"); + P2 = P2_id=== -1 ? -1 : await pokecord.Spawn(u2_data.pokemons[msg.content]); + + col.stop("done"); + }); + + col.on('end', async (shit, reason) => { + if (reason === "time") { + interaction.followUp("The mentioned user took way too much time to respond so the trade is expired"); + + msg.edit({ + embeds: [{ + title: "Trade Offer Expired", + color: "#ff0000", + descrption: `You took way too much time to respond` + }] + }) + } else if (reason === "cancel") { + interaction.followUp("The mentioned user denied ❌ the trade offer"); + + msg.edit({ + embeds: [{ + title: "Trade Offer Declined Successfully", + descrption: `Trade offer from ${interaction.user.username} is declined` + }] + }) + } else { + const msg = await interaction.followUp(`The mentioned user offered ${P2 === -1 ? "nothing" : P2.name}, do you want to confirm the trade, if yes react with ✅ else react with ❌`); + await msg.react("✅") + await msg.react("❌") + + const c = new ReactionCollector(msg, { time: 30000, filter: (r, u) => ["✅", "❌"].includes(r.emoji.name) && u.id === interaction.user.id }); + c.on('collect', (rec) => c.stop(rec.emoji.name)); + + c.on('end', async (rec) => { + if (reason === "time") { + interaction.followUp("You took way too much time to respond so the trade is expired"); + } else if (reason === "❌") { + msg.edit({ + embeds: [{ + title: "Trade Offer was Declined", + descrption: `Trade offer was declined by ${interaction.user.username}` + }] + }) + } else { + if (P1 !== -1) { + u1_data.pokemons = u1_data.pokemons.filter((v, i) => i !== P1_id); + u2_data.pokemons.push(P1.id) + } + if (P2 !== -1) { + u2_data.pokemons = u2_data.pokemons.filter((v, i) => i !== P2_id); + u1_data.pokemons.push(P2.id) + } + + msg.channel.send({ + embeds: [{ + title: "Trade Ended Successfully", + descrption: ` + ${interaction.user.username} got ${P2 === -1 ? "Nothing" : P2.name},\n + ${user.username} got ${P1 === -1 ? "Nothing" : P1.name}, + ` + }] + }) + + await userConfig.findOneAndUpdate({ user: interaction.user.id }, { pokemons: u1_data.pokemons }); + await userConfig.findOneAndUpdate({ user: user.id }, { pokemons: u2_data.pokemons }); + } + }) + } + }) + } + }) + } +} \ No newline at end of file diff --git a/commands/Fun/rps.js b/commands/Fun/rps.js new file mode 100644 index 0000000..bd99ba9 --- /dev/null +++ b/commands/Fun/rps.js @@ -0,0 +1,39 @@ +const rps = require('discord-rock-paper-scissor'); +const game = new rps({ choiceReply: "You chose {move}", + endTitle: "Game ended very very victoriously for {winner}", + readyMessage: "Choose the dang moves kiddos", + drawEndTitle: "Bruh nerds ended up getting a draw", +choiceTitle: "Choose the move boiiiiiiiiiiiiiiiii", + choiceDescription: "I hope that you can read than click on buttons to choose the move", + drawEndDescription: "{player1} chose : {player1move}\n\n{player2} chose : {player2move}\nStupid nerds arent they", + endDescription: "[Winner 👑] {winner}'s move : {winnermove}\n\n[Looser 🤮] {looser}'s move : {loosermove}", + chooseIn: "channel", + + colors: { + drawEmbed: "#0505e7", + endEmbed: "#1ae705", + errorEmbed: "#e70580", +readyEmbed: "#05b0e7" } }); + +module.exports = { + data: { + name: "rock-paper-scissor", + description: "Play rock paper scissor game", + options: [{ + name: "user", + description: "Mention a user", + required: false, + type: 6, // Corrected type to USER (6) + }], + }, + + run: async (client, interaction) => { + interaction.reply({ content: `The game is started` }); + const user = interaction.options.getUser("user"); + + if (user && user.bot) return interaction.editReply({ content: "You can not play the game with bots" }) + + if (!user) game.solo(interaction, client) + else game.duo(interaction, user); + } +} diff --git a/commands/General /avatar.js b/commands/General /avatar.js new file mode 100644 index 0000000..9a0461c --- /dev/null +++ b/commands/General /avatar.js @@ -0,0 +1,49 @@ + + const { MessageAttachment, TextChannel, MessageEmbed, MessageActionRow, MessageButton } = require('discord.js'); + +module.exports = { + data: { + name: "avatar", + description: "Check your or users avatar", + options: [{ + name: "user", + description: "Mention a user", + required: false, + type: 6, + }], + }, + + run: async (client, interaction) => { + + const user = interaction.options.getUser("user") || interaction.user; + const AvatarButtons = new MessageActionRow() + .addComponents( + new MessageButton() + .setLabel('PNG') + .setURL(interaction.user.displayAvatarURL({ size: 4096, dynamic: true, format: "png"}), true) + .setStyle('LINK'), + new MessageButton() + .setLabel('JPG') + .setURL(interaction.user.displayAvatarURL({ size: 4096, dynamic: true, format: "jpg"}), true) + .setStyle("LINK"), + new MessageButton() + .setLabel('WEBP') + .setURL(interaction.user.displayAvatarURL({ size: 4096, dynamic: true, format: "webp"}), true) + .setStyle("LINK") + ); + + + let embed = new MessageEmbed() + .setAuthor(`${user.username}'s Avatar`, interaction.user.displayAvatarURL()) + + .addField('PNG', `\n[\`LINK\`](${user.displayAvatarURL({ size: 4096, dynamic: true, format: "png" })})`, true, true) + .addField('JPG', `\n[\`LINK\`](${user.displayAvatarURL({ size: 4096, dynamic: true, format: "jpg" })})`, true, true) + .addField('WEBP', `\n[\`LINK\`](${user.displayAvatarURL({ size: 4096, dynamic: true, format: "webp" })})`, true, true) + + .setImage(user.displayAvatarURL({ size: 4096, dynamic: true })) + .setThumbnail(interaction.guild.iconURL()) + .setColor('RANDOM') + .setTimestamp() + interaction.reply({ embeds: [embed], components:[AvatarButtons] }) + } +} \ No newline at end of file diff --git a/commands/General /calculator.js b/commands/General /calculator.js new file mode 100644 index 0000000..0870e0e --- /dev/null +++ b/commands/General /calculator.js @@ -0,0 +1,188 @@ +const { MessageActionRow, MessageButton } = require('discord.js'); +const math = require('mathjs'); + +module.exports = { + data: { + name: "calculator", + description: "Use the calculator on discord", + options: [], + }, + timeout: 20000, + + run: async (client, interaction) => { + const rows = [ + new MessageActionRow().addComponents([ + new MessageButton({ + customId: 'clear', + style: 'DANGER', + label: "AC", + }), + new MessageButton({ + customId: '(', + style: 'PRIMARY', + label: "(", + }), + new MessageButton({ + customId: ')', + style: 'PRIMARY', + label: ")", + }), + new MessageButton({ + customId: '/', + style: 'PRIMARY', + label: "➗", + }) + ]), + new MessageActionRow().addComponents([ + new MessageButton({ + customId: '7', + style: 'SECONDARY', + label: "7", + }), + new MessageButton({ + customId: '8', + style: 'SECONDARY', + label: "8", + }), + new MessageButton({ + customId: '9', + style: 'SECONDARY', + label: "9", + }), + new MessageButton({ + customId: '*', + style: 'PRIMARY', + label: "✖️", + }) + ]), + new MessageActionRow().addComponents([ + new MessageButton({ + customId: '4', + style: 'SECONDARY', + label: "4", + }), + new MessageButton({ + customId: '5', + style: 'SECONDARY', + label: "5", + }), + new MessageButton({ + customId: '6', + style: 'SECONDARY', + label: "6", + }), + new MessageButton({ + customId: '-', + style: 'PRIMARY', + label: "➖", + }) + ]), + new MessageActionRow().addComponents([ + new MessageButton({ + customId: '1', + style: 'SECONDARY', + label: "1", + }), + new MessageButton({ + customId: '2', + style: 'SECONDARY', + label: "2", + }), + new MessageButton({ + customId: '3', + style: 'SECONDARY', + label: "3", + }), + new MessageButton({ + customId: '+', + style: 'PRIMARY', + label: "➕", + }) + ]), + new MessageActionRow().addComponents([ + new MessageButton({ + customId: 'backspace', + style: 'PRIMARY', + label: "⬅️", + }), + new MessageButton({ + customId: '0', + style: 'SECONDARY', + label: "0", + }), + new MessageButton({ + customId: '.', + style: 'PRIMARY', + label: "⚫", + }), + new MessageButton({ + customId: 'result', + style: 'SUCCESS', + label: "=", + }) + ]), + ]; + + const msg = await interaction.reply({ + components: rows, + embeds: [{ + description: "```\nResults will be displayed here\n```", + color: "BLUE" + }], + fetchReply: true, + }); + + let data = ""; + + const col = msg.createMessageComponentCollector({ + filter: i => i.user.id === interaction.user.id, + time: 600000 + }); + + col.on('collect', async (i) => { + let extra = ""; + + if (i.customId === "result") { + try { + data = math.evaluate(data).toString(); + } catch (e) { + data = ""; + extra = "An Error Occured, Please click on AC for restart"; + } + } else if (i.customId === "clear") { + data = ""; + extra = "Results will be displayed here" + } else if (i.customId === "backspace") { + data = data.slice(0, data.length - 2); + } else { + const lc = data[data.length - 1]; + + data += `${( + (parseInt(i.customId) == i.customId || i.customId === ".") + && + (lc == parseInt(lc) || lc === ".") + ) || data.length === 0 ? "" : " "}` + i.customId; + } + + i.update({ + embeds: [{ + color: "BLUE", + description: `\`\`\`\n${data || extra}\n\`\`\`` + }] + }) + }) + + col.on('end', () => { + msg.edit({ + components: [new MessageActionRow().addComponents([ + new MessageButton({ + label: "The Calculator Ended", + disabled: true, + style: "DANGER", + customId: "_1_" + }) + ])] + }) + }) + } +} \ No newline at end of file diff --git a/commands/General /help.js b/commands/General /help.js new file mode 100644 index 0000000..f2e1e4b --- /dev/null +++ b/commands/General /help.js @@ -0,0 +1,150 @@ +const { MessageActionRow, CommandInteraction } = require('discord.js'); +const commandInfo = require('../../utility/commandInfo'); +const pagination = require('../../utility/pagginations'); + +module.exports = { + data: { + name: "help", + description: "Get some help ;D", + options: [{ + name: "basic", + description: "Get basic information of the bot and category/command list", + type: 1 + }, { + name: "commands", + description: "Get information of all commands of a category", + type: 1, + options: [{ + name: "category", + type: 3, + required: true, + description: "The category who's commands information you want" + }] + }, { + name: "command", + description: "Get information of a command", + type: 1, + options: [{ + name: "command", + type: 3, + required: true, + description: "The command who's commands information you want" + }] + }] + }, + + /** + * + * @param {*} client + * @param {CommandInteraction} interaction + */ + run: async (client, interaction) => { + const option = interaction.options.getSubcommand(); + + if (option === "basic") { + const row = new MessageActionRow(), options = client.categories.map(v => { + return { + label: `${v.replace(v.charAt(0), v.charAt(0).toUpperCase())}`, + value: v + } + }); + + let used = false; + + row.addComponents({ + type: "SELECT_MENU", + customId: "select", + placeholder: "Choose a category", + options + }); + + const msg = await interaction.reply({ + fetchReply: true, + components: [row], + embeds: [{ + title: `${client.user.username}'s Help 📚 Menu`, + description: `To get list of commands of a category select the category from the select menu below`, + color: "#2f3136" + }] + }); + + // Select menu collector for category + const col = msg.createMessageComponentCollector({ + filter: (i) => i.user.id === interaction.user.id, + time: 10000, + }); + + // Select menu collector for category + col.on('collect', async (i) => { + let cat = i.values[0], index = 0; + used = true; + + row.components[0].options = client.commands.filter(v => v.category === cat).map(c => { + let v = c.data.name + + return { + label: v.replace(v.charAt(0), v.charAt(0).toUpperCase()), + value: v + } + }); + row.components[0].placeholder = "Choose a command"; + + const msg = await i.update({ + embeds: [{ + title: `${cat.replace(cat.charAt(0), cat.charAt(0).toUpperCase())}'s commands list`, + description: + client.commands.filter(v => v.category === cat).map((v) => `\`${++index}.\`**${v.data.name}**\n${v.data.description}`).join("\n\n") + }], + components: [row], + fetchReply: true + }); + + const col2 = msg.createMessageComponentCollector({ + filter: (i) => i.user.id === interaction.user.id, + time: 10000 + }); + + col2.on('collect', (i) => { + const command = client.commands.get(i.values[0]); + + i.update({ + embeds: [commandInfo(command)], + components: [] + }); + + col2.stop(); + }); + + col2.on('end', (reason) => { + if (reason === 'time') { + msg.edit({ + components: [] + }) + } + }) + + col.stop(); + }); + + // Select menu collector for category end + col.on('end', (reason) => { + if (reason === 'time' && !used) { + msg.edit({ + components: [] + }) + } + }) + } else if (option === "commands") { + const cat = interaction.options.getString("category")?.toLowerCase(); + const commands = client.commands.filter(v => v.category === cat); + + const embeds = commands.map(v => commandInfo(v)); + + pagination(interaction, embeds); + } else if (option === "command") { + interaction.reply({ + embeds: [commandInfo(client.commands.get(interaction.options.getString("command")?.toLowerCase()))] + }) + } + } +} \ No newline at end of file diff --git a/commands/General /ping.js b/commands/General /ping.js new file mode 100644 index 0000000..2fa8513 --- /dev/null +++ b/commands/General /ping.js @@ -0,0 +1,12 @@ +module.exports = { + data: { + name: "ping", + description: "Get Tiger bot's ping!", + options: [], + }, + timeout:10000, + + run: async (client, interaction) => { + interaction.reply({ content: `The ping of the Tiger Bot is ${client.ws.ping} ` }) + } + } \ No newline at end of file diff --git a/commands/General /suggestion.js b/commands/General /suggestion.js new file mode 100644 index 0000000..95eba66 --- /dev/null +++ b/commands/General /suggestion.js @@ -0,0 +1,222 @@ +const { MessageActionRow, MessageButton } = require("discord.js"); +const guildConfig = require("../../models/guildConfig") +const suggestions = require("../../models/suggestion") + +module.exports = { + data: { + name: "suggestion", + description: "Create or reply to suggestions", + options: [{ + name: "create", + type: 1, + description: "Create a suggestion", + options: [{ + name: "suggestion", + type: 3, + required: true, + description: "The suggesiton you want to give" + }] + }, { + name: "reply", + type: 1, + description: "Reply to a suggesiton", + options: [{ + name: "id", + type: 3, + required: true, + description: "The suggestion to which you want to reply" + }, { + name: "status", + type: 3, + required: true, + description: "Set the status of this suggestion", + choices: [{ + name: "Accepted", + value: "1" + }, { + name: "Rejected", + value: "2" + }] + }, { + name: "response", + type: 3, + required: true, + description: "The response to this status" + }] + }, { + name: 'set-channel', + type: 1, + description: "Select the suggestion channel", + options: [{ + name: "channel", + type: 7, + required: true, + description: "The channel where I should send the suggestions" + }] + }], + }, + timeout: 1000, + + run: async (client, interaction) => { + await interaction.deferReply(); + + const option = interaction.options.getSubcommand(), + suggestion = interaction.options.getString("suggestion"), + channel = interaction.options.getChannel("channel"), + id = interaction.options.getString("id"), + status = interaction.options.getString("status"), + response = interaction.options.getString("response"), + data = await guildConfig.findOne({ id: interaction.guild.id }) || await guildConfig.create({ id: interaction.guild.id }), + sug = await suggestions.findOne({ message: id }), + c = interaction.guild.channels.cache.get(data.suggestion); + + if (option === "create") { + if (!c) return interaction.editReply({ + embeds: [{ + title: " <:cros:961414487859146783> Suggestion Not Setuped" + }] + }); + + const row = new MessageActionRow().addComponents([ + new MessageButton({ + customId: "1", + label: "⬆ Up Vote", + style: "SECONDARY" + }), new MessageButton({ + customId: "2", + label: "⬇ Down Vote", + style: "SECONDARY" + }) + ]) + + const msg = await c.send({ + components: [row], + embeds: [{ + title: "New Suggestion!", + color: "BLUE", + description: suggestion, + fields: [{ + name: "Up Votes", + value: "0", + inline: true + }, { + name: "Down Votes", + value: "0", + inline: true + }, { + name: "Status", + value: "pending", + inline: true + }], + footer: { + text: interaction.user.username, + iconURL: interaction.user.displayAvatarURL() + } + }] + }); + + await suggestions.create({ + suggestion, + user: interaction.user.id, + message: msg.id, + channel: c.id, + guild: interaction.guildId, + votes: { + up: [], down: [] + }, + createdAt: Date.now(), + }); + + msg.embeds[0].fields.push({ + name: "Suggestion ID", + value: `\`\`\`\n${msg.id}\n\`\`\``, + inline: true + }); + + msg.edit({ + embeds: msg.embeds + }); + + interaction.editReply({ + embeds: [{ + color: "GREEN", + title: "<:tick:961414448520781864> Suggestion Created" + }] + }) + } else if (option === "reply") { + if (!interaction.member.permissions.has("MANAGE_GUILD")) return interaction.editReply({ + embeds: [{ + title: "<:cros:961414487859146783> You are not allowed" + }] + }); + + if (!sug) return interaction.editReply({ + embeds: [{ + title: "<:cros:961414487859146783> Invalid Suggestion ID" + }] + }); + + const msg = await interaction.guild.channels.cache.get(sug.channel)?.messages?.fetch(sug.message); + + if (!msg) return interaction.editReply({ + embeds: [{ + title: "<:cros:961414487859146783> Suggestion Message is Deleted", + description: "This suggestion can no longer be replied" + }] + }); + + const row = new MessageActionRow().addComponents([ + new MessageButton({ + customId: "1", + label: "⬆ Up Vote", + style: "SECONDARY", + disabled: true + }), new MessageButton({ + customId: "2", + label: "⬇ Down Vote", + style: "SECONDARY", + disabled: true + }) + ]); + + msg.embeds[0].fields[2].value = status === "1" ? "<:tick:961414448520781864> Accepted" : "<:cros:961414487859146783> Rejected"; + msg.embeds[0].fields.push({ + name: "Response", + value: response, + }) + + msg.edit({ + embeds: msg.embeds, + components: [row] + }); + + interaction.editReply({ + embeds: [{ + color: "GREEN", + title:"<:tick:961414448520781864> Suggestion Replied" + }] + }) + } else if (option === "set-channel") { + if (!interaction.member.permissions.has("MANAGE_GUILD")) return interaction.editReply({ + embeds: [{ + title: "<:cros:961414487859146783> You are not allowed" + }] + }); + + if (channel.type !== "GUILD_TEXT") return interaction.editReply({ + embeds: [{ + title: "<:cros:961414487859146783> Invalid Channel Type" + }] + }); + + await guildConfig.findOneAndUpdate({ id: interaction.guildId }, { suggestion: channel.id }); + + interaction.editReply({ + embeds: [{ + color: "GREEN", + title: "<:tick:961414448520781864> Suggestion Setuped! " + }] + }) + } + } +} \ No newline at end of file diff --git a/commands/Giveaway/edit.js b/commands/Giveaway/edit.js new file mode 100644 index 0000000..386ebc8 --- /dev/null +++ b/commands/Giveaway/edit.js @@ -0,0 +1,71 @@ +module.exports = { + data: { + name: 'edit', + description: '🎉 Edit a giveaway', + + options: [ + { + name: 'giveaway', + description: 'The giveaway to end (message ID)', + type: 3, // Corrected type to STRING (3) + required: true + }, + { + name: 'duration', + description: 'Setting time of mentioned giveaway. Eg. 1h sets the current giveaway to end after an hour!', + type: 3, // Corrected type to STRING (3) + required: true + }, + { + name: 'winners', + description: 'How many winners the giveaway should have', + type: 4, // Corrected type to INTEGER (4) + required: true + }, + { + name: 'prize', + description: 'What the prize of the giveaway should be', + type: 3, // Corrected type to STRING (3) + required: true + } + ]}, + + run: async (client, interaction) => { + + // If the member doesn't have enough permissions + if (!interaction.member.permissions.has('MANAGE_MESSAGES') && !interaction.member.roles.cache.some((r) => r.name === "Giveaways")) { + return interaction.reply({ + content: ':x: You need to have the manage messages permissions to start giveaways.', + ephemeral: true + }); + } + const gid = interaction.options.getString('giveaway'); + const time = interaction.options.getString('duration'); + const winnersCount = interaction.options.getInteger('winners'); + const prize = interaction.options.getString('prize'); + + await interaction.deferReply({ + ephemeral: true + }) + // Edit the giveaway + try { + await client.giveawaysManager.edit(gid, { + newWinnersCount: winnersCount, + newPrize: prize, + addTime: time + }) + } catch(e) { +return interaction.editReply({ + content: + `No giveaway found with the given message ID: \`${gid}\``, + ephemeral: true + }); + } + interaction.editReply({ + content: + `This giveaway has now been edited!`, + ephemeral: true + }); + } + +}; diff --git a/commands/Giveaway/end.js b/commands/Giveaway/end.js new file mode 100644 index 0000000..de4f49b --- /dev/null +++ b/commands/Giveaway/end.js @@ -0,0 +1,64 @@ +module.exports = { + data: { + name: "end", + description: '🎉 End an already running giveaway', + + options: [ + { + name: 'giveaway', + description: 'The giveaway to end (message ID or giveaway prize)', + type: 'STRING', + required: true + } + ]}, + + run: async (client, interaction) => { + + // If the member doesn't have enough permissions + if (!interaction.member.permissions.has('MANAGE_MESSAGES') && !interaction.member.roles.cache.some((r) => r.name === "Giveaways")) { + return interaction.reply({ + content: ':x: You need to have the manage messages permissions to end giveaways.', + ephemeral: true + }); + } + + const query = interaction.options.getString('giveaway'); + + // fetching the giveaway with message Id or prize + const giveaway = + // Search with giveaway prize + client.giveawaysManager.giveaways.find((g) => g.prize === query && g.guildId === interaction.guild.id) || + // Search with giveaway Id + client.giveawaysManager.giveaways.find((g) => g.messageId === query && g.guildId === interaction.guild.id); + + // If no giveaway was found with the corresponding input + if (!giveaway) { + return interaction.reply({ + content: 'Unable to find a giveaway for `' + query + '`.', + ephemeral: true + }); + } + + if (giveaway.ended) { + return interaction.reply({ + content: 'This giveaway has already ended!', + ephemeral: true + }); + } + + // Edit the giveaway + client.giveawaysManager.end(giveaway.messageId) + // Success message + .then(() => { + // Success message + interaction.reply(`**[This Giveaway](https://discord.com/channels/${giveaway.guildId}/${giveaway.channelId}/${giveaway.messageId})** Has Now Ended!`); + }) + .catch((e) => { + interaction.reply({ + content: e, + ephemeral: true + }); + }); + + } +}; \ No newline at end of file diff --git a/commands/Giveaway/puase.js b/commands/Giveaway/puase.js new file mode 100644 index 0000000..05745f8 --- /dev/null +++ b/commands/Giveaway/puase.js @@ -0,0 +1,64 @@ +module.exports = { + data: { + name: "pause", + description: '⏸ Pause a giveaway', + + options: [ + { + name: 'giveaway', + description: 'The giveaway to pause (message ID or giveaway prize)', + type: 'STRING', + required: true + } + ]}, + + run: async (client, interaction) => { + + // If the member doesn't have enough permissions + if (!interaction.member.permissions.has('MANAGE_MESSAGES') && !interaction.member.roles.cache.some((r) => r.name === "Giveaways")) { + return interaction.reply({ + content: ':x: You need to have the manage messages permissions to pause giveaways.', + ephemeral: true + }); + } + + const query = interaction.options.getString('giveaway'); + + // try to find the giveaway with prize alternatively with ID + const giveaway = + // Search with giveaway prize + client.giveawaysManager.giveaways.find((g) => g.prize === query && g.guildId === interaction.guild.id) || + // Search with giveaway ID + client.giveawaysManager.giveaways.find((g) => g.messageId === query && g.guildId === interaction.guild.id); + + // If no giveaway was found + if (!giveaway) { + return interaction.reply({ + content: 'Unable to find a giveaway for `' + query + '`.', + ephemeral: true + }); + } + + if (giveaway.pauseOptions.isPaused) { + return interaction.reply({ + content: `**[This giveaway](https://discord.com/channels/${giveaway.guildId}/${giveaway.channelId}/${giveaway.messageId})** is already paused.`, + ephemeral: true + }); + } + + // Edit the giveaway + client.giveawaysManager.pause(giveaway.messageId) + // Success message + .then(() => { + // Success message + interaction.reply(`**[This giveaway](https://discord.com/channels/${giveaway.guildId}/${giveaway.channelId}/${giveaway.messageId})** has now been paused!`); + }) + .catch((e) => { + interaction.reply({ + content: e, + ephemeral: true + }); + }); + + } +}; \ No newline at end of file diff --git a/commands/Giveaway/reroll.js b/commands/Giveaway/reroll.js new file mode 100644 index 0000000..141818a --- /dev/null +++ b/commands/Giveaway/reroll.js @@ -0,0 +1,63 @@ +module.exports = { + data: { + name: "reroll", + description: '🎉 Reroll a giveaway', + + options: [ + { + name: 'giveaway', + description: 'The giveaway to reroll (message ID or prize)', + type: 'STRING', + required: true + } + ]}, + + run: async (client, interaction) => { + + // If the member doesn't have enough permissions + if (!interaction.member.permissions.has('MANAGE_MESSAGES') && !interaction.member.roles.cache.some((r) => r.name === "Giveaways")) { + return interaction.reply({ + content: ':x: You need to have the manage messages permission to reroll giveaways.', + ephemeral: true + }); + } + + const query = interaction.options.getString('giveaway'); + + // try to find the giveaway with the provided prize OR with the ID + const giveaway = + // Search with giveaway prize + client.giveawaysManager.giveaways.find((g) => g.prize === query && g.guildId === interaction.guild.id) || + // Search with giveaway ID + client.giveawaysManager.giveaways.find((g) => g.messageId === query && g.guildId === interaction.guild.id); + + // If no giveaway was found + if (!giveaway) { + return interaction.reply({ + content: 'Unable to find a giveaway for `' + query + '`.', + ephemeral: true + }); + } + + if (!giveaway.ended) { + return interaction.reply({ + content: `[This Giveaway](https://discord.com/channels/${giveaway.guildId}/${giveaway.channelId}/${giveaway.messageId}) has not been ended yet`, + ephemeral: true + }); + } + + // Reroll the giveaway + client.giveawaysManager.reroll(giveaway.messageId) + .then(() => { + // Success message + interaction.reply(`Rerolled **[this giveaway](https://discord.com/channels/${giveaway.guildId}/${giveaway.channelId}/${giveaway.messageId})!**`); + }) + .catch((e) => { + interaction.reply({ + content: e, + ephemeral: true + }); + }); + + } +}; \ No newline at end of file diff --git a/commands/Giveaway/resume.js b/commands/Giveaway/resume.js new file mode 100644 index 0000000..2b12b1d --- /dev/null +++ b/commands/Giveaway/resume.js @@ -0,0 +1,64 @@ +module.exports = { + data: { + name: "resume", + description: '▶ Resume a paused giveaway', + + options: [ + { + name: 'giveaway', + description: 'The giveaway to resume (message ID or giveaway prize)', + type: 3, // Corrected type to STRING (3) + required: true + } + ]}, + + run: async (client, interaction) => { + + // If the member doesn't have enough permissions + if (!interaction.member.permissions.has('MANAGE_MESSAGES') && !interaction.member.roles.cache.some((r) => r.name === "Giveaways")) { + return interaction.reply({ + content: ':x: You need to have the manage messages permissions to pause giveaways.', + ephemeral: true + }); + } + + const query = interaction.options.getString('giveaway'); + + // try to find the giveaway with prize alternatively with ID + const giveaway = + // Search with giveaway prize + client.giveawaysManager.giveaways.find((g) => g.prize === query && g.guildId === interaction.guild.id) || + // Search with giveaway ID + client.giveawaysManager.giveaways.find((g) => g.messageId === query && g.guildId === interaction.guild.id); + + // If no giveaway was found + if (!giveaway) { + return interaction.reply({ + content: 'Unable to find a giveaway for `' + query + '`.', + ephemeral: true + }); + } + + if (!giveaway.pauseOptions.isPaused) { + return interaction.reply({ + content: `**[This giveaway](https://discord.com/channels/${giveaway.guildId}/${giveaway.channelId}/${giveaway.messageId})** is not paused!`, + ephemeral: true + }); + } + + // Edit the giveaway + client.giveawaysManager.unpause(giveaway.messageId) + // Success message + .then(() => { + // Success message + interaction.reply(`**[This giveaway](https://discord.com/channels/${giveaway.guildId}/${giveaway.channelId}/${giveaway.messageId})** has been successfully resumed!`); + }) + .catch((e) => { + interaction.reply({ + content: e, + ephemeral: true + }); + }); + + } +}; diff --git a/commands/Giveaway/start.js b/commands/Giveaway/start.js new file mode 100644 index 0000000..bddf248 --- /dev/null +++ b/commands/Giveaway/start.js @@ -0,0 +1,191 @@ +const Discord = require("discord.js") +const messages = require("../../utils/message"); +const ms = require("ms") +module.exports = { + data: { + name: 'start', + description: '🎉 Start a giveaway', + + options: [ + { + name: 'duration', + description: 'How long the giveaway should last for. Example values: 1m, 1h, 1d', + type: 'STRING', + required: true + }, + { + name: 'winners', + description: 'How many winners the giveaway should have', + type: 'INTEGER', + required: true + }, + { + name: 'prize', + description: 'What the prize of the giveaway should be', + type: 'STRING', + required: true + }, + { + name: 'channel', + description: 'The channel to start the giveaway in', + type: 'CHANNEL', + required: true + }, + { + name: 'bonusrole', + description: 'Role which would recieve bonus entries', + type: 'ROLE', + required: false + }, + { + name: 'bonusamount', + description: 'The amount of bonus entries the role will recieve', + type: 'INTEGER', + required: false + }, + { + name: 'invite', + description: 'Invite of the server you want to add as giveaway joining requirement', + type: 'STRING', + required: false + }, + { + name: 'role', + description: 'Role you want to add as giveaway joining requirement', + type: 'ROLE', + required: false + }, + ]}, + + run: async (client, interaction) => { + + // If the member doesn't have enough permissions + if (!interaction.member.permissions.has('MANAGE_MESSAGES') && !interaction.member.roles.cache.some((r) => r.name === "Giveaways")) { + return interaction.reply({ + content: ':x: You need to have the manage messages permissions to start giveaways.', + ephemeral: true + }); + } + + const giveawayChannel = interaction.options.getChannel('channel'); + const giveawayDuration = interaction.options.getString('duration'); + const giveawayWinnerCount = interaction.options.getInteger('winners'); + const giveawayPrize = interaction.options.getString('prize'); + + if (!giveawayChannel.isText()) { + return interaction.reply({ + content: ':x: Please select a text channel!', + ephemeral: true + }); + } + if(isNaN(ms(giveawayDuration))) { + return interaction.reply({ + content: ':x: Please select a valid duration!', + ephemeral: true + }); + } + if (giveawayWinnerCount < 1) { + return interaction.reply({ + content: ':x: Please select a valid winner count! greater or equal to one.', + }) + } + + const bonusRole = interaction.options.getRole('bonusrole') + const bonusEntries = interaction.options.getInteger('bonusamount') + let rolereq = interaction.options.getRole('role') + let invite = interaction.options.getString('invite') + + if (bonusRole) { + if (!bonusEntries) { + return interaction.reply({ + content: `:x: You must specify how many bonus entries would ${bonusRole} recieve!`, + ephemeral: true + }); + } + } + + + await interaction.deferReply({ ephemeral: true }) + let reqinvite; + if (invite) { + let invitex = await client.fetchInvite(invite) + let client_is_in_server = client.guilds.cache.get( + invitex.guild.id + ) + reqinvite = invitex + if (!client_is_in_server) { + return interaction.editReply({ + embeds: [{ + color: "#2F3136", + author: { + name: client.user.username, + iconURL: client.user.displayAvatarURL() + }, + title: "Server Check!", + url: "https://youtube.com/c/ZeroSync", + description: + "Woah woah woah! I see a new server! are you sure I am in that? You need to invite me there to set that as a requirement! 😳", + timestamp: new Date(), + footer: { + iconURL: client.user.displayAvatarURL(), + text: "Server Check" + } + }] + }) + } + } + + if (rolereq && !invite) { + messages.inviteToParticipate = `**React with 🎉 to participate!**\n>>> - Only members having ${rolereq} are allowed to participate in this giveaway!` + } + if (rolereq && invite) { + messages.inviteToParticipate = `**React with 🎉 to participate!**\n>>> - Only members having ${rolereq} are allowed to participate in this giveaway!\n- Members are required to join [this server](${invite}) to participate in this giveaway!` + } + if (!rolereq && invite) { + messages.inviteToParticipate = `**React with 🎉 to participate!**\n>>> - Members are required to join [this server](${invite}) to participate in this giveaway!` + } + + + // start giveaway + client.giveawaysManager.start(giveawayChannel, { + // The giveaway duration + duration: ms(giveawayDuration), + // The giveaway prize + prize: giveawayPrize, + // The giveaway winner count + winnerCount: parseInt(giveawayWinnerCount), + // BonusEntries If Provided + bonusEntries: [ + { + // Members who have the role which is assigned to "rolename" get the amount of bonus entries which are assigned to "BonusEntries" + bonus: new Function('member', `return member.roles.cache.some((r) => r.name === \'${bonusRole ?.name}\') ? ${bonusEntries} : null`), + cumulative: false + } + ], + // Messages + messages, + extraData: { + server: reqinvite == null ? "null" : reqinvite.guild.id, + role: rolereq == null ? "null" : rolereq.id, + } + }); + interaction.editReply({ + content: + `Giveaway started in ${giveawayChannel}!`, + ephemeral: true + }) + + if (bonusRole) { + let giveaway = new Discord.MessageEmbed() + .setAuthor({ name: `Bonus Entries Alert!` }) + .setDescription( + `**${bonusRole}** Has **${bonusEntries}** Extra Entries in this giveaway!` + ) + .setColor("#2F3136") + .setTimestamp(); + giveawayChannel.send({ embeds: [giveaway] }); + } + + } + +}; \ No newline at end of file diff --git a/commands/Level/rank.js b/commands/Level/rank.js new file mode 100644 index 0000000..f45cda0 --- /dev/null +++ b/commands/Level/rank.js @@ -0,0 +1,44 @@ +const users = require('../../models/user_xp'); +const { MessageAttachment, TextChannel, MessageEmbed } = require('discord.js'); + +module.exports = { + data: { + name: "rank", + description: "Check your lvl", + options: [{ + name: "user", + description: "Mention a user", + required: false, + type: 6, + }], + }, + + run: async (client, interaction) => { + + const user = interaction.options.getUser("user") || interaction.user; + let datas = await users.find({ guild: interaction.guild.id }) || {}, data, rank; + + for (let i = 0; i < datas.length; i++) { + let v = datas[i]; + + if (v.user === user.id) { + data = v; + rank = i + 1; + break; + } + }; + + if (!data) return interaction.reply("LOL you have no xp & data") + + let reqXP = 100; + + for (let i = 1; i <= data.level; i++)reqXP += 5 * (i ^ 2) + (50 * i) + 100; + const embed = new MessageEmbed() + .setTitle('USERS DATA ') + .setDescription(`USER LEVEL = ${data.level}\n\nUSER XP = ${data.xp}/${reqXP}`) + .setThumbnail(`${interaction.user.displayAvatarURL({ dynamic: true })}`) + .setColor('#2f3136') + .setTimestamp() + interaction.reply({ embeds: [embed], components:[AvatarButtons] }) + } +} \ No newline at end of file diff --git a/commands/Level/xp.js b/commands/Level/xp.js new file mode 100644 index 0000000..0e83c4d --- /dev/null +++ b/commands/Level/xp.js @@ -0,0 +1,251 @@ +const configs = require('../../models/guildConfig'); + +module.exports = { + data: { + name: "xp", + description: "Manage xp system of your server", + options: [{ + name: "enable", + type: 1, + description: "Enable the XP system in your server", + }, { + name: "disable", + type: 1, + description: "Disable the XP system in your server", + }, { + name: "rate", + type: 1, + description: "Change the XP rate of your server", + options: [{ + name: "rate", + type: 4, + required: true, + description: "The percantage of XP Rate" + }] + }, { + name: "limits", + type: 1, + description: "Change the XP icrement limits for your server", + options: [{ + name: "up-limit", + type: 4, + required: false, + description: "The maximum XP increment" + }, { + name: "down-limit", + type: 4, + required: false, + description: "The minimum XP increment" + }] + }, { + name: "level-up-message", + type: 1, + description: "Change the level up message for your server", + options: [{ + name: "message", + type: 3, + required: true, + description: "The new level up message, you can use these: {level} {xp} {mention}" + }] + }, { + name: "level-up-message-enable", + type: 1, + description: "Enable the XP level up mesage in your server", + }, { + name: "level-up-message-disable", + type: 1, + description: "Disable the XP level up mesage in your server", + }, { + name: "level-up-channel", + type: 1, + description: "Change the level up message channel", + options: [{ + name: "channel", + type: 3, + description: "Mention the channel or give ID, 0 for same channel message", + required: true + }] + }, { + name: "ignore-channel-add", + type: 1, + description: "Add ignore XP Channel", + options: [{ + name: "channel", + type: 7, + description: "Mention the channel to disable XP increment", + required: true + }] + }, { + name: "ignore-channel-remove", + type: 1, + description: "remove ignore XP Channel", + options: [{ + name: "channel", + type: 7, + description: "Mention the channel to re-enable XP increment", + required: true + }] + }, { + name: "level-up-reward-message", + type: 1, + description: "Change the level up message for your server", + options: [{ + name: "success-message", + type: 3, + required: false, + description: "The new level up message, you can use these: {level} {xp} {mention}" + }, { + name: "fail-message", + type: 3, + required: false, + description: "The new level up message, you can use these: {level} {xp} {mention}" + }] + }, { + name: "add-level-reward", + type: 1, + description: "Add a level reward for your server", + options: [{ + name: "level", + type: 3, + description: "Levle when the user will get this reward", + required: true + }, { + name: "role", + type: 8, + description: "The reward role user will get", + required: true + }] + }, { + name: "remove-level-reward", + type: 1, + description: "Remove a level reward for your server", + options: [{ + name: "level", + type: 3, + description: "Level of which you want to remove", + required: true + }] + }] + }, + permissions: ["MANAGE_SERVER"], + + /** + * + * @param {Client} client + * @param {CommandInteraction} interaction + */ + run: async (client, interaction) => { + await interaction.reply({ content: `${client.user.username} is thinking...` }); + + const option = interaction.options.getSubcommand(true).toLowerCase(), + data = await configs.findOne({ id: interaction.guild.id }) || await configs.create({ id: interaction.guild.id }); + + data.levelReward = data.levelReward || {}; + + const rate = interaction.options.getInteger("rate"), + ul = Math.floor(interaction.options.getInteger("up-limit")), + dl = Math.floor(interaction.options.getInteger("down-limit")), + message = interaction.options.getString("message"), + s_message = interaction.options.getString("success-message"), + f_message = interaction.options.getString("fail-message"), + role = interaction.options.getRole("role"), + level = interaction.options.getString("level"), + channel = interaction.options.get("channel")?.value; + + if (option === "enable") { + if (data.xp) return interaction.editReply({ content: "XP System is already enabled" }); + + interaction.editReply({ content: "XP System is now enabled" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { xp: true }) + } else if (option === "disable") { + if (!data.xp) return interaction.editReply({ content: "XP System is already disabled" }); + + interaction.editReply({ content: "XP System is now disabled" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { xp: false }) + } else if (option === "rate") { + if (rate < 0 || rate > 1000) return interaction.editReply({ content: "Please provide valid XP Rate from 1% to 1000% ( you don't have to type % just the number will work )" }) + + interaction.editReply({ content: `XP rate is change to ${rate}%` }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { xpRate: rate / 100 }) + } else if (option === "limits") { + if (dl > ul || ul < 0 || ul > 1000 || dl < 0 || dl > 1000) return interaction.editReply({ content: "Please provide valid XP increment limits from 1 to 1000 and up limit should be more than down limit" }) + if (!dl && !ul) return interaction.editReply({ content: "Please provide either of the XP increment limit i.e. up or down" }) + + ul = ul || data.xpLimit.up; + dl = dl || data.xpLimit.down; + + interaction.editReply({ content: `XP increment is change to:\nup limit: ${ul}\ndown limit: ${dl}` }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { "xpLimit.up": ul, "xpLimit.down": dl }) + } else if (option === "level-up-message-enable") { + if (data.xpLevelUp.xp) return interaction.editReply({ content: "XP level up message is already enabled" }); + + interaction.editReply({ content: "XP level up message is now enabled" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { "xpLevelUp.enable": true }) + } else if (option === "level-up-message-disable") { + if (!data.xpLevelUp.xp) return interaction.editReply({ content: "XP level up message is already disabled" }); + + interaction.editReply({ content: "XP level up message is now disabled" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { "xpLevelUp.enable": false }) + } else if (option === "level-up-message") { + interaction.editReply({ content: "XP level up message is now changed" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { "xpLevelUp.message": message }) + } else if (option === "level-up-channel") { + let c = interaction.guild.channels.cache.get(channel) || interaction.guild.channels.cache.get(channel.substring(2, channel.length - 1)) + + if ((!c && channel !== "0") || (c && channel !== "0" && c.type !== "GUILD_TEXT")) + return interaction.editReply({ content: "Either type 0 for same channel message or give a valid Text channel ID" }); + + interaction.editReply({ content: "XP level up message channel is now changed" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { "xpLevelUp.channel": channel === "0" ? channel : c.id }) + } else if (option === "ignore-channel-add") { + if (data.ignoreXP.includes("channel")) + return interaction.editReply({ content: "Yo nerd this channel is already disabled for xp increment" }); + + interaction.editReply({ content: "Now the mentioned channel will not get xp incremenets" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { $push: { ignoreXP: channel.id } }) + } else if (option === "ignore-channel-remove") { + if (!data.ignoreXP.includes("channel")) + return interaction.editReply({ content: "Yo nerd, this channel is not disabled for xp increment" }); + + interaction.editReply({ content: "Now the mentioned channel will get xp incremenets" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { $pull: { ignoreXP: channel.id } }) + } else if (option === "level-up-reward-message") { + if (!s_message && !f_message) return interaction.editReply("Either provide success message or failed message."); + + interaction.editReply({ content: "Level Up reward message(s) changed successfully" }); + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { + levelRewardMessage: { + success: s_message || data.levelRewardMessage.success, + fail: s_message || data.levelRewardMessage.fail, + } + }) + } else if (option === "remove-level-reward") { + if (!data.levelReward[level]) return interaction.editReply("Yo, you don't have any level reward for this level."); + + interaction.editReply({ content: "Level Up reward removed successfully" }); + + data.levelReward[level] = "0"; + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { levelReward: data.levelReward }) + } else if (option === "add-level-reward") { + if (data.levelReward[level] === role.id) return interaction.editReply("Yo, this level reward for this level already exist."); + + interaction.editReply({ content: "Level Up reward updated successfully" }); + + data.levelReward[level] = role.id; + + await configs.findOneAndUpdate({ id: interaction.guild.id }, { levelReward: data.levelReward }) + } + } +} \ No newline at end of file diff --git a/commands/Moderation/roleall.js b/commands/Moderation/roleall.js new file mode 100644 index 0000000..b9def17 --- /dev/null +++ b/commands/Moderation/roleall.js @@ -0,0 +1,83 @@ +const froms = ["all", "human", "bot"]; + +module.exports = { + data: { + name: "roles", + description: "Manage roles of the server", + options: [{ + name: "action", + type: 3, // Corrected type to STRING (3) + required: true, + description: "Choose the action", + choices: [{ + name: "Give Role", + value: "1" + }, { + name: "Take Role", + value: "2" + }] + }, { + name: "from", + description: "The category you want to manipulate, give role ID, or type human or bot or all", + required: true, + type: 3 // Corrected type to STRING (3) + }, { + name: "for", + description: "This is the role you want to give or take", + required: true, + type: 8 // Corrected type to ROLE (8) + }], + }, + timeout: 100000, + permissions: ["ADMINISTRATOR"], + + run: async (client, interaction) => { + const action = interaction.options.getString("action"), + from = interaction.options.getString("from")?.toLowerCase(), + _for = interaction.options.getRole("for"); + + if (!froms.includes(from) && !interaction.guild.roles.cache.get(/\d+/.exec(from) + "")) return interaction.reply({ + embeds: [{ + title: "❌ Invalid from value", + color: "RED", + description: "It should be the role ID, against which you want to take the action\nOr you can type `huamn` for taking action against humans, `bot` for the bots and `all` for everyone" + }] + }); + + if (_for.position > interaction.guild.me.roles.highest.position && !interaction.guild.me.permissions.has("MANAGE_ROLES")) return interaction.reply({ + embeds: [{ + title: "❌ Invalid Permissions", + color: "RED", + description: "Either I do not have Manage Role permission, or the provided role is above my highest role" + }] + }); + + let filter, ind = froms.indexOf(from); + + if (ind === 0) filter = (m) => m.roles.cache.has(_for.id) === (action !== "1") + else if (ind === 1) filter = (m) => !m.user.bot && m.roles.cache.has(_for.id) === (action !== "1") + else if (ind === 2) filter = (m) => m.user.bot && m.roles.cache.has(_for.id) === (action !== "1") + else filter = (m) => m.roles.cache.has(/\d+/.exec(from) + "") && m.roles.cache.has(_for.id) === (action !== "1"); + + const members = (await interaction.guild.members.fetch({ force: true })).filter(filter)?.toJSON(); + + await interaction.reply({ + embeds: [{ + color: "BLUE", + title: `Changing roles for ${members.length} member` + }] + }); + + + for (let i = 0; i < members.length; i++) { + await members[i].roles[action === "1" ? "add" : "remove"](_for); + } + + interaction.editReply({ + embeds: [{ + color: "GREEN", + title: "✅ Roles changed successfully" + }] + }) + } +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..10be804 --- /dev/null +++ b/config.json @@ -0,0 +1,7 @@ +{ + "everyoneMention": false, + + "hostedBy": true, + "fail": "<:cros:961414487859146783>", + "success": "<:tick:961414448520781864>" +} \ No newline at end of file diff --git a/events/guildMemberAdd.2.js b/events/guildMemberAdd.2.js new file mode 100644 index 0000000..156b627 --- /dev/null +++ b/events/guildMemberAdd.2.js @@ -0,0 +1,28 @@ +const guildConfig = require('../models/guildConfig'); +const canvacord = require('canvacord'); + +module.exports = async (client, member) => { + const data = await guildConfig.findOne({ id: member.guild.id }), + channel = member.guild.channels.cache.get(data?.welcome.channel); + + if (!channel || data?.welcome.enable !== true) return; + + const welcomeImage = new canvacord.Welcomer() + .setAvatar(member.user.displayAvatarURL({ dynamic: false, format: "png" })) + .setUsername(member.user.username) + .setDiscriminator(member.user.discriminator) + .setGuildName(member.guild.name) + .setMemberCount(member.guild.memberCount + 1) + .setBackground("https://cdn.discordapp.com/attachments/714747037983309866/909416865539969065/2Q.png"), + + content = data.welcome.message + .replace(/\{mention\}/g, member.user.toString()) + .replace(/\{user\}/g, member.user.username) + .replace(/\{server\}/g, member.guild.name) + .replace(/\{members\}/g, member.guild.memberCount + 1) + + channel.send({ + content, + files: [await welcomeImage.build()] + }) +} \ No newline at end of file diff --git a/events/guildMemberAdd.js b/events/guildMemberAdd.js new file mode 100644 index 0000000..89e7d45 --- /dev/null +++ b/events/guildMemberAdd.js @@ -0,0 +1,13 @@ +const stats = require('../models/guildStats'); + +module.exports =async (client, member) => { + const data = await stats.findOne({ guild: member.guild.id }); + + if (!data || !data.members || data.members === "0") return; + + const channel = member.guild.channels.cache.get(data.members); + + if (!channel || !channel.manageable) return; + + channel.setName(`Members : ${member.guild.memberCount}`) +} \ No newline at end of file diff --git a/events/guildMemberRemove.js b/events/guildMemberRemove.js new file mode 100644 index 0000000..1c05565 --- /dev/null +++ b/events/guildMemberRemove.js @@ -0,0 +1,13 @@ +const stats = require('../models/guildStats'); + +module.exports = async(client, member) => { + const data = await stats.findOne({ guild: member.guild.id }); + + if (!data || !data.members || data.members === "0") return; + + const channel = member.guild.channels.cache.get(data.members); + + if (!channel || !channel.manageable) return; + + channel.setName(`Members : ${member.guild.memberCount}`) +} \ No newline at end of file diff --git a/events/interactionCreate.2.js b/events/interactionCreate.2.js new file mode 100644 index 0000000..7126c97 --- /dev/null +++ b/events/interactionCreate.2.js @@ -0,0 +1,33 @@ +const reactionRole = require("../models/reactionRole"); + +module.exports = async (client, interaction) => { + if (!interaction.isButton() || !interaction.guild) return; + + const emoji = interaction?.component?.emoji; + + const menu = await reactionRole.findOne({ message: interaction.message.id }); + + if (!menu || menu.roles.length === 0 || !menu.roles.some(v => v.emoji === emoji.id || v.emoji === emoji.name)) return; + + const member = interaction.guild.members.cache.get(interaction.user.id); + + menu.roles.forEach(v => { + const role = interaction.guild.roles.cache.get(v.role); + + if ((v.emoji !== emoji.name && v.emoji !== emoji.id)) return; + + if (!member.roles.cache.has(role.id)) { + member.roles.add(role).then(() => { + interaction.reply({ content: `I gave you the **${role.name}** role in ${interaction.guild.name}`, ephemeral: true }) + }).catch(() => { + interaction.reply({ content: `I was unable to give you the role in ${interaction.guild.name}`, ephemeral: true }) + }) + } else { + member.roles.remove(role).then(() => { + interaction.reply({ content: `I removed the **${role.name}** role from you in ${interaction.guild.name}`, ephemeral: true }) + }).catch(() => { + interaction.reply({ content: `I was unable to remove a role from you in ${interaction.guild.name}`, ephemeral: true }) + }) + } + }) +} \ No newline at end of file diff --git a/events/interactionCreate.3.js b/events/interactionCreate.3.js new file mode 100644 index 0000000..63bff92 --- /dev/null +++ b/events/interactionCreate.3.js @@ -0,0 +1,62 @@ +const tickets = require('../models/tickets'); +const ticket = require('../models/ticket'); + +module.exports = async (client, interaction) => { + if (!interaction.isButton() || !interaction.guild) return; + + const data = await tickets.findOne({ guild: interaction.guildId, message: interaction.message.id }); + member = interaction.member; + + if (!data) return; + + const user_tickets = await ticket.find({ panel: data.name, user: interaction.user.id, closed: false }).lean(); + + if (data.banned.some(v => member.roles.cache.has(v))) return interaction.reply({ content: "You are banned from the panel", ephemeral: true }); + if (user_tickets.length >= data.max) return interaction.reply({ content: "You already made maximum tickets `(" + data.max + ")` you are allowed to make in this panel", ephemeral: true }); + + const overwrites = [{ + id: interaction.guild.roles.everyone.id, + deny: ["VIEW_CHANNEL"], + type: "role" + }, { + id: interaction.user.id, + allow: ["VIEW_CHANNEL"], + type: "member" + }]; + + data.moderators.forEach(v => overwrites.push({ id: v, allow: ["VIEW_CHANNEL"], type: "role" })); + + const channel = await interaction.guild.channels.create(`ticket - ${data.index + 1} `, { + reason: "for ticket system", + type: "GUILD_TEXT", + permissionOverwrites: overwrites + }); + + interaction.reply({ content: "ticket is created successfully", ephemeral: true }); + + channel.send({ content: `${interaction.user.toString()}, stay patient staff will be arving soon.` }); + + interaction.guild.channels.cache.get(data.logs)?.send({ + content: `${data.moderators.map(v => `<@&${v}>`).join(", ")}, A new ticket ( ${channel.toString()} ) was created go check it out`, + embeds: [{ + title: "New ticket created", + timestamps: Date.now(), + fields: [{ + name: "Panel", + value: data.name, + inline: true + }, { + name: "User", + value: interaction.user.username, + inline: true + }, { + name: "Ticket", + value: channel.toString(), + inline: true + }] + }] + }) + + await tickets.findOneAndUpdate({ guild: interaction.guildId, message: interaction.message.id }, { $inc: { index: 1 } }); + await ticket.create({ channel: channel.id, guild: interaction.guildId, user: interaction.user.id, panel: data.name }); +} \ No newline at end of file diff --git a/events/interactionCreate.4.js b/events/interactionCreate.4.js new file mode 100644 index 0000000..c765e8e --- /dev/null +++ b/events/interactionCreate.4.js @@ -0,0 +1,37 @@ +const suggestion = require("../models/suggestion"); + +module.exports = async (client, interaction) => { + if (!interaction.isButton()) return; + + const sug = await suggestion.findOne({ message: interaction.message?.id }); + + if (!sug) return; + await interaction.deferReply({ ephemeral: true }); + + if (sug.votes.up.includes(interaction.user.id) || sug.votes.down.includes(interaction.user.id)) return interaction.editReply({ + embeds: [{ + color: "RED", + title: "❌ Already voted" + }] + }); + + sug.votes[interaction.customId === "1" ? "up" : "down"]?.push(interaction.user.id); + await suggestion.findOneAndUpdate({ message: sug.message }, sug); + + interaction.editReply({ + embeds: [{ + color: "GREEN", + title: "✅ Voted Successfully" + }] + }); + const msg = await interaction.channel.messages.fetch(sug.message); + + if (!msg) return; + + msg.embeds[0].fields[0].value = sug.votes.up.length.toString(); + msg.embeds[0].fields[1].value = sug.votes.down.length.toString(); + + msg?.edit({ + embeds: msg.embeds + }) +} \ No newline at end of file diff --git a/events/interactionCreate.5.js b/events/interactionCreate.5.js new file mode 100644 index 0000000..41aa26b --- /dev/null +++ b/events/interactionCreate.5.js @@ -0,0 +1,50 @@ +const polls = require("../models/polls"); + +module.exports = async (client, interaction) => { + if (!interaction.isButton()) return; + + const pol = await polls.findOne({ message: interaction.message.id }); + + if (!pol) return; + + await interaction.deferReply({ + ephemeral: true + }); + + if (pol.voters.includes(interaction.user.id)) return interaction.editReply({ + embeds: [{ + color: "RED", + title: "❌ Already Voted!" + }] + }); + + pol.votes = pol.votes || {}; + + if (pol.votes[interaction.customId]) pol.votes[interaction.customId] += 1 + else pol.votes[interaction.customId] = 1; + + pol.voters.push(interaction.user.id); + + await polls.findOneAndUpdate({ message: pol.message }, pol); + + interaction.editReply({ + embeds: [{ + color: "GREEN", + title: "✅ Voted Successfully" + }] + }); + + const m = interaction.message; + + m.edit({ + components: m.components.map(row => { + row.components = row.components?.map(v => { + v.label = `${pol.votes[v.customId] || 0}`; + + return v; + }); + + return row; + }) + }) +} \ No newline at end of file diff --git a/events/interactionCreate.js b/events/interactionCreate.js new file mode 100644 index 0000000..d3badad --- /dev/null +++ b/events/interactionCreate.js @@ -0,0 +1,10 @@ +module.exports = (client, interaction) => { + if (!interaction.isCommand() && !interaction.isContextMenu()) return; + + try { + client.commands.get(interaction.commandName)?.run(client, interaction); + } catch (e) { + console.log(e); + interaction.reply({content: "SOMETHING WENT WRONG "}); + } +} \ No newline at end of file diff --git a/events/messageCreate.2.js b/events/messageCreate.2.js new file mode 100644 index 0000000..aa70069 --- /dev/null +++ b/events/messageCreate.2.js @@ -0,0 +1,48 @@ +const guildConfigs = require('../models/guildConfig'); +const users = require('../models/user_xp'); + +module.exports = async (client, message) => { + const data = await guildConfigs.findOne({ id: message.guild.id }) || {}; + + if (!data.xp || data?.ignoreXP?.includes(message.channel.id) || message.author.bot) return; + + const userData = await users.findOne({ user: message.author.id, guild: message.guild.id }) || await users.create({ user: message.author.id, guild: message.guild.id }); + + if (userData.lastXP + (data.xpTimeout || 1000) > Date.now()) return; + let xp = Math.floor(((Math.random() * (data.xpLimit.up - data.xpLimit.down)) + data.xpLimit.down) * data.xpRate), + reqXP = 100; + + userData.xp += xp; + + for (let i = 1; i <= userData.level; i++)reqXP += 5 * (i ^ 2) + (50 * i) + 100; + + if (userData.xp >= reqXP) { + userData.level += 1; + data.levelReward = data.levelReward || {}; + + const r = data.levelReward[userData.level], role = message.guild.roles.cache.get(r), + channel = message.guild.channels.cache.get(data.xpLevelUp.channel) || message.channel; + + if (r !==undefined) { + message.member.roles.add(role, `Level reward for reaching ${userData.level} level`).then(() => { + reply(data.levelRewardMessage.success, channel, message, userData, data, role) + }).catch(() => { + reply(data.levelRewardMessage.fail, channel, message, userData, data, role); + }) + } else { + reply(data.xpLevelUp.message, channel, message, userData, data); + } + } + + await users.findOneAndUpdate({ user: message.author.id, guild: message.guild.id }, { + xp: userData.xp, + level: userData.level, + lastXP: Date.now() + }); +} + +function reply(content, channel, message, userData, data, role) { + if (!data.xpLevelUp.enable) return; + + channel.send({ content: content.replace(/{mention}/g, message.author.toString()).replace(/{level}/, userData.level).replace(/{xp}/, userData.xp).replace(/{role}/, role?.name) }); +} \ No newline at end of file diff --git a/events/messageCreate.js b/events/messageCreate.js new file mode 100644 index 0000000..075133a --- /dev/null +++ b/events/messageCreate.js @@ -0,0 +1,73 @@ +const guildConfigs = require('../models/guildConfig'); +const users = require('../models/userConfig'); +const pokecord = require('pokecord'); +const { MessageEmbed, MessageCollector } = require('discord.js'); + +module.exports = async (client, message) => { + const p = ""; + if (message.author.bot) return; + + const data = await guildConfigs.findOne({ id: message.guild.id }); + + if (!data || !data.pokemon.spawn) return; + + data.pokemon.points += Math.floor(Math.random() * 3) + 1; + + if (data.pokemon.points < data.pokemon.afterPoints) return guildConfigs.findOneAndUpdate({ id: message.guild.id }, { "pokemon.points": data.pokemon.points }); + + await guildConfigs.findOneAndUpdate({ id: message.guild.id }, { "pokemon.points": 0 }); + + const pokemon = await pokecord.Spawn(); + + const channel = message.guild.channels.cache.get(data.pokemon.spawnAt) || message.channel; + + const embed = new MessageEmbed() + .setTitle("A new pokemon has appeared") + .setImage(pokemon.imageURL) + .setDescription(`Catch pokemon by typing \`${p}catch < pokemon name >\``).setColor('#353A3C'); + + const msg = await channel.send({ embeds: [embed] }); + + let catched = false; + + msg.channel.awaitMessages({ + time: 60000, + errors: ['time'], + filter: (m) => m.content.toLowerCase() === `${p}catch ${pokemon.name.toLowerCase()}` || m.content.toLowerCase() === `${p}c ${pokemon.name.toLowerCase()}`, + max: 1 + }).then(async col => { + catched = true; + const msg = col.first(); + + await users.findOneAndUpdate({ user: msg.author.id }, { $push: { pokemons: pokemon.id } }) || await users.create({ + user: msg.author.id, + pokemons: [pokemon.id] + }); + + msg.reply(`You successfully caught \`${pokemon.name}\` pokemon`); + }).catch(() => { + embed.setTitle("Pokemon ran away") + .setImage(pokemon.imageURL) + msg.edit({ embeds: [embed] }); + }) + + const col = new MessageCollector(message.channel, { filter: (m) => m.content.toLowerCase() === `${p}h` || m.content.toLowerCase() === `${p}hint`, time: 55000 }) + + let t = 0; + col.on('collect', (msg) => { + if (catched) return col.stop(); + + if (Date.now() - t < 10000) return msg.reply("You are on a timeout to use the hint command"); + t = Date.now(); + + let hint = pokemon.name, i = pokmeon.name.length / 2; + + while (--i >= 0) { + let p = Math.floor(Math.random() * pokemon.length); + + hint = hint.replace(hint[p], "_") + } + + msg.reply(`Hint for this pokemon is ${hint}`) + }) +} \ No newline at end of file diff --git a/events/ready.js b/events/ready.js new file mode 100644 index 0000000..cd330cf --- /dev/null +++ b/events/ready.js @@ -0,0 +1,11 @@ +const { MessageAttachment } = require('discord.js'); + + +module.exports = async (client) => { + console.log("Client is up"); + + + client.application.commands.set([...client.commands.map(v => v.data)]); + + +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..f618c59 --- /dev/null +++ b/index.js @@ -0,0 +1,119 @@ +const fs = require('fs'); +const path = require('path'); + +// Ensure the commands and events directories exist +const commandsDir = path.join(__dirname, './commands'); +const eventsDir = path.join(__dirname, './events'); + +if (!fs.existsSync(commandsDir)) { + fs.mkdirSync(commandsDir, { recursive: true }); +} + +if (!fs.existsSync(eventsDir)) { + fs.mkdirSync(eventsDir, { recursive: true }); +} + +require("http").createServer((_, res) => res.end('Bot Online')).listen(8080) +const Discord = require('discord.js'); +const { readdirSync } = require('fs'); +const { join } = require('path'); +const mongoose = require('mongoose'); +require('dotenv').config(); + +// Added to suppress the Mongoose warning +mongoose.set('strictQuery', true); +mongoose.connect(process.env.MONGO_URI, { useUnifiedTopology: true, useNewUrlParser: true }); + +const client = new Discord.Client({ + intents: 131071 +}); + +client.owners = [process.env.OWNER_ID]; + +client.commands = new Discord.Collection(); +client.categories = readdirSync(join(__dirname, "./commands")); + +readdirSync(join(__dirname, "./events")).forEach(file => + client.on(file.split(".")[0], (...args) => require(`./events/${file}`)(client, ...args)) +); + +for (let i = 0; i < client.categories.length; i++) { + const commands = readdirSync(join(__dirname, `./commands/${client.categories[i]}`)).filter(file => file.endsWith(".js")); + + for (let j = 0; j < commands.length; j++) { + const command = require(`./commands/${client.categories[i]}/${commands[j]}`); + if (!command || !command?.data?.name || typeof (command?.run) !== "function") continue; + command.category = client.categories[i]; + client.commands.set(command.data.name, command); + } +} + +const { GiveawaysManager } = require("discord-giveaways"); +client.giveawaysManager = new GiveawaysManager(client, { + storage: "./storage/giveaways.json", + default: { + botsCanWin: false, + embedColor: "#2F3136", + reaction: "🎉", + lastChance: { + enabled: true, + content: `🚨 **Last chance to enter** 🚨`, + threshold: 5000, + embedColor: '#FF0000' + } + } +}); + +client.on('ready', () => { + console.log('Tiger Bot Online "NextEra on Top!"') +}); + +process.on("unhandledRejection", (reason, p) => { + console.log(" [Error_Handling] :: Unhandled Rejection/Catch"); + console.log(reason, p); +}); +process.on("uncaughtException", (err, origin) => { + console.log(" [Error_Handling] :: Uncaught Exception/Catch"); + console.log(err, origin); +}); +process.on("uncaughtExceptionMonitor", (err, origin) => { + console.log(" [Error_Handling] :: Uncaught Exception/Catch (MONITOR)"); + console.log(err, origin); +}); + +// Removed deprecated multipleResolves event +// process.on("multipleResolves", (type, promise, reason) => { +// console.log(" [Error_Handling] :: Multiple Resolves"); +// console.log(type, promise, reason); +// }); + +client.login(process.env.TOKEN); + +// Ensure proper handling of AbortController +client.on('shardError', error => { + if (error.name === 'AbortError') { + console.error('A websocket connection was aborted:', error); + } else { + console.error('A websocket connection encountered an error:', error); + } +}); + +// Fix DiscordAPIError by ensuring correct "type" field +const commands = [ + { + name: 'command1', + description: 'Description for command1', + options: [ + { + type: 1, // Ensure this value is between 1 and 11 + name: 'option1', + description: 'Description for option1', + required: true, + }, + // Add other options here + ], + }, + // Add other commands here +]; + +client.application?.commands.set(commands); diff --git a/models/guildConfig.js b/models/guildConfig.js new file mode 100644 index 0000000..ee03697 --- /dev/null +++ b/models/guildConfig.js @@ -0,0 +1,106 @@ +const { Schema, model } = require('mongoose'); + +const guildStats = new Schema({ + id: String, + pokemon: { + spawn: { + type: Boolean, + default: false + }, + afterPoints: { + type: Number, + default: 100 + }, + points: { + type: Number, + default: 0 + }, + spawnAt: String, + lastMessage: String + }, + welcome: { + enable: Boolean, + channel: String, + message: { + type: String, + default: "Welcome {mention}, To **{server}**\nNow we are a family of {members}" + } + }, + + ignoreXP: [String], + xp: { + type: Boolean, + default: false + }, + xpTimeout: { + type: Number, + default: 60000 + }, + xpLevelUp: { + message: { + type: String, + default: "Congrats {mention} 🎉 on reaching {level} level" + }, + channel: { + type: String, + default: "0" + }, + enable: { + type: Boolean, + default: true + } + }, + xpRate: { + type: Number, + default: 1 + }, + xpLimit: { + up: { + type: Number, + default: 20 + }, + down: { + type: Number, + default: 5 + }, + }, + tags: [{ + name: String, + response: String, + embed: Boolean, + case: Boolean, + include: Boolean, + }], + levelRewardMessage: { + success: { + type: String, + default: "Congrats {mention} 🎉 on reaching {level} level, and you got **{role}** role as a reward 🎉" + }, + fail: { + type: String, + default: "Congrats {mention} 🎉 on reaching {level} level, you were supposed to get **{role}** role as a reward but I was unable to give you the role" + }, + }, + levelReward: Object, + /** + levelReward = { + "1": "roleid-1", + 2: "another-id" + // etc + } + */ + leave: { + enable: { + type: Boolean, + default: false + }, + channel: String, + message: { + type: String, + default: `**{user}** left the server.` + } + }, + suggestion:String +}) + +module.exports = model("Guild_Config", guildStats); \ No newline at end of file diff --git a/models/guildStats.js b/models/guildStats.js new file mode 100644 index 0000000..aae2b8f --- /dev/null +++ b/models/guildStats.js @@ -0,0 +1,8 @@ +const { Schema, model } = require('mongoose'); + +const guildStats = new Schema({ + guild: String, + members: String, +}) + +module.exports = model("Guild_Stats", guildStats); \ No newline at end of file diff --git a/models/polls.js b/models/polls.js new file mode 100644 index 0000000..8bf2e84 --- /dev/null +++ b/models/polls.js @@ -0,0 +1,20 @@ +const { Schema, model } = require('mongoose'); + +const Poll = new Schema({ + question: String, + message: String, + channel: String, + guild: String, + votes: Object, + voters: { + type: [String], + default: [] + }, + emojis: [String], + ended: { + type: Boolean, + default: false + } +}) + +module.exports = model("polls", Poll); \ No newline at end of file diff --git a/models/reactionRole.js b/models/reactionRole.js new file mode 100644 index 0000000..351209d --- /dev/null +++ b/models/reactionRole.js @@ -0,0 +1,13 @@ +const { Schema, model } = require('mongoose'); + +const reactionRole = new Schema({ + name: String, + guild: String, + message: String, + roles: [{ + role: String, + emoji: String, + }] +}) + +module.exports = model("Reaction_Role_Menu", reactionRole); \ No newline at end of file diff --git a/models/suggestion.js b/models/suggestion.js new file mode 100644 index 0000000..cb292fd --- /dev/null +++ b/models/suggestion.js @@ -0,0 +1,21 @@ +const { Schema, model } = require('mongoose'); + +const SuggestionSchema = new Schema({ + suggestion: String, + user: String, + message: String, + channel: String, + guild: String, + votes: { + up: { + type: [String], + default: [] + }, down: { + type: [String], + default: [] + } + }, + createdAt: Number, +}) + +module.exports = model("Suggestions-Data", SuggestionSchema); \ No newline at end of file diff --git a/models/ticket.js b/models/ticket.js new file mode 100644 index 0000000..5ab2281 --- /dev/null +++ b/models/ticket.js @@ -0,0 +1,14 @@ +const { Schema, model } = require('mongoose'); + +const Ticket = new Schema({ + panel: String, + channel: String, + guild: String, + user: String, + closed: { + type: Boolean, + default: false + } +}) + +module.exports = model("ticket", Ticket); \ No newline at end of file diff --git a/models/tickets.js b/models/tickets.js new file mode 100644 index 0000000..b4e8b24 --- /dev/null +++ b/models/tickets.js @@ -0,0 +1,26 @@ +const { Schema, model } = require('mongoose'); + +const Tickets = new Schema({ + name: String, + guild: String, + max: { + type: Number, + default: 69 + }, + logs: String, + index: { type: Number, default: 0 }, + message: { + type: String, + default: 0 + }, + moderators: { + type: [String], + default: [] + }, + banned: { + type: [String], + default: [] + } +}) + +module.exports = model("ticket_panels", Tickets); \ No newline at end of file diff --git a/models/userConfig.js b/models/userConfig.js new file mode 100644 index 0000000..4c22a42 --- /dev/null +++ b/models/userConfig.js @@ -0,0 +1,9 @@ +const { Schema, model } = require('mongoose'); + +const userConfig = new Schema({ + user: String, + pokemons: [String], + badges:[String] +}) + +module.exports = model("User_Pokemons", userConfig); \ No newline at end of file diff --git a/models/user_xp.js b/models/user_xp.js new file mode 100644 index 0000000..c5519b6 --- /dev/null +++ b/models/user_xp.js @@ -0,0 +1,20 @@ +const { Schema, model } = require('mongoose'); + +const userXPConfig = new Schema({ + user: String, + guild: String, + xp: { + type: Number, + default: 0 + }, + level: { + type: Number, + default: 0 + }, + lastXP: { + type: Number, + default: 0 + }, +}) + +module.exports = model("User_XP", userXPConfig); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e602492 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2515 @@ +{ + "name": "tiger-bot", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tiger-bot", + "version": "1.0.0", + "dependencies": { + "@discordjs/builders": "^1.10.1", + "@discordjs/rest": "^2.4.3", + "discord-fight-game": "^1.0.3", + "discord-giveaways": "^4.5.1", + "discord-rock-paper-scissor": "^1.2.2", + "discord.js": "^14.18.0", + "dotenv": "^16.4.7", + "mathjs": "^14.4.0", + "mongodb": "^6.15.0", + "mongoose": "^6.13.8", + "node-emoji": "^2.2.0", + "pokecord": "^1.0.1" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.782.0.tgz", + "integrity": "sha512-Zad5x3L5K+PuhdY2v8Q0tsafmVBa2SJJxNukPzXM1APxW7FpDVMxcdSzjfCfX7CvSpohR8zDIEROqMfoUisaTw==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-node": "3.782.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.782.0.tgz", + "integrity": "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", + "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/core": "^3.2.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.782.0.tgz", + "integrity": "sha512-rWUmO9yZUBkM2CrTN9lm5X7Ubl7bRPBKyq5hvWpVNSa6BpUcmAQ6CUwEACOc+9cXmUqmKFhP6MGT2GpVlRrzDQ==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", + "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", + "optional": true, + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", + "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", + "optional": true, + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-stream": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.782.0.tgz", + "integrity": "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw==", + "optional": true, + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.782.0.tgz", + "integrity": "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-ini": "3.782.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", + "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", + "optional": true, + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.782.0.tgz", + "integrity": "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso": "3.782.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/token-providers": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.782.0.tgz", + "integrity": "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ==", + "optional": true, + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.782.0.tgz", + "integrity": "sha512-EP0viOqgw9hU8Lt25Rc7nPlPKMCsO7ntVGSA5TDdjaOHU9wN1LdKwRmFWYE+ii0FIPmagJmgJJoHdpq85oqsUw==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.782.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-cognito-identity": "3.782.0", + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-ini": "3.782.0", + "@aws-sdk/credential-provider-node": "3.782.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", + "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", + "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", + "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.782.0.tgz", + "integrity": "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg==", + "optional": true, + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@smithy/core": "^3.2.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.782.0.tgz", + "integrity": "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz", + "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.782.0.tgz", + "integrity": "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg==", + "optional": true, + "dependencies": { + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", + "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.782.0.tgz", + "integrity": "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "@smithy/util-endpoints": "^3.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.723.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.723.0.tgz", + "integrity": "sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", + "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.782.0.tgz", + "integrity": "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA==", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.10.1.tgz", + "integrity": "sha512-OWo1fY4ztL1/M/DUyRPShB4d/EzVfuUvPTRRHRIt/YxBrUYSz0a+JicD5F5zHFoNs2oTuWavxCOVFV1UljHTng==", + "dependencies": { + "@discordjs/formatters": "^0.6.0", + "@discordjs/util": "^1.1.1", + "@sapphire/shapeshift": "^4.0.0", + "discord-api-types": "^0.37.119", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.4", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.0.tgz", + "integrity": "sha512-YIruKw4UILt/ivO4uISmrGq2GdMY6EkoTtD0oS0GvkJFRZbTSdPhzYiUILbJ/QslsvC9H9nTgGgnarnIl4jMfw==", + "dependencies": { + "discord-api-types": "^0.37.114" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.3.tgz", + "integrity": "sha512-+SO4RKvWsM+y8uFHgYQrcTl/3+cY02uQOH7/7bKbVZsTfrfpoE62o5p+mmV+s7FVhTX82/kQUGGbu4YlV60RtA==", + "dependencies": { + "@discordjs/collection": "^2.1.1", + "@discordjs/util": "^1.1.1", + "@sapphire/async-queue": "^1.5.3", + "@sapphire/snowflake": "^3.5.3", + "@vladfrangu/async_event_emitter": "^2.4.6", + "discord-api-types": "^0.37.119", + "magic-bytes.js": "^1.10.0", + "tslib": "^2.6.3", + "undici": "6.21.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz", + "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/util": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz", + "integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.1.tgz", + "integrity": "sha512-PBvenhZG56a6tMWF/f4P6f4GxZKJTBG95n7aiGSPTnodmz4N5g60t79rSIAq7ywMbv8A4jFtexMruH+oe51aQQ==", + "dependencies": { + "@discordjs/collection": "^2.1.0", + "@discordjs/rest": "^2.4.3", + "@discordjs/util": "^1.1.0", + "@sapphire/async-queue": "^1.5.2", + "@types/ws": "^8.5.10", + "@vladfrangu/async_event_emitter": "^2.2.4", + "discord-api-types": "^0.37.119", + "tslib": "^2.6.2", + "ws": "^8.17.0" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz", + "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.1.tgz", + "integrity": "sha512-1NCa8GsZ+OFLTw5KkKQS22wLS+Rs+y02sgkhr99Pm4OSXtSDHCJyq0uscPF0qA86ipGYH4PwtC2+a8Y4RKkCcg==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz", + "integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz", + "integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v16" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.3.tgz", + "integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.2.tgz", + "integrity": "sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.0.tgz", + "integrity": "sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.2.0.tgz", + "integrity": "sha512-k17bgQhVZ7YmUvA8at4af1TDpl0NDMBuBKJl8Yg0nrefwmValU+CnA5l/AriVdQNthU/33H3nK71HrLgqOPr1Q==", + "optional": true, + "dependencies": { + "@smithy/middleware-serde": "^4.0.3", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-stream": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz", + "integrity": "sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.2.tgz", + "integrity": "sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ==", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^5.1.0", + "@smithy/querystring-builder": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.2.tgz", + "integrity": "sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.2.tgz", + "integrity": "sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.2.tgz", + "integrity": "sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.0.tgz", + "integrity": "sha512-xhLimgNCbCzsUppRTGXWkZywksuTThxaIB0HwbpsVLY5sceac4e1TZ/WKYqufQLaUy+gUSJGNdwD2jo3cXL0iA==", + "optional": true, + "dependencies": { + "@smithy/core": "^3.2.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-middleware": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.0.tgz", + "integrity": "sha512-2zAagd1s6hAaI/ap6SXi5T3dDwBOczOMCSkkYzktqN1+tzbk1GAsHNAdo/1uzxz3Ky02jvZQwbi/vmDA6z4Oyg==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/service-error-classification": "^4.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.3.tgz", + "integrity": "sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.2.tgz", + "integrity": "sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz", + "integrity": "sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==", + "optional": true, + "dependencies": { + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.4.tgz", + "integrity": "sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==", + "optional": true, + "dependencies": { + "@smithy/abort-controller": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/querystring-builder": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.2.tgz", + "integrity": "sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.0.tgz", + "integrity": "sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.2.tgz", + "integrity": "sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.2.tgz", + "integrity": "sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz", + "integrity": "sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.2.tgz", + "integrity": "sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.2.tgz", + "integrity": "sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw==", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-uri-escape": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.0.tgz", + "integrity": "sha512-Qs65/w30pWV7LSFAez9DKy0Koaoh3iHhpcpCCJ4waj/iqwsuSzJna2+vYwq46yBaqO5ZbP9TjUsATUNxrKeBdw==", + "optional": true, + "dependencies": { + "@smithy/core": "^3.2.0", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-stream": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.2.tgz", + "integrity": "sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ==", + "optional": true, + "dependencies": { + "@smithy/querystring-parser": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", + "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", + "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.8.tgz", + "integrity": "sha512-ZTypzBra+lI/LfTYZeop9UjoJhhGRTg3pxrNpfSTQLd3AJ37r2z4AXTKpq1rFXiiUIJsYyFgNJdjWRGP/cbBaQ==", + "optional": true, + "dependencies": { + "@smithy/property-provider": "^4.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.8.tgz", + "integrity": "sha512-Rgk0Jc/UDfRTzVthye/k2dDsz5Xxs9LZaKCNPgJTRyoyBoeiNCnHsYGOyu1PKN+sDyPnJzMOz22JbwxzBp9NNA==", + "optional": true, + "dependencies": { + "@smithy/config-resolver": "^4.1.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz", + "integrity": "sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.2.tgz", + "integrity": "sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.2.tgz", + "integrity": "sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==", + "optional": true, + "dependencies": { + "@smithy/service-error-classification": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.0.tgz", + "integrity": "sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ==", + "optional": true, + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/types": "^4.2.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@types/node": { + "version": "22.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", + "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz", + "integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "optional": true + }, + "node_modules/bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/complex.js": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.4.2.tgz", + "integrity": "sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g==", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/discord-api-types": { + "version": "0.37.119", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.119.tgz", + "integrity": "sha512-WasbGFXEB+VQWXlo6IpW3oUv73Yuau1Ig4AZF/m13tXcTKnMpc/mHjpztIlz4+BM9FG9BHQkEXiPto3bKduQUg==" + }, + "node_modules/discord-fight-game": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/discord-fight-game/-/discord-fight-game-1.0.3.tgz", + "integrity": "sha512-E/jy5IPQWvBuUR6AjKd8futJV62pl+m7veS43UUWMt/9U0OnedWd2YgXlhoCrgARQncKNZJ0nFwyk03lGGFKLw==", + "dependencies": { + "discord.js": "^13.1.0" + } + }, + "node_modules/discord-fight-game/node_modules/@discordjs/builders": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", + "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", + "deprecated": "no longer supported", + "dependencies": { + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.36.2", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord-fight-game/node_modules/@discordjs/builders/node_modules/discord-api-types": { + "version": "0.36.3", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", + "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + }, + "node_modules/discord-fight-game/node_modules/@discordjs/collection": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz", + "integrity": "sha512-R5i8Wb8kIcBAFEPLLf7LVBQKBDYUL+ekb23sOgpkpyGT+V4P7V83wTxcsqmX+PbqHt4cEHn053uMWfRqh/Z/nA==", + "deprecated": "no longer supported", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord-fight-game/node_modules/@sapphire/shapeshift": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz", + "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v16" + } + }, + "node_modules/discord-fight-game/node_modules/discord-api-types": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.33.5.tgz", + "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" + }, + "node_modules/discord-fight-game/node_modules/discord.js": { + "version": "13.17.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.17.1.tgz", + "integrity": "sha512-h13kUf+7ZaP5ZWggzooCxFutvJJvugcAO54oTEIdVr3zQWi0Sf/61S1kETtuY9nVAyYebXR/Ey4C+oWbsgEkew==", + "dependencies": { + "@discordjs/builders": "^0.16.0", + "@discordjs/collection": "^0.7.0", + "@sapphire/async-queue": "^1.5.0", + "@types/node-fetch": "^2.6.3", + "@types/ws": "^8.5.4", + "discord-api-types": "^0.33.5", + "form-data": "^4.0.0", + "node-fetch": "^2.6.7", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.6.0", + "npm": ">=7.0.0" + } + }, + "node_modules/discord-giveaways": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/discord-giveaways/-/discord-giveaways-4.5.1.tgz", + "integrity": "sha512-aSOD7IiCqfJ2sU1GbdH0EP/xwuXZW/h7+8RH6LzgfZaYy2V89O0qKwbe52Dy2ToymAexPhEGpDKZHrm6Vd0Jqw==", + "dependencies": { + "deepmerge": "^4.2.2", + "serialize-javascript": "^5.0.1" + } + }, + "node_modules/discord-rock-paper-scissor": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/discord-rock-paper-scissor/-/discord-rock-paper-scissor-1.2.2.tgz", + "integrity": "sha512-FMjSEIe+uEs0Cl7RCRLkc+kGpjx/cpZiXq1FdY6+e2UiYEwZ9E7LQksDO2sYDOnR0qbKp2vNLilSmG1hANEjGA==", + "dependencies": { + "discord.js": "^14.7.1" + } + }, + "node_modules/discord.js": { + "version": "14.18.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.18.0.tgz", + "integrity": "sha512-SvU5kVUvwunQhN2/+0t55QW/1EHfB1lp0TtLZUSXVHDmyHTrdOj5LRKdR0zLcybaA15F+NtdWuWmGOX9lE+CAw==", + "dependencies": { + "@discordjs/builders": "^1.10.1", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.6.0", + "@discordjs/rest": "^2.4.3", + "@discordjs/util": "^1.1.1", + "@discordjs/ws": "^1.2.1", + "@sapphire/snowflake": "3.5.3", + "discord-api-types": "^0.37.119", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "tslib": "^2.6.3", + "undici": "6.21.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-latex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", + "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "optional": true, + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.2.2.tgz", + "integrity": "sha512-uXBDv5knpYmv/2gLzWQ5mBHGBRk9wcKTeWu6GLTUEQfjCxO09uM/mHDrojlL+Q1mVGIIFo149Gba7od1XPgSzQ==", + "engines": { + "node": ">= 12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==" + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, + "node_modules/kareem": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "node_modules/magic-bytes.js": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz", + "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mathjs": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-14.4.0.tgz", + "integrity": "sha512-CpoYDhNENefjIG9wU9epr+0pBHzlaySfpWcblZdAf5qXik/j/U8eSmx/oNbmXO0F5PyfwPGVD/wK4VWsTho1SA==", + "dependencies": { + "@babel/runtime": "^7.26.10", + "complex.js": "^2.2.5", + "decimal.js": "^10.4.3", + "escape-latex": "^1.2.0", + "fraction.js": "^5.2.1", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^4.2.1" + }, + "bin": { + "mathjs": "bin/cli.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mongodb": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.15.0.tgz", + "integrity": "sha512-ifBhQ0rRzHDzqp9jAQP6OwHSH7dbYIQjD3SbJs9YYk9AikKEettW/9s/tbSFDTpXcRbF+u1aLrhHxDFaYtZpFQ==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.3", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/mongodb/node_modules/bson": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.3.tgz", + "integrity": "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/mongoose": { + "version": "6.13.8", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.13.8.tgz", + "integrity": "sha512-JHKco/533CyVrqCbyQsnqMpLn8ZCiKrPDTd2mvo2W7ygIvhygWjX2wj+RPjn6upZZgw0jC6U51RD7kUsyK8NBg==", + "dependencies": { + "bson": "^4.7.2", + "kareem": "2.5.1", + "mongodb": "4.17.2", + "mpath": "0.9.0", + "mquery": "4.0.3", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/mongoose/node_modules/mongodb": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.2.tgz", + "integrity": "sha512-mLV7SEiov2LHleRJPMPrK2PMyhXFZt2UQLC4VD4pnth3jMjYKHhtqfwwkkvS/NXuo/Fp3vbhaNcXrIDaLRb9Tg==", + "dependencies": { + "bson": "^4.7.2", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "@mongodb-js/saslprep": "^1.1.0" + } + }, + "node_modules/mongoose/node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongoose/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", + "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/pokecord": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pokecord/-/pokecord-1.0.1.tgz", + "integrity": "sha512-2HSZ5DKlwh/Fc+56bgu2JcSV5fRKIlNKOg6TrpgNkPhbdOFpPpG4oXzOySm8rzeFA1IZtTqb6GCREt8AyWpcsw==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, + "node_modules/serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/sift": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "node_modules/strnum": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "optional": true + }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "node_modules/tr46": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.0.tgz", + "integrity": "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-mixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/typed-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz", + "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/undici": { + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", + "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7de3d77 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "tiger-bot", + "version": "1.0.0", + "description": "An Advanced Beta Multipurpose Bot with Slash Commands", + "main": "index.js", + "scripts": { + "dev": "node index.js" + }, + "author": "MisterBashyal", + "dependencies": { + "@discordjs/builders": "^1.10.1", + "@discordjs/rest": "^2.4.3", + "discord-fight-game": "^1.0.3", + "discord-giveaways": "^4.5.1", + "discord-rock-paper-scissor": "^1.2.2", + "discord.js": "^14.18.0", + "dotenv": "^16.4.7", + "mathjs": "^14.4.0", + "mongodb": "^6.15.0", + "mongoose": "^6.13.8", + "node-emoji": "^2.2.0", + "pokecord": "^1.0.1" + } +} diff --git a/storage/giveaway.json b/storage/giveaway.json new file mode 100644 index 0000000..e69de29 diff --git a/storage/giveaways.json b/storage/giveaways.json new file mode 100644 index 0000000..4aae146 --- /dev/null +++ b/storage/giveaways.json @@ -0,0 +1 @@ +[{"messageId":"965488714274996234","channelId":"957300151893000222","guildId":"937679957608517633","startAt":1650260847331,"endAt":1650264447331,"ended":true,"winnerCount":1,"prize":"ddf","messages":{"giveaway":"🎉 **GIVEAWAY** 🎉","giveawayEnded":"🎉 **GIVEAWAY ENDED** 🎉","inviteToParticipate":"React with 🎉 to participate!","winMessage":"Congratulations, {winners}! You won **{this.prize}**!","drawing":"Ends: **{timestamp}**","dropMessage":"Be the first to react with 🎉 !","embedFooter":"Giveaways","noWinner":"Giveaway cancelled, no valid participations.","winners":"winner(s)","endedAt":"Ended at","hostedBy":"Hosted by: {this.hostedBy}"},"bonusEntries":"[{\"bonus\":function anonymous(member\n) {\nreturn member.roles.cache.some((r) => r.name === 'undefined') ? null : null\n},\"cumulative\":false}]","extraData":{"server":"null","role":"null"}},{"messageId":"965489570705719326","channelId":"957300151893000222","guildId":"937679957608517633","startAt":1650261051530,"endAt":1650261111530,"ended":true,"winnerCount":1,"prize":"ddf","messages":{"giveaway":"🎉 **GIVEAWAY** 🎉","giveawayEnded":"🎉 **GIVEAWAY ENDED** 🎉","inviteToParticipate":"React with 🎉 to participate!","winMessage":"Congratulations, {winners}! You won **{this.prize}**!","drawing":"Ends: **{timestamp}**","dropMessage":"Be the first to react with 🎉 !","embedFooter":"Giveaways","noWinner":"Giveaway cancelled, no valid participations.","winners":"winner(s)","endedAt":"Ended at","hostedBy":"Hosted by: {this.hostedBy}"},"bonusEntries":"[{\"bonus\":function anonymous(member\n) {\nreturn member.roles.cache.some((r) => r.name === 'undefined') ? null : null\n},\"cumulative\":false}]","winnerIds":["751739804844032022"],"extraData":{"server":"null","role":"null"}},{"messageId":"965893831021178910","channelId":"965660452422049823","guildId":"937679957608517633","startAt":1650357434672,"endAt":1650357554672,"ended":true,"winnerCount":1,"prize":"f","messages":{"giveaway":"🎉 **GIVEAWAY** 🎉","giveawayEnded":"🎉 **GIVEAWAY ENDED** 🎉","inviteToParticipate":"React with 🎉 to participate!","winMessage":"Congratulations, {winners}! You won **{this.prize}**!","drawing":"Ends: **{timestamp}**","dropMessage":"Be the first to react with 🎉 !","embedFooter":"Giveaways","noWinner":"Giveaway cancelled, no valid participations.","winners":"winner(s)","endedAt":"Ended at","hostedBy":"Hosted by: {this.hostedBy}"},"bonusEntries":"[{\"bonus\":function anonymous(member\n) {\nreturn member.roles.cache.some((r) => r.name === 'undefined') ? null : null\n},\"cumulative\":false}]","winnerIds":["872594340973776967"],"extraData":{"server":"null","role":"null"}},{"messageId":"968813525147463750","channelId":"962232693221892106","guildId":"937679957608517633","startAt":1651053544022,"endAt":1651053604022,"ended":true,"winnerCount":1,"prize":"100k","messages":{"giveaway":"🎉 **GIVEAWAY** 🎉","giveawayEnded":"🎉 **GIVEAWAY ENDED** 🎉","inviteToParticipate":"React with 🎉 to participate!","winMessage":"Congratulations, {winners}! You won **{this.prize}**!","drawing":"Ends: **{timestamp}**","dropMessage":"Be the first to react with 🎉 !","embedFooter":"Giveaways","noWinner":"Giveaway cancelled, no valid participations.","winners":"winner(s)","endedAt":"Ended at","hostedBy":"Hosted by: {this.hostedBy}"},"bonusEntries":"[{\"bonus\":function anonymous(member\n) {\nreturn member.roles.cache.some((r) => r.name === 'undefined') ? null : null\n},\"cumulative\":false}]","winnerIds":["751739804844032022"],"extraData":{"server":"null","role":"null"}},{"messageId":"981078174832140288","channelId":"946747493650169910","guildId":"946747493650169907","startAt":1653977664315,"endAt":1654064064315,"ended":false,"winnerCount":1,"prize":"test","messages":{"giveaway":"🎉 **GIVEAWAY** 🎉","giveawayEnded":"🎉 **GIVEAWAY ENDED** 🎉","inviteToParticipate":"React with 🎉 to participate!","winMessage":"Congratulations, {winners}! You won **{this.prize}**!","drawing":"Ends: **{timestamp}**","dropMessage":"Be the first to react with 🎉 !","embedFooter":"Giveaways","noWinner":"Giveaway cancelled, no valid participations.","winners":"winner(s)","endedAt":"Ended at","hostedBy":"Hosted by: {this.hostedBy}"},"bonusEntries":"[{\"bonus\":function anonymous(member\n) {\nreturn member.roles.cache.some((r) => r.name === 'undefined') ? null : null\n},\"cumulative\":false}]","extraData":{"server":"null","role":"null"}}] \ No newline at end of file diff --git a/utility/commandInfo.js b/utility/commandInfo.js new file mode 100644 index 0000000..0b0ed7e --- /dev/null +++ b/utility/commandInfo.js @@ -0,0 +1,16 @@ +module.exports = (command) => { + return command?.data ? { + title: `${command.data.name[0].toUpperCase() + command.data.name.slice(1)}'s Information 📑`, + description: `\`${command.data.description || "No Description"}\`\n\n${command.data.options?.length > 0 ? "Below is the list of otptions of this command" : ""}`, + fields: command.data.options?.map(v => { + return { + name: v.name, + value: `\`${v.description}\`` + } + }), + color: "BLUE" + } : { + title: "❌ Invalid command was provided", + color: "RED" + } +} \ No newline at end of file diff --git a/utility/pagginations.js b/utility/pagginations.js new file mode 100644 index 0000000..0493121 --- /dev/null +++ b/utility/pagginations.js @@ -0,0 +1,73 @@ +const { MessageActionRow, MessageButton } = require("discord.js"); + +module.exports = async (interaction, pages, time = 60000) => { + if (!interaction || !pages || !(pages?.length > 0) || !(time > 10000)) throw new Error("Invalid parameters"); + + let index = 0, row = new MessageActionRow().addComponents([new MessageButton({ + type: "BUTTON", + customId: "1", + emoji: "◀", + style: "PRIMARY", + disabled: true + }), new MessageButton({ + type: "BUTTON", + customId: "2", + emoji: "▶", + style: "PRIMARY", + disabled: pages.length < 2 + }), new MessageButton({ + type: "BUTTON", + customId: "3", + emoji: "❌", + style: "DANGER" + })]); + + let data = { + embeds: [pages[index]], + components: [row], + fetchReply: true + }; + + const msg = interaction.replied ? await interaction.followUp(data) : await interaction.reply(data); + + const col = msg.createMessageComponentCollector({ + filter: i => i.user.id === interaction?.user?.id || interaction?.author?.id, + time + }); + + col.on('collect', (i) => { + if (i.customId === "1") index--; + else if (i.customId === "2") index++; + else return col.stop(); + + row.components = [new MessageButton({ + type: "BUTTON", + customId: "1", + emoji: "◀", + style: "PRIMARY", + disabled: index === 0 + }),new MessageButton({ + type: "BUTTON", + customId: "2", + emoji: "▶", + style: "PRIMARY", + disabled: index === pages.length - 1 + }),new MessageButton({ + type: "BUTTON", + customId: "3", + emoji: "❌", + style: "DANGER" + })]; + + i.update({ + components: [row], + embeds: [pages[index]] + }) + }); + + col.on('end', () => { + msg.edit({ + components: [] + }) + }) +} \ No newline at end of file diff --git a/utils/message.js b/utils/message.js new file mode 100644 index 0000000..b797b6c --- /dev/null +++ b/utils/message.js @@ -0,0 +1,17 @@ +const config = require('../config.json'); +module.exports = { + giveaway: + (config.everyoneMention ? "@everyone\n\n" : "") + + "🎉 **GIVEAWAY** 🎉", + giveawayEnded: + (config.everyoneMention ? "@everyone\n\n" : "") + + "🎉 **GIVEAWAY ENDED** 🎉", + drawing: `Ends: **{timestamp}**`, + inviteToParticipate: `React with 🎉 to participate!`, + winMessage: "Congratulations, {winners}! You won **{this.prize}**!", + embedFooter: "Giveaways", + noWinner: "Giveaway cancelled, no valid participations.", + hostedBy: "Hosted by: {this.hostedBy}", + winners: "winner(s)", + endedAt: "Ended at" +} \ No newline at end of file diff --git a/utils/slashsync.js b/utils/slashsync.js new file mode 100644 index 0000000..b90ad93 --- /dev/null +++ b/utils/slashsync.js @@ -0,0 +1,56 @@ +const Discord = require('discord.js'); ///check discord fasttt + +module.exports = async (client, commands, options = { + debug: false, + guildId: null +}) => { + + const log = (message) => options.debug && console.log(message); + + const ready = client.readyAt ? Promise.resolve() : new Promise(resolve => client.once('ready', resolve)); + await ready; + const currentCommands = await client.application.commands.fetch(options.guildId && { guildId: options.guildId }); + + log(`Synchronizing commands...`); + log(`Currently ${currentCommands.size} commands are registered to the bot.`); + + const newCommands = commands.filter((command) => !currentCommands.some((c) => c.name === command.name)); + for (let newCommand of newCommands) { + await client.application.commands.create(newCommand, options.guildId); + } + + log(`Created ${newCommands.length} commands!`); + + const deletedCommands = currentCommands.filter((command) => !commands.some((c) => c.name === command.name)).toJSON(); + for (let deletedCommand of deletedCommands) { + await deletedCommand.delete(); + } + + log(`Deleted ${deletedCommands.length} commands!`); + + const updatedCommands = commands.filter((command) => currentCommands.some((c) => c.name === command.name)); + let updatedCommandCount = 0; + for (let updatedCommand of updatedCommands) { + const newCommand = updatedCommand; + const previousCommand = currentCommands.find((c) => c.name === updatedCommand.name); + let modified = false; + if (previousCommand.description !== newCommand.description) modified = true; + if (!Discord.ApplicationCommand.optionsEqual(previousCommand.options ?? [], newCommand.options ?? [])) modified = true; + if (modified) { + await previousCommand.edit(newCommand); + updatedCommandCount++; + } + } + + log(`Updated ${updatedCommandCount} commands!`); + + log(`Commands synchronized!`); + + return { + currentCommandCount: currentCommands.size, + newCommandCount: newCommands.length, + deletedCommandCount: deletedCommands.length, + updatedCommandCount + }; + +}; \ No newline at end of file