Update web server and dashboard styling for improved user experience
Refactor bot.js to separate HTTP server logic and introduce Express web portal. Update dashboard.html with new styling, color themes, and font imports. Replit-Commit-Author: Agent Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 17beead7-b08f-41f9-a6ea-f8e2ff20a502 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/b2aEQYO Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
57382c58b8
commit
be74f5f0bf
10 changed files with 3523 additions and 3744 deletions
4
.replit
4
.replit
|
|
@ -22,6 +22,10 @@ externalPort = 80
|
|||
localPort = 8080
|
||||
externalPort = 8080
|
||||
|
||||
[[ports]]
|
||||
localPort = 36319
|
||||
externalPort = 3000
|
||||
|
||||
[workflows]
|
||||
runButton = "Project"
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,8 @@ const http = require("http");
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const WebSocket = require("ws");
|
||||
const { createWebServer } = require("./server/webServer");
|
||||
|
||||
// Dashboard HTML path
|
||||
const dashboardPath = path.join(__dirname, "public", "dashboard.html");
|
||||
require("dotenv").config();
|
||||
|
||||
// =============================================================================
|
||||
|
|
@ -2463,11 +2462,25 @@ httpServer.on('upgrade', (request, socket, head) => {
|
|||
});
|
||||
|
||||
httpServer.listen(healthPort, () => {
|
||||
console.log(`Health check server running on port ${healthPort}`);
|
||||
console.log(`Health/API server running on port ${healthPort}`);
|
||||
console.log(`WebSocket server available at ws://localhost:${healthPort}`);
|
||||
console.log(`Register commands at: POST http://localhost:${healthPort}/register-commands`);
|
||||
});
|
||||
|
||||
// =============================================================================
|
||||
// EXPRESS WEB PORTAL (Discord OAuth, User Dashboard, API)
|
||||
// =============================================================================
|
||||
|
||||
const webPort = process.env.PORT || 5000;
|
||||
const expressApp = createWebServer(client, supabase);
|
||||
const webServer = http.createServer(expressApp);
|
||||
|
||||
webServer.listen(webPort, '0.0.0.0', () => {
|
||||
console.log(`Web portal running on port ${webPort}`);
|
||||
console.log(`Dashboard: http://localhost:${webPort}/dashboard`);
|
||||
console.log(`Landing page: http://localhost:${webPort}/`);
|
||||
});
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// BOT LOGIN AND READY
|
||||
|
|
|
|||
620
aethex-bot/public/css/aethex-theme.css
Normal file
620
aethex-bot/public/css/aethex-theme.css
Normal file
|
|
@ -0,0 +1,620 @@
|
|||
@import url("https://fonts.googleapis.com/css2?family=VT323&family=Press+Start+2P&family=Merriweather:wght@400;700&family=Roboto+Mono:wght@300;400;500&display=swap");
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
/**
|
||||
* Tailwind CSS theme
|
||||
* tailwind.config.ts expects the following color variables to be expressed as HSL values.
|
||||
* A different format will require also updating the theme in tailwind.config.ts.
|
||||
*/
|
||||
:root {
|
||||
--background: 222 84% 4.9%;
|
||||
|
||||
/* Spacing tokens */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 24px;
|
||||
--space-6: 32px;
|
||||
--space-section-y: var(--space-6);
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
--card: 222 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
--popover: 222 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
--primary: 250 100% 60%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 250 100% 70%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
|
||||
--sidebar-background: 240 5.9% 10%;
|
||||
--sidebar-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-primary: 250 100% 60%;
|
||||
--sidebar-primary-foreground: 0 0% 100%;
|
||||
--sidebar-accent: 240 3.7% 15.9%;
|
||||
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-border: 240 3.7% 15.9%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
|
||||
/* AeThex Brand Colors */
|
||||
--aethex-50: 250 100% 97%;
|
||||
--aethex-100: 250 100% 95%;
|
||||
--aethex-200: 250 100% 90%;
|
||||
--aethex-300: 250 100% 80%;
|
||||
--aethex-400: 250 100% 70%;
|
||||
--aethex-500: 250 100% 60%;
|
||||
--aethex-600: 250 100% 50%;
|
||||
--aethex-700: 250 100% 40%;
|
||||
--aethex-800: 250 100% 30%;
|
||||
--aethex-900: 250 100% 20%;
|
||||
--aethex-950: 250 100% 10%;
|
||||
|
||||
/* Neon Colors for Accents */
|
||||
--neon-purple: 280 100% 70%;
|
||||
--neon-blue: 210 100% 70%;
|
||||
--neon-green: 120 100% 70%;
|
||||
--neon-yellow: 50 100% 70%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
font-family: "Courier New", "Courier", monospace;
|
||||
letter-spacing: 0.025em;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
/* Hide scrollbar while keeping functionality */
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar {
|
||||
display: none; /* Chrome, Safari and Opera */
|
||||
}
|
||||
|
||||
/* Hide horizontal scrollbar on all elements */
|
||||
* {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
@apply px-4 sm:px-6 lg:px-8;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
/* Arm Theme Font Classes */
|
||||
.font-labs {
|
||||
font-family: "VT323", "Courier New", monospace;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.font-gameforge {
|
||||
font-family: "Press Start 2P", "Arial Black", sans-serif;
|
||||
letter-spacing: 0.1em;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.font-corp {
|
||||
font-family: "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI",
|
||||
sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.font-foundation {
|
||||
font-family: "Merriweather", "Georgia", serif;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.font-devlink {
|
||||
font-family: "Roboto Mono", "Courier New", monospace;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.font-staff {
|
||||
font-family: "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI",
|
||||
sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.font-nexus {
|
||||
font-family: "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI",
|
||||
sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.font-default {
|
||||
font-family: "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI",
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
/* Arm Theme Wallpaper Patterns */
|
||||
.wallpaper-labs {
|
||||
background-image: radial-gradient(
|
||||
circle,
|
||||
rgba(251, 191, 36, 0.08) 1px,
|
||||
transparent 1px
|
||||
);
|
||||
background-size: 20px 20px;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.wallpaper-gameforge {
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
rgba(34, 197, 94, 0.06) 25%,
|
||||
transparent 25%,
|
||||
transparent 75%,
|
||||
rgba(34, 197, 94, 0.06) 75%
|
||||
),
|
||||
linear-gradient(
|
||||
45deg,
|
||||
rgba(34, 197, 94, 0.06) 25%,
|
||||
transparent 25%,
|
||||
transparent 75%,
|
||||
rgba(34, 197, 94, 0.06) 75%
|
||||
);
|
||||
background-size: 40px 40px;
|
||||
background-position: 0 0, 20px 20px;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.wallpaper-corp {
|
||||
background-image: linear-gradient(
|
||||
90deg,
|
||||
rgba(59, 130, 246, 0.05) 1px,
|
||||
transparent 1px
|
||||
),
|
||||
linear-gradient(rgba(59, 130, 246, 0.05) 1px, transparent 1px);
|
||||
background-size: 20px 20px;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.wallpaper-foundation {
|
||||
background-image: repeating-linear-gradient(
|
||||
0deg,
|
||||
rgba(239, 68, 68, 0.04) 0px,
|
||||
rgba(239, 68, 68, 0.04) 1px,
|
||||
transparent 1px,
|
||||
transparent 2px
|
||||
);
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.wallpaper-devlink {
|
||||
background-image: linear-gradient(
|
||||
0deg,
|
||||
transparent 24%,
|
||||
rgba(6, 182, 212, 0.08) 25%,
|
||||
rgba(6, 182, 212, 0.08) 26%,
|
||||
transparent 27%,
|
||||
transparent 74%,
|
||||
rgba(6, 182, 212, 0.08) 75%,
|
||||
rgba(6, 182, 212, 0.08) 76%,
|
||||
transparent 77%,
|
||||
transparent
|
||||
),
|
||||
linear-gradient(
|
||||
90deg,
|
||||
transparent 24%,
|
||||
rgba(6, 182, 212, 0.08) 25%,
|
||||
rgba(6, 182, 212, 0.08) 26%,
|
||||
transparent 27%,
|
||||
transparent 74%,
|
||||
rgba(6, 182, 212, 0.08) 75%,
|
||||
rgba(6, 182, 212, 0.08) 76%,
|
||||
transparent 77%,
|
||||
transparent
|
||||
);
|
||||
background-size: 50px 50px;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.wallpaper-staff {
|
||||
background-image: radial-gradient(
|
||||
circle,
|
||||
rgba(168, 85, 247, 0.08) 1px,
|
||||
transparent 1px
|
||||
);
|
||||
background-size: 20px 20px;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.wallpaper-nexus {
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
rgba(236, 72, 153, 0.06) 25%,
|
||||
transparent 25%,
|
||||
transparent 75%,
|
||||
rgba(236, 72, 153, 0.06) 75%
|
||||
),
|
||||
linear-gradient(
|
||||
45deg,
|
||||
rgba(236, 72, 153, 0.06) 25%,
|
||||
transparent 25%,
|
||||
transparent 75%,
|
||||
rgba(236, 72, 153, 0.06) 75%
|
||||
);
|
||||
background-size: 40px 40px;
|
||||
background-position: 0 0, 20px 20px;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.wallpaper-default {
|
||||
background-image: linear-gradient(
|
||||
135deg,
|
||||
rgba(167, 139, 250, 0.05) 0%,
|
||||
rgba(96, 165, 250, 0.05) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.section-cozy {
|
||||
padding-block: var(--space-section-y);
|
||||
}
|
||||
.gap-cozy {
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.pad-cozy {
|
||||
padding: var(--space-5);
|
||||
}
|
||||
|
||||
.text-gradient {
|
||||
@apply bg-gradient-to-r from-aethex-400 via-neon-blue to-aethex-600 bg-clip-text text-transparent;
|
||||
background-size: 200% 200%;
|
||||
animation: gradient-shift 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.text-gradient-purple {
|
||||
@apply bg-gradient-to-r from-neon-purple via-aethex-500 to-neon-blue bg-clip-text text-transparent;
|
||||
background-size: 200% 200%;
|
||||
animation: gradient-shift 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.bg-aethex-gradient {
|
||||
@apply bg-gradient-to-br from-aethex-900 via-background to-aethex-800;
|
||||
}
|
||||
|
||||
.border-gradient {
|
||||
@apply relative overflow-hidden;
|
||||
}
|
||||
|
||||
.border-gradient::before {
|
||||
content: "";
|
||||
@apply absolute inset-0 rounded-[inherit] p-[1px] bg-gradient-to-r from-aethex-400 via-neon-blue to-aethex-600;
|
||||
mask:
|
||||
linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
mask-composite: xor;
|
||||
background-size: 200% 200%;
|
||||
animation: gradient-shift 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.glow-purple {
|
||||
box-shadow:
|
||||
0 0 20px rgba(139, 92, 246, 0.3),
|
||||
0 0 40px rgba(139, 92, 246, 0.2);
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.glow-purple:hover {
|
||||
box-shadow:
|
||||
0 0 30px rgba(139, 92, 246, 0.5),
|
||||
0 0 60px rgba(139, 92, 246, 0.3);
|
||||
}
|
||||
|
||||
.glow-blue {
|
||||
box-shadow:
|
||||
0 0 20px rgba(59, 130, 246, 0.3),
|
||||
0 0 40px rgba(59, 130, 246, 0.2);
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.glow-blue:hover {
|
||||
box-shadow:
|
||||
0 0 30px rgba(59, 130, 246, 0.5),
|
||||
0 0 60px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.glow-green {
|
||||
box-shadow:
|
||||
0 0 20px rgba(34, 197, 94, 0.3),
|
||||
0 0 40px rgba(34, 197, 94, 0.2);
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.glow-yellow {
|
||||
box-shadow:
|
||||
0 0 20px rgba(251, 191, 36, 0.3),
|
||||
0 0 40px rgba(251, 191, 36, 0.2);
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.animate-fade-in {
|
||||
animation: fade-in 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-up {
|
||||
animation: slide-up 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-down {
|
||||
animation: slide-down 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-left {
|
||||
animation: slide-left 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-right {
|
||||
animation: slide-right 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-scale-in {
|
||||
animation: scale-in 0.4s ease-out;
|
||||
}
|
||||
|
||||
.animate-bounce-gentle {
|
||||
animation: bounce-gentle 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-float {
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-pulse-glow {
|
||||
animation: pulse-glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-typing {
|
||||
animation:
|
||||
typing 3s steps(40, end),
|
||||
blink-caret 0.75s step-end infinite;
|
||||
overflow: hidden;
|
||||
border-right: 3px solid;
|
||||
white-space: nowrap;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.hover-lift {
|
||||
transition:
|
||||
transform 0.3s ease,
|
||||
box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-lift:hover {
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
|
||||
.hover-glow {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-glow:hover {
|
||||
filter: brightness(1.1) drop-shadow(0 0 10px currentColor);
|
||||
}
|
||||
|
||||
.interactive-scale {
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.interactive-scale:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.interactive-scale:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.loading-dots::after {
|
||||
content: "";
|
||||
animation: loading-dots 1.5s infinite;
|
||||
}
|
||||
|
||||
.skeleton {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.1),
|
||||
transparent
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: skeleton-loading 1.5s infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes gradient-shift {
|
||||
0%,
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-up {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-down {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-left {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-right {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scale-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce-gentle {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse-glow {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.8;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
from {
|
||||
width: 0;
|
||||
}
|
||||
to {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink-caret {
|
||||
from,
|
||||
to {
|
||||
border-color: transparent;
|
||||
}
|
||||
50% {
|
||||
border-color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes loading-dots {
|
||||
0% {
|
||||
content: "";
|
||||
}
|
||||
25% {
|
||||
content: ".";
|
||||
}
|
||||
50% {
|
||||
content: "..";
|
||||
}
|
||||
75% {
|
||||
content: "...";
|
||||
}
|
||||
100% {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes skeleton-loading {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.001ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.001ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
536
aethex-bot/public/index.html
Normal file
536
aethex-bot/public/index.html
Normal file
|
|
@ -0,0 +1,536 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AeThex Bot - Level Up Your Discord Server</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--background: hsl(222, 84%, 4.9%);
|
||||
--foreground: hsl(210, 40%, 98%);
|
||||
--card: hsl(222, 84%, 6%);
|
||||
--card-foreground: hsl(210, 40%, 98%);
|
||||
--primary: hsl(250, 100%, 60%);
|
||||
--primary-foreground: hsl(210, 40%, 98%);
|
||||
--secondary: hsl(217.2, 32.6%, 17.5%);
|
||||
--muted: hsl(217.2, 32.6%, 17.5%);
|
||||
--muted-foreground: hsl(215, 20.2%, 65.1%);
|
||||
--border: hsl(217.2, 32.6%, 17.5%);
|
||||
--aethex-400: hsl(250, 100%, 70%);
|
||||
--aethex-500: hsl(250, 100%, 60%);
|
||||
--aethex-600: hsl(250, 100%, 50%);
|
||||
--neon-purple: hsl(280, 100%, 70%);
|
||||
--neon-blue: hsl(210, 100%, 70%);
|
||||
--neon-green: hsl(120, 100%, 70%);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.wallpaper {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-image: linear-gradient(135deg, rgba(167, 139, 250, 0.05) 0%, rgba(96, 165, 250, 0.05) 100%);
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1.5rem;
|
||||
}
|
||||
|
||||
header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
background: rgba(10, 10, 20, 0.95);
|
||||
backdrop-filter: blur(12px);
|
||||
border-bottom: 2px solid var(--aethex-500);
|
||||
box-shadow: 0 8px 32px rgba(139, 92, 246, 0.15);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
text-decoration: none;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: linear-gradient(135deg, var(--aethex-500), var(--neon-blue));
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(to right, var(--aethex-400), var(--neon-blue), var(--aethex-600));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: var(--muted-foreground);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.625rem 1.25rem;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--aethex-500), var(--neon-blue));
|
||||
color: white;
|
||||
box-shadow: 0 0 20px rgba(139, 92, 246, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 0 30px rgba(139, 92, 246, 0.5);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background: var(--secondary);
|
||||
border-color: var(--aethex-500);
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding: 6rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: clamp(2.5rem, 5vw, 4rem);
|
||||
font-weight: 700;
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.text-gradient {
|
||||
background: linear-gradient(to right, var(--aethex-400), var(--neon-blue), var(--aethex-600));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
background-size: 200% 200%;
|
||||
animation: gradient-shift 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes gradient-shift {
|
||||
0%, 100% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
}
|
||||
|
||||
.hero p {
|
||||
font-size: 1.25rem;
|
||||
color: var(--muted-foreground);
|
||||
max-width: 600px;
|
||||
margin: 0 auto 2.5rem;
|
||||
}
|
||||
|
||||
.hero-buttons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.stats-bar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 3rem;
|
||||
margin-top: 4rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.stat {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--aethex-400);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
color: var(--muted-foreground);
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.features {
|
||||
padding: 5rem 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
text-align: center;
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
background: linear-gradient(135deg, rgba(139, 92, 246, 0.1), rgba(59, 130, 246, 0.05));
|
||||
border: 1px solid rgba(139, 92, 246, 0.2);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
transform: translateY(-4px);
|
||||
border-color: var(--aethex-500);
|
||||
box-shadow: 0 0 30px rgba(139, 92, 246, 0.2);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: linear-gradient(135deg, var(--aethex-500), var(--neon-blue));
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.feature-card h3 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.feature-card p {
|
||||
color: var(--muted-foreground);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.cta {
|
||||
padding: 5rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cta-box {
|
||||
background: linear-gradient(135deg, rgba(139, 92, 246, 0.15), rgba(59, 130, 246, 0.1));
|
||||
border: 1px solid rgba(139, 92, 246, 0.3);
|
||||
border-radius: 24px;
|
||||
padding: 4rem 2rem;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cta h2 {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.cta p {
|
||||
color: var(--muted-foreground);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 3rem 0;
|
||||
text-align: center;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 2rem;
|
||||
margin-bottom: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.footer-links a {
|
||||
color: var(--muted-foreground);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer-links a:hover {
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid transparent;
|
||||
border-top-color: currentColor;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.nav-links {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.stats-bar {
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wallpaper"></div>
|
||||
|
||||
<header>
|
||||
<div class="container header-content">
|
||||
<a href="/" class="logo">
|
||||
<div class="logo-icon">A</div>
|
||||
<span class="logo-text">AeThex</span>
|
||||
</a>
|
||||
|
||||
<nav class="nav-links">
|
||||
<a href="#features">Features</a>
|
||||
<a href="#leaderboard">Leaderboard</a>
|
||||
<a href="https://discord.gg/aethex" target="_blank">Support</a>
|
||||
</nav>
|
||||
|
||||
<div class="auth-buttons">
|
||||
<a href="/auth/discord" class="btn btn-primary" id="loginBtn">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"/></svg>
|
||||
Login with Discord
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="hero">
|
||||
<div class="container">
|
||||
<h1>Level Up Your<br><span class="text-gradient">Discord Server</span></h1>
|
||||
<p>The ultimate XP, leveling, and community engagement bot. Track progress, earn achievements, complete quests, and unlock rewards.</p>
|
||||
|
||||
<div class="hero-buttons">
|
||||
<a href="https://discord.com/api/oauth2/authorize?client_id=1307534067556167720&permissions=8&scope=bot%20applications.commands" class="btn btn-primary" target="_blank">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>
|
||||
Add to Server
|
||||
</a>
|
||||
<a href="/auth/discord" class="btn btn-outline">
|
||||
View Your Profile
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="stats-bar" id="statsBar">
|
||||
<div class="stat">
|
||||
<div class="stat-value" id="serverCount">-</div>
|
||||
<div class="stat-label">Servers</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-value" id="userCount">-</div>
|
||||
<div class="stat-label">Users</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-value" id="commandCount">-</div>
|
||||
<div class="stat-label">Commands</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-value" id="uptimeValue">-</div>
|
||||
<div class="stat-label">Uptime</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="features" id="features">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Powerful <span class="text-gradient">Features</span></h2>
|
||||
|
||||
<div class="features-grid">
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">📈</div>
|
||||
<h3>XP & Leveling System</h3>
|
||||
<p>Earn XP from messages, reactions, and voice chat. Level up with customizable curves and unlock role rewards automatically.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🏆</div>
|
||||
<h3>Achievements & Badges</h3>
|
||||
<p>Create custom achievements with various triggers. Users earn badges for milestones, building their profile showcase.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🎯</div>
|
||||
<h3>Quests & Challenges</h3>
|
||||
<p>Set up rotating quests with objectives like sending messages, earning XP, or spending time in voice. Reward completion with XP and roles.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🛒</div>
|
||||
<h3>XP Shop System</h3>
|
||||
<p>Let users spend XP on cosmetics, perks, and custom roles. Fully configurable items and pricing.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">⭐</div>
|
||||
<h3>Prestige System</h3>
|
||||
<p>Reset at max level for permanent bonuses. Prestige levels unlock exclusive perks and XP multipliers.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🏅</div>
|
||||
<h3>Leaderboards</h3>
|
||||
<p>Weekly, monthly, and all-time leaderboards with automatic resets. See who's on top across your server.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🛡️</div>
|
||||
<h3>Sentinel Security</h3>
|
||||
<p>Anti-nuke protection with heat tracking. Protect your server from mass bans, kicks, and channel deletions.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🎫</div>
|
||||
<h3>Ticket System</h3>
|
||||
<p>Create support tickets with categories, transcripts, and staff assignment. Keep your community organized.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🔗</div>
|
||||
<h3>Federation Sync</h3>
|
||||
<p>Sync roles across multiple servers. Perfect for multi-server communities and partnerships.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta">
|
||||
<div class="container">
|
||||
<div class="cta-box">
|
||||
<h2 class="text-gradient">Ready to Level Up?</h2>
|
||||
<p>Join thousands of servers using AeThex to build engaged communities.</p>
|
||||
<a href="https://discord.com/api/oauth2/authorize?client_id=1307534067556167720&permissions=8&scope=bot%20applications.commands" class="btn btn-primary" target="_blank">
|
||||
Add AeThex to Your Server
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="footer-links">
|
||||
<a href="https://aethex.studio" target="_blank">AeThex Studio</a>
|
||||
<a href="https://aethex.foundation" target="_blank">Foundation</a>
|
||||
<a href="https://discord.gg/aethex" target="_blank">Discord</a>
|
||||
<a href="/dashboard">Dashboard</a>
|
||||
</div>
|
||||
<p>© 2024 AeThex. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
async function loadStats() {
|
||||
try {
|
||||
const res = await fetch('/api/bot-stats');
|
||||
const data = await res.json();
|
||||
|
||||
document.getElementById('serverCount').textContent = data.guilds.toLocaleString();
|
||||
document.getElementById('userCount').textContent = data.users.toLocaleString();
|
||||
document.getElementById('commandCount').textContent = data.commands;
|
||||
|
||||
const hours = Math.floor(data.uptime / 3600);
|
||||
const days = Math.floor(hours / 24);
|
||||
document.getElementById('uptimeValue').textContent = days > 0 ? `${days}d` : `${hours}h`;
|
||||
} catch (e) {
|
||||
console.log('Stats unavailable');
|
||||
}
|
||||
}
|
||||
|
||||
async function checkAuth() {
|
||||
try {
|
||||
const res = await fetch('/api/me');
|
||||
if (res.ok) {
|
||||
const user = await res.json();
|
||||
const btn = document.getElementById('loginBtn');
|
||||
btn.innerHTML = `<img src="${user.avatarUrl}" style="width:24px;height:24px;border-radius:50%;margin-right:8px"> ${user.globalName || user.username}`;
|
||||
btn.href = '/dashboard';
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
loadStats();
|
||||
checkAuth();
|
||||
setInterval(loadStats, 30000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
515
aethex-bot/server/webServer.js
Normal file
515
aethex-bot/server/webServer.js
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
const express = require('express');
|
||||
const session = require('express-session');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const cors = require('cors');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
|
||||
function createWebServer(discordClient, supabase, options = {}) {
|
||||
const app = express();
|
||||
|
||||
const DISCORD_CLIENT_ID = process.env.DISCORD_CLIENT_ID;
|
||||
const DISCORD_CLIENT_SECRET = process.env.DISCORD_CLIENT_SECRET;
|
||||
const SESSION_SECRET = process.env.SESSION_SECRET || crypto.randomBytes(32).toString('hex');
|
||||
const BASE_URL = process.env.REPLIT_DEV_DOMAIN
|
||||
? `https://${process.env.REPLIT_DEV_DOMAIN}`
|
||||
: process.env.BASE_URL || 'http://localhost:5000';
|
||||
|
||||
app.use(cors({
|
||||
origin: true,
|
||||
credentials: true
|
||||
}));
|
||||
app.use(cookieParser());
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
app.use(session({
|
||||
secret: SESSION_SECRET,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: {
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
httpOnly: true,
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000
|
||||
}
|
||||
}));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||
res.setHeader('Pragma', 'no-cache');
|
||||
res.setHeader('Expires', '0');
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(express.static(path.join(__dirname, '../public')));
|
||||
|
||||
app.get('/auth/discord', (req, res) => {
|
||||
if (!DISCORD_CLIENT_SECRET) {
|
||||
return res.status(500).json({ error: 'Discord OAuth not configured. Please set DISCORD_CLIENT_SECRET.' });
|
||||
}
|
||||
|
||||
const state = crypto.randomBytes(16).toString('hex');
|
||||
req.session.oauthState = state;
|
||||
|
||||
const redirectUri = `${BASE_URL}/auth/callback`;
|
||||
const scope = 'identify guilds';
|
||||
|
||||
const authUrl = `https://discord.com/api/oauth2/authorize?` +
|
||||
`client_id=${DISCORD_CLIENT_ID}` +
|
||||
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
|
||||
`&response_type=code` +
|
||||
`&scope=${encodeURIComponent(scope)}` +
|
||||
`&state=${state}`;
|
||||
|
||||
res.redirect(authUrl);
|
||||
});
|
||||
|
||||
app.get('/auth/callback', async (req, res) => {
|
||||
const { code, state } = req.query;
|
||||
|
||||
if (!code) {
|
||||
return res.redirect('/?error=no_code');
|
||||
}
|
||||
|
||||
if (state !== req.session.oauthState) {
|
||||
return res.redirect('/?error=invalid_state');
|
||||
}
|
||||
|
||||
try {
|
||||
const redirectUri = `${BASE_URL}/auth/callback`;
|
||||
|
||||
const tokenResponse = await fetch('https://discord.com/api/oauth2/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
client_id: DISCORD_CLIENT_ID,
|
||||
client_secret: DISCORD_CLIENT_SECRET,
|
||||
grant_type: 'authorization_code',
|
||||
code,
|
||||
redirect_uri: redirectUri
|
||||
})
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
console.error('Token exchange failed:', await tokenResponse.text());
|
||||
return res.redirect('/?error=token_failed');
|
||||
}
|
||||
|
||||
const tokens = await tokenResponse.json();
|
||||
|
||||
const userResponse = await fetch('https://discord.com/api/users/@me', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${tokens.access_token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!userResponse.ok) {
|
||||
return res.redirect('/?error=user_fetch_failed');
|
||||
}
|
||||
|
||||
const user = await userResponse.json();
|
||||
|
||||
const guildsResponse = await fetch('https://discord.com/api/users/@me/guilds', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${tokens.access_token}`
|
||||
}
|
||||
});
|
||||
|
||||
let guilds = [];
|
||||
if (guildsResponse.ok) {
|
||||
guilds = await guildsResponse.json();
|
||||
}
|
||||
|
||||
req.session.user = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
discriminator: user.discriminator,
|
||||
avatar: user.avatar,
|
||||
globalName: user.global_name,
|
||||
accessToken: tokens.access_token,
|
||||
refreshToken: tokens.refresh_token,
|
||||
guilds: guilds.map(g => ({
|
||||
id: g.id,
|
||||
name: g.name,
|
||||
icon: g.icon,
|
||||
owner: g.owner,
|
||||
permissions: g.permissions,
|
||||
isAdmin: (parseInt(g.permissions) & 0x20) === 0x20
|
||||
}))
|
||||
};
|
||||
|
||||
res.redirect('/dashboard');
|
||||
|
||||
} catch (error) {
|
||||
console.error('OAuth callback error:', error);
|
||||
res.redirect('/?error=auth_failed');
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/auth/logout', (req, res) => {
|
||||
req.session.destroy();
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
app.get('/api/me', (req, res) => {
|
||||
if (!req.session.user) {
|
||||
return res.status(401).json({ error: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const user = req.session.user;
|
||||
res.json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
discriminator: user.discriminator,
|
||||
avatar: user.avatar,
|
||||
globalName: user.globalName,
|
||||
avatarUrl: user.avatar
|
||||
? `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`
|
||||
: `https://cdn.discordapp.com/embed/avatars/${parseInt(user.discriminator || '0') % 5}.png`,
|
||||
guilds: user.guilds
|
||||
});
|
||||
});
|
||||
|
||||
// Profile handler function
|
||||
async function handleProfileRequest(req, res, userId) {
|
||||
if (!supabase) {
|
||||
return res.status(503).json({ error: 'Database not available' });
|
||||
}
|
||||
|
||||
const targetUserId = userId || req.session.user?.id;
|
||||
if (!targetUserId) {
|
||||
return res.status(400).json({ error: 'User ID required' });
|
||||
}
|
||||
|
||||
try {
|
||||
const { data: link } = await supabase
|
||||
.from('discord_links')
|
||||
.select('user_id')
|
||||
.eq('discord_id', targetUserId)
|
||||
.maybeSingle();
|
||||
|
||||
if (!link) {
|
||||
return res.json({ linked: false, message: 'Discord account not linked' });
|
||||
}
|
||||
|
||||
const { data: profile } = await supabase
|
||||
.from('user_profiles')
|
||||
.select('*')
|
||||
.eq('id', link.user_id)
|
||||
.maybeSingle();
|
||||
|
||||
if (!profile) {
|
||||
return res.json({ linked: true, profile: null });
|
||||
}
|
||||
|
||||
res.json({
|
||||
linked: true,
|
||||
profile: {
|
||||
id: profile.id,
|
||||
username: profile.username,
|
||||
xp: profile.xp || 0,
|
||||
prestigeLevel: profile.prestige_level || 0,
|
||||
totalXpEarned: profile.total_xp_earned || 0,
|
||||
dailyStreak: profile.daily_streak || 0,
|
||||
title: profile.title,
|
||||
bio: profile.bio,
|
||||
avatarUrl: profile.avatar_url,
|
||||
createdAt: profile.created_at
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Profile fetch error:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch profile' });
|
||||
}
|
||||
}
|
||||
|
||||
// Route for current user's profile
|
||||
app.get('/api/profile', (req, res) => handleProfileRequest(req, res, null));
|
||||
|
||||
// Route for specific user's profile
|
||||
app.get('/api/profile/:userId', (req, res) => handleProfileRequest(req, res, req.params.userId));
|
||||
|
||||
app.get('/api/stats/:userId/:guildId', async (req, res) => {
|
||||
if (!supabase) {
|
||||
return res.status(503).json({ error: 'Database not available' });
|
||||
}
|
||||
|
||||
const { userId, guildId } = req.params;
|
||||
|
||||
try {
|
||||
const { data: link } = await supabase
|
||||
.from('discord_links')
|
||||
.select('user_id')
|
||||
.eq('discord_id', userId)
|
||||
.maybeSingle();
|
||||
|
||||
if (!link) {
|
||||
return res.json({ stats: null });
|
||||
}
|
||||
|
||||
const { data: stats } = await supabase
|
||||
.from('user_stats')
|
||||
.select('*')
|
||||
.eq('user_id', link.user_id)
|
||||
.eq('guild_id', guildId)
|
||||
.maybeSingle();
|
||||
|
||||
res.json({ stats });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch stats' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/achievements/:guildId', async (req, res) => {
|
||||
if (!supabase) {
|
||||
return res.status(503).json({ error: 'Database not available' });
|
||||
}
|
||||
|
||||
const { guildId } = req.params;
|
||||
const userId = req.session.user?.id;
|
||||
|
||||
try {
|
||||
const { data: achievements } = await supabase
|
||||
.from('achievements')
|
||||
.select('*')
|
||||
.eq('guild_id', guildId)
|
||||
.eq('hidden', false)
|
||||
.order('created_at', { ascending: true });
|
||||
|
||||
let userAchievements = [];
|
||||
if (userId) {
|
||||
const { data: link } = await supabase
|
||||
.from('discord_links')
|
||||
.select('user_id')
|
||||
.eq('discord_id', userId)
|
||||
.maybeSingle();
|
||||
|
||||
if (link) {
|
||||
const { data } = await supabase
|
||||
.from('user_achievements')
|
||||
.select('achievement_id, earned_at')
|
||||
.eq('user_id', link.user_id)
|
||||
.eq('guild_id', guildId);
|
||||
userAchievements = data || [];
|
||||
}
|
||||
}
|
||||
|
||||
res.json({ achievements, userAchievements });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch achievements' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/quests/:guildId', async (req, res) => {
|
||||
if (!supabase) {
|
||||
return res.status(503).json({ error: 'Database not available' });
|
||||
}
|
||||
|
||||
const { guildId } = req.params;
|
||||
const userId = req.session.user?.id;
|
||||
|
||||
try {
|
||||
const now = new Date().toISOString();
|
||||
const { data: quests } = await supabase
|
||||
.from('quests')
|
||||
.select('*')
|
||||
.eq('guild_id', guildId)
|
||||
.eq('active', true)
|
||||
.or(`starts_at.is.null,starts_at.lte.${now}`)
|
||||
.or(`expires_at.is.null,expires_at.gt.${now}`)
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
let userQuests = [];
|
||||
if (userId) {
|
||||
const { data: link } = await supabase
|
||||
.from('discord_links')
|
||||
.select('user_id')
|
||||
.eq('discord_id', userId)
|
||||
.maybeSingle();
|
||||
|
||||
if (link) {
|
||||
const { data } = await supabase
|
||||
.from('user_quests')
|
||||
.select('*')
|
||||
.eq('user_id', link.user_id)
|
||||
.eq('guild_id', guildId);
|
||||
userQuests = data || [];
|
||||
}
|
||||
}
|
||||
|
||||
res.json({ quests, userQuests });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch quests' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/shop/:guildId', async (req, res) => {
|
||||
if (!supabase) {
|
||||
return res.status(503).json({ error: 'Database not available' });
|
||||
}
|
||||
|
||||
const { guildId } = req.params;
|
||||
|
||||
try {
|
||||
const { data: items } = await supabase
|
||||
.from('shop_items')
|
||||
.select('*')
|
||||
.eq('guild_id', guildId)
|
||||
.eq('available', true)
|
||||
.order('price', { ascending: true });
|
||||
|
||||
res.json({ items: items || [] });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch shop items' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/inventory/:guildId', async (req, res) => {
|
||||
if (!supabase) {
|
||||
return res.status(503).json({ error: 'Database not available' });
|
||||
}
|
||||
|
||||
const userId = req.session.user?.id;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ error: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const { guildId } = req.params;
|
||||
|
||||
try {
|
||||
const { data: link } = await supabase
|
||||
.from('discord_links')
|
||||
.select('user_id')
|
||||
.eq('discord_id', userId)
|
||||
.maybeSingle();
|
||||
|
||||
if (!link) {
|
||||
return res.json({ inventory: [] });
|
||||
}
|
||||
|
||||
const { data: inventory } = await supabase
|
||||
.from('user_inventory')
|
||||
.select(`
|
||||
*,
|
||||
shop_items (name, description, item_type, value)
|
||||
`)
|
||||
.eq('user_id', link.user_id)
|
||||
.eq('guild_id', guildId);
|
||||
|
||||
res.json({ inventory: inventory || [] });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch inventory' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/leaderboard/:guildId', async (req, res) => {
|
||||
if (!supabase) {
|
||||
return res.status(503).json({ error: 'Database not available' });
|
||||
}
|
||||
|
||||
const { guildId } = req.params;
|
||||
const { type = 'all', limit = 50 } = req.query;
|
||||
|
||||
try {
|
||||
let tableName = 'leaderboard_alltime';
|
||||
if (type === 'weekly') tableName = 'leaderboard_weekly';
|
||||
else if (type === 'monthly') tableName = 'leaderboard_monthly';
|
||||
|
||||
const { data: leaderboard } = await supabase
|
||||
.from(tableName)
|
||||
.select(`
|
||||
*,
|
||||
user_profiles!inner (username, avatar_url, prestige_level)
|
||||
`)
|
||||
.eq('guild_id', guildId)
|
||||
.order('xp', { ascending: false })
|
||||
.limit(parseInt(limit));
|
||||
|
||||
res.json({ leaderboard: leaderboard || [], type });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch leaderboard' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/bot-stats', (req, res) => {
|
||||
const stats = {
|
||||
guilds: discordClient.guilds.cache.size,
|
||||
users: discordClient.guilds.cache.reduce((acc, g) => acc + g.memberCount, 0),
|
||||
commands: discordClient.commands?.size || 0,
|
||||
uptime: Math.floor(process.uptime()),
|
||||
status: discordClient.user ? 'online' : 'offline',
|
||||
botName: discordClient.user?.username || 'AeThex',
|
||||
botAvatar: discordClient.user?.displayAvatarURL() || null
|
||||
};
|
||||
res.json(stats);
|
||||
});
|
||||
|
||||
app.get('/api/guild/:guildId/config', async (req, res) => {
|
||||
if (!supabase) {
|
||||
return res.status(503).json({ error: 'Database not available' });
|
||||
}
|
||||
|
||||
const userId = req.session.user?.id;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ error: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const { guildId } = req.params;
|
||||
|
||||
const userGuild = req.session.user.guilds.find(g => g.id === guildId);
|
||||
if (!userGuild || !userGuild.isAdmin) {
|
||||
return res.status(403).json({ error: 'No admin access to this server' });
|
||||
}
|
||||
|
||||
try {
|
||||
const { data: xpConfig } = await supabase
|
||||
.from('xp_config')
|
||||
.select('*')
|
||||
.eq('guild_id', guildId)
|
||||
.maybeSingle();
|
||||
|
||||
const { data: serverConfig } = await supabase
|
||||
.from('server_config')
|
||||
.select('*')
|
||||
.eq('guild_id', guildId)
|
||||
.maybeSingle();
|
||||
|
||||
res.json({ xpConfig, serverConfig });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch config' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'ok',
|
||||
bot: discordClient.user ? 'online' : 'offline',
|
||||
uptime: process.uptime()
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/dashboard', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../public/dashboard.html'));
|
||||
});
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../public/index.html'));
|
||||
});
|
||||
|
||||
// Catch-all route for SPA - use middleware instead of wildcard
|
||||
app.use((req, res, next) => {
|
||||
if (req.method === 'GET' && !req.path.startsWith('/api/')) {
|
||||
res.sendFile(path.join(__dirname, '../public/index.html'));
|
||||
} else if (req.path.startsWith('/api/')) {
|
||||
res.status(404).json({ error: 'API endpoint not found' });
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
module.exports = { createWebServer };
|
||||
BIN
attached_assets/aethex-forge_1765237530646.zip
Normal file
BIN
attached_assets/aethex-forge_1765237530646.zip
Normal file
Binary file not shown.
938
package-lock.json
generated
938
package-lock.json
generated
|
|
@ -9,10 +9,662 @@
|
|||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.2.1",
|
||||
"express-session": "^1.18.2",
|
||||
"pg": "^8.16.3",
|
||||
"ws": "^8.18.3"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-types": "^3.0.0",
|
||||
"negotiator": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz",
|
||||
"integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "^3.1.2",
|
||||
"content-type": "^1.0.5",
|
||||
"debug": "^4.4.3",
|
||||
"http-errors": "^2.0.0",
|
||||
"iconv-lite": "^0.7.0",
|
||||
"on-finished": "^2.4.1",
|
||||
"qs": "^6.14.0",
|
||||
"raw-body": "^3.0.1",
|
||||
"type-is": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bound": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
||||
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"get-intrinsic": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
|
||||
"integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser": {
|
||||
"version": "1.4.7",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
|
||||
"integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "0.7.2",
|
||||
"cookie-signature": "1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"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/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
||||
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "^2.0.0",
|
||||
"body-parser": "^2.2.1",
|
||||
"content-disposition": "^1.0.0",
|
||||
"content-type": "^1.0.5",
|
||||
"cookie": "^0.7.1",
|
||||
"cookie-signature": "^1.2.1",
|
||||
"debug": "^4.4.0",
|
||||
"depd": "^2.0.0",
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"etag": "^1.8.1",
|
||||
"finalhandler": "^2.1.0",
|
||||
"fresh": "^2.0.0",
|
||||
"http-errors": "^2.0.0",
|
||||
"merge-descriptors": "^2.0.0",
|
||||
"mime-types": "^3.0.0",
|
||||
"on-finished": "^2.4.1",
|
||||
"once": "^1.4.0",
|
||||
"parseurl": "^1.3.3",
|
||||
"proxy-addr": "^2.0.7",
|
||||
"qs": "^6.14.0",
|
||||
"range-parser": "^1.2.1",
|
||||
"router": "^2.2.0",
|
||||
"send": "^1.1.0",
|
||||
"serve-static": "^2.2.0",
|
||||
"statuses": "^2.0.1",
|
||||
"type-is": "^2.0.1",
|
||||
"vary": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express-session": {
|
||||
"version": "1.18.2",
|
||||
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
|
||||
"integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "0.7.2",
|
||||
"cookie-signature": "1.0.7",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~2.0.0",
|
||||
"on-headers": "~1.1.0",
|
||||
"parseurl": "~1.3.3",
|
||||
"safe-buffer": "5.2.1",
|
||||
"uid-safe": "~2.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express-session/node_modules/cookie-signature": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
|
||||
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/express-session/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express-session/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/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/finalhandler": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
|
||||
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.4.0",
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"on-finished": "^2.4.1",
|
||||
"parseurl": "^1.3.3",
|
||||
"statuses": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fresh": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
||||
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/http-errors": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
||||
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"depd": "~2.0.0",
|
||||
"inherits": "~2.0.4",
|
||||
"setprototypeof": "~1.2.0",
|
||||
"statuses": "~2.0.2",
|
||||
"toidentifier": "~1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
||||
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-promise": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
||||
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
||||
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
|
||||
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
||||
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ee-first": "1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/on-headers": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
|
||||
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.16.3",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||
|
|
@ -141,6 +793,224 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"forwarded": "0.2.0",
|
||||
"ipaddr.js": "1.9.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/random-bytes": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||
"integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
|
||||
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "~3.1.2",
|
||||
"http-errors": "~2.0.1",
|
||||
"iconv-lite": "~0.7.0",
|
||||
"unpipe": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/router": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
|
||||
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.4.0",
|
||||
"depd": "^2.0.0",
|
||||
"is-promise": "^4.0.0",
|
||||
"parseurl": "^1.3.3",
|
||||
"path-to-regexp": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
|
||||
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.5",
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"etag": "^1.8.1",
|
||||
"fresh": "^2.0.0",
|
||||
"http-errors": "^2.0.0",
|
||||
"mime-types": "^3.0.1",
|
||||
"ms": "^2.1.3",
|
||||
"on-finished": "^2.4.1",
|
||||
"range-parser": "^1.2.1",
|
||||
"statuses": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
||||
"integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"parseurl": "^1.3.3",
|
||||
"send": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-list": "^1.0.0",
|
||||
"side-channel-map": "^1.0.1",
|
||||
"side-channel-weakmap": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-list": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-map": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-weakmap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-map": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||
|
|
@ -150,6 +1020,74 @@
|
|||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"content-type": "^1.0.5",
|
||||
"media-typer": "^1.1.0",
|
||||
"mime-types": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/uid-safe": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"random-bytes": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.18.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.2.1",
|
||||
"express-session": "^1.18.2",
|
||||
"pg": "^8.16.3",
|
||||
"ws": "^8.18.3"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{ pkgs }: {
|
||||
deps = [
|
||||
pkgs.unzip
|
||||
];
|
||||
env = {
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue