Compare commits

...
8 Commits
Author SHA1 Message Date
1tzEmerald b941909983 Merge pull request #212 from Emerald-Services/26.2
26.2
2026-08-28 17:57:00 +01:00
1tzEmerald 01f9ebe387 removed junk 2026-08-28 17:49:56 +01:00
1tzEmerald a746c468e5 26.2 final push 2026-08-28 17:48:09 +01:00
1tzEmerald 2017c33756 update 2026-08-12 00:12:18 +01:00
1tzEmerald 4eef1867e3 26.2 pre3 2026-08-10 20:15:00 +01:00
1tzEmerald a7598d26aa Fix BETTERSQLLITE ISSUE 2026-08-06 17:29:37 +01:00
1tzEmerald 762fcf45c3 26.2-pre-2 2026-08-06 16:30:04 +01:00
1tzEmerald ea2a8c97ae Removed optional addons by default 2026-07-26 21:23:16 +01:00
55 changed files with 2946 additions and 3777 deletions

No files matched your search

+14 -3
View File
@@ -1,10 +1,21 @@
node_modules
# Local database, runtime data, and transcripts
Data/*.db
Data/*.db-shm
Data/*.db-wal
Data/Transcripts/*
Data/dashboard-groups.json
Data/dashboard-users.json
Data/transcript-settings.json
# Local log files
Logs/Output/*
Logs/Errors/*
Logs/Warns/*
# Dashboard UI source at repo root only (do not ignore public/dashboard/)
/dashboard/
# Local git hooks + secret-stripping scripts (run npm run git:setup)
scripts/
# Local secrets — use *.example as templates
Configs/api.yml
+542 -2
View File
@@ -98,6 +98,9 @@ class APIServer {
this.client = client;
this.app = express();
this.sseClients = new Set();
global.apiServer = this;
try {
const apiCfg = yaml.load(fs.readFileSync('./Configs/api.yml', 'utf8')).API;
this.config = apiCfg;
@@ -196,12 +199,25 @@ class APIServer {
req.dashboardPermissions = access.permissions;
req.dashboardRole = access.role;
req.dashboardIsOwner = access.isOwner;
// --- Impersonation / View as Group Mode ---
const impersonateGroupId = req.headers['x-impersonate-group'];
if (impersonateGroupId && (access.isOwner || hasPermission(access.permissions, 'users.manage'))) {
const groupStore = require('../Structures/DashboardGroupStore.js');
const group = groupStore.getGroup(impersonateGroupId);
if (group) {
req.dashboardPermissions = group.permissions;
req.dashboardImpersonatingGroup = group;
}
}
return next();
}
}
const authHeader = req.headers.authorization;
if (authHeader === `Bearer ${secret}`) {
const tokenQuery = req.query.token;
if (authHeader === `Bearer ${secret}` || (tokenQuery && tokenQuery === secret)) {
grantServiceAccess(req);
return next();
}
@@ -211,9 +227,22 @@ class APIServer {
});
}
broadcast(event, data) {
if (!this.sseClients || this.sseClients.size === 0) return;
const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
for (const clientRes of this.sseClients) {
try {
clientRes.write(payload);
} catch (e) {
this.sseClients.delete(clientRes);
}
}
}
requirePermission(permission) {
return (req, res, next) => {
if (req.dashboardService) return next();
if (req.dashboardIsOwner && !req.dashboardImpersonatingGroup) return next();
if (hasPermission(req.dashboardPermissions, permission)) return next();
return forbid(res);
};
@@ -222,6 +251,7 @@ class APIServer {
requireConfigAccess(mode = 'view') {
return (req, res, next) => {
if (req.dashboardService) return next();
if (req.dashboardIsOwner && !req.dashboardImpersonatingGroup) return next();
const file = req.params?.file || req.body?.filename;
if (!file) return next();
if (!canAccessConfig(req.dashboardPermissions, file, mode)) {
@@ -478,6 +508,26 @@ h1{font-size:1.25rem}a{color:#a78bfa}</style></head><body>
this.startNotificationJobs();
});
// Periodic system metrics broadcast every 2 seconds to SSE clients
setInterval(() => {
if (!this.sseClients || this.sseClients.size === 0) return;
const totalMem = os.totalmem();
const freeMem = os.freemem();
const usedMem = totalMem - freeMem;
const ramPercent = Math.round((usedMem / totalMem) * 100);
const cpuLoad = parseFloat(os.loadavg()[0].toFixed(2));
this.broadcast('metrics', {
timestamp: Date.now(),
ping: this.client?.ws?.ping ?? 0,
ram_percent: ramPercent,
ram_used_mb: Math.round(usedMem / 1024 / 1024),
ram_total_mb: Math.round(totalMem / 1024 / 1024),
cpu_load: cpuLoad,
uptime: process.uptime()
});
}, 2000);
this._httpServer.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
console.error(
@@ -543,6 +593,450 @@ h1{font-size:1.25rem}a{color:#a78bfa}</style></head><body>
const p = (permission) => this.requirePermission(permission);
const cv = (mode) => this.requireConfigAccess(mode);
// --- Real-time SSE Stream ---
app.get('/stream', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*'
});
res.write('event: connected\ndata: {"connected": true}\n\n');
this.sseClients.add(res);
req.on('close', () => {
this.sseClients.delete(res);
});
});
// --- Ticket Chat & Management API ---
app.get('/system/tickets/open', p('tickets'), async (req, res) => {
try {
const allTickets = db.getAllTickets() || [];
const openTickets = allTickets.filter(t => t.status === 'open' || t.status === undefined || t.open);
const guildId = this.client?.guilds?.cache?.first()?.id || "";
res.json({
success: true,
data: {
guildId,
tickets: openTickets.map(t => ({
ticket_id: t.ticket_id,
user_id: t.user_id,
subject: t.subject || t.reason || 'Untitled Ticket',
description: t.description || '',
department: t.department || 'general',
priority: t.priority || 'medium',
created_at: t.created_at
}))
}
});
} catch (err) {
console.error('[API] Error fetching open tickets:', err);
res.status(500).json({ success: false, error: 'Failed to fetch open tickets' });
}
});
app.post('/system/tickets/create', p('tickets'), async (req, res) => {
try {
const { department, subject, reason, userId } = req.body;
if (!this.client?.user) {
return res.status(503).json({ success: false, error: 'Bot is not connected to Discord.' });
}
const guild = this.client.guilds.cache.first();
if (!guild) {
return res.status(404).json({ success: false, error: 'No connected Discord server found.' });
}
const supportbot = configStore.supportbot;
const cmdconfig = configStore.commands;
const deptKey = department || supportbot?.Ticket?.DepartmentSystem?.DefaultDepartment || 'general';
const deptConfig = supportbot?.Ticket?.DepartmentSystem?.Departments?.[deptKey];
if (deptConfig && deptConfig.Enabled === false) {
return res.status(400).json({ success: false, error: `Ticket department '${deptKey}' is currently disabled.` });
}
const targetUserId = userId || req.dashboardUser?.id || guild.ownerId;
let targetUser = await this.client.users.fetch(targetUserId).catch(() => null);
if (!targetUser) {
targetUser = this.client.user;
}
const openCmd = this.client.commands.get(cmdconfig?.OpenTicket?.Command || "new");
if (!openCmd) {
return res.status(500).json({ success: false, error: 'Open ticket command not found in bot.' });
}
const fakeInteraction = {
client: this.client,
guild,
user: targetUser,
member: await guild.members.fetch(targetUser.id).catch(() => null),
channel: guild.channels.cache.first(),
department: deptKey,
reason: subject || reason || "Opened via Web Dashboard",
priority: deptConfig?.DefaultPriority || supportbot?.Ticket?.PrioritySystem?.DefaultPriority || "medium",
options: {
getString: (name) => {
if (name === "department") return deptKey;
if (name === "reason") return subject || reason || "Opened via Web Dashboard";
if (name === "priority") return deptConfig?.DefaultPriority || supportbot?.Ticket?.PrioritySystem?.DefaultPriority || "medium";
return null;
}
},
isCommand: () => false,
isChatInputCommand: () => false,
isButton: () => false,
isStringSelectMenu: () => false,
isModalSubmit: () => false,
deferred: false,
replied: false,
deferReply: async () => {},
reply: async (payload) => { fakeInteraction.repliedPayload = payload; },
followUp: async (payload) => { fakeInteraction.followUpPayload = payload; },
editReply: async (payload) => { fakeInteraction.editReplyPayload = payload; }
};
await openCmd.run(fakeInteraction);
res.json({
success: true,
message: `Ticket successfully created for department: ${deptConfig?.Name || deptKey}!`,
});
} catch (err) {
console.error('[API] Error creating ticket:', err);
res.status(500).json({ success: false, error: err.message || 'Failed to create ticket' });
}
});
app.get('/system/tickets/:ticketId/messages', p('tickets'), async (req, res) => {
const { ticketId } = req.params;
try {
const channel = await this.client.channels.fetch(ticketId).catch(() => null);
if (!channel || !channel.isTextBased()) {
return res.status(404).json({ success: false, error: 'Ticket channel not found or inactive.' });
}
const fetchedMessages = await channel.messages.fetch({ limit: 50 });
const messages = Array.from(fetchedMessages.values())
.reverse()
.map(m => ({
id: m.id,
author: {
id: m.author.id,
username: m.author.username,
globalName: m.author.globalName || m.author.username,
avatar: m.author.displayAvatarURL({ extension: 'png', size: 64 }),
bot: m.author.bot
},
content: (() => {
if (m.content && m.content.trim()) return m.content;
if (Array.isArray(m.components) && m.components.length > 0) {
const texts = [];
for (const comp of m.components) {
const data = typeof comp.toJSON === 'function' ? comp.toJSON() : comp;
if (data.content) texts.push(data.content);
if (Array.isArray(data.components)) {
for (const child of data.components) {
const childData = typeof child.toJSON === 'function' ? child.toJSON() : child;
if (childData.content) texts.push(childData.content);
if (childData.label && (childData.type === 10 || childData.type === 'TEXT_DISPLAY')) {
texts.push(childData.label);
}
}
}
}
if (texts.length > 0) return texts.join('\n');
}
return m.content || '';
})(),
containerColor: (() => {
if (Array.isArray(m.components)) {
for (const comp of m.components) {
const data = typeof comp.toJSON === 'function' ? comp.toJSON() : comp;
if (data.accent_color) {
return `#${data.accent_color.toString(16).padStart(6, '0')}`;
}
}
}
return null;
})(),
embeds: m.embeds.map(e => ({
title: e.title || null,
description: e.description || null,
color: e.color ? `#${e.color.toString(16).padStart(6, '0')}` : '#5865F2',
author: e.author ? { name: e.author.name, iconURL: e.author.iconURL } : null,
fields: (e.fields || []).map(f => ({ name: f.name, value: f.value, inline: f.inline })),
footer: e.footer ? { text: e.footer.text, iconURL: e.footer.iconURL } : null,
thumbnail: e.thumbnail?.url ? { url: e.thumbnail.url } : null,
image: e.image?.url ? { url: e.image.url } : null,
timestamp: e.timestamp || null
})),
components: (m.components || []).map(c => {
const data = typeof c.toJSON === 'function' ? c.toJSON() : c;
return {
type: data.type,
components: (data.components || []).map(sub => {
const subData = typeof sub.toJSON === 'function' ? sub.toJSON() : sub;
return {
type: subData.type,
label: subData.label || subData.content || null,
style: subData.style || null,
url: subData.url || null,
customId: subData.custom_id || subData.customId || null,
emoji: subData.emoji ? (subData.emoji.name || subData.emoji.id) : null
};
})
};
}),
attachments: Array.from(m.attachments.values()).map(a => ({
id: a.id,
name: a.name,
url: a.url,
contentType: a.contentType
})),
createdAt: m.createdTimestamp
}));
res.json({ success: true, data: { ticketId, messages } });
} catch (err) {
console.error('[API] Error fetching ticket messages:', err);
res.status(500).json({ success: false, error: 'Failed to fetch ticket messages' });
}
});
app.post('/system/tickets/:ticketId/reply', p('tickets'), async (req, res) => {
const { ticketId } = req.params;
const { message, staffName, attachments } = req.body;
const hasText = message && message.trim();
const hasAttachments = Array.isArray(attachments) && attachments.length > 0;
if (!hasText && !hasAttachments) {
return res.status(400).json({ success: false, error: 'Message content or attachment is required.' });
}
try {
const channel = await this.client.channels.fetch(ticketId).catch(() => null);
if (!channel || !channel.isTextBased()) {
return res.status(404).json({ success: false, error: 'Ticket channel not found or inactive.' });
}
const { AttachmentBuilder } = require('discord.js');
const files = (attachments || []).map(att => {
const base64Data = att.data.includes(',') ? att.data.split(',')[1] : att.data;
const buffer = Buffer.from(base64Data, 'base64');
return new AttachmentBuilder(buffer, { name: att.filename || 'attachment.png' });
});
const apiConfig = require('../Structures/ConfigStore').api;
const liveChatMode = (apiConfig?.API?.LiveChat?.Mode || 'webhook').toLowerCase();
const staffTag = staffName ? staffName.trim() : (req.dashboardUser?.username || 'Staff');
const contentText = hasText ? message.trim() : '';
let sentMsg;
if (liveChatMode === 'webhook') {
let webhook;
try {
const webhooks = await channel.fetchWebhooks();
webhook = webhooks.find(wh => wh.name === 'SupportBot WebChat' || wh.owner?.id === this.client.user.id);
if (!webhook) {
webhook = await channel.createWebhook({
name: 'SupportBot WebChat',
avatar: this.client.user.displayAvatarURL()
});
}
} catch (whErr) {
console.warn('[API] Could not fetch/create webhook for channel, falling back to bot send:', whErr.message);
}
if (webhook) {
let avatarURL = this.client.user.displayAvatarURL({ extension: 'png' });
if (req.dashboardUser?.id && req.dashboardUser?.avatar) {
avatarURL = `https://cdn.discordapp.com/avatars/${req.dashboardUser.id}/${req.dashboardUser.avatar}.png`;
} else {
try {
const guild = channel.guild;
if (guild) {
const members = await guild.members.fetch().catch(() => null);
const member = members?.find(m =>
m.user.username.toLowerCase() === staffTag.toLowerCase() ||
m.displayName.toLowerCase() === staffTag.toLowerCase() ||
m.user.tag.toLowerCase() === staffTag.toLowerCase()
);
if (member) {
avatarURL = member.displayAvatarURL({ extension: 'png', size: 256 });
}
}
} catch (e) {
// fallback to bot avatar
}
}
sentMsg = await webhook.send({
content: contentText || undefined,
username: staffTag,
avatarURL,
files
});
} else {
const formattedContent = contentText ? `**[${staffTag}]** ${contentText}` : `**[${staffTag}]**`;
sentMsg = await channel.send({ content: formattedContent, files });
}
} else if (liveChatMode === 'bot_noprefix' || liveChatMode === 'bot_no_prefix' || liveChatMode === 'noprefix') {
// Bot mode without [Username] prefix
sentMsg = await channel.send({ content: contentText || undefined, files });
} else {
// Bot mode with [Username] prefix
const formattedContent = contentText ? `**[${staffTag}]** ${contentText}` : `**[${staffTag}]**`;
sentMsg = await channel.send({ content: formattedContent, files });
}
const sentAttachments = Array.from(sentMsg.attachments.values()).map(a => ({
id: a.id,
name: a.name,
url: a.url,
contentType: a.contentType
}));
const messageData = {
id: sentMsg.id,
author: {
id: sentMsg.author.id,
username: staffTag,
globalName: `${staffTag} (via Dashboard)`,
avatar: sentMsg.author.displayAvatarURL({ extension: 'png', size: 64 }),
bot: false,
isDashboard: true
},
content: contentText,
embeds: [],
attachments: sentAttachments,
createdAt: sentMsg.createdTimestamp
};
this.broadcast('ticket_message', {
ticketId,
message: messageData
});
res.json({ success: true, data: messageData });
} catch (err) {
console.error('[API] Error sending ticket reply:', err);
res.status(500).json({ success: false, error: 'Failed to send message to Discord.' });
}
});
app.delete('/system/tickets/:ticketId/messages/:messageId', p('tickets'), async (req, res) => {
const { ticketId, messageId } = req.params;
try {
const channel = await this.client.channels.fetch(ticketId).catch(() => null);
if (!channel || !channel.isTextBased()) {
return res.status(404).json({ success: false, error: 'Ticket channel not found.' });
}
const targetMsg = await channel.messages.fetch(messageId).catch(() => null);
if (!targetMsg) {
return res.status(404).json({ success: false, error: 'Message not found in Discord.' });
}
await targetMsg.delete();
this.broadcast('ticket_message_deleted', {
ticketId,
messageId
});
res.json({ success: true, message: 'Message deleted successfully.' });
} catch (err) {
console.error('[API] Error deleting message:', err);
res.status(500).json({ success: false, error: 'Failed to delete message in Discord.' });
}
});
app.patch('/system/tickets/:ticketId/messages/:messageId', p('tickets'), async (req, res) => {
const { ticketId, messageId } = req.params;
const { content } = req.body;
if (!content || !content.trim()) {
return res.status(400).json({ success: false, error: 'Content cannot be empty.' });
}
try {
const channel = await this.client.channels.fetch(ticketId).catch(() => null);
if (!channel || !channel.isTextBased()) {
return res.status(404).json({ success: false, error: 'Ticket channel not found.' });
}
const targetMsg = await channel.messages.fetch(messageId).catch(() => null);
if (!targetMsg) {
return res.status(404).json({ success: false, error: 'Message not found in Discord.' });
}
const updatedMsg = await targetMsg.edit({ content: content.trim() });
this.broadcast('ticket_message_updated', {
ticketId,
messageId,
content: content.trim()
});
res.json({ success: true, data: { id: updatedMsg.id, content: content.trim() } });
} catch (err) {
console.error('[API] Error editing message:', err);
res.status(500).json({ success: false, error: 'Failed to edit message in Discord.' });
}
});
app.post('/system/tickets/:ticketId/close', p('tickets'), async (req, res) => {
const { ticketId } = req.params;
const { reason } = req.body || {};
const staffTag = req.dashboardUser?.username || 'Staff';
try {
const channel = await this.client.channels.fetch(ticketId).catch(() => null);
if (!channel || !channel.isTextBased()) {
db.updateTicketStatus(ticketId, 'closed');
this.broadcast('ticket_closed', { ticket_id: ticketId });
return res.json({ success: true, message: 'Ticket marked as closed.' });
}
try {
const ticketManager = require('../Structures/TicketManager');
if (typeof ticketManager.createTranscript === 'function') {
const fakeInteraction = {
channel,
guild: channel.guild,
user: {
id: req.dashboardUser?.id || this.client.user.id,
tag: staffTag,
displayAvatarURL: () => this.client.user.displayAvatarURL()
},
client: this.client
};
await ticketManager.createTranscript(fakeInteraction, reason || 'Closed via Web Dashboard').catch(() => null);
}
} catch (trErr) {
console.warn('[API] Transcript generation on close skipped:', trErr.message);
}
db.updateTicketStatus(ticketId, 'closed');
this.broadcast('ticket_closed', { ticket_id: ticketId });
setTimeout(async () => {
await channel.delete(`Ticket closed by ${staffTag} via Web Dashboard`).catch(() => null);
}, 1500);
res.json({ success: true, message: 'Ticket closed successfully.' });
} catch (err) {
console.error('[API] Error closing ticket:', err);
res.status(500).json({ success: false, error: 'Failed to close ticket.' });
}
});
app.put('/branding', p('settings.update'), (req, res) => {
try {
const branding = dashboardBranding.updateBranding({
@@ -631,7 +1125,7 @@ h1{font-size:1.25rem}a{color:#a78bfa}</style></head><body>
res.json({
success: true,
data: {
users: listUsers(oauth),
users: listUsers(oauth, this.client),
roles: ROLES,
configFiles: CONFIG_FILES,
},
@@ -670,6 +1164,49 @@ h1{font-size:1.25rem}a{color:#a78bfa}</style></head><body>
}
});
// --- Custom Dashboard Groups API ---
const groupStore = require('../Structures/DashboardGroupStore.js');
app.get('/dashboard-groups', p('users.view'), (req, res) => {
try {
res.json({
success: true,
data: {
groups: groupStore.listGroups(),
},
});
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
app.post('/dashboard-groups', p('users.manage'), (req, res) => {
try {
const group = groupStore.createGroup(req.body);
res.json({ success: true, data: group });
} catch (err) {
res.status(400).json({ success: false, error: err.message });
}
});
app.put('/dashboard-groups/:id', p('users.manage'), (req, res) => {
try {
const group = groupStore.updateGroup(req.params.id, req.body);
res.json({ success: true, data: group });
} catch (err) {
res.status(400).json({ success: false, error: err.message });
}
});
app.delete('/dashboard-groups/:id', p('users.manage'), (req, res) => {
try {
groupStore.deleteGroup(req.params.id);
res.json({ success: true });
} catch (err) {
res.status(400).json({ success: false, error: err.message });
}
});
app.get('/guild/status', p('overview'), (req, res) => {
try {
if (!this.client?.user) {
@@ -857,6 +1394,9 @@ h1{font-size:1.25rem}a{color:#a78bfa}</style></head><body>
});
app.put('/configs/raw', cv('edit'), async (req, res) => {
if (!hasPermission(req.dashboardUser?.permissions, 'configs.raw_yaml')) {
return res.status(403).json({ success: false, error: 'Forbidden: Raw YAML editing requires the Raw YAML Editor permission.' });
}
const validFiles = ['supportbot', 'ticket-panel', 'commands', 'messages', 'supportbot-ai', 'api'];
const file = req.body.filename;
let content = req.body.content;
-111
View File
@@ -1,111 +0,0 @@
Command:
Name: "applicationsetup"
Description: "Posts the application panel"
Permission:
- "ManageGuild"
Application:
ReviewChannelId: "1481380207305691287"
CooldownHours: 24
OneOpenApplicationPerUserPerType: true
Panel:
Title: "Applications"
Description: "Choose an application type from the dropdown below."
Placeholder: "Select an application type"
Review:
Title: "New Application"
AcceptLabel: "Accept"
RejectLabel: "Reject"
Applications:
staff:
Name: "Staff Team"
Description: "Apply for the staff team"
AcceptedRoleId: "" # Leave "" blank to disable
Questions:
Username:
Label: "What is your Discord username?"
Placeholder: "ExampleUser"
Required: true
Style: "Short"
MinLength: 2
MaxLength: 50
Age:
Label: "How old are you?"
Placeholder: "18"
Required: true
Style: "Short"
MinLength: 1
MaxLength: 3
Timezone:
Label: "What is your timezone?"
Placeholder: "GMT / BST / EST"
Required: true
Style: "Short"
MinLength: 2
MaxLength: 30
Experience:
Label: "What experience do you have?"
Placeholder: "Tell us about your experience"
Required: true
Style: "Paragraph"
MinLength: 10
MaxLength: 1000
Reason:
Label: "Why should we accept you?"
Placeholder: "Tell us why"
Required: true
Style: "Paragraph"
MinLength: 10
MaxLength: 1000
developer:
Name: "Developer"
Description: "Apply for the development team"
AcceptedRoleId: ""
Questions:
Username:
Label: "What is your Discord username?"
Placeholder: "ExampleUser"
Required: true
Style: "Short"
MinLength: 2
MaxLength: 50
Languages:
Label: "What languages do you know?"
Placeholder: "JavaScript, Python, Lua"
Required: true
Style: "Paragraph"
MinLength: 3
MaxLength: 500
Projects:
Label: "What projects have you worked on?"
Placeholder: "Describe your work"
Required: true
Style: "Paragraph"
MinLength: 10
MaxLength: 1000
Availability:
Label: "How active can you be?"
Placeholder: "How much time can you commit?"
Required: true
Style: "Paragraph"
MinLength: 5
MaxLength: 500
Reason:
Label: "Why do you want this role?"
Placeholder: "Tell us why"
Required: true
Style: "Paragraph"
MinLength: 10
MaxLength: 1000
-11
View File
@@ -1,11 +0,0 @@
# SupportBot | Emerald Services
# Discord Stats addon | Created by Xiled Emerald
Guild_ID: "GUILD_ID_HERE"
StatsCategory: "Server Statistics"
UserCount_Name: "Total Members:"
ChannelCount_Name: "Total Channels:"
RoleCount_Name: "Total Roles:"
-16
View File
@@ -1,16 +0,0 @@
# Minecraft Server Configuration
Java:
IP: "play.sapling.gg"
Port: 25565
DisplayName: "Java Edition"
Bedrock:
IP: "play.sapling.gg"
Port: 19132
DisplayName: "Bedrock Edition"
Embed:
Color: "#57F287"
OfflineColor: "#ED4245"
-38
View File
@@ -1,38 +0,0 @@
# SupportBot Temporary Voice Channels Configuration
# Addon Version 1.0
Enabled: true
# The ID of the voice channel that users join to create a new one
JoinToCreateChannelID: "CHANNEL_ID"
# The category ID where new channels should be created (Optional)
# If left blank, it will create it in the same category as the JoinToCreate channel
CategoryID: "CATEGORY_ID"
# The name pattern for new channels
# Placeholders:
# {user}: Username
ChannelNamePattern: "🔊 {user}'s Channel"
# Should the channel be deleted when the last person leaves?
AutoDelete: true
# Voice Channel Hub (Control Panel)
Hub:
Enabled: true
SendOnCreate: true
LayoutStyle: "classic" # classic | modern
# Classic Layout Settings (Standard Embed + Buttons)
Classic:
Title: "Voice Channel Hub"
Description: "Manage your voice channel using the buttons below."
Color: "#57F287"
# Modern Layout Settings (V2 Containers)
Modern:
Title: "Voice Channel Controller"
Body: "Control temporary voice channel using this control panel."
Color: "#57F287"
-28
View File
@@ -1,28 +0,0 @@
# +==================================================================================+
# | |
# | __ __ _ _ _ _ _ |
# | \ \ / /__ _ _ ___| |__ | | ___ _ _ / \ __| | __| | ___ _ __ |
# | \ \ / / _ \| | | |/ __| '_ \| |/ _ \ | | | / _ \ / _` |/ _` |/ _ \| '_ \ |
# | \ V / (_) | |_| | (__| | | | | __/ |_| | / ___ \ (_| | (_| | (_) | | | | |
# | \_/ \___/ \__,_|\___|_| |_|_|\___|\__, | /_/ \_\__,_|\__,_|\___/|_| |_| |
# | |___/ |
# | |
# | Vouchley Addon for SupportBot |
# | Created by Emerald Services |
# | |
# +==================================================================================+
Vouchley:
API_Key: "REQUEST_API_KEY_BELOW"
# Vouchley API Documentation: https://www.vouchley.com/docs/api/getting-started
# To use the API you will need an API key. To get this create a ticket in https://discord.gg/buzz
Embed:
Colour: 0x6063fc # 0x<hexcode> without the #
Ephermal: true # Make the profile searches hidden so only the interacting user can see them.
Command:
Name: "vouchley" # The name of the command (/vouchley)
Description: "Search a Vouchley Profile." # The description of the command (/vouchley)
Permissions: ["SendMessages"]
-3
View File
@@ -1,3 +0,0 @@
{
"applications": []
}
-78
View File
@@ -1,78 +0,0 @@
const Discord = require("discord.js");
const { Command } = require("../Structures/Addon.js");
const fs = require("fs");
const yaml = require("js-yaml");
const axios = require("axios");
// Load configs
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
const minecraftConfig = yaml.load(fs.readFileSync("./Addons/Configs/minecraft.yml", "utf8"));
module.exports = new Command({
name: "serverip",
description: "Display the Minecraft server IP and status",
options: [
{
name: "type",
description: "The edition of Minecraft (Java or Bedrock)",
type: Discord.ApplicationCommandOptionType.String,
required: true,
choices: [
{ name: "Java", value: "java" },
{ name: "Bedrock", value: "bedrock" },
],
},
],
permissions: ["SendMessages"],
async run(interaction) {
const type = interaction.options.getString("type");
const config = type === "java" ? minecraftConfig.Java : minecraftConfig.Bedrock;
await interaction.deferReply();
try {
const response = await axios.get(`https://api.mcstatus.io/v2/status/${type}/${config.IP}:${config.Port}`);
const data = response.data;
if (!data.online) {
throw new Error("Server is offline");
}
const embed = new Discord.EmbedBuilder()
.setTitle(`${config.DisplayName} Status`)
.setTimestamp();
embed.setColor(minecraftConfig.Embed.Color || supportbot.Embed.Colours.General)
.setDescription(`The server is currently **Online**!`)
.addFields(
{ name: "IP Address", value: `\`${config.IP}\``, inline: true },
{ name: "Port", value: `\`${config.Port}\``, inline: true },
{ name: "Players", value: `\`${data.players.online}/${data.players.max}\``, inline: true },
{ name: "Version", value: `\`${type === "java" ? data.version.name_clean : data.version.name || "Unknown"}\``, inline: true }
);
if (data.motd && data.motd.clean) {
embed.addFields({ name: "MOTD", value: `\`\`\`${data.motd.clean}\`\`\`` });
}
await interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error("Error fetching Minecraft status:", error);
const config = interaction.options.getString("type") === "java" ? minecraftConfig.Java : minecraftConfig.Bedrock;
const embed = new Discord.EmbedBuilder()
.setTitle(`${config.DisplayName} Status`)
.setTimestamp()
.setColor(minecraftConfig.Embed.OfflineColor || "#FF0000")
.setDescription(`The server is currently **Offline**.`)
.addFields(
{ name: "IP Address", value: `\`${config.IP}\``, inline: true },
{ name: "Port", value: `\`${config.Port}\``, inline: true }
);
await interaction.editReply({ embeds: [embed] });
}
},
});
@@ -1,5 +0,0 @@
# SupportBot Sanction Addon
# Created by ItsNyoty
LogChannel: "1275426007980965908"
# The ID of the channel where the logs will be sent.
-157
View File
@@ -1,157 +0,0 @@
const Discord = require('discord.js');
const fs = require('fs');
const yaml = require('js-yaml');
const { Command } = require('../Structures/Addon.js');
const supportbot = yaml.load(fs.readFileSync('./Configs/supportbot.yml', 'utf8'));
const sactionaddon = yaml.load(fs.readFileSync('./Addons/Configs/sactionaddon.yml', 'utf8'));
module.exports = new Command({
name: 'sanction',
description: 'Sanction a user (kick, ban, or timeout).',
options: [
{
name: 'action',
type: 3,
description: 'The action to perform (kick, ban, timeout)',
required: true,
choices: [
{ name: 'Kick', value: 'kick' },
{ name: 'Ban', value: 'ban' },
{ name: 'Timeout', value: 'timeout' }
]
},
{
name: 'user',
type: 6,
description: 'The user to sanction',
required: true
},
{
name: 'reason',
type: 3,
description: 'Reason for the sanction',
required: false
},
{
name: 'duration',
type: 3,
description: 'Duration of the timeout (e.g., "10m", "2h", "1d")',
required: false
}
],
permissions: [],
async run(interaction) {
const action = interaction.options.getString('action');
const user = interaction.options.getUser('user');
const reason = interaction.options.getString('reason') || 'No reason provided';
const duration = interaction.options.getString('duration');
const staffRoleId = supportbot.Roles.StaffMember.Staff;
const member = interaction.guild.members.cache.get(interaction.user.id);
if (!member || !member.roles.cache.has(staffRoleId)) {
return interaction.reply({ content: 'You do not have permission to use this command.', ephemeral: true });
}
const targetMember = interaction.guild.members.cache.get(user.id);
if (!targetMember) {
return interaction.reply({ content: 'The user is not a member of this guild.', ephemeral: true });
}
try {
let actionMessage = '';
let logEmbed = new Discord.EmbedBuilder().setColor(supportbot.Embed.Colours.General);
switch (action) {
case 'kick':
if (!targetMember.kickable) return interaction.reply({ content: 'I cannot kick this user.', ephemeral: true });
await targetMember.kick(reason);
actionMessage = `Successfully kicked ${user.tag} for: ${reason}`;
logEmbed
.setTitle('User Kicked')
.setDescription(`**User:** ${user.tag}\n**Reason:** ${reason}`)
.addFields(
{ name: 'Action By', value: interaction.user.tag, inline: true },
{ name: 'Action', value: 'Kick', inline: true },
{ name: 'Timestamp', value: new Date().toISOString(), inline: true }
);
break;
case 'ban':
if (!targetMember.bannable) return interaction.reply({ content: 'I cannot ban this user.', ephemeral: true });
await targetMember.ban({ reason });
actionMessage = `Successfully banned ${user.tag} for: ${reason}`;
logEmbed
.setTitle('User Banned')
.setDescription(`**User:** ${user.tag}\n**Reason:** ${reason}`)
.addFields(
{ name: 'Action By', value: interaction.user.tag, inline: true },
{ name: 'Action', value: 'Ban', inline: true },
{ name: 'Timestamp', value: new Date().toISOString(), inline: true }
);
break;
case 'timeout':
// Ensure a valid duration is provided
if (!duration) return interaction.reply({ content: 'You must specify a duration for the timeout.', ephemeral: true });
// Convert duration to milliseconds
const parsedDuration = ms(duration);
if (!parsedDuration) return interaction.reply({ content: 'Invalid duration format. Use "1s", "5m", "2h", or "1d".', ephemeral: true });
// Apply the timeout
await targetMember.timeout(parsedDuration, reason);
actionMessage = `Successfully timed out ${user.tag} for ${duration} with reason: ${reason}`;
logEmbed
.setTitle('User Timed Out')
.setDescription(`**User:** ${user.tag}\n**Duration:** ${duration}\n**Reason:** ${reason}`)
.addFields(
{ name: 'Action By', value: interaction.user.tag, inline: true },
{ name: 'Action', value: 'Timeout', inline: true },
{ name: 'Timestamp', value: new Date().toISOString(), inline: true }
);
break;
default:
return interaction.reply({ content: 'Invalid action specified.', ephemeral: true });
}
// Send the action message
interaction.reply({ content: actionMessage, ephemeral: true });
// Log the action to the logging channel
const logChannel = interaction.guild.channels.cache.get(sactionaddon.LogChannel);
if (logChannel) {
logChannel.send({ embeds: [logEmbed] });
} else {
console.error('Logging channel not found.');
}
} catch (error) {
console.error('Error executing sanction command:', error);
interaction.reply({ content: 'An error occurred while executing the command.', ephemeral: true });
}
},
});
/**
* Converts a time duration string to milliseconds.
* @param {string} duration - The duration string (e.g., "10m", "2h", "1d").
* @returns {number} - The duration in milliseconds.
*/
function ms(duration) {
const regex = /^(\d+)([smhd])$/;
const match = regex.exec(duration);
if (!match) return null;
const value = parseInt(match[1], 10);
const unit = match[2];
switch (unit) {
case 's': return value * 1000; // seconds
case 'm': return value * 60 * 1000; // minutes
case 'h': return value * 60 * 60 * 1000; // hours
case 'd': return value * 24 * 60 * 60 * 1000; // days
default: return null;
}
}
@@ -1,2 +0,0 @@
{
}
-85
View File
@@ -1,85 +0,0 @@
const Discord = require("discord.js");
const fs = require("fs");
const yaml = require("js-yaml");
const { Command } = require('../Structures/Addon.js'); // Adjust the path as needed
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
module.exports = new Command({
name: "tags",
description: "Retrieve a saved tag.",
options: [
{
name: 'name',
type: Discord.ApplicationCommandOptionType.String,
description: 'The name of the tag',
required: true,
autocomplete: true
},
],
permissions: ["SendMessages"],
async autocomplete(interaction) {
const tagsPath = './Addons/Data/tags.json';
const focusedValue = interaction.options.getFocused().toLowerCase();
if (!fs.existsSync(tagsPath)) {
return interaction.respond([]);
}
const tags = JSON.parse(fs.readFileSync(tagsPath, 'utf8'));
const choices = Object.keys(tags)
.filter(tag => tag.toLowerCase().includes(focusedValue))
.slice(0, 25) // Discord has a limit of 25 choices
.map(tag => ({ name: tag, value: tag }));
return interaction.respond(choices);
},
async run(interaction) {
const tagsPath = './Addons/Data/tags.json';
const tagName = interaction.options.getString('name').toLowerCase();
if (!fs.existsSync(tagsPath)) {
const embed = new Discord.EmbedBuilder()
.setDescription('No tags have been created yet.')
.setColor(supportbot.Embed.Colours.General);
return interaction.reply({ embeds: [embed], ephemeral: true });
}
const tags = JSON.parse(fs.readFileSync(tagsPath, 'utf8'));
if (tags[tagName]) {
const tag = tags[tagName];
if (tag.embed) {
// For embeds, Discord automatically handles line breaks correctly
const embed = new Discord.EmbedBuilder()
.setDescription(tag.content)
.setColor(supportbot.Embed.Colours.General);
if (tag.image) {
embed.setImage(tag.image);
}
return interaction.reply({ embeds: [embed], ephemeral: tag.ephemeral || false });
} else {
// For plain text, we need to keep the line breaks
const response = {
content: tag.content,
ephemeral: tag.ephemeral || false
};
if (tag.image) {
response.files = [tag.image];
}
return interaction.reply(response);
}
} else {
const embed = new Discord.EmbedBuilder()
.setDescription(`Tag "${tagName}" not found.`)
.setColor(supportbot.Embed.Colours.General);
return interaction.reply({ embeds: [embed], ephemeral: true });
}
}
});
-76
View File
@@ -1,76 +0,0 @@
const Discord = require("discord.js");
const fs = require("fs");
const yaml = require("js-yaml");
const { Command } = require('../Structures/Addon.js'); // Adjust the path as needed
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
module.exports = new Command({
name: "tagscreate",
description: "Create a new tag.",
options: [
{
name: 'name',
type: Discord.ApplicationCommandOptionType.String,
description: 'The name of the tag',
required: true,
},
{
name: 'content',
type: Discord.ApplicationCommandOptionType.String,
description: 'The content of the tag (use ; or /n for new lines)',
required: true,
},
{
name: 'image',
type: Discord.ApplicationCommandOptionType.Attachment,
description: 'The image URL of the tag',
required: false,
},
{
name: 'embed',
type: Discord.ApplicationCommandOptionType.Boolean,
description: 'Do you want this tag to send as an embed',
required: false,
},
{
name: 'ephemeral',
type: Discord.ApplicationCommandOptionType.Boolean,
description: 'Do you want this tag to send as ephemeral',
required: false,
},
],
permissions: ["SendMessages"],
async run(interaction) {
const tagName = interaction.options.getString('name').toLowerCase();
let tagContent = interaction.options.getString('content');
const tagImage = interaction.options.getAttachment('image');
const isEmbed = interaction.options.getBoolean('embed');
const isEphemeral = interaction.options.getBoolean('ephemeral');
const tagsPath = './Addons/Data/tags.json';
// Process line breaks in content - support both ; and /n notations
tagContent = tagContent.replace(/;/g, '\n').replace(/\/n/g, '\n');
let tags = {};
if (fs.existsSync(tagsPath)) {
tags = JSON.parse(fs.readFileSync(tagsPath, 'utf8'));
}
tags[tagName] = {
content: tagContent,
image: tagImage ? tagImage.url : null,
embed: isEmbed || false,
ephemeral: isEphemeral || false,
};
fs.writeFileSync(tagsPath, JSON.stringify(tags, null, 4));
const embed = new Discord.EmbedBuilder()
.setDescription(`Tag "${tagName}" created successfully.`)
.setColor(supportbot.Embed.Colours.General);
return interaction.reply({ embeds: [embed], ephemeral: true });
},
});
-68
View File
@@ -1,68 +0,0 @@
const Discord = require("discord.js");
const fs = require("fs");
const yaml = require("js-yaml");
const { Command } = require('../Structures/Addon.js'); // Adjust the path as needed
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
module.exports = new Command({
name: "tagsdelete",
description: "Delete an existing tag.",
options: [
{
name: 'name',
type: Discord.ApplicationCommandOptionType.String,
description: 'The name of the tag to delete',
required: true,
autocomplete: true
},
],
permissions: ["SendMessages"],
async autocomplete(interaction) {
const tagsPath = './Addons/Data/tags.json';
const focusedValue = interaction.options.getFocused().toLowerCase();
if (!fs.existsSync(tagsPath)) {
return interaction.respond([]);
}
const tags = JSON.parse(fs.readFileSync(tagsPath, 'utf8'));
const choices = Object.keys(tags)
.filter(tag => tag.toLowerCase().includes(focusedValue))
.slice(0, 25) // Discord has a limit of 25 choices
.map(tag => ({ name: tag, value: tag }));
return interaction.respond(choices);
},
async run(interaction) {
const tagsPath = './Addons/Data/tags.json';
const tagName = interaction.options.getString('name').toLowerCase();
if (!fs.existsSync(tagsPath)) {
const embed = new Discord.EmbedBuilder()
.setDescription('No tags have been created yet.')
.setColor(supportbot.Embed.Colours.General);
return interaction.reply({ embeds: [embed], ephemeral: true });
}
let tags = JSON.parse(fs.readFileSync(tagsPath, 'utf8'));
if (!tags[tagName]) {
const embed = new Discord.EmbedBuilder()
.setDescription(`Tag "${tagName}" not found.`)
.setColor(supportbot.Embed.Colours.General);
return interaction.reply({ embeds: [embed], ephemeral: true });
}
delete tags[tagName];
fs.writeFileSync(tagsPath, JSON.stringify(tags, null, 4));
const embed = new Discord.EmbedBuilder()
.setDescription(`Tag "${tagName}" deleted successfully.`)
.setColor(supportbot.Embed.Colours.General);
return interaction.reply({ embeds: [embed], ephemeral: true });
}
});
@@ -1,14 +0,0 @@
PayPal:
ClientID: "clientID_Here"
ClientSecret: "ClientSecret_Here"
Mode: "live" # or "live"
Email: "Email_Here" # Add your PayPal email here
Embed:
Colours:
General: "#0099ff"
Success: "#00ff00" # Add more colors if needed
Error: "#ff0000" # Add more colors if needed
Footer: "PayPal Invoice" # Add footer text here
Logo: "https://your-logo-url.com/logo.png" # Add logo URL if used in invoice
Note: "Thank you for your business!" # Add a note if used in invoice
TOS: "Please review our terms and conditions. https://domain.com/tos" # Add terms of service if used in invoice
-146
View File
@@ -1,146 +0,0 @@
const { EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, ApplicationCommandOptionType } = require('discord.js');
const fs = require('fs');
const yaml = require('js-yaml');
const paypal = require('paypal-rest-sdk');
const { Command } = require('../Structures/Addon.js'); // Adjust the path as needed
// Load the PayPal configuration
const config = yaml.load(fs.readFileSync("./Addons/Configs/paypal.yml", "utf8"));
const supportbot = config;
// Configure PayPal SDK
paypal.configure({
mode: supportbot.PayPal.Mode, // sandbox or live
client_id: supportbot.PayPal.ClientID,
client_secret: supportbot.PayPal.ClientSecret
});
module.exports = new Command({
name: "invoice",
description: "Generate a PayPal invoice for a user.",
options: [
{
name: "user",
description: "The user to notify.",
type: ApplicationCommandOptionType.User,
required: true,
},
{
name: "price",
description: "The amount to invoice.",
type: ApplicationCommandOptionType.String,
required: true,
},
{
name: "service",
description: "The service provided.",
type: ApplicationCommandOptionType.String,
required: true,
},
{
name: "email",
description: "The email to invoice.",
type: ApplicationCommandOptionType.String,
required: true,
}
],
permissions: ["Administrator"],
async run(interaction) {
const user = interaction.options.getUser("user");
const price = interaction.options.getString("price");
const service = interaction.options.getString("service");
const email = interaction.options.getString("email");
// Validate the price format
if (isNaN(price) || parseFloat(price) <= 0) {
const errorEmbed = new EmbedBuilder()
.setDescription(`The price provided is invalid.`)
.setColor(supportbot.Embed.Colours.Error)
.setFooter({ text: supportbot.Embed.Footer });
return interaction.reply({ embeds: [errorEmbed], ephemeral: true });
}
const invoiceData = {
"merchant_info": {
"email": supportbot.PayPal.Email,
"business_name": interaction.guild.name
},
"billing_info": [{
"email": email
}],
"items": [{
"name": service,
"quantity": 1,
"unit_price": {
"currency": "USD",
"value": price
}
}],
"logo_url": supportbot.PayPal.Logo,
"note": supportbot.PayPal.Note,
"terms": supportbot.PayPal.TOS,
"payment_term": {
"term_type": "NET_45"
},
"tax_inclusive": false,
"total_amount": {
"currency": "USD",
"value": price
}
};
paypal.invoice.create(invoiceData, function (error, invoice) {
if (error) {
console.error(error);
const errorEmbed = new EmbedBuilder()
.setTitle(`PayPal Error`)
.setDescription(`There was an error creating the invoice. Please check your configuration and try again.`)
.setColor(supportbot.Embed.Colours.Error)
.setFooter({ text: supportbot.Embed.Footer });
return interaction.reply({ embeds: [errorEmbed], ephemeral: true });
}
const invoiceId = invoice.id;
paypal.invoice.send(invoiceId, function (error) {
if (error) {
console.error(error);
const errorEmbed = new EmbedBuilder()
.setTitle(`PayPal Error`)
.setDescription(`There was an error sending the invoice. Please check your configuration and try again.`)
.setColor(supportbot.Embed.Colours.Error)
.setFooter({ text: supportbot.Embed.Footer });
return interaction.reply({ embeds: [errorEmbed], ephemeral: true });
}
const invoiceEmbed = new EmbedBuilder()
.setTitle(`Payment System | ${interaction.guild.name}`)
.addFields(
{ name: 'Service', value: service, inline: true },
{ name: 'Amount Due', value: `$${price}`, inline: true },
{ name: 'Currency', value: 'USD', inline: true },
{ name: 'Invoice ID', value: `\`${invoiceId}\``, inline: false }
)
.setColor(supportbot.Embed.Colours.General)
.setFooter({ text: supportbot.Embed.Footer })
.setTimestamp();
// Create a button with a link to the invoice
const invoiceButton = new ButtonBuilder()
.setLabel('View Invoice')
.setStyle(ButtonStyle.Link)
.setURL(`https://www.paypal.com/invoice/payerView/details/${invoiceId}`);
// Create the action row
const actionRow = new ActionRowBuilder()
.addComponents(invoiceButton);
// Send the embed with the button
interaction.reply({
embeds: [invoiceEmbed],
components: [actionRow]
});
});
});
},
});
-227
View File
@@ -1,227 +0,0 @@
const Discord = require("discord.js");
const { Event } = require("../Structures/Addon.js");
const fs = require("fs");
const yaml = require("js-yaml");
const tempVCConfig = yaml.load(fs.readFileSync("./Addons/Configs/tempvc.yml", "utf8"));
const tempChannels = new Map();
const voiceStateUpdate = new Event("voiceStateUpdate", async (client, oldState, newState) => {
if (!tempVCConfig.Enabled) return;
const member = newState.member;
const guild = newState.guild;
if (newState.channelId === tempVCConfig.JoinToCreateChannelID) {
console.log(`[TempVC] ${member.user.tag} joined the Join-to-Create channel.`);
}
if (newState.channelId === tempVCConfig.JoinToCreateChannelID) {
try {
const parentCategory = tempVCConfig.CategoryID || newState.channel.parentId;
const channelName = tempVCConfig.ChannelNamePattern.replace("{user}", member.user.username);
const newChannel = await guild.channels.create({
name: channelName,
type: Discord.ChannelType.GuildVoice,
parent: parentCategory,
permissionOverwrites: [
{
id: member.id,
allow: [Discord.PermissionFlagsBits.ManageChannels, Discord.PermissionFlagsBits.MoveMembers],
},
],
});
tempChannels.set(newChannel.id, member.id);
await member.voice.setChannel(newChannel);
console.log(`[TempVC] Created channel "${channelName}" for ${member.user.tag}`);
if (tempVCConfig.Hub.Enabled && tempVCConfig.Hub.SendOnCreate) {
try {
const { ActionRowBuilder, ButtonBuilder, EmbedBuilder, MessageFlags, ButtonStyle } = Discord;
const layoutStyle = tempVCConfig.Hub.LayoutStyle || "classic";
if (layoutStyle === "classic") {
const config = tempVCConfig.Hub.Classic;
const embed = new EmbedBuilder()
.setTitle(config.Title)
.setDescription(config.Description)
.setColor(config.Color);
const buttons = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("tempvc_lock").setLabel("Lock").setEmoji("🔒").setStyle(ButtonStyle.Secondary),
new ButtonBuilder().setCustomId("tempvc_unlock").setLabel("Unlock").setEmoji("🔓").setStyle(ButtonStyle.Secondary),
new ButtonBuilder().setCustomId("tempvc_rename").setLabel("Rename").setEmoji("✏️").setStyle(ButtonStyle.Secondary),
new ButtonBuilder().setCustomId("tempvc_limit").setLabel("Limit").setEmoji("👥").setStyle(ButtonStyle.Secondary),
new ButtonBuilder().setCustomId("tempvc_claim").setLabel("Claim Ownership").setEmoji("👑").setStyle(ButtonStyle.Primary)
);
await newChannel.send({ embeds: [embed], components: [buttons] });
} else {
const config = tempVCConfig.Hub.Modern;
const colorInt = parseInt(config.Color.replace("#", ""), 16);
const container = {
type: 11,
accent_color: colorInt,
children: [
{
type: 12,
children: [
{ type: 13, content: `## ${config.Title}` },
{ type: 13, content: config.Body }
]
},
{
type: 15,
divider: true
},
{
type: 1,
components: [
{ type: 2, custom_id: "tempvc_lock", label: "Lock", emoji: { name: "🔒" }, style: 2 },
{ type: 2, custom_id: "tempvc_unlock", label: "Unlock", emoji: { name: "🔓" }, style: 2 },
{ type: 2, custom_id: "tempvc_rename", label: "Rename", emoji: { name: "✏️" }, style: 2 },
{ type: 2, custom_id: "tempvc_limit", label: "Limit", emoji: { name: "👥" }, style: 2 }
]
},
{
type: 1,
components: [
{ type: 2, custom_id: "tempvc_claim", label: "Claim Ownership", emoji: { name: "👑" }, style: 1 }
]
}
]
};
await newChannel.send({
flags: MessageFlags.IsComponentsV2,
components: [container]
});
}
} catch (hubError) {
console.error("[TempVC] Error sending Hub:", hubError);
}
}
} catch (error) {
console.error("[TempVC] Error creating temporary channel:", error);
}
}
if (oldState.channelId && tempChannels.has(oldState.channelId)) {
const oldChannel = oldState.channel;
if (oldChannel && oldChannel.members.size === 0) {
try {
await oldChannel.delete();
tempChannels.delete(oldState.channelId);
console.log(`[TempVC] Deleted empty temporary channel "${oldChannel.name}"`);
} catch (error) {
if (error.code !== 10003) {
console.error("[TempVC] Error deleting temporary channel:", error);
}
tempChannels.delete(oldState.channelId);
}
}
}
});
const interactionEvent = new Event("interactionCreate", async (client, interaction) => {
if (!interaction.isButton() && !interaction.isModalSubmit()) return;
if (!interaction.customId.startsWith("tempvc_")) return;
const channel = interaction.channel;
if (!tempChannels.has(channel.id)) {
return interaction.reply({ content: "This channel is no longer a temporary voice channel.", flags: Discord.MessageFlags.Ephemeral });
}
const ownerId = tempChannels.get(channel.id);
const isOwner = interaction.user.id === ownerId || interaction.member.permissions.has(Discord.PermissionFlagsBits.Administrator);
if (interaction.customId === "tempvc_claim") {
const currentOwnerInVC = channel.members.has(ownerId);
if (currentOwnerInVC && interaction.user.id !== ownerId) {
return interaction.reply({ content: "The owner is still in the voice channel!", flags: Discord.MessageFlags.Ephemeral });
}
tempChannels.set(channel.id, interaction.user.id);
await channel.permissionOverwrites.edit(interaction.user.id, {
ManageChannels: true,
MoveMembers: true,
});
return interaction.reply({ content: "You are now the owner of this voice channel!", flags: Discord.MessageFlags.Ephemeral });
}
if (!isOwner) {
return interaction.reply({ content: "Only the channel owner can use these controls.", flags: Discord.MessageFlags.Ephemeral });
}
try {
switch (interaction.customId) {
case "tempvc_lock":
await channel.permissionOverwrites.edit(interaction.guild.id, { Connect: false });
await interaction.reply({ content: "Channel locked! 🔒", flags: Discord.MessageFlags.Ephemeral });
break;
case "tempvc_unlock":
await channel.permissionOverwrites.edit(interaction.guild.id, { Connect: null });
await interaction.reply({ content: "Channel unlocked! 🔓", flags: Discord.MessageFlags.Ephemeral });
break;
case "tempvc_rename":
const modal = new Discord.ModalBuilder()
.setCustomId("tempvc_modal_rename")
.setTitle("Rename Channel")
.addComponents(
new Discord.ActionRowBuilder().addComponents(
new Discord.TextInputBuilder()
.setCustomId("name")
.setLabel("New Name")
.setStyle(Discord.TextInputStyle.Short)
.setPlaceholder(channel.name)
.setRequired(true)
)
);
await interaction.showModal(modal);
break;
case "tempvc_limit":
const limitModal = new Discord.ModalBuilder()
.setCustomId("tempvc_modal_limit")
.setTitle("Set User Limit")
.addComponents(
new Discord.ActionRowBuilder().addComponents(
new Discord.TextInputBuilder()
.setCustomId("limit")
.setLabel("Limit (0-99)")
.setStyle(Discord.TextInputStyle.Short)
.setPlaceholder("0 for no limit")
.setRequired(true)
)
);
await interaction.showModal(limitModal);
break;
}
if (interaction.isModalSubmit()) {
if (interaction.customId === "tempvc_modal_rename") {
const newName = interaction.fields.getTextInputValue("name");
await channel.setName(newName);
await interaction.reply({ content: `Channel renamed to **${newName}**!`, flags: Discord.MessageFlags.Ephemeral });
} else if (interaction.customId === "tempvc_modal_limit") {
const limit = parseInt(interaction.fields.getTextInputValue("limit"));
if (isNaN(limit) || limit < 0 || limit > 99) {
return interaction.reply({ content: "Please enter a valid number between 0 and 99.", flags: Discord.MessageFlags.Ephemeral });
}
await channel.setUserLimit(limit);
await interaction.reply({ content: `User limit set to **${limit === 0 ? "Unlimited" : limit}**!`, flags: Discord.MessageFlags.Ephemeral });
}
}
} catch (error) {
console.error("[TempVC] Error handling interaction:", error);
if (!interaction.replied) await interaction.reply({ content: "An error occurred.", flags: Discord.MessageFlags.Ephemeral });
}
});
module.exports = [voiceStateUpdate, interactionEvent];
-652
View File
@@ -1,652 +0,0 @@
const Discord = require("discord.js");
const fs = require("fs");
const path = require("path");
const yaml = require("js-yaml");
const { Command } = require("../Structures/Addon.js");
// Main bot config
const supportbot = yaml.load(
fs.readFileSync("./Configs/supportbot.yml", "utf8")
);
// Addon config
const addonConfig = yaml.load(
fs.readFileSync("./Addons/Configs/applicationsystem.yml", "utf8")
);
// Data file
const dataPath = path.join(__dirname, "Data/applicationsystem.json");
function ensureDataFile() {
const dir = path.dirname(dataPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
if (!fs.existsSync(dataPath)) {
fs.writeFileSync(
dataPath,
JSON.stringify({ applications: [] }, null, 2),
"utf8"
);
}
}
function readData() {
ensureDataFile();
try {
const raw = fs.readFileSync(dataPath, "utf8");
const parsed = JSON.parse(raw);
if (!parsed || !Array.isArray(parsed.applications)) {
return { applications: [] };
}
return parsed;
} catch (error) {
console.error("[ApplicationSystem] Failed to read data file:", error);
return { applications: [] };
}
}
function writeData(data) {
ensureDataFile();
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2), "utf8");
}
function now() {
return Date.now();
}
function createId() {
return `app_${Date.now()}_${Math.floor(Math.random() * 100000)}`;
}
function parseColor(value, fallback = 0x2b2d31) {
if (typeof value === "number") return value;
if (typeof value === "string") {
const cleaned = value.trim().replace("#", "");
if (/^[0-9A-Fa-f]{6}$/.test(cleaned)) {
return parseInt(cleaned, 16);
}
}
return fallback;
}
function getGeneralColour() {
return parseColor(supportbot?.Embed?.Colours?.General, 0x2b2d31);
}
function buildNoticeContainer(title, description, colour = 0x5865f2) {
return new Discord.ContainerBuilder()
.setAccentColor(colour)
.addTextDisplayComponents(
new Discord.TextDisplayBuilder().setContent(`## ${title}`)
)
.addSeparatorComponents(new Discord.SeparatorBuilder())
.addTextDisplayComponents(
new Discord.TextDisplayBuilder().setContent(description)
);
}
function buildPanelContainer() {
const options = Object.entries(addonConfig.Applications || {})
.slice(0, 25)
.map(([key, app]) =>
new Discord.StringSelectMenuOptionBuilder()
.setLabel(String(app.Name || key).slice(0, 100))
.setDescription(
String(app.Description || "Apply for this position").slice(0, 100)
)
.setValue(key)
);
return new Discord.ContainerBuilder()
.setAccentColor(getGeneralColour())
.addTextDisplayComponents(
new Discord.TextDisplayBuilder().setContent(
`## ${addonConfig.Panel?.Title || "Applications"}`
)
)
.addSeparatorComponents(new Discord.SeparatorBuilder())
.addTextDisplayComponents(
new Discord.TextDisplayBuilder().setContent(
addonConfig.Panel?.Description ||
"Choose an application from the dropdown below."
)
)
.addActionRowComponents(
new Discord.ActionRowBuilder().addComponents(
new Discord.StringSelectMenuBuilder()
.setCustomId("appsystem_select")
.setPlaceholder(
addonConfig.Panel?.Placeholder || "Select an application type"
)
.addOptions(options)
)
);
}
function textInputStyle(style) {
return style === "Paragraph"
? Discord.TextInputStyle.Paragraph
: Discord.TextInputStyle.Short;
}
function sanitizeQuestionKey(key) {
return String(key).toLowerCase().replace(/[^a-z0-9_]/g, "_");
}
function formatQuestionTitle(key) {
return String(key)
.replace(/_/g, " ")
.replace(/\b\w/g, (char) => char.toUpperCase());
}
function buildApplicationModal(typeKey) {
const applicationType = addonConfig.Applications?.[typeKey];
if (!applicationType) return null;
const modal = new Discord.ModalBuilder()
.setCustomId(`appsystem_modal_${typeKey}`)
.setTitle(String(applicationType.Name || typeKey).slice(0, 45));
const questionEntries = Object.entries(applicationType.Questions || {}).slice(0, 5);
for (const [key, question] of questionEntries) {
const input = new Discord.TextInputBuilder()
.setCustomId(sanitizeQuestionKey(key))
.setLabel(String(question.Label || key).slice(0, 45))
.setPlaceholder(String(question.Placeholder || "Enter your answer").slice(0, 100))
.setRequired(Boolean(question.Required))
.setStyle(textInputStyle(question.Style))
.setMinLength(Number(question.MinLength || 1))
.setMaxLength(Number(question.MaxLength || 1000));
modal.addComponents(
new Discord.ActionRowBuilder().addComponents(input)
);
}
return modal;
}
function buildReviewContainer(application, reviewerText = null, locked = false) {
const statusText =
application.status === "accepted"
? "Accepted"
: application.status === "rejected"
? "Rejected"
: "Pending";
const answerLines = Object.entries(application.answers || {})
.map(([key, value]) => `### ${formatQuestionTitle(key)}\n${value}`)
.join("\n\n");
const body = [
`**Applicant:** <@${application.userId}>`,
`**Tag:** ${application.userTag}`,
`**Application Type:** ${application.typeName}`,
`**Application ID:** \`${application.id}\``,
`**Status:** ${statusText}`,
"",
answerLines || "*No answers provided.*",
].join("\n");
const container = new Discord.ContainerBuilder()
.setAccentColor(getGeneralColour())
.addTextDisplayComponents(
new Discord.TextDisplayBuilder().setContent(
`## ${addonConfig.Review?.Title || "New Application"}`
)
)
.addSeparatorComponents(new Discord.SeparatorBuilder())
.addTextDisplayComponents(
new Discord.TextDisplayBuilder().setContent(body)
);
if (reviewerText) {
container
.addSeparatorComponents(new Discord.SeparatorBuilder())
.addTextDisplayComponents(
new Discord.TextDisplayBuilder().setContent(reviewerText)
);
}
container.addActionRowComponents(
new Discord.ActionRowBuilder().addComponents(
new Discord.ButtonBuilder()
.setCustomId(`appsystem_accept_${application.id}`)
.setLabel(addonConfig.Review?.AcceptLabel || "Accept")
.setStyle(Discord.ButtonStyle.Success)
.setDisabled(locked),
new Discord.ButtonBuilder()
.setCustomId(`appsystem_reject_${application.id}`)
.setLabel(addonConfig.Review?.RejectLabel || "Reject")
.setStyle(Discord.ButtonStyle.Danger)
.setDisabled(locked)
)
);
return container;
}
function getPendingApplication(data, guildId, userId, type) {
return data.applications.find(
(app) =>
app.guildId === guildId &&
app.userId === userId &&
app.type === type &&
app.status === "pending"
);
}
function getCooldownApplication(data, guildId, userId, type) {
const cooldownMs =
Number(addonConfig.Application?.CooldownHours || 24) * 60 * 60 * 1000;
return data.applications.find(
(app) =>
app.guildId === guildId &&
app.userId === userId &&
app.type === type &&
now() - Number(app.createdAt || 0) < cooldownMs
);
}
function memberCanReview(member) {
if (!member) return false;
if (member.permissions?.has(Discord.PermissionFlagsBits.ManageGuild)) {
return true;
}
return false;
}
function registerAddonInteractions(client) {
if (client.__applicationSystemRegistered) return;
client.__applicationSystemRegistered = true;
client.on("interactionCreate", async (interaction) => {
try {
if (!interaction.guild) return;
// Application dropdown select
if (
interaction.isStringSelectMenu() &&
interaction.customId === "appsystem_select"
) {
const typeKey = interaction.values[0];
const applicationType = addonConfig.Applications?.[typeKey];
if (!applicationType) {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Invalid Application",
"That application type does not exist.",
0xed4245
),
],
});
}
const data = readData();
if (addonConfig.Application?.OneOpenApplicationPerUserPerType) {
const existing = getPendingApplication(
data,
interaction.guild.id,
interaction.user.id,
typeKey
);
if (existing) {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Application Already Open",
`You already have a pending ${applicationType.Name} application.`,
0xed4245
),
],
});
}
}
const cooldownHit = getCooldownApplication(
data,
interaction.guild.id,
interaction.user.id,
typeKey
);
if (cooldownHit && cooldownHit.status !== "pending") {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Please Wait",
`You must wait ${addonConfig.Application?.CooldownHours || 24} hours before applying again for ${applicationType.Name}.`,
0xfee75c
),
],
});
}
const modal = buildApplicationModal(typeKey);
if (!modal) {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Modal Error",
"The application form could not be created.",
0xed4245
),
],
});
}
return interaction.showModal(modal);
}
// Application modal submit
if (
interaction.isModalSubmit() &&
interaction.customId.startsWith("appsystem_modal_")
) {
const typeKey = interaction.customId.replace("appsystem_modal_", "");
const applicationType = addonConfig.Applications?.[typeKey];
if (!applicationType) {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Invalid Application",
"That application type no longer exists.",
0xed4245
),
],
});
}
const reviewChannel = interaction.guild.channels.cache.get(
addonConfig.Application?.ReviewChannelId
);
if (!reviewChannel) {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Configuration Error",
"The review channel was not found. Please contact staff.",
0xed4245
),
],
});
}
const data = readData();
if (addonConfig.Application?.OneOpenApplicationPerUserPerType) {
const existing = getPendingApplication(
data,
interaction.guild.id,
interaction.user.id,
typeKey
);
if (existing) {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Application Already Open",
`You already have a pending ${applicationType.Name} application.`,
0xed4245
),
],
});
}
}
const answers = {};
const questionEntries = Object.entries(applicationType.Questions || {}).slice(0, 5);
for (const [key] of questionEntries) {
const inputKey = sanitizeQuestionKey(key);
answers[inputKey] = interaction.fields.getTextInputValue(inputKey);
}
const application = {
id: createId(),
type: typeKey,
typeName: applicationType.Name || typeKey,
guildId: interaction.guild.id,
userId: interaction.user.id,
userTag: interaction.user.tag || interaction.user.username,
status: "pending",
createdAt: now(),
reviewerId: null,
reviewedAt: null,
reviewMessageId: null,
answers,
};
const reviewMessage = await reviewChannel.send({
flags: Discord.MessageFlags.IsComponentsV2,
components: [buildReviewContainer(application, null, false)],
});
application.reviewMessageId = reviewMessage.id;
data.applications.push(application);
writeData(data);
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Application Sent",
`Your ${applicationType.Name} application has been submitted successfully.`,
0x57f287
),
],
});
}
// Review buttons
if (
interaction.isButton() &&
(interaction.customId.startsWith("appsystem_accept_") ||
interaction.customId.startsWith("appsystem_reject_"))
) {
if (!memberCanReview(interaction.member)) {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"No Permission",
"You do not have permission to review applications.",
0xed4245
),
],
});
}
const isAccept = interaction.customId.startsWith("appsystem_accept_");
const applicationId = interaction.customId.replace(
isAccept ? "appsystem_accept_" : "appsystem_reject_",
""
);
const data = readData();
const application = data.applications.find((app) => app.id === applicationId);
if (!application) {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Not Found",
"This application no longer exists in storage.",
0xed4245
),
],
});
}
if (application.status !== "pending") {
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Already Reviewed",
`This application has already been ${application.status}.`,
0xfee75c
),
],
});
}
application.status = isAccept ? "accepted" : "rejected";
application.reviewerId = interaction.user.id;
application.reviewedAt = now();
writeData(data);
const reviewerText = [
`### Review Result`,
`**Decision:** ${isAccept ? "Accepted" : "Rejected"}`,
`**Reviewer:** <@${interaction.user.id}>`,
`**Reviewed At:** <t:${Math.floor(application.reviewedAt / 1000)}:F>`,
].join("\n");
await interaction.update({
flags: Discord.MessageFlags.IsComponentsV2,
components: [
buildReviewContainer(application, reviewerText, true),
],
});
const applicationType = addonConfig.Applications?.[application.type];
if (isAccept && applicationType?.AcceptedRoleId) {
const member = await interaction.guild.members
.fetch(application.userId)
.catch(() => null);
if (member) {
await member.roles.add(applicationType.AcceptedRoleId).catch(() => null);
}
}
const applicantUser = await interaction.client.users
.fetch(application.userId)
.catch(() => null);
if (applicantUser) {
await applicantUser
.send({
flags: Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
isAccept ? "Application Accepted" : "Application Rejected",
isAccept
? `Congratulations! Your ${application.typeName} application in **${interaction.guild.name}** has been accepted.`
: `Your ${application.typeName} application in **${interaction.guild.name}** has been rejected.`,
isAccept ? 0x57f287 : 0xed4245
),
],
})
.catch(() => null);
}
return;
}
} catch (error) {
console.error("[ApplicationSystem] Interaction error:", error);
if (interaction.deferred || interaction.replied) {
return;
}
return interaction
.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Error",
"Something went wrong while handling that application interaction.",
0xed4245
),
],
})
.catch(() => null);
}
});
}
module.exports = new Command({
name: addonConfig.Command?.Name || "applicationsetup",
description:
addonConfig.Command?.Description || "Posts the application panel",
options: [],
permissions: addonConfig.Command?.Permission || ["ManageGuild"],
async run(interaction) {
registerAddonInteractions(interaction.client);
await interaction.channel.send({
flags: Discord.MessageFlags.IsComponentsV2,
components: [buildPanelContainer()],
});
return interaction.reply({
flags:
Discord.MessageFlags.Ephemeral |
Discord.MessageFlags.IsComponentsV2,
components: [
buildNoticeContainer(
"Application Panel Posted",
"The application panel has been posted in this channel.",
0x57f287
),
],
});
},
});
-83
View File
@@ -1,83 +0,0 @@
const Discord = require("discord.js");
const fs = require("fs");
const yaml = require("js-yaml");
const { Command } = require('../Structures/Addon.js'); // Adjust the path as needed
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
module.exports = new Command({
name: "calculator",
description: "Use a calculator to solve your math problems.",
options: [],
permissions: ["SendMessages"],
async run(interaction) {
let expression = "";
let history = "";
const createButton = (label, customId) => {
return new Discord.ButtonBuilder()
.setLabel(label)
.setCustomId(customId)
.setStyle(Discord.ButtonStyle.Secondary);
};
const createRow = (buttons) => {
return new Discord.ActionRowBuilder().addComponents(buttons);
};
const rows = [
createRow([createButton('7', '7'), createButton('8', '8'), createButton('9', '9'), createButton('/', '/')]),
createRow([createButton('4', '4'), createButton('5', '5'), createButton('6', '6'), createButton('*', '*')]),
createRow([createButton('1', '1'), createButton('2', '2'), createButton('3', '3'), createButton('-', '-')]),
createRow([createButton('0', '0'), createButton('.', '.'), createButton('=', '='), createButton('+', '+')]),
createRow([createButton('Clear', 'clear')])
];
const embed = new Discord.EmbedBuilder()
.setTitle('Calculator')
.setDescription('Calculator')
.setColor(supportbot.Embed.Colours.General);
const message = await interaction.reply({
embeds: [embed],
components: rows,
fetchReply: true
});
const filter = i => i.user.id === interaction.user.id;
const collector = message.createMessageComponentCollector({ filter, time: 60000 });
collector.on('collect', async i => {
if (i.customId === 'clear') {
expression = "";
history = "";
} else if (i.customId === '=') {
try {
const result = eval(expression).toString();
history += `${expression} = ${result}\n`;
expression = result;
} catch {
expression = "Error";
}
} else {
if (history.endsWith(`${expression} = ${expression}\n`)) {
history += `\n`;
expression = i.customId;
} else {
expression += i.customId;
}
}
await i.update({
embeds: [new Discord.EmbedBuilder().setTitle('Calculator').setDescription(`\`\`\`${history}${expression}\`\`\``).setColor(supportbot.Embed.Colours.General)],
components: rows
});
});
collector.on('end', collected => {
message.edit({
components: []
});
});
},
});
-139
View File
@@ -1,139 +0,0 @@
// SupportBot | Emerald Services
// Discord Stats addon | Created by Xiled Emerald
const fs = require("fs");
const Discord = require("discord.js");
const yaml = require("js-yaml");
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
// If you need to read something from the main config!
const cmdconfig = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
// This is for your Addon Configuration
const config = yaml.load(fs.readFileSync('./Addons/Configs/discord-stats.yml', 'utf8'));
const { Command, Event } = require("../Structures/Addon");
module.exports.commands = [
new Command({
name: "stats",
description: "Create the discord statistic channels",
options: [],
permissions: ["SEND_MESSAGES"],
async run(interaction) {
const guild = interaction.guild;
const statsCategory = guild.channels.cache.find(
(category) =>
category.name === config.StatsCategory ||
category.id === config.StatsCategory
);
if (!statsCategory) {
const errorEmbed = new Discord.MessageEmbed()
.setTitle("Invalid Category")
.setDescription(
`${supportbot.InvalidChannel}\n\n**Category Required:** \`${config.StatsCategory}\``
)
.setColor(supportbot.ErrorColour);
interaction.reply({
embeds: [errorEmbed],
ephemeral: true,
});
return;
}
const guildName = guild.name;
const userCount = guild.memberCount;
const roleCount = guild.roles.cache.size;
const channelCount = guild.channels.cache.size;
try {
const guildNameChannel = await guild.channels.create(guildName, {
type: "GUILD_VOICE",
});
const userCountChannel = await guild.channels.create(
`${config.UserCount_Name} ${userCount}`,
{
type: "GUILD_VOICE",
}
);
const channelCountChannel = await guild.channels.create(
`${config.ChannelCount_Name} ${channelCount}`,
{
type: "GUILD_VOICE",
}
);
const roleCountChannel = await guild.channels.create(
`${config.RoleCount_Name} ${roleCount}`,
{
type: "GUILD_VOICE",
}
);
guildNameChannel.permissionOverwrites.edit(guild.id, {
VIEW_CHANNEL: true,
CONNECT: false,
});
userCountChannel.permissionOverwrites.edit(guild.id, {
VIEW_CHANNEL: true,
CONNECT: false,
});
channelCountChannel.permissionOverwrites.edit(guild.id, {
VIEW_CHANNEL: true,
CONNECT: false,
});
roleCountChannel.permissionOverwrites.edit(guild.id, {
VIEW_CHANNEL: true,
CONNECT: false,
});
userCountChannel.setParent(statsCategory.id);
roleCountChannel.setParent(statsCategory.id);
guildNameChannel.setParent(statsCategory.id);
channelCountChannel.setParent(statsCategory.id);
const successEmbed = new Discord.MessageEmbed()
.setDescription(":white_check_mark: **[DISCORD STATS]** Channels created successfully!")
.setColor(supportbot.EmbedColour);
interaction.reply({
embeds: [successEmbed],
ephemeral: true,
});
setInterval(() => {
userCountChannel.setName(
`${config.UserCount_Name} ${userCount}`
);
channelCountChannel.setName(
`${config.ChannelCount_Name} ${channelCount}`
);
roleCountChannel.setName(
`${config.RoleCount_Name} ${roleCount}`
);
}, 30000);
} catch (error) {
console.error(error);
const errorEmbed = new Discord.MessageEmbed()
.setTitle("Error")
.setDescription("An error occurred while creating the stats channels.")
.setColor(supportbot.ErrorColour);
interaction.reply({
embeds: [errorEmbed],
ephemeral: true,
});
}
},
}),
];
-292
View File
@@ -1,292 +0,0 @@
const Discord = require("discord.js");
const fs = require("fs");
const yaml = require("js-yaml");
const fetch = require("node-fetch");
const { Command } = require('../Structures/Addon.js');
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
const vouchleyaddon = yaml.load(fs.readFileSync("./Addons/Configs/vouchley.yml", "utf8"));
function formatURL(url) {
if (!url) return 'https://www.vouchley.com';
if (!url.startsWith('http://') && !url.startsWith('https://')) {
return `https://${url}`;
}
return url;
}
function formatDate(timestamp) {
return `<t:${Math.floor(new Date(timestamp).getTime() / 1000)}:D>`;
}
function createReviewEmbed(review, username, currentPage, totalReviews) {
const embed = new Discord.EmbedBuilder()
.setTitle(`Review for ${username}`)
.setColor(vouchleyaddon.Embed.Colour);
const fields = [
{
name: "Rating",
value: "⭐".repeat(Math.min(Math.max(review.rating, 1), 5)) || "No rating",
inline: false
},
{
name: "Platform",
value: review.platform?.toString() || "Not specified",
inline: true
},
{
name: "Date",
value: formatDate(review.time_sent),
inline: true
}
];
if (review.message && review.message.trim()) {
fields.push({
name: "Review",
value: `\`\`\`${review.message.substring(0, 1024)}\`\`\``,
inline: false
});
}
embed.addFields(fields);
embed.setFooter({ text: `Review ${currentPage + 1} of ${totalReviews}` });
return embed;
}
function createReviewNavigation(currentPage, totalReviews) {
return new Discord.ActionRowBuilder()
.addComponents(
new Discord.ButtonBuilder()
.setCustomId('prev_review')
.setLabel('Previous')
.setStyle(Discord.ButtonStyle.Primary)
.setDisabled(currentPage === 0),
new Discord.ButtonBuilder()
.setCustomId('next_review')
.setLabel('Next')
.setStyle(Discord.ButtonStyle.Primary)
.setDisabled(currentPage === totalReviews - 1),
new Discord.ButtonBuilder()
.setCustomId('back_to_profile')
.setLabel('Back to Profile')
.setStyle(Discord.ButtonStyle.Secondary)
);
}
const activeReviews = new Map();
module.exports = new Command({
name: vouchleyaddon.Command.Name,
description: vouchleyaddon.Command.Description,
options: [
{
name: "search_type",
description: "How do you want to search for the user?",
type: 3,
required: true,
choices: [
{ name: "Vouchley ID", value: "id" },
{ name: "Vouchley Username", value: "username" },
]
},
{
name: "query",
description: "Enter the ID, username, or Discord ID to search",
type: 3,
required: true
}
],
permissions: vouchleyaddon.Command.Permissions,
async run(interaction) {
const searchType = interaction.options.getString("search_type");
const query = interaction.options.getString("query");
try {
let apiUrl;
switch (searchType) {
case "id":
apiUrl = `https://www.vouchley.com/api/v1/user?id=${query}`;
break;
case "username":
apiUrl = `https://www.vouchley.com/api/v1/user?username=${query}`;
break;
}
const response = await fetch(apiUrl, {
headers: {
'Authorization': `Bearer ${vouchleyaddon.Vouchley.API_Key}`,
'Content-Type': 'application/json',
}
});
const data = await response.json();
if (!response.ok || (data.error && data.error.code !== 200)) {
return interaction.reply({
content: `Error: ${data.error?.message || 'Failed to fetch user data'}`,
ephemeral: vouchleyaddon.Embed.Ephemeral
});
}
const user = data.user;
const profileEmbed = new Discord.EmbedBuilder()
.setTitle(`${user.username} - ${String(user.title || "N/A")}`)
.setColor(vouchleyaddon.Embed.Colour)
.setThumbnail(user.avatar_url)
.addFields([
{
name: "Discord",
value: `<@${String(user.discord_id)}> (\`${String(user.discord_id)}\`)`,
inline: false
},
{
name: "Average Rating",
value: `${String(user.average_rating)} (\`${String(user.reviews.length)} Reviews\`)`,
inline: false
}
]);
const profileButtons = [
new Discord.ButtonBuilder()
.setLabel(`Review ${user.username}`)
.setURL(`https://www.vouchley.com/review?user=${user.username}`)
.setStyle(Discord.ButtonStyle.Link)
];
if (user.website) {
profileButtons.push(
new Discord.ButtonBuilder()
.setLabel('Visit Website')
.setURL(formatURL(user.website))
.setStyle(Discord.ButtonStyle.Link)
);
}
if (user.reviews && user.reviews.length > 0) {
profileButtons.push(
new Discord.ButtonBuilder()
.setCustomId('seereviews')
.setLabel('See Reviews')
.setEmoji("⭐")
.setStyle(Discord.ButtonStyle.Secondary)
);
}
const profileRow = new Discord.ActionRowBuilder()
.addComponents(profileButtons);
const message = await interaction.reply({
embeds: [profileEmbed],
components: [profileRow],
fetchReply: true,
ephemeral: vouchleyaddon.Embed.Ephemeral
});
if (user.reviews && user.reviews.length > 0) {
activeReviews.set(message.id, {
reviews: user.reviews,
currentPage: 0,
username: user.username,
profileEmbed,
profileRow
});
const collector = message.createMessageComponentCollector({
time: 600000
});
collector.on('collect', async i => {
const reviewData = activeReviews.get(message.id);
if (!reviewData) return;
switch (i.customId) {
case 'seereviews': {
const review = reviewData.reviews[reviewData.currentPage];
const reviewEmbed = createReviewEmbed(
review,
reviewData.username,
reviewData.currentPage,
reviewData.reviews.length
);
const reviewNav = createReviewNavigation(
reviewData.currentPage,
reviewData.reviews.length
);
await i.update({
embeds: [reviewEmbed],
components: [reviewNav],
ephemeral: vouchleyaddon.Embed.Ephemeral
});
break;
}
case 'prev_review': {
if (reviewData.currentPage > 0) {
reviewData.currentPage--;
const review = reviewData.reviews[reviewData.currentPage];
const reviewEmbed = createReviewEmbed(
review,
reviewData.username,
reviewData.currentPage,
reviewData.reviews.length
);
const reviewNav = createReviewNavigation(
reviewData.currentPage,
reviewData.reviews.length
);
await i.update({
embeds: [reviewEmbed],
components: [reviewNav],
ephemeral: vouchleyaddon.Embed.Ephemeral
});
}
break;
}
case 'next_review': {
if (reviewData.currentPage < reviewData.reviews.length - 1) {
reviewData.currentPage++;
const review = reviewData.reviews[reviewData.currentPage];
const reviewEmbed = createReviewEmbed(
review,
reviewData.username,
reviewData.currentPage,
reviewData.reviews.length
);
const reviewNav = createReviewNavigation(
reviewData.currentPage,
reviewData.reviews.length
);
await i.update({ embeds: [reviewEmbed], components: [reviewNav] });
}
break;
}
case 'back_to_profile': {
await i.update({
embeds: [reviewData.profileEmbed],
components: [reviewData.profileRow]
});
break;
}
}
});
collector.on('end', () => {
activeReviews.delete(message.id);
});
}
} catch (error) {
console.error(error);
if (!interaction.replied) {
await interaction.reply({
content: "There was an error fetching Vouchley user data.",
ephemeral: vouchleyaddon.Embed.Ephemeral
});
}
}
}
});
+37 -61
View File
@@ -177,6 +177,37 @@ function buildTicketStatsContainer(viewingUserId, ticketsClaimed, ticketsOpen, a
return container;
}
function getStaffTicketStats(viewingUserId) {
const allTickets = typeof db.getAllTickets === "function" ? db.getAllTickets() : [];
const ticketsClaimed = allTickets.filter(
(t) => t.claimedBy === viewingUserId || t.claimed_by === viewingUserId,
);
const ticketsOpen = ticketsClaimed.filter(
(t) => (t.status || "").toLowerCase() === "open",
);
let totalResponseTime = 0;
let responseCount = 0;
ticketsClaimed.forEach((t) => {
const claimedAt = t.claimedAt || t.claimed_at;
const createdAt = t.createdAt || t.created_at;
if (claimedAt && createdAt) {
const diff = new Date(claimedAt).getTime() - new Date(createdAt).getTime();
if (diff > 0) {
totalResponseTime += diff;
responseCount++;
}
}
});
const avgMinutes = responseCount
? Math.round(totalResponseTime / responseCount / 60000)
: 0;
return { ticketsClaimed, ticketsOpen, avgMinutes };
}
function buildOpenTicketsContainer(ticketsOpen) {
const container = new ContainerBuilder();
@@ -192,7 +223,9 @@ function buildOpenTicketsContainer(ticketsOpen) {
container.addTextDisplayComponents(
new TextDisplayBuilder().setContent(
ticketsOpen.length ? ticketsOpen.map((t) => `<#${t.id}>`).join("\n") : "No active tickets.",
ticketsOpen.length
? ticketsOpen.map((t) => `<#${t.ticket_id || t.id}>`).join("\n")
: "No active tickets.",
),
);
@@ -352,31 +385,7 @@ module.exports = new Command({
}
if (i.customId === "viewTicketStats") {
let TicketData = { tickets: [] };
try {
TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
} catch (error) {
console.error("Error reading TicketData.json:", error);
}
const ticketsClaimed = TicketData.tickets.filter((t) => t.claimedBy === viewingUserId);
const ticketsOpen = ticketsClaimed.filter((t) => t.open);
const totalTickets = ticketsClaimed.length;
let totalResponseTime = 0;
let responseCount = 0;
ticketsClaimed.forEach((t) => {
if (t.claimedAt && t.createdAt) {
totalResponseTime += new Date(t.claimedAt) - new Date(t.createdAt);
responseCount++;
}
});
const avgMinutes = responseCount
? Math.round(totalResponseTime / responseCount / 60000)
: 0;
const { ticketsClaimed, ticketsOpen, avgMinutes } = getStaffTicketStats(viewingUserId);
const statsContainer = buildTicketStatsContainer(
viewingUserId,
@@ -403,17 +412,7 @@ module.exports = new Command({
}
if (i.customId === "showOpenTickets") {
let TicketData = { tickets: [] };
try {
TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
} catch (error) {
console.error("Error reading TicketData.json:", error);
}
const ticketsOpen = TicketData.tickets.filter(
(t) => t.claimedBy === viewingUserId && t.open,
);
const { ticketsOpen } = getStaffTicketStats(viewingUserId);
const openContainer = buildOpenTicketsContainer(ticketsOpen);
@@ -431,30 +430,7 @@ module.exports = new Command({
}
if (i.customId === "backToStats") {
let TicketData = { tickets: [] };
try {
TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
} catch (error) {
console.error("Error reading TicketData.json:", error);
}
const ticketsClaimed = TicketData.tickets.filter((t) => t.claimedBy === viewingUserId);
const ticketsOpen = ticketsClaimed.filter((t) => t.open);
let totalResponseTime = 0;
let responseCount = 0;
ticketsClaimed.forEach((t) => {
if (t.claimedAt && t.createdAt) {
totalResponseTime += new Date(t.claimedAt) - new Date(t.createdAt);
responseCount++;
}
});
const avgMinutes = responseCount
? Math.round(totalResponseTime / responseCount / 60000)
: 0;
const { ticketsClaimed, ticketsOpen, avgMinutes } = getStaffTicketStats(viewingUserId);
const statsContainer = buildTicketStatsContainer(
viewingUserId,
+3 -2
View File
@@ -33,9 +33,10 @@ function buildContainer(title, lines = []) {
container.addSeparatorComponents(new Discord.SeparatorBuilder().setDivider(true));
if (lines.length > 0) {
const textContent = lines.filter(Boolean).join("\n").trim();
if (textContent.length > 0) {
container.addTextDisplayComponents(
new Discord.TextDisplayBuilder().setContent(lines.join("\n")),
new Discord.TextDisplayBuilder().setContent(textContent),
);
}
+1 -16
View File
@@ -28,22 +28,7 @@ const Command = require("../../Structures/Command.js");
const TicketNumberID = require("../../Structures/TicketID.js");
async function isBlacklisted(userId) {
let blacklistData;
try {
blacklistData = JSON.parse(
fs.readFileSync("./Data/BlacklistedUsers.json", "utf8"),
);
} catch (error) {
console.error("Error reading BlacklistedUsers.json:", error);
return false;
}
if (!blacklistData || !Array.isArray(blacklistData.blacklistedUsers)) {
console.error("blacklistedUsers is not defined or is not an array");
return false;
}
return blacklistData.blacklistedUsers.includes(userId);
return typeof db.isUserBlacklisted === "function" ? db.isUserBlacklisted(userId) : false;
}
async function getClockedInUsers(guild) {
+1
View File
@@ -116,6 +116,7 @@ module.exports = new Command({
}
const departmentOptions = Object.entries(departments)
.filter(([_, dept]) => dept && dept.Enabled !== false)
.slice(0, 25)
.map(([key, dept]) => ({
label: dept.Name || key,
+23 -49
View File
@@ -1,6 +1,7 @@
const fs = require("fs");
const { ApplicationCommandOptionType, ApplicationCommandType, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType, MessageFlags } = require("discord.js");
const yaml = require("js-yaml");
const db = require("../../Structures/Database.js");
const supportbot = require("../../Structures/ConfigStore").supportbot;
const cmdconfig = require("../../Structures/ConfigStore").commands;
const msgconfig = require("../../Structures/ConfigStore").messages;
@@ -18,28 +19,28 @@ function chunkArray(arr, size) {
module.exports = new Command({
name: cmdconfig.Mod.Command,
description: cmdconfig.Mod.Command,
description: cmdconfig.Mod.Description || "Moderation commands",
type: ApplicationCommandType.ChatInput,
options: [
{
name: cmdconfig.Mod.TicketBlacklist.Command,
description: cmdconfig.Mod.TicketBlacklist.Description,
description: cmdconfig.Mod.TicketBlacklist.Description || "Ticket Blacklist Commands",
type: ApplicationCommandOptionType.SubcommandGroup,
options: [
{
name: cmdconfig.Mod.TicketBlacklist.Add.Command,
description: msgconfig.Mod.TicketBlacklist.Add.Description || "Add a user to the ticket blacklist",
description: msgconfig.Mod.TicketBlacklist.Add.Description || "Add a user to the blacklist",
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'user',
description: msgconfig.Mod.TicketBlacklist.Add.UserDescription || "User to blacklist",
description: 'The user to blacklist',
type: ApplicationCommandOptionType.User,
required: true
},
{
name: 'reason',
description: msgconfig.Mod.TicketBlacklist.Add.ReasonDescription || "Reason for blacklisting",
name: 'reason',
description: 'Reason for blacklisting',
type: ApplicationCommandOptionType.String,
required: false
}
@@ -47,18 +48,18 @@ module.exports = new Command({
},
{
name: cmdconfig.Mod.TicketBlacklist.Remove.Command,
description: msgconfig.Mod.TicketBlacklist.Remove.Description || "Remove a user from the ticket blacklist",
description: cmdconfig.Mod.TicketBlacklist.Remove.Description || "Remove a user from the blacklist",
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'user',
description: msgconfig.Mod.TicketBlacklist.Remove.UserDescription || "User to remove from blacklist",
description: 'The user to remove from the blacklist',
type: ApplicationCommandOptionType.User,
required: true
},
{
name: 'reason',
description: msgconfig.Mod.TicketBlacklist.Remove.ReasonDescription || "Reason for removing from blacklist",
description: 'Reason for unblacklisting',
type: ApplicationCommandOptionType.String,
required: false
}
@@ -67,60 +68,32 @@ module.exports = new Command({
{
name: "view",
description: msgconfig.Mod.TicketBlacklist.View.Description || "View all blacklisted users",
type: ApplicationCommandOptionType.Subcommand,
type: ApplicationCommandOptionType.Subcommand
}
]
}
],
permissions: cmdconfig.Mod.Permission,
async run(interaction) {
const { getRole } = interaction.client;
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
let Moderator = await getRole(supportbot.Roles.StaffMember.Moderator, interaction.guild);
if (!SupportStaff || !Admin || !Moderator) {
const missingRolesEmbed = new EmbedBuilder()
.setDescription(msgconfig.Error.InvalidChannel || "Required roles are missing!")
.setColor(supportbot.Embed.Colours.Warn);
return interaction.reply({ embeds: [missingRolesEmbed] });
}
const NoPerms = new EmbedBuilder()
.setDescription(msgconfig.Error.IncorrectPerms || "You do not have the correct permissions!")
.setColor(supportbot.Embed.Colours.Warn);
if (!interaction.member.roles.cache.has(Admin.id) && !interaction.member.roles.cache.has(Moderator.id) && (!supportbot.Mod.AllowSupportStaff || !interaction.member.roles.cache.has(SupportStaff.id))) {
return interaction.reply({ embeds: [NoPerms] });
}
const subcommand = interaction.options.getSubcommand(false);
const subcommandGroup = interaction.options.getSubcommandGroup();
const subcommand = interaction.options.getSubcommand();
const user = interaction.options.getUser('user');
const reason = interaction.options.getString('reason') || "No reason provided";
try {
let blacklistedUsers;
try {
blacklistedUsers = JSON.parse(fs.readFileSync("./Data/BlacklistedUsers.json", "utf8")).blacklistedUsers;
if (!Array.isArray(blacklistedUsers)) {
blacklistedUsers = [];
}
} catch (error) {
blacklistedUsers = [];
}
const blacklistedUsers = typeof db.getBlacklistedUsers === "function" ? db.getBlacklistedUsers() : [];
if (subcommand === cmdconfig.Mod.TicketBlacklist.Add.Command) {
if (blacklistedUsers.includes(user.id)) {
if (db.isUserBlacklisted && db.isUserBlacklisted(user.id)) {
const alreadyBlacklistedEmbed = new EmbedBuilder()
.setDescription(msgconfig.Mod.TicketBlacklist.Add.AlreadyBlacklisted.replace("{userTag}", user.tag) || ":x: User is already blacklisted.")
.setColor(supportbot.Embed.Colours.Warn);
return interaction.reply({ embeds: [alreadyBlacklistedEmbed], flags: MessageFlags.Ephemeral });
}
blacklistedUsers.push(user.id);
fs.writeFileSync("./Data/BlacklistedUsers.json", JSON.stringify({ "blacklistedUsers": blacklistedUsers }, null, 4));
if (typeof db.addBlacklistedUser === "function") {
db.addBlacklistedUser(user.id, reason, interaction.user.tag);
}
const successEmbed = new EmbedBuilder()
.setDescription(msgconfig.Mod.TicketBlacklist.Add.Success.replace("{userTag}", user.tag) || ":white_check_mark: User has been blacklisted.")
@@ -133,7 +106,7 @@ module.exports = new Command({
.setColor(msgconfig.TicketBlacklistLog.Colour || supportbot.Embed.Colours.Success)
.setFooter({ text: supportbot.Embed.Footer, iconURL: interaction.user.displayAvatarURL() })
.setDescription(`> **User:** ${user.tag} (\`${user.id}\`)\n> **Actioned by:** <@${interaction.user.id}>`)
.addFields({ name: "Action", value: "\`\`\`Removed from blacklist\`\`\`", inline: false })
.addFields({ name: "Action", value: "\`\`\`Added to blacklist\`\`\`", inline: false })
.addFields({ name: "Reason", value: `\`\`\`${reason}\`\`\``, inline: false });
blacklistChannel.send({ embeds: [blacklistLogEmbed] });
@@ -145,15 +118,16 @@ module.exports = new Command({
});
} else if (subcommand === cmdconfig.Mod.TicketBlacklist.Remove.Command) {
if (!blacklistedUsers.includes(user.id)) {
if (db.isUserBlacklisted && !db.isUserBlacklisted(user.id)) {
const notBlacklistedEmbed = new EmbedBuilder()
.setDescription(msgconfig.Mod.TicketBlacklist.Remove.NotBlacklisted.replace("{userTag}", user.tag) || ":x: User is not blacklisted.")
.setColor(supportbot.Embed.Colours.Warn);
return interaction.reply({ embeds: [notBlacklistedEmbed], flags: MessageFlags.Ephemeral });
}
blacklistedUsers = blacklistedUsers.filter(id => id !== user.id);
fs.writeFileSync("./Data/BlacklistedUsers.json", JSON.stringify({ "blacklistedUsers": blacklistedUsers }, null, 4));
if (typeof db.removeBlacklistedUser === "function") {
db.removeBlacklistedUser(user.id);
}
const removedEmbed = new EmbedBuilder()
.setDescription(msgconfig.Mod.TicketBlacklist.Remove.Success.replace("{userTag}", user.tag) || ":white_check_mark: User has been removed from the blacklist.")
+5 -22
View File
@@ -1,35 +1,18 @@
const { Command } = require('../../Structures/Addon.js');
const Command = require("../../Structures/Command.js");
const Discord = require("discord.js");
const fs = require("fs");
const yaml = require("js-yaml");
const db = require("../../Structures/Database.js");
const supportbot = require("../../Structures/ConfigStore").supportbot;
const cmdconfig = require("../../Structures/ConfigStore").commands;
async function loadSettings() {
return new Promise((resolve, reject) => {
db.get("SELECT data FROM settings WHERE id = 1", (err, row) => {
if (err) return reject(err);
if (!row) return resolve({});
try {
resolve(JSON.parse(row.data));
} catch (e) {
resolve({});
}
});
});
return typeof db.getSettings === "function" ? db.getSettings() : {};
}
async function saveSettings(settings) {
const data = JSON.stringify(settings);
return new Promise((resolve, reject) => {
db.run(
"INSERT INTO settings (id, data) VALUES (1, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data",
[data],
(err) => (err ? reject(err) : resolve())
);
});
if (typeof db.saveSettings === "function") {
db.saveSettings(settings);
}
}
module.exports = new Command({
+33 -4
View File
@@ -1,34 +1,63 @@
# ___ _ ___ _
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
# |_| |_|
#
# SupportBot created by Emerald Services
# Installed with MIT License
#
# Discord Support: https://discord.gg/emeraldsrv
# Official Website & Marketplace: https://emeraldsrv.com
#
# Messages Configuration (api.yml)
# -------------------------------
# API Server Configuration
# -------------------------------
# Copy to api.yml and fill in your values (api.yml is not committed with real secrets).
API:
Enabled: true
Port: 3000
SecretKey: "SECRET_KEY"
# Set to 1 when the dashboard is behind nginx, Cloudflare, Pterodactyl proxy, etc.
# so http/https is detected from X-Forwarded-Proto.
TrustProxy: false
EmeraldAPIKey: "EMERALDSRV_API_KEY"
# This is required for the one-click addon installer. Get API key from https://emeraldsrv.dev/
OAuth:
Enabled: true
ClientId: "1530910674551574580"
ClientSecret: "GIWdonM3bdFILhkg_1XWWeVQRlGf_npu"
ClientId: "CLIENT_ID"
ClientSecret: "CLIENT_SECRET"
# Get Client ID and Client Secret from https://discord.com/developers/applications
# Canonical callback URL (host + path). Protocol (http/https) can follow the
# browser when UseRequestOrigin is true (default).
RedirectUri: "http://localhost:3000/api/auth/discord/callback"
# Optional: register extra callback URLs in Discord and list them here.
# RedirectUris:
# - "https://bot.example.com/api/auth/discord/callback"
# UseRequestOrigin: true
# CookieSecure: false
OwnerUserIds:
- "OWNER_ID"
- "OWNER_USER_ID"
AllowedUserIds: []
# Dashboard Features
LiveChat:
Mode: "webhook"
# "webhook" - Webhook to send messages with staff member's avatar and Discord username
# "bot" - Send messages as Bot account with discord username prefix.
# "bot_noprefix" - Send messages as Bot account without discord username prefix.
+6 -14
View File
@@ -21,7 +21,7 @@ Info:
Title: "About Us"
Description: "SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customization to match your own brand."
Button: "Visit Site"
URL: "https://docs.emeraldsrv.com"
URL: "https://emeraldsrv.dev"
Colour: "#45b463"
# ----------------------------
@@ -30,15 +30,15 @@ Info:
Welcome:
Enabled: true
LayoutStyle: "modern"
LayoutStyle: "classic"
# Available Layout Styles
# "modern" - For the new Discord v2 components
# "classic" - Use the classic Discord look.
Embed:
Colour: "#45b463"
Title: "Welcome to ServerName"
Message: ":smile: %joined_user% has just landed!\n\n🔨 **Server Rules:** <#CHANNEL_ID>"
Title: "Welcome!"
Message: ":smile: %joined_user% has just landed!"
Icon:
Mode: "USER" # USER | BOT | CUSTOM
CustomURL: "https://example.com/custom.png"
@@ -48,18 +48,10 @@ Welcome:
Buttons:
Enabled: true
List:
- label: "BuiltByBit"
- label: "Website"
style: "Link"
url: "https://your-website.com/how-to-play-java"
url: "https://emeraldsrv.dev"
emoji: "⌨️"
- label: "GitHub"
style: "Link"
url: "https://your-website.com/how-to-play-bedrock"
emoji: "👾"
- label: "Tebex"
style: "Link"
url: "https://your-store.tebex.io/"
emoji: "🛒"
Modern:
Colour: "#45b463"
+23 -12
View File
@@ -8,8 +8,8 @@
Enabled: true
General:
Provider: "claude"
Model: "claude-sonnet-4-6"
Provider: "openai"
Model: "MODEL"
Model_API_Key: "MODEL_API_KEY"
# Providers Available:
# "openai" - Use OpenAI's GPT models. Example: "gpt-5.4" "gpt-5-mini"
@@ -17,15 +17,15 @@ General:
# "claude" - Use Anthropic's Claude models. Example: "claude-sonnet-4-6"
Tokens: 1200
Temperature: 0.4
Name: "SupportBot AI"
PastebinAPI_Key: "PASTEBIN_API_KEY"
PastebinAPI_Key: "YOUR_PASTEBIN_API_KEY"
PastebinAPI_URL: "https://pastebin.com/api/api_post.php"
Style:
MessageType: "text"
MessageType: "components_v2"
# Available Styles for AI:
# "embed" - AI responses will be sent as Discord embeds.
# "text" - AI responses will be sent as plain messages.
@@ -59,12 +59,23 @@ Memory:
CustomInstructions:
- "You are SupportBot AI made by Emerald Services"
- "You are built with DiscordJS/NodeJS and currently running on dev build 26.0 build 2"
- "You're current build can be found here https://github.com/Emerald-Services/SupportBot/tree/26.0"
- "You're main build can be found here https://builtbybit.com/resources/supportbot-free-advanced-ticket-bot.8940/ and Polymart at https://polymart.org/product/518/supportbot-1-discord-ticket-bot which is version 8.4"
- "dev build 26.0 build 2 includes all-new AI features for SupportBot such as memory system that allows you to remember facts and summaries of conversations, which can be used to provide better responses."
- "SupportBot AI also have a new tickets AI Mode which is enabled in supportbot.ymll, which allows you to assist users in support tickets and provide better responses based on the context of the ticket."
- "Your main purpose is to assist users in the support server and provide helpful responses to their questions and issues. Always be accurate and if you do not have answer then simply ask the person to create a ticket if they need more help."
- "You are built with DiscordJS/NodeJS and currently running on version 26.2"
- "You're current build can be found here
https://github.com/Emerald-Services/SupportBot"
- "You're main build can be found here
https://builtbybit.com/resources/supportbot-free-advanced-ticket-bot.8940/
and Polymart at
https://polymart.org/product/518/supportbot-1-discord-ticket-bot"
- "SupportBot includes all-new AI features such as a memory system that allows
you to remember facts and summaries of conversations, which can be used to
provide better responses."
- "SupportBot AI also has a tickets AI Mode which is enabled in
supportbot.yml, which allows you to assist users in support tickets and
provide better responses based on the context of the ticket."
- "Your main purpose is to assist users in the support server and provide
helpful responses to their questions and issues. Always be accurate and if
you do not have answer then simply ask the person to create a ticket if they
need more help."
#- "Add custom instructions here"
Messages:
@@ -73,4 +84,4 @@ Messages:
AIDisabled: "AI is currently disabled."
MessageTooLong: "My response was too long, so I uploaded it here: {pastebin}"
SuggestTicketText: "-# Need more help? React with 🎫 to open a ticket."
SuggestTicketReaction : "🎫"
SuggestTicketReaction: "🎫"
+25 -5
View File
@@ -12,7 +12,7 @@
#
# SupportBot Configuration (supportbot.yml)
SupportBot_Version: "v26.2-pre1"
SupportBot_Version: "v26.2"
# -------------------------
# General
@@ -20,12 +20,32 @@ SupportBot_Version: "v26.2-pre1"
General:
Name: "SupportBot"
Token: "BOT_TOKEN"
Token: "YOUR_BOT_TOKEN_HERE"
Addons:
Enabled: true
GuildId: "GUILD_ID"
GuildId: "YOUR_GUILD_ID_HERE"
# -------------------------
# Database Configuration
# -------------------------
Database:
# Driver options: "mysql" (works for MariaDB & MySQL) or "sqlite"
Driver: "mysql"
# Connection Settings for MariaDB / MySQL (used when Driver is "mysql" or "mariadb")
MySQL:
Host: "localhost"
Port: 3306
User: "root"
Password: "password"
Database: "supportbot"
ConnectionLimit: 10
# Connection Settings for SQLite (used when Driver is "sqlite")
SQLite:
File: "./Data/supportbot.db"
# Activity
# -------------------------
@@ -71,7 +91,7 @@ Roles:
Moderator: "ROLE_ID"
Mod:
AllowSupportStaff: false
AllowSupportStaff: true
# Allow Support Staff to use the /mod command. (More in detail customisation in commands.yml)
# ----------------------------
@@ -225,7 +245,7 @@ Ticket:
TicketBlacklistLog: "CHANNEL_ID"
AIMode:
Enabled: false
Enabled: true
ThreadName: "Chat with SupportBot AI"
WelcomeMessage: "Hi! I’m SupportBot AI. You can chat with me here about your issue."
+7 -7
View File
@@ -20,12 +20,12 @@
Panel: true
Style:
Title: "## SupportBot Ticket Creation"
Description: "Click on the button to file a `Ticket` and our team will try their
best to assist you in the best way we can!"
Image: "https://i.imgur.com/dejQvkg.png"
Title: "## 📬 Open Ticket"
Description: "Tap the button to open a support ticket, Our team will respond as
soon as possible."
Image: "https://cdn.1tzemerald.space/Emerald%20Services/SBPoster.png"
Color: "#45b463"
Layout: "4"
Layout: "3"
# Available Layout Styles
# "1" - Style 1 - Title & Text, Button at the top -- Image at the bottom
@@ -34,8 +34,8 @@ Style:
# "4" - Style 4 - Classic Embed (Title & Text, Image on right, Button at bottom)
Button:
Text: "Create Ticket"
Emoji: "🎫"
Text: "Open"
Emoji: "🛟"
Color: "2"
CustomId: "createticket"
+49 -51
View File
@@ -140,6 +140,13 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
if (interaction.isStringSelectMenu()) {
if (interaction.customId === "ticketdepartmentselect") {
const selectedDepartment = interaction.values[0];
const deptConfig = supportbot.Ticket?.DepartmentSystem?.Departments?.[selectedDepartment];
if (deptConfig && deptConfig.Enabled === false) {
return interaction.reply({
content: "Ticket creation for this department is currently disabled.",
flags: Discord.MessageFlags.Ephemeral,
});
}
if (supportbot.Ticket.TicketReason) {
const modal = new Discord.ModalBuilder()
@@ -680,7 +687,15 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
});
}
if (interaction.customId === "createticket") {
if (interaction.customId === "createticket" || interaction.customId === "openticket") {
const panelDisabled = panelconfig.Panel === false || supportbot.Ticket?.Enabled === false;
if (panelDisabled) {
return interaction.reply({
content: "Ticket creation is currently disabled.",
flags: Discord.MessageFlags.Ephemeral,
});
}
if (supportbot.Ticket.TicketReason) {
const modal = new Discord.ModalBuilder()
.setCustomId("ticketReasonModal")
@@ -852,69 +867,52 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
interaction.customId === "downvote" ||
interaction.customId === "removevote"
) {
const suggestion = suggestions[interaction.message.id];
if (!suggestion)
return interaction.reply({
content: "Suggestion not found.",
ephemeral: true,
});
const suggestion = (typeof db.getSuggestion === "function" ? db.getSuggestion(interaction.message.id) : null) || {
id: interaction.message.id,
author_id: "",
text: "",
status: "Created",
upvotes: [],
downvotes: [],
};
const userId = interaction.user.id;
const hasUpvoted = suggestion.upvotes.includes(userId);
const hasDownvoted = suggestion.downvotes.includes(userId);
if (interaction.customId === "upvote") {
if (hasUpvoted) {
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
} else {
suggestion.upvotes.push(userId);
if (hasDownvoted) {
suggestion.downvotes = suggestion.downvotes.filter(
(id) => id !== userId,
);
}
}
} else if (interaction.customId === "downvote") {
if (hasDownvoted) {
suggestion.downvotes = suggestion.downvotes.filter(
(id) => id !== userId,
);
} else {
suggestion.downvotes.push(userId);
if (hasUpvoted) {
suggestion.upvotes = suggestion.upvotes.filter(
(id) => id !== userId,
);
}
}
} else if (interaction.customId === "removevote") {
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
suggestion.downvotes = suggestion.downvotes.filter(
(id) => id !== userId,
);
if (supportbot.Suggestions?.OwnSuggestion === false && suggestion.author_id === userId) {
return interaction.reply({
content: "You cannot vote on your own suggestion.",
flags: Discord.MessageFlags.Ephemeral,
});
}
fs.writeFileSync(
"./Data/SuggestionData.json",
JSON.stringify(suggestions, null, 2),
);
const voteResult = typeof db.voteSuggestion === "function"
? db.voteSuggestion(interaction.message.id, userId, interaction.customId)
: { upvoteCount: 0, downvoteCount: 0 };
const upvoteCount = suggestion.upvotes.length;
const downvoteCount = suggestion.downvotes.length;
const oldEmbed = interaction.message.embeds?.[0];
if (!oldEmbed) {
return interaction.reply({
content: "Suggestion embed not found.",
flags: Discord.MessageFlags.Ephemeral,
});
}
const updatedEmbed = new Discord.EmbedBuilder(
interaction.message.embeds[0].data,
).setFields([
{ name: "Suggestion", value: suggestion.suggestion, inline: true },
{ name: "From", value: `<@${suggestion.author}>` },
const suggestionText = suggestion.text || oldEmbed.fields?.find((f) => f.name === "Suggestion")?.value || "";
const authorText = suggestion.author_id
? `<@${suggestion.author_id}>`
: (oldEmbed.fields?.find((f) => f.name === "From")?.value || `<@${userId}>`);
const updatedEmbed = Discord.EmbedBuilder.from(oldEmbed).setFields([
{ name: "Suggestion", value: suggestionText, inline: true },
{ name: "From", value: authorText },
{
name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`,
value: `${upvoteCount}`,
value: `${voteResult.upvoteCount}`,
inline: true,
},
{
name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`,
value: `${downvoteCount}`,
value: `${voteResult.downvoteCount}`,
inline: true,
},
]);
+86
View File
@@ -392,6 +392,92 @@ function rememberUserFacts(message) {
}
module.exports = new Event("messageCreate", async (client, message) => {
if (message.guild && typeof db.getTicket === "function") {
const activeTicket = db.getTicket(message.channel.id);
if (activeTicket && global.apiServer) {
global.apiServer.broadcast("ticket_message", {
ticketId: message.channel.id,
message: {
id: message.id,
author: {
id: message.author.id,
username: message.author.username,
globalName: message.author.globalName || message.author.username,
avatar: message.author.displayAvatarURL({ extension: "png", size: 64 }),
bot: message.author.bot
},
content: (() => {
if (message.content && message.content.trim()) return message.content;
if (Array.isArray(message.components) && message.components.length > 0) {
const texts = [];
for (const comp of message.components) {
const data = typeof comp.toJSON === "function" ? comp.toJSON() : comp;
if (data.content) texts.push(data.content);
if (Array.isArray(data.components)) {
for (const child of data.components) {
const childData = typeof child.toJSON === "function" ? child.toJSON() : child;
if (childData.content) texts.push(childData.content);
if (childData.label && (childData.type === 10 || childData.type === "TEXT_DISPLAY")) {
texts.push(childData.label);
}
}
}
}
if (texts.length > 0) return texts.join("\n");
}
return message.content || "";
})(),
containerColor: (() => {
if (Array.isArray(message.components)) {
for (const comp of message.components) {
const data = typeof comp.toJSON === "function" ? comp.toJSON() : comp;
if (data.accent_color) {
return `#${data.accent_color.toString(16).padStart(6, "0")}`;
}
}
}
return null;
})(),
embeds: (message.embeds || []).map(e => ({
title: e.title || null,
description: e.description || null,
color: e.color ? `#${e.color.toString(16).padStart(6, "0")}` : "#5865F2",
author: e.author ? { name: e.author.name, iconURL: e.author.iconURL } : null,
fields: (e.fields || []).map(f => ({ name: f.name, value: f.value, inline: f.inline })),
footer: e.footer ? { text: e.footer.text, iconURL: e.footer.iconURL } : null,
thumbnail: e.thumbnail?.url ? { url: e.thumbnail.url } : null,
image: e.image?.url ? { url: e.image.url } : null,
timestamp: e.timestamp || null
})),
components: (message.components || []).map(c => {
const data = typeof c.toJSON === "function" ? c.toJSON() : c;
return {
type: data.type,
components: (data.components || []).map(sub => {
const subData = typeof sub.toJSON === "function" ? sub.toJSON() : sub;
return {
type: subData.type,
label: subData.label || subData.content || null,
style: subData.style || null,
url: subData.url || null,
customId: subData.custom_id || subData.customId || null,
emoji: subData.emoji ? (subData.emoji.name || subData.emoji.id) : null
};
})
};
}),
attachments: Array.from((message.attachments || []).values()).map(a => ({
id: a.id,
name: a.name,
url: a.url,
contentType: a.contentType
})),
createdAt: message.createdTimestamp
}
});
}
}
if (message.author.bot || !message.guild) return;
let shouldRespond =
+41 -178
View File
@@ -1,6 +1,6 @@
<h1 align="center">
<br>
<a href="https://github.com/Emerald-Services/SupportBot"><img src="https://i.imgur.com/cuadAYv.png"></a>
<a href="https://github.com/Emerald-Services/SupportBot"><img src="https://cdn.1tzemerald.space/Emerald%20Services/SBThreadHeader.png"></a>
<br>
SupportBot
<br>
@@ -28,195 +28,58 @@
| SupportBot | Node.JS | Discord.JS | Supported |
|------------|---------|------------|------------|
| 26.x | 22.x | 14.x. | ✅ Yes
| 8.x | 22.x | 14.x. | ✅ Yes
| 7.7.3 | 16.x | 13.x. | ❌ No
| 7.x | 16.x | 13.x. | ❌ No
| 6.x | 14.x | 13.x. | ❌ No
| 5.x | 12.x | 13.x. | ❌ No
| 4.x | 11.x | 13.x. | ❌ No
| Older | 10.x | 13.x. | ❌ No
| 26.x | 22.x | 14.x | ✅ Yes |
| 8.x | 22.x | 14.x | ❌ No |
| 7.x | 16.x | 13.x | ❌ No |
| Older | 10.x | 13.x | ❌ No |
</div>
<p align="center">
<a href="https://opensource.org/licenses/MIT">
<img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="MIT License">
</a>
<a href="https://github.com/discordjs/discord.js">
<img src="https://img.shields.io/badge/discord.js-v14-blue?style=for-the-badge" alt="discord.js v14">
</a>
<a href="https://nodejs.org/">
<img src="https://img.shields.io/badge/node.js-22.x-green?style=for-the-badge" alt="Node.js 22.x">
</a>
<a href="https://github.com/Emerald-Services/SupportBot">
<img src="https://img.shields.io/badge/upstream-SupportBot-purple?style=for-the-badge" alt="Upstream SupportBot">
</a>
</p>
<p align="center">
<a href="#about">About</a> ·
<a href="#features">Features</a> ·
<a href="#requirements">Requirements</a> ·
<a href="#getting-started">Getting started</a> ·
<a href="#dashboard-access">Dashboard access</a> ·
<a href="#configuration">Configuration</a> ·
<a href="#addons">Addons</a> ·
<a href="#development">Development</a> ·
<a href="#upstream--credits">Upstream & credits</a> ·
<a href="https://emeraldsrv.dev/">Website</a>
•
<a href="https://github.com/Emerald-Services/SupportBot/wiki">Wiki</a>
<br>
<a href="#about">About</a>
•
<a href="#support">Support</a>
•
<a href="#license">License</a>
•
<a href="https://github.com/Emerald-Services/SupportBot/wiki/Third-Party-Developer">Third-Party</a>
•
<a href="#contributors">Contributors</a>
</p>
---
## About
This repository is a **community fork** of [SupportBot](https://github.com/Emerald-Services/SupportBot) — the open-source Discord support/ticket bot by [Emerald Services](https://emeraldsrv.dev). It is **not** affiliated with or endorsed by Emerald Services.
SupportBot is an Open-Source discord bot built with [discord.js](https://github.com/discordjs/discord.js). It's primarily focused to help servers organise and manage their support system in a unique way with full customisation to match your brand.
What this fork adds is a **self-hosted dashboard**: a modern web UI and REST API that run in the **same Node process** as the bot. You configure tickets, messages, commands, AI settings, addons, and more from the browser instead of editing YAML by hand. The API starts immediately on launch, so the dashboard stays reachable even while the bot is connecting or restarting.
## Support
If you only need the original bot without the dashboard, use the [official SupportBot repository](https://github.com/Emerald-Services/SupportBot).
<a href="https://emeraldsrv.dev/discord">
<img alt="Discord" src="https://img.shields.io/discord/597779408295821323?logo=discord&logoColor=white&style=for-the-badge">
</a>
## Features
### Self-hosted dashboard
| Area | What you get |
|------|----------------|
| **Overview** | Live stats — servers, members, open/closed tickets, module setup status, RAM/CPU/uptime |
| **Visual config editors** | Edit `supportbot`, ticket panel, commands, messages, and AI config with form fields instead of raw YAML |
| **Discord pickers** | Choose channels, roles, and categories from dropdowns when configuring the bot (no copy-pasting IDs) |
| **Guild health** | Warnings if the bot is in the wrong server or extra guilds; quick link to fix `GuildId` or leave stray servers |
| **Logs** | Browse Output, Warn, and Error logs from the dashboard |
| **Transcripts** | View saved ticket HTML transcripts |
| **Notifications** | In-app alerts for bot restarts, update checks, and installs |
| **Settings** | Check for dashboard updates and apply them from the UI |
| **Users & roles** | Invite staff via Discord OAuth; assign owner, admin, editor, viewer, or custom per-page permissions |
| **Addons** | Browse and install addons from the [official Addons repo](https://github.com/Emerald-Services/Addons); edit addon configs in the sidebar like other config files |
### Bot & API (unchanged upstream behaviour, plus improvements)
- Full **SupportBot v26** ticket system, slash commands, AI assistant, and addon support
- **Discord OAuth** login for the dashboard (no shared API secret in the browser)
- **API key** (`SecretKey` in `api.yml`) still works for automation and scripts
- Config saves can **restart the Discord bot** while keeping the dashboard and API online
- Timeouts and caching so the UI does not hang when Discord or GitHub is slow
## Requirements
| Component | Version |
|-----------|---------|
| **Node.js** | 22.x (matches [SupportBot 8.x](https://github.com/Emerald-Services/SupportBot)) |
| **discord.js** | 14.x (installed via `package.json`) |
| **Discord bot** | Application with bot token and required intents |
| **Discord OAuth app** | For dashboard login (optional but recommended) |
You need a machine or VPS that can run Node and reach Discord’s API (and GitHub, if you use in-dashboard updates or the addon marketplace).
## Getting started
### 1. Clone and install
```bash
git clone https://github.com/C-h-a-r/SupportBot-Dashboard.git
cd SupportBot-Dashboard
npm install
```
### 2. Configure the bot
Edit `Configs/supportbot.yml`:
- Set `General.Token` to your bot token
- Set `General.GuildId` to your Discord server ID
- Enable addons if you use them: `General.Addons.Enabled: true`
Other YAML files in `Configs/` can stay at defaults until you open the dashboard.
### 3. Configure the API & dashboard
Edit `Configs/api.yml`:
```yaml
API:
Enabled: true
Port: 3000
SecretKey: "generate-a-long-random-string"
OAuth:
Enabled: true
ClientId: "YOUR_DISCORD_APP_CLIENT_ID"
ClientSecret: "YOUR_DISCORD_APP_CLIENT_SECRET"
RedirectUri: "http://localhost:3000/api/auth/discord/callback"
OwnerUserIds:
- "YOUR_DISCORD_USER_ID"
```
**Discord Developer Portal**
1. Create an application at [discord.com/developers/applications](https://discord.com/developers/applications)
2. Under **OAuth2 → Redirects**, add your callback URL(s). If users may sign in over **both** HTTP and HTTPS, register **both** (same host/path, different protocol), e.g. `http://bot.example.com/api/auth/discord/callback` and `https://bot.example.com/api/auth/discord/callback`.
3. Use the same app’s **Client ID** and **Client Secret** in `api.yml`
4. Put your Discord user ID in `OwnerUserIds` for full dashboard access
Set `RedirectUri` to your usual URL (host and path). By default, `UseRequestOrigin` keeps the **same protocol** as the page you opened (http vs https). Behind a reverse proxy, set `TrustProxy: 1` so forwarded `X-Forwarded-Proto` is respected.
### 4. Start the bot
```bash
npm start
```
When startup succeeds you should see:
- `[Dashboard] API listening on http://localhost:3000`
- Discord bot login and slash command registration
Open **http://localhost:3000** in your browser and sign in with Discord.
The web UI is shipped as static files in `public/dashboard/` (included in this repository). You do not need a separate frontend build step.
> **Tip:** On first run, invite the bot to your server with the permissions SupportBot needs. Set `General.GuildId` to that server’s ID so channel/role pickers and guild health checks work.
## Dashboard access
| Method | Use case |
|--------|----------|
| **Discord OAuth** | Normal use — open the site, click **Continue with Discord**, sign in as an owner or invited user |
| **Bearer token** | Scripts and automation — `Authorization: Bearer <SecretKey>` on `/api/*` routes |
Owners listed in `api.yml` (`OwnerUserIds`) always have full access. Additional users can be added under **Users** in the dashboard with granular permissions per config file and page.
## Configuration
| File | Purpose |
|------|---------|
| `Configs/supportbot.yml` | Bot token, guild, staff roles, ticket channels, embed colours, etc. |
| `Configs/ticket-panel.yml` | Ticket panel layout and buttons |
| `Configs/commands.yml` | Enable/disable slash commands |
| `Configs/messages.yml` | User-facing message strings |
| `Configs/supportbot-ai.yml` | AI assistant settings |
| `Configs/api.yml` | Dashboard port, session secret, OAuth |
| `Addons/Configs/*` | Per-addon config (after installing from **Addons** page) |
Most of these are editable from the sidebar under **Tickets & support**, **Community**, **Server control**, and **Addons**.
## Addons
1. Open **Addons** in the dashboard (or install manually into `Addons/` as in the [upstream docs](https://github.com/Emerald-Services/Addons))
2. Click **Install** on an addon from the marketplace — files are copied into `Addons/` and `Addons/Configs/`, then the bot restarts
3. Edit the addon’s config from the **Addons** section in the left sidebar (same editor as core configs)
4. Ensure `General.Addons.Enabled` is `true` in bot config
Official addon list: [github.com/Emerald-Services/Addons](https://github.com/Emerald-Services/Addons)
## Upstream & credits
- **Original project:** [Emerald-Services/SupportBot](https://github.com/Emerald-Services/SupportBot) — MIT license, ticket bot for Discord
- **Official addons:** [Emerald-Services/Addons](https://github.com/Emerald-Services/Addons)
- **Community:** [Emerald Discord](https://emeraldsrv.dev/discord) · [Wiki](https://github.com/Emerald-Services/SupportBot/wiki)
This fork is maintained independently. For bugs in **core ticket/command behaviour** that also exist upstream, consider reporting to the [official repo](https://github.com/Emerald-Services/SupportBot/issues). For **dashboard-specific** issues, use this repository’s issues.
## License
Released under the [MIT License](https://opensource.org/licenses/MIT), same as upstream SupportBot.
Released under the [MIT](https://opensource.org/licenses/MIT) license.
## Third-Party
- [Verified Addons](https://emeraldsrv.dev)
- [BuiltByBit](https://builtbybit.com/resources/supportbot-advanced-ticket-bot.8940/)
- [Voxel](https://polymart.org/resource/supportbot-1-discord-ticket-bot.518)
## Contributors
<a href="https://github.com/Emerald-Services/SupportBot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Emerald-Services/SupportBot">
</a>
## Hosting
You can use our [Pterodactyl egg](https://github.com/Emerald-Services/Pterodactyl-Egg) to host SupportBot on your own panel.
+80 -351
View File
@@ -1,438 +1,167 @@
const Database = require("better-sqlite3");
const path = require("path");
const fs = require('fs');
const path = require('path');
const db = new Database(path.join(__dirname, "../Data/ai-memory.db"));
const DB_PATH = path.join(__dirname, '../Data/ai-memory.json');
db.pragma("journal_mode = WAL");
function load() {
try {
const raw = fs.readFileSync(DB_PATH, 'utf8');
return JSON.parse(raw);
} catch (e) {
return {
ai_conversations: [],
ai_summaries: [],
ai_facts: [],
ai_knowledge: [],
ai_sessions: [],
};
}
}
db.prepare(
`
CREATE TABLE IF NOT EXISTS ai_conversations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT,
channel_id TEXT,
user_id TEXT,
role TEXT NOT NULL,
content TEXT NOT NULL,
created_at INTEGER NOT NULL
)
`,
).run();
function save(state) {
try {
fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
fs.writeFileSync(DB_PATH, JSON.stringify(state, null, 2), 'utf8');
} catch (e) {
console.error('Failed to persist ai-memory:', e);
}
}
db.prepare(
`
CREATE TABLE IF NOT EXISTS ai_summaries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT,
channel_id TEXT,
summary TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
)
`,
).run();
const state = load();
db.prepare(
`
CREATE TABLE IF NOT EXISTS ai_facts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT,
channel_id TEXT,
user_id TEXT,
fact_type TEXT NOT NULL,
fact_key TEXT NOT NULL,
fact_value TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
)
`,
).run();
db.prepare(
`
CREATE TABLE IF NOT EXISTS ai_knowledge (
id INTEGER PRIMARY KEY AUTOINCREMENT,
source_type TEXT NOT NULL,
source_name TEXT NOT NULL,
title TEXT NOT NULL,
content TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
)
`,
).run();
db.prepare(
`
CREATE TABLE IF NOT EXISTS ai_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT,
channel_id TEXT,
user_id TEXT,
model TEXT,
mode TEXT,
last_message_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
)
`,
).run();
try {
db.prepare(`ALTER TABLE ai_facts ADD COLUMN user_id TEXT`).run();
} catch (e) {
if (!String(e).includes("duplicate column name")) throw e;
function nextId(arr) {
return arr.length === 0 ? 1 : Math.max(...arr.map(a => a.id || 0)) + 1;
}
module.exports = {
saveUserFact({ guildId, userId, factType, factKey, factValue }) {
const existing = db
.prepare(
`
SELECT id FROM ai_facts
WHERE guild_id IS ? AND user_id IS ? AND fact_type = ? AND fact_key = ?
LIMIT 1
`,
)
.get(guildId || null, userId || null, factType, factKey);
const existing = state.ai_facts.find(f => f.guild_id === (guildId || null) && f.user_id === (userId || null) && f.fact_type === factType && f.fact_key === factKey);
if (existing) {
db.prepare(
`
UPDATE ai_facts
SET fact_value = ?, updated_at = ?
WHERE id = ?
`,
).run(factValue, Date.now(), existing.id);
existing.fact_value = factValue;
existing.updated_at = Date.now();
save(state);
return;
}
db.prepare(
`
INSERT INTO ai_facts (
guild_id, channel_id, user_id, fact_type, fact_key, fact_value, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`,
).run(
guildId || null,
null,
userId || null,
factType,
factKey,
factValue,
Date.now(),
Date.now(),
);
const id = nextId(state.ai_facts);
state.ai_facts.push({ id, guild_id: guildId || null, channel_id: null, user_id: userId || null, fact_type: factType, fact_key: factKey, fact_value: factValue, created_at: Date.now(), updated_at: Date.now() });
save(state);
},
getUserFacts(guildId, userId) {
return db
.prepare(
`
SELECT * FROM ai_facts
WHERE guild_id IS ? AND user_id IS ?
ORDER BY updated_at DESC
`,
)
.all(guildId || null, userId || null);
return state.ai_facts.filter(f => f.guild_id === (guildId || null) && f.user_id === (userId || null)).sort((a,b) => b.updated_at - a.updated_at);
},
getUserFactsByScope({ guildId = null, userId = null, scope = "guild" }) {
if (!userId) return [];
if (scope === "global") {
return db
.prepare(
`
SELECT * FROM ai_facts
WHERE user_id IS ?
ORDER BY updated_at DESC
`,
)
.all(userId || null);
return state.ai_facts.filter(f => f.user_id === (userId || null)).sort((a,b) => b.updated_at - a.updated_at);
}
return db
.prepare(
`
SELECT * FROM ai_facts
WHERE guild_id IS ? AND user_id IS ?
ORDER BY updated_at DESC
`,
)
.all(guildId || null, userId || null);
return state.ai_facts.filter(f => f.guild_id === (guildId || null) && f.user_id === (userId || null)).sort((a,b) => b.updated_at - a.updated_at);
},
addMessage({ guildId, channelId, userId, role, content }) {
db.prepare(
`
INSERT INTO ai_conversations (
guild_id, channel_id, user_id, role, content, created_at
) VALUES (?, ?, ?, ?, ?, ?)
`,
).run(
guildId || null,
channelId || null,
userId || null,
role,
content,
Date.now(),
);
const id = nextId(state.ai_conversations);
state.ai_conversations.push({ id, guild_id: guildId || null, channel_id: channelId || null, user_id: userId || null, role, content, created_at: Date.now() });
save(state);
},
getRecentMessages(channelId, limit = 15) {
return db
.prepare(
`
SELECT * FROM ai_conversations
WHERE channel_id = ?
ORDER BY created_at DESC
LIMIT ?
`,
)
.all(channelId, limit)
.reverse();
const msgs = state.ai_conversations.filter(m => m.channel_id === channelId).sort((a,b) => b.created_at - a.created_at).slice(0, limit).reverse();
return msgs;
},
getRecentMessagesByScope({ guildId = null, channelId = null, limit = 15, scope = "guild" }) {
if (scope === "channel") {
return db
.prepare(
`
SELECT * FROM ai_conversations
WHERE channel_id = ?
ORDER BY created_at DESC
LIMIT ?
`,
)
.all(channelId || null, limit)
.reverse();
return state.ai_conversations.filter(m => m.channel_id === (channelId || null)).sort((a,b) => b.created_at - a.created_at).slice(0, limit).reverse();
}
if (scope === "global") {
return db
.prepare(
`
SELECT * FROM ai_conversations
ORDER BY created_at DESC
LIMIT ?
`,
)
.all(limit)
.reverse();
return state.ai_conversations.sort((a,b) => b.created_at - a.created_at).slice(0, limit).reverse();
}
return db
.prepare(
`
SELECT * FROM ai_conversations
WHERE guild_id IS ?
ORDER BY created_at DESC
LIMIT ?
`,
)
.all(guildId || null, limit)
.reverse();
return state.ai_conversations.filter(m => m.guild_id === (guildId || null)).sort((a,b) => b.created_at - a.created_at).slice(0, limit).reverse();
},
saveSummary({ guildId, channelId, summary }) {
const existing = db
.prepare(
`
SELECT id FROM ai_summaries
WHERE guild_id IS ? AND channel_id IS ?
ORDER BY updated_at DESC
LIMIT 1
`,
)
.get(guildId || null, channelId || null);
const existing = state.ai_summaries.find(s => s.guild_id === (guildId || null) && s.channel_id === (channelId || null));
if (existing) {
db.prepare(
`
UPDATE ai_summaries
SET summary = ?, updated_at = ?
WHERE id = ?
`,
).run(summary, Date.now(), existing.id);
existing.summary = summary;
existing.updated_at = Date.now();
save(state);
return;
}
db.prepare(
`
INSERT INTO ai_summaries (
guild_id, channel_id, summary, created_at, updated_at
) VALUES (?, ?, ?, ?, ?)
`,
).run(guildId || null, channelId || null, summary, Date.now(), Date.now());
const id = nextId(state.ai_summaries);
state.ai_summaries.push({ id, guild_id: guildId || null, channel_id: channelId || null, summary, created_at: Date.now(), updated_at: Date.now() });
save(state);
},
getLatestSummary(channelId) {
return db
.prepare(
`
SELECT * FROM ai_summaries
WHERE channel_id = ?
ORDER BY updated_at DESC
LIMIT 1
`,
)
.get(channelId);
const arr = state.ai_summaries.filter(s => s.channel_id === channelId).sort((a,b) => b.updated_at - a.updated_at);
return arr.length ? arr[0] : null;
},
getLatestSummaryByScope({ guildId = null, channelId = null, scope = "guild" }) {
if (scope === "channel") {
return db
.prepare(
`
SELECT * FROM ai_summaries
WHERE channel_id = ?
ORDER BY updated_at DESC
LIMIT 1
`,
)
.get(channelId || null);
const arr = state.ai_summaries.filter(s => s.channel_id === (channelId || null)).sort((a,b) => b.updated_at - a.updated_at);
return arr.length ? arr[0] : null;
}
if (scope === "global") {
return db
.prepare(
`
SELECT * FROM ai_summaries
ORDER BY updated_at DESC
LIMIT 1
`,
)
.get();
const arr = state.ai_summaries.sort((a,b) => b.updated_at - a.updated_at);
return arr.length ? arr[0] : null;
}
return db
.prepare(
`
SELECT * FROM ai_summaries
WHERE guild_id IS ?
ORDER BY updated_at DESC
LIMIT 1
`,
)
.get(guildId || null);
const arr = state.ai_summaries.filter(s => s.guild_id === (guildId || null)).sort((a,b) => b.updated_at - a.updated_at);
return arr.length ? arr[0] : null;
},
saveFact({ guildId, channelId, factType, factKey, factValue }) {
const existing = db
.prepare(
`
SELECT id FROM ai_facts
WHERE guild_id IS ? AND channel_id IS ? AND fact_type = ? AND fact_key = ?
LIMIT 1
`,
)
.get(guildId || null, channelId || null, factType, factKey);
const existing = state.ai_facts.find(f => f.guild_id === (guildId || null) && f.channel_id === (channelId || null) && f.fact_type === factType && f.fact_key === factKey);
if (existing) {
db.prepare(
`
UPDATE ai_facts
SET fact_value = ?, updated_at = ?
WHERE id = ?
`,
).run(factValue, Date.now(), existing.id);
existing.fact_value = factValue;
existing.updated_at = Date.now();
save(state);
return;
}
db.prepare(
`
INSERT INTO ai_facts (
guild_id, channel_id, fact_type, fact_key, fact_value, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?)
`,
).run(
guildId || null,
channelId || null,
factType,
factKey,
factValue,
Date.now(),
Date.now(),
);
const id = nextId(state.ai_facts);
state.ai_facts.push({ id, guild_id: guildId || null, channel_id: channelId || null, user_id: null, fact_type: factType, fact_key: factKey, fact_value: factValue, created_at: Date.now(), updated_at: Date.now() });
save(state);
},
getFacts(channelId) {
return db
.prepare(
`
SELECT * FROM ai_facts
WHERE channel_id = ?
ORDER BY updated_at DESC
`,
)
.all(channelId);
return state.ai_facts.filter(f => f.channel_id === channelId).sort((a,b) => b.updated_at - a.updated_at);
},
getFactsByScope({ guildId = null, channelId = null, scope = "guild" }) {
if (scope === "channel") {
return db
.prepare(
`
SELECT * FROM ai_facts
WHERE channel_id = ? AND user_id IS NULL
ORDER BY updated_at DESC
`,
)
.all(channelId || null);
return state.ai_facts.filter(f => f.channel_id === (channelId || null) && f.user_id == null).sort((a,b) => b.updated_at - a.updated_at);
}
if (scope === "global") {
return db
.prepare(
`
SELECT * FROM ai_facts
WHERE user_id IS NULL
ORDER BY updated_at DESC
`,
)
.all();
return state.ai_facts.filter(f => f.user_id == null).sort((a,b) => b.updated_at - a.updated_at);
}
return db
.prepare(
`
SELECT * FROM ai_facts
WHERE guild_id IS ? AND user_id IS NULL
ORDER BY updated_at DESC
`,
)
.all(guildId || null);
return state.ai_facts.filter(f => f.guild_id === (guildId || null) && f.user_id == null).sort((a,b) => b.updated_at - a.updated_at);
},
addKnowledge({ sourceType, sourceName, title, content }) {
db.prepare(
`
INSERT INTO ai_knowledge (
source_type, source_name, title, content, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?)
`,
).run(sourceType, sourceName, title, content, Date.now(), Date.now());
const id = nextId(state.ai_knowledge);
state.ai_knowledge.push({ id, source_type: sourceType, source_name: sourceName, title, content, created_at: Date.now(), updated_at: Date.now() });
save(state);
},
getKnowledge(limit = 25) {
return db
.prepare(
`
SELECT * FROM ai_knowledge
ORDER BY updated_at DESC
LIMIT ?
`,
)
.all(limit);
return state.ai_knowledge.sort((a,b) => b.updated_at - a.updated_at).slice(0, limit);
},
clearKnowledge() {
db.prepare(`DELETE FROM ai_knowledge`).run();
state.ai_knowledge = [];
save(state);
},
clearConversations(channelId) {
if (!channelId) return;
db.prepare(`DELETE FROM ai_conversations WHERE channel_id = ?`).run(channelId);
state.ai_conversations = state.ai_conversations.filter(c => c.channel_id !== channelId);
save(state);
},
};
+20
View File
@@ -85,6 +85,14 @@ async function logStartup(client, options = {}) {
info("Version", botVersion);
info("Node.js", process.version);
info("Discord.js", `v${Discord.version}`);
const db = require("./Database.js");
const dbInfo = db.getDatabaseInfo ? db.getDatabaseInfo() : null;
if (dbInfo) {
const dbDisplay = dbInfo.type === "mysql"
? `${dbInfo.driver} (${dbInfo.host}:${dbInfo.port}/${dbInfo.database})`
: `${dbInfo.driver} (${dbInfo.file})`;
info("Database", dbDisplay);
}
info("Logged in as", client.user.tag);
info("Guilds", `${client.guilds.cache.size}`);
@@ -102,6 +110,16 @@ async function logStartup(client, options = {}) {
console.log("");
}
function checkSetup() {
const { isSetupComplete } = require("./DashboardSetup.js");
if (!isSetupComplete()) {
const port = configStore.api?.API?.Port || 25575;
section("Setup Required");
status("Onboarding setup incomplete", false, `http://localhost:${port}/setup`);
console.log("");
}
}
async function checkConfigs(client) {
const supportbot = configStore.supportbot;
const health = syncGuildHealth(client);
@@ -169,6 +187,8 @@ async function runBotReady(client, options = {}) {
if (logCommands) {
logSlashCommandsRegistered(client);
}
checkSetup();
}
module.exports = {
+202
View File
@@ -0,0 +1,202 @@
// SupportBot | Emerald Services
const fs = require("fs");
const path = require("path");
const { fullPermissions, normalizePermissions } = require("./DashboardPermissions.js");
const GROUPS_FILE = path.join(__dirname, "../Data/dashboard-groups.json");
const DEFAULT_GROUPS = [
{
id: "owner",
name: "Owner",
description: "Full system owner access to all features and configs",
color: "#10B981", // Emerald Green
discordRoleId: null,
isSystem: true,
permissions: fullPermissions(),
},
{
id: "admin",
name: "Admin",
description: "Full administrative access including user and group management",
color: "#3B82F6", // Blue
discordRoleId: null,
isSystem: true,
permissions: fullPermissions(false, false),
},
{
id: "support",
name: "Support Staff",
description: "Access to Overview, Live Tickets, and Transcripts",
color: "#8B5CF6", // Purple
discordRoleId: null,
isSystem: false,
permissions: {
overview: true,
tickets: true,
logs: false,
transcripts: true,
settings: { view: false, update: false },
configs: {
supportbot: { view: false, edit: false },
"ticket-panel": { view: false, edit: false },
commands: { view: false, edit: false },
messages: { view: false, edit: false },
"supportbot-ai": { view: false, edit: false },
api: { view: false, edit: false },
},
users: { view: false, manage: false },
},
},
{
id: "viewer",
name: "Viewer",
description: "Read-only access to dashboard and logs",
color: "#6B7280", // Gray
discordRoleId: null,
isSystem: false,
permissions: {
overview: true,
tickets: true,
logs: true,
transcripts: true,
settings: { view: true, update: false },
configs: {
supportbot: { view: true, edit: false },
"ticket-panel": { view: true, edit: false },
commands: { view: true, edit: false },
messages: { view: true, edit: false },
"supportbot-ai": { view: true, edit: false },
api: { view: true, edit: false },
},
users: { view: false, manage: false },
},
},
];
function ensureStorage() {
const dir = path.dirname(GROUPS_FILE);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
if (!fs.existsSync(GROUPS_FILE)) {
const initialData = {
version: 1,
groups: DEFAULT_GROUPS,
};
fs.writeFileSync(GROUPS_FILE, JSON.stringify(initialData, null, 2), "utf8");
}
}
function loadStore() {
ensureStorage();
try {
const raw = fs.readFileSync(GROUPS_FILE, "utf8");
const parsed = JSON.parse(raw);
if (parsed && Array.isArray(parsed.groups)) {
return parsed.groups;
}
} catch (err) {
console.error("[GroupStore] Error loading groups file:", err.message);
}
return DEFAULT_GROUPS;
}
function saveStore(groups) {
ensureStorage();
const payload = {
version: 1,
groups,
updatedAt: Date.now(),
};
fs.writeFileSync(GROUPS_FILE, JSON.stringify(payload, null, 2), "utf8");
}
function listGroups() {
return loadStore();
}
function getGroup(id) {
const groups = loadStore();
return groups.find((g) => g.id === id) || null;
}
function createGroup(payload = {}) {
const groups = loadStore();
const name = (payload.name || "New Group").trim();
const slug = name.toLowerCase().replace(/[^a-z0-9_-]+/g, "_");
let newId = slug || `group_${Date.now()}`;
let counter = 1;
while (groups.some((g) => g.id === newId)) {
newId = `${slug}_${counter++}`;
}
const newGroup = {
id: newId,
name,
description: (payload.description || "").trim(),
color: payload.color || "#10B981",
discordRoleId: payload.discordRoleId ? String(payload.discordRoleId).trim() : null,
isSystem: false,
permissions: normalizePermissions(payload.permissions),
createdAt: Date.now(),
updatedAt: Date.now(),
};
groups.push(newGroup);
saveStore(groups);
return newGroup;
}
function updateGroup(id, payload = {}) {
if (id === "owner") {
throw new Error('System group "Owner" cannot be modified.');
}
const groups = loadStore();
const index = groups.findIndex((g) => g.id === id);
if (index === -1) {
throw new Error(`Group with ID "${id}" not found.`);
}
const existing = groups[index];
const updatedGroup = {
...existing,
name: payload.name !== undefined ? payload.name.trim() : existing.name,
description: payload.description !== undefined ? payload.description.trim() : existing.description,
color: payload.color || existing.color,
discordRoleId: payload.discordRoleId !== undefined ? (payload.discordRoleId ? String(payload.discordRoleId).trim() : null) : existing.discordRoleId,
permissions: payload.permissions ? normalizePermissions(payload.permissions) : existing.permissions,
updatedAt: Date.now(),
};
groups[index] = updatedGroup;
saveStore(groups);
return updatedGroup;
}
function deleteGroup(id) {
const groups = loadStore();
const group = groups.find((g) => g.id === id);
if (!group) {
throw new Error(`Group with ID "${id}" not found.`);
}
if (group.isSystem) {
throw new Error(`System group "${group.name}" cannot be deleted.`);
}
const filtered = groups.filter((g) => g.id !== id);
saveStore(filtered);
return true;
}
module.exports = {
listGroups,
getGroup,
createGroup,
updateGroup,
deleteGroup,
DEFAULT_GROUPS,
};
+18 -3
View File
@@ -17,27 +17,32 @@ function configMap(view, edit) {
return configs;
}
function fullPermissions() {
function fullPermissions(rawYaml = true, userManage = true) {
return {
overview: true,
tickets: true,
logs: true,
transcripts: true,
rawYaml: Boolean(rawYaml),
settings: { view: true, update: true },
configs: configMap(true, true),
users: { view: true, manage: true },
users: { view: true, manage: Boolean(userManage) },
};
}
function permissionsFromRole(role, customPermissions) {
switch (role) {
case "owner":
return fullPermissions(true, true);
case "admin":
return fullPermissions();
return fullPermissions(false, false);
case "moderator":
return {
overview: true,
tickets: true,
logs: true,
transcripts: true,
rawYaml: false,
settings: { view: true, update: false },
configs: configMap(true, false),
users: { view: false, manage: false },
@@ -45,8 +50,10 @@ function permissionsFromRole(role, customPermissions) {
case "editor":
return {
overview: true,
tickets: true,
logs: true,
transcripts: false,
rawYaml: false,
settings: { view: true, update: false },
configs: configMap(true, true),
users: { view: false, manage: false },
@@ -54,8 +61,10 @@ function permissionsFromRole(role, customPermissions) {
case "viewer":
return {
overview: true,
tickets: true,
logs: true,
transcripts: true,
rawYaml: false,
settings: { view: true, update: false },
configs: configMap(true, false),
users: { view: false, manage: false },
@@ -73,8 +82,10 @@ function normalizePermissions(input) {
return {
overview: input.overview ?? base.overview,
tickets: input.tickets ?? input.overview ?? base.tickets,
logs: input.logs ?? base.logs,
transcripts: input.transcripts ?? base.transcripts,
rawYaml: Boolean(input.rawYaml ?? input.configs?.rawYaml ?? base.rawYaml),
settings: {
view: input.settings?.view ?? base.settings.view,
update: input.settings?.update ?? base.settings.update,
@@ -97,8 +108,12 @@ function hasPermission(permissions, check) {
if (!permissions) return false;
if (check === "overview") return Boolean(permissions.overview);
if (check === "tickets") return Boolean(permissions.tickets ?? permissions.overview);
if (check === "logs") return Boolean(permissions.logs);
if (check === "transcripts") return Boolean(permissions.transcripts);
if (check === "configs.raw_yaml" || check === "configs.rawYaml" || check === "rawYaml") {
return Boolean(permissions.rawYaml ?? permissions.configs?.rawYaml ?? false);
}
if (check === "settings.view") return Boolean(permissions.settings?.view);
if (check === "settings.update") return Boolean(permissions.settings?.update);
if (check === "users.view") return Boolean(permissions.users?.view);
+71 -1
View File
@@ -84,6 +84,7 @@ function getOwnerIds(oauth) {
function buildSteps(apiRoot, supportbot) {
const oauth = apiRoot?.OAuth || {};
const token = supportbot?.General?.Token;
const dbConfig = supportbot?.Database || {};
return [
{
@@ -92,6 +93,12 @@ function buildSteps(apiRoot, supportbot) {
description: "From the Discord Developer Portal → your application → Bot → Reset Token.",
complete: isValidBotToken(token),
},
{
id: "database",
title: "Database storage",
description: "Choose SQLite or MySQL database engine for storing bot data.",
complete: Boolean(dbConfig.Driver),
},
{
id: "secretKey",
title: "Dashboard session secret",
@@ -334,12 +341,58 @@ function validateSecretKey(secretKey) {
return { ok: true };
}
async function validateDatabase(dbDriver, dbHost, dbPort, dbUser, dbPassword, dbDatabase) {
const driver = String(dbDriver || "sqlite").toLowerCase();
if (driver === "mysql" || driver === "mariadb") {
const host = String(dbHost || "").trim();
const port = Number(dbPort) || 3306;
const user = String(dbUser || "").trim();
const password = String(dbPassword || "");
const database = String(dbDatabase || "").trim();
if (isEmpty(host)) return { ok: false, error: "MySQL Host is required." };
if (isEmpty(user)) return { ok: false, error: "MySQL User is required." };
if (isEmpty(database)) return { ok: false, error: "MySQL Database Name is required." };
try {
const mysql = require("mysql2/promise");
const connection = await mysql.createConnection({
host,
port,
user,
password,
database,
connectTimeout: 5000,
});
await connection.end();
return { ok: true, driver: "mysql" };
} catch (err) {
return {
ok: false,
error: `MySQL Connection Failed: ${err.message || err.code || "Could not connect to database host."}`,
};
}
}
return { ok: true, driver: "sqlite" };
}
async function validateSetupPayload(payload) {
const results = {};
if (payload.botToken != null) {
results.botToken = await validateBotToken(payload.botToken);
}
if (payload.dbDriver != null) {
results.database = await validateDatabase(
payload.dbDriver,
payload.dbHost,
payload.dbPort,
payload.dbUser,
payload.dbPassword,
payload.dbDatabase,
);
}
if (payload.secretKey != null) {
results.secretKey = validateSecretKey(payload.secretKey);
}
@@ -415,7 +468,24 @@ function applySetup(payload) {
fs.writeFileSync(API_FILE, apiDoc.toString());
const sbDoc = YAML.parseDocument(fs.readFileSync(SUPPORTBOT_FILE, "utf8"));
sbDoc.setIn(["General", "Token"], String(payload.botToken).trim());
if (payload.botToken != null && String(payload.botToken).trim() !== "") {
sbDoc.setIn(["General", "Token"], String(payload.botToken).trim());
}
if (payload.dbDriver != null) {
const driver = String(payload.dbDriver).toLowerCase() === "mysql" ? "mysql" : "sqlite";
sbDoc.setIn(["Database", "Driver"], driver);
if (driver === "mysql") {
sbDoc.setIn(["Database", "MySQL", "Host"], String(payload.dbHost || "127.0.0.1").trim());
sbDoc.setIn(["Database", "MySQL", "Port"], Number(payload.dbPort) || 3306);
sbDoc.setIn(["Database", "MySQL", "User"], String(payload.dbUser || "").trim());
sbDoc.setIn(["Database", "MySQL", "Password"], String(payload.dbPassword || ""));
sbDoc.setIn(["Database", "MySQL", "Database"], String(payload.dbDatabase || "").trim());
} else {
sbDoc.setIn(["Database", "SQLite", "File"], "./Data/supportbot.db");
}
}
fs.writeFileSync(SUPPORTBOT_FILE, sbDoc.toString());
configStore.reloadFile("api");
+44 -24
View File
@@ -89,19 +89,23 @@ function syncDiscordProfile(userId, profile) {
writeStore(store);
}
const { getGroup } = require("./DashboardGroupStore.js");
function resolvePermissions(entry, oauth, userId) {
if (isYamlOwner(userId, oauth)) {
return { permissions: fullPermissions(), role: "owner", isOwner: true };
return { permissions: fullPermissions(), role: "owner", isOwner: true, groupId: "owner" };
}
if (!entry?.enabled) return null;
const role = entry.role || "viewer";
const permissions =
role === "custom"
? permissionsFromRole("custom", entry.permissions)
: permissionsFromRole(role);
const groupId = entry.groupId || entry.role || "support";
const group = getGroup(groupId);
return { permissions, role, isOwner: false };
if (entry.role === "custom" && entry.permissions) {
return { permissions: normalizePermissions(entry.permissions), role: "custom", isOwner: false, groupId };
}
const permissions = group ? group.permissions : permissionsFromRole(entry.role || "viewer");
return { permissions, role: entry.role || groupId, isOwner: false, groupId };
}
function getAccess(userId, oauth) {
@@ -156,12 +160,24 @@ function formatPublicUser(entry, access, discordProfile) {
};
}
function listUsers(oauth) {
function listUsers(oauth, discordClient) {
bootstrapFromOAuth(oauth);
const store = readStore();
const yamlOwners = getOwnerIds(oauth);
return Object.values(store.users).map((entry) => {
let updated = false;
const usersList = Object.values(store.users).map((entry) => {
if (discordClient?.users?.cache) {
const cached = discordClient.users.cache.get(String(entry.id));
if (cached && (!entry.username || !entry.avatar)) {
entry.username = cached.username || entry.username;
entry.globalName = cached.globalName || cached.username || entry.globalName;
entry.avatar = cached.avatar || entry.avatar;
updated = true;
}
}
const access = resolvePermissions(entry, oauth, entry.id) || {
permissions: permissionsFromRole("viewer"),
role: entry.role,
@@ -170,12 +186,13 @@ function listUsers(oauth) {
return {
id: entry.id,
username: entry.username,
globalName: entry.globalName,
username: entry.username || (yamlOwners.has(String(entry.id)) ? "Owner" : "User"),
globalName: entry.globalName || entry.username || null,
avatar: entry.avatar
? discordAvatarUrl({ id: entry.id, avatar: entry.avatar })
: discordAvatarUrl({ id: entry.id, avatar: null }),
role: yamlOwners.has(String(entry.id)) ? "owner" : entry.role,
role: yamlOwners.has(String(entry.id)) ? "owner" : entry.role || entry.groupId || "support",
groupId: entry.groupId || entry.role || "support",
permissions:
entry.role === "custom"
? normalizePermissions(entry.permissions)
@@ -187,6 +204,12 @@ function listUsers(oauth) {
updatedAt: entry.updatedAt,
};
});
if (updated) {
writeStore(store);
}
return usersList;
}
function addUser(payload, actorId, oauth) {
@@ -195,11 +218,8 @@ function addUser(payload, actorId, oauth) {
throw new Error("Invalid Discord user ID");
}
const role = payload.role || "viewer";
if (!ROLES.includes(role)) throw new Error("Invalid role");
if (role === "owner" && !isYamlOwner(actorId, oauth)) {
throw new Error("Only api.yml owners can assign the owner role");
}
const role = payload.role || payload.groupId || "support";
const groupId = payload.groupId || payload.role || "support";
const store = readStore();
if (store.users[id]) throw new Error("User already exists");
@@ -210,6 +230,7 @@ function addUser(payload, actorId, oauth) {
globalName: payload.globalName || null,
avatar: null,
role,
groupId,
permissions:
role === "custom" ? normalizePermissions(payload.permissions) : null,
enabled: payload.enabled !== false,
@@ -231,15 +252,14 @@ function updateUser(id, payload, actorId, oauth) {
throw new Error("Cannot disable an owner defined in api.yml");
}
if (payload.groupId) {
entry.groupId = payload.groupId;
if (!payload.role) entry.role = payload.groupId;
}
if (payload.role) {
if (!ROLES.includes(payload.role)) throw new Error("Invalid role");
if (payload.role === "owner" && !isYamlOwner(actorId, oauth)) {
throw new Error("Only api.yml owners can assign the owner role");
}
if (isYamlOwner(id, oauth) && payload.role !== "owner") {
throw new Error("Cannot change role of an api.yml owner");
}
entry.role = payload.role;
if (!payload.groupId) entry.groupId = payload.role;
}
if (payload.enabled !== undefined) entry.enabled = Boolean(payload.enabled);
+1013 -363
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -180,6 +180,7 @@ function buildResourcesFromGuild(guild) {
return {
guildId: guild.id,
guildName: guild.name,
guildIcon: guild.iconURL({ extension: "png", size: 64 }) || null,
roles,
channels,
categories,
+28 -12
View File
@@ -1,30 +1,46 @@
// SupportBot | Emerald Services
// Ticket ID Structure
const db = require("./Database")
const db = require("./Database");
class TicketNumberID {
static async pad() {
let num = await this.get()
let n = num + ""
await this.set(num + 1)
return n.length >= 4 ? n : new Array(4 - n.length + 1).join("0") + n
let num = await this.get();
let n = num + "";
await this.set(num + 1);
return n.length >= 4 ? n : new Array(4 - n.length + 1).join("0") + n;
}
static async get() {
const row = db.getTicketPanel()
if (!row) return await this.set(0)
return row.id
const settings = db.getSettings ? db.getSettings() : {};
if (typeof settings.ticket_counter === "number") {
return settings.ticket_counter;
}
const row = db.getTicketPanel ? db.getTicketPanel() : null;
if (row && typeof row.message_id === "string" && row.message_id.startsWith("panel-")) {
const parsed = parseInt(row.message_id.replace("panel-", ""), 10);
if (!isNaN(parsed)) return parsed;
}
if (row && typeof row.id === "number" && row.id < 1000000) {
return row.id;
}
return 0;
}
static async set(value) {
db.saveTicketPanel(`panel-${value}`, "none")
return value
const settings = db.getSettings ? db.getSettings() : {};
settings.ticket_counter = value;
if (db.saveSettings) db.saveSettings(settings);
if (db.saveTicketPanel) db.saveTicketPanel(`panel-${value}`, "none");
return value;
}
static async reset() {
return await this.set(0)
return await this.set(0);
}
}
module.exports = TicketNumberID
module.exports = TicketNumberID;
+53 -10
View File
@@ -1,4 +1,4 @@
const fs = require("fs");
const fs = require("fs");
const path = require("path");
const Discord = require("discord.js");
const yaml = require("js-yaml");
@@ -135,7 +135,14 @@ function renderEmbeds(embeds = []) {
.join("");
}
async function createTranscript(interaction, ticket, reason) {
async function createTranscript(interaction, ticketInput, reasonInput) {
let ticketRecord = typeof ticketInput === "object" && ticketInput !== null ? ticketInput : null;
let closeReason = typeof ticketInput === "string" ? ticketInput : reasonInput;
if (!ticketRecord && typeof db.getTicket === "function") {
ticketRecord = db.getTicket(interaction.channel.id) || {};
}
const { getChannel } = interaction.client;
const transcriptChannel = await getChannel(
@@ -188,12 +195,27 @@ async function createTranscript(interaction, ticket, reason) {
db.updateTicketStatus(interaction.channel.id, "closed");
}
const ticketUserId = ticket.user_id || ticket.user;
let ticketUserId = ticketRecord?.user_id || ticketRecord?.user || ticketRecord?.author_id;
if (!ticketUserId && interaction.channel.permissionOverwrites) {
const memberOverwrite = interaction.channel.permissionOverwrites.cache.find(
(pow) => pow.type === 1 && pow.id !== interaction.client.user.id
);
if (memberOverwrite) {
ticketUserId = memberOverwrite.id;
}
}
if (!ticketUserId && allMessages.length > 0) {
const firstNonBotMsg = allMessages.find((m) => !m.author.bot);
if (firstNonBotMsg) {
ticketUserId = firstNonBotMsg.author.id;
}
}
const tUser =
interaction.client.users.cache.get(ticketUserId) ||
(ticketUserId
? await interaction.client.users.fetch(ticketUserId).catch(() => null)
: null);
(ticketUserId ? interaction.client.users.cache.get(ticketUserId) : null) ||
(ticketUserId ? await interaction.client.users.fetch(ticketUserId).catch(() => null) : null);
const transcriptEmbed = new Discord.EmbedBuilder()
.setTitle(msgconfig.TicketLog.Title)
@@ -204,16 +226,37 @@ async function createTranscript(interaction, ticket, reason) {
})
.setDescription(
`> **Ticket:** ${interaction.channel.name} (\`${interaction.channel.id}\`)\n` +
`> **User:** ${tUser?.tag || "Unknown User"} (\`${tUser?.id || ticketUserId || "Unknown"}\`)\n` +
`> **User:** ${tUser ? `<@${tUser.id}> (\`${tUser.tag}\`)` : "Unknown User"}\n` +
`> **Closed by:** <@${interaction.user.id}>\n` +
`> **Message Count:** ${transcriptData.length}`,
)
.addFields({
name: "Reason",
value: `\`\`\`${reason || "No Reason Provided."}\`\`\``,
value: `\`\`\`${closeReason || "No Reason Provided."}\`\`\``,
inline: false,
});
try {
const configStore = require("./ConfigStore");
const transcriptStore = require("./TranscriptStore");
const apiConfig = configStore.api?.API;
const tSettings = transcriptStore.getSettings();
if (apiConfig?.Enabled !== false) {
const port = apiConfig?.Port || 3000;
const isPublic = Boolean(tSettings?.publicAccess?.enabled);
const transcriptUrl = `http://localhost:${port}/transcripts/${interaction.channel.id}`;
transcriptEmbed.addFields({
name: isPublic ? "Public Web Transcript" : "Dashboard Transcript",
value: `[${isPublic ? "Click here to view public transcript" : "Click here to view in Dashboard"}](${transcriptUrl})`,
inline: false,
});
}
} catch (err) {
console.warn("[TicketManager] Could not add web transcript URL:", err.message);
}
const transcriptDir = path.join(process.cwd(), "./Data/Transcripts");
if (!fs.existsSync(transcriptDir)) {
fs.mkdirSync(transcriptDir, { recursive: true });
@@ -228,7 +271,7 @@ async function createTranscript(interaction, ticket, reason) {
name: interaction.channel.name,
messages: transcriptData,
},
reason,
closeReason,
);
fs.writeFileSync(htmlPath, html, "utf8");
+49 -8
View File
@@ -23,9 +23,14 @@ function parseMarkdown(content = "") {
safe = safe.replace(/```([\s\S]*?)```/g, "<pre><code>$1</code></pre>");
safe = safe.replace(/`(.*?)`/g, "<code>$1</code>");
safe = safe.replace(/\|\|(.*?)\|\|/g, '<span class="spoiler">$1</span>');
safe = safe.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
safe = safe.replace(/\*(.*?)\*/g, "<em>$1</em>");
safe = safe.replace(/_(.*?)_/g, "<em>$1</em>");
safe = safe.replace(/~~(.*?)~~/g, "<del>$1</del>");
safe = safe.replace(/__(.*?)__/g, "<u>$1</u>");
safe = safe.replace(/&lt;@!?(\d+)&gt;/g, '<span class="mention">@User</span>');
safe = safe.replace(/&lt;@&amp;(\d+)&gt;/g, '<span class="mention">@Role</span>');
safe = safe.replace(
/\[(.*?)\]\((.*?)\)/g,
'<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>',
@@ -112,10 +117,11 @@ function renderAttachment(att) {
function renderEmbeds(embeds = []) {
return embeds
.map((embed) => {
const color = embed.color || "#5865F2";
const fields = (embed.fields || [])
.map(
(field) => `
<div class="embed-field">
<div class="embed-field ${field.inline ? 'inline-field' : ''}">
<div class="embed-field-name">${escapeHtml(field.name || "Field")}</div>
<div class="embed-field-value">${parseMarkdown(field.value || "")}</div>
</div>
@@ -123,11 +129,37 @@ function renderEmbeds(embeds = []) {
)
.join("");
const author = embed.author ? `
<div class="embed-author">
${embed.author.iconURL ? `<img src="${escapeHtml(embed.author.iconURL)}" class="embed-author-icon" />` : ''}
<span>${escapeHtml(embed.author.name || '')}</span>
</div>
` : '';
const thumbnail = embed.thumbnail?.url ? `
<img src="${escapeHtml(embed.thumbnail.url)}" class="embed-thumbnail" />
` : '';
const image = embed.image?.url ? `
<div class="embed-image"><img src="${escapeHtml(embed.image.url)}" /></div>
` : '';
const footer = (embed.footer || embed.timestamp) ? `
<div class="embed-footer">
${embed.footer?.iconURL ? `<img src="${escapeHtml(embed.footer.iconURL)}" class="embed-footer-icon" />` : ''}
${embed.footer?.text ? `<span>${escapeHtml(embed.footer.text)}</span>` : ''}
</div>
` : '';
return `
<div class="discord-embed">
${embed.title ? `<div class="discord-embed-title">${escapeHtml(embed.title)}</div>` : ""}
<div class="discord-embed" style="border-left-color: ${escapeHtml(color)}; border-left-width: 4px; border-left-style: solid; position: relative;">
${author}
${thumbnail}
${embed.title ? `<div class="discord-embed-title">${parseMarkdown(embed.title)}</div>` : ""}
${embed.description ? `<div class="discord-embed-description">${parseMarkdown(embed.description)}</div>` : ""}
${fields}
${fields ? `<div class="embed-fields-grid">${fields}</div>` : ""}
${image}
${footer}
</div>
`;
})
@@ -451,13 +483,22 @@ function buildStyles(template) {
.discord-embed-title { font-weight: 800; margin-bottom: 6px; }
.discord-embed-description { color: var(--text); line-height: 1.5; }
.embed-author { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 0.9em; margin-bottom: 6px; }
.embed-author-icon { width: 18px; height: 18px; border-radius: 50%; }
.embed-fields-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.06); }
.embed-thumbnail { position: absolute; top: 12px; right: 12px; width: 44px; height: 44px; border-radius: 6px; object-fit: cover; }
.embed-image img { width: 100%; max-height: 300px; object-fit: cover; border-radius: 8px; margin-top: 10px; }
.embed-footer { display: flex; align-items: center; gap: 6px; font-size: 0.8em; color: var(--muted); margin-top: 8px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,0.04); }
.embed-footer-icon { width: 14px; height: 14px; border-radius: 50%; }
.mention { background: rgba(88, 101, 242, 0.2); color: #5865F2; padding: 2px 6px; border-radius: 4px; font-weight: 600; font-size: 0.9em; }
.spoiler { background: #202225; color: transparent; border-radius: 4px; padding: 0 4px; cursor: pointer; }
.spoiler:hover { color: inherit; background: rgba(255,255,255,0.1); }
.embed-field {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid rgba(255,255,255,0.06);
margin-top: 6px;
}
.embed-field-name { font-weight: 700; margin-bottom: 4px; }
.embed-field-name { font-weight: 700; margin-bottom: 4px; font-size: 0.85em; text-transform: uppercase; color: var(--muted); }
.embed-field-value { color: var(--text); line-height: 1.5; }
.attachment {
+22 -10
View File
@@ -20,27 +20,30 @@ const client = new Client({
intents: ["Guilds", "GuildMembers", "GuildMessages", "MessageContent"],
});
const { isSetupComplete } = require("./Structures/DashboardSetup.js");
const APIServer = require("./API/server.js");
// Start dashboard API immediately — do not wait for Discord clientReady
const api = new APIServer(client);
client.apiServer = api;
const port = api.config?.Port || 25575;
if (api.config?.Enabled) {
const port = api.config.Port || 3000;
api.start(port);
console.log(
`[Dashboard] API listening on http://localhost:${port} (bot may still be connecting)`,
);
if (!isSetupComplete()) {
console.log(`\n\x1b[33m\x1b[1m[Setup Required] Go to http://localhost:${port}/setup to set up your bot and dashboard.\x1b[0m\n`);
}
} else {
console.warn("[Dashboard] API disabled in Configs/api.yml");
}
client.start(configStore.supportbot.General.Token);
const token = configStore.supportbot?.General?.Token;
const isPlaceholderToken = !token || token.includes("BOT_TOKEN") || token.includes("CHANGE_ME") || token.length < 30;
client.on("clientReady", () => {
console.log("[Dashboard] Discord bot is ready — full stats and guild tools are available");
});
if (isPlaceholderToken) {
console.warn(`\x1b[33m[SupportBot] Bot token is not configured yet. Complete setup at http://localhost:${port}/setup\x1b[0m`);
} else {
client.start(token);
}
// SupportBot - New Logging System
@@ -59,7 +62,16 @@ logTypes.forEach((type) => {
function logToFile(type, data) {
const date = new Date().toISOString().split("T")[0];
const file = path.join(`./Logs/${type}`, `${type}-${date}.log`);
fs.appendFileSync(file, `[${new Date().toISOString()}] ${data}\n`);
const timestamp = new Date().toISOString();
fs.appendFileSync(file, `[${timestamp}] ${data}\n`);
if (global.apiServer) {
global.apiServer.broadcast("log", {
type,
timestamp,
message: String(data)
});
}
}
const origLog = console.log;
+263 -127
View File
@@ -1,12 +1,12 @@
{
"name": "supportbot",
"version": "26.3.0",
"version": "26.2-pre-2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "supportbot",
"version": "26.3.0",
"version": "26.2-pre-2",
"license": "MIT",
"dependencies": {
"@vitalets/google-translate-api": "^9.2.1",
@@ -24,6 +24,7 @@
"js-yaml": "^4.1.0",
"moment": "^2.29.3",
"ms": "^2.1.3",
"mysql2": "^3.23.3",
"openai": "^4.50.0",
"systeminformation": "^5.31.5",
"yaml": "^2.8.3"
@@ -75,9 +76,9 @@
}
},
"node_modules/@discordjs/rest": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.6.1.tgz",
"integrity": "sha512-wwQdgjeaoYFiaG+atbqx6aJDpqW7JHAo0HrQkBTbYzM3/PJ3GweQIpgElNcGZ26DCUOXMyawYd0YF7vtr+fZXg==",
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.6.3.tgz",
"integrity": "sha512-wvOylxNYJkwKjctS/Mn5GP1w9r3/rzyH+ThD1JlAca6zEdlHs8QWBBUQJpU5Q+W6DoIj/Ljh1IPlZs7hTU+UAg==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/collection": "^2.1.1",
@@ -85,10 +86,10 @@
"@sapphire/async-queue": "^1.5.3",
"@sapphire/snowflake": "^3.5.5",
"@vladfrangu/async_event_emitter": "^2.4.6",
"discord-api-types": "^0.38.40",
"discord-api-types": "^0.38.50",
"magic-bytes.js": "^1.13.0",
"tslib": "^2.6.3",
"undici": "6.24.1"
"undici": "^6.27.0"
},
"engines": {
"node": ">=18"
@@ -109,16 +110,6 @@
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/rest/node_modules/@sapphire/snowflake": {
"version": "3.5.5",
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.5.tgz",
"integrity": "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@discordjs/util": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.2.0.tgz",
@@ -193,9 +184,9 @@
}
},
"node_modules/@sapphire/snowflake": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.3.tgz",
"integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==",
"version": "3.5.5",
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.5.tgz",
"integrity": "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
@@ -209,12 +200,12 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "25.8.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz",
"integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==",
"version": "26.4.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.0.tgz",
"integrity": "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==",
"license": "MIT",
"dependencies": {
"undici-types": ">=7.24.0 <7.24.7"
"undici-types": "~8.3.0"
}
},
"node_modules/@types/node-fetch": {
@@ -336,14 +327,23 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/aws-ssl-profiles": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
"license": "MIT",
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/axios": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz",
"integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==",
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz",
"integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.16.0",
"form-data": "^4.0.5",
"form-data": "^4.0.6",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^2.1.0"
}
@@ -369,9 +369,9 @@
"license": "MIT"
},
"node_modules/better-sqlite3": {
"version": "12.10.0",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.10.0.tgz",
"integrity": "sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==",
"version": "12.11.1",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.11.1.tgz",
"integrity": "sha512-dq9AtApgg5PGFtBzPFSBl3HZQjHok5gaQCM6zh2Yk0aSmDCs1CbnVI8/HgASQkNKsWFpseIO9beg5xxpYhbIfA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -403,20 +403,20 @@
}
},
"node_modules/body-parser": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
"integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz",
"integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==",
"license": "MIT",
"dependencies": {
"bytes": "^3.1.2",
"content-type": "^1.0.5",
"content-type": "^2.0.0",
"debug": "^4.4.3",
"http-errors": "^2.0.0",
"iconv-lite": "^0.7.0",
"http-errors": "^2.0.1",
"iconv-lite": "^0.7.2",
"on-finished": "^2.4.1",
"qs": "^6.14.1",
"raw-body": "^3.0.1",
"type-is": "^2.0.1"
"qs": "^6.15.2",
"raw-body": "^3.0.2",
"type-is": "^2.1.0"
},
"engines": {
"node": ">=18"
@@ -426,6 +426,19 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/body-parser/node_modules/content-type": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
"integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -603,21 +616,12 @@
"node": ">= 0.8.0"
}
},
"node_modules/cookie-parser/node_modules/cookie-signature": {
"node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
"node_modules/cookie-signature": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
"license": "MIT",
"engines": {
"node": ">=6.6.0"
}
},
"node_modules/cors": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
@@ -716,33 +720,33 @@
}
},
"node_modules/discord-api-types": {
"version": "0.38.47",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.47.tgz",
"integrity": "sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA==",
"version": "0.38.54",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.54.tgz",
"integrity": "sha512-3704EKdPtVl0Mozoe6uBJQ8GNmUkH8c81nfXkdSBx+Um8GN3FI/003uTY0Pg0A4KjL8g2Q+4v5cHR247kv6vwA==",
"license": "MIT",
"workspaces": [
"scripts/actions/documentation"
]
},
"node_modules/discord.js": {
"version": "14.26.4",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.26.4.tgz",
"integrity": "sha512-4oBp8tc6Kf8IDBwAHhbsMaAqx1b5fob9SNasZT7V6yyyUydoO5i5fGuX7TmvRtR+q/WgKRnRViRoAWnG7fNyvA==",
"version": "14.27.0",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.27.0.tgz",
"integrity": "sha512-qHbFlFG2N7y3LjPySYsL6A1+BnX6bkTVgo842EX0CqVPk/KTMwZkojPHEXKsQUpWZNyz5BISNHK1cPpQw0+m4A==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/builders": "^1.14.1",
"@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.6.2",
"@discordjs/rest": "^2.6.1",
"@discordjs/rest": "^2.6.2",
"@discordjs/util": "^1.2.0",
"@discordjs/ws": "^1.2.3",
"@sapphire/snowflake": "3.5.3",
"discord-api-types": "^0.38.40",
"@sapphire/snowflake": "3.5.5",
"discord-api-types": "^0.38.49",
"fast-deep-equal": "3.1.3",
"lodash.snakecase": "4.1.1",
"magic-bytes.js": "^1.13.0",
"tslib": "^2.6.3",
"undici": "6.24.1"
"undici": "^6.27.0"
},
"engines": {
"node": ">=18"
@@ -826,9 +830,9 @@
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
"integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@@ -928,6 +932,15 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/express/node_modules/cookie-signature": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
"license": "MIT",
"engines": {
"node": ">=6.6.0"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -935,9 +948,9 @@
"license": "MIT"
},
"node_modules/figlet": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/figlet/-/figlet-1.11.0.tgz",
"integrity": "sha512-EEx3OS/l2bFqcUNN2NM9FPJp8vAMrgbCxsbl2hbcJNNxOEwVe3mEzrhan7TbJQViZa8mMqhihlbCaqD+LyYKTQ==",
"version": "1.11.4",
"resolved": "https://registry.npmjs.org/figlet/-/figlet-1.11.4.tgz",
"integrity": "sha512-ZU41480OncL+NVLQrT0GVnbO0COL24sLSrzksioDgunmdJNYEUxhJJZ4Y3x1csN8XXqN5OcCZTLG8lKdquNyfQ==",
"license": "MIT",
"dependencies": {
"commander": "^14.0.0"
@@ -997,16 +1010,16 @@
}
},
"node_modules/form-data": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
"integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
"hasown": "^2.0.4",
"mime-types": "^2.1.35"
},
"engines": {
"node": ">= 6"
@@ -1085,6 +1098,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/generate-function": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
"license": "MIT",
"dependencies": {
"is-property": "^1.0.2"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -1240,9 +1262,9 @@
}
},
"node_modules/hasown": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
"integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -1294,9 +1316,9 @@
}
},
"node_modules/iconv-lite": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
"integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -1374,6 +1396,12 @@
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
"license": "MIT"
},
"node_modules/is-redirect": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
@@ -1413,9 +1441,19 @@
}
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
"integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@@ -1453,6 +1491,12 @@
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==",
"license": "MIT"
},
"node_modules/long": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
"license": "Apache-2.0"
},
"node_modules/lowercase-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@@ -1462,10 +1506,25 @@
"node": ">=0.10.0"
}
},
"node_modules/lru.min": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz",
"integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==",
"license": "MIT",
"engines": {
"bun": ">=1.0.0",
"deno": ">=1.30.0",
"node": ">=8.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wellwelwel"
}
},
"node_modules/magic-bytes.js": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.13.0.tgz",
"integrity": "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==",
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.13.1.tgz",
"integrity": "sha512-x5sn4UX2k5gCWlcfmoFwG4TPie8+dctESyqOBdhB5p6MsgWXdBKGmt9nXPObj/JI50TTL928lc5Yt1WntMn1bw==",
"license": "MIT"
},
"node_modules/math-intrinsics": {
@@ -1478,12 +1537,16 @@
}
},
"node_modules/media-typer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz",
"integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/merge-descriptors": {
@@ -1577,6 +1640,39 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/mysql2": {
"version": "3.24.2",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.24.2.tgz",
"integrity": "sha512-l9kXeKGwd6VCbSjmpO/bLWb+YCYpbvE4whte8ec6InXebvCNyEEydyRCnRU+TSHNqRLJ8B+Tk1uWb+vMCJgJzA==",
"license": "MIT",
"dependencies": {
"aws-ssl-profiles": "^1.1.2",
"generate-function": "^2.3.1",
"iconv-lite": "^0.7.3",
"long": "^5.3.2",
"lru.min": "^1.1.4",
"named-placeholders": "^1.1.6",
"sql-escaper": "^1.5.1"
},
"engines": {
"node": ">= 8.0"
},
"peerDependencies": {
"@types/node": ">= 8"
}
},
"node_modules/named-placeholders": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz",
"integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==",
"license": "MIT",
"dependencies": {
"lru.min": "^1.1.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/napi-build-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
@@ -1584,18 +1680,38 @@
"license": "MIT"
},
"node_modules/negotiator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz",
"integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==",
"license": "MIT",
"dependencies": {
"content-type": "^2.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/negotiator/node_modules/content-type": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
"integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/node-abi": {
"version": "3.92.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz",
"integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==",
"version": "3.95.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.95.0.tgz",
"integrity": "sha512-T9iGctuocf0qIWFFOTxPzjT5q0SILqaBYXt272tlBHvTKC5+3JnkMirLxNJNkXHtFyBjU2Jx+NL4Zipr0B/c6Q==",
"license": "MIT",
"dependencies": {
"semver": "^7.3.5"
@@ -1848,12 +1964,13 @@
}
},
"node_modules/qs": {
"version": "6.15.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
"integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
"version": "6.15.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz",
"integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
"es-define-property": "^1.0.1",
"side-channel": "^1.1.1"
},
"engines": {
"node": ">=0.6"
@@ -1863,12 +1980,16 @@
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz",
"integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/raw-body": {
@@ -1964,9 +2085,9 @@
"license": "MIT"
},
"node_modules/semver": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
"integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -2027,14 +2148,14 @@
"license": "ISC"
},
"node_modules/side-channel": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
"integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
"side-channel-list": "^1.0.0",
"object-inspect": "^1.13.4",
"side-channel-list": "^1.0.1",
"side-channel-map": "^1.0.1",
"side-channel-weakmap": "^1.0.2"
},
@@ -2152,6 +2273,21 @@
"node": "*"
}
},
"node_modules/sql-escaper": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.5.1.tgz",
"integrity": "sha512-4toX5E1fQbBrpfXidaHnF0669nkAdETeIPTs2SUjxxD7RRIs9ICG4gtpmfc68JCEKehsdwLFqBu9VlQqZ1P1gg==",
"license": "MIT",
"engines": {
"bun": ">=1.0.0",
"deno": ">=2.0.0",
"node": ">=12.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/mysqljs/sql-escaper?sponsor=1"
}
},
"node_modules/statuses": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
@@ -2180,9 +2316,9 @@
}
},
"node_modules/systeminformation": {
"version": "5.31.6",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.6.tgz",
"integrity": "sha512-Uv2b2uGGM6ns+26czgW2cYRabYdnswM0ddSOOlryHOaelzsmDSet1iM/NT7VOYxW8x/BW+HkY+b1Ve2pLTSGSA==",
"version": "5.33.5",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.5.tgz",
"integrity": "sha512-0v8l1CwFOAjfkv6ynpMrv3YGjH0M7PWCpZwusr8J1TEoQFPK7WXO6gbeAiandaWoh7vbMdnFtDqVotJVnLJtIg==",
"license": "MIT",
"os": [
"darwin",
@@ -2198,7 +2334,7 @@
"systeminformation": "lib/cli.js"
},
"engines": {
"node": ">=8.0.0"
"node": ">=10.0.0"
},
"funding": {
"type": "Buy me a coffee",
@@ -2206,9 +2342,9 @@
}
},
"node_modules/tar-fs": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz",
"integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==",
"license": "MIT",
"dependencies": {
"chownr": "^1.1.1",
@@ -2316,9 +2452,9 @@
}
},
"node_modules/type-is/node_modules/content-type": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
"integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
"integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
"license": "MIT",
"engines": {
"node": ">=18"
@@ -2329,18 +2465,18 @@
}
},
"node_modules/undici": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
"integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
"version": "6.28.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
"integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
"license": "MIT",
"engines": {
"node": ">=18.17"
}
},
"node_modules/undici-types": {
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
"license": "MIT"
},
"node_modules/unpipe": {
@@ -2438,9 +2574,9 @@
}
},
"node_modules/ws": {
"version": "8.20.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
"version": "8.21.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
"integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "supportbot",
"version": "26.2",
"version": "26.2.0",
"description": "SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customization to match your own brand.",
"main": "index.js",
"scripts": {
@@ -17,7 +17,7 @@
"bugs": {
"url": "https://github.com/Emerald-Services/SupportBot/issues"
},
"homepage": "https://community.emeraldsrv.dev",
"homepage": "https://emeraldsrv.dev",
"dependencies": {
"@vitalets/google-translate-api": "^9.2.1",
"adm-zip": "^0.6.0",
@@ -34,6 +34,7 @@
"js-yaml": "^4.1.0",
"moment": "^2.29.3",
"ms": "^2.1.3",
"mysql2": "^3.23.3",
"openai": "^4.50.0",
"systeminformation": "^5.31.5",
"yaml": "^2.8.3"
-206
View File
@@ -1,206 +0,0 @@
var i3=Object.defineProperty;var l3=(e,n,a)=>n in e?i3(e,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):e[n]=a;var Mx=(e,n,a)=>l3(e,typeof n!="symbol"?n+"":n,a);function c3(e,n){for(var a=0;a<n.length;a++){const o=n[a];if(typeof o!="string"&&!Array.isArray(o)){for(const i in o)if(i!=="default"&&!(i in e)){const c=Object.getOwnPropertyDescriptor(o,i);c&&Object.defineProperty(e,i,c.get?c:{enumerable:!0,get:()=>o[i]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))o(i);new MutationObserver(i=>{for(const c of i)if(c.type==="childList")for(const d of c.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&o(d)}).observe(document,{childList:!0,subtree:!0});function a(i){const c={};return i.integrity&&(c.integrity=i.integrity),i.referrerPolicy&&(c.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?c.credentials="include":i.crossOrigin==="anonymous"?c.credentials="omit":c.credentials="same-origin",c}function o(i){if(i.ep)return;i.ep=!0;const c=a(i);fetch(i.href,c)}})();function w0(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Fm={exports:{}},Li={};/**
* @license React
* react-jsx-runtime.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var _x;function u3(){if(_x)return Li;_x=1;var e=Symbol.for("react.transitional.element"),n=Symbol.for("react.fragment");function a(o,i,c){var d=null;if(c!==void 0&&(d=""+c),i.key!==void 0&&(d=""+i.key),"key"in i){c={};for(var m in i)m!=="key"&&(c[m]=i[m])}else c=i;return i=c.ref,{$$typeof:e,type:o,key:d,ref:i!==void 0?i:null,props:c}}return Li.Fragment=n,Li.jsx=a,Li.jsxs=a,Li}var Ox;function d3(){return Ox||(Ox=1,Fm.exports=u3()),Fm.exports}var l=d3(),Ym={exports:{}},Me={};/**
* @license React
* react.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Dx;function f3(){if(Dx)return Me;Dx=1;var e=Symbol.for("react.transitional.element"),n=Symbol.for("react.portal"),a=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),c=Symbol.for("react.consumer"),d=Symbol.for("react.context"),m=Symbol.for("react.forward_ref"),p=Symbol.for("react.suspense"),h=Symbol.for("react.memo"),y=Symbol.for("react.lazy"),v=Symbol.for("react.activity"),x=Symbol.iterator;function S(M){return M===null||typeof M!="object"?null:(M=x&&M[x]||M["@@iterator"],typeof M=="function"?M:null)}var j={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},C=Object.assign,N={};function E(M,_,U){this.props=M,this.context=_,this.refs=N,this.updater=U||j}E.prototype.isReactComponent={},E.prototype.setState=function(M,_){if(typeof M!="object"&&typeof M!="function"&&M!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,M,_,"setState")},E.prototype.forceUpdate=function(M){this.updater.enqueueForceUpdate(this,M,"forceUpdate")};function k(){}k.prototype=E.prototype;function T(M,_,U){this.props=M,this.context=_,this.refs=N,this.updater=U||j}var R=T.prototype=new k;R.constructor=T,C(R,E.prototype),R.isPureReactComponent=!0;var D=Array.isArray;function P(){}var z={H:null,A:null,T:null,S:null},B=Object.prototype.hasOwnProperty;function H(M,_,U){var V=U.ref;return{$$typeof:e,type:M,key:_,ref:V!==void 0?V:null,props:U}}function Y(M,_){return H(M.type,_,M.props)}function Q(M){return typeof M=="object"&&M!==null&&M.$$typeof===e}function fe(M){var _={"=":"=0",":":"=2"};return"$"+M.replace(/[=:]/g,function(U){return _[U]})}var de=/\/+/g;function he(M,_){return typeof M=="object"&&M!==null&&M.key!=null?fe(""+M.key):_.toString(36)}function se(M){switch(M.status){case"fulfilled":return M.value;case"rejected":throw M.reason;default:switch(typeof M.status=="string"?M.then(P,P):(M.status="pending",M.then(function(_){M.status==="pending"&&(M.status="fulfilled",M.value=_)},function(_){M.status==="pending"&&(M.status="rejected",M.reason=_)})),M.status){case"fulfilled":return M.value;case"rejected":throw M.reason}}throw M}function O(M,_,U,V,F){var ae=typeof M;(ae==="undefined"||ae==="boolean")&&(M=null);var ne=!1;if(M===null)ne=!0;else switch(ae){case"bigint":case"string":case"number":ne=!0;break;case"object":switch(M.$$typeof){case e:case n:ne=!0;break;case y:return ne=M._init,O(ne(M._payload),_,U,V,F)}}if(ne)return F=F(M),ne=V===""?"."+he(M,0):V,D(F)?(U="",ne!=null&&(U=ne.replace(de,"$&/")+"/"),O(F,_,U,"",function(W){return W})):F!=null&&(Q(F)&&(F=Y(F,U+(F.key==null||M&&M.key===F.key?"":(""+F.key).replace(de,"$&/")+"/")+ne)),_.push(F)),1;ne=0;var me=V===""?".":V+":";if(D(M))for(var pe=0;pe<M.length;pe++)V=M[pe],ae=me+he(V,pe),ne+=O(V,_,U,ae,F);else if(pe=S(M),typeof pe=="function")for(M=pe.call(M),pe=0;!(V=M.next()).done;)V=V.value,ae=me+he(V,pe++),ne+=O(V,_,U,ae,F);else if(ae==="object"){if(typeof M.then=="function")return O(se(M),_,U,V,F);throw _=String(M),Error("Objects are not valid as a React child (found: "+(_==="[object Object]"?"object with keys {"+Object.keys(M).join(", ")+"}":_)+"). If you meant to render a collection of children, use an array instead.")}return ne}function $(M,_,U){if(M==null)return M;var V=[],F=0;return O(M,V,"","",function(ae){return _.call(U,ae,F++)}),V}function Z(M){if(M._status===-1){var _=M._result;_=_(),_.then(function(U){(M._status===0||M._status===-1)&&(M._status=1,M._result=U)},function(U){(M._status===0||M._status===-1)&&(M._status=2,M._result=U)}),M._status===-1&&(M._status=0,M._result=_)}if(M._status===1)return M._result.default;throw M._result}var J=typeof reportError=="function"?reportError:function(M){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var _=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof M=="object"&&M!==null&&typeof M.message=="string"?String(M.message):String(M),error:M});if(!window.dispatchEvent(_))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",M);return}console.error(M)},te={map:$,forEach:function(M,_,U){$(M,function(){_.apply(this,arguments)},U)},count:function(M){var _=0;return $(M,function(){_++}),_},toArray:function(M){return $(M,function(_){return _})||[]},only:function(M){if(!Q(M))throw Error("React.Children.only expected to receive a single React element child.");return M}};return Me.Activity=v,Me.Children=te,Me.Component=E,Me.Fragment=a,Me.Profiler=i,Me.PureComponent=T,Me.StrictMode=o,Me.Suspense=p,Me.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=z,Me.__COMPILER_RUNTIME={__proto__:null,c:function(M){return z.H.useMemoCache(M)}},Me.cache=function(M){return function(){return M.apply(null,arguments)}},Me.cacheSignal=function(){return null},Me.cloneElement=function(M,_,U){if(M==null)throw Error("The argument must be a ReaLine truncated
* @license React
* scheduler.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var zx;function m3(){return zx||(zx=1,(function(e){function n(O,$){var Z=O.length;O.push($);e:for(;0<Z;){var J=Z-1>>>1,te=O[J];if(0<i(te,$))O[J]=$,O[Z]=te,Z=J;else break e}}function a(O){return O.length===0?null:O[0]}function o(O){if(O.length===0)return null;var $=O[0],Z=O.pop();if(Z!==$){O[0]=Z;e:for(var J=0,te=O.length,M=te>>>1;J<M;){var _=2*(J+1)-1,U=O[_],V=_+1,F=O[V];if(0>i(U,Z))V<te&&0>i(F,U)?(O[J]=F,O[V]=Z,J=V):(O[J]=U,O[_]=Z,J=_);else if(V<te&&0>i(F,Z))O[J]=F,O[V]=Z,J=V;else break e}}return $}function i(O,$){var Z=O.sortIndex-$.sortIndex;return Z!==0?Z:O.id-$.id}if(e.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var c=performance;e.unstable_now=function(){return c.now()}}else{var d=Date,m=d.now();e.unstable_now=function(){return d.now()-m}}var p=[],h=[],y=1,v=null,x=3,S=!1,j=!1,C=!1,N=!1,E=typeof setTimeout=="function"?setTimeout:null,k=typeof clearTimeout=="function"?clearTimeout:null,T=typeof setImmediate<"u"?setImmediate:null;function R(O){for(var $=a(h);$!==null;){if($.callback===null)o(h);else if($.startTime<=O)o(h),$.sortIndex=$.expirationTime,n(p,$);else break;$=a(h)}}function D(O){if(C=!1,R(O),!j)if(a(p)!==null)j=!0,P||(P=!0,fe());else{var $=a(h);$!==null&&se(D,$.startTime-O)}}var P=!1,z=-1,B=5,H=-1;function Y(){return N?!0:!(e.unstable_now()-H<B)}function Q(){if(N=!1,P){var O=e.unstable_now();H=O;var $=!0;try{e:{j=!1,C&&(C=!1,k(z),z=-1),S=!0;var Z=x;try{t:{for(R(O),v=a(p);v!==null&&!(v.expirationTime>O&&Y());){var J=v.callback;if(typeof J=="function"){v.callback=null,x=v.priorityLevel;var te=J(v.expirationTime<=O);if(O=e.unstable_now(),typeof te=="function"){v.callback=te,R(O),$=!0;break t}v===a(p)&&o(p),R(O)}else o(p);v=a(p)}if(v!==null)$=!0;else{var M=a(h);M!==null&&se(D,M.startTime-O),$=!1}}break e}finally{v=null,x=Z,S=!1}$=void 0}}finally{$?fe():P=!1}}}var fe;if(typeof T=="function")fe=function(){T(Q)};else if(typeof MessageChannel<"u"){var de=new MessageChannel,he=de.port2;de.port1.onmessage=Q,fe=function(){he.postMessage(null)}}else fe=function(){E(Q,0)};function se(O,$){z=E(function(){O(e.unstable_now())},$)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(O){O.callback=null},e.unstable_forceFrameRate=function(O){0>O||125<O?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):B=0<O?Math.floor(1e3/O):5},e.unstable_getCurrentPriorityLevel=function(){return x},e.unstable_next=function(O){switch(x){case 1:case 2:case 3:var $=3;break;default:$=x}var Z=x;x=$;try{return O()}finally{x=Z}},e.unstable_requestPaint=function(){N=!0},e.unstable_runWithPriority=function(O,$){switch(O){case 1:case 2:case 3:case 4:case 5:break;default:O=3}var Z=x;x=O;try{return $()}finally{x=Z}},e.unstable_scheduleCallback=function(O,$,Z){var J=e.unstable_now();switch(typeof Z=="object"&&Z!==null?(Z=Z.delay,Z=typeof Z=="number"&&0<Z?J+Z:J):Z=J,O){case 1:var te=-1;break;case 2:te=250;break;case 5:te=1073741823;break;case 4:te=1e4;break;default:te=5e3}return te=Z+te,O={id:y++,callback:$,priorityLevel:O,startTime:Z,expirationTime:te,sortIndex:-1},Z>J?(O.sortIndex=Z,n(h,O),a(p)===null&&O===a(h)&&(C?(k(z),z=-1):C=!0,se(D,Z-J))):(O.sortIndex=te,n(p,O),j||S||(j=!0,P||(P=!0,fe()))),O},e.unstable_shouldYield=Y,e.unstable_wrapCallback=function(O){var $=x;return function(){var Z=x;x=$;try{return O.apply(this,arguments)}finally{x=Z}}}})(Km)),Km}var Px;function p3(){return Px||(Px=1,qm.exports=m3()),qm.exports}var Xm={exports:{}},Ft={};/**
* @license React
* react-dom.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Ix;function h3(){if(Ix)return Ft;Ix=1;var e=Lu();function n(p){var h="https://react.dev/errors/"+p;if(1<arguments.length){h+="?args[]="+encodeURIComponent(arguments[1]);for(var y=2;y<arguments.length;y++)h+="&args[]="+encodeURIComponent(arguments[y])}return"Minified React error #"+p+"; visit "+h+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function a(){}var o={d:{f:a,r:function(){throw Error(n(522))},D:a,C:a,L:a,m:a,X:a,S:a,M:a},p:0,findDOMNode:null},i=Symbol.for("react.portal");function c(p,h,y){var v=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:i,key:v==null?null:""+v,children:p,containerInfo:h,implementation:y}}var d=e.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function m(p,h){if(p==="font")return"";if(typeof h=="string")return h==="use-credentials"?h:""}return Ft.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=o,Ft.createPortal=function(p,h){var y=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!h||h.nodeType!==1&&h.nodeType!==9&&h.nodeType!==11)throw Error(n(299));return c(p,h,null,y)},Ft.flushSync=function(p){var h=d.T,y=o.p;try{if(d.T=null,o.p=2,p)return p()}finally{d.T=h,o.p=y,o.d.f()}},Ft.preconnect=function(p,h){typeof p=="string"&&(h?(h=h.crossOrigin,h=typeof h=="string"?h==="use-credentials"?h:"":void 0):h=null,o.d.C(p,h))},Ft.prefetchDNS=function(p){typeof p=="string"&&o.d.D(p)},Ft.preinit=function(p,h){if(typeof p=="string"&&h&&typeof h.as=="string"){var y=h.as,v=m(y,h.crossOrigin),x=typeof h.integrity=="string"?h.integrity:void 0,S=typeof h.fetchPriority=="string"?h.fetchPriority:void 0;y==="style"?o.d.S(p,typeof h.precedence=="string"?h.precedence:void 0,{crossOrigin:v,integrity:x,fetchPriority:S}):y==="script"&&o.d.X(p,{crossOrigin:v,integrity:x,fetchPriority:S,nonce:typeof h.nonce=="string"?h.nonce:void 0})}},Ft.preinitModule=function(p,h){if(typeof p=="string")if(typeof h=="object"&&h!==null){if(h.as==null||h.as==="script"){var y=m(h.as,h.crossOrigin);o.d.M(p,{crossOrigin:y,integrity:typeof h.integrity=="string"?h.integrity:void 0,nonce:typeof h.nonce=="string"?h.nonce:void 0})}}else h==null&&o.d.M(p)},Ft.preload=function(p,h){if(typeof p=="string"&&typeof h=="object"&&h!==null&&typeof h.as=="string"){var y=h.as,v=m(y,h.crossOrigin);o.d.L(p,y,{crossOrigin:v,integrity:typeof h.integrity=="string"?h.integrity:void 0,nonce:typeof h.nonce=="string"?h.nonce:void 0,type:typeof h.type=="string"?h.type:void 0,fetchPriority:typeof h.fetchPriority=="string"?h.fetchPriority:void 0,referrerPolicy:typeof h.referrerPolicy=="string"?h.referrerPolicy:void 0,imageSrcSet:typeof h.imageSrcSet=="string"?h.imageSrcSet:void 0,imageSizes:typeof h.imageSizes=="string"?h.imageSizes:void 0,media:typeof h.media=="string"?h.media:void 0})}},Ft.preloadModule=function(p,h){if(typeof p=="string")if(h){var y=m(h.as,h.crossOrigin);o.d.m(p,{as:typeof h.as=="string"&&h.as!=="script"?h.as:void 0,crossOrigin:y,integrity:typeof h.integrity=="string"?h.integrity:void 0})}else o.d.m(p)},Ft.requestFormReset=function(p){o.d.r(p)},Ft.unstable_batchedUpdates=function(p,h){return p(h)},Ft.useFormState=function(p,h,y){return d.H.useFormState(p,h,y)},Ft.useFormStatus=function(){return d.H.useHostTransitionStatus()},Ft.version="19.2.6",Ft}var $x;function C0(){if($x)return Xm.exports;$x=1;function e(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(n){console.error(n)}}return e(),Xm.exports=h3(),Xm.exports}/**
* @license React
* react-dom-client.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Bx;function g3(){if(Bx)return zi;Bx=1;var e=p3(),n=Lu(),a=C0();function o(t){var r="https://react.dev/errors/"+t;if(1<arguments.length){r+="?args[]="+encodeURIComponent(arguments[1]);for(var s=2;s<arguments.length;s++)r+="&args[]="+encodeURIComponent(arguments[s])}return"Minified React error #"+t+"; visit "+r+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function i(t){return!(!t||t.nodeType!==1&&t.nodeType!==9&&t.nodeType!==11)}function c(t){var r=t,s=t;if(t.alternate)for(;r.return;)r=r.return;else{t=r;do r=t,(r.flags&4098)!==0&&(s=r.return),t=r.return;while(t)}return r.tag===3?s:null}function d(t){if(t.tag===13){var r=t.memoizedState;if(r===null&&(t=t.alternate,t!==null&&(r=t.memoizedState)),r!==null)return r.dehydrated}return null}function m(t){if(t.tag===31){var r=t.memoizedState;if(r===null&&(t=t.alternate,t!==null&&(r=t.memoizedState)),r!==null)return r.dehydrated}return null}function p(t){if(c(t)!==t)throw Error(o(188))}function h(t){var r=t.alternate;if(!r){if(r=c(t),r===null)throw Error(o(188));return r!==t?null:t}for(var s=t,u=r;;){var g=s.return;if(g===null)break;var b=g.alternate;if(b===null){if(u=g.return,u!==null){s=u;continue}break}if(g.child===b.child){for(b=g.child;b;){if(b===s)return p(g),t;if(b===u)return p(g),r;b=b.sibling}throw Error(o(188))}if(s.return!==u.return)s=g,u=b;else{for(var w=!1,A=g.child;A;){if(A===s){w=!0,s=g,u=b;break}if(A===u){w=!0,u=g,s=b;break}A=A.sibling}if(!w){for(A=b.child;A;){if(A===s){w=!0,s=b,u=g;break}if(A===u){w=!0,u=b,s=g;break}A=A.sibling}if(!w)throw Error(o(189))}}if(s.alternate!==u)throw Error(o(190))}if(s.tag!==3)throw Error(o(188));return s.stateNode.current===s?t:r}function y(t){var r=t.tag;if(r===5||r===26||r===27||r===6)return t;for(t=t.child;t!==null;){if(r=y(t),r!==null)return r;t=t.sibling}return null}var v=Object.assign,x=Symbol.for("react.element"),S=Symbol.for("react.transitional.element"),j=Symbol.for("react.portal"),C=Symbol.for("react.fragment"),N=Symbol.for("react.strict_mode"),E=Symbol.for("react.profiler"),k=Symbol.for("react.consumer"),T=Symbol.for("react.context"),R=Symbol.for("react.forward_ref"),D=Symbol.for("react.suspense"),P=Symbol.for("react.suspense_list"),z=Symbol.for("react.memo"),B=Symbol.for("react.lazy"),H=Symbol.for("react.activity"),Y=Symbol.for("react.memo_cache_sentinel"),Q=Symbol.iterator;function fe(t){return t===null||typeof t!="object"?null:(t=Q&&t[Q]||t["@@iterator"],typeof t=="function"?t:null)}var de=Symbol.for("react.client.reference");function he(t){if(t==null)return null;if(typeof t=="function")return t.$$typeof===de?null:t.displayName||t.name||null;if(typeof t=="string")return t;switch(t){case C:return"Fragment";case E:return"Profiler";case N:return"StrictMode";case D:return"Suspense";case P:return"SuspenseList";case H:return"Activity"}if(typeof t=="object")switch(t.$$typeof){case j:return"Portal";case T:return t.displayName||"Context";case k:return(t._context.displayName||"Context")+".Consumer";case R:var r=t.render;return t=t.displayName,t||(t=r.displayName||r.name||"",t=t!==""?"ForwardRef("+t+")":"ForwardRef"),t;case z:return r=t.displayName||null,r!==null?r:he(t.type)||"Memo";case B:r=t._payload,t=t._init;try{return he(t(r))}catch{}}return null}var se=Array.isArray,O=n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,$=a.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,Z={pending:!1,data:null,method:null,action:null},J=[],te=-1;function M(t){return{current:t}}function _(t){0>te||(t.current=J[te],J[te]=null,te--)}function U(t,r){te++,J[te]=t.current,t.current=r}var V=M(null),F=M(null),ae=M(null),ne=M(null);function me(t,r){switch(U(ae,r),U(F,t),U(V,null),r.nodeType){case 9:case 11:t=(t=r.documentElement)&&(t=t.namespaceURI)?ex(t):0;break;default:if(t=r.tagName,r=r.namespaceURI)r=ex(r),t=tx(r,t);else switch(t){case"svg":t=1;break;case"math":t=2;break;default:t=0}}_(V),U(V,t)}function pe(){_(V),_(F),_(ae)}function W(t){t.memoizedState!==null&&U(ne,t);var r=V.current,s=tx(r,t.type);r!==s&&(U(F,t),U(V,s))}function ie(t){F.current===t&&(_(V),_(F)),ne.current===t&&(_(ne),Mi._currentValue=Z)}var ge,je;function Ae(t){if(ge===void 0)try{throw Error()}catch(s){var r=s.stack.trim().match(/\n( *(at )?)/);ge=r&&r[1]||"",je=-1<s.stack.indexOf(`
at`)?" (<anonymous>)":-1<s.stack.indexOf("@")?"@unknown:0:0":""}return`
`+ge+t+je}var tt=!1;function ct(t,r){if(!t||tt)return"";tt=!0;var s=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var u={DetermineComponentFrameRoot:function(){try{if(r){var le=function(){throw Error()};if(Object.defineProperty(le.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(le,[])}catch(ee){var X=ee}Reflect.construct(t,[],le)}else{try{le.call()}catch(ee){X=ee}t.call(le.prototype)}}else{try{throw Error()}catch(ee){X=ee}(le=t())&&typeof le.catch=="function"&&le.catch(function(){})}}catch(ee){if(ee&&X&&typeof ee.stack=="string")return[ee.stack,X.stack]}return[null,null]}};u.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var g=Object.getOwnPropertyDescriptor(u.DetermineComponentFrameRoot,"name");g&&g.configurable&&Object.defineProperty(u.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var b=u.DetermineComponentFrameRoot(),w=b[0],A=b[1];if(w&&A){var L=w.split(`
`),K=A.split(`
`);for(g=u=0;u<L.length&&!L[u].includes("DetermineComponentFrameRoot");)u++;for(;g<K.length&&!K[g].includes("DetermineComponentFrameRoot");)g++;if(u===L.length||g===K.length)for(u=L.length-1,g=K.length-1;1<=u&&0<=g&&L[u]!==K[g];)g--;for(;1<=u&&0<=g;u--,g--)if(L[u]!==K[g]){if(u!==1||g!==1)do if(u--,g--,0>g||L[u]!==K[g]){var re=`
`+L[u].replace(" at new "," at ");return t.displayName&&re.includes("<anonymous>")&&(re=re.replace("<anonymous>",t.displayName)),re}while(1<=u&&0<=g);break}}}finally{tt=!1,Error.prepareStackTrace=s}return(s=t?t.displayName||t.name:"")?Ae(s):""}function kt(t,r){switch(t.tag){case 26:case 27:case 5:return Ae(t.type);case 16:return Ae("Lazy");case 13:return t.child!==r&&r!==null?Ae("Suspense Fallback"):Ae("Suspense");case 19:return Ae("SuspenseList");case 0:case 15:return ct(t.type,!1);case 11:return ct(t.type.render,!1);case 1:return ct(t.type,!0);case 31:return Ae("Activity");default:return""}}function Ra(t){try{var r="",s=null;do r+=kt(t,s),s=t,t=t.return;while(t);return r}catch(u){return`
Error generating stack: `+u.message+`
`+u.stack}}var Tt=Object.prototype.hasOwnProperty,Hs=e.unstable_scheduleCallback,Vs=e.unstable_cancelCallback,Wt=e.unstable_shouldYield,Vr=e.unstable_requestPaint,qt=e.unstable_now,_d=e.unstable_getCurrentPriorityLevel,Aa=e.unstable_ImmediatePriority,Tl=e.unstable_UserBlockingPriority,Ma=e.unstable_NormalPriority,Gs=e.unstable_LowPriority,mr=e.unstable_IdlePriority,Rl=e.log,Gr=e.unstable_setDisableYieldValue,_a=null,Kt=null;function Un(t){if(typeof Rl=="function"&&Gr(t),Kt&&typeof Kt.setStrictMode=="function")try{Kt.setStrictMode(_a,t)}catch{}}var Vt=Math.clz32?Math.clz32:Qn,Od=Math.log,Fs=Math.LN2;function Qn(t){return t>>>=0,t===0?32:31-(Od(t)/Fs|0)|0}var yo=256,xo=262144,Oa=4194304;function Jn(t){var r=t&42;if(r!==0)return r;switch(t&-t){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return t&261888;case 262144:case 524288:case 1048576:case 2097152:return t&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return t&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return t}}function Re(t,r,s){var u=t.pendingLanes;if(u===0)return 0;var g=0,b=t.suspendedLanes,w=t.pingedLanes;t=t.warmLanes;var A=u&134217727;return A!==0?(u=A&~b,u!==0?g=Jn(u):(w&=A,w!==0?g=Jn(w):s||(s=A&~t,s!==0&&(g=Jn(s))))):(A=u&~b,A!==0?g=Jn(A):w!==0?g=Jn(w):s||(s=u&~t,s!==0&&(g=Jn(s)))),g===0?0:r!==0&&r!==g&&(r&b)===0&&(b=g&-g,s=r&-r,b>=s||b===32&&(s&4194048)!==0)?r:g}function ut(t,r){return(t.pendingLanes&~(t.suspendedLanes&~t.pingedLanes)&r)===0}function Rt(t,r){switch(t){case 1:case 2:case 4:case 8:case 64:return r+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return r+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Gt(){var t=Oa;return Oa<<=1,(Oa&62914560)===0&&(Oa=4194304),t}function Fr(t){for(var r=[],s=0;31>s;s++)r.push(t);return r}function mt(t,r){t.pendingLanes|=r,r!==268435456&&(t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0)}function Jt(t,r,s,u,g,b){var w=t.pendingLanes;t.pendingLanes=s,t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0,t.expiredLanes&=s,t.entangledLanes&=s,t.errorRecoveryDisabledLanes&=s,t.shellSuspendCounter=0;var A=t.entanglements,L=t.expirationTimes,K=t.hiddenUpdates;for(s=w&~s;0<s;){var re=31-Vt(s),le=1<<re;A[re]=0,L[re]=-1;var X=K[re];if(X!==null)for(K[re]=null,re=0;re<X.length;re++){var ee=X[re];ee!==null&&(ee.lane&=-536870913)}s&=~le}u!==0&&Da(t,u,0),b!==0&&g===0&&t.tag!==0&&(t.suspendedLanes|=b&~(w&~r))}function Da(t,r,s){t.pendingLanes|=r,t.suspendedLanes&=~r;var u=31-Vt(r);t.entangledLanes|=r,t.entanglements[u]=t.entanglements[u]|1073741824|s&261930}function en(t,r){var s=t.entangledLanes|=r;for(t=t.entanglements;s;){var u=31-Vt(s),g=1<<u;g&r|t[u]&r&&(t[u]|=r),s&=~g}}function tn(t,r){var s=r&-r;return s=(s&42)!==0?1:So(s),(s&(t.suspendedLanes|r))!==0?0:s}function So(t){switch(t){case 2:t=1;break;case 8:t=4;break;case 32:t=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:t=128;break;case 268435456:t=134217728;break;default:t=0}return t}function Hn(t){return t&=-t,2<t?8<t?(t&134217727)!==0?32:268435456:8:2}function Dd(){var t=$.p;return t!==0?t:(t=window.event,t===void 0?32:jx(t.type))}function Bg(t,r){var s=$.p;try{return $.p=t,r()}finally{$.p=s}}var Yr=Math.random().toString(36).slice(2),zt="__reactFiber$"+Yr,nn="__reactProps$"+Yr,wo="__reactContainer$"+Yr,Ld="__reactEvents$"+Yr,X5="__reactListeners$"+Yr,Z5="__reactHandles$"+Yr,Ug="__reactResources$"+Yr,Ys="__reactMarker$"+Yr;function zd(t){delete t[zt],delete t[nn],delete t[Ld],delete t[X5],delete t[Z5]}function Co(t){var r=t[zt];if(r)return r;for(var s=t.parentNode;s;){if(r=s[wo]||s[zt]){if(s=r.alternate,r.child!==null||s!==null&&s.child!==null)for(t=lx(t);t!==null;){if(s=t[zt])return s;t=lx(t)}return r}t=s,s=t.parentNode}return null}function jo(t){if(t=t[zt]||t[wo]){var r=t.tag;if(r===5||r===6||r===13||r===31||r===26||r===27||r===3)return t}return null}function Ws(t){var r=t.tag;if(r===5||r===26||r===27||r===6)return t.stateNode;throw Error(o(33))}function Eo(t){var r=t[Ug];return r||(r=t[Ug]={hoistableStyles:new Map,hoistableScripts:new Map}),r}function At(t){t[Ys]=!0}var Hg=new Set,Vg={};function La(t,r){No(t,r),No(t+"Capture",r)}function No(t,r){for(Vg[t]=r,t=0;t<r.length;t++)Hg.add(r[t])}var Q5=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u20 Line truncated
`).replace(RN,"")}function Qy(t,r){return r=Zy(r),Zy(t)===r}function rt(t,r,s,u,g,b){switch(s){case"children":typeof u=="string"?r==="body"||r==="textarea"&&u===""||To(t,u):(typeof u=="number"||typeof u=="bigint")&&r!=="body"&&To(t,""+u);break;case"className":Ml(t,"class",u);break;case"tabIndex":Ml(t,"tabindex",u);break;case"dir":case"role":case"viewBox":case"width":case"height":Ml(t,s,u);break;case"style":Qg(t,u,b);break;case"data":if(r!=="object"){Ml(t,"data",u);break}case"src":case"href":if(u===""&&(r!=="a"||s!=="href")){t.removeAttribute(s);break}if(u==null||typeof u=="function"||typeof u=="symbol"||typeof u=="boolean"){t.removeAttribute(s);break}u=Ol(""+u),t.setAttribute(s,u);break;case"action":case"formAction":if(typeof u=="function"){t.setAttribute(s,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof b=="function"&&(s==="formAction"?(r!=="input"&&rt(t,r,"name",g.name,g,null),rt(t,r,"formEncType",g.formEncType,g,null),rt(t,r,"formMethod",g.formMethod,g,null),rt(t,r,"formTarget",g.formTarget,g,null)):(rt(t,r,"encType",g.encType,g,null),rt(t,r,"method",g.method,g,null),rt(t,r,"target",g.target,g,null)));if(u==null||typeof u=="symbol"||typeof u=="boolean"){t.removeAttribute(s);break}u=Ol(""+u),t.setAttribute(s,u);break;case"onClick":u!=null&&(t.onclick=hr);break;case"onScroll":u!=null&&Ie("scroll",t);break;case"onScrollEnd":u!=null&&Ie("scrollend",t);break;case"dangerouslySetInnerHTML":if(u!=null){if(typeof u!="object"||!("__html"in u))throw Error(o(61));if(s=u.__html,s!=null){if(g.children!=null)throw Error(o(60));t.innerHTML=s}}break;case"multiple":t.multiple=u&&typeof u!="function"&&typeof u!="symbol";break;case"muted":t.muted=u&&typeof u!="function"&&typeof u!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(u==null||typeof u=="function"||typeof u=="boolean"||typeof u=="symbol"){t.removeAttribute("xlink:href");break}s=Ol(""+u),t.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",s);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":u!=null&&typeof u!="function"&&typeof u!="symbol"?t.setAttribute(s,""+u):t.removeAttribute(s);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":u&&typeof u!="function"&&typeof u!="symbol"?t.setAttribute(s,""):t.removeAttribute(s);break;case"capture":case"download":u===!0?t.setAttribute(s,""):u!==!1&&u!=null&&typeof u!="function"&&typeof u!="symbol"?t.setAttribute(s,u):t.removeAttribute(s);break;case"cols":case"rows":case"size":case"span":u!=null&&typeof u!="function"&&typeof u!="symbol"&&!isNaN(u)&&1<=u?t.setAttribute(s,u):t.removeAttribute(s);break;case"rowSpan":case"start":u==null||typeof u=="function"||typeof u=="symbol"||isNaN(u)?t.removeAttribute(s):t.setAttribute(s,u);break;case"popover":Ie("beforetoggle",t),Ie("toggle",t),Al(t,"popover",u);break;case"xlinkActuate":pr(t,"http://www.w3.org/1999/xlink","xlink:actuate",u);break;case"xlinkArcrole":pr(t,"http://www.w3.org/1999/xlink","xlink:arcrole",u);break;case"xlinkRole":pr(t,"http://www.w3.org/1999/xlink","xlink:role",u);break;case"xlinkShow":pr(t,"http://www.w3.org/1999/xlink","xlink:show",u);break;case"xlinkTitle":pr(t,"http://www.w3.org/1999/xlink","xlink:title",u);break;case"xlinkType":pr(t,"http://www.w3.org/1999/xlink","xlink:type",u);break;case"xmlBase":pr(t,"http://www.w3.org/XML/1998/namespace","xml:base",u);break;case"xmlLang":pr(t,"http://www.w3.org/XML/1998/namespace","xml:lang",u);break;case"xmlSpace":pr(t,"http://www.w3.org/XML/1998/namespace","xml:space",u);break;case"is":Al(t,"is",u);break;case"innerText":case"textContent":break;default:(!(2<s.length)||s[0]!=="o"&&s[0]!=="O"||s[1]!=="n"&&s[1]!=="N")&&(s=rE.get(s)||s,Al(t,s,u))}}function km(t,r,s,u,g,b){switch(s){case"style":Qg(t,u,b);break;case"dangerouslySetInnerHTML":if(u!=null){if(typeof u!="object"||!("__html"in u))throw Error(o(61));if(s=u.__html,s!=null){if(g.children!=null)throw Error(o(60));t.innerHTML=s}}break;case"children":typeof u=="string"?To(t,u):(typeof u=="number"||typeof u=="bigint")&&To(t,""+u);break;case"onScroll":u!=null&&Ie("scroll",t);break;case"onScrollEnd":u!=null&&Ie("scrollend",t);break;case"onClick":u!=null&&(t.onclick=hr);break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"inne Line truncated
* react-router v7.15.1
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/var Hx="popstate";function Vx(e){return typeof e=="object"&&e!=null&&"pathname"in e&&"search"in e&&"hash"in e&&"state"in e&&"key"in e}function y3(e={}){function n(o,i){var h;let c=(h=i.state)==null?void 0:h.masked,{pathname:d,search:m,hash:p}=c||o.location;return Op("",{pathname:d,search:m,hash:p},i.state&&i.state.usr||null,i.state&&i.state.key||"default",c?{pathname:o.location.pathname,search:o.location.search,hash:o.location.hash}:void 0)}function a(o,i){return typeof i=="string"?i:Xi(i)}return S3(n,a,null,e)}function ft(e,n){if(e===!1||e===null||typeof e>"u")throw new Error(n)}function $n(e,n){if(!e){typeof console<"u"&&console.warn(n);try{throw new Error(n)}catch{}}}function x3(){return Math.random().toString(36).substring(2,10)}function Gx(e,n){return{usr:e.state,key:e.key,idx:n,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function Op(e,n,a=null,o,i){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof n=="string"?Rs(n):n,state:a,key:n&&n.key||o||x3(),mask:i}}function Xi({pathname:e="/",search:n="",hash:a=""}){return n&&n!=="?"&&(e+=n.charAt(0)==="?"?n:"?"+n),a&&a!=="#"&&(e+=a.charAt(0)==="#"?a:"#"+a),e}function Rs(e){let n={};if(e){let a=e.indexOf("#");a>=0&&(n.hash=e.substring(a),e=e.substring(0,a));let o=e.indexOf("?");o>=0&&(n.search=e.substring(o),e=e.substring(0,o)),e&&(n.pathname=e)}return n}function S3(e,n,a,o={}){let{window:i=document.defaultView,v5Compat:c=!1}=o,d=i.history,m="POP",p=null,h=y();h==null&&(h=0,d.replaceState({...d.state,idx:h},""));function y(){return(d.state||{idx:null}).idx}function v(){m="POP";let N=y(),E=N==null?null:N-h;h=N,p&&p({action:m,location:C.location,delta:E})}function x(N,E){m="PUSH";let k=Vx(N)?N:Op(C.location,N,E);h=y()+1;let T=Gx(k,h),R=C.createHref(k.mask||k);try{d.pushState(T,"",R)}catch(D){if(D instanceof DOMException&&D.name==="DataCloneError")throw D;i.location.assign(R)}c&&p&&p({action:m,location:C.location,delta:1})}function S(N,E){m="REPLACE";let k=Vx(N)?N:Op(C.location,N,E);h=y();let T=Gx(k,h),R=C.createHref(k.mask||k);d.replaceState(T,"",R),c&&p&&p({action:m,location:C.location,delta:0})}function j(N){return w3(N)}let C={get action(){return m},get location(){return e(i,d)},listen(N){if(p)throw new Error("A history only accepts one active listener");return i.addEventListener(Hx,v),p=N,()=>{i.removeEventListener(Hx,v),p=null}},createHref(N){return n(i,N)},createURL:j,encodeLocation(N){let E=j(N);return{pathname:E.pathname,search:E.search,hash:E.hash}},push:x,replace:S,go(N){return d.go(N)}};return C}function w3(e,n=!1){let a="http://localhost";typeof window<"u"&&(a=window.location.origin!=="null"?window.location.origin:window.location.href),ft(a,"No window.location.(origin|href) available to create URL");let o=typeof e=="string"?e:Xi(e);return o=o.replace(/ $/,"%20"),!n&&o.startsWith("//")&&(o=a+o),new URL(o,a)}function j0(e,n,a="/"){return C3(e,n,a,!1)}function C3(e,n,a,o,i){let c=typeof n=="string"?Rs(n):n,d=zr(c.pathname||"/",a);if(d==null)return null;let m=j3(e),p=null,h=z3(d);for(let y=0;p==null&&y<m.length;++y)p=D3(m[y],h,o);return p}function j3(e){let n=E0(e);return E3(n),n}function E0(e,n=[],a=[],o="",i=!1){let c=(d,m,p=i,h)=>{let y={relativePath:h===void 0?d.path||"":h,caseSensitive:d.caseSensitive===!0,childrenIndex:m,route:d};if(y.relativePath.startsWith("/")){if(!y.relativePath.startsWith(o)&&p)return;ft(y.relativePath.startsWith(o),`Absolute route path "${y.relativePath}" nested under path "${o}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),y.relativePath=y.relativePath.slice(o.length)}let v=Wn([o,y.relativePath]),x=a.concat(y);d.children&&d.children.length>0&&(ft(d.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${v}".`),E0(d.children,n,x,v,p)),!(d.path==null&&!d.index)&&n.push({path:v,score:_3(v,d.index),routesMeta:x})};return e.forEach((d,m)=>{var p;if(d.path===""||!((p=d.path)!=null&&p.includes("?")))c(d,m);else for(let h of N0(d.path))c(d,m,!0,h)}),n}function N0(e){let n=e.split("/");if(n.length===0)return[];let[a,...o]=n,i=a.endsWith("?"),c=a.replace(/\?$/,"");if(o.length===0)return i?[c,""]:[c];let d=N0(o.join("/")),m=[];return m.push(...d.map(p=>p===""?c:[c,p].join("/"))),i&&m.push(...d),m.map(p=>e.startsWith("/")&&p===""?"/":p)}function E3(e){e.sort((n,a)=>n.score!==a.score?a.score-n.score:O3(n.routesMeta.map(o=>o.childrenIndex),a.routesMeta.map(o=>o.childrenIndex)))}var N3=/^:[\w-]+$/,k3=3,T3=2,R3=1,A3=10,M3=-2,Fx=e=>e==="*";function _3(e,n){let a=e.split("/"),o=a.length;return a.some(Fx)&&(o+=M3),n&&(o+=T3),a.filter(i=>!Fx(i)).reduce((i,c)=>i+(N3.test(c)?k3:c===""?R3:A3),o)}function O3(e,n){return e.length===n.length&&e.slice(0,-1).every((o,i)=>o===n[i])?e[e.length-1]-n[n.length-1]:0}function D3(e,n,a=!1){let{routesMeta:o}=e,i={},c="/",d=[];for(let m=0;m<o.length;++m){let p=o[m],h=m===o.length-1,y=c==="/"?n:n.slice(c.length)||"/",v=pu({path:p.relativePath,caseSensit Line truncated
Please change the parent <Route path="${E}"> to <Route path="${E==="/"?"*":`${E}/*`}">.`)}let y=jn(),v;if(n){let E=typeof n=="string"?Rs(n):n;ft(p==="/"||((N=E.pathname)==null?void 0:N.startsWith(p)),`When overriding the location using \`<Routes location>\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${p}" but pathname "${E.pathname}" was given in the \`location\` prop.`),v=E}else v=y;let x=v.pathname||"/",S=x;if(p!=="/"){let E=p.replace(/^\//,"").split("/");S="/"+x.replace(/^\//,"").split("/").slice(E.length).join("/")}let j=a&&a.state.matches.length?a.state.matches.map(E=>Object.assign(E,{route:a.manifest[E.route.id]||E.route})):j0(e,{pathname:S});$n(h||j!=null,`No routes matched location "${v.pathname}${v.search}${v.hash}" `),$n(j==null||j[j.length-1].route.element!==void 0||j[j.length-1].route.Component!==void 0||j[j.length-1].route.lazy!==void 0,`Matched leaf route at location "${v.pathname}${v.search}${v.hash}" does not have an element or Component. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.`);let C=c4(j&&j.map(E=>Object.assign({},E,{params:Object.assign({},d,E.params),pathname:Wn([p,o.encodeLocation?o.encodeLocation(E.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:E.pathname]),pathnameBase:E.pathnameBase==="/"?p:Wn([p,o.encodeLocation?o.encodeLocation(E.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:E.pathnameBase])})),i,a);return n&&C?f.createElement(cl.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...v},navigationType:"POP"}},C):C}function o4(){let e=p4(),n=G3(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),a=e instanceof Error?e.stack:null,o="rgba(200,200,200, 0.5)",i={padding:"0.5rem",backgroundColor:o},c={padding:"2px 4px",backgroundColor:o},d=null;return console.error("Error handled by React Router default ErrorBoundary:",e),d=f.createElement(f.Fragment,null,f.createElement("p",null,"💿 Hey developer 👋"),f.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",f.createElement("code",{style:c},"ErrorBoundary")," or"," ",f.createElement("code",{style:c},"errorElement")," prop on your route.")),f.createElement(f.Fragment,null,f.createElement("h2",null,"Unexpected Application Error!"),f.createElement("h3",{style:{fontStyle:"italic"}},n),a?f.createElement("pre",{style:i},a):null,d)}var s4=f.createElement(o4,null),P0=class extends f.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,n){return n.location!==e.location||n.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:n.error,location:n.location,revalidation:e.revalidation||n.revalidation}}componentDidCatch(e,n){this.props.onError?this.props.onError(e,n):console.error("React Router caught the following error during render",e)}render(){let e=this.state.error;if(this.context&&typeof e=="object"&&e&&"digest"in e&&typeof e.digest=="string"){const a=J3(e.digest);a&&(e=a)}let n=e!==void 0?f.createElement(Xn.Provider,{value:this.props.routeContext},f.createElement(jh.Provider,{value:e,children:this.props.component})):this.props.children;return this.context?f.createElement(i4,{error:e},n):n}};P0.contextType=M0;var Qm=new WeakMap;function i4({children:e,error:n}){let{basename:a}=f.useContext(Cn);if(typeof n=="object"&&n&&"digest"in n&&typeof n.digest=="string"){let o=Q3(n.digest);if(o){let i=Qm.get(n);if(i)throw i;let c=R0(o.location,a);if(T0&&!Qm.get(n))if(c.isExternal||o.reloadDocument)window.location.href=c.absoluteURL||c.to;else{const d=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(c.to,{replace:o.replace}));throw Qm.set(n,d),d}return f.createElement("meta",{httpEquiv:"refresh",content:`0;url=${c.absoluteURL||c.to}`})}}return e}function l4({routeContext:e,match:n,children:a}){let o=f.useContext(As);return o&&o.static&&o.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(o.staticContext._deepestRenderedBoundaryId=n.route.id),f.createElement(Xn.Provider,{value:e},a)}function c4(e,n=[],a){let o=a==null?void 0:a.state;if(e==null){if(!o)return null;if(o.errors)e=o.matches;else if(n.length===0&&!o.initialized&&o.matches.length>0)e=o.matches;else return null}let i=e,c=o==null?void 0:o.errors;if(c!=null){let y=i.findIndex(v=>v.route.id&&(c==null?void 0:c[v.route.id])!==void 0);ft(y>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(c).join(",")}`),i=i.slice(0,Math.min(i.length,y+1))}let d=!1,m=-1;if(a&&o){d=o.renderFallback;for(let y=0;y<i.length;y++){let v=i[y];if((v.route.HyLine truncated
.`.concat(U9,` {
overflow: hidden `).concat(o,`;
padding-right: `).concat(m,"px ").concat(o,`;
}
body[`).concat(hs,`] {
overflow: hidden `).concat(o,`;
overscroll-behavior: contain;
`).concat([n&&"position: relative ".concat(o,";"),a==="margin"&&`
padding-left: `.concat(i,`px;
padding-top: `).concat(c,`px;
padding-right: `).concat(d,`px;
margin-left:0;
margin-top:0;
margin-right: `).concat(m,"px ").concat(o,`;
`),a==="padding"&&"padding-right: ".concat(m,"px ").concat(o,";")].filter(Boolean).join(""),`
}
.`).concat(lu,` {
right: `).concat(m,"px ").concat(o,`;
}
.`).concat(cu,` {
margin-right: `).concat(m,"px ").concat(o,`;
}
.`).concat(lu," .").concat(lu,` {
right: 0 `).concat(o,`;
}
.`).concat(cu," .").concat(cu,` {
margin-right: 0 `).concat(o,`;
}
body[`).concat(hs,`] {
`).concat(H9,": ").concat(m,`px;
}
`)},T1=function(){var e=parseInt(document.body.getAttribute(hs)||"0",10);return isFinite(e)?e:0},iR=function(){f.useEffect(function(){return document.body.setAttribute(hs,(T1()+1).toString()),function(){var e=T1()-1;e<=0?document.body.removeAttribute(hs):document.body.setAttribute(hs,e.toString())}},[])},lR=function(e){var n=e.noRelative,a=e.noImportant,o=e.gapMode,i=o===void 0?"margin":o;iR();var c=f.useMemo(function(){return aR(i)},[i]);return f.createElement(oR,{styles:sR(c,!n,i,a?"":"!important")})},Fp=!1;if(typeof window<"u")try{var Kc=Object.defineProperty({},"passive",{get:function(){return Fp=!0,!0}});window.addEventListener("test",Kc,Kc),window.removeEventListener("test",Kc,Kc)}catch{Fp=!1}var is=Fp?{passive:!1}:!1,cR=function(e){return e.tagName==="TEXTAREA"},cS=function(e,n){if(!(e instanceof Element))return!1;var a=window.getComputedStyle(e);return a[n]!=="hidden"&&!(a.overflowY===a.overflowX&&!cR(e)&&a[n]==="visible")},uR=function(e){return cS(e,"overflowY")},dR=function(e){return cS(e,"overflowX")},R1=function(e,n){var a=n.ownerDocument,o=n;do{typeof ShadowRoot<"u"&&o instanceof ShadowRoot&&(o=o.host);var i=uS(e,o);if(i){var c=dS(e,o),d=c[1],m=c[2];if(d>m)return!0}o=o.parentNode}while(o&&o!==a.body);return!1},fR=function(e){var n=e.scrollTop,a=e.scrollHeight,o=e.clientHeight;return[n,a,o]},mR=function(e){var n=e.scrollLeft,a=e.scrollWidth,o=e.clientWidth;return[n,a,o]},uS=function(e,n){return e==="v"?uR(n):dR(n)},dS=function(e,n){return e==="v"?fR(n):mR(n)},pR=function(e,n){return e==="h"&&n==="rtl"?-1:1},hR=function(e,n,a,o,i){var c=pR(e,window.getComputedStyle(n).direction),d=c*o,m=a.target,p=n.contains(m),h=!1,y=d>0,v=0,x=0;do{if(!m)break;var S=dS(e,m),j=S[0],C=S[1],N=S[2],E=C-N-c*j;(j||E)&&uS(e,m)&&(v+=E,x+=j);var k=m.parentNode;m=k&&k.nodeType===Node.DOCUMENT_FRAGMENT_NODE?k.host:k}while(!p&&m!==document.body||p&&(n.contains(m)||n===m));return(y&&Math.abs(v)<1||!y&&Math.abs(x)<1)&&(h=!0),h},Xc=function(e){return"changedTouches"in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]},A1=function(e){return[e.deltaX,e.deltaY]},M1=function(e){return e&&"current"in e?e.current:e},gR=function(e,n){return e[0]===n[0]&&e[1]===n[1]},vR=function(e){return`
.block-interactivity-`.concat(e,` {pointer-events: none;}
.allow-interactivity-`).concat(e,` {pointer-events: all;}
`)},bR=0,ls=[];function yR(e){var n=f.useRef([]),a=f.useRef([0,0]),o=f.useRef(),i=f.useState(bR++)[0],c=f.useState(lS)[0],d=f.useRef(e);f.useEffect(function(){d.current=e},[e]),f.useEffect(function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(i));var C=B9([e.lockRef.current],(e.shards||[]).map(M1),!0).filter(Boolean);return C.forEach(function(N){return N.classList.add("allow-interactivity-".concat(i))}),function(){document.body.classList.remove("block-interactivity-".concat(i)),C.forEach(function(N){return N.classList.remove("allow-interactivity-".concat(i))})}}},[e.inert,e.lockRef.current,e.shards]);var m=f.useCallback(function(C,N){if("touches"in C&&C.touches.length===2||C.type==="wheel"&&C.ctrlKey)return!d.current.allowPinchZoom;var E=Xc(C),k=a.current,T="deltaX"in C?C.deltaX:k[0]-E[0],R="deltaY"in C?C.deltaY:k[1]-E[1],D,P=C.target,z=Math.abs(T)>Math.abs(R)?"h":"v";if("touches"in C&&z==="h"&&P.type==="range")return!1;var B=window.getSelection(),H=B&&B.anchorNode,Y=H?H===P||H.contains(P):!1;if(Y)return!1;var Q=R1(z,P);if(!Q)return!0;if(Q?D=z:(D=z==="v"?"h":"v",Q=R1(z,P)),!Q)return!1;if(!o.current&&"changedTouches"in C&&(T||R)&&(o.current=D),!D)return!0;var fe=o.current||D;return hR(fe,N,C,fe==="h"?T:R)},[]),p=f.useCallback(function(C){var N=C;if(!(!ls.length||ls[ls.length-1]!==c)){var E="deltaY"in N?A1(N):Xc(N),k=n.current.filter(function(D){return D.name===N.type&&(D.target===N.target||N.target===D.shadowParent)&&gR(D.delta,E)})[0];if(k&&k.should){N.cancelable&&N.preventDefault();return}if(!k){var T=(d.current.shards||[]).map(M1).filter(Boolean).filter(function(D){return D.contains(N.target)}),R=T.length>0?m(N,T[0]):!d.current.noIsolation;R&&N.cancelable&&N.preventDefault()}}},[]),h=f.useCallback(function(C,N,E,k){var T={name:C,delta:N,target:E,should:k,shadowParent:xR(E)};n.current.push(T),setTimeout(function(){n.current=n.current.filter(function(R){return R!==T})},1)},[]),y=f.useCallback(function(C){a.current=Xc(C),o.current=void 0},[]),v=f.useCallback(function(C){h(C.type,A1(C),C.target,m(C,e.lockRef.current))},[]),x=f.useCallback(function(C){h(C.type,Xc(C),C.target,m(C,e.lockRef.current))},[]);f.useEffect(function(){return ls.push(c),e.setCallbacks({onScrollCapture:v,onWheelCapture:v,onTouchMoveCapture:x}),document.addEventListener("wheel",p,is),document.addEventListener("touchmove",p,is),document.addEventListener("touchstart",y,is),function(){ls=ls.filter(function(C){return C!==c}),document.removeEventListener("wheel",p,is),document.removeEventListener("touchmove",p,is),document.removeEventListener("touchstart",y,is)}},[]);var S=e.removeScrollBar,j=e.inert;return f.createElement(f.Fragment,null,j?f.createElement(c,{styles:vR(i)}):null,S?f.createElement(lR,{noRelative:e.noRelative,gapMode:e.gapMode}):null)}function xR(e){for(var n=null;e!==null;)e instanceof ShadowRoot&&(n=e.host,e=e.host),e=e.parentNode;return n}const SR=K9(iS,yR);var vl=f.forwardRef(function(e,n){return f.createElement(rd,ir({},e,{ref:n,sideCar:SR}))});vl.classNames=rd.classNames;var Yp=["Enter"," "],wR=["ArrowDown","PageUp","Home"],fS=["ArrowUp","PageDown","End"],CR=[...wR,...fS],jR={ltr:[...Yp,"ArrowRight"],rtl:[...Yp,"ArrowLeft"]},ER={ltr:["ArrowLeft"],rtl:["ArrowRight"]},bl="Menu",[tl,NR,kR]=Vh(bl),[go,mS]=Hk(bl,[kR,Ea,td]),ad=Ea(),pS=td(),[TR,vo]=go(bl),[RR,yl]=go(bl),hS=e=>{const{__scopeMenu:n,open:a=!1,children:o,dir:i,onOpenChange:c,modal:d=!0}=e,m=ad(n),[p,h]=f.useState(null),y=f.useRef(!1),v=Ot(c),x=dl(i);return f.useEffect(()=>{const S=()=>{y.current=!0,document.addEventListener("pointerdown",j,{capture:!0,once:!0}),document.addEventListener("pointermove",j,{capture:!0,once:!0})},j=()=>y.current=!1;return document.addEventListener("keydown",S,{capture:!0}),()=>{document.removeEventListener("keydown",S,{capture:!0}),document.removeEventListener("pointerdown",j,{capture:!0}),document.removeEventListener("pointermove",j,{capture:!0})}},[]),l.jsx(Qu,{...m,children:l.jsx(TR,{scope:n,open:a,onOpenChange:v,content:p,onContentChange:h,children:l.jsx(RR,{scope:n,onClose:f.useCallback(()=>v(!1),[v]),isUsingKeyboardRef:y,dir:x,modal:d,children:o})})})};hS.displayName=bl;var AR="MenuAnchor",Qh=f.forwardRef((e,n)=>{const{__scopeMenu:a,...o}=e,i=ad(a);return l.jsx(pl,{...i,...o,ref:n})});Qh.displayName=AR;var Jh="MenuPortal",[MR,gS]=go(Jh,{forceMount:void 0}),vS=e=>{const{__scopeMenu:n,forceMount:a,children:o,container:i}=e,c=vo(Jh,n);return l.jsx(MR,{scope:n,forceMount:a,children:l.jsx(Ht,{present:a||c.open,children:l.jsx(Is,{asChild:!0,container:i,children:o})})})};vS.displayName=Jh;var In="MenuContent",[_R,eg]=go(In),bS=f.forwardRef((e,n)=>{const a=gS(In,e.__scopeMenu),{forceMount:o=a.forceMount,...i}=e,c=vo(In,e.__scopeMenu),d=yl(In,e.__scopeMenu);return l.jsx(tl.Provider,{scope:e.__scopeMenu,children:l.jsx(Ht,{present:o||c.open,children:l.jsx(tl.Slot,{scope:e.__scopeMenu,children:d.modal?l.jsx(OR,{...i,ref:n}):l.jsx(DR,{...i,ref:n})})})})}),OR=f.forwardRef((e,n)=>{const a=vo(In,e.__scopeMenu),o=f.useRe Line truncated
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const ow=(...e)=>e.filter((n,a,o)=>!!n&&n.trim()!==""&&o.indexOf(n)===a).join(" ").trim();/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const MA=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const _A=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(n,a,o)=>o?o.toUpperCase():a.toLowerCase());/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const O1=e=>{const n=_A(e);return n.charAt(0).toUpperCase()+n.slice(1)};/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/var pp={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const OA=e=>{for(const n in e)if(n.startsWith("aria-")||n==="role"||n==="title")return!0;return!1},DA=f.createContext({}),LA=()=>f.useContext(DA),zA=f.forwardRef(({color:e,size:n,strokeWidth:a,absoluteStrokeWidth:o,className:i="",children:c,iconNode:d,...m},p)=>{const{size:h=24,strokeWidth:y=2,absoluteStrokeWidth:v=!1,color:x="currentColor",className:S=""}=LA()??{},j=o??v?Number(a??y)*24/Number(n??h):a??y;return f.createElement("svg",{ref:p,...pp,width:n??h??pp.width,height:n??h??pp.height,stroke:e??x,strokeWidth:j,className:ow("lucide",S,i),...!c&&!OA(m)&&{"aria-hidden":"true"},...m},[...d.map(([C,N])=>f.createElement(C,N)),...Array.isArray(c)?c:[c]])});/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Ur=(e,n)=>{const a=f.forwardRef(({className:o,...i},c)=>f.createElement(zA,{ref:c,iconNode:n,className:ow(`lucide-${MA(O1(e))}`,`lucide-${e}`,o),...i}));return a.displayName=O1(e),a};/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const PA=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],sw=Ur("check",PA);/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const IA=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],iw=Ur("chevron-down",IA);/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const $A=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],BA=Ur("chevron-right",$A);/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const UA=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],HA=Ur("chevron-up",UA);/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const VA=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],D1=Ur("circle-check",VA);/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const GA=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],FA=Ur("circle",GA);/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const YA=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M9 3v18",key:"fh3hqa"}]],WA=Ur("panel-left",YA);/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const qA=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],KA=Ur("search",qA);/**
* @license lucide-react v1.16.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const XA=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],lw=Ur("x",XA),og=TA,sg=RA,ZA=f.forwardRef(({className:e,inset:n,children:a,...o},i)=>l.jsxs(rw,{ref:i,className:ce("flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",n&&"pl-8",e),...o,children:[a,l.jsx(BA,{className:"ml-auto"})]}));ZA.displayName=rw.displayName;const QA=f.forwardRef(({className:e,...n},a)=>l.jsx(aw,{ref:a,className:ce("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",e),...n}));QA.displayName=aw.displayName;const id=f.forwardRef(({className:e,sideOffset:n=4,...a},o)=>l.jsx(AA,{children:l.jsx(XS,{ref:o,sideOffset:n,className:ce("z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md","data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",e),...a})}));id.displayName=XS.displayName;const rl=f.forwardRef(({className:e,inset:n,...a},o)=>l.jsx(QS,{ref:o,className:ce("relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",n&&"pl-8",e),...a}));rl.displayName=QS.displayName;const JA=f.forwardRef(({className:e,children:n,checked:a,...o},i)=>l.jsxs(JS,{ref:i,className:ce("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",e),checked:a,...o,children:[l.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:l.jsx(tw,{children:l.jsx(sw,{className:"h-4 w-4"})})}),n]}));JA.displayName=JS.displayName;const e7=f.forwardRef(({className:e,children:n,...a},o)=>l.jsxs(ew,{ref:o,className:ce("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",e),...a,children:[l.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:l.jsx(tw,{children:l.jsx(FA,{className:"h-2 w-2 fill-current"})})}),n]}));e7.displayName=ew.displayName;const ig=f.forwardRef(({className:e,inset:n,...a},o)=>l.jsx(ZS,{ref:o,className:ce("px-2 py-1.5 text-sm font-semibold",n&&"pl-8",e),...a}));ig.displayName=ZS.displayName;const Nu=f.forwardRef(({className:e,...n},a)=>l.jsx(nw,{ref:a,className:ce("-mx-1 my-1 h-px bg-muted",e),...n}));Nu.displayName=nw.displayName;const hp=768;function t7(){const[e,n]=f.useState(void 0);return f.useEffect(()=>{const a=window.matchMedia(`(max-width: ${hp-1}px)`),o=()=>{n(window.innerWidth<hp)};return a.addEventListener("change",o),n(window.innerWidth<hp),()=>a.removeEventListener("change",o)},[]),!!e}const Ue=f.forwardRef(({className:e,type:n,...a},o)=>l.jsx("input",{type:n,className:ce("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",e),ref:o,...a}));Ue.displayName="Input";var n7=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","select","span","svg","ul"],En=n7.reduce((e,n)=>{const a=S2(`Primitive.${n}`),o=f.forwardRef((i,c)=>{const{asChild:d,...m}=i,p=d?a:n;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),l.jsx(p,{...m,ref:c})});return o.displayName=`Primitive.${n}`,{...e,[n]:o}},{}),r7="Separator",L1="horizontal",a7=["horizontal","vertical"],cw=f.forwardRef((e,n)=>{const{decorative:a,orientation:o=L1,...i}=e,c=o7(o)?o:L1,m=a?{role:"none"}:{"aria-orientation":c==="vertical"?c:void 0,role:"separator"};returnLine truncated
If you want to hide the \`${n.titleName}\`, you can wrap it with our VisuallyHidden component.
For more information, see https://radix-ui.com/primitives/docs/components/${n.docsSlug}`;return f.useEffect(()=>{e&&(document.getElementById(e)||console.error(a))},[a,e]),null},w7="DialogDescriptionWarning",C7=({contentRef:e,descriptionId:n})=>{const o=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${Tw(w7).contentName}}.`;return f.useEffect(()=>{var c;const i=(c=e.current)==null?void 0:c.getAttribute("aria-describedby");n&&i&&(document.getElementById(n)||console.warn(o))},[o,e,n]),null},dg=pw,j7=gw,fg=bw,Sl=yw,wl=xw,cd=ww,ud=jw,Rw=Nw;const E7=dg,N7=fg,Aw=f.forwardRef(({className:e,...n},a)=>l.jsx(Sl,{className:ce("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",e),...n,ref:a}));Aw.displayName=Sl.displayName;const k7=Ds("fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",{variants:{side:{top:"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",bottom:"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",left:"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",right:"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"}},defaultVariants:{side:"right"}}),Mw=f.forwardRef(({side:e="right",className:n,children:a,...o},i)=>l.jsxs(N7,{children:[l.jsx(Aw,{}),l.jsxs(wl,{ref:i,className:ce(k7({side:e}),n),...o,children:[l.jsxs(Rw,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary",children:[l.jsx(lw,{className:"h-4 w-4"}),l.jsx("span",{className:"sr-only",children:"Close"})]}),a]})]}));Mw.displayName=wl.displayName;const _w=({className:e,...n})=>l.jsx("div",{className:ce("flex flex-col space-y-2 text-center sm:text-left",e),...n});_w.displayName="SheetHeader";const Ow=f.forwardRef(({className:e,...n},a)=>l.jsx(cd,{ref:a,className:ce("text-lg font-semibold text-foreground",e),...n}));Ow.displayName=cd.displayName;const Dw=f.forwardRef(({className:e,...n},a)=>l.jsx(ud,{ref:a,className:ce("text-sm text-muted-foreground",e),...n}));Dw.displayName=ud.displayName;function Ve({className:e,...n}){return l.jsx("div",{className:ce("animate-pulse rounded-md bg-primary/10",e),...n})}function T7(e,n=[]){let a=[];function o(c,d){const m=f.createContext(d),p=a.length;a=[...a,d];const h=v=>{var E;const{scope:x,children:S,...j}=v,C=((E=x==null?void 0:x[e])==null?void 0:E[p])||m,N=f.useMemo(()=>j,Object.values(j));return l.jsx(C.Provider,{value:N,children:S})};h.displayName=c+"Provider";function y(v,x){var C;const S=((C=x==null?void 0:x[e])==null?void 0:C[p])||m,j=f.useContext(S);if(j)return j;if(d!==void 0)return d;throw new Error(`\`${v}\` must be used within \`${c}\``)}return[h,y]}const i=()=>{const c=a.map(d=>f.createContext(d));return function(m){const p=(m==null?void 0:m[e])||c;return f.useMemo(()=>({[`__scope${e}`]:{...m,[e]:p}}),[m,p])}};return i.scopeName=e,[o,R7(i,...n)]}function R7(...e){const n=e[0];if(e.length===1)return n;const a=()=>{const o=e.map(i=>({useScope:i(),scopeName:i.scopeName}));return function(c){const d=o.reduce((m,{useScope:p,scopeName:h})=>{const v=p(c)[`__scope${h}`];return{...m,...v}},{});return f.useMemo(()=>({[`__scope${n.scopeName}`]:d}),[d])}};return a.scopeName=n.scopeName,a}function A7(e){const n=M7(e),a=f.forwardRef((o,i)=>{const{children:c,...d}=o,m=f.Children.toArray(c),p=m.find(O7);if(p){const h=p.props.children,y=m.map(v=>v===p?f.Children.count(h)>1?f.Children.only(null):f.isValidElement(h)?h.props.children:null:v);return l.jsx(n,{...d,ref:i,children:f.isValidElement(h)?f.cloneElement(h,void 0,y):null})}return l.jsx(n,{...d,ref:i,children:c})});return a.displayName=`${e}.Slot`,a}function M7(e){const n=f.forwardRef((a,o)=>{const{children:i,...c}=a;if(f.isValidElement(i)){const d=L7(i),m=D7(c,i.props);return i.type!==f.Fragment&&(m.ref=o?st(o,d):d),f.cloneElement(i,m)}return f.Children.count(i)>1?f.Children.only(null):null});return n.displayName=`${e}.SlotClone`,n}var Lw=Symbol("radix.slottable");function _7(e){const n=({children:a})=>l.jsx(l.Fragment,{children:a});return n.displayName=`${e}.Slottable`,n.__radixId=Lw,n}function O7(e){return f.isValidElement(e)&&typeof e.type=="function"&&"__radixId"in e.type&&e.type.__radixId===Lw}function D7(e,n){const a={...n};for(const o in n){const i=e[o],c=n[o];/^on[A-Z]/.test(o)?i&&c?a[o]=(...m)=>{const p=c(...m);return i(...m),p}:i&&(a[o]=i):o==="style"?a[o]={...i,...c}:o==="className"&&(a[o]=[i,c].filter(Boolean).join(" "))}return{...e,...a} Line truncated
* @license React
* use-sync-external-store-shim.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var B1;function P_(){if(B1)return xp;B1=1;var e=Lu();function n(v,x){return v===x&&(v!==0||1/v===1/x)||v!==v&&x!==x}var a=typeof Object.is=="function"?Object.is:n,o=e.useState,i=e.useEffect,c=e.useLayoutEffect,d=e.useDebugValue;function m(v,x){var S=x(),j=o({inst:{value:S,getSnapshot:x}}),C=j[0].inst,N=j[1];return c(function(){C.value=S,C.getSnapshot=x,p(C)&&N({inst:C})},[v,S,x]),i(function(){return p(C)&&N({inst:C}),v(function(){p(C)&&N({inst:C})})},[v]),d(S),S}function p(v){var x=v.getSnapshot;v=v.value;try{var S=x();return!a(v,S)}catch{return!0}}function h(v,x){return x()}var y=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?h:m;return xp.useSyncExternalStore=e.useSyncExternalStore!==void 0?e.useSyncExternalStore:y,xp}var U1;function I_(){return U1||(U1=1,yp.exports=P_()),yp.exports}var $_=I_();function B_(){return $_.useSyncExternalStore(U_,()=>!0,()=>!1)}function U_(){return()=>{}}var bg="Avatar",[H_]=L_(bg),[V_,bC]=H_(bg),yC=f.forwardRef((e,n)=>{const{__scopeAvatar:a,...o}=e,[i,c]=f.useState("idle");return l.jsx(V_,{scope:a,imageLoadingStatus:i,onImageLoadingStatusChange:c,children:l.jsx(En.span,{...o,ref:n})})});yC.displayName=bg;var xC="AvatarImage",SC=f.forwardRef((e,n)=>{const{__scopeAvatar:a,src:o,onLoadingStatusChange:i=()=>{},...c}=e,d=bC(xC,a),m=G_(o,c),p=Ot(h=>{i(h),d.onImageLoadingStatusChange(h)});return jt(()=>{m!=="idle"&&p(m)},[m,p]),m==="loaded"?l.jsx(En.img,{...c,ref:n,src:o}):null});SC.displayName=xC;var wC="AvatarFallback",CC=f.forwardRef((e,n)=>{const{__scopeAvatar:a,delayMs:o,...i}=e,c=bC(wC,a),[d,m]=f.useState(o===void 0);return f.useEffect(()=>{if(o!==void 0){const p=window.setTimeout(()=>m(!0),o);return()=>window.clearTimeout(p)}},[o]),d&&c.imageLoadingStatus!=="loaded"?l.jsx(En.span,{...i,ref:n}):null});CC.displayName=wC;function H1(e,n){return e?n?(e.src!==n&&(e.src=n),e.complete&&e.naturalWidth>0?"loaded":"loading"):"error":"idle"}function G_(e,{referrerPolicy:n,crossOrigin:a}){const o=B_(),i=f.useRef(null),c=o?(i.current||(i.current=new window.Image),i.current):null,[d,m]=f.useState(()=>H1(c,e));return jt(()=>{m(H1(c,e))},[c,e]),jt(()=>{const p=v=>()=>{m(v)};if(!c)return;const h=p("loaded"),y=p("error");return c.addEventListener("load",h),c.addEventListener("error",y),n&&(c.referrerPolicy=n),typeof a=="string"&&(c.crossOrigin=a),()=>{c.removeEventListener("load",h),c.removeEventListener("error",y)}},[c,a,n]),d}var jC=yC,EC=SC,NC=CC;const Ss=f.forwardRef(({className:e,...n},a)=>l.jsx(jC,{ref:a,className:ce("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",e),...n}));Ss.displayName=jC.displayName;const ws=f.forwardRef(({className:e,...n},a)=>l.jsx(EC,{ref:a,className:ce("aspect-square h-full w-full",e),...n}));ws.displayName=EC.displayName;const Cs=f.forwardRef(({className:e,...n},a)=>l.jsx(NC,{ref:a,className:ce("flex h-full w-full items-center justify-center rounded-full bg-muted",e),...n}));Cs.displayName=NC.displayName;const kC=f.createContext(null);function F_({children:e}){const[n,a]=f.useState([]),[o,i]=f.useState(0),[c,d]=f.useState(!0),m=f.useCallback(async()=>{try{const v=await Ne.getNotifications();v.data&&(a(v.data.items),i(v.data.unreadCount))}catch{}finally{d(!1)}},[]),p=f.useCallback(async()=>{var v;try{const x=await Ne.markNotificationsRead("all");a(S=>S.map(j=>({...j,read:!0}))),i(((v=x.data)==null?void 0:v.unreadCount)??0)}catch{}},[]),h=f.useCallback(async v=>{var x;try{const S=await Ne.dismissNotification(v);a(j=>j.filter(C=>C.id!==v)),i(((x=S.data)==null?void 0:x.unreadCount)??0)}catch{}},[]);f.useEffect(()=>{m();const v=setInterval(m,3e4);return()=>clearInterval(v)},[m]);const y=f.useMemo(()=>({items:n,unreadCount:o,loading:c,refresh:m,markAllRead:p,dismiss:h}),[n,o,c,m,p,h]);return l.jsx(kC.Provider,{value:y,children:e})}function Y_(){const e=f.useContext(kC);if(!e)throw new Error("useNotifications must be used within NotificationsProvider");return e}const W_=Ds("inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",secondary:"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",destructive:"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",outline:"text-foreground"}},defaultVariants:{variant:"default"}});function gs({className:e,variant:n,...a}){return l.jsx("div",{className:ce(W_({variant:n}),e),...a})}function q_(e){const n=K_(e),a=f.forwardRef((o,i)=>{const{children:c,...d}=o,m=f.Children.toArray(c),p=m.find(Z_);if(p){const h=p.props.children,y=m.map(v=>v===p?f.Children.count(h)>1?f.Children.only(null):f.isValidElement(h)?h.props.children:null:v);return l.jsx(n,{...d,ref:i,children:f.isValidElement(h)?f.cloneElement(h,void 0,y):null})}return l.jsx(n,{...d,ref:i,children:c})});return a.displayName=`${e}.SLine truncated
--num-groups: ${c.groups.length};
--indicator-opacity: ${c.searchMode?0:1};
--num-skintones: ${Q1};`}),d(()=>{c.customEmoji&&c.database&&z()}),d(()=>{c.customEmoji&&c.customEmoji.length?c.groups!==vh&&(c.groups=vh):c.groups!==Cp&&(c.currentGroupIndex&&c.currentGroupIndex--,c.groups=Cp)}),d(()=>{async function W(){c.databaseLoaded&&(c.currentSkinTone=await c.database.getPreferredSkinTone())}W()}),d(()=>{c.skinTones=Array(Q1).fill().map((W,ie)=>Pz(c.skinToneEmoji,ie))}),d(()=>{c.skinToneButtonText=c.skinTones[c.currentSkinTone]}),d(()=>{c.skinToneButtonLabel=c.i18n.skinToneLabel.replace("{skinTone}",c.i18n.skinTones[c.currentSkinTone])}),d(()=>{async function W(){const{database:ie}=c,ge=(await Promise.all(kz.map(je=>ie.getEmojiByUnicodeOrName(je)))).filter(Boolean);c.defaultFavoriteEmojis=ge}c.databaseLoaded&&W()});function z(){const{customEmoji:W,database:ie}=c,ge=W||Rp;ie.customEmoji!==ge&&(ie.customEmoji=ge)}d(()=>{async function W(){z();const{database:ie,defaultFavoriteEmojis:ge,numColumns:je}=c,Ae=await ie.getTopFavoriteEmoji(je),tt=await he(D5([...Ae,...ge],ct=>ct.unicode||ct.name).slice(0,je));c.currentFavorites=tt}c.databaseLoaded&&c.defaultFavoriteEmojis&&W()});function B(W){Bz(W,i,()=>{{const ie=getComputedStyle(a.rootElement),ge=parseInt(ie.getPropertyValue("--num-columns"),10),je=ie.getPropertyValue("direction")==="rtl";c.numColumns=ge,c.isRtl=je}})}function H(W){sP(W,i,ie=>{for(const{target:ge,isIntersecting:je}of ie)ge.classList.toggle("onscreen",je)})}d(()=>{async function W(){const{searchText:ie,currentGroup:ge,databaseLoaded:je,customEmoji:Ae}=c;if(!je)c.currentEmojis=[],c.searchMode=!1;else if(ie.length>=wz){const tt=await O(ie);c.searchText===ie&&(S(tt),j(!0))}else{const{id:tt}=ge;if(tt!==-1||Ae&&Ae.length){const ct=await se(tt);c.currentGroup.id===tt&&(S(ct),j(!1))}}}W()});const Y=()=>{du(()=>Gz(a.tabpanelElement))};d(()=>{const{currentEmojis:W,emojiVersion:ie}=c,ge=W.filter(je=>je.unicode).filter(je=>J1(je)&&!bh.has(je.unicode));if(!ie&&ge.length)S(W),du(()=>Q(ge));else{const je=ie?W:W.filter(fe);S(je),Y()}});function Q(W){Hz(W,a.baselineEmoji,h)?Y():c.currentEmojis=[...c.currentEmojis]}function fe(W){return!W.unicode||!J1(W)||bh.get(W.unicode)}async function de(W){const ie=c.emojiVersion||await Ep();return W.filter(({version:ge})=>!ge||ge<=ie)}async function he(W){return Iz(W,c.emojiVersion||await Ep())}async function se(W){const ie=W===-1?c.customEmoji:await c.database.getEmojiByGroup(W);return he(await de(ie))}async function O(W){return he(await de(await c.database.getEmojiBySearchQuery(W)))}d(()=>{}),d(()=>{function W(){const{searchMode:ge,currentEmojis:je}=c;if(ge)return[{category:"",emojis:je}];const Ae=new Map;for(const tt of je){const ct=tt.category||"";let kt=Ae.get(ct);kt||(kt=[],Ae.set(ct,kt)),kt.push(tt)}return[...Ae.entries()].map(([tt,ct])=>({category:tt,emojis:ct})).sort((tt,ct)=>c.customCategorySorting(tt.category,ct.category))}const ie=W();C(ie)}),d(()=>{c.activeSearchItemId=c.activeSearchItem!==-1&&c.currentEmojis[c.activeSearchItem].id}),d(()=>{const{rawSearchText:W}=c;_5(()=>{c.searchText=(W||"").trim(),c.activeSearchItem=-1})});function $(W){if(!c.searchMode||!c.currentEmojis.length)return;const ie=ge=>{or(W),c.activeSearchItem=Np(ge,c.activeSearchItem,c.currentEmojis)};switch(W.key){case"ArrowDown":return ie(!1);case"ArrowUp":return ie(!0);case"Enter":if(c.activeSearchItem===-1)c.activeSearchItem=0;else return or(W),M(c.currentEmojis[c.activeSearchItem].id)}}function Z(W){const{target:ie}=W,ge=ie.closest(".nav-button");if(!ge)return;const je=parseInt(ge.dataset.groupId,10);a.searchElement.value="",c.rawSearchText="",c.searchText="",c.activeSearchItem=-1,c.currentGroupIndex=c.groups.findIndex(Ae=>Ae.id===je)}function J(W){const{target:ie,key:ge}=W,je=Ae=>{Ae&&(or(W),Ae.focus())};switch(ge){case"ArrowLeft":return je(ie.previousElementSibling);case"ArrowRight":return je(ie.nextElementSibling);case"Home":return je(ie.parentElement.firstElementChild);case"End":return je(ie.parentElement.lastElementChild)}}async function te(W){const ie=await c.database.getEmojiByUnicodeOrName(W),ge=[...c.currentEmojis,...c.currentFavorites].find(Ae=>Ae.id===W),je=ge.unicode&&N(ge,c.currentSkinTone);return await c.database.incrementFavoriteEmojiCount(W),{emoji:ie,skinTone:c.currentSkinTone,...je&&{unicode:je},...ge.name&&{name:ge.name}}}async function M(W){const ie=te(W);y("emoji-click-sync",ie),y("emoji-click",await ie)}function _(W){const{target:ie}=W;if(!ie.classList.contains("emoji"))return;or(W);const ge=ie.id.substring(4);M(ge)}function U(W){c.currentSkinTone=W,c.skinTonePickerExpanded=!1,p("skintone-button"),y("skin-tone-change",{skinTone:W}),c.database.setPreferredSkinTone(W)}function V(W){const{target:{id:ie}}=W,ge=ie&&ie.match(/^skintone-(\d)/);if(!ge)return;or(W);const je=parseInt(ge[1],10);U(je)}function F(W){c.skinTonePickerExpanded=!c.skinTonePickerExpanded,c.activeSkinTone=c.currentSkinTone,c.skinTonePickerExpanded&&(or(W),du(()=>p("skintone-list")))}d(()=>{c.skinTonePickerExpanded?a.skinToneDropdown.addEventListener("transitionend",()=>{c.ski Line truncated
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function f0(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),a.push.apply(a,o)}return a}function m0(e){for(var n=1;n<arguments.length;n++){var a=arguments[n]!=null?arguments[n]:{};n%2?f0(Object(a),!0).forEach(function(o){QP(e,o,a[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):f0(Object(a)).forEach(function(o){Object.defineProperty(e,o,Object.getOwnPropertyDescriptor(a,o))})}return e}function tI(e,n){if(e==null)return{};var a,o,i=nI(e,n);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;o<c.length;o++)a=c[o],n.indexOf(a)===-1&&{}.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}function nI(e,n){if(e==null)return{};var a={};for(var o in e)if({}.hasOwnProperty.call(e,o)){if(n.indexOf(o)!==-1)continue;a[o]=e[o]}return a}function rI(e,n){return ZP(e)||JP(e,n)||sI(e,n)||eI()}function aI(e,n){if(typeof e!="object"||!e)return e;var a=e[Symbol.toPrimitive];if(a!==void 0){var o=a.call(e,n);if(typeof o!="object")return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return(n==="string"?String:Number)(e)}function oI(e){var n=aI(e,"string");return typeof n=="symbol"?n:n+""}function sI(e,n){if(e){if(typeof e=="string")return d0(e,n);var a={}.toString.call(e).slice(8,-1);return a==="Object"&&e.constructor&&(a=e.constructor.name),a==="Map"||a==="Set"?Array.from(e):a==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?d0(e,n):void 0}}function iI(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function p0(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),a.push.apply(a,o)}return a}function h0(e){for(var n=1;n<arguments.length;n++){var a=arguments[n]!=null?arguments[n]:{};n%2?p0(Object(a),!0).forEach(function(o){iI(e,o,a[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):p0(Object(a)).forEach(function(o){Object.defineProperty(e,o,Object.getOwnPropertyDescriptor(a,o))})}return e}function lI(){for(var e=arguments.length,n=new Array(e),a=0;a<e;a++)n[a]=arguments[a];return function(o){return n.reduceRight(function(i,c){return c(i)},o)}}function Vi(e){return function n(){for(var a=this,o=arguments.length,i=new Array(o),c=0;c<o;c++)i[c]=arguments[c];return i.length>=e.length?e.apply(this,i):function(){for(var d=arguments.length,m=new Array(d),p=0;p<d;p++)m[p]=arguments[p];return n.apply(a,[].concat(i,m))}}}function Du(e){return{}.toString.call(e).includes("Object")}function cI(e){return!Object.keys(e).length}function ll(e){return typeof e=="function"}function uI(e,n){return Object.prototype.hasOwnProperty.call(e,n)}function dI(e,n){return Du(n)||ya("changeType"),Object.keys(n).some(function(a){return!uI(e,a)})&&ya("changeField"),n}function fI(e){ll(e)||ya("selectorType")}function mI(e){ll(e)||Du(e)||ya("handlerType"),Du(e)&&Object.values(e).some(function(n){return!ll(n)})&&ya("handlersType")}function pI(e){e||ya("initialIsRequired"),Du(e)||ya("initialType"),cI(e)&&ya("initialContent")}function hI(e,n){throw new Error(e[n]||e.default)}var gI={initialIsRequired:"initial state is required",initialType:"initial state should be an object",initialContent:"initial state shouldn't be an empty object",handlerType:"handler should be an object or a function",handlersType:"all handlers should be a functions",selectorType:"selector should be a function",changeType:"provided value of changes should be an object",changeField:'it seams you want to change a field in the state which is not specified in the "initial" state',default:"an unknown error accured in `state-local` package"},ya=Vi(hI)(gI),nu={changes:dI,selector:fI,handler:mI,initial:pI};function vI(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};nu.initial(e),nu.handler(n);var a={current:e},o=Vi(xI)(a,n),i=Vi(yI)(a),c=Vi(nu.changes)(e),d=Vi(bI)(a);function m(){var h=arguments.length>0&&arguments[0]!==void 0?arguments[0]:function(y){return y};return nu.selector(h),h(a.current)}function p(h){lI(o,i,c,d)(h)}return[m,p]}function bI(e,n){return ll(n)?n(e.current):n}function yI(e,n){return e.current=h0(h0({},e.current),n),n}function xI(e,n,a){return ll(n)?n(e.current):Object.keys(a).forEach(function(o){var i;return(i=n[o])===null||i===void 0?void 0:i.call(n,e.current[o])}),a}var SI={create:vI},wI={paths:{vs:"https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs"}};function CI(e){return function n(){for(var a=this,o=arguments.length,i=new Array(o),c=0;c<o;c++)i[c]=arguments[c];return i.length>=e.length?e.apply(this,i):function(){for(var d=arguments.length,m=new Array(d),p=0;p<d;p++)m[p]=arguments[p]; Line truncated
You are using deprecated way of configuration.
Instead of using
monaco.config({ urls: { monacoBase: '...' } })
use
monaco.config({ paths: { vs: '...' } })
For more please check the link https://github.com/suren-atoyan/monaco-loader#config
`},g0=CI(kI)($5),TI={config:EI},RI=function(){for(var n=arguments.length,a=new Array(n),o=0;o<n;o++)a[o]=arguments[o];return function(i){return a.reduceRight(function(c,d){return d(c)},i)}};function B5(e,n){return Object.keys(n).forEach(function(a){n[a]instanceof Object&&e[a]&&Object.assign(n[a],B5(e[a],n[a]))}),m0(m0({},e),n)}var AI={type:"cancelation",msg:"operation is manually canceled"};function Ap(e){var n=!1,a=new Promise(function(o,i){e.then(function(c){return n?i(AI):o(c)}),e.catch(i)});return a.cancel=function(){return n=!0},a}var MI=["monaco"],_I=SI.create({config:wI,isInitialized:!1,resolve:null,reject:null,monaco:null}),U5=rI(_I,2),kl=U5[0],Md=U5[1];function OI(e){var n=TI.config(e),a=n.monaco,o=tI(n,MI);Md(function(i){return{config:B5(i.config,o),monaco:a}})}function DI(){var e=kl(function(n){var a=n.monaco,o=n.isInitialized,i=n.resolve;return{monaco:a,isInitialized:o,resolve:i}});if(!e.isInitialized){if(Md({isInitialized:!0}),e.monaco)return e.resolve(e.monaco),Ap(Mp);if(window.monaco&&window.monaco.editor)return H5(window.monaco),e.resolve(window.monaco),Ap(Mp);RI(LI,PI)(II)}return Ap(Mp)}function LI(e){return document.body.appendChild(e)}function zI(e){var n=document.createElement("script");return e&&(n.src=e),n}function PI(e){var n=kl(function(o){var i=o.config,c=o.reject;return{config:i,reject:c}}),a=zI("".concat(n.config.paths.vs,"/loader.js"));return a.onload=function(){return e()},a.onerror=n.reject,a}function II(){var e=kl(function(a){var o=a.config,i=a.resolve,c=a.reject;return{config:o,resolve:i,reject:c}}),n=window.require;n.config(e.config),n(["vs/editor/editor.main"],function(a){var o=a.m||a;H5(o),e.resolve(o)},function(a){e.reject(a)})}function H5(e){kl().monaco||Md({monaco:e})}function $I(){return kl(function(e){var n=e.monaco;return n})}var Mp=new Promise(function(e,n){return Md({resolve:e,reject:n})}),V5={config:OI,init:DI,__getMonacoInstance:$I},BI={wrapper:{display:"flex",position:"relative",textAlign:"initial"},fullWidth:{width:"100%"},hide:{display:"none"}},_p=BI,UI={container:{display:"flex",height:"100%",width:"100%",justifyContent:"center",alignItems:"center"}},HI=UI;function VI({children:e}){return ue.createElement("div",{style:HI.container},e)}var GI=VI,FI=GI;function YI({width:e,height:n,isEditorReady:a,loading:o,_ref:i,className:c,wrapperProps:d}){return ue.createElement("section",{style:{..._p.wrapper,width:e,height:n},...d},!a&&ue.createElement(FI,null,o),ue.createElement("div",{ref:i,style:{..._p.fullWidth,...!a&&_p.hide},className:c}))}var WI=YI,G5=f.memo(WI);function qI(e){f.useEffect(e,[])}var F5=qI;function KI(e,n,a=!0){let o=f.useRef(!0);f.useEffect(o.current||!a?()=>{o.current=!1}:e,n)}var xn=KI;function qi(){}function ms(e,n,a,o){return XI(e,o)||ZI(e,n,a,o)}function XI(e,n){return e.editor.getModel(Y5(e,n))}function ZI(e,n,a,o){return e.editor.createModel(n,a,o?Y5(e,o):void 0)}function Y5(e,n){return e.Uri.parse(n)}function QI({original:e,modified:n,language:a,originalLanguage:o,modifiedLanguage:i,originalModelPath:c,modifiedModelPath:d,keepCurrentOriginalModel:m=!1,keepCurrentModifiedModel:p=!1,theme:h="light",loading:y="Loading...",options:v={},height:x="100%",width:S="100%",className:j,wrapperProps:C={},beforeMount:N=qi,onMount:E=qi}){let[k,T]=f.useState(!1),[R,D]=f.useState(!0),P=f.useRef(null),z=f.useRef(null),B=f.useRef(null),H=f.useRef(E),Y=f.useRef(N),Q=f.useRef(!1);F5(()=>{let se=V5.init();return se.then(O=>(z.current=O)&&D(!1)).catch(O=>(O==null?void 0:O.type)!=="cancelation"&&console.error("Monaco initialization: error:",O)),()=>P.current?he():se.cancel()}),xn(()=>{if(P.current&&z.current){let se=P.current.getOriginalEditor(),O=ms(z.current,e||"",o||a||"text",c||"");O!==se.getModel()&&se.setModel(O)}},[c],k),xn(()=>{if(P.current&&z.current){let se=P.current.getModifiedEditor(),O=ms(z.current,n||"",i||a||"text",d||"");O!==se.getModel()&&se.setModel(O)}},[d],k),xn(()=>{let se=P.current.getModifiedEditor();se.getOption(z.current.editor.EditorOption.readOnly)?se.setValue(n||""):n!==se.getValue()&&(se.executeEdits("",[{range:se.getModel().getFullModelRange(),text:n||"",forceMoveMarkers:!0}]),se.pushUndoStop())},[n],k),xn(()=>{var se,O;(O=(se=P.current)==null?void 0:se.getModel())==null||O.original.setValue(e||"")},[e],k),xn(()=>{let{original:se,modified:O}=P.current.getModel();z.current.editor.setModelLanguage(se,o||a||"text"),z.current.editor.setModelLanguage(O,i||a||"text")},[a,o,i],k),xn(()=>{var se;(se=z.current)==null||se.editor.setTheme(h)},[h],k),xn(()=>{var se;(se=P.current)==null||se.updateOptions(v)},[v],k);let fe=f.useCallback(()=>{var $;if(!z.current)return;Y.current(z.current);let se=ms(z.current,e||"",o||a||"text",c||""),O=ms(z.current,n||"",i||a||"text",d||"");($=P.current)==null||$.setModel({original:se,modified:O})},[a,n,i,e,o,c,d]),de=f.useCallback(()=>{var se;!Q.current&&B.current&&(P.current=z.current.editor.createDiffEditor(B.current,{automaticLayout:!0,...v}),fe(),(se=z.current)==null||se.editor.setTheme(h),T(!0),Q.current=!0 Line truncated
987654321098765432`,className:"min-h-[120px] font-mono text-sm"})]}),l.jsx(Us,{result:a.owners}),l.jsx("div",{className:"mt-auto",children:l.jsx(ve,{type:"button",variant:"secondary",disabled:o||!e.ownerUserIds.trim(),onClick:i,children:o?"Checking with Discord…":"Verify owner IDs"})})]})}function k$({onContinue:e}){return l.jsx("div",{className:"mx-auto flex w-full max-w-lg flex-1 flex-col justify-center py-8",children:l.jsxs("div",{className:"rounded-2xl border border-border bg-card px-6 py-10 text-center md:px-10",children:[l.jsx("div",{className:"mx-auto mb-6 flex size-16 items-center justify-center rounded-2xl bg-primary/10 text-primary",children:l.jsx(ye,{icon:Bu,size:40})}),l.jsx("h2",{className:"text-2xl font-semibold tracking-tight",children:"Setup complete"}),l.jsxs("p",{className:"mx-auto mt-3 max-w-sm text-sm leading-relaxed text-muted-foreground",children:["Your configuration has been saved. Restart the server for changes to take effect — stop the running process, then start it again (for example"," ",l.jsx("code",{className:"rounded-md bg-muted px-1.5 py-0.5 font-mono text-xs",children:"npm start"}),")."]}),l.jsx(Ye,{className:"mt-6 text-left",children:l.jsx(We,{children:"After restarting, sign in with Discord to open the dashboard."})}),l.jsx(ve,{type:"button",size:"lg",className:"mt-8 min-w-[220px]",onClick:e,children:"Continue to sign in"})]})})}function T$({currentIndex:e,validating:n,saving:a,onBack:o,onNext:i,onFinish:c}){const d=e===bs.length-1;return l.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[l.jsxs(ve,{type:"button",variant:"ghost",disabled:e===0||a,onClick:o,children:[l.jsx(ye,{icon:G0,size:18,className:"mr-1"}),"Back"]}),l.jsx("div",{className:"flex flex-1 justify-end gap-2",children:d?l.jsx(ve,{type:"button",size:"lg",disabled:a||n,onClick:c,className:"min-w-[200px]",children:a?"Saving…":"Finish setup"}):l.jsxs(ve,{type:"button",size:"lg",disabled:n||a,onClick:i,children:["Continue",l.jsx(ye,{icon:Oh,size:18,className:"ml-1"})]})})]})}function R$({values:e,setValues:n,validation:a,validating:o,onValidate:i}){return l.jsxs("div",{className:"flex flex-1 flex-col gap-5",children:[l.jsxs("p",{className:"text-sm leading-relaxed text-muted-foreground",children:["An Emerald Services API key is optional, but required to use the one-click addon installer in the dashboard. You can get yours from the"," ",l.jsx("a",{href:"https://emeraldsrv.dev",target:"_blank",rel:"noreferrer",className:"font-medium text-primary hover:underline",children:"Emerald Services Marketplace"}),"."]}),l.jsxs("div",{className:"space-y-2",children:[l.jsx(De,{htmlFor:"emeraldApiKey",children:"Emerald API key (Optional)"}),l.jsx(Ue,{id:"emeraldApiKey",type:"password",autoComplete:"off",value:e.emeraldApiKey,onChange:c=>n({...e,emeraldApiKey:c.target.value}),placeholder:"em_...",className:"h-11 font-mono text-sm"})]}),l.jsx(Us,{result:a.emeraldApi}),l.jsx("div",{className:"mt-auto",children:l.jsx(ve,{type:"button",variant:"secondary",disabled:o,onClick:i,children:o?"Checking…":e.emeraldApiKey?"Verify key":"Skip step"})})]})}function A$(){const e=crypto.randomUUID().replace(/-/g,""),n=crypto.randomUUID().replace(/-/g,"");return e+n}function M$(e){return e.split(/[\s,]+/).map(n=>n.trim()).filter(Boolean)}function v0(e){return e==="oauth"?"oauth":e==="owners"?"owners":e==="emeraldApi"?"emeraldApi":e}function _$(){const e=mo(),{branding:n}=Fu(),{loading:a,error:o,refresh:i,status:c}=GC(),[d,m]=f.useState(0),[p,h]=f.useState({botToken:"",secretKey:"",clientId:"",clientSecret:"",redirectUri:"",ownerUserIds:"",emeraldApiKey:""}),[y,v]=f.useState({}),[x,S]=f.useState(!1),[j,C]=f.useState(!1),[N,E]=f.useState(""),[k,T]=f.useState(!1),R=bs[d];f.useEffect(()=>{c!=null&&c.suggestedRedirectUri&&!p.redirectUri&&h(Q=>({...Q,redirectUri:c.suggestedRedirectUri}))},[c==null?void 0:c.suggestedRedirectUri,p.redirectUri]);const D=f.useMemo(()=>({botToken:p.botToken,secretKey:p.secretKey,clientId:p.clientId,clientSecret:p.clientSecret,redirectUri:p.redirectUri,ownerUserIds:M$(p.ownerUserIds),emeraldApiKey:p.emeraldApiKey}),[p]);async function P(){S(!0),E("");try{const Q=await Ne.validateSetup(D);return v(fe=>{var de;return{...fe,...(de=Q.data)==null?void 0:de.results}}),Q.data}catch(Q){return E(Q instanceof Error?Q.message:"Validation failed"),null}finally{S(!1)}}async function z(){var de,he;const Q=v0(R.id),fe=await P();return!!((he=(de=fe==null?void 0:fe.results)==null?void 0:de[Q])!=null&&he.ok)}async function B(){const Q=v0(R.id),fe=y[Q];!(fe!=null&&fe.ok)&&!await z()||m(de=>Math.min(de+1,bs.length-1))}async function H(){C(!0),E("");try{const Q=await P();if(!(Q!=null&&Q.ok)){E("Fix the steps marked with errors before finishing.");return}await Ne.completeSetup(D),T(!0)}catch(Q){E(Q instanceof Error?Q.message:"Could not save setup")}finally{C(!1)}}function Y(){const Q={values:p,setValues:h,validation:y,validating:x};switch(R.id){case"botToken":return l.jsx(w$,{...Q,onValidate:()=>void z()} Line truncated
+180
View File
@@ -0,0 +1,180 @@
var w3=Object.defineProperty;var xy=t=>{throw TypeError(t)};var j3=(t,n,a)=>n in t?w3(t,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[n]=a;var by=(t,n,a)=>j3(t,typeof n!="symbol"?n+"":n,a),vy=(t,n,a)=>n.has(t)||xy("Cannot "+a);var pn=(t,n,a)=>(vy(t,n,"read from private field"),a?a.call(t):n.get(t)),yy=(t,n,a)=>n.has(t)?xy("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(t):n.set(t,a),dp=(t,n,a,o)=>(vy(t,n,"write to private field"),o?o.call(t,a):n.set(t,a),a);function C3(t,n){for(var a=0;a<n.length;a++){const o=n[a];if(typeof o!="string"&&!Array.isArray(o)){for(const c in o)if(c!=="default"&&!(c in t)){const l=Object.getOwnPropertyDescriptor(o,c);l&&Object.defineProperty(t,c,l.get?l:{enumerable:!0,get:()=>o[c]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}(function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const c of document.querySelectorAll('link[rel="modulepreload"]'))o(c);new MutationObserver(c=>{for(const l of c)if(l.type==="childList")for(const d of l.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&o(d)}).observe(document,{childList:!0,subtree:!0});function a(c){const l={};return c.integrity&&(l.integrity=c.integrity),c.referrerPolicy&&(l.referrerPolicy=c.referrerPolicy),c.crossOrigin==="use-credentials"?l.credentials="include":c.crossOrigin==="anonymous"?l.credentials="omit":l.credentials="same-origin",l}function o(c){if(c.ep)return;c.ep=!0;const l=a(c);fetch(c.href,l)}})();function s2(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var fp={exports:{}},Sl={};/**
* @license React
* react-jsx-runtime.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var wy;function S3(){if(wy)return Sl;wy=1;var t=Symbol.for("react.transitional.element"),n=Symbol.for("react.fragment");function a(o,c,l){var d=null;if(l!==void 0&&(d=""+l),c.key!==void 0&&(d=""+c.key),"key"in c){l={};for(var m in c)m!=="key"&&(l[m]=c[m])}else l=c;return c=l.ref,{$$typeof:t,type:o,key:d,ref:c!==void 0?c:null,props:l}}return Sl.Fragment=n,Sl.jsx=a,Sl.jsxs=a,Sl}var jy;function N3(){return jy||(jy=1,fp.exports=S3()),fp.exports}var s=N3(),mp={exports:{}},ze={};/**
* @license React
* react.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Cy;function E3(){if(Cy)return ze;Cy=1;var t=Symbol.for("react.transitional.element"),n=Symbol.for("react.portal"),a=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),c=Symbol.for("react.profiler"),l=Symbol.for("react.consumer"),d=Symbol.for("react.context"),m=Symbol.for("react.forward_ref"),p=Symbol.for("react.suspense"),g=Symbol.for("react.memo"),b=Symbol.for("react.lazy"),v=Symbol.for("react.activity"),w=Symbol.iterator;function y(O){return O===null||typeof O!="object"?null:(O=w&&O[w]||O["@@iterator"],typeof O=="function"?O:null)}var C={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},S=Object.assign,N={};function E(O,D,B){this.props=O,this.context=D,this.refs=N,this.updater=B||C}E.prototype.isReactComponent={},E.prototype.setState=function(O,D){if(typeof O!="object"&&typeof O!="function"&&O!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,O,D,"setState")},E.prototype.forceUpdate=function(O){this.updater.enqueueForceUpdate(this,O,"forceUpdate")};function T(){}T.prototype=E.prototype;function M(O,D,B){this.props=O,this.context=D,this.refs=N,this.updater=B||C}var k=M.prototype=new T;k.constructor=M,S(k,E.prototype),k.isPureReactComponent=!0;var _=Array.isArray;function R(){}var L={H:null,A:null,T:null,S:null},ne=Object.prototype.hasOwnProperty;function X(O,D,B){var V=B.ref;return{$$typeof:t,type:O,key:D,ref:V!==void 0?V:null,props:B}}function I(O,D){return X(O.type,D,O.props)}function H(O){return typeof O=="object"&&O!==null&&O.$$typeof===t}function q(O){var D={"=":"=0",":":"=2"};return"$"+O.replace(/[=:]/g,function(B){return D[B]})}var ce=/\/+/g;function de(O,D){return typeof O=="object"&&O!==null&&O.key!=null?q(""+O.key):D.toString(36)}function se(O){switch(O.status){case"fulfilled":return O.value;case"rejected":throw O.reason;default:switch(typeof O.status=="string"?O.then(R,R):(O.status="pending",O.then(function(D){O.status==="pending"&&(O.status="fulfilled",O.value=D)},function(D){O.status==="pending"&&(O.status="rejected",O.reason=D)})),O.status){case"fulfilled":return O.value;case"rejected":throw O.reason}}throw O}function P(O,D,B,V,Z){var be=typeof O;(be==="undefined"||be==="boolean")&&(O=null);var K=!1;if(O===null)K=!0;else switch(be){case"bigint":case"string":case"number":K=!0;break;case"object":switch(O.$$typeof){case t:case n:K=!0;break;case b:return K=O._init,P(K(O._payload),D,B,V,Z)}}if(K)return Z=Z(O),K=V===""?"."+de(O,0):V,_(Z)?(B="",K!=null&&(B=K.replace(ce,"$&/")+"/"),P(Z,D,B,"",function($){return $})):Z!=null&&(H(Z)&&(Z=I(Z,B+(Z.key==null||O&&O.key===Z.key?"":(""+Z.key).replace(ce,"$&/")+"/")+K)),D.push(Z)),1;K=0;var ge=V===""?".":V+":";if(_(O))for(var me=0;me<O.length;me++)V=O[me],be=ge+de(V,me),K+=P(V,D,B,be,Z);else if(me=y(O),typeof me=="function")for(O=me.call(O),me=0;!(V=O.next()).done;)V=V.value,be=ge+de(V,me++),K+=P(V,D,B,be,Z);else if(be==="object"){if(typeof O.then=="function")return P(se(O),D,B,V,Z);throw D=String(O),Error("Objects are not valid as a React child (found: "+(D==="[object Object]"?"object with keys {"+Object.keys(O).join(", ")+"}":D)+"). If you meant to render a collection of children, use an array instead.")}return K}function W(O,D,B){if(O==null)return O;var V=[],Z=0;return P(O,V,"","",function(be){return D.call(B,be,Z++)}),V}function oe(O){if(O._status===-1){var D=O._result;D=D(),D.then(function(B){(O._status===0||O._status===-1)&&(O._status=1,O._result=B)},function(B){(O._status===0||O._status===-1)&&(O._status=2,O._result=B)}),O._status===-1&&(O._status=0,O._result=D)}if(O._status===1)return O._result.default;throw O._result}var ae=typeof reportError=="function"?reportError:function(O){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var D=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof O=="object"&&O!==null&&typeof O.message=="string"?String(O.message):String(O),error:O});if(!window.dispatchEvent(D))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",O);return}console.error(O)},G={map:W,forEach:function(O,D,B){W(O,function(){D.apply(this,arguments)},B)},count:function(O){var D=0;return W(O,function(){D++}),D},toArray:function(O){return W(O,function(D){return D})||[]},only:function(O){if(!H(O))throw Error("React.Children.only expected to receive a single React element child.");return O}};return ze.Activity=v,ze.Children=G,ze.Component=E,ze.Fragment=a,ze.Profiler=c,ze.PureComponent=M,ze.StrictMode=o,ze.Suspense=p,ze.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=L,ze.__COMPILER_RUNTIME={__proto__:null,c:function(O){return L.H.useMemoCache(O)}},ze.cache=function(O){return function(){return O.apply(null,arguments)}},ze.cacheSignal=function(){return null},ze.cloneElement=function(O,D,B){if(O==null)throw Error("The argument must be a React element, but Line truncated
* @license React
* scheduler.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Ny;function k3(){return Ny||(Ny=1,(function(t){function n(P,W){var oe=P.length;P.push(W);e:for(;0<oe;){var ae=oe-1>>>1,G=P[ae];if(0<c(G,W))P[ae]=W,P[oe]=G,oe=ae;else break e}}function a(P){return P.length===0?null:P[0]}function o(P){if(P.length===0)return null;var W=P[0],oe=P.pop();if(oe!==W){P[0]=oe;e:for(var ae=0,G=P.length,O=G>>>1;ae<O;){var D=2*(ae+1)-1,B=P[D],V=D+1,Z=P[V];if(0>c(B,oe))V<G&&0>c(Z,B)?(P[ae]=Z,P[V]=oe,ae=V):(P[ae]=B,P[D]=oe,ae=D);else if(V<G&&0>c(Z,oe))P[ae]=Z,P[V]=oe,ae=V;else break e}}return W}function c(P,W){var oe=P.sortIndex-W.sortIndex;return oe!==0?oe:P.id-W.id}if(t.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var l=performance;t.unstable_now=function(){return l.now()}}else{var d=Date,m=d.now();t.unstable_now=function(){return d.now()-m}}var p=[],g=[],b=1,v=null,w=3,y=!1,C=!1,S=!1,N=!1,E=typeof setTimeout=="function"?setTimeout:null,T=typeof clearTimeout=="function"?clearTimeout:null,M=typeof setImmediate<"u"?setImmediate:null;function k(P){for(var W=a(g);W!==null;){if(W.callback===null)o(g);else if(W.startTime<=P)o(g),W.sortIndex=W.expirationTime,n(p,W);else break;W=a(g)}}function _(P){if(S=!1,k(P),!C)if(a(p)!==null)C=!0,R||(R=!0,q());else{var W=a(g);W!==null&&se(_,W.startTime-P)}}var R=!1,L=-1,ne=5,X=-1;function I(){return N?!0:!(t.unstable_now()-X<ne)}function H(){if(N=!1,R){var P=t.unstable_now();X=P;var W=!0;try{e:{C=!1,S&&(S=!1,T(L),L=-1),y=!0;var oe=w;try{t:{for(k(P),v=a(p);v!==null&&!(v.expirationTime>P&&I());){var ae=v.callback;if(typeof ae=="function"){v.callback=null,w=v.priorityLevel;var G=ae(v.expirationTime<=P);if(P=t.unstable_now(),typeof G=="function"){v.callback=G,k(P),W=!0;break t}v===a(p)&&o(p),k(P)}else o(p);v=a(p)}if(v!==null)W=!0;else{var O=a(g);O!==null&&se(_,O.startTime-P),W=!1}}break e}finally{v=null,w=oe,y=!1}W=void 0}}finally{W?q():R=!1}}}var q;if(typeof M=="function")q=function(){M(H)};else if(typeof MessageChannel<"u"){var ce=new MessageChannel,de=ce.port2;ce.port1.onmessage=H,q=function(){de.postMessage(null)}}else q=function(){E(H,0)};function se(P,W){L=E(function(){P(t.unstable_now())},W)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(P){P.callback=null},t.unstable_forceFrameRate=function(P){0>P||125<P?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):ne=0<P?Math.floor(1e3/P):5},t.unstable_getCurrentPriorityLevel=function(){return w},t.unstable_next=function(P){switch(w){case 1:case 2:case 3:var W=3;break;default:W=w}var oe=w;w=W;try{return P()}finally{w=oe}},t.unstable_requestPaint=function(){N=!0},t.unstable_runWithPriority=function(P,W){switch(P){case 1:case 2:case 3:case 4:case 5:break;default:P=3}var oe=w;w=P;try{return W()}finally{w=oe}},t.unstable_scheduleCallback=function(P,W,oe){var ae=t.unstable_now();switch(typeof oe=="object"&&oe!==null?(oe=oe.delay,oe=typeof oe=="number"&&0<oe?ae+oe:ae):oe=ae,P){case 1:var G=-1;break;case 2:G=250;break;case 5:G=1073741823;break;case 4:G=1e4;break;default:G=5e3}return G=oe+G,P={id:b++,callback:W,priorityLevel:P,startTime:oe,expirationTime:G,sortIndex:-1},oe>ae?(P.sortIndex=oe,n(g,P),a(p)===null&&P===a(g)&&(S?(T(L),L=-1):S=!0,se(_,oe-ae))):(P.sortIndex=G,n(p,P),C||y||(C=!0,R||(R=!0,q()))),P},t.unstable_shouldYield=I,t.unstable_wrapCallback=function(P){var W=w;return function(){var oe=w;w=W;try{return P.apply(this,arguments)}finally{w=oe}}}})(gp)),gp}var Ey;function T3(){return Ey||(Ey=1,hp.exports=k3()),hp.exports}var xp={exports:{}},hn={};/**
* @license React
* react-dom.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var ky;function M3(){if(ky)return hn;ky=1;var t=Xh();function n(p){var g="https://react.dev/errors/"+p;if(1<arguments.length){g+="?args[]="+encodeURIComponent(arguments[1]);for(var b=2;b<arguments.length;b++)g+="&args[]="+encodeURIComponent(arguments[b])}return"Minified React error #"+p+"; visit "+g+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function a(){}var o={d:{f:a,r:function(){throw Error(n(522))},D:a,C:a,L:a,m:a,X:a,S:a,M:a},p:0,findDOMNode:null},c=Symbol.for("react.portal");function l(p,g,b){var v=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:c,key:v==null?null:""+v,children:p,containerInfo:g,implementation:b}}var d=t.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function m(p,g){if(p==="font")return"";if(typeof g=="string")return g==="use-credentials"?g:""}return hn.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=o,hn.createPortal=function(p,g){var b=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!g||g.nodeType!==1&&g.nodeType!==9&&g.nodeType!==11)throw Error(n(299));return l(p,g,null,b)},hn.flushSync=function(p){var g=d.T,b=o.p;try{if(d.T=null,o.p=2,p)return p()}finally{d.T=g,o.p=b,o.d.f()}},hn.preconnect=function(p,g){typeof p=="string"&&(g?(g=g.crossOrigin,g=typeof g=="string"?g==="use-credentials"?g:"":void 0):g=null,o.d.C(p,g))},hn.prefetchDNS=function(p){typeof p=="string"&&o.d.D(p)},hn.preinit=function(p,g){if(typeof p=="string"&&g&&typeof g.as=="string"){var b=g.as,v=m(b,g.crossOrigin),w=typeof g.integrity=="string"?g.integrity:void 0,y=typeof g.fetchPriority=="string"?g.fetchPriority:void 0;b==="style"?o.d.S(p,typeof g.precedence=="string"?g.precedence:void 0,{crossOrigin:v,integrity:w,fetchPriority:y}):b==="script"&&o.d.X(p,{crossOrigin:v,integrity:w,fetchPriority:y,nonce:typeof g.nonce=="string"?g.nonce:void 0})}},hn.preinitModule=function(p,g){if(typeof p=="string")if(typeof g=="object"&&g!==null){if(g.as==null||g.as==="script"){var b=m(g.as,g.crossOrigin);o.d.M(p,{crossOrigin:b,integrity:typeof g.integrity=="string"?g.integrity:void 0,nonce:typeof g.nonce=="string"?g.nonce:void 0})}}else g==null&&o.d.M(p)},hn.preload=function(p,g){if(typeof p=="string"&&typeof g=="object"&&g!==null&&typeof g.as=="string"){var b=g.as,v=m(b,g.crossOrigin);o.d.L(p,b,{crossOrigin:v,integrity:typeof g.integrity=="string"?g.integrity:void 0,nonce:typeof g.nonce=="string"?g.nonce:void 0,type:typeof g.type=="string"?g.type:void 0,fetchPriority:typeof g.fetchPriority=="string"?g.fetchPriority:void 0,referrerPolicy:typeof g.referrerPolicy=="string"?g.referrerPolicy:void 0,imageSrcSet:typeof g.imageSrcSet=="string"?g.imageSrcSet:void 0,imageSizes:typeof g.imageSizes=="string"?g.imageSizes:void 0,media:typeof g.media=="string"?g.media:void 0})}},hn.preloadModule=function(p,g){if(typeof p=="string")if(g){var b=m(g.as,g.crossOrigin);o.d.m(p,{as:typeof g.as=="string"&&g.as!=="script"?g.as:void 0,crossOrigin:b,integrity:typeof g.integrity=="string"?g.integrity:void 0})}else o.d.m(p)},hn.requestFormReset=function(p){o.d.r(p)},hn.unstable_batchedUpdates=function(p,g){return p(g)},hn.useFormState=function(p,g,b){return d.H.useFormState(p,g,b)},hn.useFormStatus=function(){return d.H.useHostTransitionStatus()},hn.version="19.2.8",hn}var Ty;function o2(){if(Ty)return xp.exports;Ty=1;function t(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(n){console.error(n)}}return t(),xp.exports=M3(),xp.exports}/**
* @license React
* react-dom-client.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var My;function R3(){if(My)return Nl;My=1;var t=T3(),n=Xh(),a=o2();function o(e){var r="https://react.dev/errors/"+e;if(1<arguments.length){r+="?args[]="+encodeURIComponent(arguments[1]);for(var i=2;i<arguments.length;i++)r+="&args[]="+encodeURIComponent(arguments[i])}return"Minified React error #"+e+"; visit "+r+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function c(e){return!(!e||e.nodeType!==1&&e.nodeType!==9&&e.nodeType!==11)}function l(e){var r=e,i=e;if(e.alternate)for(;r.return;)r=r.return;else{e=r;do r=e,(r.flags&4098)!==0&&(i=r.return),e=r.return;while(e)}return r.tag===3?i:null}function d(e){if(e.tag===13){var r=e.memoizedState;if(r===null&&(e=e.alternate,e!==null&&(r=e.memoizedState)),r!==null)return r.dehydrated}return null}function m(e){if(e.tag===31){var r=e.memoizedState;if(r===null&&(e=e.alternate,e!==null&&(r=e.memoizedState)),r!==null)return r.dehydrated}return null}function p(e){if(l(e)!==e)throw Error(o(188))}function g(e){var r=e.alternate;if(!r){if(r=l(e),r===null)throw Error(o(188));return r!==e?null:e}for(var i=e,u=r;;){var h=i.return;if(h===null)break;var x=h.alternate;if(x===null){if(u=h.return,u!==null){i=u;continue}break}if(h.child===x.child){for(x=h.child;x;){if(x===i)return p(h),e;if(x===u)return p(h),r;x=x.sibling}throw Error(o(188))}if(i.return!==u.return)i=h,u=x;else{for(var j=!1,A=h.child;A;){if(A===i){j=!0,i=h,u=x;break}if(A===u){j=!0,u=h,i=x;break}A=A.sibling}if(!j){for(A=x.child;A;){if(A===i){j=!0,i=x,u=h;break}if(A===u){j=!0,u=x,i=h;break}A=A.sibling}if(!j)throw Error(o(189))}}if(i.alternate!==u)throw Error(o(190))}if(i.tag!==3)throw Error(o(188));return i.stateNode.current===i?e:r}function b(e){var r=e.tag;if(r===5||r===26||r===27||r===6)return e;for(e=e.child;e!==null;){if(r=b(e),r!==null)return r;e=e.sibling}return null}var v=Object.assign,w=Symbol.for("react.element"),y=Symbol.for("react.transitional.element"),C=Symbol.for("react.portal"),S=Symbol.for("react.fragment"),N=Symbol.for("react.strict_mode"),E=Symbol.for("react.profiler"),T=Symbol.for("react.consumer"),M=Symbol.for("react.context"),k=Symbol.for("react.forward_ref"),_=Symbol.for("react.suspense"),R=Symbol.for("react.suspense_list"),L=Symbol.for("react.memo"),ne=Symbol.for("react.lazy"),X=Symbol.for("react.activity"),I=Symbol.for("react.memo_cache_sentinel"),H=Symbol.iterator;function q(e){return e===null||typeof e!="object"?null:(e=H&&e[H]||e["@@iterator"],typeof e=="function"?e:null)}var ce=Symbol.for("react.client.reference");function de(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ce?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case S:return"Fragment";case E:return"Profiler";case N:return"StrictMode";case _:return"Suspense";case R:return"SuspenseList";case X:return"Activity"}if(typeof e=="object")switch(e.$$typeof){case C:return"Portal";case M:return e.displayName||"Context";case T:return(e._context.displayName||"Context")+".Consumer";case k:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case L:return r=e.displayName||null,r!==null?r:de(e.type)||"Memo";case ne:r=e._payload,e=e._init;try{return de(e(r))}catch{}}return null}var se=Array.isArray,P=n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,W=a.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,oe={pending:!1,data:null,method:null,action:null},ae=[],G=-1;function O(e){return{current:e}}function D(e){0>G||(e.current=ae[G],ae[G]=null,G--)}function B(e,r){G++,ae[G]=e.current,e.current=r}var V=O(null),Z=O(null),be=O(null),K=O(null);function ge(e,r){switch(B(be,r),B(Z,e),B(V,null),r.nodeType){case 9:case 11:e=(e=r.documentElement)&&(e=e.namespaceURI)?Bv(e):0;break;default:if(e=r.tagName,r=r.namespaceURI)r=Bv(r),e=$v(r,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}D(V),B(V,e)}function me(){D(V),D(Z),D(be)}function $(e){e.memoizedState!==null&&B(K,e);var r=V.current,i=$v(r,e.type);r!==i&&(B(Z,e),B(V,i))}function ie(e){Z.current===e&&(D(V),D(Z)),K.current===e&&(D(K),yl._currentValue=oe)}var ye,Se;function Be(e){if(ye===void 0)try{throw Error()}catch(i){var r=i.stack.trim().match(/\n( *(at )?)/);ye=r&&r[1]||"",Se=-1<i.stack.indexOf(`
at`)?" (<anonymous>)":-1<i.stack.indexOf("@")?"@unknown:0:0":""}return`
`+ye+e+Se}var Ke=!1;function We(e,r){if(!e||Ke)return"";Ke=!0;var i=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var u={DetermineComponentFrameRoot:function(){try{if(r){var he=function(){throw Error()};if(Object.defineProperty(he.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(he,[])}catch(re){var ee=re}Reflect.construct(e,[],he)}else{try{he.call()}catch(re){ee=re}e.call(he.prototype)}}else{try{throw Error()}catch(re){ee=re}(he=e())&&typeof he.catch=="function"&&he.catch(function(){})}}catch(re){if(re&&ee&&typeof re.stack=="string")return[re.stack,ee.stack]}return[null,null]}};u.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var h=Object.getOwnPropertyDescriptor(u.DetermineComponentFrameRoot,"name");h&&h.configurable&&Object.defineProperty(u.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var x=u.DetermineComponentFrameRoot(),j=x[0],A=x[1];if(j&&A){var z=j.split(`
`),J=A.split(`
`);for(h=u=0;u<z.length&&!z[u].includes("DetermineComponentFrameRoot");)u++;for(;h<J.length&&!J[h].includes("DetermineComponentFrameRoot");)h++;if(u===z.length||h===J.length)for(u=z.length-1,h=J.length-1;1<=u&&0<=h&&z[u]!==J[h];)h--;for(;1<=u&&0<=h;u--,h--)if(z[u]!==J[h]){if(u!==1||h!==1)do if(u--,h--,0>h||z[u]!==J[h]){var le=`
`+z[u].replace(" at new "," at ");return e.displayName&&le.includes("<anonymous>")&&(le=le.replace("<anonymous>",e.displayName)),le}while(1<=u&&0<=h);break}}}finally{Ke=!1,Error.prepareStackTrace=i}return(i=e?e.displayName||e.name:"")?Be(i):""}function qt(e,r){switch(e.tag){case 26:case 27:case 5:return Be(e.type);case 16:return Be("Lazy");case 13:return e.child!==r&&r!==null?Be("Suspense Fallback"):Be("Suspense");case 19:return Be("SuspenseList");case 0:case 15:return We(e.type,!1);case 11:return We(e.type.render,!1);case 1:return We(e.type,!0);case 31:return Be("Activity");default:return""}}function vn(e){try{var r="",i=null;do r+=qt(e,i),i=e,e=e.return;while(e);return r}catch(u){return`
Error generating stack: `+u.message+`
`+u.stack}}var Xn=Object.prototype.hasOwnProperty,br=t.unstable_scheduleCallback,yn=t.unstable_cancelCallback,wn=t.unstable_shouldYield,Zn=t.unstable_requestPaint,Kt=t.unstable_now,po=t.unstable_getCurrentPriorityLevel,Pt=t.unstable_ImmediatePriority,Qn=t.unstable_UserBlockingPriority,Da=t.unstable_NormalPriority,Es=t.unstable_LowPriority,qr=t.unstable_IdlePriority,ho=t.log,Kr=t.unstable_setDisableYieldValue,Dn=null,yt=null;function On(e){if(typeof ho=="function"&&Kr(e),yt&&typeof yt.setStrictMode=="function")try{yt.setStrictMode(Dn,e)}catch{}}var Rt=Math.clz32?Math.clz32:go,Ai=Math.log,_i=Math.LN2;function go(e){return e>>>=0,e===0?32:31-(Ai(e)/_i|0)|0}var Wr=256,Oa=262144,Ar=4194304;function Wt(e){var r=e&42;if(r!==0)return r;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function La(e,r,i){var u=e.pendingLanes;if(u===0)return 0;var h=0,x=e.suspendedLanes,j=e.pingedLanes;e=e.warmLanes;var A=u&134217727;return A!==0?(u=A&~x,u!==0?h=Wt(u):(j&=A,j!==0?h=Wt(j):i||(i=A&~e,i!==0&&(h=Wt(i))))):(A=u&~x,A!==0?h=Wt(A):j!==0?h=Wt(j):i||(i=u&~e,i!==0&&(h=Wt(i)))),h===0?0:r!==0&&r!==h&&(r&x)===0&&(x=h&-h,i=r&-r,x>=i||x===32&&(i&4194048)!==0)?r:h}function De(e,r){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&r)===0}function rt(e,r){switch(e){case 1:case 2:case 4:case 8:case 64:return r+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return r+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function lt(){var e=Ar;return Ar<<=1,(Ar&62914560)===0&&(Ar=4194304),e}function rn(e){for(var r=[],i=0;31>i;i++)r.push(e);return r}function It(e,r){e.pendingLanes|=r,r!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Jn(e,r,i,u,h,x){var j=e.pendingLanes;e.pendingLanes=i,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=i,e.entangledLanes&=i,e.errorRecoveryDisabledLanes&=i,e.shellSuspendCounter=0;var A=e.entanglements,z=e.expirationTimes,J=e.hiddenUpdates;for(i=j&~i;0<i;){var le=31-Rt(i),he=1<<le;A[le]=0,z[le]=-1;var ee=J[le];if(ee!==null)for(J[le]=null,le=0;le<ee.length;le++){var re=ee[le];re!==null&&(re.lane&=-536870913)}i&=~he}u!==0&&er(e,u,0),x!==0&&h===0&&e.tag!==0&&(e.suspendedLanes|=x&~(j&~r))}function er(e,r,i){e.pendingLanes|=r,e.suspendedLanes&=~r;var u=31-Rt(r);e.entangledLanes|=r,e.entanglements[u]=e.entanglements[u]|1073741824|i&261930}function bt(e,r){var i=e.entangledLanes|=r;for(e=e.entanglements;i;){var u=31-Rt(i),h=1<<u;h&r|e[u]&r&&(e[u]|=r),i&=~h}}function Ln(e,r){var i=r&-r;return i=(i&42)!==0?1:Di(i),(i&(e.suspendedLanes|r))!==0?0:i}function Di(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function Oi(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function Li(){var e=W.p;return e!==0?e:(e=window.event,e===void 0?32:uy(e.type))}function zi(e,r){var i=W.p;try{return W.p=e,r()}finally{W.p=i}}var Y=Math.random().toString(36).slice(2),te="__reactFiber$"+Y,je="__reactProps$"+Y,we="__reactContainer$"+Y,Le="__reactEvents$"+Y,Xe="__reactListeners$"+Y,vt="__reactHandles$"+Y,gt="__reactResources$"+Y,jn="__reactMarker$"+Y;function mn(e){delete e[te],delete e[je],delete e[Le],delete e[Xe],delete e[vt]}function an(e){var r=e[te];if(r)return r;for(var i=e.parentNode;i;){if(r=i[we]||i[te]){if(i=r.alternate,r.child!==null||i!==null&&i.child!==null)for(e=Kv(e);e!==null;){if(i=e[te])return i;e=Kv(e)}return r}e=i,i=e.parentNode}return null}function tr(e){if(e=e[te]||e[we]){var r=e.tag;if(r===5||r===6||r===13||r===31||r===26||r===27||r===3)return e}return null}function _r(e){var r=e.tag;if(r===5||r===26||r===27||r===6)return e.stateNode;throw Error(o(33))}function Xr(e){var r=e[gt];return r||(r=e[gt]={hoistableStyles:new Map,hoistableScripts:new Map}),r}function Xt(e){e[jn]=!0}var Tx=new Set,Mx={};function ks(e,r){xo(e,r),xo(e+"Capture",r)}function xo(e,r){for(Mx[e]=r,e=0;e<r.length;e++)Tx.add(r[e])}var f5=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u Line truncated
`).replace(G4,"")}function Iv(e,r){return r=Pv(r),Pv(e)===r}function pt(e,r,i,u,h,x){switch(i){case"children":typeof u=="string"?r==="body"||r==="textarea"&&u===""||vo(e,u):(typeof u=="number"||typeof u=="bigint")&&r!=="body"&&vo(e,""+u);break;case"className":gc(e,"class",u);break;case"tabIndex":gc(e,"tabindex",u);break;case"dir":case"role":case"viewBox":case"width":case"height":gc(e,i,u);break;case"style":Ix(e,u,x);break;case"data":if(r!=="object"){gc(e,"data",u);break}case"src":case"href":if(u===""&&(r!=="a"||i!=="href")){e.removeAttribute(i);break}if(u==null||typeof u=="function"||typeof u=="symbol"||typeof u=="boolean"){e.removeAttribute(i);break}u=bc(""+u),e.setAttribute(i,u);break;case"action":case"formAction":if(typeof u=="function"){e.setAttribute(i,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof x=="function"&&(i==="formAction"?(r!=="input"&&pt(e,r,"name",h.name,h,null),pt(e,r,"formEncType",h.formEncType,h,null),pt(e,r,"formMethod",h.formMethod,h,null),pt(e,r,"formTarget",h.formTarget,h,null)):(pt(e,r,"encType",h.encType,h,null),pt(e,r,"method",h.method,h,null),pt(e,r,"target",h.target,h,null)));if(u==null||typeof u=="symbol"||typeof u=="boolean"){e.removeAttribute(i);break}u=bc(""+u),e.setAttribute(i,u);break;case"onClick":u!=null&&(e.onclick=Qr);break;case"onScroll":u!=null&&Ve("scroll",e);break;case"onScrollEnd":u!=null&&Ve("scrollend",e);break;case"dangerouslySetInnerHTML":if(u!=null){if(typeof u!="object"||!("__html"in u))throw Error(o(61));if(i=u.__html,i!=null){if(h.children!=null)throw Error(o(60));e.innerHTML=i}}break;case"multiple":e.multiple=u&&typeof u!="function"&&typeof u!="symbol";break;case"muted":e.muted=u&&typeof u!="function"&&typeof u!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(u==null||typeof u=="function"||typeof u=="boolean"||typeof u=="symbol"){e.removeAttribute("xlink:href");break}i=bc(""+u),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",i);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":u!=null&&typeof u!="function"&&typeof u!="symbol"?e.setAttribute(i,""+u):e.removeAttribute(i);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":u&&typeof u!="function"&&typeof u!="symbol"?e.setAttribute(i,""):e.removeAttribute(i);break;case"capture":case"download":u===!0?e.setAttribute(i,""):u!==!1&&u!=null&&typeof u!="function"&&typeof u!="symbol"?e.setAttribute(i,u):e.removeAttribute(i);break;case"cols":case"rows":case"size":case"span":u!=null&&typeof u!="function"&&typeof u!="symbol"&&!isNaN(u)&&1<=u?e.setAttribute(i,u):e.removeAttribute(i);break;case"rowSpan":case"start":u==null||typeof u=="function"||typeof u=="symbol"||isNaN(u)?e.removeAttribute(i):e.setAttribute(i,u);break;case"popover":Ve("beforetoggle",e),Ve("toggle",e),hc(e,"popover",u);break;case"xlinkActuate":Zr(e,"http://www.w3.org/1999/xlink","xlink:actuate",u);break;case"xlinkArcrole":Zr(e,"http://www.w3.org/1999/xlink","xlink:arcrole",u);break;case"xlinkRole":Zr(e,"http://www.w3.org/1999/xlink","xlink:role",u);break;case"xlinkShow":Zr(e,"http://www.w3.org/1999/xlink","xlink:show",u);break;case"xlinkTitle":Zr(e,"http://www.w3.org/1999/xlink","xlink:title",u);break;case"xlinkType":Zr(e,"http://www.w3.org/1999/xlink","xlink:type",u);break;case"xmlBase":Zr(e,"http://www.w3.org/XML/1998/namespace","xml:base",u);break;case"xmlLang":Zr(e,"http://www.w3.org/XML/1998/namespace","xml:lang",u);break;case"xmlSpace":Zr(e,"http://www.w3.org/XML/1998/namespace","xml:space",u);break;case"is":hc(e,"is",u);break;case"innerText":case"textContent":break;default:(!(2<i.length)||i[0]!=="o"&&i[0]!=="O"||i[1]!=="n"&&i[1]!=="N")&&(i=x5.get(i)||i,hc(e,i,u))}}function qm(e,r,i,u,h,x){switch(i){case"style":Ix(e,u,x);break;case"dangerouslySetInnerHTML":if(u!=null){if(typeof u!="object"||!("__html"in u))throw Error(o(61));if(i=u.__html,i!=null){if(h.children!=null)throw Error(o(60));e.innerHTML=i}}break;case"children":typeof u=="string"?vo(e,u):(typeof u=="number"||typeof u=="bigint")&&vo(e,""+u);break;case"onScroll":u!=null&&Ve("scroll",e);break;case"onScrollEnd":u!=null&&Ve("scrollend",e);break;case"onClick":u!=null&&(e.onclick=Qr);break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"inne Line truncated
* react-router v7.18.2
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/var Zh=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,i2=/^[\\/]{2}/;function D3(t,n){return n+t.replace(/\\/g,"/")}var Ay="popstate";function _y(t){return typeof t=="object"&&t!=null&&"pathname"in t&&"search"in t&&"hash"in t&&"state"in t&&"key"in t}function O3(t={}){function n(o,c){var g;let l=(g=c.state)==null?void 0:g.masked,{pathname:d,search:m,hash:p}=l||o.location;return Qp("",{pathname:d,search:m,hash:p},c.state&&c.state.usr||null,c.state&&c.state.key||"default",l?{pathname:o.location.pathname,search:o.location.search,hash:o.location.hash}:void 0)}function a(o,c){return typeof c=="string"?c:Il(c)}return z3(n,a,null,t)}function kt(t,n){if(t===!1||t===null||typeof t>"u")throw new Error(n)}function pr(t,n){if(!t){typeof console<"u"&&console.warn(n);try{throw new Error(n)}catch{}}}function L3(){return Math.random().toString(36).substring(2,10)}function Dy(t,n){return{usr:t.state,key:t.key,idx:n,masked:t.mask?{pathname:t.pathname,search:t.search,hash:t.hash}:void 0}}function Qp(t,n,a=null,o,c){return{pathname:typeof t=="string"?t:t.pathname,search:"",hash:"",...typeof n=="string"?hi(n):n,state:a,key:n&&n.key||o||L3(),mask:c}}function Il({pathname:t="/",search:n="",hash:a=""}){return n&&n!=="?"&&(t+=n.charAt(0)==="?"?n:"?"+n),a&&a!=="#"&&(t+=a.charAt(0)==="#"?a:"#"+a),t}function hi(t){let n={};if(t){let a=t.indexOf("#");a>=0&&(n.hash=t.substring(a),t=t.substring(0,a));let o=t.indexOf("?");o>=0&&(n.search=t.substring(o),t=t.substring(0,o)),t&&(n.pathname=t)}return n}function z3(t,n,a,o={}){let{window:c=document.defaultView,v5Compat:l=!1}=o,d=c.history,m="POP",p=null,g=b();g==null&&(g=0,d.replaceState({...d.state,idx:g},""));function b(){return(d.state||{idx:null}).idx}function v(){m="POP";let N=b(),E=N==null?null:N-g;g=N,p&&p({action:m,location:S.location,delta:E})}function w(N,E){m="PUSH";let T=_y(N)?N:Qp(S.location,N,E);g=b()+1;let M=Dy(T,g),k=S.createHref(T.mask||T);try{d.pushState(M,"",k)}catch(_){if(_ instanceof DOMException&&_.name==="DataCloneError")throw _;c.location.assign(k)}l&&p&&p({action:m,location:S.location,delta:1})}function y(N,E){m="REPLACE";let T=_y(N)?N:Qp(S.location,N,E);g=b();let M=Dy(T,g),k=S.createHref(T.mask||T);d.replaceState(M,"",k),l&&p&&p({action:m,location:S.location,delta:0})}function C(N){return P3(c,N)}let S={get action(){return m},get location(){return t(c,d)},listen(N){if(p)throw new Error("A history only accepts one active listener");return c.addEventListener(Ay,v),p=N,()=>{c.removeEventListener(Ay,v),p=null}},createHref(N){return n(c,N)},createURL:C,encodeLocation(N){let E=C(N);return{pathname:E.pathname,search:E.search,hash:E.hash}},push:w,replace:y,go(N){return d.go(N)}};return S}function P3(t,n,a=!1){let o="http://localhost";t&&(o=t.location.origin!=="null"?t.location.origin:t.location.href),kt(o,"No window.location.(origin|href) available to create URL");let c=typeof n=="string"?n:Il(n);return c=c.replace(/ $/,"%20"),!a&&i2.test(c)&&(c=o+c),new URL(c,o)}function l2(t,n,a="/"){return I3(t,n,a,!1)}function I3(t,n,a,o,c){let l=typeof n=="string"?hi(n):n,d=Na(l.pathname||"/",a);if(d==null)return null;let m=U3(t),p=null,g=X3(d);for(let b=0;p==null&&b<m.length;++b)p=W3(m[b],g,o);return p}function U3(t){let n=c2(t);return B3(n),n}function c2(t,n=[],a=[],o="",c=!1){let l=(d,m,p=c,g)=>{let b={relativePath:g===void 0?d.path||"":g,caseSensitive:d.caseSensitive===!0,childrenIndex:m,route:d};if(b.relativePath.startsWith("/")){if(!b.relativePath.startsWith(o)&&p)return;kt(b.relativePath.startsWith(o),`Absolute route path "${b.relativePath}" nested under path "${o}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),b.relativePath=b.relativePath.slice(o.length)}let v=Sr([o,b.relativePath]),w=a.concat(b);d.children&&d.children.length>0&&(kt(d.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${v}".`),c2(d.children,n,w,v,p)),!(d.path==null&&!d.index)&&n.push({path:v,score:q3(v,d.index),routesMeta:w.map((y,C)=>{let[S,N]=f2(y.relativePath,y.caseSensitive,C===w.length-1);return{...y,matcher:S,compiledParams:N}})})};return t.forEach((d,m)=>{var p;if(d.path===""||!((p=d.path)!=null&&p.includes("?")))l(d,m);else for(let g of u2(d.path))l(d,m,!0,g)}),n}function u2(t){let n=t.split("/");if(n.length===0)return[];let[a,...o]=n,c=a.endsWith("?"),l=a.replace(/\?$/,"");if(o.length===0)return c?[l,""]:[l];let d=u2(o.join("/")),m=[];return m.push(...d.map(p=>p===""?l:[l,p].join("/"))),c&&m.push(...d),m.map(p=>t.startsWith("/")&&p===""?"/":p)}function B3(t){t.sort((n,a)=>n.score!==a.score?a.score-n.score:K3(n.routesMeta.map(o=>o.childrenIndex),a.routesMeta.map(o=>o.childrenIndex)))}var $3=/^:[\w-]+$/,H3=3,G3=2,V3=1,F3=10,Y3=-2,Oy=t=>t==="*";function q3(t,n){let a=t.split("/"),o=a.length;return a.some(Oy)&&(o+=Y3),n&&(o+=G3),a.filter(c=>!Oy(c)).reduce((c,l)=>c+($3.test(l)?H3:l===""?V3:F3),o)}function K3(t,n){return t.length===n.length&&t.slice(0,-1).every((o,c)=>o===n[c])?t[t.length-1]-n[n.length-1]:0}fuLine truncated
Please change the parent <Route path="${E}"> to <Route path="${E==="/"?"*":`${E}/*`}">.`)}let b=Kn(),v;if(n){let E=typeof n=="string"?hi(n):n;kt(p==="/"||((N=E.pathname)==null?void 0:N.startsWith(p)),`When overriding the location using \`<Routes location>\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${p}" but pathname "${E.pathname}" was given in the \`location\` prop.`),v=E}else v=b;let w=v.pathname||"/",y=w;if(p!=="/"){let E=p.replace(/^\//,"").split("/");y="/"+w.replace(/^\//,"").split("/").slice(E.length).join("/")}let C=a&&a.state.matches.length?a.state.matches.map(E=>Object.assign(E,{route:a.manifest[E.route.id]||E.route})):l2(t,{pathname:y});pr(g||C!=null,`No routes matched location "${v.pathname}${v.search}${v.hash}" `),pr(C==null||C[C.length-1].route.element!==void 0||C[C.length-1].route.Component!==void 0||C[C.length-1].route.lazy!==void 0,`Matched leaf route at location "${v.pathname}${v.search}${v.hash}" does not have an element or Component. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.`);let S=SN(C&&C.map(E=>Object.assign({},E,{params:Object.assign({},d,E.params),pathname:Sr([p,o.encodeLocation?o.encodeLocation(E.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:E.pathname]),pathnameBase:E.pathnameBase==="/"?p:Sr([p,o.encodeLocation?o.encodeLocation(E.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:E.pathnameBase])})),c,a);return n&&S?f.createElement(Jl.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...v},navigationType:"POP"}},S):S}function yN(){let t=MN(),n=rN(t)?`${t.status} ${t.statusText}`:t instanceof Error?t.message:JSON.stringify(t),a=t instanceof Error?t.stack:null,o="rgba(200,200,200, 0.5)",c={padding:"0.5rem",backgroundColor:o},l={padding:"2px 4px",backgroundColor:o},d=null;return console.error("Error handled by React Router default ErrorBoundary:",t),d=f.createElement(f.Fragment,null,f.createElement("p",null,"💿 Hey developer 👋"),f.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",f.createElement("code",{style:l},"ErrorBoundary")," or"," ",f.createElement("code",{style:l},"errorElement")," prop on your route.")),f.createElement(f.Fragment,null,f.createElement("h2",null,"Unexpected Application Error!"),f.createElement("h3",{style:{fontStyle:"italic"}},n),a?f.createElement("pre",{style:c},a):null,d)}var wN=f.createElement(yN,null),C2=class extends f.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,n){return n.location!==t.location||n.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:n.error,location:n.location,revalidation:t.revalidation||n.revalidation}}componentDidCatch(t,n){this.props.onError?this.props.onError(t,n):console.error("React Router caught the following error during render",t)}render(){let t=this.state.error;if(this.context&&typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){const a=pN(t.digest);a&&(t=a)}let n=t!==void 0?f.createElement(Tr.Provider,{value:this.props.routeContext},f.createElement(Jh.Provider,{value:t,children:this.props.component})):this.props.children;return this.context?f.createElement(jN,{error:t},n):n}};C2.contextType=x2;var vp=new WeakMap;function jN({children:t,error:n}){let{basename:a}=f.useContext(qn);if(typeof n=="object"&&n&&"digest"in n&&typeof n.digest=="string"){let o=mN(n.digest);if(o){let c=vp.get(n);if(c)throw c;let l=h2(o.location,a),d=l.absoluteURL||l.to;if(iN(d))throw new Error("Invalid redirect location");if(p2&&!vp.get(n))if(l.isExternal||o.reloadDocument)window.location.href=d;else{const m=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(l.to,{replace:o.replace}));throw vp.set(n,m),m}return f.createElement("meta",{httpEquiv:"refresh",content:`0;url=${d}`})}}return t}function CN({routeContext:t,match:n,children:a}){let o=f.useContext(gi);return o&&o.static&&o.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(o.staticContext._deepestRenderedBoundaryId=n.route.id),f.createElement(Tr.Provider,{value:t},a)}function SN(t,n=[],a){let o=a==null?void 0:a.state;if(t==null){if(!o)return null;if(o.errors)t=o.matches;else if(n.length===0&&!o.initialized&&o.matches.length>0)t=o.matches;else return null}let c=t,l=o==null?void 0:o.errors;if(l!=null){let b=c.findIndex(v=>v.route.id&&(l==null?void 0:l[v.route.id])!==void 0);kt(b>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(l).join(",")}`),c=c.slice(0,Math.min(c.length,b+1))}let d=!1,m=-1;if(a&&o){d=o.renderFallback;for(let b=0;bLine truncated
.`.concat(Bk,` {
overflow: hidden `).concat(o,`;
padding-right: `).concat(m,"px ").concat(o,`;
}
body[`).concat(li,`] {
overflow: hidden `).concat(o,`;
overscroll-behavior: contain;
`).concat([n&&"position: relative ".concat(o,";"),a==="margin"&&`
padding-left: `.concat(c,`px;
padding-top: `).concat(l,`px;
padding-right: `).concat(d,`px;
margin-left:0;
margin-top:0;
margin-right: `).concat(m,"px ").concat(o,`;
`),a==="padding"&&"padding-right: ".concat(m,"px ").concat(o,";")].filter(Boolean).join(""),`
}
.`).concat(Zu,` {
right: `).concat(m,"px ").concat(o,`;
}
.`).concat(Qu,` {
margin-right: `).concat(m,"px ").concat(o,`;
}
.`).concat(Zu," .").concat(Zu,` {
right: 0 `).concat(o,`;
}
.`).concat(Qu," .").concat(Qu,` {
margin-right: 0 `).concat(o,`;
}
body[`).concat(li,`] {
`).concat($k,": ").concat(m,`px;
}
`)},f0=function(){var t=parseInt(document.body.getAttribute(li)||"0",10);return isFinite(t)?t:0},o9=function(){f.useEffect(function(){return document.body.setAttribute(li,(f0()+1).toString()),function(){var t=f0()-1;t<=0?document.body.removeAttribute(li):document.body.setAttribute(li,t.toString())}},[])},i9=function(t){var n=t.noRelative,a=t.noImportant,o=t.gapMode,c=o===void 0?"margin":o;o9();var l=f.useMemo(function(){return r9(c)},[c]);return f.createElement(a9,{styles:s9(l,!n,c,a?"":"!important")})},vh=!1;if(typeof window<"u")try{var Ou=Object.defineProperty({},"passive",{get:function(){return vh=!0,!0}});window.addEventListener("test",Ou,Ou),window.removeEventListener("test",Ou,Ou)}catch{vh=!1}var Qo=vh?{passive:!1}:!1,l9=function(t){return t.tagName==="TEXTAREA"},sj=function(t,n){if(!(t instanceof Element))return!1;var a=window.getComputedStyle(t);return a[n]!=="hidden"&&!(a.overflowY===a.overflowX&&!l9(t)&&a[n]==="visible")},c9=function(t){return sj(t,"overflowY")},u9=function(t){return sj(t,"overflowX")},m0=function(t,n){var a=n.ownerDocument,o=n;do{typeof ShadowRoot<"u"&&o instanceof ShadowRoot&&(o=o.host);var c=oj(t,o);if(c){var l=ij(t,o),d=l[1],m=l[2];if(d>m)return!0}o=o.parentNode}while(o&&o!==a.body);return!1},d9=function(t){var n=t.scrollTop,a=t.scrollHeight,o=t.clientHeight;return[n,a,o]},f9=function(t){var n=t.scrollLeft,a=t.scrollWidth,o=t.clientWidth;return[n,a,o]},oj=function(t,n){return t==="v"?c9(n):u9(n)},ij=function(t,n){return t==="v"?d9(n):f9(n)},m9=function(t,n){return t==="h"&&n==="rtl"?-1:1},p9=function(t,n,a,o,c){var l=m9(t,window.getComputedStyle(n).direction),d=l*o,m=a.target,p=n.contains(m),g=!1,b=d>0,v=0,w=0;do{if(!m)break;var y=ij(t,m),C=y[0],S=y[1],N=y[2],E=S-N-l*C;(C||E)&&oj(t,m)&&(v+=E,w+=C);var T=m.parentNode;m=T&&T.nodeType===Node.DOCUMENT_FRAGMENT_NODE?T.host:T}while(!p&&m!==document.body||p&&(n.contains(m)||n===m));return(b&&Math.abs(v)<1||!b&&Math.abs(w)<1)&&(g=!0),g},Lu=function(t){return"changedTouches"in t?[t.changedTouches[0].clientX,t.changedTouches[0].clientY]:[0,0]},p0=function(t){return[t.deltaX,t.deltaY]},h0=function(t){return t&&"current"in t?t.current:t},h9=function(t,n){return t[0]===n[0]&&t[1]===n[1]},g9=function(t){return`
.block-interactivity-`.concat(t,` {pointer-events: none;}
.allow-interactivity-`).concat(t,` {pointer-events: all;}
`)},x9=0,Jo=[];function b9(t){var n=f.useRef([]),a=f.useRef([0,0]),o=f.useRef(),c=f.useState(x9++)[0],l=f.useState(aj)[0],d=f.useRef(t);f.useEffect(function(){d.current=t},[t]),f.useEffect(function(){if(t.inert){document.body.classList.add("block-interactivity-".concat(c));var S=Uk([t.lockRef.current],(t.shards||[]).map(h0),!0).filter(Boolean);return S.forEach(function(N){return N.classList.add("allow-interactivity-".concat(c))}),function(){document.body.classList.remove("block-interactivity-".concat(c)),S.forEach(function(N){return N.classList.remove("allow-interactivity-".concat(c))})}}},[t.inert,t.lockRef.current,t.shards]);var m=f.useCallback(function(S,N){if("touches"in S&&S.touches.length===2||S.type==="wheel"&&S.ctrlKey)return!d.current.allowPinchZoom;var E=Lu(S),T=a.current,M="deltaX"in S?S.deltaX:T[0]-E[0],k="deltaY"in S?S.deltaY:T[1]-E[1],_,R=S.target,L=Math.abs(M)>Math.abs(k)?"h":"v";if("touches"in S&&L==="h"&&R.type==="range")return!1;var ne=window.getSelection(),X=ne&&ne.anchorNode,I=X?X===R||X.contains(R):!1;if(I)return!1;var H=m0(L,R);if(!H)return!0;if(H?_=L:(_=L==="v"?"h":"v",H=m0(L,R)),!H)return!1;if(!o.current&&"changedTouches"in S&&(M||k)&&(o.current=_),!_)return!0;var q=o.current||_;return p9(q,N,S,q==="h"?M:k)},[]),p=f.useCallback(function(S){var N=S;if(!(!Jo.length||Jo[Jo.length-1]!==l)){var E="deltaY"in N?p0(N):Lu(N),T=n.current.filter(function(_){return _.name===N.type&&(_.target===N.target||N.target===_.shadowParent)&&h9(_.delta,E)})[0];if(T&&T.should){N.cancelable&&N.preventDefault();return}if(!T){var M=(d.current.shards||[]).map(h0).filter(Boolean).filter(function(_){return _.contains(N.target)}),k=M.length>0?m(N,M[0]):!d.current.noIsolation;k&&N.cancelable&&N.preventDefault()}}},[]),g=f.useCallback(function(S,N,E,T){var M={name:S,delta:N,target:E,should:T,shadowParent:v9(E)};n.current.push(M),setTimeout(function(){n.current=n.current.filter(function(k){return k!==M})},1)},[]),b=f.useCallback(function(S){a.current=Lu(S),o.current=void 0},[]),v=f.useCallback(function(S){g(S.type,p0(S),S.target,m(S,t.lockRef.current))},[]),w=f.useCallback(function(S){g(S.type,Lu(S),S.target,m(S,t.lockRef.current))},[]);f.useEffect(function(){return Jo.push(l),t.setCallbacks({onScrollCapture:v,onWheelCapture:v,onTouchMoveCapture:w}),document.addEventListener("wheel",p,Qo),document.addEventListener("touchmove",p,Qo),document.addEventListener("touchstart",b,Qo),function(){Jo=Jo.filter(function(S){return S!==l}),document.removeEventListener("wheel",p,Qo),document.removeEventListener("touchmove",p,Qo),document.removeEventListener("touchstart",b,Qo)}},[]);var y=t.removeScrollBar,C=t.inert;return f.createElement(f.Fragment,null,C?f.createElement(l,{styles:g9(c)}):null,y?f.createElement(i9,{noRelative:t.noRelative,gapMode:t.gapMode}):null)}function v9(t){for(var n=null;t!==null;)t instanceof ShadowRoot&&(n=t.host,t=t.host),t=t.parentNode;return n}const y9=Kk(rj,b9);var ac=f.forwardRef(function(t,n){return f.createElement(Hd,Ur({},t,{ref:n,sideCar:y9}))});ac.classNames=Hd.classNames;var w9=Object.defineProperty,ot=(t,n)=>w9(t,"name",{value:n,configurable:!0}),yh=["Enter"," "],j9=["ArrowDown","PageUp","Home"],lj=["ArrowUp","PageDown","End"],C9=[...j9,...lj],S9={ltr:[...yh,"ArrowRight"],rtl:[...yh,"ArrowLeft"]},N9={ltr:["ArrowLeft"],rtl:["ArrowRight"]},Gd="Menu",[Hl,E9,k9]=Td(Gd),[io,cj]=bn(Gd,[k9,Cs,Bd]),Rg=Cs(),uj=Bd(),[T9,lo]=io(Gd),[M9,sc]=io(Gd),R9=ot(t=>{const{__scopeMenu:n,open:a=!1,children:o,dir:c,onOpenChange:l,modal:d=!0}=t,m=Rg(n),[p,g]=f.useState(null),b=f.useRef(!1),v=Vt(l),w=Si(c);return f.useEffect(()=>{const y=ot(()=>{b.current=!0,document.addEventListener("pointerdown",C,{capture:!0,once:!0}),document.addEventListener("pointermove",C,{capture:!0,once:!0})},"handleKeyDown"),C=ot(()=>b.current=!1,"handlePointer");return document.addEventListener("keydown",y,{capture:!0}),()=>{document.removeEventListener("keydown",y,{capture:!0}),document.removeEventListener("pointerdown",C,{capture:!0}),document.removeEventListener("pointermove",C,{capture:!0})}},[]),f.useEffect(()=>{if(!a)return;const y=ot(()=>v(!1),"handleBlur");return window.addEventListener("blur",y),()=>window.removeEventListener("blur",y)},[a,v]),s.jsx(zd,{...m,children:s.jsx(T9,{scope:n,open:a,onOpenChange:v,content:p,onContentChange:g,children:s.jsx(M9,{scope:n,onClose:f.useCallback(()=>v(!1),[v]),isUsingKeyboardRef:b,dir:w,modal:d,children:o})})})},"Menu"),dj=f.forwardRef(ot(function(n,a){const{__scopeMenu:o,...c}=n,l=Rg(o);return s.jsx(Pd,{...l,...c,ref:a})},"MenuAnchor")),fj="MenuPortal",[A9,mj]=io(fj,{forceMount:void 0}),_9=ot(t=>{const{__scopeMenu:n,forceMount:a,children:o,container:c}=t,l=lo(fj,n);return s.jsx(A9,{scope:n,forceMount:a,children:s.jsx(fn,{present:a||l.open,children:s.jsx(rc,{asChild:!0,container:c,children:o})})})},"MenuPortal"),Nr="MenuContent",[D9,Ag]=io(Nr),O9=f.forwardRef(ot(function(n,a){const o=mj(Nr,n.__scopeMenu),{forceMount:c=o.forceMount,...l}=n,d=lo(Nr,n.__scopeMenu),m=sc(Nr,n.__scopeMenu);return s.jsx( Line truncated
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const MT=t=>t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),Dj=(...t)=>t.filter((n,a,o)=>!!n&&n.trim()!==""&&o.indexOf(n)===a).join(" ").trim();/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/var RT={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const AT=f.forwardRef(({color:t="currentColor",size:n=24,strokeWidth:a=2,absoluteStrokeWidth:o,className:c="",children:l,iconNode:d,...m},p)=>f.createElement("svg",{ref:p,...RT,width:n,height:n,stroke:t,strokeWidth:o?Number(a)*24/Number(n):a,className:Dj("lucide",c),...m},[...d.map(([g,b])=>f.createElement(g,b)),...Array.isArray(l)?l:[l]]));/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Ra=(t,n)=>{const a=f.forwardRef(({className:o,...c},l)=>f.createElement(AT,{ref:l,iconNode:n,className:Dj(`lucide-${MT(t)}`,o),...c}));return a.displayName=`${t}`,a};/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const _T=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],Oj=Ra("Check",_T);/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const DT=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],Lj=Ra("ChevronDown",DT);/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const OT=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],LT=Ra("ChevronRight",OT);/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const zT=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],PT=Ra("ChevronUp",zT);/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const IT=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],x0=Ra("CircleCheck",IT);/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const UT=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],BT=Ra("Circle",UT);/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const $T=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M9 3v18",key:"fh3hqa"}]],HT=Ra("PanelLeft",$T);/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const GT=[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]],VT=Ra("Search",GT);/**
* @license lucide-react v0.475.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const FT=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],zj=Ra("X",FT),zg=ET,Pg=kT,YT=f.forwardRef(({className:t,inset:n,children:a,...o},c)=>s.jsxs(Aj,{ref:c,className:pe("flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",n&&"pl-8",t),...o,children:[a,s.jsx(LT,{className:"ml-auto"})]}));YT.displayName=Aj.displayName;const qT=f.forwardRef(({className:t,...n},a)=>s.jsx(_j,{ref:a,className:pe("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",t),...n}));qT.displayName=_j.displayName;const Fd=f.forwardRef(({className:t,sideOffset:n=4,...a},o)=>s.jsx(TT,{children:s.jsx(Sj,{ref:o,sideOffset:n,className:pe("z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md","data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",t),...a})}));Fd.displayName=Sj.displayName;const Vl=f.forwardRef(({className:t,inset:n,...a},o)=>s.jsx(Ej,{ref:o,className:pe("relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",n&&"pl-8",t),...a}));Vl.displayName=Ej.displayName;const KT=f.forwardRef(({className:t,children:n,checked:a,...o},c)=>s.jsxs(kj,{ref:c,className:pe("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",t),checked:a,...o,children:[s.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:s.jsx(Mj,{children:s.jsx(Oj,{className:"h-4 w-4"})})}),n]}));KT.displayName=kj.displayName;const WT=f.forwardRef(({className:t,children:n,...a},o)=>s.jsxs(Tj,{ref:o,className:pe("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",t),...a,children:[s.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:s.jsx(Mj,{children:s.jsx(BT,{className:"h-2 w-2 fill-current"})})}),n]}));WT.displayName=Tj.displayName;const Ig=f.forwardRef(({className:t,inset:n,...a},o)=>s.jsx(Nj,{ref:o,className:pe("px-2 py-1.5 text-sm font-semibold",n&&"pl-8",t),...a}));Ig.displayName=Nj.displayName;const Fl=f.forwardRef(({className:t,...n},a)=>s.jsx(Rj,{ref:a,className:pe("-mx-1 my-1 h-px bg-muted",t),...n}));Fl.displayName=Rj.displayName;const zp=768;function XT(){const[t,n]=f.useState(void 0);return f.useEffect(()=>{const a=window.matchMedia(`(max-width: ${zp-1}px)`),o=()=>{n(window.innerWidth<zp)};return a.addEventListener("change",o),n(window.innerWidth<zp),()=>a.removeEventListener("change",o)},[]),!!t}const _e=f.forwardRef(({className:t,type:n,...a},o)=>s.jsx("input",{type:n,className:pe("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",t),ref:o,...a}));_e.displayName="Input";var ZT=Object.defineProperty,Pj=(t,n)=>ZT(t,"name",{value:n,configurable:!0}),b0="horizontal",QT=["horizontal","vertical"],JT=f.forwardRef(Pj(function(n,a){const{decorative:o,orientation:c=b0,...l}=n,d=Ij(c)?c:b0,p=o?{role:"none"}:{"aria-orientation":d==="vertical"?d:void 0,role:"separator"};return s.jsx(Me.div,{"data-orientation":d,...p,...l,ref:a})},"Separator"));function Ij(t){return QT.includes(t)}Pj(Ij,"isValidOrientation");var Uj=JT;const Bj=f.forwardRef(({className:t,orientation:n="horizontal",decorative:a=!0,...o},c)=>s.jsx(Uj,{ref:c,decorative:a,orientation:n,className:pe(Line truncated
--num-groups: ${l.groups.length};
--indicator-opacity: ${l.searchMode?0:1};
--num-skintones: ${z0};`}),d(()=>{l.customEmoji&&l.database&&L()}),d(()=>{l.customEmoji&&l.customEmoji.length?l.groups!==Fh&&(l.groups=Fh):l.groups!==Hp&&(l.currentGroupIndex&&l.currentGroupIndex--,l.groups=Hp)}),d(()=>{async function $(){l.databaseLoaded&&(l.currentSkinTone=await l.database.getPreferredSkinTone())}$()}),d(()=>{l.skinTones=Array(z0).fill().map(($,ie)=>ID(l.skinToneEmoji,ie))}),d(()=>{l.skinToneButtonText=l.skinTones[l.currentSkinTone]}),d(()=>{l.skinToneButtonLabel=l.i18n.skinToneLabel.replace("{skinTone}",l.i18n.skinTones[l.currentSkinTone])}),d(()=>{async function $(){const{database:ie}=l,ye=(await Promise.all(TD.map(Se=>ie.getEmojiByUnicodeOrName(Se)))).filter(Boolean);l.defaultFavoriteEmojis=ye}l.databaseLoaded&&$()});function L(){const{customEmoji:$,database:ie}=l,ye=$||Kp;ie.customEmoji!==ye&&(ie.customEmoji=ye)}d(()=>{async function $(){L();const{database:ie,defaultFavoriteEmojis:ye,numColumns:Se}=l,Be=await ie.getTopFavoriteEmoji(Se),Ke=await de(XS([...Be,...ye],We=>We.unicode||We.name).slice(0,Se));l.currentFavorites=Ke}l.databaseLoaded&&l.defaultFavoriteEmojis&&$()});function ne($){$D($,c,()=>{{const ie=getComputedStyle(a.rootElement),ye=parseInt(ie.getPropertyValue("--num-columns"),10),Se=ie.getPropertyValue("direction")==="rtl";l.numColumns=ye,l.isRtl=Se}})}function X($){iO($,c,ie=>{for(const{target:ye,isIntersecting:Se}of ie)ye.classList.toggle("onscreen",Se)})}d(()=>{async function $(){const{searchText:ie,currentGroup:ye,databaseLoaded:Se,customEmoji:Be}=l;if(!Se)l.currentEmojis=[],l.searchMode=!1;else if(ie.length>=CD){const Ke=await P(ie);l.searchText===ie&&(y(Ke),C(!0))}else{const{id:Ke}=ye;if(Ke!==-1||Be&&Be.length){const We=await se(Ke);l.currentGroup.id===Ke&&(y(We),C(!1))}}}$()});const I=()=>{ed(()=>FD(a.tabpanelElement))};d(()=>{const{currentEmojis:$,emojiVersion:ie}=l,ye=$.filter(Se=>Se.unicode).filter(Se=>P0(Se)&&!Yh.has(Se.unicode));if(!ie&&ye.length)y($),ed(()=>H(ye));else{const Se=ie?$:$.filter(q);y(Se),I()}});function H($){GD($,a.baselineEmoji,g)?I():l.currentEmojis=[...l.currentEmojis]}function q($){return!$.unicode||!P0($)||Yh.get($.unicode)}async function ce($){const ie=l.emojiVersion||await Vp();return $.filter(({version:ye})=>!ye||ye<=ie)}async function de($){return UD($,l.emojiVersion||await Vp())}async function se($){const ie=$===-1?l.customEmoji:await l.database.getEmojiByGroup($);return de(await ce(ie))}async function P($){return de(await ce(await l.database.getEmojiBySearchQuery($)))}d(()=>{}),d(()=>{function $(){const{searchMode:ye,currentEmojis:Se}=l;if(ye)return[{category:"",emojis:Se}];const Be=new Map;for(const Ke of Se){const We=Ke.category||"";let qt=Be.get(We);qt||(qt=[],Be.set(We,qt)),qt.push(Ke)}return[...Be.entries()].map(([Ke,We])=>({category:Ke,emojis:We})).sort((Ke,We)=>l.customCategorySorting(Ke.category,We.category))}const ie=$();S(ie)}),d(()=>{l.activeSearchItemId=l.activeSearchItem!==-1&&l.currentEmojis[l.activeSearchItem].id}),d(()=>{const{rawSearchText:$}=l;KS(()=>{l.searchText=($||"").trim(),l.activeSearchItem=-1})});function W($){if(!l.searchMode||!l.currentEmojis.length)return;const ie=ye=>{Ir($),l.activeSearchItem=Fp(ye,l.activeSearchItem,l.currentEmojis)};switch($.key){case"ArrowDown":return ie(!1);case"ArrowUp":return ie(!0);case"Enter":if(l.activeSearchItem===-1)l.activeSearchItem=0;else return Ir($),O(l.currentEmojis[l.activeSearchItem].id)}}function oe($){const{target:ie}=$,ye=ie.closest(".nav-button");if(!ye)return;const Se=parseInt(ye.dataset.groupId,10);a.searchElement.value="",l.rawSearchText="",l.searchText="",l.activeSearchItem=-1,l.currentGroupIndex=l.groups.findIndex(Be=>Be.id===Se)}function ae($){const{target:ie,key:ye}=$,Se=Be=>{Be&&(Ir($),Be.focus())};switch(ye){case"ArrowLeft":return Se(ie.previousElementSibling);case"ArrowRight":return Se(ie.nextElementSibling);case"Home":return Se(ie.parentElement.firstElementChild);case"End":return Se(ie.parentElement.lastElementChild)}}async function G($){const ie=await l.database.getEmojiByUnicodeOrName($),ye=[...l.currentEmojis,...l.currentFavorites].find(Be=>Be.id===$),Se=ye.unicode&&N(ye,l.currentSkinTone);return await l.database.incrementFavoriteEmojiCount($),{emoji:ie,skinTone:l.currentSkinTone,...Se&&{unicode:Se},...ye.name&&{name:ye.name}}}async function O($){const ie=G($);b("emoji-click-sync",ie),b("emoji-click",await ie)}function D($){const{target:ie}=$;if(!ie.classList.contains("emoji"))return;Ir($);const ye=ie.id.substring(4);O(ye)}function B($){l.currentSkinTone=$,l.skinTonePickerExpanded=!1,p("skintone-button"),b("skin-tone-change",{skinTone:$}),l.database.setPreferredSkinTone($)}function V($){const{target:{id:ie}}=$,ye=ie&&ie.match(/^skintone-(\d)/);if(!ye)return;Ir($);const Se=parseInt(ye[1],10);B(Se)}function Z($){l.skinTonePickerExpanded=!l.skinTonePickerExpanded,l.activeSkinTone=l.currentSkinTone,l.skinTonePickerExpanded&&(Ir($),ed(()=>p("skintone-list")))}d(()=>{l.skinTonePickerExpanded?a.skinToneDropdown.addEventListener("transitionend",()=>{l.skin Line truncated
`);function Hu(t){return t.label!==void 0}var IO=3,UO="32px",BO="16px",q0=4e3,$O=356,HO=14,GO=20,VO=200;function jr(...t){return t.filter(Boolean).join(" ")}function FO(t){let[n,a]=t.split("-"),o=[];return n&&o.push(n),a&&o.push(a),o}var YO=t=>{var n,a,o,c,l,d,m,p,g,b,v;let{invert:w,toast:y,unstyled:C,interacting:S,setHeights:N,visibleToasts:E,heights:T,index:M,toasts:k,expanded:_,removeToast:R,defaultRichColors:L,closeButton:ne,style:X,cancelButtonStyle:I,actionButtonStyle:H,className:q="",descriptionClassName:ce="",duration:de,position:se,gap:P,loadingIcon:W,expandByDefault:oe,classNames:ae,icons:G,closeButtonAriaLabel:O="Close toast",pauseWhenPageIsHidden:D}=t,[B,V]=ve.useState(null),[Z,be]=ve.useState(null),[K,ge]=ve.useState(!1),[me,$]=ve.useState(!1),[ie,ye]=ve.useState(!1),[Se,Be]=ve.useState(!1),[Ke,We]=ve.useState(!1),[qt,vn]=ve.useState(0),[Xn,br]=ve.useState(0),yn=ve.useRef(y.duration||de||q0),wn=ve.useRef(null),Zn=ve.useRef(null),Kt=M===0,po=M+1<=E,Pt=y.type,Qn=y.dismissible!==!1,Da=y.className||"",Es=y.descriptionClassName||"",qr=ve.useMemo(()=>T.findIndex(De=>De.toastId===y.id)||0,[T,y.id]),ho=ve.useMemo(()=>{var De;return(De=y.closeButton)!=null?De:ne},[y.closeButton,ne]),Kr=ve.useMemo(()=>y.duration||de||q0,[y.duration,de]),Dn=ve.useRef(0),yt=ve.useRef(0),On=ve.useRef(0),Rt=ve.useRef(null),[Ai,_i]=se.split("-"),go=ve.useMemo(()=>T.reduce((De,rt,lt)=>lt>=qr?De:De+rt.height,0),[T,qr]),Wr=RO(),Oa=y.invert||w,Ar=Pt==="loading";yt.current=ve.useMemo(()=>qr*P+go,[qr,go]),ve.useEffect(()=>{yn.current=Kr},[Kr]),ve.useEffect(()=>{ge(!0)},[]),ve.useEffect(()=>{let De=Zn.current;if(De){let rt=De.getBoundingClientRect().height;return br(rt),N(lt=>[{toastId:y.id,height:rt,position:y.position},...lt]),()=>N(lt=>lt.filter(rn=>rn.toastId!==y.id))}},[N,y.id]),ve.useLayoutEffect(()=>{if(!K)return;let De=Zn.current,rt=De.style.height;De.style.height="auto";let lt=De.getBoundingClientRect().height;De.style.height=rt,br(lt),N(rn=>rn.find(It=>It.toastId===y.id)?rn.map(It=>It.toastId===y.id?{...It,height:lt}:It):[{toastId:y.id,height:lt,position:y.position},...rn])},[K,y.title,y.description,N,y.id]);let Wt=ve.useCallback(()=>{$(!0),vn(yt.current),N(De=>De.filter(rt=>rt.toastId!==y.id)),setTimeout(()=>{R(y)},VO)},[y,R,N,yt]);ve.useEffect(()=>{if(y.promise&&Pt==="loading"||y.duration===1/0||y.type==="loading")return;let De;return _||S||D&&Wr?(()=>{if(On.current<Dn.current){let rt=new Date().getTime()-Dn.current;yn.current=yn.current-rt}On.current=new Date().getTime()})():yn.current!==1/0&&(Dn.current=new Date().getTime(),De=setTimeout(()=>{var rt;(rt=y.onAutoClose)==null||rt.call(y,y),Wt()},yn.current)),()=>clearTimeout(De)},[_,S,y,Pt,D,Wr,Wt]),ve.useEffect(()=>{y.delete&&Wt()},[Wt,y.delete]);function La(){var De,rt,lt;return G!=null&&G.loading?ve.createElement("div",{className:jr(ae==null?void 0:ae.loader,(De=y==null?void 0:y.classNames)==null?void 0:De.loader,"sonner-loader"),"data-visible":Pt==="loading"},G.loading):W?ve.createElement("div",{className:jr(ae==null?void 0:ae.loader,(rt=y==null?void 0:y.classNames)==null?void 0:rt.loader,"sonner-loader"),"data-visible":Pt==="loading"},W):ve.createElement(SO,{className:jr(ae==null?void 0:ae.loader,(lt=y==null?void 0:y.classNames)==null?void 0:lt.loader),visible:Pt==="loading"})}return ve.createElement("li",{tabIndex:0,ref:Zn,className:jr(q,Da,ae==null?void 0:ae.toast,(n=y==null?void 0:y.classNames)==null?void 0:n.toast,ae==null?void 0:ae.default,ae==null?void 0:ae[Pt],(a=y==null?void 0:y.classNames)==null?void 0:a[Pt]),"data-sonner-toast":"","data-rich-colors":(o=y.richColors)!=null?o:L,"data-styled":!(y.jsx||y.unstyled||C),"data-mounted":K,"data-promise":!!y.promise,"data-swiped":Ke,"data-removed":me,"data-visible":po,"data-y-position":Ai,"data-x-position":_i,"data-index":M,"data-front":Kt,"data-swiping":ie,"data-dismissible":Qn,"data-type":Pt,"data-invert":Oa,"data-swipe-out":Se,"data-swipe-direction":Z,"data-expanded":!!(_||oe&&K),style:{"--index":M,"--toasts-before":M,"--z-index":k.length-M,"--offset":`${me?qt:yt.current}px`,"--initial-height":oe?"auto":`${Xn}px`,...X,...y.style},onDragEnd:()=>{ye(!1),V(null),Rt.current=null},onPointerDown:De=>{Ar||!Qn||(wn.current=new Date,vn(yt.current),De.target.setPointerCapture(De.pointerId),De.target.tagName!=="BUTTON"&&(ye(!0),Rt.current={x:De.clientX,y:De.clientY}))},onPointerUp:()=>{var De,rt,lt,rn;if(Se||!Qn)return;Rt.current=null;let It=Number(((De=Zn.current)==null?void 0:De.style.getPropertyValue("--swipe-amount-x").replace("px",""))||0),Jn=Number(((rt=Zn.current)==null?void 0:rt.style.getPropertyValue("--swipe-amount-y").replace("px",""))||0),er=new Date().getTime()-((lt=wn.current)==null?void 0:lt.getTime()),bt=B==="x"?It:Jn,Ln=Math.abs(bt)/er;if(Math.abs(bt)>=GO||Ln>.11){vn(yt.current),(rn=y.onDismiss)==null||rn.call(y,y),be(B==="x"?It>0?"right":"left":Jn>0?"down":"up"),Wt(),Be(!0),We(!1);return}ye(!1),V(null)},onPointerMove:De=>{var rt,lt,rn,It;if(!Rt.current||!Qn||((rt=window.getSelection())==null?void 0:rt.toS Line truncated
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function X0(t,n){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);n&&(o=o.filter(function(c){return Object.getOwnPropertyDescriptor(t,c).enumerable})),a.push.apply(a,o)}return a}function Z0(t){for(var n=1;n<arguments.length;n++){var a=arguments[n]!=null?arguments[n]:{};n%2?X0(Object(a),!0).forEach(function(o){JO(t,o,a[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(a)):X0(Object(a)).forEach(function(o){Object.defineProperty(t,o,Object.getOwnPropertyDescriptor(a,o))})}return t}function nL(t,n){if(t==null)return{};var a,o,c=rL(t,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(o=0;o<l.length;o++)a=l[o],n.indexOf(a)===-1&&{}.propertyIsEnumerable.call(t,a)&&(c[a]=t[a])}return c}function rL(t,n){if(t==null)return{};var a={};for(var o in t)if({}.hasOwnProperty.call(t,o)){if(n.indexOf(o)!==-1)continue;a[o]=t[o]}return a}function aL(t,n){return QO(t)||eL(t,n)||iL(t,n)||tL()}function sL(t,n){if(typeof t!="object"||!t)return t;var a=t[Symbol.toPrimitive];if(a!==void 0){var o=a.call(t,n);if(typeof o!="object")return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return(n==="string"?String:Number)(t)}function oL(t){var n=sL(t,"string");return typeof n=="symbol"?n:n+""}function iL(t,n){if(t){if(typeof t=="string")return W0(t,n);var a={}.toString.call(t).slice(8,-1);return a==="Object"&&t.constructor&&(a=t.constructor.name),a==="Map"||a==="Set"?Array.from(t):a==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?W0(t,n):void 0}}function lL(t,n,a){return n in t?Object.defineProperty(t,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[n]=a,t}function Q0(t,n){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);n&&(o=o.filter(function(c){return Object.getOwnPropertyDescriptor(t,c).enumerable})),a.push.apply(a,o)}return a}function J0(t){for(var n=1;n<arguments.length;n++){var a=arguments[n]!=null?arguments[n]:{};n%2?Q0(Object(a),!0).forEach(function(o){lL(t,o,a[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(a)):Q0(Object(a)).forEach(function(o){Object.defineProperty(t,o,Object.getOwnPropertyDescriptor(a,o))})}return t}function cL(){for(var t=arguments.length,n=new Array(t),a=0;a<t;a++)n[a]=arguments[a];return function(o){return n.reduceRight(function(c,l){return l(c)},o)}}function Al(t){return function n(){for(var a=this,o=arguments.length,c=new Array(o),l=0;l<o;l++)c[l]=arguments[l];return c.length>=t.length?t.apply(this,c):function(){for(var d=arguments.length,m=new Array(d),p=0;p<d;p++)m[p]=arguments[p];return n.apply(a,[].concat(c,m))}}}function hd(t){return{}.toString.call(t).includes("Object")}function uL(t){return!Object.keys(t).length}function Ql(t){return typeof t=="function"}function dL(t,n){return Object.prototype.hasOwnProperty.call(t,n)}function fL(t,n){return hd(n)||us("changeType"),Object.keys(n).some(function(a){return!dL(t,a)})&&us("changeField"),n}function mL(t){Ql(t)||us("selectorType")}function pL(t){Ql(t)||hd(t)||us("handlerType"),hd(t)&&Object.values(t).some(function(n){return!Ql(n)})&&us("handlersType")}function hL(t){t||us("initialIsRequired"),hd(t)||us("initialType"),uL(t)&&us("initialContent")}function gL(t,n){throw new Error(t[n]||t.default)}var xL={initialIsRequired:"initial state is required",initialType:"initial state should be an object",initialContent:"initial state shouldn't be an empty object",handlerType:"handler should be an object or a function",handlersType:"all handlers should be a functions",selectorType:"selector should be a function",changeType:"provided value of changes should be an object",changeField:'it seams you want to change a field in the state which is not specified in the "initial" state',default:"an unknown error accured in `state-local` package"},us=Al(gL)(xL),Gu={changes:fL,selector:mL,handler:pL,initial:hL};function bL(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};Gu.initial(t),Gu.handler(n);var a={current:t},o=Al(wL)(a,n),c=Al(yL)(a),l=Al(Gu.changes)(t),d=Al(vL)(a);function m(){var g=arguments.length>0&&arguments[0]!==void 0?arguments[0]:function(b){return b};return Gu.selector(g),g(a.current)}function p(g){cL(o,c,l,d)(g)}return[m,p]}function vL(t,n){return Ql(n)?n(t.current):n}function yL(t,n){return t.current=J0(J0({},t.current),n),n}function wL(t,n,a){return Ql(n)?n(t.current):Object.keys(a).forEach(function(o){var c;return(c=n[o])===null||c===void 0?void 0:c.call(n,t.current[o])}),a}var jL={create:bL},CL={paths:{vs:"https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs"}};function SL(t){return function n(){for(var a=this,o=arguments.length,c=new Array(o),l=0;l<o;l++)c[l]=arguments[l];return c.length>=t.length?t.apply(this,c):function(){for(var d=arguments.length,m=new Array(d),p=0;p<d;p++)m[p]=arguments[p]; Line truncated
You are using deprecated way of configuration.
Instead of using
monaco.config({ urls: { monacoBase: '...' } })
use
monaco.config({ paths: { vs: '...' } })
For more please check the link https://github.com/suren-atoyan/monaco-loader#config
`},e2=SL(TL)(t5),ML={config:EL},RL=function(){for(var n=arguments.length,a=new Array(n),o=0;o<n;o++)a[o]=arguments[o];return function(c){return a.reduceRight(function(l,d){return d(l)},c)}};function n5(t,n){return Object.keys(n).forEach(function(a){n[a]instanceof Object&&t[a]&&Object.assign(n[a],n5(t[a],n[a]))}),Z0(Z0({},t),n)}var AL={type:"cancelation",msg:"operation is manually canceled"};function Wp(t){var n=!1,a=new Promise(function(o,c){t.then(function(l){return n?c(AL):o(l)}),t.catch(c)});return a.cancel=function(){return n=!0},a}var _L=["monaco"],DL=jL.create({config:CL,isInitialized:!1,resolve:null,reject:null,monaco:null}),r5=aL(DL,2),pc=r5[0],nf=r5[1];function OL(t){var n=ML.config(t),a=n.monaco,o=nL(n,_L);nf(function(c){return{config:n5(c.config,o),monaco:a}})}function LL(){var t=pc(function(n){var a=n.monaco,o=n.isInitialized,c=n.resolve;return{monaco:a,isInitialized:o,resolve:c}});if(!t.isInitialized){if(nf({isInitialized:!0}),t.monaco)return t.resolve(t.monaco),Wp(Xp);if(window.monaco&&window.monaco.editor)return a5(window.monaco),t.resolve(window.monaco),Wp(Xp);RL(zL,IL)(UL)}return Wp(Xp)}function zL(t){return document.body.appendChild(t)}function PL(t){var n=document.createElement("script");return t&&(n.src=t),n}function IL(t){var n=pc(function(o){var c=o.config,l=o.reject;return{config:c,reject:l}}),a=PL("".concat(n.config.paths.vs,"/loader.js"));return a.onload=function(){return t()},a.onerror=n.reject,a}function UL(){var t=pc(function(a){var o=a.config,c=a.resolve,l=a.reject;return{config:o,resolve:c,reject:l}}),n=window.require;n.config(t.config),n(["vs/editor/editor.main"],function(a){var o=a.m||a;a5(o),t.resolve(o)},function(a){t.reject(a)})}function a5(t){pc().monaco||nf({monaco:t})}function BL(){return pc(function(t){var n=t.monaco;return n})}var Xp=new Promise(function(t,n){return nf({resolve:t,reject:n})}),s5={config:OL,init:LL,__getMonacoInstance:BL},$L={wrapper:{display:"flex",position:"relative",textAlign:"initial"},fullWidth:{width:"100%"},hide:{display:"none"}},Zp=$L,HL={container:{display:"flex",height:"100%",width:"100%",justifyContent:"center",alignItems:"center"}},GL=HL;function VL({children:t}){return ve.createElement("div",{style:GL.container},t)}var FL=VL,YL=FL;function qL({width:t,height:n,isEditorReady:a,loading:o,_ref:c,className:l,wrapperProps:d}){return ve.createElement("section",{style:{...Zp.wrapper,width:t,height:n},...d},!a&&ve.createElement(YL,null,o),ve.createElement("div",{ref:c,style:{...Zp.fullWidth,...!a&&Zp.hide},className:l}))}var KL=qL,o5=f.memo(KL);function WL(t){f.useEffect(t,[])}var i5=WL;function XL(t,n,a=!0){let o=f.useRef(!0);f.useEffect(o.current||!a?()=>{o.current=!1}:t,n)}var Yn=XL;function zl(){}function si(t,n,a,o){return ZL(t,o)||QL(t,n,a,o)}function ZL(t,n){return t.editor.getModel(l5(t,n))}function QL(t,n,a,o){return t.editor.createModel(n,a,o?l5(t,o):void 0)}function l5(t,n){return t.Uri.parse(n)}function JL({original:t,modified:n,language:a,originalLanguage:o,modifiedLanguage:c,originalModelPath:l,modifiedModelPath:d,keepCurrentOriginalModel:m=!1,keepCurrentModifiedModel:p=!1,theme:g="light",loading:b="Loading...",options:v={},height:w="100%",width:y="100%",className:C,wrapperProps:S={},beforeMount:N=zl,onMount:E=zl}){let[T,M]=f.useState(!1),[k,_]=f.useState(!0),R=f.useRef(null),L=f.useRef(null),ne=f.useRef(null),X=f.useRef(E),I=f.useRef(N),H=f.useRef(!1);i5(()=>{let se=s5.init();return se.then(P=>(L.current=P)&&_(!1)).catch(P=>(P==null?void 0:P.type)!=="cancelation"&&console.error("Monaco initialization: error:",P)),()=>R.current?de():se.cancel()}),Yn(()=>{if(R.current&&L.current){let se=R.current.getOriginalEditor(),P=si(L.current,t||"",o||a||"text",l||"");P!==se.getModel()&&se.setModel(P)}},[l],T),Yn(()=>{if(R.current&&L.current){let se=R.current.getModifiedEditor(),P=si(L.current,n||"",c||a||"text",d||"");P!==se.getModel()&&se.setModel(P)}},[d],T),Yn(()=>{let se=R.current.getModifiedEditor();se.getOption(L.current.editor.EditorOption.readOnly)?se.setValue(n||""):n!==se.getValue()&&(se.executeEdits("",[{range:se.getModel().getFullModelRange(),text:n||"",forceMoveMarkers:!0}]),se.pushUndoStop())},[n],T),Yn(()=>{var se,P;(P=(se=R.current)==null?void 0:se.getModel())==null||P.original.setValue(t||"")},[t],T),Yn(()=>{let{original:se,modified:P}=R.current.getModel();L.current.editor.setModelLanguage(se,o||a||"text"),L.current.editor.setModelLanguage(P,c||a||"text")},[a,o,c],T),Yn(()=>{var se;(se=L.current)==null||se.editor.setTheme(g)},[g],T),Yn(()=>{var se;(se=R.current)==null||se.updateOptions(v)},[v],T);let q=f.useCallback(()=>{var W;if(!L.current)return;I.current(L.current);let se=si(L.current,t||"",o||a||"text",l||""),P=si(L.current,n||"",c||a||"text",d||"");(W=R.current)==null||W.setModel({original:se,modified:P})},[a,n,c,t,o,l,d]),ce=f.useCallback(()=>{var se;!H.current&&ne.current&&(R.current=L.current.editor.createDiffEditor(ne.current,{automaticLayout:!0,...v}),q(),(se=L.current)==null||se.editor.setTheme(g),M(!0),H.current=! Line truncated
987654321098765432`,className:"min-h-[120px] font-mono text-sm"})]}),s.jsx(mo,{result:a.owners}),s.jsx("div",{className:"mt-auto",children:s.jsx(ue,{type:"button",variant:"secondary",disabled:o||!t.ownerUserIds.trim(),onClick:c,children:o?"Checking with Discord…":"Verify owner IDs"})})]})}function Mz({onContinue:t}){return s.jsx("div",{className:"mx-auto flex w-full max-w-lg flex-1 flex-col justify-center py-8",children:s.jsxs("div",{className:"rounded-2xl border border-border bg-card px-6 py-10 text-center md:px-10",children:[s.jsx("div",{className:"mx-auto mb-6 flex size-16 items-center justify-center rounded-2xl bg-primary/10 text-primary",children:s.jsx(xe,{icon:jd,size:40})}),s.jsx("h2",{className:"text-2xl font-semibold tracking-tight",children:"Setup complete"}),s.jsxs("p",{className:"mx-auto mt-3 max-w-sm text-sm leading-relaxed text-muted-foreground",children:["Your configuration has been saved. Restart the server for changes to take effect — stop the running process, then start it again (for example"," ",s.jsx("code",{className:"rounded-md bg-muted px-1.5 py-0.5 font-mono text-xs",children:"npm start"}),")."]}),s.jsx(Ye,{className:"mt-6 text-left",children:s.jsx(qe,{children:"After restarting, sign in with Discord to open the dashboard."})}),s.jsx(ue,{type:"button",size:"lg",className:"mt-8 min-w-[220px]",onClick:t,children:"Continue to sign in"})]})})}function Rz({currentIndex:t,validating:n,saving:a,onBack:o,onNext:c,onFinish:l}){const d=t===ui.length-1;return s.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[s.jsxs(ue,{type:"button",variant:"ghost",disabled:t===0||a,onClick:o,children:[s.jsx(xe,{icon:T2,size:18,className:"mr-1"}),"Back"]}),s.jsx("div",{className:"flex flex-1 justify-end gap-2",children:d?s.jsx(ue,{type:"button",size:"lg",disabled:a||n,onClick:l,className:"min-w-[200px]",children:a?"Saving…":"Finish setup"}):s.jsxs(ue,{type:"button",size:"lg",disabled:n||a,onClick:c,children:["Continue",s.jsx(xe,{icon:lg,size:18,className:"ml-1"})]})})]})}function Az({values:t,setValues:n,validation:a,validating:o,onValidate:c}){return s.jsxs("div",{className:"flex flex-1 flex-col gap-5",children:[s.jsxs("p",{className:"text-sm leading-relaxed text-muted-foreground",children:["An Emerald Services API key is optional, but required to use the one-click addon installer in the dashboard. You can get yours from the"," ",s.jsx("a",{href:"https://emeraldsrv.dev",target:"_blank",rel:"noreferrer",className:"font-medium text-primary hover:underline",children:"Emerald Services Marketplace"}),"."]}),s.jsxs("div",{className:"space-y-2",children:[s.jsx(Ae,{htmlFor:"emeraldApiKey",children:"Emerald API key (Optional)"}),s.jsx(_e,{id:"emeraldApiKey",type:"password",autoComplete:"off",value:t.emeraldApiKey,onChange:l=>n({...t,emeraldApiKey:l.target.value}),placeholder:"em_...",className:"h-11 font-mono text-sm"})]}),s.jsx(mo,{result:a.emeraldApi}),s.jsx("div",{className:"mt-auto",children:s.jsx(ue,{type:"button",variant:"secondary",disabled:o,onClick:c,children:o?"Checking…":t.emeraldApiKey?"Verify key":"Skip step"})})]})}function _z({values:t,setValues:n,validation:a,validating:o,onValidate:c}){const l=a.database,d=t.dbDriver==="mysql";return s.jsxs("div",{className:"flex flex-1 flex-col gap-6",children:[s.jsxs("p",{className:"text-sm leading-relaxed text-muted-foreground",children:["Choose your database storage engine. Select ",s.jsx("strong",{children:"SQLite"})," for instant zero-config local storage, or ",s.jsx("strong",{children:"MySQL / MariaDB"})," for external host databases."]}),s.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[s.jsxs("div",{onClick:()=>n(m=>({...m,dbDriver:"sqlite"})),className:pe("cursor-pointer rounded-xl border p-4 transition-all hover:border-primary",t.dbDriver==="sqlite"?"border-primary bg-primary/5 ring-2 ring-primary/20":"border-border bg-card"),children:[s.jsxs("div",{className:"flex items-center justify-between mb-2",children:[s.jsx("span",{className:"font-semibold text-foreground",children:"SQLite"}),s.jsx("span",{className:"rounded-full bg-emerald-500/10 px-2.5 py-0.5 text-xs font-medium text-emerald-500",children:"Zero Config"})]}),s.jsxs("p",{className:"text-xs text-muted-foreground",children:["Single-file SQL database stored locally at ",s.jsx("code",{className:"font-mono",children:"./Data/supportbot.db"}),". Zero extra setup required."]})]}),s.jsxs("div",{onClick:()=>n(m=>({...m,dbDriver:"mysql"})),className:pe("cursor-pointer rounded-xl border p-4 transition-all hover:border-primary",t.dbDriver==="mysql"?"border-primary bg-primary/5 ring-2 ring-primary/20":"border-border bg-card"),children:[s.jsxs("div",{className:"flex items-center justify-between mb-2",children:[s.jsx("span",{className:"font-semibold text-foreground",children:"MySQL / MariaDB"}),s.jsx("span",{className:"rounded-full bg-blue-500/10 px-2.5 py-0.5 text-xs font-medium text-blue-500",children:"External Database"})]}),s.jsx("p",{className:"text-xs te Line truncated
@@ -1 +0,0 @@
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Poppins,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 240 10% 4%;--foreground: 0 0% 98%;--card: 240 7% 11%;--card-foreground: 0 0% 98%;--popover: 240 8% 10%;--popover-foreground: 0 0% 98%;--primary: 141 45% 49%;--primary-foreground: 0 0% 100%;--secondary: 240 6% 14%;--secondary-foreground: 0 0% 90%;--muted: 240 6% 14%;--muted-foreground: 240 5%Line truncated
@@ -0,0 +1 @@
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Poppins,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 240 10% 4%;--foreground: 0 0% 98%;--card: 240 7% 11%;--card-foreground: 0 0% 98%;--popover: 240 8% 10%;--popover-foreground: 0 0% 98%;--primary: 141 45% 49%;--primary-foreground: 0 0% 100%;--secondary: 240 6% 14%;--secondary-foreground: 0 0% 90%;--muted: 240 6% 14%;--muted-foreground: 240 5%Line truncated
+2 -2
View File
@@ -10,8 +10,8 @@
href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap"
rel="stylesheet"
/>
<script type="module" crossorigin src="/assets/index-BOdhXLlb.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DoxvJPsp.css">
<script type="module" crossorigin src="/assets/index-CzmlDpil.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Dx-VdUAO.css">
</head>
<body>
<div id="root"></div>␍