diff --git a/Commands/close.js b/Commands/close.js
index 1efa899..7e87d22 100644
--- a/Commands/close.js
+++ b/Commands/close.js
@@ -28,19 +28,20 @@ module.exports = new Command({
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
- if (!SupportStaff || !Admin)
- return interaction.reply("Some roles seem to be missing!\nPlease check for errors when starting the bot.");
+ if (!SupportStaff || !Admin) {
+ return interaction.reply("Some roles seem to be missing! Please check for errors when starting the bot.");
+ }
const NoPerms = new Discord.EmbedBuilder()
.setTitle("Invalid Permissions!")
.setDescription(`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``)
- .setColor(supportbot.Embed.Colours.Warn);
+ .setColor(supportbot.Embed.Colours.Warn);
- if (!interaction.member.roles.cache.has(SupportStaff.id) && !interaction.member.roles.cache.has(Admin.id))
+ if (!interaction.member.roles.cache.has(SupportStaff.id) && !interaction.member.roles.cache.has(Admin.id)) {
return interaction.reply({ embeds: [NoPerms] });
+ }
}
- // Check if it's a thread or channel based on config
if (
(supportbot.Ticket.TicketType === "threads" && interaction.channel.type !== Discord.ChannelType.PrivateThread) ||
(supportbot.Ticket.TicketType === "channels" && interaction.channel.type !== Discord.ChannelType.GuildText)
@@ -48,14 +49,22 @@ module.exports = new Command({
const NotTicketChannel = new Discord.EmbedBuilder()
.setTitle("Invalid Channel!")
.setDescription(`This command can only be used in a ${supportbot.Ticket.TicketType === "threads" ? "ticket thread" : "ticket channel"}.`)
- .setColor(supportbot.Embed.Colours.Warn);
+ .setColor(supportbot.Embed.Colours.Warn); // Ensure valid color
return interaction.reply({ embeds: [NotTicketChannel], ephemeral: true });
}
- await interaction.deferReply();
+ await interaction.deferReply(); // Deferring to avoid double replies
+
+ // Reading TicketData.json once for efficiency
+ let tickets;
+ try {
+ tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
+ } catch (err) {
+ console.error('Error reading ticket data file:', err);
+ return interaction.followUp({ content: "There was an error loading ticket data." });
+ }
- let tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
let TicketData = tickets.tickets.findIndex((t) => t.id === interaction.channel.id);
let ticket = tickets.tickets[TicketData];
@@ -63,44 +72,112 @@ module.exports = new Command({
const Exists = new Discord.EmbedBuilder()
.setTitle("No Ticket Found!")
.setDescription(msgconfig.Error.NoValidTicket)
- .setColor(supportbot.Embed.Colours.Warn);
+ .setColor(supportbot.Embed.Colours.Warn); // Ensure valid color
return interaction.followUp({ embeds: [Exists] });
}
let reason = interaction.options?.getString("reason") || "No Reason Provided.";
- const CloseButton = new Discord.ButtonBuilder()
- .setCustomId("confirmCloseTicket")
- .setLabel(supportbot.Ticket.Close.Confirmation_Button)
- .setEmoji(supportbot.Ticket.Close.Confirmation_Emoji)
- .setStyle(supportbot.Ticket.Close.Confirmation_Style);
+ if (supportbot.Ticket.ReviewSystem.Enabled) {
+ const rating = await collectReviewRating(interaction);
+ const comment = await collectReviewComment(interaction);
- const row = new Discord.ActionRowBuilder().addComponents(CloseButton);
+ const reviewChannel = await getChannel(supportbot.Ticket.ReviewSystem.Channel, interaction.guild);
+ const reviewer = supportbot.Ticket.ClaimTickets ? `<@${ticket.claimedBy}>` : null;
- const CloseTicketRequest = new Discord.EmbedBuilder()
- .setTitle(`**${supportbot.Ticket.Close.Title}**`)
- .setDescription(`${msgconfig.Ticket.ConfirmClose}`)
- .setColor(supportbot.Embed.Colours.General);
+ const reviewEmbed = new Discord.EmbedBuilder()
+ .setTitle(msgconfig.ReviewSystem.ReviewEmbed.Title)
+ .addFields(
+ {
+ name: msgconfig.ReviewSystem.ReviewEmbed.RatingTitle,
+ value: `${msgconfig.ReviewSystem.ReviewEmbed.ReviewEmoji.repeat(rating)}`,
+ inline: false
+ },
+ {
+ name: msgconfig.ReviewSystem.ReviewEmbed.CommentTitle,
+ value: `\`\`\`${comment}\`\`\``,
+ inline: false
+ }
+ )
+ .setColor(msgconfig.ReviewSystem.ReviewEmbed.Color);
- await interaction.followUp({
- embeds: [CloseTicketRequest],
- components: [row],
- });
+ if (supportbot.Ticket.ClaimTickets.Enabled) {
+ reviewEmbed.setDescription(
+ `**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedStaffTitle}** ${reviewer}\n**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedByTitle}** <@${interaction.user.id}>` || `N/A`
+ );
+ } else {
+ reviewEmbed.setDescription(
+ `**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedByTitle}** <@${interaction.user.id}>`
+ );
+ }
- const filter = (btnInteraction) => btnInteraction.customId === "confirmCloseTicket" && btnInteraction.user.id === interaction.user.id;
+ if (reviewChannel) {
+ await reviewChannel.send({ embeds: [reviewEmbed] });
+ }
- interaction.channel.awaitMessageComponent({ filter, time: 20000 })
- .then(async (btnInteraction) => {
- await handleCloseTicket(interaction, reason, ticket, TicketData);
- await btnInteraction.reply({ content: "Ticket successfully closed.", ephemeral: true });
- })
- .catch((err) => {
- interaction.followUp(`${msgconfig.Ticket.CloseTimeout}`);
- console.error(err);
- });
+ if (!interaction.replied && !interaction.deferred) {
+ await interaction.followUp({ embeds: [reviewEmbed] });
+ }
+
+ await handleCloseTicket(interaction, reason, ticket, TicketData);
+ } else {
+ await handleCloseTicket(interaction, reason, ticket, TicketData);
+ }
},
});
+async function collectReviewRating(interaction) {
+ const reviewPrompt = new Discord.EmbedBuilder()
+ .setTitle(msgconfig.ReviewSystem.Rate.Title)
+ .setDescription(msgconfig.ReviewSystem.Rate.Description)
+ .setColor(supportbot.Embed.Colours.General); // Ensure valid color
+
+ const stars = new Discord.ActionRowBuilder().addComponents(
+ new Discord.StringSelectMenuBuilder()
+ .setCustomId("starRating")
+ .setPlaceholder("Select a rating")
+ .addOptions([
+ { label: msgconfig.ReviewSystem.Stars.One, value: "1" },
+ { label: msgconfig.ReviewSystem.Stars.Two, value: "2" },
+ { label: msgconfig.ReviewSystem.Stars.Three, value: "3" },
+ { label: msgconfig.ReviewSystem.Stars.Four, value: "4" },
+ { label: msgconfig.ReviewSystem.Stars.Five, value: "5" },
+ ])
+ );
+
+ await interaction.followUp({
+ embeds: [reviewPrompt],
+ components: [stars],
+ ephemeral: true,
+ });
+
+ const starRating = await interaction.channel.awaitMessageComponent({
+ componentType: Discord.ComponentType.StringSelect,
+ filter: (i) => i.customId === "starRating" && i.user.id === interaction.user.id,
+ time: 30000,
+ });
+
+ await starRating.deferUpdate();
+ return starRating.values[0];
+}
+
+async function collectReviewComment(interaction) {
+ const commentPrompt = new Discord.EmbedBuilder()
+ .setTitle(msgconfig.ReviewSystem.Comment.Title)
+ .setDescription(msgconfig.ReviewSystem.Comment.Description)
+ .setColor(supportbot.Embed.Colours.General); // Ensure valid color
+
+ await interaction.followUp({
+ embeds: [commentPrompt],
+ ephemeral: true,
+ });
+
+ const filter = (response) => response.author.id === interaction.user.id;
+ const commentCollection = await interaction.channel.awaitMessages({ filter, max: 1, time: 30000 });
+ const comment = commentCollection.first()?.content;
+ return comment && comment.toLowerCase() !== "no" ? comment : "No Comment Provided";
+}
+
async function handleCloseTicket(interaction, reason, ticket, TicketData) {
const { getChannel } = interaction.client;
@@ -109,196 +186,65 @@ async function handleCloseTicket(interaction, reason, ticket, TicketData) {
let transcriptChannel = await getChannel(supportbot.Ticket.Log.TicketDataLog, interaction.guild);
if (!transcriptChannel)
- return interaction.followUp("Some Channels seem to be missing!");
+ return console.log("Ticket Log Missing");
try {
tickets.tickets[TicketData].open = false;
- fs.writeFileSync(
- "./Data/TicketData.json",
- JSON.stringify(tickets, null, 4),
- (err) => {
- if (err) console.error(err);
- }
- );
+ fs.writeFileSync("./Data/TicketData.json", JSON.stringify(tickets, null, 4));
const transcriptEmbed = new Discord.EmbedBuilder()
.setTitle(msgconfig.TicketLog.Title)
- .setColor(msgconfig.TicketLog.Colour)
- .setFooter({
- text: supportbot.Embed.Footer,
- iconURL: interaction.user.displayAvatarURL(),
- })
- .addFields(
- { name: "Ticket", value: `${interaction.channel.name} (${interaction.channel.id})` },
- { name: "User", value: `${tUser?.username || "N/A"}#${tUser?.discriminator || "N/A"} (${tUser?.id || ticket.user})` },
- { name: "Closed By", value: interaction.user.tag },
- { name: "Reason", value: reason }
- );
+ .setColor(msgconfig.TicketLog.Colour) // Ensure valid color
+ .setFooter({ text: supportbot.Embed.Footer, iconURL: interaction.user.displayAvatarURL() })
+ .setDescription(`> **Ticket:** ${interaction.channel.name} (\`${interaction.channel.id}\`)\n> **User:** ${tUser?.username || "N/A"}#${tUser?.discriminator || "N/A"} (\`${tUser?.id || ticket.user}\`)\n> **Closed by:** <@${interaction.user.id}>`)
+ .addFields({ name: "Reason", value: `\`\`\`${reason}\`\`\``, inline: true });
let msgs = await interaction.channel.messages.fetch({ limit: 100 });
- let html = `
-
-
-
-
-
-
-
-
Ticket Transcript
-
Server Name: ${interaction.guild.name}
-
Ticket: ${interaction.channel.name}
-
Messages: ${msgs.size} Messages
-
- `;
-
- msgs = msgs.sort((a, b) => a.createdTimestamp - b.createdTimestamp);
- msgs.forEach((msg) => {
- if (msg.content) {
- html += `
-
-
})
-
-
${msg.author.tag}
-
${msg.createdAt.toLocaleString()}
-
${convertMarkdownToHTML(msg.content)}
-
-
- `;
- }
- });
+ let html = createTranscriptHTML(interaction, msgs);
const fileName = `${interaction.channel.name}.html`;
+ let file = new Discord.AttachmentBuilder(Buffer.from(html), { name: `SPOILER_${fileName}` });
- html += `
-
-
Download Transcript
-
-
-
- `;
-
- let file = new Discord.AttachmentBuilder(
- Buffer.from(html),
- { name: fileName }
- );
-
- await transcriptChannel
- .send({ embeds: [transcriptEmbed], files: [file] })
- .catch((err) => {
- console.error(err);
- });
-
- if (supportbot.Ticket.DMTranscripts) {
- await tUser
- ?.send({ embeds: [transcriptEmbed], files: [file] })
- .catch((err) => {
- console.error(err);
- });
-
- if (ticket.subUsers) {
- ticket.subUsers.forEach(async (subUser) => {
- await interaction.client.users.cache
- .get(subUser)
- ?.send({ embeds: [transcriptEmbed], files: [file] });
- });
- }
- }
-
- await interaction.channel.delete().catch((error) => {
- console.error(error);
- if (error.code !== Discord.Constants.APIErrors.UNKNOWN_CHANNEL) {
- console.error("Failed to delete the interaction:", error);
- }
+ transcriptChannel.send({
+ embeds: [transcriptEmbed],
+ files: [file],
});
- } catch (error) {
- console.error(error);
+ } catch (err) {
+ console.log("Error closing ticket:", err);
}
+
+ await interaction.channel.delete();
}
-function convertMarkdownToHTML(text) {
- // Convert **bold** to bold
- text = text.replace(/\*\*(.*?)\*\*/g, '$1');
+function createTranscriptHTML(interaction, msgs) {
+ let html = `
+
+
+
+
+
+ Ticket Transcript
+ Ticket: ${interaction.channel.name}
+ User: ${interaction.user.tag}
+
+ `;
- // Convert *italic* to
italic
- text = text.replace(/\*(.*?)\*/g, '
$1');
+ msgs.reverse().forEach((msg) => {
+ html += `
+
+ ${msg.author.tag}: ${msg.content}
+
+ `;
+ });
- // Convert __underline__ to
underline
- text = text.replace(/__(.*?)__/g, '
$1');
-
- // Convert ~~strikethrough~~ to
strikethrough
- text = text.replace(/~~(.*?)~~/g, '
$1');
-
- // Convert inline code `code` to
code
- text = text.replace(/`(.*?)`/g, '
$1');
-
- // Convert blockquotes > quote to
quote
- text = text.replace(/^> (.*?$)/gm, '
$1
');
-
- // Convert multiline code blocks ```code``` to
code
- text = text.replace(/```(.*?)```/gs, '
$1
');
-
- // Convert line breaks to
- text = text.replace(/\n/g, '
');
-
- return text;
+ html += `
+
+
+
+ `;
+ return html;
}
diff --git a/Commands/embed.js b/Commands/embed.js
index 1f4d447..b38470f 100644
--- a/Commands/embed.js
+++ b/Commands/embed.js
@@ -1,167 +1,479 @@
-// File path: ./commands/embed.js
+const {
+ ApplicationCommandType,
+ ApplicationCommandOptionType,
+ ActionRowBuilder,
+ ButtonBuilder,
+ EmbedBuilder,
+ StringSelectMenuBuilder,
+ ModalBuilder,
+ TextInputBuilder,
+ TextInputStyle,
+ ButtonStyle,
+ ComponentType
+} = require('discord.js');
+const Command = require('../Structures/Command.js');
+const fs = require('fs');
+const yaml = require('js-yaml');
-const fs = require("fs");
-const Discord = require("discord.js");
-const yaml = require("js-yaml");
+const supportbot = yaml.load(fs.readFileSync('./Configs/supportbot.yml', 'utf8'));
+const cmdconfig = yaml.load(fs.readFileSync('./Configs/commands.yml', 'utf8'));
+const msgconfig = yaml.load(fs.readFileSync('./Configs/messages.yml', 'utf8'));
-const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
-const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
-const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
-
-const Command = require("../Structures/Command.js");
+// Helper function to validate and convert hex color
+function parseColor(color) {
+ if (!color) return 0x5865F2;
+ if (typeof color === 'number') return color;
+ if (typeof color !== 'string') return 0x5865F2;
+ color = color.replace('#', '');
+ if (/^[0-9A-F]{6}$/i.test(color)) {
+ return parseInt(color, 16);
+ }
+ return 0x5865F2;
+}
module.exports = new Command({
name: cmdconfig.Embed.Command,
description: cmdconfig.Embed.Description,
- type: Discord.ApplicationCommandType.ChatInput,
+ type: ApplicationCommandType.ChatInput,
options: [
{
- name: "title",
- description: "Embed Title",
- type: Discord.ApplicationCommandOptionType.String,
- required: true,
- },
- {
- name: "message",
- description: "Embed Message",
- type: Discord.ApplicationCommandOptionType.String,
- required: true,
- },
- {
- name: "color",
- description: "Embed HEX Color",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "fields",
- description: "Embed Fields (title|content;title|content;...)",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "thumbnail",
- description: "Embed Thumbnail URL",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "image",
- description: "Embed Image URL",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "footer",
- description: "Embed Footer Text",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "footericon",
- description: "Embed Footer Icon URL",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "author",
- description: "Embed Author Name",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "authoricon",
- description: "Embed Author Icon URL",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "authorurl",
- description: "Embed Author URL",
- type: Discord.ApplicationCommandOptionType.String,
- required: false,
- },
- {
- name: "timestamp",
- description: "Include Timestamp",
- type: Discord.ApplicationCommandOptionType.Boolean,
- required: false,
- },
- {
- name: "inline",
- description: "Make Fields Inline",
- type: Discord.ApplicationCommandOptionType.Boolean,
- required: false,
+ name: 'channel',
+ description: 'Select channel to send the message',
+ type: ApplicationCommandOptionType.Channel,
+ required: true
}
],
permissions: cmdconfig.Embed.Permission,
async run(interaction) {
+ // Permission check
const { getRole } = interaction.client;
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
if (!SupportStaff || !Admin) {
- return interaction.reply("Some roles seem to be missing!\nPlease check for errors when starting the bot.");
+ return interaction.reply('Some roles seem to be missing!\nPlease check for errors when starting the bot.');
}
- const NoPerms = new Discord.EmbedBuilder()
- .setTitle("Invalid Permissions!")
- .setDescription(`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``)
- .setColor(supportbot.Embed.Colours.Warn);
+ if (!interaction.member.roles.cache.has(SupportStaff.id) &&
+ !interaction.member.roles.cache.has(Admin.id)) {
+ const NoPerms = new EmbedBuilder()
+ .setTitle('Invalid Permissions!')
+ .setDescription(`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``)
+ .setColor(0xFF0000);
+ return interaction.reply({ embeds: [NoPerms], ephemeral: true });
+ }
- if (
- interaction.member.roles.cache.has(SupportStaff.id) ||
- interaction.member.roles.cache.has(Admin.id)
- ) {
- const EmbedTitle = interaction.options.getString("title").replace(/\\n/g, '\n');
- const EmbedSubject = interaction.options.getString("message").replace(/\\n/g, '\n');
- const GeneralColour = interaction.options.getString("color") || supportbot.Embed.Colours.Default;
- const EmbedThumbnail = interaction.options.getString("thumbnail");
- const EmbedImage = interaction.options.getString("image");
- const EmbedFields = interaction.options.getString("fields");
- const EmbedFooter = interaction.options.getString("footer")?.replace(/\\n/g, '\n');
- const EmbedFooterIcon = interaction.options.getString("footericon");
- const EmbedAuthor = interaction.options.getString("author")?.replace(/\\n/g, '\n');
- const EmbedAuthorIcon = interaction.options.getString("authoricon");
- const EmbedAuthorURL = interaction.options.getString("authorurl");
- const EmbedTimestamp = interaction.options.getBoolean("timestamp");
- const InlineFields = interaction.options.getBoolean("inline");
+ const channel = interaction.options.getChannel('channel');
+
+ // Initial message state
+ const messageData = {
+ type: 'embed',
+ title: 'New Embed',
+ description: 'Click the buttons below to edit this embed',
+ color: 0x5865F2,
+ fields: [],
+ footer: null,
+ thumbnail: null,
+ image: null,
+ timestamp: false
+ };
- const EmbedMsg = new Discord.EmbedBuilder()
- .setTitle(EmbedTitle)
- .setDescription(EmbedSubject)
- .setColor(GeneralColour)
- .setThumbnail(EmbedThumbnail)
- .setImage(EmbedImage);
+ // Create initial embed
+ function createEmbed() {
+ const embed = new EmbedBuilder()
+ .setTitle(messageData.title)
+ .setDescription(messageData.description)
+ .setColor(messageData.color);
- if (EmbedFields) {
- const fieldsArray = EmbedFields.split(';');
- fieldsArray.forEach(field => {
- const [title, value] = field.split('|');
- if (title && value) {
- EmbedMsg.addFields({ name: title.replace(/\\n/g, '\n'), value: value.replace(/\\n/g, '\n'), inline: InlineFields || false });
- }
+ if (messageData.fields.length > 0) {
+ embed.addFields(messageData.fields);
+ }
+ if (messageData.footer) {
+ embed.setFooter({ text: messageData.footer });
+ }
+ if (messageData.thumbnail) {
+ embed.setThumbnail(messageData.thumbnail);
+ }
+ if (messageData.image) {
+ embed.setImage(messageData.image);
+ }
+ if (messageData.timestamp) {
+ embed.setTimestamp();
+ }
+
+ return embed;
+ }
+
+ // Create type selector
+ const typeRow = new ActionRowBuilder()
+ .addComponents(
+ new StringSelectMenuBuilder()
+ .setCustomId('message_type')
+ .setPlaceholder('Select message type')
+ .addOptions([
+ {
+ label: 'Embed Message',
+ description: 'Send as an embedded message',
+ value: 'embed'
+ },
+ {
+ label: 'Text Message',
+ description: 'Send as a plain text message',
+ value: 'text'
+ }
+ ])
+ );
+
+ // Create button rows function
+ function createButtons(messageType) {
+ const buttons = [];
+
+ if (messageType === 'embed') {
+ // Only show these buttons for embed mode
+ const row1 = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId('edit_title')
+ .setLabel('Edit Title')
+ .setStyle(ButtonStyle.Secondary),
+ new ButtonBuilder()
+ .setCustomId('edit_description')
+ .setLabel('Edit Description')
+ .setStyle(ButtonStyle.Secondary),
+ new ButtonBuilder()
+ .setCustomId('edit_color')
+ .setLabel('Edit Color')
+ .setStyle(ButtonStyle.Secondary),
+ new ButtonBuilder()
+ .setCustomId('add_field')
+ .setLabel('Add Field')
+ .setStyle(ButtonStyle.Secondary)
+ );
+
+ const row2 = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId('edit_footer')
+ .setLabel('Edit Footer')
+ .setStyle(ButtonStyle.Secondary),
+ new ButtonBuilder()
+ .setCustomId('edit_image')
+ .setLabel('Add Image')
+ .setStyle(ButtonStyle.Secondary),
+ new ButtonBuilder()
+ .setCustomId('edit_thumbnail')
+ .setLabel('Add Thumbnail')
+ .setStyle(ButtonStyle.Secondary),
+ new ButtonBuilder()
+ .setCustomId('toggle_timestamp')
+ .setLabel('Toggle Timestamp')
+ .setStyle(ButtonStyle.Secondary)
+ );
+
+ buttons.push(row1, row2);
+ } else {
+ // Text mode only shows edit text button
+ const textRow = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId('edit_description')
+ .setLabel('Edit Text')
+ .setStyle(ButtonStyle.Secondary)
+ );
+
+ buttons.push(textRow);
+ }
+
+ // Send button always shows
+ const sendRow = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId('send_message')
+ .setLabel('Send')
+ .setStyle(ButtonStyle.Success)
+ );
+
+ buttons.push(sendRow);
+ return buttons;
+ }
+
+ // Function to update the message preview
+ async function updatePreview(i) {
+ if (messageData.type === 'embed') {
+ await i.update({
+ content: 'Customize your message:',
+ embeds: [createEmbed()],
+ components: [typeRow, ...createButtons('embed')]
+ });
+ } else {
+ // For text mode, just show the text directly
+ await i.update({
+ content: messageData.description,
+ embeds: [],
+ components: [typeRow, ...createButtons('text')]
+ });
+ }
+ }
+
+ // Send initial message
+ const message = await interaction.reply({
+ content: messageData.type === 'text' ? messageData.description : 'Customize your message:',
+ components: [typeRow, ...createButtons(messageData.type)],
+ embeds: messageData.type === 'embed' ? [createEmbed()] : [],
+ ephemeral: true
+ });
+
+ // Create collector for interactions
+ const collector = message.createMessageComponentCollector({
+ time: 900000
+ });
+
+ collector.on('collect', async (i) => {
+ if (i.user.id !== interaction.user.id) {
+ return i.reply({
+ content: 'You cannot edit this message.',
+ ephemeral: true
});
}
- if (EmbedFooter) {
- EmbedMsg.setFooter({ text: EmbedFooter, iconURL: EmbedFooterIcon });
+ switch (i.customId) {
+ case 'message_type':
+ messageData.type = i.values[0];
+ await updatePreview(i);
+ break;
+
+ case 'edit_description':
+ const descModal = new ModalBuilder()
+ .setCustomId('desc_modal')
+ .setTitle(messageData.type === 'embed' ? 'Edit Description' : 'Edit Text');
+
+ descModal.addComponents(
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('desc_input')
+ .setLabel(messageData.type === 'embed' ? 'Description' : 'Message Text')
+ .setStyle(TextInputStyle.Paragraph)
+ .setValue(messageData.description)
+ .setMaxLength(4000)
+ )
+ );
+
+ await i.showModal(descModal);
+ break;
+
+ case 'edit_title':
+ const titleModal = new ModalBuilder()
+ .setCustomId('title_modal')
+ .setTitle('Edit Title');
+
+ titleModal.addComponents(
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('title_input')
+ .setLabel('Title')
+ .setStyle(TextInputStyle.Short)
+ .setValue(messageData.title)
+ .setMaxLength(256)
+ )
+ );
+
+ await i.showModal(titleModal);
+ break;
+
+ case 'edit_color':
+ const colorModal = new ModalBuilder()
+ .setCustomId('color_modal')
+ .setTitle('Edit Color');
+
+ colorModal.addComponents(
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('color_input')
+ .setLabel('Color (HEX)')
+ .setStyle(TextInputStyle.Short)
+ .setPlaceholder('#FF0000')
+ .setMinLength(6)
+ .setMaxLength(7)
+ .setValue(messageData.color.toString(16).padStart(6, '0'))
+ )
+ );
+
+ await i.showModal(colorModal);
+ break;
+
+ case 'add_field':
+ const fieldModal = new ModalBuilder()
+ .setCustomId('field_modal')
+ .setTitle('Add Field');
+
+ fieldModal.addComponents(
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('field_name')
+ .setLabel('Field Name')
+ .setStyle(TextInputStyle.Short)
+ .setMaxLength(256)
+ ),
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('field_value')
+ .setLabel('Field Value')
+ .setStyle(TextInputStyle.Paragraph)
+ .setMaxLength(1024)
+ ),
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('field_inline')
+ .setLabel('Inline? (true/false)')
+ .setStyle(TextInputStyle.Short)
+ .setValue('false')
+ .setPlaceholder('true or false')
+ )
+ );
+
+ await i.showModal(fieldModal);
+ break;
+
+ case 'edit_footer':
+ const footerModal = new ModalBuilder()
+ .setCustomId('footer_modal')
+ .setTitle('Edit Footer');
+
+ footerModal.addComponents(
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('footer_input')
+ .setLabel('Footer Text')
+ .setStyle(TextInputStyle.Short)
+ .setValue(messageData.footer || '')
+ .setMaxLength(2048)
+ )
+ );
+
+ await i.showModal(footerModal);
+ break;
+
+ case 'edit_image':
+ const imageModal = new ModalBuilder()
+ .setCustomId('image_modal')
+ .setTitle('Add Image');
+
+ imageModal.addComponents(
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('image_input')
+ .setLabel('Image URL')
+ .setStyle(TextInputStyle.Short)
+ .setValue(messageData.image || '')
+ .setPlaceholder('https://example.com/image.png')
+ )
+ );
+
+ await i.showModal(imageModal);
+ break;
+
+ case 'edit_thumbnail':
+ const thumbnailModal = new ModalBuilder()
+ .setCustomId('thumbnail_modal')
+ .setTitle('Add Thumbnail');
+
+ thumbnailModal.addComponents(
+ new ActionRowBuilder()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId('thumbnail_input')
+ .setLabel('Thumbnail URL')
+ .setStyle(TextInputStyle.Short)
+ .setValue(messageData.thumbnail || '')
+ .setPlaceholder('https://example.com/thumbnail.png')
+ )
+ );
+
+ await i.showModal(thumbnailModal);
+ break;
+
+ case 'toggle_timestamp':
+ messageData.timestamp = !messageData.timestamp;
+ await updatePreview(i);
+ break;
+
+ case 'send_message':
+ try {
+ if (messageData.type === 'embed') {
+ await channel.send({ embeds: [createEmbed()] });
+ } else {
+ await channel.send(messageData.description);
+ }
+ await i.update({
+ content: 'Message sent successfully!',
+ components: [],
+ embeds: []
+ });
+ collector.stop();
+ } catch (error) {
+ await i.reply({
+ content: 'Failed to send message. Please check channel permissions.',
+ ephemeral: true
+ });
+ }
+ break;
+ }
+ });
+
+ // Handle modal submissions
+ interaction.client.on('interactionCreate', async (modal) => {
+ if (!modal.isModalSubmit()) return;
+ if (modal.user.id !== interaction.user.id) return;
+
+ switch (modal.customId) {
+ case 'title_modal':
+ messageData.title = modal.fields.getTextInputValue('title_input');
+ break;
+ case 'desc_modal':
+ messageData.description = modal.fields.getTextInputValue('desc_input');
+ break;
+ case 'color_modal':
+ messageData.color = parseColor(modal.fields.getTextInputValue('color_input'));
+ break;
+ case 'field_modal':
+ const inlineValue = modal.fields.getTextInputValue('field_inline').toLowerCase();
+ messageData.fields.push({
+ name: modal.fields.getTextInputValue('field_name'),
+ value: modal.fields.getTextInputValue('field_value'),
+ inline: inlineValue === 'true'
+ });
+ break;
+ case 'footer_modal':
+ messageData.footer = modal.fields.getTextInputValue('footer_input');
+ break;
+ case 'image_modal':
+ messageData.image = modal.fields.getTextInputValue('image_input');
+ break;
+ case 'thumbnail_modal':
+ messageData.thumbnail = modal.fields.getTextInputValue('thumbnail_input');
+ break;
+ default:
+ return;
}
- if (EmbedAuthor) {
- EmbedMsg.setAuthor({ name: EmbedAuthor, iconURL: EmbedAuthorIcon, url: EmbedAuthorURL });
- }
+ await updatePreview(modal);
+ });
- if (EmbedTimestamp) {
- EmbedMsg.setTimestamp();
- }
-
- interaction.reply({
- embeds: [EmbedMsg],
- });
- } else {
- return interaction.reply({ embeds: [NoPerms] });
- }
- },
-});
+ collector.on('end', () => {
+ interaction.editReply({
+ content: 'Message editor timed out.',
+ components: [],
+ embeds: []
+ }).catch(() => {});
+ });
+ }
+});
\ No newline at end of file
diff --git a/Commands/mod.js b/Commands/mod.js
new file mode 100644
index 0000000..719fa29
--- /dev/null
+++ b/Commands/mod.js
@@ -0,0 +1,261 @@
+const fs = require("fs");
+const { ApplicationCommandOptionType, ApplicationCommandType, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } = require("discord.js");
+const yaml = require("js-yaml");
+const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
+const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
+const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
+
+const Command = require("../Structures/Command.js");
+
+// Function to chunk array into smaller arrays
+function chunkArray(arr, size) {
+ const chunks = [];
+ for (let i = 0; i < arr.length; i += size) {
+ chunks.push(arr.slice(i, i + size));
+ }
+ return chunks;
+}
+
+module.exports = new Command({
+ name: cmdconfig.Mod.Command,
+ description: cmdconfig.Mod.Command,
+ type: ApplicationCommandType.ChatInput,
+ options: [
+ {
+ name: cmdconfig.Mod.TicketBlacklist.Command,
+ description: cmdconfig.Mod.TicketBlacklist.Description,
+ type: ApplicationCommandOptionType.SubcommandGroup,
+ options: [
+ {
+ name: cmdconfig.Mod.TicketBlacklist.Add.Command,
+ description: msgconfig.Mod.TicketBlacklist.Add.Description || "Add a user to the ticket blacklist",
+ type: ApplicationCommandOptionType.Subcommand,
+ options: [
+ {
+ name: 'user',
+ description: msgconfig.Mod.TicketBlacklist.Add.UserDescription || "User to blacklist",
+ type: ApplicationCommandOptionType.User,
+ required: true
+ },
+ {
+ name: 'reason',
+ description: msgconfig.Mod.TicketBlacklist.Add.ReasonDescription || "Reason for blacklisting",
+ type: ApplicationCommandOptionType.String,
+ required: false
+ }
+ ]
+ },
+ {
+ name: cmdconfig.Mod.TicketBlacklist.Remove.Command,
+ description: msgconfig.Mod.TicketBlacklist.Remove.Description || "Remove a user from the ticket blacklist",
+ type: ApplicationCommandOptionType.Subcommand,
+ options: [
+ {
+ name: 'user',
+ description: msgconfig.Mod.TicketBlacklist.Remove.UserDescription || "User to remove from blacklist",
+ type: ApplicationCommandOptionType.User,
+ required: true
+ },
+ {
+ name: 'reason',
+ description: msgconfig.Mod.TicketBlacklist.Remove.ReasonDescription || "Reason for removing from blacklist",
+ type: ApplicationCommandOptionType.String,
+ required: false
+ }
+ ]
+ },
+ {
+ name: "view",
+ description: msgconfig.Mod.TicketBlacklist.View.Description || "View all blacklisted users",
+ type: ApplicationCommandOptionType.Subcommand,
+ }
+ ]
+ }
+ ],
+ permissions: cmdconfig.Mod.Permission,
+
+ async run(interaction) {
+ const { getRole } = interaction.client;
+
+ let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
+ let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
+ let Moderator = await getRole(supportbot.Roles.StaffMember.Moderator, interaction.guild);
+
+ if (!SupportStaff || !Admin || !Moderator) {
+ const missingRolesEmbed = new EmbedBuilder()
+ .setDescription(msgconfig.Error.InvalidChannel || "Required roles are missing!")
+ .setColor(supportbot.Embed.Colours.Warn);
+ return interaction.reply({ embeds: [missingRolesEmbed] });
+ }
+
+ const NoPerms = new EmbedBuilder()
+ .setDescription(msgconfig.Error.IncorrectPerms || "You do not have the correct permissions!")
+ .setColor(supportbot.Embed.Colours.Warn);
+
+ if (!interaction.member.roles.cache.has(Admin.id) && !interaction.member.roles.cache.has(Moderator.id) && (!supportbot.Mod.AllowSupportStaff || !interaction.member.roles.cache.has(SupportStaff.id))) {
+ return interaction.reply({ embeds: [NoPerms] });
+ }
+
+ const subcommand = interaction.options.getSubcommand(false);
+ const user = interaction.options.getUser('user');
+ const reason = interaction.options.getString('reason') || "No reason provided";
+
+ try {
+ let blacklistedUsers;
+ try {
+ blacklistedUsers = JSON.parse(fs.readFileSync("./Data/BlacklistedUsers.json", "utf8")).blacklistedUsers;
+ if (!Array.isArray(blacklistedUsers)) {
+ blacklistedUsers = [];
+ }
+ } catch (error) {
+ blacklistedUsers = [];
+ }
+
+ if (subcommand === cmdconfig.Mod.TicketBlacklist.Add.Command) {
+ if (blacklistedUsers.includes(user.id)) {
+ const alreadyBlacklistedEmbed = new EmbedBuilder()
+ .setDescription(msgconfig.Mod.TicketBlacklist.Add.AlreadyBlacklisted.replace("{userTag}", user.tag) || ":x: User is already blacklisted.")
+ .setColor(supportbot.Embed.Colours.Warn);
+ return interaction.reply({ embeds: [alreadyBlacklistedEmbed], ephemeral: true });
+ }
+
+ blacklistedUsers.push(user.id);
+ fs.writeFileSync("./Data/BlacklistedUsers.json", JSON.stringify({ "blacklistedUsers": blacklistedUsers }, null, 4));
+
+ const successEmbed = new EmbedBuilder()
+ .setDescription(msgconfig.Mod.TicketBlacklist.Add.Success.replace("{userTag}", user.tag) || ":white_check_mark: User has been blacklisted.")
+ .setColor(supportbot.Embed.Colours.Success);
+
+ const blacklistChannel = interaction.guild.channels.cache.get(supportbot.Ticket.Log.TicketBlacklistLog);
+ if (blacklistChannel) {
+ const blacklistLogEmbed = new EmbedBuilder()
+ .setTitle(msgconfig.TicketBlacklistLog.Title || "Ticket Blacklist Log")
+ .setColor(msgconfig.TicketBlacklistLog.Colour || supportbot.Embed.Colours.Success)
+ .setFooter({ text: supportbot.Embed.Footer, iconURL: interaction.user.displayAvatarURL() })
+ .setDescription(`> **User:** ${user.tag} (\`${user.id}\`)\n> **Actioned by:** <@${interaction.user.id}>`)
+ .addFields({ name: "Action", value: "\`\`\`Removed from blacklist\`\`\`", inline: false })
+ .addFields({ name: "Reason", value: `\`\`\`${reason}\`\`\``, inline: false });
+
+ blacklistChannel.send({ embeds: [blacklistLogEmbed] });
+ }
+
+ return interaction.reply({
+ embeds: [successEmbed],
+ ephemeral: true
+ });
+
+ } else if (subcommand === cmdconfig.Mod.TicketBlacklist.Remove.Command) {
+ if (!blacklistedUsers.includes(user.id)) {
+ const notBlacklistedEmbed = new EmbedBuilder()
+ .setDescription(msgconfig.Mod.TicketBlacklist.Remove.NotBlacklisted.replace("{userTag}", user.tag) || ":x: User is not blacklisted.")
+ .setColor(supportbot.Embed.Colours.Warn);
+ return interaction.reply({ embeds: [notBlacklistedEmbed], ephemeral: true });
+ }
+
+ blacklistedUsers = blacklistedUsers.filter(id => id !== user.id);
+ fs.writeFileSync("./Data/BlacklistedUsers.json", JSON.stringify({ "blacklistedUsers": blacklistedUsers }, null, 4));
+
+ const removedEmbed = new EmbedBuilder()
+ .setDescription(msgconfig.Mod.TicketBlacklist.Remove.Success.replace("{userTag}", user.tag) || ":white_check_mark: User has been removed from the blacklist.")
+ .setColor(supportbot.Embed.Colours.Success);
+
+ const blacklistChannel = interaction.guild.channels.cache.get(supportbot.Ticket.Log.TicketBlacklistLog);
+ if (blacklistChannel) {
+ const blacklistLogEmbed = new EmbedBuilder()
+ .setTitle(msgconfig.TicketBlacklistLog.Title || "Ticket Blacklist Log")
+ .setColor(msgconfig.TicketBlacklistLog.Colour || supportbot.Embed.Colours.Success)
+ .setFooter({ text: supportbot.Embed.Footer, iconURL: interaction.user.displayAvatarURL() })
+ .setDescription(`> **User:** ${user.tag} (\`${user.id}\`)\n> **Actioned by:** <@${interaction.user.id}>`)
+ .addFields({ name: "Action", value: "\`\`\`Removed from blacklist\`\`\`", inline: false })
+ .addFields({ name: "Reason", value: `\`\`\`${reason}\`\`\``, inline: false });
+
+ blacklistChannel.send({ embeds: [blacklistLogEmbed] });
+ }
+
+ return interaction.reply({ embeds: [removedEmbed], ephemeral: true });
+
+ } else if (subcommand === "view") {
+ if (blacklistedUsers.length === 0) {
+ const noBlacklistedUsersEmbed = new EmbedBuilder()
+ .setDescription(msgconfig.Mod.TicketBlacklist.View.NoBlacklistedUsers || "No users are blacklisted.")
+ .setColor(supportbot.Embed.Colours.Success);
+ return interaction.reply({ embeds: [noBlacklistedUsersEmbed], ephemeral: true });
+ }
+
+ const chunkedUsers = chunkArray(blacklistedUsers, 5);
+ let currentPage = 0;
+
+ const createEmbed = (page) => {
+ return new EmbedBuilder()
+ .setTitle(msgconfig.Mod.TicketBlacklist.View.EmbedTitle || "Blacklisted Users")
+ .setDescription(chunkedUsers[page].map(id => `<@${id}>`).join("\n"))
+ .setColor(supportbot.Embed.Colours.Success)
+ .setFooter({ text: `Page ${page + 1} of ${chunkedUsers.length}` });
+ };
+
+ const buttons = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId('previous')
+ .setLabel('Previous')
+ .setStyle(ButtonStyle.Secondary)
+ .setDisabled(currentPage === 0),
+ new ButtonBuilder()
+ .setCustomId('next')
+ .setLabel('Next')
+ .setStyle(ButtonStyle.Secondary)
+ .setDisabled(currentPage === chunkedUsers.length - 1)
+ );
+
+ const response = await interaction.reply({
+ embeds: [createEmbed(currentPage)],
+ components: chunkedUsers.length > 1 ? [buttons] : [],
+ ephemeral: true
+ });
+
+ if (chunkedUsers.length <= 1) return;
+
+ const collector = response.createMessageComponentCollector({
+ componentType: ComponentType.Button,
+ time: 60000
+ });
+
+ collector.on('collect', async (i) => {
+ if (i.user.id !== interaction.user.id) {
+ return i.reply({
+ content: 'You cannot use these buttons.',
+ ephemeral: true
+ });
+ }
+
+ if (i.customId === 'previous' && currentPage > 0) {
+ currentPage--;
+ } else if (i.customId === 'next' && currentPage < chunkedUsers.length - 1) {
+ currentPage++;
+ }
+
+ buttons.components[0].setDisabled(currentPage === 0);
+ buttons.components[1].setDisabled(currentPage === chunkedUsers.length - 1);
+
+ await i.update({
+ embeds: [createEmbed(currentPage)],
+ components: [buttons]
+ });
+ });
+
+ collector.on('end', () => {
+ buttons.components.forEach(button => button.setDisabled(true));
+ interaction.editReply({
+ components: [buttons]
+ }).catch(() => {});
+ });
+ }
+ } catch (error) {
+ console.error("Error in mod command:", error);
+ const errorEmbed = new EmbedBuilder()
+ .setDescription(msgconfig.Error.ActionFailed || "An error occurred while processing your request.")
+ .setColor(supportbot.Embed.Colours.Warn);
+ interaction.reply({ embeds: [errorEmbed], ephemeral: true });
+ }
+ }
+});
\ No newline at end of file
diff --git a/Commands/profile.js b/Commands/profile.js
index e732e55..a25f448 100644
--- a/Commands/profile.js
+++ b/Commands/profile.js
@@ -10,10 +10,6 @@ const Command = require("../Structures/Command.js");
const clockedInUsers = new Set();
-// async function getRole(roleName, guild) {
-// return guild.roles.cache.find(role => role.name === roleName);
-// }
-
function updateClockedInStatus(profileEmbed, clockedIn) {
profileEmbed.data.fields = profileEmbed.data.fields.map(field => {
if (field.name === 'Clocked In Status') {
@@ -24,6 +20,35 @@ function updateClockedInStatus(profileEmbed, clockedIn) {
return profileEmbed;
}
+function formatSchedule(schedule) {
+ if (!schedule || Object.keys(schedule).length === 0) return 'No schedule set';
+
+ const days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
+ return days
+ .filter(day => schedule[day])
+ .map(day => `${day.charAt(0).toUpperCase() + day.slice(1)}: ${schedule[day].start} - ${schedule[day].end}`)
+ .join('\n');
+}
+
+function calculateWeeklyHours(schedule) {
+ if (!schedule) return 0;
+
+ let totalMinutes = 0;
+ Object.values(schedule).forEach(day => {
+ if (day && day.start && day.end) {
+ const [startHour, startMin] = day.start.split(':').map(Number);
+ const [endHour, endMin] = day.end.split(':').map(Number);
+
+ const startMinutes = startHour * 60 + startMin;
+ const endMinutes = endHour * 60 + endMin;
+
+ totalMinutes += endMinutes - startMinutes;
+ }
+ });
+
+ return Math.round(totalMinutes / 60 * 10) / 10; // Round to 1 decimal place
+}
+
module.exports = new Command({
name: cmdconfig.Profile.Command,
description: cmdconfig.Profile.Description,
@@ -39,7 +64,7 @@ module.exports = new Command({
],
async run(interaction) {
- await interaction.deferReply({ ephemeral: true }); // Acknowledge the interaction immediately
+ await interaction.deferReply({ ephemeral: true });
const userOption = interaction.options.getUser('user');
const viewingUser = userOption || interaction.user;
@@ -47,7 +72,7 @@ module.exports = new Command({
const interactionUserId = interaction.user.id;
const user = interaction.guild.members.cache.get(viewingUserId);
- const { getRole, getChannel } = interaction.client;
+ const { getRole } = interaction.client;
const Staff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
const Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
@@ -71,12 +96,14 @@ module.exports = new Command({
profileData = {
bio: "",
timezone: "",
- clockedIn: false
+ clockedIn: false,
+ schedule: {}
};
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
}
- const { bio, timezone, clockedIn } = profileData;
+ const { bio, timezone, clockedIn, schedule } = profileData;
+ const weeklyHours = calculateWeeklyHours(schedule);
let profileEmbed = new EmbedBuilder()
.setTitle(`${viewingUser.username}'s Profile`)
@@ -88,7 +115,11 @@ module.exports = new Command({
);
if (isStaff) {
- profileEmbed.addFields({ name: 'Clocked In Status', value: clockedIn ? '✅ Clocked In' : '❌ Clocked Out', inline: true });
+ profileEmbed.addFields(
+ { name: 'Clocked In Status', value: clockedIn ? '✅ Clocked In' : '❌ Clocked Out', inline: true },
+ { name: 'Weekly Hours', value: `${weeklyHours} hours`, inline: true }, // Now inline with Schedule
+ { name: 'Schedule', value: formatSchedule(schedule), inline: true }
+ );
}
const buttonRow = new ActionRowBuilder();
@@ -105,6 +136,10 @@ module.exports = new Command({
new ButtonBuilder()
.setCustomId('clockInOut')
.setLabel(clockedIn ? 'Clock Out' : 'Clock In')
+ .setStyle(ButtonStyle.Secondary),
+ new ButtonBuilder()
+ .setCustomId('editSchedule')
+ .setLabel('Edit Schedule')
.setStyle(ButtonStyle.Secondary)
);
}
@@ -122,7 +157,7 @@ module.exports = new Command({
await interaction.editReply({ embeds: [profileEmbed], components: buttonRow.components.length > 0 ? [buttonRow] : [] });
const filter = i => (
- ['editProfile', 'clockInOut', 'viewTicketStats', 'showOpenTickets', 'backToStats', 'backToProfile'].includes(i.customId)
+ ['editProfile', 'clockInOut', 'viewTicketStats', 'editSchedule'].includes(i.customId)
&& i.user.id === interactionUserId
);
@@ -139,8 +174,7 @@ module.exports = new Command({
.setCustomId('bio')
.setLabel('Bio')
.setStyle(TextInputStyle.Paragraph)
- .setPlaceholder('Enter your bio')
- .setValue(String(bio))
+ .setValue(profileData.bio || '')
.setRequired(false)
),
new ActionRowBuilder().addComponents(
@@ -148,8 +182,7 @@ module.exports = new Command({
.setCustomId('timezone')
.setLabel('Timezone')
.setStyle(TextInputStyle.Short)
- .setPlaceholder('Enter your timezone')
- .setValue(String(timezone))
+ .setValue(profileData.timezone || '')
.setRequired(false)
)
);
@@ -160,7 +193,6 @@ module.exports = new Command({
if (i.customId === 'clockInOut') {
profileData.clockedIn = !profileData.clockedIn;
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
- profileEmbed = updateClockedInStatus(profileEmbed, profileData.clockedIn);
if (profileData.clockedIn) {
clockedInUsers.add(viewingUserId);
@@ -168,157 +200,60 @@ module.exports = new Command({
clockedInUsers.delete(viewingUserId);
}
- const updatedButtonRow = new ActionRowBuilder()
- .addComponents(
- new ButtonBuilder()
- .setCustomId('editProfile')
- .setLabel('Edit Profile')
- .setStyle(ButtonStyle.Secondary)
- );
+ profileEmbed = updateClockedInStatus(profileEmbed, profileData.clockedIn);
+ const updatedRow = new ActionRowBuilder().addComponents(
+ ...buttonRow.components.map(button => {
+ if (button.data.custom_id === 'clockInOut') {
+ return new ButtonBuilder()
+ .setCustomId('clockInOut')
+ .setLabel(profileData.clockedIn ? 'Clock Out' : 'Clock In')
+ .setStyle(ButtonStyle.Secondary);
+ }
+ return ButtonBuilder.from(button.data);
+ })
+ );
- if (isStaff) {
- updatedButtonRow.addComponents(
- new ButtonBuilder()
- .setCustomId('clockInOut')
- .setLabel(profileData.clockedIn ? 'Clock Out' : 'Clock In')
- .setStyle(ButtonStyle.Secondary)
- );
-
- if (supportbot.Ticket.ClaimTickets.Enabled) {
- updatedButtonRow.addComponents(
- new ButtonBuilder()
- .setCustomId('viewTicketStats')
- .setLabel('View Ticket Stats')
- .setStyle(ButtonStyle.Secondary)
- );
- }
- }
-
- await i.update({ embeds: [profileEmbed], components: [updatedButtonRow] });
-
- let clockedinout = new EmbedBuilder()
- .setTitle(profileData.clockedIn ? 'Clocked In!' : 'Clocked Out!')
- .setDescription(profileData.clockedIn ? 'You have successfully clocked in.' : 'You have successfully clocked out.')
- .setColor(supportbot.Embed.Colours.General)
-
- await interaction.followUp({ embeds: [clockedinout], ephemeral: true });
+ await i.update({ embeds: [profileEmbed], components: [updatedRow] });
}
if (i.customId === 'viewTicketStats') {
- const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
- const ticketsClaimed = TicketData.tickets.filter(t => t.claimedBy === viewingUserId);
- const ticketsOpen = ticketsClaimed.filter(t => t.open);
- const totalTickets = ticketsClaimed.length;
-
- let totalResponseTime = 0;
- let responseCount = 0;
-
- ticketsClaimed.forEach(ticket => {
- if (ticket.claimedAt && ticket.createdAt) {
- const responseTime = new Date(ticket.claimedAt) - new Date(ticket.createdAt);
- totalResponseTime += responseTime;
- responseCount++;
- }
- });
-
- const averageResponseTime = responseCount ? totalResponseTime / responseCount : 0;
- const averageResponseTimeMinutes = Math.round(averageResponseTime / 60000);
-
- const statsEmbed = new EmbedBuilder()
- .setTitle(msgconfig.TicketStats.Title)
- .setDescription(`> Ticket stats for <@${viewingUserId}>`)
- .setColor(supportbot.Embed.Colours.General)
- .addFields(
- { name: msgconfig.TicketStats.OpenTickets, value: `${ticketsOpen.length}`, inline: true },
- { name: msgconfig.TicketStats.TotalTickets, value: `${totalTickets}`, inline: true },
- { name: msgconfig.TicketStats.ResponseTime, value: `${averageResponseTimeMinutes} minutes`, inline: false }
- );
-
- const statsButtonRow = new ActionRowBuilder()
- .addComponents(
- new ButtonBuilder()
- .setCustomId('showOpenTickets')
- .setLabel('Show Open Tickets')
- .setStyle(ButtonStyle.Secondary),
- new ButtonBuilder()
- .setCustomId('backToProfile')
- .setLabel('Back to Profile')
- .setStyle(ButtonStyle.Secondary)
- );
-
- await i.update({ embeds: [statsEmbed], components: [statsButtonRow] });
- }
-
- if (i.customId === 'showOpenTickets') {
- const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
- const ticketsOpen = TicketData.tickets.filter(t => t.claimedBy === viewingUserId && t.open);
-
- const openTicketsEmbed = new EmbedBuilder()
- .setTitle('Active Tickets')
- .setDescription(ticketsOpen.map(t => `<#${t.id}>`).join('\n') || 'No active tickets.')
+ // Handle ticket stats viewing here
+ const ticketStatsEmbed = new EmbedBuilder()
+ .setTitle('Ticket Stats')
+ .setDescription('Here are your ticket stats...')
.setColor(supportbot.Embed.Colours.General);
- const openTicketsButtonRow = new ActionRowBuilder()
- .addComponents(
- new ButtonBuilder()
- .setCustomId('backToStats')
- .setLabel('Back to Stats')
- .setStyle(ButtonStyle.Secondary)
- );
-
- await i.update({ embeds: [openTicketsEmbed], components: [openTicketsButtonRow] });
+ await i.update({ embeds: [ticketStatsEmbed], components: [] });
}
- if (i.customId === 'backToStats') {
- const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
- const ticketsClaimed = TicketData.tickets.filter(t => t.claimedBy === viewingUserId);
- const ticketsOpen = ticketsClaimed.filter(t => t.open);
- const totalTickets = ticketsClaimed.length;
+ if (i.customId === 'editSchedule') {
+ const modal = new ModalBuilder()
+ .setCustomId('editScheduleModal')
+ .setTitle('Edit Schedule');
- let totalResponseTime = 0;
- let responseCount = 0;
-
- ticketsClaimed.forEach(ticket => {
- if (ticket.claimedAt && ticket.createdAt) {
- const responseTime = new Date(ticket.claimedAt) - new Date(ticket.createdAt);
- totalResponseTime += responseTime;
- responseCount++;
- }
+ ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'].forEach(day => {
+ modal.addComponents(
+ new ActionRowBuilder().addComponents(
+ new TextInputBuilder()
+ .setCustomId(`${day.toLowerCase()}Start`)
+ .setLabel(`${day} Start Time (HH:mm)`)
+ .setStyle(TextInputStyle.Short)
+ .setRequired(false)
+ .setValue(schedule[day.toLowerCase()]?.start || '')
+ ),
+ new ActionRowBuilder().addComponents(
+ new TextInputBuilder()
+ .setCustomId(`${day.toLowerCase()}End`)
+ .setLabel(`${day} End Time (HH:mm)`)
+ .setStyle(TextInputStyle.Short)
+ .setRequired(false)
+ .setValue(schedule[day.toLowerCase()]?.end || '')
+ )
+ );
});
- const averageResponseTime = responseCount ? totalResponseTime / responseCount : 0;
- const averageResponseTimeMinutes = Math.round(averageResponseTime / 60000);
-
- const statsEmbed = new EmbedBuilder()
- .setTitle(msgconfig.TicketStats.Title)
- .setDescription(`> Ticket stats for <@${viewingUserId}>`)
- .setColor(supportbot.Embed.Colours.General)
- .addFields(
- { name: msgconfig.TicketStats.OpenTickets, value: `${ticketsOpen.length}`, inline: true },
- { name: msgconfig.TicketStats.TotalTickets, value: `${totalTickets}`, inline: true },
- { name: msgconfig.TicketStats.ResponseTime, value: `${averageResponseTimeMinutes} minutes`, inline: false }
- );
-
- const statsButtonRow = new ActionRowBuilder()
- .addComponents(
- new ButtonBuilder()
- .setCustomId('showOpenTickets')
- .setLabel('Show Open Tickets')
- .setStyle(ButtonStyle.Secondary),
- new ButtonBuilder()
- .setCustomId('backToProfile')
- .setLabel('Back to Profile')
- .setStyle(ButtonStyle.Secondary)
- );
-
- await i.update({ embeds: [statsEmbed], components: [statsButtonRow] });
- }
-
- if (i.customId === 'backToProfile') {
- await i.update({ embeds: [profileEmbed], components: buttonRow.components.length > 0 ? [buttonRow] : [] });
+ await i.showModal(modal);
}
});
}
});
-
-module.exports.clockedInUsers = clockedInUsers;
diff --git a/Commands/ticket.js b/Commands/ticket.js
index f89261d..5260bd9 100644
--- a/Commands/ticket.js
+++ b/Commands/ticket.js
@@ -9,6 +9,7 @@ const {
StringSelectMenuBuilder,
StringSelectMenuOptionBuilder,
ButtonStyle,
+ MessageCollector,
} = require("discord.js");
const yaml = require("js-yaml");
@@ -20,6 +21,23 @@ const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
const Command = require("../Structures/Command.js");
const TicketNumberID = require("../Structures/TicketID.js");
+async function isBlacklisted(userId) {
+ let blacklistData;
+ try {
+ blacklistData = JSON.parse(fs.readFileSync("./Data/BlacklistedUsers.json", "utf8"));
+ } catch (error) {
+ console.error("Error reading BlacklistedUsers.json:", error);
+ return false; // Assume not blacklisted if there's an error
+ }
+
+ if (!blacklistData || !Array.isArray(blacklistData.blacklistedUsers)) {
+ console.error("blacklistedUsers is not defined or is not an array");
+ return false;
+ }
+
+ return blacklistData.blacklistedUsers.includes(userId);
+}
+
async function getClockedInUsers(guild) {
const clockedInUsers = new Set();
@@ -37,6 +55,60 @@ async function getClockedInUsers(guild) {
return clockedInUsers;
}
+async function askTicketQuestions(ticketChannel, interaction, questions) {
+ const answers = [];
+ let questionIndex = 0;
+
+ const sendNextQuestion = async () => {
+ if (questionIndex < questions.length) {
+
+ const questionsEmbed = new EmbedBuilder()
+ .setDescription(`**${questionIndex + 1}.** ${questions[questionIndex]}`)
+ .setColor(supportbot.Embed.Colours.General)
+
+ const questionMessage = await ticketChannel.send({
+ embeds: [questionsEmbed],
+ });
+
+ const collector = new MessageCollector(ticketChannel, {
+ filter: (m) => m.author.id === interaction.user.id,
+ max: 1,
+ time: 60000,
+ });
+
+ collector.on("collect", async (message) => {
+ answers.push({ question: questions[questionIndex], answer: message.content });
+ questionIndex++;
+ await message.delete();
+ await questionMessage.delete();
+ sendNextQuestion();
+ });
+
+ } else {
+
+ const summaryEmbed = new EmbedBuilder()
+ .setTitle(msgconfig.Ticket.TicketQuestions.Details.Title)
+ .setDescription(msgconfig.Ticket.TicketQuestions.Details.Description.replace('%user%', interaction.user.id))
+ .setColor(supportbot.Embed.Colours.General)
+ .addFields(
+ answers.map((a) => ({
+ name: `Q: ${a.question}`,
+ value: `A: ${a.answer}`,
+ inline: false,
+ }))
+ )
+ .setTimestamp();
+
+ await ticketChannel.send({
+ embeds: [summaryEmbed]
+ });
+ }
+ };
+
+ // Start asking the first question
+ sendNextQuestion();
+}
+
async function assignTicketToUser(ticketChannel, Staff, Admin, interaction, attempts = 0) {
try {
@@ -205,7 +277,16 @@ module.exports = new Command({
permissions: cmdconfig.OpenTicket.Permission,
async run(interaction) {
+
try {
+
+ if (await isBlacklisted(interaction.user.id)) {
+ return interaction.reply({
+ content: msgconfig.Ticket.Blacklisted,
+ ephemeral: true,
+ });
+ }
+
let TicketReason = null;
if (supportbot.Ticket.TicketReason) {
TicketReason = interaction.reason || null; // Retrieve the reason from the interaction object
@@ -352,6 +433,14 @@ module.exports = new Command({
});
}
+ // Ask questions to the user after the ticket is opened
+ if (supportbot.Ticket.Questions.Enabled) {
+ const questions = supportbot.Ticket.Questions.List || [];
+ if (questions.length > 0) {
+ await askTicketQuestions(ticketChannel, interaction, questions);
+ }
+ }
+
// Save ticket data
TicketData.tickets.push({
id: ticketChannel.id,
@@ -405,7 +494,6 @@ module.exports = new Command({
)
.setColor(supportbot.Embed.Colours.General);
- // Add reason field if ticket reason is enabled
if (supportbot.Ticket.TicketReason && TicketReason) {
TicketMessage.addFields(
{ name: "Reason", value: TicketReason, inline: false }
@@ -422,6 +510,11 @@ module.exports = new Command({
.setDescription("Close the ticket.")
.setEmoji(supportbot.SelectMenus.Tickets.CloseEmoji)
.setValue("ticketclose"),
+ new StringSelectMenuOptionBuilder()
+ .setLabel("Voice Channel")
+ .setDescription("Create a support voice channel.")
+ .setEmoji(supportbot.SelectMenus.Tickets.VCEmoji)
+ .setValue("supportvc"),
new StringSelectMenuOptionBuilder()
.setLabel("Archive")
.setDescription("Archive the ticket.")
@@ -463,6 +556,7 @@ module.exports = new Command({
components: [row2],
});
+
} catch (error) {
console.error("Error in run method:", error);
}
diff --git a/Configs/commands.yml b/Configs/commands.yml
index cd72e55..4f3a0cf 100644
--- a/Configs/commands.yml
+++ b/Configs/commands.yml
@@ -7,13 +7,11 @@
# SupportBot created by Emerald Services
# Installed with MIT License
#
-# Discord Support: https://dsc.gg/emerald-dev
-# Official Documentation: https://emeraldsrv.dev/wiki
-# Third-Party Documentation: https://emeraldsrv.dev/third-party
+# Discord Support: https://discord.gg/emeraldsrv
+# Official Documentation: https://docs.emeraldsrv.com
+# Addons Marketplace: https://community.emeraldsrv.com
#
-# Command Configuration
-
-# If you don't want to mess with this configuration, You can manage commands via Discord Settings the Intregations.
+# Commands Configuration (commands.yml)
Help:
Command: "help"
@@ -99,6 +97,32 @@ Ping:
Permission: ["SendMessages"]
Enabled: true
+# ---------------------------------------
+# Bot Moderator Commands
+# ---------------------------------------
+
+Mod:
+ Command: "mod"
+ Description: "Execute a moderation action."
+ Permission: ["BanMembers", "KickMembers"]
+ Enabled: true
+
+ TicketBlacklist:
+ Command: "ticket-blacklist"
+ Description: "Blacklist a user from creating Tickets."
+
+ Add:
+ Command: "add"
+ Description: "Add a user to the blacklist."
+
+ Remove:
+ Command: "remove"
+ Description: "Remove a user from the blacklist."
+
+ View:
+ Command: "view"
+ Description: "View all blacklisted users."
+
# ---------------------------------------
# Bot Administrator Commands
# ---------------------------------------
diff --git a/Configs/messages.yml b/Configs/messages.yml
index 5da7eb2..9733627 100644
--- a/Configs/messages.yml
+++ b/Configs/messages.yml
@@ -7,11 +7,15 @@
# SupportBot created by Emerald Services
# Installed with MIT License
#
-# Discord Support: https://dsc.gg/emerald-dev
-# Official Documentation: https://emeraldsrv.com/wiki
-# Third-Party Documentation: https://emeraldsrv.com/third-party
+# Discord Support: https://discord.gg/emeraldsrv
+# Official Documentation: https://docs.emeraldsrv.com
+# Addons Marketplace: https://community.emeraldsrv.com
#
-# Messages Configuration
+# Messages Configuration (messages.yml)
+
+# ----------------------------
+# Info Command
+# ----------------------------
Info:
Title: "About Us"
@@ -20,6 +24,10 @@ Info:
URL: "https://docs.emeraldsrv.com"
Colour: "#f74343"
+# ----------------------------
+# Welcome/Leave Messages
+# ----------------------------
+
Welcome:
Embed:
Colour: "#f74343"
@@ -40,12 +48,20 @@ Leave:
ImageEnabled: false
ImageURL: "https://animagelink.png/"
+# ----------------------------
+# Suggestion Messages
+# ----------------------------
+
Suggestions:
Sent_Title: "Suggestion Sent!"
Sent: ":white_check_mark: **You have successfully sent a suggestion.**"
NoSelfVote: ":x: **You cannot vote on your own suggestion.**"
RemoveVoteButton: "Remove Vote"
+# ----------------------------
+# Ticket Messages
+# ----------------------------
+
Ticket:
# Available Placeholders:
@@ -95,6 +111,44 @@ Ticket:
ReassigningTitle: "Reassigning!..."
ReassigningMessage: "<@%user%> did not claim the ticket. **Reassigning...**"
+ TicketQuestions:
+ Details:
+ Title: "Ticket Details"
+ Description: "Questions by <@%user%>" # Use <@%user%> to display the username.
+
+# ----------------------------
+# Review Messages
+# ----------------------------
+
+ReviewSystem:
+ Rate:
+ Title: "Review us!"
+ Description: "Please rate our support for this ticket (1-5 stars)."
+
+ Stars:
+ One: "⭐ 1 Star"
+ Two: "⭐⭐ 2 Stars"
+ Three: "⭐⭐⭐ 3 Stars"
+ Four: "⭐⭐⭐⭐ 4 Stars"
+ Five: "⭐⭐⭐⭐⭐ 5 Stars"
+
+ Comment:
+ Title: "Write a comment."
+ Description: "Write a comment about your experience."
+
+ ReviewEmbed:
+ Title: "Ticket Review"
+ CommentTitle: "Comment"
+ RatingTitle: "Rating"
+ ReviewedStaffTitle: "Reviewed Staff:"
+ ReviewedByTitle: "Reviewed By:"
+ ReviewEmoji: "⭐"
+ Color: "#f7a943"
+
+# ----------------------------
+# Profile Messages
+# ----------------------------
+
TicketStats:
OpenTickets: "✅ Open Tickets"
TotalTickets: "🎫 Total Tickets"
@@ -102,10 +156,46 @@ TicketStats:
Title: "Your Ticket Stats"
+# ----------------------------
+# Mod Command Messages
+# ----------------------------
+
+Mod:
+
+ TicketBlacklist:
+ Add:
+ Description: "Add a user to the ticket blacklist"
+ UserDescription: "User to blacklist"
+ AlreadyBlacklisted: ":x: {userTag} is already blacklisted."
+ Success: ":white_check_mark: {userTag} has been added to the blacklist. They can no longer use the ticket system."
+
+ Remove:
+ Description: "Remove a user from the ticket blacklist"
+ UserDescription: "User to remove from blacklist"
+ NotBlacklisted: ":x: {userTag} is not blacklisted."
+ Success: ":white_check_mark: {userTag} has been removed from the blacklist. They can now use the ticket system again."
+
+ View:
+ Description: "View the list of all blacklisted users"
+ NoBlacklistedUsers: ":information_source: There are currently no users on the blacklist."
+
+
+# ----------------------------
+# Logging Messages
+# ----------------------------
+
TicketLog:
Title: "Ticket Log"
Colour: "#0cc559"
+TicketBlacklistLog:
+ Title: "Ticket Blacklist Log"
+ Colour: "#0cc559"
+
+# ----------------------------
+# Misc Messages
+# ----------------------------
+
AddUser:
NotInTicket_Title: "Ticket Invitation"
NotInTicket_Description: "This command can only be used within a ticket thread."
@@ -171,11 +261,13 @@ ForceAddUser:
Error_Adding: "There was an error adding the user to the ticket."
Error:
- IncorrectPerms: ":x: **Err!** You do not have the correct permissions to use this."
- InvalidChannel: ":x: **Err!** Channel not found. Please create it!"
- UserNotFound: ":x: **Err!** This user doesn't exist, Are they in this server?"
- NoValidTicket: ":warning: You cannot execute this command here."
- TicketExists: ":warning: This ticket cannot be opened, It already exists!"
+ IncorrectPermissions: ":x: **Error!** You do not have the correct permissions to use this command."
+ MissingChannel: ":x: **Error!** Required channel not found. Please ensure it is set up correctly!"
+ UserNotFound: ":x: **Error!** Specified user not found. Please check if they are in this server."
+ CommandNotAllowedHere: ":warning: This command cannot be used in this channel."
+ EntryAlreadyExists: ":warning: Cannot complete the action, as the entry already exists."
+ EntryDoesNotExist: ":warning: Cannot complete the action, as the entry does not exist."
+ ActionFailed: ":x: **Error!** An error occurred while processing your request. Please try again later."
diff --git a/Configs/supportbot.yml b/Configs/supportbot.yml
index d781aa2..ea6b514 100644
--- a/Configs/supportbot.yml
+++ b/Configs/supportbot.yml
@@ -4,15 +4,16 @@
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
# |_| |_|
#
-# SupportBot created by Emerald Development
+# SupportBot created by Emerald Services
# Installed with MIT License
#
-# Discord Support: https://dsc.gg/emerald-dev
-# Official Documentation: https://github.com/Emerald-Services/SupportBot/wiki
-# Third-Party Documentation: COMING SOON
+# Discord Support: https://discord.gg/emeraldsrv
+# Official Documentation: https://docs.emeraldsrv.com
+# Addons Marketplace: https://community.emeraldsrv.com
+#
+# SupportBot Configuration (supportbot.yml)
-SupportBot_Version: "v8.2"
-# Do not change the version number
+SupportBot_Version: "v8.3"
# -------------------------
# General
@@ -20,8 +21,7 @@ SupportBot_Version: "v8.2"
General:
Name: "SupportBot"
- Token: "BOT_TOKEN_HERE"
- # To get your Discord Bot Token, Go to https://discord.com/developers/applications
+ Token: "BOT_TOKEN"
Addons:
Enabled: true
@@ -33,11 +33,16 @@ General:
Activity:
Status: "SupportBot v8"
Type: "Competing"
- # The Type can either be Playing, Watching, Listening or Competing
StreamingURL: "https://www.twitch.tv/YOUR_TWITCH_NAME"
- # Set The Type to "Streaming" for a streaming status!
- # You can update the activity via Discord using: /settings
+ # Available Types:
+ # Playing
+ # Watching
+ # Listening
+ # Competing
+ # Streaming (URL required)
+
+ # You can also update the activity via Discord using: /settings
# -------------------------
# Embeds
@@ -45,13 +50,15 @@ Activity:
Embed:
Colours:
- General: 0x0cc559 # 0x
- Success: 0x04b545 # 0x
- Error: 0xd13030 # 0x
- Warn: 0xfca117 # 0x
+ General: 0x0cc559
+ Success: 0x04b545
+ Error: 0xd13030
+ Warn: 0xfca117
Footer: "SupportBot | Developed by Emerald Development"
+ # Use 0x to change the colour of the embeds.
+
# -------------------------
# Roles
# -------------------------
@@ -62,12 +69,14 @@ Roles:
Role: "ROLE_ID"
StaffMember:
- Staff: "STAFF_ROLE_ID"
- Admin: "ADMIN_ROLE_ID"
+ Staff: "ROLE_ID"
+ Admin: "ROLE_ID"
+ Moderator: "ROLE_ID"
- ModRoles:
- Muted: "MUTED_ROLE_ID"
- Blacklisted: "BLACKLISTED_ROLE_ID"
+ Mod:
+ AllowSupportStaff: false
+
+ # Allow Support Staff to use the /mod command. (More in detail customisation in commands.yml)
# ----------------------------
# System Messages
@@ -75,18 +84,18 @@ Roles:
Welcome:
Enabled: true
- Channel: "WELCOME_CHANNEL_ID"
+ Channel: "JOIN_CHANNEL_ID"
Leave:
Enabled: true
- Channel: "LEAVE_CHANNEL_ID"
+ Channel: "JOIN_CHANNEL_ID"
# ----------------------------
# Suggestions
# ----------------------------
Suggestions:
- Channel: "SUGGEST_CHANNEL_ID"
+ Channel: "SUGGESTIONS_CHANNEL_ID"
UpvoteEmoji: "✅"
DownvoteEmoji: "❌"
@@ -94,6 +103,7 @@ Suggestions:
DownvoteTitle: "No"
OwnSuggestion: true
+
# If false this will not allow the user to vote for a suggestion they created
# If true this will allow the user to vote for a suggestion they created
@@ -120,23 +130,27 @@ Suggestions:
# Tickets
# -------------------------
-Ticket:
- TicketType: "channels" # Choose how you want tickets to be created.
- # Options:
- # channels - Tickets will be created as channels in the
- # threads - Tickets will be created as threads through the "TicketHome"
+VoiceTickets:
+ Name: "%username%'s VC"
+ Category: "VOICEE_CATEGORY_ID"
+
+Ticket:
+ TicketType: "channels"
+
+ # Available TicketTypes:
+ # channels - Tickets will be created as channels in the TicketChannelsCategory
+ # threads - Tickets will be created as threads through the "TicketHome" channel.
- # For TicketType "Threads"
TicketHome: "TICKETHOME_CHANNEL_ID"
+
# What is TicketHome?
# - Channel where the Ticket creation panel is sent.
# - Channel where ticket threads are made. (only if ticket threads is enabled above.)
- # For TicketType "Channels"
- TicketChannelsCategory: "TICKET_CATEGORY_ID" # if Type is set to channels
- TicketChannelsCategory2: "BACKUP_TICKET_CATEGORY_ID" # This will be used if the first category has reached the max channel limit.
- TicketArchiveCategory: "ARCHIVE_TICKET_CATEGORY_ID"
-
+ # For TicketType: channels
+ TicketChannelsCategory: "TICKETCHANNEL_CATEGORY_ID"
+ TicketChannelsCategory2: "TICKETCHANNEL_BACKUP_CATEGORY_ID" # This will be used if the first category has reached the max channel limit.
+ TicketArchiveCategory: "ARCHIVE_CATEGORY_ID"
# ---
Channel: "ticket-" # The prefix for ticket channel names
@@ -144,16 +158,16 @@ Ticket:
DMTranscripts: true
TicketReason: true
# If ticket reason is set to false, It will not prompt to create a reason
+
TicketSubject: "description"
+
+ # Available TicketSubjects:
# "description" will display the ticket reason within the channel description
# "embed" will display the ticket reason within the ticket embed
+
Timeout: 5
# Set to true to allow all staff to access the ticket
- Log:
- TicketDataLog: "TICKET_LOG_ID"
- TickeDataTitle: "Ticket Data"
-
Close:
StaffOnly: true
# Set to false is anyone is able to close a ticket.
@@ -164,7 +178,7 @@ Ticket:
Title: "Are you sure you want to close this ticket?"
- # Available Button Styles
+ # Available Button Styles:
# 1 - Blurple
# 2 - Grey
# 3 - Green
@@ -176,7 +190,7 @@ Ticket:
ClaimTickets:
Enabled: true
Channel: "CLAIM_TICKETS_CHANNEL_ID"
- # Channel name or Channel ID
+ # Channel where the ticket assignments are sent for staff to claim.
ClaimAcceptTime: 120000
# How long the assigned user has to accept the ticket before it gets re-assigned to someone else.
@@ -196,10 +210,34 @@ Ticket:
# 3 - Green
# 4 - Red
+ ReviewSystem:
+ Enabled: true
+ Channel: "REVIEW_CHANNEL_ID"
+ UseModal: true
+
+ Questions:
+ Enabled: true # Set to false to disable ticket questions
+ List:
+ - "Please provide your account email?"
+ - "What is the nature of your issue?"
+ - "Have you tried resolving the issue yourself?"
+
+ Log:
+ TicketDataLog: "TICKET_DATA_LOG_ID"
+ TickeDataTitle: "Ticket Data"
+ TicketBlacklistLog: "TICKET_BLACKLIST_LOG_ID"
+
# -------------------------
# Buttons
# -------------------------
Buttons:
+ General:
+ Delete: "🗑️"
+ DeleteStyle: "4"
+
+ Voice:
+ TicketDeleteText: "Delete Voice Channel"
+
Tickets:
ClaimEmoji: "🧑💻"
ClaimStyle: "1"
@@ -230,13 +268,22 @@ SelectMenus:
ArchiveEmoji: "♻️"
LockEmoji: "🔐"
RenameEmoji: "🏷️"
+ VCEmoji: "🔊"
EnableInvitesEmoji: "📤"
DisableInvitesEmoji: "📥"
# -------------------------
-# Misc
+# Logging
# -------------------------
+MessageDelete:
+ Channel: "MESSAGE_DELETE_CHANNEL_ID""
+ Colour: "#d92525"
+
+MessageUpdate:
+ Channel: "MESSAGE_UPDATE_CHANNEL_ID"
+ Colour: "#f2a024"
+
Translate:
TranslateLog: "TRANSLATE_LOG_ID"
diff --git a/Configs/ticket-panel.yml b/Configs/ticket-panel.yml
index 28072eb..5cb7f3d 100644
--- a/Configs/ticket-panel.yml
+++ b/Configs/ticket-panel.yml
@@ -7,8 +7,11 @@
# SupportBot created by Emerald Services
# Installed with MIT License
#
-# Discord Support: https://emeraldsrv.dev/discord
-# Community Resources: https://emeraldsrv.dev/resources
+# Discord Support: https://discord.gg/emeraldsrv
+# Official Documentation: https://docs.emeraldsrv.com
+# Addons Marketplace: https://community.emeraldsrv.com
+#
+# Ticket Creation Panel Configuration (ticket-panel.yml)
# -------------------------------
# Ticket Panel Configuration
diff --git a/Data/BlacklistedUsers.json b/Data/BlacklistedUsers.json
new file mode 100644
index 0000000..257b226
--- /dev/null
+++ b/Data/BlacklistedUsers.json
@@ -0,0 +1,3 @@
+{
+ "blacklistedUsers": []
+}
\ No newline at end of file
diff --git a/Data/Profiles/000000000000000.json b/Data/Profiles/000000000000000.json
new file mode 100644
index 0000000..2e52c6b
--- /dev/null
+++ b/Data/Profiles/000000000000000.json
@@ -0,0 +1,29 @@
+{
+ "bio": "",
+ "timezone": "",
+ "clockedIn": true,
+ "workingHours": 0,
+ "lastClockInTime": null,
+ "schedule": {
+ "monday": {
+ "start": "09:00",
+ "end": "17:00"
+ },
+ "tuesday": {
+ "start": "09:00",
+ "end": "17:00"
+ },
+ "wednesday": {
+ "start": "09:00",
+ "end": "17:00"
+ },
+ "thursday": {
+ "start": "09:00",
+ "end": "17:00"
+ },
+ "friday": {
+ "start": "09:00",
+ "end": "17:00"
+ }
+ }
+}
\ No newline at end of file
diff --git a/Data/Profiles/0000000000000000.json b/Data/Profiles/0000000000000000.json
new file mode 100644
index 0000000..0088126
--- /dev/null
+++ b/Data/Profiles/0000000000000000.json
@@ -0,0 +1,5 @@
+{
+ "bio": "",
+ "timezone": "",
+ "clockedIn": false
+}
diff --git a/Data/TicketData.json b/Data/TicketData.json
index 182fdc3..987b7f9 100644
--- a/Data/TicketData.json
+++ b/Data/TicketData.json
@@ -1,5 +1,5 @@
{
"tickets": [
-
+ {}
]
}
\ No newline at end of file
diff --git a/Data/ticket-panel-id.json b/Data/ticket-panel-id.json
index 3af9513..571a32a 100644
--- a/Data/ticket-panel-id.json
+++ b/Data/ticket-panel-id.json
@@ -1,4 +1,4 @@
{
"id": 0,
- "TicketPanelID": "0000000000000000000"
-}
+ "TicketPanelID": "000000000000000"
+}
\ No newline at end of file
diff --git a/Events/interactionCreate.js b/Events/interactionCreate.js
index 9d4bcf6..1849074 100644
--- a/Events/interactionCreate.js
+++ b/Events/interactionCreate.js
@@ -130,7 +130,6 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
});
}
}
-
if (interaction.isStringSelectMenu()) {
if (interaction.customId === "ticketcontrolpanel") {
const selectedOption = interaction.values[0];
@@ -146,6 +145,89 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
}
break;
+ case "supportvc":
+ const ticketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
+ const ticketInfo = ticketData.tickets.find(t => t.id === interaction.channel.id);
+
+ if (ticketInfo) {
+ const user = interaction.guild.members.cache.get(ticketInfo.user) || ticketInfo.user;
+ const claimedBy = interaction.guild.members.cache.get(ticketInfo.claimedBy) || ticketInfo.claimedBy;
+ const Admin = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Admin);
+ const Staff = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Staff);
+
+ const VCcategory = interaction.guild.channels.cache.find(
+ (c) => c.name === supportbot.VoiceTickets.Category || c.id === supportbot.VoiceTickets.Category
+ );
+
+ if (!VCcategory) {
+ return interaction.reply({
+ content: "The Support VC category does not exist!",
+ ephemeral: true,
+ });
+ }
+
+ let username = user ? user.user.username : "Unknown User";
+
+ let SupportVoice = await interaction.guild.channels.create({
+ name: supportbot.VoiceTickets.Name.replace(/%username%/g, username),
+ type: Discord.ChannelType.GuildVoice,
+ parent: VCcategory,
+ permissionOverwrites: [
+ {
+ id: user,
+ allow: [
+ Discord.PermissionsBitField.Flags.Connect,
+ Discord.PermissionsBitField.Flags.Speak,
+ Discord.PermissionsBitField.Flags.ViewChannel,
+ ],
+ },
+ {
+ id: Staff,
+ allow: [
+ Discord.PermissionsBitField.Flags.Connect,
+ Discord.PermissionsBitField.Flags.Speak,
+ Discord.PermissionsBitField.Flags.ViewChannel,
+ ],
+ },
+ {
+ id: Admin,
+ allow: [
+ Discord.PermissionsBitField.Flags.Connect,
+ Discord.PermissionsBitField.Flags.Speak,
+ Discord.PermissionsBitField.Flags.ViewChannel,
+ ],
+ },
+ {
+ id: interaction.guild.id,
+ deny: [Discord.PermissionsBitField.Flags.ViewChannel],
+ },
+ ],
+ });
+
+ ticketInfo.voiceChannelId = SupportVoice.id;
+
+ fs.writeFileSync("./Data/TicketData.json", JSON.stringify(ticketData, null, 2));
+
+ const VCDeleteButton = new Discord.ButtonBuilder()
+ .setCustomId("deleteSupportVC")
+ .setLabel(supportbot.Buttons.Voice.TicketDeleteText)
+ .setEmoji(supportbot.Buttons.General.Delete)
+ .setStyle(supportbot.Buttons.General.DeleteStyle);
+
+ const VCDeleteRow = new Discord.ActionRowBuilder().addComponents(VCDeleteButton);
+
+ const vcmadeembed = new Discord.EmbedBuilder()
+ .setDescription(`> **Support VC Created:** <#${SupportVoice.id}>`)
+ .setColor(supportbot.Embed.Colours.Success);
+
+ await interaction.reply({
+ embeds: [vcmadeembed],
+ components: [VCDeleteRow],
+ });
+
+ }
+ break;
+
case "archiveticket":
const arcembed = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.TicketArchived)
@@ -306,6 +388,64 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
}
}
+ if (interaction.customId === 'deleteSupportVC') {
+ const ticketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
+ const ticketInfo = ticketData.tickets.find(t => t.id === interaction.channel.id);
+
+ if (ticketInfo && ticketInfo.voiceChannelId) {
+ try {
+ const voiceChannel = await interaction.guild.channels.fetch(ticketInfo.voiceChannelId).catch(() => null);
+
+ if (voiceChannel) {
+ await voiceChannel.delete();
+
+ const successEmbed = new Discord.EmbedBuilder()
+ .setDescription('✅ Support voice channel has been successfully deleted!')
+ .setColor(supportbot.Embed.Colours.Success);
+
+ await interaction.reply({
+ embeds: [successEmbed],
+ ephemeral: true,
+ });
+
+ ticketInfo.voiceChannelId = null;
+ fs.writeFileSync("./Data/TicketData.json", JSON.stringify(ticketData, null, 2));
+ } else {
+ const errorEmbed = new Discord.EmbedBuilder()
+ .setDescription('❌ The associated voice channel could not be found.')
+ .setColor(supportbot.Embed.Colours.Error);
+
+ await interaction.reply({
+ embeds: [errorEmbed],
+ ephemeral: true,
+ });
+ }
+ } catch (error) {
+ console.error('Error deleting the Voice Channel:', error);
+
+ const errorEmbed = new Discord.EmbedBuilder()
+ .setDescription('❌ **There was an error trying to delete this voice channel. Please try again later.**')
+ .setColor(supportbot.Embed.Colours.Error);
+
+ await interaction.reply({
+ embeds: [errorEmbed],
+ ephemeral: true,
+ });
+ }
+ } else {
+ const errorEmbed = new Discord.EmbedBuilder()
+ .setDescription('⚠️ This button is not linked to a valid voice channel.')
+ .setColor(supportbot.Embed.Colours.Warn);
+
+ await interaction.reply({
+ embeds: [errorEmbed],
+ ephemeral: true,
+ });
+ }
+ }
+
+
+
if (interaction.isButton()) {
if (interaction.customId === "unarchiveTicket") {
diff --git a/Events/messageDelete.js b/Events/messageDelete.js
new file mode 100644
index 0000000..49807f7
--- /dev/null
+++ b/Events/messageDelete.js
@@ -0,0 +1,43 @@
+const { EmbedBuilder } = require('discord.js');
+const fs = require("fs");
+const yaml = require("js-yaml");
+const Event = require("../Structures/Event.js");
+
+// Load the configuration files
+const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
+const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
+
+module.exports = new Event("messageDelete", async (client, message) => {
+
+ // Check if the message is from a guild and not from a bot
+ if (!message.guild || message.author.bot) return;
+
+ // Get the delete log channel either by ID or by name
+ const deleteLogChannel = message.guild.channels.cache.get(supportbot.MessageDelete.Channel) ||
+ message.guild.channels.cache.find(channel => channel.name === supportbot.MessageDelete.Channel);
+
+ // Create the embed for the deleted message
+ const deletedMessageEmbed = new EmbedBuilder()
+ .setColor(supportbot.MessageDelete.Colour)
+ .setTitle("Message Deleted")
+ .setDescription(`> **Channel:** <#${message.channel.id}>\n> **Message ID** [${message.id}](https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.id})\n> **Message author:** ${message.author.tag} (${message.author.id})\n> **Message Crated:** `)
+ .addFields(
+ { name: 'Message', value: message.content || '*No content*', inline: false }
+ )
+ .setThumbnail(message.author.displayAvatarURL())
+ .setTimestamp();
+
+ // If the message contains an attachment, add it to the embed
+ if (message.attachments.size > 0) {
+ const attachment = message.attachments.first();
+ deletedMessageEmbed.addFields({ name: 'Attachment', value: `[${attachment.name}](${attachment.proxyURL})` });
+ }
+
+ // Send the embed to the delete log channel if the channel is found
+ if (deleteLogChannel) {
+ deleteLogChannel.send({
+ embeds: [deletedMessageEmbed]
+ });
+ }
+});
+
diff --git a/Events/messageUpdate.js b/Events/messageUpdate.js
new file mode 100644
index 0000000..4fac6a0
--- /dev/null
+++ b/Events/messageUpdate.js
@@ -0,0 +1,57 @@
+const { EmbedBuilder } = require('discord.js');
+const fs = require("fs");
+const yaml = require("js-yaml");
+const Event = require("../Structures/Event.js");
+
+// Load the configuration files
+const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
+const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
+
+module.exports = new Event("messageUpdate", async (client, oldMessage, newMessage) => {
+
+ // Check if the message is from a guild and not from a bot
+ if (!newMessage.guild || newMessage.author.bot) return;
+
+ // Fetch old message if it's not cached (important for message content)
+ if (!oldMessage.content && oldMessage.partial) {
+ try {
+ oldMessage = await oldMessage.fetch();
+ } catch (err) {
+ console.error('Error fetching old message:', err);
+ return;
+ }
+ }
+
+ // Fallback if content is missing
+ const oldMessageContent = oldMessage.content || (oldMessage.attachments.size > 0 ? 'Contains attachment(s)' : '*No content*');
+ const newMessageContent = newMessage.content || (newMessage.attachments.size > 0 ? 'Contains attachment(s)' : '*No content*');
+
+ // Get the update log channel either by ID or by name
+ const updateLogChannel = newMessage.guild.channels.cache.get(supportbot.MessageUpdate.Channel) ||
+ newMessage.guild.channels.cache.find(channel => channel.name === supportbot.MessageUpdate.Channel);
+
+ // Create the embed for the updated message
+ const updatedMessageEmbed = new EmbedBuilder()
+ .setColor(supportbot.MessageUpdate.Colour)
+ .setTitle("Message Updated")
+ .setDescription(`> **Channel:** <#${newMessage.channel.id}>\n> **Message ID:** [${newMessage.id}](https://discord.com/channels/${newMessage.guild.id}/${newMessage.channel.id}/${newMessage.id})\n> **Message author:** ${newMessage.author.tag} (${newMessage.author.id})\n> **Message Created:** `)
+ .addFields(
+ { name: 'Old Message', value: oldMessageContent, inline: false },
+ { name: 'New Message', value: newMessageContent, inline: false }
+ )
+ .setThumbnail(newMessage.author.displayAvatarURL())
+ .setTimestamp();
+
+ // If the new message contains an attachment, add it to the embed
+ if (newMessage.attachments.size > 0) {
+ const attachment = newMessage.attachments.first();
+ updatedMessageEmbed.addFields({ name: 'Attachment', value: `[${attachment.name}](${attachment.proxyURL})` });
+ }
+
+ // Send the embed to the update log channel if the channel is found
+ if (updateLogChannel) {
+ updateLogChannel.send({
+ embeds: [updatedMessageEmbed]
+ });
+ }
+});
diff --git a/Events/ready.js b/Events/ready.js
index 51fe00e..69a7908 100644
--- a/Events/ready.js
+++ b/Events/ready.js
@@ -89,9 +89,7 @@ module.exports = new Event("ready", async (client, interaction) => {
const roles = [
supportbot.Roles.StaffMember.Admin,
- supportbot.Roles.StaffMember.Staff,
- supportbot.Roles.ModRoles.Blacklisted,
- supportbot.Roles.ModRoles.Muted
+ supportbot.Roles.StaffMember.Staff
];
if (supportbot.Roles.AutoRole.Role) roles.push(supportbot.Roles.AutoRole.Role);
diff --git a/Structures/Client.js b/Structures/Client.js
index 3786833..812b7e0 100644
--- a/Structures/Client.js
+++ b/Structures/Client.js
@@ -13,9 +13,10 @@ class Client extends Discord.Client {
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
- GatewayIntentBits.GuildMessages
+ GatewayIntentBits.GuildMessages,
+ GatewayIntentBits.MessageContent
],
- partials: [Partials.Channel]
+ partials: [Partials.Message, Partials.Channel]
});
this.commands = new Discord.Collection();
@@ -105,6 +106,10 @@ class Client extends Discord.Client {
tempCommandFiles = tempCommandFiles.filter(item => item !== "settings.js");
}
+ if (cmdconfig.Mod.Enabled === false) {
+ tempCommandFiles = tempCommandFiles.filter(item => item !== "mod.js");
+ }
+
const commandFiles = tempCommandFiles;
const commands = commandFiles.map((file) => require(`../Commands/${file}`));
diff --git a/index.js b/index.js
index b2f9578..7343fe9 100644
--- a/index.js
+++ b/index.js
@@ -19,7 +19,7 @@ const supportbot = yaml.load(
const Client = require("./Structures/Client.js");
const client = new Client({
- intents: ['Guilds', 'GuildMembers', 'GuildMessages']
+ intents: ['Guilds', 'GuildMembers', 'GuildMessages', 'MessageContent']
});
client.start(supportbot.General.Token);
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 142e265..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,1671 +0,0 @@
-{
- "name": "supportbot",
- "version": "8.0.1",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "supportbot",
- "version": "8.0.1",
- "license": "MIT",
- "dependencies": {
- "@paypal/checkout-server-sdk": "^1.0.3",
- "@vitalets/google-translate-api": "^8.0.0",
- "axios": "^1.7.2",
- "chatgpt": "^5.2.5",
- "discord.js": "^14.13.0",
- "js": "^0.1.0",
- "js-yaml": "^4.1.0",
- "moment": "^2.29.3",
- "ms": "^2.1.3",
- "openai": "^4.50.0",
- "paypal-rest-sdk": "^1.8.1"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
- "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
- "dependencies": {
- "@babel/highlight": "^7.24.7",
- "picocolors": "^1.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
- "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
- "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.24.7",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@discordjs/builders": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.8.2.tgz",
- "integrity": "sha512-6wvG3QaCjtMu0xnle4SoOIeFB4y6fKMN6WZfy3BMKJdQQtPLik8KGzDwBVL/+wTtcE/ZlFjgEk74GublyEVZ7g==",
- "dependencies": {
- "@discordjs/formatters": "^0.4.0",
- "@discordjs/util": "^1.1.0",
- "@sapphire/shapeshift": "^3.9.7",
- "discord-api-types": "0.37.83",
- "fast-deep-equal": "^3.1.3",
- "ts-mixer": "^6.0.4",
- "tslib": "^2.6.2"
- },
- "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.4.0",
- "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.4.0.tgz",
- "integrity": "sha512-fJ06TLC1NiruF35470q3Nr1bi95BdvKFAF+T5bNfZJ4bNdqZ3VZ+Ttg6SThqTxm6qumSG3choxLBHMC69WXNXQ==",
- "dependencies": {
- "discord-api-types": "0.37.83"
- },
- "engines": {
- "node": ">=16.11.0"
- },
- "funding": {
- "url": "https://github.com/discordjs/discord.js?sponsor"
- }
- },
- "node_modules/@discordjs/rest": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.3.0.tgz",
- "integrity": "sha512-C1kAJK8aSYRv3ZwMG8cvrrW4GN0g5eMdP8AuN8ODH5DyOCbHgJspze1my3xHOAgwLJdKUbWNVyAeJ9cEdduqIg==",
- "dependencies": {
- "@discordjs/collection": "^2.1.0",
- "@discordjs/util": "^1.1.0",
- "@sapphire/async-queue": "^1.5.2",
- "@sapphire/snowflake": "^3.5.3",
- "@vladfrangu/async_event_emitter": "^2.2.4",
- "discord-api-types": "0.37.83",
- "magic-bytes.js": "^1.10.0",
- "tslib": "^2.6.2",
- "undici": "6.13.0"
- },
- "engines": {
- "node": ">=16.11.0"
- },
- "funding": {
- "url": "https://github.com/discordjs/discord.js?sponsor"
- }
- },
- "node_modules/@discordjs/rest/node_modules/@discordjs/collection": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.0.tgz",
- "integrity": "sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/discordjs/discord.js?sponsor"
- }
- },
- "node_modules/@discordjs/util": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.0.tgz",
- "integrity": "sha512-IndcI5hzlNZ7GS96RV3Xw1R2kaDuXEp7tRIy/KlhidpN/BQ1qh1NZt3377dMLTa44xDUNKT7hnXkA/oUAzD/lg==",
- "engines": {
- "node": ">=16.11.0"
- },
- "funding": {
- "url": "https://github.com/discordjs/discord.js?sponsor"
- }
- },
- "node_modules/@discordjs/ws": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.1.1.tgz",
- "integrity": "sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==",
- "dependencies": {
- "@discordjs/collection": "^2.1.0",
- "@discordjs/rest": "^2.3.0",
- "@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.83",
- "tslib": "^2.6.2",
- "ws": "^8.16.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.0",
- "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.0.tgz",
- "integrity": "sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/discordjs/discord.js?sponsor"
- }
- },
- "node_modules/@paypal/checkout-server-sdk": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@paypal/checkout-server-sdk/-/checkout-server-sdk-1.0.3.tgz",
- "integrity": "sha512-UEdq8akEdMz0Vs4qoQFU2gMp8PpyE/HKyMwiZuK4vIWUKl8jfd1fWKjQN5cDFm9NkFUIp5U7h++rdMOVj9WMNA==",
- "dependencies": {
- "@paypal/paypalhttp": "^1.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@paypal/paypalhttp": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@paypal/paypalhttp/-/paypalhttp-1.0.1.tgz",
- "integrity": "sha512-DC7AHxTT7drF6dUi3YaFdPVuT15sIkpD5H2eHmdtFgxM4UanS1o1ZDfMhR9mpxd8o+X6pz2r+EZVRRq+n1cssQ==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@sapphire/async-queue": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.3.tgz",
- "integrity": "sha512-x7zadcfJGxFka1Q3f8gCts1F0xMwCKbZweM85xECGI0hBTeIZJGGCrHgLggihBoprlQ/hBmDR5LKfIPqnmHM3w==",
- "engines": {
- "node": ">=v14.0.0",
- "npm": ">=7.0.0"
- }
- },
- "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/@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": "0.14.0",
- "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
- "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/@szmarczak/http-timer": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
- "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
- "dependencies": {
- "defer-to-connect": "^1.0.1"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/@types/node": {
- "version": "20.14.12",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz",
- "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==",
- "dependencies": {
- "undici-types": "~5.26.4"
- }
- },
- "node_modules/@types/node-fetch": {
- "version": "2.6.11",
- "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz",
- "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==",
- "dependencies": {
- "@types/node": "*",
- "form-data": "^4.0.0"
- }
- },
- "node_modules/@types/normalize-package-data": {
- "version": "2.4.4",
- "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
- "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="
- },
- "node_modules/@types/ws": {
- "version": "8.5.11",
- "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz",
- "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@vitalets/google-translate-api": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/@vitalets/google-translate-api/-/google-translate-api-8.0.0.tgz",
- "integrity": "sha512-CHOi8DRgDAoLlFQy9pm1KHUauIk5ZXys3+Eh0aSYxzJSuxAE7Z2UL8+5MgNdl1oX7t/O7u+SwGhkhu6+U1bNcg==",
- "dependencies": {
- "configstore": "^5.0.1",
- "got": "^9.6.0"
- }
- },
- "node_modules/@vladfrangu/async_event_emitter": {
- "version": "2.4.4",
- "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.4.tgz",
- "integrity": "sha512-ZL62PFXEIeGUI8btfJ5S8Flc286eU1ZUSjwyFQtIGXfRUDPZKO+CDJMYb1R71LjGWRZ4n202O+a6FGjsgTw58g==",
- "engines": {
- "node": ">=v14.0.0",
- "npm": ">=7.0.0"
- }
- },
- "node_modules/abort-controller": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
- "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
- "dependencies": {
- "event-target-shim": "^5.0.0"
- },
- "engines": {
- "node": ">=6.5"
- }
- },
- "node_modules/agentkeepalive": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz",
- "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==",
- "dependencies": {
- "humanize-ms": "^1.2.1"
- },
- "engines": {
- "node": ">= 8.0.0"
- }
- },
- "node_modules/ajv": {
- "version": "8.17.1",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
- "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
- "dependencies": {
- "fast-deep-equal": "^3.1.3",
- "fast-uri": "^3.0.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ajv-formats": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
- "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
- "dependencies": {
- "ajv": "^8.0.0"
- },
- "peerDependencies": {
- "ajv": "^8.0.0"
- },
- "peerDependenciesMeta": {
- "ajv": {
- "optional": true
- }
- }
- },
- "node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
- },
- "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/atomically": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.0.3.tgz",
- "integrity": "sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==",
- "dependencies": {
- "stubborn-fs": "^1.2.5",
- "when-exit": "^2.1.1"
- }
- },
- "node_modules/axios": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
- "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
- "dependencies": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.0",
- "proxy-from-env": "^1.1.0"
- }
- },
- "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/buffer-crc32": {
- "version": "0.2.13",
- "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
- "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/cac": {
- "version": "6.7.14",
- "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
- "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cacheable-request": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
- "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==",
- "dependencies": {
- "clone-response": "^1.0.2",
- "get-stream": "^5.1.0",
- "http-cache-semantics": "^4.0.0",
- "keyv": "^3.0.0",
- "lowercase-keys": "^2.0.0",
- "normalize-url": "^4.1.0",
- "responselike": "^1.0.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cacheable-request/node_modules/get-stream": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
- "dependencies": {
- "pump": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/cacheable-request/node_modules/json-buffer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
- "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ=="
- },
- "node_modules/cacheable-request/node_modules/keyv": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
- "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
- "dependencies": {
- "json-buffer": "3.0.0"
- }
- },
- "node_modules/cacheable-request/node_modules/lowercase-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
- "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/chatgpt": {
- "version": "5.2.5",
- "resolved": "https://registry.npmjs.org/chatgpt/-/chatgpt-5.2.5.tgz",
- "integrity": "sha512-DNhBzPb2zTDjJADY44XfngMvsvrvHRq1md2VPXLmnKeP1UCeA1B6pV3s9ZRwlcgjVT0RyM77fRj1xj5V11Vctg==",
- "dependencies": {
- "cac": "^6.7.14",
- "conf": "^11.0.1",
- "eventsource-parser": "^1.0.0",
- "js-tiktoken": "^1.0.5",
- "keyv": "^4.5.2",
- "p-timeout": "^6.1.1",
- "quick-lru": "^6.1.1",
- "read-pkg-up": "^9.1.0",
- "uuid": "^9.0.0"
- },
- "bin": {
- "chatgpt": "bin/cli.js"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/clone-response": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
- "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
- "dependencies": {
- "mimic-response": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "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/commander": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-1.1.1.tgz",
- "integrity": "sha512-71Rod2AhcH3JhkBikVpNd0pA+fWsmAaVoti6OR38T76chA7vE3pSerS0Jor4wDw+tOueD2zLVvFOw5H0Rcj7rA==",
- "dependencies": {
- "keypress": "0.1.x"
- },
- "engines": {
- "node": ">= 0.6.x"
- }
- },
- "node_modules/conf": {
- "version": "11.0.2",
- "resolved": "https://registry.npmjs.org/conf/-/conf-11.0.2.tgz",
- "integrity": "sha512-jjyhlQ0ew/iwmtwsS2RaB6s8DBifcE2GYBEaw2SJDUY/slJJbNfY4GlDVzOs/ff8cM/Wua5CikqXgbFl5eu85A==",
- "dependencies": {
- "ajv": "^8.12.0",
- "ajv-formats": "^2.1.1",
- "atomically": "^2.0.0",
- "debounce-fn": "^5.1.2",
- "dot-prop": "^7.2.0",
- "env-paths": "^3.0.0",
- "json-schema-typed": "^8.0.1",
- "semver": "^7.3.8"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/configstore": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
- "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==",
- "dependencies": {
- "dot-prop": "^5.2.0",
- "graceful-fs": "^4.1.2",
- "make-dir": "^3.0.0",
- "unique-string": "^2.0.0",
- "write-file-atomic": "^3.0.0",
- "xdg-basedir": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/configstore/node_modules/dot-prop": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
- "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
- "dependencies": {
- "is-obj": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/crypto-random-string": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
- "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/debounce-fn": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-5.1.2.tgz",
- "integrity": "sha512-Sr4SdOZ4vw6eQDvPYNxHogvrxmCIld/VenC5JbNrFwMiwd7lY/Z18ZFfo+EWNG4DD9nFlAujWAo/wGuOPHmy5A==",
- "dependencies": {
- "mimic-fn": "^4.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/decompress-response": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
- "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==",
- "dependencies": {
- "mimic-response": "^1.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/defer-to-connect": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
- "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ=="
- },
- "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.83",
- "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.83.tgz",
- "integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA=="
- },
- "node_modules/discord.js": {
- "version": "14.15.3",
- "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.15.3.tgz",
- "integrity": "sha512-/UJDQO10VuU6wQPglA4kz2bw2ngeeSbogiIPx/TsnctfzV/tNf+q+i1HlgtX1OGpeOBpJH9erZQNO5oRM2uAtQ==",
- "dependencies": {
- "@discordjs/builders": "^1.8.2",
- "@discordjs/collection": "1.5.3",
- "@discordjs/formatters": "^0.4.0",
- "@discordjs/rest": "^2.3.0",
- "@discordjs/util": "^1.1.0",
- "@discordjs/ws": "^1.1.1",
- "@sapphire/snowflake": "3.5.3",
- "discord-api-types": "0.37.83",
- "fast-deep-equal": "3.1.3",
- "lodash.snakecase": "4.1.1",
- "tslib": "2.6.2",
- "undici": "6.13.0"
- },
- "engines": {
- "node": ">=16.11.0"
- },
- "funding": {
- "url": "https://github.com/discordjs/discord.js?sponsor"
- }
- },
- "node_modules/dot-prop": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz",
- "integrity": "sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA==",
- "dependencies": {
- "type-fest": "^2.11.2"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/duplexer3": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz",
- "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA=="
- },
- "node_modules/end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "dependencies": {
- "once": "^1.4.0"
- }
- },
- "node_modules/env-paths": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
- "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "dependencies": {
- "is-arrayish": "^0.2.1"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/event-target-shim": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
- "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/eventsource-parser": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz",
- "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==",
- "engines": {
- "node": ">=14.18"
- }
- },
- "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-uri": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
- "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw=="
- },
- "node_modules/find-up": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
- "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
- "dependencies": {
- "locate-path": "^7.1.0",
- "path-exists": "^5.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/follow-redirects": {
- "version": "1.15.6",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- },
- "node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/form-data-encoder": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
- "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="
- },
- "node_modules/formdata-node": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
- "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
- "dependencies": {
- "node-domexception": "1.0.0",
- "web-streams-polyfill": "4.0.0-beta.3"
- },
- "engines": {
- "node": ">= 12.20"
- }
- },
- "node_modules/formdata-node/node_modules/web-streams-polyfill": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
- "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
- "engines": {
- "node": ">= 14"
- }
- },
- "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-stream": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
- "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
- "dependencies": {
- "pump": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/got": {
- "version": "9.6.0",
- "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
- "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==",
- "dependencies": {
- "@sindresorhus/is": "^0.14.0",
- "@szmarczak/http-timer": "^1.1.2",
- "cacheable-request": "^6.0.0",
- "decompress-response": "^3.3.0",
- "duplexer3": "^0.1.4",
- "get-stream": "^4.1.0",
- "lowercase-keys": "^1.0.1",
- "mimic-response": "^1.0.1",
- "p-cancelable": "^1.0.0",
- "to-readable-stream": "^1.0.0",
- "url-parse-lax": "^3.0.0"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
- },
- "node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "engines": {
- "node": ">=4"
- }
- },
- "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/hosted-git-info": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
- "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/http-cache-semantics": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
- "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
- },
- "node_modules/humanize-ms": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
- "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
- "dependencies": {
- "ms": "^2.0.0"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
- },
- "node_modules/is-core-module": {
- "version": "2.15.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz",
- "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==",
- "dependencies": {
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-obj": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
- "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
- },
- "node_modules/js": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/js/-/js-0.1.0.tgz",
- "integrity": "sha512-ZBbGYOpact8QAH9RprFWL4RAESYwbDodxiuDjOnzwzzk9pBzKycoifGuUrHHcDixE/eLMKPHRaXenTgu1qXBqA==",
- "dependencies": {
- "commander": "~1.1.1"
- },
- "bin": {
- "js": "bin/js"
- }
- },
- "node_modules/js-tiktoken": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.12.tgz",
- "integrity": "sha512-L7wURW1fH9Qaext0VzaUDpFGVQgjkdE3Dgsy9/+yXyGEpBKnylTd0mU0bfbNkKDlXRb6TEsZkwuflu1B8uQbJQ==",
- "dependencies": {
- "base64-js": "^1.5.1"
- }
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
- },
- "node_modules/json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
- },
- "node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
- },
- "node_modules/json-schema-typed": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.1.tgz",
- "integrity": "sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg=="
- },
- "node_modules/keypress": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz",
- "integrity": "sha512-x0yf9PL/nx9Nw9oLL8ZVErFAk85/lslwEP7Vz7s5SI1ODXZIgit3C5qyWjw4DxOuO/3Hb4866SQh28a1V1d+WA=="
- },
- "node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
- "dependencies": {
- "json-buffer": "3.0.1"
- }
- },
- "node_modules/lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
- },
- "node_modules/locate-path": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
- "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
- "dependencies": {
- "p-locate": "^6.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "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/lowercase-keys": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
- "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "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/make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dependencies": {
- "semver": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/make-dir/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "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/mimic-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
- "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mimic-response": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
- "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/moment": {
- "version": "2.30.1",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
- "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
- "engines": {
- "node": "*"
- }
- },
- "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-domexception": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
- "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/jimmywarting"
- },
- {
- "type": "github",
- "url": "https://paypal.me/jimmywarting"
- }
- ],
- "engines": {
- "node": ">=10.5.0"
- }
- },
- "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/normalize-package-data": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
- "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
- "dependencies": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/normalize-url": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz",
- "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/openai": {
- "version": "4.53.0",
- "resolved": "https://registry.npmjs.org/openai/-/openai-4.53.0.tgz",
- "integrity": "sha512-XoMaJsSLuedW5eoMEMmZbdNoXgML3ujcU5KfwRnC6rnbmZkHE2Q4J/SArwhqCxQRqJwHnQUj1LpiROmKPExZJA==",
- "dependencies": {
- "@types/node": "^18.11.18",
- "@types/node-fetch": "^2.6.4",
- "abort-controller": "^3.0.0",
- "agentkeepalive": "^4.2.1",
- "form-data-encoder": "1.7.2",
- "formdata-node": "^4.3.2",
- "node-fetch": "^2.6.7",
- "web-streams-polyfill": "^3.2.1"
- },
- "bin": {
- "openai": "bin/cli"
- }
- },
- "node_modules/openai/node_modules/@types/node": {
- "version": "18.19.42",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.42.tgz",
- "integrity": "sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg==",
- "dependencies": {
- "undici-types": "~5.26.4"
- }
- },
- "node_modules/p-cancelable": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
- "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/p-limit": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
- "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
- "dependencies": {
- "yocto-queue": "^1.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
- "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
- "dependencies": {
- "p-limit": "^4.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-timeout": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz",
- "integrity": "sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==",
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "dependencies": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/path-exists": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
- "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- }
- },
- "node_modules/paypal-rest-sdk": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/paypal-rest-sdk/-/paypal-rest-sdk-1.8.1.tgz",
- "integrity": "sha512-Trj2GuPn10GqpICAxQh5wjxuDT7rq7DMOkvyatz05wI5xPGmqXN7UC0WfDSF9WSBs4YdcWZP0g+nY+sOdaFggw==",
- "dependencies": {
- "buffer-crc32": "^0.2.3",
- "semver": "^5.0.3"
- },
- "engines": {
- "node": ">= v0.6.0"
- }
- },
- "node_modules/paypal-rest-sdk/node_modules/semver": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
- "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
- "bin": {
- "semver": "bin/semver"
- }
- },
- "node_modules/picocolors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
- },
- "node_modules/prepend-http": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
- "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/proxy-from-env": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
- "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
- },
- "node_modules/pump": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
- "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
- "dependencies": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- },
- "node_modules/quick-lru": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz",
- "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/read-pkg": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz",
- "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==",
- "dependencies": {
- "@types/normalize-package-data": "^2.4.1",
- "normalize-package-data": "^3.0.2",
- "parse-json": "^5.2.0",
- "type-fest": "^2.0.0"
- },
- "engines": {
- "node": ">=12.20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/read-pkg-up": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz",
- "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==",
- "dependencies": {
- "find-up": "^6.3.0",
- "read-pkg": "^7.1.0",
- "type-fest": "^2.5.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/responselike": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
- "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==",
- "dependencies": {
- "lowercase-keys": "^1.0.0"
- }
- },
- "node_modules/semver": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
- "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
- },
- "node_modules/spdx-correct": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
- "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
- "dependencies": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "node_modules/spdx-exceptions": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
- "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="
- },
- "node_modules/spdx-expression-parse": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
- "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
- "dependencies": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "node_modules/spdx-license-ids": {
- "version": "3.0.18",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz",
- "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ=="
- },
- "node_modules/stubborn-fs": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-1.2.5.tgz",
- "integrity": "sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g=="
- },
- "node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/to-readable-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
- "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
- },
- "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.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
- },
- "node_modules/type-fest": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
- "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
- "engines": {
- "node": ">=12.20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/typedarray-to-buffer": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
- "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
- "dependencies": {
- "is-typedarray": "^1.0.0"
- }
- },
- "node_modules/undici": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-6.13.0.tgz",
- "integrity": "sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==",
- "engines": {
- "node": ">=18.0"
- }
- },
- "node_modules/undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
- },
- "node_modules/unique-string": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
- "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
- "dependencies": {
- "crypto-random-string": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/url-parse-lax": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
- "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==",
- "dependencies": {
- "prepend-http": "^2.0.0"
- },
- "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"
- ],
- "bin": {
- "uuid": "dist/bin/uuid"
- }
- },
- "node_modules/validate-npm-package-license": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
- "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
- "dependencies": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
- "node_modules/web-streams-polyfill": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
- "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
- "engines": {
- "node": ">= 8"
- }
- },
- "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/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/when-exit": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.3.tgz",
- "integrity": "sha512-uVieSTccFIr/SFQdFWN/fFaQYmV37OKtuaGphMAzi4DmmUlrvRBJW5WSLkHyjNQY/ePJMz3LoiX9R3yy1Su6Hw=="
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- },
- "node_modules/write-file-atomic": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
- "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
- "dependencies": {
- "imurmurhash": "^0.1.4",
- "is-typedarray": "^1.0.0",
- "signal-exit": "^3.0.2",
- "typedarray-to-buffer": "^3.1.5"
- }
- },
- "node_modules/ws": {
- "version": "8.18.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
- "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
- "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
- }
- }
- },
- "node_modules/xdg-basedir": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
- "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
- "node_modules/yocto-queue": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz",
- "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==",
- "engines": {
- "node": ">=12.20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- }
- }
-}
diff --git a/package.json b/package.json
index b9f51fb..9debb6c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "supportbot",
- "version": "8.0.1",
+ "version": "8.3",
"description": "SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customization to match your own brand.",
"main": "index.js",
"scripts": {
@@ -16,17 +16,16 @@
"bugs": {
"url": "https://github.com/Emerald-Services/SupportBot/issues"
},
- "homepage": "https://github.com/Emerald-Services/SupportBot#readme",
+ "homepage": "https://community.emeraldsrv.dev",
"dependencies": {
"@paypal/checkout-server-sdk": "^1.0.3",
"@vitalets/google-translate-api": "^8.0.0",
"axios": "^1.7.2",
- "chatgpt": "^5.2.5",
"discord.js": "^14.13.0",
"js": "^0.1.0",
"js-yaml": "^4.1.0",
"moment": "^2.29.3",
"ms": "^2.1.3",
- "openai": "^4.50.0",
+ "openai": "^4.50.0"
}
}