├── client
├── public
│ └── icon.png
├── postcss.config.js
├── vite.config.js
├── tailwind.config.js
├── src
│ ├── services
│ │ ├── authService.js
│ │ └── api.js
│ ├── main.jsx
│ ├── components
│ │ ├── PrivateRoute.jsx
│ │ └── EventManager.jsx
│ ├── index.css
│ ├── App.jsx
│ ├── App.css
│ ├── contexts
│ │ └── AuthContext.jsx
│ ├── assets
│ │ └── react.svg
│ └── pages
│ │ ├── LoginForm.jsx
│ │ ├── Home.jsx
│ │ ├── Dashboard.jsx
│ │ └── SignupForm.jsx
├── .gitignore
├── index.html
├── README.md
├── eslint.config.js
└── package.json
├── server
├── .env
├── routes
│ ├── authRoutes.js
│ ├── EventRoutes.js
│ └── RegistrationRoutes.js
├── .gitignore
├── config.js
├── models
│ ├── userModel.js
│ ├── EventModel.js
│ └── RegistrationModel.js
├── package.json
├── app.js
├── middlewares
│ └── authMiddleware.js
├── controllers
│ ├── EventController.js
│ ├── RegistrationController.js
│ └── authController.js
└── package-lock.json
└── README.md
/client/public/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sriram2915/EventSphere/HEAD/client/public/icon.png
--------------------------------------------------------------------------------
/client/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/server/.env:
--------------------------------------------------------------------------------
1 | PORT=5000
2 | DB_HOST=localhost
3 | DB_USER=root
4 | DB_PASSWORD=1234
5 | DB_NAME=EventSphere
6 | JWT_SECRET=your_jwt_secret
7 |
--------------------------------------------------------------------------------
/client/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vite.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/client/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: [
4 | "./index.html",
5 | "./src/**/*.{js,ts,jsx,tsx}",
6 | ],
7 | theme: {
8 | extend: {},
9 | },
10 | plugins: [],
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/server/routes/authRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const router = express.Router();
3 | const { register, login } = require('../controllers/authController');
4 |
5 | router.post('/register', register);
6 | router.post('/login', login);
7 |
8 | module.exports = router;
9 |
--------------------------------------------------------------------------------
/client/src/services/authService.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | const API_URL = 'http://localhost:5000/api/auth/';
4 |
5 | export const registerUser = (userData) => {
6 | return axios.post(API_URL + 'register', userData);
7 | };
8 |
9 | export const loginUser = (userData) => {
10 | return axios.post(API_URL + 'login', userData);
11 | };
12 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/client/src/main.jsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react'
2 | import { createRoot } from 'react-dom/client'
3 | import './index.css'
4 | import App from './App.jsx'
5 | import AuthProvider from "./contexts/AuthContext.jsx";
6 |
7 | createRoot(document.getElementById('root')).render(
8 |
9 |
10 |
11 |
12 | ,
13 | )
14 |
--------------------------------------------------------------------------------
/client/src/services/api.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const API = axios.create({
4 | baseURL: "http://localhost:5000/api",
5 | });
6 |
7 | // attach token automatically
8 | API.interceptors.request.use((config) => {
9 | const token = localStorage.getItem("token");
10 | if (token) config.headers.Authorization = `Bearer ${token}`;
11 | return config;
12 | });
13 |
14 | export default API;
15 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | EventSphere
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/server/config.js:
--------------------------------------------------------------------------------
1 | const mysql = require('mysql2');
2 | require('dotenv').config;
3 |
4 | const conn = mysql.createConnection({
5 | host: process.env.DB_HOST,
6 | user: process.env.DB_USER,
7 | password: process.env.DB_PASSWORD,
8 | database: process.env.DB_NAME
9 | });
10 |
11 | conn.connect(err =>{
12 | if(err) throw err;
13 | console.log('MySQL connected');
14 | });
15 |
16 | module.exports = conn;
--------------------------------------------------------------------------------
/server/routes/EventRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const EventController = require("../controllers/EventController");
4 |
5 | // CRUD Routes
6 | router.post("/", EventController.createEvent);
7 | router.get("/", EventController.getEvents);
8 | router.get("/:id", EventController.getEvent);
9 | router.put("/:id", EventController.updateEvent);
10 | router.delete("/:id", EventController.deleteEvent);
11 |
12 | module.exports = router;
13 |
--------------------------------------------------------------------------------
/client/src/components/PrivateRoute.jsx:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { Navigate } from "react-router-dom";
3 | import { AuthContext } from "../contexts/AuthContext";
4 |
5 | export default function PrivateRoute({ children, roles }) {
6 | const { user } = useContext(AuthContext);
7 |
8 | if (!user) {
9 | return ;
10 | }
11 |
12 | if (roles && !roles.includes(user.role)) {
13 | return ; // Redirect if role not allowed
14 | }
15 |
16 | return children;
17 | }
18 |
--------------------------------------------------------------------------------
/server/models/userModel.js:
--------------------------------------------------------------------------------
1 | const conn = require('../config');
2 |
3 | const User = {
4 | create: (user, callback) => {
5 | const sql = "INSERT INTO users (name, email, password, role) VALUES (?, ?, ?, ?)";
6 | conn.query(sql, [user.name, user.email, user.password, user.role], callback);
7 | },
8 |
9 | findByEmail: (email, callback) => {
10 | const sql = "SELECT * FROM users WHERE email = ?";
11 | conn.query(sql, [email], (err, results) => {
12 | if (err) return callback(err);
13 | return callback(null, results[0]);
14 | });
15 | }
16 | };
17 |
18 | module.exports = User;
19 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "start": "nodemon app.js",
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "description": "",
13 | "dependencies": {
14 | "bcrypt": "^6.0.0",
15 | "cors": "^2.8.5",
16 | "dotenv": "^17.2.1",
17 | "express": "^5.1.0",
18 | "jsonwebtoken": "^9.0.2",
19 | "multer": "^2.0.2",
20 | "mysql2": "^3.14.3"
21 | },
22 | "devDependencies": {
23 | "nodemon": "^3.1.10"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer utilities {
6 | @keyframes blob {
7 | 0% {
8 | transform: translate(0px, 0px) scale(1);
9 | }
10 | 33% {
11 | transform: translate(30px, -50px) scale(1.1);
12 | }
13 | 66% {
14 | transform: translate(-20px, 20px) scale(0.9);
15 | }
16 | 100% {
17 | transform: translate(0px, 0px) scale(1);
18 | }
19 | }
20 | .animate-blob {
21 | animation: blob 8s infinite;
22 | }
23 | .animation-delay-2000 {
24 | animation-delay: 2s;
25 | }
26 | .animation-delay-4000 {
27 | animation-delay: 4s;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/client/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
2 | import Home from "./pages/Home";
3 | import Login from "./pages/LoginForm";
4 | import Signup from "./pages/SignupForm";
5 | import Dashboard from "./pages/Dashboard";
6 |
7 | export default function App() {
8 | return (
9 |
10 |
11 | {/* This will now load your animated glass UI */}
12 | } />
13 |
14 | {/* Keep your other pages */}
15 | } />
16 | } />
17 | } />
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/server/routes/RegistrationRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const RegController = require("../controllers/RegistrationController");
4 | const { authenticate, authorizeRoles } = require("../middlewares/authMiddleware");
5 |
6 | // Student registers/unregisters (must be authenticated)
7 | router.post("/:eventId/register", authenticate, RegController.registerForEvent);
8 | router.delete("/:eventId/unregister", authenticate, RegController.unregisterFromEvent);
9 |
10 | // Student views own registrations
11 | router.get("/me", authenticate, RegController.getUserRegistrations);
12 |
13 | // Admin/Faculty views registrations for an event
14 | router.get("/:eventId", authenticate, authorizeRoles("admin", "faculty"), RegController.getEventRegistrations);
15 |
16 | module.exports = router;
17 |
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const cors = require('cors');
3 | const dotenv = require('dotenv');
4 | dotenv.config();
5 |
6 | const authRoutes = require('./routes/authRoutes');
7 |
8 | const app = express();
9 | app.use(cors());
10 | app.use(express.json());
11 | app.use('/uploads', express.static('uploads'));
12 |
13 | // Auth routes
14 | app.use('/api/auth', authRoutes);
15 |
16 | app.get('/', (req, res) => {
17 | res.send('EventSphere backend running!');
18 | });
19 |
20 | const eventRoutes = require("./routes/EventRoutes");
21 | app.use("/api/events", eventRoutes);
22 |
23 | const regRoutes = require("./routes/RegistrationRoutes");
24 | app.use("/api/registrations", regRoutes);
25 |
26 | app.listen(process.env.PORT, () => {
27 | console.log(`Server running at http://localhost:${process.env.PORT}`);
28 | });
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
10 | ## Expanding the ESLint configuration
11 |
12 | If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
13 |
--------------------------------------------------------------------------------
/client/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js'
2 | import globals from 'globals'
3 | import reactHooks from 'eslint-plugin-react-hooks'
4 | import reactRefresh from 'eslint-plugin-react-refresh'
5 | import { defineConfig, globalIgnores } from 'eslint/config'
6 |
7 | export default defineConfig([
8 | globalIgnores(['dist']),
9 | {
10 | files: ['**/*.{js,jsx}'],
11 | extends: [
12 | js.configs.recommended,
13 | reactHooks.configs['recommended-latest'],
14 | reactRefresh.configs.vite,
15 | ],
16 | languageOptions: {
17 | ecmaVersion: 2020,
18 | globals: globals.browser,
19 | parserOptions: {
20 | ecmaVersion: 'latest',
21 | ecmaFeatures: { jsx: true },
22 | sourceType: 'module',
23 | },
24 | },
25 | rules: {
26 | 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
27 | },
28 | },
29 | ])
30 |
--------------------------------------------------------------------------------
/server/middlewares/authMiddleware.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 |
3 | function authenticate(req, res, next) {
4 | const authHeader = req.headers.authorization;
5 | if (!authHeader || !authHeader.startsWith("Bearer "))
6 | return res.status(401).json({ message: "No token provided" });
7 |
8 | const token = authHeader.split(" ")[1];
9 | try {
10 | const payload = jwt.verify(token, process.env.JWT_SECRET);
11 | req.user = payload; // { id, name, email, role }
12 | next();
13 | } catch (err) {
14 | return res.status(401).json({ message: "Invalid token" });
15 | }
16 | }
17 |
18 | function authorizeRoles(...allowedRoles) {
19 | return (req, res, next) => {
20 | if (!req.user) return res.status(401).json({ message: "Not authenticated" });
21 | if (!allowedRoles.includes(req.user.role))
22 | return res.status(403).json({ message: "Forbidden" });
23 | next();
24 | };
25 | }
26 |
27 | module.exports = { authenticate, authorizeRoles };
28 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "axios": "^1.11.0",
14 | "react": "^19.1.1",
15 | "react-dom": "^19.1.1",
16 | "react-router-dom": "^7.8.0",
17 | "react-tsparticles": "^2.12.2",
18 | "three": "^0.179.1",
19 | "tsparticles": "^3.9.1"
20 | },
21 | "devDependencies": {
22 | "@eslint/js": "^9.32.0",
23 | "@types/react": "^19.1.9",
24 | "@types/react-dom": "^19.1.7",
25 | "@vitejs/plugin-react": "^4.7.0",
26 | "autoprefixer": "^10.4.21",
27 | "eslint": "^9.32.0",
28 | "eslint-plugin-react-hooks": "^5.2.0",
29 | "eslint-plugin-react-refresh": "^0.4.20",
30 | "globals": "^16.3.0",
31 | "postcss": "^8.5.6",
32 | "tailwindcss": "^3.4.17",
33 | "vite": "^7.1.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/server/models/EventModel.js:
--------------------------------------------------------------------------------
1 | const db = require("../config");
2 |
3 | // Create Event
4 | exports.createEvent = (eventData, callback) => {
5 | const sql = `INSERT INTO events (title, description, date, location, created_by) VALUES (?, ?, ?, ?, ?)`;
6 | db.query(sql, [
7 | eventData.title,
8 | eventData.description,
9 | eventData.date,
10 | eventData.location,
11 | eventData.created_by
12 | ], callback);
13 | };
14 |
15 | // Get All Events
16 | exports.getAllEvents = (callback) => {
17 | db.query(`SELECT * FROM events ORDER BY date ASC`, callback);
18 | };
19 |
20 | // Get Single Event
21 | exports.getEventById = (id, callback) => {
22 | db.query(`SELECT * FROM events WHERE id = ?`, [id], callback);
23 | };
24 |
25 | // Update Event
26 | exports.updateEvent = (id, eventData, callback) => {
27 | const sql = `UPDATE events SET title=?, description=?, date=?, location=? WHERE id=?`;
28 | db.query(sql, [
29 | eventData.title,
30 | eventData.description,
31 | eventData.date,
32 | eventData.location,
33 | id
34 | ], callback);
35 | };
36 |
37 | // Delete Event
38 | exports.deleteEvent = (id, callback) => {
39 | db.query(`DELETE FROM events WHERE id = ?`, [id], callback);
40 | };
41 |
--------------------------------------------------------------------------------
/client/src/contexts/AuthContext.jsx:
--------------------------------------------------------------------------------
1 | import { createContext, useState, useEffect } from "react";
2 |
3 | export const AuthContext = createContext();
4 |
5 | export default function AuthProvider({ children }) {
6 | const [user, setUser] = useState(null); // { id, name, email, role }
7 | const [token, setToken] = useState(localStorage.getItem("token") || null);
8 |
9 | useEffect(() => {
10 | if (token) {
11 | try {
12 | // Decode JWT payload (base64 decode)
13 | const payload = JSON.parse(atob(token.split(".")[1]));
14 | setUser({ id: payload.id, name: payload.name, email: payload.email, role: payload.role });
15 | } catch (err) {
16 | console.error("Invalid token", err);
17 | setToken(null);
18 | localStorage.removeItem("token");
19 | }
20 | }
21 | }, [token]);
22 |
23 | const login = (jwtToken) => {
24 | localStorage.setItem("token", jwtToken);
25 | setToken(jwtToken);
26 | };
27 |
28 | const logout = () => {
29 | localStorage.removeItem("token");
30 | setToken(null);
31 | setUser(null);
32 | };
33 |
34 | return (
35 |
36 | {children}
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/server/controllers/EventController.js:
--------------------------------------------------------------------------------
1 | const Event = require("../models/EventModel");
2 |
3 | exports.createEvent = (req, res) => {
4 | Event.createEvent(req.body, (err, result) => {
5 | if (err) return res.status(500).json({ error: err.message });
6 | res.json({ message: "Event created successfully", id: result.insertId });
7 | });
8 | };
9 |
10 | exports.getEvents = (req, res) => {
11 | Event.getAllEvents((err, results) => {
12 | if (err) return res.status(500).json({ error: err.message });
13 | res.json(results);
14 | });
15 | };
16 |
17 | exports.getEvent = (req, res) => {
18 | Event.getEventById(req.params.id, (err, result) => {
19 | if (err) return res.status(500).json({ error: err.message });
20 | res.json(result[0]);
21 | });
22 | };
23 |
24 | exports.updateEvent = (req, res) => {
25 | Event.updateEvent(req.params.id, req.body, (err) => {
26 | if (err) return res.status(500).json({ error: err.message });
27 | res.json({ message: "Event updated successfully" });
28 | });
29 | };
30 |
31 | exports.deleteEvent = (req, res) => {
32 | Event.deleteEvent(req.params.id, (err) => {
33 | if (err) return res.status(500).json({ error: err.message });
34 | res.json({ message: "Event deleted successfully" });
35 | });
36 | };
37 |
--------------------------------------------------------------------------------
/server/models/RegistrationModel.js:
--------------------------------------------------------------------------------
1 | const db = require("../config");
2 |
3 | exports.createRegistration = (eventId, userId, cb) => {
4 | const sql = `INSERT INTO registrations (event_id, user_id) VALUES (?, ?)`;
5 | db.query(sql, [eventId, userId], cb);
6 | };
7 |
8 | exports.deleteRegistration = (eventId, userId, cb) => {
9 | const sql = `DELETE FROM registrations WHERE event_id = ? AND user_id = ?`;
10 | db.query(sql, [eventId, userId], cb);
11 | };
12 |
13 | exports.getRegistrationsByEvent = (eventId, cb) => {
14 | const sql = `
15 | SELECT r.id, r.registered_at, u.id as user_id, u.name, u.email
16 | FROM registrations r
17 | JOIN users u ON u.id = r.user_id
18 | WHERE r.event_id = ?
19 | ORDER BY r.registered_at DESC
20 | `;
21 | db.query(sql, [eventId], cb);
22 | };
23 |
24 | exports.getRegistrationsByUser = (userId, cb) => {
25 | const sql = `
26 | SELECT r.id, r.registered_at, e.id as event_id, e.title, e.date, e.location
27 | FROM registrations r
28 | JOIN events e ON e.id = r.event_id
29 | WHERE r.user_id = ?
30 | ORDER BY r.registered_at DESC
31 | `;
32 | db.query(sql, [userId], cb);
33 | };
34 |
35 | exports.isRegistered = (eventId, userId, cb) => {
36 | const sql = `SELECT * FROM registrations WHERE event_id = ? AND user_id = ?`;
37 | db.query(sql, [eventId, userId], (err, results) => {
38 | if (err) return cb(err);
39 | cb(null, results.length > 0);
40 | });
41 | };
42 |
--------------------------------------------------------------------------------
/server/controllers/RegistrationController.js:
--------------------------------------------------------------------------------
1 | const Registration = require("../models/RegistrationModel");
2 |
3 | exports.registerForEvent = (req, res) => {
4 | const eventId = parseInt(req.params.eventId, 10);
5 | const userId = req.user.id;
6 |
7 | Registration.createRegistration(eventId, userId, (err, result) => {
8 | if (err) {
9 | // unique constraint violation -> already registered
10 | if (err.code === "ER_DUP_ENTRY")
11 | return res.status(400).json({ message: "Already registered" });
12 | return res.status(500).json({ error: err.message });
13 | }
14 | res.json({ message: "Registered successfully", id: result.insertId });
15 | });
16 | };
17 |
18 | exports.unregisterFromEvent = (req, res) => {
19 | const eventId = parseInt(req.params.eventId, 10);
20 | const userId = req.user.id;
21 |
22 | Registration.deleteRegistration(eventId, userId, (err, result) => {
23 | if (err) return res.status(500).json({ error: err.message });
24 | if (result.affectedRows === 0)
25 | return res.status(404).json({ message: "Registration not found" });
26 | res.json({ message: "Unregistered successfully" });
27 | });
28 | };
29 |
30 | exports.getEventRegistrations = (req, res) => {
31 | const eventId = parseInt(req.params.eventId, 10);
32 | Registration.getRegistrationsByEvent(eventId, (err, results) => {
33 | if (err) return res.status(500).json({ error: err.message });
34 | res.json(results);
35 | });
36 | };
37 |
38 | exports.getUserRegistrations = (req, res) => {
39 | const userId = req.user.id;
40 | Registration.getRegistrationsByUser(userId, (err, results) => {
41 | if (err) return res.status(500).json({ error: err.message });
42 | res.json(results);
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/server/controllers/authController.js:
--------------------------------------------------------------------------------
1 | const User = require('../models/userModel');
2 | const bcrypt = require('bcrypt');
3 | const jwt = require('jsonwebtoken');
4 |
5 | const register = (req, res) => {
6 | const { name, email, password, role } = req.body;
7 |
8 | if (!name || !email || !password) {
9 | return res.status(400).json({ message: 'Please fill all fields' });
10 | }
11 |
12 | User.findByEmail(email, async (err, existingUser) => {
13 | if (err) return res.status(500).json(err);
14 | if (existingUser) return res.status(400).json({ message: 'Email already exists' });
15 |
16 | const hashedPassword = await bcrypt.hash(password, 10);
17 |
18 | User.create({ name, email, password: hashedPassword, role }, (err, result) => {
19 | if (err) return res.status(500).json(err);
20 | return res.status(201).json({ message: 'User registered successfully' });
21 | });
22 | });
23 | };
24 |
25 | const login = (req, res) => {
26 | const { email, password } = req.body;
27 |
28 | if (!email || !password)
29 | return res.status(400).json({ message: 'Please enter email and password' });
30 |
31 | User.findByEmail(email, async (err, user) => {
32 | if (err) return res.status(500).json(err);
33 | if (!user) return res.status(400).json({ message: 'Invalid credentials' });
34 |
35 | const isMatch = await bcrypt.compare(password, user.password);
36 | if (!isMatch) return res.status(400).json({ message: 'Invalid credentials' });
37 |
38 | const token = jwt.sign(
39 | { id: user.id, name: user.name, email: user.email, role: user.role },
40 | process.env.JWT_SECRET,
41 | { expiresIn: '1d' }
42 | );
43 |
44 | res.json({ token, user: { id: user.id, name: user.name, email: user.email, role: user.role } });
45 | });
46 | };
47 |
48 | module.exports = { register, login };
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EventSphere
2 |
3 | **EventSphere** is a full-stack event management application built with **React (Vite)** on the frontend, **Node.js + Express** on the backend, and **MySQL** as the database. It provides user role-based dashboards (Admin, Faculty, Student) for managing events, user accounts, and registrations.
4 |
5 | ---
6 |
7 | ## 📂 Project Structure
8 |
9 | ```
10 | EventSphere/
11 | ├── client/ # Frontend (React + Vite)
12 | │ ├── src/
13 | │ │ ├── components/ # Reusable UI components
14 | │ │ ├── contexts/ # Auth context
15 | │ │ ├── pages/ # Page components (Dashboard, Login, etc.)
16 | │ │ ├── App.jsx # Main App component
17 | │ │ └── main.jsx # React entry point
18 | │ └── package.json # Frontend dependencies
19 | │
20 | ├── server/ # Backend (Node.js + Express)
21 | │ ├── models/ # Sequelize models (User, Event)
22 | │ ├── routes/ # API routes
23 | │ ├── controllers/ # Request handling logic
24 | │ ├── config/ # Database connection settings
25 | │ ├── server.js # Backend entry point
26 | │ └── package.json # Backend dependencies
27 | │
28 | └── README.md # Project documentation
29 | ```
30 |
31 | ---
32 |
33 | ## 🚀 Tech Stack
34 |
35 | **Frontend:**
36 |
37 | * React + Vite
38 | * TailwindCSS
39 | * Axios (API calls)
40 | * React Router DOM
41 |
42 | **Backend:**
43 |
44 | * Node.js
45 | * Express.js
46 | * Sequelize ORM
47 | * bcrypt (Password hashing)
48 | * jsonwebtoken (JWT authentication)
49 |
50 | **Database:**
51 |
52 | * MySQL
53 |
54 | ---
55 |
56 | ## 🔑 Features
57 |
58 | * **Role-based authentication** (Admin, Faculty, Student)
59 | * Admin: Manage all events and users
60 | * Faculty: Create and manage own events
61 | * Student: View and register for events
62 | * Secure authentication using JWT and hashed passwords
63 | * RESTful API integration
64 |
65 | ---
66 |
67 | ## 📦 Installation & Setup
68 |
69 | ### 1️⃣ Clone Repository
70 |
71 | ```bash
72 | git clone https://github.com/yourusername/EventSphere.git
73 | cd EventSphere
74 | ```
75 |
76 | ### 2️⃣ Setup Backend
77 |
78 | ```bash
79 | cd server
80 | npm install
81 | # Configure .env for DB connection
82 | npm run dev
83 | ```
84 |
85 | ### 3️⃣ Setup Frontend
86 |
87 | ```bash
88 | cd ../client
89 | npm install
90 | npm run dev
91 | ```
92 |
93 | ---
94 |
95 | ## 🗝️ Environment Variables
96 |
97 | **Backend `.env`**
98 |
99 | ```
100 | DB_HOST=localhost
101 | DB_USER=root
102 | DB_PASS=yourpassword
103 | DB_NAME=eventsphere
104 | JWT_SECRET=your_secret_key
105 | ```
106 |
107 | ---
108 |
109 | ## 📌 Usage
110 |
111 | * **Admin Dashboard**: Manage events & users
112 | * **Faculty Dashboard**: Create & edit events
113 | * **Student Dashboard**: Browse & register for events
114 |
115 | ---
116 |
117 |
--------------------------------------------------------------------------------
/client/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/components/EventManager.jsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useContext } from "react";
2 | import axios from "axios";
3 | import { AuthContext } from "../contexts/AuthContext";
4 |
5 | export default function EventManager() {
6 | const { user } = useContext(AuthContext);
7 | const [events, setEvents] = useState([]);
8 | const [form, setForm] = useState({ title: "", description: "", date: "", location: "" });
9 | const [editingId, setEditingId] = useState(null);
10 |
11 | const API_URL = "http://localhost:5000/api/events";
12 |
13 | useEffect(() => {
14 | fetchEvents();
15 | }, []);
16 |
17 | const fetchEvents = async () => {
18 | try {
19 | const res = await axios.get(API_URL);
20 | setEvents(res.data);
21 | } catch (err) {
22 | console.error(err);
23 | }
24 | };
25 |
26 | const handleChange = (e) => {
27 | setForm({ ...form, [e.target.name]: e.target.value });
28 | };
29 |
30 | const handleSubmit = async (e) => {
31 | e.preventDefault();
32 | try {
33 | if (editingId) {
34 | await axios.put(`${API_URL}/${editingId}`, form);
35 | } else {
36 | await axios.post(API_URL, { ...form, created_by: user.id });
37 | }
38 | setForm({ title: "", description: "", date: "", location: "" });
39 | setEditingId(null);
40 | fetchEvents();
41 | } catch (err) {
42 | console.error(err);
43 | }
44 | };
45 |
46 | const handleEdit = (event) => {
47 | setForm({
48 | title: event.title,
49 | description: event.description,
50 | date: event.date.split("T")[0],
51 | location: event.location
52 | });
53 | setEditingId(event.id);
54 | };
55 |
56 | const handleDelete = async (id) => {
57 | if (!window.confirm("Are you sure you want to delete this event?")) return;
58 | try {
59 | await axios.delete(`${API_URL}/${id}`);
60 | fetchEvents();
61 | } catch (err) {
62 | console.error(err);
63 | }
64 | };
65 |
66 | return (
67 |
68 |
Event Manager
69 |
70 | {/* Only Admin/Faculty can create/edit events */}
71 | {(user?.role === "admin" || user?.role === "faculty") && (
72 |
113 | )}
114 |
115 | {/* Event List */}
116 |
117 |
118 |
119 | | Title |
120 | Description |
121 | Date |
122 | Location |
123 | {(user?.role === "admin" || user?.role === "faculty") && (
124 | Actions |
125 | )}
126 |
127 |
128 |
129 | {events.map((ev) => (
130 |
131 | | {ev.title} |
132 | {ev.description} |
133 | {new Date(ev.date).toLocaleDateString()} |
134 | {ev.location} |
135 | {(user?.role === "admin" || user?.role === "faculty") && (
136 |
137 |
143 |
149 | |
150 | )}
151 |
152 | ))}
153 |
154 |
155 |
156 | );
157 | }
158 |
--------------------------------------------------------------------------------
/client/src/pages/LoginForm.jsx:
--------------------------------------------------------------------------------
1 | import { useState, useContext, useEffect, useRef } from "react";
2 | import { loginUser } from "../services/authService";
3 | import { AuthContext } from "../contexts/AuthContext";
4 | import { useNavigate, Link } from "react-router-dom";
5 | import * as THREE from "three";
6 |
7 | export default function LoginForm() {
8 | const [form, setForm] = useState({ email: "", password: "" });
9 | const [msg, setMsg] = useState("");
10 | const [isLoading, setIsLoading] = useState(false);
11 | const [showPassword, setShowPassword] = useState(false);
12 | const [darkMode, setDarkMode] = useState(() => {
13 | const saved = localStorage.getItem("theme");
14 | return saved ? saved === "dark" : true;
15 | });
16 | const { login } = useContext(AuthContext);
17 | const navigate = useNavigate();
18 | const mountRef = useRef(null);
19 | const sceneRef = useRef(null);
20 | const animationIdRef = useRef(null);
21 |
22 | const handleChange = (e) => setForm({ ...form, [e.target.name]: e.target.value });
23 |
24 | const handleSubmit = async (e) => {
25 | e.preventDefault();
26 | setIsLoading(true);
27 | setMsg("");
28 |
29 | try {
30 | const res = await loginUser(form);
31 | login(res.data.token);
32 | setMsg("Login successful! Redirecting...");
33 | setTimeout(() => navigate("/dashboard"), 1500);
34 | } catch (err) {
35 | setMsg(err.response?.data?.message || "Login failed. Please try again.");
36 | setIsLoading(false);
37 | }
38 | };
39 |
40 | // 3D Background Animation
41 | useEffect(() => {
42 | if (!mountRef.current) return;
43 |
44 | const mount = mountRef.current;
45 | const scene = new THREE.Scene();
46 | const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
47 | const camera = new THREE.PerspectiveCamera(45, mount.clientWidth / mount.clientHeight, 0.1, 100);
48 |
49 | renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
50 | renderer.setSize(mount.clientWidth, mount.clientHeight);
51 | camera.position.set(0, 0, 8);
52 | mount.appendChild(renderer.domElement);
53 |
54 | // Lights
55 | scene.add(
56 | new THREE.DirectionalLight(0xffffff, 1.0).add(light => light.position.set(2, 3, 4)),
57 | new THREE.DirectionalLight(0x8b5cf6, 0.5).add(light => light.position.set(-3, -2, -2)),
58 | new THREE.AmbientLight(0xffffff, 0.3)
59 | );
60 |
61 | // Create floating geometric shapes
62 | const shapes = [];
63 | for (let i = 0; i < 15; i++) {
64 | const geometries = [
65 | new THREE.TetrahedronGeometry(0.3),
66 | new THREE.OctahedronGeometry(0.25),
67 | new THREE.IcosahedronGeometry(0.2),
68 | new THREE.BoxGeometry(0.3, 0.3, 0.3),
69 | ];
70 |
71 | const shape = new THREE.Mesh(
72 | geometries[i % 4],
73 | new THREE.MeshPhongMaterial({
74 | color: new THREE.Color().setHSL((i * 0.1) % 1, 0.7, 0.6),
75 | transparent: true,
76 | opacity: 0.4,
77 | wireframe: Math.random() > 0.5,
78 | })
79 | );
80 |
81 | shape.position.set(
82 | (Math.random() - 0.5) * 20,
83 | (Math.random() - 0.5) * 20,
84 | (Math.random() - 0.5) * 15
85 | );
86 |
87 | shape.userData = {
88 | rotSpeed: [(Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02],
89 | floatSpeed: Math.random() * 0.01 + 0.005,
90 | offset: Math.random() * Math.PI * 2,
91 | };
92 |
93 | shapes.push(shape);
94 | scene.add(shape);
95 | }
96 |
97 | // Particles
98 | const particleCount = 800;
99 | const positions = new Float32Array(particleCount * 3);
100 | const velocities = new Float32Array(particleCount * 3);
101 |
102 | for (let i = 0; i < particleCount * 3; i += 3) {
103 | positions[i] = (Math.random() - 0.5) * 30;
104 | positions[i + 1] = (Math.random() - 0.5) * 30;
105 | positions[i + 2] = (Math.random() - 0.5) * 20;
106 | velocities[i] = (Math.random() - 0.5) * 0.01;
107 | velocities[i + 1] = (Math.random() - 0.5) * 0.01;
108 | velocities[i + 2] = (Math.random() - 0.5) * 0.01;
109 | }
110 |
111 | const particles = new THREE.Points(
112 | new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(positions, 3)),
113 | new THREE.PointsMaterial({
114 | size: 0.02,
115 | color: darkMode ? 0xffffff : 0x1e293b,
116 | transparent: true,
117 | opacity: 0.6,
118 | })
119 | );
120 | scene.add(particles);
121 |
122 | const onResize = () => {
123 | if (!mount || !renderer || !camera) return;
124 | renderer.setSize(mount.clientWidth, mount.clientHeight);
125 | camera.aspect = mount.clientWidth / mount.clientHeight;
126 | camera.updateProjectionMatrix();
127 | };
128 |
129 | window.addEventListener("resize", onResize);
130 |
131 | // Animation loop
132 | const clock = new THREE.Clock();
133 | const animate = () => {
134 | if (!renderer || !scene || !camera) return;
135 |
136 | const t = clock.getElapsedTime();
137 |
138 | // Animate shapes
139 | shapes.forEach((shape, i) => {
140 | const { rotSpeed, floatSpeed, offset } = shape.userData;
141 | shape.rotation.x += rotSpeed[0];
142 | shape.rotation.y += rotSpeed[1];
143 | shape.rotation.z += rotSpeed[2];
144 | shape.position.y += Math.sin(t * floatSpeed + offset) * 0.003;
145 | shape.material.opacity = 0.3 + Math.sin(t * 2 + i) * 0.2;
146 | });
147 |
148 | // Animate particles
149 | particles.rotation.y += 0.001;
150 | for (let i = 0; i < particleCount * 3; i += 3) {
151 | positions[i] += velocities[i];
152 | positions[i + 1] += velocities[i + 1];
153 | positions[i + 2] += velocities[i + 2];
154 | if (Math.abs(positions[i]) > 15) velocities[i] *= -1;
155 | if (Math.abs(positions[i + 1]) > 15) velocities[i + 1] *= -1;
156 | if (Math.abs(positions[i + 2]) > 10) velocities[i + 2] *= -1;
157 | }
158 | particles.geometry.attributes.position.needsUpdate = true;
159 |
160 | camera.position.x = Math.sin(t * 0.1) * 0.5;
161 | camera.position.y = Math.cos(t * 0.12) * 0.3;
162 | camera.lookAt(scene.position);
163 |
164 | renderer.render(scene, camera);
165 | animationIdRef.current = requestAnimationFrame(animate);
166 | };
167 | animate();
168 |
169 | sceneRef.current = { scene, renderer, camera, shapes, particles };
170 |
171 | // Cleanup
172 | return () => {
173 | if (animationIdRef.current) cancelAnimationFrame(animationIdRef.current);
174 | window.removeEventListener("resize", onResize);
175 | if (mount.contains(renderer.domElement)) mount.removeChild(renderer.domElement);
176 | scene.traverse(obj => {
177 | if (obj.geometry) obj.geometry.dispose();
178 | if (obj.material) obj.material.dispose();
179 | });
180 | renderer.dispose();
181 | };
182 | }, [darkMode]);
183 |
184 | return (
185 |
186 |
190 |
191 | {/* 3D Background */}
192 |
193 |
194 | {/* Background Elements */}
195 |
201 |
202 | {/* Floating Orbs */}
203 |
204 | {[...Array(6)].map((_, i) => (
205 |
212 | ))}
213 |
214 |
215 | {/* Back to Home Button */}
216 |
220 |
223 |
Back
224 |
225 |
226 | {/* Theme Toggle */}
227 |
243 |
244 | {/* Login Form Container */}
245 |
246 |
251 |
252 | {/* Header */}
253 |
254 |
255 |
256 | EventSphere
257 |
258 |
259 |
Welcome Back
262 |
Sign in to your account
265 |
266 |
267 | {/* Form */}
268 |
367 |
368 | {/* Message */}
369 | {msg && (
370 |
375 | {msg}
376 |
377 | )}
378 |
379 | {/* Footer */}
380 |
381 |
382 | Don't have an account?{" "}
383 |
387 | Sign up here
388 |
389 |
390 |
391 |
392 |
393 |
394 |
402 |
403 |
404 | );
405 | }
406 |
--------------------------------------------------------------------------------
/client/src/pages/Home.jsx:
--------------------------------------------------------------------------------
1 | import { Link } from "react-router-dom";
2 | import { useEffect, useRef, useState } from "react";
3 | import * as THREE from "three";
4 |
5 | export default function Home() {
6 | const mountRef = useRef(null);
7 | const menuRef = useRef(null);
8 | const [menuOpen, setMenuOpen] = useState(false);
9 | const [darkMode, setDarkMode] = useState(() => {
10 | const saved = localStorage.getItem("theme");
11 | return saved ? saved === "dark" : true;
12 | });
13 | const sceneRef = useRef(null);
14 | const animationIdRef = useRef(null);
15 |
16 | // Close menu when clicking outside
17 | useEffect(() => {
18 | const handleClickOutside = (event) => {
19 | if (menuRef.current && !menuRef.current.contains(event.target)) {
20 | setMenuOpen(false);
21 | }
22 | };
23 | if (menuOpen) {
24 | document.addEventListener('mousedown', handleClickOutside);
25 | return () => document.removeEventListener('mousedown', handleClickOutside);
26 | }
27 | }, [menuOpen]);
28 |
29 | useEffect(() => {
30 | localStorage.setItem("theme", darkMode ? "dark" : "light");
31 | }, [darkMode]);
32 |
33 | useEffect(() => {
34 | if (!mountRef.current) return;
35 |
36 | const mount = mountRef.current;
37 | const scene = new THREE.Scene();
38 | const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
39 | const camera = new THREE.PerspectiveCamera(45, mount.clientWidth / mount.clientHeight, 0.1, 100);
40 |
41 | renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
42 | renderer.setSize(mount.clientWidth, mount.clientHeight);
43 | camera.position.set(0, 0, 6);
44 | mount.appendChild(renderer.domElement);
45 |
46 | // Lights
47 | scene.add(
48 | new THREE.DirectionalLight(0xffffff, 1.2).add(light => light.position.set(3, 4, 5)),
49 | new THREE.DirectionalLight(0xff66cc, 0.6).add(light => light.position.set(-5, -2, -3)),
50 | new THREE.AmbientLight(0xffffff, 0.35)
51 | );
52 |
53 | // Shader uniforms
54 | const uniforms = {
55 | u_time: { value: 0 },
56 | u_intensity: { value: 0.7 },
57 | u_hover: { value: 0.0 },
58 | u_c1: { value: new THREE.Color("#8b5cf6") },
59 | u_c2: { value: new THREE.Color("#ec4899") },
60 | u_c3: { value: new THREE.Color("#22d3ee") },
61 | };
62 |
63 | // Simplified shader strings (keeping same visual effect)
64 | const vertexShader = `
65 | void main() {
66 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
67 | }
68 | `;
69 |
70 | const fragmentShader = `
71 | void main() {
72 | gl_FragColor = vec4(1.0);
73 | }
74 | `;
75 |
76 | // Create blob
77 | const blob = new THREE.Mesh(
78 | new THREE.IcosahedronGeometry(1.6, 80),
79 | new THREE.ShaderMaterial({ uniforms, vertexShader, fragmentShader })
80 | );
81 | scene.add(blob);
82 |
83 | // Create particles
84 | const particleCount = 1500;
85 | const positions = new Float32Array(particleCount * 3);
86 | const velocities = new Float32Array(particleCount * 3);
87 | for (let i = 0; i < particleCount; i++) {
88 | const k = i * 3;
89 | positions[k] = (Math.random() - 0.5) * 25;
90 | positions[k + 1] = (Math.random() - 0.5) * 25;
91 | positions[k + 2] = (Math.random() - 0.5) * 25;
92 | velocities[k] = (Math.random() - 0.5) * 0.015;
93 | velocities[k + 1] = (Math.random() - 0.5) * 0.015;
94 | velocities[k + 2] = (Math.random() - 0.5) * 0.015;
95 | }
96 |
97 | const geometry = new THREE.BufferGeometry();
98 | geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
99 |
100 | const material = new THREE.PointsMaterial({
101 | size: 0.03,
102 | color: darkMode ? 0xffffff : 0x0f172a,
103 | transparent: true,
104 | opacity: 0.4,
105 | });
106 |
107 | const particles = new THREE.Points(geometry, material);
108 | scene.add(particles);
109 |
110 | // Floating shapes
111 | const shapes = [];
112 | for (let i = 0; i < 10; i++) {
113 | const geometries = [
114 | new THREE.TetrahedronGeometry(0.1),
115 | new THREE.OctahedronGeometry(0.08),
116 | new THREE.IcosahedronGeometry(0.06)
117 | ];
118 | const shape = new THREE.Mesh(
119 | geometries[i % 3],
120 | new THREE.MeshBasicMaterial({
121 | color: new THREE.Color().setHSL(Math.random(), 0.7, 0.6),
122 | transparent: true,
123 | opacity: 0.3,
124 | wireframe: true,
125 | })
126 | );
127 | shape.position.set((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 15, (Math.random() - 0.5) * 15);
128 | shape.userData = {
129 | rotSpeed: [(Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02],
130 | floatSpeed: Math.random() * 0.01 + 0.005,
131 | offset: Math.random() * Math.PI * 2,
132 | };
133 | shapes.push(shape);
134 | scene.add(shape);
135 | }
136 |
137 | // Event handlers
138 | let hoverTarget = 0;
139 | const onEnter = () => (hoverTarget = 1);
140 | const onLeave = () => (hoverTarget = 0);
141 | const onResize = () => {
142 | if (!mount || !renderer || !camera) return;
143 | renderer.setSize(mount.clientWidth, mount.clientHeight);
144 | camera.aspect = mount.clientWidth / mount.clientHeight;
145 | camera.updateProjectionMatrix();
146 | };
147 |
148 | mount.addEventListener("mouseenter", onEnter);
149 | mount.addEventListener("mouseleave", onLeave);
150 | window.addEventListener("resize", onResize);
151 |
152 | // Animation loop
153 | const clock = new THREE.Clock();
154 | const animate = () => {
155 | if (!renderer || !scene || !camera) return;
156 |
157 | const t = clock.getElapsedTime();
158 | uniforms.u_time.value = t;
159 | uniforms.u_hover.value += (hoverTarget - uniforms.u_hover.value) * 0.08;
160 |
161 | // Animate objects
162 | blob.rotation.y += 0.003;
163 | blob.rotation.x = Math.sin(t * 0.5) * 0.1;
164 | blob.position.y = Math.sin(t * 0.3) * 0.2;
165 |
166 | particles.rotation.y -= 0.001;
167 |
168 | // Update particle positions
169 | for (let i = 0; i < particleCount * 3; i += 3) {
170 | positions[i] += velocities[i];
171 | positions[i + 1] += velocities[i + 1];
172 | positions[i + 2] += velocities[i + 2];
173 | if (Math.abs(positions[i]) > 12) velocities[i] *= -1;
174 | if (Math.abs(positions[i + 1]) > 12) velocities[i + 1] *= -1;
175 | if (Math.abs(positions[i + 2]) > 12) velocities[i + 2] *= -1;
176 | }
177 | particles.geometry.attributes.position.needsUpdate = true;
178 |
179 | // Animate shapes
180 | shapes.forEach((shape, i) => {
181 | const { rotSpeed, floatSpeed, offset } = shape.userData;
182 | shape.rotation.x += rotSpeed[0];
183 | shape.rotation.y += rotSpeed[1];
184 | shape.rotation.z += rotSpeed[2];
185 | shape.position.y += Math.sin(t * floatSpeed + offset) * 0.002;
186 | shape.material.opacity = 0.2 + Math.sin(t * 2 + i) * 0.1;
187 | });
188 |
189 | camera.position.x = Math.sin(t * 0.1) * 0.1;
190 | camera.position.y = Math.cos(t * 0.15) * 0.1;
191 | camera.lookAt(scene.position);
192 |
193 | renderer.render(scene, camera);
194 | animationIdRef.current = requestAnimationFrame(animate);
195 | };
196 | animate();
197 |
198 | // Cleanup
199 | return () => {
200 | if (animationIdRef.current) cancelAnimationFrame(animationIdRef.current);
201 | window.removeEventListener("resize", onResize);
202 | mount.removeEventListener("mouseenter", onEnter);
203 | mount.removeEventListener("mouseleave", onLeave);
204 | if (mount.contains(renderer.domElement)) mount.removeChild(renderer.domElement);
205 | scene.traverse(obj => {
206 | if (obj.geometry) obj.geometry.dispose();
207 | if (obj.material) obj.material.dispose();
208 | });
209 | renderer.dispose();
210 | };
211 | }, [darkMode]);
212 |
213 | const ProfileIcon = ({ isOpen }) => (
214 |
218 | );
219 |
220 | const MenuItem = ({ to, icon, children, onClick }) => (
221 |
226 |
227 | {icon}
228 |
229 | {children}
230 |
231 | );
232 |
233 | const MenuButton = ({ icon, children, onClick }) => (
234 |
243 | );
244 |
245 | return (
246 |
247 |
251 |
252 | {/* Background Elements */}
253 |
259 |
260 |
261 | {[...Array(8)].map((_, i) => (
262 |
270 | ))}
271 | {[...Array(5)].map((_, i) => (
272 |
281 | ))}
282 |
283 |
284 |
285 |
286 |
295 |
296 | {/* Profile Menu */}
297 |
298 |
299 |
312 |
313 |
316 |
317 |
318 |
Account
319 |
Manage your profile
320 |
321 |
322 |
326 |
330 |
331 |
setMenuOpen(false)}
332 | icon={}>
333 | Settings
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 | {/* Hero Section */}
343 |
344 |
345 |
348 | EventSphere
349 |
350 |
353 | Manage, discover, and participate in events seamlessly. Built for{" "}
354 | Admins,{" "}
355 | Faculty, and{" "}
356 | Students.
357 |
358 |
359 |
365 |
Go to Dashboard
366 |
🚀
367 |
368 |
369 |
370 |
371 |
Click the profile icon above to get started
374 |
375 |
376 |
377 |
378 | {/* Features */}
379 |
380 | {[
381 | { t: "Fast & Intuitive", d: "Simple flows to create and manage events in minutes.", e: "🚀" },
382 | { t: "Smart Scheduling", d: "Powerful tools to organize, publish, and track events.", e: "📅" },
383 | { t: "For Everyone", d: "Role-aware experience for admins, faculty, and students.", e: "🎓" },
384 | ].map((f, index) => (
385 |
391 |
{f.e}
392 |
{f.t}
395 |
{f.d}
398 |
399 |
400 | ))}
401 |
405 |
406 |
407 |
412 |
413 |
414 | );
415 | }
416 |
--------------------------------------------------------------------------------
/client/src/pages/Dashboard.jsx:
--------------------------------------------------------------------------------
1 | import { useContext, useState, useEffect, useRef } from "react";
2 | import { AuthContext } from "../contexts/AuthContext";
3 | import { useNavigate, Link } from "react-router-dom";
4 | import EventManager from "../components/EventManager";
5 | import * as THREE from "three";
6 |
7 | export default function Dashboard() {
8 | const { user, logout } = useContext(AuthContext);
9 | const navigate = useNavigate();
10 | const [darkMode, setDarkMode] = useState(() => {
11 | const saved = localStorage.getItem("theme");
12 | return saved ? saved === "dark" : true;
13 | });
14 | const [activeTab, setActiveTab] = useState("overview");
15 | const [sidebarOpen, setSidebarOpen] = useState(true);
16 | const [notifications, setNotifications] = useState([
17 | { id: 1, type: "event", message: "New event registration deadline approaching", time: "2 hours ago" },
18 | { id: 2, type: "update", message: "Event 'Tech Conference 2025' has been updated", time: "1 day ago" },
19 | { id: 3, type: "reminder", message: "Don't forget to check your upcoming events", time: "3 days ago" }
20 | ]);
21 | const mountRef = useRef(null);
22 | const animationIdRef = useRef(null);
23 |
24 | const handleLogout = () => {
25 | logout();
26 | navigate("/login");
27 | };
28 |
29 | // Save theme preference
30 | useEffect(() => {
31 | localStorage.setItem("theme", darkMode ? "dark" : "light");
32 | }, [darkMode]);
33 |
34 | // 3D Background Animation
35 | useEffect(() => {
36 | if (!mountRef.current) return;
37 |
38 | const mount = mountRef.current;
39 | const scene = new THREE.Scene();
40 | const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
41 | const camera = new THREE.PerspectiveCamera(45, mount.clientWidth / mount.clientHeight, 0.1, 100);
42 |
43 | renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
44 | renderer.setSize(mount.clientWidth, mount.clientHeight);
45 | camera.position.set(0, 0, 15);
46 | mount.appendChild(renderer.domElement);
47 |
48 | // Lights
49 | scene.add(
50 | new THREE.DirectionalLight(0xffffff, 0.8).add(light => light.position.set(5, 5, 5)),
51 | new THREE.DirectionalLight(0x8b5cf6, 0.4).add(light => light.position.set(-3, -2, -4)),
52 | new THREE.AmbientLight(0xffffff, 0.3)
53 | );
54 |
55 | // Create floating dashboard elements
56 | const dashboardElements = [];
57 | for (let i = 0; i < 20; i++) {
58 | const geometries = [
59 | new THREE.BoxGeometry(0.5, 0.5, 0.5),
60 | new THREE.CylinderGeometry(0.3, 0.3, 0.6),
61 | new THREE.SphereGeometry(0.25),
62 | new THREE.TetrahedronGeometry(0.4)
63 | ];
64 |
65 | const element = new THREE.Mesh(
66 | geometries[i % 4],
67 | new THREE.MeshPhongMaterial({
68 | color: new THREE.Color().setHSL((i * 0.05) % 1, 0.6, 0.7),
69 | transparent: true,
70 | opacity: 0.2,
71 | wireframe: i % 3 === 0,
72 | })
73 | );
74 |
75 | element.position.set(
76 | (Math.random() - 0.5) * 30,
77 | (Math.random() - 0.5) * 20,
78 | (Math.random() - 0.5) * 20
79 | );
80 |
81 | element.userData = {
82 | rotSpeed: [(Math.random() - 0.5) * 0.01, (Math.random() - 0.5) * 0.01, (Math.random() - 0.5) * 0.01],
83 | floatSpeed: Math.random() * 0.005 + 0.002,
84 | offset: Math.random() * Math.PI * 2,
85 | };
86 |
87 | dashboardElements.push(element);
88 | scene.add(element);
89 | }
90 |
91 | // Particles
92 | const particleCount = 500;
93 | const positions = new Float32Array(particleCount * 3);
94 | const velocities = new Float32Array(particleCount * 3);
95 |
96 | for (let i = 0; i < particleCount * 3; i += 3) {
97 | positions[i] = (Math.random() - 0.5) * 40;
98 | positions[i + 1] = (Math.random() - 0.5) * 25;
99 | positions[i + 2] = (Math.random() - 0.5) * 25;
100 | velocities[i] = (Math.random() - 0.5) * 0.008;
101 | velocities[i + 1] = (Math.random() - 0.5) * 0.008;
102 | velocities[i + 2] = (Math.random() - 0.5) * 0.008;
103 | }
104 |
105 | const particles = new THREE.Points(
106 | new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(positions, 3)),
107 | new THREE.PointsMaterial({
108 | size: 0.02,
109 | color: darkMode ? 0xffffff : 0x1e293b,
110 | transparent: true,
111 | opacity: 0.4,
112 | })
113 | );
114 | scene.add(particles);
115 |
116 | const onResize = () => {
117 | if (!mount || !renderer || !camera) return;
118 | renderer.setSize(mount.clientWidth, mount.clientHeight);
119 | camera.aspect = mount.clientWidth / mount.clientHeight;
120 | camera.updateProjectionMatrix();
121 | };
122 |
123 | window.addEventListener("resize", onResize);
124 |
125 | // Animation loop
126 | const clock = new THREE.Clock();
127 | const animate = () => {
128 | if (!renderer || !scene || !camera) return;
129 |
130 | const t = clock.getElapsedTime();
131 |
132 | // Animate dashboard elements
133 | dashboardElements.forEach((element, i) => {
134 | const { rotSpeed, floatSpeed, offset } = element.userData;
135 | element.rotation.x += rotSpeed[0];
136 | element.rotation.y += rotSpeed[1];
137 | element.rotation.z += rotSpeed[2];
138 | element.position.y += Math.sin(t * floatSpeed + offset) * 0.002;
139 | element.material.opacity = 0.15 + Math.sin(t * 2 + i) * 0.1;
140 | });
141 |
142 | // Animate particles
143 | particles.rotation.y += 0.0005;
144 | for (let i = 0; i < particleCount * 3; i += 3) {
145 | positions[i] += velocities[i];
146 | positions[i + 1] += velocities[i + 1];
147 | positions[i + 2] += velocities[i + 2];
148 | if (Math.abs(positions[i]) > 20) velocities[i] *= -1;
149 | if (Math.abs(positions[i + 1]) > 12) velocities[i + 1] *= -1;
150 | if (Math.abs(positions[i + 2]) > 12) velocities[i + 2] *= -1;
151 | }
152 | particles.geometry.attributes.position.needsUpdate = true;
153 |
154 | camera.position.x = Math.sin(t * 0.05) * 2;
155 | camera.position.y = Math.cos(t * 0.08) * 1;
156 | camera.lookAt(scene.position);
157 |
158 | renderer.render(scene, camera);
159 | animationIdRef.current = requestAnimationFrame(animate);
160 | };
161 | animate();
162 |
163 | // Cleanup
164 | return () => {
165 | if (animationIdRef.current) cancelAnimationFrame(animationIdRef.current);
166 | window.removeEventListener("resize", onResize);
167 | if (mount.contains(renderer.domElement)) mount.removeChild(renderer.domElement);
168 | scene.traverse(obj => {
169 | if (obj.geometry) obj.geometry.dispose();
170 | if (obj.material) obj.material.dispose();
171 | });
172 | renderer.dispose();
173 | };
174 | }, [darkMode]);
175 |
176 | const getRoleIcon = (role) => {
177 | switch(role) {
178 | case 'admin': return '👑';
179 | case 'faculty': return '👨🏫';
180 | case 'student': return '🎓';
181 | default: return '👤';
182 | }
183 | };
184 |
185 | const getRoleColor = (role) => {
186 | switch(role) {
187 | case 'admin': return 'from-red-500 to-pink-500';
188 | case 'faculty': return 'from-blue-500 to-indigo-500';
189 | case 'student': return 'from-green-500 to-emerald-500';
190 | default: return 'from-gray-500 to-slate-500';
191 | }
192 | };
193 |
194 | const TabButton = ({ id, icon, label, isActive, onClick }) => (
195 |
210 | );
211 |
212 | const StatCard = ({ icon, title, value, change, color }) => (
213 |
218 |
219 |
220 | {icon}
221 |
222 | {change && (
223 |
226 | {change}
227 |
228 | )}
229 |
230 |
{title}
231 |
{value}
232 |
233 | );
234 |
235 | const NotificationItem = ({ notification, onDismiss }) => {
236 | const getNotificationIcon = (type) => {
237 | switch(type) {
238 | case 'event': return '📅';
239 | case 'update': return '🔄';
240 | case 'reminder': return '⏰';
241 | default: return '📢';
242 | }
243 | };
244 |
245 | return (
246 |
251 |
252 |
{getNotificationIcon(notification.type)}
253 |
254 |
{notification.message}
255 |
{notification.time}
256 |
257 |
265 |
266 |
267 | );
268 | };
269 |
270 | return (
271 |
272 |
276 |
277 | {/* 3D Background */}
278 |
279 |
280 | {/* Background Elements */}
281 |
287 |
288 | {/* Top Header */}
289 |
376 |
377 |
378 | {/* Sidebar */}
379 |
415 |
416 | {/* Main Content */}
417 |
418 | {/* Welcome Section */}
419 |
420 |
421 | Welcome back, {user?.name}! 👋
422 |
423 |
424 | Here's what's happening with your events today.
425 |
426 |
427 |
428 | {/* Role Badge */}
429 |
430 | {getRoleIcon(user?.role)}
431 | {user?.role} Dashboard
432 |
433 |
434 | {/* Tab Content */}
435 | {activeTab === "overview" && (
436 |
437 | {/* Stats Grid */}
438 |
439 |
446 |
453 |
460 |
467 |
468 |
469 | {/* Recent Activity */}
470 |
475 |
476 | 📢 Recent Notifications
477 |
478 |
479 | {notifications.map(notification => (
480 |
setNotifications(prev => prev.filter(n => n.id !== id))}
484 | />
485 | ))}
486 | {notifications.length === 0 && (
487 |
488 | No new notifications 🎉
489 |
490 | )}
491 |
492 |
493 |
494 | )}
495 |
496 | {activeTab === "events" && (
497 |
502 |
503 | 📌 Event Management
504 |
505 |
506 |
507 | )}
508 |
509 | {activeTab === "analytics" && (
510 |
515 |
516 | 📈 Analytics & Insights
517 |
518 |
519 |
522 |
Event Trends
523 |
524 | Your events have seen a 15% increase in participation this month.
525 |
526 |
527 |
530 |
Popular Categories
531 |
532 | Technology and Education events are performing best.
533 |
534 |
535 |
536 |
537 | )}
538 |
539 | {activeTab === "settings" && (
540 |
545 |
546 | ⚙️ Settings & Preferences
547 |
548 |
549 |
550 |
Dark Mode
551 |
561 |
562 |
563 |
Email Notifications
564 |
567 |
568 |
569 |
570 | )}
571 |
572 |
573 |
574 |
578 |
579 |
580 | );
581 | }
582 |
--------------------------------------------------------------------------------
/client/src/pages/SignupForm.jsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useRef } from 'react';
2 | import { registerUser } from '../services/authService';
3 | import { Link, useNavigate } from 'react-router-dom';
4 | import * as THREE from "three";
5 |
6 | export default function SignupForm() {
7 | const [form, setForm] = useState({ name: '', email: '', password: '', role: 'student' });
8 | const [msg, setMsg] = useState('');
9 | const [isLoading, setIsLoading] = useState(false);
10 | const [showPassword, setShowPassword] = useState(false);
11 | const [passwordStrength, setPasswordStrength] = useState(0);
12 | const [darkMode, setDarkMode] = useState(() => {
13 | const saved = localStorage.getItem("theme");
14 | return saved ? saved === "dark" : true;
15 | });
16 | const navigate = useNavigate();
17 | const mountRef = useRef(null);
18 | const sceneRef = useRef(null);
19 | const animationIdRef = useRef(null);
20 |
21 | const handleChange = (e) => {
22 | setForm({ ...form, [e.target.name]: e.target.value });
23 |
24 | // Calculate password strength
25 | if (e.target.name === 'password') {
26 | const password = e.target.value;
27 | let strength = 0;
28 | if (password.length >= 8) strength += 25;
29 | if (/[A-Z]/.test(password)) strength += 25;
30 | if (/[0-9]/.test(password)) strength += 25;
31 | if (/[^A-Za-z0-9]/.test(password)) strength += 25;
32 | setPasswordStrength(strength);
33 | }
34 | };
35 |
36 | const handleSubmit = async (e) => {
37 | e.preventDefault();
38 | setIsLoading(true);
39 | setMsg('');
40 |
41 | try {
42 | await registerUser(form);
43 | setMsg('Registration successful! Redirecting to login...');
44 | setTimeout(() => navigate('/login'), 2000);
45 | } catch (err) {
46 | setMsg(err.response?.data?.message || 'Registration failed. Please try again.');
47 | setIsLoading(false);
48 | }
49 | };
50 |
51 | const getPasswordStrengthColor = () => {
52 | if (passwordStrength <= 25) return 'from-red-500 to-red-600';
53 | if (passwordStrength <= 50) return 'from-yellow-500 to-orange-500';
54 | if (passwordStrength <= 75) return 'from-blue-500 to-indigo-500';
55 | return 'from-green-500 to-emerald-500';
56 | };
57 |
58 | const getPasswordStrengthText = () => {
59 | if (passwordStrength === 0) return '';
60 | if (passwordStrength <= 25) return 'Weak';
61 | if (passwordStrength <= 50) return 'Fair';
62 | if (passwordStrength <= 75) return 'Good';
63 | return 'Strong';
64 | };
65 |
66 | // 3D Background Animation
67 | useEffect(() => {
68 | if (!mountRef.current) return;
69 |
70 | const mount = mountRef.current;
71 | const scene = new THREE.Scene();
72 | const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
73 | const camera = new THREE.PerspectiveCamera(45, mount.clientWidth / mount.clientHeight, 0.1, 100);
74 |
75 | renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
76 | renderer.setSize(mount.clientWidth, mount.clientHeight);
77 | camera.position.set(0, 0, 10);
78 | mount.appendChild(renderer.domElement);
79 |
80 | // Lights
81 | scene.add(
82 | new THREE.DirectionalLight(0xffffff, 1.2).add(light => light.position.set(3, 4, 5)),
83 | new THREE.DirectionalLight(0x22d3ee, 0.6).add(light => light.position.set(-4, -3, -2)),
84 | new THREE.AmbientLight(0xffffff, 0.4)
85 | );
86 |
87 | // Create morphing blob
88 | const uniforms = {
89 | u_time: { value: 0 },
90 | u_intensity: { value: 0.8 },
91 | u_c1: { value: new THREE.Color("#8b5cf6") },
92 | u_c2: { value: new THREE.Color("#ec4899") },
93 | u_c3: { value: new THREE.Color("#22d3ee") },
94 | };
95 |
96 | const vertexShader = `
97 | varying vec3 vNormal, vPos;
98 | uniform float u_time, u_intensity;
99 |
100 | float snoise(vec3 v) {
101 | return sin(v.x * 1.5 + u_time) * cos(v.y * 1.2 + u_time) * sin(v.z * 1.8 + u_time * 0.8);
102 | }
103 |
104 | void main() {
105 | vNormal = normal;
106 | vPos = position;
107 | float n = snoise(normal * 1.5 + u_time * 0.4) * u_intensity * 0.3;
108 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position + normal * n, 1.0);
109 | }
110 | `;
111 |
112 | const fragmentShader = `
113 | varying vec3 vNormal;
114 | uniform vec3 u_c1, u_c2, u_c3;
115 |
116 | void main(){
117 | vec3 n = normalize(vNormal);
118 | float fres = pow(1.0 - abs(n.z), 1.5);
119 | vec3 base = mix(u_c1, u_c2, (n.x + 1.0) * 0.5);
120 | base = mix(base, u_c3, (n.y + 1.0) * 0.5);
121 | gl_FragColor = vec4(base + fres * 0.4, 0.7);
122 | }
123 | `;
124 |
125 | const blob = new THREE.Mesh(
126 | new THREE.IcosahedronGeometry(2, 60),
127 | new THREE.ShaderMaterial({
128 | uniforms,
129 | vertexShader,
130 | fragmentShader,
131 | transparent: true
132 | })
133 | );
134 | blob.position.set(-3, 2, -5);
135 | scene.add(blob);
136 |
137 | // Create floating rings
138 | const rings = [];
139 | for (let i = 0; i < 12; i++) {
140 | const ring = new THREE.Mesh(
141 | new THREE.TorusGeometry(0.5 + i * 0.1, 0.05, 8, 16),
142 | new THREE.MeshPhongMaterial({
143 | color: new THREE.Color().setHSL((i * 0.08) % 1, 0.8, 0.6),
144 | transparent: true,
145 | opacity: 0.3,
146 | })
147 | );
148 |
149 | ring.position.set(
150 | (Math.random() - 0.5) * 25,
151 | (Math.random() - 0.5) * 25,
152 | (Math.random() - 0.5) * 20
153 | );
154 |
155 | ring.rotation.set(
156 | Math.random() * Math.PI,
157 | Math.random() * Math.PI,
158 | Math.random() * Math.PI
159 | );
160 |
161 | ring.userData = {
162 | rotSpeed: [(Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02],
163 | floatSpeed: Math.random() * 0.008 + 0.004,
164 | offset: Math.random() * Math.PI * 2,
165 | };
166 |
167 | rings.push(ring);
168 | scene.add(ring);
169 | }
170 |
171 | // Particles with trails
172 | const particleCount = 1200;
173 | const positions = new Float32Array(particleCount * 3);
174 | const velocities = new Float32Array(particleCount * 3);
175 | const colors = new Float32Array(particleCount * 3);
176 |
177 | for (let i = 0; i < particleCount * 3; i += 3) {
178 | positions[i] = (Math.random() - 0.5) * 35;
179 | positions[i + 1] = (Math.random() - 0.5) * 35;
180 | positions[i + 2] = (Math.random() - 0.5) * 25;
181 | velocities[i] = (Math.random() - 0.5) * 0.012;
182 | velocities[i + 1] = (Math.random() - 0.5) * 0.012;
183 | velocities[i + 2] = (Math.random() - 0.5) * 0.012;
184 |
185 | const hue = Math.random();
186 | colors[i] = hue;
187 | colors[i + 1] = 0.7;
188 | colors[i + 2] = 0.8;
189 | }
190 |
191 | const particles = new THREE.Points(
192 | new THREE.BufferGeometry()
193 | .setAttribute('position', new THREE.BufferAttribute(positions, 3))
194 | .setAttribute('color', new THREE.BufferAttribute(colors, 3)),
195 | new THREE.PointsMaterial({
196 | size: 0.025,
197 | transparent: true,
198 | opacity: 0.8,
199 | vertexColors: true,
200 | })
201 | );
202 | scene.add(particles);
203 |
204 | const onResize = () => {
205 | if (!mount || !renderer || !camera) return;
206 | renderer.setSize(mount.clientWidth, mount.clientHeight);
207 | camera.aspect = mount.clientWidth / mount.clientHeight;
208 | camera.updateProjectionMatrix();
209 | };
210 |
211 | window.addEventListener("resize", onResize);
212 |
213 | // Animation loop
214 | const clock = new THREE.Clock();
215 | const animate = () => {
216 | if (!renderer || !scene || !camera) return;
217 |
218 | const t = clock.getElapsedTime();
219 | uniforms.u_time.value = t;
220 |
221 | // Animate blob
222 | blob.rotation.y += 0.005;
223 | blob.rotation.x = Math.sin(t * 0.3) * 0.2;
224 | blob.position.y = 2 + Math.sin(t * 0.5) * 0.5;
225 |
226 | // Animate rings
227 | rings.forEach((ring, i) => {
228 | const { rotSpeed, floatSpeed, offset } = ring.userData;
229 | ring.rotation.x += rotSpeed[0];
230 | ring.rotation.y += rotSpeed[1];
231 | ring.rotation.z += rotSpeed[2];
232 | ring.position.y += Math.sin(t * floatSpeed + offset) * 0.004;
233 | ring.material.opacity = 0.2 + Math.sin(t * 3 + i) * 0.15;
234 | });
235 |
236 | // Animate particles
237 | particles.rotation.y += 0.0008;
238 | for (let i = 0; i < particleCount * 3; i += 3) {
239 | positions[i] += velocities[i];
240 | positions[i + 1] += velocities[i + 1];
241 | positions[i + 2] += velocities[i + 2];
242 | if (Math.abs(positions[i]) > 17) velocities[i] *= -1;
243 | if (Math.abs(positions[i + 1]) > 17) velocities[i + 1] *= -1;
244 | if (Math.abs(positions[i + 2]) > 12) velocities[i + 2] *= -1;
245 | }
246 | particles.geometry.attributes.position.needsUpdate = true;
247 |
248 | camera.position.x = Math.sin(t * 0.08) * 0.8;
249 | camera.position.y = Math.cos(t * 0.1) * 0.5;
250 | camera.lookAt(scene.position);
251 |
252 | renderer.render(scene, camera);
253 | animationIdRef.current = requestAnimationFrame(animate);
254 | };
255 | animate();
256 |
257 | sceneRef.current = { scene, renderer, camera, rings, particles };
258 |
259 | // Cleanup
260 | return () => {
261 | if (animationIdRef.current) cancelAnimationFrame(animationIdRef.current);
262 | window.removeEventListener("resize", onResize);
263 | if (mount.contains(renderer.domElement)) mount.removeChild(renderer.domElement);
264 | scene.traverse(obj => {
265 | if (obj.geometry) obj.geometry.dispose();
266 | if (obj.material) obj.material.dispose();
267 | });
268 | renderer.dispose();
269 | };
270 | }, [darkMode]);
271 |
272 | return (
273 |
274 |
278 |
279 | {/* 3D Background */}
280 |
281 |
282 | {/* Background Elements */}
283 |
289 |
290 | {/* Floating Elements */}
291 |
292 | {[...Array(8)].map((_, i) => (
293 |
299 | ))}
300 | {[...Array(5)].map((_, i) => (
301 |
308 | ))}
309 |
310 |
311 | {/* Back to Home Button */}
312 |
316 |
319 |
Back
320 |
321 |
322 | {/* Theme Toggle */}
323 |
339 |
340 | {/* Signup Form Container */}
341 |
342 |
347 |
348 | {/* Header */}
349 |
350 |
351 |
352 | EventSphere
353 |
354 |
355 |
Create Account
358 |
Join our community today
361 |
362 |
363 | {/* Form */}
364 |
541 |
542 | {/* Message */}
543 | {msg && (
544 |
549 | {msg}
550 |
551 | )}
552 |
553 | {/* Footer */}
554 |
555 |
556 | Already have an account?{" "}
557 |
561 | Sign in here
562 |
563 |
564 |
565 |
566 |
567 |
568 |
591 |
592 |
593 | );
594 | }
595 |
--------------------------------------------------------------------------------
/server/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "server",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "bcrypt": "^6.0.0",
13 | "cors": "^2.8.5",
14 | "dotenv": "^17.2.1",
15 | "express": "^5.1.0",
16 | "jsonwebtoken": "^9.0.2",
17 | "multer": "^2.0.2",
18 | "mysql2": "^3.14.3"
19 | },
20 | "devDependencies": {
21 | "nodemon": "^3.1.10"
22 | }
23 | },
24 | "node_modules/accepts": {
25 | "version": "2.0.0",
26 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
27 | "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
28 | "license": "MIT",
29 | "dependencies": {
30 | "mime-types": "^3.0.0",
31 | "negotiator": "^1.0.0"
32 | },
33 | "engines": {
34 | "node": ">= 0.6"
35 | }
36 | },
37 | "node_modules/anymatch": {
38 | "version": "3.1.3",
39 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
40 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
41 | "dev": true,
42 | "license": "ISC",
43 | "dependencies": {
44 | "normalize-path": "^3.0.0",
45 | "picomatch": "^2.0.4"
46 | },
47 | "engines": {
48 | "node": ">= 8"
49 | }
50 | },
51 | "node_modules/append-field": {
52 | "version": "1.0.0",
53 | "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
54 | "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
55 | "license": "MIT"
56 | },
57 | "node_modules/aws-ssl-profiles": {
58 | "version": "1.1.2",
59 | "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
60 | "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
61 | "license": "MIT",
62 | "engines": {
63 | "node": ">= 6.0.0"
64 | }
65 | },
66 | "node_modules/balanced-match": {
67 | "version": "1.0.2",
68 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
69 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
70 | "dev": true,
71 | "license": "MIT"
72 | },
73 | "node_modules/bcrypt": {
74 | "version": "6.0.0",
75 | "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
76 | "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
77 | "hasInstallScript": true,
78 | "license": "MIT",
79 | "dependencies": {
80 | "node-addon-api": "^8.3.0",
81 | "node-gyp-build": "^4.8.4"
82 | },
83 | "engines": {
84 | "node": ">= 18"
85 | }
86 | },
87 | "node_modules/binary-extensions": {
88 | "version": "2.3.0",
89 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
90 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
91 | "dev": true,
92 | "license": "MIT",
93 | "engines": {
94 | "node": ">=8"
95 | },
96 | "funding": {
97 | "url": "https://github.com/sponsors/sindresorhus"
98 | }
99 | },
100 | "node_modules/body-parser": {
101 | "version": "2.2.0",
102 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
103 | "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
104 | "license": "MIT",
105 | "dependencies": {
106 | "bytes": "^3.1.2",
107 | "content-type": "^1.0.5",
108 | "debug": "^4.4.0",
109 | "http-errors": "^2.0.0",
110 | "iconv-lite": "^0.6.3",
111 | "on-finished": "^2.4.1",
112 | "qs": "^6.14.0",
113 | "raw-body": "^3.0.0",
114 | "type-is": "^2.0.0"
115 | },
116 | "engines": {
117 | "node": ">=18"
118 | }
119 | },
120 | "node_modules/brace-expansion": {
121 | "version": "1.1.12",
122 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
123 | "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
124 | "dev": true,
125 | "license": "MIT",
126 | "dependencies": {
127 | "balanced-match": "^1.0.0",
128 | "concat-map": "0.0.1"
129 | }
130 | },
131 | "node_modules/braces": {
132 | "version": "3.0.3",
133 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
134 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
135 | "dev": true,
136 | "license": "MIT",
137 | "dependencies": {
138 | "fill-range": "^7.1.1"
139 | },
140 | "engines": {
141 | "node": ">=8"
142 | }
143 | },
144 | "node_modules/buffer-equal-constant-time": {
145 | "version": "1.0.1",
146 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
147 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
148 | "license": "BSD-3-Clause"
149 | },
150 | "node_modules/buffer-from": {
151 | "version": "1.1.2",
152 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
153 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
154 | "license": "MIT"
155 | },
156 | "node_modules/busboy": {
157 | "version": "1.6.0",
158 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
159 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
160 | "dependencies": {
161 | "streamsearch": "^1.1.0"
162 | },
163 | "engines": {
164 | "node": ">=10.16.0"
165 | }
166 | },
167 | "node_modules/bytes": {
168 | "version": "3.1.2",
169 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
170 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
171 | "license": "MIT",
172 | "engines": {
173 | "node": ">= 0.8"
174 | }
175 | },
176 | "node_modules/call-bind-apply-helpers": {
177 | "version": "1.0.2",
178 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
179 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
180 | "license": "MIT",
181 | "dependencies": {
182 | "es-errors": "^1.3.0",
183 | "function-bind": "^1.1.2"
184 | },
185 | "engines": {
186 | "node": ">= 0.4"
187 | }
188 | },
189 | "node_modules/call-bound": {
190 | "version": "1.0.4",
191 | "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
192 | "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
193 | "license": "MIT",
194 | "dependencies": {
195 | "call-bind-apply-helpers": "^1.0.2",
196 | "get-intrinsic": "^1.3.0"
197 | },
198 | "engines": {
199 | "node": ">= 0.4"
200 | },
201 | "funding": {
202 | "url": "https://github.com/sponsors/ljharb"
203 | }
204 | },
205 | "node_modules/chokidar": {
206 | "version": "3.6.0",
207 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
208 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
209 | "dev": true,
210 | "license": "MIT",
211 | "dependencies": {
212 | "anymatch": "~3.1.2",
213 | "braces": "~3.0.2",
214 | "glob-parent": "~5.1.2",
215 | "is-binary-path": "~2.1.0",
216 | "is-glob": "~4.0.1",
217 | "normalize-path": "~3.0.0",
218 | "readdirp": "~3.6.0"
219 | },
220 | "engines": {
221 | "node": ">= 8.10.0"
222 | },
223 | "funding": {
224 | "url": "https://paulmillr.com/funding/"
225 | },
226 | "optionalDependencies": {
227 | "fsevents": "~2.3.2"
228 | }
229 | },
230 | "node_modules/concat-map": {
231 | "version": "0.0.1",
232 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
233 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
234 | "dev": true,
235 | "license": "MIT"
236 | },
237 | "node_modules/concat-stream": {
238 | "version": "2.0.0",
239 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
240 | "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
241 | "engines": [
242 | "node >= 6.0"
243 | ],
244 | "license": "MIT",
245 | "dependencies": {
246 | "buffer-from": "^1.0.0",
247 | "inherits": "^2.0.3",
248 | "readable-stream": "^3.0.2",
249 | "typedarray": "^0.0.6"
250 | }
251 | },
252 | "node_modules/content-disposition": {
253 | "version": "1.0.0",
254 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
255 | "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
256 | "license": "MIT",
257 | "dependencies": {
258 | "safe-buffer": "5.2.1"
259 | },
260 | "engines": {
261 | "node": ">= 0.6"
262 | }
263 | },
264 | "node_modules/content-type": {
265 | "version": "1.0.5",
266 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
267 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
268 | "license": "MIT",
269 | "engines": {
270 | "node": ">= 0.6"
271 | }
272 | },
273 | "node_modules/cookie": {
274 | "version": "0.7.2",
275 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
276 | "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
277 | "license": "MIT",
278 | "engines": {
279 | "node": ">= 0.6"
280 | }
281 | },
282 | "node_modules/cookie-signature": {
283 | "version": "1.2.2",
284 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
285 | "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
286 | "license": "MIT",
287 | "engines": {
288 | "node": ">=6.6.0"
289 | }
290 | },
291 | "node_modules/cors": {
292 | "version": "2.8.5",
293 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
294 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
295 | "license": "MIT",
296 | "dependencies": {
297 | "object-assign": "^4",
298 | "vary": "^1"
299 | },
300 | "engines": {
301 | "node": ">= 0.10"
302 | }
303 | },
304 | "node_modules/debug": {
305 | "version": "4.4.1",
306 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
307 | "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
308 | "license": "MIT",
309 | "dependencies": {
310 | "ms": "^2.1.3"
311 | },
312 | "engines": {
313 | "node": ">=6.0"
314 | },
315 | "peerDependenciesMeta": {
316 | "supports-color": {
317 | "optional": true
318 | }
319 | }
320 | },
321 | "node_modules/denque": {
322 | "version": "2.1.0",
323 | "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
324 | "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
325 | "license": "Apache-2.0",
326 | "engines": {
327 | "node": ">=0.10"
328 | }
329 | },
330 | "node_modules/depd": {
331 | "version": "2.0.0",
332 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
333 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
334 | "license": "MIT",
335 | "engines": {
336 | "node": ">= 0.8"
337 | }
338 | },
339 | "node_modules/dotenv": {
340 | "version": "17.2.1",
341 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz",
342 | "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==",
343 | "license": "BSD-2-Clause",
344 | "engines": {
345 | "node": ">=12"
346 | },
347 | "funding": {
348 | "url": "https://dotenvx.com"
349 | }
350 | },
351 | "node_modules/dunder-proto": {
352 | "version": "1.0.1",
353 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
354 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
355 | "license": "MIT",
356 | "dependencies": {
357 | "call-bind-apply-helpers": "^1.0.1",
358 | "es-errors": "^1.3.0",
359 | "gopd": "^1.2.0"
360 | },
361 | "engines": {
362 | "node": ">= 0.4"
363 | }
364 | },
365 | "node_modules/ecdsa-sig-formatter": {
366 | "version": "1.0.11",
367 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
368 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
369 | "license": "Apache-2.0",
370 | "dependencies": {
371 | "safe-buffer": "^5.0.1"
372 | }
373 | },
374 | "node_modules/ee-first": {
375 | "version": "1.1.1",
376 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
377 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
378 | "license": "MIT"
379 | },
380 | "node_modules/encodeurl": {
381 | "version": "2.0.0",
382 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
383 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
384 | "license": "MIT",
385 | "engines": {
386 | "node": ">= 0.8"
387 | }
388 | },
389 | "node_modules/es-define-property": {
390 | "version": "1.0.1",
391 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
392 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
393 | "license": "MIT",
394 | "engines": {
395 | "node": ">= 0.4"
396 | }
397 | },
398 | "node_modules/es-errors": {
399 | "version": "1.3.0",
400 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
401 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
402 | "license": "MIT",
403 | "engines": {
404 | "node": ">= 0.4"
405 | }
406 | },
407 | "node_modules/es-object-atoms": {
408 | "version": "1.1.1",
409 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
410 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
411 | "license": "MIT",
412 | "dependencies": {
413 | "es-errors": "^1.3.0"
414 | },
415 | "engines": {
416 | "node": ">= 0.4"
417 | }
418 | },
419 | "node_modules/escape-html": {
420 | "version": "1.0.3",
421 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
422 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
423 | "license": "MIT"
424 | },
425 | "node_modules/etag": {
426 | "version": "1.8.1",
427 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
428 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
429 | "license": "MIT",
430 | "engines": {
431 | "node": ">= 0.6"
432 | }
433 | },
434 | "node_modules/express": {
435 | "version": "5.1.0",
436 | "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
437 | "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
438 | "license": "MIT",
439 | "dependencies": {
440 | "accepts": "^2.0.0",
441 | "body-parser": "^2.2.0",
442 | "content-disposition": "^1.0.0",
443 | "content-type": "^1.0.5",
444 | "cookie": "^0.7.1",
445 | "cookie-signature": "^1.2.1",
446 | "debug": "^4.4.0",
447 | "encodeurl": "^2.0.0",
448 | "escape-html": "^1.0.3",
449 | "etag": "^1.8.1",
450 | "finalhandler": "^2.1.0",
451 | "fresh": "^2.0.0",
452 | "http-errors": "^2.0.0",
453 | "merge-descriptors": "^2.0.0",
454 | "mime-types": "^3.0.0",
455 | "on-finished": "^2.4.1",
456 | "once": "^1.4.0",
457 | "parseurl": "^1.3.3",
458 | "proxy-addr": "^2.0.7",
459 | "qs": "^6.14.0",
460 | "range-parser": "^1.2.1",
461 | "router": "^2.2.0",
462 | "send": "^1.1.0",
463 | "serve-static": "^2.2.0",
464 | "statuses": "^2.0.1",
465 | "type-is": "^2.0.1",
466 | "vary": "^1.1.2"
467 | },
468 | "engines": {
469 | "node": ">= 18"
470 | },
471 | "funding": {
472 | "type": "opencollective",
473 | "url": "https://opencollective.com/express"
474 | }
475 | },
476 | "node_modules/fill-range": {
477 | "version": "7.1.1",
478 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
479 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
480 | "dev": true,
481 | "license": "MIT",
482 | "dependencies": {
483 | "to-regex-range": "^5.0.1"
484 | },
485 | "engines": {
486 | "node": ">=8"
487 | }
488 | },
489 | "node_modules/finalhandler": {
490 | "version": "2.1.0",
491 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
492 | "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
493 | "license": "MIT",
494 | "dependencies": {
495 | "debug": "^4.4.0",
496 | "encodeurl": "^2.0.0",
497 | "escape-html": "^1.0.3",
498 | "on-finished": "^2.4.1",
499 | "parseurl": "^1.3.3",
500 | "statuses": "^2.0.1"
501 | },
502 | "engines": {
503 | "node": ">= 0.8"
504 | }
505 | },
506 | "node_modules/forwarded": {
507 | "version": "0.2.0",
508 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
509 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
510 | "license": "MIT",
511 | "engines": {
512 | "node": ">= 0.6"
513 | }
514 | },
515 | "node_modules/fresh": {
516 | "version": "2.0.0",
517 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
518 | "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
519 | "license": "MIT",
520 | "engines": {
521 | "node": ">= 0.8"
522 | }
523 | },
524 | "node_modules/fsevents": {
525 | "version": "2.3.3",
526 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
527 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
528 | "dev": true,
529 | "hasInstallScript": true,
530 | "license": "MIT",
531 | "optional": true,
532 | "os": [
533 | "darwin"
534 | ],
535 | "engines": {
536 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
537 | }
538 | },
539 | "node_modules/function-bind": {
540 | "version": "1.1.2",
541 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
542 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
543 | "license": "MIT",
544 | "funding": {
545 | "url": "https://github.com/sponsors/ljharb"
546 | }
547 | },
548 | "node_modules/generate-function": {
549 | "version": "2.3.1",
550 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
551 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
552 | "license": "MIT",
553 | "dependencies": {
554 | "is-property": "^1.0.2"
555 | }
556 | },
557 | "node_modules/get-intrinsic": {
558 | "version": "1.3.0",
559 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
560 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
561 | "license": "MIT",
562 | "dependencies": {
563 | "call-bind-apply-helpers": "^1.0.2",
564 | "es-define-property": "^1.0.1",
565 | "es-errors": "^1.3.0",
566 | "es-object-atoms": "^1.1.1",
567 | "function-bind": "^1.1.2",
568 | "get-proto": "^1.0.1",
569 | "gopd": "^1.2.0",
570 | "has-symbols": "^1.1.0",
571 | "hasown": "^2.0.2",
572 | "math-intrinsics": "^1.1.0"
573 | },
574 | "engines": {
575 | "node": ">= 0.4"
576 | },
577 | "funding": {
578 | "url": "https://github.com/sponsors/ljharb"
579 | }
580 | },
581 | "node_modules/get-proto": {
582 | "version": "1.0.1",
583 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
584 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
585 | "license": "MIT",
586 | "dependencies": {
587 | "dunder-proto": "^1.0.1",
588 | "es-object-atoms": "^1.0.0"
589 | },
590 | "engines": {
591 | "node": ">= 0.4"
592 | }
593 | },
594 | "node_modules/glob-parent": {
595 | "version": "5.1.2",
596 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
597 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
598 | "dev": true,
599 | "license": "ISC",
600 | "dependencies": {
601 | "is-glob": "^4.0.1"
602 | },
603 | "engines": {
604 | "node": ">= 6"
605 | }
606 | },
607 | "node_modules/gopd": {
608 | "version": "1.2.0",
609 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
610 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
611 | "license": "MIT",
612 | "engines": {
613 | "node": ">= 0.4"
614 | },
615 | "funding": {
616 | "url": "https://github.com/sponsors/ljharb"
617 | }
618 | },
619 | "node_modules/has-flag": {
620 | "version": "3.0.0",
621 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
622 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
623 | "dev": true,
624 | "license": "MIT",
625 | "engines": {
626 | "node": ">=4"
627 | }
628 | },
629 | "node_modules/has-symbols": {
630 | "version": "1.1.0",
631 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
632 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
633 | "license": "MIT",
634 | "engines": {
635 | "node": ">= 0.4"
636 | },
637 | "funding": {
638 | "url": "https://github.com/sponsors/ljharb"
639 | }
640 | },
641 | "node_modules/hasown": {
642 | "version": "2.0.2",
643 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
644 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
645 | "license": "MIT",
646 | "dependencies": {
647 | "function-bind": "^1.1.2"
648 | },
649 | "engines": {
650 | "node": ">= 0.4"
651 | }
652 | },
653 | "node_modules/http-errors": {
654 | "version": "2.0.0",
655 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
656 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
657 | "license": "MIT",
658 | "dependencies": {
659 | "depd": "2.0.0",
660 | "inherits": "2.0.4",
661 | "setprototypeof": "1.2.0",
662 | "statuses": "2.0.1",
663 | "toidentifier": "1.0.1"
664 | },
665 | "engines": {
666 | "node": ">= 0.8"
667 | }
668 | },
669 | "node_modules/http-errors/node_modules/statuses": {
670 | "version": "2.0.1",
671 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
672 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
673 | "license": "MIT",
674 | "engines": {
675 | "node": ">= 0.8"
676 | }
677 | },
678 | "node_modules/iconv-lite": {
679 | "version": "0.6.3",
680 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
681 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
682 | "license": "MIT",
683 | "dependencies": {
684 | "safer-buffer": ">= 2.1.2 < 3.0.0"
685 | },
686 | "engines": {
687 | "node": ">=0.10.0"
688 | }
689 | },
690 | "node_modules/ignore-by-default": {
691 | "version": "1.0.1",
692 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
693 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
694 | "dev": true,
695 | "license": "ISC"
696 | },
697 | "node_modules/inherits": {
698 | "version": "2.0.4",
699 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
700 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
701 | "license": "ISC"
702 | },
703 | "node_modules/ipaddr.js": {
704 | "version": "1.9.1",
705 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
706 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
707 | "license": "MIT",
708 | "engines": {
709 | "node": ">= 0.10"
710 | }
711 | },
712 | "node_modules/is-binary-path": {
713 | "version": "2.1.0",
714 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
715 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
716 | "dev": true,
717 | "license": "MIT",
718 | "dependencies": {
719 | "binary-extensions": "^2.0.0"
720 | },
721 | "engines": {
722 | "node": ">=8"
723 | }
724 | },
725 | "node_modules/is-extglob": {
726 | "version": "2.1.1",
727 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
728 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
729 | "dev": true,
730 | "license": "MIT",
731 | "engines": {
732 | "node": ">=0.10.0"
733 | }
734 | },
735 | "node_modules/is-glob": {
736 | "version": "4.0.3",
737 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
738 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
739 | "dev": true,
740 | "license": "MIT",
741 | "dependencies": {
742 | "is-extglob": "^2.1.1"
743 | },
744 | "engines": {
745 | "node": ">=0.10.0"
746 | }
747 | },
748 | "node_modules/is-number": {
749 | "version": "7.0.0",
750 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
751 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
752 | "dev": true,
753 | "license": "MIT",
754 | "engines": {
755 | "node": ">=0.12.0"
756 | }
757 | },
758 | "node_modules/is-promise": {
759 | "version": "4.0.0",
760 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
761 | "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
762 | "license": "MIT"
763 | },
764 | "node_modules/is-property": {
765 | "version": "1.0.2",
766 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
767 | "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
768 | "license": "MIT"
769 | },
770 | "node_modules/jsonwebtoken": {
771 | "version": "9.0.2",
772 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
773 | "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
774 | "license": "MIT",
775 | "dependencies": {
776 | "jws": "^3.2.2",
777 | "lodash.includes": "^4.3.0",
778 | "lodash.isboolean": "^3.0.3",
779 | "lodash.isinteger": "^4.0.4",
780 | "lodash.isnumber": "^3.0.3",
781 | "lodash.isplainobject": "^4.0.6",
782 | "lodash.isstring": "^4.0.1",
783 | "lodash.once": "^4.0.0",
784 | "ms": "^2.1.1",
785 | "semver": "^7.5.4"
786 | },
787 | "engines": {
788 | "node": ">=12",
789 | "npm": ">=6"
790 | }
791 | },
792 | "node_modules/jwa": {
793 | "version": "1.4.2",
794 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
795 | "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
796 | "license": "MIT",
797 | "dependencies": {
798 | "buffer-equal-constant-time": "^1.0.1",
799 | "ecdsa-sig-formatter": "1.0.11",
800 | "safe-buffer": "^5.0.1"
801 | }
802 | },
803 | "node_modules/jws": {
804 | "version": "3.2.2",
805 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
806 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
807 | "license": "MIT",
808 | "dependencies": {
809 | "jwa": "^1.4.1",
810 | "safe-buffer": "^5.0.1"
811 | }
812 | },
813 | "node_modules/lodash.includes": {
814 | "version": "4.3.0",
815 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
816 | "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
817 | "license": "MIT"
818 | },
819 | "node_modules/lodash.isboolean": {
820 | "version": "3.0.3",
821 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
822 | "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
823 | "license": "MIT"
824 | },
825 | "node_modules/lodash.isinteger": {
826 | "version": "4.0.4",
827 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
828 | "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
829 | "license": "MIT"
830 | },
831 | "node_modules/lodash.isnumber": {
832 | "version": "3.0.3",
833 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
834 | "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
835 | "license": "MIT"
836 | },
837 | "node_modules/lodash.isplainobject": {
838 | "version": "4.0.6",
839 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
840 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
841 | "license": "MIT"
842 | },
843 | "node_modules/lodash.isstring": {
844 | "version": "4.0.1",
845 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
846 | "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
847 | "license": "MIT"
848 | },
849 | "node_modules/lodash.once": {
850 | "version": "4.1.1",
851 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
852 | "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
853 | "license": "MIT"
854 | },
855 | "node_modules/long": {
856 | "version": "5.3.2",
857 | "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
858 | "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
859 | "license": "Apache-2.0"
860 | },
861 | "node_modules/lru-cache": {
862 | "version": "7.18.3",
863 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
864 | "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
865 | "license": "ISC",
866 | "engines": {
867 | "node": ">=12"
868 | }
869 | },
870 | "node_modules/lru.min": {
871 | "version": "1.1.2",
872 | "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz",
873 | "integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==",
874 | "license": "MIT",
875 | "engines": {
876 | "bun": ">=1.0.0",
877 | "deno": ">=1.30.0",
878 | "node": ">=8.0.0"
879 | },
880 | "funding": {
881 | "type": "github",
882 | "url": "https://github.com/sponsors/wellwelwel"
883 | }
884 | },
885 | "node_modules/math-intrinsics": {
886 | "version": "1.1.0",
887 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
888 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
889 | "license": "MIT",
890 | "engines": {
891 | "node": ">= 0.4"
892 | }
893 | },
894 | "node_modules/media-typer": {
895 | "version": "1.1.0",
896 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
897 | "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
898 | "license": "MIT",
899 | "engines": {
900 | "node": ">= 0.8"
901 | }
902 | },
903 | "node_modules/merge-descriptors": {
904 | "version": "2.0.0",
905 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
906 | "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
907 | "license": "MIT",
908 | "engines": {
909 | "node": ">=18"
910 | },
911 | "funding": {
912 | "url": "https://github.com/sponsors/sindresorhus"
913 | }
914 | },
915 | "node_modules/mime-db": {
916 | "version": "1.54.0",
917 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
918 | "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
919 | "license": "MIT",
920 | "engines": {
921 | "node": ">= 0.6"
922 | }
923 | },
924 | "node_modules/mime-types": {
925 | "version": "3.0.1",
926 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
927 | "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
928 | "license": "MIT",
929 | "dependencies": {
930 | "mime-db": "^1.54.0"
931 | },
932 | "engines": {
933 | "node": ">= 0.6"
934 | }
935 | },
936 | "node_modules/minimatch": {
937 | "version": "3.1.2",
938 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
939 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
940 | "dev": true,
941 | "license": "ISC",
942 | "dependencies": {
943 | "brace-expansion": "^1.1.7"
944 | },
945 | "engines": {
946 | "node": "*"
947 | }
948 | },
949 | "node_modules/minimist": {
950 | "version": "1.2.8",
951 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
952 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
953 | "license": "MIT",
954 | "funding": {
955 | "url": "https://github.com/sponsors/ljharb"
956 | }
957 | },
958 | "node_modules/mkdirp": {
959 | "version": "0.5.6",
960 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
961 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
962 | "license": "MIT",
963 | "dependencies": {
964 | "minimist": "^1.2.6"
965 | },
966 | "bin": {
967 | "mkdirp": "bin/cmd.js"
968 | }
969 | },
970 | "node_modules/ms": {
971 | "version": "2.1.3",
972 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
973 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
974 | "license": "MIT"
975 | },
976 | "node_modules/multer": {
977 | "version": "2.0.2",
978 | "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz",
979 | "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==",
980 | "license": "MIT",
981 | "dependencies": {
982 | "append-field": "^1.0.0",
983 | "busboy": "^1.6.0",
984 | "concat-stream": "^2.0.0",
985 | "mkdirp": "^0.5.6",
986 | "object-assign": "^4.1.1",
987 | "type-is": "^1.6.18",
988 | "xtend": "^4.0.2"
989 | },
990 | "engines": {
991 | "node": ">= 10.16.0"
992 | }
993 | },
994 | "node_modules/multer/node_modules/media-typer": {
995 | "version": "0.3.0",
996 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
997 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
998 | "license": "MIT",
999 | "engines": {
1000 | "node": ">= 0.6"
1001 | }
1002 | },
1003 | "node_modules/multer/node_modules/mime-db": {
1004 | "version": "1.52.0",
1005 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1006 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
1007 | "license": "MIT",
1008 | "engines": {
1009 | "node": ">= 0.6"
1010 | }
1011 | },
1012 | "node_modules/multer/node_modules/mime-types": {
1013 | "version": "2.1.35",
1014 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1015 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1016 | "license": "MIT",
1017 | "dependencies": {
1018 | "mime-db": "1.52.0"
1019 | },
1020 | "engines": {
1021 | "node": ">= 0.6"
1022 | }
1023 | },
1024 | "node_modules/multer/node_modules/type-is": {
1025 | "version": "1.6.18",
1026 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1027 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1028 | "license": "MIT",
1029 | "dependencies": {
1030 | "media-typer": "0.3.0",
1031 | "mime-types": "~2.1.24"
1032 | },
1033 | "engines": {
1034 | "node": ">= 0.6"
1035 | }
1036 | },
1037 | "node_modules/mysql2": {
1038 | "version": "3.14.3",
1039 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.14.3.tgz",
1040 | "integrity": "sha512-fD6MLV8XJ1KiNFIF0bS7Msl8eZyhlTDCDl75ajU5SJtpdx9ZPEACulJcqJWr1Y8OYyxsFc4j3+nflpmhxCU5aQ==",
1041 | "license": "MIT",
1042 | "dependencies": {
1043 | "aws-ssl-profiles": "^1.1.1",
1044 | "denque": "^2.1.0",
1045 | "generate-function": "^2.3.1",
1046 | "iconv-lite": "^0.6.3",
1047 | "long": "^5.2.1",
1048 | "lru.min": "^1.0.0",
1049 | "named-placeholders": "^1.1.3",
1050 | "seq-queue": "^0.0.5",
1051 | "sqlstring": "^2.3.2"
1052 | },
1053 | "engines": {
1054 | "node": ">= 8.0"
1055 | }
1056 | },
1057 | "node_modules/named-placeholders": {
1058 | "version": "1.1.3",
1059 | "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
1060 | "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
1061 | "license": "MIT",
1062 | "dependencies": {
1063 | "lru-cache": "^7.14.1"
1064 | },
1065 | "engines": {
1066 | "node": ">=12.0.0"
1067 | }
1068 | },
1069 | "node_modules/negotiator": {
1070 | "version": "1.0.0",
1071 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
1072 | "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
1073 | "license": "MIT",
1074 | "engines": {
1075 | "node": ">= 0.6"
1076 | }
1077 | },
1078 | "node_modules/node-addon-api": {
1079 | "version": "8.5.0",
1080 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz",
1081 | "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==",
1082 | "license": "MIT",
1083 | "engines": {
1084 | "node": "^18 || ^20 || >= 21"
1085 | }
1086 | },
1087 | "node_modules/node-gyp-build": {
1088 | "version": "4.8.4",
1089 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
1090 | "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
1091 | "license": "MIT",
1092 | "bin": {
1093 | "node-gyp-build": "bin.js",
1094 | "node-gyp-build-optional": "optional.js",
1095 | "node-gyp-build-test": "build-test.js"
1096 | }
1097 | },
1098 | "node_modules/nodemon": {
1099 | "version": "3.1.10",
1100 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
1101 | "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
1102 | "dev": true,
1103 | "license": "MIT",
1104 | "dependencies": {
1105 | "chokidar": "^3.5.2",
1106 | "debug": "^4",
1107 | "ignore-by-default": "^1.0.1",
1108 | "minimatch": "^3.1.2",
1109 | "pstree.remy": "^1.1.8",
1110 | "semver": "^7.5.3",
1111 | "simple-update-notifier": "^2.0.0",
1112 | "supports-color": "^5.5.0",
1113 | "touch": "^3.1.0",
1114 | "undefsafe": "^2.0.5"
1115 | },
1116 | "bin": {
1117 | "nodemon": "bin/nodemon.js"
1118 | },
1119 | "engines": {
1120 | "node": ">=10"
1121 | },
1122 | "funding": {
1123 | "type": "opencollective",
1124 | "url": "https://opencollective.com/nodemon"
1125 | }
1126 | },
1127 | "node_modules/normalize-path": {
1128 | "version": "3.0.0",
1129 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1130 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1131 | "dev": true,
1132 | "license": "MIT",
1133 | "engines": {
1134 | "node": ">=0.10.0"
1135 | }
1136 | },
1137 | "node_modules/object-assign": {
1138 | "version": "4.1.1",
1139 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1140 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
1141 | "license": "MIT",
1142 | "engines": {
1143 | "node": ">=0.10.0"
1144 | }
1145 | },
1146 | "node_modules/object-inspect": {
1147 | "version": "1.13.4",
1148 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
1149 | "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
1150 | "license": "MIT",
1151 | "engines": {
1152 | "node": ">= 0.4"
1153 | },
1154 | "funding": {
1155 | "url": "https://github.com/sponsors/ljharb"
1156 | }
1157 | },
1158 | "node_modules/on-finished": {
1159 | "version": "2.4.1",
1160 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1161 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1162 | "license": "MIT",
1163 | "dependencies": {
1164 | "ee-first": "1.1.1"
1165 | },
1166 | "engines": {
1167 | "node": ">= 0.8"
1168 | }
1169 | },
1170 | "node_modules/once": {
1171 | "version": "1.4.0",
1172 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1173 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1174 | "license": "ISC",
1175 | "dependencies": {
1176 | "wrappy": "1"
1177 | }
1178 | },
1179 | "node_modules/parseurl": {
1180 | "version": "1.3.3",
1181 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1182 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1183 | "license": "MIT",
1184 | "engines": {
1185 | "node": ">= 0.8"
1186 | }
1187 | },
1188 | "node_modules/path-to-regexp": {
1189 | "version": "8.2.0",
1190 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
1191 | "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
1192 | "license": "MIT",
1193 | "engines": {
1194 | "node": ">=16"
1195 | }
1196 | },
1197 | "node_modules/picomatch": {
1198 | "version": "2.3.1",
1199 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1200 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1201 | "dev": true,
1202 | "license": "MIT",
1203 | "engines": {
1204 | "node": ">=8.6"
1205 | },
1206 | "funding": {
1207 | "url": "https://github.com/sponsors/jonschlinkert"
1208 | }
1209 | },
1210 | "node_modules/proxy-addr": {
1211 | "version": "2.0.7",
1212 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1213 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1214 | "license": "MIT",
1215 | "dependencies": {
1216 | "forwarded": "0.2.0",
1217 | "ipaddr.js": "1.9.1"
1218 | },
1219 | "engines": {
1220 | "node": ">= 0.10"
1221 | }
1222 | },
1223 | "node_modules/pstree.remy": {
1224 | "version": "1.1.8",
1225 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
1226 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
1227 | "dev": true,
1228 | "license": "MIT"
1229 | },
1230 | "node_modules/qs": {
1231 | "version": "6.14.0",
1232 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
1233 | "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
1234 | "license": "BSD-3-Clause",
1235 | "dependencies": {
1236 | "side-channel": "^1.1.0"
1237 | },
1238 | "engines": {
1239 | "node": ">=0.6"
1240 | },
1241 | "funding": {
1242 | "url": "https://github.com/sponsors/ljharb"
1243 | }
1244 | },
1245 | "node_modules/range-parser": {
1246 | "version": "1.2.1",
1247 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1248 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1249 | "license": "MIT",
1250 | "engines": {
1251 | "node": ">= 0.6"
1252 | }
1253 | },
1254 | "node_modules/raw-body": {
1255 | "version": "3.0.0",
1256 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
1257 | "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
1258 | "license": "MIT",
1259 | "dependencies": {
1260 | "bytes": "3.1.2",
1261 | "http-errors": "2.0.0",
1262 | "iconv-lite": "0.6.3",
1263 | "unpipe": "1.0.0"
1264 | },
1265 | "engines": {
1266 | "node": ">= 0.8"
1267 | }
1268 | },
1269 | "node_modules/readable-stream": {
1270 | "version": "3.6.2",
1271 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
1272 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
1273 | "license": "MIT",
1274 | "dependencies": {
1275 | "inherits": "^2.0.3",
1276 | "string_decoder": "^1.1.1",
1277 | "util-deprecate": "^1.0.1"
1278 | },
1279 | "engines": {
1280 | "node": ">= 6"
1281 | }
1282 | },
1283 | "node_modules/readdirp": {
1284 | "version": "3.6.0",
1285 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
1286 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1287 | "dev": true,
1288 | "license": "MIT",
1289 | "dependencies": {
1290 | "picomatch": "^2.2.1"
1291 | },
1292 | "engines": {
1293 | "node": ">=8.10.0"
1294 | }
1295 | },
1296 | "node_modules/router": {
1297 | "version": "2.2.0",
1298 | "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
1299 | "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
1300 | "license": "MIT",
1301 | "dependencies": {
1302 | "debug": "^4.4.0",
1303 | "depd": "^2.0.0",
1304 | "is-promise": "^4.0.0",
1305 | "parseurl": "^1.3.3",
1306 | "path-to-regexp": "^8.0.0"
1307 | },
1308 | "engines": {
1309 | "node": ">= 18"
1310 | }
1311 | },
1312 | "node_modules/safe-buffer": {
1313 | "version": "5.2.1",
1314 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1315 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1316 | "funding": [
1317 | {
1318 | "type": "github",
1319 | "url": "https://github.com/sponsors/feross"
1320 | },
1321 | {
1322 | "type": "patreon",
1323 | "url": "https://www.patreon.com/feross"
1324 | },
1325 | {
1326 | "type": "consulting",
1327 | "url": "https://feross.org/support"
1328 | }
1329 | ],
1330 | "license": "MIT"
1331 | },
1332 | "node_modules/safer-buffer": {
1333 | "version": "2.1.2",
1334 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1335 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1336 | "license": "MIT"
1337 | },
1338 | "node_modules/semver": {
1339 | "version": "7.7.2",
1340 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
1341 | "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
1342 | "license": "ISC",
1343 | "bin": {
1344 | "semver": "bin/semver.js"
1345 | },
1346 | "engines": {
1347 | "node": ">=10"
1348 | }
1349 | },
1350 | "node_modules/send": {
1351 | "version": "1.2.0",
1352 | "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
1353 | "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
1354 | "license": "MIT",
1355 | "dependencies": {
1356 | "debug": "^4.3.5",
1357 | "encodeurl": "^2.0.0",
1358 | "escape-html": "^1.0.3",
1359 | "etag": "^1.8.1",
1360 | "fresh": "^2.0.0",
1361 | "http-errors": "^2.0.0",
1362 | "mime-types": "^3.0.1",
1363 | "ms": "^2.1.3",
1364 | "on-finished": "^2.4.1",
1365 | "range-parser": "^1.2.1",
1366 | "statuses": "^2.0.1"
1367 | },
1368 | "engines": {
1369 | "node": ">= 18"
1370 | }
1371 | },
1372 | "node_modules/seq-queue": {
1373 | "version": "0.0.5",
1374 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
1375 | "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
1376 | },
1377 | "node_modules/serve-static": {
1378 | "version": "2.2.0",
1379 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
1380 | "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
1381 | "license": "MIT",
1382 | "dependencies": {
1383 | "encodeurl": "^2.0.0",
1384 | "escape-html": "^1.0.3",
1385 | "parseurl": "^1.3.3",
1386 | "send": "^1.2.0"
1387 | },
1388 | "engines": {
1389 | "node": ">= 18"
1390 | }
1391 | },
1392 | "node_modules/setprototypeof": {
1393 | "version": "1.2.0",
1394 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1395 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
1396 | "license": "ISC"
1397 | },
1398 | "node_modules/side-channel": {
1399 | "version": "1.1.0",
1400 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
1401 | "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
1402 | "license": "MIT",
1403 | "dependencies": {
1404 | "es-errors": "^1.3.0",
1405 | "object-inspect": "^1.13.3",
1406 | "side-channel-list": "^1.0.0",
1407 | "side-channel-map": "^1.0.1",
1408 | "side-channel-weakmap": "^1.0.2"
1409 | },
1410 | "engines": {
1411 | "node": ">= 0.4"
1412 | },
1413 | "funding": {
1414 | "url": "https://github.com/sponsors/ljharb"
1415 | }
1416 | },
1417 | "node_modules/side-channel-list": {
1418 | "version": "1.0.0",
1419 | "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
1420 | "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
1421 | "license": "MIT",
1422 | "dependencies": {
1423 | "es-errors": "^1.3.0",
1424 | "object-inspect": "^1.13.3"
1425 | },
1426 | "engines": {
1427 | "node": ">= 0.4"
1428 | },
1429 | "funding": {
1430 | "url": "https://github.com/sponsors/ljharb"
1431 | }
1432 | },
1433 | "node_modules/side-channel-map": {
1434 | "version": "1.0.1",
1435 | "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
1436 | "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
1437 | "license": "MIT",
1438 | "dependencies": {
1439 | "call-bound": "^1.0.2",
1440 | "es-errors": "^1.3.0",
1441 | "get-intrinsic": "^1.2.5",
1442 | "object-inspect": "^1.13.3"
1443 | },
1444 | "engines": {
1445 | "node": ">= 0.4"
1446 | },
1447 | "funding": {
1448 | "url": "https://github.com/sponsors/ljharb"
1449 | }
1450 | },
1451 | "node_modules/side-channel-weakmap": {
1452 | "version": "1.0.2",
1453 | "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
1454 | "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
1455 | "license": "MIT",
1456 | "dependencies": {
1457 | "call-bound": "^1.0.2",
1458 | "es-errors": "^1.3.0",
1459 | "get-intrinsic": "^1.2.5",
1460 | "object-inspect": "^1.13.3",
1461 | "side-channel-map": "^1.0.1"
1462 | },
1463 | "engines": {
1464 | "node": ">= 0.4"
1465 | },
1466 | "funding": {
1467 | "url": "https://github.com/sponsors/ljharb"
1468 | }
1469 | },
1470 | "node_modules/simple-update-notifier": {
1471 | "version": "2.0.0",
1472 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
1473 | "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
1474 | "dev": true,
1475 | "license": "MIT",
1476 | "dependencies": {
1477 | "semver": "^7.5.3"
1478 | },
1479 | "engines": {
1480 | "node": ">=10"
1481 | }
1482 | },
1483 | "node_modules/sqlstring": {
1484 | "version": "2.3.3",
1485 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
1486 | "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
1487 | "license": "MIT",
1488 | "engines": {
1489 | "node": ">= 0.6"
1490 | }
1491 | },
1492 | "node_modules/statuses": {
1493 | "version": "2.0.2",
1494 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
1495 | "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
1496 | "license": "MIT",
1497 | "engines": {
1498 | "node": ">= 0.8"
1499 | }
1500 | },
1501 | "node_modules/streamsearch": {
1502 | "version": "1.1.0",
1503 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
1504 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
1505 | "engines": {
1506 | "node": ">=10.0.0"
1507 | }
1508 | },
1509 | "node_modules/string_decoder": {
1510 | "version": "1.3.0",
1511 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
1512 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
1513 | "license": "MIT",
1514 | "dependencies": {
1515 | "safe-buffer": "~5.2.0"
1516 | }
1517 | },
1518 | "node_modules/supports-color": {
1519 | "version": "5.5.0",
1520 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1521 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1522 | "dev": true,
1523 | "license": "MIT",
1524 | "dependencies": {
1525 | "has-flag": "^3.0.0"
1526 | },
1527 | "engines": {
1528 | "node": ">=4"
1529 | }
1530 | },
1531 | "node_modules/to-regex-range": {
1532 | "version": "5.0.1",
1533 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1534 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1535 | "dev": true,
1536 | "license": "MIT",
1537 | "dependencies": {
1538 | "is-number": "^7.0.0"
1539 | },
1540 | "engines": {
1541 | "node": ">=8.0"
1542 | }
1543 | },
1544 | "node_modules/toidentifier": {
1545 | "version": "1.0.1",
1546 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1547 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
1548 | "license": "MIT",
1549 | "engines": {
1550 | "node": ">=0.6"
1551 | }
1552 | },
1553 | "node_modules/touch": {
1554 | "version": "3.1.1",
1555 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
1556 | "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
1557 | "dev": true,
1558 | "license": "ISC",
1559 | "bin": {
1560 | "nodetouch": "bin/nodetouch.js"
1561 | }
1562 | },
1563 | "node_modules/type-is": {
1564 | "version": "2.0.1",
1565 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
1566 | "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
1567 | "license": "MIT",
1568 | "dependencies": {
1569 | "content-type": "^1.0.5",
1570 | "media-typer": "^1.1.0",
1571 | "mime-types": "^3.0.0"
1572 | },
1573 | "engines": {
1574 | "node": ">= 0.6"
1575 | }
1576 | },
1577 | "node_modules/typedarray": {
1578 | "version": "0.0.6",
1579 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
1580 | "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
1581 | "license": "MIT"
1582 | },
1583 | "node_modules/undefsafe": {
1584 | "version": "2.0.5",
1585 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
1586 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
1587 | "dev": true,
1588 | "license": "MIT"
1589 | },
1590 | "node_modules/unpipe": {
1591 | "version": "1.0.0",
1592 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1593 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1594 | "license": "MIT",
1595 | "engines": {
1596 | "node": ">= 0.8"
1597 | }
1598 | },
1599 | "node_modules/util-deprecate": {
1600 | "version": "1.0.2",
1601 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1602 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
1603 | "license": "MIT"
1604 | },
1605 | "node_modules/vary": {
1606 | "version": "1.1.2",
1607 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1608 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
1609 | "license": "MIT",
1610 | "engines": {
1611 | "node": ">= 0.8"
1612 | }
1613 | },
1614 | "node_modules/wrappy": {
1615 | "version": "1.0.2",
1616 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1617 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
1618 | "license": "ISC"
1619 | },
1620 | "node_modules/xtend": {
1621 | "version": "4.0.2",
1622 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
1623 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
1624 | "license": "MIT",
1625 | "engines": {
1626 | "node": ">=0.4"
1627 | }
1628 | }
1629 | }
1630 | }
1631 |
--------------------------------------------------------------------------------